@arcgis/core
Version:
ArcGIS Maps SDK for JavaScript: A complete 2D and 3D mapping and data visualization API
6 lines (5 loc) • 14 kB
JavaScript
/*
All material copyright ESRI, All Rights Reserved, unless otherwise specified.
See https://js.arcgis.com/4.33/esri/copyright.txt for details.
*/
import{equals as e}from"../../../core/arrayUtils.js";import"../../../core/has.js";import{isPowerOfTwo as t}from"../../../core/mathUtils.js";import{disposeMaybe as r,releaseMaybe as i}from"../../../core/maybe.js";import{j as s,F as o,H as a,d as n,n as l,e as d,a as g,G as h}from"../../../chunks/vec32.js";import{create as m,clone as u}from"../../../core/libs/gl-matrix-2/factories/vec3f64.js";import{containsXY as c}from"../../../geometry/support/aaBoundingRect.js";import{earth as f}from"../../../geometry/support/Ellipsoid.js";import{glLayout as p}from"../support/buffer/glUtil.js";import{GeometryState as y}from"./GeometryState.js";import{TextureUpdate as x}from"./interfaces.js";import{LayerClass as _}from"./LayerClass.js";import{NeighborIndex as v}from"./NeighborIndex.js";import{PatchGeometry as E}from"./PatchGeometry.js";import{maxTileNeighborLevelDelta as $}from"./TerrainConst.js";import{internalAssert as S,neighborEdgeIndices as C,oppositeEdge as D,neighborCornerIndices as b,enableTerrainInternalChecks as T,v32s as j,lij2s as R}from"./terrainUtils.js";import{TextureFader as A,ActivationTime as V}from"./TextureFader.js";import{TextureReference as w}from"./TextureReference.js";import N from"./TileOverlayData.js";import{fallsWithinLayerView as F}from"./tileUtils.js";import{VertexArrayObject as P}from"../webgl-engine/lib/VertexArrayObject.js";import{vertexAttributeLocations as G}from"../webgl-engine/shaders/TerrainTechnique.js";import{BufferObject as O}from"../../webgl/BufferObject.js";import{PixelFormat as I}from"../../webgl/enums.js";class M{constructor(){this.geometry=new E,this.intersectionData=null,this.geometryState=null,this._vao=null,this._texture=null,this._textureOpacity=1,this._textureRef=new A((()=>this._tile.surface.fadeDuration)),this.overlay=new N,this._localOrigin=null,this._geometryStateChangedSinceLastUpdate=!0,this._hasGeometry=!1,this._modifiedFlags=0}get tile(){return this._tile}get localOrigin(){return this._localOrigin}init(e,t){this.clear(),this._tile=e,this.geometry.reset(),this.intersectionData=null,this.geometryState=new y,this._localOrigin=t,this.overlay.clear()}clear(){this.releaseGeometry(),this.releaseTexture(),this._textureRef.clear(),this._tile=null,this.intersectionData=null,this.geometryState=null}updateGeometryIfNeeded(e){if((!this._vao||this._geometryStateChangedSinceLastUpdate||this.wireframeChanged||this.clippingAreaChanged||this.samplerDataChanged||this.numVerticesPerSideChanged||this.dirtyCorners||this.dirtyEdgeResolutions||this.dirtyEdges)&&(this._updateGeometry(e),this._geometryStateChangedSinceLastUpdate=!1),T&&this.tile.intersectsClippingArea)for(let t=0;t<4;++t)S(this.geometry.getEdgeCount(t)===this.geometryState.edgeResolutions[t]+1)}_calculateEdgeResolution(e,t){const r=this.tile,i=this.geometryState.numVerticesPerSide-1;if(!r.surface.isGlobal){const t=r.surface.extent;if(null!=t&&(0===e&&r.extent[3]>t[3]||1===e&&r.extent[2]>t[2]||2===e&&r.extent[1]<t[1]||3===e&&r.extent[0]<t[0]))return i}const s=r.level,o=C[e];if(!t)return S(null==r.surface?.rootTiles||r.surface.updatingRootTiles||!r.shouldHaveNeighbor(o)),i;if(t.loaded){const r=t,o=r.renderData.geometryState,a=s-r.level;if(S(a>=0),0===a){const e=o.numVerticesPerSide-1;return Math.max(e,i)}const n=2**a,l=o.edgeResolutions[(e+2)%4]/n;return Math.max(1,l)}S(!t.leaf);let a=i;return t.forAllSubtreeOnSide(D(o),(e=>e===r||(e.loaded?(a=Math.max(a,2**(e.level-s)),!0):(S(!e.leaf),!1)))),a}updateNeighborData(){const e=this.tile;if(!e.intersectsClippingArea)return;const r=e.renderData.geometryState,i=t=>(t.loaded||t.level===e.level)&&t?.intersectsClippingArea,s=r.edgePeerNeighbors,o=r.edgePeerNeighborSamplerVersions;for(let a=0;a<4;++a){const n=e.findNeighborTile(C[a],i),l=z(e,n),d=l?.renderData?.geometryState.samplerDataVersion??-1,g=s[a],h=l!==z(e,g),m=o[a]!==d;T&&n&&(S(e.level>=n.level),S(e.level-n.level<=$)),s[a]=n,(h||m)&&(o[a]=d,this._markEdgeDirty(a));const u=r.edgeResolutions[a],c=this._calculateEdgeResolution(a,n);S(t(c)),S(c>=1),r.edgeResolutions[a]=c,u!==c&&this._markEdgeResolutionDirty(a)}for(let t=0;t<4;++t){const o=e.findNeighborTile(b[t],i);r.cornerPeerNeighbors[t]=o;const a=z(e,s[t]),n=z(e,s[(t+1)%4]),l=z(e,o);q[t]=l,q[(t+1)%4]=n,q[(t+2)%4]=e,q[(t+3)%4]=a,S(q.some((t=>t?.loaded||t===e)));const d=q.reduce(((e,t)=>Math.min(e,t?.level??1/0)),1/0);q.forEach(((e,t)=>{e&&e?.level>d&&(q[t]=null)})),S(q.some((t=>t?.loaded||t===e)));const g=r.cornerNeighborCornerTiles,h=r.cornerNeighborCornerTileSamplerVersions;for(let e=0;e<4;++e){const r=q[e],i=r?.renderData.geometryState.samplerDataVersion??-1,s=4*t+e,o=g[s]!==r,a=!o&&h[s]!==i;(o||a)&&(g[s]=r,h[s]=i,this._markCornerDirty(t))}T&&S(re.some((r=>g[4*t+r]?.loaded||g[4*t+r]===e)))}T&&S(this.geometryState.edgeResolutions.every((e=>e>0)));for(let t=0;t<4;++t)q[t]=null}_updateGeometry(e){if(!this.tile.intersectsClippingArea)return;T&&S(!this.tile.intersectsClippingArea||this.geometryState.edgeResolutions.every((e=>e>0))),this.intersectionData=null;const{tile:t,_vao:r,geometry:i,geometryState:s}=this,o=!r||!{}||this.wireframeChanged||this.samplerDataChanged||this.clippingAreaChanged||this.numVerticesPerSideChanged,a=0!==this.dirtyEdgeResolutions,n=s.edgeResolutions.reduce(((e,t)=>e+t+1),0),l=o||a&&n>(i?.maxEdgeVertexCount??0),d=!l&&a,g=!d&&(0!==this.dirtyEdges||a),h=!g&&0!==this.dirtyCorners;l?(this.releaseGeometry(),this._createGeometry(e)):d?t.updateEdgeElevationsAndResolutions():g||h?t.updateEdgeElevations():h?t.updateCornerElevations():console.warn("Update for no reason?"),this._modifiedFlags=0}get hasGeometry(){return this._hasGeometry}releaseGeometry(){return this._hasGeometry=!1,this.intersectionData=null,!!this._vao&&(this._vao=r(this._vao),this.geometry.release(),!0)}ensureTexture(e,t,r,i){const s=t?I.RGBA:I.RGB;return null!=this._texture&&(r===x.FADING&&this._tile.surface.fadeDuration>0&&this._isTextureVisible(this._texture)||this._texture.descriptor.width!==e||this._texture.descriptor.pixelFormat!==s)&&this.releaseTexture(),null==this._texture&&(this._texture=i(),this.tile.setMemoryDirty()),this._texture}releaseTexture(){this._texture&&(this._texture=i(this._texture),this.tile.setMemoryDirty())}reuseTexture(e,t){return!(!e||!this._texture)&&(e.setTextureReference(new w(this._texture,x.FADING,t,this._textureOpacity,0,1)),!0)}get numVerticesPerSideChanged(){return 0!==(this._modifiedFlags&J)}get samplerDataChanged(){return 0!==(this._modifiedFlags&K)}get clippingAreaChanged(){return 0!==(this._modifiedFlags&Q)}get wireframeChanged(){return 0!==(this._modifiedFlags&Y)}get dirtyEdges(){return this._modifiedFlags>>Z&15}get dirtyCorners(){return this._modifiedFlags>>ee&15}get dirtyEdgeResolutions(){return this._modifiedFlags>>te&15}_markCornerDirty(e){const t=1<<e<<ee;this._modifiedFlags|=t}_markEdgeDirty(e){const t=1<<e<<Z;this._modifiedFlags|=t,this._markCornerDirty((e+0)%4),this._markCornerDirty((e+3)%4)}_markEdgeResolutionDirty(e){const t=1<<e<<te;this._modifiedFlags|=t,this._markEdgeDirty(e)}_markAllEdgesAndCornersDirty(){this._modifiedFlags|=15<<ee|15<<Z|15<<te}updateGeometryState(){const t=this._elevationInfo,r=this.tile,i=t.samplerData?r.getElevationVerticesPerSide(t.maxTileLevel):r.minimumVerticesPerSide,s=Math.max(i,5);let o=r.clippingArea;r.intersectsClippingArea&&!r.withinClippingArea||(o=null);const a=this.geometryState;let n=!1;a.numVerticesPerSide!==s&&(this._modifiedFlags|=1,a.numVerticesPerSide=s,a.samplerDataVersion++,n=!0),t.changed&&(this._modifiedFlags|=2,a.samplerData=t.samplerData,a.samplerDataVersion++,n=!0),e(a.clippingArea,o)||(this._modifiedFlags=4,a.clippingArea=o,n=!0);const l=r.surface.wireframe;return a.wireframe!==l&&(this._modifiedFlags=8,a.wireframe=l,n=!0),this._geometryStateChangedSinceLastUpdate||=n,n&&this._markAllEdgesAndCornersDirty(),this._hasGeometry=!0,this._geometryStateChangedSinceLastUpdate}_createGeometry(e){this.tile.createGeometry();const t=this.geometry.vertexAttributes,r=this.geometry.indices,i=e.gl;this._vao=new P(e,G,new Map([["geometry",p(t.layout)]]),new Map([["geometry",O.createVertex(e,i.STATIC_DRAW,t.buffer)]]),O.createIndex(e,i.STATIC_DRAW,r)),this._hasGeometry=!0}get vao(){return this._vao}setTextureReference(e,t=V.Immediate){e?.texture===this._texture?this._textureOpacity=e.opacities[0]:this.releaseTexture(),this._textureRef.push(e,t)}get textureReference(){return this._textureRef.current}get nextTextureReference(){return this._textureRef.next}get textureFadeFactor(){return this._textureRef.fadeFactor}get textureIsFading(){return this._textureRef.isFading}_isTextureVisible(e){return this._textureRef.current?.texture===e||this._textureRef.next?.texture===e&&this._textureRef.fadeFactor<1}get _elevationInfo(){const e=this.geometryState.samplerData,t=this.tile.layerInfo[_.ELEVATION],r=t.length,i=new Array(r);let s=0,o=0,a=!1;for(let d=0;d<r;d++){const r=t[d],n=r.upsampleInfo?.tile;if(n){const t=n.layerInfo[_.ELEVATION][d].data,r=t&&t.samplerData;e&&e[s]===r||(a=!0),i[s++]=r,o=Math.max(o,n.lij[0])}else if(r.data){const t=this.tile.surface.layerViewByIndex(d,_.ELEVATION);if(F(this.tile,t)){const t=r.data;e&&e[s]===t.samplerData||(a=!0),i[s++]=t.samplerData,o=this.tile.level}}}null!=e&&e.length!==s&&(a=!0);const n=s>0,l=n?i:null;return n&&(i.length=s),{changed:a,samplerData:l,maxTileLevel:o}}get estimatedGeometryMemoryUsage(){const e=this.intersectionData?.estimatedMemoryUsage??0;return(this.geometry.indices?.byteLength??0)+(this.geometry.vertexAttributes?.byteLength??0)+e}get texture(){return this._texture}get test(){}checkGeometryWaterproofness(){if(!T)return;const e=this.tile;if(!e.loaded||!e.intersectsClippingArea||0===e.level)return void S(e?.loaded);const r=e.surface.extent;if(null!=r&&!e.intersectsExtent(r))return;const i=C.map(((t,i)=>null!=r&&(i<2?-1:1)*(e.extent[3-i]-r[3-i])<0)),p=e.level;S(0===this.dirtyCorners),S(0===this.dirtyEdges),S(0===this.dirtyEdgeResolutions),S(!this.numVerticesPerSideChanged),S(!this.samplerDataChanged),S(!this.clippingAreaChanged),S(!this.wireframeChanged);const y=b.map((t=>e.findNeighborCornerTileExact(t,(t=>!t.intersectsClippingArea||t.loaded||t.level===e.level))??null)).map((e=>e?.intersectsClippingArea?e:null)),x=this.geometryState;for(let t=0;t<4;++t){const r=x.cornerPeerNeighbors[t],i=y[t];S(i===r,`Tile[${e.lij}].corner[${t}] out of date: cur=[${r?.lij}] exp=[${i?.lij}]`)}C.forEach(((r,y)=>{if(i[y])return;const x=e.findNeighborTile(r,(e=>(e.level===p||e?.loaded)&&e?.intersectsClippingArea));if(!x){const t=!e.surface.updatingRootTiles&&null!=e.surface.rootTiles&&e.surface.rootTiles.length>0&&e.shouldHaveNeighbor(r);return void S(!t)}S(x.loaded||x.level===e.level),S(x===this.geometryState.edgePeerNeighbors[y]);const _=p-x.level;if(!x.loaded)return S(!x.leaf),void S(0===_);const E=x.renderData;S(e.isEdgeNeighbor(x,r)),S(_>=0);const $=2**_;if(_<0)return void S(!1);const C=e.renderData,D=C.geometry,b=C.localOrigin,T=D.getEdgeCount(y),A=D.numVerticesPerSide-1,V=E.geometry;if(!V)return void S(!1);const w=E.localOrigin,N=this.geometryState.edgePeerNeighbors[y];if(N?.loaded){const e=N.renderData;S(C.geometryState.edgePeerNeighborSamplerVersions[y]===e.geometryState.samplerDataVersion),S(this.geometryState.edgePeerNeighborSamplerVersions[y]===e.geometryState.samplerDataVersion)}const F=(y+2)%4,P=V.getEdgeCount(F),G=T-1,O=P-1;S(G*$===O,`Tile[${e.lij}]:e${y},res=${G} edgeRes mismatch with Neighbor[${x.lij}]:e${F},res=${O} (expected:${G*$})`);const I=e.extent,M=r===v.NORTH||r===v.SOUTH,q=P-1,z=q>>_,J=T-1;if(z<1)return void S(1===J);S(z===J),S(t(z));const K=V.numVerticesPerSide-1;S(_>0||z===Math.max(K,A));const Q=e.getNeighborEdgeStartVertexIndex(y,x);S(0<=Q&&Q<$);const Y=Q*z;S(0<=Y&&Y<=q-z);let Z=0,ee=Y;D.getEdgeVertexPosition(y,U,b,0),D.getEdgeVertexPosition(y,k,b,T-1);const te=s(U,k),re=Math.max(W,1e-4*te);for(let t=0;t<=z;++t){D.getEdgeVertexPosition(y,U,b,Z),V.getEdgeVertexPosition(F,k,w,ee);const i=t/z,s=M?I[0]+i*(I[2]-I[0]):r===v.WEST?I[0]:I[2],p=M?r===v.SOUTH?I[1]:I[3]:I[1]+i*(I[3]-I[1]),_=e.surface.extent;if(null==_||c(_,s,p)){const t=o(U,k),r=a(U)-f.radius,i=a(k)-f.radius,c=t<re;if(!c){console.warn(`Tile edge vertex position mismatch: between [${e.lij}].edge${y}[${Z}/${T}] and [${x.lij}].edge${F}[${ee}/${P}]`),null!=_&&console.warn(" surface extent= ",_," x,y=",s,",",p);const o=m();n(o,C.localOrigin,E.localOrigin),a(o)>0&&console.warn(` localOrigins: ${C.localOrigin} vs ${E.localOrigin} d=${a(o)} [${o}]`);(()=>{const t=u(U),r=u(k);e.updateEdgeElevations(),x.updateEdgeElevations(),D.getEdgeVertexPosition(y,U,b,Z),V.getEdgeVertexPosition(F,k,w,ee);const i=m();g(i,U,t),a(i)>0&&console.warn(` XXX Tile[${e.lij}] edge out of date: ${t} vs ${U} d=${a(i)} [${i}]`),g(i,k,r),a(i)>0&&console.warn(` XXX Neighbor[${x.lij}] edge out of date: ${r} vs ${k} d=${a(i)} [${i}]`)})();const l=D.getEdgeCount(y),d=V.getEdgeCount(P);S(c,`Mismatch in tile [${e.lij}].edge[${y}][${Z}/${l}] vs neighbor [${x.lij}].edge[${F}][${ee}/${d}] ${j(U)} vs ${j(k)} dist=${t} h(t|n|d)=${r}|${i}|${i-r}`)}D.getEdgeNormal(y,L,Z),V.getEdgeNormal(F,H,ee),l(X,L),l(B,H);const v=d(X,B),$=1-v<.01||!1||e===x;if(!$){const t=m();g(t,L,H);const r=()=>`Mismatch in tile edge normal ${R(e.lij)} (${Z}/${T-1}) edge ${y} vs neighbor ${R(x.lij)} (${ee}/${P-1}) nedge ${F} :${j(L)} vs ${j(H)} dot = ${v} : ${j(t)}`;console.warn("Mismatch in tile edge normal: ",r());{e.updateEdgeElevations(),x.updateEdgeElevations();const t=m(),r=m();D.getEdgeNormal(y,t,Z),V.getEdgeNormal(F,r,ee),h(L,t)||console.warn("Missing update in tile normal: ",j(L)," => ",j(t)),h(H,r)||console.warn("Missing update in neighbor normal: ",j(H)," => ",j(r))}S($,r())}}Z+=1,ee+=1}}))}}const U=m(),k=m(),L=m(),H=m(),X=m(),B=m(),W=1,q=[null,null,null,null];function z(e,t){return t?.loaded||t===e?t:null}const J=1,K=2,Q=4,Y=8,Z=4,ee=8,te=12,re=[0,1,2,3];export{M as PatchRenderData,z as neighborTileIfLoadedOrSelf,re as zeroToFour};