mirror of
https://github.com/Matysh/houseplan-card
synced 2026-10-06 06:38:57 +00:00
+34
-14
@@ -7347,6 +7347,25 @@ class HouseplanCard extends LitElement {
|
||||
return this._t(`wall_model.reason.${reason}`);
|
||||
}
|
||||
|
||||
/** A legacy virtual-wall projection is still present only until its first
|
||||
* structural v9 write. Keep its atomic-failure copy distinct from generic
|
||||
* wall-model validation without persisting provenance on the new atoms. */
|
||||
private _hasLegacyZeroWallFields(config: any = this._serverCfg): boolean {
|
||||
return (config?.spaces || []).some((space: any) => (
|
||||
(Array.isArray(space?.open_spans) && space.open_spans.length > 0)
|
||||
|| (space?.rooms || []).some((room: any) => (
|
||||
Array.isArray(room?.open_to) && room.open_to.length > 0
|
||||
))
|
||||
));
|
||||
}
|
||||
|
||||
private _showWallModelMigrationBlocked(error: unknown): void {
|
||||
const key = this._hasLegacyZeroWallFields()
|
||||
? 'toast.zero_wall_migration_blocked'
|
||||
: 'toast.wall_model_migration_blocked';
|
||||
this._showToast(this._t(key, { reason: this._wallModelBlockerLabel(error) }));
|
||||
}
|
||||
|
||||
private _commitPhysicalGeometry(
|
||||
name: string,
|
||||
before: SpaceGeometryState | null,
|
||||
@@ -7417,9 +7436,7 @@ class HouseplanCard extends LitElement {
|
||||
} catch (error) {
|
||||
this._clearGeometryGesture();
|
||||
this._restoreGeometryStateLocal(before);
|
||||
this._showToast(this._t('toast.wall_model_migration_blocked', {
|
||||
reason: this._wallModelBlockerLabel(error),
|
||||
}));
|
||||
this._showWallModelMigrationBlocked(error);
|
||||
return false;
|
||||
}
|
||||
let safe = false;
|
||||
@@ -7551,9 +7568,7 @@ class HouseplanCard extends LitElement {
|
||||
committedCandidate = commitWallSegmentModel(restoredCandidate).config;
|
||||
} catch (error) {
|
||||
this._restoreGeometryStateLocal(before);
|
||||
this._showToast(this._t('toast.wall_model_migration_blocked', {
|
||||
reason: this._wallModelBlockerLabel(error),
|
||||
}));
|
||||
this._showWallModelMigrationBlocked(error);
|
||||
return false;
|
||||
}
|
||||
if (physicalChanged) {
|
||||
@@ -8124,7 +8139,9 @@ class HouseplanCard extends LitElement {
|
||||
});
|
||||
if (repair.kind === 'ambiguous') {
|
||||
this._wallRepairDiagnostic = repair.proposals[0] || null;
|
||||
this._showToast(this._t('toast.wall_repair_ambiguous'));
|
||||
this._showToast(this._t(
|
||||
this._drawWallCm === 0 ? 'toast.zero_wall_ambiguous' : 'toast.wall_repair_ambiguous',
|
||||
));
|
||||
return;
|
||||
}
|
||||
if (repair.kind === 'repair' && !this._overlapRoom(repair.face.ring)) {
|
||||
@@ -8200,7 +8217,9 @@ class HouseplanCard extends LitElement {
|
||||
});
|
||||
if (result.kind === 'ambiguous') {
|
||||
this._wallRepairDiagnostic = result.proposals[0] || null;
|
||||
this._showToast(this._t('toast.wall_repair_ambiguous'));
|
||||
this._showToast(this._t(
|
||||
this._drawWallCm === 0 ? 'toast.zero_wall_ambiguous' : 'toast.wall_repair_ambiguous',
|
||||
));
|
||||
return true;
|
||||
}
|
||||
if (result.kind === 'repair') {
|
||||
@@ -8327,7 +8346,7 @@ class HouseplanCard extends LitElement {
|
||||
if (p && cmRaw === 0 && zeroWallHasOpening(sp.openings, {
|
||||
kind: 'partition', id: d.id,
|
||||
})) {
|
||||
this._showToast(this._t('toast.zero_wall_opening'));
|
||||
this._showToast(this._t('toast.zero_wall_opening_conflict'));
|
||||
return;
|
||||
}
|
||||
if (p) p.cm = cmRaw;
|
||||
@@ -11699,7 +11718,7 @@ class HouseplanCard extends LitElement {
|
||||
if (cmRaw === 0 && zeroWallHasOpening(sp.openings, {
|
||||
kind: 'partition', id: partition.id,
|
||||
})) {
|
||||
this._showToast(this._t('toast.zero_wall_opening'));
|
||||
this._showToast(this._t('toast.zero_wall_opening_conflict'));
|
||||
return;
|
||||
}
|
||||
partition.cm = cmRaw;
|
||||
@@ -11739,7 +11758,7 @@ class HouseplanCard extends LitElement {
|
||||
return point.every(Number.isFinite) && distToSegment(point, target) <= eps;
|
||||
});
|
||||
if (blocked) {
|
||||
this._showToast(this._t('toast.zero_wall_opening'));
|
||||
this._showToast(this._t('toast.zero_wall_opening_conflict'));
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -15657,9 +15676,7 @@ class HouseplanCard extends LitElement {
|
||||
this._optimizeReferenceContext(removeLiveMissingPositions),
|
||||
);
|
||||
} catch (error) {
|
||||
this._showToast(this._t('toast.wall_model_migration_blocked', {
|
||||
reason: this._wallModelBlockerLabel(error),
|
||||
}));
|
||||
this._showWallModelMigrationBlocked(error);
|
||||
return;
|
||||
}
|
||||
const preflight = r.changed ? this._checkOptimizeGeometry(r.config) : null;
|
||||
@@ -16917,6 +16934,9 @@ class HouseplanCard extends LitElement {
|
||||
${r.wallSegmentsMigrated ? html`<p class="alignmsg">${this._t(
|
||||
'gs.wall_segments_migrated', { n: String(r.wallSegmentsMigrated) },
|
||||
)}</p>` : nothing}
|
||||
${r.legacyZeroWallsMigrated ? html`<p class="alignmsg">${this._t(
|
||||
'gs.zero_walls_migrated', { n: String(r.legacyZeroWallsMigrated) },
|
||||
)}</p>` : nothing}
|
||||
${modelMaintenance ? html`<p class="alignmsg">${this._t('gs.optimize_changes', {
|
||||
m: String(r.migrated), c: String(r.canonicalized),
|
||||
p: String(r.coordsCanonicalized), w: String(r.wallsMerged),
|
||||
|
||||
+5
-2
@@ -534,7 +534,9 @@
|
||||
"toast.wallthick_set": "Wall thickness set",
|
||||
"toast.wallthick_cleared": "Wall thickness removed",
|
||||
"toast.physical_range": "Enter a value from {min} to {max} {unit}",
|
||||
"toast.zero_wall_opening": "Remove the opening on this wall stretch first",
|
||||
"toast.zero_wall_opening_conflict": "Remove the opening on this wall segment first.",
|
||||
"toast.zero_wall_ambiguous": "The wall segment is ambiguous. Simplify or adjust the junction.",
|
||||
"toast.zero_wall_migration_blocked": "The space was not converted: {reason}. No data was changed.",
|
||||
"toast.physical_angle": "Enter a rotation angle from 0° up to, but not including, 90°",
|
||||
"toast.physical_limit": "The space has reached the limit for this type of geometry",
|
||||
"toast.geometry_unsafe": "Change canceled: wall geometry could not be built safely.",
|
||||
@@ -815,7 +817,8 @@
|
||||
"gs.preflight_update_hint": "The card and integration versions differ — update House Plan and retry.",
|
||||
"gs.align_preflight_space": "Space {n}",
|
||||
"gs.align_preflight_more": ", and {n} more",
|
||||
"gs.optimize_changes": "Model migrations: {m}; spaces updated: {c}; noisy coordinate values removed: {p}; merged real-wall fragments: {w}; virtual fragments: {s}; independent walls: {i}.",
|
||||
"gs.optimize_changes": "Model migrations: {m}; spaces updated: {c}; noisy coordinate values removed: {p}; merged real-wall fragments: {w}; merged zero-thickness wall fragments: {s}; independent walls: {i}.",
|
||||
"gs.zero_walls_migrated": "Virtual wall spans converted: {n}.",
|
||||
"gs.wall_segments_migrated": "Wall segments stabilised: {n}.",
|
||||
"gs.optimize_lattice_summary": "Noisy coordinate values canonicalized: {n}; maximum movement: {cm} cm.",
|
||||
"gs.optimize_lattice_space": "{space}: coordinate values canonicalized: {n}; off-grid values left unchanged: {far}.",
|
||||
|
||||
+5
-2
@@ -534,7 +534,9 @@
|
||||
"toast.wallthick_set": "Толщина стены задана",
|
||||
"toast.wallthick_cleared": "Толщина стены убрана",
|
||||
"toast.physical_range": "Введите значение от {min} до {max} {unit}",
|
||||
"toast.zero_wall_opening": "Сначала удалите проём на этом участке стены",
|
||||
"toast.zero_wall_opening_conflict": "Сначала удалите проём на этом участке стены.",
|
||||
"toast.zero_wall_ambiguous": "Не удалось однозначно выбрать участок стены. Уточните геометрию узла.",
|
||||
"toast.zero_wall_migration_blocked": "Пространство не преобразовано: {reason}. Данные не изменены.",
|
||||
"toast.physical_angle": "Введите угол поворота от 0° до 90°, не включая 90°",
|
||||
"toast.physical_limit": "В пространстве достигнут лимит объектов этого типа",
|
||||
"toast.geometry_unsafe": "Изменение отменено: геометрию стен нельзя безопасно построить.",
|
||||
@@ -815,7 +817,8 @@
|
||||
"gs.preflight_update_hint": "Версии карточки и интеграции различаются — обновите House Plan и повторите.",
|
||||
"gs.align_preflight_space": "Пространство {n}",
|
||||
"gs.align_preflight_more": " и ещё {n}",
|
||||
"gs.optimize_changes": "Миграций модели: {m}; обновлено пространств: {c}; устранён шум координат: {p}; объединено отрезков реальных стен: {w}; виртуальных: {s}; независимых: {i}.",
|
||||
"gs.optimize_changes": "Миграций модели: {m}; обновлено пространств: {c}; устранён шум координат: {p}; объединено отрезков реальных стен: {w}; объединено отрезков стен нулевой толщины: {s}; независимых: {i}.",
|
||||
"gs.zero_walls_migrated": "Преобразовано виртуальных участков: {n}.",
|
||||
"gs.wall_segments_migrated": "Стабилизировано сегментов стен: {n}.",
|
||||
"gs.optimize_lattice_summary": "Канонизировано шумовых значений координат: {n}; максимальный сдвиг: {cm} см.",
|
||||
"gs.optimize_lattice_space": "{space}: канонизировано значений координат: {n}; оставлено значений вне сетки: {far}.",
|
||||
|
||||
@@ -57,9 +57,11 @@ export interface OptimizeReport extends AlignReport, SpaceReferenceReport {
|
||||
canonicalized: number;
|
||||
/** Contour-wall atoms materialised into the stable v8 catalogue. */
|
||||
wallSegmentsMigrated: number;
|
||||
/** Read-compatible legacy virtual spans converted into zero-wall atoms. */
|
||||
legacyZeroWallsMigrated: number;
|
||||
/** Redundant equal-thickness wall entries removed by canonicalisation. */
|
||||
wallsMerged: number;
|
||||
/** Touching/overlapping virtual pieces merged on the same room pair. */
|
||||
/** Touching/overlapping zero-wall atoms merged on the same room pair. */
|
||||
spansMerged: number;
|
||||
/** Collinear independent-wall records collapsed into one (#229). */
|
||||
partitionsMerged: number;
|
||||
@@ -480,6 +482,7 @@ export function optimizePlans(
|
||||
} : { ...aligned.report };
|
||||
|
||||
let wallsMerged = 0;
|
||||
let legacyZeroWallsMigrated = 0;
|
||||
let spansMerged = 0;
|
||||
let partitionsMerged = 0;
|
||||
let partitionsReconciled = 0;
|
||||
@@ -513,7 +516,9 @@ export function optimizePlans(
|
||||
// the final identity barrier assign stable catalogue IDs. No production
|
||||
// maintenance pass writes open_spans/open_to back into the candidate.
|
||||
const knownZeroKeys = new Set(sourceZeroWalls.map((wall) => wall.key));
|
||||
for (const line of legacyZeroContourLines(before, oldModel.rooms, NORM_W, eps)) {
|
||||
const legacyZeroLines = legacyZeroContourLines(before, oldModel.rooms, NORM_W, eps);
|
||||
legacyZeroWallsMigrated += legacyZeroLines.length;
|
||||
for (const line of legacyZeroLines) {
|
||||
const a = [line[0] / NORM_W, line[1] / NORM_W];
|
||||
const b = [line[2] / NORM_W, line[3] / NORM_W];
|
||||
const key = wallKey(a, b, GRID_STEP_N);
|
||||
@@ -693,6 +698,7 @@ export function optimizePlans(
|
||||
glowRoomsMigrated: changed ? migration.glowRooms : 0,
|
||||
canonicalized: changed ? canonicalized : 0,
|
||||
wallSegmentsMigrated: changed ? wallSegmentsMigrated : 0,
|
||||
legacyZeroWallsMigrated: changed ? legacyZeroWallsMigrated : 0,
|
||||
wallsMerged: changed ? wallsMerged : 0,
|
||||
spansMerged: changed ? spansMerged : 0,
|
||||
partitionsMerged: changed ? partitionsMerged : 0,
|
||||
|
||||
Reference in New Issue
Block a user