2024-02-14 13:02:11 -05:00
|
|
|
import t from"delaunator";const n=1e-6;class Path{constructor(){this._x0=this._y0=this._x1=this._y1=null;this._=""}moveTo(t,n){this._+=`M${this._x0=this._x1=+t},${this._y0=this._y1=+n}`}closePath(){if(null!==this._x1){this._x1=this._x0,this._y1=this._y0;this._+="Z"}}lineTo(t,n){this._+=`L${this._x1=+t},${this._y1=+n}`}arc(t,e,i){t=+t,e=+e,i=+i;const s=t+i;const l=e;if(i<0)throw new Error("negative radius");null===this._x1?this._+=`M${s},${l}`:(Math.abs(this._x1-s)>n||Math.abs(this._y1-l)>n)&&(this._+="L"+s+","+l);i&&(this._+=`A${i},${i},0,1,1,${t-i},${e}A${i},${i},0,1,1,${this._x1=s},${this._y1=l}`)}rect(t,n,e,i){this._+=`M${this._x0=this._x1=+t},${this._y0=this._y1=+n}h${+e}v${+i}h${-e}Z`}value(){return this._||null}}class Polygon{constructor(){this._=[]}moveTo(t,n){this._.push([t,n])}closePath(){this._.push(this._[0].slice())}lineTo(t,n){this._.push([t,n])}value(){return this._.length?this._:null}}class Voronoi{constructor(t,[n,e,i,s]=[0,0,960,500]){if(!((i=+i)>=(n=+n))||!((s=+s)>=(e=+e)))throw new Error("invalid bounds");this.delaunay=t;this._circumcenters=new Float64Array(2*t.points.length);this.vectors=new Float64Array(2*t.points.length);this.xmax=i,this.xmin=n;this.ymax=s,this.ymin=e;this._init()}update(){this.delaunay.update();this._init();return this}_init(){const{delaunay:{points:t,hull:n,triangles:e},vectors:i}=this;let s,l;const h=this.circumcenters=this._circumcenters.subarray(0,e.length/3*2);for(let i,o,r=0,c=0,a=e.length;r<a;r+=3,c+=2){const a=2*e[r];const u=2*e[r+1];const g=2*e[r+2];const f=t[a];const d=t[a+1];const m=t[u];const _=t[u+1];const y=t[g];const x=t[g+1];const p=m-f;const v=_-d;const w=y-f;const P=x-d;const T=2*(p*P-v*w);if(Math.abs(T)<1e-9){if(void 0===s){s=l=0;for(const e of n)s+=t[2*e],l+=t[2*e+1];s/=n.length,l/=n.length}const e=1e9*Math.sign((s-f)*P-(l-d)*w);i=(f+y)/2-e*P;o=(d+x)/2+e*w}else{const t=1/T;const n=p*p+v*v;const e=w*w+P*P;i=f+(P*n-v*e)*t;o=d+(p*e-w*n)*t}h[c]=i;h[c+1]=o}let o=n[n.length-1];let r,c=4*o;let a,u=t[2*o];let g,f=t[2*o+1];i.fill(0);for(let e=0;e<n.length;++e){o=n[e];r=c,a=u,g=f;c=4*o,u=t[2*o],f=t[2*o+1];i[r+2]=i[c]=g-f;i[r+3]=i[c+1]=u-a}}render(t){const n=null==t?t=new Path:void 0;const{delaunay:{halfedges:e,inedges:i,hull:s},circumcenters:l,vectors:h}=this;if(s.length<=1)return null;for(let n=0,i=e.length;n<i;++n){const i=e[n];if(i<n)continue;const s=2*Math.floor(n/3);const h=2*Math.floor(i/3);const o=l[s];const r=l[s+1];const c=l[h];const a=l[h+1];this._renderSegment(o,r,c,a,t)}let o,r=s[s.length-1];for(let n=0;n<s.length;++n){o=r,r=s[n];const e=2*Math.floor(i[r]/3);const c=l[e];const a=l[e+1];const u=4*o;const g=this._project(c,a,h[u+2],h[u+3]);g&&this._renderSegment(c,a,g[0],g[1],t)}return n&&n.value()}renderBounds(t){const n=null==t?t=new Path:void 0;t.rect(this.xmin,this.ymin,this.xmax-this.xmin,this.ymax-this.ymin);return n&&n.value()}renderCell(t,n){const e=null==n?n=new Path:void 0;const i=this._clip(t);if(null===i||!i.length)return;n.moveTo(i[0],i[1]);let s=i.length;while(i[0]===i[s-2]&&i[1]===i[s-1]&&s>1)s-=2;for(let t=2;t<s;t+=2)i[t]===i[t-2]&&i[t+1]===i[t-1]||n.lineTo(i[t],i[t+1]);n.closePath();return e&&e.value()}*cellPolygons(){const{delaunay:{points:t}}=this;for(let n=0,e=t.length/2;n<e;++n){const t=this.cellPolygon(n);t&&(t.index=n,yield t)}}cellPolygon(t){const n=new Polygon;this.renderCell(t,n);return n.value()}_renderSegment(t,n,e,i,s){let l;const h=this._regioncode(t,n);const o=this._regioncode(e,i);if(0===h&&0===o){s.moveTo(t,n);s.lineTo(e,i)}else if(l=this._clipSegment(t,n,e,i,h,o)){s.moveTo(l[0],l[1]);s.lineTo(l[2],l[3])}}contains(t,n,e){return(n=+n,n===n)&&(e=+e,e===e)&&this.delaunay._step(t,n,e)===t}*neighbors(t){const n=this._clip(t);if(n)for(const e of this.delaunay.neighbors(t)){const t=this._clip(e);if(t)t:for(let i=0,s=n.length;i<s;i+=2)for(let l=0,h=t.length;l<h;l+=2)if(n[i]===t[l]&&n[i+1]===t[l+1]&&n[(i+2)%s]===t[(l+h-2)%h]&&n[(i+3)%s]===t[(l+h-1)%h]){yield e;break t}}}_cell(t){const{circumcenters:n,delaunay:{inedges:e,halfedges:i,triangles:s}}=this;const l=e[t];if(-1===l)return null;const h=[];let o=l;do{const e=Math.floor(o/3);h.push(
|