@equinor/videx-map 1.14.2 → 1.14.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.esm.js CHANGED
@@ -1 +1 @@
1
- import*as PIXI from"pixi.js";import Vector2 from"@equinor/videx-vector2";import{inverseLerp,lerp,clamp}from"@equinor/videx-math";import{flatten,mix}from"@equinor/videx-linear-algebra";import earcut from"earcut";import{color}from"d3-color";import{v4}from"uuid";class ModuleInterface{pixiOverlay;root;visibility=!0;constructor(){this.root=new PIXI.Container,this.root.sortableChildren=!0}destroy(){this.root.destroy({children:!0,texture:!0,baseTexture:!0}),this.root=null}toggle(){this.root.visible=!this.root.visible}setVisibility(visible){return visible!==this.visibility&&(this.root.visible=visible,this.visibility=visible,!0)}onAdd(_map){}onRemove(_map){}resize(_zoom){}}function log(text){const out=`%cVIDEX-MAP%c ${text}`;console.log(`${out} (${function(){const date=new Date;return`${date.getHours()}:${date.getMinutes()}:${date.getSeconds()}.${date.getMilliseconds()}`}()})`,"\n background: #555;\n color: #eee;\n padding: 0 6px 0 6px;\n border-radius: 2px;\n ",null)}class FaultlineModule extends ModuleInterface{spawned=[];pool=[];config={color:7503240,alpha:1,outlineWidth:.125};constructor(config){super(),config&&(isNaN(config.color)||(this.config.color=config.color),isNaN(config.alpha)||(this.config.alpha=config.alpha),isNaN(config.outlineWidth)||(this.config.outlineWidth=config.outlineWidth))}destroy(){super.destroy(),this.pool.forEach((g=>g.destroy({children:!0,texture:!0,baseTexture:!0}))),this.pool=null,this.spawned=null}set(data){this.clear();const project=this.pixiOverlay.utils.latLngToLayerPoint;let lineCount=0;data.forEach((d=>{let faultline;faultline=this.pool.length>0?this.pool.pop():new PIXI.Graphics,this.root.addChild(faultline),this.spawned.push(faultline),faultline.alpha=this.config.alpha;const projected=d.coordinates.map((p=>{const coord=project(p);return new PIXI.Point(coord.x,coord.y)})),first=projected[0],last=projected[projected.length-1];if(Vector2.equals([first.x,first.y],[last.x,last.y],1e-6))faultline.beginFill(this.config.color),faultline.lineStyle(this.config.outlineWidth,this.config.color),faultline.drawPolygon(projected),faultline.endFill();else{lineCount++,faultline.lineStyle(this.config.outlineWidth,this.config.color).moveTo(first.x,first.y);for(let i=1;i<projected.length;i++)faultline.lineTo(projected[i].x,projected[i].y)}})),lineCount>0&&log(`Drawing ${lineCount} faultline polygons as lines.`)}clear(){for(;this.spawned.length>0;){const temp=this.spawned.pop();this.root.removeChild(temp),temp.clear(),this.pool.push(temp)}}resize(_zoom){}}function Intersection(p1,d1,p2,d2){const c=[p1[0]-p2[0],p1[1]-p2[1]],len=(c[0]*d2[1]-c[1]*d2[0])/(d1[1]*d2[0]-d1[0]*d2[1]);return c[0]=d1[0]*len+p1[0],c[1]=d1[1]*len+p1[1],c}class Mesh{static WellboreSegment(points,thickness=1,type){const vertices=[],triangles=[],vertexData=[],extraData=[],_thickness=.5*thickness,point0=points[0],first=point0.position,from0=Vector2.sub(points[1].position,first).rescale(_thickness);vertices.push(-from0[1]+first[0],from0[0]+first[1],from0[1]+first[0],-from0[0]+first[1]),vertexData.push(point0.distance,1,-point0.direction[1],point0.direction[0],point0.distance,0,point0.direction[1],-point0.direction[0]),extraData.push(type,type);for(let i=1;i<points.length-1;i++){const point=points[i],prev=points[i-1].position,cur=point.position,next=points[i+1].position,to=Vector2.sub(cur,prev),from=Vector2.sub(next,cur);let upper=null,inner=null;if(Vector2.angleDeg(to,from)<90){const toU=to.rotate90().mutable.rescale(_thickness).add(prev).immutable,fromU=from.rotate90().mutable.rescale(_thickness).add(next).immutable,toI=to.rotate270().mutable.rescale(_thickness).add(prev).immutable,fromI=from.rotate270().mutable.rescale(_thickness).add(next).immutable;upper=Intersection(toU,to,fromU,from),inner=Intersection(toI,to,fromI,from)}else upper=[-point.direction[1]*_thickness+cur[0],point.direction[0]*_thickness+cur[1]],inner=[point.direction[1]*_thickness+cur[0],-point.direction[0]*_thickness+cur[1]];if(vertices.push(upper[0],upper[1],inner[0],inner[1]),vertexData.push(point.distance,1,-point.direction[1],point.direction[0],point.distance,0,point.direction[1],-point.direction[0]),extraData.push(type,type),0!==i){const n=2*i;triangles.push(n-1,n-2,n,n-1,n,n+1)}}const pointN=points[points.length-1],last=pointN.position,toN=Vector2.sub(last,points[points.length-2].position).rescale(_thickness);vertices.push(last[0]-toN[1],last[1]+toN[0],last[0]+toN[1],last[1]-toN[0]),vertexData.push(pointN.distance,1,-pointN.direction[1],pointN.direction[0],pointN.distance,0,pointN.direction[1],-pointN.direction[0]),extraData.push(type,type);const n=2*points.length-2;return triangles.push(n-1,n-2,n,n-1,n,n+1),{vertices:vertices,triangles:triangles,vertexData:vertexData,extraData:extraData}}static SimpleLine=(points,thickness=1)=>{const linethickness=.5*thickness;function GetNormal(index){if(0===index)return Vector2.sub(points[1],points[0]).mutable.rotate90().rescale(1);if(index===points.length-1)return Vector2.sub(points[points.length-1],points[points.length-2]).mutable.rotate90().rescale(1);const prev=points[index-1],cur=points[index],next=points[index+1];return Vector2.lerpRot(Vector2.sub(cur,prev),Vector2.sub(next,cur),.5).mutable.rotate90().rescale(1)}const vertices=[],triangles=[],normals=[];let prevUpperRight,baseTris=0;for(let i=0;i<points.length-1;i++){const cur=points[i],next=points[i+1],dirN=Vector2.sub(next,cur).rotate90().mutable.rescale(linethickness).immutable,leftNormal=GetNormal(i),rightNormal=GetNormal(i+1),lowerLeft=Vector2.sub(cur,dirN),upperLeft=Vector2.add(cur,dirN),lowerRight=Vector2.sub(next,dirN),upperRight=Vector2.add(next,dirN);if(vertices.push(lowerLeft[0],lowerLeft[1],upperLeft[0],upperLeft[1],lowerRight[0],lowerRight[1],upperRight[0],upperRight[1]),normals.push(-leftNormal[0],-leftNormal[1],leftNormal[0],leftNormal[1],-rightNormal[0],-rightNormal[1],rightNormal[0],rightNormal[1]),triangles.push(baseTris,baseTris+1,baseTris+3,baseTris,baseTris+3,baseTris+2),0!==i){const toPrevUpper=Vector2.sub(prevUpperRight,upperLeft);Vector2.signedAngle(dirN,toPrevUpper)<0?triangles.push(baseTris,baseTris-2,baseTris+1):triangles.push(baseTris,baseTris-1,baseTris+1)}prevUpperRight=upperRight,baseTris+=4}return{vertices:vertices,triangles:triangles,normals:normals}};static Polygon=points=>{const vertices=flatten(points);return{vertices:vertices,triangles:earcut(vertices)}};static PolygonOutline=(points,thickness=1)=>{const linethickness=.5*thickness;function GetIndex(index){let r=index%points.length;return r<0&&(r+=points.length),r}const vertices=[],triangles=[],normals=[];let prevUpperRight,firstUpperLeft,firstDirN,baseTris=0;for(let i=0;i<points.length;i++){const prev=points[GetIndex(i-1)],cur=points[GetIndex(i)],next=points[GetIndex(i+1)],next2=points[GetIndex(i+2)],dirN=Vector2.sub(next,cur).rotate90().mutable.rescale(linethickness).immutable,leftNormal=Vector2.lerpRot(Vector2.sub(cur,prev),Vector2.sub(next,cur),.5).mutable.rotate90().rescale(1),rightNormal=Vector2.lerpRot(Vector2.sub(next,cur),Vector2.sub(next2,next),.5).mutable.rotate90().rescale(1),lowerLeft=Vector2.sub(cur,dirN),upperLeft=Vector2.add(cur,dirN),lowerRight=Vector2.sub(next,dirN),upperRight=Vector2.add(next,dirN);if(vertices.push(lowerLeft[0],lowerLeft[1],upperLeft[0],upperLeft[1],lowerRight[0],lowerRight[1],upperRight[0],upperRight[1]),normals.push(-leftNormal[0],-leftNormal[1],leftNormal[0],leftNormal[1],-rightNormal[0],-rightNormal[1],rightNormal[0],rightNormal[1]),triangles.push(baseTris,baseTris+1,baseTris+3,baseTris,baseTris+3,baseTris+2),0!==i){const toPrevUpper=Vector2.sub(prevUpperRight,upperLeft);Vector2.signedAngle(dirN,toPrevUpper)<0?triangles.push(baseTris,baseTris-2,baseTris+1):triangles.push(baseTris,baseTris-1,baseTris+1)}else firstUpperLeft=upperLeft,firstDirN=dirN;if(i===points.length-1){const toLastUpper=Vector2.sub(upperRight,firstUpperLeft);Vector2.signedAngle(firstDirN,toLastUpper)<0?triangles.push(0,baseTris-2,1):triangles.push(0,baseTris-1,1)}prevUpperRight=upperRight,baseTris+=4}return{vertices:vertices,triangles:triangles,normals:normals}};static from(vertices,triangles,vertexShader,fragmentShader,uniforms,normals){const geometry=new PIXI.Geometry;geometry.addAttribute("inputVerts",vertices,2),normals&&geometry.addAttribute("inputNormals",normals,2),geometry.addIndex(triangles);const shader=PIXI.Shader.from(vertexShader,fragmentShader,uniforms);return new PIXI.Mesh(geometry,shader)}}class OutlineModule extends ModuleInterface{outlineDict={};spawned=[];static vertexShader;static fragmentShader;config={baseWidth:.1,minZoom:0,maxZoom:18,minExtraWidth:.1,maxExtraWidth:10};state={extraWidth:1};scaling;constructor(config){super(),config&&(isNaN(config.minZoom)||(this.config.minZoom=config.minZoom),isNaN(config.maxZoom)||(this.config.maxZoom=config.maxZoom),isNaN(config.minExtraWidth)||(this.config.minExtraWidth=config.minExtraWidth),isNaN(config.maxExtraWidth)||(this.config.maxExtraWidth=config.maxExtraWidth))}set(data){const project=this.pixiOverlay.utils.latLngToLayerPoint;this.clear(),data.forEach((outlineCollection=>{const uniforms={color:outlineCollection.meta.stroke,width:this.state.extraWidth,visible:!0};this.outlineDict[outlineCollection.meta.name]=uniforms;const coordinates=outlineCollection.coordinates;for(let n=0;n<coordinates.length;n++){const polygon=coordinates[n],projected=[];for(let i=0;i<polygon.length;i++){const p=polygon[i],pos=project(p);projected.push([pos.x,pos.y])}let outlineData;if(Vector2.equals(projected[0],projected[projected.length-1],1e-6)){if(projected.pop(),projected.length<=2){log(`Skipping outline (Polygon) with ${projected.length} points.`);continue}outlineData=Mesh.PolygonOutline(projected,this.config.baseWidth)}else{if(projected.length<=1){log(`Skipping outline (Line) with ${projected.length} points.`);continue}outlineData=Mesh.SimpleLine(projected,this.config.baseWidth)}const outline=Mesh.from(outlineData.vertices,outlineData.triangles,OutlineModule.vertexShader,OutlineModule.fragmentShader,uniforms,outlineData.normals);this.root.addChild(outline),this.spawned.push(outline)}}))}setVisibleLayers(names){Object.keys(this.outlineDict).forEach((key=>this.outlineDict[key].visible=!1)),names.forEach((name=>{const uniforms=this.outlineDict[name];uniforms&&(uniforms.visible=!0)}))}clear(){for(;this.spawned.length>0;){const temp=this.spawned.pop();this.root.removeChild(temp),temp.destroy()}this.outlineDict={}}resize(zoom){const t=inverseLerp(this.config.minZoom,this.config.maxZoom,zoom),width=lerp(this.config.maxExtraWidth,this.config.minExtraWidth,t);this.state.extraWidth=width,Object.keys(this.outlineDict).forEach((key=>{this.outlineDict[key].width=width}))}}function toShader(n){return n===Math.floor(n)?`${n.toString()}.0`:n.toString()}OutlineModule.vertexShader="\n attribute vec2 inputVerts;\n attribute vec2 inputNormals;\n\n uniform mat3 translationMatrix;\n uniform mat3 projectionMatrix;\n\n uniform float width;\n\n void main() {\n vec2 pos = inputVerts + inputNormals * width;\n gl_Position = vec4((projectionMatrix * translationMatrix * vec3(pos, 1.0)).xy, 0.0, 1.0);\n }\n",OutlineModule.fragmentShader="\n precision mediump float;\n\n uniform vec3 color;\n uniform bool visible;\n\n void main() {\n if (!visible) discard;\n gl_FragColor = vec4(color, 1.0);\n }\n";class WellboreShader{static program=null;static get(color,completionVisible,wellboreVisible){return new PIXI.Shader(WellboreShader.program,{wellboreColor1:color.col1,wellboreColor2:color.col2,completionVisible:completionVisible,wellboreVisible:wellboreVisible,status:0})}static build(maxScale,wellboreDash){const vertex=`\n attribute vec2 verts;\n attribute vec4 vertCol;\n attribute float typeData;\n\n uniform mat3 translationMatrix;\n uniform mat3 projectionMatrix;\n uniform float wellboreRadius;\n\n varying vec4 vCol;\n varying float type;\n\n void main() {\n vCol = vertCol;\n type = typeData;\n\n vec2 normal = vertCol.zw;\n\n float extraRadius = wellboreRadius - ${toShader(maxScale)};\n\n gl_Position = vec4((projectionMatrix * translationMatrix * vec3(verts + normal * extraRadius, 1.0)).xy, 0.0, 1.0);\n }\n `,dash=toShader(wellboreDash),doubleDash=toShader(2*wellboreDash),fragment=`\n precision mediump float;\n\n varying vec4 vCol;\n varying float type;\n\n uniform vec3 wellboreColor1;\n uniform vec3 wellboreColor2;\n uniform bool completionVisible;\n uniform bool wellboreVisible;\n uniform int status;\n\n const vec3 sunDir = vec3(0.6247, -0.6247, 0.4685);\n\n void main() {\n vec3 col = vec3(0.0);\n float alpha = 1.0;\n\n if (status == 0) {\n if(type == 0.0) {\n if (!wellboreVisible) {\n alpha = 0.03;\n }\n } else if (type == 1.0) {\n if(completionVisible){\n if(mod(vCol.x, ${doubleDash}) > ${dash}) discard;\n } else if(!wellboreVisible){\n alpha = 0.03;\n }\n }\n if (!completionVisible && type == 2.0) discard;\n\n float dist = clamp(vCol.z * vCol.z + vCol.w * vCol.w, 0.0, 1.0);\n\n vec3 dir3D = vec3(vCol.zw, sqrt(1.0 - dist * dist));\n\n float light = 0.4 + dot(dir3D, sunDir) * 0.6;\n light = clamp(light, 0.0, 1.0);\n\n col = mix(wellboreColor2, wellboreColor1, light);\n }\n\n else if (status == 1) {\n if (type == 2.0) discard;\n if(mod(vCol.x + vCol.y * 0.2, ${toShader(4*wellboreDash)}) > ${doubleDash}) discard;\n vec3 c = wellboreColor2 + wellboreColor1 * 0.5;\n vec3 gray = vec3(0.9);\n col = mix(gray, c, 0.3);\n }\n\n else if (status == 2) {\n if (type == 2.0) discard;\n alpha = 0.03;\n }\n\n col *= alpha;\n gl_FragColor = vec4(col, alpha);\n }\n `;WellboreShader.program=new PIXI.Program(vertex,fragment)}}class RootShader{static program=null;static get(){return new PIXI.Shader(RootShader.program,{active:!0,circleColor1:[0,0,0],circleColor2:[0,0,0]})}static build(maxScale){const vertex=`\n attribute vec2 verts;\n attribute vec2 inputUVs;\n\n uniform mat3 translationMatrix;\n uniform mat3 projectionMatrix;\n uniform float rootRadius;\n\n varying vec2 UVs;\n\n void main() {\n UVs = inputUVs;\n\n vec2 dir = 2.0 * inputUVs - 1.0;\n\n float extraRadius = rootRadius - ${toShader(maxScale)};\n\n gl_Position = vec4((projectionMatrix * translationMatrix * vec3(verts + dir * extraRadius, 1.0)).xy, 0.0, 1.0);\n }\n `;RootShader.program=new PIXI.Program(vertex,"\n precision mediump float;\n\n varying vec2 UVs;\n\n uniform vec3 circleColor1;\n uniform vec3 circleColor2;\n uniform bool active;\n\n const vec3 sunDir = vec3(0.6247, -0.6247, 0.4685);\n\n void main() {\n if (!active) {\n discard;\n return;\n }\n vec2 dir = 2.0 * UVs - 1.0;\n float dist = dir.x * dir.x + dir.y * dir.y;\n if (dist > 1.0) discard;\n\n vec3 dir3D = vec3(dir, sqrt(1.0 - dist * dist));\n\n float light = dot(dir3D, sunDir);\n light = 0.4 + light * 0.6;\n\n vec3 col = mix(circleColor2, circleColor1, clamp(light, 0.0, 1.0));\n\n gl_FragColor = vec4(col, 1.0);\n }\n ")}}function generateCircle(center,radius,shader){const geometry=new PIXI.Geometry;geometry.addAttribute("verts",[center[0]-radius,center[1]-radius,center[0]+radius,center[1]-radius,center[0]-radius,center[1]+radius,center[0]+radius,center[1]+radius],2),geometry.addAttribute("inputUVs",[0,0,1,0,0,1,1,1],2),geometry.addIndex([0,2,3,0,3,1]);return new PIXI.Mesh(geometry,shader)}class Label{static state={zoom:1,scale:1,visible:!0,rootDisplacement:1};static style;static config;static height;container;text;background;metrics;_attachToRoot=!1;static setStyle(fontSize){Label.style=new PIXI.TextStyle({fontFamily:"Arial",fontSize:fontSize,fill:16777215,align:"center"}),Label.height=PIXI.TextMetrics.measureText(" ",Label.style).height}static setCommon(config){Label.config=config}constructor(label,fontColor,bgColor){const metrics=PIXI.TextMetrics.measureText(label,Label.style);this.metrics=metrics;const container=new PIXI.Container;container.visible=Label.state.visible,container.zIndex=0,this.container=container;const background=new PIXI.Graphics;background.beginFill(16777215),background.drawRect(.55*-metrics.width,.525*-Label.height,1.1*metrics.width,1.05*Label.height),background.endFill(),background.alpha=Label.config.backgroundOpacity,background.tint=bgColor,this.background=background;const text=new PIXI.Text(label,Label.style);text.resolution=window.devicePixelRatio,text.tint=fontColor,text.anchor.set(.5),this.text=text,container.addChild(background,text)}get visible(){return this.container.visible}set visible(flag){this.container.visible=flag&&Label.state.visible}set fontColor(color){this.text.tint=color}get attachToRoot(){return this._attachToRoot}set attachToRoot(val){val!==this._attachToRoot&&(this._attachToRoot=val)}getBoundingBox(){const{y:y,width:width,height:height}=this.container,x=this.container.x-width/2;return new PIXI.Rectangle(x,y,width,height)}}class RootData{static state={rootRadius:1,maxScale:1};mesh;wellbores=[];position;labelIndex=0;rootLabelsBBox=null;target=null;constructor(position){this.position=position;const shader=RootShader.get();this.mesh=generateCircle(position,RootData.state.maxScale,shader)}get active(){return this.target&&this.target.active}updateLabelsBBox(label){const bbox=label.getBoundingBox();this.rootLabelsBBox?(this.rootLabelsBBox.height=bbox.y+bbox.height-this.rootLabelsBBox.y,bbox.width>this.rootLabelsBBox.width&&(this.rootLabelsBBox.x=bbox.x,this.rootLabelsBBox.width=bbox.width)):this.rootLabelsBBox=bbox}positionLabel(wellbore){if(wellbore.label.attachToRoot){!function(wellbore,position){wellbore.label.attachToRoot=!0;const{container:container}=wellbore.label,{scale:scale,rootDisplacement:rootDisplacement}=Label.state;container.rotation=0,container.pivot.set(0,.5*-Label.height);const yPos=rootDisplacement+5*scale+position*(Label.height+5)*scale+wellbore.root.position[1];container.position.set(wellbore.root.position[0],yPos),container.scale.set(scale)}(wellbore,this.labelIndex++),this.updateLabelsBBox(wellbore.label)}else!function(wellbore){wellbore.label.attachToRoot=!1;const{container:container,metrics:metrics}=wellbore.label,end=wellbore.interpolator.GetPoint(1).position,width=metrics.width*Label.state.scale,start=wellbore.interpolator.GetPointFromEnd(width),dir=Vector2.sub(end,start.position).mutable;let pivotX,pivotY,angle,pos;const mirror=!!wellbore.group?.mirrorLabels;dir.x<0?mirror?(pivotX=.5*-metrics.width,pivotY=.5*metrics.height,angle=Vector2.signedAngle(Vector2.left,dir),pos=dir.rotate90().rescale(.5*wellbore.wellboreWidth+.075).add(end)):(pivotX=.5*-metrics.width,pivotY=.5*-metrics.height,angle=Vector2.signedAngle(Vector2.left,dir),pos=dir.rotate270().rescale(.5*wellbore.wellboreWidth+.075).add(end)):mirror?(pivotX=.5*metrics.width,pivotY=.5*metrics.height,angle=Vector2.signedAngle(Vector2.right,dir),pos=dir.rotate270().rescale(.5*wellbore.wellboreWidth+.075).add(end)):(pivotX=.5*metrics.width,pivotY=.5*-metrics.height,angle=Vector2.signedAngle(Vector2.right,dir),pos=dir.rotate90().rescale(.5*wellbore.wellboreWidth+.075).add(end)),container.position.set(pos[0],pos[1]),container.pivot.set(pivotX,pivotY),container.rotation=angle,container.scale.set(Label.state.scale)}(wellbore)}append(wellbore){this.wellbores.push(wellbore),wellbore.active&&(this.target?wellbore.order<this.target.order&&wellbore.status>this.target.status?this.recalculate(!0):this.positionLabel(wellbore):this.recalculate(!0))}recalculate(labelUpdate=!1){this.updateTarget(),this.updateUniforms(),labelUpdate&&this.updateLabels()}updateTarget(){let target,smallest=Number.MAX_VALUE;for(let i=0;i<this.wellbores.length;i++){const wellbore=this.wellbores[i];if(!wellbore.active)continue;if(wellbore.selected){target=wellbore;break}const weighted=wellbore.order-1e6*wellbore.status;weighted<smallest&&(smallest=weighted,target=wellbore)}this.target=target}updateUniforms(){const uniform=this.mesh.shader.uniforms;if(uniform.active=this.active,this.target){const color=this.target.color;uniform.circleColor1=color.col1,uniform.circleColor2=color.col2,this.mesh.zIndex=this.target.status}uniform.rootRadius=RootData.state.rootRadius}updateLabels(){this.labelIndex=0,this.rootLabelsBBox=null,this.wellbores.forEach((wellbore=>{wellbore.active&&this.positionLabel(wellbore)}))}setLabelVisibility(visible){visible?this.updateLabels():this.rootLabelsBBox=null,this.wellbores.forEach((wellbore=>{wellbore.active&&(wellbore.label.visible=visible)}))}}class LineInterpolator{amount;length;singlePoint=!0;path;constructor(points,radius){const amount=points.length,path=new Array(amount),root=points[0];let initDir;initDir=points.length>=2?Vector2.sub(points[1],points[0]).normalize():Vector2.right,path[0]={point:root,direction:initDir,distance:0,relative:0};let length=0;for(let i=1;i<amount;i++){const point=points[i];length+=Vector2.distance(point,path[i-1].point),path[i]={point:point,direction:this.GetDirection(points,i),distance:length,relative:0},Vector2.distance(point,root)>radius&&(this.singlePoint=!1)}for(let i=1;i<amount;i++){const p=path[i];p.relative=0===length?0:p.distance/length}this.amount=amount,this.length=length,this.path=path}GetPoint(relative){if(this.singlePoint)return{position:this.path[0].point,direction:Vector2.up,distance:0};if(relative<0){const first=this.path[0];return{position:first.point,direction:first.direction,distance:0}}if(relative>=1){const last=this.path[this.amount-1];return{position:last.point,direction:last.direction,distance:this.length}}const base=this.GetClosestPointBelow(relative),prev=this.path[base],cur=this.path[base+1],dist=cur.relative-prev.relative,frac=(relative-prev.relative)/dist;return{position:mix(prev.point,cur.point,frac,Vector2.zero),direction:Vector2.lerpRot(prev.direction,cur.direction,frac).normalize(),distance:prev.distance*(1-frac)+cur.distance*frac}}GetSection(relativeStart,relativeEnd){if(this.singlePoint)return[{position:this.path[0].point,direction:Vector2.up,distance:0},{position:this.path[0].point,direction:Vector2.up,distance:0}];if(relativeStart>=1){const last=this.path[this.path.length-1];return[{position:last.point,direction:last.direction,distance:this.length},{position:last.point,direction:last.direction,distance:this.length}]}const base=this.GetClosestPointBelow(relativeStart),points=[],prev=this.path[base],cur=this.path[base+1],dist=cur.relative-prev.relative,frac=(relativeStart-prev.relative)/dist;points.push({position:mix(prev.point,cur.point,frac,Vector2.zero),direction:Vector2.lerpRot(prev.direction,cur.direction,frac).normalize(),distance:prev.distance*(1-frac)+cur.distance*frac});for(let i=base+1;i<this.amount;i++){const cur=this.path[i];if(cur.relative>=relativeEnd){const cur=this.path[i],prev=this.path[i-1],dist=cur.relative-prev.relative,frac=(relativeEnd-prev.relative)/dist;points.push({position:mix(prev.point,cur.point,frac,Vector2.zero),direction:Vector2.lerpRot(prev.direction,cur.direction,frac).normalize(),distance:prev.distance*(1-frac)+cur.distance*frac});break}points.push({position:cur.point,direction:this.path[i].direction,distance:cur.distance})}return points}GetClosestPointBelow(relative){let base=0,range=this.amount,idx=Math.floor(.5*range);for(;range>1;)relative<this.path[idx].relative?(range=Math.floor(.5*range),idx=base+Math.floor(.5*range)):(base+=Math.floor(.5*range),range=Math.ceil(.5*range),idx=base+Math.floor(.5*range));return base}GetPointFromStart(distance){const relative=distance/this.length;return this.GetPoint(relative)}GetPointFromEnd(distance){const relative=1-distance/this.length;return this.GetPoint(relative)}GetRangeFromStart(relative,width,resolution=10){const relativeDisp=(relative+width/this.length-relative)/resolution,points=[];for(let i=0;i<=resolution;i++)points.push(this.GetPoint(relative+relativeDisp*i));return points}GetDirection(points,idx){const end=points.length-1;if(0===idx)return Vector2.sub(points[1],points[0]).normalize();if(idx===end)return Vector2.sub(points[end],points[end-1]).normalize();{const cur=points[idx],to=Vector2.sub(cur,points[idx-1]),from=Vector2.sub(points[idx+1],cur);return Vector2.lerpRot(to,from,.5).normalize()}}}class WellboreMesh{interp;thickness;baseTris;tick;constructor(interp,thickness,tick){this.interp=interp,this.thickness=thickness,this.baseTris=0,this.tick=tick}generate(intervals=[]){const vertices=[],triangles=[],vertexData=[],extraData=[];if(intervals.length<=0){const path=this.interp.GetSection(0,1);this.appendSegment(path,0,vertices,triangles,vertexData,extraData)}else if(intervals.length>0){let p=0;intervals.forEach((i=>{const path1=this.interp.GetSection(p,i[0]);this.appendSegment(path1,0,vertices,triangles,vertexData,extraData);const path2=this.interp.GetSection(i[0],i[1]);this.appendSegment(path2,1,vertices,triangles,vertexData,extraData),p=i[1]}));const end=intervals[intervals.length-1][1];if(end<1){const lastPath=this.interp.GetSection(end,1);this.appendSegment(lastPath,0,vertices,triangles,vertexData,extraData)}}return intervals.forEach((i=>{const p1=this.interp.GetPoint(i[0]);if(this.generateCrossline(p1,vertices,triangles,vertexData,extraData),Math.abs(i[0]-i[1])<.001)return;const p2=this.interp.GetPoint(i[1]);this.generateCrossline(p2,vertices,triangles,vertexData,extraData)})),{vertices:vertices,triangles:triangles,vertexData:vertexData,extraData:extraData}}appendSegment(section,type,vertices,triangles,vertexData,extraData){const mesh=Mesh.WellboreSegment(section,this.thickness,type);vertices.push(...mesh.vertices),mesh.triangles.forEach((d=>triangles.push(d+this.baseTris))),vertexData.push(...mesh.vertexData),extraData.push(...mesh.extraData),this.baseTris+=mesh.vertices.length/2}generateCrossline(p,vertices,triangles,vertexData,extraData){const px=p.position[0],py=p.position[1],crosslinesWidth=this.tick.width,dirX=p.direction[0]*crosslinesWidth,dirY=p.direction[1]*crosslinesWidth,crosslinesHeight=this.tick.height,normX=-p.direction[1]*crosslinesHeight,normY=p.direction[0]*crosslinesHeight;vertices.push(px-dirX-normX,py-dirY-normY,px+dirX-normX,py+dirY-normY,px-dirX+normX,py-dirY+normY,px+dirX+normX,py+dirY+normY),triangles.push(this.baseTris,this.baseTris+2,this.baseTris+3,this.baseTris,this.baseTris+3,this.baseTris+1),extraData.push(2,2,2,2);const normalizedNormal=new Vector2(normX,normY).normalized(),nnx=normalizedNormal.x,nny=normalizedNormal.y;vertexData.push(p.distance,0,-nnx,-nny,p.distance,0,-nnx,-nny,p.distance,1,nnx,nny,p.distance,1,nnx,nny),this.baseTris+=4}}var WellboreStatus,FilterStatus,ColorType;!function(WellboreStatus){WellboreStatus[WellboreStatus.normal=0]="normal",WellboreStatus[WellboreStatus.highlighted=1]="highlighted",WellboreStatus[WellboreStatus.multiHighlighted=2]="multiHighlighted",WellboreStatus[WellboreStatus.selected=3]="selected"}(WellboreStatus||(WellboreStatus={})),function(FilterStatus){FilterStatus[FilterStatus.none=0]="none",FilterStatus[FilterStatus.soft=1]="soft",FilterStatus[FilterStatus.hard=2]="hard"}(FilterStatus||(FilterStatus={}));class WellboreData{static state={wellboreRadius:1,rootRadius:1};data;group;wellboreWidth;interpolator;container;label;_zIndex=0;details;detailsDict={};mesh;root;status=WellboreStatus.normal;filter=FilterStatus.none;constructor(input){if(this.data=input.data,this.group=input.group,this.root=input.root,this.wellboreWidth=input.wellboreWidth,this.interpolator=new LineInterpolator(input.coords,input.pointThreshold),this.label=new Label(input.data.labelShort,this.colors.fontColor,this.colors.default.labelBg),this.interpolator.singlePoint)this.label.attachToRoot=!0;else{this.container=new PIXI.Container;const intervals=function(intervals){let output=intervals.map((i=>[i.l1,i.l2])).sort(((a,b)=>a[0]<b[0]?-1:a[0]>b[0]?1:0));return output.length>0&&(output=function(intervals){const output=[];let prev=intervals[0].slice(0);for(let i=1;i<intervals.length;i++){const cur=intervals[i].slice(0);cur[0]<prev[1]?cur[1]>prev[1]&&(prev[1]=cur[1]):(output.push(prev),prev=cur)}return output.push(prev),output}(output)),output}(input.data.intervals);this.details=new PIXI.Container,this.mesh=this.createWellboreMesh(intervals,input.tick),this.container.addChild(this.details,this.mesh)}this.update()}set zIndex(val){this._zIndex=val,this.container&&(this.container.zIndex=this._zIndex)}get colors(){return this.group.colors}get color(){const{colors:colors}=this.group;switch(this.status){case WellboreStatus.normal:return colors.default;case WellboreStatus.highlighted:return colors.highlight;case WellboreStatus.multiHighlighted:return colors.multiHighlight;case WellboreStatus.selected:return colors.selected}}get active(){const activeUniform=this.mesh&&0===this.mesh.shader.uniforms.status;return this.group.active&&(activeUniform||this.filter===FilterStatus.none)}tryDrawDetail(key,detail){if(!this.container)return;const relative=detail.getRelative(this.data);if(!Array.isArray(relative)||0===relative.length)return;const container=new PIXI.Container;container.visible=detail.visible,relative.forEach((p=>{const graphics=detail.getGraphics(p,this.interpolator);container.addChild(graphics)})),this.details.addChild(container),this.detailsDict[key]=container}setFilter(filter){this.filter!==filter&&(this.filter=filter,this.update())}get selected(){return this.status===WellboreStatus.selected}get highlighted(){return this.status===WellboreStatus.highlighted||this.status===WellboreStatus.multiHighlighted}get order(){return this.group.order}get uniforms(){return this.mesh.shader.uniforms}createWellboreMesh(intervals,tick){const line=new WellboreMesh(this.interpolator,this.wellboreWidth,tick),{vertices:vertices,triangles:triangles,vertexData:vertexData,extraData:extraData}=line.generate(intervals),geometry=new PIXI.Geometry;geometry.addAttribute("verts",vertices,2),geometry.addAttribute("vertCol",vertexData,4),geometry.addAttribute("typeData",extraData,1),geometry.addIndex(triangles);const shader=WellboreShader.get(this.colors.default,this.group.state.completionVisible,this.group.state.wellboreVisible);return new PIXI.Mesh(geometry,shader)}setCompletionVisibility(visible){this.mesh&&(this.uniforms.completionVisible=visible)}setWellboreVisibility(visible){this.mesh&&(this.uniforms.wellboreVisible=visible)}setDetailsVisibility(key,visible){key in this.detailsDict&&(this.detailsDict[key].visible=visible)}setHighlight(isHighlighted,multiple=!1){if(this.status!==WellboreStatus.selected)if(this.status=isHighlighted?multiple?WellboreStatus.multiHighlighted:WellboreStatus.highlighted:WellboreStatus.normal,isHighlighted){const color=multiple?this.colors.multiHighlight:this.colors.highlight;this.mesh&&(this.mesh.shader.uniforms.wellboreColor1=color.col1,this.mesh.shader.uniforms.wellboreColor2=color.col2,this.container.zIndex=this._zIndex+1e5),this.label.container.zIndex=1,this.label.background.tint=color.labelBg,this.label.background.alpha=.75,this.label.fontColor=this.colors.interactFontColor}else this.mesh&&(this.mesh.shader.uniforms.wellboreColor1=this.colors.default.col1,this.mesh.shader.uniforms.wellboreColor2=this.colors.default.col2,this.container.zIndex=this._zIndex),this.label.container.zIndex=0,this.label.background.tint=this.colors.default.labelBg,this.label.background.alpha=Label.config.backgroundOpacity,this.label.fontColor=this.colors.fontColor}setSelected(isSelected){this.status=isSelected?WellboreStatus.selected:WellboreStatus.normal,isSelected?(this.mesh&&(this.mesh.shader.uniforms.wellboreColor1=this.colors.selected.col1,this.mesh.shader.uniforms.wellboreColor2=this.colors.selected.col2,this.container.zIndex=this._zIndex+1e6),this.label.container.zIndex=1,this.label.background.tint=this.colors.selected.labelBg,this.label.background.alpha=.75):(this.mesh&&(this.mesh.shader.uniforms.wellboreColor1=this.colors.default.col1,this.mesh.shader.uniforms.wellboreColor2=this.colors.default.col2,this.container.zIndex=this._zIndex),this.label.container.zIndex=0,this.label.background.tint=this.colors.default.labelBg,this.label.background.alpha=Label.config.backgroundOpacity),this.label.fontColor=this.colors.fontColor,this.root.recalculate()}update(){if(this.group.active){const noFilter=this.filter===FilterStatus.none;this.container&&(this.container.visible=!0,this.mesh.shader.uniforms.status=this.filter,this.mesh.shader.uniforms.wellboreRadius=WellboreData.state.wellboreRadius,this.mesh.shader.uniforms.rootRadius=WellboreData.state.rootRadius,this.details.visible=noFilter),this.label.visible=noFilter}else this.container&&(this.container.visible=!1,this.details.visible=!1),this.label.visible=!1}}function getDefaultColors(input){const output={fontColor:0,interactFontColor:16777215,default:{col1:[.3,.3,.3],col2:[.05,.05,.05],labelBg:16777215},highlight:{col1:[.8,.2,.9],col2:[.5,.05,.6],labelBg:10685091},multiHighlight:{col1:[.55,.55,.55],col2:[.3,.3,.3],labelBg:6710886},selected:{col1:[1,0,0],col2:[.5,0,0],labelBg:16777215}};if(!input)return output;function transfer(key){isNaN(input[key])||(output[key]=input[key])}function transferColor(color){const inputCol1=input[`${color}Color1`],inputCol2=input[`${color}Color2`],inputLabelBg=input[`${color}LabelBg`],outputColor=output[color];inputCol1&&(outputColor.col1=inputCol1),inputCol2&&(outputColor.col2=inputCol2),inputLabelBg&&(outputColor.labelBg=inputLabelBg)}return transfer("fontColor"),transfer("interactFontColor"),transferColor("default"),transferColor("highlight"),transferColor("multiHighlight"),transferColor("selected"),output}!function(ColorType){ColorType[ColorType.Default=0]="Default",ColorType[ColorType.Highlight=1]="Highlight",ColorType[ColorType.MultiHighlight=2]="MultiHighlight",ColorType[ColorType.Selected=3]="Selected"}(ColorType||(ColorType={}));class Detail{initialized=!1;visible=!1;getData;color;group;constructor(options,group="default"){this.getData=options.getData,this.color=new PIXI.Color(options.color||[0,0,0]),this.group=group}getRelative(wellbore){return this.getData(wellbore,this.group)}}class ShoeDetail extends Detail{widthTop;widthBottom;constructor(options,group="default"){super(options,group),this.widthTop=options.widthTop||1,this.widthBottom=options.widthBottom||1}getGraphics([top,bottom],interpolator){const from=interpolator.GetPoint(top).position,to=interpolator.GetPoint(bottom).position,normal=Vector2.sub(to,from).rotate90().normalize(),normalTop=normal.scale(this.widthTop),normalBottom=normal.scale(this.widthBottom),from1=Vector2.add(from,normalTop),from2=Vector2.sub(from,normalTop),to1=Vector2.add(to,normalBottom),to2=Vector2.sub(to,normalBottom);return(new PIXI.Graphics).beginFill(this.color,1).lineStyle(0).moveTo(from1.x,from1.y).lineTo(to1.x,to1.y).lineTo(to2.x,to2.y).lineTo(from2.x,from2.y).endFill()}}class Group{key;colors;order=0;mirrorLabels=!1;wellbores=[];details={};active=!0;activeFilter=null;isHardFilter;state={completionVisible:!0,wellboreVisible:!0};constructor(key,options){this.key=key,options?(isNaN(options.order)||(this.order=options.order),options.mirrorLabels&&(this.mirrorLabels=options.mirrorLabels),this.colors=getDefaultColors(options.colors)):this.colors=getDefaultColors()}registerDetail(key,detail){if(key in this.details)throw Error(`Detail already registered, ${key}, for group: ${this.key}!`);this.details[key]=((options,group="default")=>{const{shape:shape}=options;return new ShoeDetail(options,group)})(detail)}setDetailVisibility(key,visible){if(key in this.details){const detail=this.details[key];if(visible&&!detail.initialized&&(this.wellbores.forEach((wellbore=>{wellbore.tryDrawDetail(key,detail)})),detail.initialized=!0),visible===detail.visible)return;this.wellbores.forEach((wellbore=>{wellbore.setDetailsVisibility(key,visible)})),detail.visible=visible}}resetDetails(){Object.values(this.details).forEach((detail=>{detail.initialized=!1}))}append(wellbore){if(wellbore.zIndex=1e4*this.order+this.wellbores.length,this.activeFilter){const targetFilter=this.isHardFilter?FilterStatus.hard:FilterStatus.soft;wellbore.setFilter(this.activeFilter(wellbore.data)?FilterStatus.none:targetFilter),wellbore.root.recalculate(!0)}Object.entries(this.details).forEach((([key,detail])=>{detail.initialized&&wellbore.tryDrawDetail(key,detail)})),this.wellbores.push(wellbore)}forAll(wellboreFunc,rootFunc){const roots=new Set,wellbores=this.wellbores;for(let i=0;i<wellbores.length;i++){const wellbore=wellbores[i];wellboreFunc(wellbore),roots.add(wellbore.root)}roots.forEach((root=>rootFunc(root)))}setActive(active){this.active!==active&&(this.active=active,this.forAll((wellbore=>wellbore.update()),(root=>root.recalculate(!0))))}softFilter(filter){this.activeFilter=filter,this.isHardFilter=!1,this.forAll((wellbore=>wellbore.setFilter(filter(wellbore.data)?FilterStatus.none:FilterStatus.soft)),(root=>root.recalculate(!0)))}hardFilter(filter){this.activeFilter=filter,this.isHardFilter=!0,this.forAll((wellbore=>wellbore.setFilter(filter(wellbore.data)?FilterStatus.none:FilterStatus.hard)),(root=>root.recalculate(!0)))}clearFilter(){this.activeFilter=null,this.forAll((wellbore=>wellbore.setFilter(FilterStatus.none)),(root=>root.recalculate(!0)))}setCompletionVisibility(visible){this.state.completionVisible=visible,this.wellbores.forEach((wellbore=>{wellbore.setCompletionVisibility(visible)}))}setWellboreVisibility(visible){this.state.wellboreVisible=visible,this.wellbores.forEach((wellbore=>{wellbore.setWellboreVisibility(visible)}))}}class WellboreEventData{group;data;constructor(group,data){this.group=group,this.data=data}static from(wellbore){return new WellboreEventData(wellbore.group.key,wellbore.data)}}class HighlightEvent{changed;originalEvent;eventData;constructor(eventData,changed,originalEvent){this.eventData=eventData,this.changed=changed,this.originalEvent=originalEvent}static from(wellbores,changed,originalEvent){return new HighlightEvent(wellbores.map((w=>new WellboreEventData(w.group.key,w.data))),changed,originalEvent)}get count(){return this.eventData.length}}function distanceToLine(point,lineStart,lineEnd){const lineDir=Vector2.sub(lineEnd,lineStart),lineAngle=Vector2.angleRight(lineDir),len=lineDir.magnitude,dir=Vector2.sub(point,lineStart).mutable.rotate(-lineAngle);return dir[0]<0?dir.magnitude:dir[0]>len?Vector2.distance(point,lineEnd):Math.abs(dir.y)}class LineDictionary{gridsize;tiles=new Map;lineValues=new Map;testActiveFunction;lineSeq;constructor(gridsize=10,testActive){this.gridsize=gridsize,this.lineSeq=0,this.testActiveFunction=testActive}add(points,value,id){const lineID=Number.isFinite(id)?id:++this.lineSeq,line={id:lineID,value:value,segments:[]};this.lineValues.set(lineID,line);for(let i=1;i<points.length;i++){const p1=points[i-1],p2=points[i];this.addSegment(p1[0],p1[1],p2[0],p2[1],line)}return line}addSegment(x1,y1,x2,y2,line){const segment={lineID:line.id,geometry:{x1:x1,y1:y1,x2:x2,y2:y2}};line.segments.push(segment);const intersections=function(x1,x2,y1,y2,gridsize){const intersections=new Set;let downwards,xMin,xMax,yMin,yMax,m,y0;if(x1<x2){xMin=Math.floor(x1/gridsize),xMax=Math.floor(x2/gridsize),m=(y2-y1)/(x2-x1),y0=(y1-x1*m)/gridsize,downwards=y2<y1;const key=`${Math.floor(x1/gridsize)}.${Math.floor(y1/gridsize)}`;intersections.add(key)}else{xMin=Math.floor(x2/gridsize),xMax=Math.floor(x1/gridsize),m=(y1-y2)/(x1-x2),y0=(y2-x2*m)/gridsize,downwards=y1<y2;const key=`${Math.floor(x2/gridsize)}.${Math.floor(y2/gridsize)}`;intersections.add(key)}y1<y2?(yMin=Math.floor(y1/gridsize),yMax=Math.floor(y2/gridsize)):(yMin=Math.floor(y2/gridsize),yMax=Math.floor(y1/gridsize));for(let x=xMin+1;x<=xMax;x++){const y=y0+x*m;intersections.add(`${x}.${Math.floor(y)}`)}for(let y=yMin+1;y<=yMax;y++){const x=(y-y0)/m;intersections.add(`${Math.floor(x)}.${Math.floor(downwards?y-1:y)}`)}return intersections}(x1,x2,y1,y2,this.gridsize);intersections.forEach((key=>{this.tiles.has(key)?this.tiles.get(key).push(segment):this.tiles.set(key,[segment])}))}getClosest(target,maxDist=1){const segments=this.getSegmentsOn3Grid(target);if(0===segments.size)return;let minDist=1/0,minLineID=-1;return segments.forEach((seg=>{const dist=distanceToLine(target,new Vector2(seg.geometry.x1,seg.geometry.y1),new Vector2(seg.geometry.x2,seg.geometry.y2));dist<minDist&&(minDist=dist,minLineID=seg.lineID)})),minDist>maxDist*this.gridsize?void 0:this.lineValues.get(minLineID).value}getAllClosest(target,epsilon=0,maxDist=1,filter){const segments=this.getSegmentsOn3Grid(target);if(0===segments.size)return[];let minDist=1/0,minID=-1,extraLines=[];if(segments.forEach((seg=>{const distance=distanceToLine(target,new Vector2(seg.geometry.x1,seg.geometry.y1),new Vector2(seg.geometry.x2,seg.geometry.y2));if(distance<minDist+epsilon)if(distance<minDist){const upperLimit=distance+epsilon,newLines=[];minDist<=upperLimit&&newLines.push({ID:minID,distance:minDist}),extraLines.forEach((d=>{d.distance<=upperLimit&&newLines.push(d)})),extraLines=newLines,minDist=distance,minID=seg.lineID}else extraLines.push({ID:seg.lineID,distance:distance})})),minDist>maxDist*this.gridsize)return[];const unique={[minID]:!0},uniqueLines=[];extraLines.forEach((d=>{unique.hasOwnProperty(d.ID)||(unique[d.ID]=!0,uniqueLines.push(d))}));const minT=this.lineValues.get(minID).value;let extraT=uniqueLines.map((d=>this.lineValues.get(d.ID).value));if(filter){const filtered=[];extraT.forEach((curT=>{filter(minT,curT)&&filtered.push(curT)})),extraT=filtered}return[minT,...extraT]}isActive(line){return!this.testActiveFunction||line&&this.testActiveFunction(line.value)}getSegmentsOn3Grid(target){const gridSegments=new Set,keyX=Math.floor(target[0]/this.gridsize),keyY=Math.floor(target[1]/this.gridsize);for(let x=-1;x<=1;x++)for(let y=-1;y<=1;y++){const key=`${keyX+x}.${keyY+y}`;this.tiles.has(key)&&this.tiles.get(key).forEach((tileSegment=>{gridSegments.has(tileSegment)||this.isActive(this.lineValues.get(tileSegment.lineID))&&gridSegments.add(tileSegment)}))}return gridSegments}clear(filter){if(filter){const segmentsToDelete=new Set;this.lineValues.forEach(((line,key)=>{filter(line.value,key)&&(line.segments.forEach(segmentsToDelete.add,segmentsToDelete),this.lineValues.delete(key))})),segmentsToDelete.size>0&&this.tiles.forEach(((list,key)=>{const filtered=list.filter((s=>!segmentsToDelete.has(s)));filtered.length>0?this.tiles.set(key,filtered):this.tiles.delete(key)}))}else this.tiles=new Map,this.lineValues=new Map}}class PointDictionary{distThreshold;gridSize;radius;tiles=new Map;pointValues=new Map;testActiveFunction;pointSeq=0;constructor(distThreshold,gridSize=2,radius,testActive){if(gridSize<radius)throw"Gridsize of point dictionary must be greater than scaled radius of root.";this.distThreshold=distThreshold,this.gridSize=gridSize,this.radius=radius,this.testActiveFunction=testActive}add(pos,val){const id=++this.pointSeq,point={val:val,pos:pos,id:id};this.pointValues.set(id,point);const keys=this.getKeys(pos);for(let i=0;i<keys.length;i++){const key=keys[i];if(this.tiles.has(key))this.tiles.get(key).set(id,point);else{const map=new Map;map.set(id,point),this.tiles.set(key,map)}}return id}getKeys(pos){const{radius:radius,gridSize:gridSize}=this,keyX=Math.floor(pos[0]/gridSize),keyY=Math.floor(pos[1]/gridSize),keys=[`${keyX}.${keyY}`],localX=pos[0]-keyX*gridSize,localY=pos[1]-keyY*gridSize,local=[localX,localY],addKey=(deltaX,deltaY)=>{keys.push(`${keyX+deltaX}.${keyY+deltaY}`)},tryAddDiagKey=(cornerLocal,deltaX,deltaY)=>{Vector2.distance(local,cornerLocal)<radius&&keys.push(`${keyX+deltaX}.${keyY+deltaY}`)};let l=!1,r=!1,d=!1,u=!1;return localX<radius&&(addKey(-1,0),l=!0),localX>gridSize-radius&&(addKey(1,0),r=!0),localY<radius&&(addKey(0,-1),d=!0),localY>gridSize-radius&&(addKey(0,1),u=!0),l?u?tryAddDiagKey([0,gridSize],-1,1):d&&tryAddDiagKey([0,0],-1,-1):r&&(u?tryAddDiagKey([gridSize,gridSize],1,1):d&&tryAddDiagKey([gridSize,0],1,-1)),keys}isActive(point){return!this.testActiveFunction||point&&this.testActiveFunction(point.val)}getKey(position){return`${Math.floor(position[0]/this.gridSize)}.${Math.floor(position[1]/this.gridSize)}`}getOverlapping(pos){const key=this.getKey(pos);if(!this.tiles.has(key))return null;const points=Array.from(this.tiles.get(key).values());for(let i=0;i<points.length;i++){const point=points[i];if(Vector2.distance(pos,point.pos)<this.distThreshold)return point}return null}getClosestUnder(pos,radius=this.radius){const key=this.getKey(pos);let minDist=1/0,closest=null;return this.tiles.has(key)?(this.tiles.get(key).forEach((point=>{const distance=Vector2.distance(pos,point.pos);this.isActive(point)&&distance<radius&&distance<minDist&&(minDist=distance,closest=point)})),closest):null}clear(filter){filter?this.pointValues.forEach((point=>{if(!filter(point.val,point.id))return;const keys=this.getKeys(point.pos);for(let i=0;i<keys.length;i++){const key=keys[i],tile=this.tiles.get(key);tile.delete(point.id),0===tile.size&&this.tiles.delete(key)}this.pointValues.delete(point.id)})):(this.tiles=new Map,this.pointValues=new Map)}}class Projector{project;constructor(project){this.project=project}get(coord,zoom){return this.project(coord,zoom)}getVector2(coord,zoom){return new Vector2(this.project(coord,zoom))}batch(coords,zoom){const output=new Array(coords.length);for(let i=0;i<coords.length;i++)output[i]=this.project(coords[i],zoom);return output}batchVector2(coords,zoom){const output=new Array(coords.length);for(let i=0;i<coords.length;i++)output[i]=new Vector2(this.project(coords[i],zoom));return output}}function forceHighlight(module,wellbore){const{highlight:highlight}=module,root=wellbore.root,wellbores=[wellbore];highlight&&!highlight.equals(root,wellbores)&&(highlight.set(root,wellbores),module.requestRedraw())}function clearHighlight(module,onHighlightOff){module.highlight.clear(),onHighlightOff&&onHighlightOff(),module.requestRedraw()}class Highlight{active=!1;root;wellbores;get single(){return 1===this.wellbores.length}get first(){return this.wellbores[0]}set(root,wellbores){if(!this.active)return this.root=root,this.wellbores=wellbores,this.highlightWellbores(),this.highlightRoot(),void(this.active=!0);this.root!==root||this.wellbores.length!==wellbores.length?(this.clear(),this.root=root,this.wellbores=wellbores,this.highlightWellbores(),this.highlightRoot()):(this.clearWellbores(),this.wellbores=wellbores,this.highlightWellbores()),this.active=!0}highlightRoot(){this.root.recalculate(!1)}highlightWellbores(){const multiple=this.wellbores.length>1;for(let i=0;i<this.wellbores.length;i++)this.wellbores[i].setHighlight(!0,multiple)}clear(){this.active&&(this.clearWellbores(),this.clearRoot(),this.active=!1)}clearRoot(){this.root.recalculate(!1),delete this.root}clearWellbores(){for(let i=0;i<this.wellbores.length;i++)this.wellbores[i].setHighlight(!1);delete this.wellbores}equals(root,wellbores){if(this.root!==root)return!1;if(this.wellbores.length!==wellbores.length)return!1;for(let i=0;i<this.wellbores.length;i++){const wellbore=this.wellbores[i];if(!wellbores.includes(wellbore))return!1}return!0}}class AsyncLoop{timers={};Start(key,config,interval=3){this.Stop(key);const{iterations:iterations,batchSize:batchSize,func:func,postFunc:postFunc,endFunc:endFunc}=config;let front=0;const batch=()=>{if(front>=iterations)return delete this.timers[key],void(endFunc&&endFunc());const tail=Math.min(front+batchSize,iterations);for(let i=front;i<tail;i++)func(i);postFunc&&postFunc(),front+=batchSize,this.timers[key]=setTimeout(batch,interval)};this.timers[key]=setTimeout(batch,interval)}Stop(key){key in this.timers&&(clearTimeout(this.timers[key]),delete this.timers[key])}StopAll(){const keys=Object.keys(this.timers);for(let i=0;i<keys.length;i++){const key=keys[i];clearTimeout(this.timers[key]),delete this.timers[key]}}}class DefaultEventHandler{map;element;callbacks;register(map,element,callbacks){this.map=map,this.element=element,this.callbacks=callbacks,element.addEventListener("mousemove",this.callbacks.mousemove),element.addEventListener("mouseout",this.callbacks.mouseout),element.addEventListener("click",this.callbacks.click),element.addEventListener("mousedown",this.callbacks.mousedown),element.addEventListener("mouseup",this.callbacks.mouseup)}unregister(){const{element:element}=this;element.removeEventListener("mousemove",this.callbacks.mousemove),element.removeEventListener("mouseout",this.callbacks.mouseout),element.removeEventListener("click",this.callbacks.click),element.removeEventListener("mousedown",this.callbacks.mousedown),element.removeEventListener("mouseup",this.callbacks.mouseup),this.map=null,this.element=null}}class RealtimeWellbore{map;root;prevCoords=[Number.MIN_VALUE,Number.MIN_VALUE];constructor(mapInput,wellbore){if(mapInput.utils&&"getMap"in mapInput.utils){const pixiOverlay=mapInput;this.map=pixiOverlay.utils.getMap()}else this.map=mapInput;this.root=wellbore.data.path[0]}get pixelCoordinates(){const{map:map}=this,containerPoint=map.latLngToContainerPoint(this.root),rect=map.getContainer().getBoundingClientRect(),coords=[rect.x+containerPoint.x,rect.y+containerPoint.y];return this.prevCoords=coords,coords}getPixelCoordinates(){const{prevCoords:prevCoords}=this,coords=this.pixelCoordinates;return{coords:coords,changed:!this.coordinatesEqual(coords,prevCoords,1e-5)}}coordinatesEqual(c1,c2,delta){return!(Math.abs(c1[0]-c2[0])>delta)&&!(Math.abs(c1[1]-c2[1])>delta)}}class WellboreModule extends ModuleInterface{config;groups={};roots=[];asyncLoop=new AsyncLoop;lineDict;pointDict;highlight=new Highlight;currentZoom=20;_deferredSelector;_deferredSelectorKeys=null;_projector;_eventHandler;_redrawAnimFrame=null;containers;scaling;marker;constructor(inputConfig){super(),this.requestRedraw=this.requestRedraw.bind(this);const[config,extra]=function(input){const outputConfig={scale:1,batchSize:20,zoomOrigin:0,gridSize:2,wellboreResize:{min:{zoom:10,scale:.01},max:{zoom:18,scale:.001}},rootResize:{min:{zoom:0,scale:1e3},max:{zoom:18,scale:.2}},tick:{width:.02,height:.2}},outputExtra={labelBgOpacity:.5,labelScale:.011,fontSize:18,scaling:void 0,wellboreDash:.01};if(!input)return[outputConfig,outputExtra];function transfer(key,target){isNaN(input[key])||(target[key]=input[key])}function transferFunction(key,target){"function"==typeof input[key]&&(target[key]=input[key])}function transferObj(key,target){input[key]&&(target[key]=input[key])}return transfer("rootRadius",outputConfig),transfer("batchSize",outputConfig),transfer("zoomOrigin",outputConfig),transfer("gridSize",outputConfig),transfer("labelBgOpacity",outputExtra),transfer("labelScale",outputExtra),transfer("fontSize",outputExtra),transfer("wellboreDash",outputExtra),transferFunction("scaling",outputExtra),transferFunction("onWellboreClick",outputConfig),transferFunction("onHighlightOn",outputConfig),transferFunction("onHighlightOff",outputConfig),transferObj("wellboreResize",outputConfig),transferObj("rootResize",outputConfig),transferObj("tick",outputConfig),[outputConfig,outputExtra]}(inputConfig);this.config=config,this.scaling=extra.scaling,this.lineDict=new LineDictionary(config.gridSize,(value=>value.active)),this.pointDict=new PointDictionary(.25,10*config.gridSize,this.getRootRadius(20),(value=>value.active)),this.registerGroup("default");const createContainer=()=>{const container=new PIXI.Container;return container.sortableChildren=!0,this.root.addChild(container),container};this.containers={wellbores:createContainer(),roots:createContainer(),labels:createContainer()},Label.setStyle(extra.fontSize),Label.setCommon({backgroundOpacity:extra.labelBgOpacity}),this._eventHandler=inputConfig&&inputConfig.customEventHandler||new DefaultEventHandler,RootShader.build(config.rootResize.max.scale),WellboreShader.build(config.wellboreResize.max.scale,extra.wellboreDash),RootData.state.maxScale=config.rootResize.max.scale}destroy(){this.asyncLoop.StopAll(),super.destroy()}registerGroup(key,options){if(this.groups[key])throw Error(`Group already registered: ${key}!`);this.groups[key]=new Group(key,options)}registerDetail(key,groupKeys,options){this.forEachGroup(groupKeys,(group=>group.registerDetail(key,options)))}addRoot(position){const overlapping=this.pointDict.getOverlapping(position);if(overlapping)return overlapping.val;const wellboreRoot=new RootData(position);return this.containers.roots.addChild(wellboreRoot.mesh),this.pointDict.add(position,wellboreRoot),this.roots.push(wellboreRoot),wellboreRoot}addWellbore(data,group=this.groups.default){if(0===data.path.length)throw Error("Empty wellbore path!");const projectedPath=this.projector.batchVector2(data.path),root=this.addRoot(projectedPath[0]),{rootResize:rootResize,wellboreResize:wellboreResize,tick:tick}=this.config,wellbore=new WellboreData({data:data,group:group,root:root,coords:projectedPath,pointThreshold:1.5*rootResize.max.scale,wellboreWidth:wellboreResize.max.scale,tick:tick});wellbore.container&&this.containers.wellbores.addChild(wellbore.container),this.containers.labels.addChild(wellbore.label.container),group.append(wellbore),root?.recalculate(!0),wellbore.interpolator.singlePoint||this.lineDict.add(projectedPath,wellbore),root?.append(wellbore),this._deferredSelector&&(null===this._deferredSelectorKeys||this._deferredSelectorKeys.includes(group.key))&&this._deferredSelector(wellbore.data)&&(this._deferredSelector=void 0,wellbore.setSelected(!0))}set(wells,key="default",batchSize=null){return new Promise(((resolve,reject)=>{const group=this.groups[key];if(group)try{this.groups[key].wellbores.length>0&&this.clear(key),this.asyncLoop.Start(key,{iterations:wells.length,batchSize:batchSize||this.config.batchSize||20,func:i=>this.addWellbore(wells[i],group),postFunc:()=>this.requestRedraw(),endFunc:()=>{this.requestRedraw(),resolve()}},0)}catch(err){reject(err)}else reject(Error(`Group [${key}] not registered!`))}))}forAllGroups(func){Object.keys(this.groups).forEach((key=>func(this.groups[key],key))),this.requestRedraw()}forEachGroup(keys,func){const registeredKeys=Object.keys(this.groups);(0===keys.length?registeredKeys:keys.filter((key=>registeredKeys.includes(key)))).forEach((key=>func(this.groups[key],key))),this.requestRedraw()}setActive(active,keys){this.forEachGroup(keys,(group=>group.setActive(active)))}handleMouseMove(event){const latLng=this.pixiOverlay.utils.getMap().mouseEventToLatLng(event);return function(module,pos,onHighlightOn,onHighlightOff,originalEvent){let wellbores;wellbores=function(pos,radius,pointDict){const root=pointDict.getClosestUnder(pos,radius);return root?root.val.wellbores.filter((d=>d.active)):null}(pos,module.getRootRadius(),module.pointDict),!wellbores&&module.containers.labels.visible&&(wellbores=function(pos,roots){const candidates=roots.filter((root=>root.active&&root.rootLabelsBBox&&root.rootLabelsBBox.contains(pos.x,pos.y)));for(let i=0;i<candidates.length;i++)for(let j=0;j<candidates[i].wellbores.length;j++){const wellbore=candidates[i].wellbores[j];if(wellbore.active&&wellbore.label.attachToRoot){const bbox=wellbore.label.getBoundingBox();if(bbox.y>pos.y)break;if(bbox.contains(pos.x,pos.y))return[wellbore]}}return null}(pos,module.roots)),wellbores||(wellbores=function(pos,lineDict,distanceThreshold=.5){const hit=lineDict.getClosest(pos,distanceThreshold);return hit?[hit]:null}(pos,module.lineDict,.5));const{highlight:highlight}=module;if(wellbores){const root=wellbores[0].root;let changed=!1;highlight.active&&highlight.equals(root,wellbores)||(changed=!0,highlight.set(root,wellbores),module.requestRedraw()),onHighlightOn&&onHighlightOn(HighlightEvent.from(wellbores,changed,originalEvent))}else highlight?.active&&clearHighlight(module,onHighlightOff)}(this,this.projector.getVector2(latLng),this.config.onHighlightOn,this.config.onHighlightOff,event),this.highlight.active}handleMouseOut(){return this.clearHighlight(this.config.onHighlightOff)}handleMouseClick(){if(this.config.onWellboreClick&&this.highlight.active&&this.highlight.single){const wellbore=this.highlight.first;return this.config.onWellboreClick({group:wellbore.group.key,data:wellbore.data}),!0}return!1}enable(...keys){this.setActive(!0,keys)}disable(...keys){this.setActive(!1,keys)}setLabelVisibility(visible){Label.state.visible=visible,this.roots.forEach((root=>root.setLabelVisibility(visible))),this.requestRedraw()}setCompletionVisibility(visible,...keys){this.forEachGroup(keys,(group=>group.setCompletionVisibility(visible)))}setWellboresVisibility(visible,...keys){this.forEachGroup(keys,(group=>group.setWellboreVisibility(visible)))}setDetailVisibility(visible,key){this.forAllGroups((group=>group.setDetailVisibility(key,visible)))}softFilter(filterFunction,...keys){this.forEachGroup(keys,(group=>group.softFilter(filterFunction)))}hardFilter(filterFunction,...keys){this.forEachGroup(keys,(group=>group.hardFilter(filterFunction)))}clearFilter(...keys){this.forEachGroup(keys,(group=>group.clearFilter()))}setSelected(selectFunction,...keys){let nSelected=0;this.forEachGroup(keys,(group=>{group&&group.wellbores.forEach((wellbore=>{selectFunction(wellbore.data)?(wellbore.setSelected(!0),nSelected++):wellbore.selected&&wellbore.setSelected(!1)}))})),0===nSelected&&(this._deferredSelector=selectFunction,this._deferredSelectorKeys=keys)}clearSelected(...keys){this.forEachGroup(keys,(group=>{group&&group.wellbores.forEach((wellbore=>{wellbore.selected&&wellbore.setSelected(!1)}))}))}setHighlight(label,...keys){const registeredKeys=Object.keys(this.groups);keys=0===keys.length?registeredKeys:keys.filter((key=>registeredKeys.includes(key)));for(let n=0;n<keys.length;n++){const group=this.groups[keys[n]];if(!group)continue;const wellbores=group.wellbores;for(let i=0;i<wellbores.length;i++){const wellbore=wellbores[i];if(wellbore.data.label===label)return forceHighlight(this,wellbore),new RealtimeWellbore(this.pixiOverlay,wellbore)}}return null}clearHighlight(onHighlightOff){return!!this.highlight.active&&(clearHighlight(this,onHighlightOff),!0)}clearAll(){this.highlight.clear(),this.asyncLoop.StopAll(),this.lineDict.clear(),this.pointDict.clear(),Object.values(this.groups).forEach((g=>{g.wellbores=[],g.resetDetails()})),this.roots=[],this.containers.wellbores.removeChildren().forEach((child=>child.destroy())),this.containers.labels.removeChildren().forEach((child=>child.destroy())),this.containers.roots.removeChildren().forEach((child=>child.destroy())),this.requestRedraw()}clear(...keys){if(0===keys.length)return void this.clearAll();this.highlight.clear();const roots=new Set;this.forEachGroup(keys,((group,key)=>{this.asyncLoop.Stop(key),this.lineDict.clear((d=>group.wellbores.includes(d))),group.wellbores.forEach((w=>{roots.add(w.root);const wellboreIdx=w.root.wellbores.indexOf(w);-1!==wellboreIdx&&w.root.wellbores.splice(wellboreIdx,1),w.container?.destroy(),w.label?.container?.destroy()})),group.wellbores=[],group.resetDetails()})),roots.forEach((root=>{if(root.wellbores.length>0)return void root.recalculate(!0);const rootIdx=this.roots.indexOf(root);-1!==rootIdx&&this.roots.splice(rootIdx,1),this.pointDict.clear((d=>d===root)),this.containers.roots.removeChild(root.mesh)})),this.requestRedraw()}resize(zoom){this.currentZoom=zoom;const wellboreRadius=this.getWellboreRadius(zoom),rootRadius=this.getRootRadius(zoom);if(WellboreData.state={wellboreRadius:wellboreRadius,rootRadius:rootRadius},!this.scaling)return;let scale=this.scaling(zoom-this.config.zoomOrigin);Number.isFinite(scale)||(scale=1),Label.state.zoom=zoom,Label.state.scale=scale,Label.state.rootDisplacement=rootRadius,RootData.state.rootRadius=rootRadius;const labelVisible=zoom>10;this.containers.labels.visible=labelVisible,labelVisible&&Label.state.visible&&this.roots.forEach((root=>{root.updateLabels()})),Object.values(this.groups).forEach((({wellbores:wellbores})=>{wellbores.forEach((wellbore=>{wellbore.update()}))})),this.roots.forEach((root=>{root.recalculate()}))}onAdd(map){const element=this.pixiOverlay.utils.getRenderer().view.parentNode,callbacks={mousemove:this.handleMouseMove.bind(this),mouseout:this.handleMouseOut.bind(this),click:this.handleMouseClick.bind(this),mousedown:()=>!0,mouseup:()=>!0};this._eventHandler.register(map,element,callbacks)}onRemove(_map){this._eventHandler.unregister()}get projector(){return this._projector||(this._projector=new Projector(this.pixiOverlay.utils.latLngToLayerPoint)),this._projector}getRootRadius(zoom=this.currentZoom){return this.getRadius(zoom,this.config.rootResize)}getWellboreRadius(zoom=this.currentZoom){return this.getRadius(zoom,this.config.wellboreResize)}getRadius(zoom,{min:min,max:max}){const zoomClamped=clamp(zoom,min.zoom,max.zoom)-min.zoom,t=Math.pow(2,-zoomClamped);return lerp(max.scale,min.scale,t)}requestRedraw(){this._redrawAnimFrame||(this._redrawAnimFrame=requestAnimationFrame((()=>{this.pixiOverlay.redraw(),this._redrawAnimFrame=null})))}}function centerOfMass(vertices,triangles){let comX=0,comY=0,totalMass=0;for(let i=0;i<triangles.length;i+=3){const a=vertices[triangles[i]],b=vertices[triangles[i+1]],c=vertices[triangles[i+2]],ab=Vector2.sub(b,a),ac=Vector2.sub(c,a),mass=.5*Vector2.cross(ab,ac);comX+=mass*(a.x+b.x+c.x)/3,comY+=mass*(a.y+b.y+c.y)/3,totalMass+=mass}return[new Vector2(comX/totalMass,comY/totalMass),totalMass]}class Hightlighter{fields=[];cached=[];fillColor1;fillColor2;outlineColor;constructor(fillColor1,fillColor2,outlineColor){this.fillColor1=fillColor1,this.fillColor2=fillColor2,this.outlineColor=outlineColor}add(group){this.fields.push(group)}highlight(index){const target=this.fields[index];this.cached&&this.revert(),this.cached=new Array(target.length);for(let i=0;i<target.length;i++){const field=target[i];this.cached[i]={fillCol1:field.fill.uniform.col1,fillCol2:field.fill.uniform.col2,outlineCol:field.outline.uniform.color,baseZIndex:field.fill.mesh.zIndex,field:field},field.fill.uniform.col1=this.fillColor1,field.fill.uniform.col2=this.fillColor2,field.fill.mesh.zIndex+=1e4,field.outline.uniform.color=this.outlineColor,field.outline.mesh.zIndex+=1e4}}revert(){return!!this.cached&&(this.cached.forEach((d=>{d.field.fill.uniform.col1=d.fillCol1,d.field.fill.uniform.col2=d.fillCol2,d.field.fill.mesh.zIndex=d.baseZIndex,d.field.outline.uniform.color=d.outlineCol,d.field.outline.mesh.zIndex=d.baseZIndex+1})),this.cached=void 0,!0)}}function recalculatePosition(labels,selfIndex,targetIndiced){const self=labels[selfIndex];let comX=self.mass*self.position[0],comY=self.mass*self.position[1],totalMass=self.mass;return targetIndiced.forEach((idx=>{const target=labels[idx];comX+=target.mass*target.position[0],comY+=target.mass*target.position[1],totalMass+=target.mass})),[comX/totalMass,comY/totalMass]}class LabelManager{textStyle;baseScale;fields=[];multiFields=[];prevScale=1;visible=!0;constructor(textStyle,baseScale){this.textStyle=textStyle,this.baseScale=baseScale}addField(name,entries){if(entries.length<=1)this.fields.push({name:name,position:entries[0].position,instance:null});else{const textMetrics=PIXI.TextMetrics.measureText(name,this.textStyle),width=textMetrics.width*this.baseScale,height=textMetrics.height*this.baseScale,labels=entries.map((entry=>({position:entry.position,mass:entry.mass,instance:null,active:!0,consumed:[],consumer:-1})));this.multiFields.push({name:name,labels:labels,width:width,height:height})}}draw(root){const drawLabel=(name,position)=>{const instance=new PIXI.Text(name,this.textStyle);return instance.resolution=2,instance.position.set(position[0],position[1]),instance.scale.set(this.baseScale),instance.anchor.set(.5),instance.zIndex=1e5,root.addChild(instance),instance};this.fields.forEach((field=>{field.instance=drawLabel(field.name,field.position)})),this.multiFields.forEach((field=>{field.labels.forEach((label=>{label.instance=drawLabel(field.name,label.position)}))}))}resize(scale){this.fields.forEach((field=>{field.instance.scale.set(scale*this.baseScale)})),this.multiFields.forEach((field=>{field.labels.forEach((label=>{label.instance.scale.set(scale*this.baseScale)}));const centers=function(field,scale){const labels=field.labels,groups=[];for(let i=0;i<labels.length;i++)groups.push({index:i,consumed:[],consumer:-1});const isOverlapping=(a,b)=>{const dist=Vector2.sub(a.position,b.position);return Math.abs(dist[0])<field.width*scale&&Math.abs(dist[1])<field.height*scale};for(let i=0;i<labels.length;i++){const group=groups[i];if(group.consumer>=0)continue;const label=labels[i];for(let j=0;j<labels.length;j++)if(i!==j&&isOverlapping(label,labels[j])){let compIndex=j,compGroup=groups[j];if(compGroup.consumer>=0){if(compIndex=compGroup.consumer,compIndex===i)continue;compGroup=groups[compGroup.consumer]}compGroup.consumed.push(...group.consumed,i),group.consumed.forEach((d=>groups[d].consumer=compIndex)),group.consumed=[],group.consumer=compIndex;break}}const output=[];for(let i=0;i<groups.length;i++){const group=groups[i];group.consumer>=0||output.push(recalculatePosition(labels,group.index,group.consumed))}return output}(field,scale);for(let i=0;i<centers.length;i++){const label=field.labels[i],pos=centers[i];label.instance.visible=!0,label.instance.position.set(pos[0],pos[1])}for(let i=centers.length;i<field.labels.length;i++){field.labels[i].instance.visible=!1}})),this.prevScale=scale}hideLabels(){this.fields.forEach((field=>{field.instance.visible=!1})),this.multiFields.forEach((field=>{field.labels.forEach((label=>{label.instance.visible=!1}))})),this.visible=!1}showLabels(){this.fields.forEach((field=>{field.instance.visible=!0})),this.visible=!0}}function pointInsideTriangle(p,v1,v2,v3){const k1=(p[0]-v1[0])*(v2[1]-v1[1])-(p[1]-v1[1])*(v2[0]-v1[0]),k2=(p[0]-v2[0])*(v3[1]-v2[1])-(p[1]-v2[1])*(v3[0]-v2[0]),k3=(p[0]-v3[0])*(v1[1]-v3[1])-(p[1]-v3[1])*(v1[0]-v3[0]);return k1<0?k2<0&&k3<0:k2>=0&&k3>=0}class TriangleDictionary{resolution;tiles=new Map;triangles=[];polygonValues=[];constructor(decimals=0){this.resolution=10**decimals}add(vertices,triangles,value){const polygonID=this.polygonValues.length;let v1,v2,v3;this.polygonValues.push(value);for(let i=0;i<triangles.length;i+=3){const triangleID=this.triangles.length;v1=vertices[triangles[i]],v2=vertices[triangles[i+1]],v3=vertices[triangles[i+2]],this.triangles.push({v1:v1,v2:v2,v3:v3,polygonID:polygonID});const minX=Math.min(v1[0],v2[0],v3[0]),maxX=Math.max(v1[0],v2[0],v3[0]),minY=Math.min(v1[1],v2[1],v3[1]),maxY=Math.max(v1[1],v2[1],v3[1]),tileMinX=Math.floor(minX*this.resolution),tileMaxX=Math.floor(maxX*this.resolution),tileMinY=Math.floor(minY*this.resolution),tileMaxY=Math.floor(maxY*this.resolution);for(let x=tileMinX;x<=tileMaxX;x++)for(let y=tileMinY;y<=tileMaxY;y++){const key=`${x}.${y}`;this.tiles.has(key)?this.tiles.get(key).push(triangleID):this.tiles.set(key,[triangleID])}}}getPolygonAt(target){const key=`${Math.floor(target[0]*this.resolution)}.${Math.floor(target[1]*this.resolution)}`;if(!this.tiles.has(key))return null;const triangles=this.tiles.get(key);for(let i=0;i<triangles.length;i++){const triangle=this.triangles[triangles[i]];if(pointInsideTriangle(target,triangle.v1,triangle.v2,triangle.v3))return this.polygonValues[triangle.polygonID]}return null}}const red=[.8,0,0],green=[.133,.6,.133],pink=[1,.753,.796],gray=[.6,.6,.6],outlineRed=[.6,0,0],outlineGray=[.5,.5,.5];class FieldModule extends ModuleInterface{static vertexShaderFill;static fragmentShaderFill;static vertexShaderOutline;static fragmentShaderOutline;fields=[];config={initialHash:1,minHash:0,maxHash:1/0};dict=new TriangleDictionary(1.2);highlighter;labelManager;prevField=-1;constructor(config){super(),config&&(config.initialHash&&"number"==typeof config.initialHash&&(this.config.initialHash=config.initialHash),config.minHash&&"number"==typeof config.minHash&&(this.config.minHash=config.minHash),config.maxHash&&"number"==typeof config.maxHash&&(this.config.maxHash=config.maxHash))}set(data){this.config.initialHash=clamp(this.config.initialHash),this.fields=[];const textStyle=new PIXI.TextStyle({fontFamily:"Arial",fontSize:64,fontWeight:"600",fill:4539717,align:"center"});this.labelManager=new LabelManager(textStyle,.029),this.highlighter=new Hightlighter([.5,0,.5],[.25,0,.25],[.35,0,.35]);const preprocessedData=function(data){const unique={};return data.forEach((field=>{const fieldName=field.properties.label;let coordinates=[];const geometry=field.geometry;if("Polygon"===geometry.type)coordinates=geometry.coordinates;else{const multipolygons=geometry.coordinates;for(let i=0;i<multipolygons.length;i++)coordinates.push(...multipolygons[i])}function appendIndex(index){unique[fieldName].geometry.push({coordinates:coordinates[index],properties:{discname:field.properties.discname,hctype:field.properties.hctype,polygonId:field.properties.polygonId,status:field.properties.status}})}if(unique.hasOwnProperty(fieldName))for(let i=0;i<coordinates.length;i++)appendIndex(i);else if(unique[fieldName]={type:field.type,geometry:[{coordinates:coordinates[0],properties:{discname:field.properties.discname,hctype:field.properties.hctype,polygonId:field.properties.polygonId,status:field.properties.status}}],properties:{group:field.properties.group,guid:field.properties.guid,label:field.properties.label,lat:field.properties.lat,long:field.properties.long}},coordinates.length>1)for(let i=1;i<coordinates.length;i++)appendIndex(i)})),Object.values(unique)}(data);let fieldID=0,baseZIndex=0;preprocessedData.forEach((field=>{const name=field.properties.label;if("Troll"===name)return;const guid=field.properties.guid,entries=[],meshes=[];field.geometry.forEach((polygon=>{const fieldStyle=this.getFieldStyle(guid,polygon.properties.hctype),projected=this.projectPolygons(polygon.coordinates);projected.pop();const meshData=Mesh.Polygon(projected);this.dict.add(polygon.coordinates,meshData.triangles,fieldID);const outlineData=Mesh.PolygonOutline(projected,.15),[position,mass]=centerOfMass(projected,meshData.triangles);meshes.push(this.drawPolygons(meshData,outlineData,fieldStyle,baseZIndex)),baseZIndex+=2,entries.push({position:position,mass:mass})})),fieldID++,this.labelManager.addField(name,entries),this.fields.push(...meshes),this.highlighter.add(meshes)})),this.labelManager.draw(this.root)}drawPolygons(meshData,outlineData,fieldStyle,zIndex){const fillUniform={col1:fieldStyle.fillColor1,col2:fieldStyle.fillColor2,opacity:fieldStyle.fillOpacity,hashed:fieldStyle.hashed,hashDisp:10*Math.random(),hashWidth:this.config.initialHash},outlineUniform={color:fieldStyle.outlineColor,width:0},polygonMesh=Mesh.from(meshData.vertices,meshData.triangles,FieldModule.vertexShaderFill,FieldModule.fragmentShaderFill,fillUniform);polygonMesh.zIndex=zIndex,this.root.addChild(polygonMesh);const polygonOutlineMesh=Mesh.from(outlineData.vertices,outlineData.triangles,FieldModule.vertexShaderOutline,FieldModule.fragmentShaderOutline,outlineUniform,outlineData.normals);return polygonOutlineMesh.zIndex=zIndex+1,this.root.addChild(polygonOutlineMesh),{fill:{mesh:polygonMesh,uniform:fillUniform},outline:{mesh:polygonOutlineMesh,uniform:outlineUniform}}}getFieldStyle(guid,hctype){if(!guid)return{fillColor1:gray,fillColor2:gray,outlineColor:outlineGray,fillOpacity:.15,hashed:!1};const fill={fillColor1:green,fillColor2:green,outlineColor:green,fillOpacity:.6,hashed:!1};switch(hctype){case"GAS":fill.fillColor1=red,fill.fillColor2=red,fill.outlineColor=outlineRed;break;case"GAS/CONDENSATE":fill.fillColor1=pink,fill.fillColor2=red,fill.outlineColor=outlineRed,fill.hashed=!0;break;case"OIL/GAS":fill.fillColor1=red,fill.hashed=!0}return fill}projectPolygons(points){const project=this.pixiOverlay.utils.latLngToLayerPoint;return points.map((c=>{const coord=project([c[1],c[0]]);return new Vector2(coord.x,coord.y)}))}resize(_zoom){}highlight(lat,long){const field=this.dict.getPolygonAt([long,lat]);return field?(this.prevField===field||(this.highlighter.highlight(field),this.pixiOverlay.redraw(),this.prevField=field),!0):(this.highlighter.revert()&&this.pixiOverlay.redraw(),this.prevField=-1,!1)}tryUnselect(){this.highlighter.revert()&&this.pixiOverlay.redraw(),this.prevField=-1}}FieldModule.vertexShaderFill="\n attribute vec2 inputVerts;\n\n uniform mat3 translationMatrix;\n uniform mat3 projectionMatrix;\n\n varying vec2 verts;\n\n void main() {\n verts = inputVerts;\n gl_Position = vec4((projectionMatrix * translationMatrix * vec3(inputVerts, 1.0)).xy, 0.0, 1.0);\n }\n",FieldModule.fragmentShaderFill="\n precision mediump float;\n\n varying vec2 verts;\n\n uniform vec3 col1;\n uniform vec3 col2;\n uniform float opacity;\n\n uniform bool hashed;\n uniform float hashDisp;\n uniform float hashWidth;\n\n void main() {\n if(hashed && mod(verts.y + hashDisp, hashWidth * 2.0) > hashWidth) {\n gl_FragColor = vec4(col2, 1.0) * opacity;\n }\n else {\n gl_FragColor = vec4(col1, 1.0) * opacity;\n }\n }\n",FieldModule.vertexShaderOutline="\n attribute vec2 inputVerts;\n attribute vec2 inputNormals;\n\n uniform mat3 translationMatrix;\n uniform mat3 projectionMatrix;\n\n uniform float width;\n\n void main() {\n vec2 pos = inputVerts + inputNormals * width;\n gl_Position = vec4((projectionMatrix * translationMatrix * vec3(pos, 1.0)).xy, 0.0, 1.0);\n }\n",FieldModule.fragmentShaderOutline="\n precision mediump float;\n\n uniform vec3 color;\n\n void main() {\n gl_FragColor = vec4(color, 1.0);\n }\n";class GeoJSONLabels{container;textStyle;font;fontName;baseScale;labels=[];visible=!0;constructor(root,textStyle,baseScale,fontName){this.container=new PIXI.Container,this.container.sortableChildren=!0,root.addChild(this.container),this.textStyle=textStyle,this.baseScale=baseScale,this.fontName=fontName||v4(),this.font=PIXI.BitmapFont.from(this.fontName,this.textStyle,{resolution:window.devicePixelRatio,chars:PIXI.BitmapFont.ASCII})}addLabel(name,data){this.labels.push({name:name,position:data.position,instance:null})}draw(){const drawLabel=(name,position)=>{const instance=new PIXI.BitmapText(name,{fontName:this.fontName});return instance.position.set(position[0],position[1]),instance.scale.set(this.baseScale),instance.anchor.set(.5,.5),instance.zIndex=1e3,this.container.addChild(instance),instance};this.labels.forEach((label=>{label.instance=drawLabel(label.name,label.position)}))}hideLabels(){this.container.visible=!1,this.visible=!1}showLabels(){this.container.visible=!0,this.visible=!0}resize(scale){this.labels.forEach((lbl=>lbl.instance.scale.set(scale)))}}const GeoJSONVertexShaderFill="\n attribute vec2 inputVerts;\n\n uniform mat3 translationMatrix;\n uniform mat3 projectionMatrix;\n\n varying vec2 verts;\n\n void main() {\n verts = inputVerts;\n gl_Position = vec4((projectionMatrix * translationMatrix * vec3(inputVerts, 1.0)).xy, 0.0, 1.0);\n }\n ",GeoJSONFragmentShaderFill="\n precision mediump float;\n\n varying vec2 verts;\n\n uniform vec3 col1;\n uniform vec3 col2;\n uniform float opacity;\n\n uniform bool hashed;\n uniform float hashDisp;\n uniform float hashWidth;\n\n void main() {\n if(hashed && mod(verts.y + hashDisp, hashWidth * 2.0) > hashWidth) {\n gl_FragColor = vec4(col2 / 255., 1.0) * opacity;\n }\n else {\n gl_FragColor = vec4(col1 / 255., 1.0) * opacity;\n }\n }\n ",GeoJSONVertexShaderOutline="\n attribute vec2 inputVerts;\n attribute vec2 inputNormals;\n\n uniform mat3 translationMatrix;\n uniform mat3 projectionMatrix;\n\n uniform float outlineWidth;\n\n void main() {\n vec2 pos = inputVerts + inputNormals * outlineWidth;\n gl_Position = vec4((projectionMatrix * translationMatrix * vec3(pos, 1.0)).xy, 0.0, 1.0);\n }\n ",GeoJSONFragmentShaderOutline="\n precision mediump float;\n\n uniform vec3 color;\n\n void main() {\n gl_FragColor = vec4(color / 255., 1.0);\n }\n ";function getRadius(zoom,{min:min,max:max}){const zoomClamped=clamp(zoom,min.zoom,max.zoom)-min.zoom,t=Math.pow(2,-zoomClamped);return lerp(max.scale,min.scale,t)}class Defaults{static DEFAULT_Z_INDEX=1e3;static DEFAULT_LINE_WIDTH=.15;static INITIAL_ZOOM=20;static DEFAULT_FONT_FAMILY="Arial";static DEFAULT_FONT_SIZE=64;static DEFAULT_FONT_WEIGHT="600";static DEFAULT_LABEL_COLOR=4539717;static DEFAULT_LABEL_ALIGN="center";static INITIAL_HASH=1;static DEFAULT_MIN_HASH=0;static DEFAULT_BASE_SCALE=.1}class GeoJSONMultiPolygon{static vertexShaderFill;static fragmentShaderFill;static vertexShaderOutline;static fragmentShaderOutline;features=[];config={initialHash:Defaults.INITIAL_HASH,minHash:Defaults.DEFAULT_MIN_HASH,maxHash:1/0};container;pixiOverlay;dict=new TriangleDictionary(1.2);textStyle;labels;currentZoom=Defaults.INITIAL_ZOOM;constructor(root,labelRoot,pixiOverlay,config){config?.initialHash&&"number"==typeof config.initialHash&&(this.config.initialHash=config.initialHash),config?.minHash&&"number"==typeof config.minHash&&(this.config.minHash=config.minHash),config?.maxHash&&"number"==typeof config.maxHash&&(this.config.maxHash=config.maxHash),this.container=new PIXI.Container,this.container.sortableChildren=!0,root.addChild(this.container),this.pixiOverlay=pixiOverlay,this.features=[],this.config=config,this.config.initialHash=clamp(this.config.initialHash),this.textStyle=new PIXI.TextStyle({fontFamily:config?.labelFontFamily||Defaults.DEFAULT_FONT_FAMILY,fontSize:config?.labelFontSize||Defaults.DEFAULT_FONT_SIZE,fontWeight:config?.labelFontWeight||Defaults.DEFAULT_FONT_WEIGHT,fill:config?.labelColor||Defaults.DEFAULT_LABEL_COLOR,align:config?.labelAlign||Defaults.DEFAULT_LABEL_ALIGN}),this.labels=new GeoJSONLabels(labelRoot||this.container,this.textStyle,this.config.labelResize?.baseScale||Defaults.DEFAULT_BASE_SCALE)}add(feature,props){const geom=feature.geometry,properties=props(feature);properties.style.labelScale&&(this.labels.baseScale=properties.style.labelScale);const meshes=[],coordinateGroup=geom.coordinates;coordinateGroup?.length>0&&(coordinateGroup.forEach((coordinates=>{const projected=this.projectPolygons(coordinates[0]);projected.pop();const meshData=Mesh.Polygon(projected);this.dict.add(coordinates[0],meshData.triangles,feature.properties);const outlineData=Mesh.PolygonOutline(projected,Defaults.DEFAULT_LINE_WIDTH),[position,mass]=centerOfMass(projected,meshData.triangles);meshes.push(this.drawPolygons(this.container,meshData,outlineData,properties.style,Defaults.DEFAULT_Z_INDEX)),properties.label&&this.labels.addLabel(properties.label,{position:position,mass:mass})})),this.features.push(...meshes))}drawPolygons(container,meshData,outlineData,featureStyle,zIndex){const fillColor=featureStyle.fillColor?color(featureStyle.fillColor).rgb():void 0,fillColor2=featureStyle.fillColor2?color(featureStyle.fillColor2).rgb():void 0,fillUniform={col1:fillColor?[fillColor.r,fillColor.g,fillColor.b]:[0,0,0],col2:fillColor2?[fillColor2.r,fillColor2.g,fillColor2.b]:[0,0,0],opacity:featureStyle.fillOpacity,hashed:featureStyle.hashed,hashDisp:10*Math.random(),hashWidth:this.config.initialHash},lineColor=color(featureStyle.lineColor).rgb(),outlineUniform={color:[lineColor.r,lineColor.g,lineColor.b],outlineWidth:featureStyle.lineWidth},polygonMesh=Mesh.from(meshData.vertices,meshData.triangles,GeoJSONVertexShaderFill,GeoJSONFragmentShaderFill,fillUniform);polygonMesh.zIndex=zIndex,container.addChild(polygonMesh);const polygonOutlineMesh=Mesh.from(outlineData.vertices,outlineData.triangles,GeoJSONVertexShaderOutline,GeoJSONFragmentShaderOutline,outlineUniform,outlineData.normals);return polygonOutlineMesh.zIndex=zIndex+1,container.addChild(polygonOutlineMesh),{fill:{mesh:polygonMesh,uniform:fillUniform},outline:{mesh:polygonOutlineMesh,uniform:outlineUniform}}}drawLabels(){this.labels.draw()}projectPolygons(points){const project=this.pixiOverlay.utils.latLngToLayerPoint;return points.map((c=>{const coord=project([c[1],c[0]]);return new Vector2(coord.x,coord.y)}))}resize(zoom){if(!this.config.outlineResize)return;const outlineRadius=this.getOutlineRadius(zoom);if(this.config.labelResize){const labelSize=this.getLabelSize(zoom);zoom<=this.config.labelResize.threshold?this.labels.hideLabels():(this.labels.showLabels(),this.labels.resize(labelSize))}this.container.children.map((child=>{child.shader.uniformGroup.uniforms.outlineWidth&&(child.shader.uniformGroup.uniforms.outlineWidth=outlineRadius)})),this.currentZoom=zoom}testPosition(pos){return this.dict.getPolygonAt([pos.x,pos.y])}getOutlineRadius(zoom=this.currentZoom){return getRadius(zoom,this.config.outlineResize)}getLabelSize(zoom=this.currentZoom){return getRadius(zoom,this.config.labelResize)}}class GeoJSONPolygon{static vertexShaderFill;static fragmentShaderFill;static vertexShaderOutline;static fragmentShaderOutline;features=[];config={initialHash:Defaults.INITIAL_HASH,minHash:Defaults.DEFAULT_MIN_HASH,maxHash:1/0};container;pixiOverlay;dict=new TriangleDictionary(1.2);textStyle;labels;currentZoom=Defaults.INITIAL_ZOOM;outlineThickness=Defaults.DEFAULT_LINE_WIDTH;zIndex=Defaults.DEFAULT_Z_INDEX;constructor(root,labelRoot,pixiOverlay,config){config?.initialHash&&"number"==typeof config.initialHash&&(this.config.initialHash=config.initialHash),config?.minHash&&"number"==typeof config.minHash&&(this.config.minHash=config.minHash),config?.maxHash&&"number"==typeof config.maxHash&&(this.config.maxHash=config.maxHash),this.container=new PIXI.Container,this.container.sortableChildren=!0,root.addChild(this.container),this.pixiOverlay=pixiOverlay,this.features=[],this.config=config,this.config.initialHash=clamp(this.config.initialHash),this.textStyle=new PIXI.TextStyle({fontFamily:config?.labelFontFamily||Defaults.DEFAULT_FONT_FAMILY,fontSize:config?.labelFontSize||Defaults.DEFAULT_FONT_SIZE,fontWeight:config?.labelFontWeight||Defaults.DEFAULT_FONT_WEIGHT,fill:config?.labelColor||Defaults.DEFAULT_LABEL_COLOR,align:config?.labelAlign||Defaults.DEFAULT_LABEL_ALIGN}),this.labels=new GeoJSONLabels(labelRoot||this.container,this.textStyle,this.config.labelResize?.baseScale||Defaults.DEFAULT_BASE_SCALE)}add(feature,props){const geom=feature.geometry,properties=props(feature);properties.style.labelScale&&(this.labels.baseScale=properties.style.labelScale);const meshes=[],coordinates=geom.coordinates;if(coordinates?.length>0){const projected=this.projectPolygons(coordinates[0]);projected.pop();const meshData=Mesh.Polygon(projected);this.dict.add(coordinates[0],meshData.triangles,feature.properties);const outlineData=Mesh.PolygonOutline(projected,this.outlineThickness),[position,mass]=centerOfMass(projected,meshData.triangles);meshes.push(this.drawPolygons(this.container,meshData,outlineData,properties.style,this.zIndex)),properties.label&&this.labels.addLabel(properties.label,{position:position,mass:mass}),this.features.push(...meshes)}}drawPolygons(container,meshData,outlineData,featureStyle,zIndex){const fillColor=featureStyle.fillColor?color(featureStyle.fillColor).rgb():void 0,fillColor2=featureStyle.fillColor2?color(featureStyle.fillColor2).rgb():void 0,fillUniform={col1:fillColor?[fillColor.r,fillColor.g,fillColor.b]:[0,0,0],col2:fillColor2?[fillColor2.r,fillColor2.g,fillColor2.b]:[0,0,0],opacity:featureStyle.fillOpacity,hashed:featureStyle.hashed,hashDisp:10*Math.random(),hashWidth:this.config.initialHash},lineColor=color(featureStyle.lineColor).rgb(),outlineUniform={color:[lineColor.r,lineColor.g,lineColor.b],outlineWidth:featureStyle.lineWidth},polygonMesh=Mesh.from(meshData.vertices,meshData.triangles,GeoJSONVertexShaderFill,GeoJSONFragmentShaderFill,fillUniform);polygonMesh.zIndex=zIndex,container.addChild(polygonMesh);const polygonOutlineMesh=Mesh.from(outlineData.vertices,outlineData.triangles,GeoJSONVertexShaderOutline,GeoJSONFragmentShaderOutline,outlineUniform,outlineData.normals);return polygonOutlineMesh.zIndex=zIndex+1,container.addChild(polygonOutlineMesh),{fill:{mesh:polygonMesh,uniform:fillUniform},outline:{mesh:polygonOutlineMesh,uniform:outlineUniform}}}drawLabels(){this.labels.draw()}projectPolygons(points){const project=this.pixiOverlay.utils.latLngToLayerPoint;return points.map((c=>{const coord=project([c[1],c[0]]);return new Vector2(coord.x,coord.y)}))}resize(zoom){if(!this.config.outlineResize)return;const outlineRadius=this.getOutlineRadius(zoom);if(this.config.labelResize){const labelSize=this.getLabelSize(zoom);zoom<=this.config.labelResize.threshold?this.labels.hideLabels():(this.labels.showLabels(),this.labels.resize(labelSize))}this.container.children.map((child=>{child.shader.uniformGroup.uniforms.outlineWidth&&(child.shader.uniformGroup.uniforms.outlineWidth=outlineRadius)})),this.currentZoom=zoom}testPosition(pos){return this.dict.getPolygonAt([pos.x,pos.y])}getOutlineRadius(zoom=this.currentZoom){return getRadius(zoom,this.config.outlineResize)}getLabelSize(zoom=this.currentZoom){return getRadius(zoom,this.config.labelResize)}}class GeoJSONLineString{static vertexShaderOutline;static fragmentShaderOutline;features=[];config={};container;pixiOverlay;dict=new LineDictionary(1.2);textStyle;currentZoom=Defaults.INITIAL_ZOOM;constructor(root,pixiOverlay,config){this.container=new PIXI.Container,this.container.sortableChildren=!0,root.addChild(this.container),this.pixiOverlay=pixiOverlay,this.features=[],this.config=config}add(feature,props){const geom=feature.geometry,properties=props(feature),meshes=[],coordinates=geom.coordinates;if(coordinates?.length>0){const projected=this.projectPolygons(coordinates);projected.pop(),this.dict.add(projected,feature.properties);const outlineData=Mesh.SimpleLine(projected,Defaults.DEFAULT_LINE_WIDTH);meshes.push(this.drawPolygons(this.container,outlineData,properties.style,Defaults.DEFAULT_Z_INDEX)),this.features.push(...meshes)}}drawPolygons(container,outlineData,featureStyle,zIndex){const lineColor=color(featureStyle.lineColor).rgb(),outlineUniform={color:[lineColor.r,lineColor.g,lineColor.b],width:featureStyle.lineWidth},polygonOutlineMesh=Mesh.from(outlineData.vertices,outlineData.triangles,GeoJSONVertexShaderOutline,GeoJSONFragmentShaderOutline,outlineUniform,outlineData.normals);return polygonOutlineMesh.zIndex=zIndex,container.addChild(polygonOutlineMesh),{outline:{mesh:polygonOutlineMesh,uniform:outlineUniform}}}projectPolygons(points){const project=this.pixiOverlay.utils.latLngToLayerPoint;return points.map((c=>{const coord=project([c[1],c[0]]);return new Vector2(coord.x,coord.y)}))}resize(zoom){if(!this.config.outlineResize)return;const outlineRadius=this.getOutlineRadius(zoom);this.container.children.map((child=>{child.shader.uniformGroup.uniforms.outlineWidth&&(child.shader.uniformGroup.uniforms.outlineWidth=outlineRadius)})),this.currentZoom=zoom}testPosition(pos){return this.dict.getClosest(pos)}getOutlineRadius(zoom=this.currentZoom){return getRadius(zoom,this.config.outlineResize)}}class GeoJSONPoint{spawned=[];pool=[];container;pixiOverlay;dict=new PointDictionary(.25,20,4);textStyle;constructor(root,pixiOverlay){this.container=new PIXI.Container,this.container.sortableChildren=!0,root.addChild(this.container),this.pixiOverlay=pixiOverlay}add(feature,props){const geom=feature.geometry,properties=props(feature),coordinates=geom.coordinates;if(coordinates?.length>0){const projected=this.projectPoint(coordinates);let point;this.dict.add(projected,feature.properties),this.pool.length>0?point=this.pool.pop():(point=new PIXI.Graphics,this.container.addChild(point));const fillColor=properties.style.fillColor?new PIXI.Color(color(properties.style.fillColor).formatHex()).toNumber():0,lineColor=properties.style.lineColor?new PIXI.Color(color(properties.style.lineColor).formatHex()).toNumber():0,opacity=properties.style.fillOpacity||0,offset=4;point.lineStyle(properties.style.lineWidth,lineColor),point.beginFill(fillColor,opacity),point.drawRect(projected[0]-offset,projected[1]-offset,2*offset,2*offset),point.endFill(),this.spawned.push(point)}}projectPoint(point){const coord=(0,this.pixiOverlay.utils.latLngToLayerPoint)([point[1],point[0]]);return new Vector2(coord.x,coord.y)}resize(_zoom){}testPosition(pos){return this.dict.getClosestUnder(pos)}}class GeoJSONModule extends ModuleInterface{onFeatureHover;points;linestrings;polygons;multipolygons;_eventHandler;mapmoving;labelRoot;config;constructor(config){super(),this.mapmoving=!1,this._eventHandler=config?.customEventHandler||new DefaultEventHandler,this.onFeatureHover=config?.onFeatureHover,this.config=config}set(data,props){this.labelRoot=new PIXI.Container,data.features.forEach((feature=>{"Point"===feature.geometry.type?(void 0===this.points&&(this.points=new GeoJSONPoint(this.root,this.pixiOverlay)),this.points.add(feature,props)):"LineString"===feature.geometry.type?(void 0===this.linestrings&&(this.linestrings=new GeoJSONLineString(this.root,this.pixiOverlay,this.config)),this.linestrings.add(feature,props)):"Polygon"===feature.geometry.type?(void 0===this.polygons&&(this.polygons=new GeoJSONPolygon(this.root,this.labelRoot,this.pixiOverlay,this.config)),this.polygons.add(feature,props)):"MultiPolygon"===feature.geometry.type&&(void 0===this.multipolygons&&(this.multipolygons=new GeoJSONMultiPolygon(this.root,this.labelRoot,this.pixiOverlay,this.config)),this.multipolygons.add(feature,props))})),this.root.addChild(this.labelRoot),this.polygons&&this.polygons.drawLabels(),this.multipolygons&&this.multipolygons.drawLabels()}testPosition(pos){let result=[];return this.polygons&&result.push(this.polygons.testPosition(pos)),this.multipolygons&&result.push(this.multipolygons.testPosition(pos)),this.linestrings&&result.push(this.linestrings.testPosition(pos)),this.points&&result.push(this.points.testPosition(pos)),result=result.filter((v=>v)),result}onAdd(map){const element=this.pixiOverlay.utils.getRenderer().view.parentNode,callbacks={mousemove:this.handleMouseMove.bind(this),mouseout:this.handleMouseOut.bind(this),click:this.handleMouseClick.bind(this),mousedown:this.handleMouseDown.bind(this),mouseup:this.handleMouseUp.bind(this)};this._eventHandler.register(map,element,callbacks)}onRemove(_map){this._eventHandler.unregister()}resize(zoom){this.points&&this.points.resize(zoom),this.linestrings&&this.linestrings.resize(zoom),this.polygons&&this.polygons.resize(zoom),this.multipolygons&&this.multipolygons.resize(zoom)}handleMouseMove(event){if(this.mapmoving)return!1;const latLng=this.pixiOverlay.utils.getMap().mouseEventToLatLng(event),layerCoords=new Vector2([latLng.lng,latLng.lat]),hits=this.testPosition(layerCoords);return this.onFeatureHover&&this.onFeatureHover(event,hits),!0}handleMouseOut(event){return this.onFeatureHover&&this.onFeatureHover(event,[]),!0}handleMouseClick(){return!0}handleMouseDown(){return this.mapmoving=!0,!0}handleMouseUp(){return this.mapmoving=!1,!0}}class ExplorationLayer extends ModuleInterface{pointDict=new PointDictionary(.25,-2,-1);prevScale;selection;appendExploration(scale=1){const project=this.pixiOverlay.utils.latLngToLayerPoint,targetScale=this.clampScale(scale);this.prevScale=targetScale;for(let i=0;i<null.length;i++){const projected=project([null[i].latitude,null[i].longitude]),pos=new Vector2(projected.x,projected.y),well=generateCircle(pos,.3,void 0);this.root.addChild(well),this.pointDict.add(pos,{mesh:well,uniforms:void 0})}}clampScale(scale){scale<1&&(scale=1);let targetScale=.05*scale;return targetScale>1&&(targetScale=1),targetScale}highlight(lat,long){const project=this.pixiOverlay.utils.latLngToLayerPoint;if(this.selection){const point=this.selection.point;point.uniforms.circleColor1=[.3,.3,.3],point.mesh.zIndex=this.selection.zIndex,this.selection=null}const{x:x,y:y}=project([lat,long]),worldSpace=new Vector2(x,y),circleUnder=this.pointDict.getClosestUnder(worldSpace);if(circleUnder){const point=circleUnder.val;return this.selection={point:point,zIndex:point.mesh.zIndex},point.uniforms.circleColor1=[.2,.6,.7],point.mesh.zIndex=1/0,!0}return!1}}export{DefaultEventHandler,ExplorationLayer,FaultlineModule,FieldModule,GeoJSONModule,ModuleInterface,OutlineModule,WellboreModule};
1
+ import*as PIXI from"pixi.js";import Vector2 from"@equinor/videx-vector2";import{inverseLerp,lerp,clamp}from"@equinor/videx-math";import{flatten,mix}from"@equinor/videx-linear-algebra";import earcut from"earcut";import{color}from"d3-color";import{v4}from"uuid";class ModuleInterface{pixiOverlay;root;visibility=!0;constructor(){this.root=new PIXI.Container,this.root.sortableChildren=!0}destroy(){this.root.destroy({children:!0,texture:!0,baseTexture:!0}),this.root=null}toggle(){this.root.visible=!this.root.visible}setVisibility(visible){return visible!==this.visibility&&(this.root.visible=visible,this.visibility=visible,!0)}onAdd(_map){}onRemove(_map){}resize(_zoom){}}function log(text){const out=`%cVIDEX-MAP%c ${text}`;console.log(`${out} (${function(){const date=new Date;return`${date.getHours()}:${date.getMinutes()}:${date.getSeconds()}.${date.getMilliseconds()}`}()})`,"\n background: #555;\n color: #eee;\n padding: 0 6px 0 6px;\n border-radius: 2px;\n ",null)}class FaultlineModule extends ModuleInterface{spawned=[];pool=[];config={color:7503240,alpha:1,outlineWidth:.125};constructor(config){super(),config&&(isNaN(config.color)||(this.config.color=config.color),isNaN(config.alpha)||(this.config.alpha=config.alpha),isNaN(config.outlineWidth)||(this.config.outlineWidth=config.outlineWidth))}destroy(){super.destroy(),this.pool.forEach((g=>g.destroy({children:!0,texture:!0,baseTexture:!0}))),this.pool=null,this.spawned=null}set(data){this.clear();const project=this.pixiOverlay.utils.latLngToLayerPoint;let lineCount=0;data.forEach((d=>{let faultline;faultline=this.pool.length>0?this.pool.pop():new PIXI.Graphics,this.root.addChild(faultline),this.spawned.push(faultline),faultline.alpha=this.config.alpha;const projected=d.coordinates.map((p=>{const coord=project(p);return new PIXI.Point(coord.x,coord.y)})),first=projected[0],last=projected[projected.length-1];if(Vector2.equals([first.x,first.y],[last.x,last.y],1e-6))faultline.beginFill(this.config.color),faultline.lineStyle(this.config.outlineWidth,this.config.color),faultline.drawPolygon(projected),faultline.endFill();else{lineCount++,faultline.lineStyle(this.config.outlineWidth,this.config.color).moveTo(first.x,first.y);for(let i=1;i<projected.length;i++)faultline.lineTo(projected[i].x,projected[i].y)}})),lineCount>0&&log(`Drawing ${lineCount} faultline polygons as lines.`)}clear(){for(;this.spawned.length>0;){const temp=this.spawned.pop();this.root.removeChild(temp),temp.clear(),this.pool.push(temp)}}resize(_zoom){}}function Intersection(p1,d1,p2,d2){const c=[p1[0]-p2[0],p1[1]-p2[1]],len=(c[0]*d2[1]-c[1]*d2[0])/(d1[1]*d2[0]-d1[0]*d2[1]);return c[0]=d1[0]*len+p1[0],c[1]=d1[1]*len+p1[1],c}class Mesh{static WellboreSegment(points,thickness=1,type){const vertices=[],triangles=[],vertexData=[],extraData=[],_thickness=.5*thickness,point0=points[0],first=point0.position,from0=Vector2.sub(points[1].position,first).rescale(_thickness);vertices.push(-from0[1]+first[0],from0[0]+first[1],from0[1]+first[0],-from0[0]+first[1]),vertexData.push(point0.distance,1,-point0.direction[1],point0.direction[0],point0.distance,0,point0.direction[1],-point0.direction[0]),extraData.push(type,type);for(let i=1;i<points.length-1;i++){const point=points[i],prev=points[i-1].position,cur=point.position,next=points[i+1].position,to=Vector2.sub(cur,prev),from=Vector2.sub(next,cur);let upper=null,inner=null;if(Vector2.angleDeg(to,from)<90){const toU=to.rotate90().mutable.rescale(_thickness).add(prev).immutable,fromU=from.rotate90().mutable.rescale(_thickness).add(next).immutable,toI=to.rotate270().mutable.rescale(_thickness).add(prev).immutable,fromI=from.rotate270().mutable.rescale(_thickness).add(next).immutable;upper=Intersection(toU,to,fromU,from),inner=Intersection(toI,to,fromI,from)}else upper=[-point.direction[1]*_thickness+cur[0],point.direction[0]*_thickness+cur[1]],inner=[point.direction[1]*_thickness+cur[0],-point.direction[0]*_thickness+cur[1]];if(vertices.push(upper[0],upper[1],inner[0],inner[1]),vertexData.push(point.distance,1,-point.direction[1],point.direction[0],point.distance,0,point.direction[1],-point.direction[0]),extraData.push(type,type),0!==i){const n=2*i;triangles.push(n-1,n-2,n,n-1,n,n+1)}}const pointN=points[points.length-1],last=pointN.position,toN=Vector2.sub(last,points[points.length-2].position).rescale(_thickness);vertices.push(last[0]-toN[1],last[1]+toN[0],last[0]+toN[1],last[1]-toN[0]),vertexData.push(pointN.distance,1,-pointN.direction[1],pointN.direction[0],pointN.distance,0,pointN.direction[1],-pointN.direction[0]),extraData.push(type,type);const n=2*points.length-2;return triangles.push(n-1,n-2,n,n-1,n,n+1),{vertices:vertices,triangles:triangles,vertexData:vertexData,extraData:extraData}}static SimpleLine=(points,thickness=1)=>{const linethickness=.5*thickness;function GetNormal(index){if(0===index)return Vector2.sub(points[1],points[0]).mutable.rotate90().rescale(1);if(index===points.length-1)return Vector2.sub(points[points.length-1],points[points.length-2]).mutable.rotate90().rescale(1);const prev=points[index-1],cur=points[index],next=points[index+1];return Vector2.lerpRot(Vector2.sub(cur,prev),Vector2.sub(next,cur),.5).mutable.rotate90().rescale(1)}const vertices=[],triangles=[],normals=[];let prevUpperRight,baseTris=0;for(let i=0;i<points.length-1;i++){const cur=points[i],next=points[i+1],dirN=Vector2.sub(next,cur).rotate90().mutable.rescale(linethickness).immutable,leftNormal=GetNormal(i),rightNormal=GetNormal(i+1),lowerLeft=Vector2.sub(cur,dirN),upperLeft=Vector2.add(cur,dirN),lowerRight=Vector2.sub(next,dirN),upperRight=Vector2.add(next,dirN);if(vertices.push(lowerLeft[0],lowerLeft[1],upperLeft[0],upperLeft[1],lowerRight[0],lowerRight[1],upperRight[0],upperRight[1]),normals.push(-leftNormal[0],-leftNormal[1],leftNormal[0],leftNormal[1],-rightNormal[0],-rightNormal[1],rightNormal[0],rightNormal[1]),triangles.push(baseTris,baseTris+1,baseTris+3,baseTris,baseTris+3,baseTris+2),0!==i){const toPrevUpper=Vector2.sub(prevUpperRight,upperLeft);Vector2.signedAngle(dirN,toPrevUpper)<0?triangles.push(baseTris,baseTris-2,baseTris+1):triangles.push(baseTris,baseTris-1,baseTris+1)}prevUpperRight=upperRight,baseTris+=4}return{vertices:vertices,triangles:triangles,normals:normals}};static Polygon=points=>{const vertices=flatten(points);return{vertices:vertices,triangles:earcut(vertices)}};static PolygonOutline=(points,thickness=1)=>{const linethickness=.5*thickness;function GetIndex(index){let r=index%points.length;return r<0&&(r+=points.length),r}const vertices=[],triangles=[],normals=[];let prevUpperRight,firstUpperLeft,firstDirN,baseTris=0;for(let i=0;i<points.length;i++){const prev=points[GetIndex(i-1)],cur=points[GetIndex(i)],next=points[GetIndex(i+1)],next2=points[GetIndex(i+2)],dirN=Vector2.sub(next,cur).rotate90().mutable.rescale(linethickness).immutable,leftNormal=Vector2.lerpRot(Vector2.sub(cur,prev),Vector2.sub(next,cur),.5).mutable.rotate90().rescale(1),rightNormal=Vector2.lerpRot(Vector2.sub(next,cur),Vector2.sub(next2,next),.5).mutable.rotate90().rescale(1),lowerLeft=Vector2.sub(cur,dirN),upperLeft=Vector2.add(cur,dirN),lowerRight=Vector2.sub(next,dirN),upperRight=Vector2.add(next,dirN);if(vertices.push(lowerLeft[0],lowerLeft[1],upperLeft[0],upperLeft[1],lowerRight[0],lowerRight[1],upperRight[0],upperRight[1]),normals.push(-leftNormal[0],-leftNormal[1],leftNormal[0],leftNormal[1],-rightNormal[0],-rightNormal[1],rightNormal[0],rightNormal[1]),triangles.push(baseTris,baseTris+1,baseTris+3,baseTris,baseTris+3,baseTris+2),0!==i){const toPrevUpper=Vector2.sub(prevUpperRight,upperLeft);Vector2.signedAngle(dirN,toPrevUpper)<0?triangles.push(baseTris,baseTris-2,baseTris+1):triangles.push(baseTris,baseTris-1,baseTris+1)}else firstUpperLeft=upperLeft,firstDirN=dirN;if(i===points.length-1){const toLastUpper=Vector2.sub(upperRight,firstUpperLeft);Vector2.signedAngle(firstDirN,toLastUpper)<0?triangles.push(0,baseTris-2,1):triangles.push(0,baseTris-1,1)}prevUpperRight=upperRight,baseTris+=4}return{vertices:vertices,triangles:triangles,normals:normals}};static from(vertices,triangles,vertexShader,fragmentShader,uniforms,normals){const geometry=new PIXI.Geometry;geometry.addAttribute("inputVerts",vertices,2),normals&&geometry.addAttribute("inputNormals",normals,2),geometry.addIndex(triangles);const shader=PIXI.Shader.from(vertexShader,fragmentShader,uniforms);return new PIXI.Mesh(geometry,shader)}}class OutlineModule extends ModuleInterface{outlineDict={};spawned=[];static vertexShader;static fragmentShader;config={baseWidth:.1,minZoom:0,maxZoom:18,minExtraWidth:.1,maxExtraWidth:10};state={extraWidth:1};scaling;constructor(config){super(),config&&(isNaN(config.minZoom)||(this.config.minZoom=config.minZoom),isNaN(config.maxZoom)||(this.config.maxZoom=config.maxZoom),isNaN(config.minExtraWidth)||(this.config.minExtraWidth=config.minExtraWidth),isNaN(config.maxExtraWidth)||(this.config.maxExtraWidth=config.maxExtraWidth))}set(data){const project=this.pixiOverlay.utils.latLngToLayerPoint;this.clear(),data.forEach((outlineCollection=>{const uniforms={color:outlineCollection.meta.stroke,width:this.state.extraWidth,visible:!0};this.outlineDict[outlineCollection.meta.name]=uniforms;const coordinates=outlineCollection.coordinates;for(let n=0;n<coordinates.length;n++){const polygon=coordinates[n],projected=[];for(let i=0;i<polygon.length;i++){const p=polygon[i],pos=project(p);projected.push([pos.x,pos.y])}let outlineData;if(Vector2.equals(projected[0],projected[projected.length-1],1e-6)){if(projected.pop(),projected.length<=2){log(`Skipping outline (Polygon) with ${projected.length} points.`);continue}outlineData=Mesh.PolygonOutline(projected,this.config.baseWidth)}else{if(projected.length<=1){log(`Skipping outline (Line) with ${projected.length} points.`);continue}outlineData=Mesh.SimpleLine(projected,this.config.baseWidth)}const outline=Mesh.from(outlineData.vertices,outlineData.triangles,OutlineModule.vertexShader,OutlineModule.fragmentShader,uniforms,outlineData.normals);this.root.addChild(outline),this.spawned.push(outline)}}))}setVisibleLayers(names){Object.keys(this.outlineDict).forEach((key=>this.outlineDict[key].visible=!1)),names.forEach((name=>{const uniforms=this.outlineDict[name];uniforms&&(uniforms.visible=!0)}))}clear(){for(;this.spawned.length>0;){const temp=this.spawned.pop();this.root.removeChild(temp),temp.destroy()}this.outlineDict={}}resize(zoom){const t=inverseLerp(this.config.minZoom,this.config.maxZoom,zoom),width=lerp(this.config.maxExtraWidth,this.config.minExtraWidth,t);this.state.extraWidth=width,Object.keys(this.outlineDict).forEach((key=>{this.outlineDict[key].width=width}))}}function toShader(n){return n===Math.floor(n)?`${n.toString()}.0`:n.toString()}OutlineModule.vertexShader="\n attribute vec2 inputVerts;\n attribute vec2 inputNormals;\n\n uniform mat3 translationMatrix;\n uniform mat3 projectionMatrix;\n\n uniform float width;\n\n void main() {\n vec2 pos = inputVerts + inputNormals * width;\n gl_Position = vec4((projectionMatrix * translationMatrix * vec3(pos, 1.0)).xy, 0.0, 1.0);\n }\n",OutlineModule.fragmentShader="\n precision mediump float;\n\n uniform vec3 color;\n uniform bool visible;\n\n void main() {\n if (!visible) discard;\n gl_FragColor = vec4(color, 1.0);\n }\n";class WellboreShader{static program=null;static get(color,completionVisible,wellboreVisible){return new PIXI.Shader(WellboreShader.program,{wellboreColor1:color.col1,wellboreColor2:color.col2,completionVisible:completionVisible,wellboreVisible:wellboreVisible,status:0})}static build(maxScale,wellboreDash){const vertex=`\n attribute vec2 verts;\n attribute vec4 vertCol;\n attribute float typeData;\n\n uniform mat3 translationMatrix;\n uniform mat3 projectionMatrix;\n uniform float wellboreRadius;\n\n varying vec4 vCol;\n varying float type;\n\n void main() {\n vCol = vertCol;\n type = typeData;\n\n vec2 normal = vertCol.zw;\n\n float extraRadius = wellboreRadius - ${toShader(maxScale)};\n\n gl_Position = vec4((projectionMatrix * translationMatrix * vec3(verts + normal * extraRadius, 1.0)).xy, 0.0, 1.0);\n }\n `,dash=toShader(wellboreDash),doubleDash=toShader(2*wellboreDash),fragment=`\n precision mediump float;\n\n varying vec4 vCol;\n varying float type;\n\n uniform vec3 wellboreColor1;\n uniform vec3 wellboreColor2;\n uniform bool completionVisible;\n uniform bool wellboreVisible;\n uniform int status;\n\n const vec3 sunDir = vec3(0.6247, -0.6247, 0.4685);\n\n void main() {\n vec3 col = vec3(0.0);\n float alpha = 1.0;\n\n if (status == 0) {\n if(type == 0.0) {\n if (!wellboreVisible) {\n alpha = 0.03;\n }\n } else if (type == 1.0) {\n if(completionVisible){\n if(mod(vCol.x, ${doubleDash}) > ${dash}) discard;\n } else if(!wellboreVisible){\n alpha = 0.03;\n }\n }\n if (!completionVisible && type == 2.0) discard;\n\n float dist = clamp(vCol.z * vCol.z + vCol.w * vCol.w, 0.0, 1.0);\n\n vec3 dir3D = vec3(vCol.zw, sqrt(1.0 - dist * dist));\n\n float light = 0.4 + dot(dir3D, sunDir) * 0.6;\n light = clamp(light, 0.0, 1.0);\n\n col = mix(wellboreColor2, wellboreColor1, light);\n }\n\n else if (status == 1) {\n if (type == 2.0) discard;\n if(mod(vCol.x + vCol.y * 0.2, ${toShader(4*wellboreDash)}) > ${doubleDash}) discard;\n vec3 c = wellboreColor2 + wellboreColor1 * 0.5;\n vec3 gray = vec3(0.9);\n col = mix(gray, c, 0.3);\n }\n\n else if (status == 2) {\n if (type == 2.0) discard;\n alpha = 0.03;\n }\n\n col *= alpha;\n gl_FragColor = vec4(col, alpha);\n }\n `;WellboreShader.program=new PIXI.Program(vertex,fragment)}}class RootShader{static program=null;static get(){return new PIXI.Shader(RootShader.program,{active:!0,circleColor1:[0,0,0],circleColor2:[0,0,0]})}static build(maxScale){const vertex=`\n attribute vec2 verts;\n attribute vec2 inputUVs;\n\n uniform mat3 translationMatrix;\n uniform mat3 projectionMatrix;\n uniform float rootRadius;\n\n varying vec2 UVs;\n\n void main() {\n UVs = inputUVs;\n\n vec2 dir = 2.0 * inputUVs - 1.0;\n\n float extraRadius = rootRadius - ${toShader(maxScale)};\n\n gl_Position = vec4((projectionMatrix * translationMatrix * vec3(verts + dir * extraRadius, 1.0)).xy, 0.0, 1.0);\n }\n `;RootShader.program=new PIXI.Program(vertex,"\n precision mediump float;\n\n varying vec2 UVs;\n\n uniform vec3 circleColor1;\n uniform vec3 circleColor2;\n uniform bool active;\n\n const vec3 sunDir = vec3(0.6247, -0.6247, 0.4685);\n\n void main() {\n if (!active) {\n discard;\n return;\n }\n vec2 dir = 2.0 * UVs - 1.0;\n float dist = dir.x * dir.x + dir.y * dir.y;\n if (dist > 1.0) discard;\n\n vec3 dir3D = vec3(dir, sqrt(1.0 - dist * dist));\n\n float light = dot(dir3D, sunDir);\n light = 0.4 + light * 0.6;\n\n vec3 col = mix(circleColor2, circleColor1, clamp(light, 0.0, 1.0));\n\n gl_FragColor = vec4(col, 1.0);\n }\n ")}}function generateCircle(center,radius,shader){const geometry=new PIXI.Geometry;geometry.addAttribute("verts",[center[0]-radius,center[1]-radius,center[0]+radius,center[1]-radius,center[0]-radius,center[1]+radius,center[0]+radius,center[1]+radius],2),geometry.addAttribute("inputUVs",[0,0,1,0,0,1,1,1],2),geometry.addIndex([0,2,3,0,3,1]);return new PIXI.Mesh(geometry,shader)}class Label{static state={zoom:1,scale:1,visible:!0,rootDisplacement:1};static style;static config;static height;container;text;background;metrics;_attachToRoot=!1;static setStyle(fontSize){Label.style=new PIXI.TextStyle({fontFamily:"Arial",fontSize:fontSize,fill:16777215,align:"center"}),Label.height=PIXI.TextMetrics.measureText(" ",Label.style).height}static setCommon(config){Label.config=config}constructor(label,fontColor,bgColor){const metrics=PIXI.TextMetrics.measureText(label,Label.style);this.metrics=metrics;const container=new PIXI.Container;container.visible=Label.state.visible,container.zIndex=0,this.container=container;const background=new PIXI.Graphics;background.beginFill(16777215),background.drawRect(.55*-metrics.width,.525*-Label.height,1.1*metrics.width,1.05*Label.height),background.endFill(),background.alpha=Label.config.backgroundOpacity,background.tint=bgColor,this.background=background;const text=new PIXI.Text(label,Label.style);text.resolution=window.devicePixelRatio,text.tint=fontColor,text.anchor.set(.5),this.text=text,container.addChild(background,text)}get visible(){return this.container.visible}set visible(flag){this.container.visible=flag&&Label.state.visible}set fontColor(color){this.text.tint=color}get attachToRoot(){return this._attachToRoot}set attachToRoot(val){val!==this._attachToRoot&&(this._attachToRoot=val)}getBoundingBox(){const{y:y,width:width,height:height}=this.container,x=this.container.x-width/2;return new PIXI.Rectangle(x,y,width,height)}}class RootData{static state={rootRadius:1,maxScale:1};mesh;wellbores=[];position;labelIndex=0;rootLabelsBBox=null;target=null;constructor(position){this.position=position;const shader=RootShader.get();this.mesh=generateCircle(position,RootData.state.maxScale,shader)}get active(){return this.target&&this.target.active}updateLabelsBBox(label){const bbox=label.getBoundingBox();this.rootLabelsBBox?(this.rootLabelsBBox.height=bbox.y+bbox.height-this.rootLabelsBBox.y,bbox.width>this.rootLabelsBBox.width&&(this.rootLabelsBBox.x=bbox.x,this.rootLabelsBBox.width=bbox.width)):this.rootLabelsBBox=bbox}positionLabel(wellbore){if(wellbore.label.attachToRoot){!function(wellbore,position){wellbore.label.attachToRoot=!0;const{container:container}=wellbore.label,{scale:scale,rootDisplacement:rootDisplacement}=Label.state;container.rotation=0,container.pivot.set(0,.5*-Label.height);const yPos=rootDisplacement+5*scale+position*(Label.height+5)*scale+wellbore.root.position[1];container.position.set(wellbore.root.position[0],yPos),container.scale.set(scale)}(wellbore,this.labelIndex++),this.updateLabelsBBox(wellbore.label)}else!function(wellbore){wellbore.label.attachToRoot=!1;const{container:container,metrics:metrics}=wellbore.label,end=wellbore.interpolator.GetPoint(1).position,width=metrics.width*Label.state.scale,start=wellbore.interpolator.GetPointFromEnd(width),dir=Vector2.sub(end,start.position).mutable;let pivotX,pivotY,angle,pos;const mirror=!!wellbore.group?.mirrorLabels;dir.x<0?mirror?(pivotX=.5*-metrics.width,pivotY=.5*metrics.height,angle=Vector2.signedAngle(Vector2.left,dir),pos=dir.rotate90().rescale(.5*wellbore.wellboreWidth+.075).add(end)):(pivotX=.5*-metrics.width,pivotY=.5*-metrics.height,angle=Vector2.signedAngle(Vector2.left,dir),pos=dir.rotate270().rescale(.5*wellbore.wellboreWidth+.075).add(end)):mirror?(pivotX=.5*metrics.width,pivotY=.5*metrics.height,angle=Vector2.signedAngle(Vector2.right,dir),pos=dir.rotate270().rescale(.5*wellbore.wellboreWidth+.075).add(end)):(pivotX=.5*metrics.width,pivotY=.5*-metrics.height,angle=Vector2.signedAngle(Vector2.right,dir),pos=dir.rotate90().rescale(.5*wellbore.wellboreWidth+.075).add(end)),container.position.set(pos[0],pos[1]),container.pivot.set(pivotX,pivotY),container.rotation=angle,container.scale.set(Label.state.scale)}(wellbore)}append(wellbore){this.wellbores.push(wellbore),wellbore.active&&(this.target?wellbore.order<this.target.order&&wellbore.status>this.target.status?this.recalculate(!0):Label.state.visible&&this.positionLabel(wellbore):this.recalculate(!0))}recalculate(labelUpdate=!1){this.updateTarget(),this.updateUniforms(),labelUpdate&&this.updateLabels()}updateTarget(){let target,smallest=Number.MAX_VALUE;for(let i=0;i<this.wellbores.length;i++){const wellbore=this.wellbores[i];if(!wellbore.active)continue;if(wellbore.selected){target=wellbore;break}const weighted=wellbore.order-1e6*wellbore.status;weighted<smallest&&(smallest=weighted,target=wellbore)}this.target=target}updateUniforms(){const uniform=this.mesh.shader.uniforms;if(uniform.active=this.active,this.target){const color=this.target.color;uniform.circleColor1=color.col1,uniform.circleColor2=color.col2,this.mesh.zIndex=this.target.status}uniform.rootRadius=RootData.state.rootRadius}updateLabels(){this.labelIndex=0,this.rootLabelsBBox=null,Label.state.visible&&this.wellbores.forEach((wellbore=>{wellbore.active&&this.positionLabel(wellbore)}))}setLabelVisibility(visible){visible?this.updateLabels():this.rootLabelsBBox=null,this.wellbores.forEach((wellbore=>{wellbore.active&&(wellbore.label.visible=visible)}))}}class LineInterpolator{amount;length;singlePoint=!0;path;constructor(points,radius){const amount=points.length,path=new Array(amount),root=points[0];let initDir;initDir=points.length>=2?Vector2.sub(points[1],points[0]).normalize():Vector2.right,path[0]={point:root,direction:initDir,distance:0,relative:0};let length=0;for(let i=1;i<amount;i++){const point=points[i];length+=Vector2.distance(point,path[i-1].point),path[i]={point:point,direction:this.GetDirection(points,i),distance:length,relative:0},Vector2.distance(point,root)>radius&&(this.singlePoint=!1)}for(let i=1;i<amount;i++){const p=path[i];p.relative=0===length?0:p.distance/length}this.amount=amount,this.length=length,this.path=path}GetPoint(relative){if(this.singlePoint)return{position:this.path[0].point,direction:Vector2.up,distance:0};if(relative<0){const first=this.path[0];return{position:first.point,direction:first.direction,distance:0}}if(relative>=1){const last=this.path[this.amount-1];return{position:last.point,direction:last.direction,distance:this.length}}const base=this.GetClosestPointBelow(relative),prev=this.path[base],cur=this.path[base+1],dist=cur.relative-prev.relative,frac=(relative-prev.relative)/dist;return{position:mix(prev.point,cur.point,frac,Vector2.zero),direction:Vector2.lerpRot(prev.direction,cur.direction,frac).normalize(),distance:prev.distance*(1-frac)+cur.distance*frac}}GetSection(relativeStart,relativeEnd){if(this.singlePoint)return[{position:this.path[0].point,direction:Vector2.up,distance:0},{position:this.path[0].point,direction:Vector2.up,distance:0}];if(relativeStart>=1){const last=this.path[this.path.length-1];return[{position:last.point,direction:last.direction,distance:this.length},{position:last.point,direction:last.direction,distance:this.length}]}const base=this.GetClosestPointBelow(relativeStart),points=[],prev=this.path[base],cur=this.path[base+1],dist=cur.relative-prev.relative,frac=(relativeStart-prev.relative)/dist;points.push({position:mix(prev.point,cur.point,frac,Vector2.zero),direction:Vector2.lerpRot(prev.direction,cur.direction,frac).normalize(),distance:prev.distance*(1-frac)+cur.distance*frac});for(let i=base+1;i<this.amount;i++){const cur=this.path[i];if(cur.relative>=relativeEnd){const cur=this.path[i],prev=this.path[i-1],dist=cur.relative-prev.relative,frac=(relativeEnd-prev.relative)/dist;points.push({position:mix(prev.point,cur.point,frac,Vector2.zero),direction:Vector2.lerpRot(prev.direction,cur.direction,frac).normalize(),distance:prev.distance*(1-frac)+cur.distance*frac});break}points.push({position:cur.point,direction:this.path[i].direction,distance:cur.distance})}return points}GetClosestPointBelow(relative){let base=0,range=this.amount,idx=Math.floor(.5*range);for(;range>1;)relative<this.path[idx].relative?(range=Math.floor(.5*range),idx=base+Math.floor(.5*range)):(base+=Math.floor(.5*range),range=Math.ceil(.5*range),idx=base+Math.floor(.5*range));return base}GetPointFromStart(distance){const relative=distance/this.length;return this.GetPoint(relative)}GetPointFromEnd(distance){const relative=1-distance/this.length;return this.GetPoint(relative)}GetRangeFromStart(relative,width,resolution=10){const relativeDisp=(relative+width/this.length-relative)/resolution,points=[];for(let i=0;i<=resolution;i++)points.push(this.GetPoint(relative+relativeDisp*i));return points}GetDirection(points,idx){const end=points.length-1;if(0===idx)return Vector2.sub(points[1],points[0]).normalize();if(idx===end)return Vector2.sub(points[end],points[end-1]).normalize();{const cur=points[idx],to=Vector2.sub(cur,points[idx-1]),from=Vector2.sub(points[idx+1],cur);return Vector2.lerpRot(to,from,.5).normalize()}}}class WellboreMesh{interp;thickness;baseTris;tick;constructor(interp,thickness,tick){this.interp=interp,this.thickness=thickness,this.baseTris=0,this.tick=tick}generate(intervals=[]){const vertices=[],triangles=[],vertexData=[],extraData=[];if(intervals.length<=0){const path=this.interp.GetSection(0,1);this.appendSegment(path,0,vertices,triangles,vertexData,extraData)}else if(intervals.length>0){let p=0;intervals.forEach((i=>{const path1=this.interp.GetSection(p,i[0]);this.appendSegment(path1,0,vertices,triangles,vertexData,extraData);const path2=this.interp.GetSection(i[0],i[1]);this.appendSegment(path2,1,vertices,triangles,vertexData,extraData),p=i[1]}));const end=intervals[intervals.length-1][1];if(end<1){const lastPath=this.interp.GetSection(end,1);this.appendSegment(lastPath,0,vertices,triangles,vertexData,extraData)}}return intervals.forEach((i=>{const p1=this.interp.GetPoint(i[0]);if(this.generateCrossline(p1,vertices,triangles,vertexData,extraData),Math.abs(i[0]-i[1])<.001)return;const p2=this.interp.GetPoint(i[1]);this.generateCrossline(p2,vertices,triangles,vertexData,extraData)})),{vertices:vertices,triangles:triangles,vertexData:vertexData,extraData:extraData}}appendSegment(section,type,vertices,triangles,vertexData,extraData){const mesh=Mesh.WellboreSegment(section,this.thickness,type);vertices.push(...mesh.vertices),mesh.triangles.forEach((d=>triangles.push(d+this.baseTris))),vertexData.push(...mesh.vertexData),extraData.push(...mesh.extraData),this.baseTris+=mesh.vertices.length/2}generateCrossline(p,vertices,triangles,vertexData,extraData){const px=p.position[0],py=p.position[1],crosslinesWidth=this.tick.width,dirX=p.direction[0]*crosslinesWidth,dirY=p.direction[1]*crosslinesWidth,crosslinesHeight=this.tick.height,normX=-p.direction[1]*crosslinesHeight,normY=p.direction[0]*crosslinesHeight;vertices.push(px-dirX-normX,py-dirY-normY,px+dirX-normX,py+dirY-normY,px-dirX+normX,py-dirY+normY,px+dirX+normX,py+dirY+normY),triangles.push(this.baseTris,this.baseTris+2,this.baseTris+3,this.baseTris,this.baseTris+3,this.baseTris+1),extraData.push(2,2,2,2);const normalizedNormal=new Vector2(normX,normY).normalized(),nnx=normalizedNormal.x,nny=normalizedNormal.y;vertexData.push(p.distance,0,-nnx,-nny,p.distance,0,-nnx,-nny,p.distance,1,nnx,nny,p.distance,1,nnx,nny),this.baseTris+=4}}var WellboreStatus,FilterStatus,ColorType;!function(WellboreStatus){WellboreStatus[WellboreStatus.normal=0]="normal",WellboreStatus[WellboreStatus.highlighted=1]="highlighted",WellboreStatus[WellboreStatus.multiHighlighted=2]="multiHighlighted",WellboreStatus[WellboreStatus.selected=3]="selected"}(WellboreStatus||(WellboreStatus={})),function(FilterStatus){FilterStatus[FilterStatus.none=0]="none",FilterStatus[FilterStatus.soft=1]="soft",FilterStatus[FilterStatus.hard=2]="hard"}(FilterStatus||(FilterStatus={}));class WellboreData{static state={wellboreRadius:1,rootRadius:1};data;group;wellboreWidth;interpolator;container;label;_zIndex=0;details;detailsDict={};mesh;root;status=WellboreStatus.normal;filter=FilterStatus.none;constructor(input){if(this.data=input.data,this.group=input.group,this.root=input.root,this.wellboreWidth=input.wellboreWidth,this.interpolator=new LineInterpolator(input.coords,input.pointThreshold),this.label=new Label(input.data.labelShort,this.colors.fontColor,this.colors.default.labelBg),this.interpolator.singlePoint)this.label.attachToRoot=!0;else{this.container=new PIXI.Container;const intervals=function(intervals){let output=intervals.map((i=>[i.l1,i.l2])).sort(((a,b)=>a[0]<b[0]?-1:a[0]>b[0]?1:0));return output.length>0&&(output=function(intervals){const output=[];let prev=intervals[0].slice(0);for(let i=1;i<intervals.length;i++){const cur=intervals[i].slice(0);cur[0]<prev[1]?cur[1]>prev[1]&&(prev[1]=cur[1]):(output.push(prev),prev=cur)}return output.push(prev),output}(output)),output}(input.data.intervals);this.details=new PIXI.Container,this.mesh=this.createWellboreMesh(intervals,input.tick),this.container.addChild(this.details,this.mesh)}this.update()}set zIndex(val){this._zIndex=val,this.container&&(this.container.zIndex=this._zIndex)}get colors(){return this.group.colors}get color(){const{colors:colors}=this.group;switch(this.status){case WellboreStatus.normal:return colors.default;case WellboreStatus.highlighted:return colors.highlight;case WellboreStatus.multiHighlighted:return colors.multiHighlight;case WellboreStatus.selected:return colors.selected}}get active(){const activeUniform=this.mesh&&0===this.mesh.shader.uniforms.status;return this.group.active&&(activeUniform||this.filter===FilterStatus.none)}tryDrawDetail(key,detail){if(!this.container)return;const relative=detail.getRelative(this.data);if(!Array.isArray(relative)||0===relative.length)return;const container=new PIXI.Container;container.visible=detail.visible,relative.forEach((p=>{const graphics=detail.getGraphics(p,this.interpolator);container.addChild(graphics)})),this.details.addChild(container),this.detailsDict[key]=container}setFilter(filter){this.filter!==filter&&(this.filter=filter,this.update())}get selected(){return this.status===WellboreStatus.selected}get highlighted(){return this.status===WellboreStatus.highlighted||this.status===WellboreStatus.multiHighlighted}get order(){return this.group.order}get uniforms(){return this.mesh.shader.uniforms}createWellboreMesh(intervals,tick){const line=new WellboreMesh(this.interpolator,this.wellboreWidth,tick),{vertices:vertices,triangles:triangles,vertexData:vertexData,extraData:extraData}=line.generate(intervals),geometry=new PIXI.Geometry;geometry.addAttribute("verts",vertices,2),geometry.addAttribute("vertCol",vertexData,4),geometry.addAttribute("typeData",extraData,1),geometry.addIndex(triangles);const shader=WellboreShader.get(this.colors.default,this.group.state.completionVisible,this.group.state.wellboreVisible);return new PIXI.Mesh(geometry,shader)}setCompletionVisibility(visible){this.mesh&&(this.uniforms.completionVisible=visible)}setWellboreVisibility(visible){this.mesh&&(this.uniforms.wellboreVisible=visible)}setDetailsVisibility(key,visible){key in this.detailsDict&&(this.detailsDict[key].visible=visible)}setHighlight(isHighlighted,multiple=!1){if(this.status!==WellboreStatus.selected)if(this.status=isHighlighted?multiple?WellboreStatus.multiHighlighted:WellboreStatus.highlighted:WellboreStatus.normal,isHighlighted){const color=multiple?this.colors.multiHighlight:this.colors.highlight;this.mesh&&(this.mesh.shader.uniforms.wellboreColor1=color.col1,this.mesh.shader.uniforms.wellboreColor2=color.col2,this.container.zIndex=this._zIndex+1e5),this.label.container.zIndex=1,this.label.background.tint=color.labelBg,this.label.background.alpha=.75,this.label.fontColor=this.colors.interactFontColor}else this.mesh&&(this.mesh.shader.uniforms.wellboreColor1=this.colors.default.col1,this.mesh.shader.uniforms.wellboreColor2=this.colors.default.col2,this.container.zIndex=this._zIndex),this.label.container.zIndex=0,this.label.background.tint=this.colors.default.labelBg,this.label.background.alpha=Label.config.backgroundOpacity,this.label.fontColor=this.colors.fontColor}setSelected(isSelected){this.status=isSelected?WellboreStatus.selected:WellboreStatus.normal,isSelected?(this.mesh&&(this.mesh.shader.uniforms.wellboreColor1=this.colors.selected.col1,this.mesh.shader.uniforms.wellboreColor2=this.colors.selected.col2,this.container.zIndex=this._zIndex+1e6),this.label.container.zIndex=1,this.label.background.tint=this.colors.selected.labelBg,this.label.background.alpha=.75):(this.mesh&&(this.mesh.shader.uniforms.wellboreColor1=this.colors.default.col1,this.mesh.shader.uniforms.wellboreColor2=this.colors.default.col2,this.container.zIndex=this._zIndex),this.label.container.zIndex=0,this.label.background.tint=this.colors.default.labelBg,this.label.background.alpha=Label.config.backgroundOpacity),this.label.fontColor=this.colors.fontColor,this.root.recalculate()}update(){if(this.group.active){const noFilter=this.filter===FilterStatus.none;this.container&&(this.container.visible=!0,this.mesh.shader.uniforms.status=this.filter,this.mesh.shader.uniforms.wellboreRadius=WellboreData.state.wellboreRadius,this.mesh.shader.uniforms.rootRadius=WellboreData.state.rootRadius,this.details.visible=noFilter),this.label.visible=noFilter}else this.container&&(this.container.visible=!1,this.details.visible=!1),this.label.visible=!1}}function getDefaultColors(input){const output={fontColor:0,interactFontColor:16777215,default:{col1:[.3,.3,.3],col2:[.05,.05,.05],labelBg:16777215},highlight:{col1:[.8,.2,.9],col2:[.5,.05,.6],labelBg:10685091},multiHighlight:{col1:[.55,.55,.55],col2:[.3,.3,.3],labelBg:6710886},selected:{col1:[1,0,0],col2:[.5,0,0],labelBg:16777215}};if(!input)return output;function transfer(key){isNaN(input[key])||(output[key]=input[key])}function transferColor(color){const inputCol1=input[`${color}Color1`],inputCol2=input[`${color}Color2`],inputLabelBg=input[`${color}LabelBg`],outputColor=output[color];inputCol1&&(outputColor.col1=inputCol1),inputCol2&&(outputColor.col2=inputCol2),inputLabelBg&&(outputColor.labelBg=inputLabelBg)}return transfer("fontColor"),transfer("interactFontColor"),transferColor("default"),transferColor("highlight"),transferColor("multiHighlight"),transferColor("selected"),output}!function(ColorType){ColorType[ColorType.Default=0]="Default",ColorType[ColorType.Highlight=1]="Highlight",ColorType[ColorType.MultiHighlight=2]="MultiHighlight",ColorType[ColorType.Selected=3]="Selected"}(ColorType||(ColorType={}));class Detail{initialized=!1;visible=!1;getData;color;group;constructor(options,group="default"){this.getData=options.getData,this.color=new PIXI.Color(options.color||[0,0,0]),this.group=group}getRelative(wellbore){return this.getData(wellbore,this.group)}}class ShoeDetail extends Detail{widthTop;widthBottom;constructor(options,group="default"){super(options,group),this.widthTop=options.widthTop||1,this.widthBottom=options.widthBottom||1}getGraphics([top,bottom],interpolator){const from=interpolator.GetPoint(top).position,to=interpolator.GetPoint(bottom).position,normal=Vector2.sub(to,from).rotate90().normalize(),normalTop=normal.scale(this.widthTop),normalBottom=normal.scale(this.widthBottom),from1=Vector2.add(from,normalTop),from2=Vector2.sub(from,normalTop),to1=Vector2.add(to,normalBottom),to2=Vector2.sub(to,normalBottom);return(new PIXI.Graphics).beginFill(this.color,1).lineStyle(0).moveTo(from1.x,from1.y).lineTo(to1.x,to1.y).lineTo(to2.x,to2.y).lineTo(from2.x,from2.y).endFill()}}class Group{key;colors;order=0;mirrorLabels=!1;wellbores=[];details={};active=!0;activeFilter=null;isHardFilter;state={completionVisible:!0,wellboreVisible:!0};constructor(key,options){this.key=key,options?(isNaN(options.order)||(this.order=options.order),options.mirrorLabels&&(this.mirrorLabels=options.mirrorLabels),this.colors=getDefaultColors(options.colors)):this.colors=getDefaultColors()}registerDetail(key,detail){if(key in this.details)throw Error(`Detail already registered, ${key}, for group: ${this.key}!`);this.details[key]=((options,group="default")=>{const{shape:shape}=options;return new ShoeDetail(options,group)})(detail)}setDetailVisibility(key,visible){if(key in this.details){const detail=this.details[key];if(visible&&!detail.initialized&&(this.wellbores.forEach((wellbore=>{wellbore.tryDrawDetail(key,detail)})),detail.initialized=!0),visible===detail.visible)return;this.wellbores.forEach((wellbore=>{wellbore.setDetailsVisibility(key,visible)})),detail.visible=visible}}resetDetails(){Object.values(this.details).forEach((detail=>{detail.initialized=!1}))}append(wellbore){if(wellbore.zIndex=1e4*this.order+this.wellbores.length,this.activeFilter){const targetFilter=this.isHardFilter?FilterStatus.hard:FilterStatus.soft;wellbore.setFilter(this.activeFilter(wellbore.data)?FilterStatus.none:targetFilter),wellbore.root.recalculate(!0)}Object.entries(this.details).forEach((([key,detail])=>{detail.initialized&&wellbore.tryDrawDetail(key,detail)})),this.wellbores.push(wellbore)}forAll(wellboreFunc,rootFunc){const roots=new Set,wellbores=this.wellbores;for(let i=0;i<wellbores.length;i++){const wellbore=wellbores[i];wellboreFunc(wellbore),roots.add(wellbore.root)}roots.forEach((root=>rootFunc(root)))}setActive(active){this.active!==active&&(this.active=active,this.forAll((wellbore=>wellbore.update()),(root=>root.recalculate(!0))))}softFilter(filter){this.activeFilter=filter,this.isHardFilter=!1,this.forAll((wellbore=>wellbore.setFilter(filter(wellbore.data)?FilterStatus.none:FilterStatus.soft)),(root=>root.recalculate(!0)))}hardFilter(filter){this.activeFilter=filter,this.isHardFilter=!0,this.forAll((wellbore=>wellbore.setFilter(filter(wellbore.data)?FilterStatus.none:FilterStatus.hard)),(root=>root.recalculate(!0)))}clearFilter(){this.activeFilter=null,this.forAll((wellbore=>wellbore.setFilter(FilterStatus.none)),(root=>root.recalculate(!0)))}setCompletionVisibility(visible){this.state.completionVisible=visible,this.wellbores.forEach((wellbore=>{wellbore.setCompletionVisibility(visible)}))}setWellboreVisibility(visible){this.state.wellboreVisible=visible,this.wellbores.forEach((wellbore=>{wellbore.setWellboreVisibility(visible)}))}}class WellboreEventData{group;data;constructor(group,data){this.group=group,this.data=data}static from(wellbore){return new WellboreEventData(wellbore.group.key,wellbore.data)}}class HighlightEvent{changed;originalEvent;eventData;constructor(eventData,changed,originalEvent){this.eventData=eventData,this.changed=changed,this.originalEvent=originalEvent}static from(wellbores,changed,originalEvent){return new HighlightEvent(wellbores.map((w=>new WellboreEventData(w.group.key,w.data))),changed,originalEvent)}get count(){return this.eventData.length}}function distanceToLine(point,lineStart,lineEnd){const lineDir=Vector2.sub(lineEnd,lineStart),lineAngle=Vector2.angleRight(lineDir),len=lineDir.magnitude,dir=Vector2.sub(point,lineStart).mutable.rotate(-lineAngle);return dir[0]<0?dir.magnitude:dir[0]>len?Vector2.distance(point,lineEnd):Math.abs(dir.y)}class LineDictionary{gridsize;tiles=new Map;lineValues=new Map;testActiveFunction;lineSeq;constructor(gridsize=10,testActive){this.gridsize=gridsize,this.lineSeq=0,this.testActiveFunction=testActive}add(points,value,id){const lineID=Number.isFinite(id)?id:++this.lineSeq,line={id:lineID,value:value,segments:[]};this.lineValues.set(lineID,line);for(let i=1;i<points.length;i++){const p1=points[i-1],p2=points[i];this.addSegment(p1[0],p1[1],p2[0],p2[1],line)}return line}addSegment(x1,y1,x2,y2,line){const segment={lineID:line.id,geometry:{x1:x1,y1:y1,x2:x2,y2:y2}};line.segments.push(segment);const intersections=function(x1,x2,y1,y2,gridsize){const intersections=new Set;let downwards,xMin,xMax,yMin,yMax,m,y0;if(x1<x2){xMin=Math.floor(x1/gridsize),xMax=Math.floor(x2/gridsize),m=(y2-y1)/(x2-x1),y0=(y1-x1*m)/gridsize,downwards=y2<y1;const key=`${Math.floor(x1/gridsize)}.${Math.floor(y1/gridsize)}`;intersections.add(key)}else{xMin=Math.floor(x2/gridsize),xMax=Math.floor(x1/gridsize),m=(y1-y2)/(x1-x2),y0=(y2-x2*m)/gridsize,downwards=y1<y2;const key=`${Math.floor(x2/gridsize)}.${Math.floor(y2/gridsize)}`;intersections.add(key)}y1<y2?(yMin=Math.floor(y1/gridsize),yMax=Math.floor(y2/gridsize)):(yMin=Math.floor(y2/gridsize),yMax=Math.floor(y1/gridsize));for(let x=xMin+1;x<=xMax;x++){const y=y0+x*m;intersections.add(`${x}.${Math.floor(y)}`)}for(let y=yMin+1;y<=yMax;y++){const x=(y-y0)/m;intersections.add(`${Math.floor(x)}.${Math.floor(downwards?y-1:y)}`)}return intersections}(x1,x2,y1,y2,this.gridsize);intersections.forEach((key=>{this.tiles.has(key)?this.tiles.get(key).push(segment):this.tiles.set(key,[segment])}))}getClosest(target,maxDist=1){const segments=this.getSegmentsOn3Grid(target);if(0===segments.size)return;let minDist=1/0,minLineID=-1;return segments.forEach((seg=>{const dist=distanceToLine(target,new Vector2(seg.geometry.x1,seg.geometry.y1),new Vector2(seg.geometry.x2,seg.geometry.y2));dist<minDist&&(minDist=dist,minLineID=seg.lineID)})),minDist>maxDist*this.gridsize?void 0:this.lineValues.get(minLineID).value}getAllClosest(target,epsilon=0,maxDist=1,filter){const segments=this.getSegmentsOn3Grid(target);if(0===segments.size)return[];let minDist=1/0,minID=-1,extraLines=[];if(segments.forEach((seg=>{const distance=distanceToLine(target,new Vector2(seg.geometry.x1,seg.geometry.y1),new Vector2(seg.geometry.x2,seg.geometry.y2));if(distance<minDist+epsilon)if(distance<minDist){const upperLimit=distance+epsilon,newLines=[];minDist<=upperLimit&&newLines.push({ID:minID,distance:minDist}),extraLines.forEach((d=>{d.distance<=upperLimit&&newLines.push(d)})),extraLines=newLines,minDist=distance,minID=seg.lineID}else extraLines.push({ID:seg.lineID,distance:distance})})),minDist>maxDist*this.gridsize)return[];const unique={[minID]:!0},uniqueLines=[];extraLines.forEach((d=>{unique.hasOwnProperty(d.ID)||(unique[d.ID]=!0,uniqueLines.push(d))}));const minT=this.lineValues.get(minID).value;let extraT=uniqueLines.map((d=>this.lineValues.get(d.ID).value));if(filter){const filtered=[];extraT.forEach((curT=>{filter(minT,curT)&&filtered.push(curT)})),extraT=filtered}return[minT,...extraT]}isActive(line){return!this.testActiveFunction||line&&this.testActiveFunction(line.value)}getSegmentsOn3Grid(target){const gridSegments=new Set,keyX=Math.floor(target[0]/this.gridsize),keyY=Math.floor(target[1]/this.gridsize);for(let x=-1;x<=1;x++)for(let y=-1;y<=1;y++){const key=`${keyX+x}.${keyY+y}`;this.tiles.has(key)&&this.tiles.get(key).forEach((tileSegment=>{gridSegments.has(tileSegment)||this.isActive(this.lineValues.get(tileSegment.lineID))&&gridSegments.add(tileSegment)}))}return gridSegments}clear(filter){if(filter){const segmentsToDelete=new Set;this.lineValues.forEach(((line,key)=>{filter(line.value,key)&&(line.segments.forEach(segmentsToDelete.add,segmentsToDelete),this.lineValues.delete(key))})),segmentsToDelete.size>0&&this.tiles.forEach(((list,key)=>{const filtered=list.filter((s=>!segmentsToDelete.has(s)));filtered.length>0?this.tiles.set(key,filtered):this.tiles.delete(key)}))}else this.tiles=new Map,this.lineValues=new Map}}class PointDictionary{distThreshold;gridSize;radius;tiles=new Map;pointValues=new Map;testActiveFunction;pointSeq=0;constructor(distThreshold,gridSize=2,radius,testActive){if(gridSize<radius)throw"Gridsize of point dictionary must be greater than scaled radius of root.";this.distThreshold=distThreshold,this.gridSize=gridSize,this.radius=radius,this.testActiveFunction=testActive}add(pos,val){const id=++this.pointSeq,point={val:val,pos:pos,id:id};this.pointValues.set(id,point);const keys=this.getKeys(pos);for(let i=0;i<keys.length;i++){const key=keys[i];if(this.tiles.has(key))this.tiles.get(key).set(id,point);else{const map=new Map;map.set(id,point),this.tiles.set(key,map)}}return id}getKeys(pos){const{radius:radius,gridSize:gridSize}=this,keyX=Math.floor(pos[0]/gridSize),keyY=Math.floor(pos[1]/gridSize),keys=[`${keyX}.${keyY}`],localX=pos[0]-keyX*gridSize,localY=pos[1]-keyY*gridSize,local=[localX,localY],addKey=(deltaX,deltaY)=>{keys.push(`${keyX+deltaX}.${keyY+deltaY}`)},tryAddDiagKey=(cornerLocal,deltaX,deltaY)=>{Vector2.distance(local,cornerLocal)<radius&&keys.push(`${keyX+deltaX}.${keyY+deltaY}`)};let l=!1,r=!1,d=!1,u=!1;return localX<radius&&(addKey(-1,0),l=!0),localX>gridSize-radius&&(addKey(1,0),r=!0),localY<radius&&(addKey(0,-1),d=!0),localY>gridSize-radius&&(addKey(0,1),u=!0),l?u?tryAddDiagKey([0,gridSize],-1,1):d&&tryAddDiagKey([0,0],-1,-1):r&&(u?tryAddDiagKey([gridSize,gridSize],1,1):d&&tryAddDiagKey([gridSize,0],1,-1)),keys}isActive(point){return!this.testActiveFunction||point&&this.testActiveFunction(point.val)}getKey(position){return`${Math.floor(position[0]/this.gridSize)}.${Math.floor(position[1]/this.gridSize)}`}getOverlapping(pos){const key=this.getKey(pos);if(!this.tiles.has(key))return null;const points=Array.from(this.tiles.get(key).values());for(let i=0;i<points.length;i++){const point=points[i];if(Vector2.distance(pos,point.pos)<this.distThreshold)return point}return null}getClosestUnder(pos,radius=this.radius){const key=this.getKey(pos);let minDist=1/0,closest=null;return this.tiles.has(key)?(this.tiles.get(key).forEach((point=>{const distance=Vector2.distance(pos,point.pos);this.isActive(point)&&distance<radius&&distance<minDist&&(minDist=distance,closest=point)})),closest):null}clear(filter){filter?this.pointValues.forEach((point=>{if(!filter(point.val,point.id))return;const keys=this.getKeys(point.pos);for(let i=0;i<keys.length;i++){const key=keys[i],tile=this.tiles.get(key);tile.delete(point.id),0===tile.size&&this.tiles.delete(key)}this.pointValues.delete(point.id)})):(this.tiles=new Map,this.pointValues=new Map)}}class Projector{project;constructor(project){this.project=project}get(coord,zoom){return this.project(coord,zoom)}getVector2(coord,zoom){return new Vector2(this.project(coord,zoom))}batch(coords,zoom){const output=new Array(coords.length);for(let i=0;i<coords.length;i++)output[i]=this.project(coords[i],zoom);return output}batchVector2(coords,zoom){const output=new Array(coords.length);for(let i=0;i<coords.length;i++)output[i]=new Vector2(this.project(coords[i],zoom));return output}}function forceHighlight(module,wellbore){const{highlight:highlight}=module,root=wellbore.root,wellbores=[wellbore];highlight&&!highlight.equals(root,wellbores)&&(highlight.set(root,wellbores),module.requestRedraw())}function clearHighlight(module,onHighlightOff){module.highlight.clear(),onHighlightOff&&onHighlightOff(),module.requestRedraw()}class Highlight{active=!1;root;wellbores;get single(){return 1===this.wellbores.length}get first(){return this.wellbores[0]}set(root,wellbores){if(!this.active)return this.root=root,this.wellbores=wellbores,this.highlightWellbores(),this.highlightRoot(),void(this.active=!0);this.root!==root||this.wellbores.length!==wellbores.length?(this.clear(),this.root=root,this.wellbores=wellbores,this.highlightWellbores(),this.highlightRoot()):(this.clearWellbores(),this.wellbores=wellbores,this.highlightWellbores()),this.active=!0}highlightRoot(){this.root.recalculate(!1)}highlightWellbores(){const multiple=this.wellbores.length>1;for(let i=0;i<this.wellbores.length;i++)this.wellbores[i].setHighlight(!0,multiple)}clear(){this.active&&(this.clearWellbores(),this.clearRoot(),this.active=!1)}clearRoot(){this.root.recalculate(!1),delete this.root}clearWellbores(){for(let i=0;i<this.wellbores.length;i++)this.wellbores[i].setHighlight(!1);delete this.wellbores}equals(root,wellbores){if(this.root!==root)return!1;if(this.wellbores.length!==wellbores.length)return!1;for(let i=0;i<this.wellbores.length;i++){const wellbore=this.wellbores[i];if(!wellbores.includes(wellbore))return!1}return!0}}class AsyncLoop{timers={};Start(key,config,interval=3){this.Stop(key);const{iterations:iterations,batchSize:batchSize,func:func,postFunc:postFunc,endFunc:endFunc}=config;let front=0;const batch=()=>{if(front>=iterations)return delete this.timers[key],void(endFunc&&endFunc());const tail=Math.min(front+batchSize,iterations);for(let i=front;i<tail;i++)func(i);postFunc&&postFunc(),front+=batchSize,this.timers[key]=setTimeout(batch,interval)};this.timers[key]=setTimeout(batch,interval)}Stop(key){key in this.timers&&(clearTimeout(this.timers[key]),delete this.timers[key])}StopAll(){const keys=Object.keys(this.timers);for(let i=0;i<keys.length;i++){const key=keys[i];clearTimeout(this.timers[key]),delete this.timers[key]}}}class DefaultEventHandler{map;element;callbacks;register(map,element,callbacks){this.map=map,this.element=element,this.callbacks=callbacks,element.addEventListener("mousemove",this.callbacks.mousemove),element.addEventListener("mouseout",this.callbacks.mouseout),element.addEventListener("click",this.callbacks.click),element.addEventListener("mousedown",this.callbacks.mousedown),element.addEventListener("mouseup",this.callbacks.mouseup)}unregister(){const{element:element}=this;element.removeEventListener("mousemove",this.callbacks.mousemove),element.removeEventListener("mouseout",this.callbacks.mouseout),element.removeEventListener("click",this.callbacks.click),element.removeEventListener("mousedown",this.callbacks.mousedown),element.removeEventListener("mouseup",this.callbacks.mouseup),this.map=null,this.element=null}}class RealtimeWellbore{map;root;prevCoords=[Number.MIN_VALUE,Number.MIN_VALUE];constructor(mapInput,wellbore){if(mapInput.utils&&"getMap"in mapInput.utils){const pixiOverlay=mapInput;this.map=pixiOverlay.utils.getMap()}else this.map=mapInput;this.root=wellbore.data.path[0]}get pixelCoordinates(){const{map:map}=this,containerPoint=map.latLngToContainerPoint(this.root),rect=map.getContainer().getBoundingClientRect(),coords=[rect.x+containerPoint.x,rect.y+containerPoint.y];return this.prevCoords=coords,coords}getPixelCoordinates(){const{prevCoords:prevCoords}=this,coords=this.pixelCoordinates;return{coords:coords,changed:!this.coordinatesEqual(coords,prevCoords,1e-5)}}coordinatesEqual(c1,c2,delta){return!(Math.abs(c1[0]-c2[0])>delta)&&!(Math.abs(c1[1]-c2[1])>delta)}}class WellboreModule extends ModuleInterface{config;groups={};roots=[];asyncLoop=new AsyncLoop;lineDict;pointDict;highlight=new Highlight;currentZoom=20;_deferredSelector;_deferredSelectorKeys=null;_projector;_eventHandler;_redrawAnimFrame=null;containers;scaling;marker;constructor(inputConfig){super(),this.requestRedraw=this.requestRedraw.bind(this);const[config,extra]=function(input){const outputConfig={scale:1,batchSize:20,zoomOrigin:0,gridSize:2,wellboreResize:{min:{zoom:10,scale:.01},max:{zoom:18,scale:.001}},rootResize:{min:{zoom:0,scale:1e3},max:{zoom:18,scale:.2}},tick:{width:.02,height:.2}},outputExtra={labelBgOpacity:.5,labelScale:.011,fontSize:18,scaling:void 0,wellboreDash:.01};if(!input)return[outputConfig,outputExtra];function transfer(key,target){isNaN(input[key])||(target[key]=input[key])}function transferFunction(key,target){"function"==typeof input[key]&&(target[key]=input[key])}function transferObj(key,target){input[key]&&(target[key]=input[key])}return transfer("rootRadius",outputConfig),transfer("batchSize",outputConfig),transfer("zoomOrigin",outputConfig),transfer("gridSize",outputConfig),transfer("labelBgOpacity",outputExtra),transfer("labelScale",outputExtra),transfer("fontSize",outputExtra),transfer("wellboreDash",outputExtra),transferFunction("scaling",outputExtra),transferFunction("onWellboreClick",outputConfig),transferFunction("onHighlightOn",outputConfig),transferFunction("onHighlightOff",outputConfig),transferObj("wellboreResize",outputConfig),transferObj("rootResize",outputConfig),transferObj("tick",outputConfig),[outputConfig,outputExtra]}(inputConfig);this.config=config,this.scaling=extra.scaling,this.lineDict=new LineDictionary(config.gridSize,(value=>value.active)),this.pointDict=new PointDictionary(.25,10*config.gridSize,this.getRootRadius(20),(value=>value.active)),this.registerGroup("default");const createContainer=()=>{const container=new PIXI.Container;return container.sortableChildren=!0,this.root.addChild(container),container};this.containers={wellbores:createContainer(),roots:createContainer(),labels:createContainer()},Label.setStyle(extra.fontSize),Label.setCommon({backgroundOpacity:extra.labelBgOpacity}),this._eventHandler=inputConfig&&inputConfig.customEventHandler||new DefaultEventHandler,RootShader.build(config.rootResize.max.scale),WellboreShader.build(config.wellboreResize.max.scale,extra.wellboreDash),RootData.state.maxScale=config.rootResize.max.scale}destroy(){this.asyncLoop.StopAll(),super.destroy()}registerGroup(key,options){if(this.groups[key])throw Error(`Group already registered: ${key}!`);this.groups[key]=new Group(key,options)}registerDetail(key,groupKeys,options){this.forEachGroup(groupKeys,(group=>group.registerDetail(key,options)))}addRoot(position){const overlapping=this.pointDict.getOverlapping(position);if(overlapping)return overlapping.val;const wellboreRoot=new RootData(position);return this.containers.roots.addChild(wellboreRoot.mesh),this.pointDict.add(position,wellboreRoot),this.roots.push(wellboreRoot),wellboreRoot}addWellbore(data,group=this.groups.default){if(0===data.path.length)throw Error("Empty wellbore path!");const projectedPath=this.projector.batchVector2(data.path),root=this.addRoot(projectedPath[0]),{rootResize:rootResize,wellboreResize:wellboreResize,tick:tick}=this.config,wellbore=new WellboreData({data:data,group:group,root:root,coords:projectedPath,pointThreshold:1.5*rootResize.max.scale,wellboreWidth:wellboreResize.max.scale,tick:tick});wellbore.container&&this.containers.wellbores.addChild(wellbore.container),this.containers.labels.addChild(wellbore.label.container),group.append(wellbore),root?.recalculate(!0),wellbore.interpolator.singlePoint||this.lineDict.add(projectedPath,wellbore),root?.append(wellbore),this._deferredSelector&&(null===this._deferredSelectorKeys||this._deferredSelectorKeys.includes(group.key))&&this._deferredSelector(wellbore.data)&&(this._deferredSelector=void 0,wellbore.setSelected(!0))}set(wells,key="default",batchSize=null){return new Promise(((resolve,reject)=>{const group=this.groups[key];if(group)try{this.groups[key].wellbores.length>0&&this.clear(key),this.asyncLoop.Start(key,{iterations:wells.length,batchSize:batchSize||this.config.batchSize||20,func:i=>this.addWellbore(wells[i],group),postFunc:()=>this.requestRedraw(),endFunc:()=>{this.requestRedraw(),resolve()}},0)}catch(err){reject(err)}else reject(Error(`Group [${key}] not registered!`))}))}forAllGroups(func){Object.keys(this.groups).forEach((key=>func(this.groups[key],key))),this.requestRedraw()}forEachGroup(keys,func){const registeredKeys=Object.keys(this.groups);(0===keys.length?registeredKeys:keys.filter((key=>registeredKeys.includes(key)))).forEach((key=>func(this.groups[key],key))),this.requestRedraw()}setActive(active,keys){this.forEachGroup(keys,(group=>group.setActive(active)))}handleMouseMove(event){const latLng=this.pixiOverlay.utils.getMap().mouseEventToLatLng(event);return function(module,pos,onHighlightOn,onHighlightOff,originalEvent){let wellbores;wellbores=function(pos,radius,pointDict){const root=pointDict.getClosestUnder(pos,radius);return root?root.val.wellbores.filter((d=>d.active)):null}(pos,module.getRootRadius(),module.pointDict),!wellbores&&module.containers.labels.visible&&(wellbores=function(pos,roots){const candidates=roots.filter((root=>root.active&&root.rootLabelsBBox&&root.rootLabelsBBox.contains(pos.x,pos.y)));for(let i=0;i<candidates.length;i++)for(let j=0;j<candidates[i].wellbores.length;j++){const wellbore=candidates[i].wellbores[j];if(wellbore.active&&wellbore.label.attachToRoot){const bbox=wellbore.label.getBoundingBox();if(bbox.y>pos.y)break;if(bbox.contains(pos.x,pos.y))return[wellbore]}}return null}(pos,module.roots)),wellbores||(wellbores=function(pos,lineDict,distanceThreshold=.5){const hit=lineDict.getClosest(pos,distanceThreshold);return hit?[hit]:null}(pos,module.lineDict,.5));const{highlight:highlight}=module;if(wellbores){const root=wellbores[0].root;let changed=!1;highlight.active&&highlight.equals(root,wellbores)||(changed=!0,highlight.set(root,wellbores),module.requestRedraw()),onHighlightOn&&onHighlightOn(HighlightEvent.from(wellbores,changed,originalEvent))}else highlight?.active&&clearHighlight(module,onHighlightOff)}(this,this.projector.getVector2(latLng),this.config.onHighlightOn,this.config.onHighlightOff,event),this.highlight.active}handleMouseOut(){return this.clearHighlight(this.config.onHighlightOff)}handleMouseClick(){if(this.config.onWellboreClick&&this.highlight.active&&this.highlight.single){const wellbore=this.highlight.first;return this.config.onWellboreClick({group:wellbore.group.key,data:wellbore.data}),!0}return!1}enable(...keys){this.setActive(!0,keys)}disable(...keys){this.setActive(!1,keys)}setLabelVisibility(visible){Label.state.visible=visible,this.roots.forEach((root=>root.setLabelVisibility(visible))),this.requestRedraw()}setCompletionVisibility(visible,...keys){this.forEachGroup(keys,(group=>group.setCompletionVisibility(visible)))}setWellboresVisibility(visible,...keys){this.forEachGroup(keys,(group=>group.setWellboreVisibility(visible)))}setDetailVisibility(visible,key){this.forAllGroups((group=>group.setDetailVisibility(key,visible)))}softFilter(filterFunction,...keys){this.forEachGroup(keys,(group=>group.softFilter(filterFunction)))}hardFilter(filterFunction,...keys){this.forEachGroup(keys,(group=>group.hardFilter(filterFunction)))}clearFilter(...keys){this.forEachGroup(keys,(group=>group.clearFilter()))}setSelected(selectFunction,...keys){let nSelected=0;this.forEachGroup(keys,(group=>{group&&group.wellbores.forEach((wellbore=>{selectFunction(wellbore.data)?(wellbore.setSelected(!0),nSelected++):wellbore.selected&&wellbore.setSelected(!1)}))})),0===nSelected&&(this._deferredSelector=selectFunction,this._deferredSelectorKeys=keys)}clearSelected(...keys){this.forEachGroup(keys,(group=>{group&&group.wellbores.forEach((wellbore=>{wellbore.selected&&wellbore.setSelected(!1)}))}))}setHighlight(label,...keys){const registeredKeys=Object.keys(this.groups);keys=0===keys.length?registeredKeys:keys.filter((key=>registeredKeys.includes(key)));for(let n=0;n<keys.length;n++){const group=this.groups[keys[n]];if(!group)continue;const wellbores=group.wellbores;for(let i=0;i<wellbores.length;i++){const wellbore=wellbores[i];if(wellbore.data.label===label)return forceHighlight(this,wellbore),new RealtimeWellbore(this.pixiOverlay,wellbore)}}return null}clearHighlight(onHighlightOff){return!!this.highlight.active&&(clearHighlight(this,onHighlightOff),!0)}clearAll(){this.highlight.clear(),this.asyncLoop.StopAll(),this.lineDict.clear(),this.pointDict.clear(),Object.values(this.groups).forEach((g=>{g.wellbores=[],g.resetDetails()})),this.roots=[],this.containers.wellbores.removeChildren().forEach((child=>child.destroy())),this.containers.labels.removeChildren().forEach((child=>child.destroy())),this.containers.roots.removeChildren().forEach((child=>child.destroy())),this.requestRedraw()}clear(...keys){if(0===keys.length)return void this.clearAll();this.highlight.clear();const roots=new Set;this.forEachGroup(keys,((group,key)=>{this.asyncLoop.Stop(key),this.lineDict.clear((d=>group.wellbores.includes(d))),group.wellbores.forEach((w=>{roots.add(w.root);const wellboreIdx=w.root.wellbores.indexOf(w);-1!==wellboreIdx&&w.root.wellbores.splice(wellboreIdx,1),w.container?.destroy(),w.label?.container?.destroy()})),group.wellbores=[],group.resetDetails()})),roots.forEach((root=>{if(root.wellbores.length>0)return void root.recalculate(!0);const rootIdx=this.roots.indexOf(root);-1!==rootIdx&&this.roots.splice(rootIdx,1),this.pointDict.clear((d=>d===root)),this.containers.roots.removeChild(root.mesh)})),this.requestRedraw()}resize(zoom){this.currentZoom=zoom;const wellboreRadius=this.getWellboreRadius(zoom),rootRadius=this.getRootRadius(zoom);if(WellboreData.state={wellboreRadius:wellboreRadius,rootRadius:rootRadius},!this.scaling)return;let scale=this.scaling(zoom-this.config.zoomOrigin);Number.isFinite(scale)||(scale=1),Label.state.zoom=zoom,Label.state.scale=scale,Label.state.rootDisplacement=rootRadius,RootData.state.rootRadius=rootRadius;const labelVisible=zoom>10;this.containers.labels.visible=labelVisible,labelVisible&&this.roots.forEach((root=>{root.updateLabels()})),Object.values(this.groups).forEach((({wellbores:wellbores})=>{wellbores.forEach((wellbore=>{wellbore.update()}))})),this.roots.forEach((root=>{root.recalculate()}))}onAdd(map){const element=this.pixiOverlay.utils.getRenderer().view.parentNode,callbacks={mousemove:this.handleMouseMove.bind(this),mouseout:this.handleMouseOut.bind(this),click:this.handleMouseClick.bind(this),mousedown:()=>!0,mouseup:()=>!0};this._eventHandler.register(map,element,callbacks)}onRemove(_map){this._eventHandler.unregister()}get projector(){return this._projector||(this._projector=new Projector(this.pixiOverlay.utils.latLngToLayerPoint)),this._projector}getRootRadius(zoom=this.currentZoom){return this.getRadius(zoom,this.config.rootResize)}getWellboreRadius(zoom=this.currentZoom){return this.getRadius(zoom,this.config.wellboreResize)}getRadius(zoom,{min:min,max:max}){const zoomClamped=clamp(zoom,min.zoom,max.zoom)-min.zoom,t=Math.pow(2,-zoomClamped);return lerp(max.scale,min.scale,t)}requestRedraw(){this._redrawAnimFrame||(this._redrawAnimFrame=requestAnimationFrame((()=>{this.pixiOverlay.redraw(),this._redrawAnimFrame=null})))}}function centerOfMass(vertices,triangles){let comX=0,comY=0,totalMass=0;for(let i=0;i<triangles.length;i+=3){const a=vertices[triangles[i]],b=vertices[triangles[i+1]],c=vertices[triangles[i+2]],ab=Vector2.sub(b,a),ac=Vector2.sub(c,a),mass=.5*Vector2.cross(ab,ac);comX+=mass*(a.x+b.x+c.x)/3,comY+=mass*(a.y+b.y+c.y)/3,totalMass+=mass}return[new Vector2(comX/totalMass,comY/totalMass),totalMass]}class Hightlighter{fields=[];cached=[];fillColor1;fillColor2;outlineColor;constructor(fillColor1,fillColor2,outlineColor){this.fillColor1=fillColor1,this.fillColor2=fillColor2,this.outlineColor=outlineColor}add(group){this.fields.push(group)}highlight(index){const target=this.fields[index];this.cached&&this.revert(),this.cached=new Array(target.length);for(let i=0;i<target.length;i++){const field=target[i];this.cached[i]={fillCol1:field.fill.uniform.col1,fillCol2:field.fill.uniform.col2,outlineCol:field.outline.uniform.color,baseZIndex:field.fill.mesh.zIndex,field:field},field.fill.uniform.col1=this.fillColor1,field.fill.uniform.col2=this.fillColor2,field.fill.mesh.zIndex+=1e4,field.outline.uniform.color=this.outlineColor,field.outline.mesh.zIndex+=1e4}}revert(){return!!this.cached&&(this.cached.forEach((d=>{d.field.fill.uniform.col1=d.fillCol1,d.field.fill.uniform.col2=d.fillCol2,d.field.fill.mesh.zIndex=d.baseZIndex,d.field.outline.uniform.color=d.outlineCol,d.field.outline.mesh.zIndex=d.baseZIndex+1})),this.cached=void 0,!0)}}function recalculatePosition(labels,selfIndex,targetIndiced){const self=labels[selfIndex];let comX=self.mass*self.position[0],comY=self.mass*self.position[1],totalMass=self.mass;return targetIndiced.forEach((idx=>{const target=labels[idx];comX+=target.mass*target.position[0],comY+=target.mass*target.position[1],totalMass+=target.mass})),[comX/totalMass,comY/totalMass]}class LabelManager{textStyle;baseScale;fields=[];multiFields=[];prevScale=1;visible=!0;constructor(textStyle,baseScale){this.textStyle=textStyle,this.baseScale=baseScale}addField(name,entries){if(entries.length<=1)this.fields.push({name:name,position:entries[0].position,instance:null});else{const textMetrics=PIXI.TextMetrics.measureText(name,this.textStyle),width=textMetrics.width*this.baseScale,height=textMetrics.height*this.baseScale,labels=entries.map((entry=>({position:entry.position,mass:entry.mass,instance:null,active:!0,consumed:[],consumer:-1})));this.multiFields.push({name:name,labels:labels,width:width,height:height})}}draw(root){const drawLabel=(name,position)=>{const instance=new PIXI.Text(name,this.textStyle);return instance.resolution=2,instance.position.set(position[0],position[1]),instance.scale.set(this.baseScale),instance.anchor.set(.5),instance.zIndex=1e5,root.addChild(instance),instance};this.fields.forEach((field=>{field.instance=drawLabel(field.name,field.position)})),this.multiFields.forEach((field=>{field.labels.forEach((label=>{label.instance=drawLabel(field.name,label.position)}))}))}resize(scale){this.fields.forEach((field=>{field.instance.scale.set(scale*this.baseScale)})),this.multiFields.forEach((field=>{field.labels.forEach((label=>{label.instance.scale.set(scale*this.baseScale)}));const centers=function(field,scale){const labels=field.labels,groups=[];for(let i=0;i<labels.length;i++)groups.push({index:i,consumed:[],consumer:-1});const isOverlapping=(a,b)=>{const dist=Vector2.sub(a.position,b.position);return Math.abs(dist[0])<field.width*scale&&Math.abs(dist[1])<field.height*scale};for(let i=0;i<labels.length;i++){const group=groups[i];if(group.consumer>=0)continue;const label=labels[i];for(let j=0;j<labels.length;j++)if(i!==j&&isOverlapping(label,labels[j])){let compIndex=j,compGroup=groups[j];if(compGroup.consumer>=0){if(compIndex=compGroup.consumer,compIndex===i)continue;compGroup=groups[compGroup.consumer]}compGroup.consumed.push(...group.consumed,i),group.consumed.forEach((d=>groups[d].consumer=compIndex)),group.consumed=[],group.consumer=compIndex;break}}const output=[];for(let i=0;i<groups.length;i++){const group=groups[i];group.consumer>=0||output.push(recalculatePosition(labels,group.index,group.consumed))}return output}(field,scale);for(let i=0;i<centers.length;i++){const label=field.labels[i],pos=centers[i];label.instance.visible=!0,label.instance.position.set(pos[0],pos[1])}for(let i=centers.length;i<field.labels.length;i++){field.labels[i].instance.visible=!1}})),this.prevScale=scale}hideLabels(){this.fields.forEach((field=>{field.instance.visible=!1})),this.multiFields.forEach((field=>{field.labels.forEach((label=>{label.instance.visible=!1}))})),this.visible=!1}showLabels(){this.fields.forEach((field=>{field.instance.visible=!0})),this.visible=!0}}function pointInsideTriangle(p,v1,v2,v3){const k1=(p[0]-v1[0])*(v2[1]-v1[1])-(p[1]-v1[1])*(v2[0]-v1[0]),k2=(p[0]-v2[0])*(v3[1]-v2[1])-(p[1]-v2[1])*(v3[0]-v2[0]),k3=(p[0]-v3[0])*(v1[1]-v3[1])-(p[1]-v3[1])*(v1[0]-v3[0]);return k1<0?k2<0&&k3<0:k2>=0&&k3>=0}class TriangleDictionary{resolution;tiles=new Map;triangles=[];polygonValues=[];constructor(decimals=0){this.resolution=10**decimals}add(vertices,triangles,value){const polygonID=this.polygonValues.length;let v1,v2,v3;this.polygonValues.push(value);for(let i=0;i<triangles.length;i+=3){const triangleID=this.triangles.length;v1=vertices[triangles[i]],v2=vertices[triangles[i+1]],v3=vertices[triangles[i+2]],this.triangles.push({v1:v1,v2:v2,v3:v3,polygonID:polygonID});const minX=Math.min(v1[0],v2[0],v3[0]),maxX=Math.max(v1[0],v2[0],v3[0]),minY=Math.min(v1[1],v2[1],v3[1]),maxY=Math.max(v1[1],v2[1],v3[1]),tileMinX=Math.floor(minX*this.resolution),tileMaxX=Math.floor(maxX*this.resolution),tileMinY=Math.floor(minY*this.resolution),tileMaxY=Math.floor(maxY*this.resolution);for(let x=tileMinX;x<=tileMaxX;x++)for(let y=tileMinY;y<=tileMaxY;y++){const key=`${x}.${y}`;this.tiles.has(key)?this.tiles.get(key).push(triangleID):this.tiles.set(key,[triangleID])}}}getPolygonAt(target){const key=`${Math.floor(target[0]*this.resolution)}.${Math.floor(target[1]*this.resolution)}`;if(!this.tiles.has(key))return null;const triangles=this.tiles.get(key);for(let i=0;i<triangles.length;i++){const triangle=this.triangles[triangles[i]];if(pointInsideTriangle(target,triangle.v1,triangle.v2,triangle.v3))return this.polygonValues[triangle.polygonID]}return null}}const red=[.8,0,0],green=[.133,.6,.133],pink=[1,.753,.796],gray=[.6,.6,.6],outlineRed=[.6,0,0],outlineGray=[.5,.5,.5];class FieldModule extends ModuleInterface{static vertexShaderFill;static fragmentShaderFill;static vertexShaderOutline;static fragmentShaderOutline;fields=[];config={initialHash:1,minHash:0,maxHash:1/0};dict=new TriangleDictionary(1.2);highlighter;labelManager;prevField=-1;constructor(config){super(),config&&(config.initialHash&&"number"==typeof config.initialHash&&(this.config.initialHash=config.initialHash),config.minHash&&"number"==typeof config.minHash&&(this.config.minHash=config.minHash),config.maxHash&&"number"==typeof config.maxHash&&(this.config.maxHash=config.maxHash))}set(data){this.config.initialHash=clamp(this.config.initialHash),this.fields=[];const textStyle=new PIXI.TextStyle({fontFamily:"Arial",fontSize:64,fontWeight:"600",fill:4539717,align:"center"});this.labelManager=new LabelManager(textStyle,.029),this.highlighter=new Hightlighter([.5,0,.5],[.25,0,.25],[.35,0,.35]);const preprocessedData=function(data){const unique={};return data.forEach((field=>{const fieldName=field.properties.label;let coordinates=[];const geometry=field.geometry;if("Polygon"===geometry.type)coordinates=geometry.coordinates;else{const multipolygons=geometry.coordinates;for(let i=0;i<multipolygons.length;i++)coordinates.push(...multipolygons[i])}function appendIndex(index){unique[fieldName].geometry.push({coordinates:coordinates[index],properties:{discname:field.properties.discname,hctype:field.properties.hctype,polygonId:field.properties.polygonId,status:field.properties.status}})}if(unique.hasOwnProperty(fieldName))for(let i=0;i<coordinates.length;i++)appendIndex(i);else if(unique[fieldName]={type:field.type,geometry:[{coordinates:coordinates[0],properties:{discname:field.properties.discname,hctype:field.properties.hctype,polygonId:field.properties.polygonId,status:field.properties.status}}],properties:{group:field.properties.group,guid:field.properties.guid,label:field.properties.label,lat:field.properties.lat,long:field.properties.long}},coordinates.length>1)for(let i=1;i<coordinates.length;i++)appendIndex(i)})),Object.values(unique)}(data);let fieldID=0,baseZIndex=0;preprocessedData.forEach((field=>{const name=field.properties.label;if("Troll"===name)return;const guid=field.properties.guid,entries=[],meshes=[];field.geometry.forEach((polygon=>{const fieldStyle=this.getFieldStyle(guid,polygon.properties.hctype),projected=this.projectPolygons(polygon.coordinates);projected.pop();const meshData=Mesh.Polygon(projected);this.dict.add(polygon.coordinates,meshData.triangles,fieldID);const outlineData=Mesh.PolygonOutline(projected,.15),[position,mass]=centerOfMass(projected,meshData.triangles);meshes.push(this.drawPolygons(meshData,outlineData,fieldStyle,baseZIndex)),baseZIndex+=2,entries.push({position:position,mass:mass})})),fieldID++,this.labelManager.addField(name,entries),this.fields.push(...meshes),this.highlighter.add(meshes)})),this.labelManager.draw(this.root)}drawPolygons(meshData,outlineData,fieldStyle,zIndex){const fillUniform={col1:fieldStyle.fillColor1,col2:fieldStyle.fillColor2,opacity:fieldStyle.fillOpacity,hashed:fieldStyle.hashed,hashDisp:10*Math.random(),hashWidth:this.config.initialHash},outlineUniform={color:fieldStyle.outlineColor,width:0},polygonMesh=Mesh.from(meshData.vertices,meshData.triangles,FieldModule.vertexShaderFill,FieldModule.fragmentShaderFill,fillUniform);polygonMesh.zIndex=zIndex,this.root.addChild(polygonMesh);const polygonOutlineMesh=Mesh.from(outlineData.vertices,outlineData.triangles,FieldModule.vertexShaderOutline,FieldModule.fragmentShaderOutline,outlineUniform,outlineData.normals);return polygonOutlineMesh.zIndex=zIndex+1,this.root.addChild(polygonOutlineMesh),{fill:{mesh:polygonMesh,uniform:fillUniform},outline:{mesh:polygonOutlineMesh,uniform:outlineUniform}}}getFieldStyle(guid,hctype){if(!guid)return{fillColor1:gray,fillColor2:gray,outlineColor:outlineGray,fillOpacity:.15,hashed:!1};const fill={fillColor1:green,fillColor2:green,outlineColor:green,fillOpacity:.6,hashed:!1};switch(hctype){case"GAS":fill.fillColor1=red,fill.fillColor2=red,fill.outlineColor=outlineRed;break;case"GAS/CONDENSATE":fill.fillColor1=pink,fill.fillColor2=red,fill.outlineColor=outlineRed,fill.hashed=!0;break;case"OIL/GAS":fill.fillColor1=red,fill.hashed=!0}return fill}projectPolygons(points){const project=this.pixiOverlay.utils.latLngToLayerPoint;return points.map((c=>{const coord=project([c[1],c[0]]);return new Vector2(coord.x,coord.y)}))}resize(_zoom){}highlight(lat,long){const field=this.dict.getPolygonAt([long,lat]);return field?(this.prevField===field||(this.highlighter.highlight(field),this.pixiOverlay.redraw(),this.prevField=field),!0):(this.highlighter.revert()&&this.pixiOverlay.redraw(),this.prevField=-1,!1)}tryUnselect(){this.highlighter.revert()&&this.pixiOverlay.redraw(),this.prevField=-1}}FieldModule.vertexShaderFill="\n attribute vec2 inputVerts;\n\n uniform mat3 translationMatrix;\n uniform mat3 projectionMatrix;\n\n varying vec2 verts;\n\n void main() {\n verts = inputVerts;\n gl_Position = vec4((projectionMatrix * translationMatrix * vec3(inputVerts, 1.0)).xy, 0.0, 1.0);\n }\n",FieldModule.fragmentShaderFill="\n precision mediump float;\n\n varying vec2 verts;\n\n uniform vec3 col1;\n uniform vec3 col2;\n uniform float opacity;\n\n uniform bool hashed;\n uniform float hashDisp;\n uniform float hashWidth;\n\n void main() {\n if(hashed && mod(verts.y + hashDisp, hashWidth * 2.0) > hashWidth) {\n gl_FragColor = vec4(col2, 1.0) * opacity;\n }\n else {\n gl_FragColor = vec4(col1, 1.0) * opacity;\n }\n }\n",FieldModule.vertexShaderOutline="\n attribute vec2 inputVerts;\n attribute vec2 inputNormals;\n\n uniform mat3 translationMatrix;\n uniform mat3 projectionMatrix;\n\n uniform float width;\n\n void main() {\n vec2 pos = inputVerts + inputNormals * width;\n gl_Position = vec4((projectionMatrix * translationMatrix * vec3(pos, 1.0)).xy, 0.0, 1.0);\n }\n",FieldModule.fragmentShaderOutline="\n precision mediump float;\n\n uniform vec3 color;\n\n void main() {\n gl_FragColor = vec4(color, 1.0);\n }\n";class GeoJSONLabels{container;textStyle;font;fontName;baseScale;labels=[];visible=!0;constructor(root,textStyle,baseScale,fontName){this.container=new PIXI.Container,this.container.sortableChildren=!0,root.addChild(this.container),this.textStyle=textStyle,this.baseScale=baseScale,this.fontName=fontName||v4(),this.font=PIXI.BitmapFont.from(this.fontName,this.textStyle,{resolution:window.devicePixelRatio,chars:PIXI.BitmapFont.ASCII})}addLabel(name,data){this.labels.push({name:name,position:data.position,instance:null})}draw(){const drawLabel=(name,position)=>{const instance=new PIXI.BitmapText(name,{fontName:this.fontName});return instance.position.set(position[0],position[1]),instance.scale.set(this.baseScale),instance.anchor.set(.5,.5),instance.zIndex=1e3,this.container.addChild(instance),instance};this.labels.forEach((label=>{label.instance=drawLabel(label.name,label.position)}))}hideLabels(){this.container.visible=!1,this.visible=!1}showLabels(){this.container.visible=!0,this.visible=!0}resize(scale){this.labels.forEach((lbl=>lbl.instance.scale.set(scale)))}}const GeoJSONVertexShaderFill="\n attribute vec2 inputVerts;\n\n uniform mat3 translationMatrix;\n uniform mat3 projectionMatrix;\n\n varying vec2 verts;\n\n void main() {\n verts = inputVerts;\n gl_Position = vec4((projectionMatrix * translationMatrix * vec3(inputVerts, 1.0)).xy, 0.0, 1.0);\n }\n ",GeoJSONFragmentShaderFill="\n precision mediump float;\n\n varying vec2 verts;\n\n uniform vec3 col1;\n uniform vec3 col2;\n uniform float opacity;\n\n uniform bool hashed;\n uniform float hashDisp;\n uniform float hashWidth;\n\n void main() {\n if(hashed && mod(verts.y + hashDisp, hashWidth * 2.0) > hashWidth) {\n gl_FragColor = vec4(col2 / 255., 1.0) * opacity;\n }\n else {\n gl_FragColor = vec4(col1 / 255., 1.0) * opacity;\n }\n }\n ",GeoJSONVertexShaderOutline="\n attribute vec2 inputVerts;\n attribute vec2 inputNormals;\n\n uniform mat3 translationMatrix;\n uniform mat3 projectionMatrix;\n\n uniform float outlineWidth;\n\n void main() {\n vec2 pos = inputVerts + inputNormals * outlineWidth;\n gl_Position = vec4((projectionMatrix * translationMatrix * vec3(pos, 1.0)).xy, 0.0, 1.0);\n }\n ",GeoJSONFragmentShaderOutline="\n precision mediump float;\n\n uniform vec3 color;\n\n void main() {\n gl_FragColor = vec4(color / 255., 1.0);\n }\n ";function getRadius(zoom,{min:min,max:max}){const zoomClamped=clamp(zoom,min.zoom,max.zoom)-min.zoom,t=Math.pow(2,-zoomClamped);return lerp(max.scale,min.scale,t)}class Defaults{static DEFAULT_Z_INDEX=1e3;static DEFAULT_LINE_WIDTH=.15;static INITIAL_ZOOM=20;static DEFAULT_FONT_FAMILY="Arial";static DEFAULT_FONT_SIZE=64;static DEFAULT_FONT_WEIGHT="600";static DEFAULT_LABEL_COLOR=4539717;static DEFAULT_LABEL_ALIGN="center";static INITIAL_HASH=1;static DEFAULT_MIN_HASH=0;static DEFAULT_BASE_SCALE=.1}class GeoJSONMultiPolygon{static vertexShaderFill;static fragmentShaderFill;static vertexShaderOutline;static fragmentShaderOutline;features=[];config={initialHash:Defaults.INITIAL_HASH,minHash:Defaults.DEFAULT_MIN_HASH,maxHash:1/0};container;pixiOverlay;dict=new TriangleDictionary(1.2);textStyle;labels;currentZoom=Defaults.INITIAL_ZOOM;constructor(root,labelRoot,pixiOverlay,config){config?.initialHash&&"number"==typeof config.initialHash&&(this.config.initialHash=config.initialHash),config?.minHash&&"number"==typeof config.minHash&&(this.config.minHash=config.minHash),config?.maxHash&&"number"==typeof config.maxHash&&(this.config.maxHash=config.maxHash),this.container=new PIXI.Container,this.container.sortableChildren=!0,root.addChild(this.container),this.pixiOverlay=pixiOverlay,this.features=[],this.config=config,this.config.initialHash=clamp(this.config.initialHash),this.textStyle=new PIXI.TextStyle({fontFamily:config?.labelFontFamily||Defaults.DEFAULT_FONT_FAMILY,fontSize:config?.labelFontSize||Defaults.DEFAULT_FONT_SIZE,fontWeight:config?.labelFontWeight||Defaults.DEFAULT_FONT_WEIGHT,fill:config?.labelColor||Defaults.DEFAULT_LABEL_COLOR,align:config?.labelAlign||Defaults.DEFAULT_LABEL_ALIGN}),this.labels=new GeoJSONLabels(labelRoot||this.container,this.textStyle,this.config.labelResize?.baseScale||Defaults.DEFAULT_BASE_SCALE)}add(feature,props){const geom=feature.geometry,properties=props(feature);properties.style.labelScale&&(this.labels.baseScale=properties.style.labelScale);const meshes=[],coordinateGroup=geom.coordinates;coordinateGroup?.length>0&&(coordinateGroup.forEach((coordinates=>{const projected=this.projectPolygons(coordinates[0]);projected.pop();const meshData=Mesh.Polygon(projected);this.dict.add(coordinates[0],meshData.triangles,feature.properties);const outlineData=Mesh.PolygonOutline(projected,Defaults.DEFAULT_LINE_WIDTH),[position,mass]=centerOfMass(projected,meshData.triangles);meshes.push(this.drawPolygons(this.container,meshData,outlineData,properties.style,Defaults.DEFAULT_Z_INDEX)),properties.label&&this.labels.addLabel(properties.label,{position:position,mass:mass})})),this.features.push(...meshes))}drawPolygons(container,meshData,outlineData,featureStyle,zIndex){const fillColor=featureStyle.fillColor?color(featureStyle.fillColor).rgb():void 0,fillColor2=featureStyle.fillColor2?color(featureStyle.fillColor2).rgb():void 0,fillUniform={col1:fillColor?[fillColor.r,fillColor.g,fillColor.b]:[0,0,0],col2:fillColor2?[fillColor2.r,fillColor2.g,fillColor2.b]:[0,0,0],opacity:featureStyle.fillOpacity,hashed:featureStyle.hashed,hashDisp:10*Math.random(),hashWidth:this.config.initialHash},lineColor=color(featureStyle.lineColor).rgb(),outlineUniform={color:[lineColor.r,lineColor.g,lineColor.b],outlineWidth:featureStyle.lineWidth},polygonMesh=Mesh.from(meshData.vertices,meshData.triangles,GeoJSONVertexShaderFill,GeoJSONFragmentShaderFill,fillUniform);polygonMesh.zIndex=zIndex,container.addChild(polygonMesh);const polygonOutlineMesh=Mesh.from(outlineData.vertices,outlineData.triangles,GeoJSONVertexShaderOutline,GeoJSONFragmentShaderOutline,outlineUniform,outlineData.normals);return polygonOutlineMesh.zIndex=zIndex+1,container.addChild(polygonOutlineMesh),{fill:{mesh:polygonMesh,uniform:fillUniform},outline:{mesh:polygonOutlineMesh,uniform:outlineUniform}}}drawLabels(){this.labels.draw()}projectPolygons(points){const project=this.pixiOverlay.utils.latLngToLayerPoint;return points.map((c=>{const coord=project([c[1],c[0]]);return new Vector2(coord.x,coord.y)}))}resize(zoom){if(!this.config.outlineResize)return;const outlineRadius=this.getOutlineRadius(zoom);if(this.config.labelResize){const labelSize=this.getLabelSize(zoom);zoom<=this.config.labelResize.threshold?this.labels.hideLabels():(this.labels.showLabels(),this.labels.resize(labelSize))}this.container.children.map((child=>{child.shader.uniformGroup.uniforms.outlineWidth&&(child.shader.uniformGroup.uniforms.outlineWidth=outlineRadius)})),this.currentZoom=zoom}testPosition(pos){return this.dict.getPolygonAt([pos.x,pos.y])}getOutlineRadius(zoom=this.currentZoom){return getRadius(zoom,this.config.outlineResize)}getLabelSize(zoom=this.currentZoom){return getRadius(zoom,this.config.labelResize)}}class GeoJSONPolygon{static vertexShaderFill;static fragmentShaderFill;static vertexShaderOutline;static fragmentShaderOutline;features=[];config={initialHash:Defaults.INITIAL_HASH,minHash:Defaults.DEFAULT_MIN_HASH,maxHash:1/0};container;pixiOverlay;dict=new TriangleDictionary(1.2);textStyle;labels;currentZoom=Defaults.INITIAL_ZOOM;outlineThickness=Defaults.DEFAULT_LINE_WIDTH;zIndex=Defaults.DEFAULT_Z_INDEX;constructor(root,labelRoot,pixiOverlay,config){config?.initialHash&&"number"==typeof config.initialHash&&(this.config.initialHash=config.initialHash),config?.minHash&&"number"==typeof config.minHash&&(this.config.minHash=config.minHash),config?.maxHash&&"number"==typeof config.maxHash&&(this.config.maxHash=config.maxHash),this.container=new PIXI.Container,this.container.sortableChildren=!0,root.addChild(this.container),this.pixiOverlay=pixiOverlay,this.features=[],this.config=config,this.config.initialHash=clamp(this.config.initialHash),this.textStyle=new PIXI.TextStyle({fontFamily:config?.labelFontFamily||Defaults.DEFAULT_FONT_FAMILY,fontSize:config?.labelFontSize||Defaults.DEFAULT_FONT_SIZE,fontWeight:config?.labelFontWeight||Defaults.DEFAULT_FONT_WEIGHT,fill:config?.labelColor||Defaults.DEFAULT_LABEL_COLOR,align:config?.labelAlign||Defaults.DEFAULT_LABEL_ALIGN}),this.labels=new GeoJSONLabels(labelRoot||this.container,this.textStyle,this.config.labelResize?.baseScale||Defaults.DEFAULT_BASE_SCALE)}add(feature,props){const geom=feature.geometry,properties=props(feature);properties.style.labelScale&&(this.labels.baseScale=properties.style.labelScale);const meshes=[],coordinates=geom.coordinates;if(coordinates?.length>0){const projected=this.projectPolygons(coordinates[0]);projected.pop();const meshData=Mesh.Polygon(projected);this.dict.add(coordinates[0],meshData.triangles,feature.properties);const outlineData=Mesh.PolygonOutline(projected,this.outlineThickness),[position,mass]=centerOfMass(projected,meshData.triangles);meshes.push(this.drawPolygons(this.container,meshData,outlineData,properties.style,this.zIndex)),properties.label&&this.labels.addLabel(properties.label,{position:position,mass:mass}),this.features.push(...meshes)}}drawPolygons(container,meshData,outlineData,featureStyle,zIndex){const fillColor=featureStyle.fillColor?color(featureStyle.fillColor).rgb():void 0,fillColor2=featureStyle.fillColor2?color(featureStyle.fillColor2).rgb():void 0,fillUniform={col1:fillColor?[fillColor.r,fillColor.g,fillColor.b]:[0,0,0],col2:fillColor2?[fillColor2.r,fillColor2.g,fillColor2.b]:[0,0,0],opacity:featureStyle.fillOpacity,hashed:featureStyle.hashed,hashDisp:10*Math.random(),hashWidth:this.config.initialHash},lineColor=color(featureStyle.lineColor).rgb(),outlineUniform={color:[lineColor.r,lineColor.g,lineColor.b],outlineWidth:featureStyle.lineWidth},polygonMesh=Mesh.from(meshData.vertices,meshData.triangles,GeoJSONVertexShaderFill,GeoJSONFragmentShaderFill,fillUniform);polygonMesh.zIndex=zIndex,container.addChild(polygonMesh);const polygonOutlineMesh=Mesh.from(outlineData.vertices,outlineData.triangles,GeoJSONVertexShaderOutline,GeoJSONFragmentShaderOutline,outlineUniform,outlineData.normals);return polygonOutlineMesh.zIndex=zIndex+1,container.addChild(polygonOutlineMesh),{fill:{mesh:polygonMesh,uniform:fillUniform},outline:{mesh:polygonOutlineMesh,uniform:outlineUniform}}}drawLabels(){this.labels.draw()}projectPolygons(points){const project=this.pixiOverlay.utils.latLngToLayerPoint;return points.map((c=>{const coord=project([c[1],c[0]]);return new Vector2(coord.x,coord.y)}))}resize(zoom){if(!this.config.outlineResize)return;const outlineRadius=this.getOutlineRadius(zoom);if(this.config.labelResize){const labelSize=this.getLabelSize(zoom);zoom<=this.config.labelResize.threshold?this.labels.hideLabels():(this.labels.showLabels(),this.labels.resize(labelSize))}this.container.children.map((child=>{child.shader.uniformGroup.uniforms.outlineWidth&&(child.shader.uniformGroup.uniforms.outlineWidth=outlineRadius)})),this.currentZoom=zoom}testPosition(pos){return this.dict.getPolygonAt([pos.x,pos.y])}getOutlineRadius(zoom=this.currentZoom){return getRadius(zoom,this.config.outlineResize)}getLabelSize(zoom=this.currentZoom){return getRadius(zoom,this.config.labelResize)}}class GeoJSONLineString{static vertexShaderOutline;static fragmentShaderOutline;features=[];config={};container;pixiOverlay;dict=new LineDictionary(1.2);textStyle;currentZoom=Defaults.INITIAL_ZOOM;constructor(root,pixiOverlay,config){this.container=new PIXI.Container,this.container.sortableChildren=!0,root.addChild(this.container),this.pixiOverlay=pixiOverlay,this.features=[],this.config=config}add(feature,props){const geom=feature.geometry,properties=props(feature),meshes=[],coordinates=geom.coordinates;if(coordinates?.length>0){const projected=this.projectPolygons(coordinates);projected.pop(),this.dict.add(projected,feature.properties);const outlineData=Mesh.SimpleLine(projected,Defaults.DEFAULT_LINE_WIDTH);meshes.push(this.drawPolygons(this.container,outlineData,properties.style,Defaults.DEFAULT_Z_INDEX)),this.features.push(...meshes)}}drawPolygons(container,outlineData,featureStyle,zIndex){const lineColor=color(featureStyle.lineColor).rgb(),outlineUniform={color:[lineColor.r,lineColor.g,lineColor.b],width:featureStyle.lineWidth},polygonOutlineMesh=Mesh.from(outlineData.vertices,outlineData.triangles,GeoJSONVertexShaderOutline,GeoJSONFragmentShaderOutline,outlineUniform,outlineData.normals);return polygonOutlineMesh.zIndex=zIndex,container.addChild(polygonOutlineMesh),{outline:{mesh:polygonOutlineMesh,uniform:outlineUniform}}}projectPolygons(points){const project=this.pixiOverlay.utils.latLngToLayerPoint;return points.map((c=>{const coord=project([c[1],c[0]]);return new Vector2(coord.x,coord.y)}))}resize(zoom){if(!this.config.outlineResize)return;const outlineRadius=this.getOutlineRadius(zoom);this.container.children.map((child=>{child.shader.uniformGroup.uniforms.outlineWidth&&(child.shader.uniformGroup.uniforms.outlineWidth=outlineRadius)})),this.currentZoom=zoom}testPosition(pos){return this.dict.getClosest(pos)}getOutlineRadius(zoom=this.currentZoom){return getRadius(zoom,this.config.outlineResize)}}class GeoJSONPoint{spawned=[];pool=[];container;pixiOverlay;dict=new PointDictionary(.25,20,4);textStyle;constructor(root,pixiOverlay){this.container=new PIXI.Container,this.container.sortableChildren=!0,root.addChild(this.container),this.pixiOverlay=pixiOverlay}add(feature,props){const geom=feature.geometry,properties=props(feature),coordinates=geom.coordinates;if(coordinates?.length>0){const projected=this.projectPoint(coordinates);let point;this.dict.add(projected,feature.properties),this.pool.length>0?point=this.pool.pop():(point=new PIXI.Graphics,this.container.addChild(point));const fillColor=properties.style.fillColor?new PIXI.Color(color(properties.style.fillColor).formatHex()).toNumber():0,lineColor=properties.style.lineColor?new PIXI.Color(color(properties.style.lineColor).formatHex()).toNumber():0,opacity=properties.style.fillOpacity||0,offset=4;point.lineStyle(properties.style.lineWidth,lineColor),point.beginFill(fillColor,opacity),point.drawRect(projected[0]-offset,projected[1]-offset,2*offset,2*offset),point.endFill(),this.spawned.push(point)}}projectPoint(point){const coord=(0,this.pixiOverlay.utils.latLngToLayerPoint)([point[1],point[0]]);return new Vector2(coord.x,coord.y)}resize(_zoom){}testPosition(pos){return this.dict.getClosestUnder(pos)}}class GeoJSONModule extends ModuleInterface{onFeatureHover;points;linestrings;polygons;multipolygons;_eventHandler;mapmoving;labelRoot;config;constructor(config){super(),this.mapmoving=!1,this._eventHandler=config?.customEventHandler||new DefaultEventHandler,this.onFeatureHover=config?.onFeatureHover,this.config=config}set(data,props){this.labelRoot=new PIXI.Container,data.features.forEach((feature=>{"Point"===feature.geometry.type?(void 0===this.points&&(this.points=new GeoJSONPoint(this.root,this.pixiOverlay)),this.points.add(feature,props)):"LineString"===feature.geometry.type?(void 0===this.linestrings&&(this.linestrings=new GeoJSONLineString(this.root,this.pixiOverlay,this.config)),this.linestrings.add(feature,props)):"Polygon"===feature.geometry.type?(void 0===this.polygons&&(this.polygons=new GeoJSONPolygon(this.root,this.labelRoot,this.pixiOverlay,this.config)),this.polygons.add(feature,props)):"MultiPolygon"===feature.geometry.type&&(void 0===this.multipolygons&&(this.multipolygons=new GeoJSONMultiPolygon(this.root,this.labelRoot,this.pixiOverlay,this.config)),this.multipolygons.add(feature,props))})),this.root.addChild(this.labelRoot),this.polygons&&this.polygons.drawLabels(),this.multipolygons&&this.multipolygons.drawLabels()}testPosition(pos){let result=[];return this.polygons&&result.push(this.polygons.testPosition(pos)),this.multipolygons&&result.push(this.multipolygons.testPosition(pos)),this.linestrings&&result.push(this.linestrings.testPosition(pos)),this.points&&result.push(this.points.testPosition(pos)),result=result.filter((v=>v)),result}onAdd(map){const element=this.pixiOverlay.utils.getRenderer().view.parentNode,callbacks={mousemove:this.handleMouseMove.bind(this),mouseout:this.handleMouseOut.bind(this),click:this.handleMouseClick.bind(this),mousedown:this.handleMouseDown.bind(this),mouseup:this.handleMouseUp.bind(this)};this._eventHandler.register(map,element,callbacks)}onRemove(_map){this._eventHandler.unregister()}resize(zoom){this.points&&this.points.resize(zoom),this.linestrings&&this.linestrings.resize(zoom),this.polygons&&this.polygons.resize(zoom),this.multipolygons&&this.multipolygons.resize(zoom)}handleMouseMove(event){if(this.mapmoving)return!1;const latLng=this.pixiOverlay.utils.getMap().mouseEventToLatLng(event),layerCoords=new Vector2([latLng.lng,latLng.lat]),hits=this.testPosition(layerCoords);return this.onFeatureHover&&this.onFeatureHover(event,hits),!0}handleMouseOut(event){return this.onFeatureHover&&this.onFeatureHover(event,[]),!0}handleMouseClick(){return!0}handleMouseDown(){return this.mapmoving=!0,!0}handleMouseUp(){return this.mapmoving=!1,!0}}class ExplorationLayer extends ModuleInterface{pointDict=new PointDictionary(.25,-2,-1);prevScale;selection;appendExploration(scale=1){const project=this.pixiOverlay.utils.latLngToLayerPoint,targetScale=this.clampScale(scale);this.prevScale=targetScale;for(let i=0;i<null.length;i++){const projected=project([null[i].latitude,null[i].longitude]),pos=new Vector2(projected.x,projected.y),well=generateCircle(pos,.3,void 0);this.root.addChild(well),this.pointDict.add(pos,{mesh:well,uniforms:void 0})}}clampScale(scale){scale<1&&(scale=1);let targetScale=.05*scale;return targetScale>1&&(targetScale=1),targetScale}highlight(lat,long){const project=this.pixiOverlay.utils.latLngToLayerPoint;if(this.selection){const point=this.selection.point;point.uniforms.circleColor1=[.3,.3,.3],point.mesh.zIndex=this.selection.zIndex,this.selection=null}const{x:x,y:y}=project([lat,long]),worldSpace=new Vector2(x,y),circleUnder=this.pointDict.getClosestUnder(worldSpace);if(circleUnder){const point=circleUnder.val;return this.selection={point:point,zIndex:point.mesh.zIndex},point.uniforms.circleColor1=[.2,.6,.7],point.mesh.zIndex=1/0,!0}return!1}}export{DefaultEventHandler,ExplorationLayer,FaultlineModule,FieldModule,GeoJSONModule,ModuleInterface,OutlineModule,WellboreModule};