mirror of
https://github.com/Matysh/houseplan-card
synced 2026-10-07 15:09:30 +00:00
+11
-13
@@ -378,6 +378,7 @@ import {
|
||||
openingVisibleMetrics, renderOpeningVisibleGeometry,
|
||||
type OpeningFaceOffset, type OpeningVisibleSpec,
|
||||
} from './render/opening-symbol';
|
||||
import { openingLockFloorPlacement } from './opening-symbol-placement';
|
||||
import {
|
||||
openingDefaultLengthCm, openingPlacementPreset, passagePlacementPreviewGeometry,
|
||||
resolveOpeningPlacementResult, sameOpeningPlacementInput,
|
||||
@@ -6166,18 +6167,6 @@ export class HouseplanCard extends LitElement {
|
||||
const start = unprojectFloorPoint([view.x, view.y]), end = unprojectFloorPoint([view.x + view.w, view.y + view.h]);
|
||||
return { x: start[0], y: start[1], w: end[0] - start[0], h: end[1] - start[1] };
|
||||
}
|
||||
/** Shared Flat/Iso host-face semantics for raised opening locks. */
|
||||
private _openingLockAnchor(opening: RenderOpening, openingWallIndex: OpeningWallIndex): PlanPoint {
|
||||
const rad = ((opening.angle + 90) * Math.PI) / 180;
|
||||
const gateFace = opening.type === 'gate'
|
||||
? this._openingFace(opening, openingWallIndex, !opening.flip_v)
|
||||
: null;
|
||||
const lockOffset = gridVisualUnits(16, this._cellCm);
|
||||
const offset = gateFace
|
||||
? -lockOffset * gateFace.side
|
||||
: lockOffset * (opening.flip_v ? -1 : 1);
|
||||
return [opening.rx + Math.cos(rad) * offset, opening.ry + Math.sin(rad) * offset];
|
||||
}
|
||||
/** Stage 3 keeps one immutable floor point and one runtime visual point per
|
||||
* raised item. This snapshot is presentation-only and never enters config. */
|
||||
private _isoOverlayScene(
|
||||
@@ -13094,7 +13083,16 @@ export class HouseplanCard extends LitElement {
|
||||
const st = this._renderPlanHass.states[o.lock!]?.state;
|
||||
const locked = st === 'locked';
|
||||
const known = locked || ['unlocked', 'open', 'opening', 'unlocking', 'locking'].includes(String(st));
|
||||
const floorAnchor = this._openingLockAnchor(o, openingWallIndex);
|
||||
const gateFace = o.type === 'gate'
|
||||
? this._openingFace(o, openingWallIndex, !o.flip_v)
|
||||
: null;
|
||||
const floorAnchor = openingLockFloorPlacement({
|
||||
x: o.rx,
|
||||
y: o.ry,
|
||||
angle: o.angle,
|
||||
flipV: !!o.flip_v,
|
||||
gateFace,
|
||||
}, this._cellCm)[0];
|
||||
const isoPlacement = isoPlacements?.get(String(o.id));
|
||||
const point = isoPlacement?.visualScene ?? this._scenePoint(floorAnchor);
|
||||
const left = ((point[0] - view.x) / view.w) * 100;
|
||||
|
||||
@@ -35,6 +35,7 @@ import {
|
||||
type OpeningWallIndex, type WallEntry,
|
||||
} from './wall-thickness';
|
||||
import { partitionOpeningFace } from './partition-openings';
|
||||
import { openingLockFloorPlacement } from './opening-symbol-placement';
|
||||
import { physicalBodyParts, type PartitionOpeningCut } from './physical-geometry';
|
||||
import { gridVisualScale, gridVisualUnits } from './grid-scale';
|
||||
import { iconUnit, type Rect } from './space-geometry';
|
||||
@@ -855,7 +856,6 @@ export function isoOpeningLockPlacement(
|
||||
openingWallIndex: OpeningWallIndex,
|
||||
cellCm: number,
|
||||
): { floorAnchor: PlanPoint; preferredRoomId: string | null } {
|
||||
const rad = ((opening.angle + 90) * Math.PI) / 180;
|
||||
const faceFlipV = !opening.flip_v;
|
||||
const gateFace = opening.type === 'gate'
|
||||
? opening.partitionHost
|
||||
@@ -868,20 +868,21 @@ export function isoOpeningLockPlacement(
|
||||
flip_v: faceFlipV,
|
||||
})
|
||||
: null;
|
||||
const lockOffset = gridVisualUnits(16, cellCm);
|
||||
const offset = gateFace ? -lockOffset * gateFace.side : lockOffset * (opening.flip_v ? -1 : 1);
|
||||
const floorAnchor: PlanPoint = [
|
||||
opening.rx + Math.cos(rad) * offset,
|
||||
opening.ry + Math.sin(rad) * offset,
|
||||
];
|
||||
const [floorAnchor, negativeSide] = openingLockFloorPlacement({
|
||||
x: opening.rx,
|
||||
y: opening.ry,
|
||||
angle: opening.angle,
|
||||
flipV: !!opening.flip_v,
|
||||
gateFace,
|
||||
}, cellCm);
|
||||
if (opening.partitionHost) return { floorAnchor, preferredRoomId: null };
|
||||
const side = offset < 0 ? 'negative' : 'positive';
|
||||
const association = resolveOpeningWallAssociation(openingWallIndex, {
|
||||
x: opening.rx,
|
||||
y: opening.ry,
|
||||
angle: opening.angle,
|
||||
length: opening.rlen,
|
||||
}, true);
|
||||
const side = negativeSide ? 'negative' : 'positive';
|
||||
return { floorAnchor, preferredRoomId: association[side]?.roomId || null };
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import type { OpeningCfg } from './types';
|
||||
import { gridVisualUnits } from './grid-scale';
|
||||
|
||||
export interface OpeningFaceOffset {
|
||||
ox: number;
|
||||
@@ -12,6 +13,19 @@ export interface OpeningSymbolOffset {
|
||||
oy: number;
|
||||
}
|
||||
|
||||
export interface OpeningLockAnchorInput {
|
||||
x: number;
|
||||
y: number;
|
||||
angle: number;
|
||||
flipV: boolean;
|
||||
gateFace?: Pick<OpeningFaceOffset, 'side'> | null;
|
||||
}
|
||||
|
||||
export type OpeningLockFloorPlacement = [
|
||||
floorAnchor: [number, number],
|
||||
negativeSide: boolean,
|
||||
];
|
||||
|
||||
/**
|
||||
* Resolve only the visible symbol translation. Every opening symbol stays on
|
||||
* the saved wall centreline: wall-face direction/depth and flip direction are
|
||||
@@ -25,3 +39,21 @@ export function openingSymbolOffset(
|
||||
): OpeningSymbolOffset {
|
||||
return { ox: 0, oy: 0 };
|
||||
}
|
||||
|
||||
/** One Flat/Iso authority for an opening lock's immutable floor placement. */
|
||||
export function openingLockFloorPlacement(
|
||||
opening: OpeningLockAnchorInput, cellCm: number,
|
||||
): OpeningLockFloorPlacement {
|
||||
const rad = ((opening.angle + 90) * Math.PI) / 180;
|
||||
const lockOffset = gridVisualUnits(16, cellCm);
|
||||
const offset = opening.gateFace
|
||||
? -lockOffset * opening.gateFace.side
|
||||
: lockOffset * (opening.flipV ? -1 : 1);
|
||||
return [
|
||||
[
|
||||
opening.x + Math.cos(rad) * offset,
|
||||
opening.y + Math.sin(rad) * offset,
|
||||
],
|
||||
offset < 0,
|
||||
];
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user