@arcgis/core
Version:
ArcGIS Maps SDK for JavaScript: A complete 2D and 3D mapping and data visualization API
3 lines (2 loc) • 5.74 kB
JavaScript
/* COPYRIGHT Esri - https://js.arcgis.com/5.0.19/LICENSE.txt */
import{clamp as t}from"../../../../../core/mathUtils.js";import{fromValues as e}from"../../../../../core/libs/gl-matrix-2/factories/vec3f64.js";import{create as n}from"../../../../../geometry/support/aaBoundingRect.js";import{createUintArray as i}from"../../lib/triangleIntersectionUtils.js";class s{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:d}=t;if(e<d[0]||e>d[2]||n<d[1]||n>d[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],d=n[2];if(m<c&&d<c)return;if(m<c&&(t=(c-m)/(d-m)),d<c&&(r=(c-m)/(d-m)),t>r)return;const l=(1-t)*e[0]+t*n[0],M=(1-t)*e[1]+t*n[1],u=(1-t)*e[2]+t*n[2],x=(1-r)*e[0]+r*n[0],p=(1-r)*e[1]+r*n[1],f=(1-r)*e[2]+r*n[2],{planetCenterZ:g}=this,_=o-g,B=_/(u-g);i=l*B,s=M*B;const I=_/(f-g);h=x*I,a=p*I}const r=h-i,c=a-s,m=this._bspNodes;let d=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+d*e;return(s?a<h:a>h)&&(d=Math.max((h-t)/e,d),!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 l=[0,0,d];let M=0;for(;M<l.length;){const e=l[M];let n=l[M+1],h=l[M+2];if(M+=3,n>h)continue;const a=m[e],{minIndexIndex:o,maxIndexIndex:u}=a,{child0:x,child1:p,minMidIndexIndex:f,maxMidIndexIndex:g,aabb2D:_,d:B,dim:I}=a;{const t=i+n*r,e=i+h*r,s=Math.min(t,e),a=Math.max(t,e),o=_[0],c=_[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=_[1],r=_[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===x&&-1===p)this._intersectRange(o,u);else{const e=0===I?i:s,a=0===I?r:c,m=e+n*a,M=e+h*a,_=Math.min(m,M),b=Math.max(m,M),V=t((B-e)/a,0,d);o<f&&_<=B&&(-1!==x?(l.push(x),l.push(a>=0?n:Math.max(n,V)),l.push(a>=0?Math.min(h,V):h)):this._intersectRange(o,f)),this._intersectRange(f,g),g<u&&B<=b&&(-1!==p?(l.push(p),l.push(a>=0?Math.max(n,V):n),l.push(a>=0?h:Math.min(h,V))):this._intersectRange(g,u))}}}_generateBsp(){const{elementCount:t}=this;if(t<1)return;const e=i(t,t);this._elementIndexMap=e;for(let n=0;n<t;++n)e[n]=n;const s=this.model.getAabbs2D();let r=0;const d=this._bspNodes;d.length=0;const{localMode:l}=this;let M=!1;if(!l){const{planetCenterZ:t,geometryMinZ:e}=this;M=t>=0||e<.5*t}const u=[],x=(t,e,n,i,s)=>{u.push(t),u.push(e),u.push(n),u.push(i<0?-1:(s?0:1)+2*i)},{maxBspNodeDepth:p,minBspNodeElementCount:f}=this,g=(t,i,r,u,g)=>{const _=d.length;if(_>0&&(M||r>=p||i-t<f))return;const B=n();c(B,t,i,e,s);const{d:I,dim:b}=l?h(B):a(B),{rangeMidStart:V,rangeMidEnd:R}=o(t,i,b,I,e,s),y=r===p-1,C=!y&&V>=t+f,H=!y&&i>=R+f;if(C||H||0===_){const e=new m(t,V,R,i,b,I,B);if(C&&x(t,V,r+1,_,!0),H&&x(R,i,r+1,_,!1),d.push(e),-1!==u){const t=d[u];g?t.child0=_:t.child1=_}}};for(x(0,t,0,-1,!1);r<u.length;){const t=u[r],e=u[r+1],n=u[r+2],i=u[r+3];r+=4;const s=i>>1;g(t,e,n,s,i-(s<<1)==0)}this._generatedBVH=!0}}function h(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 a(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 o(t,e,n,i,s,h){let a=t;{let t=e;for(;a<t;){const e=s[a];r(e,n,i,h)<0?++a:(--t,s[a]=s[t],s[t]=e)}}const o=a;let c=a,m=e;for(;c<m;){const t=s[m-1];r(t,n,i,h)>0?--m:(s[m-1]=s[c],s[c]=t,++c)}return{rangeMidStart:o,rangeMidEnd:m}}function r(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 c(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 m{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{s as ElevationAgnosticBVH};