@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
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
function t(e, n) {
|
|
2
|
+
return n.code ? n.code : n.mezzanine ? "M" : n.elevation < 0 ? "B" + e.floors.filter(
|
|
3
|
+
(i) => i.buildingId === n.buildingId && !i.mezzanine && i.elevation < 0 && i.elevation >= n.elevation
|
|
4
|
+
).length : String(
|
|
5
|
+
e.floors.filter(
|
|
6
|
+
(i) => i.buildingId === n.buildingId && !i.mezzanine && i.elevation >= 0 && i.elevation < n.elevation
|
|
7
|
+
).length
|
|
8
|
+
).padStart(2, "0");
|
|
9
|
+
}
|
|
10
|
+
function d(e, n) {
|
|
11
|
+
const i = e.floors.find((l) => l.id === n);
|
|
12
|
+
return e.floors.filter((l) => l.buildingId === ((i == null ? void 0 : i.buildingId) ?? e.buildings[0].id)).sort((l, o) => l.elevation - o.elevation);
|
|
13
|
+
}
|
|
14
|
+
export {
|
|
15
|
+
d as floorBand,
|
|
16
|
+
t as floorCode
|
|
17
|
+
};
|
|
18
|
+
//# sourceMappingURL=floors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"floors.js","sources":["../../../../src/planner/floors.ts"],"sourcesContent":["import type { Floor, ProjectDocument } from '../model/types';\n\nexport function floorCode(project: ProjectDocument, f: Floor) {\n if (f.code) return f.code;\n return f.mezzanine\n ? 'M'\n : f.elevation < 0\n ? 'B' +\n project.floors.filter(\n x => x.buildingId === f.buildingId && !x.mezzanine && x.elevation < 0 && x.elevation >= f.elevation,\n ).length\n : String(\n project.floors.filter(\n x => x.buildingId === f.buildingId && !x.mezzanine && x.elevation >= 0 && x.elevation < f.elevation,\n ).length,\n ).padStart(2, '0');\n}\n\nexport function floorBand(project: ProjectDocument, floorId: string | null) {\n const floor = project.floors.find(f => f.id === floorId);\n return project.floors\n .filter(f => f.buildingId === (floor?.buildingId ?? project.buildings[0].id))\n .sort((a, b) => a.elevation - b.elevation);\n}\n"],"names":["floorCode","project","f","x","floorBand","floorId","floor","a","b"],"mappings":"AAEO,SAASA,EAAUC,GAA0BC,GAAU;AAC5D,SAAIA,EAAE,OAAaA,EAAE,OACdA,EAAE,YACL,MACAA,EAAE,YAAY,IACZ,MACAD,EAAQ,OAAO;AAAA,IACb,CAAAE,MAAKA,EAAE,eAAeD,EAAE,cAAc,CAACC,EAAE,aAAaA,EAAE,YAAY,KAAKA,EAAE,aAAaD,EAAE;AAAA,EAAA,EAC1F,SACF;AAAA,IACED,EAAQ,OAAO;AAAA,MACb,CAAAE,MAAKA,EAAE,eAAeD,EAAE,cAAc,CAACC,EAAE,aAAaA,EAAE,aAAa,KAAKA,EAAE,YAAYD,EAAE;AAAA,IAAA,EAC1F;AAAA,EAAA,EACF,SAAS,GAAG,GAAG;AACzB;AAEO,SAASE,EAAUH,GAA0BI,GAAwB;AAC1E,QAAMC,IAAQL,EAAQ,OAAO,KAAK,CAAAC,MAAKA,EAAE,OAAOG,CAAO;AACvD,SAAOJ,EAAQ,OACZ,OAAO,CAAAC,MAAKA,EAAE,iBAAgBI,KAAA,gBAAAA,EAAO,eAAcL,EAAQ,UAAU,CAAC,EAAE,GAAG,EAC3E,KAAK,CAACM,GAAGC,MAAMD,EAAE,YAAYC,EAAE,SAAS;AAC7C;"}
|
|
@@ -0,0 +1,341 @@
|
|
|
1
|
+
import { useState as k, useRef as vt, useMemo as xt } from "react";
|
|
2
|
+
import { applyGeometryDrag as $t, drawBarrier as I, encloseRoom as kt, endsBoundaryStroke as yt, appendAreaPoint as Pt } from "../model/authoring.js";
|
|
3
|
+
import { boundaryRegionAt as At, drawVirtualBoundary as Rt, addBoundaryHole as Nt, connectSpace as Ot } from "../model/boundaries.js";
|
|
4
|
+
import { draggedDoorSwing as jt } from "../model/doors.js";
|
|
5
|
+
import { createObject as T } from "../model/factory.js";
|
|
6
|
+
import { distance as tt, snapPoint as nt, centroid as V, closeRing as W, addBarrier as Et, objectArea as _, rectangle as et, pointInRing as St, splitRoom as Tt, objectPosition as zt } from "../model/geometry.js";
|
|
7
|
+
import { chainVertical as Bt, addNavNode as ot, addNavEdge as Dt } from "../model/navigation.js";
|
|
8
|
+
import { transformObject as Ft } from "../model/project.js";
|
|
9
|
+
import { uid as it, isOpening as Ht, isDevice as Lt, isArea as Ct } from "../model/types.js";
|
|
10
|
+
import { fitOpening as J, snapDragPoint as qt, proposeWall as st, mainAxis as rt } from "../model/walls.js";
|
|
11
|
+
const Gt = /* @__PURE__ */ new Set(["Parallel", "Square", "15°", "30°", "45°", "60°", "75°"]), Vt = { door: 0.9, window: 1.2, gate: 3.5 }, Wt = [
|
|
12
|
+
"door",
|
|
13
|
+
"window",
|
|
14
|
+
"gate",
|
|
15
|
+
"turnstile",
|
|
16
|
+
"reader",
|
|
17
|
+
"camera",
|
|
18
|
+
"elevator",
|
|
19
|
+
"stairs",
|
|
20
|
+
"office",
|
|
21
|
+
"container",
|
|
22
|
+
"storage",
|
|
23
|
+
"poi",
|
|
24
|
+
"sensor",
|
|
25
|
+
"light",
|
|
26
|
+
"alarm",
|
|
27
|
+
"equipment"
|
|
28
|
+
];
|
|
29
|
+
function nn({
|
|
30
|
+
project: m,
|
|
31
|
+
floorId: g,
|
|
32
|
+
selected: K,
|
|
33
|
+
editing: N,
|
|
34
|
+
threeD: z,
|
|
35
|
+
commit: M,
|
|
36
|
+
notify: A,
|
|
37
|
+
setSelected: O,
|
|
38
|
+
onSelect: at,
|
|
39
|
+
onFloorChange: ct,
|
|
40
|
+
onChooseTool: lt
|
|
41
|
+
}) {
|
|
42
|
+
const [s, y] = k("select"), [p, w] = k([]), [P, D] = k(null), [B, F] = k(null), [H, Q] = k(null), [U, ut] = k(!1), [dt, ft] = k(""), [R, ht] = k(!0), [L, C] = k(null), j = vt(0.7);
|
|
43
|
+
function gt(e) {
|
|
44
|
+
if (e === "hole") {
|
|
45
|
+
const r = m.objects.find((i) => i.id === K);
|
|
46
|
+
if (!(r != null && r.rings)) {
|
|
47
|
+
A("Select an area first, then use Cut a hole.");
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
y(e), w([]), F(null), Q(null), lt(), C(null);
|
|
52
|
+
}
|
|
53
|
+
function E(e, r) {
|
|
54
|
+
M((i) => Ft(i.objects.find((f) => f.id === e), r));
|
|
55
|
+
}
|
|
56
|
+
function q() {
|
|
57
|
+
if (s === "wall" || s === "boundary" || s === "fence" || s === "measure") {
|
|
58
|
+
w([]), y("select");
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
if (!["zone", "room", "hole", "evacuation"].includes(s) || p.length < 3) {
|
|
62
|
+
A("Add at least three points to finish an area.");
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
const e = [W(p)];
|
|
66
|
+
M((i) => {
|
|
67
|
+
var f;
|
|
68
|
+
if (s === "hole") {
|
|
69
|
+
const n = i.objects.find((a) => a.id === K);
|
|
70
|
+
if (!(n != null && n.rings)) throw new Error("Select an area first.");
|
|
71
|
+
((f = n.geometry) == null ? void 0 : f.mode) === "boundaries" ? Nt(i, n, e[0]) : n.rings.push(e[0]);
|
|
72
|
+
} else {
|
|
73
|
+
const n = T(s, V(p), g);
|
|
74
|
+
n.rings = e;
|
|
75
|
+
const a = p.map((t) => t[0]), c = p.map((t) => t[1]);
|
|
76
|
+
n.width = Math.max(...a) - Math.min(...a), n.depth = Math.max(...c) - Math.min(...c), i.objects.push(n), s === "room" && Ot(i, n.id), O(n.id);
|
|
77
|
+
}
|
|
78
|
+
}) && (w([]), y("select"));
|
|
79
|
+
}
|
|
80
|
+
function pt(e, r) {
|
|
81
|
+
if (!N || s === "select" || z) {
|
|
82
|
+
at(r);
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
if (s === "pan") return;
|
|
86
|
+
if (s === "partition") {
|
|
87
|
+
const a = st(m, g, e);
|
|
88
|
+
a && M((c) => {
|
|
89
|
+
I(c, g, a.segment[0], a.segment[1]);
|
|
90
|
+
}), F(null);
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
if (s === "enclose") {
|
|
94
|
+
if (!At(m, g, e)) {
|
|
95
|
+
A("Nothing encloses that point. The walls around it have a gap, or it is outside the building.");
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
let c = !1, t = "", l = 0, o = !1;
|
|
99
|
+
M((b) => {
|
|
100
|
+
const u = kt(b, g, e);
|
|
101
|
+
u && (o = !0, c = u.existing, t = u.room.name, l = _(u.room), O(u.room.id));
|
|
102
|
+
}) && o && A(
|
|
103
|
+
c ? `“${t}” follows its boundaries · ${l.toFixed(1)} m²` : `Space follows its boundaries · ${l.toFixed(1)} m²`
|
|
104
|
+
);
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
const i = p.at(-1), f = R && i ? rt(m, g) : 0, n = R ? nt(m, g, e, j.current, i, !0, f).point : e;
|
|
108
|
+
if (s === "wall" || s === "fence" || s === "boundary") {
|
|
109
|
+
if (!i) {
|
|
110
|
+
w([n]);
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
const a = yt(m, g, i, n, s);
|
|
114
|
+
let c = !1;
|
|
115
|
+
M((t) => {
|
|
116
|
+
c = !!(s === "boundary" ? Rt(t, g, i, n) : I(t, g, i, n, s));
|
|
117
|
+
}) && (c && a ? q() : w([n]));
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
if (s === "rectangle") {
|
|
121
|
+
if (!p.length) {
|
|
122
|
+
w([n]);
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
const a = p[0];
|
|
126
|
+
M((c) => {
|
|
127
|
+
const t = T("zone", [(a[0] + n[0]) / 2, (a[1] + n[1]) / 2], g, "New area");
|
|
128
|
+
t.width = Math.abs(a[0] - n[0]), t.depth = Math.abs(a[1] - n[1]), t.rings = [et(t.position, t.width, t.depth)], c.objects.push(t), O(t.id);
|
|
129
|
+
}) && (w([]), y("select"));
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
if (["zone", "room", "hole", "evacuation"].includes(s)) {
|
|
133
|
+
if (p.length >= 3 && tt(n, p[0]) < j.current) q();
|
|
134
|
+
else {
|
|
135
|
+
const a = Pt(p, n);
|
|
136
|
+
w(a.points), a.error && A(a.error);
|
|
137
|
+
}
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
if (s === "measure") {
|
|
141
|
+
w(p.length >= 2 ? [n] : [...p, n]);
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
if (s === "split") {
|
|
145
|
+
if (!p.length) {
|
|
146
|
+
w([n]);
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
const a = [(p[0][0] + n[0]) / 2, (p[0][1] + n[1]) / 2], c = m.objects.filter(
|
|
150
|
+
(t) => t.floorId === g && (t.kind === "room" || t.kind === "zone") && t.rings && St(a, t.rings[0])
|
|
151
|
+
).sort((t, l) => _(t) - _(l))[0];
|
|
152
|
+
if (!c) {
|
|
153
|
+
A("Draw the cut across a room — you can start and end past the walls.");
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
M((t) => {
|
|
157
|
+
const l = Tt(t, c.id, p[0], n);
|
|
158
|
+
O(l);
|
|
159
|
+
}) && (w([]), y("select"));
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
if (s === "route") {
|
|
163
|
+
const a = r ? m.objects.find((l) => l.id === r) : void 0;
|
|
164
|
+
let c = null;
|
|
165
|
+
M((l) => {
|
|
166
|
+
const o = a ? l.objects.find((u) => u.id === a.id) : void 0;
|
|
167
|
+
let d;
|
|
168
|
+
if (o && (o.kind === "elevator" || o.kind === "stairs")) {
|
|
169
|
+
if (d = Bt(l, o).find((h) => h.floorId === g), !d)
|
|
170
|
+
throw new Error(`${o.name} does not serve this floor — set its served floors in the properties panel.`);
|
|
171
|
+
} else o && ["door", "gate", "turnstile", "poi", "room"].includes(o.kind) ? d = ot(l, o.floorId, zt(l, o), o.id) : d = ot(l, g, n);
|
|
172
|
+
const b = L ? (l.navNodes ?? []).find((u) => u.id === L) : void 0;
|
|
173
|
+
if (b && b.id !== d.id) {
|
|
174
|
+
const u = (x) => {
|
|
175
|
+
const v = x.objectId ? l.objects.find((S) => S.id === x.objectId) : void 0;
|
|
176
|
+
return v && ["door", "gate", "turnstile"].includes(v.kind) ? v : void 0;
|
|
177
|
+
}, h = u(b) ?? u(d);
|
|
178
|
+
Dt(l, h ? "door" : "walk", b, d, h == null ? void 0 : h.id);
|
|
179
|
+
}
|
|
180
|
+
c = d.id;
|
|
181
|
+
}) && C(c);
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
Wt.includes(s) && M((c) => {
|
|
185
|
+
const t = T(s, n, g);
|
|
186
|
+
if (Ht(t.kind)) {
|
|
187
|
+
const l = J(c, g, t.kind, e, t.width, X());
|
|
188
|
+
if (!l) throw new Error(`Place this ${t.kind} on a ${t.kind === "gate" ? "fence" : "wall"}.`);
|
|
189
|
+
t.barrierId = l.barrierId, t.offset = l.offset, t.position = l.position;
|
|
190
|
+
}
|
|
191
|
+
Lt(t.kind) && (t.feedId = `device-${t.id}`), Ct(t.kind) && (t.rings = [et(t.position, t.width, t.depth)]), c.objects.push(t), O(t.id);
|
|
192
|
+
}) && y("select");
|
|
193
|
+
}
|
|
194
|
+
function bt({
|
|
195
|
+
rings: e,
|
|
196
|
+
sourceId: r,
|
|
197
|
+
storeys: i,
|
|
198
|
+
name: f
|
|
199
|
+
}) {
|
|
200
|
+
let n = "";
|
|
201
|
+
M((c) => {
|
|
202
|
+
if (c.buildings.some((h) => h.sourceId === r))
|
|
203
|
+
throw new Error("That building is already part of this project.");
|
|
204
|
+
const t = it();
|
|
205
|
+
c.buildings.push({ id: t, name: f, sourceId: r });
|
|
206
|
+
const l = e[0], o = l.map((h) => h[0]), d = l.map((h) => h[1]), b = () => e.map((h) => W(h.map((x) => [...x]))), u = T("building", V(l), null, f);
|
|
207
|
+
u.rings = b(), u.width = Math.max(...o) - Math.min(...o), u.depth = Math.max(...d) - Math.min(...d), c.objects.push(u);
|
|
208
|
+
for (let h = 0; h < i; h++) {
|
|
209
|
+
const x = it();
|
|
210
|
+
h || (n = x), c.floors.push({
|
|
211
|
+
id: x,
|
|
212
|
+
buildingId: t,
|
|
213
|
+
name: `${f} · ${h ? `floor ${h}` : "ground"}`,
|
|
214
|
+
elevation: h * 3.5,
|
|
215
|
+
height: 3.5
|
|
216
|
+
});
|
|
217
|
+
const v = T("zone", V(l), x, f);
|
|
218
|
+
v.rings = b(), v.width = u.width, v.depth = u.depth, v.color = "#f7f8f6", c.objects.push(v);
|
|
219
|
+
const S = c.barriers.length, G = W(l.map(($) => [...$]));
|
|
220
|
+
for (let $ = 1; $ < G.length; $++) Et(c, G[$ - 1], G[$], x, "wall");
|
|
221
|
+
c.barriers.slice(S).forEach(($) => {
|
|
222
|
+
$.name = "Facade wall", $.thickness = 0.45, $.color = "#a6acb8";
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
}) && (y("select"), n && ct(n), A(
|
|
226
|
+
`Adopted “${f}” from the basemap · ${i} floor${i > 1 ? "s" : ""} created from MML attributes.`
|
|
227
|
+
));
|
|
228
|
+
}
|
|
229
|
+
const X = () => Math.max(2, j.current * 2), Y = (e) => e === "door" || e === "window" || e === "gate", mt = (e, r) => {
|
|
230
|
+
if (j.current = r, s === "select" || s === "pan" || z || !N) return;
|
|
231
|
+
if (Y(s)) {
|
|
232
|
+
D(e), Q(J(m, g, s, e, Vt[s] ?? 0.9, X()));
|
|
233
|
+
return;
|
|
234
|
+
}
|
|
235
|
+
if (s === "partition") {
|
|
236
|
+
D(e), F(st(m, g, e));
|
|
237
|
+
return;
|
|
238
|
+
}
|
|
239
|
+
const i = p.at(-1), f = R && i ? rt(m, g) : null, n = R ? nt(m, g, e, r, i, !0, f ?? 0) : { point: e, label: "" }, a = f !== null && Gt.has(n.label);
|
|
240
|
+
D(n.point), ut(a), ft(a ? `${n.label} to floor axis` : n.label);
|
|
241
|
+
}, Mt = xt(() => {
|
|
242
|
+
if (!N || z) return [];
|
|
243
|
+
if (Y(s)) return H ? [{ line: H.span, role: "proposal" }] : [];
|
|
244
|
+
if (s === "partition") return B ? [{ line: B.segment, role: "proposal" }] : [];
|
|
245
|
+
const e = p.at(-1);
|
|
246
|
+
if (!U || !e || !P) return [];
|
|
247
|
+
const r = tt(e, P);
|
|
248
|
+
if (r < 0.01) return [];
|
|
249
|
+
const i = (P[0] - e[0]) / r, f = (P[1] - e[1]) / r, n = 8;
|
|
250
|
+
return [
|
|
251
|
+
{
|
|
252
|
+
line: [
|
|
253
|
+
[e[0] - i * n, e[1] - f * n],
|
|
254
|
+
[P[0] + i * n, P[1] + f * n]
|
|
255
|
+
],
|
|
256
|
+
role: "guide"
|
|
257
|
+
}
|
|
258
|
+
];
|
|
259
|
+
}, [N, z, s, B, H, p, P, U]), Z = (e, r, i, f = !1, n = 0, a = 0) => qt(m, g, e, r, i, R && !f, j.current, n, a);
|
|
260
|
+
function wt(e, r, i, f = 0, n = 0, a = !1) {
|
|
261
|
+
const c = R && !a, t = c ? [Math.round(i[0] * 2) / 2, Math.round(i[1] * 2) / 2] : i;
|
|
262
|
+
if (e === "object") {
|
|
263
|
+
E(r, { position: t });
|
|
264
|
+
return;
|
|
265
|
+
}
|
|
266
|
+
if (e === "opening") {
|
|
267
|
+
const o = m.objects.find((u) => u.id === r), d = m.barriers.find((u) => u.id === (o == null ? void 0 : o.barrierId));
|
|
268
|
+
if (!o || !d) return;
|
|
269
|
+
const b = J(
|
|
270
|
+
{ ...m, barriers: [d] },
|
|
271
|
+
o.floorId,
|
|
272
|
+
o.kind,
|
|
273
|
+
i,
|
|
274
|
+
o.width,
|
|
275
|
+
1 / 0,
|
|
276
|
+
r
|
|
277
|
+
);
|
|
278
|
+
b && E(r, {
|
|
279
|
+
offset: b.offset,
|
|
280
|
+
position: b.position,
|
|
281
|
+
...o.kind === "door" ? { doorSwing: jt(m, o, i) } : {}
|
|
282
|
+
});
|
|
283
|
+
return;
|
|
284
|
+
}
|
|
285
|
+
if (e === "rotate") {
|
|
286
|
+
const o = m.objects.find((b) => b.id === r);
|
|
287
|
+
if (!o) return;
|
|
288
|
+
const d = Math.atan2(i[1] - o.position[1], i[0] - o.position[0]) * 180 / Math.PI;
|
|
289
|
+
E(r, { rotation: c ? Math.round(d / 15) * 15 : Math.round(d * 10) / 10 });
|
|
290
|
+
return;
|
|
291
|
+
}
|
|
292
|
+
if (e === "coverage") {
|
|
293
|
+
const o = m.objects.find((S) => S.id === r);
|
|
294
|
+
if (!o) return;
|
|
295
|
+
const d = i[0] - o.position[0], b = i[1] - o.position[1], u = Math.max(1, Math.min(120, Math.hypot(d, b))), h = Math.atan2(b, d) * 180 / Math.PI, x = Math.abs(((h - (o.rotation ?? 0)) % 360 + 540) % 360 - 180), v = Math.max(10, Math.min(350, x * 2));
|
|
296
|
+
E(r, {
|
|
297
|
+
coverageRange: Math.round(u * 10) / 10,
|
|
298
|
+
coverageAngle: c ? Math.round(v / 5) * 5 : Math.round(v)
|
|
299
|
+
});
|
|
300
|
+
return;
|
|
301
|
+
}
|
|
302
|
+
if (e === "node") {
|
|
303
|
+
M((o) => {
|
|
304
|
+
const d = (o.navNodes ?? []).find((b) => b.id === r);
|
|
305
|
+
d && (d.position = t);
|
|
306
|
+
});
|
|
307
|
+
return;
|
|
308
|
+
}
|
|
309
|
+
if (!N) return;
|
|
310
|
+
const l = Z(e, r, i, a, f, n);
|
|
311
|
+
M(
|
|
312
|
+
(o) => $t(o, e === "ring" ? { kind: e, id: r, point: l, ringIndex: f, index: n } : { kind: e, id: r, point: l })
|
|
313
|
+
);
|
|
314
|
+
}
|
|
315
|
+
return {
|
|
316
|
+
tool: s,
|
|
317
|
+
setTool: y,
|
|
318
|
+
draft: p,
|
|
319
|
+
setDraft: w,
|
|
320
|
+
hover: P,
|
|
321
|
+
proposal: B,
|
|
322
|
+
snapLabel: dt,
|
|
323
|
+
snapping: R,
|
|
324
|
+
setSnapping: ht,
|
|
325
|
+
routeAnchor: L,
|
|
326
|
+
setRouteAnchor: C,
|
|
327
|
+
chooseTool: gt,
|
|
328
|
+
finish: q,
|
|
329
|
+
mapClick: pt,
|
|
330
|
+
adoptBuilding: bt,
|
|
331
|
+
onHover: mt,
|
|
332
|
+
guides: Mt,
|
|
333
|
+
geometryPreview: Z,
|
|
334
|
+
vertexMove: wt,
|
|
335
|
+
updateObject: E
|
|
336
|
+
};
|
|
337
|
+
}
|
|
338
|
+
export {
|
|
339
|
+
nn as useDrawingTools
|
|
340
|
+
};
|
|
341
|
+
//# sourceMappingURL=useDrawingTools.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useDrawingTools.js","sources":["../../../../src/planner/useDrawingTools.ts"],"sourcesContent":["import { useMemo, useRef, useState } from 'react';\nimport {\n appendAreaPoint,\n applyGeometryDrag,\n drawBarrier,\n encloseRoom,\n endsBoundaryStroke,\n type GeometryDrag,\n} from '../model/authoring';\nimport { addBoundaryHole, boundaryRegionAt, connectSpace, drawVirtualBoundary } from '../model/boundaries';\nimport { draggedDoorSwing } from '../model/doors';\nimport { createObject } from '../model/factory';\nimport {\n addBarrier,\n centroid,\n closeRing,\n distance,\n objectArea,\n objectPosition,\n pointInRing,\n rectangle,\n snapPoint,\n splitRoom,\n} from '../model/geometry';\nimport { addNavEdge, addNavNode, chainVertical } from '../model/navigation';\nimport { transformObject } from '../model/project';\nimport type { NavNode, ObjectKind, Point, ProjectDocument, SiteObject, Tool } from '../model/types';\nimport { isArea, isDevice, isOpening, uid } from '../model/types';\nimport { fitOpening, mainAxis, proposeWall, snapDragPoint, type OpeningFit, type WallProposal } from '../model/walls';\nimport type { CommitProject } from './types';\n\ninterface DrawingToolsOptions {\n project: ProjectDocument;\n floorId: string | null;\n selected: string | null;\n editing: boolean;\n threeD: boolean;\n commit: CommitProject;\n notify: (message: string) => void;\n setSelected: (id: string | null) => void;\n onSelect: (id: string | null) => void;\n onFloorChange: (id: string | null) => void;\n onChooseTool: () => void;\n}\n\n/** Snap labels that mean \"an angle is being held\", and so deserve naming what it is held to. */\nconst HELD = new Set(['Parallel', 'Square', '15°', '30°', '45°', '60°', '75°']);\n/** Default leaf widths, so the preview can size itself before the object exists. Matches factory.ts. */\nconst OPENING_WIDTH: Record<string, number> = { door: 0.9, window: 1.2, gate: 3.5 };\nconst PLACE_TOOLS: Tool[] = [\n 'door',\n 'window',\n 'gate',\n 'turnstile',\n 'reader',\n 'camera',\n 'elevator',\n 'stairs',\n 'office',\n 'container',\n 'storage',\n 'poi',\n 'sensor',\n 'light',\n 'alarm',\n 'equipment',\n];\n/**\n * Owns in-progress drawing and handle gestures. Previews only calculate geometry;\n * completed edits go through the planner's validated history transaction.\n */\nexport function useDrawingTools({\n project,\n floorId,\n selected,\n editing,\n threeD,\n commit,\n notify,\n setSelected,\n onSelect,\n onFloorChange,\n onChooseTool,\n}: DrawingToolsOptions) {\n const [tool, setTool] = useState<Tool>('select');\n const [draft, setDraft] = useState<Point[]>([]);\n const [hover, setHover] = useState<Point | null>(null);\n const [proposal, setProposal] = useState<WallProposal | null>(null);\n const [openingFit, setOpeningFit] = useState<OpeningFit | null>(null);\n const [held, setHeld] = useState(false);\n const [snapLabel, setSnapLabel] = useState('');\n const [snapping, setSnapping] = useState(true);\n const [routeAnchor, setRouteAnchor] = useState<string | null>(null);\n const toleranceRef = useRef(0.7);\n function chooseTool(next: Tool) {\n if (next === 'hole') {\n const o = project.objects.find(o => o.id === selected);\n if (!o?.rings) {\n notify('Select an area first, then use Cut a hole.');\n return;\n }\n }\n setTool(next);\n setDraft([]);\n setProposal(null);\n setOpeningFit(null);\n onChooseTool();\n setRouteAnchor(null);\n }\n function updateObject(id: string, patch: Partial<SiteObject>) {\n commit(p => transformObject(p.objects.find(o => o.id === id)!, patch));\n }\n function finish() {\n if (tool === 'wall' || tool === 'boundary' || tool === 'fence' || tool === 'measure') {\n setDraft([]);\n setTool('select');\n return;\n }\n if (!['zone', 'room', 'hole', 'evacuation'].includes(tool) || draft.length < 3) {\n notify('Add at least three points to finish an area.');\n return;\n }\n const rings = [closeRing(draft)];\n const success = commit(p => {\n if (tool === 'hole') {\n const o = p.objects.find(o => o.id === selected);\n if (!o?.rings) throw new Error('Select an area first.');\n if (o.geometry?.mode === 'boundaries') addBoundaryHole(p, o, rings[0]);\n else o.rings.push(rings[0]);\n } else {\n const object = createObject(tool as ObjectKind, centroid(draft), floorId);\n object.rings = rings;\n const xs = draft.map(p => p[0]),\n ys = draft.map(p => p[1]);\n object.width = Math.max(...xs) - Math.min(...xs);\n object.depth = Math.max(...ys) - Math.min(...ys);\n p.objects.push(object);\n if (tool === 'room') connectSpace(p, object.id);\n setSelected(object.id);\n }\n });\n if (success) {\n setDraft([]);\n setTool('select');\n }\n }\n function mapClick(raw: Point, id: string | null) {\n if (!editing || tool === 'select' || threeD) {\n onSelect(id);\n return;\n }\n if (tool === 'pan') return;\n if (tool === 'partition') {\n // Recomputed from the click rather than reused from hover, so a tap that never hovered (touch)\n // creates exactly the wall a pointer would have been shown.\n const offer = proposeWall(project, floorId, raw);\n if (offer)\n commit(p => {\n drawBarrier(p, floorId, offer.segment[0], offer.segment[1]);\n });\n setProposal(null);\n return;\n }\n // Read a space off the walls that already surround the click, rather than asking someone to\n // trace an outline the drawing has already stated. The click lands in exactly one enclosed\n // region or in none, so there is nothing to aim at but the room itself.\n if (tool === 'enclose') {\n const region = boundaryRegionAt(project, floorId, raw);\n if (!region) {\n notify('Nothing encloses that point. The walls around it have a gap, or it is outside the building.');\n return;\n }\n let existing = false;\n let roomName = '';\n let area = 0;\n let found = false;\n const done = commit(p => {\n const result = encloseRoom(p, floorId, raw);\n if (!result) return;\n found = true;\n existing = result.existing;\n roomName = result.room.name;\n area = objectArea(result.room);\n setSelected(result.room.id);\n });\n // Only when it took. A rejected commit has already said why, and a second toast claiming\n // success on top of it would contradict the first.\n if (done && found)\n notify(\n existing\n ? `“${roomName}” follows its boundaries · ${area.toFixed(1)} m²`\n : `Space follows its boundaries · ${area.toFixed(1)} m²`,\n );\n return;\n }\n const anchor = draft.at(-1);\n const axis = snapping && anchor ? mainAxis(project, floorId) : 0;\n const point = snapping ? snapPoint(project, floorId, raw, toleranceRef.current, anchor, true, axis).point : raw;\n if (tool === 'wall' || tool === 'fence' || tool === 'boundary') {\n if (!anchor) {\n setDraft([point]);\n return;\n }\n const complete = endsBoundaryStroke(project, floorId, anchor, point, tool);\n let drawn = false;\n if (\n commit(p => {\n drawn = !!(tool === 'boundary'\n ? drawVirtualBoundary(p, floorId, anchor, point)\n : drawBarrier(p, floorId, anchor, point, tool));\n })\n ) {\n if (drawn && complete) finish();\n else setDraft([point]);\n }\n return;\n }\n if (tool === 'rectangle') {\n if (!draft.length) {\n setDraft([point]);\n return;\n }\n const a = draft[0];\n if (\n commit(p => {\n const o = createObject('zone', [(a[0] + point[0]) / 2, (a[1] + point[1]) / 2], floorId, 'New area');\n o.width = Math.abs(a[0] - point[0]);\n o.depth = Math.abs(a[1] - point[1]);\n o.rings = [rectangle(o.position, o.width, o.depth)];\n p.objects.push(o);\n setSelected(o.id);\n })\n ) {\n setDraft([]);\n setTool('select');\n }\n return;\n }\n if (['zone', 'room', 'hole', 'evacuation'].includes(tool)) {\n if (draft.length >= 3 && distance(point, draft[0]) < toleranceRef.current) finish();\n else {\n const next = appendAreaPoint(draft, point);\n setDraft(next.points);\n if (next.error) notify(next.error);\n }\n return;\n }\n if (tool === 'measure') {\n setDraft(draft.length >= 2 ? [point] : [...draft, point]);\n return;\n }\n if (tool === 'split') {\n if (!draft.length) {\n setDraft([point]);\n return;\n }\n // The room being split is the smallest room/zone containing the cut's midpoint.\n const mid: Point = [(draft[0][0] + point[0]) / 2, (draft[0][1] + point[1]) / 2];\n const target = project.objects\n .filter(\n o =>\n o.floorId === floorId &&\n (o.kind === 'room' || o.kind === 'zone') &&\n o.rings &&\n pointInRing(mid, o.rings[0]),\n )\n .sort((a, b) => objectArea(a) - objectArea(b))[0];\n if (!target) {\n notify('Draw the cut across a room — you can start and end past the walls.');\n return;\n }\n if (\n commit(p => {\n const twin = splitRoom(p, target.id, draft[0], point);\n setSelected(twin);\n })\n ) {\n setDraft([]);\n setTool('select');\n }\n return;\n }\n if (tool === 'route') {\n // Route authoring chains nav nodes: lifts/stairs thread all served floors (chainVertical),\n // doors/POIs/rooms get a bound node at the object, anywhere else a free node at the snap\n // point. A kept anchor links each new node to the previous one — 'door' edges when either\n // end binds a door/gate/turnstile — and every mutation runs through commit() for undo.\n const hit = id ? project.objects.find(o => o.id === id) : undefined;\n let targetId: string | null = null;\n const ok = commit(p => {\n const obj = hit ? p.objects.find(o => o.id === hit.id) : undefined;\n let target: NavNode | undefined;\n if (obj && (obj.kind === 'elevator' || obj.kind === 'stairs')) {\n const chain = chainVertical(p, obj);\n target = chain.find(n => n.floorId === floorId);\n if (!target)\n throw new Error(`${obj.name} does not serve this floor — set its served floors in the properties panel.`);\n } else if (obj && ['door', 'gate', 'turnstile', 'poi', 'room'].includes(obj.kind))\n target = addNavNode(p, obj.floorId, objectPosition(p, obj), obj.id);\n else target = addNavNode(p, floorId, point);\n const anchor = routeAnchor ? (p.navNodes ?? []).find(n => n.id === routeAnchor) : undefined;\n if (anchor && anchor.id !== target.id) {\n const doorOf = (n: NavNode) => {\n const o = n.objectId ? p.objects.find(x => x.id === n.objectId) : undefined;\n return o && ['door', 'gate', 'turnstile'].includes(o.kind) ? o : undefined;\n };\n const doorObj = doorOf(anchor) ?? doorOf(target);\n addNavEdge(p, doorObj ? 'door' : 'walk', anchor, target, doorObj?.id);\n }\n targetId = target.id;\n });\n if (ok) setRouteAnchor(targetId);\n return;\n }\n if (PLACE_TOOLS.includes(tool)) {\n // One click, one object, and the tool is done. These tools place a single thing and leave it\n // selected, so staying armed means the next click — on the thing you just placed, to move it\n // or read it — drops another one on top instead. Drawing tools are different: a wall or a zone\n // takes several clicks, so they stay until the shape is finished.\n const placed = commit(p => {\n const o = createObject(tool as ObjectKind, point, floorId);\n if (isOpening(o.kind)) {\n // The very fit the preview drew. Two copies of this rule would drift apart, and a preview\n // that disagrees with the click is worse than no preview at all.\n const fit = fitOpening(p, floorId, o.kind as 'door', raw, o.width, openingReach());\n if (!fit) throw new Error(`Place this ${o.kind} on a ${o.kind === 'gate' ? 'fence' : 'wall'}.`);\n o.barrierId = fit.barrierId;\n o.offset = fit.offset;\n o.position = fit.position;\n }\n if (isDevice(o.kind)) o.feedId = `device-${o.id}`;\n if (isArea(o.kind)) o.rings = [rectangle(o.position, o.width, o.depth)];\n p.objects.push(o);\n setSelected(o.id);\n });\n if (placed) setTool('select');\n }\n }\n // A basemap building becomes a first-class model: its own building entry (carrying the basemap\n // source id), estimated storeys with facade walls and a zone per floor — ready to edit further.\n function adoptBuilding({\n rings,\n sourceId,\n storeys,\n name,\n }: {\n rings: Point[][];\n sourceId: string | number;\n storeys: number;\n name: string;\n }) {\n let groundFloor = '';\n const success = commit(p => {\n if (p.buildings.some(b => b.sourceId === sourceId))\n throw new Error('That building is already part of this project.');\n const bid = uid();\n p.buildings.push({ id: bid, name, sourceId });\n const outline = rings[0];\n const xs = outline.map(pt => pt[0]),\n ys = outline.map(pt => pt[1]);\n const copyRings = () => rings.map(r => closeRing(r.map(pt => [...pt] as Point)));\n const footprint = createObject('building', centroid(outline), null, name);\n footprint.rings = copyRings();\n footprint.width = Math.max(...xs) - Math.min(...xs);\n footprint.depth = Math.max(...ys) - Math.min(...ys);\n p.objects.push(footprint);\n for (let i = 0; i < storeys; i++) {\n const fid = uid();\n if (!i) groundFloor = fid;\n p.floors.push({\n id: fid,\n buildingId: bid,\n name: `${name} · ${i ? `floor ${i}` : 'ground'}`,\n elevation: i * 3.5,\n height: 3.5,\n });\n const zone = createObject('zone', centroid(outline), fid, name);\n zone.rings = copyRings();\n zone.width = footprint.width;\n zone.depth = footprint.depth;\n zone.color = '#f7f8f6';\n p.objects.push(zone);\n const from = p.barriers.length;\n const closed = closeRing(outline.map(pt => [...pt] as Point));\n for (let k = 1; k < closed.length; k++) addBarrier(p, closed[k - 1], closed[k], fid, 'wall');\n p.barriers.slice(from).forEach(b => {\n b.name = 'Facade wall';\n b.thickness = 0.45;\n b.color = '#a6acb8';\n });\n }\n });\n if (success) {\n setTool('select');\n if (groundFloor) onFloorChange(groundFloor);\n notify(\n `Adopted “${name}” from the basemap · ${storeys} floor${storeys > 1 ? 's' : ''} created from MML attributes.`,\n );\n }\n }\n /** How far an opening looks for a wall. Shared, so a preview cannot promise a fit the click refuses. */\n const openingReach = () => Math.max(2, toleranceRef.current * 2);\n const isOpeningTool = (t: string) => t === 'door' || t === 'window' || t === 'gate';\n const onHover = (point: Point, tolerance: number) => {\n toleranceRef.current = tolerance;\n if (tool === 'select' || tool === 'pan' || threeD || !editing) return;\n if (isOpeningTool(tool)) {\n // Show the leaf on the wall it would land on, before the click rather than after it. Placing an\n // opening used to be blind: you clicked and either it took or you got an error telling you to\n // aim at a wall you could not see the edge of.\n setHover(point);\n setOpeningFit(fitOpening(project, floorId, tool as 'door', point, OPENING_WIDTH[tool] ?? 0.9, openingReach()));\n return;\n }\n if (tool === 'partition') {\n // Deliberately not gated on `snapping`: that toggle governs pulling a point onto a junction or\n // the grid, whereas inferring the wall is the entire tool. Off, it would just do nothing.\n setHover(point);\n setProposal(proposeWall(project, floorId, point));\n return;\n }\n const anchor = draft.at(-1);\n // The floor defines the angular grid throughout the stroke. A pointer crossing a nearby\n // angled wall must not rotate that grid halfway through drawing; junctions still snap exactly.\n const axis = snapping && anchor ? mainAxis(project, floorId) : null;\n const snap = snapping\n ? snapPoint(project, floorId, point, tolerance, anchor, true, axis ?? 0)\n : { point, label: '' };\n const holding = axis !== null && HELD.has(snap.label);\n setHover(snap.point);\n setHeld(holding);\n setSnapLabel(holding ? `${snap.label} to floor axis` : snap.label);\n };\n /** What the map draws to explain the wall about to exist: the axis a wall is being held to — run\n * past both ends so it reads as a line the wall lies on rather than as the wall — or the whole\n * segment the partition tool is offering. */\n const guides = useMemo<{ line: [Point, Point]; role: 'guide' | 'proposal' }[]>(() => {\n if (!editing || threeD) return [];\n if (isOpeningTool(tool)) return openingFit ? [{ line: openingFit.span, role: 'proposal' }] : [];\n if (tool === 'partition') return proposal ? [{ line: proposal.segment, role: 'proposal' }] : [];\n const anchor = draft.at(-1);\n if (!held || !anchor || !hover) return [];\n const length = distance(anchor, hover);\n if (length < 0.01) return [];\n const ux = (hover[0] - anchor[0]) / length,\n uy = (hover[1] - anchor[1]) / length,\n tail = 8;\n return [\n {\n line: [\n [anchor[0] - ux * tail, anchor[1] - uy * tail],\n [hover[0] + ux * tail, hover[1] + uy * tail],\n ],\n role: 'guide',\n },\n ];\n }, [editing, threeD, tool, proposal, openingFit, draft, hover, held]);\n const geometryPreview = (\n kind: GeometryDrag['kind'],\n id: string,\n raw: Point,\n free = false,\n ringIndex = 0,\n index = 0,\n ) => snapDragPoint(project, floorId, kind, id, raw, snapping && !free, toleranceRef.current, ringIndex, index);\n function vertexMove(\n kind: 'junction' | 'ring' | 'object' | 'barrier' | 'node' | 'opening' | 'rotate' | 'coverage',\n id: string,\n raw: Point,\n ringIndex = 0,\n index = 0,\n free = false,\n ) {\n // Shift releases the drop from the grid — the escape hatch for a camera that has to point at a\n // particular corner, or a wall that genuinely runs at 3°.\n const grid = snapping && !free;\n const point: Point = grid ? [Math.round(raw[0] * 2) / 2, Math.round(raw[1] * 2) / 2] : raw;\n if (kind === 'object') {\n updateObject(id, { position: point });\n return;\n }\n // An opening lives on its wall, so a drag slides it along that wall rather than moving it to\n // where the pointer went. Offset is clamped so the leaf stays wholly on the segment — the same\n // rule validation enforces, applied while dragging instead of refused afterwards.\n if (kind === 'opening') {\n const opening = project.objects.find(o => o.id === id);\n const barrier = project.barriers.find(b => b.id === opening?.barrierId);\n if (!opening || !barrier) return;\n const fit = fitOpening(\n { ...project, barriers: [barrier] },\n opening.floorId,\n opening.kind as 'door' | 'window' | 'gate' | 'turnstile',\n raw,\n opening.width,\n Infinity,\n id,\n );\n if (fit)\n updateObject(id, {\n offset: fit.offset,\n position: fit.position,\n ...(opening.kind === 'door' ? { doorSwing: draggedDoorSwing(project, opening, raw) } : {}),\n });\n return;\n }\n if (kind === 'rotate') {\n const object = project.objects.find(o => o.id === id);\n if (!object) return;\n const degrees = (Math.atan2(raw[1] - object.position[1], raw[0] - object.position[0]) * 180) / Math.PI;\n // Snapping holds a turned object to 15° detents; Shift lets it point anywhere.\n updateObject(id, { rotation: grid ? Math.round(degrees / 15) * 15 : Math.round(degrees * 10) / 10 });\n return;\n }\n // One handle carries both halves of a camera's cone: its distance is the reach, its bearing off\n // the camera's facing is half the field of view.\n if (kind === 'coverage') {\n const object = project.objects.find(o => o.id === id);\n if (!object) return;\n const dx = raw[0] - object.position[0],\n dy = raw[1] - object.position[1];\n const range = Math.max(1, Math.min(120, Math.hypot(dx, dy)));\n const bearing = (Math.atan2(dy, dx) * 180) / Math.PI;\n const half = Math.abs(((((bearing - (object.rotation ?? 0)) % 360) + 540) % 360) - 180);\n const spread = Math.max(10, Math.min(350, half * 2));\n updateObject(id, {\n coverageRange: Math.round(range * 10) / 10,\n coverageAngle: grid ? Math.round(spread / 5) * 5 : Math.round(spread),\n });\n return;\n }\n if (kind === 'node') {\n commit(p => {\n const n = (p.navNodes ?? []).find(n => n.id === id);\n if (n) n.position = point;\n });\n return;\n }\n if (!editing) return;\n const drop = geometryPreview(kind, id, raw, free, ringIndex, index);\n commit(p =>\n applyGeometryDrag(p, kind === 'ring' ? { kind, id, point: drop, ringIndex, index } : { kind, id, point: drop }),\n );\n }\n return {\n tool,\n setTool,\n draft,\n setDraft,\n hover,\n proposal,\n snapLabel,\n snapping,\n setSnapping,\n routeAnchor,\n setRouteAnchor,\n chooseTool,\n finish,\n mapClick,\n adoptBuilding,\n onHover,\n guides,\n geometryPreview,\n vertexMove,\n updateObject,\n };\n}\n"],"names":["HELD","OPENING_WIDTH","PLACE_TOOLS","useDrawingTools","project","floorId","selected","editing","threeD","commit","notify","setSelected","onSelect","onFloorChange","onChooseTool","tool","setTool","useState","draft","setDraft","hover","setHover","proposal","setProposal","openingFit","setOpeningFit","held","setHeld","snapLabel","setSnapLabel","snapping","setSnapping","routeAnchor","setRouteAnchor","toleranceRef","useRef","chooseTool","next","o","updateObject","id","patch","p","transformObject","finish","rings","closeRing","_a","object","createObject","centroid","xs","ys","connectSpace","mapClick","raw","offer","proposeWall","drawBarrier","boundaryRegionAt","existing","roomName","area","found","result","encloseRoom","objectArea","anchor","axis","mainAxis","point","snapPoint","complete","endsBoundaryStroke","drawn","drawVirtualBoundary","rectangle","distance","appendAreaPoint","mid","target","pointInRing","a","b","twin","splitRoom","hit","targetId","obj","chainVertical","n","addNavNode","objectPosition","doorOf","x","doorObj","addNavEdge","isOpening","fit","fitOpening","openingReach","isDevice","isArea","adoptBuilding","sourceId","storeys","name","groundFloor","bid","uid","outline","pt","copyRings","r","footprint","i","fid","zone","from","closed","k","addBarrier","isOpeningTool","t","onHover","tolerance","snap","holding","guides","useMemo","length","ux","uy","tail","geometryPreview","kind","free","ringIndex","index","snapDragPoint","vertexMove","grid","opening","barrier","draggedDoorSwing","degrees","dx","dy","range","bearing","half","spread","drop","applyGeometryDrag"],"mappings":"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"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { useState as e, useMemo as g, useEffect as N } from "react";
|
|
2
|
+
import { neutralBasemap as X } from "../adapters/basemap.js";
|
|
3
|
+
import { FIXED as q, sunAt as G } from "../map/lighting.js";
|
|
4
|
+
function O(r, t, i) {
|
|
5
|
+
var a, d;
|
|
6
|
+
const [f, v] = e(!1), [b, w] = e(!0), [l, S] = e(
|
|
7
|
+
t && (i == null ? void 0 : i.basemap) !== "plan" ? "host" : "plan"
|
|
8
|
+
), [M, C] = e(!1), [D, k] = e(!0), [n, y] = e("auto"), [c, L] = e(() => Date.now()), [x, E] = e(() => r.floors.filter((o) => o.elevation < 0).length > 1), [I, $] = e(!0), [h, A] = e(!0), u = g(
|
|
9
|
+
() => n === "auto" ? G([r.origin[0], r.origin[1]], c) : q[n],
|
|
10
|
+
[n, c, r.origin]
|
|
11
|
+
);
|
|
12
|
+
N(() => {
|
|
13
|
+
if (n !== "auto") return;
|
|
14
|
+
const o = window.setInterval(() => L(Date.now()), 6e5);
|
|
15
|
+
return () => window.clearInterval(o);
|
|
16
|
+
}, [n]);
|
|
17
|
+
const P = g(() => {
|
|
18
|
+
const o = new Date(c).toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" }), F = Math.round(Math.abs(u.altitude));
|
|
19
|
+
return `${o}, ${F}° ${u.altitude < 0 ? "below" : "above"} the horizon`;
|
|
20
|
+
}, [c, u.altitude]), T = l === "host" && t ? t : X, s = l === "host" && !!(t != null && t.vectorSchema), m = s && !!((a = t == null ? void 0 : t.vectorSchema) != null && a.footprints), z = s && !!((d = t == null ? void 0 : t.vectorSchema) != null && d.cadastre);
|
|
21
|
+
return {
|
|
22
|
+
coverage: f,
|
|
23
|
+
setCoverage: v,
|
|
24
|
+
showLabels: b,
|
|
25
|
+
setShowLabels: w,
|
|
26
|
+
basemapMode: l,
|
|
27
|
+
setBasemapMode: S,
|
|
28
|
+
settings: M,
|
|
29
|
+
setSettings: C,
|
|
30
|
+
showPlan: D,
|
|
31
|
+
setShowPlan: k,
|
|
32
|
+
lighting: n,
|
|
33
|
+
setLighting: y,
|
|
34
|
+
excavation: x,
|
|
35
|
+
setExcavation: E,
|
|
36
|
+
cityBuildings: I,
|
|
37
|
+
setCityBuildings: $,
|
|
38
|
+
cadastre: h,
|
|
39
|
+
setCadastre: A,
|
|
40
|
+
sun: u,
|
|
41
|
+
sunNote: P,
|
|
42
|
+
basemap: T,
|
|
43
|
+
surveyed: s,
|
|
44
|
+
canAdopt: m,
|
|
45
|
+
hasCadastre: z
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
export {
|
|
49
|
+
O as useMapDisplay
|
|
50
|
+
};
|
|
51
|
+
//# sourceMappingURL=useMapDisplay.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useMapDisplay.js","sources":["../../../../src/planner/useMapDisplay.ts"],"sourcesContent":["import { useEffect, useMemo, useState } from 'react';\nimport { neutralBasemap } from '../adapters/basemap';\nimport { FIXED, sunAt } from '../map/lighting';\nimport type { BasemapConfig, ViewState } from '../model/host';\nimport type { ProjectDocument } from '../model/types';\n\n/** Display preferences survive switching between the map, graph, viewer and editor. */\nexport function useMapDisplay(project: ProjectDocument, hostBasemap?: BasemapConfig, initialView?: ViewState) {\n const [coverage, setCoverage] = useState(false),\n [showLabels, setShowLabels] = useState(true),\n [basemapMode, setBasemapMode] = useState<'plan' | 'host'>(\n hostBasemap && initialView?.basemap !== 'plan' ? 'host' : 'plan',\n ),\n [settings, setSettings] = useState(false),\n [showPlan, setShowPlan] = useState(true),\n // The sun follows the clock and the place by default; 'day' and 'evening' pin it, for a\n // screenshot or for looking at a building under a light it will not see for six months.\n [lighting, setLighting] = useState<'auto' | 'day' | 'evening'>('auto'),\n // Re-read every ten minutes. The sun turns 15° an hour, so that is a couple of degrees — under\n // the width of the sun itself — and it means a plan left open through the afternoon dims and\n // reddens and eventually lights its own windows, without a frame of work spent on it.\n [clock, setClock] = useState(() => Date.now()),\n // A soil section explains a basement, and a single cellar does not need explaining: the floor\n // selector already says how far down it is, and the block is bigger than the house. Below two\n // storeys of depth it is scenery in the way; below twenty it is the whole story.\n [excavation, setExcavation] = useState(() => project.floors.filter(f => f.elevation < 0).length > 1),\n [cityBuildings, setCityBuildings] = useState(true),\n [cadastre, setCadastre] = useState(true);\n // Where the sun stands over THIS building, now. The origin is a lng/lat, so the model knows the\n // latitude it is drawn at and the longitude that sets its clock — a Helsinki plan is lit by a\n // Helsinki sun, low and from the south, rather than by a fixed studio lamp.\n const sun = useMemo(\n () => (lighting === 'auto' ? sunAt([project.origin[0], project.origin[1]], clock) : FIXED[lighting]),\n [lighting, clock, project.origin],\n );\n useEffect(() => {\n if (lighting !== 'auto') return;\n const tick = window.setInterval(() => setClock(Date.now()), 600000);\n return () => window.clearInterval(tick);\n }, [lighting]);\n // \"Why has it gone dark?\" is the next question otherwise. Say the time being drawn and how high\n // the sun is, so a dusk view reads as half past three in December rather than as a bug.\n const sunNote = useMemo(() => {\n const clockTime = new Date(clock).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });\n const angle = Math.round(Math.abs(sun.altitude));\n return `${clockTime}, ${angle}° ${sun.altitude < 0 ? 'below' : 'above'} the horizon`;\n }, [clock, sun.altitude]);\n const basemap = basemapMode === 'host' && hostBasemap ? hostBasemap : neutralBasemap;\n // A host basemap that declares a vectorSchema unlocks the schema-driven features; each is gated on\n // the specific part it needs (footprints → adopt/3D-city, cadastre → the parcel overlay).\n const surveyed = basemapMode === 'host' && !!hostBasemap?.vectorSchema;\n const canAdopt = surveyed && !!hostBasemap?.vectorSchema?.footprints;\n const hasCadastre = surveyed && !!hostBasemap?.vectorSchema?.cadastre;\n return {\n coverage,\n setCoverage,\n showLabels,\n setShowLabels,\n basemapMode,\n setBasemapMode,\n settings,\n setSettings,\n showPlan,\n setShowPlan,\n lighting,\n setLighting,\n excavation,\n setExcavation,\n cityBuildings,\n setCityBuildings,\n cadastre,\n setCadastre,\n sun,\n sunNote,\n basemap,\n surveyed,\n canAdopt,\n hasCadastre,\n };\n}\n"],"names":["useMapDisplay","project","hostBasemap","initialView","coverage","setCoverage","useState","showLabels","setShowLabels","basemapMode","setBasemapMode","settings","setSettings","showPlan","setShowPlan","lighting","setLighting","clock","setClock","excavation","setExcavation","f","cityBuildings","setCityBuildings","cadastre","setCadastre","sun","useMemo","sunAt","FIXED","useEffect","tick","sunNote","clockTime","angle","basemap","neutralBasemap","surveyed","canAdopt","_a","hasCadastre","_b"],"mappings":";;;AAOO,SAASA,EAAcC,GAA0BC,GAA6BC,GAAyB;;AAC5G,QAAM,CAACC,GAAUC,CAAW,IAAIC,EAAS,EAAK,GAC5C,CAACC,GAAYC,CAAa,IAAIF,EAAS,EAAI,GAC3C,CAACG,GAAaC,CAAc,IAAIJ;AAAA,IAC9BJ,MAAeC,KAAA,gBAAAA,EAAa,aAAY,SAAS,SAAS;AAAA,EAAA,GAE5D,CAACQ,GAAUC,CAAW,IAAIN,EAAS,EAAK,GACxC,CAACO,GAAUC,CAAW,IAAIR,EAAS,EAAI,GAGvC,CAACS,GAAUC,CAAW,IAAIV,EAAqC,MAAM,GAIrE,CAACW,GAAOC,CAAQ,IAAIZ,EAAS,MAAM,KAAK,IAAA,CAAK,GAI7C,CAACa,GAAYC,CAAa,IAAId,EAAS,MAAML,EAAQ,OAAO,OAAO,CAAAoB,MAAKA,EAAE,YAAY,CAAC,EAAE,SAAS,CAAC,GACnG,CAACC,GAAeC,CAAgB,IAAIjB,EAAS,EAAI,GACjD,CAACkB,GAAUC,CAAW,IAAInB,EAAS,EAAI,GAInCoB,IAAMC;AAAA,IACV,MAAOZ,MAAa,SAASa,EAAM,CAAC3B,EAAQ,OAAO,CAAC,GAAGA,EAAQ,OAAO,CAAC,CAAC,GAAGgB,CAAK,IAAIY,EAAMd,CAAQ;AAAA,IAClG,CAACA,GAAUE,GAAOhB,EAAQ,MAAM;AAAA,EAAA;AAElC,EAAA6B,EAAU,MAAM;AACd,QAAIf,MAAa,OAAQ;AACzB,UAAMgB,IAAO,OAAO,YAAY,MAAMb,EAAS,KAAK,KAAK,GAAG,GAAM;AAClE,WAAO,MAAM,OAAO,cAAca,CAAI;AAAA,EACxC,GAAG,CAAChB,CAAQ,CAAC;AAGb,QAAMiB,IAAUL,EAAQ,MAAM;AAC5B,UAAMM,IAAY,IAAI,KAAKhB,CAAK,EAAE,mBAAmB,IAAI,EAAE,MAAM,WAAW,QAAQ,WAAW,GACzFiB,IAAQ,KAAK,MAAM,KAAK,IAAIR,EAAI,QAAQ,CAAC;AAC/C,WAAO,GAAGO,CAAS,KAAKC,CAAK,KAAKR,EAAI,WAAW,IAAI,UAAU,OAAO;AAAA,EACxE,GAAG,CAACT,GAAOS,EAAI,QAAQ,CAAC,GAClBS,IAAU1B,MAAgB,UAAUP,IAAcA,IAAckC,GAGhEC,IAAW5B,MAAgB,UAAU,CAAC,EAACP,KAAA,QAAAA,EAAa,eACpDoC,IAAWD,KAAY,CAAC,GAACE,IAAArC,KAAA,gBAAAA,EAAa,iBAAb,QAAAqC,EAA2B,aACpDC,IAAcH,KAAY,CAAC,GAACI,IAAAvC,KAAA,gBAAAA,EAAa,iBAAb,QAAAuC,EAA2B;AAC7D,SAAO;AAAA,IACL,UAAArC;AAAA,IACA,aAAAC;AAAA,IACA,YAAAE;AAAA,IACA,eAAAC;AAAA,IACA,aAAAC;AAAA,IACA,gBAAAC;AAAA,IACA,UAAAC;AAAA,IACA,aAAAC;AAAA,IACA,UAAAC;AAAA,IACA,aAAAC;AAAA,IACA,UAAAC;AAAA,IACA,aAAAC;AAAA,IACA,YAAAG;AAAA,IACA,eAAAC;AAAA,IACA,eAAAE;AAAA,IACA,kBAAAC;AAAA,IACA,UAAAC;AAAA,IACA,aAAAC;AAAA,IACA,KAAAC;AAAA,IACA,SAAAM;AAAA,IACA,SAAAG;AAAA,IACA,UAAAE;AAAA,IACA,UAAAC;AAAA,IACA,aAAAE;AAAA,EAAA;AAEJ;"}
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import { useState as E, useRef as K, useEffect as C } from "react";
|
|
2
|
+
function b({
|
|
3
|
+
graphView: y,
|
|
4
|
+
editing: w,
|
|
5
|
+
threeD: l,
|
|
6
|
+
walk: n,
|
|
7
|
+
hasDraft: o,
|
|
8
|
+
hasSelection: d,
|
|
9
|
+
mapRef: g,
|
|
10
|
+
chooseTool: L,
|
|
11
|
+
stepFloor: f,
|
|
12
|
+
commands: t
|
|
13
|
+
}) {
|
|
14
|
+
const [h, u] = E(!1), s = K(n);
|
|
15
|
+
return s.current = n, C(() => {
|
|
16
|
+
const a = (e) => {
|
|
17
|
+
if (e.target.closest('input, textarea, select, dialog, [role="tab"]') || y) return;
|
|
18
|
+
const r = e.metaKey || e.ctrlKey;
|
|
19
|
+
if (r && e.key.toLowerCase() === "z" && w) {
|
|
20
|
+
e.preventDefault(), o && !e.shiftKey ? t.undoPoint() : e.shiftKey ? t.redo() : t.undo();
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
if (r && e.key.toLowerCase() === "s") {
|
|
24
|
+
e.preventDefault(), t.export();
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
if (e.key === "Escape" && t.cancel(), e.key === "Enter" && o && (e.preventDefault(), t.finish()), !r) {
|
|
28
|
+
if (s.current && !["t", "1", "2", "3", "4", "[", "]"].includes(e.key.toLowerCase())) return;
|
|
29
|
+
const i = e.key.toLowerCase();
|
|
30
|
+
if (e.key === "?") {
|
|
31
|
+
t.help();
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
if (e.key === "1") {
|
|
35
|
+
t.view();
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
if (e.key === "2") {
|
|
39
|
+
t.edit();
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
if (e.key === "3") {
|
|
43
|
+
t.walk();
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
if (e.key === "4") {
|
|
47
|
+
t.live();
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
if (i === "t") {
|
|
51
|
+
t.cycleView();
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
if (i === "x" && l && !n) {
|
|
55
|
+
t.toggleStack();
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
if (i === "b") {
|
|
59
|
+
t.toggleSidebar();
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
if (i === "i") {
|
|
63
|
+
t.toggleInspector();
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
if (i === "f") {
|
|
67
|
+
t.toggleFullscreen();
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
if (i === "g") {
|
|
71
|
+
t.toggleNavigation();
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
if (i === "n") {
|
|
75
|
+
t.toggleTheme();
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
if (e.key === "[") {
|
|
79
|
+
f(-1);
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
if (e.key === "]") {
|
|
83
|
+
f(1);
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
if (w) {
|
|
88
|
+
if ((e.key === "Backspace" || e.key === "Delete") && o) {
|
|
89
|
+
e.preventDefault(), t.undoPoint();
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
if ((e.key === "Delete" || e.key === "Backspace") && d && (e.preventDefault(), t.deleteSelection()), r && e.key.toLowerCase() === "d" && (e.preventDefault(), t.duplicate()), !r && !e.shiftKey) {
|
|
93
|
+
const i = {
|
|
94
|
+
v: "select",
|
|
95
|
+
h: "pan",
|
|
96
|
+
w: "wall",
|
|
97
|
+
p: "partition",
|
|
98
|
+
d: "door",
|
|
99
|
+
c: "camera",
|
|
100
|
+
z: "zone",
|
|
101
|
+
m: "measure",
|
|
102
|
+
s: "split",
|
|
103
|
+
e: "enclose"
|
|
104
|
+
};
|
|
105
|
+
i[e.key.toLowerCase()] && L(i[e.key.toLowerCase()]);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}, k = (e) => {
|
|
109
|
+
if (e.target.closest('input, textarea, select, dialog, [role="tab"]') || y || s.current) return;
|
|
110
|
+
const r = g.current;
|
|
111
|
+
if (e.key.startsWith("Arrow")) {
|
|
112
|
+
e.preventDefault(), e.stopPropagation(), e.shiftKey ? e.key === "ArrowUp" || e.key === "ArrowDown" ? f(e.key === "ArrowUp" ? 1 : -1) : r == null || r.easeTo({ bearing: r.getBearing() + (e.key === "ArrowRight" ? 45 : -45), duration: 450 }) : r == null || r.panBy(
|
|
113
|
+
[
|
|
114
|
+
e.key === "ArrowLeft" ? -140 : e.key === "ArrowRight" ? 140 : 0,
|
|
115
|
+
e.key === "ArrowUp" ? -140 : e.key === "ArrowDown" ? 140 : 0
|
|
116
|
+
],
|
|
117
|
+
{ duration: 250 }
|
|
118
|
+
);
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
e.shiftKey && l && r && (e.key.toLowerCase() === "w" || e.key.toLowerCase() === "s") && (e.preventDefault(), e.stopPropagation(), r.easeTo({
|
|
122
|
+
pitch: Math.max(0, Math.min(75, r.getPitch() + (e.key.toLowerCase() === "w" ? 10 : -10))),
|
|
123
|
+
duration: 300
|
|
124
|
+
}));
|
|
125
|
+
}, p = (e) => {
|
|
126
|
+
e.key === "Shift" && u(!0);
|
|
127
|
+
}, v = (e) => {
|
|
128
|
+
e.key === "Shift" && u(!1);
|
|
129
|
+
}, c = () => u(!1);
|
|
130
|
+
return window.addEventListener("keydown", a), window.addEventListener("keydown", k, !0), window.addEventListener("keydown", p), window.addEventListener("keyup", v), window.addEventListener("blur", c), () => {
|
|
131
|
+
window.removeEventListener("keydown", a), window.removeEventListener("keydown", k, !0), window.removeEventListener("keydown", p), window.removeEventListener("keyup", v), window.removeEventListener("blur", c);
|
|
132
|
+
};
|
|
133
|
+
}), h;
|
|
134
|
+
}
|
|
135
|
+
export {
|
|
136
|
+
b as usePlannerKeyboard
|
|
137
|
+
};
|
|
138
|
+
//# sourceMappingURL=usePlannerKeyboard.js.map
|