@kerros/editor 0.0.0-stage → 0.1.0-rc.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +35 -2
- package/dist/SitePlanner.js +1189 -0
- package/dist/SitePlanner.js.map +1 -0
- package/dist/adapters/basemap.js +11 -0
- package/dist/adapters/basemap.js.map +1 -0
- package/dist/adapters/persistence.js +121 -0
- package/dist/adapters/persistence.js.map +1 -0
- package/dist/adapters/status.js +11 -0
- package/dist/adapters/status.js.map +1 -0
- package/dist/adapters/useProjectPersistence.js +56 -0
- package/dist/adapters/useProjectPersistence.js.map +1 -0
- package/dist/components/AiImportPanel.js +635 -0
- package/dist/components/AiImportPanel.js.map +1 -0
- package/dist/components/AnalysisPreview.js +179 -0
- package/dist/components/AnalysisPreview.js.map +1 -0
- package/dist/components/ElevatorPanel.js +120 -0
- package/dist/components/ElevatorPanel.js.map +1 -0
- package/dist/components/Icons.js +57 -0
- package/dist/components/Icons.js.map +1 -0
- package/dist/components/ImportDialog.js +467 -0
- package/dist/components/ImportDialog.js.map +1 -0
- package/dist/components/Inspector.js +1184 -0
- package/dist/components/Inspector.js.map +1 -0
- package/dist/components/NavigatePanel.js +301 -0
- package/dist/components/NavigatePanel.js.map +1 -0
- package/dist/components/NavigationGraph.js +234 -0
- package/dist/components/NavigationGraph.js.map +1 -0
- package/dist/components/StructureExplorer.js +510 -0
- package/dist/components/StructureExplorer.js.map +1 -0
- package/dist/components/StructureView.js +286 -0
- package/dist/components/StructureView.js.map +1 -0
- package/dist/components/controls.js +209 -0
- package/dist/components/controls.js.map +1 -0
- package/dist/components/graphLayout.js +27 -0
- package/dist/components/graphLayout.js.map +1 -0
- package/dist/host.js +175 -0
- package/dist/host.js.map +1 -0
- package/dist/i18n.js +88 -0
- package/dist/i18n.js.map +1 -0
- package/dist/import/analysisPreview.js +41 -0
- package/dist/import/analysisPreview.js.map +1 -0
- package/dist/import/brief.js +29 -0
- package/dist/import/brief.js.map +1 -0
- package/dist/import/checkpoint.js +50 -0
- package/dist/import/checkpoint.js.map +1 -0
- package/dist/import/detect.js +120 -0
- package/dist/import/detect.js.map +1 -0
- package/dist/import/documentSvg.js +49 -0
- package/dist/import/documentSvg.js.map +1 -0
- package/dist/import/instructions.js +20 -0
- package/dist/import/instructions.js.map +1 -0
- package/dist/import/openings.js +61 -0
- package/dist/import/openings.js.map +1 -0
- package/dist/import/planImport.js +233 -0
- package/dist/import/planImport.js.map +1 -0
- package/dist/import/register.js +47 -0
- package/dist/import/register.js.map +1 -0
- package/dist/import/runs.js +67 -0
- package/dist/import/runs.js.map +1 -0
- package/dist/import/session.js +23 -0
- package/dist/import/session.js.map +1 -0
- package/dist/import/types.js +13 -0
- package/dist/import/types.js.map +1 -0
- package/dist/import/usage.js +29 -0
- package/dist/import/usage.js.map +1 -0
- package/dist/import/walls.js +112 -0
- package/dist/import/walls.js.map +1 -0
- package/dist/index.js +178 -0
- package/dist/index.js.map +1 -0
- package/dist/map/CabinMaterials.js +81 -0
- package/dist/map/CabinMaterials.js.map +1 -0
- package/dist/map/CabinMirror.js +43 -0
- package/dist/map/CabinMirror.js.map +1 -0
- package/dist/map/Doors.js +80 -0
- package/dist/map/Doors.js.map +1 -0
- package/dist/map/ElevatorCabin.js +93 -0
- package/dist/map/ElevatorCabin.js.map +1 -0
- package/dist/map/FixtureLights.js +117 -0
- package/dist/map/FixtureLights.js.map +1 -0
- package/dist/map/MapCanvas.js +2161 -0
- package/dist/map/MapCanvas.js.map +1 -0
- package/dist/map/Passenger.js +69 -0
- package/dist/map/Passenger.js.map +1 -0
- package/dist/map/SceneLayer.js +1534 -0
- package/dist/map/SceneLayer.js.map +1 -0
- package/dist/map/UndergroundContext.js +153 -0
- package/dist/map/UndergroundContext.js.map +1 -0
- package/dist/map/ambience.js +194 -0
- package/dist/map/ambience.js.map +1 -0
- package/dist/map/architecture.js +305 -0
- package/dist/map/architecture.js.map +1 -0
- package/dist/map/bathMusic.js +92 -0
- package/dist/map/bathMusic.js.map +1 -0
- package/dist/map/cameraAim.js +33 -0
- package/dist/map/cameraAim.js.map +1 -0
- package/dist/map/elevators.js +56 -0
- package/dist/map/elevators.js.map +1 -0
- package/dist/map/excavation.js +52 -0
- package/dist/map/excavation.js.map +1 -0
- package/dist/map/exteriors.js +25 -0
- package/dist/map/exteriors.js.map +1 -0
- package/dist/map/features.js +218 -0
- package/dist/map/features.js.map +1 -0
- package/dist/map/fences.js +29 -0
- package/dist/map/fences.js.map +1 -0
- package/dist/map/journey.js +112 -0
- package/dist/map/journey.js.map +1 -0
- package/dist/map/levels.js +6 -0
- package/dist/map/levels.js.map +1 -0
- package/dist/map/lighting.js +143 -0
- package/dist/map/lighting.js.map +1 -0
- package/dist/map/loadBasemap.js +26 -0
- package/dist/map/loadBasemap.js.map +1 -0
- package/dist/map/materials.js +183 -0
- package/dist/map/materials.js.map +1 -0
- package/dist/map/poolLighting.js +39 -0
- package/dist/map/poolLighting.js.map +1 -0
- package/dist/map/projection.js +24 -0
- package/dist/map/projection.js.map +1 -0
- package/dist/map/rampGeometry.js +38 -0
- package/dist/map/rampGeometry.js.map +1 -0
- package/dist/map/route.js +107 -0
- package/dist/map/route.js.map +1 -0
- package/dist/map/stairSurfaces.js +115 -0
- package/dist/map/stairSurfaces.js.map +1 -0
- package/dist/map/surfaces.js +136 -0
- package/dist/map/surfaces.js.map +1 -0
- package/dist/map/textures.js +95 -0
- package/dist/map/textures.js.map +1 -0
- package/dist/map/underground.js +34 -0
- package/dist/map/underground.js.map +1 -0
- package/dist/map/walk.js +433 -0
- package/dist/map/walk.js.map +1 -0
- package/dist/map/walkContext.js +46 -0
- package/dist/map/walkContext.js.map +1 -0
- package/dist/map/walkDimensions.js +7 -0
- package/dist/map/walkDimensions.js.map +1 -0
- package/dist/map/walkJourney.js +85 -0
- package/dist/map/walkJourney.js.map +1 -0
- package/dist/map/walkSurfaces.js +106 -0
- package/dist/map/walkSurfaces.js.map +1 -0
- package/dist/map/wallJoins.js +70 -0
- package/dist/map/wallJoins.js.map +1 -0
- package/dist/map/water.js +274 -0
- package/dist/map/water.js.map +1 -0
- package/dist/model/authoring.js +99 -0
- package/dist/model/authoring.js.map +1 -0
- package/dist/model/boundaries.js +548 -0
- package/dist/model/boundaries.js.map +1 -0
- package/dist/model/coverage.js +30 -0
- package/dist/model/coverage.js.map +1 -0
- package/dist/model/document.js +52 -0
- package/dist/model/document.js.map +1 -0
- package/dist/model/doors.js +47 -0
- package/dist/model/doors.js.map +1 -0
- package/dist/model/factory.js +56 -0
- package/dist/model/factory.js.map +1 -0
- package/dist/model/geometry.js +454 -0
- package/dist/model/geometry.js.map +1 -0
- package/dist/model/history.js +29 -0
- package/dist/model/history.js.map +1 -0
- package/dist/model/imports.js +45 -0
- package/dist/model/imports.js.map +1 -0
- package/dist/model/inference.js +182 -0
- package/dist/model/inference.js.map +1 -0
- package/dist/model/materials.js +11 -0
- package/dist/model/materials.js.map +1 -0
- package/dist/model/mutations.js +157 -0
- package/dist/model/mutations.js.map +1 -0
- package/dist/model/navigation.js +275 -0
- package/dist/model/navigation.js.map +1 -0
- package/dist/model/ontology.js +109 -0
- package/dist/model/ontology.js.map +1 -0
- package/dist/model/passages.js +5 -0
- package/dist/model/passages.js.map +1 -0
- package/dist/model/portals.js +42 -0
- package/dist/model/portals.js.map +1 -0
- package/dist/model/precision.js +11 -0
- package/dist/model/precision.js.map +1 -0
- package/dist/model/project.js +31 -0
- package/dist/model/project.js.map +1 -0
- package/dist/model/ramps.js +10 -0
- package/dist/model/ramps.js.map +1 -0
- package/dist/model/roomNavigation.js +87 -0
- package/dist/model/roomNavigation.js.map +1 -0
- package/dist/model/routeClearance.js +72 -0
- package/dist/model/routeClearance.js.map +1 -0
- package/dist/model/spaces.js +104 -0
- package/dist/model/spaces.js.map +1 -0
- package/dist/model/stairGeometry.js +40 -0
- package/dist/model/stairGeometry.js.map +1 -0
- package/dist/model/stairTraversal.js +48 -0
- package/dist/model/stairTraversal.js.map +1 -0
- package/dist/model/topology.js +63 -0
- package/dist/model/topology.js.map +1 -0
- package/dist/model/types.js +35 -0
- package/dist/model/types.js.map +1 -0
- package/dist/model/validate.js +240 -0
- package/dist/model/validate.js.map +1 -0
- package/dist/model/vertical.js +129 -0
- package/dist/model/vertical.js.map +1 -0
- package/dist/model/walls.js +261 -0
- package/dist/model/walls.js.map +1 -0
- package/dist/planner/DrawingDock.js +231 -0
- package/dist/planner/DrawingDock.js.map +1 -0
- package/dist/planner/FloorControls.js +93 -0
- package/dist/planner/FloorControls.js.map +1 -0
- package/dist/planner/MapSettings.js +143 -0
- package/dist/planner/MapSettings.js.map +1 -0
- package/dist/planner/PlannerHelp.js +57 -0
- package/dist/planner/PlannerHelp.js.map +1 -0
- package/dist/planner/ProjectSidebar.js +246 -0
- package/dist/planner/ProjectSidebar.js.map +1 -0
- package/dist/planner/floors.js +18 -0
- package/dist/planner/floors.js.map +1 -0
- package/dist/planner/useDrawingTools.js +341 -0
- package/dist/planner/useDrawingTools.js.map +1 -0
- package/dist/planner/useMapDisplay.js +51 -0
- package/dist/planner/useMapDisplay.js.map +1 -0
- package/dist/planner/usePlannerKeyboard.js +138 -0
- package/dist/planner/usePlannerKeyboard.js.map +1 -0
- package/dist/planner/useReferenceAlignment.js +50 -0
- package/dist/planner/useReferenceAlignment.js.map +1 -0
- package/dist/styles.css +4931 -0
- package/dist/theme/index.js +34 -0
- package/dist/theme/index.js.map +1 -0
- package/dist/types/SitePlanner.d.ts +5 -0
- package/dist/types/adapters/basemap.d.ts +2 -0
- package/dist/types/adapters/persistence.d.ts +29 -0
- package/dist/types/adapters/status.d.ts +4 -0
- package/dist/types/adapters/useProjectPersistence.d.ts +13 -0
- package/dist/types/components/AiImportPanel.d.ts +9 -0
- package/dist/types/components/AnalysisPreview.d.ts +4 -0
- package/dist/types/components/ElevatorPanel.d.ts +18 -0
- package/dist/types/components/Icons.d.ts +8 -0
- package/dist/types/components/ImportDialog.d.ts +42 -0
- package/dist/types/components/Inspector.d.ts +38 -0
- package/dist/types/components/NavigatePanel.d.ts +27 -0
- package/dist/types/components/NavigationGraph.d.ts +10 -0
- package/dist/types/components/StructureExplorer.d.ts +8 -0
- package/dist/types/components/StructureView.d.ts +22 -0
- package/dist/types/components/controls.d.ts +52 -0
- package/dist/types/components/graphLayout.d.ts +9 -0
- package/dist/types/editor/host.d.ts +9 -0
- package/dist/types/editor/index.d.ts +2 -0
- package/dist/types/i18n.d.ts +85 -0
- package/dist/types/import/analysisPreview.d.ts +27 -0
- package/dist/types/import/brief.d.ts +22 -0
- package/dist/types/import/checkpoint.d.ts +49 -0
- package/dist/types/import/detect.d.ts +34 -0
- package/dist/types/import/documentSvg.d.ts +2 -0
- package/dist/types/import/index.d.ts +10 -0
- package/dist/types/import/instructions.d.ts +7 -0
- package/dist/types/import/openings.d.ts +22 -0
- package/dist/types/import/planImport.d.ts +22 -0
- package/dist/types/import/register.d.ts +25 -0
- package/dist/types/import/runs.d.ts +31 -0
- package/dist/types/import/session.d.ts +33 -0
- package/dist/types/import/types.d.ts +56 -0
- package/dist/types/import/usage.d.ts +10 -0
- package/dist/types/import/walls.d.ts +37 -0
- package/dist/types/map/CabinMaterials.d.ts +18 -0
- package/dist/types/map/CabinMirror.d.ts +13 -0
- package/dist/types/map/Doors.d.ts +11 -0
- package/dist/types/map/ElevatorCabin.d.ts +20 -0
- package/dist/types/map/FixtureLights.d.ts +35 -0
- package/dist/types/map/MapCanvas.d.ts +87 -0
- package/dist/types/map/Passenger.d.ts +18 -0
- package/dist/types/map/SceneLayer.d.ts +306 -0
- package/dist/types/map/UndergroundContext.d.ts +18 -0
- package/dist/types/map/ambience.d.ts +29 -0
- package/dist/types/map/architecture.d.ts +8 -0
- package/dist/types/map/bathMusic.d.ts +14 -0
- package/dist/types/map/cameraAim.d.ts +20 -0
- package/dist/types/map/elevators.d.ts +16 -0
- package/dist/types/map/excavation.d.ts +9 -0
- package/dist/types/map/exteriors.d.ts +3 -0
- package/dist/types/map/features.d.ts +33 -0
- package/dist/types/map/fences.d.ts +4 -0
- package/dist/types/map/journey.d.ts +36 -0
- package/dist/types/map/levels.d.ts +4 -0
- package/dist/types/map/lighting.d.ts +103 -0
- package/dist/types/map/loadBasemap.d.ts +4 -0
- package/dist/types/map/materials.d.ts +38 -0
- package/dist/types/map/poolLighting.d.ts +11 -0
- package/dist/types/map/projection.d.ts +9 -0
- package/dist/types/map/rampGeometry.d.ts +8 -0
- package/dist/types/map/route.d.ts +59 -0
- package/dist/types/map/stairSurfaces.d.ts +29 -0
- package/dist/types/map/surfaces.d.ts +36 -0
- package/dist/types/map/textures.d.ts +8 -0
- package/dist/types/map/underground.d.ts +30 -0
- package/dist/types/map/walk.d.ts +232 -0
- package/dist/types/map/walkContext.d.ts +11 -0
- package/dist/types/map/walkDimensions.d.ts +5 -0
- package/dist/types/map/walkJourney.d.ts +33 -0
- package/dist/types/map/walkSurfaces.d.ts +27 -0
- package/dist/types/map/wallJoins.d.ts +6 -0
- package/dist/types/map/water.d.ts +12 -0
- package/dist/types/model/authoring.d.ts +38 -0
- package/dist/types/model/boundaries.d.ts +41 -0
- package/dist/types/model/coverage.d.ts +8 -0
- package/dist/types/model/document.d.ts +9 -0
- package/dist/types/model/doors.d.ts +19 -0
- package/dist/types/model/factory.d.ts +5 -0
- package/dist/types/model/geometry.d.ts +99 -0
- package/dist/types/model/history.d.ts +10 -0
- package/dist/types/model/host.d.ts +154 -0
- package/dist/types/model/imports.d.ts +7 -0
- package/dist/types/model/inference.d.ts +46 -0
- package/dist/types/model/live.d.ts +60 -0
- package/dist/types/model/materials.d.ts +28 -0
- package/dist/types/model/mutations.d.ts +178 -0
- package/dist/types/model/navigation.d.ts +70 -0
- package/dist/types/model/ontology.d.ts +43 -0
- package/dist/types/model/passages.d.ts +2 -0
- package/dist/types/model/portals.d.ts +9 -0
- package/dist/types/model/precision.d.ts +11 -0
- package/dist/types/model/project.d.ts +8 -0
- package/dist/types/model/ramps.d.ts +7 -0
- package/dist/types/model/roomNavigation.d.ts +15 -0
- package/dist/types/model/routeClearance.d.ts +11 -0
- package/dist/types/model/spaces.d.ts +46 -0
- package/dist/types/model/stairGeometry.d.ts +27 -0
- package/dist/types/model/stairTraversal.d.ts +8 -0
- package/dist/types/model/topology.d.ts +14 -0
- package/dist/types/model/types.d.ts +369 -0
- package/dist/types/model/validate.d.ts +38 -0
- package/dist/types/model/vertical.d.ts +145 -0
- package/dist/types/model/walls.d.ts +71 -0
- package/dist/types/planner/DrawingDock.d.ts +16 -0
- package/dist/types/planner/FloorControls.d.ts +17 -0
- package/dist/types/planner/MapSettings.d.ts +16 -0
- package/dist/types/planner/PlannerHelp.d.ts +3 -0
- package/dist/types/planner/ProjectSidebar.d.ts +32 -0
- package/dist/types/planner/floors.d.ts +3 -0
- package/dist/types/planner/types.d.ts +3 -0
- package/dist/types/planner/useDrawingTools.d.ts +52 -0
- package/dist/types/planner/useMapDisplay.d.ts +29 -0
- package/dist/types/planner/usePlannerKeyboard.d.ts +18 -0
- package/dist/types/planner/useReferenceAlignment.d.ts +30 -0
- package/dist/types/schema/index.d.ts +25 -0
- package/dist/types/theme/index.d.ts +55 -0
- package/package.json +58 -4
package/dist/host.js
ADDED
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
import { IndexedAssetRepository as r, IndexedProjectRepository as t, LocalProjectRepository as a } from "./adapters/persistence.js";
|
|
2
|
+
import { neutralBasemap as i } from "./adapters/basemap.js";
|
|
3
|
+
import { KerrosThemeProvider as p, useDarkMode as d, useKerrosTheme as c, useStrings as f } from "./theme/index.js";
|
|
4
|
+
import { enclosedRegion as l, enclosedRegions as E, inSpace as g, refitEnclosedRooms as R, spaceAt as u, spacePoint as x, spaces as v } from "./model/spaces.js";
|
|
5
|
+
import { addPortalGroup as S, addZone as y, captive as h, entryInto as O, nestZone as T, perimeter as A, pruneOntology as _, removePortalGroup as L, removeZone as b, setPortalGroupMembers as B, setZoneMembers as I, zoneSpaces as N } from "./model/ontology.js";
|
|
6
|
+
import { divideSpaces as M, inferOpenBoundaries as V, inferPortals as D, mergeSpaces as F, refreshPortals as C, spacesDividedBy as G, spacesRejoinedBy as K } from "./model/inference.js";
|
|
7
|
+
import { derivedGraph as w } from "./model/topology.js";
|
|
8
|
+
import { effectivePortals as H, sharedBoundaryPortals as U } from "./model/portals.js";
|
|
9
|
+
import { OBJECT_KINDS as X, isArea as Y, isDevice as J, isOpening as W, isSpace as q, uid as Q } from "./model/types.js";
|
|
10
|
+
import { createObject as ee, emptyProject as oe } from "./model/factory.js";
|
|
11
|
+
import { addBoundaryHole as te, addVirtualBoundary as ae, bindSpaceToRegion as se, boundaryEdges as ie, boundaryRegionAt as ne, boundaryRegions as pe, boundaryRings as de, connectSpace as ce, derivedSpaceRings as fe, disconnectSpace as me, drawVirtualBoundary as le, followsBoundaries as Ee, normalizeBoundaries as ge, refreshBoundarySpaces as Re } from "./model/boundaries.js";
|
|
12
|
+
import { DEFAULT_FOV as xe, DEFAULT_RANGE as ve, coverageOf as Pe } from "./model/coverage.js";
|
|
13
|
+
import { copyProject as ye, openingFloorId as he } from "./model/project.js";
|
|
14
|
+
import { MIN_SEGMENT as Te, OPENING_MIN_SEGMENT as Ae, addBarrier as _e, barrierEnds as Le, centroid as be, closeRing as Be, distance as Ie, duplicateFloor as Ne, footprint as je, geoOrigin as Me, moveOrigin as Ve, objectArea as De, objectPosition as Fe, objectRotation as Ce, openRing as Ge, pointInRing as Ke, rectangle as Ze, removeFloor as we, ringArea as ze, rotate as He, segmentProjection as Ue, segmentsCross as ke, slopeElevation as Xe, toLngLat as Ye, toLocal as Je } from "./model/geometry.js";
|
|
15
|
+
import { blobDataUrl as qe, exportProject as Qe, importProject as $e, parseExport as eo } from "./model/document.js";
|
|
16
|
+
import { COORD_LIMIT as ro, freezeProject as to, transact as ao, validateNavigation as so, validateProject as io, validateRelationships as no, validateRings as po } from "./model/validate.js";
|
|
17
|
+
import { applyMutation as fo, applyMutations as mo } from "./model/mutations.js";
|
|
18
|
+
import { DOOR_COST as Eo, ELEVATOR_BASE as go, ELEVATOR_PER_METRE as Ro, HERE as uo, NAV_WELD as xo, STAIR_CLIMB_FACTOR as vo, addNavEdge as Po, addNavNode as So, chainVertical as yo, edgeCost as ho, edgeLength as Oo, findRoute as To, floorPhrase as Ao, navEdges as _o, navNodes as Lo, navPath as bo, routeAnchors as Bo, routeSteps as Io } from "./model/navigation.js";
|
|
19
|
+
import { EXTERIOR_PRESETS as jo } from "./model/materials.js";
|
|
20
|
+
import { PITCH as Vo, flights as Do, flightsAt as Fo, isVertical as Co, passesThrough as Go, pitchOf as Ko, primaryShafts as Zo, reaches as wo, runFor as zo, servedFloors as Ho, shaftKey as Uo, shaftVoids as ko, span as Xo } from "./model/vertical.js";
|
|
21
|
+
import { buildRoomNavigation as Jo } from "./model/roomNavigation.js";
|
|
22
|
+
import { importPlanEntities as qo } from "./import/planImport.js";
|
|
23
|
+
import { VERTEX_LAYERS as $o } from "./import/types.js";
|
|
24
|
+
import { LAYER_ROLES as or, detectLayers as rr, layerPattern as tr } from "./import/detect.js";
|
|
25
|
+
import { documentSvg as sr } from "./import/documentSvg.js";
|
|
26
|
+
import { landmarks as nr, sheetOffset as pr, shiftEntities as dr } from "./import/register.js";
|
|
27
|
+
import { StructureView as fr } from "./components/StructureView.js";
|
|
28
|
+
export {
|
|
29
|
+
ro as COORD_LIMIT,
|
|
30
|
+
xe as DEFAULT_FOV,
|
|
31
|
+
ve as DEFAULT_RANGE,
|
|
32
|
+
Eo as DOOR_COST,
|
|
33
|
+
go as ELEVATOR_BASE,
|
|
34
|
+
Ro as ELEVATOR_PER_METRE,
|
|
35
|
+
jo as EXTERIOR_PRESETS,
|
|
36
|
+
uo as HERE,
|
|
37
|
+
r as IndexedAssetRepository,
|
|
38
|
+
t as IndexedProjectRepository,
|
|
39
|
+
p as KerrosThemeProvider,
|
|
40
|
+
or as LAYER_ROLES,
|
|
41
|
+
a as LocalProjectRepository,
|
|
42
|
+
Te as MIN_SEGMENT,
|
|
43
|
+
xo as NAV_WELD,
|
|
44
|
+
X as OBJECT_KINDS,
|
|
45
|
+
Ae as OPENING_MIN_SEGMENT,
|
|
46
|
+
Vo as PITCH,
|
|
47
|
+
vo as STAIR_CLIMB_FACTOR,
|
|
48
|
+
fr as StructureView,
|
|
49
|
+
$o as VERTEX_LAYERS,
|
|
50
|
+
_e as addBarrier,
|
|
51
|
+
te as addBoundaryHole,
|
|
52
|
+
Po as addNavEdge,
|
|
53
|
+
So as addNavNode,
|
|
54
|
+
S as addPortalGroup,
|
|
55
|
+
ae as addVirtualBoundary,
|
|
56
|
+
y as addZone,
|
|
57
|
+
fo as applyMutation,
|
|
58
|
+
mo as applyMutations,
|
|
59
|
+
Le as barrierEnds,
|
|
60
|
+
se as bindSpaceToRegion,
|
|
61
|
+
qe as blobDataUrl,
|
|
62
|
+
ie as boundaryEdges,
|
|
63
|
+
ne as boundaryRegionAt,
|
|
64
|
+
pe as boundaryRegions,
|
|
65
|
+
de as boundaryRings,
|
|
66
|
+
Jo as buildRoomNavigation,
|
|
67
|
+
h as captive,
|
|
68
|
+
be as centroid,
|
|
69
|
+
yo as chainVertical,
|
|
70
|
+
Be as closeRing,
|
|
71
|
+
ce as connectSpace,
|
|
72
|
+
ye as copyProject,
|
|
73
|
+
Pe as coverageOf,
|
|
74
|
+
ee as createObject,
|
|
75
|
+
w as derivedGraph,
|
|
76
|
+
fe as derivedSpaceRings,
|
|
77
|
+
rr as detectLayers,
|
|
78
|
+
me as disconnectSpace,
|
|
79
|
+
Ie as distance,
|
|
80
|
+
M as divideSpaces,
|
|
81
|
+
sr as documentSvg,
|
|
82
|
+
le as drawVirtualBoundary,
|
|
83
|
+
Ne as duplicateFloor,
|
|
84
|
+
ho as edgeCost,
|
|
85
|
+
Oo as edgeLength,
|
|
86
|
+
H as effectivePortals,
|
|
87
|
+
oe as emptyProject,
|
|
88
|
+
l as enclosedRegion,
|
|
89
|
+
E as enclosedRegions,
|
|
90
|
+
O as entryInto,
|
|
91
|
+
Qe as exportProject,
|
|
92
|
+
To as findRoute,
|
|
93
|
+
Do as flights,
|
|
94
|
+
Fo as flightsAt,
|
|
95
|
+
Ao as floorPhrase,
|
|
96
|
+
Ee as followsBoundaries,
|
|
97
|
+
je as footprint,
|
|
98
|
+
to as freezeProject,
|
|
99
|
+
Me as geoOrigin,
|
|
100
|
+
qo as importPlanEntities,
|
|
101
|
+
$e as importProject,
|
|
102
|
+
g as inSpace,
|
|
103
|
+
V as inferOpenBoundaries,
|
|
104
|
+
D as inferPortals,
|
|
105
|
+
Y as isArea,
|
|
106
|
+
J as isDevice,
|
|
107
|
+
W as isOpening,
|
|
108
|
+
q as isSpace,
|
|
109
|
+
Co as isVertical,
|
|
110
|
+
nr as landmarks,
|
|
111
|
+
tr as layerPattern,
|
|
112
|
+
F as mergeSpaces,
|
|
113
|
+
Ve as moveOrigin,
|
|
114
|
+
_o as navEdges,
|
|
115
|
+
Lo as navNodes,
|
|
116
|
+
bo as navPath,
|
|
117
|
+
T as nestZone,
|
|
118
|
+
i as neutralBasemap,
|
|
119
|
+
ge as normalizeBoundaries,
|
|
120
|
+
De as objectArea,
|
|
121
|
+
Fe as objectPosition,
|
|
122
|
+
Ce as objectRotation,
|
|
123
|
+
Ge as openRing,
|
|
124
|
+
he as openingFloorId,
|
|
125
|
+
eo as parseExport,
|
|
126
|
+
Go as passesThrough,
|
|
127
|
+
A as perimeter,
|
|
128
|
+
Ko as pitchOf,
|
|
129
|
+
Ke as pointInRing,
|
|
130
|
+
Zo as primaryShafts,
|
|
131
|
+
_ as pruneOntology,
|
|
132
|
+
wo as reaches,
|
|
133
|
+
Ze as rectangle,
|
|
134
|
+
R as refitEnclosedRooms,
|
|
135
|
+
Re as refreshBoundarySpaces,
|
|
136
|
+
C as refreshPortals,
|
|
137
|
+
we as removeFloor,
|
|
138
|
+
L as removePortalGroup,
|
|
139
|
+
b as removeZone,
|
|
140
|
+
ze as ringArea,
|
|
141
|
+
He as rotate,
|
|
142
|
+
Bo as routeAnchors,
|
|
143
|
+
Io as routeSteps,
|
|
144
|
+
zo as runFor,
|
|
145
|
+
Ue as segmentProjection,
|
|
146
|
+
ke as segmentsCross,
|
|
147
|
+
Ho as servedFloors,
|
|
148
|
+
B as setPortalGroupMembers,
|
|
149
|
+
I as setZoneMembers,
|
|
150
|
+
Uo as shaftKey,
|
|
151
|
+
ko as shaftVoids,
|
|
152
|
+
U as sharedBoundaryPortals,
|
|
153
|
+
pr as sheetOffset,
|
|
154
|
+
dr as shiftEntities,
|
|
155
|
+
Xe as slopeElevation,
|
|
156
|
+
u as spaceAt,
|
|
157
|
+
x as spacePoint,
|
|
158
|
+
v as spaces,
|
|
159
|
+
G as spacesDividedBy,
|
|
160
|
+
K as spacesRejoinedBy,
|
|
161
|
+
Xo as span,
|
|
162
|
+
Ye as toLngLat,
|
|
163
|
+
Je as toLocal,
|
|
164
|
+
ao as transact,
|
|
165
|
+
Q as uid,
|
|
166
|
+
d as useDarkMode,
|
|
167
|
+
c as useKerrosTheme,
|
|
168
|
+
f as useStrings,
|
|
169
|
+
so as validateNavigation,
|
|
170
|
+
io as validateProject,
|
|
171
|
+
no as validateRelationships,
|
|
172
|
+
po as validateRings,
|
|
173
|
+
N as zoneSpaces
|
|
174
|
+
};
|
|
175
|
+
//# sourceMappingURL=host.js.map
|
package/dist/host.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"host.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;"}
|
package/dist/i18n.js
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
const e = {
|
|
2
|
+
app: "Spaces",
|
|
3
|
+
brand: "kerros",
|
|
4
|
+
viewer: "Plan viewer",
|
|
5
|
+
editor: "Plan editor",
|
|
6
|
+
monitor: "Live view",
|
|
7
|
+
overview: "Overview",
|
|
8
|
+
floors: "Floors & levels",
|
|
9
|
+
drawings: "Reference drawings",
|
|
10
|
+
objects: "Objects",
|
|
11
|
+
import: "Import",
|
|
12
|
+
export: "Export project",
|
|
13
|
+
saved: "All changes saved",
|
|
14
|
+
saving: "Saving changes…",
|
|
15
|
+
saveError: "Not saved · export a backup",
|
|
16
|
+
outdoors: "Outdoor site",
|
|
17
|
+
tools: {
|
|
18
|
+
select: "Select",
|
|
19
|
+
pan: "Pan",
|
|
20
|
+
wall: "Wall",
|
|
21
|
+
boundary: "Virtual boundary",
|
|
22
|
+
partition: "Partition",
|
|
23
|
+
fence: "Fence",
|
|
24
|
+
zone: "Zone polygon",
|
|
25
|
+
room: "Room polygon",
|
|
26
|
+
rectangle: "Rectangle",
|
|
27
|
+
hole: "Cut a hole",
|
|
28
|
+
door: "Door",
|
|
29
|
+
window: "Window",
|
|
30
|
+
gate: "Gate",
|
|
31
|
+
turnstile: "Turnstile",
|
|
32
|
+
reader: "RFID reader",
|
|
33
|
+
camera: "Camera",
|
|
34
|
+
elevator: "Elevator",
|
|
35
|
+
stairs: "Stairs",
|
|
36
|
+
office: "Site office",
|
|
37
|
+
container: "Container",
|
|
38
|
+
storage: "Storage area",
|
|
39
|
+
poi: "POI marker",
|
|
40
|
+
measure: "Measure",
|
|
41
|
+
adopt: "Adopt basemap building",
|
|
42
|
+
split: "Split room",
|
|
43
|
+
enclose: "Space from walls",
|
|
44
|
+
route: "Route path",
|
|
45
|
+
sensor: "Sensor",
|
|
46
|
+
light: "Ceiling light",
|
|
47
|
+
alarm: "Alarm point",
|
|
48
|
+
equipment: "Equipment",
|
|
49
|
+
evacuation: "Evacuation zone"
|
|
50
|
+
},
|
|
51
|
+
navigate: {
|
|
52
|
+
title: "Navigate",
|
|
53
|
+
from: "From",
|
|
54
|
+
to: "To",
|
|
55
|
+
choose: "Choose a place…",
|
|
56
|
+
swap: "Swap start and destination",
|
|
57
|
+
clear: "Clear route",
|
|
58
|
+
play: "Play route",
|
|
59
|
+
pause: "Pause",
|
|
60
|
+
prev: "Previous step",
|
|
61
|
+
next: "Next step",
|
|
62
|
+
walking: "walking",
|
|
63
|
+
floors: "floors",
|
|
64
|
+
steps: "steps",
|
|
65
|
+
noGraph: "No routes drawn yet",
|
|
66
|
+
noGraphHintEdit: "Use the Route path tool in the editor: click to chain walking nodes, click a lift or stairs to link floors, click doors and POIs to bind destinations.",
|
|
67
|
+
noGraphHintView: "This project has no authored route network yet.",
|
|
68
|
+
unreachable: "No route found",
|
|
69
|
+
unreachableHint: "These places are not connected by the drawn route network.",
|
|
70
|
+
pick: "Choose a start and a destination to see directions.",
|
|
71
|
+
here: "Where you are",
|
|
72
|
+
hereHint: "Where the walk left you",
|
|
73
|
+
levels: "Browse by level",
|
|
74
|
+
allLevels: "All levels",
|
|
75
|
+
places: "places",
|
|
76
|
+
more: "Scroll for more…"
|
|
77
|
+
},
|
|
78
|
+
map: {
|
|
79
|
+
basemapUnavailable: "Basemap unavailable. Your plan is still available; choose Plan background.",
|
|
80
|
+
basemapUnavailablePlan: "Basemap unavailable. The floor model remains available on the plan background.",
|
|
81
|
+
adoptMiss: "No basemap building here — click a building footprint on the map.",
|
|
82
|
+
adoptFail: "Could not trace that footprint — try zooming in first."
|
|
83
|
+
}
|
|
84
|
+
};
|
|
85
|
+
export {
|
|
86
|
+
e as en
|
|
87
|
+
};
|
|
88
|
+
//# sourceMappingURL=i18n.js.map
|
package/dist/i18n.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"i18n.js","sources":["../../../src/i18n.ts"],"sourcesContent":["// The library's user-facing English strings. A host translates/overrides any subset via\n// KerrosThemeProvider's `strings` (deep-merged over these); components read them through useStrings().\nexport const en = {\n app: 'Spaces',\n brand: 'kerros',\n viewer: 'Plan viewer',\n editor: 'Plan editor',\n monitor: 'Live view',\n overview: 'Overview',\n floors: 'Floors & levels',\n drawings: 'Reference drawings',\n objects: 'Objects',\n import: 'Import',\n export: 'Export project',\n saved: 'All changes saved',\n saving: 'Saving changes…',\n saveError: 'Not saved · export a backup',\n outdoors: 'Outdoor site',\n tools: {\n select: 'Select',\n pan: 'Pan',\n wall: 'Wall',\n boundary: 'Virtual boundary',\n partition: 'Partition',\n fence: 'Fence',\n zone: 'Zone polygon',\n room: 'Room polygon',\n rectangle: 'Rectangle',\n hole: 'Cut a hole',\n door: 'Door',\n window: 'Window',\n gate: 'Gate',\n turnstile: 'Turnstile',\n reader: 'RFID reader',\n camera: 'Camera',\n elevator: 'Elevator',\n stairs: 'Stairs',\n office: 'Site office',\n container: 'Container',\n storage: 'Storage area',\n poi: 'POI marker',\n measure: 'Measure',\n adopt: 'Adopt basemap building',\n split: 'Split room',\n enclose: 'Space from walls',\n route: 'Route path',\n sensor: 'Sensor',\n light: 'Ceiling light',\n alarm: 'Alarm point',\n equipment: 'Equipment',\n evacuation: 'Evacuation zone',\n },\n navigate: {\n title: 'Navigate',\n from: 'From',\n to: 'To',\n choose: 'Choose a place…',\n swap: 'Swap start and destination',\n clear: 'Clear route',\n play: 'Play route',\n pause: 'Pause',\n prev: 'Previous step',\n next: 'Next step',\n walking: 'walking',\n floors: 'floors',\n steps: 'steps',\n noGraph: 'No routes drawn yet',\n noGraphHintEdit:\n 'Use the Route path tool in the editor: click to chain walking nodes, click a lift or stairs to link floors, click doors and POIs to bind destinations.',\n noGraphHintView: 'This project has no authored route network yet.',\n unreachable: 'No route found',\n unreachableHint: 'These places are not connected by the drawn route network.',\n pick: 'Choose a start and a destination to see directions.',\n here: 'Where you are',\n hereHint: 'Where the walk left you',\n levels: 'Browse by level',\n allLevels: 'All levels',\n places: 'places',\n more: 'Scroll for more…',\n },\n map: {\n basemapUnavailable: 'Basemap unavailable. Your plan is still available; choose Plan background.',\n basemapUnavailablePlan: 'Basemap unavailable. The floor model remains available on the plan background.',\n adoptMiss: 'No basemap building here — click a building footprint on the map.',\n adoptFail: 'Could not trace that footprint — try zooming in first.',\n },\n};\nexport type En = typeof en;\n"],"names":["en"],"mappings":"AAEO,MAAMA,IAAK;AAAA,EAChB,KAAK;AAAA,EACL,OAAO;AAAA,EACP,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,SAAS;AAAA,EACT,UAAU;AAAA,EACV,QAAQ;AAAA,EACR,UAAU;AAAA,EACV,SAAS;AAAA,EACT,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,OAAO;AAAA,EACP,QAAQ;AAAA,EACR,WAAW;AAAA,EACX,UAAU;AAAA,EACV,OAAO;AAAA,IACL,QAAQ;AAAA,IACR,KAAK;AAAA,IACL,MAAM;AAAA,IACN,UAAU;AAAA,IACV,WAAW;AAAA,IACX,OAAO;AAAA,IACP,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,MAAM;AAAA,IACN,MAAM;AAAA,IACN,QAAQ;AAAA,IACR,MAAM;AAAA,IACN,WAAW;AAAA,IACX,QAAQ;AAAA,IACR,QAAQ;AAAA,IACR,UAAU;AAAA,IACV,QAAQ;AAAA,IACR,QAAQ;AAAA,IACR,WAAW;AAAA,IACX,SAAS;AAAA,IACT,KAAK;AAAA,IACL,SAAS;AAAA,IACT,OAAO;AAAA,IACP,OAAO;AAAA,IACP,SAAS;AAAA,IACT,OAAO;AAAA,IACP,QAAQ;AAAA,IACR,OAAO;AAAA,IACP,OAAO;AAAA,IACP,WAAW;AAAA,IACX,YAAY;AAAA,EAAA;AAAA,EAEd,UAAU;AAAA,IACR,OAAO;AAAA,IACP,MAAM;AAAA,IACN,IAAI;AAAA,IACJ,QAAQ;AAAA,IACR,MAAM;AAAA,IACN,OAAO;AAAA,IACP,MAAM;AAAA,IACN,OAAO;AAAA,IACP,MAAM;AAAA,IACN,MAAM;AAAA,IACN,SAAS;AAAA,IACT,QAAQ;AAAA,IACR,OAAO;AAAA,IACP,SAAS;AAAA,IACT,iBACE;AAAA,IACF,iBAAiB;AAAA,IACjB,aAAa;AAAA,IACb,iBAAiB;AAAA,IACjB,MAAM;AAAA,IACN,MAAM;AAAA,IACN,UAAU;AAAA,IACV,QAAQ;AAAA,IACR,WAAW;AAAA,IACX,QAAQ;AAAA,IACR,MAAM;AAAA,EAAA;AAAA,EAER,KAAK;AAAA,IACH,oBAAoB;AAAA,IACpB,wBAAwB;AAAA,IACxB,WAAW;AAAA,IACX,WAAW;AAAA,EAAA;AAEf;"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
function l(n) {
|
|
2
|
+
const e = n;
|
|
3
|
+
if (!e || typeof e.artifactId != "string" || e.artifactId.length > 200 || !Number.isSafeInteger(e.page) || e.page < 1 || e.page > 20 || !["m", "px", "pt"].includes(e.units) || typeof e.svg != "string" || e.svg.length > 2e5 || !e.svg.startsWith("<svg ") || !Number.isSafeInteger(e.shown) || e.shown < 0 || !Number.isSafeInteger(e.total) || e.total < e.shown || !e.counts || typeof e.counts != "object" || Object.keys(e.counts).length > 20 || Object.values(e.counts).some((t) => !Number.isSafeInteger(t) || t < 0) || !Array.isArray(e.warnings) || e.warnings.length > 20 || e.warnings.some((t) => typeof t != "string" || t.length > 1e3) || e.calibration !== void 0 && (typeof e.calibration != "string" || e.calibration.length > 500) || e.metresPerUnit !== void 0 && (!Number.isFinite(e.metresPerUnit) || e.metresPerUnit <= 0) || e.transformId !== void 0 && (typeof e.transformId != "string" || e.transformId.length > 200))
|
|
4
|
+
throw new Error("Invalid source-analysis preview.");
|
|
5
|
+
if (e.background) {
|
|
6
|
+
const t = e.background;
|
|
7
|
+
if (typeof t.pngBase64 != "string" || t.pngBase64.length > 6e6 || !/^iVBORw0KGgo[A-Za-z0-9+/]*={0,2}$/.test(t.pngBase64) || !Array.isArray(t.bounds) || t.bounds.length !== 4 || !Array.isArray(t.matrix) || t.matrix.length !== 6 || [...t.bounds, ...t.matrix].some((r) => !Number.isFinite(r) || Math.abs(r) > 1e12) || t.bounds[2] <= t.bounds[0] || t.bounds[3] <= t.bounds[1])
|
|
8
|
+
throw new Error("Invalid source-analysis background.");
|
|
9
|
+
}
|
|
10
|
+
const a = e.svg.matchAll(/<\/?([a-zA-Z][\w:-]*)\b/g);
|
|
11
|
+
for (const [, t] of a)
|
|
12
|
+
if (!["svg", "defs", "clipPath", "g", "path", "text", "title"].includes(t))
|
|
13
|
+
throw new Error("Unsupported analysis SVG element.");
|
|
14
|
+
if (/<!|<\?|\s(?:on\w+|(?:xlink:)?href|style)\s*=|url\(\s*[^#]/i.test(e.svg))
|
|
15
|
+
throw new Error("Unsupported analysis SVG content.");
|
|
16
|
+
return e;
|
|
17
|
+
}
|
|
18
|
+
const o = (n) => `${n}:analysis-preview`;
|
|
19
|
+
async function d(n, e, a) {
|
|
20
|
+
await n.put(
|
|
21
|
+
o(e),
|
|
22
|
+
new Blob([JSON.stringify(l(a))], { type: "application/json" })
|
|
23
|
+
);
|
|
24
|
+
}
|
|
25
|
+
async function b(n, e) {
|
|
26
|
+
const a = await n.get(o(e));
|
|
27
|
+
if (a) return l(JSON.parse(await a.text()));
|
|
28
|
+
}
|
|
29
|
+
const p = (n, e) => n.delete(o(e));
|
|
30
|
+
function y(n, e = [], a = !0, t = 0.85) {
|
|
31
|
+
const r = ["wall", "outline", "label", "symbol", "path"], g = e.filter((i) => r.includes(i)).map((i) => `g[data-kind="${i}"]{display:none}`).join(""), s = a ? n.background : void 0, u = Number.isFinite(t) ? Math.max(0, Math.min(1, t)) : 0.85, c = s ? `<image x="${s.bounds[0]}" y="${s.bounds[1]}" width="${s.bounds[2] - s.bounds[0]}" height="${s.bounds[3] - s.bounds[1]}" transform="matrix(${s.matrix.join(" ")})" preserveAspectRatio="none" href="data:image/png;base64,${s.pngBase64}"/>` : "";
|
|
32
|
+
return n.svg.replace(/(<svg\b[^>]*>)/, `$1<style>${g}</style>${c}<g opacity="${u}">`).replace("</svg>", "</g></svg>");
|
|
33
|
+
}
|
|
34
|
+
export {
|
|
35
|
+
y as analysisPreviewSvg,
|
|
36
|
+
p as deleteAnalysisPreview,
|
|
37
|
+
b as loadAnalysisPreview,
|
|
38
|
+
l as readAnalysisPreview,
|
|
39
|
+
d as saveAnalysisPreview
|
|
40
|
+
};
|
|
41
|
+
//# sourceMappingURL=analysisPreview.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"analysisPreview.js","sources":["../../../../src/import/analysisPreview.ts"],"sourcesContent":["import type { AssetRepository } from '../model/types';\n\n/** Human-only vector evidence. Never part of the model checkpoint or its conversation. */\nexport interface ImportAnalysisPreview {\n artifactId: string;\n page: number;\n units: 'm' | 'px' | 'pt';\n transformId?: string;\n metresPerUnit?: number;\n calibration?: string;\n svg: string;\n /** Human-only source raster, located in the SVG display coordinate frame. */\n background?: {\n pngBase64: string;\n bounds: [number, number, number, number];\n matrix: [number, number, number, number, number, number];\n };\n shown: number;\n total: number;\n counts: Record<string, number>;\n warnings: string[];\n}\nexport function readAnalysisPreview(value: unknown): ImportAnalysisPreview {\n const p = value as ImportAnalysisPreview;\n if (\n !p ||\n typeof p.artifactId !== 'string' ||\n p.artifactId.length > 200 ||\n !Number.isSafeInteger(p.page) ||\n p.page < 1 ||\n p.page > 20 ||\n !['m', 'px', 'pt'].includes(p.units) ||\n typeof p.svg !== 'string' ||\n p.svg.length > 200_000 ||\n !p.svg.startsWith('<svg ') ||\n !Number.isSafeInteger(p.shown) ||\n p.shown < 0 ||\n !Number.isSafeInteger(p.total) ||\n p.total < p.shown ||\n !p.counts ||\n typeof p.counts !== 'object' ||\n Object.keys(p.counts).length > 20 ||\n Object.values(p.counts).some(n => !Number.isSafeInteger(n) || n < 0) ||\n !Array.isArray(p.warnings) ||\n p.warnings.length > 20 ||\n p.warnings.some(s => typeof s !== 'string' || s.length > 1000) ||\n (p.calibration !== undefined && (typeof p.calibration !== 'string' || p.calibration.length > 500)) ||\n (p.metresPerUnit !== undefined && (!Number.isFinite(p.metresPerUnit) || p.metresPerUnit <= 0)) ||\n (p.transformId !== undefined && (typeof p.transformId !== 'string' || p.transformId.length > 200))\n )\n throw new Error('Invalid source-analysis preview.');\n if (p.background) {\n const b = p.background;\n if (\n typeof b.pngBase64 !== 'string' ||\n b.pngBase64.length > 6_000_000 ||\n !/^iVBORw0KGgo[A-Za-z0-9+/]*={0,2}$/.test(b.pngBase64) ||\n !Array.isArray(b.bounds) ||\n b.bounds.length !== 4 ||\n !Array.isArray(b.matrix) ||\n b.matrix.length !== 6 ||\n [...b.bounds, ...b.matrix].some(n => !Number.isFinite(n) || Math.abs(n) > 1e12) ||\n b.bounds[2] <= b.bounds[0] ||\n b.bounds[3] <= b.bounds[1]\n )\n throw new Error('Invalid source-analysis background.');\n }\n // Restricted geometry/text only. The component also displays SVG as an inert image, never\n // inserts source markup into the editor DOM. Keep this contract usable without an XML library.\n const tags = p.svg.matchAll(/<\\/?([a-zA-Z][\\w:-]*)\\b/g);\n for (const [, tag] of tags)\n if (!['svg', 'defs', 'clipPath', 'g', 'path', 'text', 'title'].includes(tag))\n throw new Error('Unsupported analysis SVG element.');\n if (/<!|<\\?|\\s(?:on\\w+|(?:xlink:)?href|style)\\s*=|url\\(\\s*[^#]/i.test(p.svg))\n throw new Error('Unsupported analysis SVG content.');\n return p;\n}\nconst key = (sourceId: string) => `${sourceId}:analysis-preview`;\nexport async function saveAnalysisPreview(assets: AssetRepository, sourceId: string, preview: ImportAnalysisPreview) {\n await assets.put(\n key(sourceId),\n new Blob([JSON.stringify(readAnalysisPreview(preview))], { type: 'application/json' }),\n );\n}\nexport async function loadAnalysisPreview(assets: AssetRepository, sourceId: string) {\n const blob = await assets.get(key(sourceId));\n if (blob) return readAnalysisPreview(JSON.parse(await blob.text()));\n}\nexport const deleteAnalysisPreview = (assets: AssetRepository, sourceId: string) => assets.delete(key(sourceId));\n\n/** Compose only validated local evidence. Render as an inert image, never innerHTML. */\nexport function analysisPreviewSvg(\n preview: ImportAnalysisPreview,\n hidden: string[] = [],\n showBackground = true,\n opacity = 0.85,\n) {\n const allowed = ['wall', 'outline', 'label', 'symbol', 'path'];\n const css = hidden\n .filter(k => allowed.includes(k))\n .map(kind => `g[data-kind=\"${kind}\"]{display:none}`)\n .join('');\n const b = showBackground ? preview.background : undefined;\n const alpha = Number.isFinite(opacity) ? Math.max(0, Math.min(1, opacity)) : 0.85;\n const underlay = b\n ? `<image x=\"${b.bounds[0]}\" y=\"${b.bounds[1]}\" width=\"${b.bounds[2] - b.bounds[0]}\" height=\"${b.bounds[3] - b.bounds[1]}\" transform=\"matrix(${b.matrix.join(' ')})\" preserveAspectRatio=\"none\" href=\"data:image/png;base64,${b.pngBase64}\"/>`\n : '';\n return preview.svg\n .replace(/(<svg\\b[^>]*>)/, `$1<style>${css}</style>${underlay}<g opacity=\"${alpha}\">`)\n .replace('</svg>', '</g></svg>');\n}\n"],"names":["readAnalysisPreview","value","p","n","s","b","tags","tag","key","sourceId","saveAnalysisPreview","assets","preview","loadAnalysisPreview","blob","deleteAnalysisPreview","analysisPreviewSvg","hidden","showBackground","opacity","allowed","css","k","kind","alpha","underlay"],"mappings":"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"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
function f(r) {
|
|
2
|
+
if (r === void 0) return;
|
|
3
|
+
if (!r || typeof r != "object" || Array.isArray(r)) throw new Error("Invalid import template.");
|
|
4
|
+
const t = {};
|
|
5
|
+
for (const n of ["widthMetres", "depthMetres", "footprintAreaM2"]) {
|
|
6
|
+
const o = r[n];
|
|
7
|
+
if (o !== void 0) {
|
|
8
|
+
if (typeof o != "number" || !Number.isFinite(o) || o <= 0)
|
|
9
|
+
throw new Error("Dimensions and footprint area must be positive numbers.");
|
|
10
|
+
t[n] = o;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
const { buildingType: i, floorCount: e } = r;
|
|
14
|
+
if (i !== void 0) {
|
|
15
|
+
if (!["apartment", "house", "office", "retail", "other"].includes(i))
|
|
16
|
+
throw new Error("Choose a building type from the template.");
|
|
17
|
+
t.buildingType = i;
|
|
18
|
+
}
|
|
19
|
+
if (e !== void 0) {
|
|
20
|
+
if (!Number.isSafeInteger(e) || e < 1 || e > 100)
|
|
21
|
+
throw new Error("Floor count must be a whole number between 1 and 100.");
|
|
22
|
+
t.floorCount = e;
|
|
23
|
+
}
|
|
24
|
+
return t;
|
|
25
|
+
}
|
|
26
|
+
export {
|
|
27
|
+
f as readImportBrief
|
|
28
|
+
};
|
|
29
|
+
//# sourceMappingURL=brief.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"brief.js","sources":["../../../../src/import/brief.ts"],"sourcesContent":["/** User-supplied import scope and whole-floor exterior scale references. */\nexport interface ImportBrief {\n buildingType?: 'apartment' | 'house' | 'office' | 'retail' | 'other';\n floorCount?: number;\n widthMetres?: number;\n depthMetres?: number;\n footprintAreaM2?: number;\n}\nexport function readImportBrief(value: unknown): ImportBrief | undefined {\n if (value === undefined) return;\n if (!value || typeof value !== 'object' || Array.isArray(value)) throw new Error('Invalid import template.');\n const result: ImportBrief = {};\n for (const key of ['widthMetres', 'depthMetres', 'footprintAreaM2'] as const) {\n const n = (value as ImportBrief)[key];\n if (n === undefined) continue;\n if (typeof n !== 'number' || !Number.isFinite(n) || n <= 0)\n throw new Error('Dimensions and footprint area must be positive numbers.');\n result[key] = n;\n }\n const { buildingType, floorCount } = value as ImportBrief;\n if (buildingType !== undefined) {\n if (!['apartment', 'house', 'office', 'retail', 'other'].includes(buildingType))\n throw new Error('Choose a building type from the template.');\n result.buildingType = buildingType;\n }\n if (floorCount !== undefined) {\n if (!Number.isSafeInteger(floorCount) || floorCount < 1 || floorCount > 100)\n throw new Error('Floor count must be a whole number between 1 and 100.');\n result.floorCount = floorCount;\n }\n return result;\n}\nexport function importBriefInstructions(brief?: ImportBrief): string {\n if (!brief || !Object.keys(brief).length) return '';\n return `User import template: ${JSON.stringify(brief)}. Dimensions are in metres. Footprint area is the whole floor outline to the outside of walls, not summed usable room areas. Width/depth follow the drawing's main axes, not the page margins. Calibrate to these values. For area use scale = sqrt(real footprint area / source footprint polygon area); respect non-rectangular outlines. If references disagree, ask which is more reliable instead of stretching axes independently. Check an existing draft against these references before preserving its scale. Building type guides naming/use, never invents dimensions. Import the requested floor count only where source plans exist; report missing floor drawings rather than cloning or inventing layouts.`;\n}\n\nexport interface SourceCalibration {\n drawingWidth?: number;\n drawingDepth?: number;\n drawingArea?: number;\n drawingLength?: number;\n realLengthMetres?: number;\n basis: string;\n metresPerUnit: number;\n}\n/** Compute scale from the user's references; never let the model silently substitute a smaller\n * real-world width. Multiple references must agree within 10% in linear scale. */\nexport function calibrateImport(value: unknown, brief?: ImportBrief): SourceCalibration {\n if (!value || typeof value !== 'object') throw new Error('Supply a source calibration.');\n const c = value as SourceCalibration;\n if (typeof c.basis !== 'string' || !c.basis.trim() || c.basis.length > 500)\n throw new Error('Identify the reference in basis (at most 500 characters).');\n const positive = (n: unknown, name: string) => {\n if (typeof n !== 'number' || !Number.isFinite(n) || n <= 0)\n throw new Error(`Supply a positive ${name} in original source units.`);\n return n;\n };\n const scales: number[] = [];\n const result: SourceCalibration = { basis: c.basis, metresPerUnit: 0 };\n if (brief?.widthMetres) {\n result.drawingWidth = positive(c.drawingWidth, 'drawingWidth');\n scales.push(brief.widthMetres / result.drawingWidth);\n }\n if (brief?.depthMetres) {\n result.drawingDepth = positive(c.drawingDepth, 'drawingDepth');\n scales.push(brief.depthMetres / result.drawingDepth);\n }\n if (brief?.footprintAreaM2) {\n result.drawingArea = positive(c.drawingArea, 'drawingArea');\n scales.push(Math.sqrt(brief.footprintAreaM2 / result.drawingArea));\n }\n if (!scales.length) {\n result.drawingLength = positive(c.drawingLength, 'drawingLength');\n result.realLengthMetres = positive(c.realLengthMetres, 'realLengthMetres');\n scales.push(result.realLengthMetres / result.drawingLength);\n }\n if (Math.max(...scales) / Math.min(...scales) > 1.1)\n throw new Error(\n 'Scale references disagree by more than 10%. Recheck the source outline and user dimensions; ask for clarification instead of distorting the plan.',\n );\n result.metresPerUnit = scales[0];\n return result;\n}\n"],"names":["readImportBrief","value","result","key","n","buildingType","floorCount"],"mappings":"AAQO,SAASA,EAAgBC,GAAyC;AACvE,MAAIA,MAAU,OAAW;AACzB,MAAI,CAACA,KAAS,OAAOA,KAAU,YAAY,MAAM,QAAQA,CAAK,EAAG,OAAM,IAAI,MAAM,0BAA0B;AAC3G,QAAMC,IAAsB,CAAA;AAC5B,aAAWC,KAAO,CAAC,eAAe,eAAe,iBAAiB,GAAY;AAC5E,UAAMC,IAAKH,EAAsBE,CAAG;AACpC,QAAIC,MAAM,QACV;AAAA,UAAI,OAAOA,KAAM,YAAY,CAAC,OAAO,SAASA,CAAC,KAAKA,KAAK;AACvD,cAAM,IAAI,MAAM,yDAAyD;AAC3E,MAAAF,EAAOC,CAAG,IAAIC;AAAA;AAAA,EAChB;AACA,QAAM,EAAE,cAAAC,GAAc,YAAAC,EAAA,IAAeL;AACrC,MAAII,MAAiB,QAAW;AAC9B,QAAI,CAAC,CAAC,aAAa,SAAS,UAAU,UAAU,OAAO,EAAE,SAASA,CAAY;AAC5E,YAAM,IAAI,MAAM,2CAA2C;AAC7D,IAAAH,EAAO,eAAeG;AAAA,EACxB;AACA,MAAIC,MAAe,QAAW;AAC5B,QAAI,CAAC,OAAO,cAAcA,CAAU,KAAKA,IAAa,KAAKA,IAAa;AACtE,YAAM,IAAI,MAAM,uDAAuD;AACzE,IAAAJ,EAAO,aAAaI;AAAA,EACtB;AACA,SAAOJ;AACT;"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { readImportBrief as s } from "./brief.js";
|
|
2
|
+
import { readImportInstruction as a } from "./instructions.js";
|
|
3
|
+
function d(n) {
|
|
4
|
+
var o;
|
|
5
|
+
if (n === void 0) return;
|
|
6
|
+
if (!n || typeof n != "object" || JSON.stringify(n).length > 96e3)
|
|
7
|
+
throw new Error("Import checkpoint exceeds the supported size.");
|
|
8
|
+
const e = n;
|
|
9
|
+
if (e.steering && (!Array.isArray(e.steering) || e.steering.length > 20 || JSON.stringify(e.steering).length > 8e3))
|
|
10
|
+
throw new Error("Saved human instructions exceed the supported size.");
|
|
11
|
+
(o = e.steering) == null || o.forEach(a);
|
|
12
|
+
const r = (t, i) => typeof t == "string" && t.length <= i;
|
|
13
|
+
if (e.version !== 1 || !r(e.projectId, 200) || !["inspect", "build", "review"].includes(e.phase) || !r(e.notes, 3e3) || !r(e.sourcePlan, 8e3) || !r(e.lastAssistantText, 1200) || !r(e.lastToolReport, 3e3) || !Array.isArray(e.mutationKinds) || e.mutationKinds.length > 100 || e.mutationKinds.some((t) => !r(t, 100)) || !Array.isArray(e.analysis) || e.analysis.length > 8)
|
|
14
|
+
throw new Error("Invalid import checkpoint.");
|
|
15
|
+
for (const t of e.analysis)
|
|
16
|
+
if (!t || !r(t.artifactId, 200) || !/^[a-f0-9]{64}$/.test(t.sourceHash) || !t.request || typeof t.request != "object" || Array.isArray(t.request) || t.calibration && (!Number.isSafeInteger(t.calibration.revision) || t.calibration.revision < 1 || !t.calibration.input || typeof t.calibration.input != "object"))
|
|
17
|
+
throw new Error("Invalid analysis checkpoint.");
|
|
18
|
+
if (e.calibration && (!r(e.calibration.basis, 500) || !Number.isFinite(e.calibration.metresPerUnit) || e.calibration.metresPerUnit <= 0))
|
|
19
|
+
throw new Error("Invalid saved calibration.");
|
|
20
|
+
if (e.decisions && (!Array.isArray(e.decisions) || JSON.stringify(e.decisions).length > 32e3 || e.decisions.some(
|
|
21
|
+
(t) => !t || ![t.artifactId, t.transformId, t.floorId, t.candidateId].every((i) => r(i, 200)) || !["accepted", "rejected", "needs-review"].includes(t.status) || !Array.isArray(t.modelIds) || t.modelIds.length > 500 || t.modelIds.some((i) => !r(i, 200))
|
|
22
|
+
)))
|
|
23
|
+
throw new Error("Invalid saved candidate decisions.");
|
|
24
|
+
return { ...e, brief: s(e.brief) };
|
|
25
|
+
}
|
|
26
|
+
const u = { inputTokens: 2e5, outputTokens: 24e3, maxTurns: 40 };
|
|
27
|
+
function f(n) {
|
|
28
|
+
if (n === void 0) return { ...u };
|
|
29
|
+
const e = n;
|
|
30
|
+
if (!e || !Number.isSafeInteger(e.inputTokens) || e.inputTokens < 1e4 || e.inputTokens > 2e6 || !Number.isSafeInteger(e.outputTokens) || e.outputTokens < 1e3 || e.outputTokens > 1e5)
|
|
31
|
+
throw new Error("Import budget must be 10,000–2,000,000 input and 1,000–100,000 output tokens.");
|
|
32
|
+
const r = e.maxTurns ?? 40;
|
|
33
|
+
if (!Number.isSafeInteger(r) || r < 1 || r > 100)
|
|
34
|
+
throw new Error("Choose a turn limit between 1 and 100 per run. Continue can start another run.");
|
|
35
|
+
return { inputTokens: e.inputTokens, outputTokens: e.outputTokens, maxTurns: r };
|
|
36
|
+
}
|
|
37
|
+
function m(n) {
|
|
38
|
+
if (n === void 0) return;
|
|
39
|
+
const e = n;
|
|
40
|
+
if (!e || !["input-budget", "output-budget", "turn-limit", "refusals", "repeated-tools"].includes(e.reason) || typeof e.message != "string" || e.message.length > 2e3)
|
|
41
|
+
throw new Error("Invalid import pause.");
|
|
42
|
+
return { reason: e.reason, message: e.message };
|
|
43
|
+
}
|
|
44
|
+
export {
|
|
45
|
+
u as DEFAULT_IMPORT_BUDGET,
|
|
46
|
+
f as readImportBudget,
|
|
47
|
+
d as readImportCheckpoint,
|
|
48
|
+
m as readImportPause
|
|
49
|
+
};
|
|
50
|
+
//# sourceMappingURL=checkpoint.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"checkpoint.js","sources":["../../../../src/import/checkpoint.ts"],"sourcesContent":["import { readImportBrief, type ImportBrief, type SourceCalibration } from './brief';\nimport { readImportInstruction, type ImportInstruction } from './instructions';\n\n/** Serializable continuation state, never a second copy of project geometry or source pixels.\n * Extraction recipes restore cached backend artifacts after a worker/container restart. */\nexport interface ImportCheckpoint {\n version: 1;\n projectId: string;\n brief?: ImportBrief;\n phase: 'inspect' | 'build' | 'review';\n notes: string;\n sourcePlan: string;\n calibration?: SourceCalibration;\n mutationKinds: string[];\n lastAssistantText: string;\n lastToolReport: string;\n analysis: {\n artifactId: string;\n sourceHash: string;\n request: Record<string, unknown>;\n calibration?: { input: Record<string, unknown>; revision: number };\n }[];\n decisions?: CandidateDecision[];\n steering?: ImportInstruction[];\n}\nexport interface CandidateDecision {\n artifactId: string;\n transformId: string;\n floorId: string;\n candidateId: string;\n status: 'accepted' | 'rejected' | 'needs-review';\n modelIds: string[];\n}\n\nexport function readImportCheckpoint(value: unknown): ImportCheckpoint | undefined {\n if (value === undefined) return;\n if (!value || typeof value !== 'object' || JSON.stringify(value).length > 96_000)\n throw new Error('Import checkpoint exceeds the supported size.');\n const c = value as ImportCheckpoint;\n if (c.steering && (!Array.isArray(c.steering) || c.steering.length > 20 || JSON.stringify(c.steering).length > 8000))\n throw new Error('Saved human instructions exceed the supported size.');\n c.steering?.forEach(readImportInstruction);\n const text = (v: unknown, max: number) => typeof v === 'string' && v.length <= max;\n if (\n c.version !== 1 ||\n !text(c.projectId, 200) ||\n !['inspect', 'build', 'review'].includes(c.phase) ||\n !text(c.notes, 3000) ||\n !text(c.sourcePlan, 8000) ||\n !text(c.lastAssistantText, 1200) ||\n !text(c.lastToolReport, 3000) ||\n !Array.isArray(c.mutationKinds) ||\n c.mutationKinds.length > 100 ||\n c.mutationKinds.some(k => !text(k, 100)) ||\n !Array.isArray(c.analysis) ||\n c.analysis.length > 8\n )\n throw new Error('Invalid import checkpoint.');\n for (const a of c.analysis) {\n if (\n !a ||\n !text(a.artifactId, 200) ||\n !/^[a-f0-9]{64}$/.test(a.sourceHash) ||\n !a.request ||\n typeof a.request !== 'object' ||\n Array.isArray(a.request) ||\n (a.calibration &&\n (!Number.isSafeInteger(a.calibration.revision) ||\n a.calibration.revision < 1 ||\n !a.calibration.input ||\n typeof a.calibration.input !== 'object'))\n )\n throw new Error('Invalid analysis checkpoint.');\n }\n if (\n c.calibration &&\n (!text(c.calibration.basis, 500) ||\n !Number.isFinite(c.calibration.metresPerUnit) ||\n c.calibration.metresPerUnit <= 0)\n )\n throw new Error('Invalid saved calibration.');\n if (\n c.decisions &&\n (!Array.isArray(c.decisions) ||\n JSON.stringify(c.decisions).length > 32_000 ||\n c.decisions.some(\n d =>\n !d ||\n ![d.artifactId, d.transformId, d.floorId, d.candidateId].every(s => text(s, 200)) ||\n !['accepted', 'rejected', 'needs-review'].includes(d.status) ||\n !Array.isArray(d.modelIds) ||\n d.modelIds.length > 500 ||\n d.modelIds.some(s => !text(s, 200)),\n ))\n )\n throw new Error('Invalid saved candidate decisions.');\n return { ...c, brief: readImportBrief(c.brief) };\n}\n\nexport interface ImportBudget {\n inputTokens: number;\n outputTokens: number;\n /** Maximum provider turns in this run. Omitted by older hosts: 40. */\n maxTurns?: number;\n}\nexport const DEFAULT_IMPORT_BUDGET: ImportBudget = { inputTokens: 200_000, outputTokens: 24_000, maxTurns: 40 };\nexport function readImportBudget(value: unknown): ImportBudget {\n if (value === undefined) return { ...DEFAULT_IMPORT_BUDGET };\n const b = value as ImportBudget;\n if (\n !b ||\n !Number.isSafeInteger(b.inputTokens) ||\n b.inputTokens < 10_000 ||\n b.inputTokens > 2_000_000 ||\n !Number.isSafeInteger(b.outputTokens) ||\n b.outputTokens < 1000 ||\n b.outputTokens > 100_000\n )\n throw new Error('Import budget must be 10,000–2,000,000 input and 1,000–100,000 output tokens.');\n const maxTurns = b.maxTurns ?? 40;\n if (!Number.isSafeInteger(maxTurns) || maxTurns < 1 || maxTurns > 100)\n throw new Error('Choose a turn limit between 1 and 100 per run. Continue can start another run.');\n return { inputTokens: b.inputTokens, outputTokens: b.outputTokens, maxTurns };\n}\nexport interface ImportPause {\n reason: 'input-budget' | 'output-budget' | 'turn-limit' | 'refusals' | 'repeated-tools';\n message: string;\n}\nexport function readImportPause(value: unknown): ImportPause | undefined {\n if (value === undefined) return;\n const p = value as ImportPause;\n if (\n !p ||\n !['input-budget', 'output-budget', 'turn-limit', 'refusals', 'repeated-tools'].includes(p.reason) ||\n typeof p.message !== 'string' ||\n p.message.length > 2000\n )\n throw new Error('Invalid import pause.');\n return { reason: p.reason, message: p.message };\n}\n"],"names":["readImportCheckpoint","value","c","_a","readImportInstruction","text","v","max","k","a","d","s","readImportBrief","DEFAULT_IMPORT_BUDGET","readImportBudget","b","maxTurns","readImportPause","p"],"mappings":"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"}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import { faceSegments as N, mergeRuns as O } from "./runs.js";
|
|
2
|
+
import { pairWalls as T, closeCorners as D, traceRing as W } from "./walls.js";
|
|
3
|
+
const L = [
|
|
4
|
+
"exteriorFace",
|
|
5
|
+
"interiorFace",
|
|
6
|
+
"partitionFaces",
|
|
7
|
+
"doors",
|
|
8
|
+
"windows",
|
|
9
|
+
"labels",
|
|
10
|
+
"stairs"
|
|
11
|
+
], X = (...h) => new RegExp(`^(${h.map((i) => i.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")).join("|")})$`), k = {
|
|
12
|
+
exteriorFace: /ULKO|EXT|OUTER|A-WALL-EXTR/i,
|
|
13
|
+
interiorFace: /SIS[ÄA]PINTA|INNER|INTERIOR/i,
|
|
14
|
+
partitionFaces: /V[ÄA]LISEIN|PARTITION|SEIN[ÄA]|WALL/i,
|
|
15
|
+
doors: /\bOVI|OVET|DOOR|A-DOOR/i,
|
|
16
|
+
windows: /IKKUNA|WINDOW|A-GLAZ/i,
|
|
17
|
+
labels: /HUONE|ROOM|TUNNUS|NAME|A-AREA-IDEN/i,
|
|
18
|
+
stairs: /PORTA|STAIR|TRAPP|A-FLOR-STRS/i
|
|
19
|
+
}, A = (h, i) => k[i].test(h.layer) ? 0.25 : 0, x = (h) => h.length ? [...h].sort((i, f) => i - f)[Math.floor(h.length / 2)] : 0;
|
|
20
|
+
function K(h) {
|
|
21
|
+
const i = /* @__PURE__ */ new Map();
|
|
22
|
+
for (const e of h) {
|
|
23
|
+
const t = i.get(e.layer) ?? [];
|
|
24
|
+
t.push(e), i.set(e.layer, t);
|
|
25
|
+
}
|
|
26
|
+
const f = [];
|
|
27
|
+
for (const [e, t] of i) {
|
|
28
|
+
const s = {};
|
|
29
|
+
let r = 1 / 0, n = 1 / 0, c = -1 / 0, p = -1 / 0;
|
|
30
|
+
for (const o of t) {
|
|
31
|
+
s[o.type] = (s[o.type] ?? 0) + 1;
|
|
32
|
+
for (const g of [o.a, o.b, o.at, o.center, ...o.points ?? []])
|
|
33
|
+
g && (r = Math.min(r, g[0]), n = Math.min(n, g[1]), c = Math.max(c, g[0]), p = Math.max(p, g[1]));
|
|
34
|
+
}
|
|
35
|
+
const l = N(t, /.*/), u = O(l, 4.6, [0.6, 4.6]), F = T(u, u, 0.04, 0.7, 0.5, "either");
|
|
36
|
+
f.push({
|
|
37
|
+
layer: e,
|
|
38
|
+
entities: t.length,
|
|
39
|
+
types: s,
|
|
40
|
+
width: Number.isFinite(r) ? c - r : 0,
|
|
41
|
+
height: Number.isFinite(n) ? p - n : 0,
|
|
42
|
+
length: l.reduce((o, g) => o + (g.hi - g.lo), 0),
|
|
43
|
+
selfPaired: F.length,
|
|
44
|
+
thickness: x(F.map((o) => o.thickness)),
|
|
45
|
+
scores: {},
|
|
46
|
+
ranked: []
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
const M = new Map(f.map((e) => [e.layer, N(i.get(e.layer), /.*/)])), b = (e) => Math.abs(
|
|
50
|
+
e.reduce((t, s, r) => {
|
|
51
|
+
const n = e[(r + 1) % e.length];
|
|
52
|
+
return t + s[0] * n[1] - n[0] * s[1];
|
|
53
|
+
}, 0) / 2
|
|
54
|
+
), S = (e, t) => {
|
|
55
|
+
const s = e === t ? M.get(e) : [...M.get(e), ...M.get(t)];
|
|
56
|
+
if (s.length < 4) return null;
|
|
57
|
+
const r = O(s, 4.6, [0.6, 4.6]).filter((l) => l.hi - l.lo > 0.8), n = T(r, r, 0.15, 0.7, 0.8, "either");
|
|
58
|
+
if (n.length < 4) return null;
|
|
59
|
+
const c = n.map((l) => ({ ...l, gaps: l.gaps.map((u) => [...u]) }));
|
|
60
|
+
D(c);
|
|
61
|
+
const p = W(c);
|
|
62
|
+
return p ? {
|
|
63
|
+
walls: c,
|
|
64
|
+
ring: p,
|
|
65
|
+
area: b(p),
|
|
66
|
+
thickness: x(c.map((l) => l.thickness))
|
|
67
|
+
} : null;
|
|
68
|
+
}, y = f.filter((e) => e.length > 2 && (e.types.LINE || e.types.POLYLINE)), I = [];
|
|
69
|
+
for (let e = 0; e < y.length; e++)
|
|
70
|
+
for (let t = e; t < y.length; t++) {
|
|
71
|
+
const s = S(y[e].layer, y[t].layer);
|
|
72
|
+
s && I.push({
|
|
73
|
+
a: y[e].layer,
|
|
74
|
+
b: y[t].layer,
|
|
75
|
+
area: s.area,
|
|
76
|
+
thickness: s.thickness,
|
|
77
|
+
ring: s.ring
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
const P = Math.max(0, ...I.map((e) => e.area)), m = I.filter((e) => e.area >= P * 0.9).sort((e, t) => t.thickness - e.thickness)[0] ?? null, a = /* @__PURE__ */ new Map();
|
|
81
|
+
m && (a.set("exteriorFace", m.a), a.set("interiorFace", m.b));
|
|
82
|
+
const R = m == null ? void 0 : m.ring, d = (e) => {
|
|
83
|
+
if (!R) return !0;
|
|
84
|
+
const t = R.map((n) => n[0]), s = R.map((n) => n[1]), r = 2;
|
|
85
|
+
return e.width <= Math.max(...t) - Math.min(...t) + r && e.height <= Math.max(...s) - Math.min(...s) + r;
|
|
86
|
+
}, _ = m ? Math.max(...y.map((e) => e.length)) : 1;
|
|
87
|
+
for (const e of f) {
|
|
88
|
+
const t = Math.max(1, e.entities), s = (e.types.TEXT ?? 0) / t, r = (e.types.ARC ?? 0) / t, n = e.scores;
|
|
89
|
+
e.types.TEXT && s > 0.6 && d(e) && (n.labels = 0.5 * s + 0.2 + A(e, "labels")), (r > 0.02 || k.doors.test(e.layer)) && d(e) && (n.doors = 0.4 * Math.min(1, r * 6) + 0.2 + A(e, "doors")), !e.types.ARC && e.length > 0.5 && e.length < _ * 0.6 && d(e) && e.selfPaired > 0 && (n.windows = 0.25 + 0.15 * Math.min(1, e.selfPaired / 8) + A(e, "windows")), e.selfPaired >= 2 && e.thickness > 0.03 && e.thickness < 0.4 && d(e) && (n.partitionFaces = 0.3 + 0.2 * Math.min(1, e.selfPaired / 10) + A(e, "partitionFaces")), e.ranked = Object.keys(n).sort((c, p) => (n[p] ?? 0) - (n[c] ?? 0));
|
|
90
|
+
}
|
|
91
|
+
for (const e of a.values()) {
|
|
92
|
+
const t = f.find((s) => s.layer === e);
|
|
93
|
+
t && (t.role = t.role ?? (e === a.get("exteriorFace") ? "exteriorFace" : "interiorFace"));
|
|
94
|
+
}
|
|
95
|
+
const U = L.filter((e) => !a.has(e)).flatMap((e) => f.map((t) => ({ role: e, r: t, score: t.scores[e] ?? 0 })).filter((t) => t.score > 0.2)).sort((e, t) => t.score - e.score), E = new Set(a.values());
|
|
96
|
+
for (const e of U)
|
|
97
|
+
a.has(e.role) || E.has(e.r.layer) || (a.set(e.role, e.r.layer), E.add(e.r.layer), e.r.role = e.role);
|
|
98
|
+
const w = { ...$ };
|
|
99
|
+
for (const [e, t] of a) w[e] = X(t);
|
|
100
|
+
return {
|
|
101
|
+
suggested: w,
|
|
102
|
+
layers: f.sort((e, t) => t.entities - e.entities),
|
|
103
|
+
missing: L.filter((e) => !a.has(e))
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
const $ = {
|
|
107
|
+
exteriorFace: /^12_/,
|
|
108
|
+
interiorFace: /^13_/,
|
|
109
|
+
partitionFaces: /^(186_|196_)/,
|
|
110
|
+
doors: /^27_/,
|
|
111
|
+
windows: /^26_/,
|
|
112
|
+
labels: /^55_/,
|
|
113
|
+
stairs: /^82_/
|
|
114
|
+
};
|
|
115
|
+
export {
|
|
116
|
+
L as LAYER_ROLES,
|
|
117
|
+
K as detectLayers,
|
|
118
|
+
X as layerPattern
|
|
119
|
+
};
|
|
120
|
+
//# sourceMappingURL=detect.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"detect.js","sources":["../../../../src/import/detect.ts"],"sourcesContent":["// Which layer carries what, worked out from the drawing rather than from its layer names.\n//\n// The deterministic importer needs six layers named: the two wall faces, the partition faces, doors,\n// windows and room labels. VERTEX_LAYERS names them for the Finnish prefab CAD the importer was\n// built against, and a drawing from any other office silently imports badly — its walls are on\n// layers with other names, so nothing is found and the result is empty or wrong.\n//\n// Names are the weak signal. A door swing is an arc beside a pair of short parallel lines whatever\n// the layer is called; a window is a tight bundle of parallel lines sitting ON the envelope; a room\n// label is text standing inside a room. Geometry is what this reads, with names as a tie-breaker —\n// which also means it catches the case no renaming can fix: one layer carrying both wall faces.\nimport type { PlanEntity, PlanLayerMap } from './types';\nimport { faceSegments, mergeRuns, type FaceSegment } from './runs';\nimport { closeCorners, pairWalls, traceRing, type Wall } from './walls';\n\nexport type LayerRole = keyof PlanLayerMap;\nexport const LAYER_ROLES: LayerRole[] = [\n 'exteriorFace',\n 'interiorFace',\n 'partitionFaces',\n 'doors',\n 'windows',\n 'labels',\n 'stairs',\n];\n\nexport interface LayerReport {\n layer: string;\n entities: number;\n /** Entity counts by DXF type, for the census a person reads. */\n types: Record<string, number>;\n /** Extent in metres. */\n width: number;\n height: number;\n /** Total length of its axis-aligned segments — how much wall it could possibly describe. */\n length: number;\n /** Walls its own runs pair into, and their median thickness. A layer that pairs with itself is\n * carrying both faces, which is the case no amount of renaming fixes. */\n selfPaired: number;\n thickness: number;\n /** 0..1 per role, best first in `ranked`. */\n scores: Partial<Record<LayerRole, number>>;\n ranked: LayerRole[];\n /** The role this layer was assigned, if any. */\n role?: LayerRole;\n}\nexport interface LayerDetection {\n /** Ready to hand to importPlanEntities. Roles nothing matched are left at the Vertex default. */\n suggested: PlanLayerMap;\n layers: LayerReport[];\n /** Roles no layer could be found for — the ones worth asking a person about. */\n missing: LayerRole[];\n}\n\n/** A regex matching exactly this layer. Layer names carry underscores, dots and accented letters. */\nexport const layerPattern = (...names: string[]) =>\n new RegExp(`^(${names.map(n => n.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')).join('|')})$`);\n\nconst NAME_HINTS: Record<LayerRole, RegExp> = {\n exteriorFace: /ULKO|EXT|OUTER|A-WALL-EXTR/i,\n interiorFace: /SIS[ÄA]PINTA|INNER|INTERIOR/i,\n partitionFaces: /V[ÄA]LISEIN|PARTITION|SEIN[ÄA]|WALL/i,\n doors: /\\bOVI|OVET|DOOR|A-DOOR/i,\n windows: /IKKUNA|WINDOW|A-GLAZ/i,\n labels: /HUONE|ROOM|TUNNUS|NAME|A-AREA-IDEN/i,\n stairs: /PORTA|STAIR|TRAPP|A-FLOR-STRS/i,\n};\n\nconst hint = (r: { layer: string }, role: LayerRole) => (NAME_HINTS[role].test(r.layer) ? 0.25 : 0);\nconst median = (xs: number[]) => (xs.length ? [...xs].sort((a, b) => a - b)[Math.floor(xs.length / 2)] : 0);\n\n/** Read every layer's shape, then score each against the six roles. */\nexport function detectLayers(entities: PlanEntity[]): LayerDetection {\n const byLayer = new Map<string, PlanEntity[]>();\n for (const e of entities) {\n const list = byLayer.get(e.layer) ?? [];\n list.push(e);\n byLayer.set(e.layer, list);\n }\n\n const reports: LayerReport[] = [];\n for (const [layer, group] of byLayer) {\n const types: Record<string, number> = {};\n let x0 = Infinity,\n y0 = Infinity,\n x1 = -Infinity,\n y1 = -Infinity;\n for (const e of group) {\n types[e.type] = (types[e.type] ?? 0) + 1;\n for (const p of [e.a, e.b, e.at, e.center, ...(e.points ?? [])])\n if (p) {\n x0 = Math.min(x0, p[0]);\n y0 = Math.min(y0, p[1]);\n x1 = Math.max(x1, p[0]);\n y1 = Math.max(y1, p[1]);\n }\n }\n const segs = faceSegments(group, /.*/);\n const runs = mergeRuns(segs, 4.6, [0.6, 4.6]);\n const paired = pairWalls(runs, runs, 0.04, 0.7, 0.5, 'either');\n reports.push({\n layer,\n entities: group.length,\n types,\n width: Number.isFinite(x0) ? x1 - x0 : 0,\n height: Number.isFinite(y0) ? y1 - y0 : 0,\n length: segs.reduce((s, x) => s + (x.hi - x.lo), 0),\n selfPaired: paired.length,\n thickness: median(paired.map(w => w.thickness)),\n scores: {},\n ranked: [],\n });\n }\n\n // Wall faces are not found by length — furniture and title blocks have plenty. They are found by\n // PAIRING: a wall is drawn as two parallel faces a plausible thickness apart, and the outer walls\n // of a storey close into a loop. Trying every pair of layers and keeping the pairings that trace a\n // ring is what tells a wall layer from a row of kitchen cabinets, which pair happily and close\n // into nothing.\n const segs = new Map<string, FaceSegment[]>(reports.map(r => [r.layer, faceSegments(byLayer.get(r.layer)!, /.*/)]));\n const ringArea = (ring: [number, number][]) =>\n Math.abs(\n ring.reduce((sum, p, i) => {\n const q = ring[(i + 1) % ring.length];\n return sum + p[0] * q[1] - q[0] * p[1];\n }, 0) / 2,\n );\n const envelopeOf = (a: string, b: string) => {\n const pool = a === b ? segs.get(a)! : [...segs.get(a)!, ...segs.get(b)!];\n if (pool.length < 4) return null;\n const runs = mergeRuns(pool, 4.6, [0.6, 4.6]).filter(r => r.hi - r.lo > 0.8);\n // The same window reconstructWalls uses for the envelope. Opening it wider lets a face pair with\n // the line drawn a few millimetres beside it — a sheathing line, a hatch edge — instead of with\n // the face across the wall, and the thin walls that come out do not close into anything.\n const walls: Wall[] = pairWalls(runs, runs, 0.15, 0.7, 0.8, 'either');\n if (walls.length < 4) return null;\n const copy = walls.map(w => ({ ...w, gaps: w.gaps.map(g => [...g] as [number, number]) }));\n closeCorners(copy);\n const ring = traceRing(copy);\n if (!ring) return null;\n return {\n walls: copy,\n ring,\n area: ringArea(ring as [number, number][]),\n thickness: median(copy.map(w => w.thickness)),\n };\n };\n\n const faceish = reports.filter(r => r.length > 2 && (r.types.LINE || r.types.POLYLINE));\n const rings: { a: string; b: string; area: number; thickness: number; ring: [number, number][] }[] = [];\n for (let i = 0; i < faceish.length; i++)\n for (let j = i; j < faceish.length; j++) {\n const found = envelopeOf(faceish[i].layer, faceish[j].layer);\n if (found)\n rings.push({\n a: faceish[i].layer,\n b: faceish[j].layer,\n area: found.area,\n thickness: found.thickness,\n ring: found.ring as [number, number][],\n });\n }\n // Every pairing that closes traces very nearly the same outline — they differ by which line of the\n // wall each took, a few centimetres apart, so area alone cannot choose between them. What separates\n // the true faces from a hatch edge or a stud line is thickness: the outer wall is the thickest\n // thing on the plan. Take the biggest outlines, then the thickest wall among them.\n const widest = Math.max(0, ...rings.map(r => r.area));\n const envelope = rings.filter(r => r.area >= widest * 0.9).sort((x, y) => y.thickness - x.thickness)[0] ?? null;\n\n const chosen = new Map<LayerRole, string>();\n if (envelope) {\n chosen.set('exteriorFace', envelope.a);\n chosen.set('interiorFace', envelope.b); // equal to `a` when one layer carries both faces\n }\n const ring = envelope?.ring;\n const within = (r: LayerReport) => {\n if (!ring) return true;\n const xs = ring.map(p => p[0]),\n ys = ring.map(p => p[1]);\n const pad = 2;\n return r.width <= Math.max(...xs) - Math.min(...xs) + pad && r.height <= Math.max(...ys) - Math.min(...ys) + pad;\n };\n const planLength = envelope ? Math.max(...faceish.map(r => r.length)) : 1;\n\n for (const r of reports) {\n const total = Math.max(1, r.entities);\n const text = (r.types.TEXT ?? 0) / total;\n const arcs = (r.types.ARC ?? 0) / total;\n const s = r.scores;\n // Labels: text standing inside the plan, not the sheet's own annotation blocks.\n if (r.types.TEXT && text > 0.6 && within(r)) s.labels = 0.5 * text + 0.2 + hint(r, 'labels');\n // Doors: a swing arc beside a pair of short lines is unmistakable whatever the layer is called.\n if ((arcs > 0.02 || NAME_HINTS.doors.test(r.layer)) && within(r))\n s.doors = 0.4 * Math.min(1, arcs * 6) + 0.2 + hint(r, 'doors');\n // Windows: parallel bundles with no arcs, spread along the envelope but adding up to far less\n // wall than a face layer does.\n if (!r.types.ARC && r.length > 0.5 && r.length < planLength * 0.6 && within(r) && r.selfPaired > 0)\n s.windows = 0.25 + 0.15 * Math.min(1, r.selfPaired / 8) + hint(r, 'windows');\n // Partitions: layers that pair into walls of their own, inside the envelope, but do not close a\n // loop the size of the building.\n if (r.selfPaired >= 2 && r.thickness > 0.03 && r.thickness < 0.4 && within(r))\n s.partitionFaces = 0.3 + 0.2 * Math.min(1, r.selfPaired / 10) + hint(r, 'partitionFaces');\n r.ranked = (Object.keys(s) as LayerRole[]).sort((a, b) => (s[b] ?? 0) - (s[a] ?? 0));\n }\n for (const layer of chosen.values()) {\n const r = reports.find(x => x.layer === layer);\n if (r) r.role = r.role ?? (layer === chosen.get('exteriorFace') ? 'exteriorFace' : 'interiorFace');\n }\n\n // Assign the rest, strongest claim first, so a layer that is clearly a door layer is not spent on\n // being a mediocre partition layer.\n const claims = LAYER_ROLES.filter(role => !chosen.has(role))\n .flatMap(role => reports.map(r => ({ role, r, score: r.scores[role] ?? 0 })).filter(c => c.score > 0.2))\n .sort((a, b) => b.score - a.score);\n const taken = new Set<string>(chosen.values());\n for (const c of claims) {\n if (chosen.has(c.role) || taken.has(c.r.layer)) continue;\n chosen.set(c.role, c.r.layer);\n taken.add(c.r.layer);\n c.r.role = c.role;\n }\n\n const suggested: PlanLayerMap = { ...DEFAULTS };\n for (const [role, layer] of chosen) suggested[role] = layerPattern(layer);\n return {\n suggested,\n layers: reports.sort((a, b) => b.entities - a.entities),\n missing: LAYER_ROLES.filter(role => !chosen.has(role)),\n };\n}\n\n// Falling back to the Vertex names for a role nothing matched is better than falling back to\n// nothing: on a Vertex drawing with one odd layer, the other five still work.\nconst DEFAULTS: PlanLayerMap = {\n exteriorFace: /^12_/,\n interiorFace: /^13_/,\n partitionFaces: /^(186_|196_)/,\n doors: /^27_/,\n windows: /^26_/,\n labels: /^55_/,\n stairs: /^82_/,\n};\n"],"names":["LAYER_ROLES","layerPattern","names","n","NAME_HINTS","hint","r","role","median","xs","a","b","detectLayers","entities","byLayer","list","reports","layer","group","types","x0","y0","x1","y1","e","p","segs","faceSegments","runs","mergeRuns","paired","pairWalls","s","x","w","ringArea","ring","sum","i","q","envelopeOf","pool","walls","copy","g","closeCorners","traceRing","faceish","rings","j","found","widest","envelope","y","chosen","within","ys","pad","planLength","total","text","arcs","claims","c","taken","suggested","DEFAULTS"],"mappings":"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"}
|