UNPKG

@doegis/core

Version:

DOE GIS API

3 lines (1 loc) 6.25 kB
import{isNone as t}from"../../../core/maybe.js";import s from"../../../core/RandomLCG.js";import{Placement as i}from"../CIMPlacements.js";import{PlacementGridType as e}from"../enums.js";const n=512,h=10,_=12,r=25,o=24;function a(t){return void 0!==t.rings}class l{static local(){return null===l.instance&&(l.instance=new l),l.instance}execute(t,s,i,e,n){return new f(t,s,i,e,n)}}l.instance=null;class f{constructor(t,h,_,r,o){if(this._xMin=0,this._xMax=0,this._yMin=0,this._yMax=0,this._currentX=0,this._currentY=0,this._accelerationMap=null,this._testInsidePolygon=!1,this._verticalSubdivision=!0,this._stepX=Math.abs(h.stepX??16)*_,this._stepY=Math.abs(h.stepY??16)*_,0!==this._stepX&&0!==this._stepY&&t&&a(t)&&t.rings){if(this._gridType=h.gridType??e.Fixed,this._gridType===e.Random){const t=h.seed??13,i=1;this._randomLCG=new s(t*i),this._randomness=(h.randomness??100)/100,this._gridAngle=0,this._shiftOddRows=!1,this._cosAngle=1,this._sinAngle=0,this._offsetX=0,this._offsetY=0,this._buildRandomValues()}else{if(this._randomness=0,this._gridAngle=h.gridAngle??0,this._shiftOddRows=h.shiftOddRows??!1,this._offsetX=(h.offsetX??0)*_,this._offsetY=(h.offsetY??0)*_,this._cosAngle=Math.cos(this._gridAngle/180*Math.PI),this._sinAngle=-Math.sin(this._gridAngle/180*Math.PI),this._stepX)if(this._offsetX<0)for(;this._offsetX<-.5*this._stepX;)this._offsetX+=this._stepX;else for(;this._offsetX>=.5*this._stepX;)this._offsetX-=this._stepX;if(this._stepY)if(this._offsetY<0)for(;this._offsetY<-.5*this._stepY;)this._offsetY+=this._stepY;else for(;this._offsetY>=.5*this._stepY;)this._offsetY-=this._stepY}if(this._graphicOriginX=0,this._graphicOriginY=0,null!=r){const[t,s,i]=r.split("/"),e=parseFloat(s),h=parseFloat(i);this._graphicOriginX=-h*n,this._graphicOriginY=e*n,this._testInsidePolygon=!0}this._internalPlacement=new i,this._calculateMinMax(t),this._geometry=t}}next(){return this._geometry?this._nextInside():null}_buildRandomValues(){if(!f._randValues){f._randValues=[];for(let t=0;t<o;t++)for(let s=0;s<o;s++)f._randValues.push(this._randomLCG.getFloat()),f._randValues.push(this._randomLCG.getFloat())}}_calculateMinMax(t){let s,i,e,h,o,a,l,f,c,g,u,M,p,d;this._xMin=0,this._xMax=0,this._yMin=0,this._yMax=0,l=f=p=u=Number.MAX_VALUE,c=g=d=M=-Number.MAX_VALUE;const m=1!==this._cosAngle;let X=0;for(const n of t.rings){const t=n?n.length:0;for(let _=0;_<t;_++)a=n[_][0],o=n[_][1],s=a-this._graphicOriginX-this._offsetX,i=o-this._graphicOriginY-this._offsetY,m?(e=this._cosAngle*s-this._sinAngle*i,h=this._sinAngle*s+this._cosAngle*i):(e=s,h=i),l=Math.min(l,e),c=Math.max(c,e),f=Math.min(f,h),g=Math.max(g,h),u=Math.min(u,o),M=Math.max(M,o),p=Math.min(p,a),d=Math.max(d,a),X++}u=u!==Number.MAX_VALUE?u:-n-this._stepY,M=M!==-Number.MAX_VALUE?M:this._stepY,p=p!==Number.MAX_VALUE?p:-this._stepX,d=d!==-Number.MAX_VALUE?d:n+this._stepX;const A=M-u,Y=d-p;if(this._verticalSubdivision=A>=Y,this._polygonMin=this._verticalSubdivision?u:p,this._testInsidePolygon){let t=0-this._graphicOriginX-this._offsetX-this._stepX,s=n-this._graphicOriginX-this._offsetX+this._stepX,i=-n-this._graphicOriginY-this._offsetY-this._stepY,e=0-this._graphicOriginY-this._offsetY+this._stepY;if(m){const n=[[t,i],[t,e],[s,i],[s,e]];t=i=Number.MAX_VALUE,s=e=-Number.MAX_VALUE;for(const h of n){const n=this._cosAngle*h[0]-this._sinAngle*h[1],_=this._sinAngle*h[0]+this._cosAngle*h[1];t=Math.min(t,n),s=Math.max(s,n),i=Math.min(i,_),e=Math.max(e,_)}}l=l!==Number.MAX_VALUE?Math.max(l,t):t,f=f!==Number.MAX_VALUE?Math.max(f,i):i,c=c!==-Number.MAX_VALUE?Math.min(c,s):s,g=g!==-Number.MAX_VALUE?Math.min(g,e):e}this._xMin=Math.round(l/this._stepX),this._xMax=Math.round(c/this._stepX),this._yMin=Math.round(f/this._stepY),this._yMax=Math.round(g/this._stepY),this._currentX=this._xMax+1,this._currentY=this._yMin-1,this._testInsidePolygon&&X>_&&(A>r||Y>r)&&this._buildAccelerationMap(t,p,d,u,M)}_buildAccelerationMap(t,s,i,e,_){const{rings:r}=t,o=new Map,a=this._verticalSubdivision,l=a?_-e:i-s;let f=Math.ceil(l/h);if(f<=1)return;const c=Math.floor(l/f);let u,M,p,d,m,X,A,Y,x,y;f++,this._delta=c,a?(Y=-n-this._stepY,x=this._stepY,y=e):(Y=-this._stepX,x=n+this._stepX,y=s);for(let n=0;n<r.length;n++)if(u=r[n],!(u.length<2))for(let t=1;t<u.length;t++){if(M=u[t-1],p=u[t],a){if(M[1]===p[1]||M[1]<Y&&p[1]<Y||M[1]>x&&p[1]>x)continue;d=Math.min(M[1],p[1]),m=Math.max(M[1],p[1])}else{if(M[0]===p[0]||M[0]<Y&&p[0]<Y||M[0]>x&&p[0]>x)continue;d=Math.min(M[0],p[0]),m=Math.max(M[0],p[0])}for(;d<m;)X=Math.floor((d-y)/c),g(X,n,t,o),d+=c;A=Math.floor((m-y)/c),A>X&&g(A,n,t,o)}this._accelerationMap=o}_nextInside(){for(;;){if(this._currentX>this._xMax){if(this._currentY++,this._currentY>this._yMax)return null;this._currentX=this._xMin,this._shiftOddRows&&this._currentY%2&&this._currentX--}let t=this._currentX*this._stepX+this._offsetX;this._shiftOddRows&&this._currentY%2&&(t+=.5*this._stepX);const s=this._currentY*this._stepY+this._offsetY;let i,n;if(this._currentX++,this._gridType===e.Random){const e=(this._currentX%o+o)%o,h=(this._currentY%o+o)%o;i=this._graphicOriginX+t+this._stepX*this._randomness*(.5-f._randValues[h*o+e])*2/3,n=this._graphicOriginY+s+this._stepY*this._randomness*(.5-f._randValues[h*o+e+1])*2/3}else i=this._graphicOriginX+this._cosAngle*t+this._sinAngle*s,n=this._graphicOriginY-this._sinAngle*t+this._cosAngle*s;if(!this._testInsidePolygon||this._isInsidePolygon(i,n,this._geometry))return this._internalPlacement.setTranslate(i,n),this._internalPlacement}}_isInsidePolygon(s,i,e){const{rings:n}=e;if(t(this._accelerationMap))return c(s,i,e);const h=this._verticalSubdivision,_=h?i:s,r=Math.floor((_-this._polygonMin)/this._delta),o=this._accelerationMap.get(r);if(!o)return!1;let a,l,f,g,u,M=0;for(const t of o){u=t[0];const e=n[u];if(g=t[1],a=e[g-1],l=e[g],h){if(a[1]>i==l[1]>i)continue;f=(l[0]-a[0])*(i-a[1])-(l[1]-a[1])*(s-a[0])}else{if(a[0]>s==l[0]>s)continue;f=(l[1]-a[1])*(s-a[0])-(l[0]-a[0])*(i-a[1])}f>0?M++:M--}return 0!==M}}function c(t,s,i){const{rings:e}=i;let n,h,_,r=0;for(const o of e){n=o.length;for(let i=1;i<n;++i){if(h=o[i-1],_=o[i],h[1]>s==_[1]>s)continue;(_[0]-h[0])*(s-h[1])-(_[1]-h[1])*(t-h[0])>0?r++:r--}}return 0!==r}function g(t,s,i,e){let n=e.get(t);n||(n=[],e.set(t,n)),n.push([s,i])}export{l as PlacementInsidePolygon};