12345 |
- /*
- All material copyright ESRI, All Rights Reserved, unless otherwise specified.
- See https://js.arcgis.com/4.24/esri/copyright.txt for details.
- */
- import t from"../core/CircularArray.js";import{isSome as e,mapOr as s}from"../core/maybe.js";import{decodeGeohashXY as i}from"./geohashUtils.js";import o from"../geometry/SpatialReference.js";import{convertFromPolygon as n,quantizeOptimizedGeometry as a}from"../layers/graphics/featureConversionUtils.js";import r from"../layers/graphics/OptimizedGeometry.js";import{project as l}from"../layers/graphics/data/projectionSupport.js";import{FeatureSetReaderJSON as h}from"../views/2d/layers/features/support/FeatureSetReaderJSON.js";class c{constructor(e=[],s,i=8096){this.onRelease=t=>{},this._nodes=0,this._root=new u(this,0,0,0),this._statisticFields=e,this._pool=i?new t(8096):null,this._serviceInfo=s}destroy(){this.clear()}_acquire(t,s,i){this._nodes++;let o=null;return e(this._pool)&&(o=this._pool.dequeue()),e(o)?o.realloc(t,s,i):o=new u(this,t,s,i),o}_release(t){this.onRelease(t),this._nodes--,e(this._pool)&&this._pool.enqueue(t)}get count(){return this._root.count}get size(){return this._nodes}get poolSize(){return s(this._pool,0,(t=>t.size))}get depth(){let t=0;return this.forEach((e=>t=Math.max(t,e.depth))),t}dropLevels(t){this.forEach((e=>{if(e.depth>=t)for(let t=0;t<e.children.length;t++){const s=e.children[t];s&&this._release(s)}})),this.forEach((e=>{if(e.depth>=t)for(let t=0;t<e.children.length;t++)e.children[t]=null}))}clear(){this.forEach((t=>this._release(t))),this._root=new u(this,0,0,0)}insert(t,e,s=0){const i=h.fromOptimizedFeatures([t],this._serviceInfo).getCursor();i.next();const o=i.readGeometry();if(!o)return;const[n,a]=o.coords,r=t.geohashX,l=t.geohashY;this.insertCursor(i,t.displayId,n,a,r,l,e,s)}insertCursor(t,e,s,i,o,n,a,r=0){let l=this._root,h=0,c=0,u=0;for(;null!==l;){if(l.depth>=r&&(l.count+=1,l.xTotal+=s,l.yTotal+=i,l.xGeohashTotal+=o,l.yGeohashTotal+=n,l.referenceId=e,this._updateStatisticsCursor(t,l,1)),h>=a)return void l.add(e);const d=Math.ceil((h+1)/2),f=Math.floor((h+1)/2),x=1-h%2,m=30-(3*d+2*f),p=30-(2*d+3*f),g=(o&7*x+3*(1-x)<<m)>>m,y=(n&3*x+7*(1-x)<<p)>>p,_=g+y*(8*x+4*(1-x));c=c<<3*x+2*(1-x)|g,u=u<<2*x+3*(1-x)|y,null==l.children[_]&&(l.children[_]=this._acquire(c,u,h+1)),h+=1,l=l.children[_]}}remove(t,e){const s=h.fromOptimizedFeatures([t],this._serviceInfo).getCursor();s.next();const i=s.readGeometry();if(!i)return;const[o,n]=i.coords,a=t.geohashX,r=t.geohashY;this.removeCursor(s,o,n,a,r,e)}removeCursor(t,e,s,i,o,n){let a=this._root,r=0;for(;null!==a;){if(a.count-=1,a.xTotal-=e,a.yTotal-=s,a.xGeohashTotal-=i,a.yGeohashTotal-=o,this._updateStatisticsCursor(t,a,-1),r>=n)return void a.remove(t.getDisplayId());const l=Math.ceil((r+1)/2),h=Math.floor((r+1)/2),c=1-r%2,u=30-(3*l+2*h),d=30-(2*l+3*h),f=((i&7*c+3*(1-c)<<u)>>u)+((o&3*c+7*(1-c)<<d)>>d)*(8*c+4*(1-c)),x=a.children[f];1===x.count&&(this._release(x),a.children[f]=null),r+=1,a=x}}forEach(t){let e=this._root;for(;null!==e;){const s=this._linkChildren(e)||e.next;t(e),e=s}}find(t,e,s){return this._root.find(t,e,s,0,0,0)}findIf(t){let e=null;return this.forEach((s=>{t(s)&&(e=s)})),e}findAllIf(t){const e=[];return this.forEach((s=>{t(s)&&e.push(s)})),e}findSingleOccupancyNode(t,e,s,i,o){let n=this._root;for(;null!==n;){const a=n.depth,r=n.xNode,l=n.yNode,h=1-a%2,c=n.xGeohashTotal/n.count,u=n.yGeohashTotal/n.count;if(1===n.count&&t<c&&c<=s&&e<u&&u<=i)return n;if(a>=o){n=n.next;continue}const d=Math.ceil((a+1)/2),f=Math.floor((a+1)/2),x=30-(3*d+2*f),m=30-(2*d+3*f),p=~((1<<x)-1),g=~((1<<m)-1),y=(t&p)>>x,_=(e&g)>>m,M=(s&p)>>x,N=(i&g)>>m,T=r<<3*h+2*(1-h),I=l<<2*h+3*(1-h),S=T+8*h+4*(1-h),v=I+4*h+8*(1-h),C=Math.max(T,y),b=Math.max(I,_),G=Math.min(S,M),k=Math.min(v,N);let F=null,z=null;for(let t=b;t<=k;t++)for(let e=C;e<=G;e++){const s=e-T+(t-I)*(8*h+4*(1-h)),i=n.children[s];i&&(F||(F=i,F.next=n.next),z&&(z.next=i),z=i,i.next=n.next)}n=F||n.next}return null}getRegionDisplayIds(t,e,s,i,o){let n=this._root;const a=[];for(;null!==n;){const r=n.depth,l=n.xNode,h=n.yNode;if(r>=o){const o=n.xGeohashTotal/n.count,r=n.yGeohashTotal/n.count;t<=o&&o<=s&&e<=r&&r<=i&&n.displayIds.forEach((t=>a.push(t))),n=n.next;continue}const c=Math.ceil((r+1)/2),u=Math.floor((r+1)/2),d=1-r%2,f=30-(3*c+2*u),x=30-(2*c+3*u),m=~((1<<f)-1),p=~((1<<x)-1),g=(t&m)>>f,y=(e&p)>>x,_=(s&m)>>f,M=(i&p)>>x,N=l<<3*d+2*(1-d),T=h<<2*d+3*(1-d),I=N+8*d+4*(1-d),S=T+4*d+8*(1-d),v=Math.max(N,g),C=Math.max(T,y),b=Math.min(I,_),G=Math.min(S,M);let k=null,F=null;for(let t=C;t<=G;t++)for(let e=v;e<=b;e++){const s=e-N+(t-T)*(8*d+4*(1-d)),i=n.children[s];i&&(k||(k=i,k.next=n.next),F&&(F.next=i),F=i,i.next=n.next)}n=k||n.next}return a}getRegionStatistics(t,e,s,i,o){let n=this._root,a=0,r=0,l=0;const h={};let c=0;for(;null!==n;){const u=n.depth,d=n.xNode,f=n.yNode;if(u>=o){const o=n.xGeohashTotal/n.count,u=n.yGeohashTotal/n.count;t<o&&o<=s&&e<u&&u<=i&&(a+=n.count,r+=n.xTotal,l+=n.yTotal,1===n.count&&(c=n.referenceId),this._aggregateStatistics(h,n.statistics)),n=n.next;continue}const x=Math.ceil((u+1)/2),m=Math.floor((u+1)/2),p=1-u%2,g=30-(3*x+2*m),y=30-(2*x+3*m),_=~((1<<g)-1),M=~((1<<y)-1),N=(t&_)>>g,T=(e&M)>>y,I=(s&_)>>g,S=(i&M)>>y,v=d<<3*p+2*(1-p),C=f<<2*p+3*(1-p),b=v+8*p+4*(1-p),G=C+4*p+8*(1-p),k=Math.max(v,N),F=Math.max(C,T),z=Math.min(b,I),w=Math.min(G,S);let j=null,E=null;for(let o=F;o<=w;o++)for(let u=k;u<=z;u++){const d=u-v+(o-C)*(8*p+4*(1-p)),f=n.children[d];if(f){if(o!==F&&o!==w&&u!==k&&u!==z){const o=f.xGeohashTotal/f.count,u=f.yGeohashTotal/f.count;t<o&&o<=s&&e<u&&u<=i&&(a+=f.count,r+=f.xTotal,l+=f.yTotal,1===n.count&&(c=n.referenceId),this._aggregateStatistics(h,f.statistics));continue}j||(j=f,j.next=n.next),E&&(E.next=f),E=f,f.next=n.next}}n=j||n.next}return{count:a,attributes:this.normalizeStatistics(h,a),xTotal:r,yTotal:l,referenceId:c}}getBins(t,e,s,i,o){const n=[];let a=this._root;for(;null!==a;){const r=a.depth,l=a.xNode,h=a.yNode;if(r>=o){n.push(a),a=a.next;continue}const c=Math.ceil((r+1)/2),u=Math.floor((r+1)/2),d=1-r%2,f=30-(3*c+2*u),x=30-(2*c+3*u),m=~((1<<f)-1),p=~((1<<x)-1),g=(t&m)>>f,y=(e&p)>>x,_=(s&m)>>f,M=(i&p)>>x,N=l<<3*d+2*(1-d),T=h<<2*d+3*(1-d),I=N+8*d+4*(1-d),S=T+4*d+8*(1-d),v=Math.max(N,g),C=Math.max(T,y),b=Math.min(I,_),G=Math.min(S,M);let k=null,F=null;for(let t=C;t<=G;t++)for(let e=v;e<=b;e++){const s=e-N+(t-T)*(8*d+4*(1-d)),i=a.children[s];i&&(k||(k=i,k.next=a.next),F&&(F.next=i),F=i,i.next=a.next)}a=k||a.next}return n}_linkChildren(t){let e=null,s=null;for(let i=0;i<=t.children.length;i++){const o=t.children[i];o&&(e||(e=o,e.next=t.next),s&&(s.next=o),s=o,o.next=t.next)}return e}_updateStatisticsCursor(t,e,s){for(const i of this._statisticFields){const o=i.name,n=i.inField?t.readAttribute(i.inField):t.getComputedNumericAtIndex(i.inFieldIndex);switch(i.statisticType){case"norm":{e.statistics[o]||(e.statistics[o]={});const a=i.inNormalizationField,r=t.readAttribute(a),l=e.statistics[o].onStatisticField||0,h=e.statistics[o].onStatisticNormalizationField||0;null==n||isNaN(n)||null==r||0===r||isNaN(r)||(e.statistics[o].onStatisticField=l+s*n,e.statistics[o].onStatisticNormalizationField=h+s*r);break}case"sum":case"avg":{e.statistics[o]||(e.statistics[o]={value:0,nanCount:0});const t=e.statistics[o].value,i=e.statistics[o].nanCount;null==n||isNaN(n)?e.statistics[o].nanCount=i+s:e.statistics[o].value=t+s*n;break}case"avg_angle":{e.statistics[o]||(e.statistics[o]={x:0,y:0,nanCount:0});const t=e.statistics[o].x,i=e.statistics[o].y,a=e.statistics[o].nanCount,r=Math.PI/180;null==n||isNaN(n)?e.statistics[o].nanCount=a+s:(e.statistics[o].x=t+s*Math.cos(n*r),e.statistics[o].y=i+s*Math.sin(n*r));break}case"mode":{e.statistics[o]||(e.statistics[o]={});const t=e.statistics[o][n]||0;e.statistics[o][n]=t+s;break}}}}_aggregateStatistics(t,e){for(const s of this._statisticFields){const i=s.name;switch(s.statisticType){case"sum":case"avg":case"avg_angle":case"mode":case"norm":t[i]||(t[i]={});for(const s in e[i]){const o=t[i][s]||0;t[i][s]=o+e[i][s]}}}}normalizeStatistics(t,e){const s={};for(const i of this._statisticFields){const o=i.name;switch(i.statisticType){case"norm":{const i=t[o];if(e&&null==i.onStatisticNormalizationField)break;if(e&&i.onStatisticNormalizationField){s[o]=i.onStatisticField/i.onStatisticNormalizationField;break}s[o]=0;break}case"sum":{if(!e)break;const{value:i,nanCount:n}=t[o];if(!(e-n))break;s[o]=i;break}case"avg":{if(!e)break;const{value:i,nanCount:n}=t[o];if(!(e-n))break;s[o]=i/(e-n);break}case"avg_angle":{if(!e)break;const{x:i,y:n,nanCount:a}=t[o];if(!(e-a))break;const r=i/(e-a),l=n/(e-a),h=180/Math.PI,c=Math.atan2(l,r)*h;s[o]=c;break}case"mode":{const e=t[o];let i=0,n=null;for(const t in e){const s=e[t];s>i&&(i=s,n=t)}s[o]="null"===n?null:n;break}}}return s}}class u{constructor(t,e,s,i){this.count=0,this.xTotal=0,this.yTotal=0,this.statistics={},this.displayId=0,this.referenceId=0,this.displayIds=new Set,this.next=null,this.depth=0,this.xNode=0,this.yNode=0,this.xGeohashTotal=0,this.yGeohashTotal=0,this._tree=t,this.children=new Array(32);for(let o=0;o<this.children.length;o++)this.children[o]=null;this.xNode=e,this.yNode=s,this.depth=i}realloc(t,e,s){for(let i=0;i<this.children.length;i++)this.children[i]=null;return this.xNode=t,this.yNode=e,this.depth=s,this.next=null,this.xGeohashTotal=0,this.yGeohashTotal=0,this.displayId=0,this.referenceId=0,this.xTotal=0,this.yTotal=0,this.count=0,this.statistics={},this.displayIds.clear(),this}get id(){return`${this.xNode}.${this.yNode}`}add(t){this.displayIds.add(t)}remove(t){this.displayIds.delete(t)}getAttributes(){const t=this._tree.normalizeStatistics(this.statistics,this.count);return t.aggregateId=this.id,t.aggregateCount=this.count,t}getGeometry(t,s){const i=this.getLngLatBounds(),[h,c,u,d]=i,f=l({rings:[[[h,c],[h,d],[u,d],[u,c],[h,c]]]},o.WGS84,t),x=n(new r,f,!1,!1);return e(s)?a(new r,x,!1,!1,"esriGeometryPolygon",s,!1,!1):x}getLngLatBounds(){const t=this.depth,e=Math.ceil(t/2),s=Math.floor(t/2),o=30-(3*e+2*s),n=30-(2*e+3*s),a=this.xNode<<o,r=this.yNode<<n;return i({geohashX:a,geohashY:r},this.depth)}find(t,e,s,i,o,n){if(i>=s)return this;const a=1-i%2,r=3*a+2*(1-a),l=2*a+3*(1-a),h=30-o-r,c=30-n-l,u=((t&7*a+3*(1-a)<<h)>>h)+((e&3*a+7*(1-a)<<c)>>c)*(8*a+4*(1-a)),d=this.children[u];return null==d?null:d.find(t,e,s,i+1,o+r,n+l)}}export{u as GeohashNode,c as GeohashTree};
|