UNPKG

@arcgis/core

Version:

ArcGIS Maps SDK for JavaScript: A complete 2D and 3D mapping and data visualization API

6 lines (5 loc) 5.75 kB
/* All material copyright ESRI, All Rights Reserved, unless otherwise specified. See https://js.arcgis.com/4.32/esri/copyright.txt for details. */ import{clamp as t}from"../../../../../core/mathUtils.js";import{fromValues as e}from"../../../../../core/libs/gl-matrix-2/factories/vec3f64.js";import{createUintArray as n}from"../../lib/triangleIntersectionUtils.js";class i{constructor(t,n){this.elementCount=t,this.model=n,this._elementIndexMap=null,this._bspNodes=[],this._generatedBVH=!1,this.localMode=n.localMode,this.planetCenterZ=n.planetCenterZ,this.geometryMinZ=n.geometryMinZ,this.planetCenter=e(0,0,this.planetCenterZ),this.maxBspNodeDepth=n.maxBspNodeDepth??8,this.minElementCountForBVH=n.minElementCountForBVH??15,this.minBspNodeElementCount=n.minBspNodeElementCount??5}get elementIndexMap(){return this._ensureBVH(),this._elementIndexMap}get _skipBVH(){return this.elementCount<this.minElementCountForBVH||this.geometryMinZ<.5*this.planetCenterZ}_ensureBVH(){this._generatedBVH||this._skipBVH||0===this._bspNodes.length&&this._generateBsp()}intersectRay(t,e,n){this.elementCount<1||(this._skipBVH?this._intersectRayWithoutBVH(n):this._intersectRayWithBVH(t,e,n))}_intersectRayWithoutBVH(t){this._intersectRange(0,this.elementCount)}_intersectRange(t,e){this.model.intersectRange(t,e)}_intersectRayWithBVH(t,e,n){this._ensureBVH(),n?this._intersectGeometryWithBVHVerticalRay(t):this._intersectGeometryWithBVHGeneralRay(t,e)}_intersectGeometryWithBVHVerticalRay(t){let e=t[0],n=t[1];if(!this.localMode){const{geometryMinZ:i,planetCenterZ:s}=this,h=(i-s)/(t[2]-s);e=t[0]*h,n=t[1]*h}const{_bspNodes:i}=this;let s=0;for(;s>=0;){const t=i[s],{d:h,dim:a,minIndexIndex:o,minMidIndexIndex:r,maxMidIndexIndex:c,maxIndexIndex:m,aabb2D:l}=t;if(e<l[0]||e>l[2]||n<l[1]||n>l[3])break;if(-1===a||-1===t.child0&&-1===t.child1){this._intersectRange(o,m);break}{this._intersectRange(r,c);const i=(0===a?e:n)-h;if(i<0){if(-1===t.child0){this._intersectRange(o,r);break}s=t.child0}else{if(!(i>0))break;if(-1===t.child1){this._intersectRange(c,m);break}s=t.child1}}}}_intersectGeometryWithBVHGeneralRay(e,n){let i=e[0],s=e[1],h=n[0],a=n[1];const{geometryMinZ:o}=this;if(!this.localMode){let t=0,r=1;const c=Math.min(.5*this.planetCenterZ,o),m=e[2],l=n[2];if(m<c&&l<c)return;if(m<c&&(t=(c-m)/(l-m)),l<c&&(r=(c-m)/(l-m)),t>r)return;const d=(1-t)*e[0]+t*n[0],M=(1-t)*e[1]+t*n[1],x=(1-t)*e[2]+t*n[2],u=(1-r)*e[0]+r*n[0],p=(1-r)*e[1]+r*n[1],f=(1-r)*e[2]+r*n[2],{planetCenterZ:_}=this,g=o-_,I=g/(x-_);i=d*I,s=M*I;const B=g/(f-_);h=u*B,a=p*B}const r=h-i,c=a-s,m=this._bspNodes;let l=1;{const{aabb2D:t}=m[0],e=(t,e,n,i)=>{if(Math.abs(e)<1e-5*Math.max(i-n,1))return!1;const s=e>0,h=s?i:n,a=t+l*e;return(s?a<h:a>h)&&(l=Math.max((h-t)/e,l),!0)},n=()=>e(i,r,t[0],t[2]),h=()=>e(s,c,t[1],t[3]);Math.abs(r)>=Math.abs(c)?n()||h():h()||n()}const d=[0,0,l];let M=0;for(;M<d.length;){const e=d[M];let n=d[M+1],h=d[M+2];if(M+=3,n>h)continue;const a=m[e],{minIndexIndex:o,maxIndexIndex:x}=a,{child0:u,child1:p,minMidIndexIndex:f,maxMidIndexIndex:_,aabb2D:g,d:I,dim:B}=a;{const t=i+n*r,e=i+h*r,s=Math.min(t,e),a=Math.max(t,e),o=g[0],c=g[2];if(a<o||c<s)continue;if(s<o){const t=(o-i)/r;r>0?n=Math.max(n,t):h=Math.min(h,t)}if(c<a){const t=(c-i)/r;r>0?h=Math.min(h,t):n=Math.max(n,t)}}{const t=s+n*c,e=s+h*c,i=Math.min(t,e),a=Math.max(t,e),o=g[1],r=g[3];if(a<o||r<i)continue;if(i<o){const t=(o-s)/c;c>0?n=Math.max(n,t):h=Math.min(h,t)}if(r<a){const t=(r-s)/c;c>0?h=Math.min(h,t):n=Math.max(n,t)}}if(-1===u&&-1===p)this._intersectRange(o,x);else{const e=0===B?i:s,a=0===B?r:c,m=e+n*a,M=e+h*a,g=Math.min(m,M),b=Math.max(m,M),V=t((I-e)/a,0,l);o<f&&g<=I&&(-1!==u?(d.push(u),d.push(a>=0?n:Math.max(n,V)),d.push(a>=0?Math.min(h,V):h)):this._intersectRange(o,f)),this._intersectRange(f,_),_<x&&I<=b&&(-1!==p?(d.push(p),d.push(a>=0?Math.max(n,V):n),d.push(a>=0?h:Math.min(h,V))):this._intersectRange(_,x))}}}_generateBsp(){const{elementCount:t}=this;if(t<1)return;const e=n(t,t);this._elementIndexMap=e;for(let n=0;n<t;++n)e[n]=n;const i=this.model.getAabbs2D();let o=0;const m=this._bspNodes;m.length=0;const{localMode:l}=this;let d=!1;if(!l){const{planetCenterZ:t,geometryMinZ:e}=this;d=t>=0||e<.5*t}const M=[],x=(t,e,n,i,s)=>{M.push(t),M.push(e),M.push(n),M.push(i<0?-1:(s?0:1)+2*i)},{maxBspNodeDepth:u,minBspNodeElementCount:p}=this,f=(t,n,o,M,f)=>{const _=m.length;if(_>0&&(d||o>=u||n-t<p))return;const g=[0,0,0,0];r(g,t,n,e,i);const{d:I,dim:B}=l?s(g):h(g),{rangeMidStart:b,rangeMidEnd:V}=a(t,n,B,I,e,i),C=o===u-1,H=!C&&b>=t+p,R=!C&&n>=V+p;if(H||R||0===_){const e=new c(t,b,V,n,B,I,g);if(H&&x(t,b,o+1,_,!0),R&&x(V,n,o+1,_,!1),m.push(e),-1!==M){const t=m[M];f?t.child0=_:t.child1=_}}};for(x(0,t,0,-1,!1);o<M.length;){const t=M[o],e=M[o+1],n=M[o+2],i=M[o+3];o+=4;const s=i>>1;f(t,e,n,s,i-(s<<1)==0)}this._generatedBVH=!0}}function s(t){const e=t[0],n=t[1],i=t[2],s=t[3];let h,a;return i-e>=s-n?(a=.5*(e+i),h=0):(a=.5*(n+s),h=1),{d:a,dim:h}}function h(t){const e=t[0],n=t[1],i=t[2],s=t[3];let h,a;return i-e>=s-n?(h=0,a=.5*(e+i)):(h=1,a=.5*(n+s)),{dim:h,d:a}}function a(t,e,n,i,s,h){let a=t;{let t=e;for(;a<t;){const e=s[a];o(e,n,i,h)<0?++a:(--t,s[a]=s[t],s[t]=e)}}const r=a;let c=a,m=e;for(;c<m;){const t=s[m-1];o(t,n,i,h)>0?--m:(s[m-1]=s[c],s[c]=t,++c)}return{rangeMidStart:r,rangeMidEnd:m}}function o(t,e,n,i){const s=4*t,h=i[s+0+e];return i[s+2+e]<n?-1:h>n?1:0}function r(t,e,n,i,s){let h=1/0,a=1/0,o=-1/0,r=-1/0;for(let c=e;c<n;++c){const t=4*i[c];h=Math.min(h,s[t+0]),a=Math.min(a,s[t+1]),o=Math.max(o,s[t+2]),r=Math.max(r,s[t+3])}t[0]=h,t[1]=a,t[2]=o,t[3]=r}class c{constructor(t,e,n,i,s,h,a){this.minIndexIndex=t,this.minMidIndexIndex=e,this.maxMidIndexIndex=n,this.maxIndexIndex=i,this.dim=s,this.d=h,this.aabb2D=a,this.child0=-1,this.child1=-1}}export{i as ElevationAgnosticBVH};