@pascal-app/viewer 1.1.0 → 1.1.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.
Files changed (224) hide show
  1. package/README.md +157 -0
  2. package/dist/components/viewer/drone-controller.d.ts.map +1 -1
  3. package/dist/components/viewer/drone-controller.js +1 -5
  4. package/dist/components/viewer/first-person/build-collider-world.d.ts +14 -0
  5. package/dist/components/viewer/first-person/build-collider-world.d.ts.map +1 -0
  6. package/dist/components/viewer/first-person/build-collider-world.js +426 -0
  7. package/dist/components/viewer/first-person/ground-holes.d.ts +22 -0
  8. package/dist/components/viewer/first-person/ground-holes.d.ts.map +1 -0
  9. package/dist/components/viewer/first-person/ground-holes.js +116 -0
  10. package/dist/components/viewer/first-person/mechanism-targets.d.ts +27 -0
  11. package/dist/components/viewer/first-person/mechanism-targets.d.ts.map +1 -0
  12. package/dist/components/viewer/first-person/mechanism-targets.js +79 -0
  13. package/dist/components/viewer/first-person/terrain-collider.d.ts +32 -0
  14. package/dist/components/viewer/first-person/terrain-collider.d.ts.map +1 -0
  15. package/dist/components/viewer/first-person/terrain-collider.js +175 -0
  16. package/dist/components/viewer/glb-walkthrough-controller.d.ts +1 -1
  17. package/dist/components/viewer/glb-walkthrough-controller.d.ts.map +1 -1
  18. package/dist/components/viewer/glb-walkthrough-controller.js +3 -4
  19. package/dist/components/viewer/live-walkthrough-controller.d.ts +17 -0
  20. package/dist/components/viewer/live-walkthrough-controller.d.ts.map +1 -0
  21. package/dist/components/viewer/live-walkthrough-controller.js +1449 -0
  22. package/dist/components/viewer/post-processing.d.ts.map +1 -1
  23. package/dist/components/viewer/post-processing.js +22 -1
  24. package/dist/index.d.ts +3 -0
  25. package/dist/index.d.ts.map +1 -1
  26. package/dist/index.js +3 -0
  27. package/dist/lib/daylight/room-map.d.ts +29 -4
  28. package/dist/lib/daylight/room-map.d.ts.map +1 -1
  29. package/dist/lib/daylight/room-map.js +219 -36
  30. package/dist/lib/daylight/room-scene.d.ts.map +1 -1
  31. package/dist/lib/daylight/room-scene.js +9 -3
  32. package/dist/lib/daylight/rooms.d.ts +15 -6
  33. package/dist/lib/daylight/rooms.d.ts.map +1 -1
  34. package/dist/lib/daylight/rooms.js +49 -9
  35. package/dist/lib/measurement-presentation.d.ts +2 -0
  36. package/dist/lib/measurement-presentation.d.ts.map +1 -1
  37. package/dist/lib/measurement-presentation.js +6 -0
  38. package/dist/lib/typing-target.d.ts +2 -0
  39. package/dist/lib/typing-target.d.ts.map +1 -0
  40. package/dist/lib/typing-target.js +7 -0
  41. package/dist/lib/viewer-config.d.ts +6 -0
  42. package/dist/lib/viewer-config.d.ts.map +1 -1
  43. package/dist/lib/viewer-config.js +2 -0
  44. package/dist/sfx/audio-settings.d.ts +81 -0
  45. package/dist/sfx/audio-settings.d.ts.map +1 -0
  46. package/dist/sfx/audio-settings.js +166 -0
  47. package/dist/sfx/index.d.ts +6 -0
  48. package/dist/sfx/index.d.ts.map +1 -0
  49. package/dist/sfx/index.js +5 -0
  50. package/dist/sfx/interaction-sounds.d.ts +7 -0
  51. package/dist/sfx/interaction-sounds.d.ts.map +1 -0
  52. package/dist/sfx/interaction-sounds.js +39 -0
  53. package/dist/sfx/player.d.ts +31 -0
  54. package/dist/sfx/player.d.ts.map +1 -0
  55. package/dist/sfx/player.js +255 -0
  56. package/dist/sfx/sounds.d.ts +60 -0
  57. package/dist/sfx/sounds.d.ts.map +1 -0
  58. package/dist/sfx/sounds.js +25 -0
  59. package/dist/sfx/use-viewer-ui-sounds.d.ts +8 -0
  60. package/dist/sfx/use-viewer-ui-sounds.d.ts.map +1 -0
  61. package/dist/sfx/use-viewer-ui-sounds.js +42 -0
  62. package/dist/store/use-first-person-hud.d.ts +13 -0
  63. package/dist/store/use-first-person-hud.d.ts.map +1 -0
  64. package/dist/store/use-first-person-hud.js +21 -0
  65. package/dist/systems/roof/roof-system.d.ts.map +1 -1
  66. package/dist/systems/roof/roof-system.js +27 -13
  67. package/dist/ui/components/action-button.d.ts +14 -0
  68. package/dist/ui/components/action-button.d.ts.map +1 -0
  69. package/dist/ui/components/action-button.js +21 -0
  70. package/dist/ui/components/action-menu-placement.d.ts +7 -0
  71. package/dist/ui/components/action-menu-placement.d.ts.map +1 -0
  72. package/dist/ui/components/action-menu-placement.js +10 -0
  73. package/dist/ui/components/floorplan-compass-button.d.ts +10 -0
  74. package/dist/ui/components/floorplan-compass-button.d.ts.map +1 -0
  75. package/dist/ui/components/floorplan-compass-button.js +22 -0
  76. package/dist/ui/components/follow-pascal-toggle.d.ts +6 -0
  77. package/dist/ui/components/follow-pascal-toggle.d.ts.map +1 -0
  78. package/dist/ui/components/follow-pascal-toggle.js +21 -0
  79. package/dist/ui/components/localized-html.d.ts +9 -0
  80. package/dist/ui/components/localized-html.d.ts.map +1 -0
  81. package/dist/ui/components/localized-html.js +16 -0
  82. package/dist/ui/components/render-settings-menu.d.ts +9 -0
  83. package/dist/ui/components/render-settings-menu.d.ts.map +1 -0
  84. package/dist/ui/components/render-settings-menu.js +145 -0
  85. package/dist/ui/components/rooms/room-highlight.d.ts +10 -0
  86. package/dist/ui/components/rooms/room-highlight.d.ts.map +1 -0
  87. package/dist/ui/components/rooms/room-highlight.js +56 -0
  88. package/dist/ui/components/rooms/room-labels.d.ts +278 -0
  89. package/dist/ui/components/rooms/room-labels.d.ts.map +1 -0
  90. package/dist/ui/components/rooms/room-labels.js +1295 -0
  91. package/dist/ui/components/rooms/viewer-rooms.d.ts +14 -0
  92. package/dist/ui/components/rooms/viewer-rooms.d.ts.map +1 -0
  93. package/dist/ui/components/rooms/viewer-rooms.js +123 -0
  94. package/dist/ui/components/scene-loader.d.ts +18 -0
  95. package/dist/ui/components/scene-loader.d.ts.map +1 -0
  96. package/dist/ui/components/scene-loader.js +29 -0
  97. package/dist/ui/components/sky-control.d.ts +37 -0
  98. package/dist/ui/components/sky-control.d.ts.map +1 -0
  99. package/dist/ui/components/sky-control.js +382 -0
  100. package/dist/ui/components/use-viewer-camera-navigation-sync.d.ts +4 -0
  101. package/dist/ui/components/use-viewer-camera-navigation-sync.d.ts.map +1 -0
  102. package/dist/ui/components/use-viewer-camera-navigation-sync.js +117 -0
  103. package/dist/ui/components/viewer-controls-bar.d.ts +20 -0
  104. package/dist/ui/components/viewer-controls-bar.d.ts.map +1 -0
  105. package/dist/ui/components/viewer-controls-bar.js +130 -0
  106. package/dist/ui/components/viewer-hover-label.d.ts +14 -0
  107. package/dist/ui/components/viewer-hover-label.d.ts.map +1 -0
  108. package/dist/ui/components/viewer-hover-label.js +28 -0
  109. package/dist/ui/components/viewer-scene-header.d.ts +34 -0
  110. package/dist/ui/components/viewer-scene-header.d.ts.map +1 -0
  111. package/dist/ui/components/viewer-scene-header.js +92 -0
  112. package/dist/ui/components/viewer-selection-manager.d.ts +7 -0
  113. package/dist/ui/components/viewer-selection-manager.d.ts.map +1 -0
  114. package/dist/ui/components/viewer-selection-manager.js +116 -0
  115. package/dist/ui/components/viewer-stage-modes.d.ts +7 -0
  116. package/dist/ui/components/viewer-stage-modes.d.ts.map +1 -0
  117. package/dist/ui/components/viewer-stage-modes.js +42 -0
  118. package/dist/ui/components/viewer-stage-switcher.d.ts +10 -0
  119. package/dist/ui/components/viewer-stage-switcher.d.ts.map +1 -0
  120. package/dist/ui/components/viewer-stage-switcher.js +16 -0
  121. package/dist/ui/components/viewer-stage.d.ts +25 -0
  122. package/dist/ui/components/viewer-stage.d.ts.map +1 -0
  123. package/dist/ui/components/viewer-stage.js +107 -0
  124. package/dist/ui/components/walkthrough-hud.d.ts +29 -0
  125. package/dist/ui/components/walkthrough-hud.d.ts.map +1 -0
  126. package/dist/ui/components/walkthrough-hud.js +55 -0
  127. package/dist/ui/floorplan/floorplan-camera-sync.d.ts +22 -0
  128. package/dist/ui/floorplan/floorplan-camera-sync.d.ts.map +1 -0
  129. package/dist/ui/floorplan/floorplan-camera-sync.js +157 -0
  130. package/dist/ui/floorplan/floorplan-dimension-renderer.d.ts +61 -0
  131. package/dist/ui/floorplan/floorplan-dimension-renderer.d.ts.map +1 -0
  132. package/dist/ui/floorplan/floorplan-dimension-renderer.js +280 -0
  133. package/dist/ui/floorplan/floorplan-geometry-renderer.d.ts +54 -0
  134. package/dist/ui/floorplan/floorplan-geometry-renderer.d.ts.map +1 -0
  135. package/dist/ui/floorplan/floorplan-geometry-renderer.js +317 -0
  136. package/dist/ui/floorplan/floorplan-label-angle.d.ts +24 -0
  137. package/dist/ui/floorplan/floorplan-label-angle.d.ts.map +1 -0
  138. package/dist/ui/floorplan/floorplan-label-angle.js +60 -0
  139. package/dist/ui/floorplan/floorplan-navigation-sync.d.ts +18 -0
  140. package/dist/ui/floorplan/floorplan-navigation-sync.d.ts.map +1 -0
  141. package/dist/ui/floorplan/floorplan-navigation-sync.js +41 -0
  142. package/dist/ui/floorplan/floorplan-preview-geometry.d.ts +26 -0
  143. package/dist/ui/floorplan/floorplan-preview-geometry.d.ts.map +1 -0
  144. package/dist/ui/floorplan/floorplan-preview-geometry.js +173 -0
  145. package/dist/ui/floorplan/floorplan-preview-navigation.d.ts +22 -0
  146. package/dist/ui/floorplan/floorplan-preview-navigation.d.ts.map +1 -0
  147. package/dist/ui/floorplan/floorplan-preview-navigation.js +41 -0
  148. package/dist/ui/floorplan/floorplan-preview-visibility.d.ts +8 -0
  149. package/dist/ui/floorplan/floorplan-preview-visibility.d.ts.map +1 -0
  150. package/dist/ui/floorplan/floorplan-preview-visibility.js +21 -0
  151. package/dist/ui/floorplan/floorplan-preview.d.ts +19 -0
  152. package/dist/ui/floorplan/floorplan-preview.d.ts.map +1 -0
  153. package/dist/ui/floorplan/floorplan-preview.js +700 -0
  154. package/dist/ui/hooks/use-mobile.d.ts +2 -0
  155. package/dist/ui/hooks/use-mobile.d.ts.map +1 -0
  156. package/dist/ui/hooks/use-mobile.js +14 -0
  157. package/dist/ui/index.d.ts +49 -0
  158. package/dist/ui/index.d.ts.map +1 -0
  159. package/dist/ui/index.js +48 -0
  160. package/dist/ui/lib/below-grade.d.ts +38 -0
  161. package/dist/ui/lib/below-grade.d.ts.map +1 -0
  162. package/dist/ui/lib/below-grade.js +102 -0
  163. package/dist/ui/lib/camera-pose.d.ts +19 -0
  164. package/dist/ui/lib/camera-pose.d.ts.map +1 -0
  165. package/dist/ui/lib/camera-pose.js +113 -0
  166. package/dist/ui/lib/cn.d.ts +3 -0
  167. package/dist/ui/lib/cn.d.ts.map +1 -0
  168. package/dist/ui/lib/cn.js +5 -0
  169. package/dist/ui/lib/level-name.d.ts +10 -0
  170. package/dist/ui/lib/level-name.d.ts.map +1 -0
  171. package/dist/ui/lib/level-name.js +33 -0
  172. package/dist/ui/lib/node-display-label.d.ts +8 -0
  173. package/dist/ui/lib/node-display-label.d.ts.map +1 -0
  174. package/dist/ui/lib/node-display-label.js +36 -0
  175. package/dist/ui/lib/room-area.d.ts +3 -0
  176. package/dist/ui/lib/room-area.d.ts.map +1 -0
  177. package/dist/ui/lib/room-area.js +8 -0
  178. package/dist/ui/lib/room-assembly-overlay.d.ts +46 -0
  179. package/dist/ui/lib/room-assembly-overlay.d.ts.map +1 -0
  180. package/dist/ui/lib/room-assembly-overlay.js +222 -0
  181. package/dist/ui/lib/room-name-messages.d.ts +28 -0
  182. package/dist/ui/lib/room-name-messages.d.ts.map +1 -0
  183. package/dist/ui/lib/room-name-messages.js +112 -0
  184. package/dist/ui/lib/room-selection.d.ts +58 -0
  185. package/dist/ui/lib/room-selection.d.ts.map +1 -0
  186. package/dist/ui/lib/room-selection.js +297 -0
  187. package/dist/ui/lib/scene-theme-name.d.ts +4 -0
  188. package/dist/ui/lib/scene-theme-name.d.ts.map +1 -0
  189. package/dist/ui/lib/scene-theme-name.js +22 -0
  190. package/dist/ui/lib/selection-modifiers.d.ts +20 -0
  191. package/dist/ui/lib/selection-modifiers.d.ts.map +1 -0
  192. package/dist/ui/lib/selection-modifiers.js +15 -0
  193. package/dist/ui/lib/viewer-selection.d.ts +132 -0
  194. package/dist/ui/lib/viewer-selection.d.ts.map +1 -0
  195. package/dist/ui/lib/viewer-selection.js +462 -0
  196. package/dist/ui/lib/zone-content.d.ts +6 -0
  197. package/dist/ui/lib/zone-content.d.ts.map +1 -0
  198. package/dist/ui/lib/zone-content.js +96 -0
  199. package/dist/ui/primitives/button.d.ts +11 -0
  200. package/dist/ui/primitives/button.d.ts.map +1 -0
  201. package/dist/ui/primitives/button.js +35 -0
  202. package/dist/ui/primitives/dropdown-menu.d.ts +26 -0
  203. package/dist/ui/primitives/dropdown-menu.d.ts.map +1 -0
  204. package/dist/ui/primitives/dropdown-menu.js +53 -0
  205. package/dist/ui/primitives/popover.d.ts +8 -0
  206. package/dist/ui/primitives/popover.d.ts.map +1 -0
  207. package/dist/ui/primitives/popover.js +17 -0
  208. package/dist/ui/primitives/switch.d.ts +5 -0
  209. package/dist/ui/primitives/switch.d.ts.map +1 -0
  210. package/dist/ui/primitives/switch.js +8 -0
  211. package/dist/ui/primitives/tooltip.d.ts +8 -0
  212. package/dist/ui/primitives/tooltip.d.ts.map +1 -0
  213. package/dist/ui/primitives/tooltip.js +17 -0
  214. package/dist/ui/store/camera-pose-store.d.ts +17 -0
  215. package/dist/ui/store/camera-pose-store.d.ts.map +1 -0
  216. package/dist/ui/store/camera-pose-store.js +15 -0
  217. package/dist/ui/store/navigation-sync-pose-store.d.ts +26 -0
  218. package/dist/ui/store/navigation-sync-pose-store.d.ts.map +1 -0
  219. package/dist/ui/store/navigation-sync-pose-store.js +16 -0
  220. package/dist/ui/store/use-follow-pascal.d.ts +30 -0
  221. package/dist/ui/store/use-follow-pascal.d.ts.map +1 -0
  222. package/dist/ui/store/use-follow-pascal.js +28 -0
  223. package/dist/ui/theme.css +339 -0
  224. package/package.json +34 -7
@@ -0,0 +1,317 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { floorplanAnnotationObstacleMode, isFloorplanAnnotationObstacleGeometry, loadAssetUrl, readFloorplanGeometryMetadata, } from '@pascal-app/core';
4
+ import { memo, useEffect, useState } from 'react';
5
+ import { FloorplanDimensionRenderer, FloorplanDimensionStringRenderer, } from './floorplan-dimension-renderer';
6
+ import { resolveFloorplanLabelAngle } from './floorplan-label-angle';
7
+ const STATIC_LABEL_UNITS_PER_PIXEL = 0.01;
8
+ const DOCUMENT_DEFAULT_TEXT_SIZE_PT = 8;
9
+ const DOCUMENT_ROOM_NAME_TEXT_SIZE_PT = 8;
10
+ const DOCUMENT_ROOM_NUMBER_TEXT_SIZE_PT = 7;
11
+ const DOCUMENT_ROOM_DETAIL_TEXT_SIZE_PT = 5.5;
12
+ const DOCUMENT_COLUMN_MARK_TEXT_SIZE_PT = 7;
13
+ const DOCUMENT_DEFAULT_STROKE_WIDTH_PT = 0.5;
14
+ const DOCUMENT_TEXT_OUTLINE_MIN_WIDTH_PT = 0.75;
15
+ const DOCUMENT_MARK_HEIGHT_PT = 14;
16
+ const PDF_ANNOTATION_STROKE_WIDTH_PT = 0.5;
17
+ /**
18
+ * Pure-data → SVG converter. Walks a `FloorplanGeometry` tree returned by
19
+ * `def.floorplan(node, ctx)` and emits the matching React-SVG nodes.
20
+ *
21
+ * Coordinates are level-local meters. The wrapping floor-plan panel
22
+ * applies the world→SVG transform via its viewBox, so kinds emit
23
+ * geometry in the same units they reason about in 3D.
24
+ *
25
+ * Group transforms compose: `transform={translate(x y) rotate(deg)}`.
26
+ * Rotations are radians at the data layer (consistent with three.js
27
+ * conventions used by `def.geometry`) and converted to degrees for SVG
28
+ * here — kinds never touch units.
29
+ *
30
+ * Styling props map straight onto SVG attributes. Builders that need
31
+ * theme colors should declare them inline or expose them as registry
32
+ * tokens later (deferred until a real need surfaces — AI-authored kinds
33
+ * can pick safe defaults today).
34
+ */
35
+ export const FloorplanGeometryRenderer = memo(function FloorplanGeometryRenderer({ geometry, pointerEventsOverride, sceneRotationDeg = 0, annotationUnitsPerPoint, screenUnitsPerPixel, renderMode = 'screen', }) {
36
+ return renderNode(geometry, 0, pointerEventsOverride, sceneRotationDeg, annotationUnitsPerPoint, screenUnitsPerPixel, renderMode);
37
+ });
38
+ function styleAttrs(g, pointerEventsOverride, annotationUnitsPerPoint, renderMode = 'screen') {
39
+ // Shared SVG attribute mapping for any styled primitive. Keeps the per-
40
+ // primitive switch arms terse and ensures new style fields land
41
+ // everywhere at once. `as any` avoids re-asserting every variant
42
+ // includes the style fields — they all do, except `group` (which is
43
+ // filtered out by the caller's type bound).
44
+ const s = g;
45
+ const annotationMetadata = readFloorplanGeometryMetadata(g);
46
+ const documentStyle = resolveDocumentFloorplanAnnotationStyle(g, annotationUnitsPerPoint);
47
+ const vectorEffect = documentStyle.vectorEffect ?? s.vectorEffect;
48
+ const resolvedStrokeWidth = documentStyle.strokeWidth ?? s.strokeWidth;
49
+ const strokeWidth = renderMode === 'pdf' &&
50
+ vectorEffect === 'non-scaling-stroke' &&
51
+ resolvedStrokeWidth !== undefined
52
+ ? Math.min(PDF_ANNOTATION_STROKE_WIDTH_PT, resolvedStrokeWidth)
53
+ : resolvedStrokeWidth;
54
+ return {
55
+ 'data-floorplan-annotation-obstacle': floorplanAnnotationObstacleMode(g),
56
+ 'data-floorplan-annotation-role': annotationMetadata.annotationRole,
57
+ fill: documentStyle.fill ?? s.fill ?? 'none',
58
+ fillRule: s.fillRule,
59
+ fillOpacity: s.fillOpacity,
60
+ stroke: documentStyle.stroke ?? s.stroke,
61
+ strokeWidth,
62
+ strokeDasharray: s.strokeDasharray,
63
+ strokeLinecap: s.strokeLinecap,
64
+ strokeLinejoin: s.strokeLinejoin,
65
+ strokeOpacity: s.strokeOpacity,
66
+ opacity: s.opacity,
67
+ vectorEffect,
68
+ pointerEvents: pointerEventsOverride ?? s.pointerEvents,
69
+ style: s.cursor ? { cursor: s.cursor } : undefined,
70
+ };
71
+ }
72
+ export function resolveDocumentFloorplanAnnotationStyle(geometry, annotationUnitsPerPoint) {
73
+ if (annotationUnitsPerPoint === undefined)
74
+ return {};
75
+ const styled = geometry;
76
+ if (!styled.stroke && geometry.kind !== 'text')
77
+ return {};
78
+ if (geometry.kind === 'text') {
79
+ const sourceFontSize = Math.max(geometry.fontSize, 1e-6);
80
+ const sourceStrokeWidth = geometry.strokeWidth ?? 0;
81
+ const outlineRatio = sourceStrokeWidth > 0 ? sourceStrokeWidth / sourceFontSize : 0;
82
+ const fontSize = documentTextFontSize(geometry, annotationUnitsPerPoint);
83
+ return {
84
+ strokeWidth: geometry.stroke && outlineRatio > 0
85
+ ? Math.max(DOCUMENT_TEXT_OUTLINE_MIN_WIDTH_PT * annotationUnitsPerPoint, fontSize * outlineRatio)
86
+ : undefined,
87
+ };
88
+ }
89
+ return {
90
+ strokeWidth: documentStrokeWidth(styled, annotationUnitsPerPoint),
91
+ vectorEffect: 'non-scaling-stroke',
92
+ };
93
+ }
94
+ function documentTextFontSize(geometry, annotationUnitsPerPoint) {
95
+ return documentTextSizePt(geometry) * annotationUnitsPerPoint;
96
+ }
97
+ function documentTextSizePt(geometry) {
98
+ const metadata = readFloorplanGeometryMetadata(geometry);
99
+ // an explicit paper size wins over the role's (a sheet's room tag sets its own)
100
+ if (typeof metadata.textSizePt === 'number' && metadata.textSizePt > 0)
101
+ return metadata.textSizePt;
102
+ switch (metadata.annotationRole) {
103
+ case 'room-label':
104
+ if (geometry.fontSize >= 0.18)
105
+ return DOCUMENT_ROOM_NAME_TEXT_SIZE_PT;
106
+ if (geometry.fontSize >= 0.145)
107
+ return DOCUMENT_ROOM_NUMBER_TEXT_SIZE_PT;
108
+ return DOCUMENT_ROOM_DETAIL_TEXT_SIZE_PT;
109
+ case 'column-center':
110
+ case 'stair-annotation':
111
+ return DOCUMENT_COLUMN_MARK_TEXT_SIZE_PT;
112
+ default:
113
+ return DOCUMENT_DEFAULT_TEXT_SIZE_PT;
114
+ }
115
+ }
116
+ function documentStrokeWidth(geometry, annotationUnitsPerPoint) {
117
+ return Math.max(DOCUMENT_DEFAULT_STROKE_WIDTH_PT, Math.min(1.2, geometry.strokeWidth ?? 0.5));
118
+ }
119
+ export function documentRectGeometryAttrs(geometry, annotationUnitsPerPoint) {
120
+ if (annotationUnitsPerPoint === undefined || !isAnnotationMarkRect(geometry)) {
121
+ return {
122
+ x: geometry.x,
123
+ y: geometry.y,
124
+ width: geometry.width,
125
+ height: geometry.height,
126
+ rx: geometry.rx,
127
+ ry: geometry.ry,
128
+ };
129
+ }
130
+ const centerX = geometry.x + geometry.width / 2;
131
+ const centerY = geometry.y + geometry.height / 2;
132
+ const height = DOCUMENT_MARK_HEIGHT_PT * annotationUnitsPerPoint;
133
+ const width = Math.max(height * 1.6, (geometry.width / Math.max(geometry.height, 1e-6)) * height);
134
+ return {
135
+ x: centerX - width / 2,
136
+ y: centerY - height / 2,
137
+ width,
138
+ height,
139
+ rx: height / 2,
140
+ ry: height / 2,
141
+ };
142
+ }
143
+ function isAnnotationMarkRect(geometry) {
144
+ return geometry.fill === '#ffffff' && !!geometry.stroke && geometry.height <= 0.5;
145
+ }
146
+ export function documentCircleGeometryAttrs(geometry, annotationUnitsPerPoint) {
147
+ if (annotationUnitsPerPoint === undefined || !isAnnotationMarkCircle(geometry)) {
148
+ return { r: geometry.r };
149
+ }
150
+ return { r: Math.max(geometry.r, (DOCUMENT_MARK_HEIGHT_PT / 2) * annotationUnitsPerPoint) };
151
+ }
152
+ function isAnnotationMarkCircle(geometry) {
153
+ return geometry.fill === '#ffffff' && !!geometry.stroke && geometry.r <= 0.25;
154
+ }
155
+ export function resolveDocumentAnnotationGroupChildren(children, annotationUnitsPerPoint) {
156
+ if (annotationUnitsPerPoint === undefined)
157
+ return children;
158
+ const next = [...children];
159
+ let start = 0;
160
+ while (start < next.length) {
161
+ const first = next[start];
162
+ if (!isDocumentTextLine(first)) {
163
+ start++;
164
+ continue;
165
+ }
166
+ let end = start + 1;
167
+ while (end < next.length && isSameDocumentTextRun(first, next[end]))
168
+ end++;
169
+ if (end - start > 1) {
170
+ const run = next.slice(start, end);
171
+ const adjusted = positionDocumentTextRun(run, annotationUnitsPerPoint);
172
+ for (let index = 0; index < adjusted.length; index++) {
173
+ const line = adjusted[index];
174
+ if (line)
175
+ next[start + index] = line;
176
+ }
177
+ }
178
+ start = end;
179
+ }
180
+ return next;
181
+ }
182
+ function isDocumentTextLine(geometry) {
183
+ return geometry?.kind === 'text' && geometry.upright === true;
184
+ }
185
+ function isSameDocumentTextRun(first, candidate) {
186
+ return (isDocumentTextLine(candidate) &&
187
+ Math.abs(candidate.x - first.x) < 1e-6 &&
188
+ candidate.textAnchor === first.textAnchor &&
189
+ readFloorplanGeometryMetadata(candidate).annotationRole ===
190
+ readFloorplanGeometryMetadata(first).annotationRole);
191
+ }
192
+ function positionDocumentTextRun(run, annotationUnitsPerPoint) {
193
+ const centerY = run.reduce((sum, line) => sum + line.y, 0) / run.length;
194
+ const steps = run.slice(0, -1).map((line, index) => {
195
+ const next = run[index + 1] ?? line;
196
+ const largerFontPt = Math.max(documentTextSizePt(line), documentTextSizePt(next));
197
+ return largerFontPt * 1.25 * annotationUnitsPerPoint;
198
+ });
199
+ const totalHeight = steps.reduce((sum, step) => sum + step, 0);
200
+ let y = centerY - totalHeight / 2;
201
+ return run.map((line, index) => {
202
+ if (index > 0)
203
+ y += steps[index - 1] ?? 0;
204
+ return { ...line, y };
205
+ });
206
+ }
207
+ function renderNode(g, keyHint, pointerEventsOverride, sceneRotationDeg = 0, annotationUnitsPerPoint, screenUnitsPerPixel, renderMode = 'screen') {
208
+ switch (g.kind) {
209
+ case 'path':
210
+ return (_jsx("path", { d: g.d, ...styleAttrs(g, pointerEventsOverride, annotationUnitsPerPoint, renderMode) }, keyHint));
211
+ case 'polygon':
212
+ return (_jsx("polygon", { points: pointsToAttr(g.points), ...styleAttrs(g, pointerEventsOverride, annotationUnitsPerPoint, renderMode) }, keyHint));
213
+ case 'polyline':
214
+ return (_jsx("polyline", { points: pointsToAttr(g.points), ...styleAttrs(g, pointerEventsOverride, annotationUnitsPerPoint, renderMode) }, keyHint));
215
+ case 'rect': {
216
+ const attrs = documentRectGeometryAttrs(g, annotationUnitsPerPoint);
217
+ return (_jsx("rect", { height: attrs.height, rx: attrs.rx, ry: attrs.ry, width: attrs.width, x: attrs.x, y: attrs.y, ...styleAttrs(g, pointerEventsOverride, annotationUnitsPerPoint, renderMode) }, keyHint));
218
+ }
219
+ case 'circle': {
220
+ const attrs = documentCircleGeometryAttrs(g, annotationUnitsPerPoint);
221
+ return (_jsx("circle", { cx: g.cx, cy: g.cy, r: attrs.r, ...styleAttrs(g, pointerEventsOverride, annotationUnitsPerPoint, renderMode) }, keyHint));
222
+ }
223
+ case 'line':
224
+ return (_jsx("line", { x1: g.x1, x2: g.x2, y1: g.y1, y2: g.y2, ...styleAttrs(g, pointerEventsOverride, annotationUnitsPerPoint, renderMode) }, keyHint));
225
+ case 'text': {
226
+ const fontSize = annotationUnitsPerPoint !== undefined
227
+ ? documentTextFontSize(g, annotationUnitsPerPoint)
228
+ : g.fontSize;
229
+ const textStyle = resolveDocumentFloorplanAnnotationStyle(g, annotationUnitsPerPoint);
230
+ const pdfOutlinedText = renderMode === 'pdf' && g.paintOrder === 'stroke' && !!g.stroke;
231
+ const fill = pdfOutlinedText && g.fill?.toLocaleLowerCase() === '#ffffff'
232
+ ? g.stroke
233
+ : (g.fill ?? '#171717');
234
+ if (g.upright) {
235
+ return (_jsx("g", { "data-floorplan-annotation-obstacle": floorplanAnnotationObstacleMode(g), transform: `translate(${g.x} ${g.y}) rotate(${-sceneRotationDeg})`, children: _jsx("text", { dominantBaseline: g.dominantBaseline ?? 'middle', fill: fill, fontFamily: g.fontFamily, fontSize: fontSize, fontWeight: g.fontWeight, opacity: g.opacity, paintOrder: pdfOutlinedText ? undefined : g.paintOrder, pointerEvents: pointerEventsOverride, stroke: pdfOutlinedText ? undefined : g.stroke, strokeLinecap: !pdfOutlinedText && g.stroke ? 'round' : undefined, strokeLinejoin: !pdfOutlinedText && g.stroke ? 'round' : undefined, strokeWidth: pdfOutlinedText ? undefined : (textStyle.strokeWidth ?? g.strokeWidth), textAnchor: g.textAnchor ?? 'start', x: 0, y: 0, children: g.text }) }, keyHint));
236
+ }
237
+ return (_jsx("text", { "data-floorplan-annotation-obstacle": floorplanAnnotationObstacleMode(g), dominantBaseline: g.dominantBaseline ?? 'middle', fill: fill, fontFamily: g.fontFamily, fontSize: fontSize, fontWeight: g.fontWeight, opacity: g.opacity, paintOrder: pdfOutlinedText ? undefined : g.paintOrder, stroke: pdfOutlinedText ? undefined : g.stroke, strokeLinecap: !pdfOutlinedText && g.stroke ? 'round' : undefined, strokeLinejoin: !pdfOutlinedText && g.stroke ? 'round' : undefined, strokeWidth: pdfOutlinedText ? undefined : (textStyle.strokeWidth ?? g.strokeWidth), textAnchor: g.textAnchor ?? 'start', pointerEvents: pointerEventsOverride, x: g.x, y: g.y, children: g.text }, keyHint));
238
+ }
239
+ case 'dimension':
240
+ return (_jsx(FloorplanDimensionRenderer, { geometry: g, sceneRotationDeg: sceneRotationDeg, annotationUnitsPerPoint: annotationUnitsPerPoint, renderMode: renderMode }, keyHint));
241
+ case 'dimension-string':
242
+ return (_jsx(FloorplanDimensionStringRenderer, { annotationUnitsPerPoint: annotationUnitsPerPoint, geometry: g, renderMode: renderMode, sceneRotationDeg: sceneRotationDeg }, keyHint));
243
+ case 'dimension-label': {
244
+ const unitsPerPixel = annotationUnitsPerPoint ?? screenUnitsPerPixel ?? STATIC_LABEL_UNITS_PER_PIXEL;
245
+ const documentMode = annotationUnitsPerPoint !== undefined;
246
+ const outlined = g.appearance === 'outlined';
247
+ const pdfOutlined = outlined && renderMode === 'pdf';
248
+ const padX = unitsPerPixel * 6;
249
+ const padY = unitsPerPixel * 3;
250
+ const fontSize = unitsPerPixel * (documentMode ? 8 : outlined ? 12 : 10);
251
+ const textWidth = g.text.length * unitsPerPixel * 6.2;
252
+ const plateW = textWidth + padX * 2;
253
+ const plateH = fontSize + padY * 2;
254
+ const degrees = resolveFloorplanLabelAngle(g.angle, sceneRotationDeg, g.screenUpright);
255
+ const labelTransform = `translate(${g.cx} ${g.cy}) rotate(${degrees}) translate(0 ${-(g.offsetPx ?? 0) * unitsPerPixel})`;
256
+ return (_jsxs("g", { "data-floorplan-annotation-angle-radians": g.angle, "data-floorplan-annotation-default-transform": labelTransform, "data-floorplan-annotation-label": "", "data-floorplan-annotation-priority": "20", "data-floorplan-annotation-screen-upright": g.screenUpright ? 'true' : undefined, "data-floorplan-annotation-transform-after-rotation": `translate(0 ${-(g.offsetPx ?? 0) * unitsPerPixel})`, "data-floorplan-annotation-transform-before-rotation": `translate(${g.cx} ${g.cy})`, pointerEvents: "none", transform: labelTransform, children: [outlined && !pdfOutlined ? null : (_jsx("rect", { "data-floorplan-dimension-label-plate": pdfOutlined ? '' : undefined, fill: "#ffffff", height: plateH, opacity: 0.92, rx: unitsPerPixel * 3, ry: unitsPerPixel * 3, stroke: pdfOutlined ? undefined : '#334155', strokeWidth: pdfOutlined ? undefined : unitsPerPixel * 0.5, width: plateW, x: -plateW / 2, y: -plateH / 2 })), _jsx("text", { dominantBaseline: "middle", fill: pdfOutlined ? '#111827' : outlined ? '#ffffff' : '#111827', fontFamily: outlined && !pdfOutlined
257
+ ? 'system-ui, -apple-system, sans-serif'
258
+ : 'ui-monospace, SFMono-Regular, Menlo, monospace', fontSize: fontSize, fontWeight: outlined ? 500 : 600, paintOrder: outlined && !pdfOutlined ? 'stroke' : undefined, stroke: outlined && !pdfOutlined ? '#334155' : undefined, strokeLinecap: outlined && !pdfOutlined ? 'round' : undefined, strokeLinejoin: outlined && !pdfOutlined ? 'round' : undefined, strokeWidth: outlined && !pdfOutlined ? fontSize * 0.35 : undefined, textAnchor: "middle", x: 0, y: 0, children: g.text })] }, keyHint));
259
+ }
260
+ case 'image':
261
+ return (_jsx(FloorplanImage, { center: g.center, height: g.height, opacity: g.opacity, preserveAspectRatio: g.preserveAspectRatio ?? 'xMidYMid meet', rotation: g.rotation ?? 0, url: g.url, width: g.width }, keyHint));
262
+ case 'group': {
263
+ const transform = formatTransform(g.transform);
264
+ const children = resolveDocumentAnnotationGroupChildren(g.children, annotationUnitsPerPoint);
265
+ return (_jsx("g", { "data-floorplan-annotation-obstacle": isFloorplanAnnotationObstacleGeometry(g) ? '' : undefined, transform: transform, children: children.map((child, i) => renderNode(child, i, pointerEventsOverride, sceneRotationDeg, annotationUnitsPerPoint, screenUnitsPerPixel, renderMode)) }, keyHint));
266
+ }
267
+ // The remaining interactive primitives (hatch / hit-line / endpoint-handle)
268
+ // need the SVG context + theme palette + units-per-
269
+ // pixel that only the registry layer has access to. They're rendered
270
+ // by `floorplan-registry-layer.tsx`'s interactive walker instead. If
271
+ // a caller routes one of these through this pure renderer it
272
+ // silently drops — the static renderer is for static output.
273
+ default:
274
+ return null;
275
+ }
276
+ }
277
+ function pointsToAttr(points) {
278
+ return points.map(([x, y]) => `${x},${y}`).join(' ');
279
+ }
280
+ function formatTransform(t) {
281
+ if (!t)
282
+ return undefined;
283
+ const parts = [];
284
+ if (t.translate)
285
+ parts.push(`translate(${t.translate[0]} ${t.translate[1]})`);
286
+ if (t.rotate !== undefined)
287
+ parts.push(`rotate(${(t.rotate * 180) / Math.PI})`);
288
+ return parts.length > 0 ? parts.join(' ') : undefined;
289
+ }
290
+ /**
291
+ * `image` primitive renderer. Resolves the URL asynchronously via
292
+ * `loadAssetUrl` (handles CDN / Supabase storage) and renders an SVG
293
+ * `<image>` centered at `center`, rotated around it, sized in plan-local
294
+ * metres. While the resolution is in flight, renders nothing.
295
+ */
296
+ function FloorplanImage({ url, center, width, height, rotation, preserveAspectRatio, opacity, }) {
297
+ const [resolvedUrl, setResolvedUrl] = useState(null);
298
+ useEffect(() => {
299
+ if (!url) {
300
+ setResolvedUrl(null);
301
+ return;
302
+ }
303
+ let cancelled = false;
304
+ setResolvedUrl(null);
305
+ loadAssetUrl(url).then((next) => {
306
+ if (!cancelled)
307
+ setResolvedUrl(next);
308
+ });
309
+ return () => {
310
+ cancelled = true;
311
+ };
312
+ }, [url]);
313
+ if (!resolvedUrl)
314
+ return null;
315
+ const rotationDeg = (rotation * 180) / Math.PI;
316
+ return (_jsx("g", { pointerEvents: "none", transform: `translate(${center[0]} ${center[1]}) rotate(${rotationDeg})`, children: _jsx("image", { height: height, href: resolvedUrl, opacity: opacity, preserveAspectRatio: preserveAspectRatio, width: width, x: -width / 2, y: -height / 2 }) }));
317
+ }
@@ -0,0 +1,24 @@
1
+ export declare function resolveFloorplanLabelAngle(angleRadians: number, sceneRotationDeg: number, screenUpright?: boolean): number;
2
+ export declare function shouldUpdateFloorplanLabelRotation(previousRotationDeg: number | null, nextRotationDeg: number, minimumDeltaDeg?: number): boolean;
3
+ export declare function resolveFloorplanAnnotationUpdate({ layoutInputsChanged, previousRotationDeg, nextRotationDeg, }: {
4
+ layoutInputsChanged: boolean;
5
+ previousRotationDeg: number | null;
6
+ nextRotationDeg: number;
7
+ }): {
8
+ resolveCollisions: boolean;
9
+ updateLabelPresentation: boolean;
10
+ };
11
+ export declare function resolveFloorplanAnnotationLabelTransform({ angleRadians, sceneRotationDeg, screenUpright, beforeRotation, afterRotation, layoutDx, layoutDy, }: {
12
+ angleRadians: number;
13
+ sceneRotationDeg: number;
14
+ screenUpright: boolean;
15
+ beforeRotation: string;
16
+ afterRotation: string;
17
+ layoutDx?: number;
18
+ layoutDy?: number;
19
+ }): {
20
+ defaultTransform: string;
21
+ transform: string;
22
+ };
23
+ export declare function updateSvgFloorplanLabelOrientations(labels: Iterable<SVGGElement>, sceneRotationDeg: number): number;
24
+ //# sourceMappingURL=floorplan-label-angle.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"floorplan-label-angle.d.ts","sourceRoot":"","sources":["../../../src/ui/floorplan/floorplan-label-angle.ts"],"names":[],"mappings":"AAAA,wBAAgB,0BAA0B,CACxC,YAAY,EAAE,MAAM,EACpB,gBAAgB,EAAE,MAAM,EACxB,aAAa,UAAQ,GACpB,MAAM,CASR;AAED,wBAAgB,kCAAkC,CAChD,mBAAmB,EAAE,MAAM,GAAG,IAAI,EAClC,eAAe,EAAE,MAAM,EACvB,eAAe,SAAI,GAClB,OAAO,CAIT;AAED,wBAAgB,gCAAgC,CAAC,EAC/C,mBAAmB,EACnB,mBAAmB,EACnB,eAAe,GAChB,EAAE;IACD,mBAAmB,EAAE,OAAO,CAAA;IAC5B,mBAAmB,EAAE,MAAM,GAAG,IAAI,CAAA;IAClC,eAAe,EAAE,MAAM,CAAA;CACxB,GAAG;IACF,iBAAiB,EAAE,OAAO,CAAA;IAC1B,uBAAuB,EAAE,OAAO,CAAA;CACjC,CAOA;AAED,wBAAgB,wCAAwC,CAAC,EACvD,YAAY,EACZ,gBAAgB,EAChB,aAAa,EACb,cAAc,EACd,aAAa,EACb,QAAY,EACZ,QAAY,GACb,EAAE;IACD,YAAY,EAAE,MAAM,CAAA;IACpB,gBAAgB,EAAE,MAAM,CAAA;IACxB,aAAa,EAAE,OAAO,CAAA;IACtB,cAAc,EAAE,MAAM,CAAA;IACtB,aAAa,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB,GAAG;IACF,gBAAgB,EAAE,MAAM,CAAA;IACxB,SAAS,EAAE,MAAM,CAAA;CAClB,CAYA;AAED,wBAAgB,mCAAmC,CACjD,MAAM,EAAE,QAAQ,CAAC,WAAW,CAAC,EAC7B,gBAAgB,EAAE,MAAM,GACvB,MAAM,CAwBR"}
@@ -0,0 +1,60 @@
1
+ export function resolveFloorplanLabelAngle(angleRadians, sceneRotationDeg, screenUpright = false) {
2
+ if (screenUpright)
3
+ return -sceneRotationDeg;
4
+ let localAngleDeg = (angleRadians * 180) / Math.PI;
5
+ let screenAngleDeg = localAngleDeg + sceneRotationDeg;
6
+ screenAngleDeg = ((((screenAngleDeg + 180) % 360) + 360) % 360) - 180;
7
+ if (screenAngleDeg > 90)
8
+ localAngleDeg -= 180;
9
+ else if (screenAngleDeg <= -90)
10
+ localAngleDeg += 180;
11
+ return ((((localAngleDeg + 180) % 360) + 360) % 360) - 180;
12
+ }
13
+ export function shouldUpdateFloorplanLabelRotation(previousRotationDeg, nextRotationDeg, minimumDeltaDeg = 1) {
14
+ if (previousRotationDeg === null)
15
+ return true;
16
+ const deltaDeg = ((((nextRotationDeg - previousRotationDeg + 180) % 360) + 360) % 360) - 180;
17
+ return Math.abs(deltaDeg) >= minimumDeltaDeg;
18
+ }
19
+ export function resolveFloorplanAnnotationUpdate({ layoutInputsChanged, previousRotationDeg, nextRotationDeg, }) {
20
+ return {
21
+ resolveCollisions: layoutInputsChanged,
22
+ updateLabelPresentation: layoutInputsChanged ||
23
+ shouldUpdateFloorplanLabelRotation(previousRotationDeg, nextRotationDeg),
24
+ };
25
+ }
26
+ export function resolveFloorplanAnnotationLabelTransform({ angleRadians, sceneRotationDeg, screenUpright, beforeRotation, afterRotation, layoutDx = 0, layoutDy = 0, }) {
27
+ const degrees = resolveFloorplanLabelAngle(angleRadians, sceneRotationDeg, screenUpright);
28
+ const defaultTransform = [beforeRotation, `rotate(${degrees})`, afterRotation]
29
+ .filter(Boolean)
30
+ .join(' ');
31
+ return {
32
+ defaultTransform,
33
+ transform: layoutDx === 0 && layoutDy === 0
34
+ ? defaultTransform
35
+ : `${defaultTransform} translate(${layoutDx} ${layoutDy})`,
36
+ };
37
+ }
38
+ export function updateSvgFloorplanLabelOrientations(labels, sceneRotationDeg) {
39
+ let updated = 0;
40
+ for (const label of labels) {
41
+ const angleRadians = Number(label.dataset.floorplanAnnotationAngleRadians);
42
+ if (!Number.isFinite(angleRadians))
43
+ continue;
44
+ const { defaultTransform, transform } = resolveFloorplanAnnotationLabelTransform({
45
+ angleRadians,
46
+ sceneRotationDeg,
47
+ screenUpright: label.dataset.floorplanAnnotationScreenUpright === 'true',
48
+ beforeRotation: label.dataset.floorplanAnnotationTransformBeforeRotation ?? '',
49
+ afterRotation: label.dataset.floorplanAnnotationTransformAfterRotation ?? '',
50
+ layoutDx: Number(label.dataset.floorplanAnnotationLayoutDx ?? 0),
51
+ layoutDy: Number(label.dataset.floorplanAnnotationLayoutDy ?? 0),
52
+ });
53
+ if (label.getAttribute('transform') === transform)
54
+ continue;
55
+ label.dataset.floorplanAnnotationDefaultTransform = defaultTransform;
56
+ label.setAttribute('transform', transform);
57
+ updated += 1;
58
+ }
59
+ return updated;
60
+ }
@@ -0,0 +1,18 @@
1
+ export declare function setFloorplanCompassRotation(compass: {
2
+ style: {
3
+ transform: string;
4
+ };
5
+ } | null, rotationDeg: number): void;
6
+ export type FloorplanNavigationSyncScheduler<Pose> = {
7
+ update: (pose: Pose) => void;
8
+ flush: () => void;
9
+ discard: () => void;
10
+ };
11
+ export declare function createFloorplanNavigationSyncScheduler<Pose>({ applyPresentation, commit, settleMs, schedule, cancel, }: {
12
+ applyPresentation: (pose: Pose) => void;
13
+ commit: (pose: Pose) => void;
14
+ settleMs?: number;
15
+ schedule?: (callback: () => void, delay: number) => ReturnType<typeof globalThis.setTimeout>;
16
+ cancel?: (timer: ReturnType<typeof globalThis.setTimeout>) => void;
17
+ }): FloorplanNavigationSyncScheduler<Pose>;
18
+ //# sourceMappingURL=floorplan-navigation-sync.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"floorplan-navigation-sync.d.ts","sourceRoot":"","sources":["../../../src/ui/floorplan/floorplan-navigation-sync.ts"],"names":[],"mappings":"AAAA,wBAAgB,2BAA2B,CACzC,OAAO,EAAE;IAAE,KAAK,EAAE;QAAE,SAAS,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,GAAG,IAAI,EAChD,WAAW,EAAE,MAAM,GAClB,IAAI,CAIN;AAED,MAAM,MAAM,gCAAgC,CAAC,IAAI,IAAI;IACnD,MAAM,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,IAAI,CAAA;IAC5B,KAAK,EAAE,MAAM,IAAI,CAAA;IACjB,OAAO,EAAE,MAAM,IAAI,CAAA;CACpB,CAAA;AAED,wBAAgB,sCAAsC,CAAC,IAAI,EAAE,EAC3D,iBAAiB,EACjB,MAAM,EACN,QAAc,EACd,QAAgC,EAChC,MAAgC,GACjC,EAAE;IACD,iBAAiB,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,IAAI,CAAA;IACvC,MAAM,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,IAAI,CAAA;IAC5B,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,QAAQ,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,IAAI,EAAE,KAAK,EAAE,MAAM,KAAK,UAAU,CAAC,OAAO,UAAU,CAAC,UAAU,CAAC,CAAA;IAC5F,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,UAAU,CAAC,OAAO,UAAU,CAAC,UAAU,CAAC,KAAK,IAAI,CAAA;CACnE,GAAG,gCAAgC,CAAC,IAAI,CAAC,CAqCzC"}
@@ -0,0 +1,41 @@
1
+ export function setFloorplanCompassRotation(compass, rotationDeg) {
2
+ if (compass) {
3
+ compass.style.transform = `rotate(${rotationDeg}deg)`;
4
+ }
5
+ }
6
+ export function createFloorplanNavigationSyncScheduler({ applyPresentation, commit, settleMs = 120, schedule = globalThis.setTimeout, cancel = globalThis.clearTimeout, }) {
7
+ let latestPose = null;
8
+ let settleTimer = null;
9
+ const clearSettleTimer = () => {
10
+ if (settleTimer === null)
11
+ return;
12
+ cancel(settleTimer);
13
+ settleTimer = null;
14
+ };
15
+ const flush = () => {
16
+ clearSettleTimer();
17
+ if (latestPose === null)
18
+ return;
19
+ const pose = latestPose;
20
+ latestPose = null;
21
+ commit(pose);
22
+ };
23
+ const update = (pose) => {
24
+ latestPose = pose;
25
+ applyPresentation(pose);
26
+ clearSettleTimer();
27
+ settleTimer = schedule(() => {
28
+ settleTimer = null;
29
+ if (latestPose === null)
30
+ return;
31
+ const settledPose = latestPose;
32
+ latestPose = null;
33
+ commit(settledPose);
34
+ }, settleMs);
35
+ };
36
+ const discard = () => {
37
+ clearSettleTimer();
38
+ latestPose = null;
39
+ };
40
+ return { update, flush, discard };
41
+ }
@@ -0,0 +1,26 @@
1
+ import type { FloorplanGeometry, FloorplanPoint } from '@pascal-app/core';
2
+ export type FloorplanBounds = {
3
+ minX: number;
4
+ minY: number;
5
+ maxX: number;
6
+ maxY: number;
7
+ };
8
+ export type FloorplanViewBox = {
9
+ x: number;
10
+ y: number;
11
+ width: number;
12
+ height: number;
13
+ };
14
+ export type FloorplanViewport = {
15
+ left: number;
16
+ top: number;
17
+ width: number;
18
+ height: number;
19
+ };
20
+ export declare function clientToFloorplanPoint(viewBox: FloorplanViewBox, viewport: FloorplanViewport, clientX: number, clientY: number): FloorplanPoint;
21
+ export declare function scaleFloorplanViewBox(viewBox: FloorplanViewBox, factor: number, anchorX?: number, anchorY?: number): FloorplanViewBox;
22
+ export declare function scaleFloorplanViewBoxBetweenClients(viewBox: FloorplanViewBox, factor: number, viewport: FloorplanViewport, sourceClient: FloorplanPoint, targetClient: FloorplanPoint): FloorplanViewBox;
23
+ export declare function panFloorplanViewBox(viewBox: FloorplanViewBox, viewport: FloorplanViewport, sourceClient: FloorplanPoint, targetClient: FloorplanPoint): FloorplanViewBox;
24
+ export declare function getFloorplanBounds(geometries: readonly FloorplanGeometry[]): FloorplanBounds | null;
25
+ export declare function padFloorplanBounds(bounds: FloorplanBounds, ratio?: number): FloorplanBounds;
26
+ //# sourceMappingURL=floorplan-preview-geometry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"floorplan-preview-geometry.d.ts","sourceRoot":"","sources":["../../../src/ui/floorplan/floorplan-preview-geometry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAA;AAEzE,MAAM,MAAM,eAAe,GAAG;IAC5B,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;CACb,CAAA;AAED,MAAM,MAAM,gBAAgB,GAAG;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAA;AAEtF,MAAM,MAAM,iBAAiB,GAAG;IAC9B,IAAI,EAAE,MAAM,CAAA;IACZ,GAAG,EAAE,MAAM,CAAA;IACX,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,MAAM,CAAA;CACf,CAAA;AAwBD,wBAAgB,sBAAsB,CACpC,OAAO,EAAE,gBAAgB,EACzB,QAAQ,EAAE,iBAAiB,EAC3B,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,GACd,cAAc,CAGhB;AAED,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,gBAAgB,EACzB,MAAM,EAAE,MAAM,EACd,OAAO,SAAM,EACb,OAAO,SAAM,GACZ,gBAAgB,CAYlB;AAED,wBAAgB,mCAAmC,CACjD,OAAO,EAAE,gBAAgB,EACzB,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,iBAAiB,EAC3B,YAAY,EAAE,cAAc,EAC5B,YAAY,EAAE,cAAc,GAC3B,gBAAgB,CAclB;AAED,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,gBAAgB,EACzB,QAAQ,EAAE,iBAAiB,EAC3B,YAAY,EAAE,cAAc,EAC5B,YAAY,EAAE,cAAc,GAC3B,gBAAgB,CAQlB;AA6JD,wBAAgB,kBAAkB,CAChC,UAAU,EAAE,SAAS,iBAAiB,EAAE,GACvC,eAAe,GAAG,IAAI,CAKxB;AAED,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,eAAe,EAAE,KAAK,SAAO,GAAG,eAAe,CAUzF"}