@ifc-lite/viewer 1.17.2 → 1.17.4

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 (520) hide show
  1. package/.turbo/turbo-build.log +34 -24
  2. package/.turbo/turbo-typecheck.log +1 -42
  3. package/CHANGELOG.md +24 -0
  4. package/DESKTOP_CONTRACT_VERSION +1 -0
  5. package/dist/assets/arrow-CZ5kQ26f.js +20 -0
  6. package/dist/assets/basketViewActivator-BmnNtVfZ.js +1 -0
  7. package/dist/assets/bcf-DOG9_WPX.js +281 -0
  8. package/dist/assets/{browser-BDShTXzi.js → browser-C5TFR7sH.js} +1 -1
  9. package/dist/assets/cesium-ADbP7waU.css +1 -0
  10. package/dist/assets/cesium-DUOzBlqv.js +17817 -0
  11. package/dist/assets/drawing-2d-gWfpdfYe.js +257 -0
  12. package/dist/assets/epsg-index.generated-BjJrt_0S.js +1 -0
  13. package/dist/assets/exporters-ChAtBmlj.js +80367 -0
  14. package/dist/assets/geometry.worker-BQ0rzNo-.js +1 -0
  15. package/dist/assets/ids-B4jTqB1O.js +1 -0
  16. package/dist/assets/ifc-lite_bg-BX4E7TX8.wasm +0 -0
  17. package/dist/assets/index-Co8E2-FE.js +106013 -0
  18. package/dist/assets/index-DckuDqlv.css +1 -0
  19. package/dist/assets/lens-CSASnhAL.js +1 -0
  20. package/dist/assets/maplibre-gl-CGLcoNXc.js +811 -0
  21. package/dist/assets/native-bridge-BRvbckFQ.js +429 -0
  22. package/dist/assets/{arrow2-bb-jcVEo.js → parquet-CEXmQNRO.js} +2 -2
  23. package/dist/assets/sandbox-DZiNLNMk.js +5933 -0
  24. package/dist/assets/server-client-BV8zHZ7Y.js +626 -0
  25. package/dist/assets/tauri-core-stub-D8Fa-u43.js +1 -0
  26. package/dist/assets/tauri-dialog-stub-r7Wksg7o.js +1 -0
  27. package/dist/assets/tauri-fs-stub-BdeRC7aK.js +1 -0
  28. package/dist/assets/wasm-bridge-g01g7T9b.js +1 -0
  29. package/dist/assets/zip-DBEtpeu6.js +12 -0
  30. package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_0.json +1 -0
  31. package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_1.json +1 -0
  32. package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_10.json +1 -0
  33. package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_11.json +1 -0
  34. package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_12.json +1 -0
  35. package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_13.json +1 -0
  36. package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_14.json +1 -0
  37. package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_15.json +1 -0
  38. package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_16.json +1 -0
  39. package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_17.json +1 -0
  40. package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_18.json +1 -0
  41. package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_19.json +1 -0
  42. package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_2.json +1 -0
  43. package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_20.json +1 -0
  44. package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_21.json +1 -0
  45. package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_22.json +1 -0
  46. package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_23.json +1 -0
  47. package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_24.json +1 -0
  48. package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_25.json +1 -0
  49. package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_26.json +1 -0
  50. package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_27.json +1 -0
  51. package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_3.json +1 -0
  52. package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_4.json +1 -0
  53. package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_5.json +1 -0
  54. package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_6.json +1 -0
  55. package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_7.json +1 -0
  56. package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_8.json +1 -0
  57. package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_9.json +1 -0
  58. package/dist/cesium/Assets/Images/bing_maps_credit.png +0 -0
  59. package/dist/cesium/Assets/Images/cesium_credit.png +0 -0
  60. package/dist/cesium/Assets/Images/google_earth_credit.png +0 -0
  61. package/dist/cesium/Assets/Images/ion-credit.png +0 -0
  62. package/dist/cesium/Assets/Textures/LensFlare/DirtMask.jpg +0 -0
  63. package/dist/cesium/Assets/Textures/LensFlare/StarBurst.jpg +0 -0
  64. package/dist/cesium/Assets/Textures/NaturalEarthII/0/0/0.jpg +0 -0
  65. package/dist/cesium/Assets/Textures/NaturalEarthII/0/1/0.jpg +0 -0
  66. package/dist/cesium/Assets/Textures/NaturalEarthII/1/0/0.jpg +0 -0
  67. package/dist/cesium/Assets/Textures/NaturalEarthII/1/0/1.jpg +0 -0
  68. package/dist/cesium/Assets/Textures/NaturalEarthII/1/1/0.jpg +0 -0
  69. package/dist/cesium/Assets/Textures/NaturalEarthII/1/1/1.jpg +0 -0
  70. package/dist/cesium/Assets/Textures/NaturalEarthII/1/2/0.jpg +0 -0
  71. package/dist/cesium/Assets/Textures/NaturalEarthII/1/2/1.jpg +0 -0
  72. package/dist/cesium/Assets/Textures/NaturalEarthII/1/3/0.jpg +0 -0
  73. package/dist/cesium/Assets/Textures/NaturalEarthII/1/3/1.jpg +0 -0
  74. package/dist/cesium/Assets/Textures/NaturalEarthII/2/0/0.jpg +0 -0
  75. package/dist/cesium/Assets/Textures/NaturalEarthII/2/0/1.jpg +0 -0
  76. package/dist/cesium/Assets/Textures/NaturalEarthII/2/0/2.jpg +0 -0
  77. package/dist/cesium/Assets/Textures/NaturalEarthII/2/0/3.jpg +0 -0
  78. package/dist/cesium/Assets/Textures/NaturalEarthII/2/1/0.jpg +0 -0
  79. package/dist/cesium/Assets/Textures/NaturalEarthII/2/1/1.jpg +0 -0
  80. package/dist/cesium/Assets/Textures/NaturalEarthII/2/1/2.jpg +0 -0
  81. package/dist/cesium/Assets/Textures/NaturalEarthII/2/1/3.jpg +0 -0
  82. package/dist/cesium/Assets/Textures/NaturalEarthII/2/2/0.jpg +0 -0
  83. package/dist/cesium/Assets/Textures/NaturalEarthII/2/2/1.jpg +0 -0
  84. package/dist/cesium/Assets/Textures/NaturalEarthII/2/2/2.jpg +0 -0
  85. package/dist/cesium/Assets/Textures/NaturalEarthII/2/2/3.jpg +0 -0
  86. package/dist/cesium/Assets/Textures/NaturalEarthII/2/3/0.jpg +0 -0
  87. package/dist/cesium/Assets/Textures/NaturalEarthII/2/3/1.jpg +0 -0
  88. package/dist/cesium/Assets/Textures/NaturalEarthII/2/3/2.jpg +0 -0
  89. package/dist/cesium/Assets/Textures/NaturalEarthII/2/3/3.jpg +0 -0
  90. package/dist/cesium/Assets/Textures/NaturalEarthII/2/4/0.jpg +0 -0
  91. package/dist/cesium/Assets/Textures/NaturalEarthII/2/4/1.jpg +0 -0
  92. package/dist/cesium/Assets/Textures/NaturalEarthII/2/4/2.jpg +0 -0
  93. package/dist/cesium/Assets/Textures/NaturalEarthII/2/4/3.jpg +0 -0
  94. package/dist/cesium/Assets/Textures/NaturalEarthII/2/5/0.jpg +0 -0
  95. package/dist/cesium/Assets/Textures/NaturalEarthII/2/5/1.jpg +0 -0
  96. package/dist/cesium/Assets/Textures/NaturalEarthII/2/5/2.jpg +0 -0
  97. package/dist/cesium/Assets/Textures/NaturalEarthII/2/5/3.jpg +0 -0
  98. package/dist/cesium/Assets/Textures/NaturalEarthII/2/6/0.jpg +0 -0
  99. package/dist/cesium/Assets/Textures/NaturalEarthII/2/6/1.jpg +0 -0
  100. package/dist/cesium/Assets/Textures/NaturalEarthII/2/6/2.jpg +0 -0
  101. package/dist/cesium/Assets/Textures/NaturalEarthII/2/6/3.jpg +0 -0
  102. package/dist/cesium/Assets/Textures/NaturalEarthII/2/7/0.jpg +0 -0
  103. package/dist/cesium/Assets/Textures/NaturalEarthII/2/7/1.jpg +0 -0
  104. package/dist/cesium/Assets/Textures/NaturalEarthII/2/7/2.jpg +0 -0
  105. package/dist/cesium/Assets/Textures/NaturalEarthII/2/7/3.jpg +0 -0
  106. package/dist/cesium/Assets/Textures/NaturalEarthII/tilemapresource.xml +14 -0
  107. package/dist/cesium/Assets/Textures/SkyBox/tycho2t3_80_mx.jpg +0 -0
  108. package/dist/cesium/Assets/Textures/SkyBox/tycho2t3_80_my.jpg +0 -0
  109. package/dist/cesium/Assets/Textures/SkyBox/tycho2t3_80_mz.jpg +0 -0
  110. package/dist/cesium/Assets/Textures/SkyBox/tycho2t3_80_px.jpg +0 -0
  111. package/dist/cesium/Assets/Textures/SkyBox/tycho2t3_80_py.jpg +0 -0
  112. package/dist/cesium/Assets/Textures/SkyBox/tycho2t3_80_pz.jpg +0 -0
  113. package/dist/cesium/Assets/Textures/maki/airfield.png +0 -0
  114. package/dist/cesium/Assets/Textures/maki/airport.png +0 -0
  115. package/dist/cesium/Assets/Textures/maki/alcohol-shop.png +0 -0
  116. package/dist/cesium/Assets/Textures/maki/america-football.png +0 -0
  117. package/dist/cesium/Assets/Textures/maki/art-gallery.png +0 -0
  118. package/dist/cesium/Assets/Textures/maki/bakery.png +0 -0
  119. package/dist/cesium/Assets/Textures/maki/bank.png +0 -0
  120. package/dist/cesium/Assets/Textures/maki/bar.png +0 -0
  121. package/dist/cesium/Assets/Textures/maki/baseball.png +0 -0
  122. package/dist/cesium/Assets/Textures/maki/basketball.png +0 -0
  123. package/dist/cesium/Assets/Textures/maki/beer.png +0 -0
  124. package/dist/cesium/Assets/Textures/maki/bicycle.png +0 -0
  125. package/dist/cesium/Assets/Textures/maki/building.png +0 -0
  126. package/dist/cesium/Assets/Textures/maki/bus.png +0 -0
  127. package/dist/cesium/Assets/Textures/maki/cafe.png +0 -0
  128. package/dist/cesium/Assets/Textures/maki/camera.png +0 -0
  129. package/dist/cesium/Assets/Textures/maki/campsite.png +0 -0
  130. package/dist/cesium/Assets/Textures/maki/car.png +0 -0
  131. package/dist/cesium/Assets/Textures/maki/cemetery.png +0 -0
  132. package/dist/cesium/Assets/Textures/maki/cesium.png +0 -0
  133. package/dist/cesium/Assets/Textures/maki/chemist.png +0 -0
  134. package/dist/cesium/Assets/Textures/maki/cinema.png +0 -0
  135. package/dist/cesium/Assets/Textures/maki/circle-stroked.png +0 -0
  136. package/dist/cesium/Assets/Textures/maki/circle.png +0 -0
  137. package/dist/cesium/Assets/Textures/maki/city.png +0 -0
  138. package/dist/cesium/Assets/Textures/maki/clothing-store.png +0 -0
  139. package/dist/cesium/Assets/Textures/maki/college.png +0 -0
  140. package/dist/cesium/Assets/Textures/maki/commercial.png +0 -0
  141. package/dist/cesium/Assets/Textures/maki/cricket.png +0 -0
  142. package/dist/cesium/Assets/Textures/maki/cross.png +0 -0
  143. package/dist/cesium/Assets/Textures/maki/dam.png +0 -0
  144. package/dist/cesium/Assets/Textures/maki/danger.png +0 -0
  145. package/dist/cesium/Assets/Textures/maki/disability.png +0 -0
  146. package/dist/cesium/Assets/Textures/maki/dog-park.png +0 -0
  147. package/dist/cesium/Assets/Textures/maki/embassy.png +0 -0
  148. package/dist/cesium/Assets/Textures/maki/emergency-telephone.png +0 -0
  149. package/dist/cesium/Assets/Textures/maki/entrance.png +0 -0
  150. package/dist/cesium/Assets/Textures/maki/farm.png +0 -0
  151. package/dist/cesium/Assets/Textures/maki/fast-food.png +0 -0
  152. package/dist/cesium/Assets/Textures/maki/ferry.png +0 -0
  153. package/dist/cesium/Assets/Textures/maki/fire-station.png +0 -0
  154. package/dist/cesium/Assets/Textures/maki/fuel.png +0 -0
  155. package/dist/cesium/Assets/Textures/maki/garden.png +0 -0
  156. package/dist/cesium/Assets/Textures/maki/gift.png +0 -0
  157. package/dist/cesium/Assets/Textures/maki/golf.png +0 -0
  158. package/dist/cesium/Assets/Textures/maki/grocery.png +0 -0
  159. package/dist/cesium/Assets/Textures/maki/hairdresser.png +0 -0
  160. package/dist/cesium/Assets/Textures/maki/harbor.png +0 -0
  161. package/dist/cesium/Assets/Textures/maki/heart.png +0 -0
  162. package/dist/cesium/Assets/Textures/maki/heliport.png +0 -0
  163. package/dist/cesium/Assets/Textures/maki/hospital.png +0 -0
  164. package/dist/cesium/Assets/Textures/maki/ice-cream.png +0 -0
  165. package/dist/cesium/Assets/Textures/maki/industrial.png +0 -0
  166. package/dist/cesium/Assets/Textures/maki/land-use.png +0 -0
  167. package/dist/cesium/Assets/Textures/maki/laundry.png +0 -0
  168. package/dist/cesium/Assets/Textures/maki/library.png +0 -0
  169. package/dist/cesium/Assets/Textures/maki/lighthouse.png +0 -0
  170. package/dist/cesium/Assets/Textures/maki/lodging.png +0 -0
  171. package/dist/cesium/Assets/Textures/maki/logging.png +0 -0
  172. package/dist/cesium/Assets/Textures/maki/london-underground.png +0 -0
  173. package/dist/cesium/Assets/Textures/maki/marker-stroked.png +0 -0
  174. package/dist/cesium/Assets/Textures/maki/marker.png +0 -0
  175. package/dist/cesium/Assets/Textures/maki/minefield.png +0 -0
  176. package/dist/cesium/Assets/Textures/maki/mobilephone.png +0 -0
  177. package/dist/cesium/Assets/Textures/maki/monument.png +0 -0
  178. package/dist/cesium/Assets/Textures/maki/museum.png +0 -0
  179. package/dist/cesium/Assets/Textures/maki/music.png +0 -0
  180. package/dist/cesium/Assets/Textures/maki/oil-well.png +0 -0
  181. package/dist/cesium/Assets/Textures/maki/park.png +0 -0
  182. package/dist/cesium/Assets/Textures/maki/park2.png +0 -0
  183. package/dist/cesium/Assets/Textures/maki/parking-garage.png +0 -0
  184. package/dist/cesium/Assets/Textures/maki/parking.png +0 -0
  185. package/dist/cesium/Assets/Textures/maki/pharmacy.png +0 -0
  186. package/dist/cesium/Assets/Textures/maki/pitch.png +0 -0
  187. package/dist/cesium/Assets/Textures/maki/place-of-worship.png +0 -0
  188. package/dist/cesium/Assets/Textures/maki/playground.png +0 -0
  189. package/dist/cesium/Assets/Textures/maki/police.png +0 -0
  190. package/dist/cesium/Assets/Textures/maki/polling-place.png +0 -0
  191. package/dist/cesium/Assets/Textures/maki/post.png +0 -0
  192. package/dist/cesium/Assets/Textures/maki/prison.png +0 -0
  193. package/dist/cesium/Assets/Textures/maki/rail-above.png +0 -0
  194. package/dist/cesium/Assets/Textures/maki/rail-light.png +0 -0
  195. package/dist/cesium/Assets/Textures/maki/rail-metro.png +0 -0
  196. package/dist/cesium/Assets/Textures/maki/rail-underground.png +0 -0
  197. package/dist/cesium/Assets/Textures/maki/rail.png +0 -0
  198. package/dist/cesium/Assets/Textures/maki/religious-christian.png +0 -0
  199. package/dist/cesium/Assets/Textures/maki/religious-jewish.png +0 -0
  200. package/dist/cesium/Assets/Textures/maki/religious-muslim.png +0 -0
  201. package/dist/cesium/Assets/Textures/maki/restaurant.png +0 -0
  202. package/dist/cesium/Assets/Textures/maki/roadblock.png +0 -0
  203. package/dist/cesium/Assets/Textures/maki/rocket.png +0 -0
  204. package/dist/cesium/Assets/Textures/maki/school.png +0 -0
  205. package/dist/cesium/Assets/Textures/maki/scooter.png +0 -0
  206. package/dist/cesium/Assets/Textures/maki/shop.png +0 -0
  207. package/dist/cesium/Assets/Textures/maki/skiing.png +0 -0
  208. package/dist/cesium/Assets/Textures/maki/slaughterhouse.png +0 -0
  209. package/dist/cesium/Assets/Textures/maki/soccer.png +0 -0
  210. package/dist/cesium/Assets/Textures/maki/square-stroked.png +0 -0
  211. package/dist/cesium/Assets/Textures/maki/square.png +0 -0
  212. package/dist/cesium/Assets/Textures/maki/star-stroked.png +0 -0
  213. package/dist/cesium/Assets/Textures/maki/star.png +0 -0
  214. package/dist/cesium/Assets/Textures/maki/suitcase.png +0 -0
  215. package/dist/cesium/Assets/Textures/maki/swimming.png +0 -0
  216. package/dist/cesium/Assets/Textures/maki/telephone.png +0 -0
  217. package/dist/cesium/Assets/Textures/maki/tennis.png +0 -0
  218. package/dist/cesium/Assets/Textures/maki/theatre.png +0 -0
  219. package/dist/cesium/Assets/Textures/maki/toilets.png +0 -0
  220. package/dist/cesium/Assets/Textures/maki/town-hall.png +0 -0
  221. package/dist/cesium/Assets/Textures/maki/town.png +0 -0
  222. package/dist/cesium/Assets/Textures/maki/triangle-stroked.png +0 -0
  223. package/dist/cesium/Assets/Textures/maki/triangle.png +0 -0
  224. package/dist/cesium/Assets/Textures/maki/village.png +0 -0
  225. package/dist/cesium/Assets/Textures/maki/warehouse.png +0 -0
  226. package/dist/cesium/Assets/Textures/maki/waste-basket.png +0 -0
  227. package/dist/cesium/Assets/Textures/maki/water.png +0 -0
  228. package/dist/cesium/Assets/Textures/maki/wetland.png +0 -0
  229. package/dist/cesium/Assets/Textures/maki/zoo.png +0 -0
  230. package/dist/cesium/Assets/Textures/moonSmall.jpg +0 -0
  231. package/dist/cesium/Assets/Textures/pin.svg +1 -0
  232. package/dist/cesium/Assets/Textures/waterNormals.jpg +0 -0
  233. package/dist/cesium/Assets/Textures/waterNormalsSmall.jpg +0 -0
  234. package/dist/cesium/Assets/approximateTerrainHeights.json +1 -0
  235. package/dist/cesium/ThirdParty/Workers/package.json +1 -0
  236. package/dist/cesium/ThirdParty/Workers/zip-web-worker.js +1 -0
  237. package/dist/cesium/ThirdParty/basis_transcoder.wasm +0 -0
  238. package/dist/cesium/ThirdParty/draco_decoder.wasm +0 -0
  239. package/dist/cesium/ThirdParty/google-earth-dbroot-parser.js +1 -0
  240. package/dist/cesium/ThirdParty/wasm_splats_bg.wasm +0 -0
  241. package/dist/cesium/ThirdParty/zip-module.wasm +0 -0
  242. package/dist/cesium/Widgets/Animation/Animation.css +127 -0
  243. package/dist/cesium/Widgets/Animation/lighter.css +70 -0
  244. package/dist/cesium/Widgets/BaseLayerPicker/BaseLayerPicker.css +108 -0
  245. package/dist/cesium/Widgets/BaseLayerPicker/lighter.css +22 -0
  246. package/dist/cesium/Widgets/Cesium3DTilesInspector/Cesium3DTilesInspector.css +102 -0
  247. package/dist/cesium/Widgets/CesiumInspector/CesiumInspector.css +113 -0
  248. package/dist/cesium/Widgets/CesiumWidget/CesiumWidget.css +119 -0
  249. package/dist/cesium/Widgets/CesiumWidget/lighter.css +14 -0
  250. package/dist/cesium/Widgets/FullscreenButton/FullscreenButton.css +8 -0
  251. package/dist/cesium/Widgets/Geocoder/Geocoder.css +70 -0
  252. package/dist/cesium/Widgets/Geocoder/lighter.css +17 -0
  253. package/dist/cesium/Widgets/I3SBuildingSceneLayerExplorer/I3SBuildingSceneLayerExplorer.css +27 -0
  254. package/dist/cesium/Widgets/Images/ImageryProviders/ArcGisMapServiceWorldHillshade.png +0 -0
  255. package/dist/cesium/Widgets/Images/ImageryProviders/ArcGisMapServiceWorldImagery.png +0 -0
  256. package/dist/cesium/Widgets/Images/ImageryProviders/ArcGisMapServiceWorldOcean.png +0 -0
  257. package/dist/cesium/Widgets/Images/ImageryProviders/azureAerial.png +0 -0
  258. package/dist/cesium/Widgets/Images/ImageryProviders/azureRoads.png +0 -0
  259. package/dist/cesium/Widgets/Images/ImageryProviders/bingAerial.png +0 -0
  260. package/dist/cesium/Widgets/Images/ImageryProviders/bingAerialLabels.png +0 -0
  261. package/dist/cesium/Widgets/Images/ImageryProviders/bingRoads.png +0 -0
  262. package/dist/cesium/Widgets/Images/ImageryProviders/blueMarble.png +0 -0
  263. package/dist/cesium/Widgets/Images/ImageryProviders/earthAtNight.png +0 -0
  264. package/dist/cesium/Widgets/Images/ImageryProviders/googleContour.png +0 -0
  265. package/dist/cesium/Widgets/Images/ImageryProviders/googleRoadmap.png +0 -0
  266. package/dist/cesium/Widgets/Images/ImageryProviders/googleSatellite.png +0 -0
  267. package/dist/cesium/Widgets/Images/ImageryProviders/googleSatelliteLabels.png +0 -0
  268. package/dist/cesium/Widgets/Images/ImageryProviders/mapQuestOpenStreetMap.png +0 -0
  269. package/dist/cesium/Widgets/Images/ImageryProviders/mapboxSatellite.png +0 -0
  270. package/dist/cesium/Widgets/Images/ImageryProviders/mapboxStreets.png +0 -0
  271. package/dist/cesium/Widgets/Images/ImageryProviders/mapboxTerrain.png +0 -0
  272. package/dist/cesium/Widgets/Images/ImageryProviders/naturalEarthII.png +0 -0
  273. package/dist/cesium/Widgets/Images/ImageryProviders/openStreetMap.png +0 -0
  274. package/dist/cesium/Widgets/Images/ImageryProviders/sentinel-2.png +0 -0
  275. package/dist/cesium/Widgets/Images/ImageryProviders/stadiaAlidadeSmooth.png +0 -0
  276. package/dist/cesium/Widgets/Images/ImageryProviders/stadiaAlidadeSmoothDark.png +0 -0
  277. package/dist/cesium/Widgets/Images/ImageryProviders/stamenToner.png +0 -0
  278. package/dist/cesium/Widgets/Images/ImageryProviders/stamenWatercolor.png +0 -0
  279. package/dist/cesium/Widgets/Images/NavigationHelp/Mouse.svg +84 -0
  280. package/dist/cesium/Widgets/Images/NavigationHelp/MouseLeft.svg +76 -0
  281. package/dist/cesium/Widgets/Images/NavigationHelp/MouseMiddle.svg +76 -0
  282. package/dist/cesium/Widgets/Images/NavigationHelp/MouseRight.svg +76 -0
  283. package/dist/cesium/Widgets/Images/NavigationHelp/Touch.svg +120 -0
  284. package/dist/cesium/Widgets/Images/NavigationHelp/TouchDrag.svg +129 -0
  285. package/dist/cesium/Widgets/Images/NavigationHelp/TouchRotate.svg +76 -0
  286. package/dist/cesium/Widgets/Images/NavigationHelp/TouchTilt.svg +135 -0
  287. package/dist/cesium/Widgets/Images/NavigationHelp/TouchZoom.svg +74 -0
  288. package/dist/cesium/Widgets/Images/TerrainProviders/CesiumWorldTerrain.png +0 -0
  289. package/dist/cesium/Widgets/Images/TerrainProviders/Ellipsoid.png +0 -0
  290. package/dist/cesium/Widgets/Images/TimelineIcons.png +0 -0
  291. package/dist/cesium/Widgets/Images/info-loading.gif +0 -0
  292. package/dist/cesium/Widgets/InfoBox/InfoBox.css +92 -0
  293. package/dist/cesium/Widgets/InfoBox/InfoBoxDescription.css +178 -0
  294. package/dist/cesium/Widgets/NavigationHelpButton/NavigationHelpButton.css +93 -0
  295. package/dist/cesium/Widgets/NavigationHelpButton/lighter.css +38 -0
  296. package/dist/cesium/Widgets/PerformanceWatchdog/PerformanceWatchdog.css +15 -0
  297. package/dist/cesium/Widgets/ProjectionPicker/ProjectionPicker.css +38 -0
  298. package/dist/cesium/Widgets/SceneModePicker/SceneModePicker.css +56 -0
  299. package/dist/cesium/Widgets/SelectionIndicator/SelectionIndicator.css +20 -0
  300. package/dist/cesium/Widgets/Timeline/Timeline.css +103 -0
  301. package/dist/cesium/Widgets/Timeline/lighter.css +23 -0
  302. package/dist/cesium/Widgets/VRButton/VRButton.css +8 -0
  303. package/dist/cesium/Widgets/Viewer/Viewer.css +107 -0
  304. package/dist/cesium/Widgets/VoxelInspector/VoxelInspector.css +16 -0
  305. package/dist/cesium/Widgets/lighter.css +237 -0
  306. package/dist/cesium/Widgets/lighterShared.css +46 -0
  307. package/dist/cesium/Widgets/shared.css +103 -0
  308. package/dist/cesium/Widgets/widgets.css +1342 -0
  309. package/dist/cesium/Workers/chunk-23ZQ2IVV.js +29 -0
  310. package/dist/cesium/Workers/chunk-2EQO3Q56.js +26 -0
  311. package/dist/cesium/Workers/chunk-2MJIIVP4.js +26 -0
  312. package/dist/cesium/Workers/chunk-2TE5NTVD.js +26 -0
  313. package/dist/cesium/Workers/chunk-2ZBHLJST.js +26 -0
  314. package/dist/cesium/Workers/chunk-5TJMAQVL.js +26 -0
  315. package/dist/cesium/Workers/chunk-6BD4U3VO.js +26 -0
  316. package/dist/cesium/Workers/chunk-7TVGLKQF.js +26 -0
  317. package/dist/cesium/Workers/chunk-BTSYJ5XU.js +26 -0
  318. package/dist/cesium/Workers/chunk-BXMEEOCS.js +63 -0
  319. package/dist/cesium/Workers/chunk-BYLCY7GP.js +29 -0
  320. package/dist/cesium/Workers/chunk-CTHM3W6I.js +26 -0
  321. package/dist/cesium/Workers/chunk-CUUSNIVQ.js +26 -0
  322. package/dist/cesium/Workers/chunk-E3JOOS3S.js +26 -0
  323. package/dist/cesium/Workers/chunk-E7KYDCM5.js +26 -0
  324. package/dist/cesium/Workers/chunk-EDVBB7SS.js +27 -0
  325. package/dist/cesium/Workers/chunk-EFBN7QNX.js +26 -0
  326. package/dist/cesium/Workers/chunk-EQ4YRVWL.js +26 -0
  327. package/dist/cesium/Workers/chunk-F6PRE7D6.js +26 -0
  328. package/dist/cesium/Workers/chunk-FC4ZZ65J.js +26 -0
  329. package/dist/cesium/Workers/chunk-FFBVWF2L.js +26 -0
  330. package/dist/cesium/Workers/chunk-GBAA6GVX.js +26 -0
  331. package/dist/cesium/Workers/chunk-ICALLYLG.js +26 -0
  332. package/dist/cesium/Workers/chunk-ILRYTWTP.js +26 -0
  333. package/dist/cesium/Workers/chunk-IRNLBSEJ.js +26 -0
  334. package/dist/cesium/Workers/chunk-IX4VMHEV.js +26 -0
  335. package/dist/cesium/Workers/chunk-L6QHHACZ.js +26 -0
  336. package/dist/cesium/Workers/chunk-LI2ZSORM.js +26 -0
  337. package/dist/cesium/Workers/chunk-LSLE2RL4.js +26 -0
  338. package/dist/cesium/Workers/chunk-M4HLDBCG.js +26 -0
  339. package/dist/cesium/Workers/chunk-MJHHSGEH.js +26 -0
  340. package/dist/cesium/Workers/chunk-NMVKML6W.js +26 -0
  341. package/dist/cesium/Workers/chunk-OCWJRAXS.js +26 -0
  342. package/dist/cesium/Workers/chunk-OIRKANTH.js +26 -0
  343. package/dist/cesium/Workers/chunk-OIT7J4IC.js +26 -0
  344. package/dist/cesium/Workers/chunk-OLZ3FYUM.js +26 -0
  345. package/dist/cesium/Workers/chunk-Q5BPHJQF.js +26 -0
  346. package/dist/cesium/Workers/chunk-QFM5DCMQ.js +26 -0
  347. package/dist/cesium/Workers/chunk-QKUIYMGC.js +28 -0
  348. package/dist/cesium/Workers/chunk-S44JILQT.js +26 -0
  349. package/dist/cesium/Workers/chunk-SLT4J352.js +26 -0
  350. package/dist/cesium/Workers/chunk-SQMIIXB7.js +26 -0
  351. package/dist/cesium/Workers/chunk-TJ4XLGBQ.js +26 -0
  352. package/dist/cesium/Workers/chunk-TNSUQXWK.js +27 -0
  353. package/dist/cesium/Workers/chunk-UBOGZS7F.js +26 -0
  354. package/dist/cesium/Workers/chunk-V3OSTMM6.js +26 -0
  355. package/dist/cesium/Workers/chunk-V7QEYVP3.js +26 -0
  356. package/dist/cesium/Workers/chunk-VUKYSU4H.js +26 -0
  357. package/dist/cesium/Workers/chunk-W37FE5GR.js +26 -0
  358. package/dist/cesium/Workers/chunk-WBOV35NL.js +26 -0
  359. package/dist/cesium/Workers/chunk-WPMZLB3Y.js +26 -0
  360. package/dist/cesium/Workers/chunk-WWWZVEEH.js +26 -0
  361. package/dist/cesium/Workers/chunk-XFIQ5DEQ.js +28 -0
  362. package/dist/cesium/Workers/chunk-XQHLGIO7.js +26 -0
  363. package/dist/cesium/Workers/chunk-XUSCFAVF.js +26 -0
  364. package/dist/cesium/Workers/chunk-YP7I5QBZ.js +26 -0
  365. package/dist/cesium/Workers/chunk-Z3QF2EHT.js +26 -0
  366. package/dist/cesium/Workers/combineGeometry.js +26 -0
  367. package/dist/cesium/Workers/createBoxGeometry.js +26 -0
  368. package/dist/cesium/Workers/createBoxOutlineGeometry.js +26 -0
  369. package/dist/cesium/Workers/createCircleGeometry.js +26 -0
  370. package/dist/cesium/Workers/createCircleOutlineGeometry.js +26 -0
  371. package/dist/cesium/Workers/createCoplanarPolygonGeometry.js +26 -0
  372. package/dist/cesium/Workers/createCoplanarPolygonOutlineGeometry.js +26 -0
  373. package/dist/cesium/Workers/createCorridorGeometry.js +26 -0
  374. package/dist/cesium/Workers/createCorridorOutlineGeometry.js +26 -0
  375. package/dist/cesium/Workers/createCylinderGeometry.js +26 -0
  376. package/dist/cesium/Workers/createCylinderOutlineGeometry.js +26 -0
  377. package/dist/cesium/Workers/createEllipseGeometry.js +26 -0
  378. package/dist/cesium/Workers/createEllipseOutlineGeometry.js +26 -0
  379. package/dist/cesium/Workers/createEllipsoidGeometry.js +26 -0
  380. package/dist/cesium/Workers/createEllipsoidOutlineGeometry.js +26 -0
  381. package/dist/cesium/Workers/createFrustumGeometry.js +26 -0
  382. package/dist/cesium/Workers/createFrustumOutlineGeometry.js +26 -0
  383. package/dist/cesium/Workers/createGeometry.js +26 -0
  384. package/dist/cesium/Workers/createGroundPolylineGeometry.js +26 -0
  385. package/dist/cesium/Workers/createPlaneGeometry.js +26 -0
  386. package/dist/cesium/Workers/createPlaneOutlineGeometry.js +26 -0
  387. package/dist/cesium/Workers/createPolygonGeometry.js +26 -0
  388. package/dist/cesium/Workers/createPolygonOutlineGeometry.js +26 -0
  389. package/dist/cesium/Workers/createPolylineGeometry.js +26 -0
  390. package/dist/cesium/Workers/createPolylineVolumeGeometry.js +26 -0
  391. package/dist/cesium/Workers/createPolylineVolumeOutlineGeometry.js +26 -0
  392. package/dist/cesium/Workers/createRectangleGeometry.js +26 -0
  393. package/dist/cesium/Workers/createRectangleOutlineGeometry.js +26 -0
  394. package/dist/cesium/Workers/createSimplePolylineGeometry.js +26 -0
  395. package/dist/cesium/Workers/createSphereGeometry.js +26 -0
  396. package/dist/cesium/Workers/createSphereOutlineGeometry.js +26 -0
  397. package/dist/cesium/Workers/createTaskProcessorWorker.js +26 -0
  398. package/dist/cesium/Workers/createVectorTileClampedPolylines.js +26 -0
  399. package/dist/cesium/Workers/createVectorTileGeometries.js +26 -0
  400. package/dist/cesium/Workers/createVectorTilePoints.js +26 -0
  401. package/dist/cesium/Workers/createVectorTilePolygons.js +26 -0
  402. package/dist/cesium/Workers/createVectorTilePolylines.js +26 -0
  403. package/dist/cesium/Workers/createVerticesFromCesium3DTilesTerrain.js +26 -0
  404. package/dist/cesium/Workers/createVerticesFromGoogleEarthEnterpriseBuffer.js +26 -0
  405. package/dist/cesium/Workers/createVerticesFromHeightmap.js +26 -0
  406. package/dist/cesium/Workers/createVerticesFromQuantizedTerrainMesh.js +26 -0
  407. package/dist/cesium/Workers/createWallGeometry.js +26 -0
  408. package/dist/cesium/Workers/createWallOutlineGeometry.js +26 -0
  409. package/dist/cesium/Workers/decodeDraco.js +26 -0
  410. package/dist/cesium/Workers/decodeGoogleEarthEnterprisePacket.js +26 -0
  411. package/dist/cesium/Workers/decodeI3S.js +26 -0
  412. package/dist/cesium/Workers/gaussianSplatSorter.js +26 -0
  413. package/dist/cesium/Workers/gaussianSplatTextureGenerator.js +26 -0
  414. package/dist/cesium/Workers/incrementallyBuildTerrainPicker.js +26 -0
  415. package/dist/cesium/Workers/transcodeKTX2.js +56 -0
  416. package/dist/cesium/Workers/transferTypedArrayTest.js +26 -0
  417. package/dist/cesium/Workers/upsampleQuantizedTerrainMesh.js +26 -0
  418. package/dist/cesium/Workers/upsampleVerticesFromCesium3DTilesTerrain.js +26 -0
  419. package/dist/index.html +13 -2
  420. package/package.json +27 -19
  421. package/src/App.tsx +1 -17
  422. package/src/components/viewer/BCFPanel.tsx +46 -4
  423. package/src/components/viewer/CesiumOverlay.tsx +672 -0
  424. package/src/components/viewer/CesiumSettingsDialog.tsx +100 -0
  425. package/src/components/viewer/ChatPanel.tsx +54 -16
  426. package/src/components/viewer/CommandPalette.tsx +6 -1
  427. package/src/components/viewer/DesktopEntitlementBanner.tsx +74 -0
  428. package/src/components/viewer/ExportChangesButton.tsx +24 -4
  429. package/src/components/viewer/ExportDialog.tsx +38 -9
  430. package/src/components/viewer/HierarchyPanel.tsx +202 -6
  431. package/src/components/viewer/IDSPanel.tsx +52 -3
  432. package/src/components/viewer/KeyboardShortcutsDialog.tsx +1 -1
  433. package/src/components/viewer/MainToolbar.tsx +353 -27
  434. package/src/components/viewer/PropertiesPanel.tsx +306 -131
  435. package/src/components/viewer/ScriptPanel.tsx +34 -8
  436. package/src/components/viewer/Section2DPanel.tsx +3 -2
  437. package/src/components/viewer/SettingsPage.tsx +430 -0
  438. package/src/components/viewer/StatusBar.tsx +17 -1
  439. package/src/components/viewer/UpgradePage.tsx +6 -4
  440. package/src/components/viewer/ViewerLayout.tsx +47 -6
  441. package/src/components/viewer/Viewport.tsx +49 -8
  442. package/src/components/viewer/ViewportContainer.tsx +285 -32
  443. package/src/components/viewer/ViewportOverlays.tsx +129 -27
  444. package/src/components/viewer/hierarchy/treeDataBuilder.ts +2 -1
  445. package/src/components/viewer/properties/EpsgLookupDialog.tsx +418 -0
  446. package/src/components/viewer/properties/GeoreferencingPanel.tsx +703 -0
  447. package/src/components/viewer/properties/LocationMap.tsx +730 -0
  448. package/src/components/viewer/properties/ModelMetadataPanel.tsx +3 -70
  449. package/src/components/viewer/selectionHandlers.ts +4 -3
  450. package/src/components/viewer/useAnimationLoop.ts +4 -0
  451. package/src/components/viewer/useGeometryStreaming.ts +127 -40
  452. package/src/components/viewer/useMouseControls.ts +4 -1
  453. package/src/hooks/bcfIdLookup.ts +13 -11
  454. package/src/hooks/ids/idsColorSystem.ts +3 -8
  455. package/src/hooks/ingest/viewerModelIngest.ts +275 -0
  456. package/src/hooks/useIDS.ts +32 -17
  457. package/src/hooks/useIfc.ts +7 -1
  458. package/src/hooks/useIfcCache.ts +28 -15
  459. package/src/hooks/useIfcFederation.ts +59 -227
  460. package/src/hooks/useIfcLoader.ts +1656 -130
  461. package/src/hooks/useIfcServer.ts +0 -69
  462. package/src/lib/desktop/ClerkDesktopEntitlementSync.tsx +175 -0
  463. package/src/lib/desktop/desktopEntitlementEvents.ts +39 -0
  464. package/src/lib/desktop-entitlement.ts +45 -0
  465. package/src/lib/desktop-product.ts +124 -0
  466. package/src/lib/geo/cesium-bridge.ts +310 -0
  467. package/src/lib/geo/kmz-exporter.ts +112 -0
  468. package/src/lib/geo/reproject.ts +370 -0
  469. package/src/lib/lens/adapter.ts +3 -1
  470. package/src/lib/recent-files.ts +2 -1
  471. package/src/main.tsx +1 -0
  472. package/src/sdk/adapters/export-adapter.ts +14 -1
  473. package/src/sdk/adapters/viewer-adapter.ts +5 -9
  474. package/src/sdk/adapters/visibility-adapter.ts +6 -9
  475. package/src/services/analysis-extensions.ts +125 -0
  476. package/src/services/app-navigation.ts +13 -0
  477. package/src/services/bsdd.ts +53 -4
  478. package/src/services/cacheService.ts +1 -1
  479. package/src/services/desktop-cache.ts +43 -0
  480. package/src/services/desktop-export.ts +77 -0
  481. package/src/services/desktop-harness.ts +196 -0
  482. package/src/services/desktop-logger.ts +20 -0
  483. package/src/services/desktop-native-metadata.ts +207 -0
  484. package/src/services/desktop-panel-actions.ts +43 -0
  485. package/src/services/desktop-preferences.ts +44 -0
  486. package/src/services/file-dialog.ts +147 -0
  487. package/src/services/tauri-core-stub.ts +7 -0
  488. package/src/services/tauri-dialog-stub.ts +7 -0
  489. package/src/services/tauri-fs-stub.ts +7 -0
  490. package/src/store/basketVisibleSet.ts +3 -4
  491. package/src/store/globalId.ts +79 -0
  492. package/src/store/index.ts +41 -2
  493. package/src/store/slices/cesiumSlice.ts +122 -0
  494. package/src/store/slices/chatSlice.ts +5 -1
  495. package/src/store/slices/dataSlice.ts +139 -28
  496. package/src/store/slices/desktopEntitlementSlice.ts +86 -0
  497. package/src/store/slices/loadingSlice.ts +14 -2
  498. package/src/store/slices/modelSlice.ts +58 -3
  499. package/src/store/slices/mutationSlice.ts +178 -0
  500. package/src/store/slices/pinboardSlice.ts +4 -8
  501. package/src/store/types.ts +96 -2
  502. package/src/store.ts +1 -1
  503. package/src/utils/desktopModelSnapshot.ts +358 -0
  504. package/src/utils/ifcConfig.ts +6 -1
  505. package/src/utils/nativeSpatialDataStore.ts +250 -0
  506. package/src/utils/serverDataModel.ts +4 -0
  507. package/src/utils/spatialHierarchy.ts +10 -11
  508. package/vite.config.ts +41 -0
  509. package/dist/assets/Arrow.dom-BhOg9lpn.js +0 -20
  510. package/dist/assets/arrow2_bg-BlXl-cSQ.js +0 -1
  511. package/dist/assets/basketViewActivator-BRG5DBmM.js +0 -1
  512. package/dist/assets/desktop-cache-oPzaWXYE.js +0 -1
  513. package/dist/assets/geometry.worker-kgiT_Qhh.js +0 -1
  514. package/dist/assets/ifc-lite_bg-FNRmpSvM.wasm +0 -0
  515. package/dist/assets/index-B1Ecw4AU.js +0 -189756
  516. package/dist/assets/index-Ba4eoTe7.css +0 -1
  517. package/dist/assets/index-CrgYBjTn.js +0 -229
  518. package/dist/assets/module-6F3E5H7Y-tx0BadV3.js +0 -6
  519. package/dist/assets/native-bridge-Crsb7TKz.js +0 -111
  520. package/dist/assets/wasm-bridge-mJUhb7uk.js +0 -1
@@ -0,0 +1,370 @@
1
+ /* This Source Code Form is subject to the terms of the Mozilla Public
2
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
3
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
+
5
+ /**
6
+ * Coordinate reprojection utilities.
7
+ *
8
+ * Converts projected coordinates (e.g. UTM eastings/northings) from an
9
+ * IfcMapConversion + IfcProjectedCRS pair into WGS84 longitude/latitude
10
+ * so they can be displayed on a web map.
11
+ *
12
+ * proj4 definitions are resolved from:
13
+ * 1. The bundled EPSG index (@ifc-lite/data) — covers all 7000+ codes
14
+ * 2. Programmatically constructed (UTM zones, well-known codes)
15
+ * 3. Fetched from epsg.io at runtime as last resort
16
+ */
17
+
18
+ import proj4 from 'proj4';
19
+ import type { MapConversion, ProjectedCRS } from '@ifc-lite/parser';
20
+ import type { CoordinateInfo } from '@ifc-lite/geometry';
21
+ import { lookupProj4 } from '@ifc-lite/data';
22
+
23
+ export interface LatLon {
24
+ lat: number;
25
+ lon: number;
26
+ }
27
+
28
+ // Cache resolved projection definitions (from any source).
29
+ const projDefCache = new Map<string, string | null>();
30
+
31
+ /**
32
+ * Extract EPSG numeric code from a CRS name like "EPSG:32632" or "EPSG 2056".
33
+ */
34
+ function extractEpsgCode(crs: ProjectedCRS): string | null {
35
+ const match = crs.name?.match(/EPSG[:\s]*(\d+)/i);
36
+ return match ? match[1] : null;
37
+ }
38
+
39
+ /**
40
+ * Build a proj4 definition string for a UTM zone.
41
+ */
42
+ function utmProj4String(zone: string): string | null {
43
+ const match = zone.match(/^(\d{1,2})([NS])$/i);
44
+ if (!match) return null;
45
+ const zoneNum = parseInt(match[1], 10);
46
+ const isNorth = match[2].toUpperCase() === 'N';
47
+ if (zoneNum < 1 || zoneNum > 60) return null;
48
+ return `+proj=utm +zone=${zoneNum}${isNorth ? '' : ' +south'} +datum=WGS84 +units=m +no_defs`;
49
+ }
50
+
51
+ /**
52
+ * Well-known +towgs84 approximations for datums that normally use grid files.
53
+ * These are accurate to ~1-5m, which is sufficient for map display.
54
+ * Grid files (like OSTN15_NTv2_OSGBtoETRS.gsb) cannot run in the browser.
55
+ */
56
+ const DATUM_TOWGS84: Record<string, string> = {
57
+ 'airy': '+towgs84=446.448,-125.157,542.06,0.15,0.247,0.842,-20.489', // OSGB36 (UK)
58
+ 'clrk66': '+towgs84=-8,160,176,0,0,0,0', // NAD27 (approx)
59
+ 'GRS80': '+towgs84=0,0,0,0,0,0,0', // GRS80-based (NAD83≈WGS84)
60
+ 'bessel': '+towgs84=598.1,73.7,418.2,0.202,0.045,-2.455,6.7', // DHDN (Germany)
61
+ 'intl': '+towgs84=-87,-98,-121,0,0,0,0', // NZGD49 (NZ)
62
+ 'aust_SA': '+towgs84=-134,-48,149,0,0,0,0', // AGD84 (Australia)
63
+ };
64
+
65
+ /**
66
+ * Strip +nadgrids=... from a proj4 string and add a +towgs84 approximation
67
+ * based on the ellipsoid. Grid files cannot be loaded in the browser.
68
+ */
69
+ function sanitizeProj4(def: string): string {
70
+ if (!def.includes('+nadgrids') || def.includes('+nadgrids=@null')) return def;
71
+
72
+ // Extract the ellipsoid to find the right towgs84 approximation
73
+ const ellpsMatch = def.match(/\+ellps=(\S+)/);
74
+ const ellps = ellpsMatch?.[1] ?? '';
75
+ const towgs84 = DATUM_TOWGS84[ellps] ?? '+towgs84=0,0,0,0,0,0,0';
76
+
77
+ // Remove +nadgrids=... and add +towgs84
78
+ return def.replace(/\+nadgrids=\S+/g, '').replace(/\s+/g, ' ').trim() + ' ' + towgs84;
79
+ }
80
+
81
+ /**
82
+ * Fetch a proj4 definition string from epsg.io (last-resort fallback).
83
+ */
84
+ async function fetchProj4Def(epsgCode: string): Promise<string | null> {
85
+ try {
86
+ const resp = await fetch(`https://epsg.io/${epsgCode}.proj4`);
87
+ if (!resp.ok) return null;
88
+ const text = (await resp.text()).trim();
89
+ if (!text || text.startsWith('<') || text.startsWith('{') || !text.includes('+')) {
90
+ return null;
91
+ }
92
+ return text;
93
+ } catch {
94
+ return null;
95
+ }
96
+ }
97
+
98
+ /**
99
+ * Resolve a proj4 definition for the given ProjectedCRS.
100
+ *
101
+ * Resolution order:
102
+ * 1. Cache hit
103
+ * 2. Bundled EPSG index (7000+ codes with proj4 strings)
104
+ * 3. UTM zone heuristic (from CRS metadata)
105
+ * 4. Fetch from epsg.io (network fallback)
106
+ */
107
+ export async function resolveProjection(crs: ProjectedCRS): Promise<string | null> {
108
+ const code = extractEpsgCode(crs);
109
+
110
+ // 1. Check cache
111
+ if (code && projDefCache.has(code)) {
112
+ return projDefCache.get(code) ?? null;
113
+ }
114
+
115
+ // 2. Bundled EPSG index (primary source — all 7000+ codes)
116
+ if (code) {
117
+ try {
118
+ const bundled = await lookupProj4(code);
119
+ if (bundled) {
120
+ const sanitized = sanitizeProj4(bundled);
121
+ projDefCache.set(code, sanitized);
122
+ return sanitized;
123
+ }
124
+ } catch {
125
+ // EPSG index not loaded yet, continue to fallbacks
126
+ }
127
+ }
128
+
129
+ // 3. UTM zone heuristic
130
+ if (crs.mapZone) {
131
+ const def = utmProj4String(crs.mapZone);
132
+ if (def) {
133
+ if (code) projDefCache.set(code, def);
134
+ return def;
135
+ }
136
+ }
137
+ const name = crs.name?.toUpperCase() ?? '';
138
+ const utmMatch = name.match(/UTM\s+ZONE\s+(\d{1,2}[NS])/i)
139
+ ?? crs.description?.match(/UTM\s+zone\s+(\d{1,2}[NS])/i);
140
+ if (utmMatch) {
141
+ const def = utmProj4String(utmMatch[1]);
142
+ if (def) {
143
+ if (code) projDefCache.set(code, def);
144
+ return def;
145
+ }
146
+ }
147
+
148
+ // 4. Network fallback — fetch from epsg.io
149
+ if (code) {
150
+ const raw = await fetchProj4Def(code);
151
+ const fetched = raw ? sanitizeProj4(raw) : null;
152
+ projDefCache.set(code, fetched);
153
+ return fetched;
154
+ }
155
+
156
+ return null;
157
+ }
158
+
159
+ /**
160
+ * Compute the model center in the projected CRS (easting, northing).
161
+ *
162
+ * The coordinate pipeline is:
163
+ * 1. WASM extracts IFC positions (Z-up) and may apply RTC offset (wasmRtcOffset, Z-up)
164
+ * 2. Mesh collector converts Z-up → Y-up: viewerX = ifcX, viewerY = ifcZ, viewerZ = -ifcY
165
+ * 3. CoordinateHandler may apply originShift (Y-up)
166
+ *
167
+ * To recover IFC world coordinates (Z-up) from the viewer bounds:
168
+ * world_yup = bounds_center + originShift + wasmRtcOffset_as_yup
169
+ * ifc_x = world_yup.x, ifc_y = -world_yup.z, ifc_z = world_yup.y
170
+ *
171
+ * Then the projected CRS coordinates are:
172
+ * easting = mapConversion.eastings + scale * (cos*ifc_x - sin*ifc_y)
173
+ * northing = mapConversion.northings + scale * (sin*ifc_x + cos*ifc_y)
174
+ */
175
+ function computeProjectedCenter(
176
+ conversion: MapConversion,
177
+ coordinateInfo?: CoordinateInfo,
178
+ ): { easting: number; northing: number } {
179
+ const { ifcX, ifcY } = computeLocalIfcCenter(coordinateInfo);
180
+
181
+ // Apply MapConversion rotation + scale + offset
182
+ const scale = conversion.scale ?? 1.0;
183
+ const abscissa = conversion.xAxisAbscissa ?? 1.0;
184
+ const ordinate = conversion.xAxisOrdinate ?? 0.0;
185
+
186
+ const easting = conversion.eastings + scale * (abscissa * ifcX - ordinate * ifcY);
187
+ const northing = conversion.northings + scale * (ordinate * ifcX + abscissa * ifcY);
188
+
189
+ return { easting, northing };
190
+ }
191
+
192
+ /**
193
+ * Reproject the model center from the projected CRS to WGS84 lat/lon.
194
+ *
195
+ * Uses the model's actual geometry bounds + RTC offset to determine where
196
+ * the model sits in the projected coordinate system, then reprojects to WGS84.
197
+ *
198
+ * @param conversion IfcMapConversion (offset, rotation, scale)
199
+ * @param crs IfcProjectedCRS (EPSG code)
200
+ * @param coordinateInfo Geometry coordinate info with bounds and RTC offset
201
+ */
202
+ export async function reprojectToLatLon(
203
+ conversion: MapConversion,
204
+ crs: ProjectedCRS,
205
+ coordinateInfo?: CoordinateInfo,
206
+ ): Promise<LatLon | null> {
207
+ const projDef = await resolveProjection(crs);
208
+ if (!projDef) return null;
209
+
210
+ const { easting, northing } = computeProjectedCenter(conversion, coordinateInfo);
211
+
212
+ try {
213
+ const [lon, lat] = proj4(projDef, 'WGS84', [easting, northing]);
214
+ if (!Number.isFinite(lat) || !Number.isFinite(lon)) return null;
215
+ if (lat < -90 || lat > 90 || lon < -180 || lon > 180) return null;
216
+ return { lat, lon };
217
+ } catch {
218
+ return null;
219
+ }
220
+ }
221
+
222
+ /**
223
+ * Compute the model's local IFC center offset (ifcX, ifcY) from coordinate info.
224
+ * This is the geometry center in IFC Z-up coordinates, before MapConversion is applied.
225
+ */
226
+ function computeLocalIfcCenter(coordinateInfo?: CoordinateInfo): { ifcX: number; ifcY: number } {
227
+ if (!coordinateInfo) return { ifcX: 0, ifcY: 0 };
228
+
229
+ const bounds = coordinateInfo.originalBounds;
230
+ const shift = coordinateInfo.originShift;
231
+ const rtc = coordinateInfo.wasmRtcOffset;
232
+
233
+ const rtcYup = rtc
234
+ ? { x: rtc.x, y: rtc.z, z: -rtc.y }
235
+ : { x: 0, y: 0, z: 0 };
236
+
237
+ const cx = (bounds.min.x + bounds.max.x) / 2;
238
+ const cz = (bounds.min.z + bounds.max.z) / 2;
239
+
240
+ const worldYupX = cx + shift.x + rtcYup.x;
241
+ const worldYupZ = cz + shift.z + rtcYup.z;
242
+
243
+ return { ifcX: worldYupX, ifcY: -worldYupZ };
244
+ }
245
+
246
+ /**
247
+ * Reverse-project a WGS84 lat/lon into the IfcMapConversion eastings/northings
248
+ * values that would place the model center at the given location.
249
+ *
250
+ * This accounts for the model's local geometry offset, rotation, and scale:
251
+ * projected = eastings + scale * (cos*ifcX - sin*ifcY)
252
+ * ⟹ eastings = projected - scale * (cos*ifcX - sin*ifcY)
253
+ */
254
+ export async function reprojectFromLatLon(
255
+ latLon: LatLon,
256
+ crs: ProjectedCRS,
257
+ conversion?: MapConversion,
258
+ coordinateInfo?: CoordinateInfo,
259
+ ): Promise<{ easting: number; northing: number } | null> {
260
+ const projDef = await resolveProjection(crs);
261
+ if (!projDef) return null;
262
+
263
+ try {
264
+ const [projE, projN] = proj4('WGS84', projDef, [latLon.lon, latLon.lat]);
265
+ if (!Number.isFinite(projE) || !Number.isFinite(projN)) return null;
266
+
267
+ // Subtract the rotated/scaled local geometry offset so that
268
+ // the resulting eastings/northings place the model center at this position
269
+ const { ifcX, ifcY } = computeLocalIfcCenter(coordinateInfo);
270
+ const scale = conversion?.scale ?? 1.0;
271
+ const abscissa = conversion?.xAxisAbscissa ?? 1.0;
272
+ const ordinate = conversion?.xAxisOrdinate ?? 0.0;
273
+
274
+ const easting = projE - scale * (abscissa * ifcX - ordinate * ifcY);
275
+ const northing = projN - scale * (ordinate * ifcX + abscissa * ifcY);
276
+
277
+ return { easting, northing };
278
+ } catch {
279
+ return null;
280
+ }
281
+ }
282
+
283
+ /**
284
+ * Compute a building footprint rectangle from the model's bounding box and
285
+ * reproject each corner to WGS84 for display as a GeoJSON polygon on a web map.
286
+ *
287
+ * Uses the shiftedBounds (scene-local after RTC) from CoordinateInfo, transforms
288
+ * each corner through the MapConversion pipeline (rotation + scale + offset),
289
+ * then reprojects to lat/lon. The result is a rotated rectangle matching the
290
+ * model's XZ extent on the map.
291
+ *
292
+ * @returns A single GeoJSON-compatible polygon: closed ring of [lon, lat] pairs
293
+ */
294
+ export async function computeFootprintGeoJSON(
295
+ conversion: MapConversion,
296
+ crs: ProjectedCRS,
297
+ coordinateInfo: CoordinateInfo,
298
+ ): Promise<[number, number][] | null> {
299
+ const projDef = await resolveProjection(crs);
300
+ if (!projDef) {
301
+ console.warn('[footprint] failed to resolve projection for CRS:', crs.name);
302
+ return null;
303
+ }
304
+
305
+ const scale = conversion.scale ?? 1.0;
306
+ const abscissa = conversion.xAxisAbscissa ?? 1.0;
307
+ const ordinate = conversion.xAxisOrdinate ?? 0.0;
308
+
309
+ const shift = coordinateInfo.originShift;
310
+ const rtc = coordinateInfo.wasmRtcOffset;
311
+ const rtcYup = rtc
312
+ ? { x: rtc.x, z: -rtc.y }
313
+ : { x: 0, z: 0 };
314
+
315
+ const bounds = coordinateInfo.shiftedBounds;
316
+
317
+ // Four corners of the bounding box on the XZ plane (viewer Y-up)
318
+ const corners = [
319
+ { x: bounds.min.x, z: bounds.min.z },
320
+ { x: bounds.max.x, z: bounds.min.z },
321
+ { x: bounds.max.x, z: bounds.max.z },
322
+ { x: bounds.min.x, z: bounds.max.z },
323
+ ];
324
+
325
+ const ring: [number, number][] = [];
326
+
327
+ for (const c of corners) {
328
+ // Scene-local → world Y-up
329
+ const worldX = c.x + shift.x + rtcYup.x;
330
+ const worldZ = c.z + shift.z + rtcYup.z;
331
+
332
+ // Y-up → IFC Z-up: ifcX = worldX, ifcY = -worldZ
333
+ const ifcX = worldX;
334
+ const ifcY = -worldZ;
335
+
336
+ // MapConversion: local IFC → projected CRS
337
+ const easting = conversion.eastings + scale * (abscissa * ifcX - ordinate * ifcY);
338
+ const northing = conversion.northings + scale * (ordinate * ifcX + abscissa * ifcY);
339
+
340
+ // Projected CRS → WGS84
341
+ try {
342
+ const [lon, lat] = proj4(projDef, 'WGS84', [easting, northing]);
343
+ if (!Number.isFinite(lat) || !Number.isFinite(lon)) return null;
344
+ ring.push([lon, lat]);
345
+ } catch {
346
+ return null;
347
+ }
348
+ }
349
+
350
+ // Close the ring (GeoJSON requirement)
351
+ ring.push(ring[0]);
352
+ return ring;
353
+ }
354
+
355
+ /**
356
+ * Query terrain elevation at a given lat/lon using the Open-Meteo elevation API.
357
+ * Returns height in metres above sea level, or null on failure.
358
+ */
359
+ export async function queryTerrainElevation(latLon: LatLon): Promise<number | null> {
360
+ try {
361
+ const url = `https://api.open-meteo.com/v1/elevation?latitude=${latLon.lat}&longitude=${latLon.lon}`;
362
+ const resp = await fetch(url);
363
+ if (!resp.ok) return null;
364
+ const data = await resp.json();
365
+ const elev = data?.elevation?.[0];
366
+ return typeof elev === 'number' && Number.isFinite(elev) ? elev : null;
367
+ } catch {
368
+ return null;
369
+ }
370
+ }
@@ -18,6 +18,7 @@ import {
18
18
  extractClassificationsOnDemand,
19
19
  extractMaterialsOnDemand,
20
20
  } from '@ifc-lite/parser';
21
+ import { toGlobalIdFromModels } from '@/store/globalId';
21
22
  import type { FederatedModel } from '@/store/types';
22
23
 
23
24
  interface ModelEntry {
@@ -80,12 +81,13 @@ export function createLensDataProvider(
80
81
  },
81
82
 
82
83
  forEachEntity(callback: (globalId: number, modelId: string) => void): void {
84
+ const models = new Map(entries.map((entry) => [entry.id, { idOffset: entry.idOffset }]));
83
85
  for (const entry of entries) {
84
86
  const entities = entry.ifcDataStore.entities;
85
87
  if (!entities) continue;
86
88
  for (let i = 0; i < entities.count; i++) {
87
89
  const expressId = entities.expressId[i];
88
- callback(expressId + entry.idOffset, entry.id);
90
+ callback(toGlobalIdFromModels(models, entry.id, expressId), entry.id);
89
91
  }
90
92
  }
91
93
  },
@@ -103,7 +103,8 @@ export async function cacheFileBlobs(files: File[]): Promise<void> {
103
103
  }
104
104
 
105
105
  /** Retrieve a cached file blob and reconstruct a File object. */
106
- export async function getCachedFile(name: string): Promise<File | null> {
106
+ export async function getCachedFile(target: string | RecentFileEntry): Promise<File | null> {
107
+ const name = typeof target === 'string' ? target : target.name;
107
108
  try {
108
109
  const db = await openDB();
109
110
  const tx = db.transaction(STORE_NAME, 'readonly');
package/src/main.tsx CHANGED
@@ -11,6 +11,7 @@ import ReactDOM from 'react-dom/client';
11
11
  import { ClerkProvider } from '@clerk/clerk-react';
12
12
  import { App } from './App';
13
13
  import './index.css';
14
+ import 'maplibre-gl/dist/maplibre-gl.css';
14
15
 
15
16
  const clerkPublishableKey = (import.meta.env.VITE_CLERK_PUBLISHABLE_KEY as string | undefined)?.trim();
16
17
 
@@ -119,6 +119,13 @@ function escapeCsv(value: string, sep: string): string {
119
119
  * on the same LocalBackend, providing full export support for both
120
120
  * direct dispatch calls and SDK namespace usage.
121
121
  */
122
+ function toBlobPart(content: string | Uint8Array): BlobPart {
123
+ if (typeof content === 'string') return content;
124
+ const bytes = new Uint8Array(content.byteLength);
125
+ bytes.set(content);
126
+ return bytes;
127
+ }
128
+
122
129
  export function createExportAdapter(store: StoreApi): ExportBackendMethods {
123
130
  /** Resolve entity data via the query subsystem */
124
131
  function getEntityData(ref: EntityRef): EntityData | null {
@@ -354,6 +361,11 @@ export function createExportAdapter(store: StoreApi): ExportBackendMethods {
354
361
  model.ifcDataStore,
355
362
  options.includeMutations === false ? undefined : getMutationViewForModel(store, modelId) ?? undefined,
356
363
  );
364
+ // Include georeferencing mutations if present
365
+ const georefMutations = options.includeMutations !== false
366
+ ? state.georefMutations?.get(modelId) ?? undefined
367
+ : undefined;
368
+
357
369
  const exportOptions: StepExportOptions = {
358
370
  schema: options.schema ?? model.ifcDataStore.schemaVersion,
359
371
  includeGeometry: true,
@@ -364,6 +376,7 @@ export function createExportAdapter(store: StoreApi): ExportBackendMethods {
364
376
  visibleOnly,
365
377
  hiddenEntityIds,
366
378
  isolatedEntityIds,
379
+ georefMutations,
367
380
  };
368
381
 
369
382
  return exporter.export(exportOptions).content;
@@ -381,7 +394,7 @@ function triggerDownload(content: string | Uint8Array, filename: string, mimeTyp
381
394
  if (typeof document === 'undefined') {
382
395
  throw new Error('download() requires a browser environment (document is unavailable)');
383
396
  }
384
- const blob = new Blob([content], { type: mimeType });
397
+ const blob = new Blob([toBlobPart(content)], { type: mimeType });
385
398
  const url = URL.createObjectURL(blob);
386
399
  const a = document.createElement('a');
387
400
  a.href = url;
@@ -5,6 +5,7 @@
5
5
  import type { EntityRef, SectionPlane, CameraState, ViewerBackendMethods } from '@ifc-lite/sdk';
6
6
  import type { StoreApi } from './types.js';
7
7
  import { getModelForRef } from './model-compat.js';
8
+ import { toGlobalIdForRef } from '../../store/globalId.js';
8
9
 
9
10
  const AXIS_TO_STORE: Record<string, 'down' | 'front' | 'side'> = {
10
11
  x: 'side',
@@ -25,11 +26,8 @@ export function createViewerAdapter(store: StoreApi): ViewerBackendMethods {
25
26
  const existing = state.pendingColorUpdates;
26
27
  const colorMap = existing ? new Map(existing) : new Map<number, [number, number, number, number]>();
27
28
  for (const ref of refs) {
28
- const model = getModelForRef(state, ref.modelId);
29
- if (model) {
30
- const globalId = ref.expressId + model.idOffset;
31
- colorMap.set(globalId, color);
32
- }
29
+ if (!getModelForRef(state, ref.modelId)) continue;
30
+ colorMap.set(toGlobalIdForRef(state.models, ref), color);
33
31
  }
34
32
  state.setPendingColorUpdates(colorMap);
35
33
  return undefined;
@@ -41,10 +39,8 @@ export function createViewerAdapter(store: StoreApi): ViewerBackendMethods {
41
39
  const batchMap = new Map<number, [number, number, number, number]>();
42
40
  for (const batch of batches) {
43
41
  for (const ref of batch.refs) {
44
- const model = getModelForRef(state, ref.modelId);
45
- if (model) {
46
- batchMap.set(ref.expressId + model.idOffset, batch.color);
47
- }
42
+ if (!getModelForRef(state, ref.modelId)) continue;
43
+ batchMap.set(toGlobalIdForRef(state.models, ref), batch.color);
48
44
  }
49
45
  }
50
46
  state.setPendingColorUpdates(batchMap);
@@ -6,6 +6,7 @@ import type { EntityRef, VisibilityBackendMethods } from '@ifc-lite/sdk';
6
6
  import type { StoreApi } from './types.js';
7
7
  import { getModelForRef, type ModelLike } from './model-compat.js';
8
8
  import { collectSpatialSubtreeElementsWithIfcSpace } from '../../store/basketVisibleSet.js';
9
+ import { toGlobalIdForRef, toGlobalIdFromModels } from '../../store/globalId.js';
9
10
  import { isSpaceLikeSpatialTypeName, isSpatialStructureTypeName, type SpatialNode } from '@ifc-lite/data';
10
11
 
11
12
  function findDescendantNode(root: SpatialNode, expressId: number): SpatialNode | null {
@@ -49,10 +50,8 @@ export function createVisibilityAdapter(store: StoreApi): VisibilityBackendMetho
49
50
  // hiddenEntities set (global IDs), not hiddenEntitiesByModel.
50
51
  const globalIds: number[] = [];
51
52
  for (const ref of refs) {
52
- const model = getModelForRef(state, ref.modelId);
53
- if (model) {
54
- globalIds.push(ref.expressId + model.idOffset);
55
- }
53
+ if (!getModelForRef(state, ref.modelId)) continue;
54
+ globalIds.push(toGlobalIdForRef(state.models, ref));
56
55
  }
57
56
  if (globalIds.length > 0) {
58
57
  state.hideEntities(globalIds);
@@ -63,10 +62,8 @@ export function createVisibilityAdapter(store: StoreApi): VisibilityBackendMetho
63
62
  const state = store.getState();
64
63
  const globalIds: number[] = [];
65
64
  for (const ref of refs) {
66
- const model = getModelForRef(state, ref.modelId);
67
- if (model) {
68
- globalIds.push(ref.expressId + model.idOffset);
69
- }
65
+ if (!getModelForRef(state, ref.modelId)) continue;
66
+ globalIds.push(toGlobalIdForRef(state.models, ref));
70
67
  }
71
68
  if (globalIds.length > 0) {
72
69
  state.showEntities(globalIds);
@@ -81,7 +78,7 @@ export function createVisibilityAdapter(store: StoreApi): VisibilityBackendMetho
81
78
  if (model) {
82
79
  const expanded = expandSpatialRef(ref, model);
83
80
  for (const id of expanded) {
84
- globalIds.push(id + model.idOffset);
81
+ globalIds.push(toGlobalIdFromModels(state.models, ref.modelId, id));
85
82
  }
86
83
  }
87
84
  }
@@ -0,0 +1,125 @@
1
+ /* This Source Code Form is subject to the terms of the Mozilla Public
2
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
3
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
+
5
+ import type { ComponentType, ReactNode } from 'react';
6
+
7
+ export type AnalysisExtensionPlacement = 'right' | 'bottom';
8
+
9
+ export interface AnalysisExtensionRenderProps {
10
+ onClose: () => void;
11
+ }
12
+
13
+ export interface AnalysisExtensionDefinition {
14
+ id: string;
15
+ label: string;
16
+ description?: string;
17
+ placement?: AnalysisExtensionPlacement;
18
+ icon: ComponentType<{ className?: string }>;
19
+ renderPanel: (props: AnalysisExtensionRenderProps) => ReactNode;
20
+ onBeforeOpen?: () => boolean | void;
21
+ }
22
+
23
+ export interface AnalysisExtensionsSnapshot {
24
+ activeId: string | null;
25
+ extensions: AnalysisExtensionDefinition[];
26
+ }
27
+
28
+ const listeners = new Set<() => void>();
29
+ const extensions = new Map<string, AnalysisExtensionDefinition>();
30
+
31
+ let activeId: string | null = null;
32
+ let snapshot: AnalysisExtensionsSnapshot = {
33
+ activeId,
34
+ extensions: [],
35
+ };
36
+
37
+ function rebuildSnapshot(): void {
38
+ snapshot = {
39
+ activeId,
40
+ extensions: Array.from(extensions.values()),
41
+ };
42
+ }
43
+
44
+ function emit(): void {
45
+ rebuildSnapshot();
46
+ listeners.forEach((listener) => listener());
47
+ }
48
+
49
+ function setActiveId(nextActiveId: string | null): void {
50
+ if (activeId === nextActiveId) {
51
+ return;
52
+ }
53
+ activeId = nextActiveId;
54
+ emit();
55
+ }
56
+
57
+ function canOpen(definition: AnalysisExtensionDefinition): boolean {
58
+ return definition.onBeforeOpen?.() !== false;
59
+ }
60
+
61
+ export function subscribeAnalysisExtensions(listener: () => void): () => void {
62
+ listeners.add(listener);
63
+ return () => {
64
+ listeners.delete(listener);
65
+ };
66
+ }
67
+
68
+ export function getAnalysisExtensionsSnapshot(): AnalysisExtensionsSnapshot {
69
+ return snapshot;
70
+ }
71
+
72
+ export function getAnalysisExtensionById(id: string | null | undefined): AnalysisExtensionDefinition | null {
73
+ if (!id) {
74
+ return null;
75
+ }
76
+ return extensions.get(id) ?? null;
77
+ }
78
+
79
+ export function closeActiveAnalysisExtension(): void {
80
+ setActiveId(null);
81
+ }
82
+
83
+ export function openAnalysisExtension(id: string): boolean {
84
+ const definition = extensions.get(id);
85
+ if (!definition) {
86
+ return false;
87
+ }
88
+ if (!canOpen(definition)) {
89
+ return false;
90
+ }
91
+ setActiveId(id);
92
+ return true;
93
+ }
94
+
95
+ export function toggleAnalysisExtension(id: string): boolean {
96
+ if (activeId === id) {
97
+ closeActiveAnalysisExtension();
98
+ return false;
99
+ }
100
+ return openAnalysisExtension(id);
101
+ }
102
+
103
+ export function registerAnalysisExtensions(definitions: AnalysisExtensionDefinition[]): () => void {
104
+ const nextEntries = definitions.map((definition) => [definition.id, definition] as const);
105
+ nextEntries.forEach(([id, definition]) => {
106
+ extensions.set(id, definition);
107
+ });
108
+ emit();
109
+
110
+ return () => {
111
+ let shouldEmit = false;
112
+ for (const [id] of nextEntries) {
113
+ if (extensions.delete(id)) {
114
+ shouldEmit = true;
115
+ }
116
+ if (activeId === id) {
117
+ activeId = null;
118
+ shouldEmit = true;
119
+ }
120
+ }
121
+ if (shouldEmit) {
122
+ emit();
123
+ }
124
+ };
125
+ }
@@ -0,0 +1,13 @@
1
+ /* This Source Code Form is subject to the terms of the Mozilla Public
2
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
3
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
+
5
+ export function navigateToPath(path: string, options: { replace?: boolean } = {}): void {
6
+ const { replace = false } = options;
7
+ if (replace) {
8
+ window.history.replaceState({}, '', path);
9
+ } else {
10
+ window.history.pushState({}, '', path);
11
+ }
12
+ window.dispatchEvent(new PopStateEvent('popstate'));
13
+ }