Files
houseplan-card/demo/smoke_resize_inner_dimensions.mjs
2026-08-27 20:30:07 +03:00

103 lines
4.5 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* Issue #233: resize labels measure between wall faces, not between centrelines.
*
* Before the fix one bubble carried two conventions at once — lengths along the
* centreline next to an area computed from the floor — so «3.00 × 4.00 · 11.0 m²»
* described a room that no tape measure would confirm.
*
* The room below is 300×400 cm centre-to-centre with 15 cm walls on all four
* sides, so every clear span is exactly 15 cm shorter than the axis it sits on:
* 285 and 385 cm. Thickness is set through the card's own dialog path
* (`_wallThickClick` → `_wallThickApply(true)`), and both label producers are
* then called as the drag handlers call them. The legacy room-scale frame was
* deliberately removed by #277, so only fixed-topology edge labels remain.
*/
import { launch, checkAll, finish } from './serve.mjs';
const { page, browser } = await launch();
const res = await page.evaluate(async () => {
const out = {};
const c = window.__card;
const sr = c.shadowRoot || c.renderRoot;
const upd = async () => { c._cfgEpoch++; c.requestUpdate(); await c.updateComplete; };
// First number of a label: both formatters emit a dot, so this is locale-safe.
const num = (text) => Number((String(text).match(/-?\d+(?:\.\d+)?/) || [])[0]);
c._setMode('plan');
await upd();
const space = c._curSpaceCfg;
const savedConfig = JSON.parse(JSON.stringify(c._serverCfg));
// 5 cm to a grid cell, so 300×400 cm is 60×80 cells of the plan.
space.cell_cm = 5;
c._serverCfg.model_version = 7;
space.partitions = [];
delete space.walls;
delete space.wall_segments;
delete space.open_spans;
const g = c._gridPitch;
const x0 = 20 * g, y0 = 20 * g;
const render = [
[x0, y0], [x0 + 60 * g, y0], [x0 + 60 * g, y0 + 80 * g], [x0, y0 + 80 * g],
];
space.rooms = [{ id: 'r233', name: 'r233', poly: render.map((p) => [p[0] / 1000, p[1] / 1000]) }];
await upd();
out.roomBuilt = !!c._spaceModel()?.rooms?.some((r) => r.id === 'r233');
// 15 cm on every side, applied the way the Thickness tool applies it.
c._tool = 'wallthick';
await upd();
const mid = (a, b) => [(a[0] + b[0]) / 2, (a[1] + b[1]) / 2];
c._wallThickClick(mid(render[0], render[1]));
await upd();
out.thicknessDialogOpened = !!c._wallDialog && c._wallDialog.roomId === 'r233';
if (c._wallDialog) c._wallDialog = { ...c._wallDialog, value: '15' };
c._wallThickApply(true);
await upd();
const committed = c._curSpaceCfg;
const committedRoom = committed.rooms.find((room) => room.id === 'r233');
const byId = new Map((committed.wall_segments || []).map((segment) => [segment.id, segment]));
out.fourWallsRecorded = committedRoom?.wall_ids?.length === 4;
out.everyWallFifteen = committedRoom?.wall_ids?.every((id) =>
Math.abs((byId.get(id)?.cm ?? -1) - 15) < 0.01) === true;
// Wall labels: the clear span across is 285 cm, along it 385 cm.
const spans = c._rszInnerSpanCms('r233', render, {});
out.spansComputed = Array.isArray(spans) && spans.length === 4;
out.spanAcrossIsInner = !!spans && Math.abs(spans[0] - 285) < 1;
out.spanAlongIsInner = !!spans && Math.abs(spans[1] - 385) < 1;
out.spansSymmetric = !!spans
&& Math.abs(spans[0] - spans[2]) < 1 && Math.abs(spans[1] - spans[3]) < 1;
// The whole point of #233: no label may still read the centreline.
out.noCentrelineSpan = !!spans
&& !spans.some((s) => Math.abs(s - 300) < 0.5 || Math.abs(s - 400) < 0.5);
// The two useful side-wall bubbles, called with the controller's room snapshot.
const resizeRooms = c._spaceModel().rooms.map((r) => ({ id: r.id, poly: r.poly }));
await upd();
const drag = c._rszEdgeLabels(
{ polys: { r233: render } },
{ roomId: 'r233', edge: 0, roomIds: ['r233'], edgeByRoom: { r233: 0 } },
resizeRooms,
);
const dragLens = drag.filter((l) => l.kind === 'length').map((l) => num(l.text));
out.dragLabelsTwoSideEdges = dragLens.length === 2;
out.dragLabelsInner = dragLens.every((v) => Math.abs(v - 2.85) < 0.02 || Math.abs(v - 3.85) < 0.02);
out.dragLabelsNotCentreline = !dragLens.some((v) => Math.abs(v - 3) < 0.005 || Math.abs(v - 4) < 0.005);
const dragArea = drag.find((l) => l.kind === 'area');
out.dragAreaStillInner = !!dragArea && Math.abs(num(dragArea.text) - 11) < 0.06;
out.legacyScaleLabelsAbsent = typeof c._rszScaleLabels === 'undefined';
out.legacyCornerHandlesAbsent = !sr.querySelector('.rszcorner');
c._resize.reset();
c._tool = null;
c._serverCfg = savedConfig;
c._modelCache = null; c._frame = null;
await upd();
return out;
});
checkAll(res);
await finish(browser);