@ifc-lite/viewer 1.17.3 → 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 (495) hide show
  1. package/.turbo/turbo-build.log +39 -30
  2. package/.turbo/turbo-typecheck.log +1 -1
  3. package/CHANGELOG.md +15 -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-D5-QWGO9.js → bcf-DOG9_WPX.js} +1 -1
  8. package/dist/assets/{browser-CKs-FY1P.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/{exporters-C_6J153K.js → exporters-ChAtBmlj.js} +2225 -1754
  12. package/dist/assets/geometry.worker-BQ0rzNo-.js +1 -0
  13. package/dist/assets/ifc-lite_bg-BX4E7TX8.wasm +0 -0
  14. package/dist/assets/{index-jhBr1wbn.js → index-Co8E2-FE.js} +28959 -24612
  15. package/dist/assets/index-DckuDqlv.css +1 -0
  16. package/dist/assets/{maplibre-gl-BpvwNKKy.js → maplibre-gl-CGLcoNXc.js} +1 -1
  17. package/dist/assets/native-bridge-BRvbckFQ.js +429 -0
  18. package/dist/assets/{sandbox-B79eavQ3.js → sandbox-DZiNLNMk.js} +5 -5
  19. package/dist/assets/{server-client-D3bUPJJc.js → server-client-BV8zHZ7Y.js} +4 -4
  20. package/dist/assets/tauri-core-stub-D8Fa-u43.js +1 -0
  21. package/dist/assets/tauri-dialog-stub-r7Wksg7o.js +1 -0
  22. package/dist/assets/tauri-fs-stub-BdeRC7aK.js +1 -0
  23. package/dist/assets/wasm-bridge-g01g7T9b.js +1 -0
  24. package/dist/assets/{zip-B-jFFAGa.js → zip-DBEtpeu6.js} +3 -3
  25. package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_0.json +1 -0
  26. package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_1.json +1 -0
  27. package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_10.json +1 -0
  28. package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_11.json +1 -0
  29. package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_12.json +1 -0
  30. package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_13.json +1 -0
  31. package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_14.json +1 -0
  32. package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_15.json +1 -0
  33. package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_16.json +1 -0
  34. package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_17.json +1 -0
  35. package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_18.json +1 -0
  36. package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_19.json +1 -0
  37. package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_2.json +1 -0
  38. package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_20.json +1 -0
  39. package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_21.json +1 -0
  40. package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_22.json +1 -0
  41. package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_23.json +1 -0
  42. package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_24.json +1 -0
  43. package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_25.json +1 -0
  44. package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_26.json +1 -0
  45. package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_27.json +1 -0
  46. package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_3.json +1 -0
  47. package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_4.json +1 -0
  48. package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_5.json +1 -0
  49. package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_6.json +1 -0
  50. package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_7.json +1 -0
  51. package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_8.json +1 -0
  52. package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_9.json +1 -0
  53. package/dist/cesium/Assets/Images/bing_maps_credit.png +0 -0
  54. package/dist/cesium/Assets/Images/cesium_credit.png +0 -0
  55. package/dist/cesium/Assets/Images/google_earth_credit.png +0 -0
  56. package/dist/cesium/Assets/Images/ion-credit.png +0 -0
  57. package/dist/cesium/Assets/Textures/LensFlare/DirtMask.jpg +0 -0
  58. package/dist/cesium/Assets/Textures/LensFlare/StarBurst.jpg +0 -0
  59. package/dist/cesium/Assets/Textures/NaturalEarthII/0/0/0.jpg +0 -0
  60. package/dist/cesium/Assets/Textures/NaturalEarthII/0/1/0.jpg +0 -0
  61. package/dist/cesium/Assets/Textures/NaturalEarthII/1/0/0.jpg +0 -0
  62. package/dist/cesium/Assets/Textures/NaturalEarthII/1/0/1.jpg +0 -0
  63. package/dist/cesium/Assets/Textures/NaturalEarthII/1/1/0.jpg +0 -0
  64. package/dist/cesium/Assets/Textures/NaturalEarthII/1/1/1.jpg +0 -0
  65. package/dist/cesium/Assets/Textures/NaturalEarthII/1/2/0.jpg +0 -0
  66. package/dist/cesium/Assets/Textures/NaturalEarthII/1/2/1.jpg +0 -0
  67. package/dist/cesium/Assets/Textures/NaturalEarthII/1/3/0.jpg +0 -0
  68. package/dist/cesium/Assets/Textures/NaturalEarthII/1/3/1.jpg +0 -0
  69. package/dist/cesium/Assets/Textures/NaturalEarthII/2/0/0.jpg +0 -0
  70. package/dist/cesium/Assets/Textures/NaturalEarthII/2/0/1.jpg +0 -0
  71. package/dist/cesium/Assets/Textures/NaturalEarthII/2/0/2.jpg +0 -0
  72. package/dist/cesium/Assets/Textures/NaturalEarthII/2/0/3.jpg +0 -0
  73. package/dist/cesium/Assets/Textures/NaturalEarthII/2/1/0.jpg +0 -0
  74. package/dist/cesium/Assets/Textures/NaturalEarthII/2/1/1.jpg +0 -0
  75. package/dist/cesium/Assets/Textures/NaturalEarthII/2/1/2.jpg +0 -0
  76. package/dist/cesium/Assets/Textures/NaturalEarthII/2/1/3.jpg +0 -0
  77. package/dist/cesium/Assets/Textures/NaturalEarthII/2/2/0.jpg +0 -0
  78. package/dist/cesium/Assets/Textures/NaturalEarthII/2/2/1.jpg +0 -0
  79. package/dist/cesium/Assets/Textures/NaturalEarthII/2/2/2.jpg +0 -0
  80. package/dist/cesium/Assets/Textures/NaturalEarthII/2/2/3.jpg +0 -0
  81. package/dist/cesium/Assets/Textures/NaturalEarthII/2/3/0.jpg +0 -0
  82. package/dist/cesium/Assets/Textures/NaturalEarthII/2/3/1.jpg +0 -0
  83. package/dist/cesium/Assets/Textures/NaturalEarthII/2/3/2.jpg +0 -0
  84. package/dist/cesium/Assets/Textures/NaturalEarthII/2/3/3.jpg +0 -0
  85. package/dist/cesium/Assets/Textures/NaturalEarthII/2/4/0.jpg +0 -0
  86. package/dist/cesium/Assets/Textures/NaturalEarthII/2/4/1.jpg +0 -0
  87. package/dist/cesium/Assets/Textures/NaturalEarthII/2/4/2.jpg +0 -0
  88. package/dist/cesium/Assets/Textures/NaturalEarthII/2/4/3.jpg +0 -0
  89. package/dist/cesium/Assets/Textures/NaturalEarthII/2/5/0.jpg +0 -0
  90. package/dist/cesium/Assets/Textures/NaturalEarthII/2/5/1.jpg +0 -0
  91. package/dist/cesium/Assets/Textures/NaturalEarthII/2/5/2.jpg +0 -0
  92. package/dist/cesium/Assets/Textures/NaturalEarthII/2/5/3.jpg +0 -0
  93. package/dist/cesium/Assets/Textures/NaturalEarthII/2/6/0.jpg +0 -0
  94. package/dist/cesium/Assets/Textures/NaturalEarthII/2/6/1.jpg +0 -0
  95. package/dist/cesium/Assets/Textures/NaturalEarthII/2/6/2.jpg +0 -0
  96. package/dist/cesium/Assets/Textures/NaturalEarthII/2/6/3.jpg +0 -0
  97. package/dist/cesium/Assets/Textures/NaturalEarthII/2/7/0.jpg +0 -0
  98. package/dist/cesium/Assets/Textures/NaturalEarthII/2/7/1.jpg +0 -0
  99. package/dist/cesium/Assets/Textures/NaturalEarthII/2/7/2.jpg +0 -0
  100. package/dist/cesium/Assets/Textures/NaturalEarthII/2/7/3.jpg +0 -0
  101. package/dist/cesium/Assets/Textures/NaturalEarthII/tilemapresource.xml +14 -0
  102. package/dist/cesium/Assets/Textures/SkyBox/tycho2t3_80_mx.jpg +0 -0
  103. package/dist/cesium/Assets/Textures/SkyBox/tycho2t3_80_my.jpg +0 -0
  104. package/dist/cesium/Assets/Textures/SkyBox/tycho2t3_80_mz.jpg +0 -0
  105. package/dist/cesium/Assets/Textures/SkyBox/tycho2t3_80_px.jpg +0 -0
  106. package/dist/cesium/Assets/Textures/SkyBox/tycho2t3_80_py.jpg +0 -0
  107. package/dist/cesium/Assets/Textures/SkyBox/tycho2t3_80_pz.jpg +0 -0
  108. package/dist/cesium/Assets/Textures/maki/airfield.png +0 -0
  109. package/dist/cesium/Assets/Textures/maki/airport.png +0 -0
  110. package/dist/cesium/Assets/Textures/maki/alcohol-shop.png +0 -0
  111. package/dist/cesium/Assets/Textures/maki/america-football.png +0 -0
  112. package/dist/cesium/Assets/Textures/maki/art-gallery.png +0 -0
  113. package/dist/cesium/Assets/Textures/maki/bakery.png +0 -0
  114. package/dist/cesium/Assets/Textures/maki/bank.png +0 -0
  115. package/dist/cesium/Assets/Textures/maki/bar.png +0 -0
  116. package/dist/cesium/Assets/Textures/maki/baseball.png +0 -0
  117. package/dist/cesium/Assets/Textures/maki/basketball.png +0 -0
  118. package/dist/cesium/Assets/Textures/maki/beer.png +0 -0
  119. package/dist/cesium/Assets/Textures/maki/bicycle.png +0 -0
  120. package/dist/cesium/Assets/Textures/maki/building.png +0 -0
  121. package/dist/cesium/Assets/Textures/maki/bus.png +0 -0
  122. package/dist/cesium/Assets/Textures/maki/cafe.png +0 -0
  123. package/dist/cesium/Assets/Textures/maki/camera.png +0 -0
  124. package/dist/cesium/Assets/Textures/maki/campsite.png +0 -0
  125. package/dist/cesium/Assets/Textures/maki/car.png +0 -0
  126. package/dist/cesium/Assets/Textures/maki/cemetery.png +0 -0
  127. package/dist/cesium/Assets/Textures/maki/cesium.png +0 -0
  128. package/dist/cesium/Assets/Textures/maki/chemist.png +0 -0
  129. package/dist/cesium/Assets/Textures/maki/cinema.png +0 -0
  130. package/dist/cesium/Assets/Textures/maki/circle-stroked.png +0 -0
  131. package/dist/cesium/Assets/Textures/maki/circle.png +0 -0
  132. package/dist/cesium/Assets/Textures/maki/city.png +0 -0
  133. package/dist/cesium/Assets/Textures/maki/clothing-store.png +0 -0
  134. package/dist/cesium/Assets/Textures/maki/college.png +0 -0
  135. package/dist/cesium/Assets/Textures/maki/commercial.png +0 -0
  136. package/dist/cesium/Assets/Textures/maki/cricket.png +0 -0
  137. package/dist/cesium/Assets/Textures/maki/cross.png +0 -0
  138. package/dist/cesium/Assets/Textures/maki/dam.png +0 -0
  139. package/dist/cesium/Assets/Textures/maki/danger.png +0 -0
  140. package/dist/cesium/Assets/Textures/maki/disability.png +0 -0
  141. package/dist/cesium/Assets/Textures/maki/dog-park.png +0 -0
  142. package/dist/cesium/Assets/Textures/maki/embassy.png +0 -0
  143. package/dist/cesium/Assets/Textures/maki/emergency-telephone.png +0 -0
  144. package/dist/cesium/Assets/Textures/maki/entrance.png +0 -0
  145. package/dist/cesium/Assets/Textures/maki/farm.png +0 -0
  146. package/dist/cesium/Assets/Textures/maki/fast-food.png +0 -0
  147. package/dist/cesium/Assets/Textures/maki/ferry.png +0 -0
  148. package/dist/cesium/Assets/Textures/maki/fire-station.png +0 -0
  149. package/dist/cesium/Assets/Textures/maki/fuel.png +0 -0
  150. package/dist/cesium/Assets/Textures/maki/garden.png +0 -0
  151. package/dist/cesium/Assets/Textures/maki/gift.png +0 -0
  152. package/dist/cesium/Assets/Textures/maki/golf.png +0 -0
  153. package/dist/cesium/Assets/Textures/maki/grocery.png +0 -0
  154. package/dist/cesium/Assets/Textures/maki/hairdresser.png +0 -0
  155. package/dist/cesium/Assets/Textures/maki/harbor.png +0 -0
  156. package/dist/cesium/Assets/Textures/maki/heart.png +0 -0
  157. package/dist/cesium/Assets/Textures/maki/heliport.png +0 -0
  158. package/dist/cesium/Assets/Textures/maki/hospital.png +0 -0
  159. package/dist/cesium/Assets/Textures/maki/ice-cream.png +0 -0
  160. package/dist/cesium/Assets/Textures/maki/industrial.png +0 -0
  161. package/dist/cesium/Assets/Textures/maki/land-use.png +0 -0
  162. package/dist/cesium/Assets/Textures/maki/laundry.png +0 -0
  163. package/dist/cesium/Assets/Textures/maki/library.png +0 -0
  164. package/dist/cesium/Assets/Textures/maki/lighthouse.png +0 -0
  165. package/dist/cesium/Assets/Textures/maki/lodging.png +0 -0
  166. package/dist/cesium/Assets/Textures/maki/logging.png +0 -0
  167. package/dist/cesium/Assets/Textures/maki/london-underground.png +0 -0
  168. package/dist/cesium/Assets/Textures/maki/marker-stroked.png +0 -0
  169. package/dist/cesium/Assets/Textures/maki/marker.png +0 -0
  170. package/dist/cesium/Assets/Textures/maki/minefield.png +0 -0
  171. package/dist/cesium/Assets/Textures/maki/mobilephone.png +0 -0
  172. package/dist/cesium/Assets/Textures/maki/monument.png +0 -0
  173. package/dist/cesium/Assets/Textures/maki/museum.png +0 -0
  174. package/dist/cesium/Assets/Textures/maki/music.png +0 -0
  175. package/dist/cesium/Assets/Textures/maki/oil-well.png +0 -0
  176. package/dist/cesium/Assets/Textures/maki/park.png +0 -0
  177. package/dist/cesium/Assets/Textures/maki/park2.png +0 -0
  178. package/dist/cesium/Assets/Textures/maki/parking-garage.png +0 -0
  179. package/dist/cesium/Assets/Textures/maki/parking.png +0 -0
  180. package/dist/cesium/Assets/Textures/maki/pharmacy.png +0 -0
  181. package/dist/cesium/Assets/Textures/maki/pitch.png +0 -0
  182. package/dist/cesium/Assets/Textures/maki/place-of-worship.png +0 -0
  183. package/dist/cesium/Assets/Textures/maki/playground.png +0 -0
  184. package/dist/cesium/Assets/Textures/maki/police.png +0 -0
  185. package/dist/cesium/Assets/Textures/maki/polling-place.png +0 -0
  186. package/dist/cesium/Assets/Textures/maki/post.png +0 -0
  187. package/dist/cesium/Assets/Textures/maki/prison.png +0 -0
  188. package/dist/cesium/Assets/Textures/maki/rail-above.png +0 -0
  189. package/dist/cesium/Assets/Textures/maki/rail-light.png +0 -0
  190. package/dist/cesium/Assets/Textures/maki/rail-metro.png +0 -0
  191. package/dist/cesium/Assets/Textures/maki/rail-underground.png +0 -0
  192. package/dist/cesium/Assets/Textures/maki/rail.png +0 -0
  193. package/dist/cesium/Assets/Textures/maki/religious-christian.png +0 -0
  194. package/dist/cesium/Assets/Textures/maki/religious-jewish.png +0 -0
  195. package/dist/cesium/Assets/Textures/maki/religious-muslim.png +0 -0
  196. package/dist/cesium/Assets/Textures/maki/restaurant.png +0 -0
  197. package/dist/cesium/Assets/Textures/maki/roadblock.png +0 -0
  198. package/dist/cesium/Assets/Textures/maki/rocket.png +0 -0
  199. package/dist/cesium/Assets/Textures/maki/school.png +0 -0
  200. package/dist/cesium/Assets/Textures/maki/scooter.png +0 -0
  201. package/dist/cesium/Assets/Textures/maki/shop.png +0 -0
  202. package/dist/cesium/Assets/Textures/maki/skiing.png +0 -0
  203. package/dist/cesium/Assets/Textures/maki/slaughterhouse.png +0 -0
  204. package/dist/cesium/Assets/Textures/maki/soccer.png +0 -0
  205. package/dist/cesium/Assets/Textures/maki/square-stroked.png +0 -0
  206. package/dist/cesium/Assets/Textures/maki/square.png +0 -0
  207. package/dist/cesium/Assets/Textures/maki/star-stroked.png +0 -0
  208. package/dist/cesium/Assets/Textures/maki/star.png +0 -0
  209. package/dist/cesium/Assets/Textures/maki/suitcase.png +0 -0
  210. package/dist/cesium/Assets/Textures/maki/swimming.png +0 -0
  211. package/dist/cesium/Assets/Textures/maki/telephone.png +0 -0
  212. package/dist/cesium/Assets/Textures/maki/tennis.png +0 -0
  213. package/dist/cesium/Assets/Textures/maki/theatre.png +0 -0
  214. package/dist/cesium/Assets/Textures/maki/toilets.png +0 -0
  215. package/dist/cesium/Assets/Textures/maki/town-hall.png +0 -0
  216. package/dist/cesium/Assets/Textures/maki/town.png +0 -0
  217. package/dist/cesium/Assets/Textures/maki/triangle-stroked.png +0 -0
  218. package/dist/cesium/Assets/Textures/maki/triangle.png +0 -0
  219. package/dist/cesium/Assets/Textures/maki/village.png +0 -0
  220. package/dist/cesium/Assets/Textures/maki/warehouse.png +0 -0
  221. package/dist/cesium/Assets/Textures/maki/waste-basket.png +0 -0
  222. package/dist/cesium/Assets/Textures/maki/water.png +0 -0
  223. package/dist/cesium/Assets/Textures/maki/wetland.png +0 -0
  224. package/dist/cesium/Assets/Textures/maki/zoo.png +0 -0
  225. package/dist/cesium/Assets/Textures/moonSmall.jpg +0 -0
  226. package/dist/cesium/Assets/Textures/pin.svg +1 -0
  227. package/dist/cesium/Assets/Textures/waterNormals.jpg +0 -0
  228. package/dist/cesium/Assets/Textures/waterNormalsSmall.jpg +0 -0
  229. package/dist/cesium/Assets/approximateTerrainHeights.json +1 -0
  230. package/dist/cesium/ThirdParty/Workers/package.json +1 -0
  231. package/dist/cesium/ThirdParty/Workers/zip-web-worker.js +1 -0
  232. package/dist/cesium/ThirdParty/basis_transcoder.wasm +0 -0
  233. package/dist/cesium/ThirdParty/draco_decoder.wasm +0 -0
  234. package/dist/cesium/ThirdParty/google-earth-dbroot-parser.js +1 -0
  235. package/dist/cesium/ThirdParty/wasm_splats_bg.wasm +0 -0
  236. package/dist/cesium/ThirdParty/zip-module.wasm +0 -0
  237. package/dist/cesium/Widgets/Animation/Animation.css +127 -0
  238. package/dist/cesium/Widgets/Animation/lighter.css +70 -0
  239. package/dist/cesium/Widgets/BaseLayerPicker/BaseLayerPicker.css +108 -0
  240. package/dist/cesium/Widgets/BaseLayerPicker/lighter.css +22 -0
  241. package/dist/cesium/Widgets/Cesium3DTilesInspector/Cesium3DTilesInspector.css +102 -0
  242. package/dist/cesium/Widgets/CesiumInspector/CesiumInspector.css +113 -0
  243. package/dist/cesium/Widgets/CesiumWidget/CesiumWidget.css +119 -0
  244. package/dist/cesium/Widgets/CesiumWidget/lighter.css +14 -0
  245. package/dist/cesium/Widgets/FullscreenButton/FullscreenButton.css +8 -0
  246. package/dist/cesium/Widgets/Geocoder/Geocoder.css +70 -0
  247. package/dist/cesium/Widgets/Geocoder/lighter.css +17 -0
  248. package/dist/cesium/Widgets/I3SBuildingSceneLayerExplorer/I3SBuildingSceneLayerExplorer.css +27 -0
  249. package/dist/cesium/Widgets/Images/ImageryProviders/ArcGisMapServiceWorldHillshade.png +0 -0
  250. package/dist/cesium/Widgets/Images/ImageryProviders/ArcGisMapServiceWorldImagery.png +0 -0
  251. package/dist/cesium/Widgets/Images/ImageryProviders/ArcGisMapServiceWorldOcean.png +0 -0
  252. package/dist/cesium/Widgets/Images/ImageryProviders/azureAerial.png +0 -0
  253. package/dist/cesium/Widgets/Images/ImageryProviders/azureRoads.png +0 -0
  254. package/dist/cesium/Widgets/Images/ImageryProviders/bingAerial.png +0 -0
  255. package/dist/cesium/Widgets/Images/ImageryProviders/bingAerialLabels.png +0 -0
  256. package/dist/cesium/Widgets/Images/ImageryProviders/bingRoads.png +0 -0
  257. package/dist/cesium/Widgets/Images/ImageryProviders/blueMarble.png +0 -0
  258. package/dist/cesium/Widgets/Images/ImageryProviders/earthAtNight.png +0 -0
  259. package/dist/cesium/Widgets/Images/ImageryProviders/googleContour.png +0 -0
  260. package/dist/cesium/Widgets/Images/ImageryProviders/googleRoadmap.png +0 -0
  261. package/dist/cesium/Widgets/Images/ImageryProviders/googleSatellite.png +0 -0
  262. package/dist/cesium/Widgets/Images/ImageryProviders/googleSatelliteLabels.png +0 -0
  263. package/dist/cesium/Widgets/Images/ImageryProviders/mapQuestOpenStreetMap.png +0 -0
  264. package/dist/cesium/Widgets/Images/ImageryProviders/mapboxSatellite.png +0 -0
  265. package/dist/cesium/Widgets/Images/ImageryProviders/mapboxStreets.png +0 -0
  266. package/dist/cesium/Widgets/Images/ImageryProviders/mapboxTerrain.png +0 -0
  267. package/dist/cesium/Widgets/Images/ImageryProviders/naturalEarthII.png +0 -0
  268. package/dist/cesium/Widgets/Images/ImageryProviders/openStreetMap.png +0 -0
  269. package/dist/cesium/Widgets/Images/ImageryProviders/sentinel-2.png +0 -0
  270. package/dist/cesium/Widgets/Images/ImageryProviders/stadiaAlidadeSmooth.png +0 -0
  271. package/dist/cesium/Widgets/Images/ImageryProviders/stadiaAlidadeSmoothDark.png +0 -0
  272. package/dist/cesium/Widgets/Images/ImageryProviders/stamenToner.png +0 -0
  273. package/dist/cesium/Widgets/Images/ImageryProviders/stamenWatercolor.png +0 -0
  274. package/dist/cesium/Widgets/Images/NavigationHelp/Mouse.svg +84 -0
  275. package/dist/cesium/Widgets/Images/NavigationHelp/MouseLeft.svg +76 -0
  276. package/dist/cesium/Widgets/Images/NavigationHelp/MouseMiddle.svg +76 -0
  277. package/dist/cesium/Widgets/Images/NavigationHelp/MouseRight.svg +76 -0
  278. package/dist/cesium/Widgets/Images/NavigationHelp/Touch.svg +120 -0
  279. package/dist/cesium/Widgets/Images/NavigationHelp/TouchDrag.svg +129 -0
  280. package/dist/cesium/Widgets/Images/NavigationHelp/TouchRotate.svg +76 -0
  281. package/dist/cesium/Widgets/Images/NavigationHelp/TouchTilt.svg +135 -0
  282. package/dist/cesium/Widgets/Images/NavigationHelp/TouchZoom.svg +74 -0
  283. package/dist/cesium/Widgets/Images/TerrainProviders/CesiumWorldTerrain.png +0 -0
  284. package/dist/cesium/Widgets/Images/TerrainProviders/Ellipsoid.png +0 -0
  285. package/dist/cesium/Widgets/Images/TimelineIcons.png +0 -0
  286. package/dist/cesium/Widgets/Images/info-loading.gif +0 -0
  287. package/dist/cesium/Widgets/InfoBox/InfoBox.css +92 -0
  288. package/dist/cesium/Widgets/InfoBox/InfoBoxDescription.css +178 -0
  289. package/dist/cesium/Widgets/NavigationHelpButton/NavigationHelpButton.css +93 -0
  290. package/dist/cesium/Widgets/NavigationHelpButton/lighter.css +38 -0
  291. package/dist/cesium/Widgets/PerformanceWatchdog/PerformanceWatchdog.css +15 -0
  292. package/dist/cesium/Widgets/ProjectionPicker/ProjectionPicker.css +38 -0
  293. package/dist/cesium/Widgets/SceneModePicker/SceneModePicker.css +56 -0
  294. package/dist/cesium/Widgets/SelectionIndicator/SelectionIndicator.css +20 -0
  295. package/dist/cesium/Widgets/Timeline/Timeline.css +103 -0
  296. package/dist/cesium/Widgets/Timeline/lighter.css +23 -0
  297. package/dist/cesium/Widgets/VRButton/VRButton.css +8 -0
  298. package/dist/cesium/Widgets/Viewer/Viewer.css +107 -0
  299. package/dist/cesium/Widgets/VoxelInspector/VoxelInspector.css +16 -0
  300. package/dist/cesium/Widgets/lighter.css +237 -0
  301. package/dist/cesium/Widgets/lighterShared.css +46 -0
  302. package/dist/cesium/Widgets/shared.css +103 -0
  303. package/dist/cesium/Widgets/widgets.css +1342 -0
  304. package/dist/cesium/Workers/chunk-23ZQ2IVV.js +29 -0
  305. package/dist/cesium/Workers/chunk-2EQO3Q56.js +26 -0
  306. package/dist/cesium/Workers/chunk-2MJIIVP4.js +26 -0
  307. package/dist/cesium/Workers/chunk-2TE5NTVD.js +26 -0
  308. package/dist/cesium/Workers/chunk-2ZBHLJST.js +26 -0
  309. package/dist/cesium/Workers/chunk-5TJMAQVL.js +26 -0
  310. package/dist/cesium/Workers/chunk-6BD4U3VO.js +26 -0
  311. package/dist/cesium/Workers/chunk-7TVGLKQF.js +26 -0
  312. package/dist/cesium/Workers/chunk-BTSYJ5XU.js +26 -0
  313. package/dist/cesium/Workers/chunk-BXMEEOCS.js +63 -0
  314. package/dist/cesium/Workers/chunk-BYLCY7GP.js +29 -0
  315. package/dist/cesium/Workers/chunk-CTHM3W6I.js +26 -0
  316. package/dist/cesium/Workers/chunk-CUUSNIVQ.js +26 -0
  317. package/dist/cesium/Workers/chunk-E3JOOS3S.js +26 -0
  318. package/dist/cesium/Workers/chunk-E7KYDCM5.js +26 -0
  319. package/dist/cesium/Workers/chunk-EDVBB7SS.js +27 -0
  320. package/dist/cesium/Workers/chunk-EFBN7QNX.js +26 -0
  321. package/dist/cesium/Workers/chunk-EQ4YRVWL.js +26 -0
  322. package/dist/cesium/Workers/chunk-F6PRE7D6.js +26 -0
  323. package/dist/cesium/Workers/chunk-FC4ZZ65J.js +26 -0
  324. package/dist/cesium/Workers/chunk-FFBVWF2L.js +26 -0
  325. package/dist/cesium/Workers/chunk-GBAA6GVX.js +26 -0
  326. package/dist/cesium/Workers/chunk-ICALLYLG.js +26 -0
  327. package/dist/cesium/Workers/chunk-ILRYTWTP.js +26 -0
  328. package/dist/cesium/Workers/chunk-IRNLBSEJ.js +26 -0
  329. package/dist/cesium/Workers/chunk-IX4VMHEV.js +26 -0
  330. package/dist/cesium/Workers/chunk-L6QHHACZ.js +26 -0
  331. package/dist/cesium/Workers/chunk-LI2ZSORM.js +26 -0
  332. package/dist/cesium/Workers/chunk-LSLE2RL4.js +26 -0
  333. package/dist/cesium/Workers/chunk-M4HLDBCG.js +26 -0
  334. package/dist/cesium/Workers/chunk-MJHHSGEH.js +26 -0
  335. package/dist/cesium/Workers/chunk-NMVKML6W.js +26 -0
  336. package/dist/cesium/Workers/chunk-OCWJRAXS.js +26 -0
  337. package/dist/cesium/Workers/chunk-OIRKANTH.js +26 -0
  338. package/dist/cesium/Workers/chunk-OIT7J4IC.js +26 -0
  339. package/dist/cesium/Workers/chunk-OLZ3FYUM.js +26 -0
  340. package/dist/cesium/Workers/chunk-Q5BPHJQF.js +26 -0
  341. package/dist/cesium/Workers/chunk-QFM5DCMQ.js +26 -0
  342. package/dist/cesium/Workers/chunk-QKUIYMGC.js +28 -0
  343. package/dist/cesium/Workers/chunk-S44JILQT.js +26 -0
  344. package/dist/cesium/Workers/chunk-SLT4J352.js +26 -0
  345. package/dist/cesium/Workers/chunk-SQMIIXB7.js +26 -0
  346. package/dist/cesium/Workers/chunk-TJ4XLGBQ.js +26 -0
  347. package/dist/cesium/Workers/chunk-TNSUQXWK.js +27 -0
  348. package/dist/cesium/Workers/chunk-UBOGZS7F.js +26 -0
  349. package/dist/cesium/Workers/chunk-V3OSTMM6.js +26 -0
  350. package/dist/cesium/Workers/chunk-V7QEYVP3.js +26 -0
  351. package/dist/cesium/Workers/chunk-VUKYSU4H.js +26 -0
  352. package/dist/cesium/Workers/chunk-W37FE5GR.js +26 -0
  353. package/dist/cesium/Workers/chunk-WBOV35NL.js +26 -0
  354. package/dist/cesium/Workers/chunk-WPMZLB3Y.js +26 -0
  355. package/dist/cesium/Workers/chunk-WWWZVEEH.js +26 -0
  356. package/dist/cesium/Workers/chunk-XFIQ5DEQ.js +28 -0
  357. package/dist/cesium/Workers/chunk-XQHLGIO7.js +26 -0
  358. package/dist/cesium/Workers/chunk-XUSCFAVF.js +26 -0
  359. package/dist/cesium/Workers/chunk-YP7I5QBZ.js +26 -0
  360. package/dist/cesium/Workers/chunk-Z3QF2EHT.js +26 -0
  361. package/dist/cesium/Workers/combineGeometry.js +26 -0
  362. package/dist/cesium/Workers/createBoxGeometry.js +26 -0
  363. package/dist/cesium/Workers/createBoxOutlineGeometry.js +26 -0
  364. package/dist/cesium/Workers/createCircleGeometry.js +26 -0
  365. package/dist/cesium/Workers/createCircleOutlineGeometry.js +26 -0
  366. package/dist/cesium/Workers/createCoplanarPolygonGeometry.js +26 -0
  367. package/dist/cesium/Workers/createCoplanarPolygonOutlineGeometry.js +26 -0
  368. package/dist/cesium/Workers/createCorridorGeometry.js +26 -0
  369. package/dist/cesium/Workers/createCorridorOutlineGeometry.js +26 -0
  370. package/dist/cesium/Workers/createCylinderGeometry.js +26 -0
  371. package/dist/cesium/Workers/createCylinderOutlineGeometry.js +26 -0
  372. package/dist/cesium/Workers/createEllipseGeometry.js +26 -0
  373. package/dist/cesium/Workers/createEllipseOutlineGeometry.js +26 -0
  374. package/dist/cesium/Workers/createEllipsoidGeometry.js +26 -0
  375. package/dist/cesium/Workers/createEllipsoidOutlineGeometry.js +26 -0
  376. package/dist/cesium/Workers/createFrustumGeometry.js +26 -0
  377. package/dist/cesium/Workers/createFrustumOutlineGeometry.js +26 -0
  378. package/dist/cesium/Workers/createGeometry.js +26 -0
  379. package/dist/cesium/Workers/createGroundPolylineGeometry.js +26 -0
  380. package/dist/cesium/Workers/createPlaneGeometry.js +26 -0
  381. package/dist/cesium/Workers/createPlaneOutlineGeometry.js +26 -0
  382. package/dist/cesium/Workers/createPolygonGeometry.js +26 -0
  383. package/dist/cesium/Workers/createPolygonOutlineGeometry.js +26 -0
  384. package/dist/cesium/Workers/createPolylineGeometry.js +26 -0
  385. package/dist/cesium/Workers/createPolylineVolumeGeometry.js +26 -0
  386. package/dist/cesium/Workers/createPolylineVolumeOutlineGeometry.js +26 -0
  387. package/dist/cesium/Workers/createRectangleGeometry.js +26 -0
  388. package/dist/cesium/Workers/createRectangleOutlineGeometry.js +26 -0
  389. package/dist/cesium/Workers/createSimplePolylineGeometry.js +26 -0
  390. package/dist/cesium/Workers/createSphereGeometry.js +26 -0
  391. package/dist/cesium/Workers/createSphereOutlineGeometry.js +26 -0
  392. package/dist/cesium/Workers/createTaskProcessorWorker.js +26 -0
  393. package/dist/cesium/Workers/createVectorTileClampedPolylines.js +26 -0
  394. package/dist/cesium/Workers/createVectorTileGeometries.js +26 -0
  395. package/dist/cesium/Workers/createVectorTilePoints.js +26 -0
  396. package/dist/cesium/Workers/createVectorTilePolygons.js +26 -0
  397. package/dist/cesium/Workers/createVectorTilePolylines.js +26 -0
  398. package/dist/cesium/Workers/createVerticesFromCesium3DTilesTerrain.js +26 -0
  399. package/dist/cesium/Workers/createVerticesFromGoogleEarthEnterpriseBuffer.js +26 -0
  400. package/dist/cesium/Workers/createVerticesFromHeightmap.js +26 -0
  401. package/dist/cesium/Workers/createVerticesFromQuantizedTerrainMesh.js +26 -0
  402. package/dist/cesium/Workers/createWallGeometry.js +26 -0
  403. package/dist/cesium/Workers/createWallOutlineGeometry.js +26 -0
  404. package/dist/cesium/Workers/decodeDraco.js +26 -0
  405. package/dist/cesium/Workers/decodeGoogleEarthEnterprisePacket.js +26 -0
  406. package/dist/cesium/Workers/decodeI3S.js +26 -0
  407. package/dist/cesium/Workers/gaussianSplatSorter.js +26 -0
  408. package/dist/cesium/Workers/gaussianSplatTextureGenerator.js +26 -0
  409. package/dist/cesium/Workers/incrementallyBuildTerrainPicker.js +26 -0
  410. package/dist/cesium/Workers/transcodeKTX2.js +56 -0
  411. package/dist/cesium/Workers/transferTypedArrayTest.js +26 -0
  412. package/dist/cesium/Workers/upsampleQuantizedTerrainMesh.js +26 -0
  413. package/dist/cesium/Workers/upsampleVerticesFromCesium3DTilesTerrain.js +26 -0
  414. package/dist/index.html +10 -8
  415. package/package.json +15 -12
  416. package/src/App.tsx +1 -17
  417. package/src/components/viewer/BCFPanel.tsx +46 -4
  418. package/src/components/viewer/CesiumOverlay.tsx +672 -0
  419. package/src/components/viewer/CesiumSettingsDialog.tsx +100 -0
  420. package/src/components/viewer/ChatPanel.tsx +54 -16
  421. package/src/components/viewer/CommandPalette.tsx +6 -1
  422. package/src/components/viewer/DesktopEntitlementBanner.tsx +74 -0
  423. package/src/components/viewer/ExportChangesButton.tsx +6 -1
  424. package/src/components/viewer/ExportDialog.tsx +22 -6
  425. package/src/components/viewer/HierarchyPanel.tsx +196 -0
  426. package/src/components/viewer/IDSPanel.tsx +52 -3
  427. package/src/components/viewer/KeyboardShortcutsDialog.tsx +1 -1
  428. package/src/components/viewer/MainToolbar.tsx +353 -27
  429. package/src/components/viewer/PropertiesPanel.tsx +218 -79
  430. package/src/components/viewer/ScriptPanel.tsx +34 -8
  431. package/src/components/viewer/SettingsPage.tsx +430 -0
  432. package/src/components/viewer/StatusBar.tsx +17 -1
  433. package/src/components/viewer/UpgradePage.tsx +6 -4
  434. package/src/components/viewer/ViewerLayout.tsx +47 -6
  435. package/src/components/viewer/Viewport.tsx +49 -8
  436. package/src/components/viewer/ViewportContainer.tsx +280 -28
  437. package/src/components/viewer/ViewportOverlays.tsx +129 -27
  438. package/src/components/viewer/properties/GeoreferencingPanel.tsx +117 -5
  439. package/src/components/viewer/properties/LocationMap.tsx +458 -17
  440. package/src/components/viewer/selectionHandlers.ts +4 -3
  441. package/src/components/viewer/useAnimationLoop.ts +4 -0
  442. package/src/components/viewer/useGeometryStreaming.ts +127 -40
  443. package/src/components/viewer/useMouseControls.ts +4 -1
  444. package/src/hooks/ingest/viewerModelIngest.ts +275 -0
  445. package/src/hooks/useIDS.ts +1 -1
  446. package/src/hooks/useIfc.ts +7 -1
  447. package/src/hooks/useIfcCache.ts +28 -15
  448. package/src/hooks/useIfcFederation.ts +57 -225
  449. package/src/hooks/useIfcLoader.ts +1656 -130
  450. package/src/hooks/useIfcServer.ts +0 -69
  451. package/src/lib/desktop/ClerkDesktopEntitlementSync.tsx +175 -0
  452. package/src/lib/desktop/desktopEntitlementEvents.ts +39 -0
  453. package/src/lib/desktop-entitlement.ts +45 -0
  454. package/src/lib/desktop-product.ts +124 -0
  455. package/src/lib/geo/cesium-bridge.ts +310 -0
  456. package/src/lib/geo/reproject.ts +151 -25
  457. package/src/lib/recent-files.ts +2 -1
  458. package/src/services/analysis-extensions.ts +125 -0
  459. package/src/services/app-navigation.ts +13 -0
  460. package/src/services/bsdd.ts +53 -4
  461. package/src/services/cacheService.ts +1 -1
  462. package/src/services/desktop-cache.ts +43 -0
  463. package/src/services/desktop-export.ts +77 -0
  464. package/src/services/desktop-harness.ts +196 -0
  465. package/src/services/desktop-logger.ts +20 -0
  466. package/src/services/desktop-native-metadata.ts +207 -0
  467. package/src/services/desktop-panel-actions.ts +43 -0
  468. package/src/services/desktop-preferences.ts +44 -0
  469. package/src/services/file-dialog.ts +147 -0
  470. package/src/services/tauri-core-stub.ts +7 -0
  471. package/src/services/tauri-dialog-stub.ts +7 -0
  472. package/src/services/tauri-fs-stub.ts +7 -0
  473. package/src/store/index.ts +40 -2
  474. package/src/store/slices/cesiumSlice.ts +122 -0
  475. package/src/store/slices/chatSlice.ts +5 -1
  476. package/src/store/slices/dataSlice.ts +139 -28
  477. package/src/store/slices/desktopEntitlementSlice.ts +86 -0
  478. package/src/store/slices/loadingSlice.ts +14 -2
  479. package/src/store/slices/modelSlice.ts +58 -3
  480. package/src/store/types.ts +96 -2
  481. package/src/store.ts +1 -1
  482. package/src/utils/desktopModelSnapshot.ts +358 -0
  483. package/src/utils/ifcConfig.ts +6 -1
  484. package/src/utils/nativeSpatialDataStore.ts +250 -0
  485. package/src/utils/serverDataModel.ts +4 -0
  486. package/src/utils/spatialHierarchy.ts +10 -11
  487. package/vite.config.ts +24 -0
  488. package/dist/assets/arrow-DJf2ErbF.js +0 -20
  489. package/dist/assets/basketViewActivator-aojwdomq.js +0 -1
  490. package/dist/assets/desktop-cache-oPzaWXYE.js +0 -1
  491. package/dist/assets/geometry.worker-Nz9_YIqh.js +0 -1
  492. package/dist/assets/ifc-lite_bg-eSkBTizQ.wasm +0 -0
  493. package/dist/assets/index-pbE7itQS.css +0 -1
  494. package/dist/assets/native-bridge-DSIyEYXG.js +0 -113
  495. package/dist/assets/wasm-bridge-B0J07fZZ.js +0 -1
@@ -0,0 +1,310 @@
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
+ * Cesium coordinate bridge — lookAtTransform approach.
7
+ *
8
+ * KEY INSIGHT (from Cesium GitHub #6032): Camera.setView() with direction/up
9
+ * vectors causes drift because it doesn't properly orthonormalize. The fix:
10
+ * use lookAtTransform() which sets a reference frame and keeps the camera
11
+ * matrix clean.
12
+ *
13
+ * APPROACH: Build a single 4x4 matrix that transforms from IFC viewer space
14
+ * to ECEF, pass it to Cesium via lookAtTransform(). Then set camera position,
15
+ * direction, and up in IFC viewer coordinates — Cesium applies the transform
16
+ * internally with full precision.
17
+ *
18
+ * The viewer→ECEF transform is composed of:
19
+ * 1. Translate by (-modelCenter) to center on model origin
20
+ * 2. Rotate via viewerYup→ifcZup axis swap
21
+ * 3. Rotate via Helmert (IFC→projected CRS alignment)
22
+ * 4. Transform ENU→ECEF via Cesium.Transforms.eastNorthUpToFixedFrame()
23
+ *
24
+ * Since this is a SINGLE matrix, it's applied atomically by Cesium — no
25
+ * intermediate rounding or re-orthonormalization. The model stays pinned.
26
+ */
27
+
28
+ import proj4 from 'proj4';
29
+ import type { MapConversion, ProjectedCRS } from '@ifc-lite/parser';
30
+ import type { CoordinateInfo } from '@ifc-lite/geometry';
31
+ import { resolveProjection } from './reproject';
32
+
33
+ export interface GeodesicPosition {
34
+ longitude: number;
35
+ latitude: number;
36
+ height: number;
37
+ }
38
+
39
+ export interface CesiumBridge {
40
+ modelOrigin: GeodesicPosition;
41
+ rotationAngle: number;
42
+
43
+ /**
44
+ * Sync the Cesium camera using lookAtTransform with a viewer→ECEF matrix.
45
+ * The IFC camera position/direction/up are passed in viewer coordinates —
46
+ * Cesium transforms them to ECEF internally using one consistent matrix.
47
+ */
48
+ syncCamera(
49
+ Cesium: typeof import('cesium'),
50
+ viewer: InstanceType<typeof import('cesium').Viewer>,
51
+ camPos: { x: number; y: number; z: number },
52
+ camTarget: { x: number; y: number; z: number },
53
+ camUp: { x: number; y: number; z: number },
54
+ fov: number,
55
+ terrainClampOffset?: number,
56
+ ): void;
57
+
58
+ /** Query terrain height at model origin. */
59
+ queryTerrainHeight(
60
+ Cesium: typeof import('cesium'),
61
+ viewer: InstanceType<typeof import('cesium').Viewer>,
62
+ ): Promise<number | null>;
63
+
64
+ viewerToGeodetic(vx: number, vy: number, vz: number): GeodesicPosition | null;
65
+ }
66
+
67
+ const TERRAIN_QUERY_RETRY_DELAY_MS = 3000;
68
+
69
+ export async function createCesiumBridge(
70
+ mapConversion: MapConversion,
71
+ projectedCRS: ProjectedCRS,
72
+ coordinateInfo?: CoordinateInfo,
73
+ ): Promise<CesiumBridge | null> {
74
+ const projDef = await resolveProjection(projectedCRS);
75
+ if (!projDef) return null;
76
+
77
+ const hScale = mapConversion.scale ?? 1.0;
78
+ const absc = mapConversion.xAxisAbscissa ?? 1.0;
79
+ const ordi = mapConversion.xAxisOrdinate ?? 0.0;
80
+ const rotAngle = Math.atan2(ordi, absc);
81
+
82
+ const shift = coordinateInfo?.originShift ?? { x: 0, y: 0, z: 0 };
83
+ const rtc = coordinateInfo?.wasmRtcOffset;
84
+ const rtcYup = rtc
85
+ ? { x: rtc.x, y: rtc.z, z: -rtc.y }
86
+ : { x: 0, y: 0, z: 0 };
87
+
88
+ const bounds = coordinateInfo?.originalBounds;
89
+ const modelVX = bounds ? (bounds.min.x + bounds.max.x) / 2 : 0;
90
+ const modelVY = bounds ? (bounds.min.y + bounds.max.y) / 2 : 0;
91
+ const modelVZ = bounds ? (bounds.min.z + bounds.max.z) / 2 : 0;
92
+
93
+ // ── Compute model origin in WGS84 ──
94
+ const owx = modelVX + shift.x + rtcYup.x;
95
+ const owy = modelVY + shift.y + rtcYup.y;
96
+ const owz = modelVZ + shift.z + rtcYup.z;
97
+ // Viewer Y-up → IFC Z-up
98
+ const oIfcX = owx;
99
+ const oIfcY = -owz;
100
+ const oIfcZ = owy;
101
+ const oEasting = mapConversion.eastings + hScale * (absc * oIfcX - ordi * oIfcY);
102
+ const oNorthing = mapConversion.northings + hScale * (ordi * oIfcX + absc * oIfcY);
103
+ const oHeight = mapConversion.orthogonalHeight + oIfcZ;
104
+
105
+ let originLon: number, originLat: number;
106
+ try {
107
+ const [lon, lat] = proj4(projDef, 'WGS84', [oEasting, oNorthing]);
108
+ if (!Number.isFinite(lat) || !Number.isFinite(lon)) return null;
109
+ originLon = lon;
110
+ originLat = lat;
111
+ } catch {
112
+ return null;
113
+ }
114
+
115
+ const modelOrigin: GeodesicPosition = {
116
+ longitude: originLon,
117
+ latitude: originLat,
118
+ height: oHeight,
119
+ };
120
+
121
+ // ── Build the viewer→ENU 3x3 rotation matrix ──
122
+ // This converts a DELTA vector from viewer space to ENU.
123
+ // Step 1: viewer Y-up → IFC Z-up: (vx, vy, vz) → (vx, -vz, vy)
124
+ // Step 2: Helmert rotation: (ifcX, ifcY) → (east, north) with scale
125
+ //
126
+ // Combined as a 3x3 matrix M where [east, north, up] = M * [vx, vy, vz]:
127
+ // east = hScale * (absc * vx - ordi * (-vz)) = hScale * (absc*vx + ordi*vz)
128
+ // north = hScale * (ordi * vx + absc * (-vz)) = hScale * (ordi*vx - absc*vz)
129
+ // up = vy (ifcZ = vy, vertical is viewer Y)
130
+ //
131
+ // So M = [hScale*absc, 0, hScale*ordi ]
132
+ // [hScale*ordi, 0, -hScale*absc ]
133
+ // [0, 1, 0 ]
134
+ const m00 = hScale * absc; // east from vx
135
+ const m01 = 0; // east from vy
136
+ const m02 = hScale * ordi; // east from vz
137
+ const m10 = hScale * ordi; // north from vx
138
+ const m11 = 0; // north from vy
139
+ const m12 = -hScale * absc; // north from vz
140
+ const m20 = 0; // up from vx
141
+ const m21 = 1; // up from vy
142
+ const m22 = 0; // up from vz
143
+
144
+ // ── Cache for ECEF objects ──
145
+ let viewerToEcefMatrix: InstanceType<typeof import('cesium').Matrix4> | null = null;
146
+ let modelOriginCartesian: InstanceType<typeof import('cesium').Cartesian3> | null = null;
147
+ let cachedClampUp: number | null = null;
148
+
149
+ function ensureEcefCache(Cesium: typeof import('cesium'), clampUp: number) {
150
+ if (cachedClampUp === clampUp && viewerToEcefMatrix !== null) return;
151
+ cachedClampUp = clampUp;
152
+
153
+ const originWithClamp = Cesium.Cartesian3.fromDegrees(
154
+ originLon, originLat, oHeight + clampUp,
155
+ );
156
+ modelOriginCartesian = originWithClamp;
157
+
158
+ // Get ENU→ECEF 4x4 matrix at model origin
159
+ const enuToEcef = Cesium.Transforms.eastNorthUpToFixedFrame(originWithClamp);
160
+
161
+ // Build viewer→ECEF = enuToEcef * viewerToENU
162
+ // viewerToENU is: translate(-modelCenter) then rotate by M
163
+ // As a 4x4: columns are the ENU directions of viewer axes, translation is -modelCenter in ENU
164
+ //
165
+ // viewerToENU_4x4 = [ m00 m01 m02 tx ]
166
+ // [ m10 m11 m12 ty ]
167
+ // [ m20 m21 m22 tz ]
168
+ // [ 0 0 0 1 ]
169
+ // where (tx, ty, tz) = M * (-modelVX, -modelVY, -modelVZ)
170
+ const tx = m00 * (-modelVX) + m01 * (-modelVY) + m02 * (-modelVZ);
171
+ const ty = m10 * (-modelVX) + m11 * (-modelVY) + m12 * (-modelVZ);
172
+ const tz = m20 * (-modelVX) + m21 * (-modelVY) + m22 * (-modelVZ);
173
+
174
+ // Cesium Matrix4 is column-major
175
+ const viewerToEnu = new Cesium.Matrix4(
176
+ m00, m01, m02, tx,
177
+ m10, m11, m12, ty,
178
+ m20, m21, m22, tz,
179
+ 0, 0, 0, 1,
180
+ );
181
+
182
+ // Compose: viewerToEcef = enuToEcef * viewerToEnu
183
+ viewerToEcefMatrix = Cesium.Matrix4.multiply(
184
+ enuToEcef, viewerToEnu, new Cesium.Matrix4(),
185
+ );
186
+ }
187
+
188
+ function syncCamera(
189
+ Cesium: typeof import('cesium'),
190
+ viewer: InstanceType<typeof import('cesium').Viewer>,
191
+ camPos: { x: number; y: number; z: number },
192
+ camTarget: { x: number; y: number; z: number },
193
+ camUp: { x: number; y: number; z: number },
194
+ fov: number,
195
+ terrainClampOffset?: number,
196
+ ): void {
197
+ const clampUp = terrainClampOffset ?? 0;
198
+ ensureEcefCache(Cesium, clampUp);
199
+ if (!viewerToEcefMatrix) return;
200
+
201
+ // Set the camera's reference frame to our viewer→ECEF transform.
202
+ // After this call, all camera properties (position, direction, up)
203
+ // are interpreted in IFC VIEWER coordinates, not ECEF.
204
+ viewer.camera.lookAtTransform(viewerToEcefMatrix);
205
+
206
+ // Now set camera in VIEWER coordinates — Cesium applies the transform
207
+ viewer.camera.position = new Cesium.Cartesian3(camPos.x, camPos.y, camPos.z);
208
+
209
+ const dirX = camTarget.x - camPos.x;
210
+ const dirY = camTarget.y - camPos.y;
211
+ const dirZ = camTarget.z - camPos.z;
212
+ const dirLen = Math.sqrt(dirX * dirX + dirY * dirY + dirZ * dirZ);
213
+ if (dirLen > 1e-8) {
214
+ viewer.camera.direction = new Cesium.Cartesian3(
215
+ dirX / dirLen, dirY / dirLen, dirZ / dirLen,
216
+ );
217
+ }
218
+
219
+ viewer.camera.up = new Cesium.Cartesian3(camUp.x, camUp.y, camUp.z);
220
+
221
+ // Recompute right = direction × up (maintain orthonormality)
222
+ const right = Cesium.Cartesian3.cross(
223
+ viewer.camera.direction, viewer.camera.up, new Cesium.Cartesian3(),
224
+ );
225
+ Cesium.Cartesian3.normalize(right, right);
226
+ viewer.camera.right = right;
227
+
228
+ // Sync FOV — CRITICAL for preventing model drift.
229
+ // IFC renderer uses `fov` as VERTICAL FOV always.
230
+ // Cesium's PerspectiveFrustum.fov is HORIZONTAL when aspect > 1 (landscape).
231
+ // If we set Cesium's fov = IFC's vertical fov, Cesium treats it as horizontal,
232
+ // producing a completely different projection — the model slides during orbit.
233
+ // Fix: convert vertical FOV → horizontal FOV.
234
+ const frustum = viewer.camera.frustum;
235
+ if (frustum instanceof Cesium.PerspectiveFrustum) {
236
+ const aspect = frustum.aspectRatio || (viewer.canvas.width / viewer.canvas.height);
237
+ if (aspect > 1) {
238
+ // Landscape: Cesium expects horizontal FOV
239
+ // horizontal_fov = 2 * atan(aspect * tan(vertical_fov / 2))
240
+ frustum.fov = 2 * Math.atan(aspect * Math.tan(fov / 2));
241
+ } else {
242
+ // Portrait: Cesium uses fov as vertical — pass through
243
+ frustum.fov = fov;
244
+ }
245
+ }
246
+
247
+ viewer.scene.requestRender();
248
+ }
249
+
250
+ async function queryTerrainHeight(
251
+ Cesium: typeof import('cesium'),
252
+ viewer: InstanceType<typeof import('cesium').Viewer>,
253
+ ): Promise<number | null> {
254
+ const position = Cesium.Cartographic.fromDegrees(originLon, originLat);
255
+
256
+ try {
257
+ const globeHeight = viewer.scene.globe.getHeight(position);
258
+ if (globeHeight !== undefined && Number.isFinite(globeHeight)) {
259
+ return globeHeight;
260
+ }
261
+ } catch { /* not available yet */ }
262
+
263
+ try {
264
+ const terrainProvider = viewer.terrainProvider;
265
+ if (terrainProvider) {
266
+ const results = await Cesium.sampleTerrainMostDetailed(terrainProvider, [position]);
267
+ if (results && results.length > 0 && Number.isFinite(results[0].height)) {
268
+ return results[0].height;
269
+ }
270
+ }
271
+ } catch { /* terrain sampling failed */ }
272
+
273
+ await new Promise(r => setTimeout(r, TERRAIN_QUERY_RETRY_DELAY_MS));
274
+ try {
275
+ const globeHeight = viewer.scene.globe.getHeight(position);
276
+ if (globeHeight !== undefined && Number.isFinite(globeHeight)) {
277
+ return globeHeight;
278
+ }
279
+ } catch { /* still not available */ }
280
+
281
+ return null;
282
+ }
283
+
284
+ function viewerToGeodetic(vx: number, vy: number, vz: number): GeodesicPosition | null {
285
+ const wx = vx + shift.x + rtcYup.x;
286
+ const wy = vy + shift.y + rtcYup.y;
287
+ const wz = vz + shift.z + rtcYup.z;
288
+ const ifcX = wx;
289
+ const ifcY = -wz;
290
+ const ifcZ = wy;
291
+ const easting = mapConversion.eastings + hScale * (absc * ifcX - ordi * ifcY);
292
+ const northing = mapConversion.northings + hScale * (ordi * ifcX + absc * ifcY);
293
+ const height = mapConversion.orthogonalHeight + ifcZ;
294
+ try {
295
+ const [lon, lat] = proj4(projDef!, 'WGS84', [easting, northing]);
296
+ if (!Number.isFinite(lat) || !Number.isFinite(lon)) return null;
297
+ return { longitude: lon, latitude: lat, height };
298
+ } catch {
299
+ return null;
300
+ }
301
+ }
302
+
303
+ return {
304
+ modelOrigin,
305
+ rotationAngle: rotAngle,
306
+ syncCamera,
307
+ queryTerrainHeight,
308
+ viewerToGeodetic,
309
+ };
310
+ }
@@ -176,31 +176,7 @@ function computeProjectedCenter(
176
176
  conversion: MapConversion,
177
177
  coordinateInfo?: CoordinateInfo,
178
178
  ): { easting: number; northing: number } {
179
- let ifcX = 0;
180
- let ifcY = 0;
181
-
182
- if (coordinateInfo) {
183
- const bounds = coordinateInfo.originalBounds;
184
- const shift = coordinateInfo.originShift;
185
- const rtc = coordinateInfo.wasmRtcOffset;
186
-
187
- // Convert WASM RTC offset from IFC Z-up to viewer Y-up
188
- const rtcYup = rtc
189
- ? { x: rtc.x, y: rtc.z, z: -rtc.y }
190
- : { x: 0, y: 0, z: 0 };
191
-
192
- // Bounds center in viewer Y-up (scene-local)
193
- const cx = (bounds.min.x + bounds.max.x) / 2;
194
- const cz = (bounds.min.z + bounds.max.z) / 2;
195
-
196
- // World Y-up = scene_local + originShift + wasmRtcOffset_yup
197
- const worldYupX = cx + shift.x + rtcYup.x;
198
- const worldYupZ = cz + shift.z + rtcYup.z;
199
-
200
- // Convert Y-up to IFC Z-up: ifc_x = viewer_x, ifc_y = -viewer_z
201
- ifcX = worldYupX;
202
- ifcY = -worldYupZ;
203
- }
179
+ const { ifcX, ifcY } = computeLocalIfcCenter(coordinateInfo);
204
180
 
205
181
  // Apply MapConversion rotation + scale + offset
206
182
  const scale = conversion.scale ?? 1.0;
@@ -242,3 +218,153 @@ export async function reprojectToLatLon(
242
218
  return null;
243
219
  }
244
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
+ }
@@ -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');
@@ -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
+ }