From 95c7277e5588427149969efd92ec569a573c47b7 Mon Sep 17 00:00:00 2001
From: mie <79989386+mahach666@users.noreply.github.com>
Date: Thu, 12 Nov 2026 11:08:37 +0300
Subject: [PATCH 01/19] feat: add ViewerElement.SourceId and document metres
and Z up
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
ViewerElement.SourceId holds the element's id in its source format (a Revit
UniqueId or an IFC GlobalId); the numeric Id stays the viewer key. The HTML
page writes it to the META elements as "sourceId" only when set, the
properties panel shows it as its own row (Source ID / ID источника) and the
model tree search finds it. JSON round-trips it and leaves it out when null,
so snapshots of documents without source ids are unchanged.
ViewerDocument, ViewerMesh.Vertices, ViewerGeometry.Vertices and Transform3d
now state that the model is in metres with Z up.
---
CHANGELOG.md | 10 +++++++++
docs/public-api.md | 4 ++--
src/IOViewer/Exporters/ViewerPayloadWriter.cs | 1 +
src/IOViewer/Model/MathTypes.cs | 1 +
src/IOViewer/Model/ViewerDocument.cs | 5 +++++
src/IOViewer/Model/ViewerElement.cs | 8 +++++++
src/IOViewer/Model/ViewerGeometry.cs | 2 +-
src/IOViewer/Model/ViewerMesh.cs | 1 +
src/IOViewer/Viewer/dist/viewer.js | 5 +++--
src/IOViewer/Viewer/src/i18n.js | 2 ++
src/IOViewer/Viewer/src/ui/properties.js | 1 +
src/IOViewer/Viewer/src/ui/tree.js | 4 ++--
src/IOViewer/Viewer/test/e2e/ui.spec.js | 14 +++++++++++++
src/IOViewer/Viewer/test/unit/tree.test.js | 8 ++++++-
.../IOViewer.Tests/HtmlViewerExporterTests.cs | 21 +++++++++++++++++++
tests/IOViewer.Tests/JsonAndImportTests.cs | 16 ++++++++++++++
tests/fixtures/viewer/building.json | 1 +
tests/fixtures/viewer/escaping.json | 1 +
tests/fixtures/viewer/generate-fixtures.cs | 10 +++++++--
19 files changed, 105 insertions(+), 10 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 92b1c56..18cd239 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -6,6 +6,16 @@ API between minor releases.
## [Unreleased]
+### Added
+- `ViewerElement.SourceId`: the element's id in its source format, such as a Revit UniqueId or an IFC GlobalId. The
+ HTML viewer shows it as its own row in the properties panel ("Source ID" / "ID источника") and the model tree search
+ finds it. It is written to the page's element list and to JSON only when set, so the element data of documents
+ without it is written as before.
+
+### Changed
+- The documentation states the model's units and axes: all coordinates and lengths in a `ViewerDocument` are in
+ metres, with Z up.
+
## [0.2.0] - 2026-11-12
### Fixed
diff --git a/docs/public-api.md b/docs/public-api.md
index 720d85a..956b17e 100644
--- a/docs/public-api.md
+++ b/docs/public-api.md
@@ -6,8 +6,8 @@
### Document & Model (`IOViewer.Model`)
-- `ViewerDocument`: The root container holding elements, meshes, shared geometries, materials, textures, viewpoints, grids, section planes and box, clash tests, linked files, and 4D schedules.
-- `ViewerElement`: Represents a BIM element (Revit element, IFC product, Navisworks node) with properties and associated mesh parts.
+- `ViewerDocument`: The root container holding elements, meshes, shared geometries, materials, textures, viewpoints, grids, section planes and box, clash tests, linked files, and 4D schedules. All coordinates and lengths are in metres, with Z up; importers and adapters convert to this on the way in.
+- `ViewerElement`: Represents a BIM element (Revit element, IFC product, Navisworks node) with properties and associated mesh parts. `SourceId` optionally holds the element's id in its source format (for example a Revit UniqueId or an IFC GlobalId); the viewer shows it in the properties panel and finds it in the model tree search. The numeric `Id` stays the key that meshes, 4D tasks and clashes use.
- `ViewerMesh`: Triangulated 3D mesh geometry with vertex coordinates, triangle indices, normals, colors, and bounding box. A mesh can instead draw a shared `ViewerGeometry` (`GeometryId`) and place it with `Transform`.
- `ViewerGeometry`: Triangle geometry stored once in `ViewerDocument.Geometries` and drawn by every mesh that references its `Id`.
- `Transform3d`: Affine transform stored by columns (`XAxis`, `YAxis`, `ZAxis`, `Translation`), with `Identity`, `Translate`, `Apply` and `Then`.
diff --git a/src/IOViewer/Exporters/ViewerPayloadWriter.cs b/src/IOViewer/Exporters/ViewerPayloadWriter.cs
index dc0d946..6c2d305 100644
--- a/src/IOViewer/Exporters/ViewerPayloadWriter.cs
+++ b/src/IOViewer/Exporters/ViewerPayloadWriter.cs
@@ -539,6 +539,7 @@ public void WriteMeta(Stream output)
w.WriteString("level", el.Level);
if (string.IsNullOrEmpty(el.LinkName)) w.WriteNull("link");
else w.WriteString("link", el.LinkName);
+ if (!string.IsNullOrEmpty(el.SourceId)) w.WriteString("sourceId", el.SourceId);
w.WriteEndObject();
FlushIfLarge(w);
}
diff --git a/src/IOViewer/Model/MathTypes.cs b/src/IOViewer/Model/MathTypes.cs
index b2592d8..ec8a2fd 100644
--- a/src/IOViewer/Model/MathTypes.cs
+++ b/src/IOViewer/Model/MathTypes.cs
@@ -106,6 +106,7 @@ public BoundingBox3d Encapsulate(BoundingBox3d other)
/// Affine 3D transform stored by columns: the result of is
/// XAxis * p.X + YAxis * p.Y + ZAxis * p.Z + Translation.
///
+/// The translation is in metres, in the document's Z-up coordinates.
/// Image of the unit X vector (first matrix column).
/// Image of the unit Y vector (second matrix column).
/// Image of the unit Z vector (third matrix column).
diff --git a/src/IOViewer/Model/ViewerDocument.cs b/src/IOViewer/Model/ViewerDocument.cs
index 755b016..33b3bab 100644
--- a/src/IOViewer/Model/ViewerDocument.cs
+++ b/src/IOViewer/Model/ViewerDocument.cs
@@ -5,6 +5,11 @@ namespace IOViewer.Model;
///
/// Root container representing a 3D BIM/CAD model scene graph ready for interactive 3D WebGL viewing.
///
+///
+/// All coordinates and lengths in the document are in metres, in a right-handed system with Z up: vertices,
+/// transforms, bounding boxes, cameras, grids, sections and clash points. Producers convert to this on the way in
+/// (for example, converts glTF's Y-up).
+///
public sealed class ViewerDocument
{
public string Title { get; set; } = "3D BIM Model";
diff --git a/src/IOViewer/Model/ViewerElement.cs b/src/IOViewer/Model/ViewerElement.cs
index 18ed756..20985c0 100644
--- a/src/IOViewer/Model/ViewerElement.cs
+++ b/src/IOViewer/Model/ViewerElement.cs
@@ -14,6 +14,14 @@ public sealed class ViewerElement
public string Level { get; set; } = string.Empty;
public string? LinkName { get; set; }
+ ///
+ /// The element's id in its source format, e.g. a Revit UniqueId or an IFC GlobalId; null when there is none.
+ /// stays the key the viewer, meshes, 4D tasks and clashes use.
+ ///
+ // Left out of JSON when null, so snapshots of documents without source ids stay as they were.
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ public string? SourceId { get; set; }
+
///
/// Parameters grouped by property category (e.g. "Identity Data", "Dimensions", "Phasing").
///
diff --git a/src/IOViewer/Model/ViewerGeometry.cs b/src/IOViewer/Model/ViewerGeometry.cs
index bc338e6..9693ef9 100644
--- a/src/IOViewer/Model/ViewerGeometry.cs
+++ b/src/IOViewer/Model/ViewerGeometry.cs
@@ -8,7 +8,7 @@ public sealed class ViewerGeometry
/// Identifier referenced by .
public int Id { get; set; }
- /// Vertex positions in the geometry's local coordinates.
+ /// Vertex positions in the geometry's local coordinates, in metres with Z up.
public IReadOnlyList Vertices { get; set; } = [];
/// Triangle vertex indices (three per triangle).
diff --git a/src/IOViewer/Model/ViewerMesh.cs b/src/IOViewer/Model/ViewerMesh.cs
index 7b863a5..7e1e610 100644
--- a/src/IOViewer/Model/ViewerMesh.cs
+++ b/src/IOViewer/Model/ViewerMesh.cs
@@ -9,6 +9,7 @@ public sealed class ViewerMesh
public string Name { get; set; } = string.Empty;
public long? ElementId { get; set; }
+ /// Vertex positions in metres with Z up, placed by .
public IReadOnlyList Vertices { get; set; } = [];
public IReadOnlyList Indices { get; set; } = [];
public IReadOnlyList? Normals { get; set; }
diff --git a/src/IOViewer/Viewer/dist/viewer.js b/src/IOViewer/Viewer/dist/viewer.js
index 2671878..a8d0685 100644
--- a/src/IOViewer/Viewer/dist/viewer.js
+++ b/src/IOViewer/Viewer/dist/viewer.js
@@ -4252,7 +4252,7 @@ transformedNormal = - transformedNormal;
${Cc}`);t=di(t,"#include ",`${Ic}
vTint = state.rgb;`),t=di(t,"#include ","vec3 objectNormal = ioOct( normal.xy );"),t=di(t,"#include ",Tx),t=di(t,"#include ","vec3 transformed = slotPosition;"),t=di(t,"#include ",`#include
${Ex}`),i.vertexShader=t;let e=di(i.fragmentShader,"#include ",`#include
-varying vec3 vTint;`);e=di(e,"#include ","diffuseColor.rgb *= vTint;"),i.fragmentShader=e}function Pc(i,t,e=!1){return i.userData.slotUniforms=t,i.onBeforeCompile=Ax,i.index0AttributeName="q",e&&(i.defines={IO_NO_HIDE_BRANCH:""}),i}var Nc=["materials","textures","white","wireframe"],Rx=[245,158,11],Cx=[235,235,237],dr=4294967295,Di=2048,Lc=256,Ix=16,Md=1024,Px=.1,Lx=8192,Dx=1.4;function Nx(i,t){let[e,n,s,r,o,a,l,c,h]=i.subarray(t*12,t*12+9);return e*(o*h-a*c)-r*(n*h-s*c)+l*(n*a-s*o)<0}function Ux(){this.array=null}function yn(i,t,e=!1,n=we){return new n(i,t,e).onUpload(Ux)}var fr=class extends RangeError{constructor(t,e){super(`${t} drawable instances exceed the limit of ${e}.`),this.name="ModelTooLargeError",this.count=t,this.limit=e}},Sd=(i,t)=>{for(let e=t*6;e{let t=i.getHex(Se);return[t>>16&255,t>>8&255,t&255]},pr=class{constructor(t,e={}){let{meta:n}=t,s=n.instances,r=s.count,o=t.view(s.geometry),a=t.view(s.material),l=t.view(s.matrix);this.root=new be,this.elementCount=n.elements.length,this._elements=n.elements,this._meta=n,this._mode="materials",this._opacity=1,this._picking=!1,this._textures=new Map,this._elementOf=t.view(s.element).slice(),this._bucketOf=new Uint32Array(r),this._visible=new Uint8Array(r).fill(1),this._layers=new Map,this._layerHides=new Uint8Array(r),this._highlight=new Uint8Array(r),this._highlighted=[],this._tint=new Map,this._boxes=new Float32Array(r*6),this._minPixels=0,this._viewHeight=1,this.visibleCost=0;let c=!!e.noHideBranch;this.slotUniforms={slotInfo:{value:null},slotState:{value:null}},this._buckets=this._createBuckets(n,a,c),this._indexElements();let h=new Ht,d=new se;for(let p=0;pthis._shown(e)?1:0)}instancesOf(t){return this._checkElement(t),this._elementInstances.subarray(this._elementStart[t],this._elementStart[t+1])}isVisible(t){this._checkElement(t);for(let e=this._elementStart[t];e=0&&t<=1))throw new RangeError(`Opacity must be within 0..1, got ${t}.`);this._opacity=t;for(let e of this._buckets)this._applyOpacity(e);this._changed("appearance")}setDetail(t,e=1){this._minPixels=t,this._viewHeight=e;for(let s of this._cut)this._showUnit(s);this._cut.length=0;let n=this._unitScale;!(t>0)||!n||(this._unitScale=null,this._cutInView=0,this._cutFrame=null,this._units.forEach((s,r)=>{!(n[r]>=0)||s.shown===0||(s.dirty&&this._span(s),!(this._slotRadius[s.slotBase+s.first]*n[r]>=t)&&(s.mesh.visible=!1,s.lines&&(s.lines.visible=!1),this._cut.push(s),this._cutInView+=Dc(s,s.first,s.last+1)))}))}get totalCost(){return this._totalCost}detailThreshold(t,e,n){if(this.visibleCost=this._totalCost,this._totalCost<=n)return 0;t.updateMatrixWorld();let s=nd(t,this._planes),r=wc(t,e,this._detailView),o=this._pixels.fill(-1),a=this._state.image.data,l=this._unitScale=new Float64Array(this._units.length).fill(-1),c=0;for(let h=0;h0?r[6]/p:1/0:r[6];l[h]=g;for(let _=d.slotBase;_o-a)}memory(){let t=this._units[this._chunkCount]?.slotBase??this._slotInstance.length;return{gpuBytes:this._mergedBytes+this._instancedBytes+this._lineBytes+this._stateBytes,mergedBytes:this._mergedBytes,instancedBytes:this._instancedBytes,stateBytes:this._stateBytes,lineBytes:this._lineBytes,chunks:this._chunkCount,cells:this._units.length-this._chunkCount,mergedInstances:t,instancedInstances:this._slotInstance.length-t,triangles:this._triangles}}setClipping(t,e){for(let n of this._buckets)for(let s of[n.material,n.wire])s.clippingPlanes=t.length>0?t:null,s.clipIntersection=e,s.needsUpdate=!0;this._changed("clipping")}_build(t,e,n,s,r){let o=e.length,a=this._meta,l=new Map,c=B=>{let U=l.get(B);if(!U){let H=a.geometries[B],Z=t.view(H.indices),rt=H.uvs?t.view(H.uvs):null;U=yd(ad(t,H),H.q??null,ld(t,H),Z,rt),l.set(B,U)}return U},h=new Uint8Array(o),d=new Float64Array(o*3),u=new Float32Array(o*3),p=new Uint32Array(o),g=new Float32Array(o),_=new Uint8Array(o),m=new Map,f=this._boxes;for(let B=0;BB-U).map(B=>{let U=m.get(B),H=c(e[U[0]]),Z=this._buckets[this._bucketOf[U[0]]].texture!==null,rt=[0,1,2].every(Ft=>(H.max[Ft]-H.min[Ft])/Xn<=65535),at=H.vertices*((rt?12:20)+(Z?8:0))+H.indices.length*(H.vertices>65535?4:2);return{k:U.length,bytes:at,members:U,textured:Z}}),S=s.mergedCap??Ac,b=s.minRepeats??Ix;if(R.reduce((B,U)=>B+U.k*U.bytes,0)>S){let B=this.visibleBox(),U=B.isEmpty()?1/0:B.min.distanceTo(B.max)*(s.cellExtent??Px);for(let H of R)H.k{if(y[U]){for(let H of B.leaves)E.push({shape:B,members:Rc(H,g)});return}for(let H of B.members){v[e[H]]++;let Z=this._bucketOf[H]*2+(h[H]===ws?1:0),rt=T.get(Z);rt||T.set(Z,rt=[]),rt.push(H)}});let P=[];for(let B of[...T.keys()].sort((U,H)=>U-H))for(let U of dd(u,p,T.get(B),s.chunkVertices??cd))P.push(Rc(U,g));let D=[...P,...E.map(B=>B.members)].reduce((B,U)=>B+U.length,0);if(D>r)throw new fr(D,r);let z=Math.max(1,Math.ceil(D/Di)),O=new Float32Array(Di*z*4);this._state=new ei(new Uint8Array(Di*z*4),Di,z),this._state.colorSpace=Se,this._state.onUpdate=()=>{this._fullPending=!1,this._pendingRanges=0},this._fullPending=!0,this._pendingRanges=0,this._dirty=new Uint32Array(Lc),this._dirtyCount=0;let I=new ei(O,Di,z,tn,We);I.needsUpdate=!0,I.onUpdate=()=>I.image.data=null,this.slotUniforms.slotInfo.value=I,this.slotUniforms.slotState.value=this._state,this._stateBytes=Di*z*20,this._slotOf=new Uint32Array(o).fill(dr),this._slotInstance=new Uint32Array(D),this._slotUnit=new Uint32Array(D),this._slotRadius=new Float32Array(D),this._slotCost=new Float32Array(D),this._pixels=new Float32Array(D),this._planes=new Float64Array(24),this._detailView=new Float64Array(8),this._frameView=new Float64Array(8),this._frameViewAt=NaN,this._units=[],this._cut=[],this._unitScale=null,this._cutInView=0,this._cutFrame=-1,this._mergedBytes=0,this._instancedBytes=0,this._lineBytes=0;let k={matrices:n,geometryOf:e,mirrored:_,kind:h,origins:d,source:c,textured:!1};this._lineSources=new Map;let X=0;for(let B of P){let U=this._buckets[this._bucketOf[B[0]]];k.textured=U.texture!==null;let H=vd(B,k);for(let Z=0;ZB+U,0);let Y=new Map;for(let{shape:B,members:U}of E){let H=U[0],Z=c(e[H]),rt=Y.get(B);rt||Y.set(B,rt=this._shape(Z,_[H]===1,B.textured));for(let at=0;atB+U,0)}_shape(t,e,n){let s=t.vertices,r=t.q?new Uint16Array(s*4):new Float32Array(s*4);for(let h=0;hn+g),1,!1,Hn)),a.setIndex(s.index);let l=wd(this._boxes,e),c=new Le(new C(l[0],l[1],l[2]),l[3]);a.boundingSphere=c;let h=new cs(a,t.material,0),d=new Float32Array(o*16);for(let p=0;pthis._range(u,p,_,h),h.visible=!1,this.root.add(h),u}_chunk(t,e,n,s,r,o){let a=new fs;a.instanceCount=1,a.setAttribute("q",yn(s.q,4)),a.setAttribute("normal",yn(s.o,2,!0)),s.uv&&a.setAttribute("uv",yn(s.uv,2)),a.setAttribute("slotBase",yn(new Float32Array([n]),1,!1,Hn)),a.setIndex(yn(s.index,1));let l=wd(this._boxes,e);a.boundingSphere=new Le(new C(l[0],l[1],l[2]),l[3]),this._mergedBytes+=s.q.byteLength+s.o.byteLength+(s.uv?.byteLength??0)+s.index.byteLength;let c=new _e(a,t.material),h={bucket:t,mesh:c,lines:null,slotBase:n,n:e.length,sphere:l,shown:0,first:0,last:-1,end:0,dirty:!1,cell:!1,starts:s.indexStart,vertices:s.q.length/4,f32:s.q instanceof Float32Array,members:e.slice(),lastFrame:-1/0};return c.onBeforeRender=(d,u,p)=>this._range(h,d,p,c),c.visible=!1,this.root.add(c),h}_buildLines(){if(!this._lineSources)return;let{mirrored:t,geometryOf:e}=this._lineMembers;for(let n of this._units){if(n.cell){let h=n.mesh.geometry.index;n.lines=new cs(n.mesh.geometry,n.bucket.wire,0),n.lines.instanceMatrix=n.mesh.instanceMatrix,n.lines.boundingSphere=n.mesh.boundingSphere,n.lines.onBeforeRender=(d,u,p)=>this._range(n,d,p,n.lines),this._lineBytes+=h.count*2*h.array.BYTES_PER_ELEMENT,this.root.add(n.lines);continue}let s=n.starts[n.n],r=Ra(n.vertices,s*2),o=0,a=0;for(let h of n.members){let d=this._lineSources.get(e[h]),u=t[h]===1;for(let p=0;pthis._range(n,h,u,n.lines),this.root.add(n.lines),n.members=null}this._lineSources=null,this._lineMembers=null}_range(t,e,n,s){t.dirty&&this._span(t);let r=t.last+1;if(this._minPixels>0&&r>t.first){let o=e.info.render.frame;o!==this._frameViewAt&&(wc(n,this._viewHeight,this._frameView),this._frameViewAt=o);let a=this._frameView,l=bd(a,t.sphere),c=a[7]?l>0?this._minPixels*l/a[6]:0:this._minPixels/a[6];r=Math.min(r,gd(this._slotRadius,t.slotBase+t.first,t.slotBase+r,c)-t.slotBase)}if(t.cell)s.count=Math.max(r,0);else{let o=s.isLineSegments?2:1,[a,l]=_d(t.starts,t.first,r);s.geometry.setDrawRange(a*o,l*o)}t.end=r,t.lastFrame=e.info.render.frame,this._cutFrame===null&&this._minPixels>0&&(this._cutFrame=t.lastFrame)}_span(t){let e=this._state.image.data,n=0;for(;n=n&&e[(t.slotBase+s)*4+3]===0;)s--;t.first=n0&&!e,t.lines&&(t.lines.visible=t.shown>0&&e)}_createBuckets(t,e,n){let s=new Map,r=[];for(let o=0;oMath.round(h*255)),opacity:c.opacity,texture:c.texture,material:Pc(new ds({side:Be}),this.slotUniforms,n),wire:Pc(new ds({side:Be,wireframe:!0}),this.slotUniforms,n)},this._applyOpacity(l),s.set(a,l),r.push(l)}this._bucketOf[o]=l.index}return r}_indexElements(){let t=new Uint32Array(this.elementCount+1);for(let s of this._elementOf)s>=0&&t[s+1]++;for(let s=0;s{s>=0&&(e[n[s]++]=r)}),this._elementStart=t,this._elementInstances=e}_texture(t){let e=this._textures.get(t);if(!e){let n=this._meta.textures[t],s=new Image;e=new Ue(s),e.colorSpace=Se,e.wrapS=e.wrapT=ns,e.repeat.set(1/n.sx,1/n.sy),s.onload=()=>{e.needsUpdate=!0,this._changed("appearance")},s.src=`data:${n.mime};base64,${n.data}`,this._textures.set(t,e)}return e}_applyOpacity(t){let e=t.opacity*this._opacity,n=e<1;for(let s of[t.material,t.wire])s.transparent!==n&&(s.needsUpdate=!0),s.opacity=e,s.transparent=n,s.depthWrite=!n}_colorOf(t){return this._highlight[t]?Rx:this._tint.get(t)??(this._mode==="white"?Cx:this._buckets[this._bucketOf[t]].bytes)}_applyColor(t){let e=this._slotOf[t];e!==dr&&(this._state.image.data.set(this._colorOf(t),e*4),this._markDirty(e))}_setInstanceVisible(t,e){this._visible[t]=e?1:0,this._draw(t)}_setLayerFlag(t,e,n){t[e]!==(n?1:0)&&(t[e]=n?1:0,this._layerHides[e]+=n?1:-1,this._draw(e))}_shown(t){return this._visible[t]===1&&this._layerHides[t]===0}_draw(t){let e=this._slotOf[t];if(e===dr)return;let n=this._shown(t)?255:0,s=this._state.image.data;if(s[e*4+3]===n)return;s[e*4+3]=n,this._markDirty(e);let r=this._units[this._slotUnit[e]];r.shown+=n?1:-1,r.dirty=!0,this._showUnit(r)}_markDirty(t){this._dirtyCountLc)e.clearUpdateRanges(),this._fullPending=!0;else{for(let n=0;n=this.elementCount)throw new RangeError(`Element index ${t} is out of range 0..${this.elementCount-1}.`)}_expandBox(t,e){if(!Sd(this._boxes,e))return;let n=this._boxes,s=e*6;t.min.set(Math.min(t.min.x,n[s]),Math.min(t.min.y,n[s+1]),Math.min(t.min.z,n[s+2])),t.max.set(Math.max(t.max.x,n[s+3]),Math.max(t.max.y,n[s+4]),Math.max(t.max.z,n[s+5]))}_changed(t){this._flush(),this.root.dispatchEvent({type:"change",detail:{kind:t}})}};function Dc(i,t,e){return e<=t?0:i.cell?(e-t)*i.triangles:(i.starts[e]-i.starts[t])/3}function bd(i,t){return(t[0]-i[0])*i[3]+(t[1]-i[1])*i[4]+(t[2]-i[2])*i[5]-t[3]}function wd(i,t){let e=[1/0,1/0,1/0],n=[-1/0,-1/0,-1/0];for(let s of t)for(let r=0;r<3;r++)e[r]=Math.min(e[r],i[s*6+r]),n[r]=Math.max(n[r],i[s*6+3+r]);return Float64Array.of((e[0]+n[0])/2,(e[1]+n[1])/2,(e[2]+n[2])/2,Math.hypot(n[0]-e[0],n[1]-e[1],n[2]-e[2])/2)}var Bx={ru:{elements:"\u042D\u043B\u0435\u043C\u0435\u043D\u0442\u043E\u0432",noGeometry:"\u041D\u0435\u0442 \u0433\u0435\u043E\u043C\u0435\u0442\u0440\u0438\u0438",contextLost:"\u0412\u0438\u0434\u0435\u043E\u043A\u0430\u0440\u0442\u0430 \u0441\u0431\u0440\u043E\u0448\u0435\u043D\u0430 \u2014 \u043F\u0435\u0440\u0435\u0437\u0430\u0433\u0440\u0443\u0437\u0438\u0442\u0435 \u0441\u0442\u0440\u0430\u043D\u0438\u0446\u0443",noWebGL:"\u041D\u0443\u0436\u0435\u043D \u0431\u0440\u0430\u0443\u0437\u0435\u0440 \u0441 \u043F\u043E\u0434\u0434\u0435\u0440\u0436\u043A\u043E\u0439 WebGL 2",badData:"\u041D\u0435 \u0443\u0434\u0430\u043B\u043E\u0441\u044C \u043F\u0440\u043E\u0447\u0438\u0442\u0430\u0442\u044C \u0434\u0430\u043D\u043D\u044B\u0435 \u043C\u043E\u0434\u0435\u043B\u0438",tooLarge:"\u041C\u043E\u0434\u0435\u043B\u044C \u0441\u043B\u0438\u0448\u043A\u043E\u043C \u0431\u043E\u043B\u044C\u0448\u0430\u044F \u0434\u043B\u044F \u044D\u0442\u043E\u0433\u043E \u043F\u0440\u043E\u0441\u043C\u043E\u0442\u0440\u0449\u0438\u043A\u0430: \u043E\u0431\u044A\u0435\u043A\u0442\u043E\u0432 \u0441 \u0433\u0435\u043E\u043C\u0435\u0442\u0440\u0438\u0435\u0439 \u2014 {count}, \u043F\u0440\u0435\u0434\u0435\u043B \u2014 {limit}",selected:"\u0412\u044B\u0431\u0440\u0430\u043D\u043E",close:"\u0417\u0430\u043A\u0440\u044B\u0442\u044C",elementGroup:"\u042D\u043B\u0435\u043C\u0435\u043D\u0442",id:"Id",category:"\u041A\u0430\u0442\u0435\u0433\u043E\u0440\u0438\u044F",type:"\u0422\u0438\u043F",level:"\u0423\u0440\u043E\u0432\u0435\u043D\u044C",link:"\u0421\u0432\u044F\u0437\u0430\u043D\u043D\u044B\u0439 \u0444\u0430\u0439\u043B",panels:"\u041F\u0430\u043D\u0435\u043B\u0438","panel.model":"\u041C\u043E\u0434\u0435\u043B\u044C","panel.views":"\u0412\u0438\u0434\u044B","panel.sections":"\u0421\u0435\u0447\u0435\u043D\u0438\u044F","panel.clashes":"\u041A\u043E\u043B\u043B\u0438\u0437\u0438\u0438","panel.timeliner":"4D-\u0433\u0440\u0430\u0444\u0438\u043A","panel.links":"\u0421\u0432\u044F\u0437\u0430\u043D\u043D\u044B\u0435 \u0444\u0430\u0439\u043B\u044B","group.navigation":"\u041D\u0430\u0432\u0438\u0433\u0430\u0446\u0438\u044F","group.sections":"\u0421\u0435\u0447\u0435\u043D\u0438\u044F","group.measure":"\u0418\u0437\u043C\u0435\u0440\u0435\u043D\u0438\u044F","group.display":"\u041E\u0442\u043E\u0431\u0440\u0430\u0436\u0435\u043D\u0438\u0435","group.view":"\u0412\u0438\u0434","tool.orbit":"\u0412\u0440\u0430\u0449\u0435\u043D\u0438\u0435","tool.pan":"\u041F\u0430\u043D\u043E\u0440\u0430\u043C\u0430","tool.fit":"\u0412\u043F\u0438\u0441\u0430\u0442\u044C \u0432\u0441\u0451","tool.projection":"\u041F\u0435\u0440\u0441\u043F\u0435\u043A\u0442\u0438\u0432\u0430 / \u043E\u0440\u0442\u043E\u0433\u0440\u0430\u0444\u0438\u044F","tool.plane":"\u041F\u043B\u043E\u0441\u043A\u043E\u0441\u0442\u044C \u0441\u0435\u0447\u0435\u043D\u0438\u044F","tool.box":"\u0411\u043E\u043A\u0441 \u0441\u0435\u0447\u0435\u043D\u0438\u044F","tool.resetSections":"\u0421\u0431\u0440\u043E\u0441\u0438\u0442\u044C \u0441\u0435\u0447\u0435\u043D\u0438\u044F","tool.distance":"\u0420\u0430\u0441\u0441\u0442\u043E\u044F\u043D\u0438\u0435","tool.displayMode":"\u0420\u0435\u0436\u0438\u043C \u043E\u0442\u043E\u0431\u0440\u0430\u0436\u0435\u043D\u0438\u044F","tool.grids":"\u041E\u0441\u0438","tool.opacity":"\u041F\u0440\u043E\u0437\u0440\u0430\u0447\u043D\u043E\u0441\u0442\u044C","tool.fullscreen":"\u041F\u043E\u043B\u043D\u044B\u0439 \u044D\u043A\u0440\u0430\u043D","menu.properties":"\u0421\u0432\u043E\u0439\u0441\u0442\u0432\u0430","menu.hide":"\u0421\u043A\u0440\u044B\u0442\u044C","menu.isolate":"\u0418\u0437\u043E\u043B\u0438\u0440\u043E\u0432\u0430\u0442\u044C","menu.showAll":"\u041F\u043E\u043A\u0430\u0437\u0430\u0442\u044C \u0432\u0441\u0451","menu.zoomTo":"\u041F\u0440\u0438\u0431\u043B\u0438\u0437\u0438\u0442\u044C \u043A \u043E\u0431\u044A\u0435\u043A\u0442\u0443","menu.sectionBox":"\u0411\u043E\u043A\u0441 \u0441\u0435\u0447\u0435\u043D\u0438\u044F \u043F\u043E \u043E\u0431\u044A\u0435\u043A\u0442\u0443","menu.copyId":"\u041A\u043E\u043F\u0438\u0440\u043E\u0432\u0430\u0442\u044C Id","menu.fitAll":"\u0412\u043F\u0438\u0441\u0430\u0442\u044C \u0432\u0441\u0451","menu.resetSections":"\u0421\u0431\u0440\u043E\u0441\u0438\u0442\u044C \u0441\u0435\u0447\u0435\u043D\u0438\u044F",searchPlaceholder:"\u041F\u043E\u0438\u0441\u043A \u043F\u043E \u0438\u043C\u0435\u043D\u0438, \u0442\u0438\u043F\u0443, Id\u2026",noCategory:"\u0411\u0435\u0437 \u043A\u0430\u0442\u0435\u0433\u043E\u0440\u0438\u0438",noMatches:"\u041D\u0438\u0447\u0435\u0433\u043E \u043D\u0435 \u043D\u0430\u0439\u0434\u0435\u043D\u043E",idCopied:"Id \u0441\u043A\u043E\u043F\u0438\u0440\u043E\u0432\u0430\u043D",copyFailed:"\u041D\u0435 \u0443\u0434\u0430\u043B\u043E\u0441\u044C \u0441\u043A\u043E\u043F\u0438\u0440\u043E\u0432\u0430\u0442\u044C Id",fullscreenUnavailable:"\u041F\u043E\u043B\u043D\u043E\u044D\u043A\u0440\u0430\u043D\u043D\u044B\u0439 \u0440\u0435\u0436\u0438\u043C \u043D\u0435\u0434\u043E\u0441\u0442\u0443\u043F\u0435\u043D","face.front":"\u0421\u043F\u0435\u0440\u0435\u0434\u0438","face.back":"\u0421\u0437\u0430\u0434\u0438","face.left":"\u0421\u043B\u0435\u0432\u0430","face.right":"\u0421\u043F\u0440\u0430\u0432\u0430","face.top":"\u0421\u0432\u0435\u0440\u0445\u0443","face.bottom":"\u0421\u043D\u0438\u0437\u0443","cube.title":"\u041A\u0443\u0431 \u0432\u0438\u0434\u0430","cube.up":"\u041F\u043E\u0432\u0435\u0440\u043D\u0443\u0442\u044C \u0432\u0432\u0435\u0440\u0445","cube.down":"\u041F\u043E\u0432\u0435\u0440\u043D\u0443\u0442\u044C \u0432\u043D\u0438\u0437","cube.left":"\u041F\u043E\u0432\u0435\u0440\u043D\u0443\u0442\u044C \u0432\u043B\u0435\u0432\u043E","cube.right":"\u041F\u043E\u0432\u0435\u0440\u043D\u0443\u0442\u044C \u0432\u043F\u0440\u0430\u0432\u043E","cube.home":"\u0418\u0441\u0445\u043E\u0434\u043D\u044B\u0439 \u0432\u0438\u0434","sections.mode":"\u0420\u0435\u0436\u0438\u043C \u0441\u0435\u0447\u0435\u043D\u0438\u044F","sections.planes":"\u041F\u043B\u043E\u0441\u043A\u043E\u0441\u0442\u0438","sections.box":"\u0411\u043E\u043A\u0441","sections.off":"\u0412\u044B\u043A\u043B","sections.axis":"\u041E\u0441\u044C","sections.addPlane":"\u0414\u043E\u0431\u0430\u0432\u0438\u0442\u044C \u043F\u043B\u043E\u0441\u043A\u043E\u0441\u0442\u044C","sections.noPlanes":"\u041F\u043B\u043E\u0441\u043A\u043E\u0441\u0442\u0435\u0439 \u043D\u0435\u0442","sections.rotated":"\u043F\u043E\u0432\u0451\u0440\u043D\u0443\u0442\u0430","sections.position":"\u041F\u043E\u043B\u043E\u0436\u0435\u043D\u0438\u0435 \u043F\u043B\u043E\u0441\u043A\u043E\u0441\u0442\u0438","sections.flip":"\u0421\u043C\u0435\u043D\u0438\u0442\u044C \u0441\u0442\u043E\u0440\u043E\u043D\u0443","sections.enabled":"\u0412\u043A\u043B","sections.delete":"\u0423\u0434\u0430\u043B\u0438\u0442\u044C \u043F\u043B\u043E\u0441\u043A\u043E\u0441\u0442\u044C","sections.keepInside":"\u041F\u043E\u043A\u0430\u0437\u0430\u0442\u044C \u0432\u043D\u0443\u0442\u0440\u0438","sections.cutInside":"\u0412\u044B\u0440\u0435\u0437\u0430\u0442\u044C \u0432\u043D\u0443\u0442\u0440\u0438","sections.fitSelection":"\u041F\u043E \u0432\u044B\u0434\u0435\u043B\u0435\u043D\u043D\u043E\u043C\u0443","sections.showGizmo":"\u041F\u043E\u043A\u0430\u0437\u044B\u0432\u0430\u0442\u044C \u043C\u0430\u043D\u0438\u043F\u0443\u043B\u044F\u0442\u043E\u0440","sections.maxPlanes":"\u041D\u0435 \u0431\u043E\u043B\u044C\u0448\u0435 6 \u043F\u043B\u043E\u0441\u043A\u043E\u0441\u0442\u0435\u0439","unit.m":"\u043C","display.materials":"\u041C\u0430\u0442\u0435\u0440\u0438\u0430\u043B\u044B","display.textures":"\u0422\u0435\u043A\u0441\u0442\u0443\u0440\u044B","display.white":"\u0411\u0435\u043B\u044B\u0439","display.wireframe":"\u041A\u0430\u0440\u043A\u0430\u0441","opacity.label":"\u041D\u0435\u043F\u0440\u043E\u0437\u0440\u0430\u0447\u043D\u043E\u0441\u0442\u044C","opacity.value":"{value} %","views.tour":"\u0422\u0443\u0440 \u043F\u043E \u0432\u0438\u0434\u0430\u043C","views.stop":"\u041E\u0441\u0442\u0430\u043D\u043E\u0432\u0438\u0442\u044C \u0442\u0443\u0440","clash.New":"\u041D\u043E\u0432\u0430\u044F","clash.Active":"\u0410\u043A\u0442\u0438\u0432\u043D\u0430\u044F","clash.Reviewed":"\u041F\u0440\u043E\u0432\u0435\u0440\u0435\u043D\u0430","clash.Approved":"\u0423\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043D\u0430","clash.Resolved":"\u0423\u0441\u0442\u0440\u0430\u043D\u0435\u043D\u0430","task.construct":"\u0421\u0442\u0440\u043E\u0438\u0442\u0435\u043B\u044C\u0441\u0442\u0432\u043E","task.demolish":"\u0421\u043D\u043E\u0441","task.temporary":"\u0412\u0440\u0435\u043C\u0435\u043D\u043D\u043E\u0435","player.title":"4D-\u043F\u0440\u043E\u0438\u0433\u0440\u044B\u0432\u0430\u0442\u0435\u043B\u044C","player.play":"\u0412\u043E\u0441\u043F\u0440\u043E\u0438\u0437\u0432\u0435\u0441\u0442\u0438","player.pause":"\u041F\u0430\u0443\u0437\u0430","player.date":"\u0414\u0430\u0442\u0430 \u0433\u0440\u0430\u0444\u0438\u043A\u0430","player.speed":"\u0421\u043A\u043E\u0440\u043E\u0441\u0442\u044C",truncated:"\u041F\u043E\u043A\u0430\u0437\u0430\u043D\u043E {meshes} \u0438\u0437 {total} \u043C\u0435\u0448\u0435\u0439: \u043C\u043E\u0434\u0435\u043B\u044C \u043E\u0431\u0440\u0435\u0437\u0430\u043D\u0430 \u043D\u0430\u0441\u0442\u0440\u043E\u0439\u043A\u043E\u0439 MaxMeshVertices"},en:{elements:"Elements",noGeometry:"No geometry",contextLost:"The graphics context was lost \u2014 reload the page",noWebGL:"This page needs a browser with WebGL 2",badData:"The model data could not be read",tooLarge:"The model is too large for this viewer: {count} objects with geometry, the limit is {limit}",selected:"Selected",close:"Close",elementGroup:"Element",id:"Id",category:"Category",type:"Type",level:"Level",link:"Link",panels:"Panels","panel.model":"Model","panel.views":"Views","panel.sections":"Sections","panel.clashes":"Clashes","panel.timeliner":"4D schedule","panel.links":"Linked files","group.navigation":"Navigation","group.sections":"Sections","group.measure":"Measure","group.display":"Display","group.view":"View","tool.orbit":"Orbit","tool.pan":"Pan","tool.fit":"Fit all","tool.projection":"Perspective / orthographic","tool.plane":"Section plane","tool.box":"Section box","tool.resetSections":"Reset sections","tool.distance":"Distance","tool.displayMode":"Display mode","tool.grids":"Grids","tool.opacity":"Transparency","tool.fullscreen":"Full screen","menu.properties":"Properties","menu.hide":"Hide","menu.isolate":"Isolate","menu.showAll":"Show all","menu.zoomTo":"Zoom to object","menu.sectionBox":"Section box around object","menu.copyId":"Copy Id","menu.fitAll":"Fit all","menu.resetSections":"Reset sections",searchPlaceholder:"Search by name, type, Id\u2026",noCategory:"No category",noMatches:"No matches",idCopied:"Id copied",copyFailed:"Could not copy Id",fullscreenUnavailable:"Fullscreen is not available","face.front":"Front","face.back":"Back","face.left":"Left","face.right":"Right","face.top":"Top","face.bottom":"Bottom","cube.title":"View cube","cube.up":"Rotate up","cube.down":"Rotate down","cube.left":"Rotate left","cube.right":"Rotate right","cube.home":"Home view","sections.mode":"Section mode","sections.planes":"Planes","sections.box":"Box","sections.off":"Off","sections.axis":"Axis","sections.addPlane":"Add plane","sections.noPlanes":"No planes","sections.rotated":"rotated","sections.position":"Plane position","sections.flip":"Flip side","sections.enabled":"On","sections.delete":"Delete plane","sections.keepInside":"Show inside","sections.cutInside":"Cut inside","sections.fitSelection":"Fit to selection","sections.showGizmo":"Show gizmo","sections.maxPlanes":"At most 6 planes","unit.m":"m","display.materials":"Materials","display.textures":"Textures","display.white":"White","display.wireframe":"Wireframe","opacity.label":"Opacity","opacity.value":"{value}%","views.tour":"Play tour","views.stop":"Stop tour","clash.New":"New","clash.Active":"Active","clash.Reviewed":"Reviewed","clash.Approved":"Approved","clash.Resolved":"Resolved","task.construct":"Construct","task.demolish":"Demolish","task.temporary":"Temporary","player.title":"4D player","player.play":"Play","player.pause":"Pause","player.date":"Schedule date","player.speed":"Speed",truncated:"Showing {meshes} of {total} meshes: the model was truncated by the MaxMeshVertices setting"}},mr=(globalThis.navigator?.language??"").toLowerCase().startsWith("ru")?"ru":"en";function st(i,t=mr){let e=Bx[t][i];if(e===void 0)throw new Error(`Missing UI string '${i}'.`);return e}var Ed=new C(0,0,1),Ia=Math.PI/2-.01;function Ad(i,t,e=4){return Math.hypot(t.x-i.x,t.y-i.y)<=e}function Rd(i,t,e,n,s,r){let o=i.clone().sub(e),a=t.clone().sub(e),l=d=>(o.applyQuaternion(d),a.applyQuaternion(d));l(new Ne().setFromAxisAngle(Ed,-n*r));let c=a.clone().sub(o).normalize(),h=c.clone().cross(Ed);if(h.lengthSq()>1e-12){let d=Math.asin(Oe.clamp(c.z,-1,1)),u=Oe.clamp(s*r,d-Ia,d+Ia);l(new Ne().setFromAxisAngle(h.normalize(),-u))}return{position:o.add(e),target:a.add(e)}}function Cd(i,t,e,n){let s=r=>r.clone().sub(e).multiplyScalar(n).add(e);return{position:s(i),target:s(t)}}var Ox=.85,zx=100/3;function Id(i,t,e){let n=i*(t===1?zx:t===2?e:1);return Oe.clamp(Ox**(-n/100),.5,2)}var Uc=(i,t)=>t>=i?"window":"crossing";function Pd(i,t,e){let n=Td(i.position,i.target),s=Td(t.position,t.target),r=n.azimuth??s.azimuth??0,o=s.azimuth??r,a=Oe.euclideanModulo(o-r+Math.PI,2*Math.PI)-Math.PI,l=(_,m)=>_+(m-_)*e,c=r+a*e,h=Oe.clamp(l(n.elevation,s.elevation),-Ia,Ia),d=l(n.distance,s.distance),u=i.target.clone().lerp(t.target,e),p=Math.cos(h)*d;return{position:u.clone().add(new C(p*Math.cos(c),p*Math.sin(c),Math.sin(h)*d)),target:u}}function Td(i,t){let e=i.clone().sub(t),n=e.length(),s=Math.hypot(e.x,e.y);return{distance:n,elevation:n>1e-12?Math.asin(Oe.clamp(e.z/n,-1,1)):0,azimuth:s>1e-9*Math.max(n,1e-12)?Math.atan2(e.y,e.x):null}}var kx=.005,Vx=new C(1,-1,.8).normalize(),Fc=(i,t)=>new CustomEvent(i,{detail:t}),Pa=class extends EventTarget{constructor(t,e,{pick:n=()=>null,visibleBox:s=()=>new se}={}){super(),this.dom=e,this.pick=n,this.visibleBox=s,this.target=new C,this.leftButtonMode="orbit",this._perspective=t,this._orthographic=new In(-1,1,1,-1),this.camera=t,this._drag=null,this._wheelPick=null,this._animation=0,this._overlay=null,this._bounds=null,this._extraBounds=new Map,e.style.touchAction="none",e.addEventListener("pointerdown",r=>this._down(r)),e.addEventListener("pointermove",r=>this._move(r)),e.addEventListener("pointerup",r=>this._up(r)),e.addEventListener("pointercancel",()=>this._end()),e.addEventListener("lostpointercapture",r=>this._lostCapture(r)),window.addEventListener("blur",()=>this._end()),e.addEventListener("wheel",r=>this._wheel(r),{passive:!1}),e.addEventListener("contextmenu",r=>r.preventDefault())}setLeftButtonMode(t){if(t!=="orbit"&&t!=="pan")throw new RangeError(`Unknown left button mode: ${t}`);this.leftButtonMode=t}setProjection(t){if(t!=="perspective"&&t!=="orthographic")throw new RangeError(`Unknown projection: ${t}`);let e=t==="perspective"?this._perspective:this._orthographic,n=this.camera;if(e!==n){e.position.copy(n.position),e.quaternion.copy(n.quaternion),e.up.copy(n.up),n.parent?.add(e),n.parent?.remove(n);for(let s of[...n.children])e.add(s);this.camera=e,this.resize()}}resize(){let t=this.camera,e=this.dom.clientWidth/Math.max(this.dom.clientHeight,1),n=Math.max(t.position.distanceTo(this.target),1e-6);if(t.isPerspectiveCamera)t.aspect=e;else{let r=n*Math.tan(Oe.degToRad(this._perspective.fov/2));Object.assign(t,{top:r,bottom:-r,left:-r*e,right:r*e})}let s=this._rangeSphere();if(s){let r=t.position.distanceTo(s.center);t.far=(r+s.radius)*1.05,t.near=Math.max((r-s.radius)*.95,t.far/5e3)}t.updateProjectionMatrix(),this.dispatchEvent(new Event("change"))}setExtraBounds(t,e){e&&!e.isEmpty()?this._extraBounds.set(t,e.clone()):this._extraBounds.delete(t),this.resize()}_rangeSphere(){let t=this._visibleBounds()?.sphere??null;if(this._extraBounds.size===0)return t;let e=t?this._bounds.box.clone():new se;for(let n of this._extraBounds.values())e.union(n);return e.getBoundingSphere(new Le)}invalidateBounds(){this._bounds=null}_visibleBounds(){if(!this._bounds){let t=this.visibleBox();this._bounds={box:t,sphere:t.isEmpty()?null:t.getBoundingSphere(new Le)}}return this._bounds.sphere&&this._bounds}fitBox(t,e=!0){if(t.isEmpty())return;let n=t.getBoundingSphere(new Le),s=Math.max(n.radius,.001),r=Oe.degToRad(this._perspective.fov/2),o=this.dom.clientWidth/Math.max(this.dom.clientHeight,1),a=s/Math.sin(Math.min(r,Math.atan(Math.tan(r)*o))),l=this.camera.position.clone().sub(this.target);l.lengthSq()<1e-12&&l.copy(Vx);let c=l.normalize().multiplyScalar(a).add(n.center);e?this.animateTo({position:c,target:n.center}):this._set(c,n.center)}zoomToBox(t){this.fitBox(t,!0)}animateTo({position:t,target:e},n=400){this._stopAnimation();let s={position:this.camera.position.clone(),target:this.target.clone()},r={position:t??s.position,target:e??s.target},o=performance.now(),a=l=>{let c=Math.min((l-o)/n,1),h=Pd(s,r,c*c*(3-2*c));this._set(h.position,h.target),this._animation=c<1?requestAnimationFrame(a):0};this._animation=requestAnimationFrame(a)}get animating(){return this._animation!==0}_stopAnimation(){cancelAnimationFrame(this._animation),this._animation=0}_set(t,e){this.camera.position.copy(t),this.target.copy(e),this.camera.lookAt(e),this.resize()}_down(t){this._end(),this._stopAnimation(),this.dom.setPointerCapture(t.pointerId),t.preventDefault();let e=t.button===0&&t.shiftKey?"box":t.button===0&&this.leftButtonMode==="orbit"?"orbit":"pan",n={x:t.clientX,y:t.clientY},s=null;e==="orbit"&&(s=this.pick(n.x,n.y),s||(s=this._visibleBounds()?.sphere.center.clone()??this.target.clone())),this._drag={id:t.pointerId,button:t.button,mode:e,pivot:s,down:n,last:n,moved:!1}}_move(t){let e=this._drag;if(!e||t.pointerId!==e.id)return;if(t.buttons===0)return this._end();let n={x:t.clientX,y:t.clientY};if(!e.moved&&Ad(e.down,n))return;e.moved=!0;let s=n.x-e.last.x,r=n.y-e.last.y;if(e.last=n,e.mode==="box")this._drawRect(e.down,n);else if(e.mode==="orbit"){let o=Rd(this.camera.position,this.target,e.pivot,s,r,kx);this._set(o.position,o.target)}else this._pan(s,r)}_pan(t,e){let n=this.camera,s=Math.max(this.dom.clientHeight,1),r=n.isPerspectiveCamera?2*n.position.distanceTo(this.target)*Math.tan(Oe.degToRad(n.fov/2))/s:(n.top-n.bottom)/s,o=new C(1,0,0).applyQuaternion(n.quaternion),a=new C(0,1,0).applyQuaternion(n.quaternion),l=o.multiplyScalar(-t*r).addScaledVector(a,e*r);this._set(n.position.clone().add(l),this.target.clone().add(l))}_up(t){let e=this._drag;if(!e||t.pointerId!==e.id||t.button!==e.button)return;let n={x:t.clientX,y:t.clientY};if(this._end(),e.mode==="box"&&e.moved){let s={x:Math.min(e.down.x,n.x),y:Math.min(e.down.y,n.y),width:Math.abs(n.x-e.down.x),height:Math.abs(n.y-e.down.y)},r=Uc(e.down.x,n.x);this.dispatchEvent(Fc("boxselect",{rect:s,mode:r,ctrl:t.ctrlKey,shift:t.shiftKey}))}else!e.moved&&e.button===0?this.dispatchEvent(Fc("click",{x:n.x,y:n.y,button:0,ctrl:t.ctrlKey,shift:t.shiftKey})):!e.moved&&e.button===2&&this.dispatchEvent(Fc("contextmenu",{x:n.x,y:n.y}))}_lostCapture(t){this._drag&&t.buttons?this.dom.setPointerCapture(this._drag.id):this._end()}_end(){this._drag=null,this._overlay?.remove(),this._overlay=null}_drawRect(t,e){this._overlay||(this._overlay=document.createElement("div"),Object.assign(this._overlay.style,{position:"fixed",pointerEvents:"none",border:"1px solid #2563eb",background:"rgba(37,99,235,0.12)"}),(this.dom.parentElement??document.body).appendChild(this._overlay)),Object.assign(this._overlay.style,{borderStyle:Uc(t.x,e.x)==="window"?"solid":"dashed",left:`${Math.min(t.x,e.x)}px`,top:`${Math.min(t.y,e.y)}px`,width:`${Math.abs(e.x-t.x)}px`,height:`${Math.abs(e.y-t.y)}px`})}_wheel(t){if(t.preventDefault(),t.deltaY===0)return;this._stopAnimation(),this._wheelPick||(this._wheelPick={point:this.pick(t.clientX,t.clientY)},requestAnimationFrame(()=>this._wheelPick=null));let e=this._wheelPick.point??this.target,n=Cd(this.camera.position,this.target,e,Id(t.deltaY,t.deltaMode,this.dom.clientHeight));this._set(n.position,n.target)}};function nt(i,t,e){let n=document.createElement(i);return t&&(n.className=t),e!==void 0&&(n.textContent=e),n}function qe(i,t,e){let n=nt("button",i);return n.type="button",n.innerHTML=t,n.title=e,n.setAttribute("aria-label",e),n}function La(i){i.preventDefault(),i.stopPropagation()}function Da(i){La(i);let t=()=>{window.removeEventListener("pointerup",e,!0),setTimeout(()=>window.removeEventListener("click",La,!0))},e=n=>{La(n),t()};window.addEventListener("pointerup",e,!0),window.addEventListener("click",La,!0)}function Na(i,t,e,n){let s=t.clone().applyMatrix4(e.matrixWorldInverse).z<0,r=t.clone().project(e);i.hidden=!(s&&Math.abs(r.x)<=1&&Math.abs(r.y)<=1),!i.hidden&&(i.style.left=`${n.left+(r.x+1)/2*n.width}px`,i.style.top=`${n.top+(1-r.y)/2*n.height}px`)}var de=i=>``,Ld='',Zt={model:de(''),views:de(''),sections:de(''),clashes:de(''),timeliner:de(''),links:de(''),orbit:de(''),pan:de(''),fit:de(''),projection:de(Ld),plane:de(''),box:de(`${Ld}`),resetSections:de(''),distance:de(''),displayMode:de(''),grids:de(''),opacity:de(''),fullscreen:de(''),close:de(''),chevron:de(''),flip:de(''),remove:de(''),play:de(''),pause:de(''),home:de('')};var gr=new C(0,0,1),on={right:new C(1,0,0),left:new C(-1,0,0),back:new C(0,1,0),front:new C(0,-1,0),top:new C(0,0,1),bottom:new C(0,0,-1)},Hx={right:gr,left:gr,back:gr,front:gr,top:on.back,bottom:on.front},Ni=.7,Gx=Oe.degToRad(1),Dd=.01,Nd=96,Ua=1.75;function Ud(i){let t=i.split("-"),e=new C;for(let n of t){if(!Object.hasOwn(on,n))throw new RangeError(`Unknown view cube region: ${i}`);e.add(on[n])}if(new Set(t).size!==t.length||e.lengthSq()!==t.length)throw new RangeError(`Unknown view cube region: ${i}`);return e.normalize()}function Wx(i){let t=[];return Math.abs(i.z)>=Ni&&t.push(i.z>0?"top":"bottom"),Math.abs(i.y)>=Ni&&t.push(i.y>0?"back":"front"),Math.abs(i.x)>=Ni&&t.push(i.x>0?"right":"left"),t.join("-")}function Fd(i,t=Gx){let e=i.clone().normalize(),n=Math.cos(t);return Object.keys(on).find(s=>e.dot(on[s])>=n)??null}function Bd(i){let t=new C(i.x,i.y,0);if(t.lengthSq()<1e-24)return"front";t.normalize();let e=["front","right","back","left"],n=Math.max(...e.map(s=>t.dot(on[s])));return e.find(s=>t.dot(on[s])>=n-1e-9)}function Bc(i,t){return on[Bd(t)].clone().multiplyScalar(Math.sin(Dd)).addScaledVector(on[i],Math.cos(Dd))}function Xx(i,t){let e=Fd(i);if(!e)return null;let n=e==="top"||e==="bottom";if(t==="left"||t==="right")return(n?Bc(e,i):Ud(e)).applyAxisAngle(gr,t==="right"?Math.PI/2:-Math.PI/2);if(t!=="up"&&t!=="down")throw new RangeError(`Unknown arrow: ${t}`);if(!n)return Bc(t==="up"?"top":"bottom",i);let s=on[Bd(i)];return t==="up"==(e==="top")?s.clone().negate():s.clone()}function qx(i,t){let e=document.createElement("canvas");e.width=e.height=128;let n=e.getContext("2d");n.fillStyle="#2a2f38",n.fillRect(0,0,128,128),n.fillStyle="#cbd5e1",n.textAlign="center",n.textBaseline="middle",n.font=`600 26px ${t}`;let s=n.measureText(i).width;s>112&&(n.font=`600 ${Math.floor(2912/s)}px ${t}`),n.fillText(i,64,64);let r=new Ws(e);return r.colorSpace=Se,r}var Fa=class{constructor(t,e,n){this.controls=n,this.home={position:e.position.clone(),target:n.target.clone()},this.element=nt("div","ioviewer-viewcube"),this.canvas=nt("canvas","ioviewer-viewcube-canvas"),this.canvas.title=st("cube.title"),this.canvas.setAttribute("aria-label",st("cube.title")),this.element.append(this.canvas),this.error=null,this.renderer=this._createRenderer(),this.scene=new Mi,this.camera=new In(-Ua,Ua,Ua,-Ua,.1,10),this.faces=new be;let s=getComputedStyle(t).fontFamily;for(let[a,l]of Object.entries(on)){let c=st(`face.${a}`),h=new _e(new Gn(2,2),new cn({map:qx(c,s)})),d=Hx[a];h.quaternion.setFromRotationMatrix(new Ht().makeBasis(d.clone().cross(l),d,l)),h.position.copy(l),h.name=a,h.userData.label=c,this.faces.add(h)}let r=new gn(new Ti(new hn(2,2,2)),new sn({color:"#5b6575"}));this.highlight=new _e(new hn(1,1,1),new cn({color:"#2563eb",transparent:!0,opacity:.6})),this.highlight.visible=!1,this.scene.add(this.faces,r,this.highlight),this._raycaster=new Ai,this.hovered=null,this.canvas.addEventListener("pointermove",a=>this._hover(this.regionAtClient(a.clientX,a.clientY))),this.canvas.addEventListener("pointerleave",()=>this._hover(null)),this.canvas.addEventListener("click",a=>{let l=this.regionAtClient(a.clientX,a.clientY);if(!l)return;let c=l==="top"||l==="bottom";this._look(c?Bc(l,n.camera.position.clone().sub(n.target)):Ud(l))}),this.arrows=["up","down","left","right"].map(a=>{let l=qe("ioviewer-viewcube-arrow",Zt.chevron,st(`cube.${a}`));return l.dataset.arrow=a,l.addEventListener("click",()=>this._arrow(a)),l});let o=qe("ioviewer-viewcube-home",Zt.home,st("cube.home"));o.addEventListener("click",()=>n.animateTo({position:this.home.position.clone(),target:this.home.target.clone()})),this.element.append(...this.arrows,o),t.append(this.element),this.update()}_createRenderer(){this.canvas.addEventListener("webglcontextlost",e=>{e.stopImmediatePropagation(),this._fail(new Error("The view cube lost its WebGL context."))});let t=this.canvas.getContext("webgl2",{alpha:!0,antialias:!0});if(!t)return this._fail(new Error("WebGL 2 is not available for the view cube."));try{let e=new Ss({canvas:this.canvas,context:t,alpha:!0,antialias:!0});return e.setPixelRatio(window.devicePixelRatio),e.setSize(Nd,Nd),e}catch(e){return this._fail(e)}}_fail(t){return this.error=t,this.renderer=null,this.element.hidden=!0,null}_render(){if(this.renderer)try{this.renderer.render(this.scene,this.camera)}catch(t){this._fail(t)}}update(){if(!this.renderer)return;let t=this.controls.camera;this.camera.quaternion.copy(t.quaternion),this.camera.position.set(0,0,5).applyQuaternion(t.quaternion),this.camera.updateMatrixWorld();let e=Fd(t.position.clone().sub(this.controls.target))!==null;for(let n of this.arrows)n.hidden=!e;this._render()}regionAtClient(t,e){let n=this.canvas.getBoundingClientRect(),s=new zt((t-n.left)/n.width*2-1,1-(e-n.top)/n.height*2);this._raycaster.setFromCamera(s,this.camera);let r=this._raycaster.intersectObjects(this.faces.children)[0];return r?Wx(r.point):null}_hover(t){if(t!==this.hovered){if(this.hovered=t,this.highlight.visible=!!t,t){let e=t.split("-").reduce((a,l)=>a.add(on[l]),new C),n=a=>a===0?[-Ni,Ni]:a>0?[Ni,1.02]:[-1.02,-Ni],[s,r,o]=e.toArray().map(n);this.highlight.scale.set(s[1]-s[0],r[1]-r[0],o[1]-o[0]),this.highlight.position.set((s[0]+s[1])/2,(r[0]+r[1])/2,(o[0]+o[1])/2)}this._render()}}_arrow(t){let n=this.controls.camera.position.clone().sub(this.controls.target),s=Xx(n,t);s&&this._look(s)}_look(t){let{controls:e}=this,n=e.camera.position.distanceTo(e.target);e.animateTo({position:t.clone().multiplyScalar(n).add(e.target),target:e.target.clone()})}};var Yx=`
+varying vec3 vTint;`);e=di(e,"#include ","diffuseColor.rgb *= vTint;"),i.fragmentShader=e}function Pc(i,t,e=!1){return i.userData.slotUniforms=t,i.onBeforeCompile=Ax,i.index0AttributeName="q",e&&(i.defines={IO_NO_HIDE_BRANCH:""}),i}var Nc=["materials","textures","white","wireframe"],Rx=[245,158,11],Cx=[235,235,237],dr=4294967295,Di=2048,Lc=256,Ix=16,Md=1024,Px=.1,Lx=8192,Dx=1.4;function Nx(i,t){let[e,n,s,r,o,a,l,c,h]=i.subarray(t*12,t*12+9);return e*(o*h-a*c)-r*(n*h-s*c)+l*(n*a-s*o)<0}function Ux(){this.array=null}function yn(i,t,e=!1,n=we){return new n(i,t,e).onUpload(Ux)}var fr=class extends RangeError{constructor(t,e){super(`${t} drawable instances exceed the limit of ${e}.`),this.name="ModelTooLargeError",this.count=t,this.limit=e}},Sd=(i,t)=>{for(let e=t*6;e{let t=i.getHex(Se);return[t>>16&255,t>>8&255,t&255]},pr=class{constructor(t,e={}){let{meta:n}=t,s=n.instances,r=s.count,o=t.view(s.geometry),a=t.view(s.material),l=t.view(s.matrix);this.root=new be,this.elementCount=n.elements.length,this._elements=n.elements,this._meta=n,this._mode="materials",this._opacity=1,this._picking=!1,this._textures=new Map,this._elementOf=t.view(s.element).slice(),this._bucketOf=new Uint32Array(r),this._visible=new Uint8Array(r).fill(1),this._layers=new Map,this._layerHides=new Uint8Array(r),this._highlight=new Uint8Array(r),this._highlighted=[],this._tint=new Map,this._boxes=new Float32Array(r*6),this._minPixels=0,this._viewHeight=1,this.visibleCost=0;let c=!!e.noHideBranch;this.slotUniforms={slotInfo:{value:null},slotState:{value:null}},this._buckets=this._createBuckets(n,a,c),this._indexElements();let h=new Ht,d=new se;for(let p=0;pthis._shown(e)?1:0)}instancesOf(t){return this._checkElement(t),this._elementInstances.subarray(this._elementStart[t],this._elementStart[t+1])}isVisible(t){this._checkElement(t);for(let e=this._elementStart[t];e=0&&t<=1))throw new RangeError(`Opacity must be within 0..1, got ${t}.`);this._opacity=t;for(let e of this._buckets)this._applyOpacity(e);this._changed("appearance")}setDetail(t,e=1){this._minPixels=t,this._viewHeight=e;for(let s of this._cut)this._showUnit(s);this._cut.length=0;let n=this._unitScale;!(t>0)||!n||(this._unitScale=null,this._cutInView=0,this._cutFrame=null,this._units.forEach((s,r)=>{!(n[r]>=0)||s.shown===0||(s.dirty&&this._span(s),!(this._slotRadius[s.slotBase+s.first]*n[r]>=t)&&(s.mesh.visible=!1,s.lines&&(s.lines.visible=!1),this._cut.push(s),this._cutInView+=Dc(s,s.first,s.last+1)))}))}get totalCost(){return this._totalCost}detailThreshold(t,e,n){if(this.visibleCost=this._totalCost,this._totalCost<=n)return 0;t.updateMatrixWorld();let s=nd(t,this._planes),r=wc(t,e,this._detailView),o=this._pixels.fill(-1),a=this._state.image.data,l=this._unitScale=new Float64Array(this._units.length).fill(-1),c=0;for(let h=0;h0?r[6]/p:1/0:r[6];l[h]=g;for(let _=d.slotBase;_o-a)}memory(){let t=this._units[this._chunkCount]?.slotBase??this._slotInstance.length;return{gpuBytes:this._mergedBytes+this._instancedBytes+this._lineBytes+this._stateBytes,mergedBytes:this._mergedBytes,instancedBytes:this._instancedBytes,stateBytes:this._stateBytes,lineBytes:this._lineBytes,chunks:this._chunkCount,cells:this._units.length-this._chunkCount,mergedInstances:t,instancedInstances:this._slotInstance.length-t,triangles:this._triangles}}setClipping(t,e){for(let n of this._buckets)for(let s of[n.material,n.wire])s.clippingPlanes=t.length>0?t:null,s.clipIntersection=e,s.needsUpdate=!0;this._changed("clipping")}_build(t,e,n,s,r){let o=e.length,a=this._meta,l=new Map,c=B=>{let U=l.get(B);if(!U){let H=a.geometries[B],Z=t.view(H.indices),rt=H.uvs?t.view(H.uvs):null;U=yd(ad(t,H),H.q??null,ld(t,H),Z,rt),l.set(B,U)}return U},h=new Uint8Array(o),d=new Float64Array(o*3),u=new Float32Array(o*3),p=new Uint32Array(o),g=new Float32Array(o),_=new Uint8Array(o),m=new Map,f=this._boxes;for(let B=0;BB-U).map(B=>{let U=m.get(B),H=c(e[U[0]]),Z=this._buckets[this._bucketOf[U[0]]].texture!==null,rt=[0,1,2].every(Ft=>(H.max[Ft]-H.min[Ft])/Xn<=65535),at=H.vertices*((rt?12:20)+(Z?8:0))+H.indices.length*(H.vertices>65535?4:2);return{k:U.length,bytes:at,members:U,textured:Z}}),S=s.mergedCap??Ac,b=s.minRepeats??Ix;if(R.reduce((B,U)=>B+U.k*U.bytes,0)>S){let B=this.visibleBox(),U=B.isEmpty()?1/0:B.min.distanceTo(B.max)*(s.cellExtent??Px);for(let H of R)H.k{if(y[U]){for(let H of B.leaves)E.push({shape:B,members:Rc(H,g)});return}for(let H of B.members){v[e[H]]++;let Z=this._bucketOf[H]*2+(h[H]===ws?1:0),rt=T.get(Z);rt||T.set(Z,rt=[]),rt.push(H)}});let P=[];for(let B of[...T.keys()].sort((U,H)=>U-H))for(let U of dd(u,p,T.get(B),s.chunkVertices??cd))P.push(Rc(U,g));let D=[...P,...E.map(B=>B.members)].reduce((B,U)=>B+U.length,0);if(D>r)throw new fr(D,r);let z=Math.max(1,Math.ceil(D/Di)),O=new Float32Array(Di*z*4);this._state=new ei(new Uint8Array(Di*z*4),Di,z),this._state.colorSpace=Se,this._state.onUpdate=()=>{this._fullPending=!1,this._pendingRanges=0},this._fullPending=!0,this._pendingRanges=0,this._dirty=new Uint32Array(Lc),this._dirtyCount=0;let I=new ei(O,Di,z,tn,We);I.needsUpdate=!0,I.onUpdate=()=>I.image.data=null,this.slotUniforms.slotInfo.value=I,this.slotUniforms.slotState.value=this._state,this._stateBytes=Di*z*20,this._slotOf=new Uint32Array(o).fill(dr),this._slotInstance=new Uint32Array(D),this._slotUnit=new Uint32Array(D),this._slotRadius=new Float32Array(D),this._slotCost=new Float32Array(D),this._pixels=new Float32Array(D),this._planes=new Float64Array(24),this._detailView=new Float64Array(8),this._frameView=new Float64Array(8),this._frameViewAt=NaN,this._units=[],this._cut=[],this._unitScale=null,this._cutInView=0,this._cutFrame=-1,this._mergedBytes=0,this._instancedBytes=0,this._lineBytes=0;let k={matrices:n,geometryOf:e,mirrored:_,kind:h,origins:d,source:c,textured:!1};this._lineSources=new Map;let X=0;for(let B of P){let U=this._buckets[this._bucketOf[B[0]]];k.textured=U.texture!==null;let H=vd(B,k);for(let Z=0;ZB+U,0);let Y=new Map;for(let{shape:B,members:U}of E){let H=U[0],Z=c(e[H]),rt=Y.get(B);rt||Y.set(B,rt=this._shape(Z,_[H]===1,B.textured));for(let at=0;atB+U,0)}_shape(t,e,n){let s=t.vertices,r=t.q?new Uint16Array(s*4):new Float32Array(s*4);for(let h=0;hn+g),1,!1,Hn)),a.setIndex(s.index);let l=wd(this._boxes,e),c=new Le(new C(l[0],l[1],l[2]),l[3]);a.boundingSphere=c;let h=new cs(a,t.material,0),d=new Float32Array(o*16);for(let p=0;pthis._range(u,p,_,h),h.visible=!1,this.root.add(h),u}_chunk(t,e,n,s,r,o){let a=new fs;a.instanceCount=1,a.setAttribute("q",yn(s.q,4)),a.setAttribute("normal",yn(s.o,2,!0)),s.uv&&a.setAttribute("uv",yn(s.uv,2)),a.setAttribute("slotBase",yn(new Float32Array([n]),1,!1,Hn)),a.setIndex(yn(s.index,1));let l=wd(this._boxes,e);a.boundingSphere=new Le(new C(l[0],l[1],l[2]),l[3]),this._mergedBytes+=s.q.byteLength+s.o.byteLength+(s.uv?.byteLength??0)+s.index.byteLength;let c=new _e(a,t.material),h={bucket:t,mesh:c,lines:null,slotBase:n,n:e.length,sphere:l,shown:0,first:0,last:-1,end:0,dirty:!1,cell:!1,starts:s.indexStart,vertices:s.q.length/4,f32:s.q instanceof Float32Array,members:e.slice(),lastFrame:-1/0};return c.onBeforeRender=(d,u,p)=>this._range(h,d,p,c),c.visible=!1,this.root.add(c),h}_buildLines(){if(!this._lineSources)return;let{mirrored:t,geometryOf:e}=this._lineMembers;for(let n of this._units){if(n.cell){let h=n.mesh.geometry.index;n.lines=new cs(n.mesh.geometry,n.bucket.wire,0),n.lines.instanceMatrix=n.mesh.instanceMatrix,n.lines.boundingSphere=n.mesh.boundingSphere,n.lines.onBeforeRender=(d,u,p)=>this._range(n,d,p,n.lines),this._lineBytes+=h.count*2*h.array.BYTES_PER_ELEMENT,this.root.add(n.lines);continue}let s=n.starts[n.n],r=Ra(n.vertices,s*2),o=0,a=0;for(let h of n.members){let d=this._lineSources.get(e[h]),u=t[h]===1;for(let p=0;pthis._range(n,h,u,n.lines),this.root.add(n.lines),n.members=null}this._lineSources=null,this._lineMembers=null}_range(t,e,n,s){t.dirty&&this._span(t);let r=t.last+1;if(this._minPixels>0&&r>t.first){let o=e.info.render.frame;o!==this._frameViewAt&&(wc(n,this._viewHeight,this._frameView),this._frameViewAt=o);let a=this._frameView,l=bd(a,t.sphere),c=a[7]?l>0?this._minPixels*l/a[6]:0:this._minPixels/a[6];r=Math.min(r,gd(this._slotRadius,t.slotBase+t.first,t.slotBase+r,c)-t.slotBase)}if(t.cell)s.count=Math.max(r,0);else{let o=s.isLineSegments?2:1,[a,l]=_d(t.starts,t.first,r);s.geometry.setDrawRange(a*o,l*o)}t.end=r,t.lastFrame=e.info.render.frame,this._cutFrame===null&&this._minPixels>0&&(this._cutFrame=t.lastFrame)}_span(t){let e=this._state.image.data,n=0;for(;n=n&&e[(t.slotBase+s)*4+3]===0;)s--;t.first=n0&&!e,t.lines&&(t.lines.visible=t.shown>0&&e)}_createBuckets(t,e,n){let s=new Map,r=[];for(let o=0;oMath.round(h*255)),opacity:c.opacity,texture:c.texture,material:Pc(new ds({side:Be}),this.slotUniforms,n),wire:Pc(new ds({side:Be,wireframe:!0}),this.slotUniforms,n)},this._applyOpacity(l),s.set(a,l),r.push(l)}this._bucketOf[o]=l.index}return r}_indexElements(){let t=new Uint32Array(this.elementCount+1);for(let s of this._elementOf)s>=0&&t[s+1]++;for(let s=0;s{s>=0&&(e[n[s]++]=r)}),this._elementStart=t,this._elementInstances=e}_texture(t){let e=this._textures.get(t);if(!e){let n=this._meta.textures[t],s=new Image;e=new Ue(s),e.colorSpace=Se,e.wrapS=e.wrapT=ns,e.repeat.set(1/n.sx,1/n.sy),s.onload=()=>{e.needsUpdate=!0,this._changed("appearance")},s.src=`data:${n.mime};base64,${n.data}`,this._textures.set(t,e)}return e}_applyOpacity(t){let e=t.opacity*this._opacity,n=e<1;for(let s of[t.material,t.wire])s.transparent!==n&&(s.needsUpdate=!0),s.opacity=e,s.transparent=n,s.depthWrite=!n}_colorOf(t){return this._highlight[t]?Rx:this._tint.get(t)??(this._mode==="white"?Cx:this._buckets[this._bucketOf[t]].bytes)}_applyColor(t){let e=this._slotOf[t];e!==dr&&(this._state.image.data.set(this._colorOf(t),e*4),this._markDirty(e))}_setInstanceVisible(t,e){this._visible[t]=e?1:0,this._draw(t)}_setLayerFlag(t,e,n){t[e]!==(n?1:0)&&(t[e]=n?1:0,this._layerHides[e]+=n?1:-1,this._draw(e))}_shown(t){return this._visible[t]===1&&this._layerHides[t]===0}_draw(t){let e=this._slotOf[t];if(e===dr)return;let n=this._shown(t)?255:0,s=this._state.image.data;if(s[e*4+3]===n)return;s[e*4+3]=n,this._markDirty(e);let r=this._units[this._slotUnit[e]];r.shown+=n?1:-1,r.dirty=!0,this._showUnit(r)}_markDirty(t){this._dirtyCountLc)e.clearUpdateRanges(),this._fullPending=!0;else{for(let n=0;n=this.elementCount)throw new RangeError(`Element index ${t} is out of range 0..${this.elementCount-1}.`)}_expandBox(t,e){if(!Sd(this._boxes,e))return;let n=this._boxes,s=e*6;t.min.set(Math.min(t.min.x,n[s]),Math.min(t.min.y,n[s+1]),Math.min(t.min.z,n[s+2])),t.max.set(Math.max(t.max.x,n[s+3]),Math.max(t.max.y,n[s+4]),Math.max(t.max.z,n[s+5]))}_changed(t){this._flush(),this.root.dispatchEvent({type:"change",detail:{kind:t}})}};function Dc(i,t,e){return e<=t?0:i.cell?(e-t)*i.triangles:(i.starts[e]-i.starts[t])/3}function bd(i,t){return(t[0]-i[0])*i[3]+(t[1]-i[1])*i[4]+(t[2]-i[2])*i[5]-t[3]}function wd(i,t){let e=[1/0,1/0,1/0],n=[-1/0,-1/0,-1/0];for(let s of t)for(let r=0;r<3;r++)e[r]=Math.min(e[r],i[s*6+r]),n[r]=Math.max(n[r],i[s*6+3+r]);return Float64Array.of((e[0]+n[0])/2,(e[1]+n[1])/2,(e[2]+n[2])/2,Math.hypot(n[0]-e[0],n[1]-e[1],n[2]-e[2])/2)}var Bx={ru:{elements:"\u042D\u043B\u0435\u043C\u0435\u043D\u0442\u043E\u0432",noGeometry:"\u041D\u0435\u0442 \u0433\u0435\u043E\u043C\u0435\u0442\u0440\u0438\u0438",contextLost:"\u0412\u0438\u0434\u0435\u043E\u043A\u0430\u0440\u0442\u0430 \u0441\u0431\u0440\u043E\u0448\u0435\u043D\u0430 \u2014 \u043F\u0435\u0440\u0435\u0437\u0430\u0433\u0440\u0443\u0437\u0438\u0442\u0435 \u0441\u0442\u0440\u0430\u043D\u0438\u0446\u0443",noWebGL:"\u041D\u0443\u0436\u0435\u043D \u0431\u0440\u0430\u0443\u0437\u0435\u0440 \u0441 \u043F\u043E\u0434\u0434\u0435\u0440\u0436\u043A\u043E\u0439 WebGL 2",badData:"\u041D\u0435 \u0443\u0434\u0430\u043B\u043E\u0441\u044C \u043F\u0440\u043E\u0447\u0438\u0442\u0430\u0442\u044C \u0434\u0430\u043D\u043D\u044B\u0435 \u043C\u043E\u0434\u0435\u043B\u0438",tooLarge:"\u041C\u043E\u0434\u0435\u043B\u044C \u0441\u043B\u0438\u0448\u043A\u043E\u043C \u0431\u043E\u043B\u044C\u0448\u0430\u044F \u0434\u043B\u044F \u044D\u0442\u043E\u0433\u043E \u043F\u0440\u043E\u0441\u043C\u043E\u0442\u0440\u0449\u0438\u043A\u0430: \u043E\u0431\u044A\u0435\u043A\u0442\u043E\u0432 \u0441 \u0433\u0435\u043E\u043C\u0435\u0442\u0440\u0438\u0435\u0439 \u2014 {count}, \u043F\u0440\u0435\u0434\u0435\u043B \u2014 {limit}",selected:"\u0412\u044B\u0431\u0440\u0430\u043D\u043E",close:"\u0417\u0430\u043A\u0440\u044B\u0442\u044C",elementGroup:"\u042D\u043B\u0435\u043C\u0435\u043D\u0442",id:"Id",category:"\u041A\u0430\u0442\u0435\u0433\u043E\u0440\u0438\u044F",type:"\u0422\u0438\u043F",level:"\u0423\u0440\u043E\u0432\u0435\u043D\u044C",sourceId:"ID \u0438\u0441\u0442\u043E\u0447\u043D\u0438\u043A\u0430",link:"\u0421\u0432\u044F\u0437\u0430\u043D\u043D\u044B\u0439 \u0444\u0430\u0439\u043B",panels:"\u041F\u0430\u043D\u0435\u043B\u0438","panel.model":"\u041C\u043E\u0434\u0435\u043B\u044C","panel.views":"\u0412\u0438\u0434\u044B","panel.sections":"\u0421\u0435\u0447\u0435\u043D\u0438\u044F","panel.clashes":"\u041A\u043E\u043B\u043B\u0438\u0437\u0438\u0438","panel.timeliner":"4D-\u0433\u0440\u0430\u0444\u0438\u043A","panel.links":"\u0421\u0432\u044F\u0437\u0430\u043D\u043D\u044B\u0435 \u0444\u0430\u0439\u043B\u044B","group.navigation":"\u041D\u0430\u0432\u0438\u0433\u0430\u0446\u0438\u044F","group.sections":"\u0421\u0435\u0447\u0435\u043D\u0438\u044F","group.measure":"\u0418\u0437\u043C\u0435\u0440\u0435\u043D\u0438\u044F","group.display":"\u041E\u0442\u043E\u0431\u0440\u0430\u0436\u0435\u043D\u0438\u0435","group.view":"\u0412\u0438\u0434","tool.orbit":"\u0412\u0440\u0430\u0449\u0435\u043D\u0438\u0435","tool.pan":"\u041F\u0430\u043D\u043E\u0440\u0430\u043C\u0430","tool.fit":"\u0412\u043F\u0438\u0441\u0430\u0442\u044C \u0432\u0441\u0451","tool.projection":"\u041F\u0435\u0440\u0441\u043F\u0435\u043A\u0442\u0438\u0432\u0430 / \u043E\u0440\u0442\u043E\u0433\u0440\u0430\u0444\u0438\u044F","tool.plane":"\u041F\u043B\u043E\u0441\u043A\u043E\u0441\u0442\u044C \u0441\u0435\u0447\u0435\u043D\u0438\u044F","tool.box":"\u0411\u043E\u043A\u0441 \u0441\u0435\u0447\u0435\u043D\u0438\u044F","tool.resetSections":"\u0421\u0431\u0440\u043E\u0441\u0438\u0442\u044C \u0441\u0435\u0447\u0435\u043D\u0438\u044F","tool.distance":"\u0420\u0430\u0441\u0441\u0442\u043E\u044F\u043D\u0438\u0435","tool.displayMode":"\u0420\u0435\u0436\u0438\u043C \u043E\u0442\u043E\u0431\u0440\u0430\u0436\u0435\u043D\u0438\u044F","tool.grids":"\u041E\u0441\u0438","tool.opacity":"\u041F\u0440\u043E\u0437\u0440\u0430\u0447\u043D\u043E\u0441\u0442\u044C","tool.fullscreen":"\u041F\u043E\u043B\u043D\u044B\u0439 \u044D\u043A\u0440\u0430\u043D","menu.properties":"\u0421\u0432\u043E\u0439\u0441\u0442\u0432\u0430","menu.hide":"\u0421\u043A\u0440\u044B\u0442\u044C","menu.isolate":"\u0418\u0437\u043E\u043B\u0438\u0440\u043E\u0432\u0430\u0442\u044C","menu.showAll":"\u041F\u043E\u043A\u0430\u0437\u0430\u0442\u044C \u0432\u0441\u0451","menu.zoomTo":"\u041F\u0440\u0438\u0431\u043B\u0438\u0437\u0438\u0442\u044C \u043A \u043E\u0431\u044A\u0435\u043A\u0442\u0443","menu.sectionBox":"\u0411\u043E\u043A\u0441 \u0441\u0435\u0447\u0435\u043D\u0438\u044F \u043F\u043E \u043E\u0431\u044A\u0435\u043A\u0442\u0443","menu.copyId":"\u041A\u043E\u043F\u0438\u0440\u043E\u0432\u0430\u0442\u044C Id","menu.fitAll":"\u0412\u043F\u0438\u0441\u0430\u0442\u044C \u0432\u0441\u0451","menu.resetSections":"\u0421\u0431\u0440\u043E\u0441\u0438\u0442\u044C \u0441\u0435\u0447\u0435\u043D\u0438\u044F",searchPlaceholder:"\u041F\u043E\u0438\u0441\u043A \u043F\u043E \u0438\u043C\u0435\u043D\u0438, \u0442\u0438\u043F\u0443, Id\u2026",noCategory:"\u0411\u0435\u0437 \u043A\u0430\u0442\u0435\u0433\u043E\u0440\u0438\u0438",noMatches:"\u041D\u0438\u0447\u0435\u0433\u043E \u043D\u0435 \u043D\u0430\u0439\u0434\u0435\u043D\u043E",idCopied:"Id \u0441\u043A\u043E\u043F\u0438\u0440\u043E\u0432\u0430\u043D",copyFailed:"\u041D\u0435 \u0443\u0434\u0430\u043B\u043E\u0441\u044C \u0441\u043A\u043E\u043F\u0438\u0440\u043E\u0432\u0430\u0442\u044C Id",fullscreenUnavailable:"\u041F\u043E\u043B\u043D\u043E\u044D\u043A\u0440\u0430\u043D\u043D\u044B\u0439 \u0440\u0435\u0436\u0438\u043C \u043D\u0435\u0434\u043E\u0441\u0442\u0443\u043F\u0435\u043D","face.front":"\u0421\u043F\u0435\u0440\u0435\u0434\u0438","face.back":"\u0421\u0437\u0430\u0434\u0438","face.left":"\u0421\u043B\u0435\u0432\u0430","face.right":"\u0421\u043F\u0440\u0430\u0432\u0430","face.top":"\u0421\u0432\u0435\u0440\u0445\u0443","face.bottom":"\u0421\u043D\u0438\u0437\u0443","cube.title":"\u041A\u0443\u0431 \u0432\u0438\u0434\u0430","cube.up":"\u041F\u043E\u0432\u0435\u0440\u043D\u0443\u0442\u044C \u0432\u0432\u0435\u0440\u0445","cube.down":"\u041F\u043E\u0432\u0435\u0440\u043D\u0443\u0442\u044C \u0432\u043D\u0438\u0437","cube.left":"\u041F\u043E\u0432\u0435\u0440\u043D\u0443\u0442\u044C \u0432\u043B\u0435\u0432\u043E","cube.right":"\u041F\u043E\u0432\u0435\u0440\u043D\u0443\u0442\u044C \u0432\u043F\u0440\u0430\u0432\u043E","cube.home":"\u0418\u0441\u0445\u043E\u0434\u043D\u044B\u0439 \u0432\u0438\u0434","sections.mode":"\u0420\u0435\u0436\u0438\u043C \u0441\u0435\u0447\u0435\u043D\u0438\u044F","sections.planes":"\u041F\u043B\u043E\u0441\u043A\u043E\u0441\u0442\u0438","sections.box":"\u0411\u043E\u043A\u0441","sections.off":"\u0412\u044B\u043A\u043B","sections.axis":"\u041E\u0441\u044C","sections.addPlane":"\u0414\u043E\u0431\u0430\u0432\u0438\u0442\u044C \u043F\u043B\u043E\u0441\u043A\u043E\u0441\u0442\u044C","sections.noPlanes":"\u041F\u043B\u043E\u0441\u043A\u043E\u0441\u0442\u0435\u0439 \u043D\u0435\u0442","sections.rotated":"\u043F\u043E\u0432\u0451\u0440\u043D\u0443\u0442\u0430","sections.position":"\u041F\u043E\u043B\u043E\u0436\u0435\u043D\u0438\u0435 \u043F\u043B\u043E\u0441\u043A\u043E\u0441\u0442\u0438","sections.flip":"\u0421\u043C\u0435\u043D\u0438\u0442\u044C \u0441\u0442\u043E\u0440\u043E\u043D\u0443","sections.enabled":"\u0412\u043A\u043B","sections.delete":"\u0423\u0434\u0430\u043B\u0438\u0442\u044C \u043F\u043B\u043E\u0441\u043A\u043E\u0441\u0442\u044C","sections.keepInside":"\u041F\u043E\u043A\u0430\u0437\u0430\u0442\u044C \u0432\u043D\u0443\u0442\u0440\u0438","sections.cutInside":"\u0412\u044B\u0440\u0435\u0437\u0430\u0442\u044C \u0432\u043D\u0443\u0442\u0440\u0438","sections.fitSelection":"\u041F\u043E \u0432\u044B\u0434\u0435\u043B\u0435\u043D\u043D\u043E\u043C\u0443","sections.showGizmo":"\u041F\u043E\u043A\u0430\u0437\u044B\u0432\u0430\u0442\u044C \u043C\u0430\u043D\u0438\u043F\u0443\u043B\u044F\u0442\u043E\u0440","sections.maxPlanes":"\u041D\u0435 \u0431\u043E\u043B\u044C\u0448\u0435 6 \u043F\u043B\u043E\u0441\u043A\u043E\u0441\u0442\u0435\u0439","unit.m":"\u043C","display.materials":"\u041C\u0430\u0442\u0435\u0440\u0438\u0430\u043B\u044B","display.textures":"\u0422\u0435\u043A\u0441\u0442\u0443\u0440\u044B","display.white":"\u0411\u0435\u043B\u044B\u0439","display.wireframe":"\u041A\u0430\u0440\u043A\u0430\u0441","opacity.label":"\u041D\u0435\u043F\u0440\u043E\u0437\u0440\u0430\u0447\u043D\u043E\u0441\u0442\u044C","opacity.value":"{value} %","views.tour":"\u0422\u0443\u0440 \u043F\u043E \u0432\u0438\u0434\u0430\u043C","views.stop":"\u041E\u0441\u0442\u0430\u043D\u043E\u0432\u0438\u0442\u044C \u0442\u0443\u0440","clash.New":"\u041D\u043E\u0432\u0430\u044F","clash.Active":"\u0410\u043A\u0442\u0438\u0432\u043D\u0430\u044F","clash.Reviewed":"\u041F\u0440\u043E\u0432\u0435\u0440\u0435\u043D\u0430","clash.Approved":"\u0423\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043D\u0430","clash.Resolved":"\u0423\u0441\u0442\u0440\u0430\u043D\u0435\u043D\u0430","task.construct":"\u0421\u0442\u0440\u043E\u0438\u0442\u0435\u043B\u044C\u0441\u0442\u0432\u043E","task.demolish":"\u0421\u043D\u043E\u0441","task.temporary":"\u0412\u0440\u0435\u043C\u0435\u043D\u043D\u043E\u0435","player.title":"4D-\u043F\u0440\u043E\u0438\u0433\u0440\u044B\u0432\u0430\u0442\u0435\u043B\u044C","player.play":"\u0412\u043E\u0441\u043F\u0440\u043E\u0438\u0437\u0432\u0435\u0441\u0442\u0438","player.pause":"\u041F\u0430\u0443\u0437\u0430","player.date":"\u0414\u0430\u0442\u0430 \u0433\u0440\u0430\u0444\u0438\u043A\u0430","player.speed":"\u0421\u043A\u043E\u0440\u043E\u0441\u0442\u044C",truncated:"\u041F\u043E\u043A\u0430\u0437\u0430\u043D\u043E {meshes} \u0438\u0437 {total} \u043C\u0435\u0448\u0435\u0439: \u043C\u043E\u0434\u0435\u043B\u044C \u043E\u0431\u0440\u0435\u0437\u0430\u043D\u0430 \u043D\u0430\u0441\u0442\u0440\u043E\u0439\u043A\u043E\u0439 MaxMeshVertices"},en:{elements:"Elements",noGeometry:"No geometry",contextLost:"The graphics context was lost \u2014 reload the page",noWebGL:"This page needs a browser with WebGL 2",badData:"The model data could not be read",tooLarge:"The model is too large for this viewer: {count} objects with geometry, the limit is {limit}",selected:"Selected",close:"Close",elementGroup:"Element",id:"Id",category:"Category",type:"Type",level:"Level",sourceId:"Source ID",link:"Link",panels:"Panels","panel.model":"Model","panel.views":"Views","panel.sections":"Sections","panel.clashes":"Clashes","panel.timeliner":"4D schedule","panel.links":"Linked files","group.navigation":"Navigation","group.sections":"Sections","group.measure":"Measure","group.display":"Display","group.view":"View","tool.orbit":"Orbit","tool.pan":"Pan","tool.fit":"Fit all","tool.projection":"Perspective / orthographic","tool.plane":"Section plane","tool.box":"Section box","tool.resetSections":"Reset sections","tool.distance":"Distance","tool.displayMode":"Display mode","tool.grids":"Grids","tool.opacity":"Transparency","tool.fullscreen":"Full screen","menu.properties":"Properties","menu.hide":"Hide","menu.isolate":"Isolate","menu.showAll":"Show all","menu.zoomTo":"Zoom to object","menu.sectionBox":"Section box around object","menu.copyId":"Copy Id","menu.fitAll":"Fit all","menu.resetSections":"Reset sections",searchPlaceholder:"Search by name, type, Id\u2026",noCategory:"No category",noMatches:"No matches",idCopied:"Id copied",copyFailed:"Could not copy Id",fullscreenUnavailable:"Fullscreen is not available","face.front":"Front","face.back":"Back","face.left":"Left","face.right":"Right","face.top":"Top","face.bottom":"Bottom","cube.title":"View cube","cube.up":"Rotate up","cube.down":"Rotate down","cube.left":"Rotate left","cube.right":"Rotate right","cube.home":"Home view","sections.mode":"Section mode","sections.planes":"Planes","sections.box":"Box","sections.off":"Off","sections.axis":"Axis","sections.addPlane":"Add plane","sections.noPlanes":"No planes","sections.rotated":"rotated","sections.position":"Plane position","sections.flip":"Flip side","sections.enabled":"On","sections.delete":"Delete plane","sections.keepInside":"Show inside","sections.cutInside":"Cut inside","sections.fitSelection":"Fit to selection","sections.showGizmo":"Show gizmo","sections.maxPlanes":"At most 6 planes","unit.m":"m","display.materials":"Materials","display.textures":"Textures","display.white":"White","display.wireframe":"Wireframe","opacity.label":"Opacity","opacity.value":"{value}%","views.tour":"Play tour","views.stop":"Stop tour","clash.New":"New","clash.Active":"Active","clash.Reviewed":"Reviewed","clash.Approved":"Approved","clash.Resolved":"Resolved","task.construct":"Construct","task.demolish":"Demolish","task.temporary":"Temporary","player.title":"4D player","player.play":"Play","player.pause":"Pause","player.date":"Schedule date","player.speed":"Speed",truncated:"Showing {meshes} of {total} meshes: the model was truncated by the MaxMeshVertices setting"}},mr=(globalThis.navigator?.language??"").toLowerCase().startsWith("ru")?"ru":"en";function st(i,t=mr){let e=Bx[t][i];if(e===void 0)throw new Error(`Missing UI string '${i}'.`);return e}var Ed=new C(0,0,1),Ia=Math.PI/2-.01;function Ad(i,t,e=4){return Math.hypot(t.x-i.x,t.y-i.y)<=e}function Rd(i,t,e,n,s,r){let o=i.clone().sub(e),a=t.clone().sub(e),l=d=>(o.applyQuaternion(d),a.applyQuaternion(d));l(new Ne().setFromAxisAngle(Ed,-n*r));let c=a.clone().sub(o).normalize(),h=c.clone().cross(Ed);if(h.lengthSq()>1e-12){let d=Math.asin(Oe.clamp(c.z,-1,1)),u=Oe.clamp(s*r,d-Ia,d+Ia);l(new Ne().setFromAxisAngle(h.normalize(),-u))}return{position:o.add(e),target:a.add(e)}}function Cd(i,t,e,n){let s=r=>r.clone().sub(e).multiplyScalar(n).add(e);return{position:s(i),target:s(t)}}var Ox=.85,zx=100/3;function Id(i,t,e){let n=i*(t===1?zx:t===2?e:1);return Oe.clamp(Ox**(-n/100),.5,2)}var Uc=(i,t)=>t>=i?"window":"crossing";function Pd(i,t,e){let n=Td(i.position,i.target),s=Td(t.position,t.target),r=n.azimuth??s.azimuth??0,o=s.azimuth??r,a=Oe.euclideanModulo(o-r+Math.PI,2*Math.PI)-Math.PI,l=(_,m)=>_+(m-_)*e,c=r+a*e,h=Oe.clamp(l(n.elevation,s.elevation),-Ia,Ia),d=l(n.distance,s.distance),u=i.target.clone().lerp(t.target,e),p=Math.cos(h)*d;return{position:u.clone().add(new C(p*Math.cos(c),p*Math.sin(c),Math.sin(h)*d)),target:u}}function Td(i,t){let e=i.clone().sub(t),n=e.length(),s=Math.hypot(e.x,e.y);return{distance:n,elevation:n>1e-12?Math.asin(Oe.clamp(e.z/n,-1,1)):0,azimuth:s>1e-9*Math.max(n,1e-12)?Math.atan2(e.y,e.x):null}}var kx=.005,Vx=new C(1,-1,.8).normalize(),Fc=(i,t)=>new CustomEvent(i,{detail:t}),Pa=class extends EventTarget{constructor(t,e,{pick:n=()=>null,visibleBox:s=()=>new se}={}){super(),this.dom=e,this.pick=n,this.visibleBox=s,this.target=new C,this.leftButtonMode="orbit",this._perspective=t,this._orthographic=new In(-1,1,1,-1),this.camera=t,this._drag=null,this._wheelPick=null,this._animation=0,this._overlay=null,this._bounds=null,this._extraBounds=new Map,e.style.touchAction="none",e.addEventListener("pointerdown",r=>this._down(r)),e.addEventListener("pointermove",r=>this._move(r)),e.addEventListener("pointerup",r=>this._up(r)),e.addEventListener("pointercancel",()=>this._end()),e.addEventListener("lostpointercapture",r=>this._lostCapture(r)),window.addEventListener("blur",()=>this._end()),e.addEventListener("wheel",r=>this._wheel(r),{passive:!1}),e.addEventListener("contextmenu",r=>r.preventDefault())}setLeftButtonMode(t){if(t!=="orbit"&&t!=="pan")throw new RangeError(`Unknown left button mode: ${t}`);this.leftButtonMode=t}setProjection(t){if(t!=="perspective"&&t!=="orthographic")throw new RangeError(`Unknown projection: ${t}`);let e=t==="perspective"?this._perspective:this._orthographic,n=this.camera;if(e!==n){e.position.copy(n.position),e.quaternion.copy(n.quaternion),e.up.copy(n.up),n.parent?.add(e),n.parent?.remove(n);for(let s of[...n.children])e.add(s);this.camera=e,this.resize()}}resize(){let t=this.camera,e=this.dom.clientWidth/Math.max(this.dom.clientHeight,1),n=Math.max(t.position.distanceTo(this.target),1e-6);if(t.isPerspectiveCamera)t.aspect=e;else{let r=n*Math.tan(Oe.degToRad(this._perspective.fov/2));Object.assign(t,{top:r,bottom:-r,left:-r*e,right:r*e})}let s=this._rangeSphere();if(s){let r=t.position.distanceTo(s.center);t.far=(r+s.radius)*1.05,t.near=Math.max((r-s.radius)*.95,t.far/5e3)}t.updateProjectionMatrix(),this.dispatchEvent(new Event("change"))}setExtraBounds(t,e){e&&!e.isEmpty()?this._extraBounds.set(t,e.clone()):this._extraBounds.delete(t),this.resize()}_rangeSphere(){let t=this._visibleBounds()?.sphere??null;if(this._extraBounds.size===0)return t;let e=t?this._bounds.box.clone():new se;for(let n of this._extraBounds.values())e.union(n);return e.getBoundingSphere(new Le)}invalidateBounds(){this._bounds=null}_visibleBounds(){if(!this._bounds){let t=this.visibleBox();this._bounds={box:t,sphere:t.isEmpty()?null:t.getBoundingSphere(new Le)}}return this._bounds.sphere&&this._bounds}fitBox(t,e=!0){if(t.isEmpty())return;let n=t.getBoundingSphere(new Le),s=Math.max(n.radius,.001),r=Oe.degToRad(this._perspective.fov/2),o=this.dom.clientWidth/Math.max(this.dom.clientHeight,1),a=s/Math.sin(Math.min(r,Math.atan(Math.tan(r)*o))),l=this.camera.position.clone().sub(this.target);l.lengthSq()<1e-12&&l.copy(Vx);let c=l.normalize().multiplyScalar(a).add(n.center);e?this.animateTo({position:c,target:n.center}):this._set(c,n.center)}zoomToBox(t){this.fitBox(t,!0)}animateTo({position:t,target:e},n=400){this._stopAnimation();let s={position:this.camera.position.clone(),target:this.target.clone()},r={position:t??s.position,target:e??s.target},o=performance.now(),a=l=>{let c=Math.min((l-o)/n,1),h=Pd(s,r,c*c*(3-2*c));this._set(h.position,h.target),this._animation=c<1?requestAnimationFrame(a):0};this._animation=requestAnimationFrame(a)}get animating(){return this._animation!==0}_stopAnimation(){cancelAnimationFrame(this._animation),this._animation=0}_set(t,e){this.camera.position.copy(t),this.target.copy(e),this.camera.lookAt(e),this.resize()}_down(t){this._end(),this._stopAnimation(),this.dom.setPointerCapture(t.pointerId),t.preventDefault();let e=t.button===0&&t.shiftKey?"box":t.button===0&&this.leftButtonMode==="orbit"?"orbit":"pan",n={x:t.clientX,y:t.clientY},s=null;e==="orbit"&&(s=this.pick(n.x,n.y),s||(s=this._visibleBounds()?.sphere.center.clone()??this.target.clone())),this._drag={id:t.pointerId,button:t.button,mode:e,pivot:s,down:n,last:n,moved:!1}}_move(t){let e=this._drag;if(!e||t.pointerId!==e.id)return;if(t.buttons===0)return this._end();let n={x:t.clientX,y:t.clientY};if(!e.moved&&Ad(e.down,n))return;e.moved=!0;let s=n.x-e.last.x,r=n.y-e.last.y;if(e.last=n,e.mode==="box")this._drawRect(e.down,n);else if(e.mode==="orbit"){let o=Rd(this.camera.position,this.target,e.pivot,s,r,kx);this._set(o.position,o.target)}else this._pan(s,r)}_pan(t,e){let n=this.camera,s=Math.max(this.dom.clientHeight,1),r=n.isPerspectiveCamera?2*n.position.distanceTo(this.target)*Math.tan(Oe.degToRad(n.fov/2))/s:(n.top-n.bottom)/s,o=new C(1,0,0).applyQuaternion(n.quaternion),a=new C(0,1,0).applyQuaternion(n.quaternion),l=o.multiplyScalar(-t*r).addScaledVector(a,e*r);this._set(n.position.clone().add(l),this.target.clone().add(l))}_up(t){let e=this._drag;if(!e||t.pointerId!==e.id||t.button!==e.button)return;let n={x:t.clientX,y:t.clientY};if(this._end(),e.mode==="box"&&e.moved){let s={x:Math.min(e.down.x,n.x),y:Math.min(e.down.y,n.y),width:Math.abs(n.x-e.down.x),height:Math.abs(n.y-e.down.y)},r=Uc(e.down.x,n.x);this.dispatchEvent(Fc("boxselect",{rect:s,mode:r,ctrl:t.ctrlKey,shift:t.shiftKey}))}else!e.moved&&e.button===0?this.dispatchEvent(Fc("click",{x:n.x,y:n.y,button:0,ctrl:t.ctrlKey,shift:t.shiftKey})):!e.moved&&e.button===2&&this.dispatchEvent(Fc("contextmenu",{x:n.x,y:n.y}))}_lostCapture(t){this._drag&&t.buttons?this.dom.setPointerCapture(this._drag.id):this._end()}_end(){this._drag=null,this._overlay?.remove(),this._overlay=null}_drawRect(t,e){this._overlay||(this._overlay=document.createElement("div"),Object.assign(this._overlay.style,{position:"fixed",pointerEvents:"none",border:"1px solid #2563eb",background:"rgba(37,99,235,0.12)"}),(this.dom.parentElement??document.body).appendChild(this._overlay)),Object.assign(this._overlay.style,{borderStyle:Uc(t.x,e.x)==="window"?"solid":"dashed",left:`${Math.min(t.x,e.x)}px`,top:`${Math.min(t.y,e.y)}px`,width:`${Math.abs(e.x-t.x)}px`,height:`${Math.abs(e.y-t.y)}px`})}_wheel(t){if(t.preventDefault(),t.deltaY===0)return;this._stopAnimation(),this._wheelPick||(this._wheelPick={point:this.pick(t.clientX,t.clientY)},requestAnimationFrame(()=>this._wheelPick=null));let e=this._wheelPick.point??this.target,n=Cd(this.camera.position,this.target,e,Id(t.deltaY,t.deltaMode,this.dom.clientHeight));this._set(n.position,n.target)}};function nt(i,t,e){let n=document.createElement(i);return t&&(n.className=t),e!==void 0&&(n.textContent=e),n}function qe(i,t,e){let n=nt("button",i);return n.type="button",n.innerHTML=t,n.title=e,n.setAttribute("aria-label",e),n}function La(i){i.preventDefault(),i.stopPropagation()}function Da(i){La(i);let t=()=>{window.removeEventListener("pointerup",e,!0),setTimeout(()=>window.removeEventListener("click",La,!0))},e=n=>{La(n),t()};window.addEventListener("pointerup",e,!0),window.addEventListener("click",La,!0)}function Na(i,t,e,n){let s=t.clone().applyMatrix4(e.matrixWorldInverse).z<0,r=t.clone().project(e);i.hidden=!(s&&Math.abs(r.x)<=1&&Math.abs(r.y)<=1),!i.hidden&&(i.style.left=`${n.left+(r.x+1)/2*n.width}px`,i.style.top=`${n.top+(1-r.y)/2*n.height}px`)}var de=i=>``,Ld='',Zt={model:de(''),views:de(''),sections:de(''),clashes:de(''),timeliner:de(''),links:de(''),orbit:de(''),pan:de(''),fit:de(''),projection:de(Ld),plane:de(''),box:de(`${Ld}`),resetSections:de(''),distance:de(''),displayMode:de(''),grids:de(''),opacity:de(''),fullscreen:de(''),close:de(''),chevron:de(''),flip:de(''),remove:de(''),play:de(''),pause:de(''),home:de('')};var gr=new C(0,0,1),on={right:new C(1,0,0),left:new C(-1,0,0),back:new C(0,1,0),front:new C(0,-1,0),top:new C(0,0,1),bottom:new C(0,0,-1)},Hx={right:gr,left:gr,back:gr,front:gr,top:on.back,bottom:on.front},Ni=.7,Gx=Oe.degToRad(1),Dd=.01,Nd=96,Ua=1.75;function Ud(i){let t=i.split("-"),e=new C;for(let n of t){if(!Object.hasOwn(on,n))throw new RangeError(`Unknown view cube region: ${i}`);e.add(on[n])}if(new Set(t).size!==t.length||e.lengthSq()!==t.length)throw new RangeError(`Unknown view cube region: ${i}`);return e.normalize()}function Wx(i){let t=[];return Math.abs(i.z)>=Ni&&t.push(i.z>0?"top":"bottom"),Math.abs(i.y)>=Ni&&t.push(i.y>0?"back":"front"),Math.abs(i.x)>=Ni&&t.push(i.x>0?"right":"left"),t.join("-")}function Fd(i,t=Gx){let e=i.clone().normalize(),n=Math.cos(t);return Object.keys(on).find(s=>e.dot(on[s])>=n)??null}function Bd(i){let t=new C(i.x,i.y,0);if(t.lengthSq()<1e-24)return"front";t.normalize();let e=["front","right","back","left"],n=Math.max(...e.map(s=>t.dot(on[s])));return e.find(s=>t.dot(on[s])>=n-1e-9)}function Bc(i,t){return on[Bd(t)].clone().multiplyScalar(Math.sin(Dd)).addScaledVector(on[i],Math.cos(Dd))}function Xx(i,t){let e=Fd(i);if(!e)return null;let n=e==="top"||e==="bottom";if(t==="left"||t==="right")return(n?Bc(e,i):Ud(e)).applyAxisAngle(gr,t==="right"?Math.PI/2:-Math.PI/2);if(t!=="up"&&t!=="down")throw new RangeError(`Unknown arrow: ${t}`);if(!n)return Bc(t==="up"?"top":"bottom",i);let s=on[Bd(i)];return t==="up"==(e==="top")?s.clone().negate():s.clone()}function qx(i,t){let e=document.createElement("canvas");e.width=e.height=128;let n=e.getContext("2d");n.fillStyle="#2a2f38",n.fillRect(0,0,128,128),n.fillStyle="#cbd5e1",n.textAlign="center",n.textBaseline="middle",n.font=`600 26px ${t}`;let s=n.measureText(i).width;s>112&&(n.font=`600 ${Math.floor(2912/s)}px ${t}`),n.fillText(i,64,64);let r=new Ws(e);return r.colorSpace=Se,r}var Fa=class{constructor(t,e,n){this.controls=n,this.home={position:e.position.clone(),target:n.target.clone()},this.element=nt("div","ioviewer-viewcube"),this.canvas=nt("canvas","ioviewer-viewcube-canvas"),this.canvas.title=st("cube.title"),this.canvas.setAttribute("aria-label",st("cube.title")),this.element.append(this.canvas),this.error=null,this.renderer=this._createRenderer(),this.scene=new Mi,this.camera=new In(-Ua,Ua,Ua,-Ua,.1,10),this.faces=new be;let s=getComputedStyle(t).fontFamily;for(let[a,l]of Object.entries(on)){let c=st(`face.${a}`),h=new _e(new Gn(2,2),new cn({map:qx(c,s)})),d=Hx[a];h.quaternion.setFromRotationMatrix(new Ht().makeBasis(d.clone().cross(l),d,l)),h.position.copy(l),h.name=a,h.userData.label=c,this.faces.add(h)}let r=new gn(new Ti(new hn(2,2,2)),new sn({color:"#5b6575"}));this.highlight=new _e(new hn(1,1,1),new cn({color:"#2563eb",transparent:!0,opacity:.6})),this.highlight.visible=!1,this.scene.add(this.faces,r,this.highlight),this._raycaster=new Ai,this.hovered=null,this.canvas.addEventListener("pointermove",a=>this._hover(this.regionAtClient(a.clientX,a.clientY))),this.canvas.addEventListener("pointerleave",()=>this._hover(null)),this.canvas.addEventListener("click",a=>{let l=this.regionAtClient(a.clientX,a.clientY);if(!l)return;let c=l==="top"||l==="bottom";this._look(c?Bc(l,n.camera.position.clone().sub(n.target)):Ud(l))}),this.arrows=["up","down","left","right"].map(a=>{let l=qe("ioviewer-viewcube-arrow",Zt.chevron,st(`cube.${a}`));return l.dataset.arrow=a,l.addEventListener("click",()=>this._arrow(a)),l});let o=qe("ioviewer-viewcube-home",Zt.home,st("cube.home"));o.addEventListener("click",()=>n.animateTo({position:this.home.position.clone(),target:this.home.target.clone()})),this.element.append(...this.arrows,o),t.append(this.element),this.update()}_createRenderer(){this.canvas.addEventListener("webglcontextlost",e=>{e.stopImmediatePropagation(),this._fail(new Error("The view cube lost its WebGL context."))});let t=this.canvas.getContext("webgl2",{alpha:!0,antialias:!0});if(!t)return this._fail(new Error("WebGL 2 is not available for the view cube."));try{let e=new Ss({canvas:this.canvas,context:t,alpha:!0,antialias:!0});return e.setPixelRatio(window.devicePixelRatio),e.setSize(Nd,Nd),e}catch(e){return this._fail(e)}}_fail(t){return this.error=t,this.renderer=null,this.element.hidden=!0,null}_render(){if(this.renderer)try{this.renderer.render(this.scene,this.camera)}catch(t){this._fail(t)}}update(){if(!this.renderer)return;let t=this.controls.camera;this.camera.quaternion.copy(t.quaternion),this.camera.position.set(0,0,5).applyQuaternion(t.quaternion),this.camera.updateMatrixWorld();let e=Fd(t.position.clone().sub(this.controls.target))!==null;for(let n of this.arrows)n.hidden=!e;this._render()}regionAtClient(t,e){let n=this.canvas.getBoundingClientRect(),s=new zt((t-n.left)/n.width*2-1,1-(e-n.top)/n.height*2);this._raycaster.setFromCamera(s,this.camera);let r=this._raycaster.intersectObjects(this.faces.children)[0];return r?Wx(r.point):null}_hover(t){if(t!==this.hovered){if(this.hovered=t,this.highlight.visible=!!t,t){let e=t.split("-").reduce((a,l)=>a.add(on[l]),new C),n=a=>a===0?[-Ni,Ni]:a>0?[Ni,1.02]:[-1.02,-Ni],[s,r,o]=e.toArray().map(n);this.highlight.scale.set(s[1]-s[0],r[1]-r[0],o[1]-o[0]),this.highlight.position.set((s[0]+s[1])/2,(r[0]+r[1])/2,(o[0]+o[1])/2)}this._render()}}_arrow(t){let n=this.controls.camera.position.clone().sub(this.controls.target),s=Xx(n,t);s&&this._look(s)}_look(t){let{controls:e}=this,n=e.camera.position.distanceTo(e.target);e.animateTo({position:t.clone().multiplyScalar(n).add(e.target),target:e.target.clone()})}};var Yx=`
#include
${Cc}
#include
@@ -4288,7 +4288,8 @@ void main() {
#endif
}`,Od=i=>i&&{element:i.element,point:i.point.clone()};function Oc(i,t){let e=new Ze({vertexShader:Yx,fragmentShader:$x,uniforms:i,defines:t?{[t]:""}:{},side:Be,clipping:!0});return e.index0AttributeName="q",e}var Ba=class{constructor(t,e,n,s={}){this.renderer=t,this.scene=e,this.camera=n,this._lost=!1,t.domElement.addEventListener("webglcontextlost",()=>this._lost=!0),this._last=null,this._key=new Float64Array(36),e.root.addEventListener("change",o=>o.detail.kind!=="appearance"&&(this._last=null));let r=e.slotUniforms;this._float=s.pickFloat!==!1&&t.extensions.has("EXT_color_buffer_float"),this._float?(this._material=Oc(r,null),this._target=new Fe(1,1,{type:We}),this._pixel=new Float32Array(4)):(this._material=Oc(r,"IO_PICK_RGBA8"),this._depthMaterial=Oc(r,"IO_PICK_DEPTH"),this._target=new Fe(1,1),this._pixel=new Uint8Array(4))}pick(t,e){let n=this.renderer.domElement.getBoundingClientRect(),s=Math.floor(t-n.left),r=Math.floor(e-n.top);if(this._lost||!(s>=0&&r>=0&&sh===a[d]))return Od(l.hit);let c=this._pick(s,r,n);return this._last={camera:o,key:a.slice(),hit:c},Od(c)}_pick(t,e,n){let s=this._render(this._material,t,e,n),r=(this._float?Math.round(s[3]):new Uint32Array(s.buffer)[0])-1;if(r<0)return null;let o=this.scene.slotElement(r);if(this._float)return{element:o,point:new C(s[0],s[1],s[2])};let[a,l,c,h]=this._render(this._depthMaterial,t,e,n),d=a/256+l/65536+c/16777216+h/255/16777216,u=new C((t+.5)/n.width*2-1,1-(e+.5)/n.height*2,d*2-1);return{element:o,point:u.unproject(this.camera)}}_render(t,e,n,s){let{renderer:r,camera:o}=this,a={target:r.getRenderTarget(),color:r.getClearColor(new Dt),alpha:r.getClearAlpha()},l=this.scene._buckets[0]?.material;t.clippingPlanes=l?.clippingPlanes??null,t.clipIntersection=l?.clipIntersection??!1,o.updateMatrixWorld(),o.setViewOffset(s.width,s.height,e,n,1,1);try{r.setRenderTarget(this._target),r.setClearColor(0,0),this.scene.withMaterial(t,()=>r.render(this.scene.root,o)),r.readRenderTargetPixels(this._target,0,0,1,1,this._pixel)}finally{r.setRenderTarget(a.target),r.setClearColor(a.color,a.alpha),o.clearViewOffset()}return this._pixel}};var zd=33.333333333333336,Zx=200,kd=1e6,Oa=class{constructor(t,e,n=1e7){this.scene=t,this.budget=n,this.minPixels=0,this._requestRender=e,this._last=new Float64Array(32),this._seen=!1,this._requestedAt=null,this._frame=null,this._cost=0,this._settle=0}requested(t){this._requestedAt??(this._requestedAt=t)}begin(t,e,n){t.updateMatrixWorld();let s=this._requestedAt===null?0:Math.max(n-this._requestedAt,0);this._requestedAt=null;let r=this._moved(t);this._frame=r?{start:n,waited:s}:null,this.minPixels=r?this.scene.detailThreshold(t,e,this.budget):0,this.scene.setDetail(this.minPixels,e),r&&(clearTimeout(this._settle),this.minPixels>0&&(this._settle=setTimeout(this._requestRender,Zx)))}end(t){this.scene.setDetail(0),this._frame&&this._adapt(this._frame.waited+(t-this._frame.start)),this._frame=null}_adapt(t){this._cost=this._cost?this._cost*.8+t*.2:t,this._cost>zd*1.1?this.budget=Math.max(this.budget*.9,kd):this._cost0&&(this.budget=Math.max(Math.min(this.budget*1.05,this.scene.visibleCost),kd))}_moved(t){let e=this._last,n=[...t.matrixWorld.elements,...t.projectionMatrix.elements],s=(o,a)=>a!==26&&a!==30&&Math.abs(o-e[a])>1e-9*Math.max(1,Math.abs(o)),r=this._seen&&n.some(s);return this._seen=!0,e.set(n),r}};var Mn,Es,za,ka=class extends EventTarget{constructor(){super(...arguments);ja(this,Es);ja(this,Mn,new Set)}get size(){return Zn(this,Mn).size}has(e){return Zn(this,Mn).has(e)}values(){return Zn(this,Mn).values()}set(e){th(this,Mn,new Set(e)),br(this,Es,za).call(this)}toggle(e){Zn(this,Mn).delete(e)||Zn(this,Mn).add(e),br(this,Es,za).call(this)}clear(){Zn(this,Mn).size!==0&&(Zn(this,Mn).clear(),br(this,Es,za).call(this))}};Mn=new WeakMap,Es=new WeakSet,za=function(){this.dispatchEvent(new Event("change"))};function Vd(i,t,e){if(t!=="window"&&t!=="crossing")throw new RangeError(`Unknown box select mode: ${t}`);let n=i.x+i.width,s=i.y+i.height,r=t==="window"?o=>o.minX>=i.x&&o.maxX<=n&&o.minY>=i.y&&o.maxY<=s:o=>o.maxX>=i.x&&o.minX<=n&&o.maxY>=i.y&&o.minY<=s;return e.filter(r).map(o=>o.index)}function Hd(i,t,e){let n=new Ht().multiplyMatrices(t.projectionMatrix,t.matrixWorldInverse).elements,{left:s,top:r,width:o,height:a}=e,l=new se,c=[];for(let h=0;hn===l?r(l):o(l));let m=[...t.children].find(b=>Gd.indexOf(b.dataset.panel)>g);t.insertBefore(_,m??null);let f=nt("section","ioviewer-side-panel ioviewer-floating");f.dataset.panel=l,f.hidden=!0,f.setAttribute("aria-label",h);let w=qe("ioviewer-panel-close",Zt.close,st("close"));w.addEventListener("click",()=>r(l));let R=nt("header","ioviewer-panel-header");R.append(nt("h2","",h),w);let S=nt("div","ioviewer-panel-body");f.append(R,S),i.append(f),e.set(l,{button:_,panel:f,onClose:p}),d(S)}return{rail:t,openPanel:o,closePanel:r,registerPanel:a}}var Xd=[{id:"navigation",items:["orbit","pan","fit","projection"]},{id:"sections",items:["plane","box","resetSections"]},{id:"measure",items:["distance"]},{id:"display",items:["displayMode","grids","opacity"]},{id:"view",items:["fullscreen"]}];function qd(i,t){let e=nt("div","ioviewer-toolbar ioviewer-floating");e.setAttribute("role","toolbar");let n=new Map;for(let o of t){let a=nt("div","ioviewer-toolbar-group");a.setAttribute("role","group"),a.setAttribute("aria-label",st(`group.${o.id}`));let l=nt("div","ioviewer-toolbar-row");for(let c of o.items){let h=qe("ioviewer-tool",Zt[c],st(`tool.${c}`));h.dataset.tool=c,h.setAttribute("aria-disabled","true");let d={button:h,handler:null};h.addEventListener("click",()=>{h.getAttribute("aria-disabled")!=="true"&&d.handler?.()}),n.set(c,d),l.append(h)}a.append(l,nt("div","ioviewer-toolbar-label",st(`group.${o.id}`))),e.append(a)}i.append(e);function s(o){let a=n.get(o);if(!a)throw new RangeError(`Unknown tool: ${o}`);return a}function r(o,a){s(o).button.setAttribute("aria-disabled",String(!a))}return{element:e,setHandler(o,a){s(o).handler=a,r(o,!0)},setEnabled:r,setActive(o,a){let{button:l}=s(o);l.classList.toggle("active",a),l.setAttribute("aria-pressed",String(a))}}}var Ui=24,Jx=8;function Kx(i,t,e,n,s){let r=Math.min(n,Math.max(0,Math.floor(i/t)-s)),o=Math.min(n,Math.ceil((i+e)/t)+s);return{start:r,end:Math.max(r,o)}}function jx(i){let t=null;return e=>{let n=e.trim().toLowerCase();t??(t=i.map(r=>`${r.name??""}
${r.type??""}
-${r.id}`.toLowerCase()));let s=[];for(let r=0;r{let s=e.category??"";t.has(s)||t.set(s,[]),t.get(s).push(n)}),[...t].map(([e,n])=>({name:e,indices:n})).sort((e,n)=>e.name.localeCompare(n.name))}function Yd(i,{elements:t,selection:e,scene:n,activate:s}){let r=Qx(t),o=new Int32Array(t.length);r.forEach((b,y)=>b.indices.forEach(T=>o[T]=y));let a=new Uint8Array(r.length),l=jx(t),c="",h=new Int32Array(0),d=-1,u=nt("input","ioviewer-tree-search");u.type="search",u.placeholder=st("searchPlaceholder"),u.setAttribute("aria-label",st("searchPlaceholder"));let p=nt("div","ioviewer-tree");p.setAttribute("role","tree"),p.setAttribute("aria-label",st("panel.model"));let g=nt("div","ioviewer-tree-spacer");p.append(g);let _=nt("div","ioviewer-tree-empty",st("noMatches"));i.append(u,p,_);function m(){if(c)h=Int32Array.from(l(c));else{let b=r.length;r.forEach((T,v)=>a[v]&&(b+=T.indices.length)),h=new Int32Array(b);let y=0;r.forEach((T,v)=>{if(h[y++]=-(v+1),a[v])for(let E of T.indices)h[y++]=E})}g.style.height=`${h.length*Ui}px`,_.hidden=h.length>0||!c,f()}function f(){let{start:b,end:y}=Kx(p.scrollTop,Ui,p.clientHeight,h.length,Jx),T=[];for(let v=b;vp.scrollTop+y&&(p.scrollTop=T+Ui-y)}function S(b){let y=o[b];!c&&!a[y]&&(a[y]=1,m());let T=h.indexOf(b);T>=0&&R(T),f()}u.addEventListener("input",()=>{c=u.value.trim(),p.scrollTop=0,m()}),p.addEventListener("scroll",f),p.addEventListener("click",b=>{let y=b.target.closest(".tree-row");if(!y)return;let T=h[Number(y.dataset.row)];if(T>=0){s(T);return}a[-T-1]^=1,m()}),new ResizeObserver(()=>{d>=0&&p.clientHeight>0&&(R(d),d=-1),f()}).observe(p),e.addEventListener("change",()=>{let b=-1;for(let y of e.values())b=y;b>=0?S(b):f()}),n.root.addEventListener("change",b=>b.detail.kind==="visibility"&&f()),m()}var $d={element:["properties","hide","isolate","showAll","-","zoomTo","sectionBox","-","copyId"],empty:["showAll","fitAll","resetSections"]},tv={hide:"H",isolate:"I",showAll:"Shift+H",zoomTo:"F"},Va=4;function Zd(i){let t=nt("div","ioviewer-context-menu");t.setAttribute("role","menu"),t.hidden=!0,i.append(t);let e=new Map(Object.values($d).flat().filter(l=>l!=="-").map(l=>[l,{enabled:!1,handler:null}]));function n(){t.hidden||(t.hidden=!0,t.replaceChildren(),window.removeEventListener("pointerdown",r,!0),window.removeEventListener("wheel",n,!0),window.removeEventListener("scroll",s,!0),window.removeEventListener("resize",n))}function s(l){i.contains(l.target)||n()}function r(l){t.contains(l.target)||(n(),Da(l))}function o(l,c,h,d){let u=$d[l];if(!u)throw new RangeError(`Unknown menu: ${l}`);n();for(let _ of u){if(_==="-"){t.append(nt("div","ioviewer-menu-separator"));continue}let m=e.get(_),f=nt("button","ioviewer-menu-item");f.type="button",f.dataset.item=_,f.setAttribute("role","menuitem"),f.disabled=!m.enabled,f.append(nt("span","",st(`menu.${_}`)),nt("kbd","",tv[_]??"")),f.addEventListener("click",()=>{n(),m.handler(d)}),t.append(f)}t.hidden=!1;let{width:p,height:g}=t.getBoundingClientRect();t.style.left=`${Math.max(Va,Math.min(c,innerWidth-p-Va))}px`,t.style.top=`${Math.max(Va,Math.min(h,innerHeight-g-Va))}px`,window.addEventListener("pointerdown",r,!0),window.addEventListener("wheel",n,!0),window.addEventListener("scroll",s,!0),window.addEventListener("resize",n)}function a(l,{enabled:c=!0,handler:h}){let d=e.get(l);if(!d)throw new RangeError(`Unknown menu item: ${l}`);h&&(d.handler=h),d.enabled=c&&!!d.handler}return{element:t,open:o,close:n,setItem:a,get isOpen(){return!t.hidden}}}var ev="input, textarea, select, [contenteditable]";function nv(i){if(i.ctrlKey||i.altKey||i.metaKey||i.repeat||i.target?.closest?.(ev))return null;switch(i.code){case"KeyH":return i.shiftKey?"showAll":"hide";case"KeyI":return i.shiftKey?null:"isolate";case"KeyF":return i.shiftKey?null:"zoomTo";case"Escape":return"escape";default:return null}}function Jd(i,t){i.addEventListener("keydown",e=>{let n=nv(e);n&&(e.preventDefault(),t[n]())})}var iv=1600;function Kd(i,t,e){let n=()=>i.textContent=`${st("selected")}: ${t.size} \xB7 ${st("elements")}: ${e}`;t.addEventListener("change",n),n()}function jd(i,t){if(!t)return;let e=nt("div","ioviewer-banner ioviewer-floating");e.setAttribute("role","status");let n=st("truncated").replace("{meshes}",t.meshes).replace("{total}",t.totalMeshes),s=qe("ioviewer-panel-close",Zt.close,st("close"));s.addEventListener("click",()=>e.remove()),e.append(nt("span","",n),s),i.append(e)}function Ts(i,t){let e=nt("div","ioviewer-toast",t);e.setAttribute("role","status"),i.append(e),setTimeout(()=>e.remove(),iv)}function Qd(i,t){let e=nt("table");for(let[s,r]of t)e.insertRow().append(nt("th","",s),nt("td","",String(r??"")));let n=nt("section");return n.append(nt("h3","",i),e),n}function tf(i,t,e){let n=nt("h2","ioviewer-properties-title"),s=nt("button","ioviewer-properties-close","\xD7");s.type="button",s.title=st("close"),s.setAttribute("aria-label",st("close")),s.addEventListener("click",()=>t.clear());let r=nt("header");r.append(n,s);let o=nt("div","ioviewer-properties-body");i.replaceChildren(r,o),i.hidden=!0,t.addEventListener("change",()=>{if(i.hidden=t.size===0,o.replaceChildren(),t.size!==1){n.textContent=`${st("selected")}: ${t.size}`;return}let[a]=t.values(),l=e.meta.elements[a];n.textContent=l.name||`#${l.id}`;let c=[[st("id"),l.id],[st("category"),l.category],[st("type"),l.type],[st("level"),l.level]];l.link&&c.push([st("link"),l.link]),o.append(Qd(st("elementGroup"),c));for(let[h,d]of Object.entries(e.props(l.id)??{}))o.append(Qd(h,Object.entries(d)))})}async function sv(i){if(await navigator.clipboard?.writeText(i).then(()=>!0,()=>!1))return!0;let t=document.createElement("textarea");t.value=i,t.setAttribute("readonly",""),t.className="ioviewer-offscreen",document.body.append(t),t.select();try{return document.execCommand("copy")}finally{t.remove()}}function ef({root:i,data:t,scene:e,controls:n,picker:s,selection:r,measure:o}){let{meta:a}=t,l=()=>n.fitBox(e.visibleBox()),c={hide:()=>r.size&&e.setVisible([...r.values()],!1),isolate:()=>r.size&&e.isolate([...r.values()]),showAll:()=>e.showAll(),zoomTo:()=>{if(!r.size)return l();let[m,...f]=r.values(),w=e.elementBox(m);for(let R of f)w.union(e.elementBox(R));n.zoomToBox(w)},fitAll:l},h=Wd(i);h.registerPanel("model",{icon:Zt.model,title:st("panel.model"),render:m=>Yd(m,{elements:a.elements,selection:r,scene:e,activate:f=>{r.set([f]),n.zoomToBox(e.elementBox(f))}})});let d=document.createElement("aside");d.id="ioviewer-properties",d.className="ioviewer-floating",i.append(d),tf(d,r,t);let u=qd(i,Xd),p=m=>{n.setLeftButtonMode(m),u.setActive("orbit",m==="orbit"),u.setActive("pan",m==="pan")};u.setHandler("orbit",()=>p("orbit")),u.setHandler("pan",()=>p("pan")),p(n.leftButtonMode),u.setHandler("fit",l),u.setHandler("projection",()=>{let m=!n.camera.isOrthographicCamera;n.setProjection(m?"orthographic":"perspective"),u.setActive("projection",m)}),u.setActive("projection",!1),document.fullscreenEnabled&&(u.setHandler("fullscreen",()=>{(document.fullscreenElement?document.exitFullscreen():document.documentElement.requestFullscreen()).catch(()=>{u.setActive("fullscreen",!!document.fullscreenElement),Ts(i,st("fullscreenUnavailable"))})}),document.addEventListener("fullscreenchange",()=>u.setActive("fullscreen",!!document.fullscreenElement)));let g=Zd(i);g.setItem("properties",{handler:m=>r.set([m])});for(let m of["hide","isolate","showAll","zoomTo","fitAll"])g.setItem(m,{handler:c[m]});g.setItem("copyId",{handler:m=>sv(String(a.elements[m].id)).then(f=>Ts(i,st(f?"idCopied":"copyFailed")),()=>Ts(i,st("copyFailed")))}),n.addEventListener("contextmenu",m=>{let{x:f,y:w}=m.detail;if(o.active){let[S]=r.values();return S===void 0?g.open("empty",f,w,null):g.open("element",f,w,S)}let R=s.pick(f,w);if(!R||R.element<0)return g.open("empty",f,w,null);r.has(R.element)||r.set([R.element]),g.open("element",f,w,R.element)});let _=[];return Jd(window,{...c,escape:()=>{if(g.isOpen)return g.close();_.some(m=>m())||r.clear()}}),Kd(document.getElementById("ioviewer-status"),r,e.elementCount),jd(i,a.truncated),{shell:h,toolbar:u,contextMenu:g,onEscape:m=>_.push(m)}}var rv={x:new C(1,0,0),y:new C(0,1,0),z:new C(0,0,1)};function zc(i){let t=rv[i];if(!t)throw new RangeError(`Unknown axis: ${i}`);return t.clone()}function nf(i,t,e,n){let s=i.clone().normalize(),r=s.dot(t)+e;return n?new ge(s,-r):new ge(s.negate(),r)}function sf(i,t){if(t!=="keepInside"&&t!=="cutInside")throw new RangeError(`Unknown box mode: ${t}`);let{min:e,max:n}=i,s=[new ge(new C(1,0,0),-e.x),new ge(new C(-1,0,0),n.x),new ge(new C(0,1,0),-e.y),new ge(new C(0,-1,0),n.y),new ge(new C(0,0,1),-e.z),new ge(new C(0,0,-1),n.z)];return t==="keepInside"?{planes:s,intersection:!1}:{planes:s.map(r=>r.negate()),intersection:!0}}function rf(i){let{min:t,max:e}=i;return Array.from({length:8},(n,s)=>new C(s&1?e.x:t.x,s&2?e.y:t.y,s&4?e.z:t.z))}function Ha(i,t,e){if(t.length===0||i.isEmpty())return!1;let n=rf(i),s=r=>n.every(o=>r.distanceToPoint(o)<0);return e?t.every(s):t.some(s)}function of(i,t){let e=i.getSize(new C).multiplyScalar(.5);return Math.abs(t.x)*e.x+Math.abs(t.y)*e.y+Math.abs(t.z)*e.z}function _r(i,t,e){let n=t.clone().sub(i.origin),s=e.dot(i.direction),r=1-s*s;return r<.03?null:(s*i.direction.dot(n)-e.dot(n))/r}function af(i,t,e){let n=new C(1,0,0).applyQuaternion(t),s=new C(0,1,0).applyQuaternion(t),[r,o,a,l]=[1/0,-1/0,1/0,-1/0];for(let h of rf(i)){h.sub(e);let d=h.dot(n),u=h.dot(s);[r,o,a,l]=[Math.min(r,d),Math.max(o,d),Math.min(a,u),Math.max(l,u)]}return{center:e.clone().addScaledVector(n,(r+o)/2).addScaledVector(s,(a+l)/2),width:(o-r)*1.1,height:(l-a)*1.1}}var xr=6,ov=["off","planes","box"],av=.05,lf=new C(0,0,1),Ga=class extends EventTarget{constructor(t,e){super(),this.scene=t,this.modelBox=e.clone(),this.center=e.getCenter(new C),this.planes=[],this.active=-1,this.box=null,this.boxMode="keepInside",this.gizmoVisible=!0,this._mode="off"}get mode(){return this._mode}setMode(t){if(!ov.includes(t))throw new RangeError(`Unknown section mode: ${t}`);t==="box"&&!this.box&&this.fitBoxToShown()||(this._mode=t,this._changed(!0))}addPlane(t){let e=zc(t);if(this.planes.length>=xr||this.modelBox.isEmpty())return null;let n=new Ne().setFromUnitVectors(lf,e);return this.planes.push({axis:t,quaternion:n,offset:0,flipped:!1,enabled:!0,rotated:!1}),this.active=this.planes.length-1,this._mode="planes",this._changed(!0),this.active}removePlane(t){this._plane(t),this.planes.splice(t,1),(this.active>=this.planes.length||this.active>t)&&this.active--,this._changed(!0)}updatePlane(t,{offset:e,flipped:n,enabled:s,quaternion:r}){let o=this._plane(t);if(e!==void 0){if(!Number.isFinite(e))throw new RangeError(`Offset must be a finite number, got ${e}.`);o.offset=e}n!==void 0&&(o.flipped=!!n),s!==void 0&&(o.enabled=!!s),r&&(o.quaternion.copy(r).normalize(),o.rotated=this.normal(t).angleTo(zc(o.axis))>1e-6),this._changed(!0)}setActivePlane(t){this._plane(t),this.active=t,this._changed(!1)}normal(t){return lf.clone().applyQuaternion(this._plane(t).quaternion)}extent(t){return of(this.modelBox,this.normal(t))}origin(t){return this.center.clone().addScaledVector(this.normal(t),this._plane(t).offset)}clipPlane(t){let e=this._plane(t);return nf(this.normal(t),this.center,e.offset,e.flipped)}setBox(t){if(t.isEmpty())throw new RangeError("The section box is empty.");this.box=t.clone(),this._mode="box",this._changed(!0)}setBoxMode(t){if(t!=="keepInside"&&t!=="cutInside")throw new RangeError(`Unknown box mode: ${t}`);this.boxMode=t,this._changed(!0)}fitBoxToElements(t){let e=new se;for(let s of t)e.union(this.scene.elementBox(s));if(e.isEmpty())return!1;let n=e.getSize(new C);return this.setBox(e.expandByScalar(av*Math.max(n.x,n.y,n.z))),!0}fitBoxToShown(){let t=this.scene.visibleBox();if(t.isEmpty())return!1;let e=t.getSize(new C);return this.setBox(t.expandByScalar(.001*Math.max(e.x,e.y,e.z))),!0}setGizmoVisible(t){this.gizmoVisible=!!t,this._changed(!1)}reset(){this.planes=[],this.active=-1,this.box=null,this._mode="off",this._changed(!0)}clipping(){return this._mode==="planes"?{planes:this.planes.flatMap((e,n)=>e.enabled?[this.clipPlane(n)]:[]),intersection:!1}:this._mode==="box"&&this.box?sf(this.box,this.boxMode):{planes:[],intersection:!1}}isCut(t){let{planes:e,intersection:n}=this.clipping();return Ha(t,e,n)}_plane(t){let e=this.planes[t];if(!Number.isInteger(t)||!e)throw new RangeError(`Plane index ${t} is out of range 0..${this.planes.length-1}.`);return e}_changed(t){if(t){let{planes:e,intersection:n}=this.clipping();this.scene.setClipping(e,n)}this.dispatchEvent(new Event("change"))}};var lv=80,cv=8,fi={x:"#ef4444",y:"#22c55e",z:"#3b82f6",centre:"#e2e8f0",hover:"#facc15",frame:"#93c5fd",fill:"#60a5fa"},Wa=["x","y","z"],hv=Math.cos(Oe.degToRad(12)),cf=new C(0,0,1),uv=i=>new cn({color:i,depthTest:!1,depthWrite:!1,transparent:!0,opacity:.9}),dv=new cn({visible:!1});function Xa(i,t,e,n){let s=new be,r=uv(t);for(let a of e)s.add(new _e(a,r));let o=new _e(n,dv);return o.userData.handle=s,s.add(o),s.userData={kind:i,color:t,material:r,proxy:o},s.traverse(a=>a.renderOrder=1e3),s}var qa=class extends EventTarget{constructor(t,e){super(),this.sections=t,this.dom=e,this.camera=null,this.group=new be,this.group.name="sections",this._raycaster=new Ai,this._drag=null,this._hovered=null,this._buildPlanes(),this._buildPlaneGizmo(),this._buildBox(),t.addEventListener("change",()=>this._sync()),(e.parentElement??e).addEventListener("pointerdown",n=>this._down(n),!0),e.addEventListener("pointermove",n=>this._move(n)),e.addEventListener("pointerup",n=>this._up(n)),e.addEventListener("pointercancel",()=>this._end()),e.addEventListener("lostpointercapture",()=>this._end()),this._sync()}get dragging(){return this._drag!==null}update(t){this.camera=t;let e=this.planeGizmo;e.visible&&(e.scale.setScalar(this._worldPerPixel(e.position)*lv),this.arrow.visible=this._across(cf.clone().applyQuaternion(e.quaternion),e.position));for(let n of this.boxHandles){let{shown:s,axis:r}=n.userData;n.visible=s&&(!r||this._across(new C().setComponent(Wa.indexOf(r),1),n.position)),n.visible&&n.scale.setScalar(this._worldPerPixel(n.position)*cv)}}_across(t,e){let n=this.camera,s=n.isOrthographicCamera?n.getWorldDirection(new C):e.clone().sub(n.position).normalize();return Math.abs(t.dot(s))new C(r/2,o/2,0))),n=new cn({color:fi.fill,transparent:!0,opacity:.12,side:Be,depthWrite:!1}),s=new sn({color:fi.frame});this.planeVisuals=Array.from({length:xr},()=>{let r=new be;return r.add(new _e(t,n),new Hs(e,s)),this.group.add(r),r})}_buildPlaneGizmo(){let t=(s,r)=>s.rotateX(Math.PI/2).translate(0,0,r),e=Xa("move",fi.z,[t(new Ei(.025,.025,1),.5),t(new qs(.08,.25),1.125)],t(new Ei(.12,.12,1.25),.625));e.name="arrow",this.arrow=e;let n=(s,r,o)=>{let a=Xa("rotate",fi[r],[o(new us(.8,.018,8,64))],o(new us(.8,.09,8,48)));return a.name=s,a.userData.axis=r,a};this.planeGizmo=new be,this.planeGizmo.add(e,n("ringX","x",s=>s.rotateY(Math.PI/2)),n("ringY","y",s=>s.rotateX(Math.PI/2))),this.group.add(this.planeGizmo)}_buildBox(){this.boxWire=new gn(new Ti(new hn(1,1,1)),new sn({color:fi.frame})),this.group.add(this.boxWire);let t=new hs(1,16,12),e=new hs(1.6,8,6);this.boxHandles=[];for(let s of Wa)for(let r of[-1,1]){let o=Xa("face",fi[s],[t],e);o.name=`face${r>0?"+":"-"}${s}`,Object.assign(o.userData,{axis:s,sign:r}),this.boxHandles.push(o)}let n=Xa("centre",fi.centre,[new hn(1.4,1.4,1.4)],e);n.name="centre",this.boxHandles.push(n),this.group.add(...this.boxHandles)}_sync(){let t=this.sections,e=t.mode==="planes";this.planeVisuals.forEach((r,o)=>{let a=t.planes[o];if(r.visible=e&&!!a?.enabled,!r.visible)return;let l=af(t.modelBox,a.quaternion,t.origin(o));r.position.copy(l.center),r.quaternion.copy(a.quaternion),r.scale.set(l.width,l.height,1)});let n=t.planes[t.active];this.planeGizmo.visible=e&&t.gizmoVisible&&!!n?.enabled,this.planeGizmo.visible&&(this.planeGizmo.position.copy(t.origin(t.active)),this.planeGizmo.quaternion.copy(n.quaternion));let s=t.mode==="box"?t.box:null;this.boxWire.visible=!!s;for(let r of this.boxHandles)r.visible=r.userData.shown=!!s&&t.gizmoVisible;if(s){let r=s.getCenter(new C),o=s.getSize(new C);this.boxWire.position.copy(r),this.boxWire.scale.copy(o).max(new C(1e-6,1e-6,1e-6));for(let a of this.boxHandles){a.position.copy(r);let{axis:l,sign:c}=a.userData;l&&(a.position[l]=c>0?s.max[l]:s.min[l])}}}_worldPerPixel(t){let e=this.camera,n=Math.max(this.dom.clientHeight,1);if(e.isOrthographicCamera)return(e.top-e.bottom)/e.zoom/n;let s=t.clone().sub(e.position).dot(e.getWorldDirection(new C));return 2*Math.max(s,e.near)*Math.tan(Oe.degToRad(e.fov/2))/n}_ray(t){let e=this.dom.getBoundingClientRect(),n=new zt((t.clientX-e.left)/e.width*2-1,1-(t.clientY-e.top)/e.height*2);return this.camera.updateMatrixWorld(),this._raycaster.setFromCamera(n,this.camera),this._raycaster.ray.clone()}_hit(t){if(!this.camera)return null;this.update(this.camera),this.group.updateMatrixWorld(!0);let e=r=>{for(;r&&r!==this.group;r=r.parent)if(!r.visible)return!1;return!0},n=[];this.group.traverse(r=>r.userData.handle&&e(r)&&n.push(r)),this._ray(t);let s=this._raycaster.intersectObjects(n,!1)[0];return s?s.object.userData.handle:null}_down(t){if(t.target!==this.dom||t.button!==0)return;let e=this._hit(t),n=e&&this._start(e,this._ray(t));n&&(t.stopPropagation(),t.preventDefault(),this.dom.setPointerCapture(t.pointerId),this._drag={id:t.pointerId,handle:e,...n},this._highlight(e))}_start(t,e){let n=this.sections,{kind:s}=t.userData;if(s==="move"||s==="rotate"){let c=n.active,h=n.origin(c),d=n.planes[c].quaternion.clone();if(s==="move"){let _=n.normal(c),m=_r(e,h,_);return m===null?null:{index:c,origin:h,normal:_,offset:n.planes[c].offset,s0:m}}let u=new C().setComponent(Wa.indexOf(t.userData.axis),1).applyQuaternion(d),p=new ge().setFromNormalAndCoplanarPoint(u,h),g=e.intersectPlane(p,new C)?.sub(h);return g?{index:c,origin:h,quaternion:d,axis:u,plane:p,from:g}:null}let r=n.box.clone();if(s==="face"){let{axis:c,sign:h}=t.userData,d=new C().setComponent(Wa.indexOf(c),h),u=t.position.clone(),p=_r(e,u,d);return p===null?null:{box:r,normal:d,at:u,s0:p}}let o=this.camera.getWorldDirection(new C),a=new ge().setFromNormalAndCoplanarPoint(o,r.getCenter(new C)),l=e.intersectPlane(a,new C);return l?{box:r,plane:a,from:l}:null}_move(t){let e=this._drag;if(!e)return this._hover(t);if(t.pointerId!==e.id)return;if(t.buttons===0)return this._end();let n=this._ray(t),s=this.sections,{kind:r}=e.handle.userData;if(r==="move"){let o=_r(n,e.origin,e.normal);o!==null&&s.updatePlane(e.index,{offset:e.offset+o-e.s0})}else if(r==="rotate"){let o=n.intersectPlane(e.plane,new C)?.sub(e.origin);if(!o)return;let a=Math.atan2(e.axis.dot(new C().crossVectors(e.from,o)),e.from.dot(o)),l=new Ne().setFromAxisAngle(e.axis,a).multiply(e.quaternion),c=cf.clone().applyQuaternion(l);s.updatePlane(e.index,{quaternion:l,offset:c.dot(e.origin.clone().sub(s.center))})}else if(r==="face"){let o=_r(n,e.at,e.normal);if(o===null)return;let{axis:a,sign:l}=e.handle.userData,c=e.box.clone(),h=.001*Math.max(...s.modelBox.getSize(new C).toArray(),.001),d=(l>0?e.box.max[a]:e.box.min[a])+l*(o-e.s0);l>0?c.max[a]=Math.max(d,c.min[a]+h):c.min[a]=Math.min(d,c.max[a]-h),s.setBox(c)}else{let o=n.intersectPlane(e.plane,new C);o&&s.setBox(e.box.clone().translate(o.sub(e.from)))}}_up(t){this._drag&&t.pointerId===this._drag.id&&this._end()}_end(){this._drag&&(this._drag=null,this._highlight(null))}_hover(t){t.buttons===0&&this._highlight(this._hit(t))}_highlight(t){if(this._hovered!==t){for(let e of[this._hovered,t])e&&e.userData.material.color.set(e===t?fi.hover:e.userData.color);this._hovered=t,this.dom.style.cursor=t?"grab":"",this.dispatchEvent(new Event("change"))}}};function vr(i,t,e){let n=nt("div","ioviewer-segmented");n.setAttribute("role","group"),n.setAttribute("aria-label",i);let s=t.map(([o,a])=>{let l=nt("button","",a);return l.type="button",l.dataset.value=o,l.addEventListener("click",()=>e(o)),n.append(l),l});return{element:n,update:o=>s.forEach(a=>a.setAttribute("aria-pressed",String(a.dataset.value===o)))}}function hf(i,t){let e=nt("label","ioviewer-check"),n=nt("input");return n.type="checkbox",n.addEventListener("change",()=>t(n.checked)),e.append(n,nt("span","",i)),{element:e,input:n}}function fv(i,t){let e=nt("li","ioviewer-section-plane");e.addEventListener("pointerdown",()=>i.active!==t&&i.setActivePlane(t));let n=nt("span","ioviewer-section-name"),s=qe("ioviewer-icon-button",Zt.flip,st("sections.flip"));s.addEventListener("click",()=>i.updatePlane(t,{flipped:!i.planes[t].flipped}));let r=hf(st("sections.enabled"),h=>i.updatePlane(t,{enabled:h})),o=qe("ioviewer-icon-button",Zt.remove,st("sections.delete"));o.addEventListener("click",()=>i.removePlane(t));let a=nt("input","ioviewer-section-slider");a.type="range",a.step="any",a.setAttribute("aria-label",st("sections.position")),a.addEventListener("input",()=>i.updatePlane(t,{offset:Number(a.value)}));let l=nt("div","ioviewer-section-head");return l.append(n,s,r.element,o),e.append(l,a),{element:e,update:()=>{let h=i.planes[t],d=h.rotated?` (${st("sections.rotated")})`:"";n.textContent=`${t+1}. ${h.axis.toUpperCase()}${d}`,e.classList.toggle("active",i.active===t),s.setAttribute("aria-pressed",String(h.flipped)),r.input.checked=h.enabled;let u=i.extent(t);a.min=String(-u),a.max=String(u),a.value=String(h.offset)}}}function uf({root:i,shell:t,toolbar:e,contextMenu:n,sections:s,selection:r}){let o="z",a=()=>{s.addPlane(o)===null&&(s.setMode("planes"),Ts(i,st("sections.maxPlanes")))},l=()=>[...r.values()],c=()=>s.fitBoxToElements(l()),h=vr(st("sections.mode"),[["planes",st("sections.planes")],["box",st("sections.box")],["off",st("sections.off")]],E=>s.setMode(E)),d=vr(st("sections.axis"),["x","y","z"].map(E=>[E,E.toUpperCase()]),E=>d.update(o=E));d.update(o);let u=nt("button","ioviewer-text-button",st("sections.addPlane"));u.type="button",u.addEventListener("click",a);let p=nt("ul","ioviewer-section-list"),g=nt("div","ioviewer-section-empty",st("sections.noPlanes")),_=nt("div","ioviewer-section-block"),m=nt("div","ioviewer-section-row");m.append(nt("span","",st("sections.axis")),d.element,u),_.append(m,p,g);let f=vr(st("sections.box"),[["keepInside",st("sections.keepInside")],["cutInside",st("sections.cutInside")]],E=>s.setBoxMode(E)),w=nt("button","ioviewer-text-button",st("sections.fitSelection"));w.type="button",w.addEventListener("click",c);let R=nt("div","ioviewer-section-block");R.append(f.element,w);let S=hf(st("sections.showGizmo"),E=>s.setGizmoVisible(E)),b=[],y=()=>{h.update(s.mode),_.hidden=s.mode!=="planes",R.hidden=s.mode!=="box",u.disabled=s.planes.length>=xr,b.length!==s.planes.length&&(b=s.planes.map((E,P)=>fv(s,P)),p.replaceChildren(...b.map(E=>E.element))),b.forEach(E=>E.update()),g.hidden=b.length>0,f.update(s.boxMode),S.input.checked=s.gizmoVisible,e.setActive("plane",s.mode==="planes"),e.setActive("box",s.mode==="box")},T=()=>w.disabled=r.size===0;if(t.registerPanel("sections",{icon:Zt.sections,title:st("panel.sections"),visible:!s.modelBox.isEmpty(),render:E=>E.append(h.element,_,R,S.element)}),s.addEventListener("change",y),r.addEventListener("change",T),y(),T(),e.setActive("plane",!1),e.setActive("box",!1),s.modelBox.isEmpty())return;let v=()=>t.openPanel("sections");e.setHandler("plane",()=>{a(),v()}),e.setHandler("box",()=>{!(r.size&&c())&&!s.fitBoxToShown()||v()}),e.setHandler("resetSections",()=>s.reset()),n.setItem("sectionBox",{handler:E=>{s.fitBoxToElements(r.has(E)?l():[E]),v()}}),n.setItem("resetSections",{handler:()=>s.reset()})}var pv="#facc15",mv=9;function kc(i,t=mr){return`${new Intl.NumberFormat(t,{minimumFractionDigits:2,maximumFractionDigits:2,useGrouping:!1}).format(i)} ${st("unit.m",t)}`}var Ya=class extends EventTarget{constructor(t){super(),this.active=!1,this.points=[],this.group=new be,this.group.name="measure";let e=new re;e.setAttribute("position",new we(new Float32Array(6),3));let n={color:pv,depthTest:!1,depthWrite:!1,transparent:!0};this._line=new bi(e,new sn(n)),this._markers=new wi(e,new ni({...n,size:mv,sizeAttenuation:!1}));for(let s of[this._line,this._markers])s.frustumCulled=!1,s.renderOrder=1001,this.group.add(s);this.label=nt("div","ioviewer-measure-label"),this.label.hidden=!0,t.prepend(this.label),this._sync()}get distance(){return this.points.length===2?this.points[0].distanceTo(this.points[1]):null}get box(){return new se().setFromPoints(this.points)}setActive(t){this.active=!!t,this.active||(this.points=[]),this._sync()}add(t){this.active&&(this.points=this.points.length===1?[this.points[0],t.clone()]:[t.clone()],this._sync())}clear(){return this.points.length===0?!1:(this.points=[],this._sync(),!0)}update(t,e){this.distance!==null&&Na(this.label,this.points[0].clone().lerp(this.points[1],.5),t,e)}_sync(){let t=this._line.geometry.attributes.position;this.points.forEach((e,n)=>t.setXYZ(n,e.x,e.y,e.z)),t.needsUpdate=!0,this._line.geometry.setDrawRange(0,this.points.length),this._line.visible=this.points.length===2,this._markers.visible=this.points.length>0,this.label.hidden=this.distance===null,this.distance!==null&&(this.label.textContent=kc(this.distance)),this.dispatchEvent(new Event("change"))}};var $a=class extends EventTarget{constructor(t,e){super(),this.count=e.length,this.group=new gn(new re().setAttribute("position",new ce(e.flatMap(s=>[...s.start,...s.end]),3)),new sn({color:"#93c5fd",transparent:!0,opacity:.55,depthTest:!1,depthWrite:!1})),this.group.name="grids",this.group.geometry.computeBoundingBox(),this.box=this.group.geometry.boundingBox,this.group.renderOrder=999,this._labels=e.flatMap(s=>[s.start,s.end].map(r=>({element:nt("div","ioviewer-grid-label",s.name),point:new C(...r)})));let n=nt("div","ioviewer-grid-labels");n.append(...this._labels.map(s=>s.element)),t.prepend(n),this._layer=n,this.setVisible(this.count>0)}get visible(){return this.group.visible}setVisible(t){this.group.visible=!!t,this._layer.hidden=!t,this.dispatchEvent(new Event("change"))}update(t,e){if(this.visible)for(let{element:n,point:s}of this._labels)Na(n,s,t,e)}};var gv=8,df=4;function Vc(i,t,e,n="dialog"){let s=nt("div","ioviewer-popover ioviewer-floating");s.setAttribute("role",n),s.setAttribute("aria-label",e),s.hidden=!0,t.setAttribute("aria-haspopup",n),t.setAttribute("aria-expanded","false"),i.append(s);function r(l){s.contains(l.target)||(a(),Da(l))}s.addEventListener("keydown",l=>{l.key==="Escape"&&(l.preventDefault(),l.stopPropagation(),a(),t.focus())});function o(){s.hidden=!1,t.setAttribute("aria-expanded","true");let l=t.getBoundingClientRect(),{width:c}=s.getBoundingClientRect();s.style.left=`${Math.max(df,Math.min(l.left+l.width/2-c/2,innerWidth-c-df))}px`,s.style.bottom=`${innerHeight-l.top+gv}px`,window.addEventListener("pointerdown",r,!0),window.addEventListener("resize",a)}function a(){return s.hidden?!1:(s.hidden=!0,t.setAttribute("aria-expanded","false"),window.removeEventListener("pointerdown",r,!0),window.removeEventListener("resize",a),!0)}return{element:s,close:a,toggle:()=>s.hidden?o():a(),get isOpen(){return!s.hidden}}}function _v(i){return i?.initialWireframe?"wireframe":i?.initialWhiteMode?"white":"materials"}function ff({root:i,toolbar:t,scene:e,meta:n,grids:s}){let r=_=>t.element.querySelector(`[data-tool="${_}"]`),o=Vc(i,r("displayMode"),st("tool.displayMode"),"menu");o.element.classList.add("ioviewer-display-modes");let a=(n.textures??[]).length>0,l=Nc.map(_=>{let m=nt("button","ioviewer-menu-item",st(`display.${_}`));return m.type="button",m.dataset.mode=_,m.setAttribute("role","menuitemradio"),m.disabled=_==="textures"&&!a,m.addEventListener("click",()=>{c(_),o.close()}),o.element.append(m),m}),c=_=>{e.setDisplayMode(_);for(let m of l)m.setAttribute("aria-checked",String(m.dataset.mode===_))};c(_v(n.options)),t.setHandler("displayMode",o.toggle),t.setActive("grids",s.visible),s.count>0&&t.setHandler("grids",()=>{s.setVisible(!s.visible),t.setActive("grids",s.visible)});let h=Vc(i,r("opacity"),st("tool.opacity"));h.element.classList.add("ioviewer-opacity");let d=nt("input","ioviewer-opacity-slider");Object.assign(d,{type:"range",min:"10",max:"100",step:"1",value:"100"}),d.setAttribute("aria-label",st("opacity.label"));let u=nt("output","ioviewer-opacity-value"),p=()=>u.textContent=st("opacity.value").replace("{value}",d.value);d.addEventListener("input",()=>{e.setOpacity(Number(d.value)/100),p()}),p();let g=nt("div","ioviewer-opacity-head");return g.append(nt("span","",st("opacity.label")),u),h.element.append(g,d),t.setHandler("opacity",h.toggle),[o,h]}var xv=3e3;function Hc(i,t){let e=nt("button",i);return e.type="button",e.setAttribute("title",t),e.append(nt("span","ioviewer-row-name",t)),e}function pf({shell:i,toolbar:t,controls:e,views:n}){let s=null,r=nt("button","ioviewer-text-button ioviewer-tour");r.type="button";function o(g){let _=g.camera.projection==="orthographic";e.setProjection(_?"orthographic":"perspective"),t.setActive("projection",_),e.animateTo({position:new C(...g.camera.position),target:new C(...g.camera.target)})}function a(){o(n[s.next]),s.next=(s.next+1)%n.length;let g=()=>{e.animating?s.frame=requestAnimationFrame(g):s.timer=setTimeout(a,xv)};s.frame=requestAnimationFrame(g)}let l=g=>r.contains(g.target),c=g=>!l(g)&&d(),h=g=>!(l(g)&&(g.key==="Enter"||g.key===" "))&&d();function d(){s&&(cancelAnimationFrame(s.frame),clearTimeout(s.timer),s=null,window.removeEventListener("pointerdown",c,!0),window.removeEventListener("wheel",d,!0),window.removeEventListener("keydown",h,!0),p())}function u(){s={next:0,frame:0,timer:0},window.addEventListener("pointerdown",c,!0),window.addEventListener("wheel",d,!0),window.addEventListener("keydown",h,!0),p(),a()}function p(){let g=st(s?"views.stop":"views.tour");r.replaceChildren(),r.insertAdjacentHTML("afterbegin",s?Zt.pause:Zt.play),r.append(nt("span","",g)),r.setAttribute("aria-pressed",String(!!s))}r.addEventListener("click",()=>s?d():u()),p(),i.registerPanel("views",{icon:Zt.views,title:st("panel.views"),visible:n.length>0,render:g=>{let _=nt("div","ioviewer-row-list");for(let m of n){let f=Hc("ioviewer-row ioviewer-view",String(m.name??""));f.addEventListener("click",()=>o(m)),_.append(f)}g.append(r,_)}})}function mf(i,t){let e=[];for(let[n,s]of[[i.element1Id,i.element1Name],[i.element2Id,i.element2Name]]){let r=n!=null?t.findIndex(o=>o.id===n&&!o.mesh):vv(t,s);r>=0&&!e.includes(r)&&e.push(r)}return e}function vv(i,t){if(t==null)return-1;let e=i.findIndex(n=>n.name===t);return e>=0&&i.findIndex((n,s)=>s>e&&n.name===t)<0?e:-1}var yv=["New","Active","Reviewed","Approved","Resolved"],Mv=14,Sv=2,bv=new C(1,-1,.8).normalize();function gf({shell:i,tests:t,elements:e,scene:n,controls:s,selection:r}){let o=new be;o.name="clash-marker";let a=new re;a.setAttribute("position",new we(new Float32Array(3),3));let l={color:"#ef4444",depthTest:!1,depthWrite:!1,transparent:!0},c=new wi(a,new ni({...l,size:Mv,sizeAttenuation:!1}));c.frustumCulled=!1,c.renderOrder=1002,o.add(c),o.visible=!1;let h=null;function d(){o.visible=!1,h?.removeAttribute("aria-current"),h=null,s.setExtraBounds("clash",null)}function u(_,m){let f=mf(_,e);f.length?r.set(f):r.clear();let w=new C(..._.point),R=0;for(let y of f){let T=n.elementBox(y);T.isEmpty()||(R=Math.max(R,...T.getSize(new C).toArray()))}let S=s.camera.position.clone().sub(s.target);S.lengthSq()<1e-12&&S.copy(bv);let b=Math.max(3*R,Sv);s.animateTo({position:S.normalize().multiplyScalar(b).add(w),target:w}),a.attributes.position.setXYZ(0,w.x,w.y,w.z),a.attributes.position.needsUpdate=!0,o.visible=!0,h?.removeAttribute("aria-current"),h=m,m.setAttribute("aria-current","true"),s.setExtraBounds("clash",new se(w.clone(),w.clone()))}function p(_){let m=Hc("ioviewer-row ioviewer-clash",String(_.name??""));m.setAttribute("title",`${_.name??""}: ${_.element1Name??""} \u2014 ${_.element2Name??""}`);let f=yv.includes(_.status),w=nt("span","ioviewer-clash-status",f?st(`clash.${_.status}`):String(_.status??""));return f&&(w.dataset.status=_.status),m.append(w,nt("span","ioviewer-clash-distance",kc(_.distance))),m.addEventListener("click",()=>u(_,m)),m}function g(_){let m=nt("div","ioviewer-clash-test"),f=nt("button","ioviewer-row ioviewer-clash-header");f.type="button",f.setAttribute("aria-expanded","true");let w=`${_.name??""} (${_.clashes.length})`;f.setAttribute("title",w),f.insertAdjacentHTML("afterbegin",Zt.chevron),f.append(nt("span","ioviewer-row-name",w));let R=nt("div","ioviewer-row-list");return R.append(..._.clashes.map(p)),f.addEventListener("click",()=>{R.hidden=!R.hidden,f.setAttribute("aria-expanded",String(!R.hidden))}),m.append(f,R),m}return i.registerPanel("clashes",{icon:Zt.clashes,title:st("panel.clashes"),visible:t.length>0,render:_=>_.append(...t.map(g)),onClose:()=>o.visible&&d()}),{group:o}}var wv=["construct","demolish","temporary"],Ev=Date.parse("0002-01-01T00:00:00Z");function _f(i){let t=typeof i=="string"?Date.parse(i):NaN;return t>=Ev?t:NaN}function xf(i,t){let e=new Map(t.flatMap((o,a)=>o.mesh?[]:[[o.id,a]])),n=[];for(let o of Array.isArray(i?.tasks)?i.tasks:[]){let a=_f(o?.start),l=_f(o?.end);if(!wv.includes(o?.type)||!(a<=l))continue;let c=Array.isArray(o.attachedElements)?o.attachedElements:[];n.push({name:o.name,type:o.type,start:a,end:l,elements:c.filter(h=>e.has(h)).map(h=>e.get(h))})}let s=n.reduce((o,a)=>Math.min(o,a.start),1/0),r=n.reduce((o,a)=>Math.max(o,a.end),-1/0);return{start:s,end:r,tasks:n}}function vf(i,t){let e=new Set,n=new Map;for(let s of i){let r=ts.end,a=s.type==="construct"?r:s.type==="demolish"?o:r||o;for(let l of s.elements)a?e.add(l):!r&&!o&&n.set(l,s.type)}for(let s of e)n.delete(s);return{hidden:e,active:n}}var Tv=864e5,Av=["1","5","15"],Rv={construct:"#22c55e",demolish:"#ef4444",temporary:"#a855f7"},Cv="156px";function yf({root:i,shell:t,timeliner:e,elements:n,scene:s}){let r=xf(e,n);if(r.tasks.length===0)return t.registerPanel("timeliner",{icon:Zt.timeliner,title:st("panel.timeliner"),visible:!1,render:()=>{}}),null;let o=new Intl.DateTimeFormat(void 0,{dateStyle:"short",timeZone:"UTC"}),a=new Intl.DateTimeFormat(void 0,{dateStyle:"medium",timeZone:"UTC"}),l=r.start,c=1,h=0,d=0,u=!1,p=new Set,g=new Map,_=nt("div","ioviewer-player ioviewer-floating");_.setAttribute("role","group"),_.setAttribute("aria-label",st("player.title")),_.hidden=!0;let m=qe("ioviewer-icon-button ioviewer-player-play",Zt.play,st("player.play"));m.addEventListener("click",()=>h?D():P());let f=nt("output","ioviewer-player-date"),w=nt("input","ioviewer-player-slider");Object.assign(w,{type:"range",min:String(r.start),max:String(r.end),step:"any"}),w.setAttribute("aria-label",st("player.date")),w.addEventListener("input",()=>y(Number(w.value)));let R=vr(st("player.speed"),Av.map(O=>[O,`${O}\xD7`]),O=>{c=Number(O),R.update(O)});R.update(String(c));let S=qe("ioviewer-panel-close",Zt.close,st("close"));S.addEventListener("click",v),_.append(m,f,w,R.element,S),i.append(_);function b(){let O=vf(r.tasks,l),I=[...p].filter(B=>!O.hidden.has(B)),k=[...O.hidden].filter(B=>!p.has(B));p=O.hidden;let X=[...g.keys()].filter(B=>O.active.get(B)!==g.get(B)),Y=new Map;for(let[B,U]of O.active)g.get(B)!==U&&(Y.has(U)||Y.set(U,[]),Y.get(U).push(B));g=O.active,I.length&&s.setLayerHidden("schedule",I,!1),k.length&&s.setLayerHidden("schedule",k,!0),X.length&&s.setTint(X,null);for(let[B,U]of Y)s.setTint(U,Rv[B])}function y(O){l=Math.min(Math.max(O,r.start),r.end),w.value=String(l),f.textContent=a.format(l),u&&b()}function T(){u||(u=!0,_.hidden=!1,i.style.setProperty("--toolbar-space",Cv),y(r.start))}function v(){u&&(D(),u=!1,s.setTint([...g.keys()],null),g=new Map,p=new Set,s.clearLayer("schedule"),_.hidden=!0,i.style.removeProperty("--toolbar-space"))}function E(O){y(l+Math.max(O-d,0)/1e3*c*Tv),d=O,l>=r.end?D():h=requestAnimationFrame(E)}function P(){T(),!h&&(l>=r.end&&y(r.start),d=performance.now(),h=requestAnimationFrame(E),z())}function D(){cancelAnimationFrame(h),h=0,z()}function z(){let O=st(h?"player.pause":"player.play");m.innerHTML=h?Zt.pause:Zt.play,m.title=O,m.setAttribute("aria-label",O)}return t.registerPanel("timeliner",{icon:Zt.timeliner,title:st("panel.timeliner"),render:O=>{let I=nt("button","ioviewer-text-button ioviewer-player-open");I.type="button",I.insertAdjacentHTML("afterbegin",Zt.play),I.append(nt("span","",st("player.play"))),I.addEventListener("click",P);let k=nt("div","ioviewer-row-list");for(let X of r.tasks){let Y=String(X.name??""),B=nt("div","ioviewer-row ioviewer-task");B.dataset.type=X.type,B.setAttribute("title",`${Y} \xB7 ${st(`task.${X.type}`)}`);let U=`${o.format(X.start)} \u2013 ${o.format(X.end)}`;B.append(nt("span","ioviewer-row-name",Y),nt("span","ioviewer-task-dates",U)),k.append(B)}O.append(I,k)}}),{open:T,close:v,play:P,pause:D,setDate:y,get date(){return l},get isOpen(){return u}}}function Mf({shell:i,files:t,elements:e,scene:n}){let s=t.map((o,a)=>({file:o,layer:`link:${a}`,members:e.flatMap((l,c)=>l.link!=null&&(l.link===o.name||l.link===o.path)?[c]:[])})),r=(o,a)=>a?n.clearLayer(o.layer):n.setLayerHidden(o.layer,o.members,!0);i.registerPanel("links",{icon:Zt.links,title:st("panel.links"),visible:s.length>0,render:o=>{let a=nt("div","ioviewer-row-list");for(let l of s){let c=String(l.file.name??""),h=nt("label","ioviewer-row ioviewer-check ioviewer-link");h.setAttribute("title",`${c} (${l.file.path??""})`);let d=nt("input");d.type="checkbox",d.checked=l.members.length===0||l.file.visible!==!1,d.disabled=l.members.length===0,d.addEventListener("change",()=>r(l,d.checked)),d.checked||r(l,!1),h.append(d,nt("span","ioviewer-row-name",c),nt("span","ioviewer-row-count",String(l.members.length))),a.append(h)}o.append(a)}})}document.documentElement.lang=mr;var pi=document.getElementById("ioviewer-canvas");function yr(i){let t=document.getElementById("ioviewer-message");t.textContent=i,t.hidden=!1}var Sf=pi.getContext("webgl2",{antialias:!0});if(!Sf)yr(st("noWebGL"));else try{Iv(ju(),Sf)}catch(i){if(!(i instanceof Li))throw i;yr(st("badData"))}function Iv(i,t){i.meta.title&&(document.title=i.meta.title);let e=new Ss({canvas:pi,context:t,antialias:!0});e.setPixelRatio(window.devicePixelRatio),e.localClippingEnabled=!0;let n=new Mi;n.background=new Dt("#1f2228");let s=new Zs("#ffffff","#8a8f99",1.6);s.position.set(0,0,1),n.add(s);let r=new Ge(45,1,.1,1e3);r.up.set(0,0,1),r.position.set(1,-1,.8);let o=new Ks("#ffffff",1.4);o.position.set(.3,.6,0),r.add(o,o.target),o.target.position.set(0,0,-1),n.add(r);let a=window.IOVIEWER_TEST??{},l=_();i.releaseBinary();let c=new Oa(l,S,Math.min(l.totalCost,2e7));n.add(l.root);let h=new Ga(l,l.visibleBox()),d=new qa(h,pi);n.add(d.group);let u=document.getElementById("ioviewer-ui"),p=new Ya(u),g=new $a(u,i.meta.grids??[]);n.add(p.group,g.group);function _(){try{return new pr(i,{...a,maxTextureSize:e.capabilities.maxTextureSize})}catch(I){if(!(I instanceof fr))throw I;yr(st("tooLarge").replace("{count}",I.count).replace("{limit}",I.limit));let k=Y=>({o:0,n:0,t:Y}),X={count:0,geometry:k("u32"),material:k("u32"),element:k("i32"),matrix:k("f32")};return new pr({...i,meta:{...i.meta,instances:X}})}}i.meta.instances.count===0&&yr(st("noGeometry"));let m=!1;pi.addEventListener("webglcontextlost",()=>{m=!0,yr(st("contextLost"))});let f,w=new Promise(I=>f=I),R=!1;function S(){R||m||(R=!0,c.requested(performance.now()),requestAnimationFrame(()=>{if(R=!1,m)return;let I=pi.getBoundingClientRect();y.camera.updateMatrixWorld(),d.update(y.camera),p.update(y.camera,I),g.update(y.camera,I),c.begin(y.camera,I.height,performance.now()),e.render(n,y.camera),c.end(performance.now()),O.update(),f()}))}l.root.addEventListener("change",S),h.addEventListener("change",S),d.addEventListener("change",S),p.addEventListener("change",S),g.addEventListener("change",S);let b=new Ba(e,l,r,{pickFloat:a.pickFloat}),y=new Pa(r,pi,{pick:(I,k)=>b.pick(I,k)?.point??null,visibleBox:()=>l.visibleBox()});y.addEventListener("change",()=>{b.camera=y.camera,S()}),l.root.addEventListener("change",I=>{I.detail.kind==="visibility"&&(y.invalidateBounds(),y.resize())});let T=new ka;T.addEventListener("change",()=>l.setHighlighted([...T.values()]));let v=ef({root:u,data:i,scene:l,controls:y,picker:b,selection:T,measure:p});uf({root:u,...v,sections:h,selection:T});let{meta:E}=i;pf({...v,controls:y,views:E.viewpoints??[]});let P=gf({...v,tests:E.clashTests??[],elements:E.elements,scene:l,controls:y,selection:T});n.add(P.group);let D=yf({root:u,...v,timeliner:E.timeliner,elements:E.elements,scene:l});Mf({...v,files:E.linkedFiles??[],elements:E.elements,scene:l});for(let I of ff({root:u,toolbar:v.toolbar,scene:l,meta:i.meta,grids:g}))v.onEscape(I.close);v.toolbar.setHandler("distance",()=>{p.setActive(!p.active),v.toolbar.setActive("distance",p.active)}),v.toolbar.setActive("distance",!1),v.onEscape(()=>p.clear());let z=()=>{y.setExtraBounds("grids",g.visible?g.box:null),y.setExtraBounds("measure",p.box)};g.addEventListener("change",z),p.addEventListener("change",z),z(),y.addEventListener("click",I=>{let{x:k,y:X,ctrl:Y,shift:B}=I.detail,U=b.pick(k,X),H=U?.element??-1;p.active?U&&p.add(U.point):Y?H>=0&&T.toggle(H):H>=0?T.set([H]):B||T.clear()}),y.addEventListener("boxselect",I=>{if(p.active)return;let{rect:k,mode:X,ctrl:Y,shift:B}=I.detail;if(k.width<4||k.height<4){!Y&&!B&&T.clear();return}let U=new se,H=Vd(k,X,Hd(l,y.camera,pi.getBoundingClientRect())),{planes:Z,intersection:rt}=h.clipping(),at=H.filter(Ft=>!Ha(l.elementBox(Ft,U),Z,rt));T.set(Y?[...T.values(),...at]:at)}),window.addEventListener("resize",()=>{e.setSize(window.innerWidth,window.innerHeight,!1),y.resize()}),e.setSize(window.innerWidth,window.innerHeight,!1),y.resize(),y.fitBox(l.visibleBox(),!1);let O=new Fa(document.getElementById("ioviewer-ui"),r,y);window.addEventListener("pointerdown",I=>{(I.target===pi||O.element.contains(I.target))&&document.activeElement?.blur()},!0),window.__ioviewer={scene:l,motionDetail:c,controls:y,picker:b,selection:T,ui:v,viewCube:O,sections:h,sectionGizmo:d,measure:p,grids:g,clashes:P,timeliner:D,ready:w,get camera(){return y.camera}}}})();
+${r.id}
+${r.sourceId??""}`.toLowerCase()));let s=[];for(let r=0;r{let s=e.category??"";t.has(s)||t.set(s,[]),t.get(s).push(n)}),[...t].map(([e,n])=>({name:e,indices:n})).sort((e,n)=>e.name.localeCompare(n.name))}function Yd(i,{elements:t,selection:e,scene:n,activate:s}){let r=Qx(t),o=new Int32Array(t.length);r.forEach((b,y)=>b.indices.forEach(T=>o[T]=y));let a=new Uint8Array(r.length),l=jx(t),c="",h=new Int32Array(0),d=-1,u=nt("input","ioviewer-tree-search");u.type="search",u.placeholder=st("searchPlaceholder"),u.setAttribute("aria-label",st("searchPlaceholder"));let p=nt("div","ioviewer-tree");p.setAttribute("role","tree"),p.setAttribute("aria-label",st("panel.model"));let g=nt("div","ioviewer-tree-spacer");p.append(g);let _=nt("div","ioviewer-tree-empty",st("noMatches"));i.append(u,p,_);function m(){if(c)h=Int32Array.from(l(c));else{let b=r.length;r.forEach((T,v)=>a[v]&&(b+=T.indices.length)),h=new Int32Array(b);let y=0;r.forEach((T,v)=>{if(h[y++]=-(v+1),a[v])for(let E of T.indices)h[y++]=E})}g.style.height=`${h.length*Ui}px`,_.hidden=h.length>0||!c,f()}function f(){let{start:b,end:y}=Kx(p.scrollTop,Ui,p.clientHeight,h.length,Jx),T=[];for(let v=b;vp.scrollTop+y&&(p.scrollTop=T+Ui-y)}function S(b){let y=o[b];!c&&!a[y]&&(a[y]=1,m());let T=h.indexOf(b);T>=0&&R(T),f()}u.addEventListener("input",()=>{c=u.value.trim(),p.scrollTop=0,m()}),p.addEventListener("scroll",f),p.addEventListener("click",b=>{let y=b.target.closest(".tree-row");if(!y)return;let T=h[Number(y.dataset.row)];if(T>=0){s(T);return}a[-T-1]^=1,m()}),new ResizeObserver(()=>{d>=0&&p.clientHeight>0&&(R(d),d=-1),f()}).observe(p),e.addEventListener("change",()=>{let b=-1;for(let y of e.values())b=y;b>=0?S(b):f()}),n.root.addEventListener("change",b=>b.detail.kind==="visibility"&&f()),m()}var $d={element:["properties","hide","isolate","showAll","-","zoomTo","sectionBox","-","copyId"],empty:["showAll","fitAll","resetSections"]},tv={hide:"H",isolate:"I",showAll:"Shift+H",zoomTo:"F"},Va=4;function Zd(i){let t=nt("div","ioviewer-context-menu");t.setAttribute("role","menu"),t.hidden=!0,i.append(t);let e=new Map(Object.values($d).flat().filter(l=>l!=="-").map(l=>[l,{enabled:!1,handler:null}]));function n(){t.hidden||(t.hidden=!0,t.replaceChildren(),window.removeEventListener("pointerdown",r,!0),window.removeEventListener("wheel",n,!0),window.removeEventListener("scroll",s,!0),window.removeEventListener("resize",n))}function s(l){i.contains(l.target)||n()}function r(l){t.contains(l.target)||(n(),Da(l))}function o(l,c,h,d){let u=$d[l];if(!u)throw new RangeError(`Unknown menu: ${l}`);n();for(let _ of u){if(_==="-"){t.append(nt("div","ioviewer-menu-separator"));continue}let m=e.get(_),f=nt("button","ioviewer-menu-item");f.type="button",f.dataset.item=_,f.setAttribute("role","menuitem"),f.disabled=!m.enabled,f.append(nt("span","",st(`menu.${_}`)),nt("kbd","",tv[_]??"")),f.addEventListener("click",()=>{n(),m.handler(d)}),t.append(f)}t.hidden=!1;let{width:p,height:g}=t.getBoundingClientRect();t.style.left=`${Math.max(Va,Math.min(c,innerWidth-p-Va))}px`,t.style.top=`${Math.max(Va,Math.min(h,innerHeight-g-Va))}px`,window.addEventListener("pointerdown",r,!0),window.addEventListener("wheel",n,!0),window.addEventListener("scroll",s,!0),window.addEventListener("resize",n)}function a(l,{enabled:c=!0,handler:h}){let d=e.get(l);if(!d)throw new RangeError(`Unknown menu item: ${l}`);h&&(d.handler=h),d.enabled=c&&!!d.handler}return{element:t,open:o,close:n,setItem:a,get isOpen(){return!t.hidden}}}var ev="input, textarea, select, [contenteditable]";function nv(i){if(i.ctrlKey||i.altKey||i.metaKey||i.repeat||i.target?.closest?.(ev))return null;switch(i.code){case"KeyH":return i.shiftKey?"showAll":"hide";case"KeyI":return i.shiftKey?null:"isolate";case"KeyF":return i.shiftKey?null:"zoomTo";case"Escape":return"escape";default:return null}}function Jd(i,t){i.addEventListener("keydown",e=>{let n=nv(e);n&&(e.preventDefault(),t[n]())})}var iv=1600;function Kd(i,t,e){let n=()=>i.textContent=`${st("selected")}: ${t.size} \xB7 ${st("elements")}: ${e}`;t.addEventListener("change",n),n()}function jd(i,t){if(!t)return;let e=nt("div","ioviewer-banner ioviewer-floating");e.setAttribute("role","status");let n=st("truncated").replace("{meshes}",t.meshes).replace("{total}",t.totalMeshes),s=qe("ioviewer-panel-close",Zt.close,st("close"));s.addEventListener("click",()=>e.remove()),e.append(nt("span","",n),s),i.append(e)}function Ts(i,t){let e=nt("div","ioviewer-toast",t);e.setAttribute("role","status"),i.append(e),setTimeout(()=>e.remove(),iv)}function Qd(i,t){let e=nt("table");for(let[s,r]of t)e.insertRow().append(nt("th","",s),nt("td","",String(r??"")));let n=nt("section");return n.append(nt("h3","",i),e),n}function tf(i,t,e){let n=nt("h2","ioviewer-properties-title"),s=nt("button","ioviewer-properties-close","\xD7");s.type="button",s.title=st("close"),s.setAttribute("aria-label",st("close")),s.addEventListener("click",()=>t.clear());let r=nt("header");r.append(n,s);let o=nt("div","ioviewer-properties-body");i.replaceChildren(r,o),i.hidden=!0,t.addEventListener("change",()=>{if(i.hidden=t.size===0,o.replaceChildren(),t.size!==1){n.textContent=`${st("selected")}: ${t.size}`;return}let[a]=t.values(),l=e.meta.elements[a];n.textContent=l.name||`#${l.id}`;let c=[[st("id"),l.id],[st("category"),l.category],[st("type"),l.type],[st("level"),l.level]];l.sourceId&&c.push([st("sourceId"),l.sourceId]),l.link&&c.push([st("link"),l.link]),o.append(Qd(st("elementGroup"),c));for(let[h,d]of Object.entries(e.props(l.id)??{}))o.append(Qd(h,Object.entries(d)))})}async function sv(i){if(await navigator.clipboard?.writeText(i).then(()=>!0,()=>!1))return!0;let t=document.createElement("textarea");t.value=i,t.setAttribute("readonly",""),t.className="ioviewer-offscreen",document.body.append(t),t.select();try{return document.execCommand("copy")}finally{t.remove()}}function ef({root:i,data:t,scene:e,controls:n,picker:s,selection:r,measure:o}){let{meta:a}=t,l=()=>n.fitBox(e.visibleBox()),c={hide:()=>r.size&&e.setVisible([...r.values()],!1),isolate:()=>r.size&&e.isolate([...r.values()]),showAll:()=>e.showAll(),zoomTo:()=>{if(!r.size)return l();let[m,...f]=r.values(),w=e.elementBox(m);for(let R of f)w.union(e.elementBox(R));n.zoomToBox(w)},fitAll:l},h=Wd(i);h.registerPanel("model",{icon:Zt.model,title:st("panel.model"),render:m=>Yd(m,{elements:a.elements,selection:r,scene:e,activate:f=>{r.set([f]),n.zoomToBox(e.elementBox(f))}})});let d=document.createElement("aside");d.id="ioviewer-properties",d.className="ioviewer-floating",i.append(d),tf(d,r,t);let u=qd(i,Xd),p=m=>{n.setLeftButtonMode(m),u.setActive("orbit",m==="orbit"),u.setActive("pan",m==="pan")};u.setHandler("orbit",()=>p("orbit")),u.setHandler("pan",()=>p("pan")),p(n.leftButtonMode),u.setHandler("fit",l),u.setHandler("projection",()=>{let m=!n.camera.isOrthographicCamera;n.setProjection(m?"orthographic":"perspective"),u.setActive("projection",m)}),u.setActive("projection",!1),document.fullscreenEnabled&&(u.setHandler("fullscreen",()=>{(document.fullscreenElement?document.exitFullscreen():document.documentElement.requestFullscreen()).catch(()=>{u.setActive("fullscreen",!!document.fullscreenElement),Ts(i,st("fullscreenUnavailable"))})}),document.addEventListener("fullscreenchange",()=>u.setActive("fullscreen",!!document.fullscreenElement)));let g=Zd(i);g.setItem("properties",{handler:m=>r.set([m])});for(let m of["hide","isolate","showAll","zoomTo","fitAll"])g.setItem(m,{handler:c[m]});g.setItem("copyId",{handler:m=>sv(String(a.elements[m].id)).then(f=>Ts(i,st(f?"idCopied":"copyFailed")),()=>Ts(i,st("copyFailed")))}),n.addEventListener("contextmenu",m=>{let{x:f,y:w}=m.detail;if(o.active){let[S]=r.values();return S===void 0?g.open("empty",f,w,null):g.open("element",f,w,S)}let R=s.pick(f,w);if(!R||R.element<0)return g.open("empty",f,w,null);r.has(R.element)||r.set([R.element]),g.open("element",f,w,R.element)});let _=[];return Jd(window,{...c,escape:()=>{if(g.isOpen)return g.close();_.some(m=>m())||r.clear()}}),Kd(document.getElementById("ioviewer-status"),r,e.elementCount),jd(i,a.truncated),{shell:h,toolbar:u,contextMenu:g,onEscape:m=>_.push(m)}}var rv={x:new C(1,0,0),y:new C(0,1,0),z:new C(0,0,1)};function zc(i){let t=rv[i];if(!t)throw new RangeError(`Unknown axis: ${i}`);return t.clone()}function nf(i,t,e,n){let s=i.clone().normalize(),r=s.dot(t)+e;return n?new ge(s,-r):new ge(s.negate(),r)}function sf(i,t){if(t!=="keepInside"&&t!=="cutInside")throw new RangeError(`Unknown box mode: ${t}`);let{min:e,max:n}=i,s=[new ge(new C(1,0,0),-e.x),new ge(new C(-1,0,0),n.x),new ge(new C(0,1,0),-e.y),new ge(new C(0,-1,0),n.y),new ge(new C(0,0,1),-e.z),new ge(new C(0,0,-1),n.z)];return t==="keepInside"?{planes:s,intersection:!1}:{planes:s.map(r=>r.negate()),intersection:!0}}function rf(i){let{min:t,max:e}=i;return Array.from({length:8},(n,s)=>new C(s&1?e.x:t.x,s&2?e.y:t.y,s&4?e.z:t.z))}function Ha(i,t,e){if(t.length===0||i.isEmpty())return!1;let n=rf(i),s=r=>n.every(o=>r.distanceToPoint(o)<0);return e?t.every(s):t.some(s)}function of(i,t){let e=i.getSize(new C).multiplyScalar(.5);return Math.abs(t.x)*e.x+Math.abs(t.y)*e.y+Math.abs(t.z)*e.z}function _r(i,t,e){let n=t.clone().sub(i.origin),s=e.dot(i.direction),r=1-s*s;return r<.03?null:(s*i.direction.dot(n)-e.dot(n))/r}function af(i,t,e){let n=new C(1,0,0).applyQuaternion(t),s=new C(0,1,0).applyQuaternion(t),[r,o,a,l]=[1/0,-1/0,1/0,-1/0];for(let h of rf(i)){h.sub(e);let d=h.dot(n),u=h.dot(s);[r,o,a,l]=[Math.min(r,d),Math.max(o,d),Math.min(a,u),Math.max(l,u)]}return{center:e.clone().addScaledVector(n,(r+o)/2).addScaledVector(s,(a+l)/2),width:(o-r)*1.1,height:(l-a)*1.1}}var xr=6,ov=["off","planes","box"],av=.05,lf=new C(0,0,1),Ga=class extends EventTarget{constructor(t,e){super(),this.scene=t,this.modelBox=e.clone(),this.center=e.getCenter(new C),this.planes=[],this.active=-1,this.box=null,this.boxMode="keepInside",this.gizmoVisible=!0,this._mode="off"}get mode(){return this._mode}setMode(t){if(!ov.includes(t))throw new RangeError(`Unknown section mode: ${t}`);t==="box"&&!this.box&&this.fitBoxToShown()||(this._mode=t,this._changed(!0))}addPlane(t){let e=zc(t);if(this.planes.length>=xr||this.modelBox.isEmpty())return null;let n=new Ne().setFromUnitVectors(lf,e);return this.planes.push({axis:t,quaternion:n,offset:0,flipped:!1,enabled:!0,rotated:!1}),this.active=this.planes.length-1,this._mode="planes",this._changed(!0),this.active}removePlane(t){this._plane(t),this.planes.splice(t,1),(this.active>=this.planes.length||this.active>t)&&this.active--,this._changed(!0)}updatePlane(t,{offset:e,flipped:n,enabled:s,quaternion:r}){let o=this._plane(t);if(e!==void 0){if(!Number.isFinite(e))throw new RangeError(`Offset must be a finite number, got ${e}.`);o.offset=e}n!==void 0&&(o.flipped=!!n),s!==void 0&&(o.enabled=!!s),r&&(o.quaternion.copy(r).normalize(),o.rotated=this.normal(t).angleTo(zc(o.axis))>1e-6),this._changed(!0)}setActivePlane(t){this._plane(t),this.active=t,this._changed(!1)}normal(t){return lf.clone().applyQuaternion(this._plane(t).quaternion)}extent(t){return of(this.modelBox,this.normal(t))}origin(t){return this.center.clone().addScaledVector(this.normal(t),this._plane(t).offset)}clipPlane(t){let e=this._plane(t);return nf(this.normal(t),this.center,e.offset,e.flipped)}setBox(t){if(t.isEmpty())throw new RangeError("The section box is empty.");this.box=t.clone(),this._mode="box",this._changed(!0)}setBoxMode(t){if(t!=="keepInside"&&t!=="cutInside")throw new RangeError(`Unknown box mode: ${t}`);this.boxMode=t,this._changed(!0)}fitBoxToElements(t){let e=new se;for(let s of t)e.union(this.scene.elementBox(s));if(e.isEmpty())return!1;let n=e.getSize(new C);return this.setBox(e.expandByScalar(av*Math.max(n.x,n.y,n.z))),!0}fitBoxToShown(){let t=this.scene.visibleBox();if(t.isEmpty())return!1;let e=t.getSize(new C);return this.setBox(t.expandByScalar(.001*Math.max(e.x,e.y,e.z))),!0}setGizmoVisible(t){this.gizmoVisible=!!t,this._changed(!1)}reset(){this.planes=[],this.active=-1,this.box=null,this._mode="off",this._changed(!0)}clipping(){return this._mode==="planes"?{planes:this.planes.flatMap((e,n)=>e.enabled?[this.clipPlane(n)]:[]),intersection:!1}:this._mode==="box"&&this.box?sf(this.box,this.boxMode):{planes:[],intersection:!1}}isCut(t){let{planes:e,intersection:n}=this.clipping();return Ha(t,e,n)}_plane(t){let e=this.planes[t];if(!Number.isInteger(t)||!e)throw new RangeError(`Plane index ${t} is out of range 0..${this.planes.length-1}.`);return e}_changed(t){if(t){let{planes:e,intersection:n}=this.clipping();this.scene.setClipping(e,n)}this.dispatchEvent(new Event("change"))}};var lv=80,cv=8,fi={x:"#ef4444",y:"#22c55e",z:"#3b82f6",centre:"#e2e8f0",hover:"#facc15",frame:"#93c5fd",fill:"#60a5fa"},Wa=["x","y","z"],hv=Math.cos(Oe.degToRad(12)),cf=new C(0,0,1),uv=i=>new cn({color:i,depthTest:!1,depthWrite:!1,transparent:!0,opacity:.9}),dv=new cn({visible:!1});function Xa(i,t,e,n){let s=new be,r=uv(t);for(let a of e)s.add(new _e(a,r));let o=new _e(n,dv);return o.userData.handle=s,s.add(o),s.userData={kind:i,color:t,material:r,proxy:o},s.traverse(a=>a.renderOrder=1e3),s}var qa=class extends EventTarget{constructor(t,e){super(),this.sections=t,this.dom=e,this.camera=null,this.group=new be,this.group.name="sections",this._raycaster=new Ai,this._drag=null,this._hovered=null,this._buildPlanes(),this._buildPlaneGizmo(),this._buildBox(),t.addEventListener("change",()=>this._sync()),(e.parentElement??e).addEventListener("pointerdown",n=>this._down(n),!0),e.addEventListener("pointermove",n=>this._move(n)),e.addEventListener("pointerup",n=>this._up(n)),e.addEventListener("pointercancel",()=>this._end()),e.addEventListener("lostpointercapture",()=>this._end()),this._sync()}get dragging(){return this._drag!==null}update(t){this.camera=t;let e=this.planeGizmo;e.visible&&(e.scale.setScalar(this._worldPerPixel(e.position)*lv),this.arrow.visible=this._across(cf.clone().applyQuaternion(e.quaternion),e.position));for(let n of this.boxHandles){let{shown:s,axis:r}=n.userData;n.visible=s&&(!r||this._across(new C().setComponent(Wa.indexOf(r),1),n.position)),n.visible&&n.scale.setScalar(this._worldPerPixel(n.position)*cv)}}_across(t,e){let n=this.camera,s=n.isOrthographicCamera?n.getWorldDirection(new C):e.clone().sub(n.position).normalize();return Math.abs(t.dot(s))new C(r/2,o/2,0))),n=new cn({color:fi.fill,transparent:!0,opacity:.12,side:Be,depthWrite:!1}),s=new sn({color:fi.frame});this.planeVisuals=Array.from({length:xr},()=>{let r=new be;return r.add(new _e(t,n),new Hs(e,s)),this.group.add(r),r})}_buildPlaneGizmo(){let t=(s,r)=>s.rotateX(Math.PI/2).translate(0,0,r),e=Xa("move",fi.z,[t(new Ei(.025,.025,1),.5),t(new qs(.08,.25),1.125)],t(new Ei(.12,.12,1.25),.625));e.name="arrow",this.arrow=e;let n=(s,r,o)=>{let a=Xa("rotate",fi[r],[o(new us(.8,.018,8,64))],o(new us(.8,.09,8,48)));return a.name=s,a.userData.axis=r,a};this.planeGizmo=new be,this.planeGizmo.add(e,n("ringX","x",s=>s.rotateY(Math.PI/2)),n("ringY","y",s=>s.rotateX(Math.PI/2))),this.group.add(this.planeGizmo)}_buildBox(){this.boxWire=new gn(new Ti(new hn(1,1,1)),new sn({color:fi.frame})),this.group.add(this.boxWire);let t=new hs(1,16,12),e=new hs(1.6,8,6);this.boxHandles=[];for(let s of Wa)for(let r of[-1,1]){let o=Xa("face",fi[s],[t],e);o.name=`face${r>0?"+":"-"}${s}`,Object.assign(o.userData,{axis:s,sign:r}),this.boxHandles.push(o)}let n=Xa("centre",fi.centre,[new hn(1.4,1.4,1.4)],e);n.name="centre",this.boxHandles.push(n),this.group.add(...this.boxHandles)}_sync(){let t=this.sections,e=t.mode==="planes";this.planeVisuals.forEach((r,o)=>{let a=t.planes[o];if(r.visible=e&&!!a?.enabled,!r.visible)return;let l=af(t.modelBox,a.quaternion,t.origin(o));r.position.copy(l.center),r.quaternion.copy(a.quaternion),r.scale.set(l.width,l.height,1)});let n=t.planes[t.active];this.planeGizmo.visible=e&&t.gizmoVisible&&!!n?.enabled,this.planeGizmo.visible&&(this.planeGizmo.position.copy(t.origin(t.active)),this.planeGizmo.quaternion.copy(n.quaternion));let s=t.mode==="box"?t.box:null;this.boxWire.visible=!!s;for(let r of this.boxHandles)r.visible=r.userData.shown=!!s&&t.gizmoVisible;if(s){let r=s.getCenter(new C),o=s.getSize(new C);this.boxWire.position.copy(r),this.boxWire.scale.copy(o).max(new C(1e-6,1e-6,1e-6));for(let a of this.boxHandles){a.position.copy(r);let{axis:l,sign:c}=a.userData;l&&(a.position[l]=c>0?s.max[l]:s.min[l])}}}_worldPerPixel(t){let e=this.camera,n=Math.max(this.dom.clientHeight,1);if(e.isOrthographicCamera)return(e.top-e.bottom)/e.zoom/n;let s=t.clone().sub(e.position).dot(e.getWorldDirection(new C));return 2*Math.max(s,e.near)*Math.tan(Oe.degToRad(e.fov/2))/n}_ray(t){let e=this.dom.getBoundingClientRect(),n=new zt((t.clientX-e.left)/e.width*2-1,1-(t.clientY-e.top)/e.height*2);return this.camera.updateMatrixWorld(),this._raycaster.setFromCamera(n,this.camera),this._raycaster.ray.clone()}_hit(t){if(!this.camera)return null;this.update(this.camera),this.group.updateMatrixWorld(!0);let e=r=>{for(;r&&r!==this.group;r=r.parent)if(!r.visible)return!1;return!0},n=[];this.group.traverse(r=>r.userData.handle&&e(r)&&n.push(r)),this._ray(t);let s=this._raycaster.intersectObjects(n,!1)[0];return s?s.object.userData.handle:null}_down(t){if(t.target!==this.dom||t.button!==0)return;let e=this._hit(t),n=e&&this._start(e,this._ray(t));n&&(t.stopPropagation(),t.preventDefault(),this.dom.setPointerCapture(t.pointerId),this._drag={id:t.pointerId,handle:e,...n},this._highlight(e))}_start(t,e){let n=this.sections,{kind:s}=t.userData;if(s==="move"||s==="rotate"){let c=n.active,h=n.origin(c),d=n.planes[c].quaternion.clone();if(s==="move"){let _=n.normal(c),m=_r(e,h,_);return m===null?null:{index:c,origin:h,normal:_,offset:n.planes[c].offset,s0:m}}let u=new C().setComponent(Wa.indexOf(t.userData.axis),1).applyQuaternion(d),p=new ge().setFromNormalAndCoplanarPoint(u,h),g=e.intersectPlane(p,new C)?.sub(h);return g?{index:c,origin:h,quaternion:d,axis:u,plane:p,from:g}:null}let r=n.box.clone();if(s==="face"){let{axis:c,sign:h}=t.userData,d=new C().setComponent(Wa.indexOf(c),h),u=t.position.clone(),p=_r(e,u,d);return p===null?null:{box:r,normal:d,at:u,s0:p}}let o=this.camera.getWorldDirection(new C),a=new ge().setFromNormalAndCoplanarPoint(o,r.getCenter(new C)),l=e.intersectPlane(a,new C);return l?{box:r,plane:a,from:l}:null}_move(t){let e=this._drag;if(!e)return this._hover(t);if(t.pointerId!==e.id)return;if(t.buttons===0)return this._end();let n=this._ray(t),s=this.sections,{kind:r}=e.handle.userData;if(r==="move"){let o=_r(n,e.origin,e.normal);o!==null&&s.updatePlane(e.index,{offset:e.offset+o-e.s0})}else if(r==="rotate"){let o=n.intersectPlane(e.plane,new C)?.sub(e.origin);if(!o)return;let a=Math.atan2(e.axis.dot(new C().crossVectors(e.from,o)),e.from.dot(o)),l=new Ne().setFromAxisAngle(e.axis,a).multiply(e.quaternion),c=cf.clone().applyQuaternion(l);s.updatePlane(e.index,{quaternion:l,offset:c.dot(e.origin.clone().sub(s.center))})}else if(r==="face"){let o=_r(n,e.at,e.normal);if(o===null)return;let{axis:a,sign:l}=e.handle.userData,c=e.box.clone(),h=.001*Math.max(...s.modelBox.getSize(new C).toArray(),.001),d=(l>0?e.box.max[a]:e.box.min[a])+l*(o-e.s0);l>0?c.max[a]=Math.max(d,c.min[a]+h):c.min[a]=Math.min(d,c.max[a]-h),s.setBox(c)}else{let o=n.intersectPlane(e.plane,new C);o&&s.setBox(e.box.clone().translate(o.sub(e.from)))}}_up(t){this._drag&&t.pointerId===this._drag.id&&this._end()}_end(){this._drag&&(this._drag=null,this._highlight(null))}_hover(t){t.buttons===0&&this._highlight(this._hit(t))}_highlight(t){if(this._hovered!==t){for(let e of[this._hovered,t])e&&e.userData.material.color.set(e===t?fi.hover:e.userData.color);this._hovered=t,this.dom.style.cursor=t?"grab":"",this.dispatchEvent(new Event("change"))}}};function vr(i,t,e){let n=nt("div","ioviewer-segmented");n.setAttribute("role","group"),n.setAttribute("aria-label",i);let s=t.map(([o,a])=>{let l=nt("button","",a);return l.type="button",l.dataset.value=o,l.addEventListener("click",()=>e(o)),n.append(l),l});return{element:n,update:o=>s.forEach(a=>a.setAttribute("aria-pressed",String(a.dataset.value===o)))}}function hf(i,t){let e=nt("label","ioviewer-check"),n=nt("input");return n.type="checkbox",n.addEventListener("change",()=>t(n.checked)),e.append(n,nt("span","",i)),{element:e,input:n}}function fv(i,t){let e=nt("li","ioviewer-section-plane");e.addEventListener("pointerdown",()=>i.active!==t&&i.setActivePlane(t));let n=nt("span","ioviewer-section-name"),s=qe("ioviewer-icon-button",Zt.flip,st("sections.flip"));s.addEventListener("click",()=>i.updatePlane(t,{flipped:!i.planes[t].flipped}));let r=hf(st("sections.enabled"),h=>i.updatePlane(t,{enabled:h})),o=qe("ioviewer-icon-button",Zt.remove,st("sections.delete"));o.addEventListener("click",()=>i.removePlane(t));let a=nt("input","ioviewer-section-slider");a.type="range",a.step="any",a.setAttribute("aria-label",st("sections.position")),a.addEventListener("input",()=>i.updatePlane(t,{offset:Number(a.value)}));let l=nt("div","ioviewer-section-head");return l.append(n,s,r.element,o),e.append(l,a),{element:e,update:()=>{let h=i.planes[t],d=h.rotated?` (${st("sections.rotated")})`:"";n.textContent=`${t+1}. ${h.axis.toUpperCase()}${d}`,e.classList.toggle("active",i.active===t),s.setAttribute("aria-pressed",String(h.flipped)),r.input.checked=h.enabled;let u=i.extent(t);a.min=String(-u),a.max=String(u),a.value=String(h.offset)}}}function uf({root:i,shell:t,toolbar:e,contextMenu:n,sections:s,selection:r}){let o="z",a=()=>{s.addPlane(o)===null&&(s.setMode("planes"),Ts(i,st("sections.maxPlanes")))},l=()=>[...r.values()],c=()=>s.fitBoxToElements(l()),h=vr(st("sections.mode"),[["planes",st("sections.planes")],["box",st("sections.box")],["off",st("sections.off")]],E=>s.setMode(E)),d=vr(st("sections.axis"),["x","y","z"].map(E=>[E,E.toUpperCase()]),E=>d.update(o=E));d.update(o);let u=nt("button","ioviewer-text-button",st("sections.addPlane"));u.type="button",u.addEventListener("click",a);let p=nt("ul","ioviewer-section-list"),g=nt("div","ioviewer-section-empty",st("sections.noPlanes")),_=nt("div","ioviewer-section-block"),m=nt("div","ioviewer-section-row");m.append(nt("span","",st("sections.axis")),d.element,u),_.append(m,p,g);let f=vr(st("sections.box"),[["keepInside",st("sections.keepInside")],["cutInside",st("sections.cutInside")]],E=>s.setBoxMode(E)),w=nt("button","ioviewer-text-button",st("sections.fitSelection"));w.type="button",w.addEventListener("click",c);let R=nt("div","ioviewer-section-block");R.append(f.element,w);let S=hf(st("sections.showGizmo"),E=>s.setGizmoVisible(E)),b=[],y=()=>{h.update(s.mode),_.hidden=s.mode!=="planes",R.hidden=s.mode!=="box",u.disabled=s.planes.length>=xr,b.length!==s.planes.length&&(b=s.planes.map((E,P)=>fv(s,P)),p.replaceChildren(...b.map(E=>E.element))),b.forEach(E=>E.update()),g.hidden=b.length>0,f.update(s.boxMode),S.input.checked=s.gizmoVisible,e.setActive("plane",s.mode==="planes"),e.setActive("box",s.mode==="box")},T=()=>w.disabled=r.size===0;if(t.registerPanel("sections",{icon:Zt.sections,title:st("panel.sections"),visible:!s.modelBox.isEmpty(),render:E=>E.append(h.element,_,R,S.element)}),s.addEventListener("change",y),r.addEventListener("change",T),y(),T(),e.setActive("plane",!1),e.setActive("box",!1),s.modelBox.isEmpty())return;let v=()=>t.openPanel("sections");e.setHandler("plane",()=>{a(),v()}),e.setHandler("box",()=>{!(r.size&&c())&&!s.fitBoxToShown()||v()}),e.setHandler("resetSections",()=>s.reset()),n.setItem("sectionBox",{handler:E=>{s.fitBoxToElements(r.has(E)?l():[E]),v()}}),n.setItem("resetSections",{handler:()=>s.reset()})}var pv="#facc15",mv=9;function kc(i,t=mr){return`${new Intl.NumberFormat(t,{minimumFractionDigits:2,maximumFractionDigits:2,useGrouping:!1}).format(i)} ${st("unit.m",t)}`}var Ya=class extends EventTarget{constructor(t){super(),this.active=!1,this.points=[],this.group=new be,this.group.name="measure";let e=new re;e.setAttribute("position",new we(new Float32Array(6),3));let n={color:pv,depthTest:!1,depthWrite:!1,transparent:!0};this._line=new bi(e,new sn(n)),this._markers=new wi(e,new ni({...n,size:mv,sizeAttenuation:!1}));for(let s of[this._line,this._markers])s.frustumCulled=!1,s.renderOrder=1001,this.group.add(s);this.label=nt("div","ioviewer-measure-label"),this.label.hidden=!0,t.prepend(this.label),this._sync()}get distance(){return this.points.length===2?this.points[0].distanceTo(this.points[1]):null}get box(){return new se().setFromPoints(this.points)}setActive(t){this.active=!!t,this.active||(this.points=[]),this._sync()}add(t){this.active&&(this.points=this.points.length===1?[this.points[0],t.clone()]:[t.clone()],this._sync())}clear(){return this.points.length===0?!1:(this.points=[],this._sync(),!0)}update(t,e){this.distance!==null&&Na(this.label,this.points[0].clone().lerp(this.points[1],.5),t,e)}_sync(){let t=this._line.geometry.attributes.position;this.points.forEach((e,n)=>t.setXYZ(n,e.x,e.y,e.z)),t.needsUpdate=!0,this._line.geometry.setDrawRange(0,this.points.length),this._line.visible=this.points.length===2,this._markers.visible=this.points.length>0,this.label.hidden=this.distance===null,this.distance!==null&&(this.label.textContent=kc(this.distance)),this.dispatchEvent(new Event("change"))}};var $a=class extends EventTarget{constructor(t,e){super(),this.count=e.length,this.group=new gn(new re().setAttribute("position",new ce(e.flatMap(s=>[...s.start,...s.end]),3)),new sn({color:"#93c5fd",transparent:!0,opacity:.55,depthTest:!1,depthWrite:!1})),this.group.name="grids",this.group.geometry.computeBoundingBox(),this.box=this.group.geometry.boundingBox,this.group.renderOrder=999,this._labels=e.flatMap(s=>[s.start,s.end].map(r=>({element:nt("div","ioviewer-grid-label",s.name),point:new C(...r)})));let n=nt("div","ioviewer-grid-labels");n.append(...this._labels.map(s=>s.element)),t.prepend(n),this._layer=n,this.setVisible(this.count>0)}get visible(){return this.group.visible}setVisible(t){this.group.visible=!!t,this._layer.hidden=!t,this.dispatchEvent(new Event("change"))}update(t,e){if(this.visible)for(let{element:n,point:s}of this._labels)Na(n,s,t,e)}};var gv=8,df=4;function Vc(i,t,e,n="dialog"){let s=nt("div","ioviewer-popover ioviewer-floating");s.setAttribute("role",n),s.setAttribute("aria-label",e),s.hidden=!0,t.setAttribute("aria-haspopup",n),t.setAttribute("aria-expanded","false"),i.append(s);function r(l){s.contains(l.target)||(a(),Da(l))}s.addEventListener("keydown",l=>{l.key==="Escape"&&(l.preventDefault(),l.stopPropagation(),a(),t.focus())});function o(){s.hidden=!1,t.setAttribute("aria-expanded","true");let l=t.getBoundingClientRect(),{width:c}=s.getBoundingClientRect();s.style.left=`${Math.max(df,Math.min(l.left+l.width/2-c/2,innerWidth-c-df))}px`,s.style.bottom=`${innerHeight-l.top+gv}px`,window.addEventListener("pointerdown",r,!0),window.addEventListener("resize",a)}function a(){return s.hidden?!1:(s.hidden=!0,t.setAttribute("aria-expanded","false"),window.removeEventListener("pointerdown",r,!0),window.removeEventListener("resize",a),!0)}return{element:s,close:a,toggle:()=>s.hidden?o():a(),get isOpen(){return!s.hidden}}}function _v(i){return i?.initialWireframe?"wireframe":i?.initialWhiteMode?"white":"materials"}function ff({root:i,toolbar:t,scene:e,meta:n,grids:s}){let r=_=>t.element.querySelector(`[data-tool="${_}"]`),o=Vc(i,r("displayMode"),st("tool.displayMode"),"menu");o.element.classList.add("ioviewer-display-modes");let a=(n.textures??[]).length>0,l=Nc.map(_=>{let m=nt("button","ioviewer-menu-item",st(`display.${_}`));return m.type="button",m.dataset.mode=_,m.setAttribute("role","menuitemradio"),m.disabled=_==="textures"&&!a,m.addEventListener("click",()=>{c(_),o.close()}),o.element.append(m),m}),c=_=>{e.setDisplayMode(_);for(let m of l)m.setAttribute("aria-checked",String(m.dataset.mode===_))};c(_v(n.options)),t.setHandler("displayMode",o.toggle),t.setActive("grids",s.visible),s.count>0&&t.setHandler("grids",()=>{s.setVisible(!s.visible),t.setActive("grids",s.visible)});let h=Vc(i,r("opacity"),st("tool.opacity"));h.element.classList.add("ioviewer-opacity");let d=nt("input","ioviewer-opacity-slider");Object.assign(d,{type:"range",min:"10",max:"100",step:"1",value:"100"}),d.setAttribute("aria-label",st("opacity.label"));let u=nt("output","ioviewer-opacity-value"),p=()=>u.textContent=st("opacity.value").replace("{value}",d.value);d.addEventListener("input",()=>{e.setOpacity(Number(d.value)/100),p()}),p();let g=nt("div","ioviewer-opacity-head");return g.append(nt("span","",st("opacity.label")),u),h.element.append(g,d),t.setHandler("opacity",h.toggle),[o,h]}var xv=3e3;function Hc(i,t){let e=nt("button",i);return e.type="button",e.setAttribute("title",t),e.append(nt("span","ioviewer-row-name",t)),e}function pf({shell:i,toolbar:t,controls:e,views:n}){let s=null,r=nt("button","ioviewer-text-button ioviewer-tour");r.type="button";function o(g){let _=g.camera.projection==="orthographic";e.setProjection(_?"orthographic":"perspective"),t.setActive("projection",_),e.animateTo({position:new C(...g.camera.position),target:new C(...g.camera.target)})}function a(){o(n[s.next]),s.next=(s.next+1)%n.length;let g=()=>{e.animating?s.frame=requestAnimationFrame(g):s.timer=setTimeout(a,xv)};s.frame=requestAnimationFrame(g)}let l=g=>r.contains(g.target),c=g=>!l(g)&&d(),h=g=>!(l(g)&&(g.key==="Enter"||g.key===" "))&&d();function d(){s&&(cancelAnimationFrame(s.frame),clearTimeout(s.timer),s=null,window.removeEventListener("pointerdown",c,!0),window.removeEventListener("wheel",d,!0),window.removeEventListener("keydown",h,!0),p())}function u(){s={next:0,frame:0,timer:0},window.addEventListener("pointerdown",c,!0),window.addEventListener("wheel",d,!0),window.addEventListener("keydown",h,!0),p(),a()}function p(){let g=st(s?"views.stop":"views.tour");r.replaceChildren(),r.insertAdjacentHTML("afterbegin",s?Zt.pause:Zt.play),r.append(nt("span","",g)),r.setAttribute("aria-pressed",String(!!s))}r.addEventListener("click",()=>s?d():u()),p(),i.registerPanel("views",{icon:Zt.views,title:st("panel.views"),visible:n.length>0,render:g=>{let _=nt("div","ioviewer-row-list");for(let m of n){let f=Hc("ioviewer-row ioviewer-view",String(m.name??""));f.addEventListener("click",()=>o(m)),_.append(f)}g.append(r,_)}})}function mf(i,t){let e=[];for(let[n,s]of[[i.element1Id,i.element1Name],[i.element2Id,i.element2Name]]){let r=n!=null?t.findIndex(o=>o.id===n&&!o.mesh):vv(t,s);r>=0&&!e.includes(r)&&e.push(r)}return e}function vv(i,t){if(t==null)return-1;let e=i.findIndex(n=>n.name===t);return e>=0&&i.findIndex((n,s)=>s>e&&n.name===t)<0?e:-1}var yv=["New","Active","Reviewed","Approved","Resolved"],Mv=14,Sv=2,bv=new C(1,-1,.8).normalize();function gf({shell:i,tests:t,elements:e,scene:n,controls:s,selection:r}){let o=new be;o.name="clash-marker";let a=new re;a.setAttribute("position",new we(new Float32Array(3),3));let l={color:"#ef4444",depthTest:!1,depthWrite:!1,transparent:!0},c=new wi(a,new ni({...l,size:Mv,sizeAttenuation:!1}));c.frustumCulled=!1,c.renderOrder=1002,o.add(c),o.visible=!1;let h=null;function d(){o.visible=!1,h?.removeAttribute("aria-current"),h=null,s.setExtraBounds("clash",null)}function u(_,m){let f=mf(_,e);f.length?r.set(f):r.clear();let w=new C(..._.point),R=0;for(let y of f){let T=n.elementBox(y);T.isEmpty()||(R=Math.max(R,...T.getSize(new C).toArray()))}let S=s.camera.position.clone().sub(s.target);S.lengthSq()<1e-12&&S.copy(bv);let b=Math.max(3*R,Sv);s.animateTo({position:S.normalize().multiplyScalar(b).add(w),target:w}),a.attributes.position.setXYZ(0,w.x,w.y,w.z),a.attributes.position.needsUpdate=!0,o.visible=!0,h?.removeAttribute("aria-current"),h=m,m.setAttribute("aria-current","true"),s.setExtraBounds("clash",new se(w.clone(),w.clone()))}function p(_){let m=Hc("ioviewer-row ioviewer-clash",String(_.name??""));m.setAttribute("title",`${_.name??""}: ${_.element1Name??""} \u2014 ${_.element2Name??""}`);let f=yv.includes(_.status),w=nt("span","ioviewer-clash-status",f?st(`clash.${_.status}`):String(_.status??""));return f&&(w.dataset.status=_.status),m.append(w,nt("span","ioviewer-clash-distance",kc(_.distance))),m.addEventListener("click",()=>u(_,m)),m}function g(_){let m=nt("div","ioviewer-clash-test"),f=nt("button","ioviewer-row ioviewer-clash-header");f.type="button",f.setAttribute("aria-expanded","true");let w=`${_.name??""} (${_.clashes.length})`;f.setAttribute("title",w),f.insertAdjacentHTML("afterbegin",Zt.chevron),f.append(nt("span","ioviewer-row-name",w));let R=nt("div","ioviewer-row-list");return R.append(..._.clashes.map(p)),f.addEventListener("click",()=>{R.hidden=!R.hidden,f.setAttribute("aria-expanded",String(!R.hidden))}),m.append(f,R),m}return i.registerPanel("clashes",{icon:Zt.clashes,title:st("panel.clashes"),visible:t.length>0,render:_=>_.append(...t.map(g)),onClose:()=>o.visible&&d()}),{group:o}}var wv=["construct","demolish","temporary"],Ev=Date.parse("0002-01-01T00:00:00Z");function _f(i){let t=typeof i=="string"?Date.parse(i):NaN;return t>=Ev?t:NaN}function xf(i,t){let e=new Map(t.flatMap((o,a)=>o.mesh?[]:[[o.id,a]])),n=[];for(let o of Array.isArray(i?.tasks)?i.tasks:[]){let a=_f(o?.start),l=_f(o?.end);if(!wv.includes(o?.type)||!(a<=l))continue;let c=Array.isArray(o.attachedElements)?o.attachedElements:[];n.push({name:o.name,type:o.type,start:a,end:l,elements:c.filter(h=>e.has(h)).map(h=>e.get(h))})}let s=n.reduce((o,a)=>Math.min(o,a.start),1/0),r=n.reduce((o,a)=>Math.max(o,a.end),-1/0);return{start:s,end:r,tasks:n}}function vf(i,t){let e=new Set,n=new Map;for(let s of i){let r=ts.end,a=s.type==="construct"?r:s.type==="demolish"?o:r||o;for(let l of s.elements)a?e.add(l):!r&&!o&&n.set(l,s.type)}for(let s of e)n.delete(s);return{hidden:e,active:n}}var Tv=864e5,Av=["1","5","15"],Rv={construct:"#22c55e",demolish:"#ef4444",temporary:"#a855f7"},Cv="156px";function yf({root:i,shell:t,timeliner:e,elements:n,scene:s}){let r=xf(e,n);if(r.tasks.length===0)return t.registerPanel("timeliner",{icon:Zt.timeliner,title:st("panel.timeliner"),visible:!1,render:()=>{}}),null;let o=new Intl.DateTimeFormat(void 0,{dateStyle:"short",timeZone:"UTC"}),a=new Intl.DateTimeFormat(void 0,{dateStyle:"medium",timeZone:"UTC"}),l=r.start,c=1,h=0,d=0,u=!1,p=new Set,g=new Map,_=nt("div","ioviewer-player ioviewer-floating");_.setAttribute("role","group"),_.setAttribute("aria-label",st("player.title")),_.hidden=!0;let m=qe("ioviewer-icon-button ioviewer-player-play",Zt.play,st("player.play"));m.addEventListener("click",()=>h?D():P());let f=nt("output","ioviewer-player-date"),w=nt("input","ioviewer-player-slider");Object.assign(w,{type:"range",min:String(r.start),max:String(r.end),step:"any"}),w.setAttribute("aria-label",st("player.date")),w.addEventListener("input",()=>y(Number(w.value)));let R=vr(st("player.speed"),Av.map(O=>[O,`${O}\xD7`]),O=>{c=Number(O),R.update(O)});R.update(String(c));let S=qe("ioviewer-panel-close",Zt.close,st("close"));S.addEventListener("click",v),_.append(m,f,w,R.element,S),i.append(_);function b(){let O=vf(r.tasks,l),I=[...p].filter(B=>!O.hidden.has(B)),k=[...O.hidden].filter(B=>!p.has(B));p=O.hidden;let X=[...g.keys()].filter(B=>O.active.get(B)!==g.get(B)),Y=new Map;for(let[B,U]of O.active)g.get(B)!==U&&(Y.has(U)||Y.set(U,[]),Y.get(U).push(B));g=O.active,I.length&&s.setLayerHidden("schedule",I,!1),k.length&&s.setLayerHidden("schedule",k,!0),X.length&&s.setTint(X,null);for(let[B,U]of Y)s.setTint(U,Rv[B])}function y(O){l=Math.min(Math.max(O,r.start),r.end),w.value=String(l),f.textContent=a.format(l),u&&b()}function T(){u||(u=!0,_.hidden=!1,i.style.setProperty("--toolbar-space",Cv),y(r.start))}function v(){u&&(D(),u=!1,s.setTint([...g.keys()],null),g=new Map,p=new Set,s.clearLayer("schedule"),_.hidden=!0,i.style.removeProperty("--toolbar-space"))}function E(O){y(l+Math.max(O-d,0)/1e3*c*Tv),d=O,l>=r.end?D():h=requestAnimationFrame(E)}function P(){T(),!h&&(l>=r.end&&y(r.start),d=performance.now(),h=requestAnimationFrame(E),z())}function D(){cancelAnimationFrame(h),h=0,z()}function z(){let O=st(h?"player.pause":"player.play");m.innerHTML=h?Zt.pause:Zt.play,m.title=O,m.setAttribute("aria-label",O)}return t.registerPanel("timeliner",{icon:Zt.timeliner,title:st("panel.timeliner"),render:O=>{let I=nt("button","ioviewer-text-button ioviewer-player-open");I.type="button",I.insertAdjacentHTML("afterbegin",Zt.play),I.append(nt("span","",st("player.play"))),I.addEventListener("click",P);let k=nt("div","ioviewer-row-list");for(let X of r.tasks){let Y=String(X.name??""),B=nt("div","ioviewer-row ioviewer-task");B.dataset.type=X.type,B.setAttribute("title",`${Y} \xB7 ${st(`task.${X.type}`)}`);let U=`${o.format(X.start)} \u2013 ${o.format(X.end)}`;B.append(nt("span","ioviewer-row-name",Y),nt("span","ioviewer-task-dates",U)),k.append(B)}O.append(I,k)}}),{open:T,close:v,play:P,pause:D,setDate:y,get date(){return l},get isOpen(){return u}}}function Mf({shell:i,files:t,elements:e,scene:n}){let s=t.map((o,a)=>({file:o,layer:`link:${a}`,members:e.flatMap((l,c)=>l.link!=null&&(l.link===o.name||l.link===o.path)?[c]:[])})),r=(o,a)=>a?n.clearLayer(o.layer):n.setLayerHidden(o.layer,o.members,!0);i.registerPanel("links",{icon:Zt.links,title:st("panel.links"),visible:s.length>0,render:o=>{let a=nt("div","ioviewer-row-list");for(let l of s){let c=String(l.file.name??""),h=nt("label","ioviewer-row ioviewer-check ioviewer-link");h.setAttribute("title",`${c} (${l.file.path??""})`);let d=nt("input");d.type="checkbox",d.checked=l.members.length===0||l.file.visible!==!1,d.disabled=l.members.length===0,d.addEventListener("change",()=>r(l,d.checked)),d.checked||r(l,!1),h.append(d,nt("span","ioviewer-row-name",c),nt("span","ioviewer-row-count",String(l.members.length))),a.append(h)}o.append(a)}})}document.documentElement.lang=mr;var pi=document.getElementById("ioviewer-canvas");function yr(i){let t=document.getElementById("ioviewer-message");t.textContent=i,t.hidden=!1}var Sf=pi.getContext("webgl2",{antialias:!0});if(!Sf)yr(st("noWebGL"));else try{Iv(ju(),Sf)}catch(i){if(!(i instanceof Li))throw i;yr(st("badData"))}function Iv(i,t){i.meta.title&&(document.title=i.meta.title);let e=new Ss({canvas:pi,context:t,antialias:!0});e.setPixelRatio(window.devicePixelRatio),e.localClippingEnabled=!0;let n=new Mi;n.background=new Dt("#1f2228");let s=new Zs("#ffffff","#8a8f99",1.6);s.position.set(0,0,1),n.add(s);let r=new Ge(45,1,.1,1e3);r.up.set(0,0,1),r.position.set(1,-1,.8);let o=new Ks("#ffffff",1.4);o.position.set(.3,.6,0),r.add(o,o.target),o.target.position.set(0,0,-1),n.add(r);let a=window.IOVIEWER_TEST??{},l=_();i.releaseBinary();let c=new Oa(l,S,Math.min(l.totalCost,2e7));n.add(l.root);let h=new Ga(l,l.visibleBox()),d=new qa(h,pi);n.add(d.group);let u=document.getElementById("ioviewer-ui"),p=new Ya(u),g=new $a(u,i.meta.grids??[]);n.add(p.group,g.group);function _(){try{return new pr(i,{...a,maxTextureSize:e.capabilities.maxTextureSize})}catch(I){if(!(I instanceof fr))throw I;yr(st("tooLarge").replace("{count}",I.count).replace("{limit}",I.limit));let k=Y=>({o:0,n:0,t:Y}),X={count:0,geometry:k("u32"),material:k("u32"),element:k("i32"),matrix:k("f32")};return new pr({...i,meta:{...i.meta,instances:X}})}}i.meta.instances.count===0&&yr(st("noGeometry"));let m=!1;pi.addEventListener("webglcontextlost",()=>{m=!0,yr(st("contextLost"))});let f,w=new Promise(I=>f=I),R=!1;function S(){R||m||(R=!0,c.requested(performance.now()),requestAnimationFrame(()=>{if(R=!1,m)return;let I=pi.getBoundingClientRect();y.camera.updateMatrixWorld(),d.update(y.camera),p.update(y.camera,I),g.update(y.camera,I),c.begin(y.camera,I.height,performance.now()),e.render(n,y.camera),c.end(performance.now()),O.update(),f()}))}l.root.addEventListener("change",S),h.addEventListener("change",S),d.addEventListener("change",S),p.addEventListener("change",S),g.addEventListener("change",S);let b=new Ba(e,l,r,{pickFloat:a.pickFloat}),y=new Pa(r,pi,{pick:(I,k)=>b.pick(I,k)?.point??null,visibleBox:()=>l.visibleBox()});y.addEventListener("change",()=>{b.camera=y.camera,S()}),l.root.addEventListener("change",I=>{I.detail.kind==="visibility"&&(y.invalidateBounds(),y.resize())});let T=new ka;T.addEventListener("change",()=>l.setHighlighted([...T.values()]));let v=ef({root:u,data:i,scene:l,controls:y,picker:b,selection:T,measure:p});uf({root:u,...v,sections:h,selection:T});let{meta:E}=i;pf({...v,controls:y,views:E.viewpoints??[]});let P=gf({...v,tests:E.clashTests??[],elements:E.elements,scene:l,controls:y,selection:T});n.add(P.group);let D=yf({root:u,...v,timeliner:E.timeliner,elements:E.elements,scene:l});Mf({...v,files:E.linkedFiles??[],elements:E.elements,scene:l});for(let I of ff({root:u,toolbar:v.toolbar,scene:l,meta:i.meta,grids:g}))v.onEscape(I.close);v.toolbar.setHandler("distance",()=>{p.setActive(!p.active),v.toolbar.setActive("distance",p.active)}),v.toolbar.setActive("distance",!1),v.onEscape(()=>p.clear());let z=()=>{y.setExtraBounds("grids",g.visible?g.box:null),y.setExtraBounds("measure",p.box)};g.addEventListener("change",z),p.addEventListener("change",z),z(),y.addEventListener("click",I=>{let{x:k,y:X,ctrl:Y,shift:B}=I.detail,U=b.pick(k,X),H=U?.element??-1;p.active?U&&p.add(U.point):Y?H>=0&&T.toggle(H):H>=0?T.set([H]):B||T.clear()}),y.addEventListener("boxselect",I=>{if(p.active)return;let{rect:k,mode:X,ctrl:Y,shift:B}=I.detail;if(k.width<4||k.height<4){!Y&&!B&&T.clear();return}let U=new se,H=Vd(k,X,Hd(l,y.camera,pi.getBoundingClientRect())),{planes:Z,intersection:rt}=h.clipping(),at=H.filter(Ft=>!Ha(l.elementBox(Ft,U),Z,rt));T.set(Y?[...T.values(),...at]:at)}),window.addEventListener("resize",()=>{e.setSize(window.innerWidth,window.innerHeight,!1),y.resize()}),e.setSize(window.innerWidth,window.innerHeight,!1),y.resize(),y.fitBox(l.visibleBox(),!1);let O=new Fa(document.getElementById("ioviewer-ui"),r,y);window.addEventListener("pointerdown",I=>{(I.target===pi||O.element.contains(I.target))&&document.activeElement?.blur()},!0),window.__ioviewer={scene:l,motionDetail:c,controls:y,picker:b,selection:T,ui:v,viewCube:O,sections:h,sectionGizmo:d,measure:p,grids:g,clashes:P,timeliner:D,ready:w,get camera(){return y.camera}}}})();
/*! Bundled license information:
three/build/three.core.js:
diff --git a/src/IOViewer/Viewer/src/i18n.js b/src/IOViewer/Viewer/src/i18n.js
index 53ede53..7d437f0 100644
--- a/src/IOViewer/Viewer/src/i18n.js
+++ b/src/IOViewer/Viewer/src/i18n.js
@@ -13,6 +13,7 @@ const dictionaries = {
category: 'Категория',
type: 'Тип',
level: 'Уровень',
+ sourceId: 'ID источника',
link: 'Связанный файл',
panels: 'Панели',
'panel.model': 'Модель',
@@ -120,6 +121,7 @@ const dictionaries = {
category: 'Category',
type: 'Type',
level: 'Level',
+ sourceId: 'Source ID',
link: 'Link',
panels: 'Panels',
'panel.model': 'Model',
diff --git a/src/IOViewer/Viewer/src/ui/properties.js b/src/IOViewer/Viewer/src/ui/properties.js
index 1ad2465..d655b41 100644
--- a/src/IOViewer/Viewer/src/ui/properties.js
+++ b/src/IOViewer/Viewer/src/ui/properties.js
@@ -41,6 +41,7 @@ export function mountProperties(container, selection, data) {
const element = data.meta.elements[index];
title.textContent = element.name || `#${element.id}`;
const fields = [[t('id'), element.id], [t('category'), element.category], [t('type'), element.type], [t('level'), element.level]];
+ if (element.sourceId) fields.push([t('sourceId'), element.sourceId]);
if (element.link) fields.push([t('link'), element.link]);
body.append(group(t('elementGroup'), fields));
for (const [name, values] of Object.entries(data.props(element.id) ?? {})) body.append(group(name, Object.entries(values)));
diff --git a/src/IOViewer/Viewer/src/ui/tree.js b/src/IOViewer/Viewer/src/ui/tree.js
index c5f98a9..e898c65 100644
--- a/src/IOViewer/Viewer/src/ui/tree.js
+++ b/src/IOViewer/Viewer/src/ui/tree.js
@@ -12,12 +12,12 @@ export function visibleRange(scrollTop, rowHeight, viewportHeight, total, oversc
return { start, end: Math.max(start, end) };
}
-// search(query) -> indices of elements whose name, type or Id contains the query, case-insensitively.
+// search(query) -> indices of elements whose name, type, Id or source id contains the query, case-insensitively.
export function createSearch(elements) {
let texts = null; // lower-cased once, on the first search
return (query) => {
const q = query.trim().toLowerCase();
- texts ??= elements.map((e) => `${e.name ?? ''}\n${e.type ?? ''}\n${e.id}`.toLowerCase());
+ texts ??= elements.map((e) => `${e.name ?? ''}\n${e.type ?? ''}\n${e.id}\n${e.sourceId ?? ''}`.toLowerCase());
const found = [];
for (let i = 0; i < texts.length; i++) if (texts[i].includes(q)) found.push(i);
return found;
diff --git a/src/IOViewer/Viewer/test/e2e/ui.spec.js b/src/IOViewer/Viewer/test/e2e/ui.spec.js
index b53f340..294d68e 100644
--- a/src/IOViewer/Viewer/test/e2e/ui.spec.js
+++ b/src/IOViewer/Viewer/test/e2e/ui.spec.js
@@ -269,6 +269,8 @@ test('tree: search by Id, type and name flattens the matches', async ({ page })
await expect(search).toHaveAttribute('placeholder', 'Поиск по имени, типу, Id…');
await search.fill('300063');
await expect(rows(page)).toHaveText(['Supply Duct SA-1Rectangular 600x400']);
+ await search.fill('2XQ$N5SLP');
+ await expect(rows(page)).toHaveText(['Supply Duct SA-1Rectangular 600x400']);
await search.fill('steel i');
await expect(rows(page)).toHaveCount(34);
await search.fill('column d2');
@@ -402,6 +404,7 @@ test('hostile names and properties are shown as text and never run (Review Focus
const errors = await open(page, 'escaping');
const name = '
';
const script = '';
+ const sourceId = '">