perf: разбить вычитание лестниц по кадрам (#663)

Issue: #663
User-Visible: no
This commit is contained in:
Matysh
2026-09-26 23:48:01 +03:00
parent bcc5481557
commit ea1f19c352
4 changed files with 79 additions and 4 deletions
+30
View File
@@ -247,3 +247,33 @@ export function geometryMinusStairs(
return geometry;
}
}
/**
* The summary panel calculates floor area after the first paint. A maximum
* size space may contain 250 stairs; clipping all their footprints in one
* polyclip call is observably one long main-thread task on slower clients.
* Keep the synchronous helper above for ordinary room-sized callers, while
* this iterator bounds each background slice and lets the scheduler yield.
*/
export function* geometryMinusStairsSteps(
source: Geom,
stairs: readonly Stair[] | null | undefined,
scale = NORM_W,
batchSize = 24,
): Generator<void, Geom, void> {
const footprints = stairList(stairs).map((stair) => stairFootprintGeometry(stair, scale));
const size = Math.max(1, Math.floor(batchSize));
let geometry = source;
for (let index = 0; index < footprints.length; index += size) {
const batch = footprints.slice(index, index + size);
try {
geometry = difference(geometry, ...batch);
} catch {
for (const footprint of batch) {
try { geometry = difference(geometry, footprint); } catch { /* skip only the bad record */ }
}
}
yield;
}
return geometry;
}
+11 -4
View File
@@ -9,7 +9,7 @@ import { innerContourForRoom, multiWallNodesForGeometry, wallBodiesGeometry } fr
import type { Marker, ServerConfig, SpaceModel, SummaryPanelSource } from './types';
import type { HaRegistrySnapshot } from './ha-binding-status';
import type { SummaryHass } from './summary-panel-host';
import { geometryMinusStairs } from './stairs';
import { geometryMinusStairsSteps } from './stairs';
/** Count the unique real HA devices represented anywhere on the plan. */
export function representedHaDeviceIds(input: {
@@ -119,9 +119,16 @@ export function* cleanFloorAreaSteps(
spaceFloor = unionGeometry(spaceFloor, clean);
yield;
}
// Difference distributes over union. Subtracting the shared stair set once
// avoids rooms x stairs polygon clips on dense plans (#663).
spaceFloor = geometryMinusStairs(spaceFloor || [], space.stairs);
// Difference distributes over union. Subtract the shared stair set once,
// but in bounded batches: 250 footprints in one polyclip sweep becomes a
// visible long task on slower clients (#663).
const stairSteps = geometryMinusStairsSteps(spaceFloor || [], space.stairs);
let stairStep = stairSteps.next();
while (!stairStep.done) {
yield;
stairStep = stairSteps.next();
}
spaceFloor = stairStep.value;
const cmPerUnit = prepared.cellCm / GRID_PITCH;
total += geometryArea(spaceFloor) * cmPerUnit * cmPerUnit / 1e4;
}