@ifc-lite/viewer 1.17.3 → 1.17.6

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 (530) hide show
  1. package/.turbo/turbo-build.log +39 -30
  2. package/.turbo/turbo-typecheck.log +1 -1
  3. package/CHANGELOG.md +132 -0
  4. package/DESKTOP_CONTRACT_VERSION +1 -0
  5. package/dist/assets/arrow-CZ5kQ26f.js +20 -0
  6. package/dist/assets/basketViewActivator-86rgogji.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/drawing-2d-DoxKMqbO.js +257 -0
  12. package/dist/assets/{exporters-C_6J153K.js → exporters-CcPS9MK5.js} +2898 -2380
  13. package/dist/assets/geometry.worker-BFUYA08u.js +1 -0
  14. package/dist/assets/ids-DQ5jY0E8.js +1 -0
  15. package/dist/assets/ifc-lite_bg-BINvzoCP.wasm +0 -0
  16. package/dist/assets/{index-jhBr1wbn.js → index-Bfms9I4A.js} +41036 -34613
  17. package/dist/assets/index-_bfZsDCC.css +1 -0
  18. package/dist/assets/{maplibre-gl-BpvwNKKy.js → maplibre-gl-CGLcoNXc.js} +1 -1
  19. package/dist/assets/native-bridge-DUyLCMZS.js +429 -0
  20. package/dist/assets/{sandbox-B79eavQ3.js → sandbox-C8575tul.js} +4342 -4324
  21. package/dist/assets/{server-client-D3bUPJJc.js → server-client-BuZK7OST.js} +4 -4
  22. package/dist/assets/tauri-core-stub-D8Fa-u43.js +1 -0
  23. package/dist/assets/tauri-dialog-stub-r7Wksg7o.js +1 -0
  24. package/dist/assets/tauri-fs-stub-BdeRC7aK.js +1 -0
  25. package/dist/assets/wasm-bridge-JsqEGDV8.js +1 -0
  26. package/dist/assets/{zip-B-jFFAGa.js → zip-DBEtpeu6.js} +3 -3
  27. package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_0.json +1 -0
  28. package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_1.json +1 -0
  29. package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_10.json +1 -0
  30. package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_11.json +1 -0
  31. package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_12.json +1 -0
  32. package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_13.json +1 -0
  33. package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_14.json +1 -0
  34. package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_15.json +1 -0
  35. package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_16.json +1 -0
  36. package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_17.json +1 -0
  37. package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_18.json +1 -0
  38. package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_19.json +1 -0
  39. package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_2.json +1 -0
  40. package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_20.json +1 -0
  41. package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_21.json +1 -0
  42. package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_22.json +1 -0
  43. package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_23.json +1 -0
  44. package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_24.json +1 -0
  45. package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_25.json +1 -0
  46. package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_26.json +1 -0
  47. package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_27.json +1 -0
  48. package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_3.json +1 -0
  49. package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_4.json +1 -0
  50. package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_5.json +1 -0
  51. package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_6.json +1 -0
  52. package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_7.json +1 -0
  53. package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_8.json +1 -0
  54. package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_9.json +1 -0
  55. package/dist/cesium/Assets/Images/bing_maps_credit.png +0 -0
  56. package/dist/cesium/Assets/Images/cesium_credit.png +0 -0
  57. package/dist/cesium/Assets/Images/google_earth_credit.png +0 -0
  58. package/dist/cesium/Assets/Images/ion-credit.png +0 -0
  59. package/dist/cesium/Assets/Textures/LensFlare/DirtMask.jpg +0 -0
  60. package/dist/cesium/Assets/Textures/LensFlare/StarBurst.jpg +0 -0
  61. package/dist/cesium/Assets/Textures/NaturalEarthII/0/0/0.jpg +0 -0
  62. package/dist/cesium/Assets/Textures/NaturalEarthII/0/1/0.jpg +0 -0
  63. package/dist/cesium/Assets/Textures/NaturalEarthII/1/0/0.jpg +0 -0
  64. package/dist/cesium/Assets/Textures/NaturalEarthII/1/0/1.jpg +0 -0
  65. package/dist/cesium/Assets/Textures/NaturalEarthII/1/1/0.jpg +0 -0
  66. package/dist/cesium/Assets/Textures/NaturalEarthII/1/1/1.jpg +0 -0
  67. package/dist/cesium/Assets/Textures/NaturalEarthII/1/2/0.jpg +0 -0
  68. package/dist/cesium/Assets/Textures/NaturalEarthII/1/2/1.jpg +0 -0
  69. package/dist/cesium/Assets/Textures/NaturalEarthII/1/3/0.jpg +0 -0
  70. package/dist/cesium/Assets/Textures/NaturalEarthII/1/3/1.jpg +0 -0
  71. package/dist/cesium/Assets/Textures/NaturalEarthII/2/0/0.jpg +0 -0
  72. package/dist/cesium/Assets/Textures/NaturalEarthII/2/0/1.jpg +0 -0
  73. package/dist/cesium/Assets/Textures/NaturalEarthII/2/0/2.jpg +0 -0
  74. package/dist/cesium/Assets/Textures/NaturalEarthII/2/0/3.jpg +0 -0
  75. package/dist/cesium/Assets/Textures/NaturalEarthII/2/1/0.jpg +0 -0
  76. package/dist/cesium/Assets/Textures/NaturalEarthII/2/1/1.jpg +0 -0
  77. package/dist/cesium/Assets/Textures/NaturalEarthII/2/1/2.jpg +0 -0
  78. package/dist/cesium/Assets/Textures/NaturalEarthII/2/1/3.jpg +0 -0
  79. package/dist/cesium/Assets/Textures/NaturalEarthII/2/2/0.jpg +0 -0
  80. package/dist/cesium/Assets/Textures/NaturalEarthII/2/2/1.jpg +0 -0
  81. package/dist/cesium/Assets/Textures/NaturalEarthII/2/2/2.jpg +0 -0
  82. package/dist/cesium/Assets/Textures/NaturalEarthII/2/2/3.jpg +0 -0
  83. package/dist/cesium/Assets/Textures/NaturalEarthII/2/3/0.jpg +0 -0
  84. package/dist/cesium/Assets/Textures/NaturalEarthII/2/3/1.jpg +0 -0
  85. package/dist/cesium/Assets/Textures/NaturalEarthII/2/3/2.jpg +0 -0
  86. package/dist/cesium/Assets/Textures/NaturalEarthII/2/3/3.jpg +0 -0
  87. package/dist/cesium/Assets/Textures/NaturalEarthII/2/4/0.jpg +0 -0
  88. package/dist/cesium/Assets/Textures/NaturalEarthII/2/4/1.jpg +0 -0
  89. package/dist/cesium/Assets/Textures/NaturalEarthII/2/4/2.jpg +0 -0
  90. package/dist/cesium/Assets/Textures/NaturalEarthII/2/4/3.jpg +0 -0
  91. package/dist/cesium/Assets/Textures/NaturalEarthII/2/5/0.jpg +0 -0
  92. package/dist/cesium/Assets/Textures/NaturalEarthII/2/5/1.jpg +0 -0
  93. package/dist/cesium/Assets/Textures/NaturalEarthII/2/5/2.jpg +0 -0
  94. package/dist/cesium/Assets/Textures/NaturalEarthII/2/5/3.jpg +0 -0
  95. package/dist/cesium/Assets/Textures/NaturalEarthII/2/6/0.jpg +0 -0
  96. package/dist/cesium/Assets/Textures/NaturalEarthII/2/6/1.jpg +0 -0
  97. package/dist/cesium/Assets/Textures/NaturalEarthII/2/6/2.jpg +0 -0
  98. package/dist/cesium/Assets/Textures/NaturalEarthII/2/6/3.jpg +0 -0
  99. package/dist/cesium/Assets/Textures/NaturalEarthII/2/7/0.jpg +0 -0
  100. package/dist/cesium/Assets/Textures/NaturalEarthII/2/7/1.jpg +0 -0
  101. package/dist/cesium/Assets/Textures/NaturalEarthII/2/7/2.jpg +0 -0
  102. package/dist/cesium/Assets/Textures/NaturalEarthII/2/7/3.jpg +0 -0
  103. package/dist/cesium/Assets/Textures/NaturalEarthII/tilemapresource.xml +14 -0
  104. package/dist/cesium/Assets/Textures/SkyBox/tycho2t3_80_mx.jpg +0 -0
  105. package/dist/cesium/Assets/Textures/SkyBox/tycho2t3_80_my.jpg +0 -0
  106. package/dist/cesium/Assets/Textures/SkyBox/tycho2t3_80_mz.jpg +0 -0
  107. package/dist/cesium/Assets/Textures/SkyBox/tycho2t3_80_px.jpg +0 -0
  108. package/dist/cesium/Assets/Textures/SkyBox/tycho2t3_80_py.jpg +0 -0
  109. package/dist/cesium/Assets/Textures/SkyBox/tycho2t3_80_pz.jpg +0 -0
  110. package/dist/cesium/Assets/Textures/maki/airfield.png +0 -0
  111. package/dist/cesium/Assets/Textures/maki/airport.png +0 -0
  112. package/dist/cesium/Assets/Textures/maki/alcohol-shop.png +0 -0
  113. package/dist/cesium/Assets/Textures/maki/america-football.png +0 -0
  114. package/dist/cesium/Assets/Textures/maki/art-gallery.png +0 -0
  115. package/dist/cesium/Assets/Textures/maki/bakery.png +0 -0
  116. package/dist/cesium/Assets/Textures/maki/bank.png +0 -0
  117. package/dist/cesium/Assets/Textures/maki/bar.png +0 -0
  118. package/dist/cesium/Assets/Textures/maki/baseball.png +0 -0
  119. package/dist/cesium/Assets/Textures/maki/basketball.png +0 -0
  120. package/dist/cesium/Assets/Textures/maki/beer.png +0 -0
  121. package/dist/cesium/Assets/Textures/maki/bicycle.png +0 -0
  122. package/dist/cesium/Assets/Textures/maki/building.png +0 -0
  123. package/dist/cesium/Assets/Textures/maki/bus.png +0 -0
  124. package/dist/cesium/Assets/Textures/maki/cafe.png +0 -0
  125. package/dist/cesium/Assets/Textures/maki/camera.png +0 -0
  126. package/dist/cesium/Assets/Textures/maki/campsite.png +0 -0
  127. package/dist/cesium/Assets/Textures/maki/car.png +0 -0
  128. package/dist/cesium/Assets/Textures/maki/cemetery.png +0 -0
  129. package/dist/cesium/Assets/Textures/maki/cesium.png +0 -0
  130. package/dist/cesium/Assets/Textures/maki/chemist.png +0 -0
  131. package/dist/cesium/Assets/Textures/maki/cinema.png +0 -0
  132. package/dist/cesium/Assets/Textures/maki/circle-stroked.png +0 -0
  133. package/dist/cesium/Assets/Textures/maki/circle.png +0 -0
  134. package/dist/cesium/Assets/Textures/maki/city.png +0 -0
  135. package/dist/cesium/Assets/Textures/maki/clothing-store.png +0 -0
  136. package/dist/cesium/Assets/Textures/maki/college.png +0 -0
  137. package/dist/cesium/Assets/Textures/maki/commercial.png +0 -0
  138. package/dist/cesium/Assets/Textures/maki/cricket.png +0 -0
  139. package/dist/cesium/Assets/Textures/maki/cross.png +0 -0
  140. package/dist/cesium/Assets/Textures/maki/dam.png +0 -0
  141. package/dist/cesium/Assets/Textures/maki/danger.png +0 -0
  142. package/dist/cesium/Assets/Textures/maki/disability.png +0 -0
  143. package/dist/cesium/Assets/Textures/maki/dog-park.png +0 -0
  144. package/dist/cesium/Assets/Textures/maki/embassy.png +0 -0
  145. package/dist/cesium/Assets/Textures/maki/emergency-telephone.png +0 -0
  146. package/dist/cesium/Assets/Textures/maki/entrance.png +0 -0
  147. package/dist/cesium/Assets/Textures/maki/farm.png +0 -0
  148. package/dist/cesium/Assets/Textures/maki/fast-food.png +0 -0
  149. package/dist/cesium/Assets/Textures/maki/ferry.png +0 -0
  150. package/dist/cesium/Assets/Textures/maki/fire-station.png +0 -0
  151. package/dist/cesium/Assets/Textures/maki/fuel.png +0 -0
  152. package/dist/cesium/Assets/Textures/maki/garden.png +0 -0
  153. package/dist/cesium/Assets/Textures/maki/gift.png +0 -0
  154. package/dist/cesium/Assets/Textures/maki/golf.png +0 -0
  155. package/dist/cesium/Assets/Textures/maki/grocery.png +0 -0
  156. package/dist/cesium/Assets/Textures/maki/hairdresser.png +0 -0
  157. package/dist/cesium/Assets/Textures/maki/harbor.png +0 -0
  158. package/dist/cesium/Assets/Textures/maki/heart.png +0 -0
  159. package/dist/cesium/Assets/Textures/maki/heliport.png +0 -0
  160. package/dist/cesium/Assets/Textures/maki/hospital.png +0 -0
  161. package/dist/cesium/Assets/Textures/maki/ice-cream.png +0 -0
  162. package/dist/cesium/Assets/Textures/maki/industrial.png +0 -0
  163. package/dist/cesium/Assets/Textures/maki/land-use.png +0 -0
  164. package/dist/cesium/Assets/Textures/maki/laundry.png +0 -0
  165. package/dist/cesium/Assets/Textures/maki/library.png +0 -0
  166. package/dist/cesium/Assets/Textures/maki/lighthouse.png +0 -0
  167. package/dist/cesium/Assets/Textures/maki/lodging.png +0 -0
  168. package/dist/cesium/Assets/Textures/maki/logging.png +0 -0
  169. package/dist/cesium/Assets/Textures/maki/london-underground.png +0 -0
  170. package/dist/cesium/Assets/Textures/maki/marker-stroked.png +0 -0
  171. package/dist/cesium/Assets/Textures/maki/marker.png +0 -0
  172. package/dist/cesium/Assets/Textures/maki/minefield.png +0 -0
  173. package/dist/cesium/Assets/Textures/maki/mobilephone.png +0 -0
  174. package/dist/cesium/Assets/Textures/maki/monument.png +0 -0
  175. package/dist/cesium/Assets/Textures/maki/museum.png +0 -0
  176. package/dist/cesium/Assets/Textures/maki/music.png +0 -0
  177. package/dist/cesium/Assets/Textures/maki/oil-well.png +0 -0
  178. package/dist/cesium/Assets/Textures/maki/park.png +0 -0
  179. package/dist/cesium/Assets/Textures/maki/park2.png +0 -0
  180. package/dist/cesium/Assets/Textures/maki/parking-garage.png +0 -0
  181. package/dist/cesium/Assets/Textures/maki/parking.png +0 -0
  182. package/dist/cesium/Assets/Textures/maki/pharmacy.png +0 -0
  183. package/dist/cesium/Assets/Textures/maki/pitch.png +0 -0
  184. package/dist/cesium/Assets/Textures/maki/place-of-worship.png +0 -0
  185. package/dist/cesium/Assets/Textures/maki/playground.png +0 -0
  186. package/dist/cesium/Assets/Textures/maki/police.png +0 -0
  187. package/dist/cesium/Assets/Textures/maki/polling-place.png +0 -0
  188. package/dist/cesium/Assets/Textures/maki/post.png +0 -0
  189. package/dist/cesium/Assets/Textures/maki/prison.png +0 -0
  190. package/dist/cesium/Assets/Textures/maki/rail-above.png +0 -0
  191. package/dist/cesium/Assets/Textures/maki/rail-light.png +0 -0
  192. package/dist/cesium/Assets/Textures/maki/rail-metro.png +0 -0
  193. package/dist/cesium/Assets/Textures/maki/rail-underground.png +0 -0
  194. package/dist/cesium/Assets/Textures/maki/rail.png +0 -0
  195. package/dist/cesium/Assets/Textures/maki/religious-christian.png +0 -0
  196. package/dist/cesium/Assets/Textures/maki/religious-jewish.png +0 -0
  197. package/dist/cesium/Assets/Textures/maki/religious-muslim.png +0 -0
  198. package/dist/cesium/Assets/Textures/maki/restaurant.png +0 -0
  199. package/dist/cesium/Assets/Textures/maki/roadblock.png +0 -0
  200. package/dist/cesium/Assets/Textures/maki/rocket.png +0 -0
  201. package/dist/cesium/Assets/Textures/maki/school.png +0 -0
  202. package/dist/cesium/Assets/Textures/maki/scooter.png +0 -0
  203. package/dist/cesium/Assets/Textures/maki/shop.png +0 -0
  204. package/dist/cesium/Assets/Textures/maki/skiing.png +0 -0
  205. package/dist/cesium/Assets/Textures/maki/slaughterhouse.png +0 -0
  206. package/dist/cesium/Assets/Textures/maki/soccer.png +0 -0
  207. package/dist/cesium/Assets/Textures/maki/square-stroked.png +0 -0
  208. package/dist/cesium/Assets/Textures/maki/square.png +0 -0
  209. package/dist/cesium/Assets/Textures/maki/star-stroked.png +0 -0
  210. package/dist/cesium/Assets/Textures/maki/star.png +0 -0
  211. package/dist/cesium/Assets/Textures/maki/suitcase.png +0 -0
  212. package/dist/cesium/Assets/Textures/maki/swimming.png +0 -0
  213. package/dist/cesium/Assets/Textures/maki/telephone.png +0 -0
  214. package/dist/cesium/Assets/Textures/maki/tennis.png +0 -0
  215. package/dist/cesium/Assets/Textures/maki/theatre.png +0 -0
  216. package/dist/cesium/Assets/Textures/maki/toilets.png +0 -0
  217. package/dist/cesium/Assets/Textures/maki/town-hall.png +0 -0
  218. package/dist/cesium/Assets/Textures/maki/town.png +0 -0
  219. package/dist/cesium/Assets/Textures/maki/triangle-stroked.png +0 -0
  220. package/dist/cesium/Assets/Textures/maki/triangle.png +0 -0
  221. package/dist/cesium/Assets/Textures/maki/village.png +0 -0
  222. package/dist/cesium/Assets/Textures/maki/warehouse.png +0 -0
  223. package/dist/cesium/Assets/Textures/maki/waste-basket.png +0 -0
  224. package/dist/cesium/Assets/Textures/maki/water.png +0 -0
  225. package/dist/cesium/Assets/Textures/maki/wetland.png +0 -0
  226. package/dist/cesium/Assets/Textures/maki/zoo.png +0 -0
  227. package/dist/cesium/Assets/Textures/moonSmall.jpg +0 -0
  228. package/dist/cesium/Assets/Textures/pin.svg +1 -0
  229. package/dist/cesium/Assets/Textures/waterNormals.jpg +0 -0
  230. package/dist/cesium/Assets/Textures/waterNormalsSmall.jpg +0 -0
  231. package/dist/cesium/Assets/approximateTerrainHeights.json +1 -0
  232. package/dist/cesium/ThirdParty/Workers/package.json +1 -0
  233. package/dist/cesium/ThirdParty/Workers/zip-web-worker.js +1 -0
  234. package/dist/cesium/ThirdParty/basis_transcoder.wasm +0 -0
  235. package/dist/cesium/ThirdParty/draco_decoder.wasm +0 -0
  236. package/dist/cesium/ThirdParty/google-earth-dbroot-parser.js +1 -0
  237. package/dist/cesium/ThirdParty/wasm_splats_bg.wasm +0 -0
  238. package/dist/cesium/ThirdParty/zip-module.wasm +0 -0
  239. package/dist/cesium/Widgets/Animation/Animation.css +127 -0
  240. package/dist/cesium/Widgets/Animation/lighter.css +70 -0
  241. package/dist/cesium/Widgets/BaseLayerPicker/BaseLayerPicker.css +108 -0
  242. package/dist/cesium/Widgets/BaseLayerPicker/lighter.css +22 -0
  243. package/dist/cesium/Widgets/Cesium3DTilesInspector/Cesium3DTilesInspector.css +102 -0
  244. package/dist/cesium/Widgets/CesiumInspector/CesiumInspector.css +113 -0
  245. package/dist/cesium/Widgets/CesiumWidget/CesiumWidget.css +119 -0
  246. package/dist/cesium/Widgets/CesiumWidget/lighter.css +14 -0
  247. package/dist/cesium/Widgets/FullscreenButton/FullscreenButton.css +8 -0
  248. package/dist/cesium/Widgets/Geocoder/Geocoder.css +70 -0
  249. package/dist/cesium/Widgets/Geocoder/lighter.css +17 -0
  250. package/dist/cesium/Widgets/I3SBuildingSceneLayerExplorer/I3SBuildingSceneLayerExplorer.css +27 -0
  251. package/dist/cesium/Widgets/Images/ImageryProviders/ArcGisMapServiceWorldHillshade.png +0 -0
  252. package/dist/cesium/Widgets/Images/ImageryProviders/ArcGisMapServiceWorldImagery.png +0 -0
  253. package/dist/cesium/Widgets/Images/ImageryProviders/ArcGisMapServiceWorldOcean.png +0 -0
  254. package/dist/cesium/Widgets/Images/ImageryProviders/azureAerial.png +0 -0
  255. package/dist/cesium/Widgets/Images/ImageryProviders/azureRoads.png +0 -0
  256. package/dist/cesium/Widgets/Images/ImageryProviders/bingAerial.png +0 -0
  257. package/dist/cesium/Widgets/Images/ImageryProviders/bingAerialLabels.png +0 -0
  258. package/dist/cesium/Widgets/Images/ImageryProviders/bingRoads.png +0 -0
  259. package/dist/cesium/Widgets/Images/ImageryProviders/blueMarble.png +0 -0
  260. package/dist/cesium/Widgets/Images/ImageryProviders/earthAtNight.png +0 -0
  261. package/dist/cesium/Widgets/Images/ImageryProviders/googleContour.png +0 -0
  262. package/dist/cesium/Widgets/Images/ImageryProviders/googleRoadmap.png +0 -0
  263. package/dist/cesium/Widgets/Images/ImageryProviders/googleSatellite.png +0 -0
  264. package/dist/cesium/Widgets/Images/ImageryProviders/googleSatelliteLabels.png +0 -0
  265. package/dist/cesium/Widgets/Images/ImageryProviders/mapQuestOpenStreetMap.png +0 -0
  266. package/dist/cesium/Widgets/Images/ImageryProviders/mapboxSatellite.png +0 -0
  267. package/dist/cesium/Widgets/Images/ImageryProviders/mapboxStreets.png +0 -0
  268. package/dist/cesium/Widgets/Images/ImageryProviders/mapboxTerrain.png +0 -0
  269. package/dist/cesium/Widgets/Images/ImageryProviders/naturalEarthII.png +0 -0
  270. package/dist/cesium/Widgets/Images/ImageryProviders/openStreetMap.png +0 -0
  271. package/dist/cesium/Widgets/Images/ImageryProviders/sentinel-2.png +0 -0
  272. package/dist/cesium/Widgets/Images/ImageryProviders/stadiaAlidadeSmooth.png +0 -0
  273. package/dist/cesium/Widgets/Images/ImageryProviders/stadiaAlidadeSmoothDark.png +0 -0
  274. package/dist/cesium/Widgets/Images/ImageryProviders/stamenToner.png +0 -0
  275. package/dist/cesium/Widgets/Images/ImageryProviders/stamenWatercolor.png +0 -0
  276. package/dist/cesium/Widgets/Images/NavigationHelp/Mouse.svg +84 -0
  277. package/dist/cesium/Widgets/Images/NavigationHelp/MouseLeft.svg +76 -0
  278. package/dist/cesium/Widgets/Images/NavigationHelp/MouseMiddle.svg +76 -0
  279. package/dist/cesium/Widgets/Images/NavigationHelp/MouseRight.svg +76 -0
  280. package/dist/cesium/Widgets/Images/NavigationHelp/Touch.svg +120 -0
  281. package/dist/cesium/Widgets/Images/NavigationHelp/TouchDrag.svg +129 -0
  282. package/dist/cesium/Widgets/Images/NavigationHelp/TouchRotate.svg +76 -0
  283. package/dist/cesium/Widgets/Images/NavigationHelp/TouchTilt.svg +135 -0
  284. package/dist/cesium/Widgets/Images/NavigationHelp/TouchZoom.svg +74 -0
  285. package/dist/cesium/Widgets/Images/TerrainProviders/CesiumWorldTerrain.png +0 -0
  286. package/dist/cesium/Widgets/Images/TerrainProviders/Ellipsoid.png +0 -0
  287. package/dist/cesium/Widgets/Images/TimelineIcons.png +0 -0
  288. package/dist/cesium/Widgets/Images/info-loading.gif +0 -0
  289. package/dist/cesium/Widgets/InfoBox/InfoBox.css +92 -0
  290. package/dist/cesium/Widgets/InfoBox/InfoBoxDescription.css +178 -0
  291. package/dist/cesium/Widgets/NavigationHelpButton/NavigationHelpButton.css +93 -0
  292. package/dist/cesium/Widgets/NavigationHelpButton/lighter.css +38 -0
  293. package/dist/cesium/Widgets/PerformanceWatchdog/PerformanceWatchdog.css +15 -0
  294. package/dist/cesium/Widgets/ProjectionPicker/ProjectionPicker.css +38 -0
  295. package/dist/cesium/Widgets/SceneModePicker/SceneModePicker.css +56 -0
  296. package/dist/cesium/Widgets/SelectionIndicator/SelectionIndicator.css +20 -0
  297. package/dist/cesium/Widgets/Timeline/Timeline.css +103 -0
  298. package/dist/cesium/Widgets/Timeline/lighter.css +23 -0
  299. package/dist/cesium/Widgets/VRButton/VRButton.css +8 -0
  300. package/dist/cesium/Widgets/Viewer/Viewer.css +107 -0
  301. package/dist/cesium/Widgets/VoxelInspector/VoxelInspector.css +16 -0
  302. package/dist/cesium/Widgets/lighter.css +237 -0
  303. package/dist/cesium/Widgets/lighterShared.css +46 -0
  304. package/dist/cesium/Widgets/shared.css +103 -0
  305. package/dist/cesium/Widgets/widgets.css +1342 -0
  306. package/dist/cesium/Workers/chunk-23ZQ2IVV.js +29 -0
  307. package/dist/cesium/Workers/chunk-2EQO3Q56.js +26 -0
  308. package/dist/cesium/Workers/chunk-2MJIIVP4.js +26 -0
  309. package/dist/cesium/Workers/chunk-2TE5NTVD.js +26 -0
  310. package/dist/cesium/Workers/chunk-2ZBHLJST.js +26 -0
  311. package/dist/cesium/Workers/chunk-5TJMAQVL.js +26 -0
  312. package/dist/cesium/Workers/chunk-6BD4U3VO.js +26 -0
  313. package/dist/cesium/Workers/chunk-7TVGLKQF.js +26 -0
  314. package/dist/cesium/Workers/chunk-BTSYJ5XU.js +26 -0
  315. package/dist/cesium/Workers/chunk-BXMEEOCS.js +63 -0
  316. package/dist/cesium/Workers/chunk-BYLCY7GP.js +29 -0
  317. package/dist/cesium/Workers/chunk-CTHM3W6I.js +26 -0
  318. package/dist/cesium/Workers/chunk-CUUSNIVQ.js +26 -0
  319. package/dist/cesium/Workers/chunk-E3JOOS3S.js +26 -0
  320. package/dist/cesium/Workers/chunk-E7KYDCM5.js +26 -0
  321. package/dist/cesium/Workers/chunk-EDVBB7SS.js +27 -0
  322. package/dist/cesium/Workers/chunk-EFBN7QNX.js +26 -0
  323. package/dist/cesium/Workers/chunk-EQ4YRVWL.js +26 -0
  324. package/dist/cesium/Workers/chunk-F6PRE7D6.js +26 -0
  325. package/dist/cesium/Workers/chunk-FC4ZZ65J.js +26 -0
  326. package/dist/cesium/Workers/chunk-FFBVWF2L.js +26 -0
  327. package/dist/cesium/Workers/chunk-GBAA6GVX.js +26 -0
  328. package/dist/cesium/Workers/chunk-ICALLYLG.js +26 -0
  329. package/dist/cesium/Workers/chunk-ILRYTWTP.js +26 -0
  330. package/dist/cesium/Workers/chunk-IRNLBSEJ.js +26 -0
  331. package/dist/cesium/Workers/chunk-IX4VMHEV.js +26 -0
  332. package/dist/cesium/Workers/chunk-L6QHHACZ.js +26 -0
  333. package/dist/cesium/Workers/chunk-LI2ZSORM.js +26 -0
  334. package/dist/cesium/Workers/chunk-LSLE2RL4.js +26 -0
  335. package/dist/cesium/Workers/chunk-M4HLDBCG.js +26 -0
  336. package/dist/cesium/Workers/chunk-MJHHSGEH.js +26 -0
  337. package/dist/cesium/Workers/chunk-NMVKML6W.js +26 -0
  338. package/dist/cesium/Workers/chunk-OCWJRAXS.js +26 -0
  339. package/dist/cesium/Workers/chunk-OIRKANTH.js +26 -0
  340. package/dist/cesium/Workers/chunk-OIT7J4IC.js +26 -0
  341. package/dist/cesium/Workers/chunk-OLZ3FYUM.js +26 -0
  342. package/dist/cesium/Workers/chunk-Q5BPHJQF.js +26 -0
  343. package/dist/cesium/Workers/chunk-QFM5DCMQ.js +26 -0
  344. package/dist/cesium/Workers/chunk-QKUIYMGC.js +28 -0
  345. package/dist/cesium/Workers/chunk-S44JILQT.js +26 -0
  346. package/dist/cesium/Workers/chunk-SLT4J352.js +26 -0
  347. package/dist/cesium/Workers/chunk-SQMIIXB7.js +26 -0
  348. package/dist/cesium/Workers/chunk-TJ4XLGBQ.js +26 -0
  349. package/dist/cesium/Workers/chunk-TNSUQXWK.js +27 -0
  350. package/dist/cesium/Workers/chunk-UBOGZS7F.js +26 -0
  351. package/dist/cesium/Workers/chunk-V3OSTMM6.js +26 -0
  352. package/dist/cesium/Workers/chunk-V7QEYVP3.js +26 -0
  353. package/dist/cesium/Workers/chunk-VUKYSU4H.js +26 -0
  354. package/dist/cesium/Workers/chunk-W37FE5GR.js +26 -0
  355. package/dist/cesium/Workers/chunk-WBOV35NL.js +26 -0
  356. package/dist/cesium/Workers/chunk-WPMZLB3Y.js +26 -0
  357. package/dist/cesium/Workers/chunk-WWWZVEEH.js +26 -0
  358. package/dist/cesium/Workers/chunk-XFIQ5DEQ.js +28 -0
  359. package/dist/cesium/Workers/chunk-XQHLGIO7.js +26 -0
  360. package/dist/cesium/Workers/chunk-XUSCFAVF.js +26 -0
  361. package/dist/cesium/Workers/chunk-YP7I5QBZ.js +26 -0
  362. package/dist/cesium/Workers/chunk-Z3QF2EHT.js +26 -0
  363. package/dist/cesium/Workers/combineGeometry.js +26 -0
  364. package/dist/cesium/Workers/createBoxGeometry.js +26 -0
  365. package/dist/cesium/Workers/createBoxOutlineGeometry.js +26 -0
  366. package/dist/cesium/Workers/createCircleGeometry.js +26 -0
  367. package/dist/cesium/Workers/createCircleOutlineGeometry.js +26 -0
  368. package/dist/cesium/Workers/createCoplanarPolygonGeometry.js +26 -0
  369. package/dist/cesium/Workers/createCoplanarPolygonOutlineGeometry.js +26 -0
  370. package/dist/cesium/Workers/createCorridorGeometry.js +26 -0
  371. package/dist/cesium/Workers/createCorridorOutlineGeometry.js +26 -0
  372. package/dist/cesium/Workers/createCylinderGeometry.js +26 -0
  373. package/dist/cesium/Workers/createCylinderOutlineGeometry.js +26 -0
  374. package/dist/cesium/Workers/createEllipseGeometry.js +26 -0
  375. package/dist/cesium/Workers/createEllipseOutlineGeometry.js +26 -0
  376. package/dist/cesium/Workers/createEllipsoidGeometry.js +26 -0
  377. package/dist/cesium/Workers/createEllipsoidOutlineGeometry.js +26 -0
  378. package/dist/cesium/Workers/createFrustumGeometry.js +26 -0
  379. package/dist/cesium/Workers/createFrustumOutlineGeometry.js +26 -0
  380. package/dist/cesium/Workers/createGeometry.js +26 -0
  381. package/dist/cesium/Workers/createGroundPolylineGeometry.js +26 -0
  382. package/dist/cesium/Workers/createPlaneGeometry.js +26 -0
  383. package/dist/cesium/Workers/createPlaneOutlineGeometry.js +26 -0
  384. package/dist/cesium/Workers/createPolygonGeometry.js +26 -0
  385. package/dist/cesium/Workers/createPolygonOutlineGeometry.js +26 -0
  386. package/dist/cesium/Workers/createPolylineGeometry.js +26 -0
  387. package/dist/cesium/Workers/createPolylineVolumeGeometry.js +26 -0
  388. package/dist/cesium/Workers/createPolylineVolumeOutlineGeometry.js +26 -0
  389. package/dist/cesium/Workers/createRectangleGeometry.js +26 -0
  390. package/dist/cesium/Workers/createRectangleOutlineGeometry.js +26 -0
  391. package/dist/cesium/Workers/createSimplePolylineGeometry.js +26 -0
  392. package/dist/cesium/Workers/createSphereGeometry.js +26 -0
  393. package/dist/cesium/Workers/createSphereOutlineGeometry.js +26 -0
  394. package/dist/cesium/Workers/createTaskProcessorWorker.js +26 -0
  395. package/dist/cesium/Workers/createVectorTileClampedPolylines.js +26 -0
  396. package/dist/cesium/Workers/createVectorTileGeometries.js +26 -0
  397. package/dist/cesium/Workers/createVectorTilePoints.js +26 -0
  398. package/dist/cesium/Workers/createVectorTilePolygons.js +26 -0
  399. package/dist/cesium/Workers/createVectorTilePolylines.js +26 -0
  400. package/dist/cesium/Workers/createVerticesFromCesium3DTilesTerrain.js +26 -0
  401. package/dist/cesium/Workers/createVerticesFromGoogleEarthEnterpriseBuffer.js +26 -0
  402. package/dist/cesium/Workers/createVerticesFromHeightmap.js +26 -0
  403. package/dist/cesium/Workers/createVerticesFromQuantizedTerrainMesh.js +26 -0
  404. package/dist/cesium/Workers/createWallGeometry.js +26 -0
  405. package/dist/cesium/Workers/createWallOutlineGeometry.js +26 -0
  406. package/dist/cesium/Workers/decodeDraco.js +26 -0
  407. package/dist/cesium/Workers/decodeGoogleEarthEnterprisePacket.js +26 -0
  408. package/dist/cesium/Workers/decodeI3S.js +26 -0
  409. package/dist/cesium/Workers/gaussianSplatSorter.js +26 -0
  410. package/dist/cesium/Workers/gaussianSplatTextureGenerator.js +26 -0
  411. package/dist/cesium/Workers/incrementallyBuildTerrainPicker.js +26 -0
  412. package/dist/cesium/Workers/transcodeKTX2.js +56 -0
  413. package/dist/cesium/Workers/transferTypedArrayTest.js +26 -0
  414. package/dist/cesium/Workers/upsampleQuantizedTerrainMesh.js +26 -0
  415. package/dist/cesium/Workers/upsampleVerticesFromCesium3DTilesTerrain.js +26 -0
  416. package/dist/index.html +13 -10
  417. package/index.html +1 -0
  418. package/package.json +18 -15
  419. package/src/App.tsx +7 -9
  420. package/src/components/viewer/BCFPanel.tsx +46 -4
  421. package/src/components/viewer/CesiumOverlay.tsx +715 -0
  422. package/src/components/viewer/CesiumSettingsDialog.tsx +100 -0
  423. package/src/components/viewer/ChatPanel.tsx +232 -90
  424. package/src/components/viewer/CommandPalette.tsx +6 -1
  425. package/src/components/viewer/DesktopEntitlementBanner.tsx +74 -0
  426. package/src/components/viewer/ExportChangesButton.tsx +6 -1
  427. package/src/components/viewer/ExportDialog.tsx +22 -6
  428. package/src/components/viewer/HierarchyPanel.tsx +196 -0
  429. package/src/components/viewer/IDSPanel.tsx +52 -3
  430. package/src/components/viewer/KeyboardShortcutsDialog.tsx +1 -1
  431. package/src/components/viewer/MainToolbar.tsx +355 -28
  432. package/src/components/viewer/PropertiesPanel.tsx +234 -81
  433. package/src/components/viewer/ScriptPanel.tsx +34 -8
  434. package/src/components/viewer/SettingsPage.tsx +581 -0
  435. package/src/components/viewer/StatusBar.tsx +17 -1
  436. package/src/components/viewer/ThemeSwitch.tsx +63 -7
  437. package/src/components/viewer/ViewerLayout.tsx +48 -6
  438. package/src/components/viewer/Viewport.tsx +61 -8
  439. package/src/components/viewer/ViewportContainer.tsx +265 -28
  440. package/src/components/viewer/ViewportOverlays.tsx +132 -27
  441. package/src/components/viewer/bcf/BCFTopicDetail.tsx +4 -4
  442. package/src/components/viewer/chat/ModelSelector.tsx +90 -54
  443. package/src/components/viewer/properties/GeoreferencingPanel.tsx +229 -55
  444. package/src/components/viewer/properties/LocationMap.tsx +462 -19
  445. package/src/components/viewer/properties/ModelMetadataPanel.tsx +1 -1
  446. package/src/components/viewer/selectionHandlers.ts +4 -3
  447. package/src/components/viewer/tools/SectionCapControls.tsx +237 -0
  448. package/src/components/viewer/tools/SectionPanel.tsx +39 -18
  449. package/src/components/viewer/useAnimationLoop.ts +13 -1
  450. package/src/components/viewer/useGeometryStreaming.ts +127 -40
  451. package/src/components/viewer/useMouseControls.ts +4 -1
  452. package/src/components/viewer/useRenderUpdates.ts +1 -1
  453. package/src/hooks/ids/idsDataAccessor.ts +60 -24
  454. package/src/hooks/ingest/viewerModelIngest.ts +280 -0
  455. package/src/hooks/useIDS.ts +1 -1
  456. package/src/hooks/useIfc.ts +7 -1
  457. package/src/hooks/useIfcCache.ts +28 -15
  458. package/src/hooks/useIfcFederation.ts +378 -291
  459. package/src/hooks/useIfcLoader.ts +1657 -130
  460. package/src/hooks/useIfcServer.ts +0 -69
  461. package/src/hooks/useViewControls.ts +13 -5
  462. package/src/index.css +484 -10
  463. package/src/lib/desktop/desktopEntitlementEvents.ts +39 -0
  464. package/src/lib/desktop-entitlement.ts +43 -0
  465. package/src/lib/desktop-product.ts +124 -0
  466. package/src/lib/geo/cesium-bridge.ts +318 -0
  467. package/src/lib/geo/effective-georef.test.ts +73 -0
  468. package/src/lib/geo/effective-georef.ts +111 -0
  469. package/src/lib/geo/reproject.ts +249 -37
  470. package/src/lib/llm/byok-guard.test.ts +77 -0
  471. package/src/lib/llm/byok-guard.ts +39 -0
  472. package/src/lib/llm/free-models.test.ts +0 -6
  473. package/src/lib/llm/models.ts +104 -42
  474. package/src/lib/llm/stream-client.ts +74 -110
  475. package/src/lib/llm/stream-direct.test.ts +130 -0
  476. package/src/lib/llm/stream-direct.ts +316 -0
  477. package/src/lib/llm/types.ts +14 -2
  478. package/src/lib/recent-files.ts +2 -1
  479. package/src/main.tsx +1 -10
  480. package/src/services/analysis-extensions.ts +125 -0
  481. package/src/services/api-keys.ts +73 -0
  482. package/src/services/app-navigation.ts +13 -0
  483. package/src/services/bsdd.ts +53 -4
  484. package/src/services/cacheService.ts +1 -1
  485. package/src/services/desktop-cache.ts +43 -0
  486. package/src/services/desktop-export.ts +77 -0
  487. package/src/services/desktop-harness.ts +196 -0
  488. package/src/services/desktop-logger.ts +20 -0
  489. package/src/services/desktop-native-metadata.ts +207 -0
  490. package/src/services/desktop-panel-actions.ts +43 -0
  491. package/src/services/desktop-preferences.ts +44 -0
  492. package/src/services/file-dialog.ts +147 -0
  493. package/src/services/tauri-core-stub.ts +7 -0
  494. package/src/services/tauri-dialog-stub.ts +7 -0
  495. package/src/services/tauri-fs-stub.ts +7 -0
  496. package/src/store/constants.ts +20 -2
  497. package/src/store/index.ts +52 -7
  498. package/src/store/slices/cesiumSlice.ts +127 -0
  499. package/src/store/slices/chatSlice.test.ts +6 -76
  500. package/src/store/slices/chatSlice.ts +21 -58
  501. package/src/store/slices/dataSlice.ts +139 -28
  502. package/src/store/slices/desktopEntitlementSlice.ts +86 -0
  503. package/src/store/slices/loadingSlice.ts +14 -2
  504. package/src/store/slices/modelSlice.ts +58 -3
  505. package/src/store/slices/sectionSlice.test.ts +87 -7
  506. package/src/store/slices/sectionSlice.ts +151 -5
  507. package/src/store/slices/uiSlice.ts +28 -5
  508. package/src/store/types.ts +122 -2
  509. package/src/store.ts +1 -1
  510. package/src/utils/desktopModelSnapshot.ts +358 -0
  511. package/src/utils/ifcConfig.ts +6 -1
  512. package/src/utils/nativeSpatialDataStore.ts +253 -0
  513. package/src/utils/serverDataModel.ts +4 -0
  514. package/src/utils/spatialHierarchy.ts +10 -11
  515. package/src/utils/viewportUtils.ts +7 -2
  516. package/src/vite-env.d.ts +0 -4
  517. package/vite.config.ts +24 -0
  518. package/dist/assets/arrow-DJf2ErbF.js +0 -20
  519. package/dist/assets/basketViewActivator-aojwdomq.js +0 -1
  520. package/dist/assets/desktop-cache-oPzaWXYE.js +0 -1
  521. package/dist/assets/drawing-2d-gWfpdfYe.js +0 -257
  522. package/dist/assets/geometry.worker-Nz9_YIqh.js +0 -1
  523. package/dist/assets/ids-B4jTqB1O.js +0 -1
  524. package/dist/assets/ifc-lite_bg-eSkBTizQ.wasm +0 -0
  525. package/dist/assets/index-pbE7itQS.css +0 -1
  526. package/dist/assets/native-bridge-DSIyEYXG.js +0 -113
  527. package/dist/assets/wasm-bridge-B0J07fZZ.js +0 -1
  528. package/src/components/viewer/UpgradePage.tsx +0 -69
  529. package/src/lib/llm/ClerkChatSync.tsx +0 -74
  530. package/src/lib/llm/clerk-auth.ts +0 -62
@@ -36,6 +36,29 @@ function extractEpsgCode(crs: ProjectedCRS): string | null {
36
36
  return match ? match[1] : null;
37
37
  }
38
38
 
39
+ /**
40
+ * Well-known CRS names that IFC authoring tools set without an EPSG: prefix.
41
+ * Maps normalised name → EPSG code.
42
+ */
43
+ const WELL_KNOWN_CRS: Record<string, string> = {
44
+ 'wgs 84': '4326',
45
+ 'wgs84': '4326',
46
+ 'wgs-84': '4326',
47
+ 'nad83': '4269',
48
+ 'nad27': '4267',
49
+ 'etrs89': '4258',
50
+ 'gcs_wgs_1984': '4326', // ArcGIS / Revit export alias
51
+ 'gcs_north_american_1983': '4269',
52
+ };
53
+
54
+ /**
55
+ * Check if a proj4 definition is a geographic (longlat) CRS rather than a projected one.
56
+ * Geographic CRS coordinates are in degrees, not metres.
57
+ */
58
+ function isGeographicProj4(def: string): boolean {
59
+ return /\+proj=longlat\b/.test(def);
60
+ }
61
+
39
62
  /**
40
63
  * Build a proj4 definition string for a UTM zone.
41
64
  */
@@ -101,11 +124,12 @@ async function fetchProj4Def(epsgCode: string): Promise<string | null> {
101
124
  * Resolution order:
102
125
  * 1. Cache hit
103
126
  * 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)
127
+ * 3. Well-known CRS name lookup (e.g. "WGS 84" → EPSG:4326)
128
+ * 4. UTM zone heuristic (from CRS metadata — mapZone, name, description, mapProjection)
129
+ * 5. Fetch from epsg.io (network fallback)
106
130
  */
107
131
  export async function resolveProjection(crs: ProjectedCRS): Promise<string | null> {
108
- const code = extractEpsgCode(crs);
132
+ let code = extractEpsgCode(crs);
109
133
 
110
134
  // 1. Check cache
111
135
  if (code && projDefCache.has(code)) {
@@ -126,7 +150,31 @@ export async function resolveProjection(crs: ProjectedCRS): Promise<string | nul
126
150
  }
127
151
  }
128
152
 
129
- // 3. UTM zone heuristic
153
+ // 3. Well-known CRS name → EPSG code (handles "WGS 84", "NAD83", etc.)
154
+ if (!code) {
155
+ const normalised = crs.name?.trim().toLowerCase() ?? '';
156
+ const wellKnownCode = WELL_KNOWN_CRS[normalised];
157
+ if (wellKnownCode) {
158
+ code = wellKnownCode;
159
+ if (projDefCache.has(code)) {
160
+ return projDefCache.get(code) ?? null;
161
+ }
162
+ try {
163
+ const bundled = await lookupProj4(code);
164
+ if (bundled) {
165
+ const sanitized = sanitizeProj4(bundled);
166
+ projDefCache.set(code, sanitized);
167
+ // For geographic CRS (longlat), check if we can infer a projected CRS
168
+ // from the UTM zone metadata — a projected CRS is much more useful.
169
+ // If we can't, fall through and return the geographic def below.
170
+ }
171
+ } catch {
172
+ // continue
173
+ }
174
+ }
175
+ }
176
+
177
+ // 4. UTM zone heuristic — check mapZone, name, description, AND mapProjection
130
178
  if (crs.mapZone) {
131
179
  const def = utmProj4String(crs.mapZone);
132
180
  if (def) {
@@ -136,7 +184,8 @@ export async function resolveProjection(crs: ProjectedCRS): Promise<string | nul
136
184
  }
137
185
  const name = crs.name?.toUpperCase() ?? '';
138
186
  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);
187
+ ?? crs.description?.match(/UTM\s+zone\s+(\d{1,2}[NS])/i)
188
+ ?? crs.mapProjection?.match(/UTM\s+zone\s+(\d{1,2}[NS])/i);
140
189
  if (utmMatch) {
141
190
  const def = utmProj4String(utmMatch[1]);
142
191
  if (def) {
@@ -145,7 +194,14 @@ export async function resolveProjection(crs: ProjectedCRS): Promise<string | nul
145
194
  }
146
195
  }
147
196
 
148
- // 4. Network fallback fetch from epsg.io
197
+ // If step 3 resolved a geographic CRS (e.g. EPSG:4326) and we couldn't
198
+ // upgrade it to a projected CRS via the UTM heuristic, still return it —
199
+ // reprojectToLatLon will handle the longlat identity case.
200
+ if (code && projDefCache.has(code)) {
201
+ return projDefCache.get(code) ?? null;
202
+ }
203
+
204
+ // 5. Network fallback — fetch from epsg.io
149
205
  if (code) {
150
206
  const raw = await fetchProj4Def(code);
151
207
  const fetched = raw ? sanitizeProj4(raw) : null;
@@ -175,40 +231,19 @@ export async function resolveProjection(crs: ProjectedCRS): Promise<string | nul
175
231
  function computeProjectedCenter(
176
232
  conversion: MapConversion,
177
233
  coordinateInfo?: CoordinateInfo,
234
+ lengthUnitScale = 1,
178
235
  ): { 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
- }
236
+ const { ifcX, ifcY } = computeLocalIfcCenter(coordinateInfo);
204
237
 
205
- // Apply MapConversion rotation + scale + offset
238
+ // Geometry coordinates (ifcX, ifcY) are already in metres — the geometry engine
239
+ // converts from the IFC file's native unit during extraction. Only MapConversion
240
+ // values (eastings, northings) are in the file's native unit and need scaling.
206
241
  const scale = conversion.scale ?? 1.0;
207
242
  const abscissa = conversion.xAxisAbscissa ?? 1.0;
208
243
  const ordinate = conversion.xAxisOrdinate ?? 0.0;
209
244
 
210
- const easting = conversion.eastings + scale * (abscissa * ifcX - ordinate * ifcY);
211
- const northing = conversion.northings + scale * (ordinate * ifcX + abscissa * ifcY);
245
+ const easting = conversion.eastings * lengthUnitScale + scale * (abscissa * ifcX - ordinate * ifcY);
246
+ const northing = conversion.northings * lengthUnitScale + scale * (ordinate * ifcX + abscissa * ifcY);
212
247
 
213
248
  return { easting, northing };
214
249
  }
@@ -219,19 +254,34 @@ function computeProjectedCenter(
219
254
  * Uses the model's actual geometry bounds + RTC offset to determine where
220
255
  * the model sits in the projected coordinate system, then reprojects to WGS84.
221
256
  *
222
- * @param conversion IfcMapConversion (offset, rotation, scale)
223
- * @param crs IfcProjectedCRS (EPSG code)
257
+ * @param conversion IfcMapConversion (offset, rotation, scale)
258
+ * @param crs IfcProjectedCRS (EPSG code, mapUnitScale)
224
259
  * @param coordinateInfo Geometry coordinate info with bounds and RTC offset
260
+ * @param lengthUnitScale IFC project length unit → metres (fallback when crs.mapUnitScale is absent)
225
261
  */
226
262
  export async function reprojectToLatLon(
227
263
  conversion: MapConversion,
228
264
  crs: ProjectedCRS,
229
265
  coordinateInfo?: CoordinateInfo,
266
+ lengthUnitScale = 1,
230
267
  ): Promise<LatLon | null> {
231
268
  const projDef = await resolveProjection(crs);
232
269
  if (!projDef) return null;
233
270
 
234
- const { easting, northing } = computeProjectedCenter(conversion, coordinateInfo);
271
+ // Geographic CRS (e.g. EPSG:4326) eastings/northings are already lon/lat.
272
+ // Don't add the model's geometry center (in meters) to degree-based coordinates.
273
+ if (isGeographicProj4(projDef)) {
274
+ const lon = conversion.eastings;
275
+ const lat = conversion.northings;
276
+ if (!Number.isFinite(lat) || !Number.isFinite(lon)) return null;
277
+ if (lat < -90 || lat > 90 || lon < -180 || lon > 180) return null;
278
+ return { lat, lon };
279
+ }
280
+
281
+ // MapConversion values use the unit from IfcProjectedCRS.MapUnit. If MapUnit
282
+ // is not specified, the IFC spec defaults to the project's length unit.
283
+ const mapScale = crs.mapUnitScale ?? lengthUnitScale;
284
+ const { easting, northing } = computeProjectedCenter(conversion, coordinateInfo, mapScale);
235
285
 
236
286
  try {
237
287
  const [lon, lat] = proj4(projDef, 'WGS84', [easting, northing]);
@@ -242,3 +292,165 @@ export async function reprojectToLatLon(
242
292
  return null;
243
293
  }
244
294
  }
295
+
296
+ /**
297
+ * Compute the model's local IFC center offset (ifcX, ifcY) from coordinate info.
298
+ * This is the geometry center in IFC Z-up coordinates, before MapConversion is applied.
299
+ */
300
+ function computeLocalIfcCenter(coordinateInfo?: CoordinateInfo): { ifcX: number; ifcY: number } {
301
+ if (!coordinateInfo) return { ifcX: 0, ifcY: 0 };
302
+
303
+ const bounds = coordinateInfo.originalBounds;
304
+ const shift = coordinateInfo.originShift;
305
+ const rtc = coordinateInfo.wasmRtcOffset;
306
+
307
+ const rtcYup = rtc
308
+ ? { x: rtc.x, y: rtc.z, z: -rtc.y }
309
+ : { x: 0, y: 0, z: 0 };
310
+
311
+ const cx = (bounds.min.x + bounds.max.x) / 2;
312
+ const cz = (bounds.min.z + bounds.max.z) / 2;
313
+
314
+ const worldYupX = cx + shift.x + rtcYup.x;
315
+ const worldYupZ = cz + shift.z + rtcYup.z;
316
+
317
+ return { ifcX: worldYupX, ifcY: -worldYupZ };
318
+ }
319
+
320
+ /**
321
+ * Reverse-project a WGS84 lat/lon into the IfcMapConversion eastings/northings
322
+ * values that would place the model center at the given location.
323
+ *
324
+ * This accounts for the model's local geometry offset, rotation, and scale:
325
+ * projected = eastings + scale * (cos*ifcX - sin*ifcY)
326
+ * ⟹ eastings = projected - scale * (cos*ifcX - sin*ifcY)
327
+ */
328
+ export async function reprojectFromLatLon(
329
+ latLon: LatLon,
330
+ crs: ProjectedCRS,
331
+ conversion?: MapConversion,
332
+ coordinateInfo?: CoordinateInfo,
333
+ lengthUnitScale = 1,
334
+ ): Promise<{ easting: number; northing: number } | null> {
335
+ const projDef = await resolveProjection(crs);
336
+ if (!projDef) return null;
337
+
338
+ // Geographic CRS — coordinates are lon/lat in degrees, no projection needed.
339
+ if (isGeographicProj4(projDef)) {
340
+ return { easting: latLon.lon, northing: latLon.lat };
341
+ }
342
+
343
+ try {
344
+ const [projE, projN] = proj4('WGS84', projDef, [latLon.lon, latLon.lat]);
345
+ if (!Number.isFinite(projE) || !Number.isFinite(projN)) return null;
346
+
347
+ // Convert projected metres back to MapConversion's unit.
348
+ // Geometry offsets (ifcX/Y) are already in metres.
349
+ const mapScale = crs.mapUnitScale ?? lengthUnitScale;
350
+ const invScale = mapScale !== 0 ? 1 / mapScale : 1;
351
+ const { ifcX, ifcY } = computeLocalIfcCenter(coordinateInfo);
352
+ const scale = conversion?.scale ?? 1.0;
353
+ const abscissa = conversion?.xAxisAbscissa ?? 1.0;
354
+ const ordinate = conversion?.xAxisOrdinate ?? 0.0;
355
+
356
+ // Result is in IFC native units (the reverse of: E_native * LUS + geom_offset = E_metres)
357
+ const easting = (projE - scale * (abscissa * ifcX - ordinate * ifcY)) * invScale;
358
+ const northing = (projN - scale * (ordinate * ifcX + abscissa * ifcY)) * invScale;
359
+
360
+ return { easting, northing };
361
+ } catch {
362
+ return null;
363
+ }
364
+ }
365
+
366
+ /**
367
+ * Compute a building footprint rectangle from the model's bounding box and
368
+ * reproject each corner to WGS84 for display as a GeoJSON polygon on a web map.
369
+ *
370
+ * Uses the shiftedBounds (scene-local after RTC) from CoordinateInfo, transforms
371
+ * each corner through the MapConversion pipeline (rotation + scale + offset),
372
+ * then reprojects to lat/lon. The result is a rotated rectangle matching the
373
+ * model's XZ extent on the map.
374
+ *
375
+ * @param lengthUnitScale IFC project length unit → metres (fallback when crs.mapUnitScale is absent)
376
+ * @returns A single GeoJSON-compatible polygon: closed ring of [lon, lat] pairs
377
+ */
378
+ export async function computeFootprintGeoJSON(
379
+ conversion: MapConversion,
380
+ crs: ProjectedCRS,
381
+ coordinateInfo: CoordinateInfo,
382
+ lengthUnitScale = 1,
383
+ ): Promise<[number, number][] | null> {
384
+ const projDef = await resolveProjection(crs);
385
+ if (!projDef) {
386
+ console.warn('[footprint] failed to resolve projection for CRS:', crs.name);
387
+ return null;
388
+ }
389
+
390
+ const scale = conversion.scale ?? 1.0;
391
+ const abscissa = conversion.xAxisAbscissa ?? 1.0;
392
+ const ordinate = conversion.xAxisOrdinate ?? 0.0;
393
+
394
+ const shift = coordinateInfo.originShift;
395
+ const rtc = coordinateInfo.wasmRtcOffset;
396
+ const rtcYup = rtc
397
+ ? { x: rtc.x, z: -rtc.y }
398
+ : { x: 0, z: 0 };
399
+
400
+ const bounds = coordinateInfo.shiftedBounds;
401
+
402
+ // Four corners of the bounding box on the XZ plane (viewer Y-up)
403
+ const corners = [
404
+ { x: bounds.min.x, z: bounds.min.z },
405
+ { x: bounds.max.x, z: bounds.min.z },
406
+ { x: bounds.max.x, z: bounds.max.z },
407
+ { x: bounds.min.x, z: bounds.max.z },
408
+ ];
409
+
410
+ const ring: [number, number][] = [];
411
+
412
+ for (const c of corners) {
413
+ // Scene-local → world Y-up
414
+ const worldX = c.x + shift.x + rtcYup.x;
415
+ const worldZ = c.z + shift.z + rtcYup.z;
416
+
417
+ // Y-up → IFC Z-up: ifcX = worldX, ifcY = -worldZ
418
+ const ifcX = worldX;
419
+ const ifcY = -worldZ;
420
+
421
+ // Geometry coords (ifcX/Y) are already in metres; only MapConversion needs scaling
422
+ const mapScale = crs.mapUnitScale ?? lengthUnitScale;
423
+ const easting = conversion.eastings * mapScale + scale * (abscissa * ifcX - ordinate * ifcY);
424
+ const northing = conversion.northings * mapScale + scale * (ordinate * ifcX + abscissa * ifcY);
425
+
426
+ // Projected CRS → WGS84
427
+ try {
428
+ const [lon, lat] = proj4(projDef, 'WGS84', [easting, northing]);
429
+ if (!Number.isFinite(lat) || !Number.isFinite(lon)) return null;
430
+ ring.push([lon, lat]);
431
+ } catch {
432
+ return null;
433
+ }
434
+ }
435
+
436
+ // Close the ring (GeoJSON requirement)
437
+ ring.push(ring[0]);
438
+ return ring;
439
+ }
440
+
441
+ /**
442
+ * Query terrain elevation at a given lat/lon using the Open-Meteo elevation API.
443
+ * Returns height in metres above sea level, or null on failure.
444
+ */
445
+ export async function queryTerrainElevation(latLon: LatLon): Promise<number | null> {
446
+ try {
447
+ const url = `https://api.open-meteo.com/v1/elevation?latitude=${latLon.lat}&longitude=${latLon.lon}`;
448
+ const resp = await fetch(url);
449
+ if (!resp.ok) return null;
450
+ const data = await resp.json();
451
+ const elev = data?.elevation?.[0];
452
+ return typeof elev === 'number' && Number.isFinite(elev) ? elev : null;
453
+ } catch {
454
+ return null;
455
+ }
456
+ }
@@ -0,0 +1,77 @@
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 test from 'node:test';
6
+ import assert from 'node:assert/strict';
7
+ import { resolveStreamRoute } from './byok-guard.js';
8
+ import { DEFAULT_BYOK_MODEL, BYOK_MODELS } from './models.js';
9
+
10
+ const ANTHROPIC_MODEL = BYOK_MODELS.find((m) => m.source === 'anthropic')!;
11
+ const OPENAI_MODEL = BYOK_MODELS.find((m) => m.source === 'openai')!;
12
+
13
+ test('resolveStreamRoute returns proxy route for free models', () => {
14
+ const route = resolveStreamRoute('openai/gpt-free', { anthropicKey: '', openaiKey: '' });
15
+ assert.equal(route.kind, 'proxy');
16
+ if (route.kind === 'proxy') {
17
+ assert.equal(route.model, 'openai/gpt-free');
18
+ }
19
+ });
20
+
21
+ test('resolveStreamRoute returns proxy route for unknown model ids', () => {
22
+ const route = resolveStreamRoute('made-up-model', { anthropicKey: 'sk-ant-...', openaiKey: '' });
23
+ assert.equal(route.kind, 'proxy');
24
+ });
25
+
26
+ test('resolveStreamRoute returns anthropic route when key present', () => {
27
+ const route = resolveStreamRoute(ANTHROPIC_MODEL.id, {
28
+ anthropicKey: 'sk-ant-abc',
29
+ openaiKey: '',
30
+ });
31
+ assert.equal(route.kind, 'anthropic');
32
+ if (route.kind === 'anthropic') {
33
+ assert.equal(route.apiKey, 'sk-ant-abc');
34
+ assert.equal(route.model, ANTHROPIC_MODEL.id);
35
+ }
36
+ });
37
+
38
+ test('resolveStreamRoute returns missing-key when anthropic model selected without key', () => {
39
+ const route = resolveStreamRoute(ANTHROPIC_MODEL.id, {
40
+ anthropicKey: '',
41
+ openaiKey: 'sk-openai-xyz',
42
+ });
43
+ assert.equal(route.kind, 'missing-key');
44
+ if (route.kind === 'missing-key') {
45
+ assert.equal(route.provider, 'anthropic');
46
+ }
47
+ });
48
+
49
+ test('resolveStreamRoute returns openai route when key present', () => {
50
+ const route = resolveStreamRoute(OPENAI_MODEL.id, {
51
+ anthropicKey: '',
52
+ openaiKey: 'sk-openai-xyz',
53
+ });
54
+ assert.equal(route.kind, 'openai');
55
+ if (route.kind === 'openai') {
56
+ assert.equal(route.apiKey, 'sk-openai-xyz');
57
+ }
58
+ });
59
+
60
+ test('resolveStreamRoute returns missing-key when openai model selected without key', () => {
61
+ const route = resolveStreamRoute(OPENAI_MODEL.id, {
62
+ anthropicKey: 'sk-ant-abc',
63
+ openaiKey: '',
64
+ });
65
+ assert.equal(route.kind, 'missing-key');
66
+ if (route.kind === 'missing-key') {
67
+ assert.equal(route.provider, 'openai');
68
+ }
69
+ });
70
+
71
+ test('resolveStreamRoute treats whitespace-only keys as missing', () => {
72
+ const route = resolveStreamRoute(DEFAULT_BYOK_MODEL.id, {
73
+ anthropicKey: ' ',
74
+ openaiKey: ' ',
75
+ });
76
+ assert.equal(route.kind, 'missing-key');
77
+ });
@@ -0,0 +1,39 @@
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
+ * Pure routing guard for chat streams.
7
+ *
8
+ * Given a model id and the current BYOK key bag, decide whether the send
9
+ * should go through the proxy, direct to a provider, or be blocked because
10
+ * a required key is missing. Pulled out of ChatPanel so we can unit-test
11
+ * the guard without spinning up React — and so the "missing key" check
12
+ * happens BEFORE the user message is appended to the chat history.
13
+ */
14
+
15
+ import { getModelById } from './models.js';
16
+ import type { ApiKeyConfig } from '../../services/api-keys.js';
17
+
18
+ export type StreamRoute =
19
+ | { kind: 'proxy'; model: string }
20
+ | { kind: 'anthropic'; model: string; apiKey: string }
21
+ | { kind: 'openai'; model: string; apiKey: string }
22
+ | { kind: 'missing-key'; provider: 'anthropic' | 'openai' };
23
+
24
+ export function resolveStreamRoute(modelId: string, keys: ApiKeyConfig): StreamRoute {
25
+ const model = getModelById(modelId);
26
+ const source = model?.source ?? 'proxy';
27
+
28
+ if (source === 'anthropic') {
29
+ const apiKey = keys.anthropicKey.trim();
30
+ if (!apiKey) return { kind: 'missing-key', provider: 'anthropic' };
31
+ return { kind: 'anthropic', model: modelId, apiKey };
32
+ }
33
+ if (source === 'openai') {
34
+ const apiKey = keys.openaiKey.trim();
35
+ if (!apiKey) return { kind: 'missing-key', provider: 'openai' };
36
+ return { kind: 'openai', model: modelId, apiKey };
37
+ }
38
+ return { kind: 'proxy', model: modelId };
39
+ }
@@ -47,9 +47,6 @@ test('registry free models match configured env list', async (t) => {
47
47
  }
48
48
 
49
49
  process.env.VITE_LLM_FREE_MODELS = configuredFreeModels.join(',');
50
- process.env.VITE_LLM_PRO_MODELS_LOW = '';
51
- process.env.VITE_LLM_PRO_MODELS_MEDIUM = '';
52
- process.env.VITE_LLM_PRO_MODELS_HIGH = '';
53
50
  process.env.VITE_LLM_IMAGE_MODELS = '';
54
51
  process.env.VITE_LLM_FILE_ATTACHMENT_MODELS = '';
55
52
 
@@ -63,9 +60,6 @@ test('registry free models match configured env list', async (t) => {
63
60
 
64
61
  test('model capabilities follow override env lists', async () => {
65
62
  process.env.VITE_LLM_FREE_MODELS = 'qwen/qwen3-coder,mistralai/devstral-2512';
66
- process.env.VITE_LLM_PRO_MODELS_LOW = '';
67
- process.env.VITE_LLM_PRO_MODELS_MEDIUM = '';
68
- process.env.VITE_LLM_PRO_MODELS_HIGH = '';
69
63
  process.env.VITE_LLM_IMAGE_MODELS = 'mistralai/devstral-2512';
70
64
  process.env.VITE_LLM_FILE_ATTACHMENT_MODELS = 'qwen/qwen3-coder';
71
65