@equinor/esv-intersection 3.0.3 → 3.0.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/index.cjs +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +1 -2
- package/dist/index.mjs.map +1 -1
- package/dist/index.umd.js +1 -1
- package/dist/index.umd.js.map +1 -1
- package/package.json +11 -11
- package/dist/components/axis.d.ts +0 -47
- package/dist/components/index.d.ts +0 -1
- package/dist/control/ExtendedCurveInterpolator.d.ts +0 -58
- package/dist/control/IntersectionReferenceSystem.d.ts +0 -96
- package/dist/control/LayerManager.d.ts +0 -76
- package/dist/control/MainController.d.ts +0 -154
- package/dist/control/ZoomPanHandler.d.ts +0 -158
- package/dist/control/index.d.ts +0 -5
- package/dist/control/interfaces.d.ts +0 -37
- package/dist/control/overlay.d.ts +0 -20
- package/dist/datautils/colortable.d.ts +0 -1
- package/dist/datautils/findsample.d.ts +0 -2
- package/dist/datautils/index.d.ts +0 -6
- package/dist/datautils/interfaces.d.ts +0 -63
- package/dist/datautils/picks.d.ts +0 -74
- package/dist/datautils/schematicShapeGenerator.d.ts +0 -59
- package/dist/datautils/seismicimage.d.ts +0 -45
- package/dist/datautils/surfacedata.d.ts +0 -10
- package/dist/datautils/trajectory.d.ts +0 -14
- package/dist/layers/CalloutCanvasLayer.d.ts +0 -60
- package/dist/layers/CustomDisplayObjects/ComplexRope.d.ts +0 -22
- package/dist/layers/CustomDisplayObjects/ComplexRopeGeometry.d.ts +0 -27
- package/dist/layers/CustomDisplayObjects/FixedWidthSimpleRope.d.ts +0 -20
- package/dist/layers/CustomDisplayObjects/FixedWidthSimpleRopeGeometry.d.ts +0 -26
- package/dist/layers/CustomDisplayObjects/UniformTextureStretchRope.d.ts +0 -17
- package/dist/layers/CustomDisplayObjects/UniformTextureStretchRopeGeometry.d.ts +0 -24
- package/dist/layers/GeomodelCanvasLayer.d.ts +0 -28
- package/dist/layers/GeomodelLabelsLayer.d.ts +0 -49
- package/dist/layers/GeomodelLayerV2.d.ts +0 -12
- package/dist/layers/GridLayer.d.ts +0 -29
- package/dist/layers/ImageCanvasLayer.d.ts +0 -20
- package/dist/layers/ReferenceLineLayer.d.ts +0 -29
- package/dist/layers/SchematicLayer.d.ts +0 -113
- package/dist/layers/SeismicCanvasLayer.d.ts +0 -18
- package/dist/layers/WellborePathLayer.d.ts +0 -17
- package/dist/layers/base/CanvasLayer.d.ts +0 -19
- package/dist/layers/base/HTMLLayer.d.ts +0 -13
- package/dist/layers/base/Layer.d.ts +0 -69
- package/dist/layers/base/PixiLayer.d.ts +0 -32
- package/dist/layers/base/SVGLayer.d.ts +0 -13
- package/dist/layers/base/index.d.ts +0 -5
- package/dist/layers/index.d.ts +0 -16
- package/dist/layers/schematicInterfaces.d.ts +0 -209
- package/dist/utils/arc-length.d.ts +0 -23
- package/dist/utils/binary-search.d.ts +0 -8
- package/dist/utils/color.d.ts +0 -5
- package/dist/utils/index.d.ts +0 -1
- package/dist/utils/root-finder.d.ts +0 -34
- package/dist/utils/text.d.ts +0 -14
- package/dist/utils/vectorUtils.d.ts +0 -15
- package/dist/vendor/pixi-dashed-line/index.d.ts +0 -57
- package/src/components/axis.ts +0 -247
- package/src/components/index.ts +0 -1
- package/src/control/ExtendedCurveInterpolator.ts +0 -155
- package/src/control/IntersectionReferenceSystem.ts +0 -391
- package/src/control/LayerManager.ts +0 -294
- package/src/control/MainController.ts +0 -296
- package/src/control/ZoomPanHandler.ts +0 -436
- package/src/control/index.ts +0 -5
- package/src/control/interfaces.ts +0 -42
- package/src/control/overlay.ts +0 -118
- package/src/datautils/colortable.ts +0 -14
- package/src/datautils/findsample.ts +0 -64
- package/src/datautils/index.ts +0 -6
- package/src/datautils/interfaces.ts +0 -68
- package/src/datautils/picks.ts +0 -328
- package/src/datautils/schematicShapeGenerator.ts +0 -1008
- package/src/datautils/seismicimage.ts +0 -180
- package/src/datautils/surfacedata.ts +0 -318
- package/src/datautils/trajectory.ts +0 -206
- package/src/layers/CalloutCanvasLayer.ts +0 -338
- package/src/layers/CustomDisplayObjects/ComplexRope.ts +0 -45
- package/src/layers/CustomDisplayObjects/ComplexRopeGeometry.ts +0 -190
- package/src/layers/CustomDisplayObjects/FixedWidthSimpleRope.ts +0 -41
- package/src/layers/CustomDisplayObjects/FixedWidthSimpleRopeGeometry.ts +0 -149
- package/src/layers/CustomDisplayObjects/UniformTextureStretchRope.ts +0 -39
- package/src/layers/CustomDisplayObjects/UniformTextureStretchRopeGeometry.ts +0 -174
- package/src/layers/GeomodelCanvasLayer.ts +0 -176
- package/src/layers/GeomodelLabelsLayer.ts +0 -619
- package/src/layers/GeomodelLayerV2.ts +0 -110
- package/src/layers/GridLayer.ts +0 -145
- package/src/layers/ImageCanvasLayer.ts +0 -55
- package/src/layers/ReferenceLineLayer.ts +0 -185
- package/src/layers/SchematicLayer.ts +0 -872
- package/src/layers/SeismicCanvasLayer.ts +0 -46
- package/src/layers/WellborePathLayer.ts +0 -129
- package/src/layers/base/CanvasLayer.ts +0 -102
- package/src/layers/base/HTMLLayer.ts +0 -70
- package/src/layers/base/Layer.ts +0 -217
- package/src/layers/base/PixiLayer.ts +0 -190
- package/src/layers/base/SVGLayer.ts +0 -63
- package/src/layers/base/index.ts +0 -5
- package/src/layers/index.ts +0 -16
- package/src/layers/schematicInterfaces.ts +0 -472
- package/src/utils/arc-length.ts +0 -66
- package/src/utils/binary-search.ts +0 -26
- package/src/utils/color.ts +0 -22
- package/src/utils/index.ts +0 -1
- package/src/utils/root-finder.ts +0 -78
- package/src/utils/text.ts +0 -88
- package/src/utils/vectorUtils.ts +0 -67
- package/src/vendor/pixi-dashed-line/index.ts +0 -394
|
@@ -1,180 +0,0 @@
|
|
|
1
|
-
import { clamp } from '@equinor/videx-math';
|
|
2
|
-
import { SeismicCanvasDataOptions } from '../layers/SeismicCanvasLayer';
|
|
3
|
-
|
|
4
|
-
import { createColorTable } from './colortable';
|
|
5
|
-
import { findIndexOfSample } from './findsample';
|
|
6
|
-
|
|
7
|
-
export type SeismicInfo = {
|
|
8
|
-
minX: number;
|
|
9
|
-
maxX: number;
|
|
10
|
-
minTvdMsl: number;
|
|
11
|
-
maxTvdMsl: number;
|
|
12
|
-
domain: {
|
|
13
|
-
min: number;
|
|
14
|
-
max: number;
|
|
15
|
-
difference: number;
|
|
16
|
-
};
|
|
17
|
-
};
|
|
18
|
-
|
|
19
|
-
export const getSeismicOptions = (info: SeismicInfo | null): SeismicCanvasDataOptions => {
|
|
20
|
-
if (!info) {
|
|
21
|
-
return {
|
|
22
|
-
x: 0,
|
|
23
|
-
y: 0,
|
|
24
|
-
width: 0,
|
|
25
|
-
height: 0,
|
|
26
|
-
};
|
|
27
|
-
}
|
|
28
|
-
return {
|
|
29
|
-
x: info.minX,
|
|
30
|
-
y: info.minTvdMsl,
|
|
31
|
-
width: info.maxX - info.minX,
|
|
32
|
-
height: info.maxTvdMsl - info.minTvdMsl,
|
|
33
|
-
};
|
|
34
|
-
};
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* Get key information about the seismic data
|
|
38
|
-
* Code originally developed for the REP project
|
|
39
|
-
* @param data Seismic data
|
|
40
|
-
* @param trajectory Wellbore or freehand trajectory
|
|
41
|
-
* @return Key domain and depth information for seismic data
|
|
42
|
-
*/
|
|
43
|
-
export function getSeismicInfo(data: { datapoints: number[][]; yAxisValues: number[] }, trajectory: number[][]): SeismicInfo | null {
|
|
44
|
-
if (!(data && data.datapoints)) {
|
|
45
|
-
return null;
|
|
46
|
-
}
|
|
47
|
-
const minX = trajectory.reduce((acc: number, val: number[]) => Math.min(acc, val[0]), 0);
|
|
48
|
-
const maxX = trajectory.reduce((acc: number, val: number[]) => Math.max(acc, val[0]), 0);
|
|
49
|
-
|
|
50
|
-
const minTvdMsl = data.yAxisValues && data.yAxisValues[0];
|
|
51
|
-
const maxTvdMsl = data.yAxisValues && data.yAxisValues[data.yAxisValues.length - 1];
|
|
52
|
-
|
|
53
|
-
// Find value domain
|
|
54
|
-
const dp = data.datapoints || [];
|
|
55
|
-
const min = -dp.reduce((val: number, array: number[]) => Math.min(...array, val), 0);
|
|
56
|
-
const max = dp.reduce((val: number, array: number[]) => Math.max(...array, val), 0);
|
|
57
|
-
|
|
58
|
-
const absMax = Math.max(Math.abs(min), Math.abs(max));
|
|
59
|
-
|
|
60
|
-
const dmin = -absMax;
|
|
61
|
-
const dmax = absMax;
|
|
62
|
-
|
|
63
|
-
const info = {
|
|
64
|
-
minX,
|
|
65
|
-
maxX,
|
|
66
|
-
minTvdMsl,
|
|
67
|
-
maxTvdMsl,
|
|
68
|
-
domain: {
|
|
69
|
-
min: dmin,
|
|
70
|
-
max: dmax,
|
|
71
|
-
difference: dmax - dmin,
|
|
72
|
-
},
|
|
73
|
-
};
|
|
74
|
-
|
|
75
|
-
return info;
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
/**
|
|
79
|
-
* Generate seismic
|
|
80
|
-
* Code originally developed for the REP project
|
|
81
|
-
* @param data Seismic data
|
|
82
|
-
* @param trajectory Wellbore or freehand trajectory
|
|
83
|
-
* @param colormap Color map for rendering
|
|
84
|
-
* @param options.isLeftToRight (optional) draw left to right
|
|
85
|
-
* @param options.seismicRange (optional) Range for mapping seimic values to color map
|
|
86
|
-
* @param options.seismicMin (optional) Min seismic value for mapping seimic values to color map
|
|
87
|
-
* @param options.seismicMax (optional) Max seismic value for mapping seimic values to color map
|
|
88
|
-
* @return Key domain and depth information for seismic data
|
|
89
|
-
*/
|
|
90
|
-
export async function generateSeismicSliceImage(
|
|
91
|
-
data: { datapoints: number[][]; yAxisValues: number[] },
|
|
92
|
-
trajectory: number[][],
|
|
93
|
-
colormap: string[],
|
|
94
|
-
options?: {
|
|
95
|
-
isLeftToRight: true;
|
|
96
|
-
seismicRange?: number;
|
|
97
|
-
seismicMin?: number;
|
|
98
|
-
seismicMax?: number;
|
|
99
|
-
},
|
|
100
|
-
): Promise<ImageBitmap> {
|
|
101
|
-
if (!(data && data.datapoints && data.datapoints.length > 0)) {
|
|
102
|
-
return;
|
|
103
|
-
}
|
|
104
|
-
const { datapoints: dp } = data;
|
|
105
|
-
|
|
106
|
-
const min = options?.seismicMin || options?.seismicRange || dp.reduce((val: number, array: number[]) => Math.min(...array, val), 0);
|
|
107
|
-
const max = options?.seismicMax || options?.seismicRange || dp.reduce((val: number, array: number[]) => Math.max(...array, val), 0);
|
|
108
|
-
|
|
109
|
-
const absMax = Math.max(Math.abs(min), Math.abs(max));
|
|
110
|
-
|
|
111
|
-
const dmin = -absMax;
|
|
112
|
-
const dmax = absMax;
|
|
113
|
-
|
|
114
|
-
const domain = {
|
|
115
|
-
min: dmin,
|
|
116
|
-
max: dmax,
|
|
117
|
-
difference: dmax - dmin,
|
|
118
|
-
};
|
|
119
|
-
|
|
120
|
-
const length = trajectory[0][0] - trajectory[trajectory.length - 1][0];
|
|
121
|
-
// eslint-disable-next-line no-magic-numbers
|
|
122
|
-
const width = Math.abs(Math.floor(length / 5));
|
|
123
|
-
const height = data.yAxisValues.length;
|
|
124
|
-
|
|
125
|
-
// Generate color table
|
|
126
|
-
const colorTableSize = 1000;
|
|
127
|
-
const colorTable = createColorTable(colormap, colorTableSize);
|
|
128
|
-
|
|
129
|
-
// Generate image
|
|
130
|
-
const d = new Uint8ClampedArray(width * height * 4);
|
|
131
|
-
|
|
132
|
-
let offset = 0;
|
|
133
|
-
const colorFactor = (colorTableSize - 1) / domain.difference;
|
|
134
|
-
|
|
135
|
-
let pos = options?.isLeftToRight ? trajectory[0][0] : trajectory[trajectory.length - 1][0];
|
|
136
|
-
|
|
137
|
-
const step = (length / width) * (options?.isLeftToRight ? -1 : 1);
|
|
138
|
-
|
|
139
|
-
let val1;
|
|
140
|
-
let val2;
|
|
141
|
-
let val;
|
|
142
|
-
let i;
|
|
143
|
-
let col: number[];
|
|
144
|
-
const black = [0, 0, 0];
|
|
145
|
-
let opacity;
|
|
146
|
-
|
|
147
|
-
for (let x = 0; x < width; x++) {
|
|
148
|
-
offset = x * 4;
|
|
149
|
-
const index = findIndexOfSample(trajectory, pos);
|
|
150
|
-
const x1 = trajectory[index][0];
|
|
151
|
-
const x2 = trajectory[index + 1][0];
|
|
152
|
-
const span = x2 - x1;
|
|
153
|
-
const dx = pos - x1;
|
|
154
|
-
const ratio = dx / span;
|
|
155
|
-
|
|
156
|
-
for (let y = 0; y < height; y++) {
|
|
157
|
-
val1 = dp[y][index];
|
|
158
|
-
val2 = dp[y][index + 1];
|
|
159
|
-
if (val1 == null || val2 == null) {
|
|
160
|
-
col = black;
|
|
161
|
-
opacity = 0;
|
|
162
|
-
} else {
|
|
163
|
-
val = val1 * (1 - ratio) + val2 * ratio;
|
|
164
|
-
i = (val - domain.min) * colorFactor;
|
|
165
|
-
i = clamp(~~i, 0, colorTableSize - 1);
|
|
166
|
-
col = colorTable[i];
|
|
167
|
-
opacity = 255;
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
d.set([col[0], col[1], col[2], opacity], offset);
|
|
171
|
-
|
|
172
|
-
offset += width * 4;
|
|
173
|
-
}
|
|
174
|
-
pos += step;
|
|
175
|
-
}
|
|
176
|
-
const imageData = new ImageData(d, width, height);
|
|
177
|
-
const image = await createImageBitmap(imageData, 0, 0, width, height);
|
|
178
|
-
|
|
179
|
-
return image;
|
|
180
|
-
}
|
|
@@ -1,318 +0,0 @@
|
|
|
1
|
-
import { interpolateRgb, quantize } from 'd3-interpolate';
|
|
2
|
-
import { scaleOrdinal } from 'd3-scale';
|
|
3
|
-
import { convertColor } from '../utils/color';
|
|
4
|
-
import { StratUnit, SurfaceMetaAndValues, SurfaceLine, SurfaceArea, SurfaceData } from './interfaces';
|
|
5
|
-
|
|
6
|
-
const TRANSLUCENT_RED = 0x80000000;
|
|
7
|
-
const WHITE = 0xffffffff;
|
|
8
|
-
|
|
9
|
-
type MappedSurfaces = {
|
|
10
|
-
name: string;
|
|
11
|
-
isBase: boolean;
|
|
12
|
-
values: number[];
|
|
13
|
-
color: string;
|
|
14
|
-
visualization: string;
|
|
15
|
-
};
|
|
16
|
-
|
|
17
|
-
type StratGroup = {
|
|
18
|
-
age: number;
|
|
19
|
-
name: string;
|
|
20
|
-
};
|
|
21
|
-
|
|
22
|
-
type Stratigraphy = {
|
|
23
|
-
unit: StratUnit;
|
|
24
|
-
group: string;
|
|
25
|
-
name: string;
|
|
26
|
-
isBase: boolean;
|
|
27
|
-
values: number[];
|
|
28
|
-
color: string;
|
|
29
|
-
visualization: string;
|
|
30
|
-
};
|
|
31
|
-
|
|
32
|
-
type MappedGroup = {
|
|
33
|
-
id: string;
|
|
34
|
-
label: string;
|
|
35
|
-
color: string;
|
|
36
|
-
top: number[];
|
|
37
|
-
};
|
|
38
|
-
|
|
39
|
-
interface SurfaceAreaGrouping {
|
|
40
|
-
[propType: string]: SurfaceArea[];
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
/**
|
|
44
|
-
* Generate surface data from trajectory, stratcolum and surface data
|
|
45
|
-
* Code originally developed for the REP project
|
|
46
|
-
* @param trajectory Projected trajectory generated from the poslog used when retrieving surface data from surface API
|
|
47
|
-
* @param stratColumn Strat columnd from SMDA
|
|
48
|
-
* @param surfaceData - Surfaces meta data with surface values in data section
|
|
49
|
-
* @return Surface areas ready for rendering in geolayer
|
|
50
|
-
*/
|
|
51
|
-
export function generateSurfaceData(trajectory: number[][], stratColumn: StratUnit[], surfaceData: SurfaceMetaAndValues[]): SurfaceData {
|
|
52
|
-
const filteredSurfaces: SurfaceMetaAndValues[] = surfaceData.filter((s) => s.data.values);
|
|
53
|
-
const mappedSurfaces = mapSurfaceData(filteredSurfaces);
|
|
54
|
-
|
|
55
|
-
const stratGroups = new Map<string, StratGroup>();
|
|
56
|
-
const stratigraphies = combineSurfacesAndStratColumn(mappedSurfaces, stratColumn, stratGroups);
|
|
57
|
-
sortStratigraphies(stratigraphies);
|
|
58
|
-
|
|
59
|
-
const lines: SurfaceLine[] = getSurfaceLines(mappedSurfaces, trajectory);
|
|
60
|
-
const surfaceAreas: SurfaceAreaGrouping = generateSurfaceAreas(trajectory, stratigraphies, stratColumn);
|
|
61
|
-
|
|
62
|
-
const groups: MappedGroup[] = mapGroups(stratGroups, surfaceAreas);
|
|
63
|
-
const groupAreas: SurfaceArea[] = generateGroupAreas(groups, trajectory);
|
|
64
|
-
|
|
65
|
-
//Combine group areas with surface areas
|
|
66
|
-
const areas: SurfaceArea[] = [
|
|
67
|
-
...groupAreas,
|
|
68
|
-
...Object.values(surfaceAreas)
|
|
69
|
-
.flat()
|
|
70
|
-
.filter((d) => !d.exclude),
|
|
71
|
-
];
|
|
72
|
-
|
|
73
|
-
const data = {
|
|
74
|
-
lines,
|
|
75
|
-
areas,
|
|
76
|
-
};
|
|
77
|
-
|
|
78
|
-
return data;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
/**
|
|
82
|
-
* Get surfaces which should be rendered as lines
|
|
83
|
-
* @param mappedSurfaces
|
|
84
|
-
* @param trajectory
|
|
85
|
-
*/
|
|
86
|
-
function getSurfaceLines(mappedSurfaces: MappedSurfaces[], trajectory: number[][]): SurfaceLine[] {
|
|
87
|
-
const lines: SurfaceLine[] = mappedSurfaces
|
|
88
|
-
.filter((d: MappedSurfaces) => d.visualization === 'line')
|
|
89
|
-
.map((l: MappedSurfaces) => ({
|
|
90
|
-
id: l.name,
|
|
91
|
-
label: l.name,
|
|
92
|
-
width: 2,
|
|
93
|
-
color: convertColor(l.color || 'black'),
|
|
94
|
-
data: trajectory.map((p, j) => [p[0], l.values[j]]),
|
|
95
|
-
}));
|
|
96
|
-
|
|
97
|
-
return lines;
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
function generateGroupAreas(groups: MappedGroup[], trajectory: number[][]): SurfaceArea[] {
|
|
101
|
-
const groupAreas = groups.map((g: MappedGroup, i: number) => {
|
|
102
|
-
const next: MappedGroup | null = i + 1 < groups.length ? groups[i + 1] : null;
|
|
103
|
-
return {
|
|
104
|
-
id: g.id,
|
|
105
|
-
label: g.label,
|
|
106
|
-
color: convertColor(g.color),
|
|
107
|
-
data: trajectory.map((p: number[], j: number) => [p[0], g.top[j], next ? next.top[j] : null]),
|
|
108
|
-
};
|
|
109
|
-
});
|
|
110
|
-
return groupAreas;
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
function mapGroups(stratGroups: Map<string, StratGroup>, surfaceAreas: SurfaceAreaGrouping): MappedGroup[] {
|
|
114
|
-
const groups = Array.from(stratGroups.values())
|
|
115
|
-
.sort((a: StratGroup, b: StratGroup) => a.age - b.age)
|
|
116
|
-
.filter((g: StratGroup) => {
|
|
117
|
-
const surfaces: SurfaceArea[] = surfaceAreas[g.name];
|
|
118
|
-
const isValid = surfaces && surfaces.length > 0;
|
|
119
|
-
if (!isValid) {
|
|
120
|
-
console.warn(`Intersection surface group '${g.name}' has no valid entries and will be discarded.`);
|
|
121
|
-
}
|
|
122
|
-
return isValid;
|
|
123
|
-
})
|
|
124
|
-
.map((g: StratGroup, i: number) => {
|
|
125
|
-
const surface: SurfaceArea[] = surfaceAreas[g.name];
|
|
126
|
-
const top = surface[0];
|
|
127
|
-
return {
|
|
128
|
-
id: g.name,
|
|
129
|
-
label: g.name,
|
|
130
|
-
color: unassignedColorScale(i),
|
|
131
|
-
top: top.data.map((d: number[]) => d[1]),
|
|
132
|
-
};
|
|
133
|
-
});
|
|
134
|
-
return groups;
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
function combineSurfacesAndStratColumn(
|
|
138
|
-
mappedSurfaces: MappedSurfaces[],
|
|
139
|
-
stratColumn: StratUnit[],
|
|
140
|
-
stratGroups: Map<string, StratGroup>,
|
|
141
|
-
): Stratigraphy[] {
|
|
142
|
-
const firstUnit = stratColumn && stratColumn.find((d: StratUnit) => d.stratUnitLevel === 1);
|
|
143
|
-
const defaultGroupName: string = firstUnit ? firstUnit.identifier : 'SEABED';
|
|
144
|
-
const stratigrafies = mappedSurfaces
|
|
145
|
-
.filter((d: MappedSurfaces) => d.visualization === 'interval' || d.visualization === 'none')
|
|
146
|
-
.map((s: MappedSurfaces) => {
|
|
147
|
-
const path: StratUnit[] = [];
|
|
148
|
-
const stratUnit: StratUnit = findStratcolumnUnit(stratColumn, s.name, path);
|
|
149
|
-
if (!stratUnit) {
|
|
150
|
-
console.warn(`No match for ${s.name} in strat column`);
|
|
151
|
-
}
|
|
152
|
-
const group: StratUnit = path[0] || stratUnit;
|
|
153
|
-
const groupName: string = (group && group.identifier) || defaultGroupName;
|
|
154
|
-
if (group && !stratGroups.has(groupName)) {
|
|
155
|
-
stratGroups.set(groupName, {
|
|
156
|
-
age: group.topAge,
|
|
157
|
-
name: group.identifier,
|
|
158
|
-
});
|
|
159
|
-
}
|
|
160
|
-
return {
|
|
161
|
-
...s,
|
|
162
|
-
unit: stratUnit,
|
|
163
|
-
group: groupName,
|
|
164
|
-
};
|
|
165
|
-
});
|
|
166
|
-
return stratigrafies;
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
/**
|
|
170
|
-
* Sort stratigrafies on unit and age, base after top and higher level after lower
|
|
171
|
-
* @param stratigrafies
|
|
172
|
-
*/
|
|
173
|
-
function sortStratigraphies(stratigrafies: Stratigraphy[]): void {
|
|
174
|
-
stratigrafies.sort((a: Stratigraphy, b: Stratigraphy) => {
|
|
175
|
-
if (!a.unit && !b.unit) {
|
|
176
|
-
return 0;
|
|
177
|
-
}
|
|
178
|
-
if (!a.unit) {
|
|
179
|
-
return -1;
|
|
180
|
-
}
|
|
181
|
-
if (!b.unit) {
|
|
182
|
-
return 1;
|
|
183
|
-
}
|
|
184
|
-
const aAge = a.isBase ? a.unit.baseAge : a.unit.topAge;
|
|
185
|
-
const bAge = b.isBase ? b.unit.baseAge : b.unit.topAge;
|
|
186
|
-
if (aAge !== bAge) {
|
|
187
|
-
return aAge - bAge;
|
|
188
|
-
}
|
|
189
|
-
if (a.isBase && !b.isBase) {
|
|
190
|
-
return 1;
|
|
191
|
-
}
|
|
192
|
-
if (!a.isBase && b.isBase) {
|
|
193
|
-
return -1;
|
|
194
|
-
}
|
|
195
|
-
return a.unit.stratUnitLevel - b.unit.stratUnitLevel;
|
|
196
|
-
});
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
/**
|
|
200
|
-
* @param {[]} units
|
|
201
|
-
* @param {string} unitname
|
|
202
|
-
* @param {[]} path
|
|
203
|
-
*/
|
|
204
|
-
function findStratcolumnUnit(units: StratUnit[], unitname: string, path: StratUnit[] = []): StratUnit | null {
|
|
205
|
-
const unit: StratUnit = units.find((u: StratUnit) => u.identifier.toLowerCase() === unitname.toLowerCase());
|
|
206
|
-
if (unit) {
|
|
207
|
-
// Build path
|
|
208
|
-
let temp: StratUnit = unit;
|
|
209
|
-
do {
|
|
210
|
-
path.unshift(temp);
|
|
211
|
-
temp = units.find((u: StratUnit) => u.identifier === temp.stratUnitParent);
|
|
212
|
-
} while (temp);
|
|
213
|
-
|
|
214
|
-
return unit;
|
|
215
|
-
}
|
|
216
|
-
return null;
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
function mapSurfaceData(surfaces: SurfaceMetaAndValues[]): MappedSurfaces[] {
|
|
220
|
-
return surfaces.map((s: SurfaceMetaAndValues) => {
|
|
221
|
-
const displayName: string = s.visualSettings.displayName;
|
|
222
|
-
const name: string = displayName.replace(/\s(Base|Top)/gi, '');
|
|
223
|
-
const isBase: boolean = displayName.toLowerCase().endsWith('base');
|
|
224
|
-
|
|
225
|
-
return {
|
|
226
|
-
name,
|
|
227
|
-
isBase,
|
|
228
|
-
values: s.data.values,
|
|
229
|
-
color: s.visualSettings.colors.crossSection,
|
|
230
|
-
visualization: s.visualSettings.crossSection.toLowerCase(),
|
|
231
|
-
};
|
|
232
|
-
});
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
function getColorFromUnit(unit: StratUnit): number {
|
|
236
|
-
if (unit.colorR === null || unit.colorG === null || unit.colorB === null) {
|
|
237
|
-
return TRANSLUCENT_RED;
|
|
238
|
-
}
|
|
239
|
-
const res: number = (unit.colorR << 16) | (unit.colorG << 8) | unit.colorB;
|
|
240
|
-
return res;
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
const unassignedColorScale = scaleOrdinal<number, string>()
|
|
244
|
-
.domain([0, 100])
|
|
245
|
-
// eslint-disable-next-line no-magic-numbers
|
|
246
|
-
.range(quantize(interpolateRgb('#e6f1cf', '#85906d'), 10));
|
|
247
|
-
|
|
248
|
-
/**
|
|
249
|
-
* Find the best matching base index based on name or by values
|
|
250
|
-
*/
|
|
251
|
-
function findBestMatchingBaseIndex(top: Stratigraphy, index: number, surfaces: Stratigraphy[], stratColumn: StratUnit[]): number {
|
|
252
|
-
const nextIndex: number = index + 1;
|
|
253
|
-
|
|
254
|
-
if (!surfaces || nextIndex >= surfaces.length) {
|
|
255
|
-
return null;
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
// If there is a matching base by name, use that. More robust, does not rely on sorting
|
|
259
|
-
const baseSurfaceIndex = surfaces.findIndex((candidate: Stratigraphy) => candidate.isBase && candidate.name === top.name);
|
|
260
|
-
if (baseSurfaceIndex !== -1) {
|
|
261
|
-
return baseSurfaceIndex;
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
for (let i = nextIndex; i < surfaces.length; i++) {
|
|
265
|
-
const candidate = surfaces[i];
|
|
266
|
-
if (!candidate.isBase) {
|
|
267
|
-
return i;
|
|
268
|
-
}
|
|
269
|
-
if (isAnchestor(top, candidate, stratColumn)) {
|
|
270
|
-
return i;
|
|
271
|
-
}
|
|
272
|
-
}
|
|
273
|
-
return null;
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
function isAnchestor(descendant: Stratigraphy, candidate: Stratigraphy, stratColumn: StratUnit[]): boolean {
|
|
277
|
-
const path: StratUnit[] = [];
|
|
278
|
-
findStratcolumnUnit(stratColumn, descendant.name, path);
|
|
279
|
-
return path.some((p: StratUnit) => candidate.name === p.identifier);
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
function generateSurfaceAreas(projection: number[][], surfaces: Stratigraphy[], stratColumn: StratUnit[]): SurfaceAreaGrouping {
|
|
283
|
-
const areas: SurfaceAreaGrouping = surfaces.reduce((acc: SurfaceAreaGrouping, surface: Stratigraphy, i: number) => {
|
|
284
|
-
if (!surface.isBase) {
|
|
285
|
-
if (!acc[surface.group]) {
|
|
286
|
-
acc[surface.group] = [];
|
|
287
|
-
}
|
|
288
|
-
const baseIndex: number = findBestMatchingBaseIndex(surface, i, surfaces, stratColumn);
|
|
289
|
-
acc[surface.group].push({
|
|
290
|
-
id: surface.name,
|
|
291
|
-
label: surface.name,
|
|
292
|
-
color: (surface.unit && getColorFromUnit(surface.unit)) || WHITE,
|
|
293
|
-
exclude: surface.visualization === 'none' || !surface.unit,
|
|
294
|
-
data: projection.map((p, j) => {
|
|
295
|
-
const baseValue: number = surface.values[j] !== null ? getBaseValue(baseIndex, surfaces, j) : null;
|
|
296
|
-
return [p[0], surface.values[j], baseValue];
|
|
297
|
-
}),
|
|
298
|
-
});
|
|
299
|
-
}
|
|
300
|
-
return acc;
|
|
301
|
-
}, {});
|
|
302
|
-
return areas;
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
// get the value from the surface with the supplied index,
|
|
306
|
-
// iterate to next surface if value is null
|
|
307
|
-
function getBaseValue(index: number, surfaces: Stratigraphy[], datapoint: number): number {
|
|
308
|
-
if (!surfaces || !index || index >= surfaces.length) {
|
|
309
|
-
return null;
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
for (let i: number = index; i < surfaces.length; i++) {
|
|
313
|
-
if (surfaces[i].values[datapoint] !== null) {
|
|
314
|
-
return surfaces[i].values[datapoint];
|
|
315
|
-
}
|
|
316
|
-
}
|
|
317
|
-
return null;
|
|
318
|
-
}
|
|
@@ -1,206 +0,0 @@
|
|
|
1
|
-
import Vector2 from '@equinor/videx-vector2';
|
|
2
|
-
import { seqI } from '@equinor/videx-math';
|
|
3
|
-
import { CurveInterpolator } from 'curve-interpolator';
|
|
4
|
-
import { SurveySample } from './interfaces';
|
|
5
|
-
|
|
6
|
-
const stepSize = 0.1;
|
|
7
|
-
const extensionLength = 1000;
|
|
8
|
-
const thresholdRelativeDist = 150;
|
|
9
|
-
const thresholdDirectionDist = 30;
|
|
10
|
-
|
|
11
|
-
const pathSteps = 10;
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* Generate projected wellbore path for drawing using wellbore path layer
|
|
15
|
-
* Code originally developed for REP
|
|
16
|
-
* @param {[]} poslog Position log from SMDA
|
|
17
|
-
*/
|
|
18
|
-
export function generateProjectedWellborePath(poslog: SurveySample[]): number[][] {
|
|
19
|
-
if (!poslog || poslog.length === 0) {
|
|
20
|
-
return [];
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
const points: number[][] = poslog ? poslog.map((p: SurveySample) => [p.easting, p.northing, p.tvd, p.md]) : [];
|
|
24
|
-
|
|
25
|
-
const projection: number[][] = simplify(projectCurtain(points));
|
|
26
|
-
const offset: number = projection[projection.length - 1][0];
|
|
27
|
-
|
|
28
|
-
projection.forEach((p, i) => {
|
|
29
|
-
projection[i][0] = offset - p[0];
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
return projection;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
/**
|
|
36
|
-
* Generate Trajectory
|
|
37
|
-
* Code originally developed for REP
|
|
38
|
-
* @param {[]} poslog Position log from SMDA
|
|
39
|
-
* @param {number} defaultIntersectionAngle Default intersection angle for the field
|
|
40
|
-
*/
|
|
41
|
-
export function generateProjectedTrajectory(poslog: SurveySample[], defaultIntersectionAngle: number): number[][] {
|
|
42
|
-
if (!poslog || poslog.length === 0) {
|
|
43
|
-
return [];
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
const points: number[][] = poslog ? poslog.map((p) => [p.easting, p.northing, p.tvd, p.md]) : [];
|
|
47
|
-
|
|
48
|
-
const interpolator: CurveInterpolator = new CurveInterpolator(points, { tension: 0.75, arcDivisions: 5000 });
|
|
49
|
-
const displacement: number = interpolator.length;
|
|
50
|
-
|
|
51
|
-
const nPoints: number = Math.round(displacement * pathSteps);
|
|
52
|
-
let path: number[][] = null;
|
|
53
|
-
if (nPoints > 0) {
|
|
54
|
-
const maxOffset = 0.0005;
|
|
55
|
-
const maxDistance = 10;
|
|
56
|
-
path = simplify(interpolator.getPoints(nPoints), maxOffset, maxDistance);
|
|
57
|
-
} else {
|
|
58
|
-
path = [[points[0][0], points[0][1]]];
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
const first: number[] = path[0];
|
|
62
|
-
const last: number[] = path[path.length - 1];
|
|
63
|
-
const relativeDist: number = Vector2.distance(first, last);
|
|
64
|
-
let v: Vector2 = null;
|
|
65
|
-
|
|
66
|
-
if (relativeDist < thresholdRelativeDist) {
|
|
67
|
-
const oneEighty = 180;
|
|
68
|
-
const radCurtainDirection = (defaultIntersectionAngle / oneEighty) * Math.PI;
|
|
69
|
-
v = new Vector2(Math.cos(radCurtainDirection), Math.sin(radCurtainDirection)).mutable;
|
|
70
|
-
} else {
|
|
71
|
-
v = getDirectionVector(path, thresholdDirectionDist);
|
|
72
|
-
}
|
|
73
|
-
const extensionLengthStart: number = Math.max(0, extensionLength - displacement);
|
|
74
|
-
const offset: number = extensionLengthStart + displacement;
|
|
75
|
-
const trajectory: number[][] = [];
|
|
76
|
-
|
|
77
|
-
let firstPoints: number[][] = [];
|
|
78
|
-
|
|
79
|
-
// Reference to initial vector
|
|
80
|
-
const initial: number[] = v.toArray();
|
|
81
|
-
|
|
82
|
-
if (extensionLengthStart > 0) {
|
|
83
|
-
// extend from start
|
|
84
|
-
firstPoints = seqI(Math.ceil(extensionLengthStart * stepSize)).map((t) =>
|
|
85
|
-
v
|
|
86
|
-
.set(initial)
|
|
87
|
-
.scale(extensionLengthStart * (1 - t))
|
|
88
|
-
.subFrom(first)
|
|
89
|
-
.toArray(),
|
|
90
|
-
);
|
|
91
|
-
firstPoints.pop();
|
|
92
|
-
trajectory.push(...firstPoints);
|
|
93
|
-
}
|
|
94
|
-
trajectory.push(...path);
|
|
95
|
-
|
|
96
|
-
const endPoints: number[][] = seqI(Math.ceil(extensionLength * stepSize))
|
|
97
|
-
.map((t) =>
|
|
98
|
-
v
|
|
99
|
-
.set(initial)
|
|
100
|
-
.scale(extensionLength * t)
|
|
101
|
-
.add(last)
|
|
102
|
-
.toArray(),
|
|
103
|
-
)
|
|
104
|
-
.splice(1);
|
|
105
|
-
|
|
106
|
-
trajectory.push(...endPoints);
|
|
107
|
-
|
|
108
|
-
const projectedTrajectory: number[][] = projectCurtain(trajectory, null, offset);
|
|
109
|
-
|
|
110
|
-
return projectedTrajectory;
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
/**
|
|
114
|
-
* Get direction vector
|
|
115
|
-
* Code originally developed for REP
|
|
116
|
-
* @param {[]} path
|
|
117
|
-
* @param {number} threshold
|
|
118
|
-
* @returns {Vector2}
|
|
119
|
-
*/
|
|
120
|
-
function getDirectionVector(path: number[][], threshold: number): Vector2 {
|
|
121
|
-
const res: Vector2 = Vector2.zero.mutable;
|
|
122
|
-
let len = 0;
|
|
123
|
-
const temp: Vector2 = Vector2.zero.mutable;
|
|
124
|
-
|
|
125
|
-
for (let i = 0; i < path.length - 1; i++) {
|
|
126
|
-
const index = path.length - 1 - i;
|
|
127
|
-
temp.set(path[index]).sub(path[index - 1]);
|
|
128
|
-
res.add(temp);
|
|
129
|
-
|
|
130
|
-
len = res.magnitude;
|
|
131
|
-
if (len > threshold) {
|
|
132
|
-
break;
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
if (len === 0) {
|
|
137
|
-
return new Vector2([0, 0]);
|
|
138
|
-
}
|
|
139
|
-
return res.scale(1 / len);
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
/**
|
|
143
|
-
* Simplify array
|
|
144
|
-
*
|
|
145
|
-
* Simplifies an array using given parameters.
|
|
146
|
-
* Code originally developed for REP
|
|
147
|
-
* @access public
|
|
148
|
-
*
|
|
149
|
-
* @param {Number[]} inputArr Array to simplify
|
|
150
|
-
* @param {Number} [maxOffset=0.001] Max offset (Default = 0.001)
|
|
151
|
-
* @param {Number} [maxDistance=10] Max distance (Default = 10)
|
|
152
|
-
*
|
|
153
|
-
* @return {Number[]} Simplified array
|
|
154
|
-
*/
|
|
155
|
-
function simplify(inputArr: number[][], maxOffset = 0.001, maxDistance = 10): number[][] {
|
|
156
|
-
if (inputArr.length <= 4) {
|
|
157
|
-
return inputArr;
|
|
158
|
-
}
|
|
159
|
-
const [o0, o1] = inputArr[0];
|
|
160
|
-
const arr = inputArr.map((d) => [d[0] - o0, d[1] - o1]);
|
|
161
|
-
let [a0, a1] = arr[0];
|
|
162
|
-
const sim: number[][] = [inputArr[0]];
|
|
163
|
-
|
|
164
|
-
for (let i = 1; i + 1 < arr.length; i++) {
|
|
165
|
-
const [t0, t1] = arr[i];
|
|
166
|
-
const [b0, b1] = arr[i + 1];
|
|
167
|
-
|
|
168
|
-
// If t->b vector is NOT [0, 0]
|
|
169
|
-
if (b0 - t0 !== 0 || b1 - t1 !== 0) {
|
|
170
|
-
// Proximity check
|
|
171
|
-
const proximity: number = Math.abs(a0 * b1 - a1 * b0 + b0 * t1 - b1 * t0 + a1 * t0 - a0 * t1) / Math.sqrt((b0 - a0) ** 2 + (b1 - a1) ** 2);
|
|
172
|
-
|
|
173
|
-
const dir: number[] = [a0 - t0, a1 - t1];
|
|
174
|
-
const len: number = Math.sqrt(dir[0] ** 2 + dir[1] ** 2);
|
|
175
|
-
|
|
176
|
-
if (proximity > maxOffset || len >= maxDistance) {
|
|
177
|
-
sim.push([t0 + o0, t1 + o1]);
|
|
178
|
-
[a0, a1] = [t0, t1];
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
const last: number[] = arr[arr.length - 1];
|
|
183
|
-
sim.push([last[0] + o0, last[1] + o1]);
|
|
184
|
-
|
|
185
|
-
return sim;
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
/**
|
|
189
|
-
* Perform a curtain projection on a set of points in 3D
|
|
190
|
-
* @param points
|
|
191
|
-
* @param origin
|
|
192
|
-
* @param offset
|
|
193
|
-
* @returns {array}
|
|
194
|
-
*/
|
|
195
|
-
function projectCurtain(points: number[][], origin: number[] = null, offset = 0): number[][] {
|
|
196
|
-
let p0: number[] = origin || points[0];
|
|
197
|
-
let l = 0;
|
|
198
|
-
const projected = points.map((p1: number[]) => {
|
|
199
|
-
const dx = p1[0] - p0[0];
|
|
200
|
-
const dy = p1[1] - p0[1];
|
|
201
|
-
l += Math.sqrt(dx ** 2 + dy ** 2);
|
|
202
|
-
p0 = p1;
|
|
203
|
-
return [offset > 0 ? offset - l : l, p1[2] || 0];
|
|
204
|
-
});
|
|
205
|
-
return projected;
|
|
206
|
-
}
|