@giro3d/piero 1.0.0-beta.0 → 1.0.0-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,2 +1,3 @@
1
- "use strict";var O=Object.defineProperty;var D=(l,a,t)=>a in l?O(l,a,{enumerable:!0,configurable:!0,writable:!0,value:t}):l[a]=t;var h=(l,a,t)=>D(l,typeof a!="symbol"?a+"":a,t);Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const A=require("/builds/giro3d/piero/node_modules/@giro3d/giro3d/gui/EntityPanel.js"),g=require("/builds/giro3d/piero/node_modules/openbim-components/index.js"),f=require("./Components.cjs.js"),B=require("/builds/giro3d/piero/node_modules/@giro3d/giro3d/entities/Entity3D.js"),_=require("/builds/giro3d/piero/node_modules/three"),z=require("/builds/giro3d/piero/node_modules/@giro3d/giro3d/gui/EntityInspector.js"),c=require("/builds/giro3d/piero/node_modules/vue/dist/vue.runtime.esm-bundler.js"),j=require("/builds/giro3d/piero/node_modules/three/examples/jsm/loaders/PLYLoader.js"),V=require("/builds/giro3d/piero/node_modules/@giro3d/giro3d/entities/PointCloud.js"),R=require("/builds/giro3d/piero/node_modules/@giro3d/giro3d/sources/PotreeSource.js"),w=require("/builds/giro3d/piero/node_modules/shepherd.js/dist/js/shepherd.esm.js"),x=new _.Matrix4,U={bbox:new _.MeshBasicMaterial({color:"#FFFF00",depthTest:!0,opacity:.2,transparent:!0}),selection:new _.MeshBasicMaterial({color:"#FF0000",depthTest:!1,opacity:.6,transparent:!0})},Y=4186316022,q=781010003,G=2655215786,W=3242617779,H=919958153,$=1307041759,F=1451395588,L=1883228015,Q=[F,L],J=[Y,q,G,W,H,$],M=l=>f.isObject(l)&&l.isIFCPickResult,P=class P extends B{constructor(t){super(new _.Group);h(this,"isIfcEntity",!0);h(this,"isPickableFeatures",!0);h(this,"type","IfcEntity");h(this,"_classificationCache");h(this,"_components");h(this,"_fragmentBoundingBox");h(this,"_fragmentClassifier");h(this,"_fragmentManager");h(this,"_ifcSelection");h(this,"_indexMap");h(this,"_model");h(this,"_source");this._source=t,this._components=new g.Components,this._components.ui.enabled=!1,this._components.scene=new g.SimpleScene(this._components),this._components.renderer=new g.SimpleRenderer(this._components,document.createElement("div")),this._components.camera=new g.SimpleCamera(this._components),this._components.raycaster=new g.SimpleRaycaster(this._components),this._components.init(),this._ifcSelection={bbox:{},selection:{}},this._indexMap={},this._classificationCache=null,this._fragmentBoundingBox=null}clearHighlight(t="selection"){for(const e of Object.keys(this._ifcSelection[t])){const o=this._fragmentManager.list[e],n=o==null?void 0:o.fragments[t];n!=null&&n.mesh.removeFromParent()}this.notifyChange(this),this._ifcSelection[t]={}}getBoundingBoxById(t){this.clearHighlight("bbox"),this.highlightById(t,"bbox");const e=this._fragmentBoundingBox;if(e===null)throw new Error("Must call initClassification before getBoundingBoxById");const o=this._fragmentManager;e.reset();const n=this._ifcSelection.bbox;if(!Object.keys(n).length)return;for(const d of Object.keys(n)){const y=o.list[d].fragments.bbox;e.addMesh(y.mesh)}const s=e.get(),{y:r,z:u}=s.min,{y:m,z:i}=s.max;return s.min.y=-i,s.max.y=-u,s.min.z=r,s.max.z=m,s.translate(this._model.position),this.clearHighlight("bbox"),s}getClassification(){if(this._classificationCache===null)throw new Error("Must call initClassification before getClassification");return this._classificationCache}getProperties(t){const e=[],o=this._model.properties;if(!o)return[];for(const n of this._indexMap[t]){const s=o[n];if(s==null)continue;const{name:r}=g.IfcPropertiesUtils.getEntityName(o,n);if(r!==null){if(s.type===F){const u=g.IfcPropertiesUtils.getPsetProps(o,n);if(u!==null)for(const m of u){if(o[m]==null)continue;const d=this.getProperty(m);d!==null&&e.push({parentName:r,...d})}}else if(s.type===L){const u=g.IfcPropertiesUtils.getQsetQuantities(o,n);if(u!==null)for(const m of u){const{key:i}=g.IfcPropertiesUtils.getQuantityValue(o,m);if(i===null)continue;const d=this.getProperty(m);d!==null&&e.push({parentName:r,...d})}}}}return e}getProperty(t){const e=this._model.properties;if(e===void 0)return null;const{name:o}=g.IfcPropertiesUtils.getEntityName(e,t);if(o===null)return null;const{value:n}=g.IfcPropertiesUtils.getQuantityValue(e,t);return{name:o,value:n}}highlight(t,e,o){this._ifcSelection[t][e.uuid]=new Set;const n=parseInt(o,10);this._ifcSelection[t][e.uuid].add(o),this.addComposites(t,e,n),this.regenerate(t,e.uuid);const s=e.fragment.group;if(s){const r=s.data[n][0];for(let u=0;u<r.length;u++){const m=r[u],i=s.keyFragments[m],d=this._fragmentManager.list[i];i in this._ifcSelection[t]||(this._ifcSelection[t][i]=new Set),this._ifcSelection[t][i].add(o),this.addComposites(t,d.mesh,n),this.regenerate(t,i)}}this.notifyChange(this)}highlightById(t,e="selection"){for(const o of Object.keys(t)){o in this._ifcSelection[e]||(this._ifcSelection[e][o]=new Set);const n=this._fragmentManager.list[o],s=new Set;for(const r of t[o])this._ifcSelection[e][o].add(r),s.add(parseInt(r,10));for(const r of s)this.addComposites(e,n.mesh,r);this.regenerate(e,o)}this.notifyChange(this)}pick(t,e){return super.pick(t,e).map(o=>({...o,entity:this,features:o.features,isIFCPickResult:!0,object:o.object}))}pickFeaturesFrom(t){var o,n,s;const e=t.object;if(e.fragment!=null&&t.instanceId!=null&&t.face){const r=e.fragment.getVertexBlockID(e.geometry,t.face.a),u=(o=e.fragment.getItemID(t.instanceId,r))==null?void 0:o.replace(/\..*/,"");if(u&&((s=(n=e.fragment.group)==null?void 0:n.properties)==null?void 0:s[u])!=null){const i=e.fragment.group.properties[u],p=[{ifcProperties:this.getProperties(u),itemProperties:i}];return t.features=p,p}}return[]}async initClassification(){this._classificationCache=await this.regenerateClassification(["storeys","entities"]),this._classificationCache.length===0&&(this._classificationCache=await this.regenerateClassification(["entities"])),this._fragmentBoundingBox=await this._components.tools.get(g.FragmentBoundingBox)}async preprocess(){const t=await f.Fetcher.fetchArrayBuffer(this._source.url);this._fragmentManager=await this._components.tools.get(g.FragmentManager),this._fragmentClassifier=await this._components.tools.get(g.FragmentClassifier);const e=new g.FragmentIfcLoader(this._components);e.settings.webIfc.COORDINATE_TO_ORIGIN=!0,e.settings.webIfc.OPTIMIZE_PROFILES=!0;const o=new Uint8Array(t);this._model=await e.load(o,this._source.name),this._model.rotateX(Math.PI/2);const n=new _.Vector3;if(this._source.at)this._source.at.toVector3(n),this._model.position.copy(n);else{const r=this._model.coordinationMatrix.clone().invert();n.applyMatrix4(r),this._model.position.set(n.x,-n.z,n.y)}this._model.updateWorldMatrix(!0,!0),this._model.updateMatrix(),this._model.updateMatrixWorld(!0),this.initializeEntityIndexes(),this._fragmentClassifier.byStorey(this._model),this._fragmentClassifier.byEntity(this._model),await this.initClassification(),this.object3d.add(this._model),this.onObjectCreated(this._model);const s=f.Fetcher.getContext(this._source.url);f.fillObject3DUserData(this,{filename:s.filename}),this.notifyChange(this.object3d)}addComposites(t,e,o){this.addHighlightToFragment(t,e.fragment);const n=e.fragment.composites[o];if(n)for(let s=1;s<n;s++){const r=g.toCompositeID(o,s);this._ifcSelection[t][e.uuid].add(r)}}addHighlightToFragment(t,e){if(!(t in e.fragments)){const o=e.addFragment(t,[U[t]]);e.blocks.count>1&&(o.setInstance(0,{ids:Array.from(e.ids),transform:x}),o.blocks.setVisibility(!1)),this._model.add(o.mesh),o.mesh.renderOrder=30,o.mesh.frustumCulled=!1,o.mesh.name=t,o.mesh.updateMatrixWorld(!0)}}initializeEntityIndexes(){this._indexMap={};const t=this._model.properties;if(t!==void 0)for(const e of J)g.IfcPropertiesUtils.getRelationMap(t,e,(o,n)=>{const s=t[o];Q.includes(s.type)||this.setEntityIndex(o);for(const r of n)this.setEntityIndex(r).add(o)})}regenerate(t,e){this.updateFragmentFill(t,e)}async regenerateClassification(t,e={}){const o=this._fragmentClassifier.get(),n=[],s=t[0],r=o[s];if(s==null||r==null)return n;for(const u of Object.keys(r)){const m={...e,[s]:[u]},i=await this._fragmentClassifier.find(m);if(Object.keys(i).length>0){const y=s[0].toUpperCase()+s.slice(1),b=await this.regenerateClassification(t.slice(1),m);n.push({children:b,fragments:i,name:u,treeItemName:y})}}return n}setEntityIndex(t){return t in this._indexMap||(this._indexMap[t]=new Set),this._indexMap[t]}updateFragmentFill(t,e){const o=this._ifcSelection[t][e],n=this._fragmentManager.list[e];if(n==null)return;const s=n.fragments[t];if(s==null)return;const r=n.mesh.parent;if(r==null)return;if(r.add(s.mesh),s.blocks.count>1)n.getInstance(0,x),s.setInstance(0,{ids:Array.from(n.ids),transform:x}),s.blocks.setVisibility(!0,o,!0);else{let m=0;for(const i of o){s.mesh.count=m+1;const{instanceID:d}=n.getInstanceAndBlockID(i);n.getInstance(d,x),s.setInstance(m,{ids:[i],transform:x}),m++}}}};h(P,"isIFCEntity",t=>f.isObject(t)&&t.isIfcEntity),h(P,"isIFCPickResult",t=>f.isObject(t)&&P.isIFCEntity(t.entity));let k=P;class Z extends z{constructor(a,t,e){super(a,t,e,{visibility:!0})}}const K={class:"d-flex"},X=["title"],tt=["id"],et={class:"list-unstyled border-start"},ot=c.defineComponent({__name:"IfcSubtree",props:{classificationElement:{},ifcEntity:{}},setup(l){const a=l,t=_.MathUtils.generateUUID(),e=`#${t}`,o=c.ref(!1),n=f.useCameraStore(),s=f.useAnalysisStore();function r(){const i=a.ifcEntity.getBoundingBoxById(a.classificationElement.fragments);i&&!i.isEmpty()&&(s.setClippingBox(i),s.enableClippingBox(!0))}function u(){o.value=!0,a.ifcEntity.clearHighlight(),a.ifcEntity.highlightById(a.classificationElement.fragments),setTimeout(()=>o.value=!1,2e3)}function m(){const i=a.ifcEntity.getBoundingBoxById(a.classificationElement.fragments);i&&!i.isEmpty()&&n.lookTopDownAt(i)}return(i,d)=>{const p=c.resolveComponent("IfcSubtree",!0);return c.openBlock(),c.createElementBlock("div",null,[c.createElementVNode("div",K,[c.createElementVNode("span",{class:c.normalizeClass(["border rounded px-1 py-0 fw-normal",o.value?"text-danger border-danger":"text-secondary border-secondary"]),title:i.classificationElement.treeItemName},c.toDisplayString(i.classificationElement.treeItemName),11,X),i.classificationElement.children.length>0?(c.openBlock(),c.createBlock(f.IconList,{key:0},{default:c.withCtx(()=>[c.createVNode(f.IconListButton,{title:"Expand group",icon:"bi-chevron-down","data-bs-toggle":"collapse","data-bs-target":e,"aria-controls":c.unref(t),"aria-expanded":"true"},null,8,["aria-controls"])]),_:1})):c.createCommentVNode("",!0),c.createVNode(f._sfc_main$2,{class:c.normalizeClass(["label",o.value?"text-danger-emphasis":"text-muted"]),text:i.classificationElement.name,title:`Zoom to ${i.classificationElement.name}`,onClick:m},null,8,["class","text","title"]),c.createVNode(f.IconList,{class:"ms-1"},{default:c.withCtx(()=>[c.createVNode(f.IconListButton,{title:"Highlight",icon:"bi-highlighter",onClick:u}),c.createVNode(f.IconListButton,{title:"Clip to",icon:"bi-bounding-box",onClick:r})]),_:1})]),i.classificationElement.children.length>0?(c.openBlock(),c.createElementBlock("div",{key:0,id:c.unref(t),class:"collapse show"},[c.createElementVNode("ul",et,[(c.openBlock(!0),c.createElementBlock(c.Fragment,null,c.renderList(i.classificationElement.children,(y,b)=>(c.openBlock(),c.createElementBlock("li",{key:b},[c.createVNode(p,{"ifc-entity":a.ifcEntity,"classification-element":y},null,8,["ifc-entity","classification-element"])]))),128))])],8,tt)):c.createCommentVNode("",!0)])}}}),nt=f._export_sfc(ot,[["__scopeId","data-v-c2ab888d"]]),st={key:0},it=c.defineComponent({__name:"IfcPropertyView",props:{dataset:{}},setup(l){const a=f.useDatasetStore(),t=l,e=f.refAndWatch(t.dataset,"isPreloaded");function o(){const s=n();return s==null?null:s.getClassification()}function n(){const s=a.getEntity(t.dataset);return s??null}return(s,r)=>c.unref(e)?(c.openBlock(),c.createElementBlock("div",st,[c.createElementVNode("ul",null,[(c.openBlock(!0),c.createElementBlock(c.Fragment,null,c.renderList(o(),(u,m)=>(c.openBlock(),c.createElementBlock("li",{key:m},[c.createVNode(nt,{"ifc-entity":n(),"classification-element":u},null,8,["ifc-entity","classification-element"])]))),128))])])):c.createCommentVNode("",!0)}}),at=f._export_sfc(it,[["__scopeId","data-v-d2d82ae7"]]),rt=l=>{if(M(l)){const a=l.object;if(a.fragment!=null&&l.face&&l.instanceId!=null){const t=a.fragment.getVertexBlockID(a.geometry,l.face.a),e=a.fragment.getItemID(l.instanceId,t).replace(/\..*/,"");return l.entity.highlight("selection",a,e),()=>l.entity.clearHighlight()}}return null},ct=l=>({name:l.filename,source:{url:l.file},type:"ifc",visible:!0}),lt=(l,a)=>{var u,m,i,d,p,y,b,I,C;if(!M(l))return;const t=(u=l.features)==null?void 0:u.at(0);if(!t)return;a.has("IFC")||a.set("IFC",[]);const e=a.get("IFC"),{ifcProperties:o,itemProperties:n}=t,s="NULL",r=((m=n.Name)==null?void 0:m.value)??s;e.push({key:"Site",value:((d=(i=l.entity.object3d.userData)==null?void 0:i.dataset)==null?void 0:d.name)??s}),e.push({key:"IFCType",value:g.IfcCategoryMap[n.type]??s}),e.push({key:"Name",value:r}),e.push({key:"ID",value:n.expressID}),e.push({key:"GlobalId",value:((p=n.GlobalId)==null?void 0:p.value)??s}),((y=n.Description)==null?void 0:y.value)!=null&&e.push({key:"Description",value:n.Description.value}),((b=n.PredefinedType)==null?void 0:b.value)!=null&&e.push({key:"PredefinedType",value:n.PredefinedType.value}),((I=n.ObjectType)==null?void 0:I.value)!=null&&e.push({key:"ObjectType",value:n.ObjectType.value});for(const{name:S,parentName:T,value:N}of o)a.has(T)||a.set(T,[]),(C=a.get(T))==null||C.push({key:S,value:N})},ut=l=>{const a=l.dataset,t=a.config,e=f.getCoordinates(t.source.position??a.get("position")),o=new k({...t.source,at:e,name:a.name});return Promise.resolve(o)};class dt{constructor(){h(this,"name","IFC")}async initialize(a){a.datasets.registerDatasetType("ifc",{attributeExtractor:lt,entityBuilder:ut,fileExtensions:["ifc"],highlight:rt,icon:"bi-building",loader:ct,name:"IFC",propertyView:at}),A.registerInspector("IfcEntity",Z),await f.Fetcher.fetch("web-ifc.wasm").catch(t=>{console.warn("Could not load web-ifc.wasm",t)})}}const v=class v extends _.Mesh{constructor(){super(...arguments);h(this,"isPickableFeatures",!0);h(this,"isPlyMesh",!0)}pickFeaturesFrom(t){if(this.geometry.hasAttribute("color")&&t.face){const e=this.geometry.getAttribute("color").array,o=t.face,s=[{color:new _.Color(e[o.a*3],e[o.a*3+1],e[o.a*3+2])}];return t.features=s,s}return[]}};h(v,"isPlyMesh",t=>f.isObject(t)&&t.isPlyMesh),h(v,"isPlyPickResult",t=>f.isObject(t)&&v.isPlyMesh(t==null?void 0:t.object));let E=v;class ht extends B{constructor(t){super(new _.Group);h(this,"isPlyEntity",!0);h(this,"source");this.source=t}async preprocess(){const t=await f.Fetcher.fetchArrayBuffer(this.source.url),e=this.source.at.as(this.source.featureProjection).toVector3(),n=new j.PLYLoader().parse(t),s=new _.MeshLambertMaterial({side:_.DoubleSide});n.hasAttribute("color")&&(s.vertexColors=!0),n.computeVertexNormals();const r=new E(n,s);r.name="plyModel",n.computeBoundingBox(),r.position.copy(e),r.updateWorldMatrix(!0,!0),this.object3d.add(r),this.onObjectCreated(r);const u=f.Fetcher.getContext(this.source.url);f.fillObject3DUserData(this,{filename:u.filename}),this.notifyChange(this.object3d)}}const mt=l=>{const{dataset:a,instance:t}=l,e=a.config,o=f.getCoordinates(e.source.position??a.get("position")),n=new ht({...e.source,at:o,featureProjection:t.referenceCrs});return Promise.resolve(n)},ft=(l,a)=>{var o;if(!E.isPlyPickResult(l))return;const t=(o=l.features)==null?void 0:o.at(0);if(!t)return;a.has("PLY")||a.set("PLY",[]),a.get("PLY").push({key:"Color",value:t.color})};class pt{constructor(){h(this,"name","PLY")}initialize(a){a.datasets.registerDatasetType("ply",{attributeExtractor:ft,entityBuilder:mt,icon:"bi-file-earmark-binary",name:"PLY"})}}const gt=l=>{const a=l.dataset.config,t=new V({source:new R({url:`${a.source.url}/${a.source.filename}`})});return f.fillObject3DUserData(t,{filename:a.source.url}),Promise.resolve(t)};class yt{constructor(){h(this,"name","Potree")}initialize(a){a.datasets.registerDatasetType("potree",{entityBuilder:gt,icon:"fg-multipoint",name:"Potree Point Cloud"})}}class bt{constructor(){h(this,"name","Tour");h(this,"_camera",null);h(this,"_cameraCallback",null);h(this,"_context",null);h(this,"_tours",null)}initialize(a){this._context=a,a.events.addEventListener("ready",this.start.bind(this))}buildTours(){const a=this._camera,t=new w.Tour({tourName:"main",useModalOverlay:!0}),e=new w.Tour({tourName:"navigating",useModalOverlay:!0}),o=new w.Tour({tourName:"analyzing",useModalOverlay:!0}),n=[{action:()=>{var i;return(i=w.activeTour)==null?void 0:i.next()},text:"Next"},{action:()=>{var i;return(i=w.activeTour)==null?void 0:i.cancel()},secondary:!0,text:"Exit"}],s=()=>{var C,S;const i=(C=w.activeTour)==null?void 0:C.getCurrentStep(),d=i==null?void 0:i.getElement(),p=d==null?void 0:d.querySelector(".shepherd-text"),y=(S=w.activeTour)==null?void 0:S.steps;if(i==null||d==null||p==null||y==null)return;const b=document.createElement("div");b.className="progress mt-3",b.setAttribute("role","progressbar"),b.style.height="2px";const I=document.createElement("div");I.className="progress-bar bg-success",I.style.width=`${100*(y.indexOf(i)/y.length)}%`,b.appendChild(I),p.appendChild(b)},r=async(i,d)=>new Promise(p=>{const y=document.getElementById(i);if(y&&!y.classList.contains("active")&&y.click(),document.querySelector(d))return p(document.querySelector(d));const b=new MutationObserver(()=>{document.querySelector(d)&&(b.disconnect(),p(document.querySelector(d)))});b.observe(document.body,{childList:!0,subtree:!0})});t.addStep({buttons:[{action:()=>{var i;(i=w.activeTour)==null||i.complete(),e.show(0)},text:"Navigating"},{action:()=>{var i;(i=w.activeTour)==null||i.complete(),o.show(0)},text:"Analyzing data"},{action:()=>{var i;return(i=w.activeTour)==null?void 0:i.cancel()},secondary:!0,text:"Exit"}],cancelIcon:{enabled:!0,label:"Exit tutorial"},id:"example-step",text:"<p>Welcome to <strong>Piero</strong>, the Giro3D application.<br/>We can guide you through the different features.</p>",title:"Welcome!",when:{show:s}}),e.addStep({attachTo:{element:"#main-view",on:"bottom"},buttons:n,id:"view",text:"<p>This is the <b>main view</b>.</p><p>Giro3D natively supports a broad range of data sources, from 2D raster and vector data, to 3D point clouds and tilesets.</p><p>Piero adds support for CityJSON and IFC files.</p>",when:{show:s}}),e.addStep({attachTo:{element:"#main-view",on:"bottom"},buttons:n,id:"navigate",text:'<p>This application integrates <a href="https://github.com/yomotsu/camera-controls">camera-controls</a>, a camera control for three.js.</p><p><b>Click</b> to move the camera. <b>Right-click</b> to rotate around a point. <b>Scroll</b> to zoom in or out.</p>',when:{hide:()=>{this._cameraCallback&&a.removeEventListener("interaction-end",this._cameraCallback),this._cameraCallback=null},show:()=>{let i=0;this._cameraCallback=()=>{var d;i+=1,i>2&&((d=w.activeTour)==null||d.next())},a.addEventListener("interaction-end",this._cameraCallback),s()}}}),e.addStep({attachTo:{element:"#toolbar",on:"right"},beforeShowPromise:()=>r("toolbar-datasets","#datasets-drop-zone"),buttons:n,id:"toolbar-layers",text:"<p>Giro3D supports multiple datasets.</p><p>You can toggle datasets as you wish with the <b>Datasets</b> panel.</p>",when:{show:s}}),e.addStep({attachTo:{element:"#basemap-list",on:"right"},beforeShowPromise:()=>r("toolbar-datasets","#datasets-drop-zone"),buttons:n,id:"basemaps",text:"<p><b>Basemaps</b> are color and elevation layers that make the basic shape and aspect of the <b>Map</b>.</p>",when:{show:s}}),e.addStep({attachTo:{element:"#overlay-list",on:"right"},beforeShowPromise:()=>r("toolbar-datasets","#datasets-drop-zone"),buttons:n,id:"overlays",text:"<p><b>Overlays</b> are vector layers in various formats (WFS, GML, GeoJSON...).</p>",when:{show:s}}),e.addStep({attachTo:{element:"#dataset-list",on:"right"},beforeShowPromise:()=>r("toolbar-datasets","#datasets-drop-zone"),buttons:n,id:"layers",text:"<p>The <b>Datasets</b> panel contains all 3D objects in the scene.</><p>You can toggle their visibility and delete them.<p><p>Most objects leverage Giro3D's adaptive resolution to optimize their display.</p>",when:{show:s}}),e.addStep({attachTo:{element:"#datasets-drop-zone",on:"right"},beforeShowPromise:()=>r("toolbar-datasets","#datasets-drop-zone"),buttons:n,id:"adddata",text:"<p>You can add your own data from your computer by <b>dragging the file</b> into this page.</p><p>While you won't benefit from Giro3D's tiling mechanism, this can be a great way to quickly visualize datasets up to 100MB.</p><p>This application supports CityJSONs, IFCs, LAS/LAZs, CSV pointclouds, and simple GeoJSON features.</p>",when:{show:s}}),e.addStep({attachTo:{element:"#main-view",on:"bottom"},buttons:n,id:"attributes",text:"<p>By clicking on any feature on the map, you can see its <strong>Attribute table</strong>. Clickable features display a cursor when hovered.</p>",when:{show:s}}),e.addStep({attachTo:{element:"#search-place-autocomplete",on:"bottom"},buttons:[{action:()=>{var i;(i=w.activeTour)==null||i.complete(),o.show(0)},text:"Analyzing data"},{action:()=>{var i;return(i=w.activeTour)==null?void 0:i.complete()},secondary:!0,text:"Exit"}],id:"widgets",text:"Giro3D is highly extensible. Here we added a widget to search and navigate to locations based on the French address database.",when:{show:s}}),o.addStep({attachTo:{element:"#annotations-fieldset",on:"right"},beforeShowPromise:()=>r("toolbar-annotations","#annotations-fieldset"),buttons:n,id:"annotation",text:"<p>You can <strong>annotate</strong> any data displayed using Giro3D native tools.<br>Select the <strong>geometry</strong> of your annotation, and <strong>click</strong> on the scene to add points. <strong>Right-click</strong> to end the shape.</p>",when:{show:s}}),o.addStep({attachTo:{element:"#annotations-fieldset",on:"right"},beforeShowPromise:()=>r("toolbar-annotations","#annotations-fieldset"),buttons:n,id:"annotations",text:"You can download your annotations as GeoJSON files. You can also upload your own by dragging them into this panel.",when:{show:s}}),f.hasExperimentalFeature("measurements")&&o.addStep({attachTo:{element:"#panel-container",on:"right"},beforeShowPromise:()=>r("toolbar-measures","#measures-fieldset"),buttons:n,id:"measurements",text:"You can add <strong>measurements</strong> to easily get distances betwween objects.<br>Once started, moving the mouse will display the measure. <strong>Click</strong> to save the measurement. <strong>Right-click</strong> to end.",when:{show:s}}),o.addStep({attachTo:{element:"#panel-container",on:"right"},beforeShowPromise:()=>r("toolbar-analysis","#panel-container .card"),buttons:[{action:()=>{var i;return(i=w.activeTour)==null?void 0:i.complete()},text:"Done!"}],id:"analysis",text:"In the <strong>Analysis</strong> panel you'll find some advanced analysis tools.",when:{show:s}});const u=()=>{const i=new URL(document.URL);i.searchParams.delete("tourStep"),i.searchParams.set("tour","none"),window.history.replaceState({},"",i.toString())},m=i=>{const d=new URL(document.URL);let p="main";i.tour.id.startsWith("navigating")?p="navigating":i.tour.id.startsWith("analyzing")&&(p="analyzing"),d.searchParams.set("tour",p),d.searchParams.set("tourStep",i.step.id),window.history.replaceState({},"",d.toString())};return t.on("cancel",u),t.on("complete",u),t.on("show",m),e.on("cancel",u),e.on("complete",u),e.on("show",m),o.on("cancel",u),o.on("complete",u),o.on("show",m),{analyzingTour:o,mainTour:t,navigatingTour:e}}getTours(){return this._tours||(this._tours=this.buildTours()),this._tours}restart(){const{mainTour:a}=this.getTours();a.show(0)}start(){if(!this._context)throw new Error("module is not initialized");const{analyzingTour:a,mainTour:t,navigatingTour:e}=this.getTours();this._camera=this._context.view.getCameraController();const o=new URL(document.URL),n=o.searchParams.get("tour")??"main";if(n!=="none"){const s=o.searchParams.get("tourStep")??0;n==="navigating"?e.show(s):n==="analyzing"?a.show(s):t.show(s)}}}exports.IFCLoader=dt;exports.PLYLoader=pt;exports.PotreeLoader=yt;exports.Tour=bt;
1
+ "use strict";var G=Object.defineProperty;var q=(m,i,t)=>i in m?G(m,i,{enumerable:!0,configurable:!0,writable:!0,value:t}):m[i]=t;var C=(m,i,t)=>q(m,typeof i!="symbol"?i+"":i,t);Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const H=require("@giro3d/giro3d/gui/EntityPanel"),B=require("openbim-components"),p=require("./Components.cjs.js"),V=require("@giro3d/giro3d/entities/Entity3D"),W=require("@giro3d/giro3d/gui/EntityInspector"),f=require("vue"),$=require("@giro3d/giro3d/entities/PointCloud"),Z=require("@giro3d/giro3d/sources/PotreeSource"),k=require("shepherd.js"),L=new p.Matrix4,Q={bbox:new p.MeshBasicMaterial({color:"#FFFF00",depthTest:!0,opacity:.2,transparent:!0}),selection:new p.MeshBasicMaterial({color:"#FF0000",depthTest:!1,opacity:.6,transparent:!0})},X=4186316022,J=781010003,K=2655215786,tt=3242617779,et=919958153,nt=1307041759,j=1451395588,U=1883228015,st=[j,U],ot=[X,J,K,tt,et,nt],Y=m=>p.isObject(m)&&m.isIFCPickResult,A=class A extends V{constructor(t){super(new p.Group);C(this,"isIfcEntity",!0);C(this,"isPickableFeatures",!0);C(this,"type","IfcEntity");C(this,"_classificationCache");C(this,"_components");C(this,"_fragmentBoundingBox");C(this,"_fragmentClassifier");C(this,"_fragmentManager");C(this,"_ifcSelection");C(this,"_indexMap");C(this,"_model");C(this,"_source");this._source=t,this._components=new B.Components,this._components.ui.enabled=!1,this._components.scene=new B.SimpleScene(this._components),this._components.renderer=new B.SimpleRenderer(this._components,document.createElement("div")),this._components.camera=new B.SimpleCamera(this._components),this._components.raycaster=new B.SimpleRaycaster(this._components),this._components.init(),this._ifcSelection={bbox:{},selection:{}},this._indexMap={},this._classificationCache=null,this._fragmentBoundingBox=null}clearHighlight(t="selection"){for(const e of Object.keys(this._ifcSelection[t])){const n=this._fragmentManager.list[e],o=n==null?void 0:n.fragments[t];o!=null&&o.mesh.removeFromParent()}this.notifyChange(this),this._ifcSelection[t]={}}getBoundingBoxById(t){this.clearHighlight("bbox"),this.highlightById(t,"bbox");const e=this._fragmentBoundingBox;if(e===null)throw new Error("Must call initClassification before getBoundingBoxById");const n=this._fragmentManager;e.reset();const o=this._ifcSelection.bbox;if(!Object.keys(o).length)return;for(const x of Object.keys(o)){const P=n.list[x].fragments.bbox;e.addMesh(P.mesh)}const s=e.get(),{y:d,z:g}=s.min,{y:_,z:r}=s.max;return s.min.y=-r,s.max.y=-g,s.min.z=d,s.max.z=_,s.translate(this._model.position),this.clearHighlight("bbox"),s}getClassification(){if(this._classificationCache===null)throw new Error("Must call initClassification before getClassification");return this._classificationCache}getProperties(t){const e=[],n=this._model.properties;if(!n)return[];for(const o of this._indexMap[t]){const s=n[o];if(s==null)continue;const{name:d}=B.IfcPropertiesUtils.getEntityName(n,o);if(d!==null){if(s.type===j){const g=B.IfcPropertiesUtils.getPsetProps(n,o);if(g!==null)for(const _ of g){if(n[_]==null)continue;const x=this.getProperty(_);x!==null&&e.push({parentName:d,...x})}}else if(s.type===U){const g=B.IfcPropertiesUtils.getQsetQuantities(n,o);if(g!==null)for(const _ of g){const{key:r}=B.IfcPropertiesUtils.getQuantityValue(n,_);if(r===null)continue;const x=this.getProperty(_);x!==null&&e.push({parentName:d,...x})}}}}return e}getProperty(t){const e=this._model.properties;if(e===void 0)return null;const{name:n}=B.IfcPropertiesUtils.getEntityName(e,t);if(n===null)return null;const{value:o}=B.IfcPropertiesUtils.getQuantityValue(e,t);return{name:n,value:o}}highlight(t,e,n){this._ifcSelection[t][e.uuid]=new Set;const o=parseInt(n,10);this._ifcSelection[t][e.uuid].add(n),this.addComposites(t,e,o),this.regenerate(t,e.uuid);const s=e.fragment.group;if(s){const d=s.data[o][0];for(let g=0;g<d.length;g++){const _=d[g],r=s.keyFragments[_],x=this._fragmentManager.list[r];r in this._ifcSelection[t]||(this._ifcSelection[t][r]=new Set),this._ifcSelection[t][r].add(n),this.addComposites(t,x.mesh,o),this.regenerate(t,r)}}this.notifyChange(this)}highlightById(t,e="selection"){for(const n of Object.keys(t)){n in this._ifcSelection[e]||(this._ifcSelection[e][n]=new Set);const o=this._fragmentManager.list[n],s=new Set;for(const d of t[n])this._ifcSelection[e][n].add(d),s.add(parseInt(d,10));for(const d of s)this.addComposites(e,o.mesh,d);this.regenerate(e,n)}this.notifyChange(this)}pick(t,e){return super.pick(t,e).map(n=>({...n,entity:this,features:n.features,isIFCPickResult:!0,object:n.object}))}pickFeaturesFrom(t){var n,o,s;const e=t.object;if(e.fragment!=null&&t.instanceId!=null&&t.face){const d=e.fragment.getVertexBlockID(e.geometry,t.face.a),g=(n=e.fragment.getItemID(t.instanceId,d))==null?void 0:n.replace(/\..*/,"");if(g&&((s=(o=e.fragment.group)==null?void 0:o.properties)==null?void 0:s[g])!=null){const r=e.fragment.group.properties[g],v=[{ifcProperties:this.getProperties(g),itemProperties:r}];return t.features=v,v}}return[]}async initClassification(){this._classificationCache=await this.regenerateClassification(["storeys","entities"]),this._classificationCache.length===0&&(this._classificationCache=await this.regenerateClassification(["entities"])),this._fragmentBoundingBox=await this._components.tools.get(B.FragmentBoundingBox)}async preprocess(){const t=await p.Fetcher.fetchArrayBuffer(this._source.url);this._fragmentManager=await this._components.tools.get(B.FragmentManager),this._fragmentClassifier=await this._components.tools.get(B.FragmentClassifier);const e=new B.FragmentIfcLoader(this._components);e.settings.webIfc.COORDINATE_TO_ORIGIN=!0,e.settings.webIfc.OPTIMIZE_PROFILES=!0;const n=new Uint8Array(t);this._model=await e.load(n,this._source.name),this._model.rotateX(Math.PI/2);const o=new p.Vector3;if(this._source.at)this._source.at.toVector3(o),this._model.position.copy(o);else{const d=this._model.coordinationMatrix.clone().invert();o.applyMatrix4(d),this._model.position.set(o.x,-o.z,o.y)}this._model.updateWorldMatrix(!0,!0),this._model.updateMatrix(),this._model.updateMatrixWorld(!0),this.initializeEntityIndexes(),this._fragmentClassifier.byStorey(this._model),this._fragmentClassifier.byEntity(this._model),await this.initClassification(),this.object3d.add(this._model),this.onObjectCreated(this._model);const s=p.Fetcher.getContext(this._source.url);p.fillObject3DUserData(this,{filename:s.filename}),this.notifyChange(this.object3d)}addComposites(t,e,n){this.addHighlightToFragment(t,e.fragment);const o=e.fragment.composites[n];if(o)for(let s=1;s<o;s++){const d=B.toCompositeID(n,s);this._ifcSelection[t][e.uuid].add(d)}}addHighlightToFragment(t,e){if(!(t in e.fragments)){const n=e.addFragment(t,[Q[t]]);e.blocks.count>1&&(n.setInstance(0,{ids:Array.from(e.ids),transform:L}),n.blocks.setVisibility(!1)),this._model.add(n.mesh),n.mesh.renderOrder=30,n.mesh.frustumCulled=!1,n.mesh.name=t,n.mesh.updateMatrixWorld(!0)}}initializeEntityIndexes(){this._indexMap={};const t=this._model.properties;if(t!==void 0)for(const e of ot)B.IfcPropertiesUtils.getRelationMap(t,e,(n,o)=>{const s=t[n];st.includes(s.type)||this.setEntityIndex(n);for(const d of o)this.setEntityIndex(d).add(n)})}regenerate(t,e){this.updateFragmentFill(t,e)}async regenerateClassification(t,e={}){const n=this._fragmentClassifier.get(),o=[],s=t[0],d=n[s];if(s==null||d==null)return o;for(const g of Object.keys(d)){const _={...e,[s]:[g]},r=await this._fragmentClassifier.find(_);if(Object.keys(r).length>0){const P=s[0].toUpperCase()+s.slice(1),S=await this.regenerateClassification(t.slice(1),_);o.push({children:S,fragments:r,name:g,treeItemName:P})}}return o}setEntityIndex(t){return t in this._indexMap||(this._indexMap[t]=new Set),this._indexMap[t]}updateFragmentFill(t,e){const n=this._ifcSelection[t][e],o=this._fragmentManager.list[e];if(o==null)return;const s=o.fragments[t];if(s==null)return;const d=o.mesh.parent;if(d==null)return;if(d.add(s.mesh),s.blocks.count>1)o.getInstance(0,L),s.setInstance(0,{ids:Array.from(o.ids),transform:L}),s.blocks.setVisibility(!0,n,!0);else{let _=0;for(const r of n){s.mesh.count=_+1;const{instanceID:x}=o.getInstanceAndBlockID(r);o.getInstance(x,L),s.setInstance(_,{ids:[r],transform:L}),_++}}}};C(A,"isIFCEntity",t=>p.isObject(t)&&t.isIfcEntity),C(A,"isIFCPickResult",t=>p.isObject(t)&&A.isIFCEntity(t.entity));let R=A;class it extends W{constructor(i,t,e){super(i,t,e,{visibility:!0})}}const rt={class:"d-flex"},at=["title"],ct=["id"],lt={class:"list-unstyled border-start"},ut=f.defineComponent({__name:"IfcSubtree",props:{classificationElement:{},ifcEntity:{}},setup(m){const i=m,t=p.MathUtils.generateUUID(),e=`#${t}`,n=f.ref(!1),o=p.useCameraStore(),s=p.useAnalysisStore();function d(){const r=i.ifcEntity.getBoundingBoxById(i.classificationElement.fragments);r&&!r.isEmpty()&&(s.setClippingBox(r),s.enableClippingBox(!0))}function g(){n.value=!0,i.ifcEntity.clearHighlight(),i.ifcEntity.highlightById(i.classificationElement.fragments),setTimeout(()=>n.value=!1,2e3)}function _(){const r=i.ifcEntity.getBoundingBoxById(i.classificationElement.fragments);r&&!r.isEmpty()&&o.lookTopDownAt(r)}return(r,x)=>{const v=f.resolveComponent("IfcSubtree",!0);return f.openBlock(),f.createElementBlock("div",null,[f.createElementVNode("div",rt,[f.createElementVNode("span",{class:f.normalizeClass(["border rounded px-1 py-0 fw-normal",n.value?"text-danger border-danger":"text-secondary border-secondary"]),title:r.classificationElement.treeItemName},f.toDisplayString(r.classificationElement.treeItemName),11,at),r.classificationElement.children.length>0?(f.openBlock(),f.createBlock(p.IconList,{key:0},{default:f.withCtx(()=>[f.createVNode(p.IconListButton,{title:"Expand group",icon:"bi-chevron-down","data-bs-toggle":"collapse","data-bs-target":e,"aria-controls":f.unref(t),"aria-expanded":"true"},null,8,["aria-controls"])]),_:1})):f.createCommentVNode("",!0),f.createVNode(p._sfc_main$2,{class:f.normalizeClass(["label",n.value?"text-danger-emphasis":"text-muted"]),text:r.classificationElement.name,title:`Zoom to ${r.classificationElement.name}`,onClick:_},null,8,["class","text","title"]),f.createVNode(p.IconList,{class:"ms-1"},{default:f.withCtx(()=>[f.createVNode(p.IconListButton,{title:"Highlight",icon:"bi-highlighter",onClick:g}),f.createVNode(p.IconListButton,{title:"Clip to",icon:"bi-bounding-box",onClick:d})]),_:1})]),r.classificationElement.children.length>0?(f.openBlock(),f.createElementBlock("div",{key:0,id:f.unref(t),class:"collapse show"},[f.createElementVNode("ul",lt,[(f.openBlock(!0),f.createElementBlock(f.Fragment,null,f.renderList(r.classificationElement.children,(P,S)=>(f.openBlock(),f.createElementBlock("li",{key:S},[f.createVNode(v,{"ifc-entity":i.ifcEntity,"classification-element":P},null,8,["ifc-entity","classification-element"])]))),128))])],8,ct)):f.createCommentVNode("",!0)])}}}),dt=p._export_sfc(ut,[["__scopeId","data-v-c2ab888d"]]),ht={key:0},pt=f.defineComponent({__name:"IfcPropertyView",props:{dataset:{}},setup(m){const i=p.useDatasetStore(),t=m,e=p.refAndWatch(t.dataset,"isPreloaded");function n(){const s=o();return s==null?null:s.getClassification()}function o(){const s=i.getEntity(t.dataset);return s??null}return(s,d)=>f.unref(e)?(f.openBlock(),f.createElementBlock("div",ht,[f.createElementVNode("ul",null,[(f.openBlock(!0),f.createElementBlock(f.Fragment,null,f.renderList(n(),(g,_)=>(f.openBlock(),f.createElementBlock("li",{key:_},[f.createVNode(dt,{"ifc-entity":o(),"classification-element":g},null,8,["ifc-entity","classification-element"])]))),128))])])):f.createCommentVNode("",!0)}}),ft=p._export_sfc(pt,[["__scopeId","data-v-d2d82ae7"]]),mt=m=>{if(Y(m)){const i=m.object;if(i.fragment!=null&&m.face&&m.instanceId!=null){const t=i.fragment.getVertexBlockID(i.geometry,m.face.a),e=i.fragment.getItemID(m.instanceId,t).replace(/\..*/,"");return m.entity.highlight("selection",i,e),()=>m.entity.clearHighlight()}}return null},gt=m=>({name:m.filename,source:{url:m.file},type:"ifc",visible:!0}),yt=(m,i)=>{var g,_,r,x,v,P,S,N,a;if(!Y(m))return;const t=(g=m.features)==null?void 0:g.at(0);if(!t)return;i.has("IFC")||i.set("IFC",[]);const e=i.get("IFC"),{ifcProperties:n,itemProperties:o}=t,s="NULL",d=((_=o.Name)==null?void 0:_.value)??s;e.push({key:"Site",value:((x=(r=m.entity.object3d.userData)==null?void 0:r.dataset)==null?void 0:x.name)??s}),e.push({key:"IFCType",value:B.IfcCategoryMap[o.type]??s}),e.push({key:"Name",value:d}),e.push({key:"ID",value:o.expressID}),e.push({key:"GlobalId",value:((v=o.GlobalId)==null?void 0:v.value)??s}),((P=o.Description)==null?void 0:P.value)!=null&&e.push({key:"Description",value:o.Description.value}),((S=o.PredefinedType)==null?void 0:S.value)!=null&&e.push({key:"PredefinedType",value:o.PredefinedType.value}),((N=o.ObjectType)==null?void 0:N.value)!=null&&e.push({key:"ObjectType",value:o.ObjectType.value});for(const{name:u,parentName:l,value:c}of n)i.has(l)||i.set(l,[]),(a=i.get(l))==null||a.push({key:u,value:c})},bt=m=>{const i=m.dataset,t=i.config,e=p.getCoordinates(t.source.position??i.get("position")),n=new R({...t.source,at:e,name:i.name});return Promise.resolve(n)};class xt{constructor(){C(this,"name","IFC")}async initialize(i){i.datasets.registerDatasetType("ifc",{attributeExtractor:yt,entityBuilder:bt,fileExtensions:["ifc"],highlight:mt,icon:"bi-building",loader:gt,name:"IFC",propertyView:ft}),H.registerInspector("IfcEntity",it),await p.Fetcher.fetch("web-ifc.wasm").catch(t=>{console.warn("Could not load web-ifc.wasm",t)})}}const F=new p.Color;let wt=class extends p.Loader{constructor(i){super(i),this.propertyNameMapping={},this.customPropertyMapping={}}load(i,t,e,n){const o=this,s=new p.FileLoader(this.manager);s.setPath(this.path),s.setResponseType("arraybuffer"),s.setRequestHeader(this.requestHeader),s.setWithCredentials(this.withCredentials),s.load(i,function(d){try{t(o.parse(d))}catch(g){n?n(g):console.error(g),o.manager.itemError(i)}},e,n)}setPropertyNameMapping(i){this.propertyNameMapping=i}setCustomPropertyNameMapping(i){this.customPropertyMapping=i}parse(i){function t(a,u=0){const l=/^ply([\s\S]*)end_header(\r\n|\r|\n)/;let c="";const h=l.exec(a);h!==null&&(c=h[1]);const y={comments:[],elements:[],headerLength:u,objInfo:""},w=c.split(/\r\n|\r|\n/);let b;function M(T,E){const I={type:T[0]};return I.type==="list"?(I.name=T[3],I.countType=T[1],I.itemType=T[2]):I.name=T[1],I.name in E&&(I.name=E[I.name]),I}for(let T=0;T<w.length;T++){let E=w[T];if(E=E.trim(),E==="")continue;const I=E.split(/\s+/),z=I.shift();switch(E=I.join(" "),z){case"format":y.format=I[0],y.version=I[1];break;case"comment":y.comments.push(E);break;case"element":b!==void 0&&y.elements.push(b),b={},b.name=I[0],b.count=parseInt(I[1]),b.properties=[];break;case"property":b.properties.push(M(I,N.propertyNameMapping));break;case"obj_info":y.objInfo=E;break;default:console.log("unhandled",z,I)}}return b!==void 0&&y.elements.push(b),y}function e(a,u){switch(u){case"char":case"uchar":case"short":case"ushort":case"int":case"uint":case"int8":case"uint8":case"int16":case"uint16":case"int32":case"uint32":return parseInt(a);case"float":case"double":case"float32":case"float64":return parseFloat(a)}}function n(a,u){const l={};for(let c=0;c<a.length;c++){if(u.empty())return null;if(a[c].type==="list"){const h=[],y=e(u.next(),a[c].countType);for(let w=0;w<y;w++){if(u.empty())return null;h.push(e(u.next(),a[c].itemType))}l[a[c].name]=h}else l[a[c].name]=e(u.next(),a[c].type)}return l}function o(){const a={indices:[],vertices:[],normals:[],uvs:[],faceVertexUvs:[],colors:[],faceVertexColors:[]};for(const u of Object.keys(N.customPropertyMapping))a[u]=[];return a}function s(a){const u=a.map(c=>c.name);function l(c){for(let h=0,y=c.length;h<y;h++){const w=c[h];if(u.includes(w))return w}return null}return{attrX:l(["x","px","posx"])||"x",attrY:l(["y","py","posy"])||"y",attrZ:l(["z","pz","posz"])||"z",attrNX:l(["nx","normalx"]),attrNY:l(["ny","normaly"]),attrNZ:l(["nz","normalz"]),attrS:l(["s","u","texture_u","tx"]),attrT:l(["t","v","texture_v","ty"]),attrR:l(["red","diffuse_red","r","diffuse_r"]),attrG:l(["green","diffuse_green","g","diffuse_g"]),attrB:l(["blue","diffuse_blue","b","diffuse_b"])}}function d(a,u){const l=o(),c=/end_header\s+(\S[\s\S]*\S|\S)\s*$/;let h,y;(y=c.exec(a))!==null?h=y[1].split(/\s+/):h=[];const w=new _t(h);t:for(let b=0;b<u.elements.length;b++){const M=u.elements[b],T=s(M.properties);for(let E=0;E<M.count;E++){const I=n(M.properties,w);if(!I)break t;_(l,M.name,I,T)}}return g(l)}function g(a){let u=new p.BufferGeometry;a.indices.length>0&&u.setIndex(a.indices),u.setAttribute("position",new p.Float32BufferAttribute(a.vertices,3)),a.normals.length>0&&u.setAttribute("normal",new p.Float32BufferAttribute(a.normals,3)),a.uvs.length>0&&u.setAttribute("uv",new p.Float32BufferAttribute(a.uvs,2)),a.colors.length>0&&u.setAttribute("color",new p.Float32BufferAttribute(a.colors,3)),(a.faceVertexUvs.length>0||a.faceVertexColors.length>0)&&(u=u.toNonIndexed(),a.faceVertexUvs.length>0&&u.setAttribute("uv",new p.Float32BufferAttribute(a.faceVertexUvs,2)),a.faceVertexColors.length>0&&u.setAttribute("color",new p.Float32BufferAttribute(a.faceVertexColors,3)));for(const l of Object.keys(N.customPropertyMapping))a[l].length>0&&u.setAttribute(l,new p.Float32BufferAttribute(a[l],N.customPropertyMapping[l].length));return u.computeBoundingSphere(),u}function _(a,u,l,c){if(u==="vertex"){a.vertices.push(l[c.attrX],l[c.attrY],l[c.attrZ]),c.attrNX!==null&&c.attrNY!==null&&c.attrNZ!==null&&a.normals.push(l[c.attrNX],l[c.attrNY],l[c.attrNZ]),c.attrS!==null&&c.attrT!==null&&a.uvs.push(l[c.attrS],l[c.attrT]),c.attrR!==null&&c.attrG!==null&&c.attrB!==null&&(F.setRGB(l[c.attrR]/255,l[c.attrG]/255,l[c.attrB]/255,p.SRGBColorSpace),a.colors.push(F.r,F.g,F.b));for(const h of Object.keys(N.customPropertyMapping))for(const y of N.customPropertyMapping[h])a[h].push(l[y])}else if(u==="face"){const h=l.vertex_indices||l.vertex_index,y=l.texcoord;h.length===3?(a.indices.push(h[0],h[1],h[2]),y&&y.length===6&&(a.faceVertexUvs.push(y[0],y[1]),a.faceVertexUvs.push(y[2],y[3]),a.faceVertexUvs.push(y[4],y[5]))):h.length===4&&(a.indices.push(h[0],h[1],h[3]),a.indices.push(h[1],h[2],h[3])),c.attrR!==null&&c.attrG!==null&&c.attrB!==null&&(F.setRGB(l[c.attrR]/255,l[c.attrG]/255,l[c.attrB]/255,p.SRGBColorSpace),a.faceVertexColors.push(F.r,F.g,F.b),a.faceVertexColors.push(F.r,F.g,F.b),a.faceVertexColors.push(F.r,F.g,F.b))}}function r(a,u){const l={};let c=0;for(let h=0;h<u.length;h++){const y=u[h],w=y.valueReader;if(y.type==="list"){const b=[],M=y.countReader.read(a+c);c+=y.countReader.size;for(let T=0;T<M;T++)b.push(w.read(a+c)),c+=w.size;l[y.name]=b}else l[y.name]=w.read(a+c),c+=w.size}return[l,c]}function x(a,u,l){function c(h,y,w){switch(y){case"int8":case"char":return{read:b=>h.getInt8(b),size:1};case"uint8":case"uchar":return{read:b=>h.getUint8(b),size:1};case"int16":case"short":return{read:b=>h.getInt16(b,w),size:2};case"uint16":case"ushort":return{read:b=>h.getUint16(b,w),size:2};case"int32":case"int":return{read:b=>h.getInt32(b,w),size:4};case"uint32":case"uint":return{read:b=>h.getUint32(b,w),size:4};case"float32":case"float":return{read:b=>h.getFloat32(b,w),size:4};case"float64":case"double":return{read:b=>h.getFloat64(b,w),size:8}}}for(let h=0,y=a.length;h<y;h++){const w=a[h];w.type==="list"?(w.countReader=c(u,w.countType,l),w.valueReader=c(u,w.itemType,l)):w.valueReader=c(u,w.type,l)}}function v(a,u){const l=o(),c=u.format==="binary_little_endian",h=new DataView(a,u.headerLength);let y,w=0;for(let b=0;b<u.elements.length;b++){const M=u.elements[b],T=M.properties,E=s(T);x(T,h,c);for(let I=0;I<M.count;I++){y=r(w,T),w+=y[1];const z=y[0];_(l,M.name,z,E)}}return g(l)}function P(a){let u=0,l=!0,c="";const h=[],y=new TextDecoder().decode(a.subarray(0,5)),w=/^ply\r\n/.test(y);do{const b=String.fromCharCode(a[u++]);b!==`
2
+ `&&b!=="\r"?c+=b:(c==="end_header"&&(l=!1),c!==""&&(h.push(c),c=""))}while(l&&u<a.length);return w===!0&&u++,{headerText:h.join("\r")+"\r",headerLength:u}}let S;const N=this;if(i instanceof ArrayBuffer){const a=new Uint8Array(i),{headerText:u,headerLength:l}=P(a),c=t(u,l);if(c.format==="ascii"){const h=new TextDecoder().decode(a);S=d(h,c)}else S=v(i,c)}else S=d(i,t(i));return S}};class _t{constructor(i){this.arr=i,this.i=0}empty(){return this.i>=this.arr.length}next(){return this.arr[this.i++]}}const O=class O extends p.Mesh{constructor(){super(...arguments);C(this,"isPickableFeatures",!0);C(this,"isPlyMesh",!0)}pickFeaturesFrom(t){if(this.geometry.hasAttribute("color")&&t.face){const e=this.geometry.getAttribute("color").array,n=t.face,s=[{color:new p.Color(e[n.a*3],e[n.a*3+1],e[n.a*3+2])}];return t.features=s,s}return[]}};C(O,"isPlyMesh",t=>p.isObject(t)&&t.isPlyMesh),C(O,"isPlyPickResult",t=>p.isObject(t)&&O.isPlyMesh(t==null?void 0:t.object));let D=O;class Ct extends V{constructor(t){super(new p.Group);C(this,"isPlyEntity",!0);C(this,"source");this.source=t}async preprocess(){const t=await p.Fetcher.fetchArrayBuffer(this.source.url),e=this.source.at.as(this.source.featureProjection).toVector3(),o=new wt().parse(t),s=new p.MeshLambertMaterial({side:p.DoubleSide});o.hasAttribute("color")&&(s.vertexColors=!0),o.computeVertexNormals();const d=new D(o,s);d.name="plyModel",o.computeBoundingBox(),d.position.copy(e),d.updateWorldMatrix(!0,!0),this.object3d.add(d),this.onObjectCreated(d);const g=p.Fetcher.getContext(this.source.url);p.fillObject3DUserData(this,{filename:g.filename}),this.notifyChange(this.object3d)}}const It=m=>{const{dataset:i,instance:t}=m,e=i.config,n=p.getCoordinates(e.source.position??i.get("position")),o=new Ct({...e.source,at:n,featureProjection:t.referenceCrs});return Promise.resolve(o)},vt=(m,i)=>{var n;if(!D.isPlyPickResult(m))return;const t=(n=m.features)==null?void 0:n.at(0);if(!t)return;i.has("PLY")||i.set("PLY",[]),i.get("PLY").push({key:"Color",value:t.color})};class St{constructor(){C(this,"name","PLY")}initialize(i){i.datasets.registerDatasetType("ply",{attributeExtractor:vt,entityBuilder:It,icon:"bi-file-earmark-binary",name:"PLY"})}}const Pt=m=>{const i=m.dataset.config,t=new $({source:new Z({url:`${i.source.url}/${i.source.filename}`})});return p.fillObject3DUserData(t,{filename:i.source.url}),Promise.resolve(t)};class Tt{constructor(){C(this,"name","Potree")}initialize(i){i.datasets.registerDatasetType("potree",{entityBuilder:Pt,icon:"fg-multipoint",name:"Potree Point Cloud"})}}class Bt{constructor(){C(this,"name","Tour");C(this,"_camera",null);C(this,"_cameraCallback",null);C(this,"_context",null);C(this,"_tours",null)}initialize(i){this._context=i,i.events.addEventListener("ready",this.start.bind(this))}buildTours(){const i=this._camera,t=new k.Tour({tourName:"main",useModalOverlay:!0}),e=new k.Tour({tourName:"navigating",useModalOverlay:!0}),n=new k.Tour({tourName:"analyzing",useModalOverlay:!0}),o=[{action:()=>{var r;return(r=k.activeTour)==null?void 0:r.next()},text:"Next"},{action:()=>{var r;return(r=k.activeTour)==null?void 0:r.cancel()},secondary:!0,text:"Exit"}],s=()=>{var a,u;const r=(a=k.activeTour)==null?void 0:a.getCurrentStep(),x=r==null?void 0:r.getElement(),v=x==null?void 0:x.querySelector(".shepherd-text"),P=(u=k.activeTour)==null?void 0:u.steps;if(r==null||x==null||v==null||P==null)return;const S=document.createElement("div");S.className="progress mt-3",S.setAttribute("role","progressbar"),S.style.height="2px";const N=document.createElement("div");N.className="progress-bar bg-success",N.style.width=`${100*(P.indexOf(r)/P.length)}%`,S.appendChild(N),v.appendChild(S)},d=async(r,x)=>new Promise(v=>{const P=document.getElementById(r);if(P&&!P.classList.contains("active")&&P.click(),document.querySelector(x))return v(document.querySelector(x));const S=new MutationObserver(()=>{document.querySelector(x)&&(S.disconnect(),v(document.querySelector(x)))});S.observe(document.body,{childList:!0,subtree:!0})});t.addStep({buttons:[{action:()=>{var r;(r=k.activeTour)==null||r.complete(),e.show(0)},text:"Navigating"},{action:()=>{var r;(r=k.activeTour)==null||r.complete(),n.show(0)},text:"Analyzing data"},{action:()=>{var r;return(r=k.activeTour)==null?void 0:r.cancel()},secondary:!0,text:"Exit"}],cancelIcon:{enabled:!0,label:"Exit tutorial"},id:"example-step",text:"<p>Welcome to <strong>Piero</strong>, the Giro3D application.<br/>We can guide you through the different features.</p>",title:"Welcome!",when:{show:s}}),e.addStep({attachTo:{element:"#main-view",on:"bottom"},buttons:o,id:"view",text:"<p>This is the <b>main view</b>.</p><p>Giro3D natively supports a broad range of data sources, from 2D raster and vector data, to 3D point clouds and tilesets.</p><p>Piero adds support for CityJSON and IFC files.</p>",when:{show:s}}),e.addStep({attachTo:{element:"#main-view",on:"bottom"},buttons:o,id:"navigate",text:'<p>This application integrates <a href="https://github.com/yomotsu/camera-controls">camera-controls</a>, a camera control for three.js.</p><p><b>Click</b> to move the camera. <b>Right-click</b> to rotate around a point. <b>Scroll</b> to zoom in or out.</p>',when:{hide:()=>{this._cameraCallback&&i.removeEventListener("interaction-end",this._cameraCallback),this._cameraCallback=null},show:()=>{let r=0;this._cameraCallback=()=>{var x;r+=1,r>2&&((x=k.activeTour)==null||x.next())},i.addEventListener("interaction-end",this._cameraCallback),s()}}}),e.addStep({attachTo:{element:"#toolbar",on:"right"},beforeShowPromise:()=>d("toolbar-datasets","#datasets-drop-zone"),buttons:o,id:"toolbar-layers",text:"<p>Giro3D supports multiple datasets.</p><p>You can toggle datasets as you wish with the <b>Datasets</b> panel.</p>",when:{show:s}}),e.addStep({attachTo:{element:"#basemap-list",on:"right"},beforeShowPromise:()=>d("toolbar-datasets","#datasets-drop-zone"),buttons:o,id:"basemaps",text:"<p><b>Basemaps</b> are color and elevation layers that make the basic shape and aspect of the <b>Map</b>.</p>",when:{show:s}}),e.addStep({attachTo:{element:"#overlay-list",on:"right"},beforeShowPromise:()=>d("toolbar-datasets","#datasets-drop-zone"),buttons:o,id:"overlays",text:"<p><b>Overlays</b> are vector layers in various formats (WFS, GML, GeoJSON...).</p>",when:{show:s}}),e.addStep({attachTo:{element:"#dataset-list",on:"right"},beforeShowPromise:()=>d("toolbar-datasets","#datasets-drop-zone"),buttons:o,id:"layers",text:"<p>The <b>Datasets</b> panel contains all 3D objects in the scene.</><p>You can toggle their visibility and delete them.<p><p>Most objects leverage Giro3D's adaptive resolution to optimize their display.</p>",when:{show:s}}),e.addStep({attachTo:{element:"#datasets-drop-zone",on:"right"},beforeShowPromise:()=>d("toolbar-datasets","#datasets-drop-zone"),buttons:o,id:"adddata",text:"<p>You can add your own data from your computer by <b>dragging the file</b> into this page.</p><p>While you won't benefit from Giro3D's tiling mechanism, this can be a great way to quickly visualize datasets up to 100MB.</p><p>This application supports CityJSONs, IFCs, LAS/LAZs, CSV pointclouds, and simple GeoJSON features.</p>",when:{show:s}}),e.addStep({attachTo:{element:"#main-view",on:"bottom"},buttons:o,id:"attributes",text:"<p>By clicking on any feature on the map, you can see its <strong>Attribute table</strong>. Clickable features display a cursor when hovered.</p>",when:{show:s}}),e.addStep({attachTo:{element:"#search-place-autocomplete",on:"bottom"},buttons:[{action:()=>{var r;(r=k.activeTour)==null||r.complete(),n.show(0)},text:"Analyzing data"},{action:()=>{var r;return(r=k.activeTour)==null?void 0:r.complete()},secondary:!0,text:"Exit"}],id:"widgets",text:"Giro3D is highly extensible. Here we added a widget to search and navigate to locations based on the French address database.",when:{show:s}}),n.addStep({attachTo:{element:"#annotations-fieldset",on:"right"},beforeShowPromise:()=>d("toolbar-annotations","#annotations-fieldset"),buttons:o,id:"annotation",text:"<p>You can <strong>annotate</strong> any data displayed using Giro3D native tools.<br>Select the <strong>geometry</strong> of your annotation, and <strong>click</strong> on the scene to add points. <strong>Right-click</strong> to end the shape.</p>",when:{show:s}}),n.addStep({attachTo:{element:"#annotations-fieldset",on:"right"},beforeShowPromise:()=>d("toolbar-annotations","#annotations-fieldset"),buttons:o,id:"annotations",text:"You can download your annotations as GeoJSON files. You can also upload your own by dragging them into this panel.",when:{show:s}}),p.hasExperimentalFeature("measurements")&&n.addStep({attachTo:{element:"#panel-container",on:"right"},beforeShowPromise:()=>d("toolbar-measures","#measures-fieldset"),buttons:o,id:"measurements",text:"You can add <strong>measurements</strong> to easily get distances betwween objects.<br>Once started, moving the mouse will display the measure. <strong>Click</strong> to save the measurement. <strong>Right-click</strong> to end.",when:{show:s}}),n.addStep({attachTo:{element:"#panel-container",on:"right"},beforeShowPromise:()=>d("toolbar-analysis","#panel-container .card"),buttons:[{action:()=>{var r;return(r=k.activeTour)==null?void 0:r.complete()},text:"Done!"}],id:"analysis",text:"In the <strong>Analysis</strong> panel you'll find some advanced analysis tools.",when:{show:s}});const g=()=>{const r=new URL(document.URL);r.searchParams.delete("tourStep"),r.searchParams.set("tour","none"),window.history.replaceState({},"",r.toString())},_=r=>{const x=new URL(document.URL);let v="main";r.tour.id.startsWith("navigating")?v="navigating":r.tour.id.startsWith("analyzing")&&(v="analyzing"),x.searchParams.set("tour",v),x.searchParams.set("tourStep",r.step.id),window.history.replaceState({},"",x.toString())};return t.on("cancel",g),t.on("complete",g),t.on("show",_),e.on("cancel",g),e.on("complete",g),e.on("show",_),n.on("cancel",g),n.on("complete",g),n.on("show",_),{analyzingTour:n,mainTour:t,navigatingTour:e}}getTours(){return this._tours||(this._tours=this.buildTours()),this._tours}restart(){const{mainTour:i}=this.getTours();i.show(0)}start(){if(!this._context)throw new Error("module is not initialized");const{analyzingTour:i,mainTour:t,navigatingTour:e}=this.getTours();this._camera=this._context.view.getCameraController();const n=new URL(document.URL),o=n.searchParams.get("tour")??"main";if(o!=="none"){const s=n.searchParams.get("tourStep")??0;o==="navigating"?e.show(s):o==="analyzing"?i.show(s):t.show(s)}}}exports.IFCLoader=xt;exports.PLYLoader=St;exports.PotreeLoader=Tt;exports.Tour=Bt;
2
3
  //# sourceMappingURL=modules.cjs.js.map