@webviz/subsurface-viewer 1.17.8 → 1.18.2

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.
Files changed (143) hide show
  1. package/dist/DashSubsurfaceViewer.js +2 -13
  2. package/dist/DashSubsurfaceViewer.js.map +1 -1
  3. package/dist/SubsurfaceViewer.js +10 -16
  4. package/dist/SubsurfaceViewer.js.map +1 -1
  5. package/dist/components/ColorLegend.js +3 -4
  6. package/dist/components/ColorLegend.js.map +1 -1
  7. package/dist/components/ColorLegends.js +6 -1
  8. package/dist/components/ColorLegends.js.map +1 -1
  9. package/dist/components/DistanceScale.js +5 -2
  10. package/dist/components/DistanceScale.js.map +1 -1
  11. package/dist/components/InfoCard.js +9 -13
  12. package/dist/components/InfoCard.js.map +1 -1
  13. package/dist/components/Map.d.ts +15 -1
  14. package/dist/components/Map.js +182 -151
  15. package/dist/components/Map.js.map +1 -1
  16. package/dist/components/settings/DrawModeSelector.js +2 -2
  17. package/dist/components/settings/DrawModeSelector.js.map +1 -1
  18. package/dist/components/settings/Settings.js +1 -1
  19. package/dist/components/settings/Settings.js.map +1 -1
  20. package/dist/extensions/side-projection-extension.js +2 -2
  21. package/dist/extensions/side-projection-extension.js.map +1 -1
  22. package/dist/hooks/useMultiViewCursorTracking/useMultiViewCursorTracking.js +11 -6
  23. package/dist/hooks/useMultiViewCursorTracking/useMultiViewCursorTracking.js.map +1 -1
  24. package/dist/hooks/useMultiViewPicking/MultiViewPickingInfoAssembler.js +83 -97
  25. package/dist/hooks/useMultiViewPicking/MultiViewPickingInfoAssembler.js.map +1 -1
  26. package/dist/hooks/useMultiViewPicking/useMultiViewPicking.js +4 -1
  27. package/dist/hooks/useMultiViewPicking/useMultiViewPicking.js.map +1 -1
  28. package/dist/layers/BoxSelectionLayer/boxSelectionLayer.js +2 -3
  29. package/dist/layers/BoxSelectionLayer/boxSelectionLayer.js.map +1 -1
  30. package/dist/layers/axes/axesLayer.js +11 -4
  31. package/dist/layers/axes/axesLayer.js.map +1 -1
  32. package/dist/layers/axes/boxLayer.js +17 -10
  33. package/dist/layers/axes/boxLayer.js.map +1 -1
  34. package/dist/layers/axes2d/axes2DLayer.js +56 -32
  35. package/dist/layers/axes2d/axes2DLayer.js.map +1 -1
  36. package/dist/layers/colormap/colormapLayer.js +33 -34
  37. package/dist/layers/colormap/colormapLayer.js.map +1 -1
  38. package/dist/layers/crosshair/crosshairLayer.js +2 -2
  39. package/dist/layers/crosshair/crosshairLayer.js.map +1 -1
  40. package/dist/layers/drawing/drawingLayer.js +6 -4
  41. package/dist/layers/drawing/drawingLayer.js.map +1 -1
  42. package/dist/layers/fault_polygons/faultPolygonsLayer.js +5 -6
  43. package/dist/layers/fault_polygons/faultPolygonsLayer.js.map +1 -1
  44. package/dist/layers/gpglLayers/gpglValueMappedSurfaceLayer.js +194 -168
  45. package/dist/layers/gpglLayers/gpglValueMappedSurfaceLayer.js.map +1 -1
  46. package/dist/layers/grid3d/grid3dLayer.js +46 -53
  47. package/dist/layers/grid3d/grid3dLayer.js.map +1 -1
  48. package/dist/layers/grid3d/privateGrid3dLayer.js +73 -48
  49. package/dist/layers/grid3d/privateGrid3dLayer.js.map +1 -1
  50. package/dist/layers/grid3d/webworker.js +17 -6
  51. package/dist/layers/grid3d/webworker.js.map +1 -1
  52. package/dist/layers/hillshading2d/hillshading2dLayer.js +15 -9
  53. package/dist/layers/hillshading2d/hillshading2dLayer.js.map +1 -1
  54. package/dist/layers/index.d.ts +2 -0
  55. package/dist/layers/index.js +1 -0
  56. package/dist/layers/index.js.map +1 -1
  57. package/dist/layers/map/mapLayer.js +49 -50
  58. package/dist/layers/map/mapLayer.js.map +1 -1
  59. package/dist/layers/map/privateMapLayer.js +52 -28
  60. package/dist/layers/map/privateMapLayer.js.map +1 -1
  61. package/dist/layers/map/webworker.js +1 -1
  62. package/dist/layers/map/webworker.js.map +1 -1
  63. package/dist/layers/northarrow/northArrow3DLayer.js +17 -10
  64. package/dist/layers/northarrow/northArrow3DLayer.js.map +1 -1
  65. package/dist/layers/piechart/pieChartLayer.js +26 -21
  66. package/dist/layers/piechart/pieChartLayer.js.map +1 -1
  67. package/dist/layers/points/pointsLayer.js +5 -3
  68. package/dist/layers/points/pointsLayer.js.map +1 -1
  69. package/dist/layers/points/privatePointsLayer.js +1 -2
  70. package/dist/layers/points/privatePointsLayer.js.map +1 -1
  71. package/dist/layers/polyline_group/polylineGroupLayer.d.ts +239 -0
  72. package/dist/layers/polyline_group/polylineGroupLayer.js +674 -0
  73. package/dist/layers/polyline_group/polylineGroupLayer.js.map +1 -0
  74. package/dist/layers/polylines/polylinesLayer.d.ts +4 -0
  75. package/dist/layers/polylines/polylinesLayer.js +9 -3
  76. package/dist/layers/polylines/polylinesLayer.js.map +1 -1
  77. package/dist/layers/polylines/privatePolylinesLayer.js +1 -2
  78. package/dist/layers/polylines/privatePolylinesLayer.js.map +1 -1
  79. package/dist/layers/seismic/seismicLayer.js +28 -23
  80. package/dist/layers/seismic/seismicLayer.js.map +1 -1
  81. package/dist/layers/shader_modules/phong-lighting/phong-material.js +2 -2
  82. package/dist/layers/shader_modules/phong-lighting/phong-material.js.map +1 -1
  83. package/dist/layers/shader_modules/test-precision/precisionForTests-shaders-glsl.js +4 -3
  84. package/dist/layers/shader_modules/test-precision/precisionForTests-shaders-glsl.js.map +1 -1
  85. package/dist/layers/triangle/privateTriangleLayer.js +66 -40
  86. package/dist/layers/triangle/privateTriangleLayer.js.map +1 -1
  87. package/dist/layers/triangle/triangleLayer.js +66 -66
  88. package/dist/layers/triangle/triangleLayer.js.map +1 -1
  89. package/dist/layers/utils/colormapTools.js +16 -3
  90. package/dist/layers/utils/colormapTools.js.map +1 -1
  91. package/dist/layers/utils/layerTools.js +5 -7
  92. package/dist/layers/utils/layerTools.js.map +1 -1
  93. package/dist/layers/well_markers/wellMarkersLayer.js +41 -16
  94. package/dist/layers/well_markers/wellMarkersLayer.js.map +1 -1
  95. package/dist/layers/wells/layers/dashedSectionsPathLayer.js +60 -31
  96. package/dist/layers/wells/layers/dashedSectionsPathLayer.js.map +1 -1
  97. package/dist/layers/wells/layers/flatWellMarkersLayer.js +79 -33
  98. package/dist/layers/wells/layers/flatWellMarkersLayer.js.map +1 -1
  99. package/dist/layers/wells/layers/logCurveLayer.js +80 -69
  100. package/dist/layers/wells/layers/logCurveLayer.js.map +1 -1
  101. package/dist/layers/wells/layers/mergedTextLayer.js +18 -12
  102. package/dist/layers/wells/layers/mergedTextLayer.js.map +1 -1
  103. package/dist/layers/wells/layers/wellLabelLayer.js +20 -13
  104. package/dist/layers/wells/layers/wellLabelLayer.js.map +1 -1
  105. package/dist/layers/wells/utils/abscissaTransform.js +10 -4
  106. package/dist/layers/wells/utils/abscissaTransform.js.map +1 -1
  107. package/dist/layers/wells/utils/features.js +2 -4
  108. package/dist/layers/wells/utils/features.js.map +1 -1
  109. package/dist/layers/wells/utils/log.js +11 -11
  110. package/dist/layers/wells/utils/log.js.map +1 -1
  111. package/dist/layers/wells/utils/readout.js +2 -4
  112. package/dist/layers/wells/utils/readout.js.map +1 -1
  113. package/dist/layers/wells/utils/spline.js +19 -25
  114. package/dist/layers/wells/utils/spline.js.map +1 -1
  115. package/dist/layers/wells/utils/trajectory.js +28 -22
  116. package/dist/layers/wells/utils/trajectory.js.map +1 -1
  117. package/dist/layers/wells/utils/wells.js +3 -4
  118. package/dist/layers/wells/utils/wells.js.map +1 -1
  119. package/dist/layers/wells/wellsLayer.js +232 -138
  120. package/dist/layers/wells/wellsLayer.js.map +1 -1
  121. package/dist/utils/BoundingBox2D.js +2 -2
  122. package/dist/utils/BoundingBox2D.js.map +1 -1
  123. package/dist/utils/BoundingBox3D.js +2 -2
  124. package/dist/utils/BoundingBox3D.js.map +1 -1
  125. package/dist/utils/Color.js +2 -3
  126. package/dist/utils/Color.js.map +1 -1
  127. package/dist/utils/camera.js +3 -5
  128. package/dist/utils/camera.js.map +1 -1
  129. package/dist/utils/configuration.d.ts +5 -5
  130. package/dist/utils/configuration.js +7 -2
  131. package/dist/utils/configuration.js.map +1 -1
  132. package/dist/utils/event.js +7 -7
  133. package/dist/utils/event.js.map +1 -1
  134. package/dist/utils/serialize.js +52 -68
  135. package/dist/utils/serialize.js.map +1 -1
  136. package/dist/utils/specExtractor.js +1 -1
  137. package/dist/utils/specExtractor.js.map +1 -1
  138. package/dist/views/sectionView.js +1 -1
  139. package/dist/views/sectionView.js.map +1 -1
  140. package/dist/views/viewport.d.ts +1 -0
  141. package/dist/views/viewport.js +10 -4
  142. package/dist/views/viewport.js.map +1 -1
  143. package/package.json +15 -16
@@ -0,0 +1,674 @@
1
+ import { CompositeLayer } from "@deck.gl/core";
2
+ import { DataFilterExtension, PathStyleExtension } from "@deck.gl/extensions";
3
+ import { PathLayer } from "@deck.gl/layers";
4
+ import { SectionViewport } from "../../viewports";
5
+ import { createPropertyData } from "../utils/layerTools";
6
+ import _ from "lodash";
7
+ const DEFAULT_GROUP_STYLE = {
8
+ color: [0, 128, 255, 255],
9
+ width: 2,
10
+ dashArray: [0, 0],
11
+ };
12
+ // ---------------------------------------------------------------------------
13
+ // Default props
14
+ // ---------------------------------------------------------------------------
15
+ const defaultProps = {
16
+ "@@type": "PolylineGroupLayer",
17
+ name: "PolylineGroupLayer",
18
+ id: "polyline-group-layer",
19
+ pickable: false,
20
+ visible: true,
21
+ depthTest: true,
22
+ ZIncreasingDownwards: true,
23
+ defaultGroupStyle: DEFAULT_GROUP_STYLE,
24
+ widthUnits: "meters",
25
+ widthScale: 1,
26
+ widthMinPixels: 0,
27
+ widthMaxPixels: Number.MAX_SAFE_INTEGER,
28
+ jointRounded: false,
29
+ capRounded: false,
30
+ miterLimit: 4,
31
+ billboard: true,
32
+ getGroupPolylines: (g) => g.polylines,
33
+ getPolylinePath: (p) => p.path,
34
+ };
35
+ // ---------------------------------------------------------------------------
36
+ // Resolution helpers
37
+ // ---------------------------------------------------------------------------
38
+ function resolveColor(polyline, group, props) {
39
+ const fromPolylineAccessor = props.getPolylineColor?.(polyline, group);
40
+ if (fromPolylineAccessor != null)
41
+ return fromPolylineAccessor;
42
+ if (polyline.color != null)
43
+ return polyline.color;
44
+ const fromGroupAccessor = props.getGroupColor?.(group);
45
+ if (fromGroupAccessor != null)
46
+ return fromGroupAccessor;
47
+ if (group.color != null)
48
+ return group.color;
49
+ return props.defaultGroupStyle?.color ?? DEFAULT_GROUP_STYLE.color;
50
+ }
51
+ function resolveWidth(polyline, group, props) {
52
+ const fromPolylineAccessor = props.getPolylineWidth?.(polyline, group);
53
+ if (fromPolylineAccessor != null)
54
+ return fromPolylineAccessor;
55
+ if (polyline.width != null)
56
+ return polyline.width;
57
+ const fromGroupAccessor = props.getGroupWidth?.(group);
58
+ if (fromGroupAccessor != null)
59
+ return fromGroupAccessor;
60
+ if (group.width != null)
61
+ return group.width;
62
+ return props.defaultGroupStyle?.width ?? DEFAULT_GROUP_STYLE.width;
63
+ }
64
+ // ---------------------------------------------------------------------------
65
+ // Flatten
66
+ // ---------------------------------------------------------------------------
67
+ function isBinaryPolylines(p) {
68
+ return !Array.isArray(p) && "positions" in p;
69
+ }
70
+ function resolveDashArray(polyline, group, props) {
71
+ const fromPolylineAccessor = props.getPolylineDashArray?.(polyline, group);
72
+ if (fromPolylineAccessor != null)
73
+ return fromPolylineAccessor;
74
+ if (polyline.dashArray != null)
75
+ return polyline.dashArray;
76
+ const fromGroupAccessor = props.getGroupDashArray?.(group);
77
+ if (fromGroupAccessor != null)
78
+ return fromGroupAccessor;
79
+ if (group.dashArray != null)
80
+ return group.dashArray;
81
+ return props.defaultGroupStyle?.dashArray ?? DEFAULT_GROUP_STYLE.dashArray;
82
+ }
83
+ // ---------------------------------------------------------------------------
84
+ // Segment resolution helpers (used when polyline.path is a PolylineGroup)
85
+ // ---------------------------------------------------------------------------
86
+ // Cascade: accessor(segment) -> segment field -> subGroup field -> parent polyline
87
+ // resolution (which itself cascades through accessor -> field -> outerGroup -> default).
88
+ function resolveSegmentColor(segment, subGroup, parentPolyline, outerGroup, props) {
89
+ const fromAccessor = props.getPolylineColor?.(segment, outerGroup);
90
+ if (fromAccessor != null)
91
+ return fromAccessor;
92
+ if (segment.color != null)
93
+ return segment.color;
94
+ if (subGroup.color != null)
95
+ return subGroup.color;
96
+ return resolveColor(parentPolyline, outerGroup, props);
97
+ }
98
+ function resolveSegmentWidth(segment, subGroup, parentPolyline, outerGroup, props) {
99
+ const fromAccessor = props.getPolylineWidth?.(segment, outerGroup);
100
+ if (fromAccessor != null)
101
+ return fromAccessor;
102
+ if (segment.width != null)
103
+ return segment.width;
104
+ if (subGroup.width != null)
105
+ return subGroup.width;
106
+ return resolveWidth(parentPolyline, outerGroup, props);
107
+ }
108
+ function resolveSegmentDashArray(segment, subGroup, parentPolyline, outerGroup, props) {
109
+ const fromAccessor = props.getPolylineDashArray?.(segment, outerGroup);
110
+ if (fromAccessor != null)
111
+ return fromAccessor;
112
+ if (segment.dashArray != null)
113
+ return segment.dashArray;
114
+ if (subGroup.dashArray != null)
115
+ return subGroup.dashArray;
116
+ return resolveDashArray(parentPolyline, outerGroup, props);
117
+ }
118
+ /**
119
+ * Expands a polyline whose `path` is a {@link PolylineGroup} (i.e. a
120
+ * discontinuous polyline made of disjoint segments) into one {@link FlatEntry}
121
+ * per segment. Returns an empty array and emits a warning if the sub-group
122
+ * contains {@link BinaryPolylines}, which are not supported at the segment level.
123
+ */
124
+ function flattenSubGroupPolyline(polyline, subGroup, group, getPath, props) {
125
+ const segPolylines = subGroup.polylines;
126
+ if (isBinaryPolylines(segPolylines)) {
127
+ console.warn("PolylineGroupLayer: BinaryPolylines inside a sub-group path is not supported. Skipping.");
128
+ return [];
129
+ }
130
+ return segPolylines.flatMap((segment) => {
131
+ if (!Array.isArray(segment.path)) {
132
+ console.warn("PolylineGroupLayer: nested PolylineGroup paths inside segment polylines are not supported. Skipping segment.");
133
+ return [];
134
+ }
135
+ return [
136
+ {
137
+ path: getPath(segment, group),
138
+ color: resolveSegmentColor(segment, subGroup, polyline, group, props),
139
+ width: resolveSegmentWidth(segment, subGroup, polyline, group, props),
140
+ dashArray: resolveSegmentDashArray(segment, subGroup, polyline, group, props),
141
+ _polyline: polyline, // root polyline — for picking & hiddenPolylines
142
+ _group: group,
143
+ },
144
+ ];
145
+ });
146
+ }
147
+ /**
148
+ * Allocates combined typed-array buffers and fills them from all raw binary
149
+ * groups. Positions and indices are concatenated; color/width are replicated
150
+ * per vertex so the GPU can read them without per-vertex JS work.
151
+ *
152
+ * @remarks * `polylines` is a sanitized copy of group.polylines with invalid
153
+ * colors/widths buffers stripped out; do not read from group.polylines directly.
154
+ */
155
+ function buildBinaryData(binaryRaw, totalVerts, totalPaths, ZIncreasingDownwards, props) {
156
+ const positions = new Float32Array(totalVerts * 3);
157
+ const colors = new Uint8Array(totalVerts * 4);
158
+ const widths = new Float32Array(totalVerts);
159
+ const vertexGroupIndex = new Uint32Array(totalVerts);
160
+ const startIndices = new Uint32Array(totalPaths + 1);
161
+ const pathGroup = new Array(totalPaths);
162
+ const groups = binaryRaw.map((b) => b.group);
163
+ let vOffset = 0;
164
+ let pOffset = 0;
165
+ for (let gIdx = 0; gIdx < binaryRaw.length; gIdx++) {
166
+ const { group, polylines } = binaryRaw[gIdx];
167
+ const src = polylines.positions;
168
+ // Ensure positions buffer length is a multiple of 3; if not, ignore
169
+ // trailing vertices.
170
+ if (src.length % 3 !== 0) {
171
+ console.warn(`PolylineGroupLayer: BinaryPolylines group (id=` +
172
+ `${group.id ?? "unknown"}) has a positions buffer whose` +
173
+ `length (${src.length}) is not a multiple of 3. Trailing ` +
174
+ `incomplete vertex will be ignored.`);
175
+ }
176
+ const srcVerts = Math.floor(src.length / 3);
177
+ // Copy positions (optionally flipping Z)
178
+ const base = vOffset * 3;
179
+ const srcLen = srcVerts * 3;
180
+ if (ZIncreasingDownwards) {
181
+ for (let i = 0; i < srcLen; i += 3) {
182
+ positions[base + i] = src[i];
183
+ positions[base + i + 1] = src[i + 1];
184
+ positions[base + i + 2] = -src[i + 2];
185
+ }
186
+ }
187
+ else {
188
+ // Slice to srcLen to exclude any trailing incomplete vertex.
189
+ positions.set(srcLen < src.length ? src.subarray(0, srcLen) : src, base);
190
+ }
191
+ if (polylines.colors) {
192
+ colors.set(polylines.colors, vOffset * 4);
193
+ }
194
+ else {
195
+ const color = props.getGroupColor?.(group) ??
196
+ group.color ??
197
+ props.defaultGroupStyle?.color ?? [0, 128, 255, 255];
198
+ // Flood-fill the group color across all vertices efficiently:
199
+ // 1. Write the first RGBA (4 × Uint8) into the combined Uint8Array
200
+ // at byte offset vOffset*4.
201
+ // 2. Reinterpret the same ArrayBuffer as Uint32 (1 element = 4 bytes
202
+ // = one RGBA pixel). Index vOffset in the Uint32 view therefore
203
+ // aliases the four bytes we just wrote.
204
+ // 3. Use TypedArray.fill to copy that single 32-bit value into every
205
+ // remaining vertex slot in one call — no per-channel bit-shifting.
206
+ colors.set([color[0], color[1], color[2], color[3] ?? 255], vOffset * 4);
207
+ new Uint32Array(colors.buffer).fill(new Uint32Array(colors.buffer)[vOffset], vOffset + 1, vOffset + srcVerts);
208
+ }
209
+ if (polylines.widths) {
210
+ widths.set(polylines.widths, vOffset);
211
+ }
212
+ else {
213
+ widths.fill(props.getGroupWidth?.(group) ??
214
+ group.width ??
215
+ props.defaultGroupStyle?.width ??
216
+ 2, vOffset, vOffset + srcVerts);
217
+ }
218
+ for (let v = 0; v < srcVerts; v++) {
219
+ vertexGroupIndex[vOffset + v] = gIdx;
220
+ }
221
+ // Offset and copy startIndices into the combined buffer.
222
+ const srcIdx = polylines.startIndices;
223
+ for (let p = 0; p < srcIdx.length; p++) {
224
+ startIndices[pOffset + p] = srcIdx[p] + vOffset;
225
+ pathGroup[pOffset + p] = group;
226
+ }
227
+ vOffset += srcVerts;
228
+ pOffset += srcIdx.length;
229
+ }
230
+ startIndices[totalPaths] = totalVerts; // terminal entry
231
+ return {
232
+ positions,
233
+ startIndices,
234
+ colors,
235
+ widths,
236
+ pathGroup,
237
+ vertexGroupIndex,
238
+ groups,
239
+ };
240
+ }
241
+ /**
242
+ * Builds the per-vertex GPU filter buffer for the binary sub-layer.
243
+ * Each vertex gets 1.0 if its group is visible, 0.0 if it is hidden.
244
+ * This is a plain typed-array allocation (O(vertices)); separated so it can
245
+ * be re-run cheaply when only `hiddenGroups` changes, without rebuilding the
246
+ * full `BinaryData`.
247
+ */
248
+ function buildFilterValues(binaryData, hiddenGroups) {
249
+ const filterValues = new Float32Array(binaryData.vertexGroupIndex.length);
250
+ for (let i = 0; i < filterValues.length; i++) {
251
+ const g = binaryData.groups[binaryData.vertexGroupIndex[i]];
252
+ filterValues[i] = g.id != null && hiddenGroups?.has(g.id) ? 0 : 1;
253
+ }
254
+ return filterValues;
255
+ }
256
+ /**
257
+ * Assembles the `data` object passed to the binary PathLayer sub-layer.
258
+ * Thin wrapper around the cached typed arrays; cheap to call, but creating a
259
+ * new object reference signals deck.gl to re-examine attribute buffers.
260
+ */
261
+ function buildBinaryLayerData(binaryData, filterValues) {
262
+ return {
263
+ length: binaryData.startIndices.length - 1,
264
+ startIndices: binaryData.startIndices,
265
+ attributes: {
266
+ getPath: { value: binaryData.positions, size: 3 },
267
+ getFilterValue: { value: filterValues, size: 1 },
268
+ getColor: { value: binaryData.colors, size: 4, normalized: true },
269
+ getWidth: { value: binaryData.widths, size: 1 },
270
+ },
271
+ };
272
+ }
273
+ function flattenGroupData(data, props) {
274
+ const getPolylines = props.getGroupPolylines ??
275
+ ((g) => g.polylines);
276
+ const getPath = props.getPolylinePath ?? ((p) => p.path);
277
+ const flatData = [];
278
+ const ZIncreasingDownwards = props.ZIncreasingDownwards ?? true;
279
+ // First pass over binary groups: collect groups + sum sizes so we can
280
+ // allocate combined typed arrays once.
281
+ const binaryRaw = [];
282
+ let totalVerts = 0;
283
+ let totalPaths = 0;
284
+ for (const group of data) {
285
+ const polylines = getPolylines(group);
286
+ if (isBinaryPolylines(polylines)) {
287
+ if (group.dashArray != null ||
288
+ props.getGroupDashArray?.(group) != null) {
289
+ console.warn("PolylineGroupLayer: dashArray is not supported on BinaryPolylines groups; ignoring.");
290
+ }
291
+ if (polylines.positions.length % 3 !== 0) {
292
+ console.warn(`PolylineGroupLayer: BinaryPolylines group (id=${group.id ?? "unknown"}) has a positions buffer whose length (${polylines.positions.length}) is not a multiple of 3. Trailing incomplete vertex will be ignored.`);
293
+ }
294
+ const srcVerts = Math.floor(polylines.positions.length / 3);
295
+ let colors = polylines.colors;
296
+ if (colors && colors.length !== srcVerts * 4) {
297
+ console.warn(`PolylineGroupLayer: BinaryPolylines group (id=${group.id ?? "unknown"}) has a colors buffer with wrong length (expected ${srcVerts * 4}, got ${colors.length}). Ignoring colors.`);
298
+ colors = undefined;
299
+ }
300
+ let widths = polylines.widths;
301
+ if (widths && widths.length !== srcVerts) {
302
+ console.warn(`PolylineGroupLayer: BinaryPolylines group (id=${group.id ?? "unknown"}) has a widths buffer with wrong length (expected ${srcVerts}, got ${widths.length}). Ignoring widths.`);
303
+ widths = undefined;
304
+ }
305
+ binaryRaw.push({
306
+ group,
307
+ polylines: { ...polylines, colors, widths },
308
+ });
309
+ totalVerts += srcVerts;
310
+ totalPaths += polylines.startIndices.length;
311
+ }
312
+ else {
313
+ for (const polyline of polylines) {
314
+ if (!Array.isArray(polyline.path)) {
315
+ flatData.push(...flattenSubGroupPolyline(polyline, polyline.path, group, getPath, props));
316
+ }
317
+ else {
318
+ flatData.push({
319
+ path: getPath(polyline, group),
320
+ color: resolveColor(polyline, group, props),
321
+ width: resolveWidth(polyline, group, props),
322
+ dashArray: resolveDashArray(polyline, group, props),
323
+ _polyline: polyline,
324
+ _group: group,
325
+ });
326
+ }
327
+ }
328
+ }
329
+ }
330
+ if (binaryRaw.length === 0) {
331
+ return { flatData, binaryData: null };
332
+ }
333
+ return {
334
+ flatData,
335
+ binaryData: buildBinaryData(binaryRaw, totalVerts, totalPaths, ZIncreasingDownwards, props),
336
+ };
337
+ }
338
+ function buildSectionIndex(path) {
339
+ const cumDist = [0];
340
+ for (let i = 1; i < path.length; i++) {
341
+ const dx = path[i][0] - path[i - 1][0];
342
+ const dy = path[i][1] - path[i - 1][1];
343
+ cumDist.push(cumDist[i - 1] + Math.sqrt(dx * dx + dy * dy));
344
+ }
345
+ return { cumDist, path };
346
+ }
347
+ /** Return the (x, y) world position on the fence at the given cumulative distance. */
348
+ function projectAbscissa(abscissa, idx) {
349
+ const { cumDist, path } = idx;
350
+ if (path.length === 0)
351
+ return [0, 0];
352
+ if (abscissa <= cumDist[0])
353
+ return [path[0][0], path[0][1]];
354
+ const last = cumDist.length - 1;
355
+ if (abscissa >= cumDist[last])
356
+ return [path[last][0], path[last][1]];
357
+ let lo = 0, hi = last;
358
+ while (hi - lo > 1) {
359
+ const mid = (lo + hi) >> 1;
360
+ if (cumDist[mid] <= abscissa)
361
+ lo = mid;
362
+ else
363
+ hi = mid;
364
+ }
365
+ const t = (abscissa - cumDist[lo]) / (cumDist[hi] - cumDist[lo]);
366
+ return [
367
+ path[lo][0] + t * (path[hi][0] - path[lo][0]),
368
+ path[lo][1] + t * (path[hi][1] - path[lo][1]),
369
+ ];
370
+ }
371
+ // ---------------------------------------------------------------------------
372
+ // Layer class
373
+ // ---------------------------------------------------------------------------
374
+ /**
375
+ * A deck.gl {@link CompositeLayer} that renders collections of polylines
376
+ * organised into named groups.
377
+ *
378
+ * **Data formats**
379
+ *
380
+ * Each {@link PolylineGroup} holds one or more polylines. Two formats are
381
+ * supported for `PolylineGroup.polylines`:
382
+ * - `Polyline[]` — per-object format; supports `id`, and per-polyline `color`,
383
+ * `width`, and `dashArray` overrides.
384
+ * - {@link BinaryPolylines} — flat typed-array format; more efficient for
385
+ * large datasets loaded from binary sources. Group-level styling only.
386
+ *
387
+ * **Discontinuous polylines**
388
+ *
389
+ * A `Polyline.path` may be a nested {@link PolylineGroup}, making one logical
390
+ * polyline consist of disjoint segments (e.g. a seismic horizon cut by faults).
391
+ * All segments share the root `Polyline.id` for picking and visibility filtering.
392
+ *
393
+ * **Styling cascade**
394
+ *
395
+ * Color, width, and dash pattern are resolved per-path in this order:
396
+ * polyline accessor → `Polyline` field → group accessor → `PolylineGroup` field
397
+ * → layer default prop.
398
+ *
399
+ * **Section-view projection**
400
+ *
401
+ * When {@link PolylineGroupLayerProps.sectionPath} is provided, path coordinates
402
+ * are interpreted as `[abscissa, depth]`. The layer renders two sub-layers:
403
+ * one in abscissa/depth space for {@link SectionViewport}s, and one with
404
+ * abscissa values projected back to world XY for 3-D viewports.
405
+ *
406
+ * **GPU-side visibility**
407
+ *
408
+ * {@link PolylineGroupLayerProps.hiddenGroups} and
409
+ * {@link PolylineGroupLayerProps.hiddenPolylines} use `DataFilterExtension`.
410
+ * Changing these sets triggers only a GPU attribute update; the flattened
411
+ * data buffer is never rebuilt.
412
+ */
413
+ export class PolylineGroupLayer extends CompositeLayer {
414
+ /** @override Builds the initial flat data buffer and section index from `props.data`. */
415
+ initializeState() {
416
+ const { data, sectionPath, hiddenGroups } = this.props;
417
+ const { flatData, binaryData } = flattenGroupData(data, this.props);
418
+ const binaryLayerData = binaryData
419
+ ? buildBinaryLayerData(binaryData, buildFilterValues(binaryData, hiddenGroups))
420
+ : null;
421
+ this.setState({
422
+ flatData,
423
+ binaryData,
424
+ binaryLayerData,
425
+ sectionIndex: sectionPath ? buildSectionIndex(sectionPath) : null,
426
+ });
427
+ }
428
+ /**
429
+ * @override
430
+ * Rebuilds the flat data buffer when `data` or any accessor/default prop changes.
431
+ * Rebuilds the section index when `sectionPath` changes.
432
+ */
433
+ updateState({ props, oldProps, }) {
434
+ const needsRebuild = props.data !== oldProps.data ||
435
+ props.getGroupColor !== oldProps.getGroupColor ||
436
+ props.getGroupWidth !== oldProps.getGroupWidth ||
437
+ props.getGroupDashArray !== oldProps.getGroupDashArray ||
438
+ props.getPolylineColor !== oldProps.getPolylineColor ||
439
+ props.getPolylineWidth !== oldProps.getPolylineWidth ||
440
+ props.getPolylineDashArray !== oldProps.getPolylineDashArray ||
441
+ props.getGroupPolylines !== oldProps.getGroupPolylines ||
442
+ props.getPolylinePath !== oldProps.getPolylinePath ||
443
+ !_.isEqual(props.defaultGroupStyle, oldProps.defaultGroupStyle) ||
444
+ props.ZIncreasingDownwards !== oldProps.ZIncreasingDownwards;
445
+ if (needsRebuild) {
446
+ const { flatData, binaryData } = flattenGroupData(props.data, props);
447
+ const binaryLayerData = binaryData
448
+ ? buildBinaryLayerData(binaryData, buildFilterValues(binaryData, props.hiddenGroups))
449
+ : null;
450
+ this.setState({ flatData, binaryData, binaryLayerData });
451
+ }
452
+ else if (props.hiddenGroups !== oldProps.hiddenGroups) {
453
+ // Only the per-vertex filter buffer needs rebuilding; the large
454
+ // position/color/width buffers are untouched.
455
+ const binaryData = this.state["binaryData"];
456
+ if (binaryData) {
457
+ this.setState({
458
+ binaryLayerData: buildBinaryLayerData(binaryData, buildFilterValues(binaryData, props.hiddenGroups)),
459
+ });
460
+ }
461
+ }
462
+ if (props.sectionPath !== oldProps.sectionPath) {
463
+ this.setState({
464
+ sectionIndex: props.sectionPath
465
+ ? buildSectionIndex(props.sectionPath)
466
+ : null,
467
+ });
468
+ }
469
+ }
470
+ /**
471
+ * @override
472
+ * Routes the `paths-section` sub-layer to {@link SectionViewport}s and
473
+ * the `paths-3d` sub-layer to all other viewports.
474
+ * Only active when `sectionPath` is set; otherwise the single `paths` sub-layer
475
+ * is always visible.
476
+ */
477
+ filterSubLayer({ layer, viewport }) {
478
+ const isSV = viewport.constructor === SectionViewport;
479
+ if (layer.id.endsWith("-paths-section"))
480
+ return isSV;
481
+ if (layer.id.endsWith("-paths-3d"))
482
+ return !isSV;
483
+ return true;
484
+ }
485
+ /**
486
+ * @override
487
+ * Returns one or more `PathLayer` sub-layers.
488
+ * - Without `sectionPath`: a single `paths` sub-layer for non-binary groups,
489
+ * plus a single `paths-binary` sub-layer that merges all binary groups into
490
+ * combined typed-array buffers and passes them straight to the GPU.
491
+ * - With `sectionPath`: a `paths-section` sub-layer (abscissa/depth space)
492
+ * and a `paths-3d` sub-layer (world XY space), routed by {@link filterSubLayer}.
493
+ * Binary groups are not supported in section mode and are skipped with a warning.
494
+ */
495
+ renderLayers() {
496
+ const flatData = this.state["flatData"];
497
+ const binaryData = this.state["binaryData"];
498
+ const sectionIndex = this.state["sectionIndex"];
499
+ const { widthUnits, widthScale, widthMinPixels, widthMaxPixels, jointRounded, capRounded, miterLimit, billboard, pickable, depthTest, ZIncreasingDownwards, hiddenGroups, hiddenPolylines, highPrecisionDash, } = this.props;
500
+ // Shared props for all sub-layers
501
+ const sharedProps = {
502
+ data: flatData,
503
+ pickable,
504
+ billboard,
505
+ widthUnits,
506
+ widthScale,
507
+ widthMinPixels,
508
+ widthMaxPixels,
509
+ jointRounded,
510
+ capRounded,
511
+ miterLimit,
512
+ parameters: { depthTest },
513
+ extensions: [
514
+ new DataFilterExtension({ filterSize: 1 }),
515
+ new PathStyleExtension({
516
+ dash: true,
517
+ highPrecisionDash: highPrecisionDash ?? false,
518
+ }),
519
+ ],
520
+ getFilterValue: (d) => {
521
+ if (d._group.id != null && hiddenGroups?.has(d._group.id))
522
+ return 0;
523
+ if (d._polyline?.id != null &&
524
+ hiddenPolylines?.has(d._polyline.id))
525
+ return 0;
526
+ return 1;
527
+ },
528
+ filterRange: [1, 1],
529
+ getColor: (d) => d.color,
530
+ getWidth: (d) => d.width,
531
+ getDashArray: (d) => d.dashArray,
532
+ };
533
+ const updateTriggers = {
534
+ getFilterValue: [hiddenGroups, hiddenPolylines],
535
+ getColor: [flatData],
536
+ getWidth: [flatData],
537
+ getDashArray: [flatData],
538
+ getPath: [ZIncreasingDownwards],
539
+ };
540
+ const layers = [];
541
+ if (sectionIndex) {
542
+ if (binaryData) {
543
+ console.warn("PolylineGroupLayer: BinaryPolylines are not supported when sectionPath is set; skipping binary groups.");
544
+ }
545
+ // Two separate sub-layers — one per coordinate system — so each has
546
+ // its own GPU attribute buffer. filterSubLayer() routes each to the
547
+ // appropriate viewport type (SectionViewport vs. 3D).
548
+ const sectionUpdateTriggers = {
549
+ ...updateTriggers,
550
+ getPath: [...updateTriggers.getPath, sectionIndex],
551
+ };
552
+ layers.push(new PathLayer(this.getSubLayerProps({
553
+ ...sharedProps,
554
+ id: "paths-section",
555
+ getPath: (d) => d.path.map((pt) => {
556
+ const z = ZIncreasingDownwards ? -pt[1] : pt[1];
557
+ return [pt[0], z, 0];
558
+ }),
559
+ updateTriggers: sectionUpdateTriggers,
560
+ })), new PathLayer(this.getSubLayerProps({
561
+ ...sharedProps,
562
+ id: "paths-3d",
563
+ getPath: (d) => d.path.map((pt) => {
564
+ const z = ZIncreasingDownwards ? -pt[1] : pt[1];
565
+ const [wx, wy] = projectAbscissa(pt[0], sectionIndex);
566
+ return [wx, wy, z];
567
+ }),
568
+ updateTriggers: sectionUpdateTriggers,
569
+ })));
570
+ return layers;
571
+ }
572
+ if (flatData.length > 0) {
573
+ layers.push(new PathLayer(this.getSubLayerProps({
574
+ ...sharedProps,
575
+ id: "paths",
576
+ getPath: (d) => {
577
+ if (!ZIncreasingDownwards)
578
+ return d.path;
579
+ return d.path.map(([x, y, z]) => [x, y, -(z ?? 0)]);
580
+ },
581
+ updateTriggers,
582
+ })));
583
+ }
584
+ const binaryLayerData = this.state["binaryLayerData"];
585
+ if (binaryLayerData) {
586
+ layers.push(new PathLayer(this.getSubLayerProps({
587
+ id: "paths-binary",
588
+ ...sharedProps,
589
+ extensions: [
590
+ new DataFilterExtension({ filterSize: 1 }),
591
+ ],
592
+ data: binaryLayerData,
593
+ // Experimental deck.gl prop: tells PathLayer the paths
594
+ // are open (not closed rings), skipping the closure
595
+ // check. Safe here since BinaryPolylines are never
596
+ // closed. Re-evaluate if deck.gl removes/renames this.
597
+ _pathType: "open",
598
+ getColor: undefined, // color comes from attribute
599
+ getWidth: undefined, // width comes from attribute
600
+ getFilterValue: undefined, // filter value comes from attribute
601
+ getDashArray: undefined, // dash array is not supported for binary groups
602
+ })));
603
+ }
604
+ return layers;
605
+ }
606
+ /**
607
+ * @override
608
+ * Enriches the pick result with the originating {@link PolylineGroup} (`info.group`),
609
+ * the root {@link Polyline} (`info.object`), and layer properties for display
610
+ * (group name, polyline id, depth at the picked coordinate).
611
+ */
612
+ getPickingInfo({ info }) {
613
+ if (info.index < 0)
614
+ return info;
615
+ // Resolve the source group/polyline. For Polyline[] groups the picked
616
+ // FlatEntry carries them directly. For BinaryPolylines the sub-layer id
617
+ // (`paths-binary`) is used to look up the source group; the polyline
618
+ // is unavailable.
619
+ let pickedGroup;
620
+ let pickedPolyline;
621
+ let pickedSource;
622
+ const entry = info.object;
623
+ if (entry && entry._group) {
624
+ pickedGroup = entry._group;
625
+ pickedPolyline = entry._polyline;
626
+ pickedSource = entry;
627
+ }
628
+ else {
629
+ const sourceId = info.sourceLayer?.id;
630
+ // Robust check: deck.gl may prefix/suffix the sub-layer id.
631
+ if (sourceId && sourceId.indexOf("paths-binary") !== -1) {
632
+ const binaryData = this.state["binaryData"];
633
+ const group = binaryData?.pathGroup[info.index];
634
+ if (group) {
635
+ pickedGroup = group;
636
+ pickedSource = group;
637
+ }
638
+ }
639
+ }
640
+ if (!pickedSource)
641
+ return info;
642
+ const layerProperties = [];
643
+ if (pickedGroup?.name) {
644
+ layerProperties.push(createPropertyData("Group", pickedGroup.name));
645
+ }
646
+ if (pickedPolyline?.id != null) {
647
+ layerProperties.push(createPropertyData("Polyline", String(pickedPolyline.id)));
648
+ }
649
+ const zScale = this.props.modelMatrix ? this.props.modelMatrix[10] : 1;
650
+ // Omit Depth property when the pick originated from a SectionView.
651
+ const viewport = info
652
+ .viewport;
653
+ const isSectionView = viewport?.constructor === SectionViewport;
654
+ if (!isSectionView && typeof info.coordinate?.[2] !== "undefined") {
655
+ const depth = (this.props.ZIncreasingDownwards
656
+ ? -info.coordinate[2]
657
+ : info.coordinate[2]) / Math.max(0.001, zScale);
658
+ layerProperties.push(createPropertyData("Depth", depth));
659
+ }
660
+ return {
661
+ ...info,
662
+ // Expose the original polyline (when available) and group for
663
+ // onHover/onClick handlers. For binary groups `object` falls back
664
+ // to the BinaryGroupEntry so consumers always receive something stable.
665
+ object: pickedPolyline ?? pickedSource,
666
+ // @ts-expect-error -- deck.gl PickingInfo doesn't type extra fields; consumers can cast
667
+ group: pickedGroup,
668
+ properties: layerProperties,
669
+ };
670
+ }
671
+ }
672
+ PolylineGroupLayer.layerName = "PolylineGroupLayer";
673
+ PolylineGroupLayer.defaultProps = defaultProps;
674
+ //# sourceMappingURL=polylineGroupLayer.js.map