memoscan
← all memos

Memo 0xce8086cd…67a914 on Ethereum

3, 8., 0.6) * (lineDistanceMax / (uIsShading ? 2. : 2.));\n \n float lineWeightEdgeNoise = fbm(uv + uNoiseOffset + currentLineNoiseOffset, 3, 300., 0.54) * (lineDistanceMax / 10.);\n\n float lineDistance = (lineSDF + lineWeightWobble + lineWeightEdgeNoise); \n \n \n float lineFineNoise = clamp(\n smoothstep(0., 0.9, fbm(uv + currentLineNoiseOffset, 2, 700., 0.9) - 0.1) + remap(lineHardness, 1., 0., 1. - uMaterialHardness, 0.5),\n 0., 1.);\n\n float lineFineNoise2 = clamp(\n smoothstep(0., 0.9, fbm(uv, 1, 900., 0.9)) + remap(lineHardness, 1., 0., 0.01, 0.5),\n 0., (1. - uMaterialHardness) + .1);\n \n\n float alphaWobblePerLine = fbm(uNoiseOffset + currentLineNoiseOffset, 1, 300., 0.9) * 0.015;\n\n float lineColorWobble = 0.008;\n \n float lightnessWobblePerLine = ((fbm(uNoiseOffset + (currentLineNoiseOffset / 1.), 1, 1000., 0.9) + .5) / 2. ) * lineColorWobble;\n localColor.x += lightnessWobblePerLine;\n\n float saturationWobblePerLine = ((fbm(uNoiseOffset + (currentLineNoiseOffset / 1.1), 1, 1100., 0.9) + .5) / 2. ) * (lineColorWobble * 0.4);\n localColor.y += saturationWobblePerLine;\n \n float maxLineHardness = clamp(smoothstep(0., 1., lineHardness - alphaWobblePerLine), 0., 1.);\n\n float lineRolloff = 0.0001;\n float alphaHardLineSpread = lineDistanceMax * 1.;\n float hardLineSS = smoothstep(alphaHardLineSpread + lineRolloff, alphaHardLineSpread - lineRolloff, lineDistance);\n\n float alphaHardLine = clamp(\n (hardLineSS * (1. - lineFineNoise) * (1. - lineFineNoise2)) * maxLineHardness,\n 0., 1.);\n\n float alphaSoftLine = 0.;\n\n if(!uIsShading) {\n float alphaSoftLineNoise = clamp((fbm(uv + currentLineNoiseOffset, 1, 800., 0.9) - 0.3), 0., 1.);\n\n\n float alphaSoftLineSpread = lineDistanceMax * 1.5;\n float softLineSS = smoothstep(alphaSoftLineSpread + lineRolloff, alphaSoftLineSpread - lineRolloff, lineDistance);\n\n alphaSoftLine = clamp(\n (step(lineDistance, alphaSoftLineSpread) * alphaSoftLineNoise) * maxLineHardness,\n 0., .7);\n }\n \n\n float lineAlpha = max(alphaSoftLine, alphaHardLine) * segmentDistanceAlphaMult;\n \n \n\n \n // if(alphaHardLine > alpha) {\n // if(alpha == 0.) {\n // alpha = lineAlpha;\n // }\n // if(uIsShading) {\n // // 0 is always the closest line, so use this as our based for subsequent accumulation\n // if(i == 0) {\n // alpha = lineAlpha * 0.7;\n // } else {\n // alpha = clamp(alpha + (1.0 - alpha) * lineAlpha * alphaIncrement, 0., 1.);\n // }\n // } else {\n // alpha = max(alpha, lineAlpha);\n // }\n \n // clamp(alpha, 0., 1.);\n accumulationValue = clamp(accumulationValue + (1.0 - accumulationValue) * lineAlpha * 0.1, 0., 5.);\n // alpha = clamp(alpha + (1.0 - alpha) * lineAlpha * alphaIncrement, 0., 1.);\n // alpha = clamp(alpha, 0., 1.);\n\n // if(alphaHardLine > alpha) {\n alpha = clamp(1.0 - (1.0 - alpha) * (1.0 - lineAlpha * alphaIncrement), 0., 1.);\n color.x = clamp(\n 1.0 - (1.0 - localColor.x) * (1.0 - lineAlpha * lightnessIncrement), \n originalColor.x - accumulationClamp.x, \n originalColor.x + accumulationClamp.x\n );\n if(!uDisableSaturationShift) {\n color.y = clamp(1.0 - (1.0 - localColor.y) * (1.0 - lineAlpha * chromaIncrement), \n originalColor.y - accumulationClamp.y, \n originalColor.y + accumulationClamp.y\n );\n }\n \n \n }\n\n if(alpha <= 0.) {\n return vec4(frameBuffer, 1.);\n }\n\n // accumulationValue *= (smoothstep(.08, .0, sdf) + .5);\n \n // if(uIsShading) {\n // float chromaIncrement = 0.07 * uAccumulationStrength; // adjust for subtlety\n // float lightnessIncrement = -0.07 * uAccumulationStrength;\n\n // // if(uIsShading) {\n // // accumulationValue = clamp(accumulationValue, 0., .1);\n // color.x += accumulationValue * lightnessIncrement;\n // color.y += accumulationValue * chromaIncrement;\n\n // color.x += 0.08;\n // color.y -= (chromaIncrement * 0.4);\n // }\n\n // alpha = clamp(alpha, 0., 1.);\n float brightnessNoiseInfluence = smoothstep(-1., 1., fbm(uv + uNoiseOffset, 2, 50., 0.9)) + 0.4;\n float brightnessNoise = smoothstep(0.1, 0.31, fbm(uv + uNoiseOffset, 2, 1800., 0.5)) * brightnessNoiseInfluence * 0.002;\n color.x += brightnessNoise;\n\n float alphaNoise2 = smoothstep(-1., 1., fbm(uv, 1, 1000., 0.1)) * 0.02;\n float alphaNoise = smoothstep(-0.6, 1., fbm(uv, 2, 1200., 0.1)) * 0.12;\n alpha -= (alphaNoise + alphaNoise2);\n alpha = clamp(alpha, 0., 1.);\n\n // float colourShift = (smoothstep(0.1, 0.4, fbm(uv + uNoiseOffset, 2, 5., 0.6)) - 0.5) * 0.0001;\n // color.x += colourShift;\n\n \n \n float colorBrightWobble = fbm(uv + uNoiseOffset, 2, 20., 0.9) * 0.001;\n float colorEase = (\n easeOut(smoothstep(.02, .0, sdf + colorBrightWobble), 1.) \n * (0.01 + (accumulationValue * 0.02))\n );\n\n float colorBrightNoise = smoothstep(-0.4, 0.4, fbm(uv + uNoiseOffset, 2, 700., 0.9));\n float darkenEdge = easeOut(smoothstep(.0035, .0, sdf - (colorBrightWobble * 4.)), 1.) \n * (0.06 + (accumulationValue * 0.02)) * colorBrightNoise;\n\n colorEase += darkenEdge;\n \n color.x -= colorEase;\n color.y += (colorEase * 0.4);\n\n // color.x += 0.005;\n // color.y -= 0.005;\n\n // color.x -= 0.01;\n // color.y -= 0.02;\n\n // LINE SDF\n \n // LINE BRIGHTNESS\n \n color.x = clamp(color.x, 0., .84);\n color.y = clamp(color.y, 0., .4); \n // float satWeight = 0.05;\n // color.y *= remap(uBrightness, 0., 2., 1. + satWeight + 0.3, 1. - satWeight);\n\n \n\n // LIGHTING\n vec3 lightDir = normalize(vec3(.6f, 1.6f, 1.6f));\n vec3 lightColor = vec3(1.0f) * 1.7f;\n \n vec3 paperTextureNormals = calculateNormals(screenSpaceUV + msaaOffset, 0.0002 * tileScaleFactor.x, 4.);\n vec3 diffuse = calculateDiffuse(paperTextureNormals, lightDir, lightColor);\n\n vec3 colorRGB = OKLCHtoP3LRGB(color) * diffuse;\n vec3 colorMult = (frameBuffer * colorRGB) * diffuse;\n\n colorRGB = mix(frameBuffer, mix(colorMult, colorRGB * diffuse, clamp(0.9, 1., alpha + 0.3)), alpha);\n // colorRGB\n\n // colorRGB = mix(frameBuffer, colorRGB, alpha);\n\n // if(uEnableFadeAtLineSegment) {\n // colorRGB = vec3(segmentDistanceAlphaMult);\n // }\n\n return vec4(colorRGB, 1.0);\n }\n\n void main() {\n const vec2 H2 = vec2(0.5698402909980532f, 0.7548776662466927f);\n vec2 px = 1.f / resolution;\n px *= 1.25;\n vec2 uv = vUv;\n\n \n // Check if this fragment is within the SDF\n vec2 uvOffset = lookupWarpSample(uv).xy;\n float texCheck = (texture(tPolyEdgeDistance, uv + uvOffset).r - 0.5) * 2.0;\n if(texCheck < -0.1) {\n discard;\n }\n\n vec3 frameBuffer = texture(tScreenBuffer, vUv).rgb;\n\n\n const float samples = 4.f;\n \n vec4 sumColour;\n vec2 d0 = vec2(randomNonDet(uv), randomNonDet(uv + 1.f));\n\n \n for(float i = 0.f; i < samples; i++) {\n vec2 d = (fract(i * H2 + d0) - .5f);\n\n vec2 localCoord = vUv + d * px; /* changed */\n vec2 screenCoord = uTileOffset + localCoord * uTileSize; /* changed */\n vec2 globalUV = screenCoord / resolution; /* changed */\n\n // vec4 sampleColor = render(globalUV, vUv, d * px);\n vec4 sampleColor = render(globalUV, vUv, d * px, frameBuffer);\n // sampleColor.rgb *= sampleColor.a; // Convert to premultiplied alpha\n sumColour += sampleColor;\n }\n \n vec4 averageColor = clamp(sumColour / samples, 0., 1.);\n \n outColor = averageColor;\n }\n `});let n=t.isShading?At:Et;n.updatePolylines(t.lines,t.closedPolyOrLine);let i=jt.uniforms;re(jt),Vt.material=jt,i.tScreenBuffer.value=Xt.getReadBuffer().texture;let l=t.lineColor;if(i.uLineColor.value=Ht(l),i.uDisableSaturationShift.value=t.disableSaturationShift||!1,i.uLineWeight.value=t.lineWeight,i.uLineHardness.value=t.linePressure,i.uMaterialHardness.value=t.materialHardness||1,i.uIsShading.value=t.isShading||!1,i.tWarpTex.value=t.canWarp?Ct.displacementMapWarped.target.texture:Ct.displacementMap.target.texture,i.uNoiseOffset.value=new le(...t.noiseOffset),i.uFaceIndex.value=_t++,i.uLineWeight.value=t.lineWeight,i.uTaperingFadeIn.value=t.lineTapering.fade.in.enabled?t.lineTapering.fade.in.length:0,i.uTaperingFadeOut.value=t.lineTapering.fade.out.enabled?t.lineTapering.fade.out.length:0,i.uTaperingScaleIn.value=t.lineTapering.scale.in.enabled?t.lineTapering.scale.in.length:0,i.uTaperingScaleOut.value=t.lineTapering.scale.out.enabled?t.lineTapering.scale.out.length:0,i.uBrightness.value=t.lineBrightness||1,i.uEdgeSharpness.value=t.edgeSharpness||1,i.uAccumulationStrength.value=t.accumulationStrength||1,t?.fadeAtLineSegment){let e=Ot(t.fadeAtLineSegment.segment);const n=i.uFadeAtLineSegmentVertices.value;n[0]=e[0][0],n[1]=e[0][1],n[2]=e[1][0],n[3]=e[1][1],i.uFadeAtLineSegmentDistance.value=t.fadeAtLineSegment.distance,i.uFadeAtLineSegmentStrength.value=t.fadeAtLineSegment.strength,i.uEnableFadeAtLineSegment.value=!0,jt.needsUpdate=!0}else i.uEnableFadeAtLineSegment.value=!1;if(!qt||$t!==n){const{cellsWide:e,cellsHigh:t,cellSize:l}=n,{segmentDataTexture:a,segmentMetaDataTexture:s,segmentIndexTexture:o}=n.getTextures();i.uSegmentDataTex.value=a,i.uSegmentMetaDataTex.value=s,i.uSegmentIndexTex.value=o,i.tPolyLineGrid.value={width:e*l,height:t*l,cellSize:l},qt=!0}i.uIsClosedPoly.value=t.closedPolyOrLine,X.setRenderTarget(Xt.getWriteBuffer()),Vt.render(),Xt.copyAndSwapBuffers(),$t=n}let tn=new e.Vector4;class nn{minX=1/0;minY=1/0;maxX=-1/0;maxY=-1/0;constructor(){}get width(){return this.maxX-this.minX}get height(){return this.maxY-this.minY}get center(){return new zt((this.minX+this.maxX)/2,(this.minY+this.maxY)/2)}get vertexList(){return[new zt(this.minX,this.minY),new zt(this.maxX,this.minY),new zt(this.maxX,this.maxY),new zt(this.minX,this.maxY)]}get area(){return this.width*this.height}reset(){this.minX=1/0,this.minY=1/0,this.maxX=-1/0,this.maxY=-1/0}expand(e){this.minX=Math.min(e.x,this.minX),this.minY=Math.min(e.y,this.minY),this.maxX=Math.max(e.x,this.maxX),this.maxY=Math.max(e.y,this.maxY)}expands(e){for(let t=0,n=e.length;t<n;t++)this.expand(e[t]);return this}expandByPoint(e){return this.minX=Math.min(e[0],this.minX),this.minY=Math.min(e[1],this.minY),this.maxX=Math.max(e[0],this.maxX),this.maxY=Math.max(e[1],this.maxY),this}expandsByPoint(e){for(let t=0,n=e.length;t<n;t++)this.expandByPoint(e[t])}intersects(e,t=b){return!(e.maxX<this.minX-t||e.minX>this.maxX+t||e.maxY<this.minY-t||e.minY>this.maxY+t)}expandByValue(e){return this.minX-=e,this.minY-=e,this.maxX+=e,this.maxY+=e,this}containsPoint(e){return e.x<=this.maxX+b&&e.x>=this.minX-b&&e.y<=this.maxY+b&&e.y>=this.minY-b}distanceToPoint(e){const t=r(this.minX-e.x,0,e.x-this.maxX),n=r(this.minY-e.y,0,e.y-this.maxY);return d(t*t+n*n)}containsBB(e){return e.minX>=this.minX-b&&e.maxX<=this.maxX+b&&e.minY>=this.minY-b&&e.maxY<=this.maxY+b}containsPoints(e){for(let t=0,n=e.length;t<n;t++)if(!this.containsPoint(e[t]))return!1;return!0}size(){return{width:this.maxX-this.minX,height:this.maxY-this.minY}}}let ln,an=[];var sn,on;function rn(i){ln=ln||new e.ShaderMaterial({uniforms:{resolution:{value:new e.Vector2(B,Q)},tPositions:{value:new e.DataTexture},uPositionsCount:{value:0},...ce()},colorWrite:!0,depthWrite:!1,depthTest:!1,glslVersion:e.GLSL3,vertexShader:ie,fragmentShader:`\n precision highp float;\n\t\t\tprecision highp int;\n \n uniform highp sampler2D tPositions;\n uniform vec2 resolution;\n uniform int uPositionsCount;\n uniform vec2 uTileOffset;\n uniform vec2 uTileSize;\n \n varying vec2 vUv;\n out vec4 outColor;\n\n ${ne}\n\n float pointLineSegSDF(vec2 p, vec2 a, vec2 b) {\n vec2 pa = p - a;\n vec2 ba = b - a;\n float t = clamp(dot(pa, ba) / dot(ba, ba), 0.0, 1.0);\n return length(pa - ba * t);\n }\n \n bool isIntersecting(vec2 point, vec2 p1, vec2 p2) {\n if(p1.y == p2.y) {\n return false;\n }\n \n if(p1.y > point.y && p2.y > point.y) {\n return false;\n }\n \n if(p1.y < point.y && p2.y < point.y) {\n return false;\n }\n \n float intersectionX = p1.x + (point.y - p1.y) * (p2.x - p1.x) / (p2.y - p1.y);\n return intersectionX > point.x;\n }\n\n vec2 fetchVertex(int vertexIndex) {\n int textureWidth = textureSize(tPositions, 0).x;\n int x = vertexIndex % textureWidth;\n int y = vertexIndex / textureWidth;\n return texelFetch(tPositions, ivec2(x, y), 0).rg;\n }\n \n float polyDistanceSDF(vec2 uv) {\n float minDist = 1e20;\n int intersections = 0;\n \n for(int i = 0; i < uPositionsCount; i++) {\n vec2 vertex1 = fetchVertex(i) / resolution.xy;\n vec2 vertex2 = fetchVertex((i + 1) % uPositionsCount) / resolution.xy;\n \n minDist = min(minDist, pointLineSegSDF(uv, vertex1, vertex2));\n \n if(isIntersecting(uv, vertex1, vertex2)) {\n intersections++;\n }\n }\n return float(intersections % 2 == 1 ? minDist : -minDist);\n // return float(intersections % 2 == 1 ? minDist : 1.5);\n }\n \n vec4 render(vec2 uv) {\n float dist = polyDistanceSDF(uv);\n return vec4(dist) * 0.5 + .5;\n }\n \n\n void main() {\n // A pseudo-random distribution for multi-sample\n const vec2 H2 = vec2(0.56984029, 0.75487766);\n // We do sub-pixel offsets relative to tile size, \n // because each tile is scaled to fill the entire local canvas\n vec2 px = 1.0 / resolution.xy;\n px *= 1.25;\n\n // We'll accumulate color across multiple samples\n const float samples = 4.0;\n vec4 sumColour = vec4(0.0);\n \n // Vary the random offset per pixel\n vec2 d0 = vec2(randomNonDet(vUv), randomNonDet(vUv + 1.0));\n\n for (float i = 0.0; i < samples; i++) {\n vec2 d = fract(i * H2 + d0) - 0.5;\n // localCoord in [0..1] in the local canvas\n vec2 sampleCoord = vUv + d * px;\n\n // Now map that to the large “full” coordinate space \n // subregion given by uTileOffset..uTileOffset+uTileSize\n vec2 screenCoord = uTileOffset + sampleCoord * uTileSize;\n\n // Next convert to [0..1] over the entire original geometry\n vec2 globalUV = screenCoord / resolution;\n\n vec4 sampleColor = render(globalUV);\n sumColour += sampleColor;\n }\n\n vec4 finalColor = clamp(sumColour / samples, 0.0, 1.0);\n outColor = finalColor;\n }\n `});let l=Ot(i.polygon);ln.uniforms.uPositionsCount.value=l.length;let a=function(t){const i=t.flat(),l=i.length/2,a=o(C,l),s=n(l/C),r=new Float32Array(a*s*2);for(let e=0;e<l;e++){const t=2*e;r[t]=i[t]||0,r[t+1]=i[t+1]||0}let c=new e.DataTexture(r,a,s,e.RGFormat,e.FloatType);return c.needsUpdate=!0,{texture:c,width:a,height:s}}(l);ln.uniforms.tPositions.value=a.texture,re(ln),Vt.material=ln,X.setRenderTarget(Ct.polyEdgeDistance.target),X.setClearColor(1,0),X.clear();let s=oe();var c;((e,i=5)=>{i/=U,X.setScissorTest(!0),X.setScissor(((e,i=5)=>{let l=i*U,a=o(...e.map((e=>e.x)))-l,s=r(...e.map((e=>e.x)))+l,c=o(...e.map((e=>e.y)))-l,d=r(...e.map((e=>e.y)))+l,u=s-a,h=d-c;return tn.set(kt(t(a),0,B),kt(t(Q-d),0,Q),n(o(u,B)),n(o(h,Q))).divideScalar(N).round()})(e,i))})((c=i.polygon.map((e=>new le(e.x,e.y))),c.map((e=>e.clone().multiplyScalar(U)))).map((e=>(e.x=t((e.x-s.xOff)*(B/s.width)),e.y=n((e.y-s.yOff)*(Q/s.height)),e))),n(10*U*(B/s.width))),Vt.render(),X.setScissorTest(!1)}!function(e){e[e.constructionLine=0]="constructionLine",e[e.detail=1]="detail",e[e.foreground=2]="foreground",e[e.background=3]="background",e[e.shadow=4]="shadow",e[e.walker=5]="walker",e[e.overlay=6]="overlay",e[e.overlayOutline=7]="overlayOutline"}(sn||(sn={})),function(e){e[e.regular=0]="regular",e[e.warped=1]="warped"}(on||(on={}));const cn=4095,dn=e=>.5*(1-l(e*g));let un;function hn(e){un=new Float32Array(4096);for(let e=0;e<4096;e++)un[e]=J.dec()}let mn=(e,n,i=0,l=5,a=0,s=1)=>Kt(function(e,n=0,i=0){un||hn(),e<0&&(e=-e),n<0&&(n=-n),i<0&&(i=-i);let l,a,s,o,r,c=t(e),d=t(n),u=t(i),h=e-c,m=n-d,p=i-u,g=0,b=.5;for(let e=0;e<3;e++){let e=c+(d<<4)+(u<<8);l=dn(h),a=dn(m),s=un[e&cn],s+=l*(un[e+1&cn]-s),o=un[e+16&cn],o+=l*(un[e+16+1&cn]-o),s+=a*(o-s),e+=256,o=un[e&cn],o+=l*(un[e+1&cn]-o),r=un[e+16&cn],r+=l*(un[e+16+1&cn]-r),o+=a*(r-o),s+=dn(p)*(o-s),g+=s*b,b*=.8,c<<=1,h*=2,d<<=1,m*=2,u<<=1,p*=2,h>=1&&(c++,h--),m>=1&&(d++,m--),p>=1&&(u++,p--)}return g}((e+100)/l,(n+100)/l,(i+100)/l),0,1,a,s);const pn=b;var gn;function bn(e,t,n=!1){if(0===t.length)return e;if(1===t.length)return t[0];let i,l=1/0,a=n?t.length:t.length-1;for(let n=0;n<a;n++){const a=t[n],s=t[(n+1)%t.length],o=xn(e,a,s);o<l&&(l=o,i=[a,s])}return i?function(e,t,n){const[i,l]=t,[a,s]=n,[o,r]=e,c=a-i,d=s-l,u=c*c+d*d;if(u<pn)return[i,l];let h=((o-i)*c+(r-l)*d)/u;return h<-1e-7?h=0:h>1+pn&&(h=1),[i+h*c,l+h*d]}(e,...i):e}function fn(e,t,n=!1){let i=1/0;const l=t.length,a=n?l:l-1;for(let n=0;n<a;n++){const a=Zn(e,t[n],n===l-1?t[0]:t[n+1]);if(a<pn)return 0;i=Math.min(i,a)}return Math.sqrt(i)}function xn(e,t,n){return d(Zn(e,t,n))}function Zn(e,t,n){const[i,l]=t,[a,s]=n,[o,r]=e,c=a-i,d=s-l,u=c*c+d*d;if(u<pn){const e=o-i,t=r-l;return e*e+t*t}let h=((o-i)*c+(r-l)*d)/u;h<-1e-7?h=0:h>1+pn&&(h=1);const m=o-(i+h*c),p=r-(l+h*d);return m*m+p*p}!function(e){e[e.intersecting=0]="intersecting",e[e.colinear=1]="colinear",e[e.parallel=2]="parallel"}(gn||(gn={}));let yn=0;class Gn{v1;v2;id=yn++;origin;angle;length;twin=null;nexthedge=null;prevhedge=null;face=null;constructor(e,t){this.v1=e,this.v2=t,this.id=yn++,this.origin=t,this.angle=function(e,t){let n=t.x-e.x,i=t.y-e.y;const l=d(n*n+i*i);return i>0?u(n/l):2*g-u(n/l)}(e,t),this.length=d(a(t.x-e.x,2)+a(t.y-e.y,2))}dispose(){this.origin=null,this.twin=null,this.nexthedge=null,this.prevhedge=null,this.face=null}getAABB(){let e=new nn;return e.expands([this.origin,this.twin.origin]),e}intersectWithLineSegment([e,t]){return function(e,t,n,i){const{x:l,y:a}=e,{x:s,y:o}=t,{x:r,y:c}=n,{x:d,y:u}=i,h=(u-c)*(s-l)-(d-r)*(o-a),m=(d-r)*(a-c)-(u-c)*(l-r),p=(s-l)*(a-c)-(o-a)*(l-r);if(Math.abs(h)<pn)return Math.abs(m)<pn&&Math.abs(p)<pn?{type:gn.colinear,point:null,ua:0,ub:0}:{type:gn.parallel,point:null,ua:0,ub:0};const g=m/h,b=p/h;return g>=-1e-7&&g<=1+pn&&b>=-1e-7&&b<=1+pn?{type:gn.intersecting,point:new zt(l+g*(s-l),a+g*(o-a)),ua:g,ub:b}:{type:null,point:null,ua:g,ub:b}}(this.origin,this.twin.origin,e,t)}}const Wn=b;class vn{tolerance;vertices=[];hedges=[];faces=[];vertexMap=new Map;constructor(e,t,n=Wn){this.tolerance=n,e&&t&&this.setDatas(e,t)}getVertexKey(e,t){const n=e/this.tolerance,i=t/this.tolerance;return`${Z(n,this.tolerance)},${Z(i,this.tolerance)}`}addVertex(e,t){const n=this.getVertexKey(e,t);let i=this.vertexMap.get(n);i||(i=[],this.vertexMap.set(n,i));for(const n of i)if(this.isClose(n.x,e)&&this.isClose(n.y,t))return n;const l=new zt(e,t);return this.vertices.push(l),i.push(l),l}deleteVertex(e){const t=this.getVertexKey(e.x,e.y),n=this.vertexMap.get(t);if(n){const i=n.indexOf(e);i>-1&&(n.splice(i,1),0===n.length&&this.vertexMap.delete(t))}const i=this.vertices.indexOf(e);i>-1&&this.vertices.splice(i,1),e.dispose()}findVertex(e,t){const n=this.getVertexKey(e,t),i=this.vertexMap.get(n);if(i)for(const n of i)if(this.isClose(n.x,e)&&this.isClose(n.y,t))return n;return null}verticesInPoly(e){let t=e.map((e=>(new zt).fromArray(e))),n=new nn;n.expands(t);let i=[],l=this.verticesInBB(n);for(let e of l)Tn(t,e)&&i.push(e);return i}verticesInBB(e){const t=[];for(let n of this.vertices)e.containsPoint(n)&&t.push(n);return t}setDatas(e,t){const{vertices:n,hedges:i,faces:l}=this;for(let t=0,n=e.length;t<n;t++){const n=e[t];this.addVertex(n[0],n[1])}for(let e=0,l=t.length;e<l;e++){const l=t[e],a=new Gn(n[l[0]],n[l[1]]),s=new Gn(n[l[1]],n[l[0]]);a.twin=s,s.twin=a,n[l[1]].hedgelist.push(a),n[l[0]].hedgelist.push(s),i.push(s),i.push(a)}for(let e=0,t=n.length;e<t;e++){const t=n[e];t.sortincident();const i=t.hedgelist.length;if(0!=i)if(i<2)t.hedgelist[0].prevhedge=t.hedgelist[0].twin,t.hedgelist[0].twin.nexthedge=t.hedgelist[0];else{for(let e=0;e<i-1;e++)t.hedgelist[e].twin.nexthedge=t.hedgelist[e+1],t.hedgelist[e+1].prevhedge=t.hedgelist[e].twin;t.hedgelist[i-1].twin.nexthedge=t.hedgelist[0],t.hedgelist[0].prevhedge=t.hedgelist[i-1].twin}}const a=i.slice(0);let s=i.length;for(;s>0;){let e=a.pop();if(s-=1,null==e.face){const t=new Rn(this);for(t.wedge=e,t.wedge.face=t;e.nexthedge!==t.wedge;)e=e.nexthedge,e.face=t;l.push(t)}}}internalFaces(){const e=[],t=this.faces;for(let n=0,i=t.length;n<i;n++){const i=t[n];i.internal&&e.push(i)}return e}externalFaces(){const e=[],t=this.faces;for(let n=0,i=t.length;n<i;n++){const i=t[n];i.external&&e.push(i)}return e}dispose(){const{vertices:e,hedges:t,faces:n}=this;for(let t=0,n=e.length;t<n;t++)e[t].dispose();for(let e=0,n=t.length;e<n;e++)t[e].dispose();for(let e=0,t=n.length;e<t;e++)n[e].dispose();e.length=0,t.length=0,n.length=0}isClose=(e,t)=>s(e-t)<this.tolerance;findHedge(e,t,n,i){const{isClose:l}=this,a=this.findVertex(e,t);if(a)for(const e of a.hedgelist){const t=e.twin.origin;if(l(t.x,n)&&l(t.y,i))return e}const s=this.findVertex(n,i);if(s)for(const n of s.hedgelist){const i=n.twin.origin;if(l(i.x,e)&&l(i.y,t))return n}return null}addEdge(e,t,n,i){const{vertices:l,hedges:a,faces:s}=this;let o=!1,r=!1,c=!1,d=this.findVertex(e,t);d||(d=this.addVertex(e,t),o=!0);let u=this.findVertex(n,i);u||(u=this.addVertex(n,i),r=!0);const h=new Gn(u,d);a.push(h),d.hedgelist.push(h),d.sortincident();const m=new Gn(d,u);if(a.push(m),u.hedgelist.push(m),u.sortincident(),h.twin=m,m.twin=h,o)h.