@equinor/videx-map 2.1.3 → 2.1.4
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/GeoJSONModule/shader.d.ts +1 -1
- package/dist/index.esm.js +1 -1
- package/dist/index.js +1 -1
- package/dist/index.umd.js +1 -1
- package/package.json +2 -2
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Shared shaders for polygon and multipolygon
|
|
3
3
|
*/
|
|
4
4
|
export declare const GeoJSONVertexShaderFill = "\n in vec2 inputVerts;\n\n uniform mat3 uWorldTransformMatrix;\n uniform mat3 uProjectionMatrix;\n\n out vec2 verts;\n\n void main() {\n verts = inputVerts;\n gl_Position = vec4((uProjectionMatrix * uWorldTransformMatrix * vec3(inputVerts, 1.0)).xy, 0.0, 1.0);\n }\n ";
|
|
5
|
-
export declare const GeoJSONFragmentShaderFill = "\n precision mediump float;\n\n in vec2 verts;\n\n uniform vec3 col1;\n uniform vec3 col2;\n uniform float opacity;\n uniform float hashDisp;\n uniform float hashWidth;\n\n void main() {\n if(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 ";
|
|
5
|
+
export declare const GeoJSONFragmentShaderFill = "\n precision mediump float;\n\n in vec2 verts;\n\n uniform vec3 col1;\n uniform vec3 col2;\n uniform float opacity;\n uniform int hashed;\n uniform float hashDisp;\n uniform float hashWidth;\n\n void main() {\n if(hashed == 1 && 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 ";
|
|
6
6
|
/**
|
|
7
7
|
* Shared shaders for polygon, multipolygon and linestring
|
|
8
8
|
*/
|
package/dist/index.esm.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{Container,Graphics,Point,Geometry,Shader,Mesh,GlProgram,TextStyle,CanvasTextMetrics,Text,Rectangle,Color,BitmapFontManager,BitmapText}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 Container,this.root.sortableChildren=!0}destroy(){this.root.destroy({children:!0,texture:!0,textureSource:!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,textureSource:!0})),this.pool=null,this.spawned=null}set(data,redraw=!1){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 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 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.poly(projected),faultline.fill(this.config.color),faultline.stroke({width:this.config.outlineWidth,color:this.config.color});else{lineCount++,faultline.moveTo(first.x,first.y);for(let i=1;i<projected.length;i++)faultline.lineTo(projected[i].x,projected[i].y),faultline.stroke({width:this.config.outlineWidth,color:this.config.color})}}),lineCount>0&&log(`Drawing ${lineCount} faultline polygons as lines.`),redraw&&this.pixiOverlay.redraw()}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 LineMesh{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 Geometry;geometry.addAttribute("inputVerts",vertices),normals&&geometry.addAttribute("inputNormals",normals),geometry.addIndex(triangles);const shader=Shader.from({gl:{vertex:vertexShader,fragment:fragmentShader},resources:{uniforms:uniforms}});return new Mesh({geometry:geometry,shader: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=>{this.outlineDict[outlineCollection.meta.name]={color:{value:outlineCollection.meta.stroke,type:"vec3<f32>"},visible:{value:1,type:"i32"},width:{value:this.state.extraWidth,type:"f32"}};const outlineGroup=new Container({label:outlineCollection.meta.name}),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=LineMesh.PolygonOutline(projected,this.config.baseWidth)}else{if(projected.length<=1){log(`Skipping outline (Line) with ${projected.length} points.`);continue}outlineData=LineMesh.SimpleLine(projected,this.config.baseWidth)}const outline=LineMesh.from(outlineData.vertices,outlineData.triangles,OutlineModule.vertexShader,OutlineModule.fragmentShader,this.outlineDict[outlineCollection.meta.name],outlineData.normals);outlineGroup.addChild(outline)}this.root.addChild(outlineGroup),this.spawned.push(outlineGroup)})}setVisibleLayers(names){this.root.children.forEach(container=>container.children.forEach(mesh=>mesh.shader.resources.uniforms.uniforms.visible=0)),names.forEach(name=>{const outlineGroup=this.root.children.find(container=>container.label===name);outlineGroup?.children?.forEach(mesh=>mesh.shader.resources.uniforms.uniforms.visible=1)})}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,this.root.children.forEach(container=>container.children.forEach(mesh=>mesh.shader.resources.uniforms.uniforms.width=width))}}function toShader(n){return n===Math.floor(n)?`${n.toString()}.0`:n.toString()}OutlineModule.vertexShader="\n in vec2 inputVerts;\n in vec2 inputNormals;\n\n uniform mat3 uWorldTransformMatrix;\n uniform mat3 uProjectionMatrix;\n\n uniform float width;\n\n void main() {\n vec2 pos = inputVerts + inputNormals * width;\n gl_Position = vec4((uProjectionMatrix * uWorldTransformMatrix * vec3(pos, 1.0)).xy, 0.0, 1.0);\n }\n",OutlineModule.fragmentShader="\n precision mediump float;\n\n uniform vec3 color;\n uniform int visible;\n\n void main() {\n if (visible == 0) discard;\n gl_FragColor = vec4(color, 1.0);\n }\n";class WellboreShader{static program=null;static get(color,completionVisible,wellboreVisible){return new Shader({glProgram:WellboreShader.program,resources:{uniforms:{wellboreColor1:{value:color.col1,type:"vec3<f32>"},wellboreColor2:{value:color.col2,type:"vec3<f32>"},completionVisible:{value:completionVisible?1:0,type:"i32"},wellboreVisible:{value:wellboreVisible?1:0,type:"i32"},status:{value:0,type:"i32"},wellboreRadius:{value:1,type:"f32"}}}})}static build(maxScale,wellboreDash){const vertex=`\n in vec2 verts;\n in vec4 vertCol;\n in float typeData;\n\n uniform mat3 uWorldTransformMatrix;\n uniform mat3 uProjectionMatrix;\n uniform float wellboreRadius;\n\n out vec4 vCol;\n out 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((uProjectionMatrix * uWorldTransformMatrix * 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 in vec4 vCol;\n in float type;\n\n uniform vec3 wellboreColor1;\n uniform vec3 wellboreColor2;\n uniform int completionVisible;\n uniform int 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 == 0) {\n alpha = 0.03;\n }\n } else if (type == 1.0) {\n if(completionVisible == 1){\n if(mod(vCol.x, ${doubleDash}) > ${dash}) discard;\n } else if(wellboreVisible == 0){\n alpha = 0.03;\n }\n }\n if (completionVisible == 0 && 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 GlProgram({vertex:vertex,fragment:fragment})}}class RootShader{static program=null;static get(){return new Shader({glProgram:RootShader.program,resources:{uniforms:{circleColor1:{value:new Float32Array([0,0,0]),type:"vec3<f32>"},circleColor2:{value:new Float32Array([0,0,0]),type:"vec3<f32>"},active:{value:1,type:"i32"},rootRadius:{value:1,type:"f32"}}}})}static build(maxScale){const vertex=`\n in vec2 verts;\n in vec2 inputUVs;\n\n uniform mat3 uWorldTransformMatrix;\n uniform mat3 uProjectionMatrix;\n uniform float rootRadius;\n\n out 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((uProjectionMatrix * uWorldTransformMatrix * vec3(verts + dir * extraRadius, 1.0)).xy, 0.0, 1.0);\n }\n `;RootShader.program=new GlProgram({vertex:vertex,fragment:"\n precision mediump float;\n\n in vec2 UVs;\n\n uniform vec3 circleColor1;\n uniform vec3 circleColor2;\n uniform int active;\n\n const vec3 sunDir = vec3(0.6247, -0.6247, 0.4685);\n\n void main() {\n if (active == 0) {\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 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]),geometry.addAttribute("inputUVs",[0,0,1,0,0,1,1,1]),geometry.addIndex([0,2,3,0,3,1]);return new Mesh({geometry:geometry,shader: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 TextStyle({fontFamily:"Arial",fontSize:fontSize,fill:16777215,align:"center"}),Label.height=CanvasTextMetrics.measureText(" ",Label.style).height}static setCommon(config){Label.config=config}constructor(label,fontColor,bgColor){const metrics=CanvasTextMetrics.measureText(label,Label.style);this.metrics=metrics;const container=new Container;container.visible=Label.state.visible,container.zIndex=0,this.container=container;const background=new Graphics;background.rect(.55*-metrics.width,.525*-Label.height,1.1*metrics.width,1.05*Label.height),background.fill({color:16777215}),background.alpha=Label.config.backgroundOpacity,background.tint=bgColor,this.background=background;const text=new Text({text:label,style: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 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.resources.uniforms.uniforms;if(uniform.active=this.active?1:0,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=LineMesh.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 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 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.resources.uniforms.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 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.resources.uniforms.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 Geometry;geometry.addAttribute("verts",vertices),geometry.addAttribute("vertCol",vertexData),geometry.addAttribute("typeData",extraData),geometry.addIndex(triangles);const shader=WellboreShader.get(this.colors.default,this.group.state.completionVisible,this.group.state.wellboreVisible);return new Mesh({geometry:geometry,shader:shader})}setCompletionVisibility(visible){this.mesh&&(this.uniforms.completionVisible=visible?1:0)}setWellboreVisibility(visible){this.mesh&&(this.uniforms.wellboreVisible=visible?1:0)}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.resources.uniforms.uniforms.wellboreColor1=color.col1,this.mesh.shader.resources.uniforms.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.resources.uniforms.uniforms.wellboreColor1=this.colors.default.col1,this.mesh.shader.resources.uniforms.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.resources.uniforms.uniforms.wellboreColor1=this.colors.selected.col1,this.mesh.shader.resources.uniforms.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.resources.uniforms.uniforms.wellboreColor1=this.colors.default.col1,this.mesh.shader.resources.uniforms.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.resources.uniforms.uniforms.status=this.filter,this.mesh.shader.resources.uniforms.uniforms.wellboreRadius=WellboreData.state.wellboreRadius,this.mesh.shader.resources.uniforms.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 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 Graphics).fill({color:this.color,alpha:1}).setStrokeStyle(0).moveTo(from1.x,from1.y).lineTo(to1.x,to1.y).lineTo(to2.x,to2.y).lineTo(from2.x,from2.y)}}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?1:0)})}setWellboreVisibility(visible){this.state.wellboreVisible=visible,this.wellbores.forEach(wellbore=>{wellbore.setWellboreVisibility(visible?1:0)})}}class WellboreEventData{group;data;mouseEvent;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 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(mouseEvent){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,mouseEvent:mouseEvent}),!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().canvas.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(){const pixiOverlayUtils=this.pixiOverlay.utils;return pixiOverlayUtils||console.log("pixiOverlayUtils undefined",pixiOverlayUtils),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.value,fillCol2:field.fill.uniform.col2.value,outlineCol:field.outline.uniform.color.value,baseZIndex:field.fill.mesh.zIndex,field:field},field.fill.uniform.col1.value=this.fillColor1,field.fill.uniform.col2.value=this.fillColor2,field.fill.mesh.zIndex+=1e4,field.outline.uniform.color.value=this.outlineColor,field.outline.mesh.zIndex+=1e4}}revert(){return!!this.cached&&(this.cached.forEach(d=>{d.field.fill.uniform.col1.value=d.fillCol1,d.field.fill.uniform.col2.value=d.fillCol2,d.field.fill.mesh.zIndex=d.baseZIndex,d.field.outline.uniform.color.value=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=CanvasTextMetrics.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 Text({text:name,style: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 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=LineMesh.Polygon(projected);this.dict.add(polygon.coordinates,meshData.triangles,fieldID);const outlineData=LineMesh.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:{value:fieldStyle.fillColor1,type:"vec3<f32>"},col2:{value:fieldStyle.fillColor2,type:"vec3<f32>"},opacity:{value:fieldStyle.fillOpacity,type:"f32"},hashed:{value:fieldStyle.hashed,type:"i32"},hashDisp:{value:10*Math.random(),type:"f32"},hashWidth:{value:this.config.initialHash,type:"f32"}},outlineUniform={color:{value:fieldStyle.outlineColor,type:"vec3<f32>"},outlineWidth:{value:0,type:"f32"}},polygonMesh=LineMesh.from(meshData.vertices,meshData.triangles,FieldModule.vertexShaderFill,FieldModule.fragmentShaderFill,fillUniform);polygonMesh.zIndex=zIndex,this.root.addChild(polygonMesh);const polygonOutlineMesh=LineMesh.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:0};const fill={fillColor1:green,fillColor2:green,outlineColor:green,fillOpacity:.6,hashed:0};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=1;break;case"OIL/GAS":fill.fillColor1=red,fill.hashed=1}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 in vec2 inputVerts;\n\n uniform mat3 uWorldTransformMatrix;\n uniform mat3 uProjectionMatrix;\n\n out vec2 verts;\n\n void main() {\n verts = inputVerts;\n gl_Position = vec4((uProjectionMatrix * uWorldTransformMatrix * vec3(inputVerts, 1.0)).xy, 0.0, 1.0);\n }\n",FieldModule.fragmentShaderFill="\n precision mediump float;\n\n in vec2 verts;\n\n uniform vec3 col1;\n uniform vec3 col2;\n uniform float opacity;\n\n uniform int hashed;\n uniform float hashDisp;\n uniform float hashWidth;\n\n void main() {\n if(hashed == 1 && 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 in vec2 inputVerts;\n in vec2 inputNormals;\n\n uniform mat3 uWorldTransformMatrix ;\n uniform mat3 uProjectionMatrix;\n\n uniform float width;\n\n void main() {\n vec2 pos = inputVerts + inputNormals * width;\n gl_Position = vec4((uProjectionMatrix * uWorldTransformMatrix * 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 Container,this.container.sortableChildren=!0,root.addChild(this.container),this.textStyle=textStyle,this.baseScale=baseScale,this.fontName=fontName||v4(),this.font=BitmapFontManager.install({name:this.fontName,style:this.textStyle,resolution:window.devicePixelRatio,chars:BitmapFontManager.ASCII})}addLabel(name,data){this.labels.push({name:name,position:data.position,instance:null})}draw(){const drawLabel=(name,position)=>{const instance=new BitmapText({text:name,style:{fontFamily: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 in vec2 inputVerts;\n\n uniform mat3 uWorldTransformMatrix;\n uniform mat3 uProjectionMatrix;\n\n out vec2 verts;\n\n void main() {\n verts = inputVerts;\n gl_Position = vec4((uProjectionMatrix * uWorldTransformMatrix * vec3(inputVerts, 1.0)).xy, 0.0, 1.0);\n }\n ",GeoJSONFragmentShaderFill="\n precision mediump float;\n\n in vec2 verts;\n\n uniform vec3 col1;\n uniform vec3 col2;\n uniform float opacity;\n uniform float hashDisp;\n uniform float hashWidth;\n\n void main() {\n if(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 in vec2 inputVerts;\n in vec2 inputNormals;\n\n uniform mat3 uWorldTransformMatrix;\n uniform mat3 uProjectionMatrix;\n\n uniform float outlineWidth;\n\n void main() {\n vec2 pos = inputVerts + inputNormals * outlineWidth;\n gl_Position = vec4((uProjectionMatrix * uWorldTransformMatrix * 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 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 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=LineMesh.Polygon(projected);this.dict.add(coordinates[0],meshData.triangles,feature.properties);const outlineData=LineMesh.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:{value:fillColor?[fillColor.r,fillColor.g,fillColor.b]:[0,0,0],type:"vec3<f32>"},col2:{value:fillColor2?[fillColor2.r,fillColor2.g,fillColor2.b]:[0,0,0],type:"vec3<f32>"},opacity:{value:featureStyle.fillOpacity,type:"f32"},hashed:{value:featureStyle.hashed,type:"f32"},hashDisp:{value:10*Math.random(),type:"f32"},hashWidth:{value:this.config.initialHash,type:"f32"}},lineColor=color(featureStyle.lineColor).rgb(),outlineUniform={color:{value:[lineColor.r,lineColor.g,lineColor.b],type:"vec3<f32>"},outlineWidth:{value:featureStyle.lineWidth,type:"f32"}},polygonMesh=LineMesh.from(meshData.vertices,meshData.triangles,GeoJSONVertexShaderFill,GeoJSONFragmentShaderFill,fillUniform);container.zIndex=zIndex,container.addChild(polygonMesh);const polygonOutlineMesh=LineMesh.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.resources.uniforms.uniforms.outlineWidth&&(child.shader.resources.uniforms.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 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 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=LineMesh.Polygon(projected);this.dict.add(coordinates[0],meshData.triangles,feature.properties);const outlineData=LineMesh.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:{value:fillColor?[fillColor.r,fillColor.g,fillColor.b]:[0,0,0],type:"vec3<f32>"},col2:{value:fillColor2?[fillColor2.r,fillColor2.g,fillColor2.b]:[0,0,0],type:"vec3<f32>"},opacity:{value:featureStyle.fillOpacity,type:"f32"},hashed:{value:featureStyle.hashed?1:0,type:"f32"},hashDisp:{value:10*Math.random(),type:"f32"},hashWidth:{value:this.config.initialHash,type:"f32"}},lineColor=color(featureStyle.lineColor).rgb(),outlineUniform={color:{value:[lineColor.r,lineColor.g,lineColor.b],type:"vec3<f32>"},outlineWidth:{value:featureStyle.lineWidth,type:"f32"}},polygonMesh=LineMesh.from(meshData.vertices,meshData.triangles,GeoJSONVertexShaderFill,GeoJSONFragmentShaderFill,fillUniform);polygonMesh.zIndex=zIndex,container.addChild(polygonMesh);const polygonOutlineMesh=LineMesh.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.resources.uniforms.uniforms.outlineWidth&&(child.shader.resources.uniforms.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 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=LineMesh.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:{value:[lineColor.r,lineColor.g,lineColor.b],type:"vec3<f32>"},width:{value:featureStyle.lineWidth,type:"f32"}},polygonOutlineMesh=LineMesh.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.resources.uniforms.uniforms.outlineWidth&&(child.shader.resources.uniforms.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 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 Graphics,this.container.addChild(point));const fillColor=properties.style.fillColor?new Color(color(properties.style.fillColor).formatHex()).toNumber():0,lineColor=properties.style.lineColor?new Color(color(properties.style.lineColor).formatHex()).toNumber():0,alpha=properties.style.fillOpacity||0,offset=4;point.rect(projected[0]-offset,projected[1]-offset,2*offset,2*offset),point.fill({color:fillColor,alpha:alpha}),point.setStrokeStyle(properties.style.lineWidth,lineColor),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 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().canvas.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{Container,Graphics,Point,Geometry,Shader,Mesh,GlProgram,TextStyle,CanvasTextMetrics,Text,Rectangle,Color,BitmapFontManager,BitmapText}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 Container,this.root.sortableChildren=!0}destroy(){this.root.destroy({children:!0,texture:!0,textureSource:!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,textureSource:!0})),this.pool=null,this.spawned=null}set(data,redraw=!1){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 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 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.poly(projected),faultline.fill(this.config.color),faultline.stroke({width:this.config.outlineWidth,color:this.config.color});else{lineCount++,faultline.moveTo(first.x,first.y);for(let i=1;i<projected.length;i++)faultline.lineTo(projected[i].x,projected[i].y),faultline.stroke({width:this.config.outlineWidth,color:this.config.color})}}),lineCount>0&&log(`Drawing ${lineCount} faultline polygons as lines.`),redraw&&this.pixiOverlay.redraw()}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 LineMesh{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 Geometry;geometry.addAttribute("inputVerts",vertices),normals&&geometry.addAttribute("inputNormals",normals),geometry.addIndex(triangles);const shader=Shader.from({gl:{vertex:vertexShader,fragment:fragmentShader},resources:{uniforms:uniforms}});return new Mesh({geometry:geometry,shader: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=>{this.outlineDict[outlineCollection.meta.name]={color:{value:outlineCollection.meta.stroke,type:"vec3<f32>"},visible:{value:1,type:"i32"},width:{value:this.state.extraWidth,type:"f32"}};const outlineGroup=new Container({label:outlineCollection.meta.name}),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=LineMesh.PolygonOutline(projected,this.config.baseWidth)}else{if(projected.length<=1){log(`Skipping outline (Line) with ${projected.length} points.`);continue}outlineData=LineMesh.SimpleLine(projected,this.config.baseWidth)}const outline=LineMesh.from(outlineData.vertices,outlineData.triangles,OutlineModule.vertexShader,OutlineModule.fragmentShader,this.outlineDict[outlineCollection.meta.name],outlineData.normals);outlineGroup.addChild(outline)}this.root.addChild(outlineGroup),this.spawned.push(outlineGroup)})}setVisibleLayers(names){this.root.children.forEach(container=>container.children.forEach(mesh=>mesh.shader.resources.uniforms.uniforms.visible=0)),names.forEach(name=>{const outlineGroup=this.root.children.find(container=>container.label===name);outlineGroup?.children?.forEach(mesh=>mesh.shader.resources.uniforms.uniforms.visible=1)})}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,this.root.children.forEach(container=>container.children.forEach(mesh=>mesh.shader.resources.uniforms.uniforms.width=width))}}function toShader(n){return n===Math.floor(n)?`${n.toString()}.0`:n.toString()}OutlineModule.vertexShader="\n in vec2 inputVerts;\n in vec2 inputNormals;\n\n uniform mat3 uWorldTransformMatrix;\n uniform mat3 uProjectionMatrix;\n\n uniform float width;\n\n void main() {\n vec2 pos = inputVerts + inputNormals * width;\n gl_Position = vec4((uProjectionMatrix * uWorldTransformMatrix * vec3(pos, 1.0)).xy, 0.0, 1.0);\n }\n",OutlineModule.fragmentShader="\n precision mediump float;\n\n uniform vec3 color;\n uniform int visible;\n\n void main() {\n if (visible == 0) discard;\n gl_FragColor = vec4(color, 1.0);\n }\n";class WellboreShader{static program=null;static get(color,completionVisible,wellboreVisible){return new Shader({glProgram:WellboreShader.program,resources:{uniforms:{wellboreColor1:{value:color.col1,type:"vec3<f32>"},wellboreColor2:{value:color.col2,type:"vec3<f32>"},completionVisible:{value:completionVisible?1:0,type:"i32"},wellboreVisible:{value:wellboreVisible?1:0,type:"i32"},status:{value:0,type:"i32"},wellboreRadius:{value:1,type:"f32"}}}})}static build(maxScale,wellboreDash){const vertex=`\n in vec2 verts;\n in vec4 vertCol;\n in float typeData;\n\n uniform mat3 uWorldTransformMatrix;\n uniform mat3 uProjectionMatrix;\n uniform float wellboreRadius;\n\n out vec4 vCol;\n out 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((uProjectionMatrix * uWorldTransformMatrix * 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 in vec4 vCol;\n in float type;\n\n uniform vec3 wellboreColor1;\n uniform vec3 wellboreColor2;\n uniform int completionVisible;\n uniform int 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 == 0) {\n alpha = 0.03;\n }\n } else if (type == 1.0) {\n if(completionVisible == 1){\n if(mod(vCol.x, ${doubleDash}) > ${dash}) discard;\n } else if(wellboreVisible == 0){\n alpha = 0.03;\n }\n }\n if (completionVisible == 0 && 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 GlProgram({vertex:vertex,fragment:fragment})}}class RootShader{static program=null;static get(){return new Shader({glProgram:RootShader.program,resources:{uniforms:{circleColor1:{value:new Float32Array([0,0,0]),type:"vec3<f32>"},circleColor2:{value:new Float32Array([0,0,0]),type:"vec3<f32>"},active:{value:1,type:"i32"},rootRadius:{value:1,type:"f32"}}}})}static build(maxScale){const vertex=`\n in vec2 verts;\n in vec2 inputUVs;\n\n uniform mat3 uWorldTransformMatrix;\n uniform mat3 uProjectionMatrix;\n uniform float rootRadius;\n\n out 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((uProjectionMatrix * uWorldTransformMatrix * vec3(verts + dir * extraRadius, 1.0)).xy, 0.0, 1.0);\n }\n `;RootShader.program=new GlProgram({vertex:vertex,fragment:"\n precision mediump float;\n\n in vec2 UVs;\n\n uniform vec3 circleColor1;\n uniform vec3 circleColor2;\n uniform int active;\n\n const vec3 sunDir = vec3(0.6247, -0.6247, 0.4685);\n\n void main() {\n if (active == 0) {\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 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]),geometry.addAttribute("inputUVs",[0,0,1,0,0,1,1,1]),geometry.addIndex([0,2,3,0,3,1]);return new Mesh({geometry:geometry,shader: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 TextStyle({fontFamily:"Arial",fontSize:fontSize,fill:16777215,align:"center"}),Label.height=CanvasTextMetrics.measureText(" ",Label.style).height}static setCommon(config){Label.config=config}constructor(label,fontColor,bgColor){const metrics=CanvasTextMetrics.measureText(label,Label.style);this.metrics=metrics;const container=new Container;container.visible=Label.state.visible,container.zIndex=0,this.container=container;const background=new Graphics;background.rect(.55*-metrics.width,.525*-Label.height,1.1*metrics.width,1.05*Label.height),background.fill({color:16777215}),background.alpha=Label.config.backgroundOpacity,background.tint=bgColor,this.background=background;const text=new Text({text:label,style: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 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.resources.uniforms.uniforms;if(uniform.active=this.active?1:0,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=LineMesh.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 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 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.resources.uniforms.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 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.resources.uniforms.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 Geometry;geometry.addAttribute("verts",vertices),geometry.addAttribute("vertCol",vertexData),geometry.addAttribute("typeData",extraData),geometry.addIndex(triangles);const shader=WellboreShader.get(this.colors.default,this.group.state.completionVisible,this.group.state.wellboreVisible);return new Mesh({geometry:geometry,shader:shader})}setCompletionVisibility(visible){this.mesh&&(this.uniforms.completionVisible=visible?1:0)}setWellboreVisibility(visible){this.mesh&&(this.uniforms.wellboreVisible=visible?1:0)}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.resources.uniforms.uniforms.wellboreColor1=color.col1,this.mesh.shader.resources.uniforms.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.resources.uniforms.uniforms.wellboreColor1=this.colors.default.col1,this.mesh.shader.resources.uniforms.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.resources.uniforms.uniforms.wellboreColor1=this.colors.selected.col1,this.mesh.shader.resources.uniforms.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.resources.uniforms.uniforms.wellboreColor1=this.colors.default.col1,this.mesh.shader.resources.uniforms.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.resources.uniforms.uniforms.status=this.filter,this.mesh.shader.resources.uniforms.uniforms.wellboreRadius=WellboreData.state.wellboreRadius,this.mesh.shader.resources.uniforms.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 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 Graphics).fill({color:this.color,alpha:1}).setStrokeStyle(0).moveTo(from1.x,from1.y).lineTo(to1.x,to1.y).lineTo(to2.x,to2.y).lineTo(from2.x,from2.y)}}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?1:0)})}setWellboreVisibility(visible){this.state.wellboreVisible=visible,this.wellbores.forEach(wellbore=>{wellbore.setWellboreVisibility(visible?1:0)})}}class WellboreEventData{group;data;mouseEvent;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 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(mouseEvent){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,mouseEvent:mouseEvent}),!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().canvas.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(){const pixiOverlayUtils=this.pixiOverlay.utils;return pixiOverlayUtils||console.log("pixiOverlayUtils undefined",pixiOverlayUtils),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.value,fillCol2:field.fill.uniform.col2.value,outlineCol:field.outline.uniform.color.value,baseZIndex:field.fill.mesh.zIndex,field:field},field.fill.uniform.col1.value=this.fillColor1,field.fill.uniform.col2.value=this.fillColor2,field.fill.mesh.zIndex+=1e4,field.outline.uniform.color.value=this.outlineColor,field.outline.mesh.zIndex+=1e4}}revert(){return!!this.cached&&(this.cached.forEach(d=>{d.field.fill.uniform.col1.value=d.fillCol1,d.field.fill.uniform.col2.value=d.fillCol2,d.field.fill.mesh.zIndex=d.baseZIndex,d.field.outline.uniform.color.value=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=CanvasTextMetrics.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 Text({text:name,style: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 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=LineMesh.Polygon(projected);this.dict.add(polygon.coordinates,meshData.triangles,fieldID);const outlineData=LineMesh.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:{value:fieldStyle.fillColor1,type:"vec3<f32>"},col2:{value:fieldStyle.fillColor2,type:"vec3<f32>"},opacity:{value:fieldStyle.fillOpacity,type:"f32"},hashed:{value:fieldStyle.hashed,type:"i32"},hashDisp:{value:10*Math.random(),type:"f32"},hashWidth:{value:this.config.initialHash,type:"f32"}},outlineUniform={color:{value:fieldStyle.outlineColor,type:"vec3<f32>"},outlineWidth:{value:0,type:"f32"}},polygonMesh=LineMesh.from(meshData.vertices,meshData.triangles,FieldModule.vertexShaderFill,FieldModule.fragmentShaderFill,fillUniform);polygonMesh.zIndex=zIndex,this.root.addChild(polygonMesh);const polygonOutlineMesh=LineMesh.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:0};const fill={fillColor1:green,fillColor2:green,outlineColor:green,fillOpacity:.6,hashed:0};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=1;break;case"OIL/GAS":fill.fillColor1=red,fill.hashed=1}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 in vec2 inputVerts;\n\n uniform mat3 uWorldTransformMatrix;\n uniform mat3 uProjectionMatrix;\n\n out vec2 verts;\n\n void main() {\n verts = inputVerts;\n gl_Position = vec4((uProjectionMatrix * uWorldTransformMatrix * vec3(inputVerts, 1.0)).xy, 0.0, 1.0);\n }\n",FieldModule.fragmentShaderFill="\n precision mediump float;\n\n in vec2 verts;\n\n uniform vec3 col1;\n uniform vec3 col2;\n uniform float opacity;\n\n uniform int hashed;\n uniform float hashDisp;\n uniform float hashWidth;\n\n void main() {\n if(hashed == 1 && 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 in vec2 inputVerts;\n in vec2 inputNormals;\n\n uniform mat3 uWorldTransformMatrix ;\n uniform mat3 uProjectionMatrix;\n\n uniform float width;\n\n void main() {\n vec2 pos = inputVerts + inputNormals * width;\n gl_Position = vec4((uProjectionMatrix * uWorldTransformMatrix * 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 Container,this.container.sortableChildren=!0,root.addChild(this.container),this.textStyle=textStyle,this.baseScale=baseScale,this.fontName=fontName||v4(),this.font=BitmapFontManager.install({name:this.fontName,style:this.textStyle,resolution:window.devicePixelRatio,chars:BitmapFontManager.ASCII})}addLabel(name,data){this.labels.push({name:name,position:data.position,instance:null})}draw(){const drawLabel=(name,position)=>{const instance=new BitmapText({text:name,style:{fontFamily:this.fontName,fontSize:this.textStyle.fontSize}});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 in vec2 inputVerts;\n\n uniform mat3 uWorldTransformMatrix;\n uniform mat3 uProjectionMatrix;\n\n out vec2 verts;\n\n void main() {\n verts = inputVerts;\n gl_Position = vec4((uProjectionMatrix * uWorldTransformMatrix * vec3(inputVerts, 1.0)).xy, 0.0, 1.0);\n }\n ",GeoJSONFragmentShaderFill="\n precision mediump float;\n\n in vec2 verts;\n\n uniform vec3 col1;\n uniform vec3 col2;\n uniform float opacity;\n uniform int hashed;\n uniform float hashDisp;\n uniform float hashWidth;\n\n void main() {\n if(hashed == 1 && 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 in vec2 inputVerts;\n in vec2 inputNormals;\n\n uniform mat3 uWorldTransformMatrix;\n uniform mat3 uProjectionMatrix;\n\n uniform float outlineWidth;\n\n void main() {\n vec2 pos = inputVerts + inputNormals * outlineWidth;\n gl_Position = vec4((uProjectionMatrix * uWorldTransformMatrix * 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 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 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=LineMesh.Polygon(projected);this.dict.add(coordinates[0],meshData.triangles,feature.properties);const outlineData=LineMesh.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:{value:fillColor?[fillColor.r,fillColor.g,fillColor.b]:[0,0,0],type:"vec3<f32>"},col2:{value:fillColor2?[fillColor2.r,fillColor2.g,fillColor2.b]:[0,0,0],type:"vec3<f32>"},opacity:{value:featureStyle.fillOpacity,type:"f32"},hashed:{value:featureStyle.hashed,type:"f32"},hashDisp:{value:10*Math.random(),type:"f32"},hashWidth:{value:this.config.initialHash,type:"f32"}},lineColor=color(featureStyle.lineColor).rgb(),outlineUniform={color:{value:[lineColor.r,lineColor.g,lineColor.b],type:"vec3<f32>"},outlineWidth:{value:featureStyle.lineWidth,type:"f32"}},polygonMesh=LineMesh.from(meshData.vertices,meshData.triangles,GeoJSONVertexShaderFill,GeoJSONFragmentShaderFill,fillUniform);container.zIndex=zIndex,container.addChild(polygonMesh);const polygonOutlineMesh=LineMesh.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.resources.uniforms.uniforms.outlineWidth&&(child.shader.resources.uniforms.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 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 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=LineMesh.Polygon(projected);this.dict.add(coordinates[0],meshData.triangles,feature.properties);const outlineData=LineMesh.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:{value:fillColor?[fillColor.r,fillColor.g,fillColor.b]:[0,0,0],type:"vec3<f32>"},col2:{value:fillColor2?[fillColor2.r,fillColor2.g,fillColor2.b]:[0,0,0],type:"vec3<f32>"},opacity:{value:featureStyle.fillOpacity,type:"f32"},hashed:{value:featureStyle.hashed?1:0,type:"f32"},hashDisp:{value:10*Math.random(),type:"f32"},hashWidth:{value:this.config.initialHash,type:"f32"}},lineColor=color(featureStyle.lineColor).rgb(),outlineUniform={color:{value:[lineColor.r,lineColor.g,lineColor.b],type:"vec3<f32>"},outlineWidth:{value:featureStyle.lineWidth,type:"f32"}},polygonMesh=LineMesh.from(meshData.vertices,meshData.triangles,GeoJSONVertexShaderFill,GeoJSONFragmentShaderFill,fillUniform);polygonMesh.zIndex=zIndex,container.addChild(polygonMesh);const polygonOutlineMesh=LineMesh.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.resources.uniforms.uniforms.outlineWidth&&(child.shader.resources.uniforms.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 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=LineMesh.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:{value:[lineColor.r,lineColor.g,lineColor.b],type:"vec3<f32>"},width:{value:featureStyle.lineWidth,type:"f32"}},polygonOutlineMesh=LineMesh.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.resources.uniforms.uniforms.outlineWidth&&(child.shader.resources.uniforms.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 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 Graphics,this.container.addChild(point));const fillColor=properties.style.fillColor?new Color(color(properties.style.fillColor).formatHex()).toNumber():0,lineColor=properties.style.lineColor?new Color(color(properties.style.lineColor).formatHex()).toNumber():0,alpha=properties.style.fillOpacity||0,offset=4;point.rect(projected[0]-offset,projected[1]-offset,2*offset,2*offset),point.fill({color:fillColor,alpha:alpha}),point.setStrokeStyle(properties.style.lineWidth,lineColor),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 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().canvas.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};
|