fix v1.38.4: derived wall segments trimmed under open boundaries

- the markup layer's .seg lines ran solid through open stretches;
  cutSegments extracted (outlineWithout now reuses it) and applied to
  _segments in _renderMarkupLayer
- smoke_openwall: planSegCut check (15 total); docs same-commit
This commit is contained in:
Matysh
2026-07-23 17:20:06 +03:00
parent 9c92bcdf2f
commit 9bfef453db
11 changed files with 111 additions and 81 deletions
+7 -3
View File
@@ -14,7 +14,7 @@ import {
import {
lqiColor, snapToGrid, samePoint, pointInPolygon, markerIdForBinding,
segmentCm, formatLength, roomEdges, roomPoly, pointStrictlyInside, roomsOverlap,
pointOnBoundary, mergeRooms, splitRoomPath, polygonArea, closestPointOnBoundary, pointStrictlyInside as ptInside, islandsOf, sharedBoundary, openZoneOf, distToSegment, outlineWithout,
pointOnBoundary, mergeRooms, splitRoomPath, polygonArea, closestPointOnBoundary, pointStrictlyInside as ptInside, islandsOf, sharedBoundary, openZoneOf, distToSegment, outlineWithout, cutSegments,
snapToWall, openingAmount,
averageLqi, fitView, declump, safeUrl, resolveTapAction, floorsOf, type FloorInfo,
stateIcon, lightColorOf, isAlarmState, parseRoomRef, diffNewDevices, glowColorOf, doorSector, hasRoomBehind, controlsAction, isControllable,
@@ -32,7 +32,7 @@ import './space-card';
import { cardStyles } from './styles';
import { langOf, t, type I18nKey } from './i18n';
const CARD_VERSION = '1.38.3';
const CARD_VERSION = '1.38.4';
const LS_KEY = 'houseplan_card_layout_v1';
const LS_CFG = 'houseplan_card_cfg_v1'; // cache of the server config+layout for instant rendering
const LS_ZOOM = 'houseplan_card_zoom_v1';
@@ -3780,7 +3780,11 @@ class HouseplanCard extends LitElement {
}
private _renderMarkupLayer(vb: number[]): TemplateResult {
const segs = this._segments;
// derived walls minus the open stretches — those are drawn dashed on top
const openCuts = this._openPairs().flatMap((p) => p.segs);
const segs = openCuts.length
? cutSegments(this._segments, openCuts, this._gridPitch * 0.02)
: this._segments;
const path = this._path;
const g = this._gridPitch;
return svg`
+15 -6
View File
@@ -912,14 +912,13 @@ export function openZoneOf(roomId: string, rooms: { id?: string; open_to?: strin
}
/**
* Room outline pieces with the given collinear stretches removed used to
* draw a TRUE dashed open boundary (the solid stroke must not run beneath).
* Returns segments [x1,y1,x2,y2].
* Segments with the given collinear stretches removed the workhorse behind
* TRUE dashed open boundaries (derived walls and room outlines alike).
*/
export function outlineWithout(poly: number[][], cuts: number[][], eps = 1e-6): number[][] {
export function cutSegments(segs: number[][], cuts: number[][], eps = 1e-6): number[][] {
const out: number[][] = [];
for (let i = 0; i < poly.length; i++) {
const p1 = poly[i], p2 = poly[(i + 1) % poly.length];
for (const seg of segs) {
const p1 = [seg[0], seg[1]], p2 = [seg[2], seg[3]];
const dx = p2[0] - p1[0], dy = p2[1] - p1[1];
const len = Math.hypot(dx, dy);
if (len < eps) continue;
@@ -952,6 +951,16 @@ export function outlineWithout(poly: number[][], cuts: number[][], eps = 1e-6):
return out;
}
/** Room outline pieces with the given collinear stretches removed. */
export function outlineWithout(poly: number[][], cuts: number[][], eps = 1e-6): number[][] {
const edges: number[][] = [];
for (let i = 0; i < poly.length; i++) {
const p1 = poly[i], p2 = poly[(i + 1) % poly.length];
edges.push([p1[0], p1[1], p2[0], p2[1]]);
}
return cutSegments(edges, cuts, eps);
}
/** Distance from a point to a segment [x1,y1,x2,y2]. */
export function distToSegment(p: number[], s: number[]): number {
const dx = s[2] - s[0], dy = s[3] - s[1];