mirror of
https://github.com/Matysh/houseplan-card
synced 2026-09-29 03:09:36 +00:00
fix: preserve legacy resize lattice endpoints
Issue: #298 User-Visible: no
This commit is contained in:
File diff suppressed because one or more lines are too long
Vendored
+112
-112
File diff suppressed because one or more lines are too long
+2
-2
@@ -149,8 +149,8 @@ vertex; an interior thickness breakpoint stays on its physical boundary rather
|
||||
than keeping a proportional fraction of the new edge. Unrelated exact records
|
||||
remain byte-equivalent. The candidate then proves that every new exact record
|
||||
is lattice-safe and continuously covered by room-wall/partition carriers. An
|
||||
unchanged historical violation may remain readable, but Resize cannot add or
|
||||
replace it with a different violation.
|
||||
unchanged historical endpoint may remain readable even when its record changes
|
||||
around it, but Resize cannot add or replace it with a different violation.
|
||||
|
||||
When the two owners of a shared moving seam split one physically continuous
|
||||
side-wall record at their meeting point, the mapped atoms are joined back only
|
||||
|
||||
@@ -71,9 +71,10 @@ projection for side walls. A rigidly translated moving edge carries every
|
||||
breakpoint by the same vector; a side edge that only changes length moves its
|
||||
paired topology endpoint and leaves interior thickness boundaries fixed. A
|
||||
continuous carrier-coverage and lattice proof runs before preview/commit. It
|
||||
compares exact historical debt by record identity, so an old off-grid record is
|
||||
not silently migrated, while a new or changed violation rejects the whole
|
||||
candidate. This is distinct from the retained generic scale/rotation helper
|
||||
compares exact historical debt by record identity and endpoint identity, so an
|
||||
old off-grid endpoint is not silently migrated even when its record's other end
|
||||
moves, while a new or changed violation rejects the whole candidate. This is
|
||||
distinct from the retained generic scale/rotation helper
|
||||
used only by isolated historical pure tests.
|
||||
|
||||
## 2. Growth (centreline ±½)
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 290 KiB After Width: | Height: | Size: 290 KiB |
@@ -2,7 +2,7 @@
|
||||
"version": 1,
|
||||
"fixture": "synthetic-only",
|
||||
"chromium": "151.0.7922.34",
|
||||
"sourceFingerprint": "c3a3a4e0cf22bec8f48da581241ac553747a0c3cfe5db34e5c8be9bad4240561",
|
||||
"sourceFingerprint": "662c04e08745a510fd710d98780c3960471546776bf6dfd66c1529bd892a0826",
|
||||
"captureScriptSha256": "ce2e9542fed9dade3085be87d16f69adb2ac8262893ad78ad966b1b9673f2983",
|
||||
"command": "npm run build && node demo/docs/capture.mjs",
|
||||
"scenarios": {
|
||||
@@ -14,7 +14,7 @@
|
||||
},
|
||||
"theme": "dark",
|
||||
"language": "en",
|
||||
"sourceSha256": "c3a3a4e0cf22bec8f48da581241ac553747a0c3cfe5db34e5c8be9bad4240561",
|
||||
"sourceSha256": "662c04e08745a510fd710d98780c3960471546776bf6dfd66c1529bd892a0826",
|
||||
"imageSha256": "5ba555c1f46416ce17e40ef2b6ecd9eb6e1d0ce6b8d467acd0682af95bd36307"
|
||||
},
|
||||
"view-touch": {
|
||||
@@ -25,7 +25,7 @@
|
||||
},
|
||||
"theme": "dark",
|
||||
"language": "en",
|
||||
"sourceSha256": "c3a3a4e0cf22bec8f48da581241ac553747a0c3cfe5db34e5c8be9bad4240561",
|
||||
"sourceSha256": "662c04e08745a510fd710d98780c3960471546776bf6dfd66c1529bd892a0826",
|
||||
"imageSha256": "deaae14893e66337b42e45ccfe87cf16f571cfc10f98da4250a6a6589a092a43"
|
||||
},
|
||||
"space-create": {
|
||||
@@ -36,7 +36,7 @@
|
||||
},
|
||||
"theme": "dark",
|
||||
"language": "en",
|
||||
"sourceSha256": "c3a3a4e0cf22bec8f48da581241ac553747a0c3cfe5db34e5c8be9bad4240561",
|
||||
"sourceSha256": "662c04e08745a510fd710d98780c3960471546776bf6dfd66c1529bd892a0826",
|
||||
"imageSha256": "c33a7279165a4cec6fa6fadb6fd08cd967e082a17fe101ef442d27d36ae59b6b"
|
||||
},
|
||||
"room-contour-close": {
|
||||
@@ -47,7 +47,7 @@
|
||||
},
|
||||
"theme": "dark",
|
||||
"language": "en",
|
||||
"sourceSha256": "c3a3a4e0cf22bec8f48da581241ac553747a0c3cfe5db34e5c8be9bad4240561",
|
||||
"sourceSha256": "662c04e08745a510fd710d98780c3960471546776bf6dfd66c1529bd892a0826",
|
||||
"imageSha256": "29b57b4e38cc332849bf7198f709b9af4f6f4a3044fb042308d181ffe2ae1eda"
|
||||
},
|
||||
"plan-context-tray": {
|
||||
@@ -58,7 +58,7 @@
|
||||
},
|
||||
"theme": "dark",
|
||||
"language": "en",
|
||||
"sourceSha256": "c3a3a4e0cf22bec8f48da581241ac553747a0c3cfe5db34e5c8be9bad4240561",
|
||||
"sourceSha256": "662c04e08745a510fd710d98780c3960471546776bf6dfd66c1529bd892a0826",
|
||||
"imageSha256": "b0398943d8a7c8215159d2d54b895c28feb1be8e303e65ca106ea5185c34644e"
|
||||
},
|
||||
"device-editor": {
|
||||
@@ -69,7 +69,7 @@
|
||||
},
|
||||
"theme": "dark",
|
||||
"language": "en",
|
||||
"sourceSha256": "c3a3a4e0cf22bec8f48da581241ac553747a0c3cfe5db34e5c8be9bad4240561",
|
||||
"sourceSha256": "662c04e08745a510fd710d98780c3960471546776bf6dfd66c1529bd892a0826",
|
||||
"imageSha256": "c3704489b36fd4177e761124fac032d8d09d6a94e3110f9a77d40ec110c1590b"
|
||||
},
|
||||
"device-display-preview": {
|
||||
@@ -80,7 +80,7 @@
|
||||
},
|
||||
"theme": "dark",
|
||||
"language": "en",
|
||||
"sourceSha256": "c3a3a4e0cf22bec8f48da581241ac553747a0c3cfe5db34e5c8be9bad4240561",
|
||||
"sourceSha256": "662c04e08745a510fd710d98780c3960471546776bf6dfd66c1529bd892a0826",
|
||||
"imageSha256": "7241478b3fae2a5b1895f241bc50a65f1aaacce907d311cc87796a251c389a8b"
|
||||
},
|
||||
"background-editor": {
|
||||
@@ -91,8 +91,8 @@
|
||||
},
|
||||
"theme": "dark",
|
||||
"language": "en",
|
||||
"sourceSha256": "c3a3a4e0cf22bec8f48da581241ac553747a0c3cfe5db34e5c8be9bad4240561",
|
||||
"imageSha256": "4f40aef13801fda2749f9b42e1db56993756e4517d2a06265d40a26743913b78"
|
||||
"sourceSha256": "662c04e08745a510fd710d98780c3960471546776bf6dfd66c1529bd892a0826",
|
||||
"imageSha256": "8241b09b0d821247a86eaadd6043a37dde29623c870d8a142bcd381c638a306d"
|
||||
},
|
||||
"room-card": {
|
||||
"file": "08-room-card.png",
|
||||
@@ -102,7 +102,7 @@
|
||||
},
|
||||
"theme": "dark",
|
||||
"language": "en",
|
||||
"sourceSha256": "c3a3a4e0cf22bec8f48da581241ac553747a0c3cfe5db34e5c8be9bad4240561",
|
||||
"sourceSha256": "662c04e08745a510fd710d98780c3960471546776bf6dfd66c1529bd892a0826",
|
||||
"imageSha256": "029a3e69ec647a8a370d99e6bb7f9225833c526739076022f6b52ba54bff30ea"
|
||||
},
|
||||
"device-info": {
|
||||
@@ -113,7 +113,7 @@
|
||||
},
|
||||
"theme": "dark",
|
||||
"language": "en",
|
||||
"sourceSha256": "c3a3a4e0cf22bec8f48da581241ac553747a0c3cfe5db34e5c8be9bad4240561",
|
||||
"sourceSha256": "662c04e08745a510fd710d98780c3960471546776bf6dfd66c1529bd892a0826",
|
||||
"imageSha256": "8e65ff2191ad1f1172848418c8381967ecff2cc831653a8f9c3ae11352a0e84b"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8600,7 +8600,7 @@ class HouseplanCard extends LitElement {
|
||||
else changedWalls.push(wall);
|
||||
}
|
||||
if (wallRecordCarrierViolations(
|
||||
changedWalls, wallCarriers, this._wallKeyPitch, NORM_W,
|
||||
changedWalls, wallCarriers, this._wallKeyPitch, NORM_W, s.walls || [],
|
||||
).length) return { ok: false, reason: 'wall-metadata' };
|
||||
if (!this._rszSpaceCandidateRenderable(this._space, sp)) {
|
||||
return { ok: false, reason: 'physical-geometry' };
|
||||
|
||||
+16
-2
@@ -777,6 +777,7 @@ export function wallRecordCarrierViolations(
|
||||
carriers: [number[], number[]][],
|
||||
pitch: number,
|
||||
coordScale = 1,
|
||||
latticeDebt: WallEntry[] | null | undefined = [],
|
||||
): string[] {
|
||||
const scale = coordScale > 0 ? coordScale : 1;
|
||||
const latticePitch = Math.abs(pitch);
|
||||
@@ -787,6 +788,16 @@ export function wallRecordCarrierViolations(
|
||||
const steps = normalised / latticePitch;
|
||||
return Math.abs(steps - Math.round(steps)) < LATTICE_NOISE_STEPS;
|
||||
};
|
||||
// A Resize may need to rewrite a record whose other endpoint was authored
|
||||
// off-grid historically. That coordinate is not newly produced by Resize:
|
||||
// allow it only when the exact same physical endpoint already existed in the
|
||||
// immutable source snapshot. Carrier coverage is still proved below.
|
||||
const oldEndpoints = (latticeDebt || []).flatMap((wall) => {
|
||||
const span = entrySpan(wall, scale);
|
||||
return span ? span.map((point) => [...point]) : [];
|
||||
});
|
||||
const pointIsLatticeSafe = (point: number[]): boolean => point.every((value, axis) =>
|
||||
onLattice(value) || oldEndpoints.some((old) => Math.abs(value - old[axis]) <= eps));
|
||||
|
||||
const violations: string[] = [];
|
||||
const signature = (wall: WallEntry): string => JSON.stringify([
|
||||
@@ -797,7 +808,7 @@ export function wallRecordCarrierViolations(
|
||||
if (!span) continue;
|
||||
const [a, b] = span;
|
||||
if (![a[0], a[1], b[0], b[1]].every(Number.isFinite)
|
||||
|| ![a[0], a[1], b[0], b[1]].every(onLattice)) {
|
||||
|| !pointIsLatticeSafe(a) || !pointIsLatticeSafe(b)) {
|
||||
violations.push(signature(wall));
|
||||
continue;
|
||||
}
|
||||
@@ -838,8 +849,11 @@ export function wallRecordsHaveCarrierCoverage(
|
||||
carriers: [number[], number[]][],
|
||||
pitch: number,
|
||||
coordScale = 1,
|
||||
latticeDebt: WallEntry[] | null | undefined = [],
|
||||
): boolean {
|
||||
return wallRecordCarrierViolations(walls, carriers, pitch, coordScale).length === 0;
|
||||
return wallRecordCarrierViolations(
|
||||
walls, carriers, pitch, coordScale, latticeDebt,
|
||||
).length === 0;
|
||||
}
|
||||
|
||||
/** Upsert or remove a wall entry by endpoints. */
|
||||
|
||||
@@ -676,6 +676,13 @@ test('issue 298 carrier proof covers collinear chains and rejects gaps or off-gr
|
||||
assert.equal(wallRecordsHaveCarrierCoverage(
|
||||
offGrid, [[[0.01, 0], [100, 0]]], pitch, 1000,
|
||||
), false, 'a true off-grid coordinate is not storage noise');
|
||||
assert.equal(wallRecordsHaveCarrierCoverage(
|
||||
offGrid, [[[0.01, 0], [100, 0]]], pitch, 1000, offGrid,
|
||||
), true, 'an identical historical endpoint is debt, not a new Resize coordinate');
|
||||
assert.equal(wallRecordsHaveCarrierCoverage(
|
||||
[{ ...offGrid[0], a: [0.00002, 0] }],
|
||||
[[[0.02, 0], [100, 0]]], pitch, 1000, offGrid,
|
||||
), false, 'Resize may not replace old debt with a different off-grid endpoint');
|
||||
});
|
||||
|
||||
test('issue 253 key collisions never erase different exact or legacy records', () => {
|
||||
|
||||
Reference in New Issue
Block a user