@arcgis/core
Version:
ArcGIS Maps SDK for JavaScript: A complete 2D and 3D mapping and data visualization API
3 lines (2 loc) • 13.9 kB
JavaScript
/* COPYRIGHT Esri - https://js.arcgis.com/5.0.19/LICENSE.txt */
import{normalize as e,sub as t,dot as i,scaleAndAdd as s,set as n,equals as r,subtract as o,len as a,sqrDist as c,copy as u,scale as l,dist as d,distance as h,length as m,squaredLength as _,squaredDistance as p,add as f}from"../../../../core/libs/gl-matrix-2/math/vec3.js";import{create as v}from"../../../../core/libs/gl-matrix-2/factories/vec3f64.js";import{getReferenceEllipsoid as R}from"../../../../geometry/ellipsoidUtils.js";import{getSphericalPCPF as S}from"../../../../geometry/spatialReferenceEllipsoidUtils.js";import{projectBoundingSphere as b}from"../../../../geometry/projection/projectBoundingSphere.js";import{getProjector as g}from"../../../../geometry/projection/projectors.js";import{create as M,fromMatrix as x,intersectsSphere as I,createPoints as C}from"../../../../geometry/support/frustum.js";import{signedDistance as E,getNormal as D}from"../../../../geometry/support/plane.js";import{isPlateCarree as P}from"../../../../geometry/support/spatialReferenceUtils.js";import{Sphere as A}from"../../../../geometry/support/sphere.js";import{evaluateElevationAlignmentAtPoint as O}from"../graphics/elevationAlignmentUtils.js";import{ElevationContext as F}from"../graphics/ElevationContext.js";import{createContextWithoutExpressionSupport as V,extractExpressionInfo as j}from"../graphics/featureExpressionInfoUtils.js";import{intersectBoundingRectWithMbs as B}from"./I3SUtil.js";import{SphereCylinderLocal as w,SphereConeGlobal as L}from"./SphereCone.js";import{Obb as y,computeOffsetObb as U}from"../../support/orientedBoundingBox.js";const q=1e5;class G{get _frustumMbsCenter(){return this._frustumMbs.center}get _frustumMbsRadius(){return this._frustumMbs.radius}get _frustumPlanes(){return this._frustum}constructor(e,t,i,s,n,r,o,a,c={}){this._indexSR=e,this._renderCoordsHelper=t,this._clippingArea=n,this._elevationProvider=r,this._viewingMode=o,this._options=c,this._frustum=M(),this._frustumMbs=new A,this._viewDirection=v(),this._useFrustumCulling=!1,this._poi=v(),this._cameraPOIDirection=v(),this._elevationContext=null,this.minDistance=1/0,this.maxDistance=0,this.maxLodLevel=2,this._screenspaceErrorBias=c.screenspaceErrorBias||1,this._progressiveLoadFactor=c.progressiveLoadFactor||1,this.updateCamera(i,s);const u=this._renderCoordsHelper.spatialReference;this._renderSR=u,this._renderSRSphericalPCPF=S(u),this._isGlobalMode=u===this._renderSRSphericalPCPF,this.updateElevationInfo(a),this._isECEFOBBInLocalMode=this._indexSR.isWGS84&&(u.isWebMercator||P(u)),this._indexSREllipsoidRadius=R(this._indexSR).radius,this._indexSRSphericalPCPF=S(e),this._projectorIndexSRToIndexSRSphericalPCPF=g(this._indexSR,this._indexSRSphericalPCPF)}updateElevationInfo(e){null!=e?(this._elevationContext=F.fromElevationInfo(e),this._elevationContext.setFeatureExpressionInfoContext(V(j(e,!1)))):this._elevationContext=null}updateCamera(n,r){if(this._useFrustumCulling=r,e(this._viewDirection,n.viewForward),r){x(n.viewMatrix,n.projectionMatrix,this._frustum,z);{const e=n.eye,r=T;t(r,z[4],e);const o=.5*i(r,r)/i(this._viewDirection,r),a=this._frustumMbs,c=a.center;s(c,e,this._viewDirection,o);const u=1+o;a.radius=u}}this._screenSizeFactor=1/(n.perScreenPixelRatio/2),this._camPos=n.eye,this._updateCameraPOIDirection(),this.minDistance=1/0,this.maxDistance=0}setPointOfInterest(e){this._poi=e,this._updateCameraPOIDirection()}updateScreenSpaceErrorBias(e){const t=this._screenspaceErrorBias;return this._screenspaceErrorBias=e,t}updateClippingArea(e){this._clippingArea=e}expandElevationRange(e,t,i){if(null==this._elevationContext)return;const s=e.serviceMbsInIndexSR;if(!s)return;const n="relative-to-scene"===this._elevationContext.mode?"scene":"ground",r=this._elevationProvider;if(r.getSphereElevationRange){const e=r.getSphereElevationRange(s,this._indexSR,n);if(e)return void i.expandElevationRange(e)}const[o,a,c]=s.center,u=r.getElevation(o,a,c,this._indexSR,n);u&&i.expandElevationRangeValues(u,u);const l=t?null:r.getRootElevationRange?.();l&&i.expandElevationRange(l)}calculateServiceMbsInRenderSR(e){const{serviceMbsInRenderSR:t}=e;if(t.isValid)return t;const{serviceMbsInIndexSR:i}=e;if(!i?.isValid)return t;const s=ie;return b(i,this._indexSR,s,this._renderSR),e.updateServiceMbsInRenderSR(s)}calculateServiceMbsInRenderSRElevationAdjusted(e){const{serviceMbsInRenderSRElevationAdjusted:t}=e;if(t.isValid)return t;const{serviceMbsInIndexSR:i}=e,s=this.calculateServiceMbsInRenderSR(e);if(!s.isValid||!i?.isValid)return t;const n=ie;n.copyFrom(s);const{_elevationContext:r}=this;if(r){const{minElevation:t}=e,{_renderCoordsHelper:s}=this,o=i.center;let a=0;if(Number.isFinite(t)){let i=0,c=0;const{maxElevation:u}=e,l=o[2];switch(r.mode){case"relative-to-ground":case"relative-to-scene":i=r.geometryZWithOffset(l,s)+t-l,c=u-t;break;case"on-the-ground":i=t-l,c=u-t}a=i+.5*c,n.radius+=.5*c}else n.radius<q&&(a=O(o,this._elevationProvider,r,s)-o[2]);a&&ae(n,a,this._viewingMode)}return e.updateServiceMbsInRenderSRElevationAdjusted(n)}calculateMbsConeInRenderSR(e){const{mbsConeInRenderSR:t}=e;if(t)return t;if(!e.elevationRangeValid)return null;const{minElevation:i,maxElevation:s}=e;if(!(Number.isFinite(i)&&i<s))return null;const n=this.calculateServiceMbsInRenderSR(e);if(!n.isValid)return null;const r=this._renderCoordsHelper.referenceEllipsoid.radius,o=2===this._viewingMode?new w(n,i,s):new L(n,r+i,r+s);return e.updateMbsConeInRenderSR(o)}getAndUpdateVisibilityObbInRenderSR(e){{const t=e.visibilityObbInRenderSR;if(t)return t}const t=.01*this._indexSREllipsoidRadius,{serviceMbsInIndexSR:i,serviceObbInIndexSR:s}=e;if(null==s||!i||!s.isValid||this._isECEFOBBInLocalMode&&(s.halfSizeX>t||s.halfSizeY>t||s.halfSizeZ>t))return null;{let t=e.serviceObbInRenderSR;if(null==t)t=new y,e.serviceObbInRenderSR=t;else if(t.isValid)return t;const r=i.radius;let o=0,a=0;const c=s.centerZ,u=this._renderCoordsHelper,l=this._elevationContext;if(l&&e.elevationRangeValid){const{minElevation:t,maxElevation:i}=e;switch(l.mode){case"relative-to-ground":case"relative-to-scene":o=l.geometryZWithOffset(c,u)+t-c,a=i-t;break;case"on-the-ground":o=t-c,a=i-t}}else if(l&&r<q){const e=n(Y,s.centerX,s.centerY,c);o=O(e,this._elevationProvider,l,u)-c}const d=a>0,h=d?X:t;return s.transform(h,this._indexSR,this._renderSR,o,this._renderSRSphericalPCPF,this._indexSRSphericalPCPF,this._projectorIndexSRToIndexSRSphericalPCPF),d&&U(h,0,a,this._viewingMode,t),t}}getNodeObbInRenderSRIndependentOfElevationOffset(e){{const t=e.visibilityObbInRenderSR??e.serviceObbInRenderSR??null;if(t?.isValid)return t}const t=e.serviceObbInIndexSR;if(!t)return null;const i=.2;return 2===this._viewingMode&&Math.max(...t.halfSize)>i*this._indexSREllipsoidRadius?null:(t.transform(X,this._indexSR,this._renderSR,void 0,this._renderSRSphericalPCPF,this._indexSRSphericalPCPF,this._projectorIndexSRToIndexSRSphericalPCPF),X)}ensureElevationAgnosticBoundingVolume(e){return!e.elevationAgnosticBoundingVolume.valid&&e.level>0&&(1===this._viewingMode?this._updateElevationAgnosticBoundingVolumeGlobal(e):this._updateElevationAgnosticBoundingVolumeLocal(e)),e.elevationAgnosticBoundingVolume}_updateCameraPOIDirection(){r(this._poi,this._camPos)?this._cameraPOIDirection=this._viewDirection:(o(this._cameraPOIDirection,this._camPos,this._poi),e(this._cameraPOIDirection,this._cameraPOIDirection))}_updateElevationAgnosticBoundingVolumeGlobal(t){const s=this.getNodeObbInRenderSRIndependentOfElevationOffset(t),n=t.elevationAgnosticBoundingVolume;let r,o=-1;if(s){const t=Y;s.getCenter(t),e(t,t),r=t,s.getCorners(J);for(const s of J){e(s,s);const r=i(s,t);if(r<=0)return void n.invalidate();const a=Math.sqrt(Math.max(0,1-r*r));o=Math.max(o,a)}}else{const i=t.serviceMbsInRenderSR;if(!i.isValid)return void n.invalidate();const{center:s,radius:c}=i,u=a(s);if(u<c)return void n.invalidate();o=c/u,r=e(te,s)}n.set(r,o+ce)}_updateElevationAgnosticBoundingVolumeLocal(e){const t=e.elevationAgnosticBoundingVolume,i=this.getNodeObbInRenderSRIndependentOfElevationOffset(e);if(i){const e=i.getCenter(Y);e[2]=0;let s=0;const n=K;i.getCorners(J);for(const t of J){t[2]=0;const e=c(n,t);s=Math.max(s,e)}t.set(e,Math.sqrt(s))}else{const i=e.serviceMbsInRenderSR;if(i.isValid){const e=u(Y,i.center);e[2]=0,t.set(e,i.radius)}}}isNodeVisible(e){if(!this._isMBSinClippingArea(this.calculateServiceMbsInRenderSR(e)))return!1;if(!this._useFrustumCulling)return!0;const t=this.getAndUpdateVisibilityObbInRenderSR(e);return t?t.intersectsFrustumConservativeApproximation(this._frustum):I(this._frustum,this.calculateServiceMbsInRenderSRElevationAdjusted(e))}isElevationAgnosticBoundingVolumeVisible(e){return!this._useFrustumCulling||(!e.valid||(1===this._viewingMode?this._isConeVisibleInFrustum(e):this._isCylinderVisibleInFrustum(e)))}_isConeVisibleInFrustum(n){if(!this._isConeVisibleInFrustumMbs(n)||!n.valid)return!1;const r=n.radius;if(r>.9)return!0;const o=this._frustumPlanes,a=this._frustumMbsCenter,c=n.getAxis(te),u=i(c,a),d=this._frustumMbsRadius,h=u-d,m=u+d;if(h<=0)return!0;const _=l(k,c,h),p=l(H,c,m),f=r/Math.sqrt(1-r*r);for(const v of o){const n=D(v),r=e(Z,n),o=i(r,c);if(Math.abs(1-o)<.01)continue;const a=Q;l(a,c,o),t(a,a,r),e(a,a);const u=$;s(u,_,a,h*f);if(E(v,u)<=0)continue;s(u,p,a,m*f);if(E(v,u)<=0)continue;return!1}return!0}_isConeVisibleInFrustumMbs(e){const t=e.radius;if(t>.9)return!0;const s=this._frustumMbsRadius,n=this._frustumMbsCenter,r=a(n);if(r<=s)return!0;const o=e.getAxis(te),c=i(o,n);{const e=l(W,o,c);if(d(e,n)<s)return!0}const u=c/r;if(c<=0){return-u<s}const h=Math.sqrt(1-u*u);if(h<t)return!0;const m=s/r;return h*Math.sqrt(1-m*m)-m*u<t}isObbVisibleIndependentOfElevation(e,t){if(!this._useFrustumCulling)return!0;if(!e.valid)return!0;const s=this._frustumMbsRadius,n=this._frustumMbsCenter,r=this._frustumPlanes,o=J;if(t.getCorners(o),1===this._viewingMode){const t=e.getAxis(te),a=i(t,n),c=a-s,u=a+s;if(c<=0)return!0;for(const e of r){let s=!0;for(const n of o){const r=i(n,t),o=ee;if(l(o,n,c/r),E(e,o)<=0){s=!1;break}const a=ee;if(l(a,n,u/r),E(e,a)<=0){s=!1;break}}if(s)return!1}}else{const e=n[2]-s,t=n[2]+s;for(const i of r){let s=!0;const n=D(i),r=n[0],a=n[1],c=n[2],u=i[3];for(const i of o){const n=r*i[0]+a*i[1]+u;if(n+c*e<=0||n+c*t<=0){s=!1;break}}if(s)return!1}}return!0}_isCylinderVisibleInFrustum(e){const t=this._frustumMbsCenter,i=this._frustumMbsRadius,s=u(W,t);s[2]=0;const n=e.radius,r=e.getAxis(te);return d(s,r)<=n+i}isGeometryVisible(e){if(!this._useFrustumCulling)return!0;const t=e.geometryObbInRenderSR;return t?.intersectsFrustumConservativeApproximation(this._frustum)??this.isNodeVisible(e)}_isMBSinClippingArea(e){return null==this._clippingArea||0!==B(this._clippingArea,e)}_screenSpaceDiameterMbs(e,t){const i=this.calcCameraDistanceAndUpdateMinmaxWithCone(e);return i<0?.5*Number.MAX_VALUE:t/i*this._screenSizeFactor}calcCameraDistanceAndUpdateMinmaxWithCone(e){const t=this.calculateMbsConeInRenderSR(e),i=t?.calculateSurfaceDistanceFromPoint(this._camPos)??this.calcCameraDistanceAndUpdateMinmax(e);return t&&this._updateMinMaxDistance(i),i}calcCameraDistanceAndUpdateMinmax(e){return this.calcCameraDistanceToCenterAndUpdateMinmax(e)-this.calculateServiceMbsInRenderSRElevationAdjusted(e).radius}calcCameraDistanceToCenterAndUpdateMinmax(e){const t=this.calculateServiceMbsInRenderSRElevationAdjusted(e),i=h(t.center,this._camPos);return this._updateMinMaxDistance(i),i}calcAngleDependentLoD(e){const{center:s,radius:n}=this.calculateServiceMbsInRenderSRElevationAdjusted(e),r=t(K,s,this._camPos),o=(Math.abs(i(s,r))/m(s)+n)/m(r);return Math.min(1,o)}hasLOD(e){return 0!==e.lodMetric}_getDistanceGlobeMode(e,t){const s=m(t.center),n=m(e)-s;l(se,e,i(e,t.center)/_(e));const r=p(t.center,se),a=t.radius;if(r<=a*a)return Math.abs(n);{const r=l(se,t.center,1/s),c=l(ne,r,s-a*a/2/s),u=e,d=o(re,u,c),_=o(re,d,l(oe,r,i(r,d))),p=f(re,c,l(re,_,a/m(_)));let v=h(u,p);if(n>=2e5){const e=o(ne,u,p);let t=i(e,r)/m(e);t<.08&&(t=1e-4),v/=t}return v}}_getDistance(e,t){return this._isGlobalMode?this._getDistanceGlobeMode(e,t):N(e,t)}_updateMinMaxDistance(e){e>0?(this.minDistance=Math.min(this.minDistance,e),this.maxDistance=Math.max(this.maxDistance,e)):(this.minDistance=0,this.maxDistance=Math.max(this.maxDistance,-e))}getLodLevel(e){if(0===e.lodMetric)return 0;if(0===e.childCount)return this.maxLodLevel;if(this._useFrustumCulling&&this._progressiveLoadFactor<1){const t=this._progressiveLoadFactor*this._screenspaceErrorBias,i=this._screenspaceErrorBias;return this.evaluateLODmetric(e,t)?this.evaluateLODmetric(e,i)?2:1:0}return this.evaluateLODmetric(e,this._screenspaceErrorBias)?this.maxLodLevel:0}evaluateLODmetric(e,t){switch(e.lodMetric){case 1:{let i=this._screenSpaceDiameterMbs(e,(e.serviceMbsInIndexSR?.radius??0)*t);return this._options.angleDependentLoD&&(i*=this.calcAngleDependentLoD(e)),i<e.maxError}case 2:{const i=this.calculateServiceMbsInRenderSRElevationAdjusted(e),s=this._getDistance(this._camPos,i),n=2*s/this._screenSizeFactor,r=s+i.radius;return this._updateMinMaxDistance(r),e.maxError*t<=n}case 3:return this._screenSpaceDiameterMbs(e,e.maxError)*t<10;case 4:return this.calcCameraDistanceAndUpdateMinmax(e)>e.maxError*t}return!1}distToCameraPOIRay(e){if(null==e)return 0;const t=this.calculateServiceMbsInRenderSRElevationAdjusted(e),s=t.center,n=i(s,this._cameraPOIDirection),r=n*n,o=_(s)-r;return Math.sqrt(o)-t.radius}distCameraToPOI(){return h(this._camPos,this._poi)}}function N(e,t){const i=e[0]-t.center[0],s=e[1]-t.center[1],n=e[2]-t.center[2],r=i*i+s*s,o=t.radius;if(r<=o*o)return Math.abs(n);const a=Math.sqrt(r)-o;return Math.sqrt(n*n+a*a)}const z=C(),T=v(),W=v(),k=v(),H=v(),Z=v(),X=new y,Y=v(),J=[v(),v(),v(),v(),v(),v(),v(),v()],K=v(),Q=v(),$=v(),ee=v(),te=v(),ie=new A,se=v(),ne=v(),re=v(),oe=v();function ae(e,t,i){if(2===i)e.center[2]+=t;else{const i=m(e.center);l(e.center,e.center,1+t/i)}}const ce=.001;export{G as default};