@ifc-lite/viewer 1.17.4 → 1.18.0
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/.turbo/turbo-build.log +20 -17
- package/.turbo/turbo-typecheck.log +1 -1
- package/CHANGELOG.md +630 -0
- package/DESKTOP_CONTRACT_VERSION +1 -1
- package/dist/assets/{basketViewActivator-BmnNtVfZ.js → basketViewActivator-Cm1QEk_R.js} +1 -1
- package/dist/assets/drawing-2d-DoxKMqbO.js +257 -0
- package/dist/assets/{exporters-ChAtBmlj.js → exporters-B_OBqIyD.js} +3479 -2845
- package/dist/assets/{geometry.worker-BQ0rzNo-.js → geometry.worker-xHHy-9DV.js} +1 -1
- package/dist/assets/ids-DQ5jY0E8.js +1 -0
- package/dist/assets/ifc-lite_bg-ADjKXSms.wasm +0 -0
- package/dist/assets/{index-Co8E2-FE.js → index-BKq-M3Mk.js} +55873 -40593
- package/dist/assets/index-COnQRuqY.css +1 -0
- package/dist/assets/{native-bridge-BRvbckFQ.js → native-bridge-SHXiQwFW.js} +104 -104
- package/dist/assets/sandbox-jez21HtV.js +9627 -0
- package/dist/assets/{server-client-BV8zHZ7Y.js → server-client-ncOQVNso.js} +1 -1
- package/dist/assets/{wasm-bridge-g01g7T9b.js → wasm-bridge-DyfBSB8z.js} +1 -1
- package/dist/index.html +8 -7
- package/index.html +1 -0
- package/package.json +13 -13
- package/src/App.tsx +16 -2
- package/src/apache-arrow.d.ts +30 -0
- package/src/components/viewer/AddElementPanel.tsx +758 -0
- package/src/components/viewer/BulkPropertyEditor.tsx +7 -0
- package/src/components/viewer/CesiumOverlay.tsx +62 -19
- package/src/components/viewer/ChatPanel.tsx +259 -93
- package/src/components/viewer/CommandPalette.tsx +56 -7
- package/src/components/viewer/EntityContextMenu.tsx +168 -4
- package/src/components/viewer/ExportChangesButton.tsx +25 -5
- package/src/components/viewer/ExportDialog.tsx +19 -1
- package/src/components/viewer/MainToolbar.tsx +73 -13
- package/src/components/viewer/PropertiesPanel.tsx +237 -23
- package/src/components/viewer/SearchInline.tsx +669 -0
- package/src/components/viewer/SearchModal.filter.builder.tsx +766 -0
- package/src/components/viewer/SearchModal.filter.tsx +514 -0
- package/src/components/viewer/SearchModal.text.tsx +388 -0
- package/src/components/viewer/SearchModal.tsx +235 -0
- package/src/components/viewer/SettingsPage.tsx +252 -101
- package/src/components/viewer/ThemeSwitch.tsx +63 -7
- package/src/components/viewer/ToolOverlays.tsx +5 -0
- package/src/components/viewer/ViewerLayout.tsx +25 -4
- package/src/components/viewer/Viewport.tsx +25 -3
- package/src/components/viewer/ViewportContainer.tsx +51 -64
- package/src/components/viewer/ViewportOverlays.tsx +5 -2
- package/src/components/viewer/annotations/AnnotationDropInput.tsx +203 -0
- package/src/components/viewer/annotations/AnnotationLayer.tsx +287 -0
- package/src/components/viewer/annotations/AnnotationPin.tsx +90 -0
- package/src/components/viewer/annotations/AnnotationPopover.tsx +296 -0
- package/src/components/viewer/bcf/BCFTopicDetail.tsx +4 -4
- package/src/components/viewer/chat/ModelSelector.tsx +90 -54
- package/src/components/viewer/lists/ListPanel.tsx +14 -21
- package/src/components/viewer/properties/GeoreferencingPanel.tsx +113 -51
- package/src/components/viewer/properties/LocationMap.tsx +9 -7
- package/src/components/viewer/properties/ModelMetadataPanel.tsx +1 -1
- package/src/components/viewer/properties/RawStepCard.tsx +332 -0
- package/src/components/viewer/properties/RawStepRow.tsx +261 -0
- package/src/components/viewer/properties/ScheduleCard.tsx +224 -0
- package/src/components/viewer/properties/TaskEditCard.tsx +510 -0
- package/src/components/viewer/properties/raw-step-format.ts +193 -0
- package/src/components/viewer/schedule/AnimationSettingsPopover.tsx +542 -0
- package/src/components/viewer/schedule/GanttDependencyArrows.tsx +89 -0
- package/src/components/viewer/schedule/GanttDragTooltip.tsx +48 -0
- package/src/components/viewer/schedule/GanttEmptyState.tsx +97 -0
- package/src/components/viewer/schedule/GanttPanel.tsx +295 -0
- package/src/components/viewer/schedule/GanttTaskBar.tsx +199 -0
- package/src/components/viewer/schedule/GanttTaskTree.tsx +250 -0
- package/src/components/viewer/schedule/GanttTimeline.tsx +305 -0
- package/src/components/viewer/schedule/GanttToolbar.tsx +406 -0
- package/src/components/viewer/schedule/GenerateAdvancedPanel.tsx +147 -0
- package/src/components/viewer/schedule/GenerateScheduleDialog.tsx +392 -0
- package/src/components/viewer/schedule/HeightStrategyPanel.tsx +120 -0
- package/src/components/viewer/schedule/generate-schedule.test.ts +439 -0
- package/src/components/viewer/schedule/generate-schedule.ts +648 -0
- package/src/components/viewer/schedule/schedule-animator.test.ts +452 -0
- package/src/components/viewer/schedule/schedule-animator.ts +488 -0
- package/src/components/viewer/schedule/schedule-selection.test.ts +148 -0
- package/src/components/viewer/schedule/schedule-selection.ts +163 -0
- package/src/components/viewer/schedule/schedule-utils.ts +223 -0
- package/src/components/viewer/schedule/useConstructionSequence.ts +156 -0
- package/src/components/viewer/schedule/useGanttBarDrag.test.ts +90 -0
- package/src/components/viewer/schedule/useGanttBarDrag.ts +305 -0
- package/src/components/viewer/schedule/useGanttSelection3DHighlight.ts +152 -0
- package/src/components/viewer/schedule/useOverlayCompositor.ts +108 -0
- package/src/components/viewer/selectionHandlers.ts +446 -0
- package/src/components/viewer/tools/AddElementOverlay.tsx +540 -0
- package/src/components/viewer/tools/SectionCapControls.tsx +237 -0
- package/src/components/viewer/tools/SectionPanel.tsx +39 -18
- package/src/components/viewer/useAnimationLoop.ts +9 -1
- package/src/components/viewer/useDuplicateShortcut.ts +77 -0
- package/src/components/viewer/useMouseControls.ts +9 -1
- package/src/components/viewer/useRenderUpdates.ts +1 -1
- package/src/hooks/ids/idsDataAccessor.ts +60 -24
- package/src/hooks/ingest/viewerModelIngest.ts +7 -2
- package/src/hooks/useIfcFederation.ts +326 -71
- package/src/hooks/useIfcLoader.ts +23 -10
- package/src/hooks/useKeyboardShortcuts.ts +25 -0
- package/src/hooks/useSandbox.ts +1 -1
- package/src/hooks/useSearchIndex.ts +125 -0
- package/src/hooks/useViewControls.ts +13 -5
- package/src/index.css +550 -10
- package/src/lib/desktop-entitlement.ts +2 -4
- package/src/lib/geo/cesium-bridge.ts +15 -7
- package/src/lib/geo/effective-georef.test.ts +73 -0
- package/src/lib/geo/effective-georef.ts +111 -0
- package/src/lib/geo/reproject.ts +105 -19
- package/src/lib/llm/byok-guard.test.ts +77 -0
- package/src/lib/llm/byok-guard.ts +39 -0
- package/src/lib/llm/free-models.test.ts +0 -6
- package/src/lib/llm/models.ts +104 -42
- package/src/lib/llm/stream-client.ts +74 -110
- package/src/lib/llm/stream-direct.test.ts +130 -0
- package/src/lib/llm/stream-direct.ts +316 -0
- package/src/lib/llm/system-prompt.test.ts +14 -0
- package/src/lib/llm/system-prompt.ts +102 -1
- package/src/lib/llm/types.ts +20 -2
- package/src/lib/recent-files.ts +38 -4
- package/src/lib/scripts/templates/bim-globals.d.ts +136 -114
- package/src/lib/scripts/templates/construction-schedule.ts +223 -0
- package/src/lib/scripts/templates.ts +7 -0
- package/src/lib/search/common-ifc-types.ts +36 -0
- package/src/lib/search/filter-evaluate.test.ts +537 -0
- package/src/lib/search/filter-evaluate.ts +610 -0
- package/src/lib/search/filter-rules.test.ts +119 -0
- package/src/lib/search/filter-rules.ts +198 -0
- package/src/lib/search/filter-schema.test.ts +233 -0
- package/src/lib/search/filter-schema.ts +146 -0
- package/src/lib/search/recent-searches.test.ts +116 -0
- package/src/lib/search/recent-searches.ts +93 -0
- package/src/lib/search/result-export.test.ts +101 -0
- package/src/lib/search/result-export.ts +104 -0
- package/src/lib/search/saved-filters.test.ts +118 -0
- package/src/lib/search/saved-filters.ts +154 -0
- package/src/lib/search/tier0-scan.test.ts +196 -0
- package/src/lib/search/tier0-scan.ts +237 -0
- package/src/lib/search/tier1-index.test.ts +242 -0
- package/src/lib/search/tier1-index.ts +448 -0
- package/src/main.tsx +1 -10
- package/src/sdk/adapters/export-adapter.test.ts +434 -1
- package/src/sdk/adapters/export-adapter.ts +404 -1
- package/src/sdk/adapters/export-schedule-splice.test.ts +127 -0
- package/src/sdk/adapters/export-schedule-splice.ts +87 -0
- package/src/sdk/adapters/model-compat.ts +8 -2
- package/src/sdk/adapters/schedule-adapter.ts +73 -0
- package/src/sdk/adapters/store-adapter.ts +201 -0
- package/src/sdk/adapters/visibility-adapter.ts +3 -0
- package/src/sdk/local-backend.ts +16 -8
- package/src/services/api-keys.ts +73 -0
- package/src/services/desktop-export.ts +3 -1
- package/src/services/desktop-native-metadata.ts +41 -18
- package/src/services/file-dialog.ts +4 -1
- package/src/services/tauri-modules.d.ts +25 -0
- package/src/store/basketVisibleSet.ts +3 -0
- package/src/store/constants.ts +20 -2
- package/src/store/globalId.ts +4 -1
- package/src/store/index.ts +82 -6
- package/src/store/slices/addElementMeshes.ts +365 -0
- package/src/store/slices/addElementSlice.ts +275 -0
- package/src/store/slices/annotationsSlice.test.ts +133 -0
- package/src/store/slices/annotationsSlice.ts +251 -0
- package/src/store/slices/cesiumSlice.ts +5 -0
- package/src/store/slices/chatSlice.test.ts +6 -76
- package/src/store/slices/chatSlice.ts +17 -58
- package/src/store/slices/dataSlice.test.ts +23 -4
- package/src/store/slices/dataSlice.ts +1 -1
- package/src/store/slices/modelSlice.test.ts +67 -9
- package/src/store/slices/modelSlice.ts +39 -7
- package/src/store/slices/mutationSlice.ts +964 -3
- package/src/store/slices/overlayCompositor.test.ts +164 -0
- package/src/store/slices/overlaySlice.test.ts +93 -0
- package/src/store/slices/overlaySlice.ts +151 -0
- package/src/store/slices/pinboardSlice.test.ts +6 -1
- package/src/store/slices/playbackSlice.ts +128 -0
- package/src/store/slices/schedule-edit-helpers.test.ts +97 -0
- package/src/store/slices/schedule-edit-helpers.ts +179 -0
- package/src/store/slices/scheduleSlice.test.ts +694 -0
- package/src/store/slices/scheduleSlice.ts +1330 -0
- package/src/store/slices/searchSlice.test.ts +342 -0
- package/src/store/slices/searchSlice.ts +341 -0
- package/src/store/slices/sectionSlice.test.ts +87 -7
- package/src/store/slices/sectionSlice.ts +151 -5
- package/src/store/slices/selectionSlice.test.ts +46 -0
- package/src/store/slices/selectionSlice.ts +20 -0
- package/src/store/slices/uiSlice.ts +28 -5
- package/src/store/types.ts +26 -0
- package/src/store.ts +14 -0
- package/src/utils/nativeSpatialDataStore.ts +4 -1
- package/src/utils/viewportUtils.ts +7 -2
- package/src/vite-env.d.ts +0 -4
- package/dist/assets/drawing-2d-gWfpdfYe.js +0 -257
- package/dist/assets/ids-B4jTqB1O.js +0 -1
- package/dist/assets/ifc-lite_bg-BX4E7TX8.wasm +0 -0
- package/dist/assets/index-DckuDqlv.css +0 -1
- package/dist/assets/sandbox-DZiNLNMk.js +0 -5933
- package/src/components/viewer/UpgradePage.tsx +0 -71
- package/src/lib/desktop/ClerkDesktopEntitlementSync.tsx +0 -175
- package/src/lib/llm/ClerkChatSync.tsx +0 -74
- package/src/lib/llm/clerk-auth.ts +0 -62
|
@@ -1,257 +0,0 @@
|
|
|
1
|
-
const wt={projectionDepth:10,includeHiddenLines:!0,creaseAngle:30,scale:100};function W(n,t){return`${n}:${t}`}const $=1e-7;function G(n,t,e){return{x:n,y:t,z:e}}function Z(n,t){return{x:n.x-t.x,y:n.y-t.y,z:n.z-t.z}}function _(n,t){return n.x*t.x+n.y*t.y+n.z*t.z}function Ft(n,t){return{x:n.y*t.z-n.z*t.y,y:n.z*t.x-n.x*t.z,z:n.x*t.y-n.y*t.x}}function St(n){return Math.sqrt(n.x*n.x+n.y*n.y+n.z*n.z)}function J(n){const t=St(n);return t<$?{x:0,y:0,z:0}:{x:n.x/t,y:n.y/t,z:n.z/t}}function $t(n,t,e){return{x:n.x+e*(t.x-n.x),y:n.y+e*(t.y-n.y),z:n.z+e*(t.z-n.z)}}function z(n,t){return{x:n.x-t.x,y:n.y-t.y}}function At(n,t){return n.x*t.x+n.y*t.y}function Pt(n){return Math.sqrt(n.x*n.x+n.y*n.y)}function R(n,t){const e=t.x-n.x,i=t.y-n.y;return Math.sqrt(e*e+i*i)}function K(n,t,e){return{x:n.x+e*(t.x-n.x),y:n.y+e*(t.y-n.y)}}function Lt(n){const t=Pt(n);return t<$?{x:0,y:0}:{x:n.x/t,y:n.y/t}}function Q(n,t){return n.x*t.y-n.y*t.x}function tt(n){return R(n.start,n.end)}function Y(n){return Lt(z(n.end,n.start))}function lt(){return{min:{x:1/0,y:1/0},max:{x:-1/0,y:-1/0}}}function H(n,t){return{min:{x:Math.min(n.min.x,t.x),y:Math.min(n.min.y,t.y)},max:{x:Math.max(n.max.x,t.x),y:Math.max(n.max.y,t.y)}}}function Et(n,t){let e=H(n,t.start);return e=H(e,t.end),e}function kt(n){return{x:(n.min.x+n.max.x)/2,y:(n.min.y+n.max.y)/2}}function vt(n){return{x:n.max.x-n.min.x,y:n.max.y-n.min.y}}function N(n,t,e){return _(n,t)-e}function ct(n,t){const e=t?-1:1;switch(n){case"x":return{x:e,y:0,z:0};case"y":return{x:0,y:e,z:0};case"z":return{x:0,y:0,z:e}}}function ht(n){switch(n){case"x":return{u:"z",v:"y"};case"y":return{u:"x",v:"z"};case"z":return{u:"x",v:"y"}}}function D(n,t,e){const i=ht(t),s=n[i.u],o=n[i.v];return{x:e?-s:s,y:o}}function dt(n){if(n.length<3)return 0;let t=0;for(let e=0;e<n.length;e++){const i=(e+1)%n.length;t+=n[e].x*n[i].y,t-=n[i].x*n[e].y}return t/2}function ut(n){return dt(n)>0}function ft(n){return[...n].reverse()}function Tt(n){return ut(n)?n:ft(n)}function Rt(n){return ut(n)?ft(n):n}class gt{tolerance;constructor(t=1e-4){this.tolerance=t}buildPolygons(t){const e=new Map;for(const s of t){const o=W(s.modelIndex,s.entityId);e.has(o)||e.set(o,[]),e.get(o).push(s)}const i=[];for(const[s,o]of e){const r=this.buildEntityPolygons(o);i.push(r)}return i.flat()}buildEntityPolygons(t){if(t.length===0)return[];const e=t[0],{entityId:i,ifcType:s,modelIndex:o}=e,r=t.map(c=>({start:c.p0_2d,end:c.p1_2d,used:!1})),a=this.buildLoops(r);return a.length===0?[]:this.classifyLoops(a).map(c=>({polygon:{outer:c.outer,holes:c.holes},entityId:i,ifcType:s,modelIndex:o,isCut:!0}))}buildLoops(t){const e=[];for(;;){const i=t.findIndex(o=>!o.used);if(i===-1)break;const s=this.buildSingleLoop(t,i);if(s&&s.length>=3){const o=dt(s);e.push({points:s,area:o})}}return e}buildSingleLoop(t,e){const i=[],s=t[e];s.used=!0,i.push(s.start);let o=s.end;const r=s.start,a=t.length;let l=0;for(;l<a;){if(l++,R(o,r)<this.tolerance)return i;const c=this.findConnectingSegment(t,o);if(c===-1)break;const u=t[c];u.used=!0,R(u.start,o)<this.tolerance?(i.push(u.start),o=u.end):(i.push(u.end),o=u.start)}return i.length>=3?i:null}findConnectingSegment(t,e){let i=-1,s=this.tolerance;for(let o=0;o<t.length;o++){if(t[o].used)continue;const r=t[o],a=R(r.start,e);a<s&&(s=a,i=o);const l=R(r.end,e);l<s&&(s=l,i=o)}return i}classifyLoops(t){if(t.length===0)return[];const e=[...t].sort((o,r)=>Math.abs(r.area)-Math.abs(o.area)),i=[],s=new Set;for(let o=0;o<e.length;o++){if(s.has(o))continue;const r=e[o],a=Tt(r.points),l=[];for(let c=o+1;c<e.length;c++){if(s.has(c))continue;const u=e[c];this.isLoopContainedIn(u.points,a)&&(l.push(Rt(u.points)),s.add(c))}s.add(o),i.push({outer:a,holes:l})}return i}isLoopContainedIn(t,e){const i=t[0];return this.pointInPolygon(i,e)}pointInPolygon(t,e){let i=!1;const s=e.length;for(let o=0,r=s-1;o<s;r=o++){const a=e[o],l=e[r];a.y>t.y!=l.y>t.y&&t.x<(l.x-a.x)*(t.y-a.y)/(l.y-a.y)+a.x&&(i=!i)}return i}}class Dt{planeNormal;planeDistance;axis;flipped;constructor(t){this.axis=t.axis,this.flipped=t.flipped,this.planeNormal=ct(t.axis,t.flipped),this.planeDistance=t.position}cutMeshes(t){const e=performance.now(),i=[];let s=0,o=0;for(const u of t){const h=this.cutSingleMesh(u);i.push(h.segments),s+=h.trianglesProcessed,o+=h.trianglesIntersected}const r=i.flat(),l=new gt().buildPolygons(r),c=performance.now()-e;return{segments:r,polygons:l,stats:{totalTriangles:s,intersectedTriangles:o,segmentCount:r.length,polygonCount:l.length,processingTimeMs:c}}}cutSingleMesh(t){const e=[],{positions:i,indices:s,expressId:o,ifcType:r,modelIndex:a}=t,l=s.length/3;let c=0;for(let u=0;u<l;u++){const h=s[u*3],d=s[u*3+1],f=s[u*3+2],g=this.getVertex(i,h),y=this.getVertex(i,d),p=this.getVertex(i,f),m=N(g,this.planeNormal,this.planeDistance),I=N(y,this.planeNormal,this.planeDistance),w=N(p,this.planeNormal,this.planeDistance),x=this.intersectTrianglePlane(g,y,p,m,I,w);if(x){c++;const C=D(x.p0,this.axis,this.flipped),b=D(x.p1,this.axis,this.flipped),A=b.x-C.x,M=b.y-C.y;if(A*A+M*M<$*$)continue;e.push({p0:x.p0,p1:x.p1,p0_2d:C,p1_2d:b,entityId:o,ifcType:r||"Unknown",modelIndex:a||0})}}return{segments:e,trianglesProcessed:l,trianglesIntersected:c}}getVertex(t,e){const i=e*3;return G(t[i],t[i+1],t[i+2])}intersectTrianglePlane(t,e,i,s,o,r){const a=(s>$?1:0)+(o>$?1:0)+(r>$?1:0),l=(s<-$?1:0)+(o<-$?1:0)+(r<-$?1:0);if(a===3||l===3||a===0&&l===0)return null;const c=[],u=this.edgePlaneIntersection(t,e,s,o);u&&c.push(u);const h=this.edgePlaneIntersection(e,i,o,r);if(h&&c.push(h),c.length<2){const d=this.edgePlaneIntersection(i,t,r,s);d&&c.push(d)}return c.length>=2?{p0:c[0],p1:c[1]}:null}edgePlaneIntersection(t,e,i,s){if(Math.abs(i)<$&&Math.abs(s)<$)return null;if(Math.abs(i)<$)return t;if(Math.abs(s)<$)return e;if(i>0==s>0)return null;const o=i/(i-s);return $t(t,e,o)}}const pt={angleTolerance:.01,distanceTolerance:.001,gapTolerance:.01};function Wt(n,t={}){const e={...pt,...t},i=new Map;for(const o of n){const r=`${o.modelIndex}:${o.entityId}:${o.category}:${o.visibility}`;i.has(r)||i.set(r,[]),i.get(r).push(o)}const s=[];for(const o of i.values()){const r=_t(o,e);s.push(...r)}return s}function _t(n,t){if(n.length<=1)return n;const e=n.map(o=>o.line),i=zt(e,t),s=n[0];return i.map(o=>({...s,line:o}))}function zt(n,t={}){const e={...pt,...t};if(n.length<=1)return n;const i=Bt(n,e.angleTolerance),s=[];for(const o of i.values()){const r=Nt(o,e.distanceTolerance);for(const a of r){const l=Ht(a,e.gapTolerance);s.push(...l)}}return s}function Bt(n,t){const e=new Map,i=t*2;for(const s of n){const o=Y(s);let r=Math.atan2(o.y,o.x);r<0&&(r+=Math.PI),r>=Math.PI&&(r-=Math.PI);const a=Math.floor(r/i);e.has(a)||e.set(a,[]),e.get(a).push(s)}return e}function Nt(n,t){const e=[],i=new Set;for(let s=0;s<n.length;s++){if(i.has(s))continue;const o=[n[s]];i.add(s);for(let r=s+1;r<n.length;r++)i.has(r)||Ot(n[s],n[r],t)&&(o.push(n[r]),i.add(r));e.push(o)}return e}function Ot(n,t,e){const i=Y(n),s=z(t.start,n.start);if(Math.abs(Q(i,s))>e)return!1;const r=z(t.end,n.start);return Math.abs(Q(i,r))<=e}function Ht(n,t){if(n.length<=1)return n;const e=n[0],i=Y(e),s=e.start,o=n.map(l=>{const c=et(l.start,s,i),u=et(l.end,s,i);return{t0:Math.min(c,u),t1:Math.max(c,u)}});o.sort((l,c)=>l.t0-c.t0);const r=[];let a=o[0];for(let l=1;l<o.length;l++){const c=o[l];c.t0<=a.t1+t?a={t0:a.t0,t1:Math.max(a.t1,c.t1)}:(r.push(a),a=c)}return r.push(a),r.map(l=>({start:{x:s.x+i.x*l.t0,y:s.y+i.y*l.t0},end:{x:s.x+i.x*l.t1,y:s.y+i.y*l.t1}}))}function et(n,t,e){const i=z(n,t);return At(i,e)}class Ut{creaseAngle;constructor(t=30){this.creaseAngle=t*Math.PI/180}extractEdges(t){const{positions:e,indices:i,expressId:s,ifcType:o,modelIndex:r}=t,a=new Map,l=[],c=i.length/3;for(let h=0;h<c;h++){const d=i[h*3],f=i[h*3+1],g=i[h*3+2],y=this.getVertex(e,d),p=this.getVertex(e,f),m=this.getVertex(e,g),I=this.computeFaceNormal(y,p,m);l.push(I),this.registerEdge(a,d,f,h),this.registerEdge(a,f,g,h),this.registerEdge(a,g,d,h)}const u=[];for(const[,h]of a){const d=this.getVertex(e,h.v0Idx),f=this.getVertex(e,h.v1Idx);let g=null,y=null,p=0,m="smooth";if(h.faceIndices.length===1)m="boundary",g=l[h.faceIndices[0]];else if(h.faceIndices.length>=2){g=l[h.faceIndices[0]],y=l[h.faceIndices[1]];const I=Math.max(-1,Math.min(1,_(g,y)));p=Math.acos(I),p>this.creaseAngle&&(m="crease")}m!=="smooth"&&u.push({v0:d,v1:f,face0Normal:g,face1Normal:y,dihedralAngle:p,type:m,entityId:s,ifcType:o||"Unknown",modelIndex:r||0})}return u}extractEdgesFromMeshes(t){const e=[];for(const i of t){const s=this.extractEdges(i);e.push(...s)}return e}extractSilhouettes(t,e){const i=J(e);return t.filter(s=>{if(s.type==="boundary")return!0;if(!s.face0Normal||!s.face1Normal)return!1;const o=_(s.face0Normal,i),r=_(s.face1Normal,i);return o<0!=r<0})}edgesToDrawingLines(t,e,i,s,o){return t.map(r=>{const a=D(r.v0,e,i),l=D(r.v1,e,i),c=e,u=Math.min(Math.abs(r.v0[c]-o),Math.abs(r.v1[c]-o));return{line:{start:a,end:l},category:s,visibility:"visible",entityId:r.entityId,ifcType:r.ifcType,modelIndex:r.modelIndex,depth:u}})}filterEdgesByDepth(t,e,i,s,o){return t.filter(r=>{const a=r.v0[e]-i,l=r.v1[e]-i,c=o?-s:0,u=o?0:s,h=a>=c&&a<=u,d=l>=c&&l<=u,f=a<c&&l>u||l<c&&a>u;return h||d||f})}getVertex(t,e){const i=e*3;return G(t[i],t[i+1],t[i+2])}computeFaceNormal(t,e,i){const s=Z(e,t),o=Z(i,t),r=Ft(s,o);return J(r)}registerEdge(t,e,i,s){const o=Math.min(e,i),r=Math.max(e,i),a=`${o}:${r}`;t.has(a)||t.set(a,{v0Idx:o,v1Idx:r,faceIndices:[]}),t.get(a).faceIndices.push(s)}}function jt(n,t){const e=t?1:-1;switch(n){case"x":return{x:e,y:0,z:0};case"y":return{x:0,y:e,z:0};case"z":return{x:0,y:0,z:e}}}function Gt(n,t,e){const i=[];for(const s of n){if(!Yt(s,t,e))continue;nt(i,s,s.outerPoints,"projection",t);let o=0;for(let r=0;r<s.holeCounts.length;r++){const a=s.holeCounts[r];if(a<2||o+a*2>s.holePoints.length){o+=a*2;continue}const l=s.holePoints.subarray(o,o+a*2);nt(i,s,l,"projection",t),o+=a*2}}return i}function Yt(n,t,e){const{axis:i,position:s,flipped:o}=t,{min:r,max:a}=Xt(n,i),l=o?s-e:s,c=o?s:s+e;return r<=c&&a>=l}function nt(n,t,e,i,s){const o=Math.floor(e.length/2);if(o<2)return;const r=t.transform;for(let a=0;a<o;a++){const l=(a+1)%o,c=e[a*2],u=e[a*2+1],h=e[l*2],d=e[l*2+1],f=U(c,u,r),g=U(h,d,r),y=D(f,s.axis,s.flipped),p=D(g,s.axis,s.flipped);Math.abs(y.x-p.x)<1e-7&&Math.abs(y.y-p.y)<1e-7||n.push({line:{start:y,end:p},category:i,visibility:"visible",entityId:t.expressId,ifcType:t.ifcType,modelIndex:t.modelIndex,depth:qt(f,g,s.axis,s.position)})}}function U(n,t,e){return{x:e[0]*n+e[4]*t+e[12],y:e[1]*n+e[5]*t+e[13],z:e[2]*n+e[6]*t+e[14]}}function Vt(n,t){return n[12+yt(t)]}function Xt(n,t){const e=t,i=n.extrusionDir[yt(t)]*n.extrusionDepth;let s=Number.POSITIVE_INFINITY,o=Number.NEGATIVE_INFINITY;const r=a=>{const l=Math.floor(a.length/2);for(let c=0;c<l;c++){const h=U(a[c*2],a[c*2+1],n.transform)[e],d=h+i;s=Math.min(s,h,d),o=Math.max(o,h,d)}};if(r(n.outerPoints),r(n.holePoints),!Number.isFinite(s)||!Number.isFinite(o)){const a=Vt(n.transform,t),l=a+i;return{min:Math.min(a,l),max:Math.max(a,l)}}return{min:s,max:o}}function yt(n){return n==="x"?0:n==="y"?1:2}function qt(n,t,e,i){const s=(n[e]+t[e])/2;return Math.abs(s-i)}const Zt={resolution:1024,samplesPerLine:10,depthBias:.001};class Jt{options;depthBuffer=null;width=0;height=0;bounds=null;constructor(t={}){this.options={...Zt,...t}}buildDepthBuffer(t,e,i,s,o,r){r||(r=this.computeBounds(t,e,i,s,o)),this.bounds=r;const a=r.max.x-r.min.x,l=r.max.y-r.min.y;if(a<$||l<$){this.width=1,this.height=1,this.depthBuffer=new Float32Array([1/0]);return}const c=a/l;c>1?(this.width=this.options.resolution,this.height=Math.max(1,Math.floor(this.options.resolution/c))):(this.height=this.options.resolution,this.width=Math.max(1,Math.floor(this.options.resolution*c))),this.depthBuffer=new Float32Array(this.width*this.height),this.depthBuffer.fill(1/0);for(const u of t)this.rasterizeMesh(u,e,i,s,o)}classifyLines(t){if(!this.depthBuffer||!this.bounds)throw new Error("Depth buffer not built. Call buildDepthBuffer first.");const e=[];for(const i of t){const s=this.classifySingleLine(i);e.push(s)}return e}applyVisibility(t){const e=this.classifyLines(t),i=[];for(const s of e)if(s.overallVisibility==="visible")i.push({...s.line,visibility:"visible"});else if(s.overallVisibility==="hidden")i.push({...s.line,visibility:"hidden"});else for(const o of s.segments)i.push({...s.line,line:{start:o.start,end:o.end},visibility:o.visible?"visible":"hidden"});return i}computeBounds(t,e,i,s,o){let r=lt();const a=this.getProjectionAxes(e);for(const c of t){const{positions:u}=c,h=u.length/3;for(let d=0;d<h;d++){const f=u[d*3],g=u[d*3+1],y=u[d*3+2],p={x:f,y:g,z:y},m=p[e]-i;if(o?m<=0&&m>=-s:m>=0&&m<=s){const w=p[a.u],x=p[a.v],C={x:o?-w:w,y:x};r=H(r,C)}}}const l=Math.max(r.max.x-r.min.x,r.max.y-r.min.y)*.01;return r.min.x-=l,r.min.y-=l,r.max.x+=l,r.max.y+=l,r}getProjectionAxes(t){switch(t){case"x":return{u:"z",v:"y"};case"y":return{u:"x",v:"z"};case"z":return{u:"x",v:"y"}}}rasterizeMesh(t,e,i,s,o){const{positions:r,indices:a}=t,l=this.getProjectionAxes(e),c=a.length/3;for(let u=0;u<c;u++){const h=a[u*3],d=a[u*3+1],f=a[u*3+2],g=this.getVertex(r,h),y=this.getVertex(r,d),p=this.getVertex(r,f),m=g[e]-i,I=y[e]-i,w=p[e]-i,x=M=>o?M<=0&&M>=-s:M>=0&&M<=s;if(!x(m)&&!x(I)&&!x(w))continue;const C=this.projectVertex(g,l,o),b=this.projectVertex(y,l,o),A=this.projectVertex(p,l,o);this.rasterizeTriangle(C,b,A)}}getVertex(t,e){const i=e*3;return G(t[i],t[i+1],t[i+2])}projectVertex(t,e,i){const s=t[e.u],o=t[e.v],a=["x","y","z"].find(l=>l!==e.u&&l!==e.v)??"z";return{x:i?-s:s,y:o,depth:t[a]}}rasterizeTriangle(t,e,i){if(!this.bounds||!this.depthBuffer)return;const s=f=>(f-this.bounds.min.x)/(this.bounds.max.x-this.bounds.min.x)*(this.width-1),o=f=>(f-this.bounds.min.y)/(this.bounds.max.y-this.bounds.min.y)*(this.height-1),r={x:s(t.x),y:o(t.y),depth:t.depth},a={x:s(e.x),y:o(e.y),depth:e.depth},l={x:s(i.x),y:o(i.y),depth:i.depth},c=Math.max(0,Math.floor(Math.min(r.x,a.x,l.x))),u=Math.min(this.width-1,Math.ceil(Math.max(r.x,a.x,l.x))),h=Math.max(0,Math.floor(Math.min(r.y,a.y,l.y))),d=Math.min(this.height-1,Math.ceil(Math.max(r.y,a.y,l.y)));for(let f=h;f<=d;f++)for(let g=c;g<=u;g++){const y=this.barycentricCoords(g+.5,f+.5,r,a,l);if(y.u>=0&&y.v>=0&&y.w>=0){const p=y.u*r.depth+y.v*a.depth+y.w*l.depth,m=f*this.width+g;p<this.depthBuffer[m]&&(this.depthBuffer[m]=p)}}}barycentricCoords(t,e,i,s,o){const r=s.x-i.x,a=s.y-i.y,l=o.x-i.x,c=o.y-i.y,u=t-i.x,h=e-i.y,d=r*r+a*a,f=r*l+a*c,g=r*u+a*h,y=l*l+c*c,p=l*u+c*h,m=d*y-f*f;if(Math.abs(m)<1e-10)return{u:-1,v:-1,w:-1};const I=1/m,w=(y*g-f*p)*I,x=(d*p-f*g)*I;return{u:1-w-x,v:w,w:x}}classifySingleLine(t){if(!this.bounds||!this.depthBuffer)return{line:t,segments:[{start:t.line.start,end:t.line.end,visible:!0}],overallVisibility:"visible"};const{samplesPerLine:e,depthBias:i}=this.options,o=R(t.line.start,t.line.end)<$?1:Math.max(2,e),r=[];let a=t.line.start,l=this.sampleVisibility(t.line.start,t.depth,i),c=l?1:0;for(let h=1;h<=o;h++){const d=h/o,f=K(t.line.start,t.line.end,d),g=this.sampleVisibility(f,t.depth,i);if(g&&c++,g!==l&&h<o){const y=(h-.5)/o,p=K(t.line.start,t.line.end,y);r.push({start:a,end:p,visible:l}),a=p,l=g}}r.push({start:a,end:t.line.end,visible:l});let u;return c===o+1?u="visible":c===0?u="hidden":u="partial",{line:t,segments:r,overallVisibility:u}}sampleVisibility(t,e,i){if(!this.bounds||!this.depthBuffer)return!0;const s=(t.x-this.bounds.min.x)/(this.bounds.max.x-this.bounds.min.x)*(this.width-1),o=(t.y-this.bounds.min.y)/(this.bounds.max.y-this.bounds.min.y)*(this.height-1),r=Math.max(0,Math.min(this.width-1,Math.floor(s))),a=Math.max(0,Math.min(this.height-1,Math.floor(o))),l=this.depthBuffer[a*this.width+r];return e<=l+i}}const it={IfcWall:{type:"diagonal",spacing:3,angle:45,lineWeight:.18,strokeColor:"#000000"},IfcWallStandardCase:{type:"diagonal",spacing:3,angle:45,lineWeight:.18,strokeColor:"#000000"},IfcCurtainWall:{type:"none",spacing:0,angle:0,lineWeight:.13,strokeColor:"#0066CC"},IfcSlab:{type:"concrete",spacing:2.5,angle:0,lineWeight:.13,strokeColor:"#666666"},IfcRoof:{type:"cross-hatch",spacing:4,angle:45,secondaryAngle:-45,lineWeight:.13,strokeColor:"#8B4513"},IfcCovering:{type:"horizontal",spacing:8,angle:0,lineWeight:.09,strokeColor:"#999999"},IfcColumn:{type:"steel",spacing:2,angle:45,lineWeight:.25,strokeColor:"#333333"},IfcBeam:{type:"steel",spacing:2,angle:45,lineWeight:.25,strokeColor:"#333333"},IfcMember:{type:"diagonal",spacing:2.5,angle:45,lineWeight:.18,strokeColor:"#444444"},IfcPlate:{type:"steel",spacing:1.5,angle:45,lineWeight:.18,strokeColor:"#555555"},IfcFooting:{type:"concrete",spacing:3,angle:0,lineWeight:.18,strokeColor:"#777777"},IfcPile:{type:"concrete",spacing:2.5,angle:0,lineWeight:.18,strokeColor:"#666666"},IfcWindow:{type:"glass",spacing:0,angle:0,lineWeight:.13,strokeColor:"#0099CC",fillColor:"rgba(200, 230, 255, 0.3)"},IfcDoor:{type:"none",spacing:0,angle:0,lineWeight:.25,strokeColor:"#000000"},IfcOpeningElement:{type:"none",spacing:0,angle:0,lineWeight:.13,strokeColor:"#CCCCCC"},IfcStair:{type:"horizontal",spacing:5,angle:0,lineWeight:.18,strokeColor:"#444444"},IfcStairFlight:{type:"horizontal",spacing:5,angle:0,lineWeight:.18,strokeColor:"#444444"},IfcRamp:{type:"diagonal",spacing:6,angle:30,lineWeight:.13,strokeColor:"#555555"},IfcRailing:{type:"none",spacing:0,angle:0,lineWeight:.13,strokeColor:"#666666"},IfcFlowTerminal:{type:"none",spacing:0,angle:0,lineWeight:.13,strokeColor:"#0066AA"},IfcFlowSegment:{type:"none",spacing:0,angle:0,lineWeight:.18,strokeColor:"#0066AA"},IfcDistributionElement:{type:"none",spacing:0,angle:0,lineWeight:.13,strokeColor:"#006688"},IfcSpace:{type:"none",spacing:0,angle:0,lineWeight:.09,strokeColor:"#CCCCCC"},IfcFurnishingElement:{type:"none",spacing:0,angle:0,lineWeight:.13,strokeColor:"#888888"},IfcFurniture:{type:"none",spacing:0,angle:0,lineWeight:.13,strokeColor:"#888888"},default:{type:"diagonal",spacing:4,angle:45,lineWeight:.13,strokeColor:"#666666"}};function mt(n){return it[n]||it.default}const Kt={cut:{weight:.5,color:"#000000",dashPattern:[],lineCap:"round",lineJoin:"round"},projection:{weight:.25,color:"#000000",dashPattern:[],lineCap:"round",lineJoin:"round"},hidden:{weight:.18,color:"#666666",dashPattern:[2,1],lineCap:"butt",lineJoin:"round"},silhouette:{weight:.35,color:"#000000",dashPattern:[],lineCap:"round",lineJoin:"round"},crease:{weight:.18,color:"#000000",dashPattern:[],lineCap:"round",lineJoin:"round"},boundary:{weight:.25,color:"#000000",dashPattern:[],lineCap:"round",lineJoin:"round"},annotation:{weight:.13,color:"#000000",dashPattern:[],lineCap:"butt",lineJoin:"miter"}},ot={IfcWall:{cut:.7,projection:.35},IfcWallStandardCase:{cut:.7,projection:.35},IfcSlab:{cut:.5,projection:.25},IfcColumn:{cut:.5,projection:.35},IfcBeam:{cut:.5,projection:.35},IfcWindow:{cut:.35,projection:.18},IfcDoor:{cut:.35,projection:.25},IfcStair:{cut:.35,projection:.25},IfcFurnishingElement:{cut:.18,projection:.13},IfcFurniture:{cut:.18,projection:.13},IfcSpace:{cut:.09,projection:.09}};function Qt(n,t){const e=Kt[n];if(t&&ot[t]){const i=ot[t][n];if(i!==void 0)return{...e,weight:i}}return e}const O=[{name:"1:1",factor:1,useCase:"Full size details"},{name:"1:2",factor:2,useCase:"Large details"},{name:"1:5",factor:5,useCase:"Construction details"},{name:"1:10",factor:10,useCase:"Details"},{name:"1:20",factor:20,useCase:"Room plans, sections"},{name:"1:50",factor:50,useCase:"Floor plans, elevations"},{name:"1:100",factor:100,useCase:"Building plans"},{name:"1:200",factor:200,useCase:"Site plans"},{name:"1:500",factor:500,useCase:"Site context"},{name:"1:1000",factor:1e3,useCase:"Urban context"}],st={A3_LANDSCAPE:{name:"A3 Landscape",width:420,height:297}};class xt{generateHatch(t,e=100,i){const s=mt(t.ifcType),o=i?{...s,type:i.type,spacing:i.spacing??s.spacing,angle:i.angle??s.angle,secondaryAngle:i.secondaryAngle??s.secondaryAngle}:s;if(o.type==="none"||o.type==="solid"||o.type==="glass")return{lines:[],pattern:o,polygon:t};const r=o.spacing*(e/100);let a=[];const l=this.generateParallelLines(t.polygon,r,o.angle,t.entityId,t.ifcType,t.modelIndex);if(a.push(...l),o.type==="cross-hatch"&&o.secondaryAngle!==void 0){const c=this.generateParallelLines(t.polygon,r,o.secondaryAngle,t.entityId,t.ifcType,t.modelIndex);a.push(...c)}if(o.type==="concrete"){const c=this.generateParallelLines(t.polygon,r*1.5,o.angle+90,t.entityId,t.ifcType,t.modelIndex);a.push(...c)}return{lines:a,pattern:o,polygon:t}}generateHatches(t,e=100,i){return t.map(s=>{const o=i?.(s);return this.generateHatch(s,e,o)})}generateParallelLines(t,e,i,s,o,r){if(e<$)return[];const a=i*Math.PI/180,l=Math.cos(a),c=Math.sin(a),u=-c,h=l,d=this.computePolygonBounds(t);if(!d)return[];const f=[{x:d.min.x,y:d.min.y},{x:d.max.x,y:d.min.y},{x:d.max.x,y:d.max.y},{x:d.min.x,y:d.max.y}];let g=1/0,y=-1/0;for(const I of f){const w=I.x*l+I.y*c;g=Math.min(g,w),y=Math.max(y,w)}const p=Math.sqrt(Math.pow(d.max.x-d.min.x,2)+Math.pow(d.max.y-d.min.y,2))*1.5,m=[];for(let I=g;I<=y;I+=e){const w=I*l,x=I*c,C={x:w-u*p,y:x-h*p},b={x:w+u*p,y:x+h*p},A=this.clipLineToPolygon({start:C,end:b},t);for(const M of A)m.push({line:M,entityId:s,ifcType:o,modelIndex:r})}return m}clipLineToPolygon(t,e){let i=this.clipLineToRing(t,e.outer,!0);for(const s of e.holes){const o=[];for(const r of i){const a=this.clipLineToRing(r,s,!1);o.push(...a)}i=o}return i}clipLineToRing(t,e,i){const s=[],o=t.end.x-t.start.x,r=t.end.y-t.start.y;for(let h=0;h<e.length;h++){const d=(h+1)%e.length,f=e[h],g=e[d],y=this.lineLineIntersection(t.start,t.end,f,g);if(y!==null&&y.t>=0&&y.t<=1){const p=-(g.y-f.y),m=g.x-f.x,I=o*p+r*m>0;s.push({t:y.t,entering:I})}}s.sort((h,d)=>h.t-d.t);const a=[];for(const h of s)(a.length===0||Math.abs(h.t-a[a.length-1].t)>$)&&a.push(h);if(a.length===0){const h={x:(t.start.x+t.end.x)/2,y:(t.start.y+t.end.y)/2};return this.pointInRing(h,e)===i?[t]:[]}const l=[];let c=this.pointInRing(t.start,e),u=0;for(const h of a)c===i&&l.push({start:{x:t.start.x+u*o,y:t.start.y+u*r},end:{x:t.start.x+h.t*o,y:t.start.y+h.t*r}}),u=h.t,c=!c;return c===i&&l.push({start:{x:t.start.x+u*o,y:t.start.y+u*r},end:t.end}),l.filter(h=>Math.abs(h.end.x-h.start.x)+Math.abs(h.end.y-h.start.y)>$)}lineLineIntersection(t,e,i,s){const o=e.x-t.x,r=e.y-t.y,a=s.x-i.x,l=s.y-i.y,c=o*l-r*a;if(Math.abs(c)<$)return null;const u=i.x-t.x,h=i.y-t.y,d=(u*l-h*a)/c,f=(u*r-h*o)/c;return f<0||f>1?null:{t:d,u:f}}pointInRing(t,e){let i=!1;const s=e.length;for(let o=0,r=s-1;o<s;r=o++){const a=e[o],l=e[r];a.y>t.y!=l.y>t.y&&t.x<(l.x-a.x)*(t.y-a.y)/(l.y-a.y)+a.x&&(i=!i)}return i}computePolygonBounds(t){if(t.outer.length===0)return null;let e=1/0,i=1/0,s=-1/0,o=-1/0;for(const r of t.outer)e=Math.min(e,r.x),i=Math.min(i,r.y),s=Math.max(s,r.x),o=Math.max(o,r.y);return{min:{x:e,y:i},max:{x:s,y:o}}}}class te{hatchGenerator=new xt;export(t,e={}){const{paperSize:i=st.A3_LANDSCAPE,scale:s=O.find(m=>m.factor===t.config.scale)||O[5],padding:o=20,showHiddenLines:r=!0,showHatching:a=!0,showTitleBlock:l=!1,title:c="Section",projectName:u="",backgroundColor:h="#FFFFFF"}=e,d=this.computeTransform(t.bounds,i,s,o);let f=this.createHeader(i,h);if(f+=this.createDefs(t,s.factor),a&&t.cutPolygons.length>0&&(f+=this.createHatchingLayer(t.cutPolygons,d,s.factor)),r){const m=t.lines.filter(I=>I.visibility==="hidden");m.length>0&&(f+=this.createLineLayer("hidden-lines",m,d,"Hidden Lines"))}const g=t.lines.filter(m=>m.category==="projection"&&m.visibility!=="hidden");g.length>0&&(f+=this.createLineLayer("projection-lines",g,d,"Projection"));const y=t.lines.filter(m=>(m.category==="silhouette"||m.category==="crease"||m.category==="boundary")&&m.visibility!=="hidden");y.length>0&&(f+=this.createLineLayer("feature-lines",y,d,"Feature Edges"));const p=t.lines.filter(m=>m.category==="cut");return p.length>0&&(f+=this.createLineLayer("cut-lines",p,d,"Cut Lines")),l&&(f+=this.createTitleBlock(i,c,u,s)),f+="</svg>",f}exportPolygons(t,e,i={}){const{paperSize:s=st.A3_LANDSCAPE,scale:o=O[5],padding:r=20,backgroundColor:a="#FFFFFF"}=i,l=this.computeTransform(e,s,o,r);let c=this.createHeader(s,a);return c+=this.createPolygonDefs(o.factor),c+=this.createHatchingLayer(t,l,o.factor),c+="</svg>",c}computeTransform(t,e,i,s){vt(t);const o=kt(t);e.width-s*2,e.height-s*2;const r=1e3/i.factor,a=e.width/2-o.x*r,l=e.height/2+o.y*r;return{scale:r,offsetX:a,offsetY:l,flipY:!0}}transformPoint(t,e){return{x:t.x*e.scale+e.offsetX,y:e.flipY?-t.y*e.scale+e.offsetY:t.y*e.scale+e.offsetY}}createHeader(t,e){return`<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
-
<svg xmlns="http://www.w3.org/2000/svg"
|
|
3
|
-
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
|
4
|
-
width="${t.width}mm"
|
|
5
|
-
height="${t.height}mm"
|
|
6
|
-
viewBox="0 0 ${t.width} ${t.height}">
|
|
7
|
-
<rect width="100%" height="100%" fill="${e}"/>
|
|
8
|
-
`}createDefs(t,e){let i=` <defs>
|
|
9
|
-
`;return i+=this.createHatchPatternDefs(e),i+=` </defs>
|
|
10
|
-
`,i}createPolygonDefs(t){let e=` <defs>
|
|
11
|
-
`;return e+=this.createHatchPatternDefs(t),e+=` </defs>
|
|
12
|
-
`,e}createHatchPatternDefs(t){const e=3*(t/100);let i="";return i+=` <pattern id="hatch-diagonal" patternUnits="userSpaceOnUse"
|
|
13
|
-
width="${e}" height="${e}" patternTransform="rotate(45)">
|
|
14
|
-
<line x1="0" y1="0" x2="0" y2="${e}" stroke="#000" stroke-width="0.15"/>
|
|
15
|
-
</pattern>
|
|
16
|
-
`,i+=` <pattern id="hatch-cross" patternUnits="userSpaceOnUse"
|
|
17
|
-
width="${e}" height="${e}">
|
|
18
|
-
<line x1="0" y1="0" x2="${e}" y2="${e}" stroke="#000" stroke-width="0.1"/>
|
|
19
|
-
<line x1="${e}" y1="0" x2="0" y2="${e}" stroke="#000" stroke-width="0.1"/>
|
|
20
|
-
</pattern>
|
|
21
|
-
`,i+=` <pattern id="hatch-horizontal" patternUnits="userSpaceOnUse"
|
|
22
|
-
width="${e}" height="${e}">
|
|
23
|
-
<line x1="0" y1="${e/2}" x2="${e}" y2="${e/2}" stroke="#000" stroke-width="0.1"/>
|
|
24
|
-
</pattern>
|
|
25
|
-
`,i+=` <pattern id="hatch-concrete" patternUnits="userSpaceOnUse"
|
|
26
|
-
width="${e*2}" height="${e*2}">
|
|
27
|
-
<circle cx="${e*.3}" cy="${e*.3}" r="0.3" fill="#666"/>
|
|
28
|
-
<circle cx="${e*1.3}" cy="${e*1.3}" r="0.3" fill="#666"/>
|
|
29
|
-
<circle cx="${e*.8}" cy="${e*1.6}" r="0.2" fill="#888"/>
|
|
30
|
-
</pattern>
|
|
31
|
-
`,i+=` <pattern id="hatch-steel" patternUnits="userSpaceOnUse"
|
|
32
|
-
width="${e*.7}" height="${e*.7}" patternTransform="rotate(45)">
|
|
33
|
-
<line x1="0" y1="0" x2="0" y2="${e*.7}" stroke="#333" stroke-width="0.2"/>
|
|
34
|
-
</pattern>
|
|
35
|
-
`,i}createLineLayer(t,e,i,s){let o=` <g id="${t}" inkscape:label="${s}" inkscape:groupmode="layer">
|
|
36
|
-
`;for(const r of e)o+=this.renderLine(r,i);return o+=` </g>
|
|
37
|
-
`,o}renderLine(t,e){const i=Qt(t.category,t.ifcType),s=this.transformPoint(t.line.start,e),o=this.transformPoint(t.line.end,e),r=i.dashPattern.length>0?` stroke-dasharray="${i.dashPattern.join(" ")}"`:"";return` <line x1="${s.x.toFixed(3)}" y1="${s.y.toFixed(3)}" x2="${o.x.toFixed(3)}" y2="${o.y.toFixed(3)}"
|
|
38
|
-
stroke="${i.color}" stroke-width="${i.weight}"
|
|
39
|
-
stroke-linecap="${i.lineCap}"${r}
|
|
40
|
-
data-entity-id="${t.entityId}" data-ifc-type="${t.ifcType}"/>
|
|
41
|
-
`}createHatchingLayer(t,e,i){let s=` <g id="hatching" inkscape:label="Hatching" inkscape:groupmode="layer">
|
|
42
|
-
`;for(const o of t){const r=mt(o.ifcType);if(r.type!=="none"&&(s+=this.renderPolygon(o,e,r),r.type!=="solid"&&r.type!=="glass")){const a=this.hatchGenerator.generateHatch(o,i);for(const l of a.lines)s+=this.renderHatchLine(l,e,r)}}return s+=` </g>
|
|
43
|
-
`,s}renderPolygon(t,e,i){const s=this.polygonToPath(t.polygon,e);let o;return i.type==="solid"?o=i.fillColor||"#CCCCCC":i.type==="glass"?o=i.fillColor||"rgba(200, 230, 255, 0.3)":i.type==="none"?o="none":o=`url(#hatch-${i.type})`,` <path d="${s}" fill="${o}"
|
|
44
|
-
stroke="${i.strokeColor}" stroke-width="${i.lineWeight}"
|
|
45
|
-
data-entity-id="${t.entityId}" data-ifc-type="${t.ifcType}"/>
|
|
46
|
-
`}polygonToPath(t,e){let i="";if(t.outer.length>0){const s=this.transformPoint(t.outer[0],e);i+=`M ${s.x.toFixed(3)} ${s.y.toFixed(3)}`;for(let o=1;o<t.outer.length;o++){const r=this.transformPoint(t.outer[o],e);i+=` L ${r.x.toFixed(3)} ${r.y.toFixed(3)}`}i+=" Z"}for(const s of t.holes)if(s.length>0){const o=this.transformPoint(s[0],e);i+=` M ${o.x.toFixed(3)} ${o.y.toFixed(3)}`;for(let r=1;r<s.length;r++){const a=this.transformPoint(s[r],e);i+=` L ${a.x.toFixed(3)} ${a.y.toFixed(3)}`}i+=" Z"}return i}renderHatchLine(t,e,i){const s=this.transformPoint(t.line.start,e),o=this.transformPoint(t.line.end,e);return` <line x1="${s.x.toFixed(3)}" y1="${s.y.toFixed(3)}" x2="${o.x.toFixed(3)}" y2="${o.y.toFixed(3)}"
|
|
47
|
-
stroke="${i.strokeColor}" stroke-width="${i.lineWeight}" stroke-linecap="butt"/>
|
|
48
|
-
`}createTitleBlock(t,e,i,s){const a=t.width-180-10,l=t.height-50-10;return` <g id="title-block">
|
|
49
|
-
<rect x="${a}" y="${l}" width="180" height="50"
|
|
50
|
-
fill="white" stroke="black" stroke-width="0.5"/>
|
|
51
|
-
<line x1="${a}" y1="${l+20}" x2="${a+180}" y2="${l+20}" stroke="black" stroke-width="0.3"/>
|
|
52
|
-
<line x1="${a}" y1="${l+35}" x2="${a+180}" y2="${l+35}" stroke="black" stroke-width="0.3"/>
|
|
53
|
-
<line x1="${a+100}" y1="${l+20}" x2="${a+100}" y2="${l+50}" stroke="black" stroke-width="0.3"/>
|
|
54
|
-
<text x="${a+5}" y="${l+14}" font-family="Arial" font-size="10" font-weight="bold">${this.escapeXml(e)}</text>
|
|
55
|
-
<text x="${a+5}" y="${l+30}" font-family="Arial" font-size="8">${this.escapeXml(i)}</text>
|
|
56
|
-
<text x="${a+5}" y="${l+45}" font-family="Arial" font-size="8">Scale: ${s.name}</text>
|
|
57
|
-
<text x="${a+105}" y="${l+30}" font-family="Arial" font-size="7">Date:</text>
|
|
58
|
-
<text x="${a+105}" y="${l+45}" font-family="Arial" font-size="7">${new Date().toLocaleDateString()}</text>
|
|
59
|
-
</g>
|
|
60
|
-
`}escapeXml(t){return t.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'")}}const ee=`
|
|
61
|
-
struct Triangle {
|
|
62
|
-
v0: vec3<f32>,
|
|
63
|
-
v1: vec3<f32>,
|
|
64
|
-
v2: vec3<f32>,
|
|
65
|
-
entityId: u32,
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
struct Plane {
|
|
69
|
-
normal: vec3<f32>,
|
|
70
|
-
distance: f32,
|
|
71
|
-
// Projection axes for 2D output
|
|
72
|
-
axisU: u32, // 0=x, 1=y, 2=z
|
|
73
|
-
axisV: u32,
|
|
74
|
-
flipU: f32, // 1.0 or -1.0
|
|
75
|
-
_padding: f32,
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
struct Segment {
|
|
79
|
-
p0_3d: vec3<f32>,
|
|
80
|
-
_pad0: f32,
|
|
81
|
-
p1_3d: vec3<f32>,
|
|
82
|
-
_pad1: f32,
|
|
83
|
-
p0_2d: vec2<f32>,
|
|
84
|
-
p1_2d: vec2<f32>,
|
|
85
|
-
entityId: u32,
|
|
86
|
-
valid: u32,
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
@group(0) @binding(0) var<storage, read> triangles: array<Triangle>;
|
|
90
|
-
@group(0) @binding(1) var<uniform> plane: Plane;
|
|
91
|
-
@group(0) @binding(2) var<storage, read_write> segments: array<Segment>;
|
|
92
|
-
@group(0) @binding(3) var<storage, read_write> segmentCount: atomic<u32>;
|
|
93
|
-
|
|
94
|
-
const EPSILON: f32 = 1e-7;
|
|
95
|
-
|
|
96
|
-
fn signedDistance(point: vec3<f32>) -> f32 {
|
|
97
|
-
return dot(point, plane.normal) - plane.distance;
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
fn edgeIntersection(v0: vec3<f32>, v1: vec3<f32>, d0: f32, d1: f32) -> vec3<f32> {
|
|
101
|
-
let t = d0 / (d0 - d1);
|
|
102
|
-
return mix(v0, v1, t);
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
fn projectTo2D(p: vec3<f32>) -> vec2<f32> {
|
|
106
|
-
var coords: array<f32, 3>;
|
|
107
|
-
coords[0] = p.x;
|
|
108
|
-
coords[1] = p.y;
|
|
109
|
-
coords[2] = p.z;
|
|
110
|
-
|
|
111
|
-
let u = coords[plane.axisU] * plane.flipU;
|
|
112
|
-
let v = coords[plane.axisV];
|
|
113
|
-
return vec2<f32>(u, v);
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
@compute @workgroup_size(64)
|
|
117
|
-
fn main(@builtin(global_invocation_id) id: vec3<u32>) {
|
|
118
|
-
let triIdx = id.x;
|
|
119
|
-
if (triIdx >= arrayLength(&triangles)) {
|
|
120
|
-
return;
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
let tri = triangles[triIdx];
|
|
124
|
-
|
|
125
|
-
// Signed distances from plane
|
|
126
|
-
let d0 = signedDistance(tri.v0);
|
|
127
|
-
let d1 = signedDistance(tri.v1);
|
|
128
|
-
let d2 = signedDistance(tri.v2);
|
|
129
|
-
|
|
130
|
-
// Check for intersection
|
|
131
|
-
let pos = u32(d0 > EPSILON) + u32(d1 > EPSILON) + u32(d2 > EPSILON);
|
|
132
|
-
let neg = u32(d0 < -EPSILON) + u32(d1 < -EPSILON) + u32(d2 < -EPSILON);
|
|
133
|
-
|
|
134
|
-
// No intersection if all on same side
|
|
135
|
-
if (pos == 3u || neg == 3u || (pos == 0u && neg == 0u)) {
|
|
136
|
-
return;
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
// Find intersection points
|
|
140
|
-
var points: array<vec3<f32>, 2>;
|
|
141
|
-
var count: u32 = 0u;
|
|
142
|
-
|
|
143
|
-
// Edge v0-v1
|
|
144
|
-
if ((d0 > EPSILON) != (d1 > EPSILON)) {
|
|
145
|
-
points[count] = edgeIntersection(tri.v0, tri.v1, d0, d1);
|
|
146
|
-
count = count + 1u;
|
|
147
|
-
} else if (abs(d0) < EPSILON) {
|
|
148
|
-
points[count] = tri.v0;
|
|
149
|
-
count = count + 1u;
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
// Edge v1-v2
|
|
153
|
-
if ((d1 > EPSILON) != (d2 > EPSILON)) {
|
|
154
|
-
points[count] = edgeIntersection(tri.v1, tri.v2, d1, d2);
|
|
155
|
-
count = count + 1u;
|
|
156
|
-
} else if (abs(d1) < EPSILON && count < 2u) {
|
|
157
|
-
points[count] = tri.v1;
|
|
158
|
-
count = count + 1u;
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
// Edge v2-v0
|
|
162
|
-
if (count < 2u) {
|
|
163
|
-
if ((d2 > EPSILON) != (d0 > EPSILON)) {
|
|
164
|
-
points[count] = edgeIntersection(tri.v2, tri.v0, d2, d0);
|
|
165
|
-
count = count + 1u;
|
|
166
|
-
} else if (abs(d2) < EPSILON && count < 2u) {
|
|
167
|
-
points[count] = tri.v2;
|
|
168
|
-
count = count + 1u;
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
if (count >= 2u) {
|
|
173
|
-
// Project to 2D
|
|
174
|
-
let p0_2d = projectTo2D(points[0]);
|
|
175
|
-
let p1_2d = projectTo2D(points[1]);
|
|
176
|
-
|
|
177
|
-
// Skip degenerate segments
|
|
178
|
-
let diff = p1_2d - p0_2d;
|
|
179
|
-
if (dot(diff, diff) < EPSILON * EPSILON) {
|
|
180
|
-
return;
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
// Atomically allocate output slot
|
|
184
|
-
let outIdx = atomicAdd(&segmentCount, 1u);
|
|
185
|
-
|
|
186
|
-
segments[outIdx].p0_3d = points[0];
|
|
187
|
-
segments[outIdx].p1_3d = points[1];
|
|
188
|
-
segments[outIdx].p0_2d = p0_2d;
|
|
189
|
-
segments[outIdx].p1_2d = p1_2d;
|
|
190
|
-
segments[outIdx].entityId = tri.entityId;
|
|
191
|
-
segments[outIdx].valid = 1u;
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
`;class ne{device;resources=null;constructor(t){this.device=t}async initialize(t){const e=t,i=this.device.createShaderModule({code:ee}),s=this.device.createComputePipeline({layout:"auto",compute:{module:i,entryPoint:"main"}}),o=t*48,r=this.device.createBuffer({size:o,usage:GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_DST}),a=this.device.createBuffer({size:32,usage:GPUBufferUsage.UNIFORM|GPUBufferUsage.COPY_DST}),l=e*64,c=this.device.createBuffer({size:l,usage:GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_SRC}),u=this.device.createBuffer({size:4,usage:GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_DST|GPUBufferUsage.COPY_SRC}),h=this.device.createBuffer({size:l,usage:GPUBufferUsage.MAP_READ|GPUBufferUsage.COPY_DST}),d=this.device.createBuffer({size:4,usage:GPUBufferUsage.MAP_READ|GPUBufferUsage.COPY_DST}),f=this.device.createBindGroup({layout:s.getBindGroupLayout(0),entries:[{binding:0,resource:{buffer:r}},{binding:1,resource:{buffer:a}},{binding:2,resource:{buffer:c}},{binding:3,resource:{buffer:u}}]});this.resources={pipeline:s,triangleBuffer:r,planeBuffer:a,segmentBuffer:c,countBuffer:u,readbackBuffer:h,countReadbackBuffer:d,bindGroup:f,maxTriangles:t,maxSegments:e}}async cutMeshes(t,e){if(!this.resources)throw new Error("GPU resources not initialized. Call initialize() first.");const i=this.collectTriangles(t),s=i.count;if(s===0)return[];s>this.resources.maxTriangles&&await this.initialize(s*2);const o=this.resources;if(!o)throw new Error("GPU resources became unavailable after initialization");this.device.queue.writeBuffer(o.triangleBuffer,0,i.buffer.buffer,i.buffer.byteOffset,i.buffer.byteLength);const r=this.createPlaneData(e);this.device.queue.writeBuffer(o.planeBuffer,0,r.buffer,r.byteOffset,r.byteLength),this.device.queue.writeBuffer(o.countBuffer,0,new Uint32Array([0]));const a=this.device.createCommandEncoder(),l=a.beginComputePass();l.setPipeline(o.pipeline),l.setBindGroup(0,o.bindGroup);const c=Math.ceil(s/64);l.dispatchWorkgroups(c),l.end(),a.copyBufferToBuffer(o.countBuffer,0,o.countReadbackBuffer,0,4),this.device.queue.submit([a.finish()]),await o.countReadbackBuffer.mapAsync(GPUMapMode.READ);const h=new Uint32Array(o.countReadbackBuffer.getMappedRange())[0];if(o.countReadbackBuffer.unmap(),h===0)return[];const d=this.device.createCommandEncoder();d.copyBufferToBuffer(o.segmentBuffer,0,o.readbackBuffer,0,h*64),this.device.queue.submit([d.finish()]),await o.readbackBuffer.mapAsync(GPUMapMode.READ);const f=new Float32Array(o.readbackBuffer.getMappedRange(0,h*64)),g=this.parseSegments(f,h,i.entityMap);return o.readbackBuffer.unmap(),g}collectTriangles(t){let e=0;for(const a of t)e+=a.indices.length/3;const i=new Float32Array(e*12),s=new Map;let o=0,r=0;for(const a of t){const{positions:l,indices:c,expressId:u,ifcType:h,modelIndex:d}=a,f=c.length/3;s.set(r,{entityId:u,ifcType:h||"Unknown",modelIndex:d||0});for(let g=0;g<f;g++){const y=c[g*3],p=c[g*3+1],m=c[g*3+2],I=o*12;i[I+0]=l[y*3],i[I+1]=l[y*3+1],i[I+2]=l[y*3+2],i[I+3]=l[p*3],i[I+4]=l[p*3+1],i[I+5]=l[p*3+2],i[I+6]=l[m*3],i[I+7]=l[m*3+1],i[I+8]=l[m*3+2],new DataView(i.buffer,(I+9)*4,4).setUint32(0,r,!0),i[I+10]=0,i[I+11]=0,o++}r++}return{buffer:i,count:e,entityMap:s}}createPlaneData(t){const e=ct(t.axis,t.flipped),i=ht(t.axis),s={x:0,y:1,z:2},o=new Float32Array(8);o[0]=e.x,o[1]=e.y,o[2]=e.z,o[3]=t.position;const r=new DataView(o.buffer);return r.setUint32(16,s[i.u],!0),r.setUint32(20,s[i.v],!0),o[6]=t.flipped?-1:1,o[7]=0,o}parseSegments(t,e,i){const s=[];for(let o=0;o<e;o++){const r=o*16;if(new DataView(t.buffer,(r+14)*4,4).getUint32(0,!0)!==1)continue;const l=new DataView(t.buffer,(r+13)*4,4).getUint32(0,!0),c=i.get(l)||{entityId:0,ifcType:"Unknown",modelIndex:0};s.push({p0:{x:t[r+0],y:t[r+1],z:t[r+2]},p1:{x:t[r+4],y:t[r+5],z:t[r+6]},p0_2d:{x:t[r+8],y:t[r+9]},p1_2d:{x:t[r+10],y:t[r+11]},entityId:c.entityId,ifcType:c.ifcType,modelIndex:c.modelIndex})}return s}destroy(){this.resources&&(this.resources.triangleBuffer.destroy(),this.resources.planeBuffer.destroy(),this.resources.segmentBuffer.destroy(),this.resources.countBuffer.destroy(),this.resources.readbackBuffer.destroy(),this.resources.countReadbackBuffer.destroy(),this.resources=null)}}const ie={useGPU:!0,includeHiddenLines:!0,includeProjection:!0,includeEdges:!0,mergeLines:!0};class ke{gpuCutter=null;cpuCutter=null;polygonBuilder=new gt;edgeExtractor=new Ut(30);hiddenLineClassifier=new Jt({resolution:1024});hatchGenerator=new xt;svgExporter=new te;gpuDevice=null;initialized=!1;async initialize(t){t&&(this.gpuDevice=t,this.gpuCutter=new ne(t),await this.gpuCutter.initialize(1e5)),this.initialized=!0}async generate(t,e,i={},s){const o={...ie,...i},r=performance.now(),a=(x,C)=>{o.onProgress?.(x,C)};a("cutting",0);let l;o.useGPU&&this.gpuCutter&&this.gpuDevice?l=await this.gpuCutter.cutMeshes(t,e.plane):((!this.cpuCutter||this.cpuCutter===null)&&(this.cpuCutter=new Dt(e.plane)),l=this.cpuCutter.cutMeshes(t).segments),a("cutting",1),a("polygons",0);const c=this.polygonBuilder.buildPolygons(l);a("polygons",1);const u=l.map(x=>({line:{start:x.p0_2d,end:x.p1_2d},category:"cut",visibility:"visible",entityId:x.entityId,ifcType:x.ifcType,modelIndex:x.modelIndex,depth:0}));let h=[],d=[];if(o.includeProjection||o.includeEdges){if(a("edges",0),s&&s.length>0&&o.includeProjection&&(h=Gt(s,e.plane,e.projectionDepth)),o.includeEdges){const C=this.edgeExtractor.extractEdgesFromMeshes(t),b=this.edgeExtractor.filterEdgesByDepth(C,e.plane.axis,e.plane.position,e.projectionDepth,e.plane.flipped),A=jt(e.plane.axis,e.plane.flipped),M=this.edgeExtractor.extractSilhouettes(b,A);if(d=this.edgeExtractor.edgesToDrawingLines(M,e.plane.axis,e.plane.flipped,"silhouette",e.plane.position),o.includeProjection){const P=new Set((s??[]).map(L=>W(L.modelIndex,L.expressId))),E=b.filter(L=>L.type!=="crease"||M.includes(L)?!1:P.size===0?!0:!P.has(W(L.modelIndex,L.entityId)));h=[...h,...this.edgeExtractor.edgesToDrawingLines(E,e.plane.axis,e.plane.flipped,"projection",e.plane.position)]}}else if(o.includeProjection){const C=new Set((s??[]).map(P=>W(P.modelIndex,P.expressId))),b=this.edgeExtractor.extractEdgesFromMeshes(t),M=this.edgeExtractor.filterEdgesByDepth(b,e.plane.axis,e.plane.position,e.projectionDepth,e.plane.flipped).filter(P=>P.type!=="crease"?!1:C.size===0?!0:!C.has(W(P.modelIndex,P.entityId)));h=[...h,...this.edgeExtractor.edgesToDrawingLines(M,e.plane.axis,e.plane.flipped,"projection",e.plane.position)]}const x=this.computeBounds(u);if(x.min.x<x.max.x&&x.min.y<x.max.y){const C=x.max.x-x.min.x,b=x.max.y-x.min.y,M=Math.sqrt(C*C+b*b)*1.5;d=d.filter(P=>tt(P.line)<=M),h=h.filter(P=>tt(P.line)<=M)}a("edges",1)}let f=[...u,...h,...d];if(o.includeHiddenLines&&(h.length>0||d.length>0)){a("hidden",0);const x=this.computeBounds(f);this.hiddenLineClassifier.buildDepthBuffer(t,e.plane.axis,e.plane.position,e.projectionDepth,e.plane.flipped,x);const C=f.filter(A=>A.category!=="cut"),b=this.hiddenLineClassifier.applyVisibility(C);f=[...u,...b],a("hidden",1)}o.mergeLines&&(a("merging",0),f=Wt(f),a("merging",1));const g=this.computeBounds(f),y=performance.now()-r,p=f.filter(x=>x.category==="cut").length,m=f.filter(x=>x.category==="projection").length,I=f.filter(x=>x.visibility==="hidden").length,w=f.filter(x=>x.category==="silhouette").length;return a("complete",1),{config:e,lines:f,cutPolygons:c,projectionPolygons:[],bounds:g,stats:{cutLineCount:p,projectionLineCount:m,hiddenLineCount:I,silhouetteLineCount:w,polygonCount:c.length,totalTriangles:t.reduce((x,C)=>x+C.indices.length/3,0),processingTimeMs:y}}}exportSVG(t,e){return this.svgExporter.export(t,e)}generateHatching(t){const e=this.hatchGenerator.generateHatches(t.cutPolygons,t.config.scale),i=[];for(const s of e)for(const o of s.lines)i.push({line:o.line,category:"annotation",visibility:"visible",entityId:o.entityId,ifcType:o.ifcType,modelIndex:o.modelIndex,depth:0});return i}computeBounds(t){let e=lt();for(const i of t)e=Et(e,i.line);return e}dispose(){this.gpuCutter&&(this.gpuCutter.destroy(),this.gpuCutter=null),this.gpuDevice=null,this.initialized=!1}}function ve(n,t,e={}){return{plane:{axis:n,position:t,flipped:!1},...wt,...e}}const oe={heavy:.5,medium:.35,light:.25,hairline:.18},rt={solid:[],dashed:[2,1],dotted:[.5,.5],dashdot:[3,1,.5,1],center:[6,1,1,1]},k={fillColor:"#CCCCCC",strokeColor:"#000000",backgroundColor:"#FFFFFF",lineWeight:.25,lineCap:"round",lineJoin:"round",dashPattern:[],hatchPattern:"none",hatchSpacing:3,hatchAngle:45,hatchSecondaryAngle:-45,hatchColor:"#000000",hatchLineWeight:.13,visible:!0,opacity:1,drawOrder:0},se={IfcWall:["IfcWallStandardCase","IfcWallElementedCase"],IfcSlab:["IfcSlabStandardCase","IfcSlabElementedCase"],IfcBeam:["IfcBeamStandardCase"],IfcColumn:["IfcColumnStandardCase"],IfcDoor:["IfcDoorStandardCase"],IfcWindow:["IfcWindowStandardCase"],IfcMember:["IfcMemberStandardCase"],IfcPlate:["IfcPlateStandardCase"],IfcStair:["IfcStairFlight"],IfcRamp:["IfcRampFlight"],IfcBuildingElement:["IfcWall","IfcSlab","IfcBeam","IfcColumn","IfcDoor","IfcWindow","IfcStair","IfcRamp","IfcRoof","IfcRailing","IfcCovering"],IfcDistributionElement:["IfcDistributionFlowElement","IfcDistributionControlElement"],IfcFlowElement:["IfcFlowTerminal","IfcFlowSegment","IfcFlowFitting","IfcFlowController"]};function Ct(n){const t=se[n]||[],e=[...t];for(const i of t)e.push(...Ct(i));return e}function re(n,t,e){switch(t){case"equals":return n===e;case"notEquals":return n!==e;case"contains":return typeof n=="string"&&typeof e=="string"?n.toLowerCase().includes(e.toLowerCase()):!1;case"notContains":return typeof n=="string"&&typeof e=="string"?!n.toLowerCase().includes(e.toLowerCase()):!0;case"startsWith":return typeof n=="string"&&typeof e=="string"?n.toLowerCase().startsWith(e.toLowerCase()):!1;case"endsWith":return typeof n=="string"&&typeof e=="string"?n.toLowerCase().endsWith(e.toLowerCase()):!1;case"greaterThan":return typeof n=="number"&&typeof e=="number"?n>e:!1;case"lessThan":return typeof n=="number"&&typeof e=="number"?n<e:!1;case"greaterOrEqual":return typeof n=="number"&&typeof e=="number"?n>=e:!1;case"lessOrEqual":return typeof n=="number"&&typeof e=="number"?n<=e:!1;case"exists":return n!=null;case"notExists":return n==null;case"in":return Array.isArray(e)?e.includes(n):!1;case"notIn":return Array.isArray(e)?!e.includes(n):!0;default:return!1}}function ae(n,t){switch(n.type){case"all":return!0;case"ifcType":return!n.ifcTypes||n.ifcTypes.length===0?!0:(n.includeSubtypes?n.ifcTypes.flatMap(i=>[i,...Ct(i)]):n.ifcTypes).some(i=>i.toLowerCase()===t.ifcType.toLowerCase());case"property":{if(!n.propertyName)return!1;const e=n.operator||"equals";let i;if(n.propertySet&&t.properties)i=t.properties[n.propertySet]?.[n.propertyName];else if(t.properties){for(const s of Object.values(t.properties))if(n.propertyName in s){i=s[n.propertyName];break}}return re(i,e,n.value)}case"propertySet":{if(!n.propertySet||!t.properties)return n.operator==="notExists";const e=n.propertySet in t.properties,i=n.operator||"exists";return i==="exists"?e:i==="notExists"?!e:e}case"material":return!n.materialNames||!t.materials?!1:n.materialNames.some(e=>t.materials.some(i=>i.toLowerCase().includes(e.toLowerCase())));case"layer":return!n.layerNames||!t.layers?!1:n.layerNames.some(e=>t.layers.some(i=>i.toLowerCase().includes(e.toLowerCase())));case"expressId":return n.expressIds?n.expressIds.includes(t.expressId):!1;case"modelId":return!n.modelIds||!t.modelId?!1:n.modelIds.includes(t.modelId);default:return!1}}function It(n){return"logic"in n&&"conditions"in n}function j(n,t){if(It(n)){const e=n.conditions.map(i=>j(i,t));return n.logic==="and"?e.every(Boolean):e.some(Boolean)}return ae(n,t)}function le(n){if(n===void 0)return k.lineWeight;if(typeof n=="number")return n;const t=oe[n];return t!==void 0?t:k.lineWeight}function ce(n){return n===void 0?k.dashPattern:typeof n=="string"?rt[n]??k.dashPattern:n.custom?n.custom:n.preset?rt[n.preset]??k.dashPattern:k.dashPattern}function at(n,t){return{fillColor:t.fillColor??n.fillColor,strokeColor:t.strokeColor??n.strokeColor,backgroundColor:t.backgroundColor??n.backgroundColor,lineWeight:t.lineWeight!==void 0?le(t.lineWeight):n.lineWeight,lineCap:t.lineCap??n.lineCap,lineJoin:t.lineJoin??n.lineJoin,dashPattern:t.lineStyle?ce(t.lineStyle):n.dashPattern,hatchPattern:t.hatchPattern??n.hatchPattern,hatchSpacing:t.hatchSpacing??n.hatchSpacing,hatchAngle:t.hatchAngle??n.hatchAngle,hatchSecondaryAngle:t.hatchSecondaryAngle??n.hatchSecondaryAngle,hatchColor:t.hatchColor??n.hatchColor,hatchLineWeight:t.hatchLineWeight??n.hatchLineWeight,visible:t.visible??n.visible,opacity:t.opacity??n.opacity,drawOrder:t.drawOrder??n.drawOrder}}class bt{rules=[];constructor(t){t&&this.setRules(t)}setRules(t){this.rules=[...t].sort((e,i)=>e.priority-i.priority)}addRule(t){this.rules.push(t),this.rules.sort((e,i)=>e.priority-i.priority)}removeRule(t){this.rules=this.rules.filter(e=>e.id!==t)}getRules(){return[...this.rules]}applyOverrides(t,e){let i=e?at(k,e):{...k};const s=[];for(const o of this.rules)o.enabled&&j(o.criteria,t)&&(i=at(i,o.style),s.push(o));return{element:t,style:i,matchedRules:s}}applyOverridesToMany(t,e){const i=new Map;for(const s of t){const o=e?.get(s.expressId);i.set(s.expressId,this.applyOverrides(s,o))}return i}getMatchingRules(t){return this.rules.filter(e=>e.enabled&&j(e.criteria,t))}static validateCriteria(t){const e=[];if(It(t)){(!t.conditions||t.conditions.length===0)&&e.push("Compound criteria must have at least one condition");for(const i of t.conditions)e.push(...bt.validateCriteria(i))}else t.type||e.push("Criterion must have a type"),t.type==="property"&&!t.propertyName&&e.push("Property criterion requires propertyName"),t.type==="ifcType"&&(!t.ifcTypes||t.ifcTypes.length===0)&&e.push("IFC type criterion requires at least one type");return e}}function S(n,t=!0){return{type:"ifcType",ifcTypes:n,includeSubtypes:t}}function v(n,t,e,i){return{type:"property",propertyName:n,propertySet:i,operator:t,value:e}}function T(...n){return{logic:"and",conditions:n}}let he=0;function de(){return`builtin-rule-${++he}`}function F(n,t,e,i=100,s){return{id:de(),name:n,description:s,enabled:!0,priority:i,criteria:t,style:e}}const ue=[F("Walls - Heavy cut lines",S(["IfcWall"]),{lineWeight:"heavy",strokeColor:"#000000",hatchPattern:"diagonal",hatchSpacing:3,hatchAngle:45},100,"Standard wall representation"),F("Columns - Heavy cut lines",S(["IfcColumn"]),{lineWeight:"heavy",strokeColor:"#000000",hatchPattern:"cross-hatch",hatchSpacing:2},100),F("Slabs - Medium lines",S(["IfcSlab"]),{lineWeight:"medium",fillColor:"#E0E0E0",hatchPattern:"concrete"},90),F("Windows - Light blue tint",S(["IfcWindow"]),{lineWeight:"light",fillColor:"#E3F2FD",strokeColor:"#1976D2",hatchPattern:"none"},80),F("Doors - No fill",S(["IfcDoor"]),{lineWeight:"medium",fillColor:"#FFFFFF",strokeColor:"#000000",hatchPattern:"none"},80),F("Furniture - Hairline",S(["IfcFurnishingElement","IfcFurniture"]),{lineWeight:"hairline",strokeColor:"#666666",fillColor:"#F5F5F5",hatchPattern:"none"},60)],fe={id:"preset-architectural",name:"Architectural Standards",description:"ISO 128 compliant architectural drawing standards",icon:"PenTool",rules:ue,builtIn:!0,category:"Standards"},ge=[F("Fire Rated 2hr+ - Red",T(S(["IfcWall"]),v("FireRating","greaterOrEqual",120)),{fillColor:"#FFCDD2",strokeColor:"#C62828",lineWeight:"heavy",hatchPattern:"diagonal",hatchColor:"#C62828"},200,"2-hour or higher fire rating"),F("Fire Rated 1hr - Orange",T(S(["IfcWall"]),v("FireRating","greaterOrEqual",60)),{fillColor:"#FFE0B2",strokeColor:"#E65100",lineWeight:"heavy",hatchPattern:"diagonal",hatchColor:"#E65100"},190),F("Fire Rated 30min - Yellow",T(S(["IfcWall"]),v("FireRating","greaterOrEqual",30)),{fillColor:"#FFF9C4",strokeColor:"#F9A825",lineWeight:"medium",hatchPattern:"diagonal",hatchColor:"#F9A825"},180),F("Fire Doors - Red outline",T(S(["IfcDoor"]),v("FireRating","exists")),{strokeColor:"#C62828",lineWeight:"heavy"},200),F("Escape Routes - Green",T(S(["IfcSpace"]),v("OccupancyType","contains","CIRCULATION")),{fillColor:"#C8E6C9",strokeColor:"#2E7D32",lineWeight:"light"},150)],pe={id:"preset-fire-safety",name:"Fire Safety",description:"Highlight fire-rated elements and escape routes",icon:"Flame",rules:ge,builtIn:!0,category:"Safety"},ye=[F("Load-bearing Walls - Blue",T(S(["IfcWall"]),v("LoadBearing","equals",!0)),{fillColor:"#BBDEFB",strokeColor:"#1565C0",lineWeight:"heavy",hatchPattern:"diagonal",hatchColor:"#1565C0"},200),F("Columns - Blue heavy",S(["IfcColumn"]),{fillColor:"#90CAF9",strokeColor:"#0D47A1",lineWeight:"heavy",hatchPattern:"cross-hatch",hatchColor:"#0D47A1"},190),F("Beams - Blue medium",S(["IfcBeam"]),{fillColor:"#64B5F6",strokeColor:"#1976D2",lineWeight:"medium",hatchPattern:"diagonal"},180),F("Slabs - Light blue",S(["IfcSlab"]),{fillColor:"#E3F2FD",strokeColor:"#42A5F5",lineWeight:"medium"},170),F("Footings - Dark blue",S(["IfcFooting","IfcPile"]),{fillColor:"#1976D2",strokeColor:"#0D47A1",lineWeight:"heavy",hatchPattern:"concrete"},200),F("Non-structural - Faded",S(["IfcFurnishingElement","IfcFurniture","IfcCovering"]),{opacity:.3,lineWeight:"hairline"},50)],me={id:"preset-structural",name:"Structural Highlight",description:"Emphasize structural elements, fade non-structural",icon:"Building2",rules:ye,builtIn:!0,category:"Discipline"},xe=[F("HVAC Ducts - Blue",S(["IfcDuctSegment","IfcDuctFitting"]),{fillColor:"#E3F2FD",strokeColor:"#1976D2",lineWeight:"medium"},150),F("Air Terminals - Blue",S(["IfcAirTerminal","IfcAirTerminalBox"]),{fillColor:"#BBDEFB",strokeColor:"#1565C0",lineWeight:"light"},140),F("Pipes - Green",S(["IfcPipeSegment","IfcPipeFitting"]),{fillColor:"#E8F5E9",strokeColor:"#388E3C",lineWeight:"medium"},150),F("Plumbing Fixtures - Green",S(["IfcSanitaryTerminal","IfcWasteTerminal"]),{fillColor:"#C8E6C9",strokeColor:"#2E7D32",lineWeight:"light"},140),F("Cable Trays - Orange",S(["IfcCableCarrierSegment","IfcCableCarrierFitting"]),{fillColor:"#FFF3E0",strokeColor:"#E65100",lineWeight:"light"},150),F("Electrical Equipment - Yellow",S(["IfcElectricDistributionBoard","IfcSwitchingDevice","IfcOutlet"]),{fillColor:"#FFFDE7",strokeColor:"#F9A825",lineWeight:"light"},140),F("Architectural - Faded",S(["IfcWall","IfcSlab","IfcDoor","IfcWindow"]),{opacity:.4,strokeColor:"#9E9E9E"},50)],Ce={id:"preset-mep",name:"MEP Highlight",description:"Color-code mechanical, electrical, and plumbing systems",icon:"Wrench",rules:xe,builtIn:!0,category:"Discipline"},Ie={id:"preset-3d-colors",name:"Default",description:"By material color",icon:"Palette",rules:[],builtIn:!0,category:"Standards"},be=[F("All elements - Black and white",{type:"all"},{strokeColor:"#000000",fillColor:"#FFFFFF",hatchColor:"#000000"},1),F("Cut elements - Gray fill",S(["IfcWall","IfcColumn","IfcSlab","IfcBeam"]),{fillColor:"#E0E0E0"},10)],Me={id:"preset-monochrome",name:"Monochrome",description:"Black and white print-ready output",icon:"Printer",rules:be,builtIn:!0,category:"Output"},Te=[Ie,fe,pe,me,Ce,Me],Re={A0_LANDSCAPE:{id:"A0_LANDSCAPE",name:"A0 Landscape",category:"ISO",widthMm:1189,heightMm:841,orientation:"landscape",defaultMarginMm:20},A0_PORTRAIT:{id:"A0_PORTRAIT",name:"A0 Portrait",category:"ISO",widthMm:841,heightMm:1189,orientation:"portrait",defaultMarginMm:20},A1_LANDSCAPE:{id:"A1_LANDSCAPE",name:"A1 Landscape",category:"ISO",widthMm:841,heightMm:594,orientation:"landscape",defaultMarginMm:20},A1_PORTRAIT:{id:"A1_PORTRAIT",name:"A1 Portrait",category:"ISO",widthMm:594,heightMm:841,orientation:"portrait",defaultMarginMm:20},A2_LANDSCAPE:{id:"A2_LANDSCAPE",name:"A2 Landscape",category:"ISO",widthMm:594,heightMm:420,orientation:"landscape",defaultMarginMm:15},A2_PORTRAIT:{id:"A2_PORTRAIT",name:"A2 Portrait",category:"ISO",widthMm:420,heightMm:594,orientation:"portrait",defaultMarginMm:15},A3_LANDSCAPE:{id:"A3_LANDSCAPE",name:"A3 Landscape",category:"ISO",widthMm:420,heightMm:297,orientation:"landscape",defaultMarginMm:10},A3_PORTRAIT:{id:"A3_PORTRAIT",name:"A3 Portrait",category:"ISO",widthMm:297,heightMm:420,orientation:"portrait",defaultMarginMm:10},A4_LANDSCAPE:{id:"A4_LANDSCAPE",name:"A4 Landscape",category:"ISO",widthMm:297,heightMm:210,orientation:"landscape",defaultMarginMm:10},A4_PORTRAIT:{id:"A4_PORTRAIT",name:"A4 Portrait",category:"ISO",widthMm:210,heightMm:297,orientation:"portrait",defaultMarginMm:10},LETTER_LANDSCAPE:{id:"LETTER_LANDSCAPE",name:"US Letter Landscape",category:"ANSI",widthMm:279.4,heightMm:215.9,orientation:"landscape",defaultMarginMm:10},LETTER_PORTRAIT:{id:"LETTER_PORTRAIT",name:"US Letter Portrait",category:"ANSI",widthMm:215.9,heightMm:279.4,orientation:"portrait",defaultMarginMm:10},LEGAL_LANDSCAPE:{id:"LEGAL_LANDSCAPE",name:"US Legal Landscape",category:"ANSI",widthMm:355.6,heightMm:215.9,orientation:"landscape",defaultMarginMm:10},LEGAL_PORTRAIT:{id:"LEGAL_PORTRAIT",name:"US Legal Portrait",category:"ANSI",widthMm:215.9,heightMm:355.6,orientation:"portrait",defaultMarginMm:10},TABLOID_LANDSCAPE:{id:"TABLOID_LANDSCAPE",name:"US Tabloid Landscape",category:"ANSI",widthMm:431.8,heightMm:279.4,orientation:"landscape",defaultMarginMm:15},TABLOID_PORTRAIT:{id:"TABLOID_PORTRAIT",name:"US Tabloid Portrait",category:"ANSI",widthMm:279.4,heightMm:431.8,orientation:"portrait",defaultMarginMm:15},ANSI_C:{id:"ANSI_C",name:"ANSI C (17x22)",category:"ANSI",widthMm:558.8,heightMm:431.8,orientation:"landscape",defaultMarginMm:15},ANSI_D:{id:"ANSI_D",name:"ANSI D (22x34)",category:"ANSI",widthMm:863.6,heightMm:558.8,orientation:"landscape",defaultMarginMm:20},ANSI_E:{id:"ANSI_E",name:"ANSI E (34x44)",category:"ANSI",widthMm:1117.6,heightMm:863.6,orientation:"landscape",defaultMarginMm:20},ARCH_A:{id:"ARCH_A",name:"ARCH A (9x12)",category:"ARCH",widthMm:304.8,heightMm:228.6,orientation:"landscape",defaultMarginMm:10},ARCH_B:{id:"ARCH_B",name:"ARCH B (12x18)",category:"ARCH",widthMm:457.2,heightMm:304.8,orientation:"landscape",defaultMarginMm:15},ARCH_C:{id:"ARCH_C",name:"ARCH C (18x24)",category:"ARCH",widthMm:609.6,heightMm:457.2,orientation:"landscape",defaultMarginMm:15},ARCH_D:{id:"ARCH_D",name:"ARCH D (24x36)",category:"ARCH",widthMm:914.4,heightMm:609.6,orientation:"landscape",defaultMarginMm:20},ARCH_E:{id:"ARCH_E",name:"ARCH E (36x48)",category:"ARCH",widthMm:1219.2,heightMm:914.4,orientation:"landscape",defaultMarginMm:20},ARCH_E1:{id:"ARCH_E1",name:"ARCH E1 (30x42)",category:"ARCH",widthMm:1066.8,heightMm:762,orientation:"landscape",defaultMarginMm:20}},De={simple:{margins:{top:10,right:10,bottom:10,left:10,bindingMargin:0},border:{outerLineWeight:.7,innerLineWeight:.35,borderGap:0,showFoldMarks:!1,showTrimMarks:!1},showZoneReferences:!1,horizontalZones:0,verticalZones:0,zoneFontSize:3},professional:{margins:{top:10,right:10,bottom:10,left:20,bindingMargin:10},border:{outerLineWeight:.7,innerLineWeight:.35,borderGap:5,showFoldMarks:!0,showTrimMarks:!0},showZoneReferences:!0,horizontalZones:8,verticalZones:6,zoneFontSize:3.5},minimal:{margins:{top:5,right:5,bottom:5,left:5,bindingMargin:0},border:{outerLineWeight:.35,innerLineWeight:0,borderGap:0,showFoldMarks:!1,showTrimMarks:!1},showZoneReferences:!1,horizontalZones:0,verticalZones:0,zoneFontSize:3},iso:{margins:{top:10,right:10,bottom:10,left:20,bindingMargin:10},border:{outerLineWeight:.7,innerLineWeight:.35,borderGap:5,showFoldMarks:!0,showTrimMarks:!0},showZoneReferences:!0,horizontalZones:8,verticalZones:4,zoneFontSize:3.5},custom:{margins:{top:10,right:10,bottom:10,left:10,bindingMargin:0},border:{outerLineWeight:.5,innerLineWeight:.25,borderGap:3,showFoldMarks:!1,showTrimMarks:!1},showZoneReferences:!1,horizontalZones:0,verticalZones:0,zoneFontSize:3}},We=[{id:"project-name",label:"Project",value:"",editable:!0,autoPopulate:!0,autoPopulateSource:"project.name",fontSize:4.5,fontWeight:"bold",row:0,col:0,colSpan:2},{id:"drawing-title",label:"Drawing Title",value:"Section",editable:!0,autoPopulate:!1,fontSize:5,fontWeight:"bold",row:1,col:0,colSpan:2},{id:"drawing-number",label:"Drawing No.",value:"A-001",editable:!0,autoPopulate:!1,fontSize:4,fontWeight:"bold",row:2,col:0},{id:"revision",label:"Rev",value:"-",editable:!0,autoPopulate:!1,fontSize:3.5,fontWeight:"bold",row:2,col:1},{id:"scale",label:"Scale",value:"1:100",editable:!1,autoPopulate:!0,autoPopulateSource:"drawing.scale",fontSize:3.5,fontWeight:"normal",row:3,col:0},{id:"date",label:"Date",value:"",editable:!0,autoPopulate:!0,autoPopulateSource:"date.today",fontSize:3,fontWeight:"normal",row:3,col:1},{id:"drawn-by",label:"Drawn",value:"",editable:!0,autoPopulate:!1,fontSize:3,fontWeight:"normal",row:4,col:0},{id:"checked-by",label:"Checked",value:"",editable:!0,autoPopulate:!1,fontSize:3,fontWeight:"normal",row:4,col:1},{id:"sheet-number",label:"Sheet",value:"1 of 1",editable:!0,autoPopulate:!1,fontSize:3,fontWeight:"normal",row:5,col:0,colSpan:2}],_e={compact:{layout:"compact",position:"bottom-right",widthMm:120,heightMm:35,borderWeight:.5,gridWeight:.25,showRevisionHistory:!1,maxRevisionEntries:0},standard:{layout:"standard",position:"bottom-right",widthMm:180,heightMm:55,borderWeight:.5,gridWeight:.25,showRevisionHistory:!0,maxRevisionEntries:3},extended:{layout:"extended",position:"bottom-full",widthMm:0,heightMm:70,borderWeight:.5,gridWeight:.25,showRevisionHistory:!0,maxRevisionEntries:5},custom:{layout:"custom",position:"bottom-right",widthMm:180,heightMm:55,borderWeight:.5,gridWeight:.25,showRevisionHistory:!1,maxRevisionEntries:0}},ze={visible:!0,style:"alternating",position:"below-viewport",units:"metric",totalLengthM:5,primaryDivisions:5,subdivisions:2,heightMm:3,labelFontSize:2.5,showUnitLabel:!0,fillColor:"#000000",strokeColor:"#000000",lineWeight:.25};function Be(n,t){const i=Math.min(80,t*.8)*n/1e3,s=[.1,.2,.5,1,2,5,10,20,50,100,200,500,1e3];for(const o of s)if(o>=i*.5&&o<=i*1.5)return o;return Math.round(i)}const Ne={style:"simple",rotation:0,positionMm:{x:30,y:30},sizeMm:15};function Oe(n,t,e){const i=t.margins.left+t.margins.bindingMargin+t.border.borderGap,s=n.widthMm-t.margins.right-t.border.borderGap,o=t.margins.top+t.border.borderGap,r=n.heightMm-t.margins.bottom-t.border.borderGap;let a=i,l=o,c=s-i,u=r-o;const h=5;switch(e.position){case"bottom-right":u=r-o-e.heightMm-h;break;case"bottom-full":u=r-o-e.heightMm-h;break;case"right-strip":c=s-i-e.widthMm-h;break}return{x:a,y:l,width:c,height:u}}function He(n,t,e){const i=n.maxX-n.minX,s=n.maxY-n.minY,o=1e3/e.factor,r=i*o,a=s*o,l=.95,c=t.width*l/r,u=t.height*l/a,h=Math.min(c,u,1),d=o*h,f=i*d,g=s*d,y=t.x+(t.width-f)/2-n.minX*d,p=t.y+(t.height-g)/2+n.maxY*d;return{translateX:y,translateY:p,scaleFactor:d}}function Ue(n,t){let e=` <g id="drawing-frame">
|
|
195
|
-
`;const i=t.margins.left+t.margins.bindingMargin,s=t.margins.top,o=n.widthMm-t.margins.left-t.margins.right-t.margins.bindingMargin,r=n.heightMm-t.margins.top-t.margins.bottom;e+=` <rect x="${i.toFixed(2)}" y="${s.toFixed(2)}" `,e+=`width="${o.toFixed(2)}" height="${r.toFixed(2)}" `,e+=`fill="none" stroke="#000000" stroke-width="${t.border.outerLineWeight}"/>
|
|
196
|
-
`;let a=i,l=s,c=o,u=r;return t.border.borderGap>0&&t.border.innerLineWeight>0&&(a=i+t.border.borderGap,l=s+t.border.borderGap,c=o-2*t.border.borderGap,u=r-2*t.border.borderGap,e+=` <rect x="${a.toFixed(2)}" y="${l.toFixed(2)}" `,e+=`width="${c.toFixed(2)}" height="${u.toFixed(2)}" `,e+=`fill="none" stroke="#000000" stroke-width="${t.border.innerLineWeight}"/>
|
|
197
|
-
`),t.showZoneReferences&&t.horizontalZones>0&&(e+=we(i,s,o,r,t.border.borderGap,t.horizontalZones,t.verticalZones,t.zoneFontSize,t.border.innerLineWeight)),t.border.showFoldMarks&&(e+=Fe(n)),t.border.showTrimMarks&&(e+=Se(n)),e+=` </g>
|
|
198
|
-
`,{svgElements:e,innerBounds:{x:a,y:l,width:c,height:u}}}function we(n,t,e,i,s,o,r,a,l){let c=` <g id="zone-references">
|
|
199
|
-
`;const u=e/o,h=i/r,d="ABCDEFGHIJKLMNOPQRSTUVWXYZ";for(let f=0;f<o;f++){const g=n+u*(f+.5),y=d[f%26];if(c+=` <text x="${g.toFixed(2)}" y="${(t-s/2).toFixed(2)}" `,c+=`font-family="Arial, sans-serif" font-size="${a}" `,c+=`text-anchor="middle" dominant-baseline="middle">${y}</text>
|
|
200
|
-
`,c+=` <text x="${g.toFixed(2)}" y="${(t+i+s/2).toFixed(2)}" `,c+=`font-family="Arial, sans-serif" font-size="${a}" `,c+=`text-anchor="middle" dominant-baseline="middle">${y}</text>
|
|
201
|
-
`,f>0){const p=n+u*f;c+=` <line x1="${p.toFixed(2)}" y1="${t.toFixed(2)}" `,c+=`x2="${p.toFixed(2)}" y2="${(t-s+2).toFixed(2)}" `,c+=`stroke="#000000" stroke-width="${l}"/>
|
|
202
|
-
`,c+=` <line x1="${p.toFixed(2)}" y1="${(t+i).toFixed(2)}" `,c+=`x2="${p.toFixed(2)}" y2="${(t+i+s-2).toFixed(2)}" `,c+=`stroke="#000000" stroke-width="${l}"/>
|
|
203
|
-
`}}for(let f=0;f<r;f++){const g=t+h*(f+.5),y=(f+1).toString();if(c+=` <text x="${(n-s/2).toFixed(2)}" y="${g.toFixed(2)}" `,c+=`font-family="Arial, sans-serif" font-size="${a}" `,c+=`text-anchor="middle" dominant-baseline="middle">${y}</text>
|
|
204
|
-
`,c+=` <text x="${(n+e+s/2).toFixed(2)}" y="${g.toFixed(2)}" `,c+=`font-family="Arial, sans-serif" font-size="${a}" `,c+=`text-anchor="middle" dominant-baseline="middle">${y}</text>
|
|
205
|
-
`,f>0){const p=t+h*f;c+=` <line x1="${n.toFixed(2)}" y1="${p.toFixed(2)}" `,c+=`x2="${(n-s+2).toFixed(2)}" y2="${p.toFixed(2)}" `,c+=`stroke="#000000" stroke-width="${l}"/>
|
|
206
|
-
`,c+=` <line x1="${(n+e).toFixed(2)}" y1="${p.toFixed(2)}" `,c+=`x2="${(n+e+s-2).toFixed(2)}" y2="${p.toFixed(2)}" `,c+=`stroke="#000000" stroke-width="${l}"/>
|
|
207
|
-
`}}return c+=` </g>
|
|
208
|
-
`,c}function Fe(n,t,e,i,s){let o=` <g id="fold-marks">
|
|
209
|
-
`;if(n.heightMm>297){const u=Math.ceil(n.heightMm/297);for(let h=1;h<u;h++){const d=h*297;d<n.heightMm-20&&(o+=` <line x1="0" y1="${d.toFixed(2)}" x2="${5 .toFixed(2)}" y2="${d.toFixed(2)}" `,o+=`stroke="#000000" stroke-width="${.25}"/>
|
|
210
|
-
`,o+=` <line x1="${(n.widthMm-5).toFixed(2)}" y1="${d.toFixed(2)}" `,o+=`x2="${n.widthMm.toFixed(2)}" y2="${d.toFixed(2)}" `,o+=`stroke="#000000" stroke-width="${.25}"/>
|
|
211
|
-
`)}}if(n.widthMm>210){const u=Math.ceil(n.widthMm/210);for(let h=1;h<u;h++){const d=n.widthMm-h*210;d>20&&(o+=` <line x1="${d.toFixed(2)}" y1="0" x2="${d.toFixed(2)}" y2="${5 .toFixed(2)}" `,o+=`stroke="#000000" stroke-width="${.25}"/>
|
|
212
|
-
`,o+=` <line x1="${d.toFixed(2)}" y1="${(n.heightMm-5).toFixed(2)}" `,o+=`x2="${d.toFixed(2)}" y2="${n.heightMm.toFixed(2)}" `,o+=`stroke="#000000" stroke-width="${.25}"/>
|
|
213
|
-
`)}}return o+=` </g>
|
|
214
|
-
`,o}function Se(n){let t=` <g id="trim-marks">
|
|
215
|
-
`;return t+=` <line x1="${3 .toFixed(2)}" y1="0" x2="${3 .toFixed(2)}" y2="${8 .toFixed(2)}" `,t+=`stroke="#000000" stroke-width="${.15}"/>
|
|
216
|
-
`,t+=` <line x1="0" y1="${3 .toFixed(2)}" x2="${8 .toFixed(2)}" y2="${3 .toFixed(2)}" `,t+=`stroke="#000000" stroke-width="${.15}"/>
|
|
217
|
-
`,t+=` <line x1="${(n.widthMm-3).toFixed(2)}" y1="0" `,t+=`x2="${(n.widthMm-3).toFixed(2)}" y2="${8 .toFixed(2)}" `,t+=`stroke="#000000" stroke-width="${.15}"/>
|
|
218
|
-
`,t+=` <line x1="${(n.widthMm-8).toFixed(2)}" y1="${3 .toFixed(2)}" `,t+=`x2="${n.widthMm.toFixed(2)}" y2="${3 .toFixed(2)}" `,t+=`stroke="#000000" stroke-width="${.15}"/>
|
|
219
|
-
`,t+=` <line x1="${3 .toFixed(2)}" y1="${(n.heightMm-8).toFixed(2)}" `,t+=`x2="${3 .toFixed(2)}" y2="${n.heightMm.toFixed(2)}" `,t+=`stroke="#000000" stroke-width="${.15}"/>
|
|
220
|
-
`,t+=` <line x1="0" y1="${(n.heightMm-3).toFixed(2)}" `,t+=`x2="${8 .toFixed(2)}" y2="${(n.heightMm-3).toFixed(2)}" `,t+=`stroke="#000000" stroke-width="${.15}"/>
|
|
221
|
-
`,t+=` <line x1="${(n.widthMm-3).toFixed(2)}" y1="${(n.heightMm-8).toFixed(2)}" `,t+=`x2="${(n.widthMm-3).toFixed(2)}" y2="${n.heightMm.toFixed(2)}" `,t+=`stroke="#000000" stroke-width="${.15}"/>
|
|
222
|
-
`,t+=` <line x1="${(n.widthMm-8).toFixed(2)}" y1="${(n.heightMm-3).toFixed(2)}" `,t+=`x2="${n.widthMm.toFixed(2)}" y2="${(n.heightMm-3).toFixed(2)}" `,t+=`stroke="#000000" stroke-width="${.15}"/>
|
|
223
|
-
`,t+=` </g>
|
|
224
|
-
`,t}function je(n,t,e=[],i){let s,o,r,a;switch(n.position){case"bottom-right":r=n.widthMm,a=n.heightMm,s=t.x+t.width-r,o=t.y+t.height-a;break;case"bottom-full":r=t.width,a=n.heightMm,s=t.x,o=t.y+t.height-a;break;case"right-strip":r=n.widthMm,a=t.height,s=t.x+t.width-r,o=t.y;break;default:r=n.widthMm,a=n.heightMm,s=t.x+t.width-r,o=t.y+t.height-a}let l=` <g id="title-block">
|
|
225
|
-
`;return n.backgroundColor&&(l+=` <rect x="${s.toFixed(2)}" y="${o.toFixed(2)}" `,l+=`width="${r.toFixed(2)}" height="${a.toFixed(2)}" `,l+=`fill="${n.backgroundColor}"/>
|
|
226
|
-
`),l+=` <rect x="${s.toFixed(2)}" y="${o.toFixed(2)}" `,l+=`width="${r.toFixed(2)}" height="${a.toFixed(2)}" `,l+=`fill="none" stroke="#000000" stroke-width="${n.borderWeight}"/>
|
|
227
|
-
`,l+=$e(n,s,o,r,a),n.logo?.source&&(l+=Ae(n.logo,s,o,r,a)),i?.scaleBar?.visible&&i?.scale&&a>10&&(l+=Le(i.scaleBar,i.scale,s,o,r,a,n.logo!=null,i.effectiveScaleFactor)),i?.northArrow&&i.northArrow.style!=="none"&&a>15&&(l+=Ee(i.northArrow,s,o,r,a,n.logo!=null,n.position)),n.showRevisionHistory&&e.length>0&&(l+=Pe(e.slice(0,n.maxRevisionEntries),s,o,r,a,n)),l+=` </g>
|
|
228
|
-
`,{svgElements:l,bounds:{x:s,y:o,width:r,height:a}}}function $e(n,t,e,i,s){let o=` <g id="title-block-fields">
|
|
229
|
-
`;const a=n.logo?50:0,l=n.showRevisionHistory?20:0,c=i-a-5,u=s-l-4,h=new Map;for(const C of n.fields){const b=C.row??0;h.has(b)||h.set(b,[]),h.get(b).push(C)}const d=Math.max(...Array.from(h.keys()))+1,f=[];let g=0;for(let C=0;C<d;C++){const b=h.get(C)||[],A=b.length>0?Math.max(...b.map(E=>E.fontSize)):3,P=Math.min(A*.5,2.2)+1+A+2;f.push(P),g+=P}const y=g>u?u/g:1,p=f.map(C=>C*y),m=t+a+2,I=e+2,w=c/2,x=[I];for(let C=0;C<p.length-1;C++)x.push(x[C]+p[C]);for(let C=1;C<d;C++){const b=x[C];o+=` <line x1="${m.toFixed(2)}" y1="${b.toFixed(2)}" `,o+=`x2="${(m+c-4).toFixed(2)}" y2="${b.toFixed(2)}" `,o+=`stroke="#000000" stroke-width="${n.gridWeight}"/>
|
|
230
|
-
`}for(const[C,b]of h)if(b.some(M=>(M.colSpan??1)<2)){const M=m+w,P=x[C],E=x[C]+p[C];o+=` <line x1="${M.toFixed(2)}" y1="${P.toFixed(2)}" `,o+=`x2="${M.toFixed(2)}" y2="${E.toFixed(2)}" `,o+=`stroke="#000000" stroke-width="${n.gridWeight}"/>
|
|
231
|
-
`}for(const[C,b]of h){const A=x[C];p[C];for(const M of b){const P=M.col??0;M.colSpan;const E=m+P*w+1.5,L=y<1?y:1,V=Math.min(M.fontSize*.45,2.2)*Math.max(L,.7),X=M.fontSize*Math.max(L,.7),q=A+.5+V;o+=` <text x="${E.toFixed(2)}" y="${q.toFixed(2)}" `,o+=`font-family="Arial, sans-serif" font-size="${V.toFixed(2)}" `,o+=`fill="#666666">${B(M.label)}</text>
|
|
232
|
-
`;const Mt=q+.8+X*.8;o+=` <text x="${E.toFixed(2)}" y="${Mt.toFixed(2)}" `,o+=`font-family="Arial, sans-serif" font-size="${X.toFixed(2)}" `,o+=`font-weight="${M.fontWeight}" fill="#000000">${B(M.value)}</text>
|
|
233
|
-
`}}return o+=` </g>
|
|
234
|
-
`,o}function Ae(n,t,e,i,s){let o=` <g id="title-block-logo">
|
|
235
|
-
`,r,a;switch(n.position){case"top-left":r=t+3,a=e+3;break;case"top-right":r=t+i-n.widthMm-3,a=e+3;break;case"bottom-left":default:r=t+3,a=e+s-n.heightMm-3;break}return o+=` <image x="${r.toFixed(2)}" y="${a.toFixed(2)}" `,o+=`width="${n.widthMm.toFixed(2)}" height="${n.heightMm.toFixed(2)}" `,o+=`href="${B(n.source)}" preserveAspectRatio="xMidYMid meet"/>
|
|
236
|
-
`,o+=` </g>
|
|
237
|
-
`,o}function Pe(n,t,e,i,s,o){let r=` <g id="revision-history">
|
|
238
|
-
`;const l=e-18-2,c=4,u=2.2;r+=` <rect x="${t.toFixed(2)}" y="${l.toFixed(2)}" `,r+=`width="${i.toFixed(2)}" height="${18 .toFixed(2)}" `,r+=`fill="none" stroke="#000000" stroke-width="${o.gridWeight}"/>
|
|
239
|
-
`;const h=[{label:"REV",width:i*.1},{label:"DESCRIPTION",width:i*.5},{label:"DATE",width:i*.2},{label:"BY",width:i*.2}];let d=t;for(const f of h)r+=` <text x="${(d+1).toFixed(2)}" y="${(l+3).toFixed(2)}" `,r+=`font-family="Arial, sans-serif" font-size="${u}" `,r+=`font-weight="bold" fill="#000000">${f.label}</text>
|
|
240
|
-
`,d>t&&(r+=` <line x1="${d.toFixed(2)}" y1="${l.toFixed(2)}" `,r+=`x2="${d.toFixed(2)}" y2="${(l+18).toFixed(2)}" `,r+=`stroke="#000000" stroke-width="${o.gridWeight}"/>
|
|
241
|
-
`),d+=f.width;r+=` <line x1="${t.toFixed(2)}" y1="${(l+c).toFixed(2)}" `,r+=`x2="${(t+i).toFixed(2)}" y2="${(l+c).toFixed(2)}" `,r+=`stroke="#000000" stroke-width="${o.gridWeight}"/>
|
|
242
|
-
`;for(let f=0;f<n.length&&f<o.maxRevisionEntries;f++){const g=n[f],y=l+c*(f+1.5);d=t;const p=[g.revision,g.description,g.date,g.author];for(let m=0;m<h.length;m++){const I=Math.floor(h[m].width/2),w=p[m].length>I?p[m].substring(0,I-2)+"..":p[m];r+=` <text x="${(d+1).toFixed(2)}" y="${y.toFixed(2)}" `,r+=`font-family="Arial, sans-serif" font-size="${u}" `,r+=`fill="#000000">${B(w)}</text>
|
|
243
|
-
`,d+=h[m].width}f<n.length-1&&(r+=` <line x1="${t.toFixed(2)}" y1="${(l+c*(f+2)).toFixed(2)}" `,r+=`x2="${(t+i).toFixed(2)}" y2="${(l+c*(f+2)).toFixed(2)}" `,r+=`stroke="#000000" stroke-width="${o.gridWeight*.5}"/>
|
|
244
|
-
`)}return r+=` </g>
|
|
245
|
-
`,r}function Le(n,t,e,i,s,o,r,a){let l=` <g id="title-block-scale-bar">
|
|
246
|
-
`;const c=a??t.factor,u=e+3,h=i+o-8,d=Math.min(s*.3,50),f=n.totalLengthM*1e3/c,g=Math.min(f,d),y=Math.min(n.heightMm,3),p=g*c/1e3,m=n.primaryDivisions,I=g/m;for(let b=0;b<m;b++){const A=u+b*I,M=b%2===0?n.fillColor:"#ffffff";l+=` <rect x="${A.toFixed(2)}" y="${h.toFixed(2)}" `,l+=`width="${I.toFixed(2)}" height="${y.toFixed(2)}" `,l+=`fill="${M}" stroke="${n.strokeColor}" stroke-width="${n.lineWeight}"/>
|
|
247
|
-
`}const w=1.8,x=h+y+w+.3;l+=` <text x="${u.toFixed(2)}" y="${x.toFixed(2)}" `,l+=`font-family="Arial, sans-serif" font-size="${w}" `,l+=`text-anchor="start" fill="#000000">0</text>
|
|
248
|
-
`;const C=p<1?`${(p*100).toFixed(0)}cm`:`${p.toFixed(0)}m`;return l+=` <text x="${(u+g).toFixed(2)}" y="${x.toFixed(2)}" `,l+=`font-family="Arial, sans-serif" font-size="${w}" `,l+=`text-anchor="end" fill="#000000">${C}</text>
|
|
249
|
-
`,l+=` </g>
|
|
250
|
-
`,l}function Ee(n,t,e,i,s,o,r){let a=` <g id="title-block-north-arrow">
|
|
251
|
-
`;const l=Math.min(n.sizeMm,8,s*.6),c=t+i-l-5,u=e+s-l/2-3,h=n.rotation;a+=` <g transform="translate(${c.toFixed(2)}, ${u.toFixed(2)}) rotate(${h})">
|
|
252
|
-
`;const d=l/2;a+=` <polygon points="0,${(-d).toFixed(2)} ${(-d/3).toFixed(2)},${(d/2).toFixed(2)} ${(d/3).toFixed(2)},${(d/2).toFixed(2)}" `,a+=`fill="#000000" stroke="none"/>
|
|
253
|
-
`,a+=` <polygon points="0,${(d/3).toFixed(2)} ${(-d/3).toFixed(2)},${(d/2).toFixed(2)} ${(d/3).toFixed(2)},${(d/2).toFixed(2)}" `,a+=`fill="#ffffff" stroke="#000000" stroke-width="0.25"/>
|
|
254
|
-
`;const f=l*.4;return a+=` <text x="0" y="${(-d-1).toFixed(2)}" `,a+=`font-family="Arial, sans-serif" font-size="${f.toFixed(2)}" font-weight="bold" `,a+=`text-anchor="middle" fill="#000000">N</text>
|
|
255
|
-
`,a+=` </g>
|
|
256
|
-
`,a+=` </g>
|
|
257
|
-
`,a}function B(n){return n.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'")}export{Te as B,O as C,We as D,De as F,bt as G,Re as P,_e as T,Oe as a,Ne as b,Be as c,ze as d,He as e,ke as f,ve as g,je as h,Ue as r};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
const x="http://www.w3.org/2001/XMLSchema";class M extends Error{constructor(e,a){super(e),this.details=a,this.name="IDSParseError"}}function Ie(t){const e=typeof t=="string"?t:new TextDecoder().decode(t),i=new DOMParser().parseFromString(e,"text/xml"),n=i.querySelector("parsererror");if(n)throw new M("Invalid XML format",n.textContent||void 0);const s=i.documentElement;if(s.localName!=="ids")throw new M(`Invalid root element: expected "ids", got "${s.localName}"`);return{info:F(s),specifications:_(s)}}function F(t){const e=o(t,"info");return e?{title:b(e,"title")||"Untitled IDS",copyright:b(e,"copyright"),version:b(e,"version"),author:b(e,"author"),date:b(e,"date"),purpose:b(e,"purpose"),milestone:b(e,"milestone"),description:b(e,"description")}:{title:"Untitled IDS"}}function _(t){const e=o(t,"specifications");return e?R(e,"specification").map((i,n)=>L(i,n)):[]}function L(t,e){const a=t.getAttribute("name")||`Specification ${e+1}`,n=(t.getAttribute("ifcVersion")||"IFC4").split(/\s+/).map(d=>D(d)).filter(d=>d!==null),s=o(t,"applicability"),r={facets:s?B(s):[]},u=(s?s.getAttribute("minOccurs"):null)??t.getAttribute("minOccurs"),p=(s?s.getAttribute("maxOccurs"):null)??t.getAttribute("maxOccurs");let c;if(u!==null){const d=parseInt(u,10);Number.isFinite(d)&&(c=d)}let m;if(p!==null){const d=parseInt(p,10);p==="unbounded"?m="unbounded":Number.isFinite(d)&&(m=d)}const h=o(t,"requirements"),v=h?z(h):[];return{id:t.getAttribute("identifier")||`spec-${e}`,name:a,description:t.getAttribute("description")||void 0,instructions:t.getAttribute("instructions")||void 0,identifier:t.getAttribute("identifier")||void 0,ifcVersions:n.length>0?n:["IFC4"],applicability:r,requirements:v,minOccurs:c,maxOccurs:m}}function D(t){const e=t.toUpperCase().replace(/[^A-Z0-9]/g,"");switch(e){case"IFC2X3":return"IFC2X3";case"IFC4":return"IFC4";case"IFC4X3":case"IFC4X3ADD2":return"IFC4X3";default:return e.startsWith("IFC4X3")?"IFC4X3":e.startsWith("IFC4")?"IFC4":e.startsWith("IFC2X3")?"IFC2X3":null}}function B(t){const e=[];for(const a of Array.from(t.children)){const i=C(a);i&&e.push(i)}return e}function C(t){switch(t.localName.toLowerCase()){case"entity":return V(t);case"attribute":return q(t);case"property":return H(t);case"classification":return k(t);case"material":return U(t);case"partof":return Y(t);default:return null}}function V(t){const e=o(t,"name"),a=o(t,"predefinedType");if(!e)throw new M("Entity facet must have a name element");return{type:"entity",name:f(e),predefinedType:a?f(a):void 0}}function q(t){const e=o(t,"name"),a=o(t,"value");if(!e)throw new M("Attribute facet must have a name element");return{type:"attribute",name:f(e),value:a?f(a):void 0}}function H(t){const e=o(t,"propertySet"),a=o(t,"baseName"),i=o(t,"dataType"),n=o(t,"value");if(!e)throw new M("Property facet must have a propertySet element");if(!a)throw new M("Property facet must have a baseName element");return{type:"property",propertySet:f(e),baseName:f(a),dataType:i?f(i):void 0,value:n?f(n):void 0}}function k(t){const e=o(t,"system"),a=o(t,"value");return{type:"classification",system:e?f(e):void 0,value:a?f(a):void 0}}function U(t){const e=o(t,"value");return{type:"material",value:e?f(e):void 0}}function Y(t){const e=t.getAttribute("relation")||"IfcRelContainedInSpatialStructure",a=o(t,"entity");return{type:"partOf",relation:G(e),entity:a?V(a):void 0}}function G(t){const e=t.toUpperCase();return e.includes("AGGREGATE")?"IfcRelAggregates":e.includes("CONTAINED")||e.includes("SPATIAL")?"IfcRelContainedInSpatialStructure":e.includes("NEST")?"IfcRelNests":e.includes("VOID")?"IfcRelVoidsElement":e.includes("FILL")?"IfcRelFillsElement":"IfcRelContainedInSpatialStructure"}function z(t){const e=[];let a=0;for(const i of Array.from(t.children)){const n=C(i);if(n){const s=i.getAttribute("minOccurs"),r=i.getAttribute("maxOccurs");let u="required";s==="0"&&r==="0"?u="prohibited":s==="0"&&(u="optional"),e.push({id:`req-${a++}`,facet:n,optionality:u,description:i.getAttribute("description")||void 0,instructions:i.getAttribute("instructions")||void 0})}}return e}function f(t){const e=o(t,"simpleValue");if(e)return{type:"simpleValue",value:e.textContent?.trim()||""};const a=T(t,"restriction",x)||o(t,"restriction");if(a)return j(a);const i=t.textContent?.trim();return i?{type:"simpleValue",value:i}:{type:"simpleValue",value:""}}function j(t){const e=T(t,"pattern",x)||o(t,"pattern");if(e)return{type:"pattern",pattern:e.getAttribute("value")||e.textContent||""};const a=W(t,"enumeration",x);if(a.length===0){const p=R(t,"enumeration");if(p.length>0)return{type:"enumeration",values:p.map(c=>c.getAttribute("value")||c.textContent||"")}}else return{type:"enumeration",values:a.map(p=>p.getAttribute("value")||p.textContent||"")};const i=T(t,"minInclusive",x)||o(t,"minInclusive"),n=T(t,"maxInclusive",x)||o(t,"maxInclusive"),s=T(t,"minExclusive",x)||o(t,"minExclusive"),r=T(t,"maxExclusive",x)||o(t,"maxExclusive");if(i||n||s||r){const p={type:"bounds"};if(i){const c=parseFloat(i.getAttribute("value")||i.textContent||"");isNaN(c)||(p.minInclusive=c)}if(n){const c=parseFloat(n.getAttribute("value")||n.textContent||"");isNaN(c)||(p.maxInclusive=c)}if(s){const c=parseFloat(s.getAttribute("value")||s.textContent||"");isNaN(c)||(p.minExclusive=c)}if(r){const c=parseFloat(r.getAttribute("value")||r.textContent||"");isNaN(c)||(p.maxExclusive=c)}return p}const u=t.getAttribute("base");return u?{type:"simpleValue",value:u}:{type:"simpleValue",value:t.textContent?.trim()||""}}function o(t,e){for(const a of Array.from(t.children))if(a.localName.toLowerCase()===e.toLowerCase())return a;return null}function R(t,e){const a=[];for(const i of Array.from(t.children))i.localName.toLowerCase()===e.toLowerCase()&&a.push(i);return a}function T(t,e,a){for(const i of Array.from(t.children))if(i.localName.toLowerCase()===e.toLowerCase()&&i.namespaceURI===a)return i;return null}function W(t,e,a){const i=[];for(const n of Array.from(t.children))n.localName.toLowerCase()===e.toLowerCase()&&n.namespaceURI===a&&i.push(n);return i}function b(t,e){return o(t,e)?.textContent?.trim()||void 0}const A=1e-6;function y(t,e){if(e==null)return!1;switch(t.type){case"simpleValue":return X(t,e);case"pattern":return K(t,e);case"enumeration":return Z(t,e);case"bounds":return Q(t,e);default:return!1}}function X(t,e){const a=t.value,i=String(e);if(i===a||i.toUpperCase()===a.toUpperCase())return!0;const n=parseFloat(a),s=typeof e=="number"?e:parseFloat(i);if(!isNaN(n)&&!isNaN(s))return Math.abs(n-s)<=A;if(typeof e=="boolean"){const p=a.toLowerCase();if(p==="true"||p==="1")return e===!0;if(p==="false"||p==="0")return e===!1}const r=i.toLowerCase(),u=a.toLowerCase();return(r==="true"||r==="false")&&(u==="true"||u==="false")?r===u:!1}function K(t,e){const a=String(e);try{const i=J(t.pattern);return new RegExp(`^${i}$`,"i").test(a)}catch{return!1}}function J(t){return t.replace(/\\i/g,"[A-Za-z_:]").replace(/\\c/g,"[A-Za-z0-9._:-]").replace(/\\p\{[^}]+\}/g,".").replace(/\[([^\]]+)-\[[^\]]+\]\]/g,"[$1]")}function Z(t,e){const a=String(e),i=a.toUpperCase();return t.values.some(n=>{if(n===a||n.toUpperCase()===i)return!0;const s=parseFloat(n),r=typeof e=="number"?e:parseFloat(a);return!isNaN(s)&&!isNaN(r)?Math.abs(s-r)<=A:!1})}function Q(t,e){const a=typeof e=="number"?e:parseFloat(String(e));return!(isNaN(a)||t.minInclusive!==void 0&&a<t.minInclusive-A||t.maxInclusive!==void 0&&a>t.maxInclusive+A||t.minExclusive!==void 0&&a<=t.minExclusive||t.maxExclusive!==void 0&&a>=t.maxExclusive)}function l(t){switch(t.type){case"simpleValue":return`"${t.value}"`;case"pattern":return`pattern "${t.pattern}"`;case"enumeration":return t.values.length===1?`"${t.values[0]}"`:`one of [${t.values.map(e=>`"${e}"`).join(", ")}]`;case"bounds":return ee(t);default:return"unknown"}}function ee(t){const e=[];return t.minInclusive!==void 0&&t.maxInclusive!==void 0?`between ${t.minInclusive} and ${t.maxInclusive}`:(t.minInclusive!==void 0&&e.push(`>= ${t.minInclusive}`),t.maxInclusive!==void 0&&e.push(`<= ${t.maxInclusive}`),t.minExclusive!==void 0&&e.push(`> ${t.minExclusive}`),t.maxExclusive!==void 0&&e.push(`< ${t.maxExclusive}`),e.join(" and ")||"any value")}function te(t,e,a){const i=a.getEntityType(e);if(!i)return{passed:!1,actualValue:void 0,expectedValue:l(t.name),failure:{type:"ENTITY_TYPE_MISMATCH",field:"entityType",actual:"unknown",expected:l(t.name)}};if(!y(t.name,i))return{passed:!1,actualValue:i,expectedValue:l(t.name),failure:{type:"ENTITY_TYPE_MISMATCH",field:"entityType",actual:i,expected:l(t.name)}};if(t.predefinedType){const n=a.getObjectType(e);if(!n)return{passed:!1,actualValue:i,expectedValue:`${l(t.name)} with predefinedType ${l(t.predefinedType)}`,failure:{type:"PREDEFINED_TYPE_MISSING",field:"predefinedType",expected:l(t.predefinedType)}};if(!y(t.predefinedType,n))return{passed:!1,actualValue:`${i}[${n}]`,expectedValue:`${l(t.name)} with predefinedType ${l(t.predefinedType)}`,failure:{type:"PREDEFINED_TYPE_MISMATCH",field:"predefinedType",actual:n,expected:l(t.predefinedType)}}}return{passed:!0,actualValue:t.predefinedType?`${i}[${a.getObjectType(e)||""}]`:i,expectedValue:l(t.name)}}function ie(t,e){const a=t.name;if(a.type==="simpleValue")return e.getEntitiesByType(a.value);if(a.type==="enumeration"){const i=[];for(const n of a.values)i.push(...e.getEntitiesByType(n));return i}}const ae=["Name","Description","ObjectType","Tag","GlobalId","LongName"];function ne(t,e,a){const i=t.name;let n;if(i.type==="simpleValue")n=i.value;else{const r=ae.filter(u=>y(i,u));if(r.length===0)return{passed:!1,failure:{type:"ATTRIBUTE_MISSING",field:l(i),expected:l(i)}};n=r[0]}const s=se(n,e,a);return s==null||s===""?{passed:!1,actualValue:void 0,expectedValue:t.value?l(t.value):`attribute "${n}" to exist`,failure:{type:"ATTRIBUTE_MISSING",field:n,expected:t.value?l(t.value):"any value"}}:t.value?y(t.value,s)?{passed:!0,actualValue:String(s),expectedValue:l(t.value)}:{passed:!1,actualValue:String(s),expectedValue:l(t.value),failure:{type:t.value.type==="pattern"?"ATTRIBUTE_PATTERN_MISMATCH":"ATTRIBUTE_VALUE_MISMATCH",field:n,actual:String(s),expected:l(t.value)}}:{passed:!0,actualValue:String(s),expectedValue:`attribute "${n}" to exist`}}function se(t,e,a){switch(t.toLowerCase()){case"name":return a.getEntityName(e);case"description":return a.getDescription(e);case"objecttype":return a.getObjectType(e);case"globalid":return a.getGlobalId(e);default:return a.getAttribute(e,t)}}function re(t,e,a){const i=a.getPropertySets(e);if(i.length===0)return{passed:!1,expectedValue:`property "${l(t.baseName)}" in "${l(t.propertySet)}"`,failure:{type:"PSET_MISSING",field:l(t.propertySet),expected:l(t.propertySet)}};const n=i.filter(u=>y(t.propertySet,u.name));if(n.length===0){const u=i.map(p=>p.name).join(", ");return{passed:!1,actualValue:u||"(none)",expectedValue:l(t.propertySet),failure:{type:"PSET_MISSING",field:"propertySet",actual:u,expected:l(t.propertySet),context:{availablePsets:u}}}}for(const u of n){const p=le(t,u);if(p.passed)return p}const s=n.map(u=>u.name).join(", "),r=n.flatMap(u=>u.properties.map(p=>`${u.name}.${p.name}`)).join(", ");return{passed:!1,actualValue:r||"(none)",expectedValue:`${l(t.propertySet)}.${l(t.baseName)}`,failure:{type:"PROPERTY_MISSING",field:l(t.baseName),expected:l(t.baseName),context:{propertySet:s,availableProperties:r}}}}function le(t,e){const a=e.properties.filter(i=>y(t.baseName,i.name));if(a.length===0)return{passed:!1,failure:{type:"PROPERTY_MISSING",field:l(t.baseName),expected:l(t.baseName),context:{propertySet:e.name,availableProperties:e.properties.map(i=>i.name).join(", ")}}};for(const i of a){if(t.dataType&&!y(t.dataType,i.dataType))return{passed:!1,actualValue:`${e.name}.${i.name} (${i.dataType})`,expectedValue:`dataType ${l(t.dataType)}`,failure:{type:"PROPERTY_DATATYPE_MISMATCH",field:`${e.name}.${i.name}`,actual:i.dataType,expected:l(t.dataType)}};if(t.value){const n=i.value;if(n==null)return{passed:!1,actualValue:"(empty)",expectedValue:l(t.value),failure:{type:"PROPERTY_VALUE_MISMATCH",field:`${e.name}.${i.name}`,actual:"(empty)",expected:l(t.value)}};if(!y(t.value,n)){const s=t.value.type==="bounds"?"PROPERTY_OUT_OF_BOUNDS":"PROPERTY_VALUE_MISMATCH";return{passed:!1,actualValue:String(n),expectedValue:l(t.value),failure:{type:s,field:`${e.name}.${i.name}`,actual:String(n),expected:l(t.value)}}}}return{passed:!0,actualValue:`${e.name}.${i.name} = ${i.value}`,expectedValue:t.value?l(t.value):"property exists"}}return{passed:!1,failure:{type:"PROPERTY_MISSING",field:l(t.baseName)}}}function ue(t,e,a){const i=a.getClassifications(e);if(!t.system&&!t.value)return i.length===0?{passed:!1,actualValue:"(none)",expectedValue:"any classification",failure:{type:"CLASSIFICATION_MISSING",expected:"any classification"}}:{passed:!0,actualValue:i.map(s=>`${s.system}:${s.value}`).join(", "),expectedValue:"any classification"};let n=i;if(t.system&&(n=i.filter(s=>y(t.system,s.system)),n.length===0)){const s=[...new Set(i.map(r=>r.system))].join(", ");return{passed:!1,actualValue:s||"(none)",expectedValue:l(t.system),failure:{type:"CLASSIFICATION_SYSTEM_MISMATCH",field:"system",actual:s,expected:l(t.system),context:{availableSystems:s}}}}if(t.value){const s=n.filter(r=>y(t.value,r.value));if(s.length===0){const r=n.map(u=>u.value).join(", ");return{passed:!1,actualValue:r||"(none)",expectedValue:l(t.value),failure:{type:"CLASSIFICATION_VALUE_MISMATCH",field:"value",actual:r,expected:l(t.value),context:{system:t.system?l(t.system):"any",availableValues:r}}}}return{passed:!0,actualValue:s.map(r=>`${r.system}:${r.value}`).join(", "),expectedValue:t.system?`${l(t.system)}:${l(t.value)}`:l(t.value)}}return{passed:!0,actualValue:n.map(s=>`${s.system}:${s.value}`).join(", "),expectedValue:l(t.system)}}function pe(t,e,a){const i=a.getMaterials(e);if(!t.value)return i.length===0?{passed:!1,actualValue:"(none)",expectedValue:"any material",failure:{type:"MATERIAL_MISSING",expected:"any material"}}:{passed:!0,actualValue:i.map(s=>s.name).join(", "),expectedValue:"any material"};const n=i.filter(s=>y(t.value,s.name)||s.category&&y(t.value,s.category));if(n.length===0){if(i.length===0)return{passed:!1,actualValue:"(none)",expectedValue:l(t.value),failure:{type:"MATERIAL_MISSING",expected:l(t.value)}};const s=i.map(r=>r.name).join(", ");return{passed:!1,actualValue:s,expectedValue:l(t.value),failure:{type:"MATERIAL_VALUE_MISMATCH",field:"material",actual:s,expected:l(t.value),context:{availableMaterials:s}}}}return{passed:!0,actualValue:n.map(s=>s.name).join(", "),expectedValue:l(t.value)}}const S={IfcRelAggregates:"aggregated in",IfcRelContainedInSpatialStructure:"contained in",IfcRelNests:"nested in",IfcRelVoidsElement:"voiding",IfcRelFillsElement:"filling"};function oe(t,e,a){const i=a.getParent(e,t.relation);if(!i){const r=S[t.relation]||t.relation,u=t.entity?l(t.entity.name):"any entity";return{passed:!1,actualValue:"(no parent)",expectedValue:`${r} ${u}`,failure:{type:"PARTOF_RELATION_MISSING",field:t.relation,expected:`${r} ${u}`,context:{relation:t.relation}}}}if(!t.entity){const r=S[t.relation]||t.relation;return{passed:!0,actualValue:`${r} ${i.entityType}`,expectedValue:`${r} any entity`}}if(!y(t.entity.name,i.entityType)){const r=S[t.relation]||t.relation;return{passed:!1,actualValue:`${r} ${i.entityType}`,expectedValue:`${r} ${l(t.entity.name)}`,failure:{type:"PARTOF_ENTITY_MISMATCH",field:"entity",actual:i.entityType,expected:l(t.entity.name),context:{relation:t.relation,parentId:String(i.expressId)}}}}if(t.entity.predefinedType){if(!i.predefinedType)return{passed:!1,actualValue:`${i.entityType} (no predefinedType)`,expectedValue:`${l(t.entity.name)} with predefinedType ${l(t.entity.predefinedType)}`,failure:{type:"PARTOF_ENTITY_MISMATCH",field:"predefinedType",expected:l(t.entity.predefinedType),context:{relation:t.relation,parentType:i.entityType}}};if(!y(t.entity.predefinedType,i.predefinedType))return{passed:!1,actualValue:`${i.entityType}[${i.predefinedType}]`,expectedValue:`${l(t.entity.name)}[${l(t.entity.predefinedType)}]`,failure:{type:"PARTOF_ENTITY_MISMATCH",field:"predefinedType",actual:i.predefinedType,expected:l(t.entity.predefinedType),context:{relation:t.relation,parentType:i.entityType}}}}const n=S[t.relation]||t.relation,s=i.predefinedType?`${i.entityType}[${i.predefinedType}]`:i.entityType;return{passed:!0,actualValue:`${n} ${s}`,expectedValue:`${n} ${l(t.entity.name)}`}}function w(t,e,a){switch(t.type){case"entity":return te(t,e,a);case"attribute":return ne(t,e,a);case"property":return re(t,e,a);case"classification":return ue(t,e,a);case"material":return pe(t,e,a);case"partOf":return oe(t,e,a);default:return{passed:!1,failure:{type:"ENTITY_TYPE_MISMATCH",expected:"known facet type",actual:t.type}}}}function ce(t,e){switch(t.type){case"entity":return ie(t,e);default:return}}async function Se(t,e,a,i={}){const{translator:n,onProgress:s,includePassingEntities:r=!0}=i,u=[],p=t.specifications.length;for(let m=0;m<p;m++){const h=t.specifications[m];s&&s({phase:"filtering",specificationIndex:m,totalSpecifications:p,entitiesProcessed:0,totalEntities:0,percentage:Math.floor(m/p*100)});const v=await de(h,e,a.modelId,i,d=>{s&&s({...d,specificationIndex:m,totalSpecifications:p,percentage:Math.floor((m+d.entitiesProcessed/Math.max(d.totalEntities,1))/p*100)})});u.push(v)}s&&s({phase:"complete",specificationIndex:p,totalSpecifications:p,entitiesProcessed:0,totalEntities:0,percentage:100});const c=ve(u);return{document:t,modelInfo:a,timestamp:new Date,summary:c,specificationResults:u}}async function de(t,e,a,i,n){const{translator:s,maxEntities:r,includePassingEntities:u=!0}=i,p=me(t,e),c=r?p.slice(0,r):p,m=[],h=c.length;for(let E=0;E<h;E++){const $=c[E];n&&E%100===0&&n({phase:"validating",entitiesProcessed:E,totalEntities:h});const P=ye(t,$,a,e,s);(u||!P.passed)&&m.push(P)}let v=0,d=0;for(const E of m)E.passed?v++:d++;u||(v=h-d);const I=he(t,p.length);let g="pass";p.length===0?I?.passed===!1?g="fail":I?.passed===!0?g="pass":g="not_applicable":(d>0||I?.passed===!1)&&(g="fail");const O=h>0?Math.floor(v/h*100):100;return{specification:t,status:g,applicableCount:p.length,passedCount:v,failedCount:d,passRate:O,entityResults:m,cardinalityResult:I}}function me(t,e){const a=t.applicability.facets;if(a.length===0)return e.getAllEntityIds();let i;for(const s of a){const r=ce(s,e);if(r!==void 0){i=r;break}}i===void 0&&(i=e.getAllEntityIds());const n=[];for(const s of i){let r=!0;for(const u of a)if(!w(u,s,e).passed){r=!1;break}r&&n.push(s)}return n}function ye(t,e,a,i,n){const s=[];let r=!0;for(const u of t.requirements){const p=fe(u,e,i,n);s.push(p),p.status==="fail"&&(r=!1)}return{expressId:e,modelId:a,entityType:i.getEntityType(e)||"Unknown",entityName:i.getEntityName(e),globalId:i.getGlobalId(e),passed:r,requirementResults:s}}function fe(t,e,a,i){const n=w(t.facet,e,a);let s,r;switch(t.optionality){case"required":s=n.passed?"pass":"fail",n.passed||(r=i?i.describeFailure({requirement:t,status:"fail",facetType:t.facet.type,checkedDescription:"",actualValue:n.actualValue,expectedValue:n.expectedValue,failure:n.failure}):be(n));break;case"optional":s="pass";break;case"prohibited":s=n.passed?"fail":"pass",s==="fail"&&(r=i?i.t("failures.prohibited",{field:n.actualValue||"value"}):`Prohibited: found ${n.actualValue}`);break;default:s=n.passed?"pass":"fail"}const u=i?i.describeRequirement(t):Ee(t);return{requirement:t,status:s,facetType:t.facet.type,checkedDescription:u,failureReason:r,actualValue:n.actualValue,expectedValue:n.expectedValue,failure:n.failure}}function he(t,e){if(t.minOccurs===void 0&&t.maxOccurs===void 0)return;const a=t.minOccurs??0,i=t.maxOccurs;let n=!0;const s=[];return e<a&&(n=!1,s.push(`Expected at least ${a}, found ${e}`)),i!=="unbounded"&&i!==void 0&&e>i&&(n=!1,s.push(`Expected at most ${i}, found ${e}`)),{passed:n,actualCount:e,minExpected:t.minOccurs,maxExpected:t.maxOccurs,message:s.length>0?s.join("; "):"Cardinality satisfied"}}function ve(t){let e=t.length,a=0,i=0,n=0,s=0,r=0;for(const p of t)p.status==="pass"?a++:p.status==="fail"&&i++,n+=p.applicableCount,s+=p.passedCount,r+=p.failedCount;const u=n>0?Math.floor(s/n*100):100;return{totalSpecifications:e,passedSpecifications:a,failedSpecifications:i,totalEntitiesChecked:n,totalEntitiesPassed:s,totalEntitiesFailed:r,overallPassRate:u}}function be(t){if(!t.failure)return`Expected ${t.expectedValue}, got ${t.actualValue}`;const{type:e,field:a,actual:i,expected:n}=t.failure;switch(e){case"ENTITY_TYPE_MISMATCH":return`Entity type "${i}" does not match expected ${n}`;case"PREDEFINED_TYPE_MISMATCH":return`Predefined type "${i}" does not match expected ${n}`;case"PREDEFINED_TYPE_MISSING":return`Predefined type is missing, expected ${n}`;case"ATTRIBUTE_MISSING":return`Attribute "${a}" is missing`;case"ATTRIBUTE_VALUE_MISMATCH":return`Attribute "${a}" value "${i}" does not match expected ${n}`;case"ATTRIBUTE_PATTERN_MISMATCH":return`Attribute "${a}" value "${i}" does not match pattern ${n}`;case"PSET_MISSING":return`Property set "${a||n}" not found`;case"PROPERTY_MISSING":return`Property "${a}" not found`;case"PROPERTY_VALUE_MISMATCH":return`Property "${a}" value "${i}" does not match expected ${n}`;case"PROPERTY_DATATYPE_MISMATCH":return`Property "${a}" type "${i}" does not match expected ${n}`;case"PROPERTY_OUT_OF_BOUNDS":return`Property "${a}" value ${i} is out of bounds ${n}`;case"CLASSIFICATION_MISSING":return"No classification found";case"CLASSIFICATION_SYSTEM_MISMATCH":return`Classification system "${i}" does not match expected ${n}`;case"CLASSIFICATION_VALUE_MISMATCH":return`Classification value "${i}" does not match expected ${n}`;case"MATERIAL_MISSING":return"No material assigned";case"MATERIAL_VALUE_MISMATCH":return`Material "${i}" does not match expected ${n}`;case"PARTOF_RELATION_MISSING":return`Not ${a} any entity`;case"PARTOF_ENTITY_MISMATCH":return`Parent entity "${i}" does not match expected ${n}`;default:return`Validation failed: ${e}`}}function Ee(t){const e=t.facet,a=t.optionality;let i;switch(e.type){case"entity":i=`Must be ${l(e.name)}`,e.predefinedType&&(i+=` with predefinedType ${l(e.predefinedType)}`);break;case"attribute":e.value?i=`Attribute "${l(e.name)}" must equal ${l(e.value)}`:i=`Attribute "${l(e.name)}" must exist`;break;case"property":e.value?i=`Property "${l(e.propertySet)}.${l(e.baseName)}" must equal ${l(e.value)}`:i=`Property "${l(e.propertySet)}.${l(e.baseName)}" must exist`;break;case"classification":e.system&&e.value?i=`Must have classification ${l(e.value)} in ${l(e.system)}`:e.system?i=`Must be classified in ${l(e.system)}`:e.value?i=`Must have classification ${l(e.value)}`:i="Must have a classification";break;case"material":e.value?i=`Must have material ${l(e.value)}`:i="Must have a material assigned";break;case"partOf":{const n=e.relation.replace("IfcRel","").toLowerCase();e.entity?i=`Must be ${n} ${l(e.entity.name)}`:i=`Must be ${n} some entity`;break}default:i="Unknown requirement"}return a==="prohibited"?i=i.replace("Must","Must NOT").replace("must","must NOT"):a==="optional"&&(i=i.replace("Must","Should").replace("must","should")),i}const xe={status:{pass:"PASS",fail:"FAIL",not_applicable:"NOT APPLICABLE"},optionality:{required:"Required",optional:"Optional",prohibited:"Prohibited"},cardinality:{satisfied:"Cardinality satisfied",atLeast:"Expected at least {min}, found {count}",atMost:"Expected at most {max}, found {count}",between:"Expected between {min} and {max}, found {count}",exactly:"Expected exactly {count}"},relations:{IfcRelAggregates:"part of",IfcRelContainedInSpatialStructure:"contained in",IfcRelNests:"nested in",IfcRelVoidsElement:"voiding",IfcRelFillsElement:"filling"},constraints:{simpleValue:'"{value}"',pattern:'matching pattern "{pattern}"',enumeration:{single:'"{value}"',multiple:"one of [{values}]"},bounds:{between:"between {min} and {max}",atLeast:"at least {min}",atMost:"at most {max}",greaterThan:"greater than {min}",lessThan:"less than {max}"}},applicability:{entity:{simple:"Elements of type {entityType}",withPredefined:"{entityType} elements with predefined type {predefinedType}",pattern:"Elements with type matching {pattern}"},attribute:{exists:'Elements where attribute "{name}" exists',equals:'Elements where "{name}" equals {value}',pattern:'Elements where "{name}" matches {pattern}'},property:{exists:'Elements with property "{property}" in "{pset}"',equals:'Elements where "{pset}.{property}" equals {value}',pattern:'Elements where "{pset}.{property}" matches {pattern}',bounded:'Elements where "{pset}.{property}" is {bounds}'},classification:{any:"Elements with any classification",system:'Elements classified in "{system}"',value:'Elements with classification "{value}"',systemAndValue:'Elements classified as "{value}" in "{system}"'},material:{any:"Elements with any material assigned",value:'Elements with material "{value}"',pattern:"Elements with material matching {pattern}"},partOf:{simple:"Elements that are {relation} another element",withEntity:"Elements that are {relation} a {entity}",withEntityAndType:"Elements that are {relation} a {entity} with type {predefinedType}"}},requirements:{entity:{mustBe:"Must be of type {entityType}",mustHavePredefined:"Must have predefined type {predefinedType}",mustBeWithPredefined:"Must be {entityType} with predefined type {predefinedType}"},attribute:{mustExist:'Attribute "{name}" must exist',mustEqual:'Attribute "{name}" must equal {value}',mustMatch:'Attribute "{name}" must match {pattern}',mustNotExist:'Attribute "{name}" must not exist',mustNotEqual:'Attribute "{name}" must not equal {value}'},property:{mustExist:'Property "{pset}.{property}" must exist',mustEqual:'Property "{pset}.{property}" must equal {value}',mustMatch:'Property "{pset}.{property}" must match {pattern}',mustBeBounded:'Property "{pset}.{property}" must be {bounds}',mustHaveType:'Property "{pset}.{property}" must be of type {dataType}',mustNotExist:'Property "{pset}.{property}" must not exist'},classification:{mustHave:"Must have a classification",mustBeInSystem:'Must be classified in "{system}"',mustHaveValue:'Must have classification "{value}"',mustBeInSystemWithValue:'Must be classified as "{value}" in "{system}"',mustNotHave:"Must not have any classification",mustNotBeInSystem:'Must not be classified in "{system}"'},material:{mustHave:"Must have a material assigned",mustBe:'Must have material "{value}"',mustMatch:"Must have material matching {pattern}",mustNotHave:"Must not have any material assigned"},partOf:{mustBe:"Must be {relation} a {entity}",mustBeSimple:"Must be {relation} another element",mustNotBe:"Must not be {relation} any element"}},failures:{entityTypeMismatch:'Entity type is "{actual}", expected {expected}',predefinedTypeMismatch:'Predefined type is "{actual}", expected {expected}',predefinedTypeMissing:"Predefined type is not set, expected {expected}",attributeMissing:'Attribute "{name}" does not exist',attributeEmpty:'Attribute "{name}" is empty',attributeValueMismatch:'Attribute "{name}" is "{actual}", expected {expected}',attributePatternMismatch:'Attribute "{name}" value "{actual}" does not match pattern {expected}',attributeProhibited:'Prohibited attribute "{name}" exists with value "{actual}"',psetMissing:'Property set "{pset}" not found',psetMissingAvailable:'Property set "{pset}" not found. Available: {available}',propertyMissing:'Property "{property}" not found in "{pset}"',propertyMissingAvailable:'Property "{property}" not found in "{pset}". Available: {available}',propertyEmpty:'Property "{pset}.{property}" has no value',propertyValueMismatch:'Property "{pset}.{property}" is "{actual}", expected {expected}',propertyPatternMismatch:'Property "{pset}.{property}" value "{actual}" does not match {expected}',propertyDatatypeMismatch:'Property "{pset}.{property}" data type is "{actual}", expected {expected}',propertyOutOfBounds:'Property "{pset}.{property}" value {actual} is out of range {expected}',propertyProhibited:'Prohibited property "{pset}.{property}" exists with value "{actual}"',classificationMissing:"No classification assigned",classificationSystemMismatch:'Classification system "{actual}" does not match expected "{expected}"',classificationSystemMissingAvailable:'Classification system "{expected}" not found. Available: {available}',classificationValueMismatch:'Classification code "{actual}" does not match expected {expected}',classificationValueMissingAvailable:"Classification code {expected} not found. Available: {available}",classificationProhibited:'Prohibited classification "{actual}" exists in system "{system}"',materialMissing:"No material assigned",materialValueMismatch:'Material "{actual}" does not match expected {expected}',materialValueMissingAvailable:"Material {expected} not found. Available: {available}",materialProhibited:'Prohibited material "{actual}" is assigned',partOfMissing:"Element is not {relation} any {entity}",partOfMissingSimple:"Element is not {relation} any element",partOfEntityMismatch:"Parent element is {actual}, expected {expected}",partOfPredefinedMismatch:'Parent predefined type is "{actual}", expected {expected}',partOfProhibited:"Element is {relation} {actual}, which is prohibited",prohibited:'Prohibited {field} found: "{actual}"',unknown:"Validation failed: {reason}"},summary:{title:"IDS Validation Report",specifications:"{passed}/{total} specifications passed",entities:"{passed}/{total} entities compliant ({percent}%)",overallPass:"Model meets all requirements",overallFail:"Model has {count} failing specifications",noApplicable:"No applicable entities found"},ui:{specification:"Specification",specifications:"Specifications",requirement:"Requirement",requirements:"Requirements",applicability:"Applies to",entity:"Entity",entities:"Entities",passed:"Passed",failed:"Failed",passRate:"Pass rate",actualValue:"Actual",expectedValue:"Expected",failureReason:"Reason",showAll:"Show all",showFailed:"Show failed only",isolateFailed:"Isolate failed",isolatePassed:"Isolate passed",exportJson:"Export JSON",exportBcf:"Export BCF",loadIds:"Load IDS file",runValidation:"Run validation",clearResults:"Clear results"}},Te={status:{pass:"BESTANDEN",fail:"FEHLGESCHLAGEN",not_applicable:"NICHT ANWENDBAR"},optionality:{required:"Erforderlich",optional:"Optional",prohibited:"Verboten"},cardinality:{satisfied:"Kardinalität erfüllt",atLeast:"Mindestens {min} erwartet, {count} gefunden",atMost:"Maximal {max} erwartet, {count} gefunden",between:"Zwischen {min} und {max} erwartet, {count} gefunden",exactly:"Genau {count} erwartet"},relations:{IfcRelAggregates:"Teil von",IfcRelContainedInSpatialStructure:"enthalten in",IfcRelNests:"verschachtelt in",IfcRelVoidsElement:"durchbrechend",IfcRelFillsElement:"ausfüllend"},constraints:{simpleValue:'"{value}"',pattern:'entsprechend Muster "{pattern}"',enumeration:{single:'"{value}"',multiple:"eines von [{values}]"},bounds:{between:"zwischen {min} und {max}",atLeast:"mindestens {min}",atMost:"höchstens {max}",greaterThan:"größer als {min}",lessThan:"kleiner als {max}"}},applicability:{entity:{simple:"Elemente vom Typ {entityType}",withPredefined:"{entityType}-Elemente mit vordefiniertem Typ {predefinedType}",pattern:"Elemente mit Typ entsprechend {pattern}"},attribute:{exists:'Elemente bei denen Attribut "{name}" existiert',equals:'Elemente bei denen "{name}" gleich {value} ist',pattern:'Elemente bei denen "{name}" dem Muster {pattern} entspricht'},property:{exists:'Elemente mit Eigenschaft "{property}" in "{pset}"',equals:'Elemente bei denen "{pset}.{property}" gleich {value} ist',pattern:'Elemente bei denen "{pset}.{property}" dem Muster {pattern} entspricht',bounded:'Elemente bei denen "{pset}.{property}" {bounds} ist'},classification:{any:"Elemente mit beliebiger Klassifizierung",system:'Elemente klassifiziert in "{system}"',value:'Elemente mit Klassifizierung "{value}"',systemAndValue:'Elemente klassifiziert als "{value}" in "{system}"'},material:{any:"Elemente mit zugewiesenem Material",value:'Elemente mit Material "{value}"',pattern:"Elemente mit Material entsprechend {pattern}"},partOf:{simple:"Elemente die {relation} einem anderen Element sind",withEntity:"Elemente die {relation} einem/einer {entity} sind",withEntityAndType:"Elemente die {relation} einem/einer {entity} mit Typ {predefinedType} sind"}},requirements:{entity:{mustBe:"Muss vom Typ {entityType} sein",mustHavePredefined:"Muss vordefinierten Typ {predefinedType} haben",mustBeWithPredefined:"Muss {entityType} mit vordefiniertem Typ {predefinedType} sein"},attribute:{mustExist:'Attribut "{name}" muss existieren',mustEqual:'Attribut "{name}" muss {value} entsprechen',mustMatch:'Attribut "{name}" muss dem Muster {pattern} entsprechen',mustNotExist:'Attribut "{name}" darf nicht existieren',mustNotEqual:'Attribut "{name}" darf nicht {value} sein'},property:{mustExist:'Eigenschaft "{pset}.{property}" muss existieren',mustEqual:'Eigenschaft "{pset}.{property}" muss {value} sein',mustMatch:'Eigenschaft "{pset}.{property}" muss dem Muster {pattern} entsprechen',mustBeBounded:'Eigenschaft "{pset}.{property}" muss {bounds} sein',mustHaveType:'Eigenschaft "{pset}.{property}" muss vom Datentyp {dataType} sein',mustNotExist:'Eigenschaft "{pset}.{property}" darf nicht existieren'},classification:{mustHave:"Muss eine Klassifizierung haben",mustBeInSystem:'Muss in "{system}" klassifiziert sein',mustHaveValue:'Muss Klassifizierung "{value}" haben',mustBeInSystemWithValue:'Muss als "{value}" in "{system}" klassifiziert sein',mustNotHave:"Darf keine Klassifizierung haben",mustNotBeInSystem:'Darf nicht in "{system}" klassifiziert sein'},material:{mustHave:"Muss ein Material zugewiesen haben",mustBe:'Muss Material "{value}" haben',mustMatch:"Muss Material entsprechend {pattern} haben",mustNotHave:"Darf kein Material zugewiesen haben"},partOf:{mustBe:"Muss {relation} einem/einer {entity} sein",mustBeSimple:"Muss {relation} einem anderen Element sein",mustNotBe:"Darf nicht {relation} einem Element sein"}},failures:{entityTypeMismatch:'Elementtyp ist "{actual}", erwartet {expected}',predefinedTypeMismatch:'Vordefinierter Typ ist "{actual}", erwartet {expected}',predefinedTypeMissing:"Vordefinierter Typ ist nicht gesetzt, erwartet {expected}",attributeMissing:'Attribut "{name}" existiert nicht',attributeEmpty:'Attribut "{name}" ist leer',attributeValueMismatch:'Attribut "{name}" ist "{actual}", erwartet {expected}',attributePatternMismatch:'Attribut "{name}" Wert "{actual}" entspricht nicht dem Muster {expected}',attributeProhibited:'Verbotenes Attribut "{name}" existiert mit Wert "{actual}"',psetMissing:'PropertySet "{pset}" nicht gefunden',psetMissingAvailable:'PropertySet "{pset}" nicht gefunden. Verfügbar: {available}',propertyMissing:'Eigenschaft "{property}" nicht in "{pset}" gefunden',propertyMissingAvailable:'Eigenschaft "{property}" nicht in "{pset}" gefunden. Verfügbar: {available}',propertyEmpty:'Eigenschaft "{pset}.{property}" hat keinen Wert',propertyValueMismatch:'Eigenschaft "{pset}.{property}" ist "{actual}", erwartet {expected}',propertyPatternMismatch:'Eigenschaft "{pset}.{property}" Wert "{actual}" entspricht nicht {expected}',propertyDatatypeMismatch:'Eigenschaft "{pset}.{property}" Datentyp ist "{actual}", erwartet {expected}',propertyOutOfBounds:'Eigenschaft "{pset}.{property}" Wert {actual} liegt außerhalb des Bereichs {expected}',propertyProhibited:'Verbotene Eigenschaft "{pset}.{property}" existiert mit Wert "{actual}"',classificationMissing:"Keine Klassifizierung zugewiesen",classificationSystemMismatch:'Klassifizierungssystem "{actual}" entspricht nicht dem erwarteten "{expected}"',classificationSystemMissingAvailable:'Klassifizierungssystem "{expected}" nicht gefunden. Verfügbar: {available}',classificationValueMismatch:'Klassifizierungscode "{actual}" entspricht nicht dem erwarteten {expected}',classificationValueMissingAvailable:"Klassifizierungscode {expected} nicht gefunden. Verfügbar: {available}",classificationProhibited:'Verbotene Klassifizierung "{actual}" existiert im System "{system}"',materialMissing:"Kein Material zugewiesen",materialValueMismatch:'Material "{actual}" entspricht nicht dem erwarteten {expected}',materialValueMissingAvailable:"Material {expected} nicht gefunden. Verfügbar: {available}",materialProhibited:'Verbotenes Material "{actual}" ist zugewiesen',partOfMissing:"Element ist nicht {relation} einem/einer {entity}",partOfMissingSimple:"Element ist nicht {relation} einem anderen Element",partOfEntityMismatch:"Übergeordnetes Element ist {actual}, erwartet {expected}",partOfPredefinedMismatch:'Vordefinierter Typ des übergeordneten Elements ist "{actual}", erwartet {expected}',partOfProhibited:"Element ist {relation} {actual}, was verboten ist",prohibited:'Verbotenes {field} gefunden: "{actual}"',unknown:"Validierung fehlgeschlagen: {reason}"},summary:{title:"IDS-Validierungsbericht",specifications:"{passed}/{total} Spezifikationen bestanden",entities:"{passed}/{total} Elemente konform ({percent}%)",overallPass:"Modell erfüllt alle Anforderungen",overallFail:"Modell hat {count} fehlgeschlagene Spezifikationen",noApplicable:"Keine anwendbaren Elemente gefunden"},ui:{specification:"Spezifikation",specifications:"Spezifikationen",requirement:"Anforderung",requirements:"Anforderungen",applicability:"Gilt für",entity:"Element",entities:"Elemente",passed:"Bestanden",failed:"Fehlgeschlagen",passRate:"Erfolgsquote",actualValue:"Tatsächlich",expectedValue:"Erwartet",failureReason:"Grund",showAll:"Alle anzeigen",showFailed:"Nur fehlgeschlagene",isolateFailed:"Fehlgeschlagene isolieren",isolatePassed:"Bestandene isolieren",exportJson:"JSON exportieren",exportBcf:"BCF exportieren",loadIds:"IDS-Datei laden",runValidation:"Validierung starten",clearResults:"Ergebnisse löschen"}},Me={status:{pass:"CONFORME",fail:"NON CONFORME",not_applicable:"NON APPLICABLE"},optionality:{required:"Obligatoire",optional:"Optionnel",prohibited:"Interdit"},cardinality:{satisfied:"Cardinalité respectée",atLeast:"Au moins {min} attendu(s), {count} trouvé(s)",atMost:"Au maximum {max} attendu(s), {count} trouvé(s)",between:"Entre {min} et {max} attendu(s), {count} trouvé(s)",exactly:"Exactement {count} attendu(s)"},relations:{IfcRelAggregates:"agrégé dans",IfcRelContainedInSpatialStructure:"contenu dans",IfcRelNests:"imbriqué dans",IfcRelVoidsElement:"perçant",IfcRelFillsElement:"remplissant"},constraints:{simpleValue:'"{value}"',pattern:'correspondant au motif "{pattern}"',enumeration:{single:'"{value}"',multiple:"l'un de [{values}]"},bounds:{between:"entre {min} et {max}",atLeast:"au moins {min}",atMost:"au plus {max}",greaterThan:"supérieur à {min}",lessThan:"inférieur à {max}"}},applicability:{entity:{simple:"Éléments de type {entityType}",withPredefined:"Éléments {entityType} avec type prédéfini {predefinedType}",pattern:"Éléments avec type correspondant à {pattern}"},attribute:{exists:`Éléments où l'attribut "{name}" existe`,equals:'Éléments où "{name}" est égal à {value}',pattern:'Éléments où "{name}" correspond au motif {pattern}'},property:{exists:'Éléments avec propriété "{property}" dans "{pset}"',equals:'Éléments où "{pset}.{property}" est égal à {value}',pattern:'Éléments où "{pset}.{property}" correspond au motif {pattern}',bounded:'Éléments où "{pset}.{property}" est {bounds}'},classification:{any:"Éléments avec une classification quelconque",system:'Éléments classifiés dans "{system}"',value:'Éléments avec classification "{value}"',systemAndValue:'Éléments classifiés comme "{value}" dans "{system}"'},material:{any:"Éléments avec un matériau attribué",value:'Éléments avec matériau "{value}"',pattern:"Éléments avec matériau correspondant à {pattern}"},partOf:{simple:"Éléments qui sont {relation} un autre élément",withEntity:"Éléments qui sont {relation} un(e) {entity}",withEntityAndType:"Éléments qui sont {relation} un(e) {entity} de type {predefinedType}"}},requirements:{entity:{mustBe:"Doit être de type {entityType}",mustHavePredefined:"Doit avoir le type prédéfini {predefinedType}",mustBeWithPredefined:"Doit être {entityType} avec type prédéfini {predefinedType}"},attribute:{mustExist:`L'attribut "{name}" doit exister`,mustEqual:`L'attribut "{name}" doit être égal à {value}`,mustMatch:`L'attribut "{name}" doit correspondre au motif {pattern}`,mustNotExist:`L'attribut "{name}" ne doit pas exister`,mustNotEqual:`L'attribut "{name}" ne doit pas être {value}`},property:{mustExist:'La propriété "{pset}.{property}" doit exister',mustEqual:'La propriété "{pset}.{property}" doit être égale à {value}',mustMatch:'La propriété "{pset}.{property}" doit correspondre au motif {pattern}',mustBeBounded:'La propriété "{pset}.{property}" doit être {bounds}',mustHaveType:'La propriété "{pset}.{property}" doit être de type {dataType}',mustNotExist:'La propriété "{pset}.{property}" ne doit pas exister'},classification:{mustHave:"Doit avoir une classification",mustBeInSystem:'Doit être classifié dans "{system}"',mustHaveValue:'Doit avoir la classification "{value}"',mustBeInSystemWithValue:'Doit être classifié comme "{value}" dans "{system}"',mustNotHave:"Ne doit pas avoir de classification",mustNotBeInSystem:'Ne doit pas être classifié dans "{system}"'},material:{mustHave:"Doit avoir un matériau attribué",mustBe:'Doit avoir le matériau "{value}"',mustMatch:"Doit avoir un matériau correspondant à {pattern}",mustNotHave:"Ne doit pas avoir de matériau attribué"},partOf:{mustBe:"Doit être {relation} un(e) {entity}",mustBeSimple:"Doit être {relation} un autre élément",mustNotBe:"Ne doit pas être {relation} un élément"}},failures:{entityTypeMismatch:`Le type d'élément est "{actual}", attendu {expected}`,predefinedTypeMismatch:'Le type prédéfini est "{actual}", attendu {expected}',predefinedTypeMissing:"Le type prédéfini n'est pas défini, attendu {expected}",attributeMissing:`L'attribut "{name}" n'existe pas`,attributeEmpty:`L'attribut "{name}" est vide`,attributeValueMismatch:`L'attribut "{name}" est "{actual}", attendu {expected}`,attributePatternMismatch:`La valeur de l'attribut "{name}" "{actual}" ne correspond pas au motif {expected}`,attributeProhibited:`L'attribut interdit "{name}" existe avec la valeur "{actual}"`,psetMissing:`L'ensemble de propriétés "{pset}" n'a pas été trouvé`,psetMissingAvailable:`L'ensemble de propriétés "{pset}" n'a pas été trouvé. Disponibles : {available}`,propertyMissing:`La propriété "{property}" n'a pas été trouvée dans "{pset}"`,propertyMissingAvailable:`La propriété "{property}" n'a pas été trouvée dans "{pset}". Disponibles : {available}`,propertyEmpty:`La propriété "{pset}.{property}" n'a pas de valeur`,propertyValueMismatch:'La propriété "{pset}.{property}" est "{actual}", attendu {expected}',propertyPatternMismatch:'La valeur de la propriété "{pset}.{property}" "{actual}" ne correspond pas à {expected}',propertyDatatypeMismatch:'Le type de données de la propriété "{pset}.{property}" est "{actual}", attendu {expected}',propertyOutOfBounds:'La valeur de la propriété "{pset}.{property}" {actual} est hors de la plage {expected}',propertyProhibited:'La propriété interdite "{pset}.{property}" existe avec la valeur "{actual}"',classificationMissing:"Aucune classification attribuée",classificationSystemMismatch:'Le système de classification "{actual}" ne correspond pas à "{expected}" attendu',classificationSystemMissingAvailable:`Le système de classification "{expected}" n'a pas été trouvé. Disponibles : {available}`,classificationValueMismatch:'Le code de classification "{actual}" ne correspond pas à {expected} attendu',classificationValueMissingAvailable:"Le code de classification {expected} n'a pas été trouvé. Disponibles : {available}",classificationProhibited:'La classification interdite "{actual}" existe dans le système "{system}"',materialMissing:"Aucun matériau attribué",materialValueMismatch:'Le matériau "{actual}" ne correspond pas à {expected} attendu',materialValueMissingAvailable:"Le matériau {expected} n'a pas été trouvé. Disponibles : {available}",materialProhibited:'Le matériau interdit "{actual}" est attribué',partOfMissing:"L'élément n'est pas {relation} un(e) {entity}",partOfMissingSimple:"L'élément n'est pas {relation} un autre élément",partOfEntityMismatch:"L'élément parent est {actual}, attendu {expected}",partOfPredefinedMismatch:`Le type prédéfini de l'élément parent est "{actual}", attendu {expected}`,partOfProhibited:"L'élément est {relation} {actual}, ce qui est interdit",prohibited:'{field} interdit trouvé : "{actual}"',unknown:"Validation échouée : {reason}"},summary:{title:"Rapport de validation IDS",specifications:"{passed}/{total} spécifications conformes",entities:"{passed}/{total} éléments conformes ({percent}%)",overallPass:"Le modèle respecte toutes les exigences",overallFail:"Le modèle a {count} spécifications non conformes",noApplicable:"Aucun élément applicable trouvé"},ui:{specification:"Spécification",specifications:"Spécifications",requirement:"Exigence",requirements:"Exigences",applicability:"S'applique à",entity:"Élément",entities:"Éléments",passed:"Conforme",failed:"Non conforme",passRate:"Taux de conformité",actualValue:"Réel",expectedValue:"Attendu",failureReason:"Raison",showAll:"Afficher tout",showFailed:"Afficher non conformes",isolateFailed:"Isoler non conformes",isolatePassed:"Isoler conformes",exportJson:"Exporter JSON",exportBcf:"Exporter BCF",loadIds:"Charger fichier IDS",runValidation:"Lancer la validation",clearResults:"Effacer les résultats"}},N={en:xe,de:Te,fr:Me};function Ae(t="en"){return new ge(t)}class ge{locale;translations;constructor(e){this.locale=e,this.translations=N[e]||N.en}t(e,a){const i=e.split(".");let n=this.translations;for(const s of i)if(n&&typeof n=="object"&&s in n)n=n[s];else return e;return typeof n!="string"?e:a?this.interpolate(n,a):n}interpolate(e,a){return e.replace(/\{(\w+)\}/g,(i,n)=>n in a?String(a[n]):i)}describeFacet(e,a){switch(this.translations,e.type){case"entity":return this.describeEntityFacet(e,a);case"attribute":return this.describeAttributeFacet(e,a);case"property":return this.describePropertyFacet(e,a);case"classification":return this.describeClassificationFacet(e,a);case"material":return this.describeMaterialFacet(e,a);case"partOf":return this.describePartOfFacet(e,a);default:return"Unknown facet"}}describeEntityFacet(e,a){const i=this.translations,n=this.describeConstraint(e.name);return a==="applicability"?e.predefinedType?this.interpolate(i.applicability.entity.withPredefined,{entityType:n,predefinedType:this.describeConstraint(e.predefinedType)}):this.interpolate(i.applicability.entity.simple,{entityType:n}):e.predefinedType?this.interpolate(i.requirements.entity.mustBeWithPredefined,{entityType:n,predefinedType:this.describeConstraint(e.predefinedType)}):this.interpolate(i.requirements.entity.mustBe,{entityType:n})}describeAttributeFacet(e,a){const i=this.translations,n=this.describeConstraint(e.name);return a==="applicability"?e.value?e.value.type==="pattern"?this.interpolate(i.applicability.attribute.pattern,{name:n,pattern:this.describeConstraint(e.value)}):this.interpolate(i.applicability.attribute.equals,{name:n,value:this.describeConstraint(e.value)}):this.interpolate(i.applicability.attribute.exists,{name:n}):e.value?e.value.type==="pattern"?this.interpolate(i.requirements.attribute.mustMatch,{name:n,pattern:this.describeConstraint(e.value)}):this.interpolate(i.requirements.attribute.mustEqual,{name:n,value:this.describeConstraint(e.value)}):this.interpolate(i.requirements.attribute.mustExist,{name:n})}describePropertyFacet(e,a){const i=this.translations,n=this.describeConstraint(e.propertySet),s=this.describeConstraint(e.baseName);return a==="applicability"?e.value?e.value.type==="pattern"?this.interpolate(i.applicability.property.pattern,{pset:n,property:s,pattern:this.describeConstraint(e.value)}):e.value.type==="bounds"?this.interpolate(i.applicability.property.bounded,{pset:n,property:s,bounds:this.describeConstraint(e.value)}):this.interpolate(i.applicability.property.equals,{pset:n,property:s,value:this.describeConstraint(e.value)}):this.interpolate(i.applicability.property.exists,{pset:n,property:s}):e.value?e.value.type==="pattern"?this.interpolate(i.requirements.property.mustMatch,{pset:n,property:s,pattern:this.describeConstraint(e.value)}):e.value.type==="bounds"?this.interpolate(i.requirements.property.mustBeBounded,{pset:n,property:s,bounds:this.describeConstraint(e.value)}):this.interpolate(i.requirements.property.mustEqual,{pset:n,property:s,value:this.describeConstraint(e.value)}):this.interpolate(i.requirements.property.mustExist,{pset:n,property:s})}describeClassificationFacet(e,a){const i=this.translations;return a==="applicability"?e.system&&e.value?this.interpolate(i.applicability.classification.systemAndValue,{system:this.describeConstraint(e.system),value:this.describeConstraint(e.value)}):e.system?this.interpolate(i.applicability.classification.system,{system:this.describeConstraint(e.system)}):e.value?this.interpolate(i.applicability.classification.value,{value:this.describeConstraint(e.value)}):i.applicability.classification.any:e.system&&e.value?this.interpolate(i.requirements.classification.mustBeInSystemWithValue,{system:this.describeConstraint(e.system),value:this.describeConstraint(e.value)}):e.system?this.interpolate(i.requirements.classification.mustBeInSystem,{system:this.describeConstraint(e.system)}):e.value?this.interpolate(i.requirements.classification.mustHaveValue,{value:this.describeConstraint(e.value)}):i.requirements.classification.mustHave}describeMaterialFacet(e,a){const i=this.translations;return a==="applicability"?e.value?e.value.type==="pattern"?this.interpolate(i.applicability.material.pattern,{pattern:this.describeConstraint(e.value)}):this.interpolate(i.applicability.material.value,{value:this.describeConstraint(e.value)}):i.applicability.material.any:e.value?e.value.type==="pattern"?this.interpolate(i.requirements.material.mustMatch,{pattern:this.describeConstraint(e.value)}):this.interpolate(i.requirements.material.mustBe,{value:this.describeConstraint(e.value)}):i.requirements.material.mustHave}describePartOfFacet(e,a){const i=this.translations,n=this.getRelationDescription(e.relation);return a==="applicability"?e.entity?e.entity.predefinedType?this.interpolate(i.applicability.partOf.withEntityAndType,{relation:n,entity:this.describeConstraint(e.entity.name),predefinedType:this.describeConstraint(e.entity.predefinedType)}):this.interpolate(i.applicability.partOf.withEntity,{relation:n,entity:this.describeConstraint(e.entity.name)}):this.interpolate(i.applicability.partOf.simple,{relation:n}):e.entity?this.interpolate(i.requirements.partOf.mustBe,{relation:n,entity:this.describeConstraint(e.entity.name)}):this.interpolate(i.requirements.partOf.mustBeSimple,{relation:n})}describeConstraint(e){const a=this.translations;switch(e.type){case"simpleValue":return this.interpolate(a.constraints.simpleValue,{value:e.value});case"pattern":return this.interpolate(a.constraints.pattern,{pattern:e.pattern});case"enumeration":return e.values.length===1?this.interpolate(a.constraints.enumeration.single,{value:e.values[0]}):this.interpolate(a.constraints.enumeration.multiple,{values:e.values.map(i=>`"${i}"`).join(", ")});case"bounds":return this.describeBounds(e);default:return"unknown constraint"}}describeBounds(e){const a=this.translations.constraints.bounds;return e.minInclusive!==void 0&&e.maxInclusive!==void 0?this.interpolate(a.between,{min:e.minInclusive,max:e.maxInclusive}):e.minInclusive!==void 0?this.interpolate(a.atLeast,{min:e.minInclusive}):e.maxInclusive!==void 0?this.interpolate(a.atMost,{max:e.maxInclusive}):e.minExclusive!==void 0?this.interpolate(a.greaterThan,{min:e.minExclusive}):e.maxExclusive!==void 0?this.interpolate(a.lessThan,{max:e.maxExclusive}):"any value"}describeFailure(e){const a=this.translations.failures;if(!e.failure)return e.actualValue&&e.expectedValue?`${e.actualValue} ≠ ${e.expectedValue}`:a.unknown.replace("{reason}","no details");const{type:i,field:n,actual:s,expected:r,context:u}=e.failure;switch(i){case"ENTITY_TYPE_MISMATCH":return this.interpolate(a.entityTypeMismatch,{actual:s||"?",expected:r||"?"});case"PREDEFINED_TYPE_MISMATCH":return this.interpolate(a.predefinedTypeMismatch,{actual:s||"?",expected:r||"?"});case"PREDEFINED_TYPE_MISSING":return this.interpolate(a.predefinedTypeMissing,{expected:r||"?"});case"ATTRIBUTE_MISSING":return this.interpolate(a.attributeMissing,{name:n||"?"});case"ATTRIBUTE_VALUE_MISMATCH":return this.interpolate(a.attributeValueMismatch,{name:n||"?",actual:s||"?",expected:r||"?"});case"ATTRIBUTE_PATTERN_MISMATCH":return this.interpolate(a.attributePatternMismatch,{name:n||"?",actual:s||"?",expected:r||"?"});case"PSET_MISSING":return u?.availablePsets?this.interpolate(a.psetMissingAvailable,{pset:n||r||"?",available:u.availablePsets}):this.interpolate(a.psetMissing,{pset:n||r||"?"});case"PROPERTY_MISSING":return u?.availableProperties?this.interpolate(a.propertyMissingAvailable,{property:n||"?",pset:u.propertySet||"?",available:u.availableProperties}):this.interpolate(a.propertyMissing,{property:n||"?",pset:u?.propertySet||"?"});case"PROPERTY_VALUE_MISMATCH":return this.interpolate(a.propertyValueMismatch,{pset:this.extractPsetFromField(n),property:this.extractPropertyFromField(n),actual:s||"?",expected:r||"?"});case"PROPERTY_DATATYPE_MISMATCH":return this.interpolate(a.propertyDatatypeMismatch,{pset:this.extractPsetFromField(n),property:this.extractPropertyFromField(n),actual:s||"?",expected:r||"?"});case"PROPERTY_OUT_OF_BOUNDS":return this.interpolate(a.propertyOutOfBounds,{pset:this.extractPsetFromField(n),property:this.extractPropertyFromField(n),actual:s||"?",expected:r||"?"});case"CLASSIFICATION_MISSING":return a.classificationMissing;case"CLASSIFICATION_SYSTEM_MISMATCH":return u?.availableSystems?this.interpolate(a.classificationSystemMissingAvailable,{expected:r||"?",available:u.availableSystems}):this.interpolate(a.classificationSystemMismatch,{actual:s||"?",expected:r||"?"});case"CLASSIFICATION_VALUE_MISMATCH":return u?.availableValues?this.interpolate(a.classificationValueMissingAvailable,{expected:r||"?",available:u.availableValues}):this.interpolate(a.classificationValueMismatch,{actual:s||"?",expected:r||"?"});case"MATERIAL_MISSING":return a.materialMissing;case"MATERIAL_VALUE_MISMATCH":return u?.availableMaterials?this.interpolate(a.materialValueMissingAvailable,{expected:r||"?",available:u.availableMaterials}):this.interpolate(a.materialValueMismatch,{actual:s||"?",expected:r||"?"});case"PARTOF_RELATION_MISSING":return u?.entity?this.interpolate(a.partOfMissing,{relation:this.getRelationDescription(n||"IfcRelContainedInSpatialStructure"),entity:u.entity}):this.interpolate(a.partOfMissingSimple,{relation:this.getRelationDescription(n||"IfcRelContainedInSpatialStructure")});case"PARTOF_ENTITY_MISMATCH":return this.interpolate(a.partOfEntityMismatch,{actual:s||"?",expected:r||"?"});case"PROHIBITED_ATTRIBUTE_EXISTS":case"PROHIBITED_PROPERTY_EXISTS":case"PROHIBITED_CLASSIFICATION_EXISTS":case"PROHIBITED_MATERIAL_EXISTS":return this.interpolate(a.prohibited,{field:n||"value",actual:s||"?"});default:return this.interpolate(a.unknown,{reason:i})}}extractPsetFromField(e){if(!e)return"?";const a=e.split(".");return a.length>1?a[0]:"?"}extractPropertyFromField(e){if(!e)return"?";const a=e.split(".");return a.length>1?a.slice(1).join("."):e}describeRequirement(e){let a=this.describeFacet(e.facet,"requirement");return e.optionality==="prohibited"?a=this.applyProhibited(a):e.optionality==="optional"&&(a=this.applyOptional(a)),a}applyProhibited(e){return e.replace(/^Must be/i,"Must NOT be").replace(/^Must have/i,"Must NOT have").replace(/^Muss/i,"Darf nicht").replace(/^Doit être/i,"Ne doit pas être").replace(/^Doit avoir/i,"Ne doit pas avoir")}applyOptional(e){return e.replace(/^Must/i,"Should").replace(/^Muss/i,"Sollte").replace(/^Doit/i,"Devrait")}getStatusText(e){return this.translations.status[e]}getOptionalityText(e){return this.translations.optionality[e]}getRelationDescription(e){return this.translations.relations[e]||e.replace("IfcRel","").toLowerCase()}}export{Ae as c,Ie as p,Se as v};
|
|
Binary file
|