@bldrs-ai/conway 1.389.1221 → 1.394.1504
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +36 -22
- package/compiled/Dist/ConwayGeomWasmNode.js +0 -0
- package/compiled/Dist/ConwayGeomWasmNodeMT.js +0 -0
- package/compiled/Dist/ConwayGeomWasmWeb.js +0 -0
- package/compiled/Dist/ConwayGeomWasmWebMT.js +1 -1
- package/compiled/Dist/ConwayGeomWasmWebMT.wasm +0 -0
- package/compiled/dependencies/conway-geom/Dist/ConwayGeomWasmNode.js +0 -0
- package/compiled/dependencies/conway-geom/Dist/ConwayGeomWasmNodeMT.js +0 -0
- package/compiled/dependencies/conway-geom/Dist/ConwayGeomWasmWeb.js +0 -0
- package/compiled/dependencies/conway-geom/Dist/ConwayGeomWasmWebMT.js +1 -1
- package/compiled/dependencies/conway-geom/Dist/ConwayGeomWasmWebMT.wasm +0 -0
- package/compiled/dependencies/conway-geom/interface/conway_geometry.d.ts +19 -0
- package/compiled/dependencies/conway-geom/interface/conway_geometry.d.ts.map +1 -1
- package/compiled/dependencies/conway-geom/interface/conway_geometry.js +17 -0
- package/compiled/dependencies/conway-geom/interface/parameters/surface_object.d.ts +6 -0
- package/compiled/dependencies/conway-geom/interface/parameters/surface_object.d.ts.map +1 -1
- package/compiled/examples/browser-bundled.cjs +1569 -51
- package/compiled/examples/cli-bundled.cjs +2790 -436
- package/compiled/examples/cli-step-bundled.cjs +1904 -229
- package/compiled/examples/validator-bundled.cjs +1569 -51
- package/compiled/src/AP214E3_2010/AP214E3_2010_gen/b_spline_curve.gen.d.ts +2 -2
- package/compiled/src/AP214E3_2010/AP214E3_2010_gen/b_spline_curve.gen.d.ts.map +1 -1
- package/compiled/src/AP214E3_2010/AP214E3_2010_gen/b_spline_curve.gen.js +2 -2
- package/compiled/src/AP214E3_2010/AP214E3_2010_gen/b_spline_surface.gen.d.ts +3 -3
- package/compiled/src/AP214E3_2010/AP214E3_2010_gen/b_spline_surface.gen.d.ts.map +1 -1
- package/compiled/src/AP214E3_2010/AP214E3_2010_gen/b_spline_surface.gen.js +3 -3
- package/compiled/src/AP214E3_2010/AP214E3_2010_gen/composite_curve.gen.d.ts +1 -1
- package/compiled/src/AP214E3_2010/AP214E3_2010_gen/composite_curve.gen.d.ts.map +1 -1
- package/compiled/src/AP214E3_2010/AP214E3_2010_gen/composite_curve.gen.js +1 -1
- package/compiled/src/AP214E3_2010/AP214E3_2010_gen/offset_curve_2d.gen.d.ts +1 -1
- package/compiled/src/AP214E3_2010/AP214E3_2010_gen/offset_curve_2d.gen.d.ts.map +1 -1
- package/compiled/src/AP214E3_2010/AP214E3_2010_gen/offset_curve_2d.gen.js +1 -1
- package/compiled/src/AP214E3_2010/AP214E3_2010_gen/offset_curve_3d.gen.d.ts +1 -1
- package/compiled/src/AP214E3_2010/AP214E3_2010_gen/offset_curve_3d.gen.d.ts.map +1 -1
- package/compiled/src/AP214E3_2010/AP214E3_2010_gen/offset_curve_3d.gen.js +1 -1
- package/compiled/src/AP214E3_2010/AP214E3_2010_gen/offset_surface.gen.d.ts +1 -1
- package/compiled/src/AP214E3_2010/AP214E3_2010_gen/offset_surface.gen.d.ts.map +1 -1
- package/compiled/src/AP214E3_2010/AP214E3_2010_gen/offset_surface.gen.js +1 -1
- package/compiled/src/AP214E3_2010/AP214E3_2010_gen/presentation_style_assignment.gen.d.ts.map +1 -1
- package/compiled/src/AP214E3_2010/AP214E3_2010_gen/presentation_style_assignment.gen.js +2 -2
- package/compiled/src/AP214E3_2010/AP214E3_2010_gen/schema_ap214.gen.js +11 -11
- package/compiled/src/AP214E3_2010/AP214E3_2010_gen/shape_aspect.gen.d.ts +1 -1
- package/compiled/src/AP214E3_2010/AP214E3_2010_gen/shape_aspect.gen.d.ts.map +1 -1
- package/compiled/src/AP214E3_2010/AP214E3_2010_gen/shape_aspect.gen.js +1 -1
- package/compiled/src/AP214E3_2010/ap214_command_line_main.js +7 -3
- package/compiled/src/AP214E3_2010/ap214_geometry_extraction.d.ts +181 -7
- package/compiled/src/AP214E3_2010/ap214_geometry_extraction.d.ts.map +1 -1
- package/compiled/src/AP214E3_2010/ap214_geometry_extraction.js +906 -137
- package/compiled/src/AP214E3_2010/ap214_geometry_extraction.test.js +10 -2
- package/compiled/src/AP214E3_2010/ap214_logical_attribute.test.d.ts +2 -0
- package/compiled/src/AP214E3_2010/ap214_logical_attribute.test.d.ts.map +1 -0
- package/compiled/src/AP214E3_2010/ap214_logical_attribute.test.js +114 -0
- package/compiled/src/AP214E3_2010/ap214_model_geometry.d.ts +6 -0
- package/compiled/src/AP214E3_2010/ap214_model_geometry.d.ts.map +1 -1
- package/compiled/src/AP214E3_2010/ap214_model_geometry.js +9 -0
- package/compiled/src/AP214E3_2010/ap214_pcurve_basis_surfaces.test.d.ts +2 -0
- package/compiled/src/AP214E3_2010/ap214_pcurve_basis_surfaces.test.d.ts.map +1 -0
- package/compiled/src/AP214E3_2010/ap214_pcurve_basis_surfaces.test.js +233 -0
- package/compiled/src/AP214E3_2010/ap214_sphere_vertex_loop.test.d.ts +2 -0
- package/compiled/src/AP214E3_2010/ap214_sphere_vertex_loop.test.d.ts.map +1 -0
- package/compiled/src/AP214E3_2010/ap214_sphere_vertex_loop.test.js +147 -0
- package/compiled/src/AP214E3_2010/ap214_step_model.d.ts +2 -1
- package/compiled/src/AP214E3_2010/ap214_step_model.d.ts.map +1 -1
- package/compiled/src/AP214E3_2010/ap214_step_model.js +1 -1
- package/compiled/src/AP214E3_2010/ap214_typed_select_enum.test.d.ts +2 -0
- package/compiled/src/AP214E3_2010/ap214_typed_select_enum.test.d.ts.map +1 -0
- package/compiled/src/AP214E3_2010/ap214_typed_select_enum.test.js +65 -0
- package/compiled/src/AP214E3_2010/ap214_unit_scale.test.d.ts +2 -0
- package/compiled/src/AP214E3_2010/ap214_unit_scale.test.d.ts.map +1 -0
- package/compiled/src/AP214E3_2010/ap214_unit_scale.test.js +111 -0
- package/compiled/src/compat/web-ifc/ap214_streamed_open.test.d.ts +2 -0
- package/compiled/src/compat/web-ifc/ap214_streamed_open.test.d.ts.map +1 -0
- package/compiled/src/compat/web-ifc/ap214_streamed_open.test.js +190 -0
- package/compiled/src/compat/web-ifc/coordination_export_order.test.d.ts +2 -0
- package/compiled/src/compat/web-ifc/coordination_export_order.test.d.ts.map +1 -0
- package/compiled/src/compat/web-ifc/coordination_export_order.test.js +110 -0
- package/compiled/src/compat/web-ifc/coordination_f64.d.ts +165 -0
- package/compiled/src/compat/web-ifc/coordination_f64.d.ts.map +1 -0
- package/compiled/src/compat/web-ifc/coordination_f64.js +286 -0
- package/compiled/src/compat/web-ifc/coordination_f64.test.d.ts +2 -0
- package/compiled/src/compat/web-ifc/coordination_f64.test.d.ts.map +1 -0
- package/compiled/src/compat/web-ifc/coordination_f64.test.js +225 -0
- package/compiled/src/compat/web-ifc/ifc_api.d.ts +154 -0
- package/compiled/src/compat/web-ifc/ifc_api.d.ts.map +1 -1
- package/compiled/src/compat/web-ifc/ifc_api.js +211 -3
- package/compiled/src/compat/web-ifc/ifc_api_deferred_open.test.d.ts +2 -0
- package/compiled/src/compat/web-ifc/ifc_api_deferred_open.test.d.ts.map +1 -0
- package/compiled/src/compat/web-ifc/ifc_api_deferred_open.test.js +288 -0
- package/compiled/src/compat/web-ifc/ifc_api_model_passthrough.d.ts +39 -0
- package/compiled/src/compat/web-ifc/ifc_api_model_passthrough.d.ts.map +1 -1
- package/compiled/src/compat/web-ifc/ifc_api_model_passthrough_factory.d.ts +30 -0
- package/compiled/src/compat/web-ifc/ifc_api_model_passthrough_factory.d.ts.map +1 -1
- package/compiled/src/compat/web-ifc/ifc_api_model_passthrough_factory.js +83 -0
- package/compiled/src/compat/web-ifc/ifc_api_preview_channel.test.d.ts +2 -0
- package/compiled/src/compat/web-ifc/ifc_api_preview_channel.test.d.ts.map +1 -0
- package/compiled/src/compat/web-ifc/ifc_api_preview_channel.test.js +383 -0
- package/compiled/src/compat/web-ifc/ifc_api_preview_coordination.test.d.ts +2 -0
- package/compiled/src/compat/web-ifc/ifc_api_preview_coordination.test.d.ts.map +1 -0
- package/compiled/src/compat/web-ifc/ifc_api_preview_coordination.test.js +124 -0
- package/compiled/src/compat/web-ifc/ifc_api_proxy_ap214.d.ts +132 -0
- package/compiled/src/compat/web-ifc/ifc_api_proxy_ap214.d.ts.map +1 -1
- package/compiled/src/compat/web-ifc/ifc_api_proxy_ap214.js +488 -92
- package/compiled/src/compat/web-ifc/ifc_api_proxy_ifc.d.ts +268 -0
- package/compiled/src/compat/web-ifc/ifc_api_proxy_ifc.d.ts.map +1 -1
- package/compiled/src/compat/web-ifc/ifc_api_proxy_ifc.js +996 -149
- package/compiled/src/compat/web-ifc/ifc_api_streamed_open.test.d.ts +2 -0
- package/compiled/src/compat/web-ifc/ifc_api_streamed_open.test.d.ts.map +1 -0
- package/compiled/src/compat/web-ifc/ifc_api_streamed_open.test.js +129 -0
- package/compiled/src/compat/web-ifc/spatial_imposter.d.ts +134 -0
- package/compiled/src/compat/web-ifc/spatial_imposter.d.ts.map +1 -0
- package/compiled/src/compat/web-ifc/spatial_imposter.js +933 -0
- package/compiled/src/compat/web-ifc/spatial_imposter.test.d.ts +2 -0
- package/compiled/src/compat/web-ifc/spatial_imposter.test.d.ts.map +1 -0
- package/compiled/src/compat/web-ifc/spatial_imposter.test.js +467 -0
- package/compiled/src/compat/web-ifc/store_preview_channel.d.ts +187 -0
- package/compiled/src/compat/web-ifc/store_preview_channel.d.ts.map +1 -0
- package/compiled/src/compat/web-ifc/store_preview_channel.js +524 -0
- package/compiled/src/compat/web-ifc/store_preview_channel.test.d.ts +2 -0
- package/compiled/src/compat/web-ifc/store_preview_channel.test.d.ts.map +1 -0
- package/compiled/src/compat/web-ifc/store_preview_channel.test.js +234 -0
- package/compiled/src/compat/web-ifc/streamed_preview_channel.d.ts +306 -0
- package/compiled/src/compat/web-ifc/streamed_preview_channel.d.ts.map +1 -0
- package/compiled/src/compat/web-ifc/streamed_preview_channel.js +580 -0
- package/compiled/src/compat/web-ifc/web_wasm_directory.test.d.ts +2 -0
- package/compiled/src/compat/web-ifc/web_wasm_directory.test.d.ts.map +1 -0
- package/compiled/src/compat/web-ifc/web_wasm_directory.test.js +22 -0
- package/compiled/src/core/composed_model_skeleton.d.ts +63 -0
- package/compiled/src/core/composed_model_skeleton.d.ts.map +1 -0
- package/compiled/src/core/composed_model_skeleton.js +66 -0
- package/compiled/src/core/composed_model_skeleton.test.d.ts +2 -0
- package/compiled/src/core/composed_model_skeleton.test.d.ts.map +1 -0
- package/compiled/src/core/composed_model_skeleton.test.js +69 -0
- package/compiled/src/core/demand_geometry_queue.d.ts +147 -0
- package/compiled/src/core/demand_geometry_queue.d.ts.map +1 -0
- package/compiled/src/core/demand_geometry_queue.js +223 -0
- package/compiled/src/core/demand_geometry_queue.test.d.ts +2 -0
- package/compiled/src/core/demand_geometry_queue.test.d.ts.map +1 -0
- package/compiled/src/core/demand_geometry_queue.test.js +133 -0
- package/compiled/src/core/demand_residency_pump.d.ts +93 -0
- package/compiled/src/core/demand_residency_pump.d.ts.map +1 -0
- package/compiled/src/core/demand_residency_pump.js +120 -0
- package/compiled/src/core/demand_residency_pump.test.d.ts +2 -0
- package/compiled/src/core/demand_residency_pump.test.d.ts.map +1 -0
- package/compiled/src/core/demand_residency_pump.test.js +148 -0
- package/compiled/src/core/geometry_tile_bindings.d.ts +110 -0
- package/compiled/src/core/geometry_tile_bindings.d.ts.map +1 -0
- package/compiled/src/core/geometry_tile_bindings.js +76 -0
- package/compiled/src/core/geometry_tile_bindings.test.d.ts +2 -0
- package/compiled/src/core/geometry_tile_bindings.test.d.ts.map +1 -0
- package/compiled/src/core/geometry_tile_bindings.test.js +211 -0
- package/compiled/src/core/geometry_tile_pool.d.ts +99 -0
- package/compiled/src/core/geometry_tile_pool.d.ts.map +1 -0
- package/compiled/src/core/geometry_tile_pool.js +104 -0
- package/compiled/src/core/geometry_tile_pool.test.d.ts +2 -0
- package/compiled/src/core/geometry_tile_pool.test.d.ts.map +1 -0
- package/compiled/src/core/geometry_tile_pool.test.js +180 -0
- package/compiled/src/core/mem/chunked_pool.d.ts +116 -0
- package/compiled/src/core/mem/chunked_pool.d.ts.map +1 -0
- package/compiled/src/core/mem/chunked_pool.js +149 -0
- package/compiled/src/core/mem/chunked_pool.test.d.ts +2 -0
- package/compiled/src/core/mem/chunked_pool.test.d.ts.map +1 -0
- package/compiled/src/core/mem/chunked_pool.test.js +63 -0
- package/compiled/src/core/mem/shared_asset_pool.d.ts +82 -0
- package/compiled/src/core/mem/shared_asset_pool.d.ts.map +1 -0
- package/compiled/src/core/mem/shared_asset_pool.js +113 -0
- package/compiled/src/core/mem/shared_asset_pool.test.d.ts +2 -0
- package/compiled/src/core/mem/shared_asset_pool.test.d.ts.map +1 -0
- package/compiled/src/core/mem/shared_asset_pool.test.js +49 -0
- package/compiled/src/core/model_registry.d.ts +87 -0
- package/compiled/src/core/model_registry.d.ts.map +1 -0
- package/compiled/src/core/model_registry.js +101 -0
- package/compiled/src/core/model_registry.test.d.ts +2 -0
- package/compiled/src/core/model_registry.test.d.ts.map +1 -0
- package/compiled/src/core/model_registry.test.js +60 -0
- package/compiled/src/core/model_uri.d.ts +57 -0
- package/compiled/src/core/model_uri.d.ts.map +1 -0
- package/compiled/src/core/model_uri.js +101 -0
- package/compiled/src/core/model_uri.test.d.ts +2 -0
- package/compiled/src/core/model_uri.test.d.ts.map +1 -0
- package/compiled/src/core/model_uri.test.js +49 -0
- package/compiled/src/core/progress.d.ts +16 -2
- package/compiled/src/core/progress.d.ts.map +1 -1
- package/compiled/src/core/progress.js +31 -5
- package/compiled/src/core/progress.test.js +11 -2
- package/compiled/src/core/progress_log.d.ts +1 -0
- package/compiled/src/core/progress_log.d.ts.map +1 -1
- package/compiled/src/core/progress_log.js +7 -2
- package/compiled/src/core/progress_log.test.js +21 -0
- package/compiled/src/core/shared_byte_budget.d.ts +60 -0
- package/compiled/src/core/shared_byte_budget.d.ts.map +1 -0
- package/compiled/src/core/shared_byte_budget.js +85 -0
- package/compiled/src/core/shared_byte_budget.test.d.ts +2 -0
- package/compiled/src/core/shared_byte_budget.test.d.ts.map +1 -0
- package/compiled/src/core/shared_byte_budget.test.js +55 -0
- package/compiled/src/core/wasm_heap.d.ts +208 -0
- package/compiled/src/core/wasm_heap.d.ts.map +1 -0
- package/compiled/src/core/wasm_heap.js +417 -0
- package/compiled/src/core/wasm_heap.test.d.ts +2 -0
- package/compiled/src/core/wasm_heap.test.d.ts.map +1 -0
- package/compiled/src/core/wasm_heap.test.js +546 -0
- package/compiled/src/demand/index.d.ts +23 -0
- package/compiled/src/demand/index.d.ts.map +1 -0
- package/compiled/src/demand/index.js +22 -0
- package/compiled/src/ifc/ifc4_gen/IfcLogical.gen.d.ts +1 -1
- package/compiled/src/ifc/ifc4_gen/IfcLogical.gen.d.ts.map +1 -1
- package/compiled/src/ifc/ifc4_gen/IfcLogical.gen.js +1 -1
- package/compiled/src/ifc/ifc4_gen/IfcPresentationStyleAssignment.gen.d.ts.map +1 -1
- package/compiled/src/ifc/ifc4_gen/IfcPresentationStyleAssignment.gen.js +2 -2
- package/compiled/src/ifc/ifc4_gen/IfcRelInterferesElements.gen.d.ts +1 -1
- package/compiled/src/ifc/ifc4_gen/IfcRelInterferesElements.gen.d.ts.map +1 -1
- package/compiled/src/ifc/ifc4_gen/IfcRelInterferesElements.gen.js +1 -1
- package/compiled/src/ifc/ifc4_gen/schema_ifc.gen.js +2 -2
- package/compiled/src/ifc/ifc_demand_extraction.test.d.ts +2 -0
- package/compiled/src/ifc/ifc_demand_extraction.test.d.ts.map +1 -0
- package/compiled/src/ifc/ifc_demand_extraction.test.js +251 -0
- package/compiled/src/ifc/ifc_geometry_extraction.d.ts +367 -6
- package/compiled/src/ifc/ifc_geometry_extraction.d.ts.map +1 -1
- package/compiled/src/ifc/ifc_geometry_extraction.js +1322 -389
- package/compiled/src/ifc/ifc_grid_placement.test.d.ts +2 -0
- package/compiled/src/ifc/ifc_grid_placement.test.d.ts.map +1 -0
- package/compiled/src/ifc/ifc_grid_placement.test.js +261 -0
- package/compiled/src/ifc/ifc_model_geometry.d.ts +12 -0
- package/compiled/src/ifc/ifc_model_geometry.d.ts.map +1 -1
- package/compiled/src/ifc/ifc_model_geometry.js +15 -0
- package/compiled/src/ifc/ifc_regression_batch_main.js +210 -12
- package/compiled/src/ifc/ifc_spatial_skeleton.d.ts +145 -0
- package/compiled/src/ifc/ifc_spatial_skeleton.d.ts.map +1 -0
- package/compiled/src/ifc/ifc_spatial_skeleton.js +266 -0
- package/compiled/src/ifc/ifc_spatial_skeleton.test.d.ts +2 -0
- package/compiled/src/ifc/ifc_spatial_skeleton.test.d.ts.map +1 -0
- package/compiled/src/ifc/ifc_spatial_skeleton.test.js +199 -0
- package/compiled/src/ifc/ifc_step_model.d.ts +6 -2
- package/compiled/src/ifc/ifc_step_model.d.ts.map +1 -1
- package/compiled/src/ifc/ifc_step_model.js +6 -4
- package/compiled/src/ifc/ifc_step_parser.d.ts +58 -0
- package/compiled/src/ifc/ifc_step_parser.d.ts.map +1 -1
- package/compiled/src/ifc/ifc_step_parser.js +64 -0
- package/compiled/src/ifc/ifc_stream_model.test.d.ts +2 -0
- package/compiled/src/ifc/ifc_stream_model.test.d.ts.map +1 -0
- package/compiled/src/ifc/ifc_stream_model.test.js +70 -0
- package/compiled/src/ifc/ifc_stream_open.d.ts +131 -0
- package/compiled/src/ifc/ifc_stream_open.d.ts.map +1 -0
- package/compiled/src/ifc/ifc_stream_open.js +116 -0
- package/compiled/src/ifc/ifc_stream_open.test.d.ts +2 -0
- package/compiled/src/ifc/ifc_stream_open.test.d.ts.map +1 -0
- package/compiled/src/ifc/ifc_stream_open.test.js +230 -0
- package/compiled/src/ifc/ifc_tile_extractor.d.ts +84 -0
- package/compiled/src/ifc/ifc_tile_extractor.d.ts.map +1 -0
- package/compiled/src/ifc/ifc_tile_extractor.js +134 -0
- package/compiled/src/ifc/ifc_tile_extractor.test.d.ts +2 -0
- package/compiled/src/ifc/ifc_tile_extractor.test.d.ts.map +1 -0
- package/compiled/src/ifc/ifc_tile_extractor.test.js +118 -0
- package/compiled/src/ifc/ifc_typed_select_enum.test.d.ts +2 -0
- package/compiled/src/ifc/ifc_typed_select_enum.test.d.ts.map +1 -0
- package/compiled/src/ifc/ifc_typed_select_enum.test.js +60 -0
- package/compiled/src/index.d.ts +21 -1
- package/compiled/src/index.d.ts.map +1 -1
- package/compiled/src/index.js +28 -1
- package/compiled/src/logging/logger.d.ts +16 -2
- package/compiled/src/logging/logger.d.ts.map +1 -1
- package/compiled/src/logging/logger.js +34 -7
- package/compiled/src/logging/logger.test.js +30 -0
- package/compiled/src/mem/index.d.ts +17 -0
- package/compiled/src/mem/index.d.ts.map +1 -0
- package/compiled/src/mem/index.js +16 -0
- package/compiled/src/namespace_surface.test.d.ts +2 -0
- package/compiled/src/namespace_surface.test.d.ts.map +1 -0
- package/compiled/src/namespace_surface.test.js +43 -0
- package/compiled/src/parsing/parsing_buffer.d.ts +23 -0
- package/compiled/src/parsing/parsing_buffer.d.ts.map +1 -1
- package/compiled/src/parsing/parsing_buffer.js +31 -0
- package/compiled/src/scripts/model_report_displacement.test.d.ts +2 -0
- package/compiled/src/scripts/model_report_displacement.test.d.ts.map +1 -0
- package/compiled/src/scripts/model_report_displacement.test.js +104 -0
- package/compiled/src/scripts/render_glb_paths.test.d.ts +2 -0
- package/compiled/src/scripts/render_glb_paths.test.d.ts.map +1 -0
- package/compiled/src/scripts/render_glb_paths.test.js +115 -0
- package/compiled/src/step/indexing/step_type_indexer.d.ts +20 -0
- package/compiled/src/step/indexing/step_type_indexer.d.ts.map +1 -1
- package/compiled/src/step/indexing/step_type_indexer.js +67 -0
- package/compiled/src/step/parsing/byte_source.d.ts +153 -0
- package/compiled/src/step/parsing/byte_source.d.ts.map +1 -0
- package/compiled/src/step/parsing/byte_source.js +106 -0
- package/compiled/src/step/parsing/byte_source.test.d.ts +2 -0
- package/compiled/src/step/parsing/byte_source.test.d.ts.map +1 -0
- package/compiled/src/step/parsing/byte_source.test.js +47 -0
- package/compiled/src/step/parsing/byte_source_node.d.ts +41 -0
- package/compiled/src/step/parsing/byte_source_node.d.ts.map +1 -0
- package/compiled/src/step/parsing/byte_source_node.js +54 -0
- package/compiled/src/step/parsing/columnar_index.d.ts +103 -0
- package/compiled/src/step/parsing/columnar_index.d.ts.map +1 -0
- package/compiled/src/step/parsing/columnar_index.js +224 -0
- package/compiled/src/step/parsing/columnar_index.test.d.ts +2 -0
- package/compiled/src/step/parsing/columnar_index.test.d.ts.map +1 -0
- package/compiled/src/step/parsing/columnar_index.test.js +155 -0
- package/compiled/src/step/parsing/cross_reference_registry.d.ts +95 -0
- package/compiled/src/step/parsing/cross_reference_registry.d.ts.map +1 -0
- package/compiled/src/step/parsing/cross_reference_registry.js +91 -0
- package/compiled/src/step/parsing/cross_reference_registry.test.d.ts +2 -0
- package/compiled/src/step/parsing/cross_reference_registry.test.d.ts.map +1 -0
- package/compiled/src/step/parsing/cross_reference_registry.test.js +66 -0
- package/compiled/src/step/parsing/decode_utf8.d.ts +15 -0
- package/compiled/src/step/parsing/decode_utf8.d.ts.map +1 -1
- package/compiled/src/step/parsing/decode_utf8.js +28 -0
- package/compiled/src/step/parsing/express_ref_scan.d.ts +20 -0
- package/compiled/src/step/parsing/express_ref_scan.d.ts.map +1 -0
- package/compiled/src/step/parsing/express_ref_scan.js +91 -0
- package/compiled/src/step/parsing/express_ref_scan.test.d.ts +2 -0
- package/compiled/src/step/parsing/express_ref_scan.test.d.ts.map +1 -0
- package/compiled/src/step/parsing/express_ref_scan.test.js +28 -0
- package/compiled/src/step/parsing/index_sidecar.d.ts +81 -0
- package/compiled/src/step/parsing/index_sidecar.d.ts.map +1 -0
- package/compiled/src/step/parsing/index_sidecar.js +283 -0
- package/compiled/src/step/parsing/index_sidecar.test.d.ts +2 -0
- package/compiled/src/step/parsing/index_sidecar.test.d.ts.map +1 -0
- package/compiled/src/step/parsing/index_sidecar.test.js +122 -0
- package/compiled/src/step/parsing/inf_recovery_index.test.d.ts +2 -0
- package/compiled/src/step/parsing/inf_recovery_index.test.d.ts.map +1 -0
- package/compiled/src/step/parsing/inf_recovery_index.test.js +108 -0
- package/compiled/src/step/parsing/prefix_type_index.d.ts +124 -0
- package/compiled/src/step/parsing/prefix_type_index.d.ts.map +1 -0
- package/compiled/src/step/parsing/prefix_type_index.js +207 -0
- package/compiled/src/step/parsing/prefix_type_index.test.d.ts +2 -0
- package/compiled/src/step/parsing/prefix_type_index.test.d.ts.map +1 -0
- package/compiled/src/step/parsing/prefix_type_index.test.js +298 -0
- package/compiled/src/step/parsing/range_byte_source.d.ts +69 -0
- package/compiled/src/step/parsing/range_byte_source.d.ts.map +1 -0
- package/compiled/src/step/parsing/range_byte_source.js +78 -0
- package/compiled/src/step/parsing/range_byte_source.test.d.ts +2 -0
- package/compiled/src/step/parsing/range_byte_source.test.d.ts.map +1 -0
- package/compiled/src/step/parsing/range_byte_source.test.js +70 -0
- package/compiled/src/step/parsing/record_event.d.ts +23 -0
- package/compiled/src/step/parsing/record_event.d.ts.map +1 -0
- package/compiled/src/step/parsing/record_event.js +1 -0
- package/compiled/src/step/parsing/record_field_cursor.d.ts +94 -0
- package/compiled/src/step/parsing/record_field_cursor.d.ts.map +1 -0
- package/compiled/src/step/parsing/record_field_cursor.js +189 -0
- package/compiled/src/step/parsing/step_deserialization_functions.d.ts +29 -0
- package/compiled/src/step/parsing/step_deserialization_functions.d.ts.map +1 -1
- package/compiled/src/step/parsing/step_deserialization_functions.js +45 -0
- package/compiled/src/step/parsing/step_deserialization_functions.test.js +59 -1
- package/compiled/src/step/parsing/step_parser.d.ts +66 -1
- package/compiled/src/step/parsing/step_parser.d.ts.map +1 -1
- package/compiled/src/step/parsing/step_parser.js +164 -10
- package/compiled/src/step/parsing/step_string_parser.js +8 -8
- package/compiled/src/step/parsing/streaming_index_builder.d.ts +141 -0
- package/compiled/src/step/parsing/streaming_index_builder.d.ts.map +1 -0
- package/compiled/src/step/parsing/streaming_index_builder.js +280 -0
- package/compiled/src/step/parsing/streaming_index_builder.test.d.ts +2 -0
- package/compiled/src/step/parsing/streaming_index_builder.test.d.ts.map +1 -0
- package/compiled/src/step/parsing/streaming_index_builder.test.js +107 -0
- package/compiled/src/step/parsing/streaming_index_builder_async.test.d.ts +2 -0
- package/compiled/src/step/parsing/streaming_index_builder_async.test.d.ts.map +1 -0
- package/compiled/src/step/parsing/streaming_index_builder_async.test.js +109 -0
- package/compiled/src/step/parsing/streaming_record_dispatcher.d.ts +71 -0
- package/compiled/src/step/parsing/streaming_record_dispatcher.d.ts.map +1 -0
- package/compiled/src/step/parsing/streaming_record_dispatcher.js +88 -0
- package/compiled/src/step/parsing/streaming_record_dispatcher.test.d.ts +2 -0
- package/compiled/src/step/parsing/streaming_record_dispatcher.test.d.ts.map +1 -0
- package/compiled/src/step/parsing/streaming_record_dispatcher.test.js +66 -0
- package/compiled/src/step/parsing/uint32_sink.d.ts +72 -0
- package/compiled/src/step/parsing/uint32_sink.d.ts.map +1 -0
- package/compiled/src/step/parsing/uint32_sink.js +180 -0
- package/compiled/src/step/parsing/uint32_sink.test.d.ts +2 -0
- package/compiled/src/step/parsing/uint32_sink.test.d.ts.map +1 -0
- package/compiled/src/step/parsing/uint32_sink.test.js +199 -0
- package/compiled/src/step/step_buffer_provider.d.ts +48 -3
- package/compiled/src/step/step_buffer_provider.d.ts.map +1 -1
- package/compiled/src/step/step_buffer_provider.js +60 -11
- package/compiled/src/step/step_buffer_provider.test.js +14 -0
- package/compiled/src/step/step_entity_base.d.ts +65 -3
- package/compiled/src/step/step_entity_base.d.ts.map +1 -1
- package/compiled/src/step/step_entity_base.js +135 -3
- package/compiled/src/step/step_model_base.d.ts +221 -8
- package/compiled/src/step/step_model_base.d.ts.map +1 -1
- package/compiled/src/step/step_model_base.js +542 -7
- package/compiled/src/stream/index.d.ts +34 -0
- package/compiled/src/stream/index.d.ts.map +1 -0
- package/compiled/src/stream/index.js +32 -0
- package/compiled/src/version/version.js +1 -1
- package/compiled/tsconfig.tsbuildinfo +1 -1
- package/package.json +16 -1
|
@@ -0,0 +1,933 @@
|
|
|
1
|
+
import EntityTypesIfc from "../../ifc/ifc4_gen/entity_types_ifc.gen.js";
|
|
2
|
+
import { IfcBuilding, IfcBuildingStorey, IfcProject, IfcRelAggregates, IfcRelContainedInSpatialStructure, IfcSite, IfcSpace, } from "../../ifc/ifc4_gen/index.js";
|
|
3
|
+
import { deriveCoordinationF64, mat4MultiplyF64, NORMALIZE_MAT_F64, } from "./coordination_f64.js";
|
|
4
|
+
/* eslint-disable no-magic-numbers */
|
|
5
|
+
/** Black, almost transparent — Share honours `w` as opacity. */
|
|
6
|
+
export const SPATIAL_IMPOSTER_COLOR = { x: 0, y: 0, z: 0, w: 0.3 };
|
|
7
|
+
/** Sample this many contained-product placements per spatial node. */
|
|
8
|
+
const PRODUCT_SAMPLE = 32;
|
|
9
|
+
/** Collapse a parent whose box matches its only child this closely. */
|
|
10
|
+
const COLLAPSE_REL = 0.15;
|
|
11
|
+
/**
|
|
12
|
+
* Minimum box edge IN METRES so a point origin still draws. Every box in
|
|
13
|
+
* this module is in raw IFC source units, so callers convert this by the
|
|
14
|
+
* model's linear scaling factor before use ({@link minEdgeSourceUnits}) —
|
|
15
|
+
* a bare `1` is one metre on a metre model but one millimetre on a
|
|
16
|
+
* millimetre one, which made the padding invisible on mm files.
|
|
17
|
+
*/
|
|
18
|
+
const MIN_EDGE_M = 1;
|
|
19
|
+
/** Degenerate-scale floor for a box matrix (source units). */
|
|
20
|
+
const MIN_BOX_SCALE = 0.001;
|
|
21
|
+
/**
|
|
22
|
+
* MIN_EDGE_M expressed in the model's own source units.
|
|
23
|
+
*
|
|
24
|
+
* @param linearScalingFactor Source units -> metres.
|
|
25
|
+
* @return {number} The minimum edge in source units.
|
|
26
|
+
*/
|
|
27
|
+
function minEdgeSourceUnits(linearScalingFactor) {
|
|
28
|
+
return MIN_EDGE_M / sanitizeScale_(linearScalingFactor);
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* @param linearScalingFactor Source units -> metres, possibly garbage.
|
|
32
|
+
* @return {number} The factor, or 1 when it is not usable.
|
|
33
|
+
*/
|
|
34
|
+
function sanitizeScale_(linearScalingFactor) {
|
|
35
|
+
return Number.isFinite(linearScalingFactor) && linearScalingFactor > 0 ?
|
|
36
|
+
linearScalingFactor : 1;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Column-major 4x4 mapping a centred unit cube onto `aabb`, entirely in
|
|
40
|
+
* RAW IFC space: `translate(centre) * scale(size)`.
|
|
41
|
+
*
|
|
42
|
+
* Deliberately carries NO Z-up -> Y-up flip and NO unit scaling: both of
|
|
43
|
+
* those live in the coordination matrix this is composed under (see
|
|
44
|
+
* {@link emitSpatialStructureImposters}), exactly as they do for real
|
|
45
|
+
* meshes. Baking the flip here — which the parse-time point-list
|
|
46
|
+
* imposter this replaced used to do — put the plates in a frame the
|
|
47
|
+
* durable geometry never shares (conway#515).
|
|
48
|
+
*
|
|
49
|
+
* @param aabb The IFC-space bounds.
|
|
50
|
+
* @return {number[]} 16-element matrix.
|
|
51
|
+
*/
|
|
52
|
+
export function aabbBoxMatrix(aabb) {
|
|
53
|
+
const sx = Math.max(aabb.max[0] - aabb.min[0], MIN_BOX_SCALE);
|
|
54
|
+
const sy = Math.max(aabb.max[1] - aabb.min[1], MIN_BOX_SCALE);
|
|
55
|
+
const sz = Math.max(aabb.max[2] - aabb.min[2], MIN_BOX_SCALE);
|
|
56
|
+
const cx = (aabb.min[0] + aabb.max[0]) * 0.5;
|
|
57
|
+
const cy = (aabb.min[1] + aabb.max[1]) * 0.5;
|
|
58
|
+
const cz = (aabb.min[2] + aabb.max[2]) * 0.5;
|
|
59
|
+
return [
|
|
60
|
+
sx,
|
|
61
|
+
0,
|
|
62
|
+
0,
|
|
63
|
+
0,
|
|
64
|
+
0,
|
|
65
|
+
sy,
|
|
66
|
+
0,
|
|
67
|
+
0,
|
|
68
|
+
0,
|
|
69
|
+
0,
|
|
70
|
+
sz,
|
|
71
|
+
0,
|
|
72
|
+
cx,
|
|
73
|
+
cy,
|
|
74
|
+
cz,
|
|
75
|
+
1,
|
|
76
|
+
];
|
|
77
|
+
}
|
|
78
|
+
const REL_AGGREGATES_RELATING = [4, 4, 3];
|
|
79
|
+
const REL_AGGREGATES_RELATED = [5, 4, 3];
|
|
80
|
+
const REL_CONTAINED_RELATED = [4, 4, 3];
|
|
81
|
+
const REL_CONTAINED_RELATING = [5, 4, 3];
|
|
82
|
+
const PRODUCT_PLACEMENT = [5, 5, 3];
|
|
83
|
+
const LOCAL_PLACEMENT_REL_TO = [0, 0, 1];
|
|
84
|
+
const LOCAL_PLACEMENT_RELATIVE = [1, 0, 1];
|
|
85
|
+
const PLACEMENT_LOCATION = [0, 0, 2];
|
|
86
|
+
const PLACEMENT_AXIS = [1, 1, 3];
|
|
87
|
+
const PLACEMENT_REF_DIRECTION = [2, 1, 3];
|
|
88
|
+
const STOREY_ELEVATION = [9, 9, 6];
|
|
89
|
+
const IDENTITY_PLACEMENT = [
|
|
90
|
+
1,
|
|
91
|
+
0,
|
|
92
|
+
0,
|
|
93
|
+
0,
|
|
94
|
+
0,
|
|
95
|
+
1,
|
|
96
|
+
0,
|
|
97
|
+
0,
|
|
98
|
+
0,
|
|
99
|
+
0,
|
|
100
|
+
1,
|
|
101
|
+
0,
|
|
102
|
+
0,
|
|
103
|
+
0,
|
|
104
|
+
0,
|
|
105
|
+
1,
|
|
106
|
+
];
|
|
107
|
+
/** Column-major indices of a 4x4's translation component. */
|
|
108
|
+
const TRANSLATION = [12, 13, 14];
|
|
109
|
+
/** Column-major index of the local +Z axis' world Z component. */
|
|
110
|
+
const LOCAL_Z_WORLD_Z = 10;
|
|
111
|
+
/** Cross-product magnitude below which two unit axes are parallel. */
|
|
112
|
+
const MIN_AXIS_CROSS = 1e-9;
|
|
113
|
+
const SPACE_TYPES = new Set([
|
|
114
|
+
EntityTypesIfc.IFCSPACE,
|
|
115
|
+
EntityTypesIfc.IFCSPATIALZONE,
|
|
116
|
+
EntityTypesIfc.IFCEXTERNALSPATIALELEMENT,
|
|
117
|
+
]);
|
|
118
|
+
const STOREY_TYPES = new Set([
|
|
119
|
+
EntityTypesIfc.IFCBUILDINGSTOREY,
|
|
120
|
+
]);
|
|
121
|
+
/**
|
|
122
|
+
* Deepest spatial depth we still emit (never Spaces). Halfway down the
|
|
123
|
+
* tree, plus every BuildingStorey — floor plates are the useful cut.
|
|
124
|
+
*
|
|
125
|
+
* @param maxDepth Deepest spatial node (spaces included).
|
|
126
|
+
* @return {number} Inclusive depth cap for non-storey nodes.
|
|
127
|
+
*/
|
|
128
|
+
export function spatialImposterDepthCap(maxDepth) {
|
|
129
|
+
return Math.max(0, Math.ceil(maxDepth / 2));
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Whether this spatial node should become a box.
|
|
133
|
+
*
|
|
134
|
+
* @param depth Node depth from the project root.
|
|
135
|
+
* @param maxDepth Tree depth.
|
|
136
|
+
* @param typeID Schema type.
|
|
137
|
+
* @return {boolean} True to emit.
|
|
138
|
+
*/
|
|
139
|
+
export function shouldEmitSpatialNode(depth, maxDepth, typeID) {
|
|
140
|
+
if (SPACE_TYPES.has(typeID)) {
|
|
141
|
+
return false;
|
|
142
|
+
}
|
|
143
|
+
if (STOREY_TYPES.has(typeID)) {
|
|
144
|
+
return true;
|
|
145
|
+
}
|
|
146
|
+
return depth <= spatialImposterDepthCap(maxDepth);
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* True when two AABBs are within `rel` of each other on every axis
|
|
150
|
+
* (used to drop Project/Site wrappers that match the Building).
|
|
151
|
+
*
|
|
152
|
+
* @param a First box.
|
|
153
|
+
* @param b Second box.
|
|
154
|
+
* @param rel Relative slack.
|
|
155
|
+
* @param minEdge Span floor, in the same source units as `a` and `b`.
|
|
156
|
+
* The walk always passes {@link minEdgeSourceUnits}' converted value;
|
|
157
|
+
* the default is the unconverted MIN_EDGE_M, which is only correct on a
|
|
158
|
+
* metre model — a caller that omits it on a millimetre one gets a
|
|
159
|
+
* one-millimetre floor, the very bug MIN_EDGE_M removed.
|
|
160
|
+
* @return {boolean} True if they match.
|
|
161
|
+
*/
|
|
162
|
+
export function aabbMostlyEqual(a, b, rel = COLLAPSE_REL, minEdge = MIN_EDGE_M) {
|
|
163
|
+
for (let axis = 0; axis < 3; ++axis) {
|
|
164
|
+
const span = Math.max(a.max[axis] - a.min[axis], b.max[axis] - b.min[axis], minEdge);
|
|
165
|
+
const slack = span * rel;
|
|
166
|
+
if (Math.abs(a.min[axis] - b.min[axis]) > slack ||
|
|
167
|
+
Math.abs(a.max[axis] - b.max[axis]) > slack) {
|
|
168
|
+
return false;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
return true;
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* Union of boxes; ignores undefined.
|
|
175
|
+
*
|
|
176
|
+
* @param boxes Boxes to join.
|
|
177
|
+
* @return {Aabb3 | undefined} The union.
|
|
178
|
+
*/
|
|
179
|
+
export function unionAabb(...boxes) {
|
|
180
|
+
let min;
|
|
181
|
+
let max;
|
|
182
|
+
for (const box of boxes) {
|
|
183
|
+
if (box === void 0) {
|
|
184
|
+
continue;
|
|
185
|
+
}
|
|
186
|
+
if (min === void 0 || max === void 0) {
|
|
187
|
+
min = [box.min[0], box.min[1], box.min[2]];
|
|
188
|
+
max = [box.max[0], box.max[1], box.max[2]];
|
|
189
|
+
continue;
|
|
190
|
+
}
|
|
191
|
+
for (let axis = 0; axis < 3; ++axis) {
|
|
192
|
+
if (box.min[axis] < min[axis]) {
|
|
193
|
+
min[axis] = box.min[axis];
|
|
194
|
+
}
|
|
195
|
+
if (box.max[axis] > max[axis]) {
|
|
196
|
+
max[axis] = box.max[axis];
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
return min === void 0 || max === void 0 ? void 0 : { min, max };
|
|
201
|
+
}
|
|
202
|
+
function padAabb_(box, minEdge) {
|
|
203
|
+
const min = [box.min[0], box.min[1], box.min[2]];
|
|
204
|
+
const max = [box.max[0], box.max[1], box.max[2]];
|
|
205
|
+
for (let axis = 0; axis < 3; ++axis) {
|
|
206
|
+
if (max[axis] - min[axis] < minEdge) {
|
|
207
|
+
const mid = (min[axis] + max[axis]) * 0.5;
|
|
208
|
+
min[axis] = mid - minEdge * 0.5;
|
|
209
|
+
max[axis] = mid + minEdge * 0.5;
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
return { min, max };
|
|
213
|
+
}
|
|
214
|
+
function pointAabb_(x, y, z) {
|
|
215
|
+
return { min: [x, y, z], max: [x, y, z] };
|
|
216
|
+
}
|
|
217
|
+
async function ensure_(model, localID) {
|
|
218
|
+
await model.ensureResidentByLocalID(localID);
|
|
219
|
+
}
|
|
220
|
+
/**
|
|
221
|
+
* @param v A vector.
|
|
222
|
+
* @return {[number, number, number] | undefined} `v` scaled to unit
|
|
223
|
+
* length, or undefined when it has none (zero / non-finite input).
|
|
224
|
+
*/
|
|
225
|
+
function normalize3_(v) {
|
|
226
|
+
const length = Math.hypot(v[0], v[1], v[2]);
|
|
227
|
+
return Number.isFinite(length) && length > 0 ?
|
|
228
|
+
[v[0] / length, v[1] / length, v[2] / length] : void 0;
|
|
229
|
+
}
|
|
230
|
+
/**
|
|
231
|
+
* @param a Left vector.
|
|
232
|
+
* @param b Right vector.
|
|
233
|
+
* @return {[number, number, number]} `a` x `b`.
|
|
234
|
+
*/
|
|
235
|
+
function cross3_(a, b) {
|
|
236
|
+
return [
|
|
237
|
+
a[1] * b[2] - a[2] * b[1],
|
|
238
|
+
a[2] * b[0] - a[0] * b[2],
|
|
239
|
+
a[0] * b[1] - a[1] * b[0],
|
|
240
|
+
];
|
|
241
|
+
}
|
|
242
|
+
/**
|
|
243
|
+
* The `DirectionRatios` of an IfcDirection referenced from `field` of
|
|
244
|
+
* `entity`, or undefined when the field is absent.
|
|
245
|
+
*
|
|
246
|
+
* @param model The model.
|
|
247
|
+
* @param entity The referring entity.
|
|
248
|
+
* @param field The (index, min, max) field triple.
|
|
249
|
+
* @return {Promise<[number, number, number] | undefined>} The ratios.
|
|
250
|
+
*/
|
|
251
|
+
async function directionRatios_(model, entity, field) {
|
|
252
|
+
const directionID = entity.extractReferenceLocalID(field[0], field[1], field[2], true);
|
|
253
|
+
if (directionID === null) {
|
|
254
|
+
return;
|
|
255
|
+
}
|
|
256
|
+
await ensure_(model, directionID);
|
|
257
|
+
const direction = model.getElementByLocalID(directionID);
|
|
258
|
+
const ratios = direction?.DirectionRatios;
|
|
259
|
+
if (ratios === void 0 || ratios.length < 2) {
|
|
260
|
+
return;
|
|
261
|
+
}
|
|
262
|
+
return [ratios[0], ratios[1], ratios[2] ?? 0];
|
|
263
|
+
}
|
|
264
|
+
/**
|
|
265
|
+
* The local +X reference to use when a placement states an `Axis` but no
|
|
266
|
+
* `RefDirection`: world +X, unless that is (nearly) parallel to the
|
|
267
|
+
* stated axis, in which case world +Y.
|
|
268
|
+
*
|
|
269
|
+
* IFC's own `IfcFirstProjAxis` makes exactly this substitution, and
|
|
270
|
+
* without it a lie-down placement — `Axis = (1,0,0)`, RefDirection
|
|
271
|
+
* omitted, which is how a wall-mounted or rotated-into-plan element is
|
|
272
|
+
* commonly written — has its Axis cross the defaulted (1,0,0) to zero
|
|
273
|
+
* and falls all the way back to the world frame, discarding a perfectly
|
|
274
|
+
* well-formed rotation. conway-geom divides by that zero cross product
|
|
275
|
+
* and returns NaN, so matching the C++ settles nothing here; keeping the
|
|
276
|
+
* stated Axis is strictly better than dropping it.
|
|
277
|
+
*
|
|
278
|
+
* @param zAxis The normalized local +Z.
|
|
279
|
+
* @return {[number, number, number]} A reference not parallel to it.
|
|
280
|
+
*/
|
|
281
|
+
function defaultRefDirection_(zAxis) {
|
|
282
|
+
// |cross(zAxis, worldX)| — world +X stays the default (which is what
|
|
283
|
+
// the IFC default says, and what the overwhelmingly common
|
|
284
|
+
// zAxis = (0,0,1) needs) until it degenerates.
|
|
285
|
+
return Math.hypot(zAxis[1], zAxis[2]) > MIN_AXIS_CROSS ?
|
|
286
|
+
[1, 0, 0] : [0, 1, 0];
|
|
287
|
+
}
|
|
288
|
+
/**
|
|
289
|
+
* The 4x4 an IfcAxis2Placement denotes: Location as the translation,
|
|
290
|
+
* and — on the 3D form only — Axis as local +Z and RefDirection as local
|
|
291
|
+
* +X, both defaulting to the world axes when absent per the IFC
|
|
292
|
+
* defaults.
|
|
293
|
+
*
|
|
294
|
+
* The 2D form has to be handled, not assumed away.
|
|
295
|
+
* `IfcLocalPlacement.RelativePlacement` is
|
|
296
|
+
* `IfcAxis2Placement2D | IfcAxis2Placement3D`, and the two disagree on
|
|
297
|
+
* every field past Location: offset 1 is `Axis` on the 3D entity but
|
|
298
|
+
* `RefDirection` on the 2D one, and offset 2 does not exist there at
|
|
299
|
+
* all, so reading it throws "too few fields in record". That throw would
|
|
300
|
+
* escape to {@link placementTransform_}'s catch, which memoizes
|
|
301
|
+
* `undefined` for the placement — and a memoized undefined is not merely
|
|
302
|
+
* a lost sample: every descendant placement then takes the
|
|
303
|
+
* no-parent branch and is composed in LOCAL coordinates, silently
|
|
304
|
+
* reparenting a whole subtree to the origin. So the direction fields are
|
|
305
|
+
* read only once the type is confirmed 3D, which also restores the
|
|
306
|
+
* pre-#517 behaviour for 2D links (translation only).
|
|
307
|
+
*
|
|
308
|
+
* Deliberately the same construction as conway-geom's
|
|
309
|
+
* `GetAxis2Placement3D` (ConwayGeometryProcessor.cpp) — normalize the
|
|
310
|
+
* two references, `y = normalize(z x x)`, then re-derive
|
|
311
|
+
* `x = normalize(y x z)` so a non-perpendicular RefDirection is
|
|
312
|
+
* projected rather than skewing the frame. It has to match: the plates
|
|
313
|
+
* are previewing meshes the durable pipeline places with that function,
|
|
314
|
+
* and a second convention here (Gram-Schmidt on x, say) would rotate
|
|
315
|
+
* them apart on any file whose RefDirection is off-perpendicular.
|
|
316
|
+
*
|
|
317
|
+
* One deviation, on degenerate input: where the C++ divides by a zero
|
|
318
|
+
* cross product and yields NaN, this falls back to the identity axes. A
|
|
319
|
+
* NaN transform reaching Share is an invisible or scene-destroying box,
|
|
320
|
+
* and the imposter path's standing rule is that a preview must never
|
|
321
|
+
* break open.
|
|
322
|
+
*
|
|
323
|
+
* @param model The model.
|
|
324
|
+
* @param axisLocalID The IfcAxis2Placement3D's local ID.
|
|
325
|
+
* @return {Promise<Mat4>} The placement, identity if unreadable.
|
|
326
|
+
*/
|
|
327
|
+
async function axisPlacementMatrix_(model, axisLocalID) {
|
|
328
|
+
await ensure_(model, axisLocalID);
|
|
329
|
+
const placement = model.getElementByLocalID(axisLocalID);
|
|
330
|
+
if (placement === void 0) {
|
|
331
|
+
return IDENTITY_PLACEMENT.slice();
|
|
332
|
+
}
|
|
333
|
+
let translation = [0, 0, 0];
|
|
334
|
+
const locationID = placement.extractReferenceLocalID(PLACEMENT_LOCATION[0], PLACEMENT_LOCATION[1], PLACEMENT_LOCATION[2], false);
|
|
335
|
+
if (locationID !== null) {
|
|
336
|
+
await ensure_(model, locationID);
|
|
337
|
+
const point = model.getElementByLocalID(locationID);
|
|
338
|
+
const coords = point?.Coordinates;
|
|
339
|
+
if (coords !== void 0 && coords.length >= 2) {
|
|
340
|
+
translation = [coords[0], coords[1], coords[2] ?? 0];
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
const is3D = model.typeIDOf(axisLocalID) === EntityTypesIfc.IFCAXIS2PLACEMENT3D;
|
|
344
|
+
const axisRatios = is3D ?
|
|
345
|
+
await directionRatios_(model, placement, PLACEMENT_AXIS) : void 0;
|
|
346
|
+
const refRatios = is3D ?
|
|
347
|
+
await directionRatios_(model, placement, PLACEMENT_REF_DIRECTION) : void 0;
|
|
348
|
+
let zAxis = (axisRatios !== void 0 ? normalize3_(axisRatios) : void 0) ?? [0, 0, 1];
|
|
349
|
+
let refAxis = (refRatios !== void 0 ? normalize3_(refRatios) : void 0) ??
|
|
350
|
+
defaultRefDirection_(zAxis);
|
|
351
|
+
let yAxis = normalize3_(cross3_(zAxis, refAxis));
|
|
352
|
+
if (yAxis === void 0) {
|
|
353
|
+
// Axis and RefDirection are parallel (or garbage): nothing here
|
|
354
|
+
// determines a frame, so keep the translation and drop back to world
|
|
355
|
+
// axes. Only reachable with an explicit RefDirection now — an Axis
|
|
356
|
+
// on its own gets a perpendicular default instead of being thrown
|
|
357
|
+
// away with it (see defaultRefDirection_).
|
|
358
|
+
zAxis = [0, 0, 1];
|
|
359
|
+
refAxis = [1, 0, 0];
|
|
360
|
+
yAxis = [0, 1, 0];
|
|
361
|
+
}
|
|
362
|
+
const xAxis = normalize3_(cross3_(yAxis, zAxis)) ?? refAxis;
|
|
363
|
+
return [
|
|
364
|
+
xAxis[0],
|
|
365
|
+
xAxis[1],
|
|
366
|
+
xAxis[2],
|
|
367
|
+
0,
|
|
368
|
+
yAxis[0],
|
|
369
|
+
yAxis[1],
|
|
370
|
+
yAxis[2],
|
|
371
|
+
0,
|
|
372
|
+
zAxis[0],
|
|
373
|
+
zAxis[1],
|
|
374
|
+
zAxis[2],
|
|
375
|
+
0,
|
|
376
|
+
translation[0],
|
|
377
|
+
translation[1],
|
|
378
|
+
translation[2],
|
|
379
|
+
1,
|
|
380
|
+
];
|
|
381
|
+
}
|
|
382
|
+
/**
|
|
383
|
+
* The composed world transform of an IfcLocalPlacement chain: every
|
|
384
|
+
* link's IfcAxis2Placement3D built out in full and multiplied
|
|
385
|
+
* `parent * local`, which is exactly conway-geom's `GetLocalPlacement`.
|
|
386
|
+
*
|
|
387
|
+
* Rotation used to be dropped here — the chain summed Location
|
|
388
|
+
* translations and nothing else (conway#514's shortcut). That is correct
|
|
389
|
+
* only while every ancestor placement is axis-aligned, and Revit
|
|
390
|
+
* routinely rotates the site or building placement to true north, so on
|
|
391
|
+
* a real export every sampled origin landed unrotated in raw model space
|
|
392
|
+
* while the durable meshes beside it did not: the plate cloud read as a
|
|
393
|
+
* rotated ghost of the building (conway#517).
|
|
394
|
+
*
|
|
395
|
+
* @param model The model.
|
|
396
|
+
* @param placementLocalID IfcObjectPlacement local ID.
|
|
397
|
+
* @param cache Memo of composed transforms, keyed by placement local ID.
|
|
398
|
+
* A placement re-entered while it is being composed (a cyclic RelativeTo)
|
|
399
|
+
* reads back undefined and stops the recursion.
|
|
400
|
+
* @return {Promise<Mat4 | undefined>} The world transform.
|
|
401
|
+
*/
|
|
402
|
+
async function placementTransform_(model, placementLocalID, cache) {
|
|
403
|
+
if (cache.has(placementLocalID)) {
|
|
404
|
+
return cache.get(placementLocalID);
|
|
405
|
+
}
|
|
406
|
+
cache.set(placementLocalID, void 0);
|
|
407
|
+
try {
|
|
408
|
+
await ensure_(model, placementLocalID);
|
|
409
|
+
const typeID = model.typeIDOf(placementLocalID);
|
|
410
|
+
if (typeID !== EntityTypesIfc.IFCLOCALPLACEMENT) {
|
|
411
|
+
return;
|
|
412
|
+
}
|
|
413
|
+
const entity = model.getElementByLocalID(placementLocalID);
|
|
414
|
+
if (entity === void 0) {
|
|
415
|
+
return;
|
|
416
|
+
}
|
|
417
|
+
const relativeID = entity.extractReferenceLocalID(LOCAL_PLACEMENT_RELATIVE[0], LOCAL_PLACEMENT_RELATIVE[1], LOCAL_PLACEMENT_RELATIVE[2], false);
|
|
418
|
+
const local = relativeID !== null ?
|
|
419
|
+
await axisPlacementMatrix_(model, relativeID) :
|
|
420
|
+
IDENTITY_PLACEMENT.slice();
|
|
421
|
+
const parentID = entity.extractReferenceLocalID(LOCAL_PLACEMENT_REL_TO[0], LOCAL_PLACEMENT_REL_TO[1], LOCAL_PLACEMENT_REL_TO[2], true);
|
|
422
|
+
if (parentID === null) {
|
|
423
|
+
cache.set(placementLocalID, local);
|
|
424
|
+
return local;
|
|
425
|
+
}
|
|
426
|
+
const parent = await placementTransform_(model, parentID, cache);
|
|
427
|
+
const world = parent === void 0 ? local : mat4MultiplyF64(parent, local);
|
|
428
|
+
cache.set(placementLocalID, world);
|
|
429
|
+
return world;
|
|
430
|
+
}
|
|
431
|
+
catch {
|
|
432
|
+
return;
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
/**
|
|
436
|
+
* @param transform A composed world transform.
|
|
437
|
+
* @return {[number, number, number]} Its translation column, i.e. where
|
|
438
|
+
* the placement's own origin lands in world space.
|
|
439
|
+
*/
|
|
440
|
+
function originOf_(transform) {
|
|
441
|
+
return [
|
|
442
|
+
transform[TRANSLATION[0]],
|
|
443
|
+
transform[TRANSLATION[1]],
|
|
444
|
+
transform[TRANSLATION[2]],
|
|
445
|
+
];
|
|
446
|
+
}
|
|
447
|
+
async function productTransform_(model, localID, cache) {
|
|
448
|
+
await ensure_(model, localID);
|
|
449
|
+
const entity = model.getElementByLocalID(localID);
|
|
450
|
+
if (entity === void 0) {
|
|
451
|
+
return;
|
|
452
|
+
}
|
|
453
|
+
const placementID = entity.extractReferenceLocalID(PRODUCT_PLACEMENT[0], PRODUCT_PLACEMENT[1], PRODUCT_PLACEMENT[2], true);
|
|
454
|
+
if (placementID === null) {
|
|
455
|
+
return;
|
|
456
|
+
}
|
|
457
|
+
return placementTransform_(model, placementID, cache);
|
|
458
|
+
}
|
|
459
|
+
/**
|
|
460
|
+
* Walk the IFC spatial tree and emit AABB imposters for Share.
|
|
461
|
+
*
|
|
462
|
+
* Project → Site → Building → Storey → Space. Spaces are never
|
|
463
|
+
* drawn (too dense). Everything else is drawn down to half the tree
|
|
464
|
+
* depth, and storeys are always drawn when present. Nested wrappers
|
|
465
|
+
* whose box matches their only child are collapsed.
|
|
466
|
+
*
|
|
467
|
+
* **Frame.** Every box is measured in raw IFC source units and Z-up,
|
|
468
|
+
* because that is what the placement chains this walk reads carry. The
|
|
469
|
+
* emitted `flatTransformation` is `C * M_box`, where `M_box` is that raw
|
|
470
|
+
* box ({@link aabbBoxMatrix}) and `C` is the durable coordination frame —
|
|
471
|
+
* metres, Y-up, recentred per the quantized model-zero policy. So the
|
|
472
|
+
* plates land exactly where the real meshes do, which they did not
|
|
473
|
+
* before (raw units, a locally baked axis flip, no coordination: on a
|
|
474
|
+
* millimetre model the plates came out 1000x too big, and a
|
|
475
|
+
* georeferenced one put them a site-offset away — conway#515).
|
|
476
|
+
* `payload.aabb` stays in raw IFC space as the consumer's reference.
|
|
477
|
+
*
|
|
478
|
+
* **Call it after `prepareDemandExtraction()`, never before.** The frame
|
|
479
|
+
* needs `getLinearScalingFactor()`, which reads 1 until the extraction
|
|
480
|
+
* maps — and with them the unit assignment — are prepared, and
|
|
481
|
+
* `extractLinearScalingFactor()` is `*=`-accumulating, so it cannot be
|
|
482
|
+
* pulled forward on its own without squaring the unit prefix. The cost
|
|
483
|
+
* is latency on the model's first visible feedback: on the resident path
|
|
484
|
+
* the plates now follow the prep instead of preceding it, and on the
|
|
485
|
+
* store-backed path they also follow an awaited
|
|
486
|
+
* `ensureResidentForDemandPrep()`, so on a large model they land
|
|
487
|
+
* measurably later than they used to. Accepted deliberately — a plate at
|
|
488
|
+
* 1000x the model's scale is worse than a plate slightly late.
|
|
489
|
+
*
|
|
490
|
+
* **The latched frame is adopted, not guaranteed.** The deferred durable
|
|
491
|
+
* pump re-derives its own when the composed placement overruns
|
|
492
|
+
* LARGE_COORDINATE_BUDGET_M (`validatePreviewFrame`, Share#1634). Plates
|
|
493
|
+
* emitted here are not re-emitted, so on that path they keep the
|
|
494
|
+
* rejected frame and sit a site-offset from the durable meshes — the
|
|
495
|
+
* conway#515 symptom again, now confined to a case the preview meshes
|
|
496
|
+
* beside them share, and to scenery Share tears down at load end.
|
|
497
|
+
* Re-emitting on rejection is the fix if it ever shows up live.
|
|
498
|
+
*
|
|
499
|
+
* @param model Parsed IFC model (windowed or resident).
|
|
500
|
+
* @param onMesh Preview consumer.
|
|
501
|
+
* @param coordinationMatrix The frame already latched by the preview
|
|
502
|
+
* channel (the one the durable pump adopts). When it is `undefined` — no
|
|
503
|
+
* preview instance was ever captured — the walk derives the same frame
|
|
504
|
+
* from an identity placement anchored on the root spatial box's centre.
|
|
505
|
+
* That is best-effort by construction: below LARGE_COORDINATE_BUDGET_M
|
|
506
|
+
* the policy recentres nothing, so it agrees with the durable derivation
|
|
507
|
+
* exactly; above it, both snap to COORDINATION_SNAP_M and agree as long
|
|
508
|
+
* as the spatial root and the first geometry share a grid cell.
|
|
509
|
+
* @param linearScalingFactor Source units -> metres, from
|
|
510
|
+
* `IfcGeometryExtraction.getLinearScalingFactor()`. Only consulted for
|
|
511
|
+
* the fallback derivation and the minimum-edge padding; when
|
|
512
|
+
* `coordinationMatrix` is supplied its own scaling is already baked in.
|
|
513
|
+
* @return {Promise<number>} Boxes emitted.
|
|
514
|
+
*/
|
|
515
|
+
export async function emitSpatialStructureImposters(model, onMesh, coordinationMatrix, linearScalingFactor = 1) {
|
|
516
|
+
const minEdge = minEdgeSourceUnits(linearScalingFactor);
|
|
517
|
+
const nodes = new Map();
|
|
518
|
+
const childrenOf = new Map();
|
|
519
|
+
const parentOf = new Map();
|
|
520
|
+
const addNode = (localID, expressID, typeID) => {
|
|
521
|
+
if (!nodes.has(localID)) {
|
|
522
|
+
nodes.set(localID, {
|
|
523
|
+
localID,
|
|
524
|
+
expressID,
|
|
525
|
+
typeID,
|
|
526
|
+
depth: 0,
|
|
527
|
+
children: [],
|
|
528
|
+
});
|
|
529
|
+
}
|
|
530
|
+
};
|
|
531
|
+
const spatialTypes = [
|
|
532
|
+
IfcProject,
|
|
533
|
+
IfcSite,
|
|
534
|
+
IfcBuilding,
|
|
535
|
+
IfcBuildingStorey,
|
|
536
|
+
IfcSpace,
|
|
537
|
+
];
|
|
538
|
+
for (const type of spatialTypes) {
|
|
539
|
+
for (const expressID of model.expressIDsOfTypes(type)) {
|
|
540
|
+
const localID = model.resolveExpressID(expressID);
|
|
541
|
+
if (localID === void 0) {
|
|
542
|
+
continue;
|
|
543
|
+
}
|
|
544
|
+
addNode(localID, expressID, model.typeIDOf(localID) ?? -1);
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
if (nodes.size === 0) {
|
|
548
|
+
return 0;
|
|
549
|
+
}
|
|
550
|
+
for (const expressID of model.expressIDsOfTypes(IfcRelAggregates)) {
|
|
551
|
+
const relLocalID = model.resolveExpressID(expressID);
|
|
552
|
+
if (relLocalID === void 0) {
|
|
553
|
+
continue;
|
|
554
|
+
}
|
|
555
|
+
try {
|
|
556
|
+
await ensure_(model, relLocalID);
|
|
557
|
+
const rel = model.getElementByLocalID(relLocalID);
|
|
558
|
+
if (rel === void 0) {
|
|
559
|
+
continue;
|
|
560
|
+
}
|
|
561
|
+
const relatingID = rel.extractReferenceLocalID(REL_AGGREGATES_RELATING[0], REL_AGGREGATES_RELATING[1], REL_AGGREGATES_RELATING[2], false);
|
|
562
|
+
if (relatingID === null || !nodes.has(relatingID)) {
|
|
563
|
+
continue;
|
|
564
|
+
}
|
|
565
|
+
rel.forEachReferenceInField(REL_AGGREGATES_RELATED[0], REL_AGGREGATES_RELATED[1], REL_AGGREGATES_RELATED[2], (relatedExpressID) => {
|
|
566
|
+
if (relatedExpressID === void 0) {
|
|
567
|
+
return true;
|
|
568
|
+
}
|
|
569
|
+
const relatedID = model.resolveExpressID(relatedExpressID);
|
|
570
|
+
if (relatedID === void 0 || !nodes.has(relatedID)) {
|
|
571
|
+
return true;
|
|
572
|
+
}
|
|
573
|
+
const list = childrenOf.get(relatingID) ?? [];
|
|
574
|
+
list.push(relatedID);
|
|
575
|
+
childrenOf.set(relatingID, list);
|
|
576
|
+
parentOf.set(relatedID, relatingID);
|
|
577
|
+
return true;
|
|
578
|
+
});
|
|
579
|
+
}
|
|
580
|
+
catch {
|
|
581
|
+
// One bad relationship must not kill the preview.
|
|
582
|
+
}
|
|
583
|
+
}
|
|
584
|
+
const contained = new Map();
|
|
585
|
+
for (const expressID of model.expressIDsOfTypes(IfcRelContainedInSpatialStructure)) {
|
|
586
|
+
const relLocalID = model.resolveExpressID(expressID);
|
|
587
|
+
if (relLocalID === void 0) {
|
|
588
|
+
continue;
|
|
589
|
+
}
|
|
590
|
+
try {
|
|
591
|
+
await ensure_(model, relLocalID);
|
|
592
|
+
const rel = model.getElementByLocalID(relLocalID);
|
|
593
|
+
if (rel === void 0) {
|
|
594
|
+
continue;
|
|
595
|
+
}
|
|
596
|
+
const structureID = rel.extractReferenceLocalID(REL_CONTAINED_RELATING[0], REL_CONTAINED_RELATING[1], REL_CONTAINED_RELATING[2], false);
|
|
597
|
+
if (structureID === null || !nodes.has(structureID)) {
|
|
598
|
+
continue;
|
|
599
|
+
}
|
|
600
|
+
const products = [];
|
|
601
|
+
rel.forEachReferenceInField(REL_CONTAINED_RELATED[0], REL_CONTAINED_RELATED[1], REL_CONTAINED_RELATED[2], (productExpressID) => {
|
|
602
|
+
if (productExpressID === void 0) {
|
|
603
|
+
return true;
|
|
604
|
+
}
|
|
605
|
+
const productID = model.resolveExpressID(productExpressID);
|
|
606
|
+
if (productID !== void 0) {
|
|
607
|
+
products.push(productID);
|
|
608
|
+
}
|
|
609
|
+
return true;
|
|
610
|
+
});
|
|
611
|
+
if (products.length > 0) {
|
|
612
|
+
const existing = contained.get(structureID) ?? [];
|
|
613
|
+
existing.push(...products);
|
|
614
|
+
contained.set(structureID, existing);
|
|
615
|
+
}
|
|
616
|
+
}
|
|
617
|
+
catch {
|
|
618
|
+
// Preview must never break open.
|
|
619
|
+
}
|
|
620
|
+
}
|
|
621
|
+
for (const [parent, kids] of childrenOf) {
|
|
622
|
+
const node = nodes.get(parent);
|
|
623
|
+
if (node !== void 0) {
|
|
624
|
+
node.children = kids;
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
const roots = [];
|
|
628
|
+
for (const localID of nodes.keys()) {
|
|
629
|
+
if (!parentOf.has(localID)) {
|
|
630
|
+
roots.push(localID);
|
|
631
|
+
}
|
|
632
|
+
}
|
|
633
|
+
if (roots.length === 0) {
|
|
634
|
+
roots.push(...nodes.keys());
|
|
635
|
+
}
|
|
636
|
+
const queue = roots.slice();
|
|
637
|
+
const queued = new Set(roots);
|
|
638
|
+
let maxDepth = 0;
|
|
639
|
+
while (queue.length > 0) {
|
|
640
|
+
const id = queue.shift();
|
|
641
|
+
const node = nodes.get(id);
|
|
642
|
+
if (node === void 0) {
|
|
643
|
+
continue;
|
|
644
|
+
}
|
|
645
|
+
const parentID = parentOf.get(id);
|
|
646
|
+
node.depth = parentID === void 0 ? 0 : (nodes.get(parentID)?.depth ?? 0) + 1;
|
|
647
|
+
maxDepth = Math.max(maxDepth, node.depth);
|
|
648
|
+
for (const childID of node.children) {
|
|
649
|
+
if (queued.has(childID)) {
|
|
650
|
+
continue;
|
|
651
|
+
}
|
|
652
|
+
queued.add(childID);
|
|
653
|
+
queue.push(childID);
|
|
654
|
+
}
|
|
655
|
+
}
|
|
656
|
+
const placementCache = new Map();
|
|
657
|
+
for (const node of nodes.values()) {
|
|
658
|
+
try {
|
|
659
|
+
// IfcProject is an IfcContext, not an IfcProduct — field 5 is
|
|
660
|
+
// not ObjectPlacement.
|
|
661
|
+
if (node.typeID !== EntityTypesIfc.IFCPROJECT) {
|
|
662
|
+
node.placement =
|
|
663
|
+
await productTransform_(model, node.localID, placementCache);
|
|
664
|
+
node.origin = node.placement !== void 0 ?
|
|
665
|
+
originOf_(node.placement) : void 0;
|
|
666
|
+
}
|
|
667
|
+
if (STOREY_TYPES.has(node.typeID)) {
|
|
668
|
+
await ensure_(model, node.localID);
|
|
669
|
+
const entity = model.getElementByLocalID(node.localID);
|
|
670
|
+
if (entity !== void 0) {
|
|
671
|
+
const elevation = entity.extractNumber(STOREY_ELEVATION[0], STOREY_ELEVATION[1], STOREY_ELEVATION[2], true);
|
|
672
|
+
if (elevation !== null) {
|
|
673
|
+
node.elevation = elevation;
|
|
674
|
+
}
|
|
675
|
+
}
|
|
676
|
+
}
|
|
677
|
+
}
|
|
678
|
+
catch {
|
|
679
|
+
// Keep walking.
|
|
680
|
+
}
|
|
681
|
+
}
|
|
682
|
+
const productOrigins = new Map();
|
|
683
|
+
for (const [structureID, products] of contained) {
|
|
684
|
+
const stride = Math.max(1, Math.floor(products.length / PRODUCT_SAMPLE));
|
|
685
|
+
const origins = [];
|
|
686
|
+
for (let i = 0; i < products.length && origins.length < PRODUCT_SAMPLE; i += stride) {
|
|
687
|
+
try {
|
|
688
|
+
const transform = await productTransform_(model, products[i], placementCache);
|
|
689
|
+
if (transform !== void 0) {
|
|
690
|
+
origins.push(originOf_(transform));
|
|
691
|
+
}
|
|
692
|
+
}
|
|
693
|
+
catch {
|
|
694
|
+
// Skip one product.
|
|
695
|
+
}
|
|
696
|
+
}
|
|
697
|
+
if (origins.length > 0) {
|
|
698
|
+
productOrigins.set(structureID, origins);
|
|
699
|
+
}
|
|
700
|
+
}
|
|
701
|
+
const storeysByParent = new Map();
|
|
702
|
+
for (const node of nodes.values()) {
|
|
703
|
+
if (!STOREY_TYPES.has(node.typeID) || node.elevation === void 0) {
|
|
704
|
+
continue;
|
|
705
|
+
}
|
|
706
|
+
const parentKey = parentOf.get(node.localID) ?? "root";
|
|
707
|
+
const group = storeysByParent.get(parentKey) ?? [];
|
|
708
|
+
group.push(node);
|
|
709
|
+
storeysByParent.set(parentKey, group);
|
|
710
|
+
}
|
|
711
|
+
const storeyHeight = new Map();
|
|
712
|
+
for (const group of storeysByParent.values()) {
|
|
713
|
+
group.sort((a, b) => (a.elevation ?? 0) - (b.elevation ?? 0));
|
|
714
|
+
for (let i = 0; i < group.length; ++i) {
|
|
715
|
+
const here = group[i].elevation ?? 0;
|
|
716
|
+
const next = group[i + 1]?.elevation;
|
|
717
|
+
let height = next !== void 0 && next > here ? next - here : void 0;
|
|
718
|
+
if (height === void 0) {
|
|
719
|
+
const samples = productOrigins.get(group[i].localID);
|
|
720
|
+
if (samples !== void 0 && samples.length > 0) {
|
|
721
|
+
let minZ = samples[0][2];
|
|
722
|
+
let maxZ = samples[0][2];
|
|
723
|
+
for (const origin of samples) {
|
|
724
|
+
if (origin[2] < minZ) {
|
|
725
|
+
minZ = origin[2];
|
|
726
|
+
}
|
|
727
|
+
if (origin[2] > maxZ) {
|
|
728
|
+
maxZ = origin[2];
|
|
729
|
+
}
|
|
730
|
+
}
|
|
731
|
+
height = Math.max(maxZ - minZ, minEdge);
|
|
732
|
+
}
|
|
733
|
+
else {
|
|
734
|
+
height = minEdge;
|
|
735
|
+
}
|
|
736
|
+
}
|
|
737
|
+
storeyHeight.set(group[i].localID, height);
|
|
738
|
+
}
|
|
739
|
+
}
|
|
740
|
+
const aabbOf = (localID) => {
|
|
741
|
+
const node = nodes.get(localID);
|
|
742
|
+
if (node === void 0) {
|
|
743
|
+
return;
|
|
744
|
+
}
|
|
745
|
+
if (node.aabb !== void 0) {
|
|
746
|
+
return node.aabb;
|
|
747
|
+
}
|
|
748
|
+
if (node.computing === true) {
|
|
749
|
+
return;
|
|
750
|
+
}
|
|
751
|
+
node.computing = true;
|
|
752
|
+
try {
|
|
753
|
+
const pieces = [];
|
|
754
|
+
// Where a storey states an Elevation, its floor is the building
|
|
755
|
+
// datum plus that — see the banding block below, which this has to
|
|
756
|
+
// agree with. Under the ordinary authoring it equals the storey's
|
|
757
|
+
// own placement Z; the two only part on files that leave every
|
|
758
|
+
// storey placement on the datum.
|
|
759
|
+
const storeyZ0 = STOREY_TYPES.has(node.typeID) && node.elevation !== void 0 ?
|
|
760
|
+
storeyFloorZ_(localID, node.elevation, nodes, parentOf) : void 0;
|
|
761
|
+
if (node.origin !== void 0) {
|
|
762
|
+
// The placement point contributes this node's XY footprint. For
|
|
763
|
+
// a storey with an Elevation its Z is the DATUM, not its
|
|
764
|
+
// contents, so seeding the band with it would drag every
|
|
765
|
+
// storey's floor down onto the building origin — substitute the
|
|
766
|
+
// banded floor. Non-storeys keep their own Z.
|
|
767
|
+
pieces.push(pointAabb_(node.origin[0], node.origin[1], storeyZ0 ?? node.origin[2]));
|
|
768
|
+
}
|
|
769
|
+
const samples = productOrigins.get(localID);
|
|
770
|
+
if (samples !== void 0) {
|
|
771
|
+
for (const origin of samples) {
|
|
772
|
+
pieces.push(pointAabb_(...origin));
|
|
773
|
+
}
|
|
774
|
+
}
|
|
775
|
+
for (const childID of node.children) {
|
|
776
|
+
const childBox = aabbOf(childID);
|
|
777
|
+
if (childBox !== void 0) {
|
|
778
|
+
pieces.push(childBox);
|
|
779
|
+
}
|
|
780
|
+
}
|
|
781
|
+
let box = unionAabb(...pieces);
|
|
782
|
+
if (box !== void 0 && STOREY_TYPES.has(node.typeID)) {
|
|
783
|
+
const height = storeyHeight.get(localID);
|
|
784
|
+
// IfcBuildingStorey.Elevation is measured from the BUILDING
|
|
785
|
+
// datum, not from world zero, so a building placed at z=100
|
|
786
|
+
// drew its plates 100 units low. Add the datum back rather than
|
|
787
|
+
// letting the storey's own placement Z replace elevation
|
|
788
|
+
// outright: the two agree under the ordinary authoring (the
|
|
789
|
+
// storey placement is offset from the building BY the
|
|
790
|
+
// elevation), but a file that parks every storey placement on
|
|
791
|
+
// the building datum and carries the height only in Elevation
|
|
792
|
+
// would then collapse all of its plates onto one Z. Storey
|
|
793
|
+
// HEIGHTS stay on elevation deltas — datum-invariant either way,
|
|
794
|
+
// though on a datum tilted out of plumb they over-thicken the
|
|
795
|
+
// plate by 1/cos(tilt) (the floor Z is tilt-correct; see
|
|
796
|
+
// storeyFloorZ_). Left alone: the sample-derived height fallback
|
|
797
|
+
// is already a world-Z span, so one scale cannot serve both, and
|
|
798
|
+
// a tilted building has no horizontal storeys to plate anyway.
|
|
799
|
+
const z0 = storeyZ0 ?? node.origin?.[2] ?? box.min[2];
|
|
800
|
+
const z1 = height !== void 0 ? z0 + height : box.max[2];
|
|
801
|
+
box = {
|
|
802
|
+
min: [box.min[0], box.min[1], Math.min(box.min[2], z0)],
|
|
803
|
+
max: [box.max[0], box.max[1], Math.max(box.max[2], z1)],
|
|
804
|
+
};
|
|
805
|
+
}
|
|
806
|
+
node.aabb = box;
|
|
807
|
+
return box;
|
|
808
|
+
}
|
|
809
|
+
finally {
|
|
810
|
+
node.computing = false;
|
|
811
|
+
}
|
|
812
|
+
};
|
|
813
|
+
for (const root of roots) {
|
|
814
|
+
aabbOf(root);
|
|
815
|
+
}
|
|
816
|
+
const emitIDs = [];
|
|
817
|
+
for (const node of nodes.values()) {
|
|
818
|
+
if (!shouldEmitSpatialNode(node.depth, maxDepth, node.typeID)) {
|
|
819
|
+
continue;
|
|
820
|
+
}
|
|
821
|
+
if (node.aabb === void 0) {
|
|
822
|
+
continue;
|
|
823
|
+
}
|
|
824
|
+
if (node.children.length === 1) {
|
|
825
|
+
const child = nodes.get(node.children[0]);
|
|
826
|
+
if (child?.aabb !== void 0 &&
|
|
827
|
+
aabbMostlyEqual(node.aabb, child.aabb, COLLAPSE_REL, minEdge) &&
|
|
828
|
+
shouldEmitSpatialNode(child.depth, maxDepth, child.typeID)) {
|
|
829
|
+
continue;
|
|
830
|
+
}
|
|
831
|
+
}
|
|
832
|
+
emitIDs.push(node.localID);
|
|
833
|
+
}
|
|
834
|
+
const coordination = coordinationMatrix ??
|
|
835
|
+
fallbackCoordination_(roots, nodes, linearScalingFactor);
|
|
836
|
+
let emitted = 0;
|
|
837
|
+
for (const localID of emitIDs) {
|
|
838
|
+
const node = nodes.get(localID);
|
|
839
|
+
if (node?.aabb === void 0) {
|
|
840
|
+
continue;
|
|
841
|
+
}
|
|
842
|
+
const aabb = padAabb_(node.aabb, minEdge);
|
|
843
|
+
try {
|
|
844
|
+
onMesh({
|
|
845
|
+
expressID: node.expressID,
|
|
846
|
+
geometryExpressID: -1,
|
|
847
|
+
color: SPATIAL_IMPOSTER_COLOR,
|
|
848
|
+
flatTransformation: mat4MultiplyF64(coordination, aabbBoxMatrix(aabb)),
|
|
849
|
+
aabb,
|
|
850
|
+
});
|
|
851
|
+
++emitted;
|
|
852
|
+
}
|
|
853
|
+
catch {
|
|
854
|
+
// Preview must never break open.
|
|
855
|
+
}
|
|
856
|
+
}
|
|
857
|
+
return emitted;
|
|
858
|
+
}
|
|
859
|
+
/**
|
|
860
|
+
* World Z of an IfcBuildingStorey's floor: `Elevation` measured up the
|
|
861
|
+
* datum's own +Z from the datum's world origin, where the datum is the
|
|
862
|
+
* nearest ancestor with a resolved placement (the IfcBuilding in a
|
|
863
|
+
* well-formed file).
|
|
864
|
+
*
|
|
865
|
+
* Elevation is a length along the datum's Z, not along world Z, so the
|
|
866
|
+
* datum's whole transform is needed and not just its height — on a
|
|
867
|
+
* building tilted out of plumb the two differ by `cos(tilt)`. Only the
|
|
868
|
+
* Z component is taken, because that is all the banding uses: the plate
|
|
869
|
+
* keeps the XY footprint its placement and contained samples give it.
|
|
870
|
+
* A tilted building's storeys are not horizontal anyway, so the
|
|
871
|
+
* axis-aligned plate is an approximation there by construction — this
|
|
872
|
+
* just stops it being an approximation on the *height* as well.
|
|
873
|
+
*
|
|
874
|
+
* Falls back to a world-relative Elevation (datum at zero, +Z up) when
|
|
875
|
+
* nothing up the chain resolved a placement: the pre-fix behaviour, and
|
|
876
|
+
* the only thing left to anchor on.
|
|
877
|
+
*
|
|
878
|
+
* @param localID The storey.
|
|
879
|
+
* @param elevation The storey's `Elevation`, in source units.
|
|
880
|
+
* @param nodes All walked nodes.
|
|
881
|
+
* @param parentOf Child -> parent.
|
|
882
|
+
* @return {number} The floor's world Z.
|
|
883
|
+
*/
|
|
884
|
+
function storeyFloorZ_(localID, elevation, nodes, parentOf) {
|
|
885
|
+
let id = parentOf.get(localID);
|
|
886
|
+
// Bounded rather than while-truthy: parentOf is built by a BFS and so
|
|
887
|
+
// should be acyclic, but this module treats the aggregate graph as
|
|
888
|
+
// untrusted everywhere else too (see `computing` in aabbOf).
|
|
889
|
+
for (let hops = 0; id !== void 0 && hops <= nodes.size; ++hops) {
|
|
890
|
+
const placement = nodes.get(id)?.placement;
|
|
891
|
+
if (placement !== void 0) {
|
|
892
|
+
return placement[TRANSLATION[2]] +
|
|
893
|
+
elevation * placement[LOCAL_Z_WORLD_Z];
|
|
894
|
+
}
|
|
895
|
+
id = parentOf.get(id);
|
|
896
|
+
}
|
|
897
|
+
return elevation;
|
|
898
|
+
}
|
|
899
|
+
/**
|
|
900
|
+
* The durable coordination frame, derived the way the preview channels
|
|
901
|
+
* derive theirs but anchored on the spatial root's centre instead of the
|
|
902
|
+
* first extracted geometry's first point: identity placement + that
|
|
903
|
+
* anchor is exactly `deriveCoordinationF64`'s input contract, so the
|
|
904
|
+
* quantized model-zero policy (no recentre inside
|
|
905
|
+
* LARGE_COORDINATE_BUDGET_M, snap to COORDINATION_SNAP_M beyond) applies
|
|
906
|
+
* unchanged. Used only when no preview instance latched a frame first.
|
|
907
|
+
*
|
|
908
|
+
* Best-effort by construction, and the failure has two shapes. Beyond
|
|
909
|
+
* LARGE_COORDINATE_BUDGET_M both sides snap to COORDINATION_SNAP_M and
|
|
910
|
+
* agree as long as the spatial root and the first geometry share a grid
|
|
911
|
+
* cell. Worse: the anchor comes from `placementTransform_`, which reads
|
|
912
|
+
* IfcLocalPlacement chains and never looks at geometry — so a file that
|
|
913
|
+
* keeps identity placements and bakes absolute coordinates into the
|
|
914
|
+
* vertices (civil/GIS exports do this) has a root box near zero and gets
|
|
915
|
+
* no recentre at all, while the durable walk anchors tens of km out and
|
|
916
|
+
* does. That is a full site-offset, not a one-cell disagreement. Whenever
|
|
917
|
+
* the preview channel latched a frame we use it instead, precisely
|
|
918
|
+
* because it was derived from real geometry.
|
|
919
|
+
*
|
|
920
|
+
* @param roots Root spatial node local IDs.
|
|
921
|
+
* @param nodes The walked spatial nodes.
|
|
922
|
+
* @param linearScalingFactor Source units -> metres.
|
|
923
|
+
* @return {number[]} The coordination matrix.
|
|
924
|
+
*/
|
|
925
|
+
function fallbackCoordination_(roots, nodes, linearScalingFactor) {
|
|
926
|
+
const rootBox = unionAabb(...roots.map((id) => nodes.get(id)?.aabb));
|
|
927
|
+
const anchor = rootBox !== void 0 ? {
|
|
928
|
+
x: (rootBox.min[0] + rootBox.max[0]) * 0.5,
|
|
929
|
+
y: (rootBox.min[1] + rootBox.max[1]) * 0.5,
|
|
930
|
+
z: (rootBox.min[2] + rootBox.max[2]) * 0.5,
|
|
931
|
+
} : { x: 0, y: 0, z: 0 };
|
|
932
|
+
return deriveCoordinationF64(void 0, anchor, NORMALIZE_MAT_F64, sanitizeScale_(linearScalingFactor));
|
|
933
|
+
}
|