PageSourceSearch

https://smartmanageai.ai/assets/BimViewer-CSqR6y42.js

js smartmanageai.ai collected 2026-10-05 15:07:43 UTC 32,037 bytes, 1 lines download raw bytes

1import{r as o,j as e}from"./vendor-react-DKbe1Umz.js";import{G as Fe,M as De,D as ze,S as Rt,C as tt,P as Ft,W as Et,a as Lt,O as kt,A as Tt,b as st,H as Gt,c as At,B as Oe,d as at,e as We,f as Bt,g as nt,V as ee,h as Ee,L as rt,i as ot,j as Pt,k as Dt,R as zt,l as Ot}from"./OrbitControls-tnvu5uAJ.js";import{IfcAPI as Wt,IFCRELDEFINESBYPROPERTIES as $t,IFCRELDEFINESBYTYPE as Vt,IFCRELASSOCIATESMATERIAL as _t,IFCRELCONTAINEDINSPATIALSTRUCTURE as _e,IFCBUILDINGSTOREY as ut,IFCRELAGGREGATES as Ut,IFCPROJECT as mt,IFCDUCTSEGMENT as Ht,IFCPIPESEGMENT as Yt,IFCFLOWFITTING as Zt,IFCFLOWTERMINAL as Kt,IFCFLOWSEGMENT as Qt,IFCOPENINGELEMENT as Xt,IFCCURTAINWALL as Jt,IFCFOOTING as qt,IFCCOVERING as es,IFCMEMBER as ts,IFCPLATE as ss,IFCFURNISHINGELEMENT as as,IFCRAILING as ns,IFCROOF as rs,IFCSTAIRFLIGHT as os,IFCSTAIR as is,IFCWINDOW as cs,IFCDOOR as ls,IFCBEAM as ds,IFCCOLUMN as us,IFCSLAB as ms,IFCWALLSTANDARDCASE as hs,IFCWALL as fs,IFCSPACE as ps,IFCBUILDING as xs,IFCSITE as gs}from"./web-ifc-api-ClTnnoLv.js";import{B as D,m as it,l as $e,aX as ws,k as bs}from"./index-DZ74KeH3.js";import{i as ys,cW as ct,gJ as vs,gK as Ns,fe as js,fd as Cs,b6 as Is,gL as Ms,ex as Ss,ew as Rs,cP as Fs,gM as Es,X as lt,b3 as Ls,c0 as ks,gN as Ts,ct as ht,Z as Gs,n as As,bz as Bs,cE as Ps}from"./vendor-ui-DMaW9-Ov.js";import"./vendor-data-CjSe2wkl.js";import"./vendor-charts-DWX9qznF.js";import"./vendor-dates-5UNeOyFW.js";import"./vendor-forms-C2vWC2ab.js";const Le={[mt]:"Project",[gs]:"Site",[xs]:"Building",[ut]:"Building Storey",[ps]:"Space",[fs]:"Wall",[hs]:"Wall",[ms]:"Slab",[us]:"Column",[ds]:"Beam",[ls]:"Door",[cs]:"Window",[is]:"Stair",[os]:"Stair Flight",[rs]:"Roof",[ns]:"Railing",[as]:"Furniture",[ss]:"Plate",[ts]:"Member",[es]:"Covering",[qt]:"Footing",[Jt]:"Curtain Wall",[Xt]:"Opening",[Qt]:"Flow Segment",[Kt]:"Flow Terminal",[Zt]:"Flow Fitting",[Yt]:"Pipe Segment",[Ht]:"Duct Segment"};function Ds(s){return s==null?"":typeof s=="object"?s.value!==void 0?String(s.value):"":String(s)}function ft({node:s,level:l,selectedIds:w,expandedIds:j,onToggle:M,onSelect:F}){const S=s.children.length>0,x=j.has(s.expressID),C=w.has(s.expressID);return e.jsxs("div",{children:[e.jsxs("div",{className:bs("flex items-center gap-1 px-1 py-0.5 text-xs cursor-pointer hover:bg-accent/50 rounded-sm transition-colors",C&&"bg-primary/20 text-primary font-medium"),style:{paddingLeft:`${l*12+4}px`},onClick:I=>F(s.expressID,I.shiftKey),"data-testid":`bim-tree-node-${s.expressID}`,children:[S?e.jsx("button",{className:"shrink-0 p-0.5",onClick:I=>{I.stopPropagation(),M(s.expressID)},"data-testid":`bim-tree-toggle-${s.expressID}`,children:x?e.jsx(Gs,{className:"w-3 h-3"}):e.jsx(As,{className:"w-3 h-3"})}):e.jsx("span",{className:"w-4 shrink-0"}),s.type==="Building"||s.type==="Building Storey"?e.jsx(Bs,{className:"w-3 h-3 shrink-0 text-muted-foreground"}):s.type==="Site"||s.type==="Project"?e.jsx(Ps,{className:"w-3 h-3 shrink-0 text-muted-foreground"}):e.jsx(ht,{className:"w-3 h-3 shrink-0 text-muted-foreground"}),e.jsx("span",{className:"truncate",children:s.name||s.type})]}),S&&x&&e.jsx("div",{children:s.children.map(I=>e.jsx(ft,{node:I,level:l+1,selectedIds:w,expandedIds:j,onToggle:M,onSelect:F},I.expressID))})]})}function zs(s,l,w){var I,v;const j=new Map,M=new Map;try{const m=s.GetLineIDsWithType(l,Ut);for(let i=0;i<m.size();i++)try{const d=s.GetLine(l,m.get(i)),g=(I=d==null?void 0:d.RelatingObject)==null?void 0:I.value,y=d==null?void 0:d.RelatedObjects;if(g&&Array.isArray(y)){const z=y.map(Y=>Y.value).filter(Boolean),L=j.get(g)||[];j.set(g,[...L,...z])}}catch(d){console.warn("[BIM] Failed to parse IfcRelAggregates entry:",d)}}catch(m){console.warn("[BIM] Failed to load IfcRelAggregates:",m)}try{const m=s.GetLineIDsWithType(l,_e);for(let i=0;i<m.size();i++)try{const d=s.GetLine(l,m.get(i)),g=(v=d==null?void 0:d.RelatingStructure)==null?void 0:v.value,y=d==null?void 0:d.RelatedElements;if(g&&Array.isArray(y)){const z=y.map(Y=>Y.value).filter(Boolean),L=M.get(g)||[];M.set(g,[...L,...z])}}catch(d){console.warn("[BIM] Failed to parse IfcRelContainedInSpatialStructure entry:",d)}}catch(m){console.warn("[BIM] Failed to load IfcRelContainedInSpatialStructure:",m)}function F(m){var i,d;try{const g=s.GetLine(l,m);return((i=g==null?void 0:g.Name)==null?void 0:i.value)||((d=g==null?void 0:g.LongName)==null?void 0:d.value)||""}catch(g){return console.warn(`[BIM] Failed to get name for element ${m}:`,g),""}}function S(m){var i,d,g;try{const y=s.GetLine(l,m),z=y==null?void 0:y.type;return z&&Le[z]?Le[z]:((g=(d=(i=y==null?void 0:y.constructor)==null?void 0:i.name)==null?void 0:d.replace("Ifc",""))==null?void 0:g.replace(/([A-Z])/g," $1").trim())||"Element"}catch(y){return console.warn(`[BIM] Failed to get type for element ${m}:`,y),"Element"}}function x(m){const i=F(m),d=S(m),g=[],y=j.get(m)||[];for(const L of y)g.push(x(L));const z=M.get(m)||[];for(const L of z)g.push(x(L));return{expressID:m,type:d,name:i||`${d} #${m}`,children:g}}const C=[];try{const m=s.GetLineIDsWithType(l,mt);for(let i=0;i<m.size();i++)C.push(x(m.get(i)))}catch(m){console.warn("[BIM] Failed to load IfcProject entries:",m)}return C.length===0?[{expressID:-1,type:"Model",name:w||"IFC Model",children:[]}]:C}function Ve(s,l,w){var j,M,F,S,x,C,I,v,m,i,d,g,y,z,L,Y,ne,se,fe,_,ye,Q;try{const f=s.GetLine(l,w),le=((j=f==null?void 0:f.Name)==null?void 0:j.value)||`Element #${w}`,de=f==null?void 0:f.type,ue=de&&Le[de]?Le[de]:"Element",O=[];O.push({name:"Express ID",value:String(w)}),(M=f==null?void 0:f.GlobalId)!=null&&M.value&&O.push({name:"Global ID",value:f.GlobalId.value}),(F=f==null?void 0:f.Name)!=null&&F.value&&O.push({name:"Name",value:f.Name.value}),(S=f==null?void 0:f.Description)!=null&&S.value&&O.push({name:"Description",value:f.Description.value}),(x=f==null?void 0:f.ObjectType)!=null&&x.value&&O.push({name:"Object Type",value:f.ObjectType.value}),(C=f==null?void 0:f.Tag)!=null&&C.value&&O.push({name:"Tag",value:f.Tag.value}),(I=f==null?void 0:f.LongName)!=null&&I.value&&O.push({name:"Long Name",value:f.LongName.value});try{const A=s.GetLineIDsWithType(l,$t);for(let B=0;B<A.size();B++)try{const b=s.GetLine(l,A.get(B)),X=b==null?void 0:b.RelatedObjects;if(!Array.isArray(X)||!X.some(k=>k.value===w))continue;const R=(v=b==null?void 0:b.RelatingPropertyDefinition)==null?void 0:v.value;if(!R)continue;const h=s.GetLine(l,R),$=((m=h==null?void 0:h.Name)==null?void 0:m.value)||"";if(h!=null&&h.HasProperties&&Array.isArray(h.HasProperties)){for(const k of h.HasProperties)if(k!=null&&k.value)try{const p=s.GetLine(l,k.value);(i=p==null?void 0:p.Name)!=null&&i.value&&(p==null?void 0:p.NominalValue)!==void 0&&O.push({name:`${$?$+" / ":""}${p.Name.value}`,value:Ds(p.NominalValue)})}catch(p){console.warn(`[BIM] Failed to read property ${k.value}:`,p)}}if(h!=null&&h.Quantities&&Array.isArray(h.Quantities)){for(const k of h.Quantities)if(k!=null&&k.value)try{const p=s.GetLine(l,k.value),xe=(d=p==null?void 0:p.Name)==null?void 0:d.value,ge=((g=p==null?void 0:p.LengthValue)==null?void 0:g.value)??((y=p==null?void 0:p.AreaValue)==null?void 0:y.value)??((z=p==null?void 0:p.VolumeValue)==null?void 0:z.value)??((L=p==null?void 0:p.CountValue)==null?void 0:L.value)??((Y=p==null?void 0:p.WeightV
1alue)==null?void 0:Y.value);xe&&ge!==void 0&&O.push({name:`${$?$+" / ":""}${xe}`,value:String(ge)})}catch(p){console.warn(`[BIM] Failed to read quantity ${k.value}:`,p)}}}catch(b){console.warn("[BIM] Failed to parse IfcRelDefinesByProperties entry:",b)}}catch(A){console.warn("[BIM] Failed to load IfcRelDefinesByProperties:",A)}try{const A=s.GetLineIDsWithType(l,Vt);for(let B=0;B<A.size();B++)try{const b=s.GetLine(l,A.get(B)),X=b==null?void 0:b.RelatedObjects;if(!Array.isArray(X)||!X.some(h=>h.value===w))continue;const R=(ne=b==null?void 0:b.RelatingType)==null?void 0:ne.value;if(R){const h=s.GetLine(l,R);(se=h==null?void 0:h.Name)!=null&&se.value&&O.push({name:"Type Name",value:h.Name.value})}}catch(b){console.warn("[BIM] Failed to parse IfcRelDefinesByType entry:",b)}}catch(A){console.warn("[BIM] Failed to load IfcRelDefinesByType:",A)}try{const A=s.GetLineIDsWithType(l,_t);for(let B=0;B<A.size();B++)try{const b=s.GetLine(l,A.get(B)),X=b==null?void 0:b.RelatedObjects;if(!Array.isArray(X)||!X.some(h=>h.value===w))continue;const R=(fe=b==null?void 0:b.RelatingMaterial)==null?void 0:fe.value;if(R){const h=s.GetLine(l,R);if((_=h==null?void 0:h.Name)!=null&&_.value)O.push({name:"Material",value:h.Name.value});else if((ye=h==null?void 0:h.ForLayerSet)!=null&&ye.value){const $=s.GetLine(l,h.ForLayerSet.value);(Q=$==null?void 0:$.LayerSetName)!=null&&Q.value&&O.push({name:"Material Layer Set",value:$.LayerSetName.value})}}}catch(b){console.warn("[BIM] Failed to parse IfcRelAssociatesMaterial entry:",b)}}catch(A){console.warn("[BIM] Failed to load IfcRelAssociatesMaterial:",A)}return{expressID:w,type:ue,name:le,properties:O.slice(0,40)}}catch(f){return console.warn(`[BIM] Failed to get element properties for ${w}:`,f),null}}function Os(s,l,w){var j,M,F;try{const S=s.GetLineIDsWithType(l,_e);for(let x=0;x<S.size();x++)try{const C=s.GetLine(l,S.get(x)),I=C==null?void 0:C.RelatedElements;if(!Array.isArray(I)||!I.some(d=>d.value===w))continue;const m=(j=C==null?void 0:C.RelatingStructure)==null?void 0:j.value;if(!m)continue;const i=s.GetLine(l,m);if((i==null?void 0:i.type)===ut)return{expressID:m,name:((M=i==null?void 0:i.Name)==null?void 0:M.value)||((F=i==null?void 0:i.LongName)==null?void 0:F.value)||`Storey #${m}`}}catch(C){console.warn(`[BIM] Failed to check spatial containment for element ${w}:`,C)}}catch(S){console.warn(`[BIM] Failed to load spatial structure for element ${w}:`,S)}return null}function Ws(s){const l=[];function w(j){j.type==="Building Storey"&&l.push({expressID:j.expressID,name:j.name}),j.children.forEach(w)}return s.forEach(w),l}function $s(s,l,w){var M;const j=[];try{const F=s.GetLineIDsWithType(l,_e);for(let S=0;S<F.size();S++)try{const x=s.GetLine(l,F.get(S));if(((M=x==null?void 0:x.RelatingStructure)==null?void 0:M.value)!==w)continue;const I=x==null?void 0:x.RelatedElements;Array.isArray(I)&&I.forEach(v=>{v.value&&j.push(v.value)})}catch(x){console.warn(`[BIM] Failed to parse spatial containment entry for storey ${w}:`,x)}}catch(F){console.warn(`[BIM] Failed to load spatial structure for storey ${w}:`,F)}return j}function dt(){const s=[];typeof WebAssembly>"u"&&s.push("WebAssembly is not supported by your browser.");try{const l=document.createElement("canvas");l.getContext("webgl2")||l.getContext("webgl")||s.push("WebGL is not supported or is disabled in your browser.")}catch{s.push("Could not detect WebGL support.")}return{supported:s.length===0,warnings:s}}function Js({fileUrl:s,fileName:l,fileSize:w,uploadDate:j,onAddToTakeoff:M,onElementSelect:F,highlightStoreyId:S}){var Xe;const x=o.useRef(null),C=o.useRef(null),I=o.useRef(null),v=o.useRef(null),m=o.useRef(null),i=o.useRef(null),d=o.useRef(null),g=o.useRef(new Map),y=o.useRef(0),z=o.useRef(0),L=o.useRef(new Fe),Y=o.useRef(new Fe),[ne,se]=o.useState(!0),[fe,_]=o.useState(0),[ye,Q]=o.useState("Checking browser compatibility..."),[f,le]=o.useState(null),[de,ue]=o.useState([]),[O,A]=o.useState(0),[B,b]=o.useState([]),[X,pe]=o.useState(new Set),[R,h]=o.useState(new Set),[$,k]=o.useState(null),[p,xe]=o.useState(!0),[ge,Ue]=o.useState(!0),[U,ve]=o.useState("orbit"),[He,ke]=o.useState([]),[pt,re]=o.useState([]),[xt,Te]=o.useState(!1),Ye=o.useMemo(()=>new De({color:43775,transparent:!0,opacity:.85,side:ze}),[]),Ze=o.useMemo(()=>new De({color:16746496,transparent:!0,opacity:.6,side:ze}),[]),oe=o.useRef(new Map);o.useMemo(()=>Ws(B),[B]);const ae=o.useMemo(()=>
1{if(R.size===0||!d.current)return[];const t=[];for(const a of R){const n=Ve(d.current,y.current,a);if(n){const r={};for(const u of n.properties){const N=u.name.toLowerCase();N.includes("length")&&(r.length=parseFloat(u.value)||void 0),N.includes("area")&&(r.area=parseFloat(u.value)||void 0),N.includes("volume")&&(r.volume=parseFloat(u.value)||void 0)}const c=n.properties.find(u=>u.name==="Material"||u.name==="Material Layer Set");t.push({expressID:n.expressID,type:n.type,name:n.name,material:c==null?void 0:c.value,dimensions:r,properties:n.properties})}}return t},[R]);o.useEffect(()=>{if(R.size>0?Te(!0):Te(!1),F&&d.current){const t=[];for(const a of R){const n=Ve(d.current,y.current,a);if(n){const r=Os(d.current,y.current,a);t.push({expressID:a,type:n.type,name:n.name,storeyExpressId:r==null?void 0:r.expressID,storeyName:r==null?void 0:r.name})}}F(t)}},[R,F]),o.useEffect(()=>{if(!d.current||ne)return;const t=S?$s(d.current,y.current,S):[];g.current.forEach((a,n)=>{const r=oe.current.get(n);r&&(R.has(n)||(t.includes(n)?a.forEach(c=>{c.material=Ze}):a.forEach(c=>{const u=r.get(c);u&&(c.material=u)})))})},[S,ne,R,Ze]);const Ke=o.useCallback(()=>{if(!x.current||!C.current)return;const t=dt();if(!t.supported){ue(t.warnings),le("3D viewer could not load. Your browser may not support this feature, or there was a network issue."),se(!1);return}const a=new Rt;a.background=new tt(15790320),I.current=a;const n=x.current.clientWidth,r=x.current.clientHeight,c=new Ft(45,n/r,.1,1e4);c.position.set(30,30,30),v.current=c;let u;try{u=new Et({canvas:C.current,antialias:!0,alpha:!0})}catch{ue(["WebGL renderer failed to initialize. Your browser or GPU may not support WebGL."]),le("3D viewer could not load. Your browser may not support this feature, or there was a network issue."),se(!1);return}u.setSize(n,r),u.setPixelRatio(Math.min(window.devicePixelRatio,2)),u.shadowMap.enabled=!0,u.shadowMap.type=Lt,m.current=u;const N=new kt(c,u.domElement);N.enableDamping=!0,N.dampingFactor=.1,N.screenSpacePanning=!0,N.minDistance=.5,N.maxDistance=5e3,i.current=N,a.add(new Tt(16777215,.6));const E=new st(16777215,.8);E.position.set(50,100,50),E.castShadow=!0,a.add(E);const P=new st(16777215,.3);P.position.set(-50,50,-50),a.add(P),a.add(new Gt(14544639,986637,.3)),a.add(new At(200,50,13421772,14737632)),a.add(L.current),a.add(Y.current);const G=()=>{z.current=requestAnimationFrame(G),N.update(),u.render(a,c)};G();const T=()=>{if(!x.current)return;const H=x.current.clientWidth,Z=x.current.clientHeight;c.aspect=H/Z,c.updateProjectionMatrix(),u.setSize(H,Z)},V=new ResizeObserver(T);return V.observe(x.current),()=>{V.disconnect(),cancelAnimationFrame(z.current),u.dispose(),N.dispose()}},[]),Qe=o.useCallback(async()=>{var t;try{Q("Checking browser compatibility..."),_(2);const a=dt();if(!a.supported)throw ue(a.warnings),new Error("3D viewer could not load. Your browser may not support this feature, or there was a network issue.");Q("Loading 3D engine..."),_(5);const n=new Wt;n.SetWasmPath("/"),await n.Init(),d.current=n,Q("Downloading IFC file..."),_(15);const r=await fetch(s);if(!r.ok)throw new Error(`Failed to download file: ${r.statusText}`);const c=r.headers.get("content-length"),u=c?parseInt(c,10):0,N=(t=r.body)==null?void 0:t.getReader();if(!N)throw new Error("Failed to read file stream");const E=[];let P=0;for(;;){const{done:W,value:J}=await N.read();if(W)break;E.push(J),P+=J.length,u>0&&_(15+Math.floor(P/u*40))}const G=new Uint8Array(P);let T=0;for(const W of E)G.set(W,T),T+=W.length;Q("Processing model data..."),_(60);const V=n.OpenModel(G);if(y.current=V,Q("Building 3D geometry..."),_(70),!I.current)throw new Error("Scene not initialized");const H=g.current;H.clear(),oe.current.clear();const Z=n.LoadAllGeometry(V),me=Z.size();for(let W=0;W<me;W++){const J=Z.get(W),K=J.expressID,Je=J.geometries;for(let Pe=0;Pe<Je.size();Pe++){const ce=Je.get(Pe),Ie=n.GetGeometry(V,ce.geometryExpressID),q=n.GetVertexArray(Ie.GetVertexData(),Ie.GetVertexDataSize()),qe=n.GetIndexArray(Ie.GetIndexData(),Ie.GetIndexDataSize());if(q.length===0||qe.length===0)continue;const Me=new Oe,Se=new Float32Array(q.length/2),Re=new Float32Array(q.length/2);for(let te=0;te<q.length;te+=6){const he=te/2;Se[he]=q[te],Se[he+1]=q[te+1],Se[he+2]=q[te+2],Re[he]=q[te+3],Re[he+1]=q[te+4],Re[he+2]=q[te+5]}Me.setAttribute("position",new at(Se,3)),Me.setAttribute("normal",new at(Re,3)),Me.setIndex(Array.from(qe));const Mt=new tt(ce.color.x,ce.color.y,ce.color.z),et=new De({color:Mt,transparent:ce.color.w<1,opacity:ce.color.w,side:ze,roughness:.7,metalness:.1}),be=new We(Me,et);be.userData.expressID=K;const St=new Bt().fromArray(ce.flatTransformation);be.applyMatrix4(St),L.current.add(be),H.has(K)||H.set(K,[]),H.get(K).push(be),oe.current.has(K)||oe.current.set(K,new Map),oe.current.get(K).set(be,et)}W%50===0&&_(70+Math.floor(W/me*20))}Q("Building model tree..."),_(92);const Ce=zs(n,V,l);b(Ce);const we=new Set,Be=(W,J)=>{if(!(J>3))for(const K of W)K.children.length>0&&(we.add(K.expressID),Be(K.children,J+1))};Be(Ce,0),pe(we),Ne(),_(100),Q("Model loaded"),se(!1)}catch(a){console.error("IFC load error:",a),le("3D viewer could not load. Your browser may not support this feature, or there was a network issue."),se(!1)}},[s,l]),Ne=o.useCallback(()=>{const t=L.current;if(t.children.length===0)return;const a=new nt().setFromObject(t),n=a.getCenter(new ee),r=a.getSize(new ee),c=Math.max(r.x,r.y,r.z);if(v.current&&i.current){const u=v.current.fov*(Math.PI/180),N=c/(2*Math.tan(u/2))*1.5;v.current.position.set(n.x+N*.5,n.y+N*.5,n.z+N*.5),v.current.near=c*.001,v.current.far=c*100,v.current.updateProjectionMatrix(),i.current.target.copy(n),i.current.update(
1)}},[]),ie=o.useCallback(t=>{g.current.forEach((a,n)=>{const r=oe.current.get(n);r&&(t.has(n)?a.forEach(c=>{c.material=Ye}):a.forEach(c=>{const u=r.get(c);u&&(c.material=u)}))})},[Ye]),je=o.useCallback((t,a=!1)=>{if(t<0){h(new Set),k(null),ie(new Set);return}h(r=>{let c;return a?(c=new Set(r),c.has(t)?c.delete(t):c.add(t)):c=new Set([t]),ie(c),c});const n=g.current.get(t);if(n&&n.length>0){const r=new nt;n.forEach(u=>r.expandByObject(u));const c=r.getCenter(new ee);i.current&&(i.current.target.copy(c),i.current.update())}if(d.current){const r=Ve(d.current,y.current,t);k(r)}},[ie]),gt=o.useCallback(t=>{pe(a=>{const n=new Set(a);return n.has(t)?n.delete(t):n.add(t),n})},[]),wt=o.useCallback(()=>{Ne(),h(new Set),ie(new Set),k(null),re([])},[Ne,ie]),bt=o.useCallback(()=>{if(v.current&&i.current){const t=new ee;v.current.getWorldDirection(t),v.current.position.addScaledVector(t,5),i.current.update()}},[]),yt=o.useCallback(()=>{if(v.current&&i.current){const t=new ee;v.current.getWorldDirection(t),v.current.position.addScaledVector(t,-5),i.current.update()}},[]),Ge=o.useCallback(()=>{i.current&&(i.current.mouseButtons.LEFT=Ee.ROTATE,ve("orbit"),re([]))},[]),vt=o.useCallback(()=>{i.current&&(i.current.mouseButtons.LEFT=Ee.PAN,ve("pan"),re([]))},[]),Nt=o.useCallback(()=>{i.current&&(i.current.mouseButtons.LEFT=Ee.ROTATE,ve("measure_distance"),re([]))},[]),jt=o.useCallback(()=>{i.current&&(i.current.mouseButtons.LEFT=Ee.ROTATE,ve("measure_area"),re([]))},[]),Ae=o.useCallback(t=>{const a=Y.current;if(t.type==="distance"&&t.points.length===2){const n=t.points[0],r=t.points[1],c=new rt({color:16729156,linewidth:2}),u=new Oe().setFromPoints([n,r]),N=new ot(u,c);N.userData.measurementId=t.id,a.add(N);const E=new Pt(.15,8,8),P=new Dt({color:16729156}),G=new We(E,P);G.position.copy(n),G.userData.measurementId=t.id,a.add(G);const T=new We(E,P);T.position.copy(r),T.userData.measurementId=t.id,a.add(T)}else if(t.type==="area"&&t.points.length>=3){const n=t.points,r=new Oe().setFromPoints([...n,n[0]]),c=new rt({color:4500223,linewidth:2}),u=new ot(r,c);u.userData.measurementId=t.id,a.add(u)}},[]),Ct=o.useCallback(t=>{const a=Y.current;a.children.filter(r=>r.userData.measurementId===t).forEach(r=>{a.remove(r),r.geometry&&r.geometry.dispose(),r.material&&r.material.dispose()}),ke(r=>r.filter(c=>c.id!==t))},[]);o.useEffect(()=>{const t=C.current;if(!t||!I.current||!v.current)return;const a=new zt,n=new Ot,r=c=>{if(!x.current||!v.current)return;const u=t.getBoundingClientRect();if(n.x=(c.clientX-u.left)/u.width*2-1,n.y=-((c.clientY-u.top)/u.height)*2+1,a.setFromCamera(n,v.current),U==="measure_distance"){const E=a.intersectObjects(L.current.children,!0);if(E.length>0){const P=E[0].point.clone();re(G=>{const T=[...G,P];if(T.length===2){const V=T[0].distanceTo(T[1]),Z={id:`dist-${Date.now()}`,type:"distance",points:T,value:V,label:`${V.toFixed(2)} m`};return ke(me=>[...me,Z]),Ae(Z),[]}return T})}return}if(U==="measure_area"){const E=a.intersectObjects(L.current.children,!0);if(E.length>0){const P=E[0].face,G=E[0].object;if(P&&G.geometry){const T=G.geometry.attributes.position,V=new ee().fromBufferAttribute(T,P.a).applyMatrix4(G.matrixWorld),H=new ee().fromBufferAttribute(T,P.b).applyMatrix4(G.matrixWorld),Z=new ee().fromBufferAttribute(T,P.c).applyMatrix4(G.matrixWorld),me=new ee().subVectors(H,V),Ce=new ee().subVectors(Z,V),we=me.cross(Ce).length()/2,W={id:`area-${Date.now()}`,type:"area",points:[V,H,Z],value:we,label:`${we.toFixed(2)} m²`};ke(J=>[...J,W]),Ae(W)}}return}const N=a.intersectObjects(L.current.children,!0);if(N.length>0){const E=N[0].object.userData.expressID;E!==void 0&&je(E,c.shiftKey)}else c.shiftKey||je(-1)};return t.addEventListener("click",r),()=>t.removeEventListener("click",r)},[je,U,Ae]),o.useEffect(()=>{const t=a=>{a.key==="Escape"&&(h(new Set),ie(new Set),k(null),re([]),(U==="measure_distance"||U==="measure_area")&&Ge())};return window.addEventListener("keydown",t),()=>window.removeEventListener("keydown",t)},[ie,U,Ge]),o.useEffect(()=>{L.current=new Fe,Y.current=new Fe,g.current.clear(),oe.current.clear();const t=Ke();return I.current&&Qe(),()=>{if(t==null||t(),d.current)try{d.current.CloseModel(y.current)}catch(a){console.warn("[BIM] Failed to close model:",a)}}},[Ke,Qe,O]);const It=o.useCallback(()=>{M&&ae.length>0&&M(ae)},[M,ae]);return f?e.jsxs("div",{className:"flex flex-col items-center justify-center h-full p-8 text-center","data-testid":"bim-viewer-error",children:[e.jsx(ys,{className:"w-16 h-16 text-destructive/50 mb-4"}),e.jsx("h3",{className:"text-lg font-semibold mb-2","data-testid":"bim-error-title",children:"Failed to Load BIM Model"}),e.jsx("p",{className:"text-sm text-muted-foreground max-w-md mb-4","data-testid":"bim-error-message",children:f}),de.length>0&&e.jsx("div",{className:"text-xs text-muted-foreground max-w-md mb-4 space-y-1","data-testid":"bim-compat-warnings",children:de.map((t,a)=>e.jsxs("p",{children:["• ",t]},a))}),(l||w!=null||j)&&e.jsxs("div",{className:"border rounded-lg p-4 mb-4 bg-muted/30 text-left max-w-sm w-full","data-testid":"bim-file-metadata",children:[e.jsx("p",{className:"text-xs font-medium text-muted-foreground uppercase tracking-wider mb-2",children:"File Information"}),e.jsxs("div",{className:"space-y-1 text-sm",children:[l&&e.jsxs("div",{className:"flex justify-between",children:[e.jsx("span",{className:"text-muted-foreground",children:"File name"}),e.jsx("span",{className:"font-medium truncate ml-2 max-w-[200px]","data-testid":"bim-meta-filename",children:l})]}),l&&e.jsxs("div",{className:"flex justify-between",children:[e.jsx("span",{className:"text-muted-foreground",children:"Format"}),e.jsx("span",{className:"font-medium","data-testid":"bim-meta-format",children:((Xe=l.split(".").pop())==null?void 0:Xe.toUpperCase())||"IFC"})]}),w!=null&&w>0&&e.jsxs("div",{className:"flex justify-between",children:[e.jsx("span",{className:"text-muted-foreground",children:"Size"}),e.jsxs("span",{className:"font-medium","data-testid":"bim-meta-size",children:[(w/(1024*1024)).toFixed(1)," MB"]})]}),j&&e.jsxs("div",{className:"flex justify-between",children:[e.jsx("span",{className:"text-muted-foreground",children:"Upload date"}),e.jsx("span",{className:"font-medium","data-testid":"bim-meta-date",children:new Date(j).toLocaleDateString()})]})]})]}),e.jsxs(D,{variant:"outline",onClick:()=>{le(null),ue([]),se(!0),_(0),A(t=>t+1)},"data-testid":"bim-retry-button",children:[e.jsx(ct,{className:"w-4 h-4 mr-2"})," Retry"]})]}):e.jsxs("div",{className:"flex h-full w-full","data-testid":"bim-viewer",children:[p&&e.jsxs("div",{className:"w-56 border-r bg-card flex flex-col shrink-0","data-testid":"bim-model-tree",children:[e.jsxs("div",{className:"flex items-center justify-between px-2 py-1.5 border-b",children:[e.jsx("span",{className:"text-xs font-semibold uppercase tracking-wider text-muted-foreground",children:"Model Tree"}),e.jsx(D,{size:"icon",variant:"ghost",className:"h-6 w-6",onClick:()=>xe(!1),"data-testid":"bim-hide-tree",children:e.jsx(vs,{className:"w-3.5 h-3.5"})})]}),e.jsx(it,{className:"flex-1",children:e.jsx("div",{className:"py-1",children:B.length===0&&!ne?e.jsx("div",{className:"px-3 py-4 text-xs text-muted-foreground text-center",children:"No elements found"}):B.map(t=>e.jsx(ft,{node:t,level:0,selectedIds:R,expandedIds:X,onToggle:gt,onSelect:je},t.expressID))})})]}),e.jsxs("div",{className:"flex-1 flex flex-col min-w-0 relative",ref:x,children:[e.jsxs("div",{className:"absolute top-2 left-2 z-10 flex gap-1 bg-background/80 backdrop-blur-sm rounded-md border p-1","data-testid":"bim-toolbar",children:[!p&&e.jsx(D,{size:"icon",variant:"ghost",className:"h-7 w-7",onClick:()=>xe(!0),title:"Show Tree","data-testid":"bim-show-tree",children:e.jsx(Ns,{className:"w-3.5 h-3.5"})}),e.jsx(D,{size:"icon",variant:U==="orbit"?"secondary":"ghost",className:"h-7 w-7",onClick:Ge,title:"Orbit","data-testid":"bim-orbit-button",children:e.jsx(js,{className:"w-3.5 h-3.5"})}),e.jsx(D,{size:"icon",variant:U==="pan"?"secondary":"ghost",className:"h-7 w-7",onClick:vt,title:"Pan","data-testid":"bim-pan-button",children:e.jsx(Cs,{className:"w-3.5 h-3.5"})}),e.jsx(D,{size:"icon",variant:U==="measure_distance"?"secondary":"ghost",className:"h-7 w-7",onClick:Nt,title:"Measure Distance","data-testid":"bim-measure-distance-button",children:e.jsx(Is,{className:"w-3.5 h-3.5"})}),e.jsx(D,{size:"icon",variant:U==="measure_area"?"secondary":"ghost",className:"h-7 w-7",onClick:jt,title:"Measure Surface Area","data-testid":"bim-measure-area-button",children:e.jsx(Ms,{className:"w-3.5 h-3.5"})}),e.jsx(D,{size:"icon",variant:"ghost",className:"h-7 w-7",onClick:bt,title:"Zoom In","data-testid":"bim-zoom-in",children:e.jsx(Ss,{className:"w-3.5 h-3.5"})}),e.jsx(D,{size:"icon",variant:"ghost",className:"h-7 w-7",onClick:yt,title:"Zoom Out","data-testid":"bim-zoom-out",children:e.jsx(Rs,{className:"w-3.5 h-3.5"})}),e.jsx(D,{size:"icon",variant:"ghost",className:"h-7 w-7",onClick:Ne,title:"Fit All","data-testid":"bim-fit-all",children:e.jsx(Fs,{className:"w-3.5 h-3.5"})}),e.jsx(D,{size:"icon",variant:"ghost",className:"h-7 w-7",onClick:wt,title:"Reset View","data-testid":"bim-reset-view",children:e.jsx(ct,{className:"w-3.5 h-3.5"})}),!ge&&e.jsx(D,{size:"icon",variant:"ghost",className:"h-7 w-7",onClick:()=>Ue(!0),title:"Show Properties","data-testid":"bim-show-properties",children:e.jsx(Es,{className:"w-3.5 h-3.5"})}),R.size>0&&e.jsxs($e,{variant:"secondary",className:"text-[10px] px-1.5 ml-1","data-testid":"bim-selection-count",children:[R.size," selected"]})]}),(U==="measure_distance"||U==="measure_area")&&e.jsx("div",{className:"absolute top-12 left-2 z-10 bg-background/90 backdrop-blur-sm rounded-md border p-2 text-xs text-muted-foreground max-w-[220px]","data-testid":"bim-measure-hint",children:U==="measure_distance"?pt.length===0?"Click first point on the model to start measuring":"Click second point to complete distance measurement":"Click a surface on the model to measure its area"}),He.length>0&&e.jsxs("div",{className:"absolute bottom-2 left-2 z-10 bg-background/90 backdrop-blur-sm rounded-md border p-2 space-y-1 max-w-[250px] max-h-40 overflow-auto","data-testid":"bim-measurements-list",children:[e.jsx("span",{className:"text-[10px] font-semibold uppercase text-muted-foreground",children:"Measurements"}),He.map(t=>e.jsxs("div",{className:"flex items-center justify-between text-xs gap-2",children:[e.jsxs("span",{className:"truncate",children:[t.type==="distance"?"Distance":"Area",": ",t.label]}),e.jsx(D,{size:"icon",variant:"ghost",className:"h-4 w-4 shrink-0",onClick:()=>Ct(t.id),"data-testid":`bim-clear-measurement-${t.id}`,children:e.jsx(lt,{className:"w-3 h-3"})})]},t.id))]}),xt&&ae.length>0&&e.jsxs("div",{className:"absolute bottom-2 right-2 z-10 bg-background/95 backdrop-blur-sm rounded-lg border shadow-lg p-3 w-72 max-h-60 overflow-auto","data-testid":"bim-action-panel",children:[e.jsxs("div",{className:"flex items-center justify-between mb-2",children:[e.jsx("span",{className:"text-xs font-semibold uppercase text-muted-foreground",children:"Selection Summary"}),e.jsx(D,{size:"icon",variant:"ghost",className:"h-5 w-5",onClick:()=>Te(!1),"data-testid":"bim-close-action-panel",children:e.jsx(lt,{className:"w-3 h-3"})})]}),e.jsxs("div",{className:"space-y-1.5 mb-3",children:[ae.slice(0,5).map(t=>{var a,n,r;return e.jsxs("div",{className:"text-xs border-b border-border/50 pb-1 last:border-0",children:[e.jsxs("div",{className:"flex items-center gap-1.5",children:[e.jsx($e,{variant:"outline",className:"text-[9px] px-1 shrink-0",children:t.type}),e.jsx("span",{className:"truncate font-medium",children:t.name})]}),t.material&&e.jsxs("span",{className:"text-[10px] text-muted-foreground",children:["Material: ",t.material]}),e.jsxs("div",{className:"flex gap-2 text-[10px] text-muted-foreground mt-0.5",children:[((a=t.dimensions)==null?void 0:a.length)!==void 0&&e.jsxs("span",{children:["L: ",t.dimensions.length.toFixed(2)]}),((n=t.dimensions)==null?void 0:n.area)!==void 0&&e.jsxs("span",{children:["A: ",t.dimensions.area.toFixed(2)]}),((r=t.dimensions)==null?void 0:r.volume)!==void 0&&e.jsxs("span",{children:["V: ",t.dimensions.volume.toFixed(2)]})]})]},t.expressID)}),ae.length>5&&e.jsxs("div",{className:"text-[10px] text-muted-foreground",children:["...and ",ae.length-5," more elements"]})]}),M&&e.jsxs(D,{size:"sm",className:"w-full h-7 text-xs",onClick:It,"data-testid":"bim-add-to-takeoff",children:[e.jsx(Ls,{className:"w-3 h-3 mr-1"}),"Add to Takeoff (",ae.length,")"]})]}),ne&&e.jsxs("div",{className:"absolute inset-0 z-20 flex flex-col items-center justify-center bg-background/90 backdrop-blur-sm","data-testid":"bim-loading",children:[e.jsx(ks,{className:"w-10 h-10 animate-spin text-primary mb-4"}),e.jsx("p",{className:"text-sm font-medium mb-2","data-testid":"bim-loading-status",children:ye}),e.jsx("div",{className:"w-64",children:e.jsx(ws,{value:fe,className:"h-2","data-testid":"bim-loading-progress"})}),e.jsxs("p",{className:"text-xs text-muted-foreground mt-1",children:[fe,"%"]})]}),e.jsx("canvas",{ref:C,className:"w-full h-full block","data-testid":"bim-canvas"})]}),ge&&e.jsxs("div",{className:"w-64 border-l bg-card flex flex-col shrink-0","data-testid":"bim-properties-panel",children:[e.jsxs("div",{className:"flex items-center justify-between px-2 py-1.5 border-b",children:[e.jsx("span",{className:"text-xs font-semibold uppercase tracking-wider text-muted-foreground",children:"Properties"}),e.jsx(D,{size:"icon",variant:"ghost",className:"h-6 w-6",onClick:()=>Ue(!1),"data-testid":"bim-hide-properties",children:e.jsx(Ts,{className:"w-3.5 h-3.5"})})]}),e.jsx(it,{className:"flex-1",children:$?e.jsxs("div",{className:"p-2 space-y-3","data-testid":"bim-element-info",children:[e.jsxs("div",{children:[e.jsx("p",{className:"text-sm font-semibold break-words","data-testid":"bim-element-name",children:$.name}),e.jsx($e,{variant:"secondary",className:"text-[10px] mt-1","data-testid":"bim-element-type",children:$.type})]}),e.jsx("div",{className:"space-y-1",children:$.properties.map((t,a)=>e.jsxs("div",{className:"flex flex-col py-1 border-b border-border/50 last:border-0",children:[e.jsx("span",{className:"text-[10px] text-muted-foreground uppercase tracking-wider",children:t.name}),e.jsx("span",{className:"text-xs break-words","data-testid":`bim-prop-${a}`,children:t.value||"—"})]},a))})]}):e.jsxs("div",{className:"flex flex-col items-center justify-center h-40 text-center p-4","data-testid":"bim-no-selection",children:[e.jsx(ht,{className:"w-8 h-8 text-muted-foreground
1/30 mb-2"}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"Click an element in the 3D view or model tree to see its properties"})]})})]})]})}export{Js as default};

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.