mirror of
https://github.com/Matysh/houseplan-card
synced 2026-09-30 19:58:50 +00:00
File diff suppressed because one or more lines are too long
@@ -263,12 +263,12 @@ export const GOLDEN_SCENARIOS = Object.freeze([
|
||||
{ id: 'junction-patch-resilience-plan-dark', fixture: 'visual',
|
||||
space: 'golden-junction-patch-resilience', junctionPatchResilience: true, mode: 'plan',
|
||||
retainedWedgeProbe: [0.8955, 0.556],
|
||||
absentWallProbes: [[0.420833333, 0.37625], [0.936524285, 0.345833333]],
|
||||
absentWallProbes: [[0.420833333, 0.37625], [0.92, 0.348]],
|
||||
theme: 'dark', viewport: { width: 1180, height: 900 }, ...page },
|
||||
{ id: 'junction-patch-resilience-view-dark', fixture: 'visual',
|
||||
space: 'golden-junction-patch-resilience', junctionPatchResilience: true, mode: 'view',
|
||||
retainedWedgeProbe: [0.8955, 0.556],
|
||||
absentWallProbes: [[0.420833333, 0.37625], [0.936524285, 0.345833333]],
|
||||
absentWallProbes: [[0.420833333, 0.37625], [0.92, 0.348]],
|
||||
theme: 'dark', viewport: { width: 1000, height: 900 }, ...stage },
|
||||
{ id: 'multiwall-junction-bevel-view-dark', fixture: 'visual',
|
||||
space: 'golden-multiwall-junction', mode: 'view',
|
||||
|
||||
@@ -13,6 +13,8 @@ const result = await page.evaluate(async (spaceFixture) => {
|
||||
const root = () => card.shadowRoot || card.renderRoot;
|
||||
const retainedWedgeProbe = [895.5, 556];
|
||||
const finiteRayOutsideProbe = [0.420833333 * 1000, 0.37625 * card._spaceH];
|
||||
const finiteRayDoorApproachProbe = [0.92 * 1000, 0.348 * card._spaceH];
|
||||
const finiteDoorSlotProbe = [0.95 * 1000, 0.345833333 * card._spaceH];
|
||||
const svgContains = (element, point = retainedWedgeProbe) =>
|
||||
!!element?.isPointInFill?.(new DOMPoint(point[0], point[1]));
|
||||
const pathDataContains = (d, point) => {
|
||||
@@ -93,6 +95,7 @@ const result = await page.evaluate(async (spaceFixture) => {
|
||||
out.paperKeepsFootprint = !!canonical?.paperD && !!root().querySelector('.hp-paper');
|
||||
out.planRetainsMeasuredWedge = svgContains(planPath);
|
||||
out.planStopsAtFiniteRayEndpoint = !svgContains(planPath, finiteRayOutsideProbe);
|
||||
out.planStopsAtLateralFiniteRayProbe = !svgContains(planPath, finiteRayDoorApproachProbe);
|
||||
out.paperRetainsMeasuredWedge = [...root().querySelectorAll('.hp-paper')]
|
||||
.some((paper) => svgContains(paper));
|
||||
|
||||
@@ -106,6 +109,9 @@ const result = await page.evaluate(async (spaceFixture) => {
|
||||
out.lightAndSunStopAtFiniteRayEndpoint = !geometryContains(
|
||||
barriers.masonryGeometry, finiteRayOutsideProbe,
|
||||
);
|
||||
out.lightAndSunStopAtLateralFiniteRayProbe = !geometryContains(
|
||||
barriers.masonryGeometry, finiteRayDoorApproachProbe,
|
||||
);
|
||||
const barrierFingerprint = barriers.fingerprint;
|
||||
const cacheBeforeState = card._wallUnionCache;
|
||||
|
||||
@@ -133,6 +139,9 @@ const result = await page.evaluate(async (spaceFixture) => {
|
||||
out.viewStopsAtFiniteRayEndpoint = !svgContains(
|
||||
root().querySelector('[data-hp="wall"]'), finiteRayOutsideProbe,
|
||||
);
|
||||
out.viewStopsAtLateralFiniteRayProbe = !svgContains(
|
||||
root().querySelector('[data-hp="wall"]'), finiteRayDoorApproachProbe,
|
||||
);
|
||||
card._hoverRoom = { space: spaceFixture.id, room: model.rooms[0] };
|
||||
const hoverFloor = card._roomHoverPaths(model);
|
||||
out.cleanFloorConsumerStaysNonEmpty = !!hoverFloor?.fillD && !!hoverFloor.outlineD;
|
||||
@@ -148,6 +157,11 @@ const result = await page.evaluate(async (spaceFixture) => {
|
||||
if (!floor?.fillD) return false;
|
||||
return pathDataContains(floor.fillD, finiteRayOutsideProbe);
|
||||
});
|
||||
out.cleanFloorOwnsFiniteDoorApproach = model.rooms.some((room) => {
|
||||
card._hoverRoom = { space: spaceFixture.id, room };
|
||||
const floor = card._roomHoverPaths(model);
|
||||
return !!floor?.fillD && pathDataContains(floor.fillD, finiteRayDoorApproachProbe);
|
||||
});
|
||||
card._hoverRoom = null;
|
||||
|
||||
const kioskBefore = card._config.kiosk;
|
||||
@@ -158,6 +172,9 @@ const result = await page.evaluate(async (spaceFixture) => {
|
||||
out.kioskStopsAtFiniteRayEndpoint = !svgContains(
|
||||
root().querySelector('[data-hp="wall"]'), finiteRayOutsideProbe,
|
||||
);
|
||||
out.kioskStopsAtLateralFiniteRayProbe = !svgContains(
|
||||
root().querySelector('[data-hp="wall"]'), finiteRayDoorApproachProbe,
|
||||
);
|
||||
card._config.kiosk = kioskBefore;
|
||||
await update(false);
|
||||
|
||||
@@ -187,6 +204,9 @@ const result = await page.evaluate(async (spaceFixture) => {
|
||||
out.staticStopsAtFiniteRayEndpoint = !svgContains(
|
||||
staticCard.renderRoot?.querySelector('[data-hp="wall"]'), finiteRayOutsideProbe,
|
||||
);
|
||||
out.staticStopsAtLateralFiniteRayProbe = !svgContains(
|
||||
staticCard.renderRoot?.querySelector('[data-hp="wall"]'), finiteRayDoorApproachProbe,
|
||||
);
|
||||
staticCard.remove();
|
||||
|
||||
const labs = Object.freeze(['iso']);
|
||||
@@ -201,8 +221,44 @@ const result = await page.evaluate(async (spaceFixture) => {
|
||||
out.hiddenIsoStopsAtFiniteRayEndpoint = !geometryContains(
|
||||
isoWalls, finiteRayOutsideProbe,
|
||||
);
|
||||
|
||||
out.hiddenIsoStopsAtLateralFiniteRayProbe = !geometryContains(
|
||||
isoWalls, finiteRayDoorApproachProbe,
|
||||
);
|
||||
out.renderNeverWritesConfig = JSON.stringify(card._serverCfg.spaces[0]) === sourceBefore;
|
||||
|
||||
// AC4: add an actual door only after the all-surface structural parity pass,
|
||||
// so the static-card comparison above remains about one identical model.
|
||||
// The door begins after the lateral phantom probe: final masonry must cut
|
||||
// its slot, while the light barrier must still be empty before that slot.
|
||||
const openingCfg = structuredClone(cfg);
|
||||
openingCfg.spaces[0].openings = [{
|
||||
id: 'finite-door', type: 'door', x: 0.95, y: 0.345833333,
|
||||
angle: 0, length: 0.025,
|
||||
}];
|
||||
card._serverCfg = openingCfg;
|
||||
card._setProjection('flat');
|
||||
card._setMode('plan');
|
||||
await update(true);
|
||||
const openingSource = JSON.stringify(card._serverCfg.spaces[0]);
|
||||
const openingPlanPath = root().querySelector('[data-hp="wall"]');
|
||||
out.nearDoorPlanStopsAtFiniteRay = !svgContains(
|
||||
openingPlanPath, finiteRayDoorApproachProbe,
|
||||
);
|
||||
out.nearDoorPlanKeepsSlotEmpty = !svgContains(openingPlanPath, finiteDoorSlotProbe);
|
||||
out.nearDoorPlanKeepsSymbol = !!root().querySelector('.opening[data-id="finite-door"]');
|
||||
const openingModel = card._spaceModel();
|
||||
const openingPolys = openingModel.rooms.map((room) => ({ r: room, poly: room.poly }));
|
||||
const openingBarriers = card._lightBarriers(openingModel, openingPolys);
|
||||
out.nearDoorLightStopsAtFiniteRay = !geometryContains(
|
||||
openingBarriers.masonryGeometry, finiteRayDoorApproachProbe,
|
||||
);
|
||||
card._setMode('view');
|
||||
await update(false);
|
||||
out.nearDoorViewKeepsSlotEmpty = !svgContains(
|
||||
root().querySelector('[data-hp="wall"]'), finiteDoorSlotProbe,
|
||||
);
|
||||
out.nearDoorViewKeepsSymbol = !!root().querySelector('.opening[data-id="finite-door"]');
|
||||
out.nearDoorRenderNeverWritesConfig = JSON.stringify(card._serverCfg.spaces[0]) === openingSource;
|
||||
return out;
|
||||
}, fixture);
|
||||
|
||||
|
||||
Vendored
+89
-89
File diff suppressed because one or more lines are too long
@@ -374,7 +374,7 @@ test('issue #197 golden keeps the complete junction fixture in Plan and View', (
|
||||
assert.deepEqual(scenario.retainedWedgeProbe, [0.8955, 0.556]);
|
||||
assert.deepEqual(
|
||||
scenario.absentWallProbes,
|
||||
[[0.420833333, 0.37625], [0.936524285, 0.345833333]],
|
||||
[[0.420833333, 0.37625], [0.92, 0.348]],
|
||||
);
|
||||
const fixture = prepareGoldenFixture(scenario);
|
||||
const space = fixture.config.spaces.find((item) => item.id === scenario.space);
|
||||
|
||||
@@ -914,6 +914,50 @@ test('issue #271 keeps finite co-directional ray supports and never rebuilds pas
|
||||
);
|
||||
});
|
||||
|
||||
test('issue #271 keeps a nearby door slot and its light-side approach free of a phantom ray', () => {
|
||||
const fixture = JSON.parse(readFileSync(
|
||||
new URL('./fixtures/197-junction-patch.json', import.meta.url), 'utf8',
|
||||
));
|
||||
const rooms = fixture.rooms.map((room) => ({
|
||||
...room,
|
||||
poly: room.poly.map(([x, y]) => [x * NORM_W, y * NORM_W]),
|
||||
}));
|
||||
const cuts = resolveOpenCuts(
|
||||
rooms, fixture.open_spans, NORM_W, GRID_PITCH * 0.02,
|
||||
);
|
||||
const opening = {
|
||||
x: 950, y: 345.8333333333333, angle: 0, length: 25,
|
||||
};
|
||||
const geometry = wallBodiesGeometry(
|
||||
rooms, fixture.walls, cuts, [opening], pitch,
|
||||
fixture.cell_cm, GRID_PITCH, NORM_W,
|
||||
);
|
||||
assert.ok(geometry);
|
||||
assertProbeInside(
|
||||
geometry.roomGeom, [950, 345.8333333333333],
|
||||
'fixture no longer puts the door on physical masonry before the cut',
|
||||
);
|
||||
assertProbeOutside(
|
||||
geometry.geom, [950, 345.8333333333333],
|
||||
'the final door slot is not empty through the complete masonry',
|
||||
);
|
||||
assertProbeOutside(
|
||||
geometry.roomGeom, [920, 348],
|
||||
'the short 15 cm ray still paints a lateral phantom before the nearby door',
|
||||
);
|
||||
assertProbeOutside(
|
||||
geometry.geom, [920, 348],
|
||||
'opening subtraction or final union revived the lateral phantom',
|
||||
);
|
||||
assert.ok(
|
||||
openingTunnelGeometry(
|
||||
rooms, opening, fixture.walls, cuts, pitch,
|
||||
fixture.cell_cm, GRID_PITCH, NORM_W,
|
||||
),
|
||||
'the associated opening tunnel contract disappeared',
|
||||
);
|
||||
});
|
||||
|
||||
test('issue #249 node classification is order, direction and scale independent', () => {
|
||||
const cases = [
|
||||
{ angles: [0, 30, 200], halves: [5, 5, 5], bevel: true },
|
||||
|
||||
Reference in New Issue
Block a user