@equinor/esv-intersection 3.0.4 → 3.0.7

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 (169) hide show
  1. package/README.md +18 -3
  2. package/dist/components/axis.d.ts +48 -0
  3. package/dist/components/axis.d.ts.map +1 -0
  4. package/dist/components/index.d.ts +2 -0
  5. package/dist/components/index.d.ts.map +1 -0
  6. package/dist/constants.d.ts +1 -0
  7. package/dist/constants.d.ts.map +1 -0
  8. package/dist/control/ExtendedCurveInterpolator.d.ts +59 -0
  9. package/dist/control/ExtendedCurveInterpolator.d.ts.map +1 -0
  10. package/dist/control/IntersectionReferenceSystem.d.ts +97 -0
  11. package/dist/control/IntersectionReferenceSystem.d.ts.map +1 -0
  12. package/dist/control/LayerManager.d.ts +77 -0
  13. package/dist/control/LayerManager.d.ts.map +1 -0
  14. package/dist/control/MainController.d.ts +155 -0
  15. package/dist/control/MainController.d.ts.map +1 -0
  16. package/dist/control/ZoomPanHandler.d.ts +159 -0
  17. package/dist/control/ZoomPanHandler.d.ts.map +1 -0
  18. package/dist/control/index.d.ts +6 -0
  19. package/dist/control/index.d.ts.map +1 -0
  20. package/dist/control/interfaces.d.ts +38 -0
  21. package/dist/control/interfaces.d.ts.map +1 -0
  22. package/dist/control/overlay.d.ts +21 -0
  23. package/dist/control/overlay.d.ts.map +1 -0
  24. package/dist/datautils/colortable.d.ts +2 -0
  25. package/dist/datautils/colortable.d.ts.map +1 -0
  26. package/dist/datautils/findsample.d.ts +3 -0
  27. package/dist/datautils/findsample.d.ts.map +1 -0
  28. package/dist/datautils/index.d.ts +7 -0
  29. package/dist/datautils/index.d.ts.map +1 -0
  30. package/dist/datautils/interfaces.d.ts +64 -0
  31. package/dist/datautils/interfaces.d.ts.map +1 -0
  32. package/dist/datautils/picks.d.ts +75 -0
  33. package/dist/datautils/picks.d.ts.map +1 -0
  34. package/dist/datautils/schematicShapeGenerator.d.ts +60 -0
  35. package/dist/datautils/schematicShapeGenerator.d.ts.map +1 -0
  36. package/dist/datautils/seismicimage.d.ts +46 -0
  37. package/dist/datautils/seismicimage.d.ts.map +1 -0
  38. package/dist/datautils/surfacedata.d.ts +11 -0
  39. package/dist/datautils/surfacedata.d.ts.map +1 -0
  40. package/dist/datautils/trajectory.d.ts +15 -0
  41. package/dist/datautils/trajectory.d.ts.map +1 -0
  42. package/dist/index.cjs +1 -1
  43. package/dist/index.cjs.map +1 -1
  44. package/dist/index.d.ts +1 -0
  45. package/dist/index.d.ts.map +1 -0
  46. package/dist/index.mjs +162 -160
  47. package/dist/index.mjs.map +1 -1
  48. package/dist/index.umd.js +1 -1
  49. package/dist/index.umd.js.map +1 -1
  50. package/dist/interfaces.d.ts +1 -0
  51. package/dist/interfaces.d.ts.map +1 -0
  52. package/dist/layers/CalloutCanvasLayer.d.ts +61 -0
  53. package/dist/layers/CalloutCanvasLayer.d.ts.map +1 -0
  54. package/dist/layers/CustomDisplayObjects/ComplexRope.d.ts +22 -0
  55. package/dist/layers/CustomDisplayObjects/ComplexRope.d.ts.map +1 -0
  56. package/dist/layers/CustomDisplayObjects/ComplexRopeGeometry.d.ts +24 -0
  57. package/dist/layers/CustomDisplayObjects/ComplexRopeGeometry.d.ts.map +1 -0
  58. package/dist/layers/CustomDisplayObjects/FixedWidthSimpleRope.d.ts +21 -0
  59. package/dist/layers/CustomDisplayObjects/FixedWidthSimpleRope.d.ts.map +1 -0
  60. package/dist/layers/CustomDisplayObjects/FixedWidthSimpleRopeGeometry.d.ts +27 -0
  61. package/dist/layers/CustomDisplayObjects/FixedWidthSimpleRopeGeometry.d.ts.map +1 -0
  62. package/dist/layers/CustomDisplayObjects/UniformTextureStretchRope.d.ts +18 -0
  63. package/dist/layers/CustomDisplayObjects/UniformTextureStretchRope.d.ts.map +1 -0
  64. package/dist/layers/CustomDisplayObjects/UniformTextureStretchRopeGeometry.d.ts +25 -0
  65. package/dist/layers/CustomDisplayObjects/UniformTextureStretchRopeGeometry.d.ts.map +1 -0
  66. package/dist/layers/GeomodelCanvasLayer.d.ts +29 -0
  67. package/dist/layers/GeomodelCanvasLayer.d.ts.map +1 -0
  68. package/dist/layers/GeomodelLabelsLayer.d.ts +50 -0
  69. package/dist/layers/GeomodelLabelsLayer.d.ts.map +1 -0
  70. package/dist/layers/GeomodelLayerV2.d.ts +13 -0
  71. package/dist/layers/GeomodelLayerV2.d.ts.map +1 -0
  72. package/dist/layers/GridLayer.d.ts +30 -0
  73. package/dist/layers/GridLayer.d.ts.map +1 -0
  74. package/dist/layers/ImageCanvasLayer.d.ts +21 -0
  75. package/dist/layers/ImageCanvasLayer.d.ts.map +1 -0
  76. package/dist/layers/ReferenceLineLayer.d.ts +30 -0
  77. package/dist/layers/ReferenceLineLayer.d.ts.map +1 -0
  78. package/dist/layers/SchematicLayer.d.ts +114 -0
  79. package/dist/layers/SchematicLayer.d.ts.map +1 -0
  80. package/dist/layers/SeismicCanvasLayer.d.ts +19 -0
  81. package/dist/layers/SeismicCanvasLayer.d.ts.map +1 -0
  82. package/dist/layers/WellborePathLayer.d.ts +18 -0
  83. package/dist/layers/WellborePathLayer.d.ts.map +1 -0
  84. package/dist/layers/base/CanvasLayer.d.ts +20 -0
  85. package/dist/layers/base/CanvasLayer.d.ts.map +1 -0
  86. package/dist/layers/base/HTMLLayer.d.ts +14 -0
  87. package/dist/layers/base/HTMLLayer.d.ts.map +1 -0
  88. package/dist/layers/base/Layer.d.ts +70 -0
  89. package/dist/layers/base/Layer.d.ts.map +1 -0
  90. package/dist/layers/base/PixiLayer.d.ts +33 -0
  91. package/dist/layers/base/PixiLayer.d.ts.map +1 -0
  92. package/dist/layers/base/SVGLayer.d.ts +14 -0
  93. package/dist/layers/base/SVGLayer.d.ts.map +1 -0
  94. package/dist/layers/base/index.d.ts +6 -0
  95. package/dist/layers/base/index.d.ts.map +1 -0
  96. package/dist/layers/index.d.ts +17 -0
  97. package/dist/layers/index.d.ts.map +1 -0
  98. package/dist/layers/schematicInterfaces.d.ts +210 -0
  99. package/dist/layers/schematicInterfaces.d.ts.map +1 -0
  100. package/dist/utils/arc-length.d.ts +24 -0
  101. package/dist/utils/arc-length.d.ts.map +1 -0
  102. package/dist/utils/binary-search.d.ts +9 -0
  103. package/dist/utils/binary-search.d.ts.map +1 -0
  104. package/dist/utils/color.d.ts +6 -0
  105. package/dist/utils/color.d.ts.map +1 -0
  106. package/dist/utils/index.d.ts +2 -0
  107. package/dist/utils/index.d.ts.map +1 -0
  108. package/dist/utils/root-finder.d.ts +35 -0
  109. package/dist/utils/root-finder.d.ts.map +1 -0
  110. package/dist/utils/text.d.ts +15 -0
  111. package/dist/utils/text.d.ts.map +1 -0
  112. package/dist/utils/vectorUtils.d.ts +16 -0
  113. package/dist/utils/vectorUtils.d.ts.map +1 -0
  114. package/dist/vendor/pixi-dashed-line/index.d.ts +57 -0
  115. package/dist/vendor/pixi-dashed-line/index.d.ts.map +1 -0
  116. package/package.json +29 -21
  117. package/src/.eslintrc.json +5 -0
  118. package/src/components/axis.ts +247 -0
  119. package/src/components/index.ts +1 -0
  120. package/src/control/ExtendedCurveInterpolator.ts +155 -0
  121. package/src/control/IntersectionReferenceSystem.ts +391 -0
  122. package/src/control/LayerManager.ts +294 -0
  123. package/src/control/MainController.ts +296 -0
  124. package/src/control/ZoomPanHandler.ts +436 -0
  125. package/src/control/index.ts +5 -0
  126. package/src/control/interfaces.ts +42 -0
  127. package/src/control/overlay.ts +118 -0
  128. package/src/datautils/colortable.ts +14 -0
  129. package/src/datautils/findsample.ts +72 -0
  130. package/src/datautils/index.ts +6 -0
  131. package/src/datautils/interfaces.ts +68 -0
  132. package/src/datautils/picks.ts +328 -0
  133. package/src/datautils/schematicShapeGenerator.ts +1008 -0
  134. package/src/datautils/seismicimage.ts +180 -0
  135. package/src/datautils/surfacedata.ts +317 -0
  136. package/src/datautils/trajectory.ts +206 -0
  137. package/src/layers/CalloutCanvasLayer.ts +338 -0
  138. package/src/layers/CustomDisplayObjects/ComplexRope.ts +44 -0
  139. package/src/layers/CustomDisplayObjects/ComplexRopeGeometry.ts +184 -0
  140. package/src/layers/CustomDisplayObjects/FixedWidthSimpleRope.ts +41 -0
  141. package/src/layers/CustomDisplayObjects/FixedWidthSimpleRopeGeometry.ts +149 -0
  142. package/src/layers/CustomDisplayObjects/UniformTextureStretchRope.ts +39 -0
  143. package/src/layers/CustomDisplayObjects/UniformTextureStretchRopeGeometry.ts +174 -0
  144. package/src/layers/GeomodelCanvasLayer.ts +176 -0
  145. package/src/layers/GeomodelLabelsLayer.ts +615 -0
  146. package/src/layers/GeomodelLayerV2.ts +111 -0
  147. package/src/layers/GridLayer.ts +145 -0
  148. package/src/layers/ImageCanvasLayer.ts +55 -0
  149. package/src/layers/ReferenceLineLayer.ts +185 -0
  150. package/src/layers/SchematicLayer.ts +870 -0
  151. package/src/layers/SeismicCanvasLayer.ts +46 -0
  152. package/src/layers/WellborePathLayer.ts +129 -0
  153. package/src/layers/base/CanvasLayer.ts +102 -0
  154. package/src/layers/base/HTMLLayer.ts +70 -0
  155. package/src/layers/base/Layer.ts +217 -0
  156. package/src/layers/base/PixiLayer.ts +190 -0
  157. package/src/layers/base/SVGLayer.ts +63 -0
  158. package/src/layers/base/index.ts +5 -0
  159. package/src/layers/index.ts +16 -0
  160. package/src/layers/schematicInterfaces.ts +472 -0
  161. package/src/tsconfig.json +9 -0
  162. package/src/utils/arc-length.ts +66 -0
  163. package/src/utils/binary-search.ts +26 -0
  164. package/src/utils/color.ts +22 -0
  165. package/src/utils/index.ts +1 -0
  166. package/src/utils/root-finder.ts +78 -0
  167. package/src/utils/text.ts +88 -0
  168. package/src/utils/vectorUtils.ts +67 -0
  169. package/src/vendor/pixi-dashed-line/index.ts +390 -0
@@ -0,0 +1,338 @@
1
+ import { ScaleLinear } from 'd3-scale';
2
+
3
+ import { CanvasLayer } from './base/CanvasLayer';
4
+ import { OnUpdateEvent, Annotation, OnRescaleEvent, BoundingBox } from '../interfaces';
5
+ import { calcSize, isOverlapping, getOverlapOffset } from '../utils';
6
+ import { LayerOptions } from './base/Layer';
7
+
8
+ const DEFAULT_MIN_FONT_SIZE = 7;
9
+ const DEFAULT_MAX_FONT_SIZE = 11;
10
+ const DEFAULT_FONT_SIZE_FACTOR = 7;
11
+
12
+ const DEFAULT_OFFSET_MIN = 20;
13
+ const DEFAULT_OFFSET_MAX = 120;
14
+ const DEFAULT_OFFSET_FACTOR = 19;
15
+
16
+ const Location = {
17
+ topleft: 'topleft',
18
+ topright: 'topright',
19
+ bottomleft: 'bottomleft',
20
+ bottomright: 'bottomright',
21
+ };
22
+
23
+ export type Point = {
24
+ x: number;
25
+ y: number;
26
+ };
27
+
28
+ export type Callout = {
29
+ title: string;
30
+ label: string;
31
+ color: string;
32
+ pos: Point;
33
+ group: string;
34
+ alignment: string;
35
+ boundingBox: BoundingBox;
36
+ dx: number;
37
+ dy: number;
38
+ };
39
+
40
+ export interface CalloutOptions<T extends Annotation[]> extends LayerOptions<T> {
41
+ minFontSize?: number;
42
+ maxFontSize?: number;
43
+ fontSizeFactor?: number;
44
+ offsetMin?: number;
45
+ offsetMax?: number;
46
+ offsetFactor?: number;
47
+ }
48
+
49
+ export class CalloutCanvasLayer<T extends Annotation[]> extends CanvasLayer<T> {
50
+ rescaleEvent: OnRescaleEvent;
51
+ xRatio: number;
52
+ callouts: Callout[];
53
+ groupFilter: string[] = null;
54
+ minFontSize: number;
55
+ maxFontSize: number;
56
+ fontSizeFactor: number;
57
+ offsetMin: number;
58
+ offsetMax: number;
59
+ offsetFactor: number;
60
+
61
+ constructor(id?: string, options?: CalloutOptions<T>) {
62
+ super(id, options);
63
+ this.minFontSize = options.minFontSize || DEFAULT_MIN_FONT_SIZE;
64
+ this.maxFontSize = options.maxFontSize || DEFAULT_MAX_FONT_SIZE;
65
+ this.fontSizeFactor = options.fontSizeFactor || DEFAULT_FONT_SIZE_FACTOR;
66
+ this.offsetMin = options.offsetMin || DEFAULT_OFFSET_MIN;
67
+ this.offsetMax = options.offsetMax || DEFAULT_OFFSET_MAX;
68
+ this.offsetFactor = options.offsetFactor || DEFAULT_OFFSET_FACTOR;
69
+ }
70
+
71
+ setGroupFilter(filter: string[]): void {
72
+ this.groupFilter = filter;
73
+ this.callouts = undefined;
74
+ this.render();
75
+ }
76
+
77
+ override onUpdate(event: OnUpdateEvent<T>): void {
78
+ super.onUpdate(event);
79
+
80
+ this.callouts = undefined;
81
+
82
+ this.render();
83
+ }
84
+
85
+ override onRescale(event: OnRescaleEvent): void {
86
+ super.onRescale(event);
87
+ const isPanning = this.rescaleEvent && this.rescaleEvent.xRatio === event.xRatio;
88
+ this.rescaleEvent = event;
89
+
90
+ this.render(isPanning);
91
+ }
92
+
93
+ render(isPanning = false): void {
94
+ requestAnimationFrame(() => {
95
+ this.clearCanvas();
96
+
97
+ if (!this.data || !this.rescaleEvent || !this.referenceSystem) {
98
+ return;
99
+ }
100
+
101
+ const { xScale, yScale, xBounds } = this.rescaleEvent;
102
+
103
+ const fontSize = calcSize(this.fontSizeFactor, this.minFontSize, this.maxFontSize, xScale);
104
+
105
+ if (!isPanning || !this.callouts) {
106
+ const { data, ctx, groupFilter } = this;
107
+ const { calculateDisplacementFromBottom } = this.referenceSystem.options;
108
+ const isLeftToRight = calculateDisplacementFromBottom ? xBounds[0] < xBounds[1] : xBounds[0] > xBounds[1];
109
+ const scale = 0;
110
+
111
+ ctx.font = `bold ${fontSize}px arial`;
112
+ const filtered = data.filter((d: Annotation) => !groupFilter || groupFilter.includes(d.group));
113
+ const offset = calcSize(this.offsetFactor, this.offsetMin, this.offsetMax, xScale);
114
+ this.callouts = this.positionCallouts(filtered, isLeftToRight, xScale, yScale, scale, fontSize, offset);
115
+ }
116
+
117
+ this.callouts.forEach((callout) => {
118
+ const { pos, title, color } = callout;
119
+ const x = xScale(pos.x);
120
+ const y = yScale(pos.y);
121
+
122
+ const calloutBB = {
123
+ x,
124
+ y,
125
+ width: callout.boundingBox.width,
126
+ height: fontSize,
127
+ offsetX: callout.dx,
128
+ offsetY: callout.dy,
129
+ };
130
+
131
+ this.renderCallout(title, callout.label, calloutBB, color, callout.alignment);
132
+ });
133
+ });
134
+ }
135
+
136
+ private renderAnnotation = (title: string, label: string, x: number, y: number, fontSize: number, color: string): void => {
137
+ this.renderText(title, x, y - fontSize, fontSize, color, 'arial', 'bold');
138
+ this.renderText(label, x, y, fontSize, color);
139
+ };
140
+
141
+ private renderText(
142
+ title: string,
143
+ x: number,
144
+ y: number,
145
+ fontSize: number,
146
+ color: string,
147
+ font: string = 'arial',
148
+ fontStyle: string = 'normal',
149
+ ): void {
150
+ const { ctx } = this;
151
+ ctx.font = `${fontStyle} ${fontSize}px ${font}`;
152
+ ctx.fillStyle = color;
153
+ ctx.fillText(title, x, y);
154
+ }
155
+
156
+ private renderPoint(x: number, y: number, radius: number = 3): void {
157
+ const { ctx } = this;
158
+ ctx.beginPath();
159
+ ctx.moveTo(x, y);
160
+ ctx.arc(x, y, radius, 0, Math.PI * 2);
161
+ ctx.fill();
162
+ }
163
+
164
+ private renderCallout(title: string, label: string, boundingBox: BoundingBox, color: string, location: string): void {
165
+ const pos = this.getPosition(boundingBox, location);
166
+ const { x, y } = pos;
167
+ const { height, width, x: dotX, y: dotY } = boundingBox;
168
+
169
+ const placeLeft = location === Location.topright || location === Location.bottomright;
170
+ this.renderAnnotation(title, label, x, y, height, color);
171
+ this.renderPoint(dotX, dotY);
172
+ this.renderLine(x, y, width, dotX, dotY, color, placeLeft);
173
+ }
174
+
175
+ private renderLine = (x: number, y: number, width: number, dotX: number, dotY: number, color: string, placeLeft: boolean = true): void => {
176
+ const { ctx } = this;
177
+ const textX = placeLeft ? x : x + width;
178
+ const inverseTextX = placeLeft ? x + width : x;
179
+ const textY = y + 2;
180
+
181
+ ctx.strokeStyle = color;
182
+ ctx.lineWidth = 1;
183
+
184
+ ctx.beginPath();
185
+ ctx.moveTo(dotX, dotY);
186
+ ctx.lineTo(textX, textY);
187
+ ctx.lineTo(inverseTextX, textY);
188
+
189
+ ctx.stroke();
190
+ };
191
+
192
+ private getPosition(boundingBox: BoundingBox, location: string): Point {
193
+ const { x, y, offsetX, offsetY, width } = boundingBox;
194
+ switch (location) {
195
+ case Location.topleft:
196
+ return {
197
+ x: x - width - offsetX,
198
+ y: y - offsetY,
199
+ };
200
+ case Location.topright:
201
+ return {
202
+ x: x + offsetX,
203
+ y: y - offsetY,
204
+ };
205
+ case Location.bottomleft:
206
+ return {
207
+ x: x - width - offsetX,
208
+ y: y + offsetY,
209
+ };
210
+ case Location.bottomright:
211
+ return {
212
+ x: x + offsetX,
213
+ y: y + offsetY,
214
+ };
215
+ default:
216
+ return {
217
+ x,
218
+ y,
219
+ };
220
+ }
221
+ }
222
+
223
+ // Calculates position of a list of annotations
224
+ positionCallouts(
225
+ annotations: Annotation[],
226
+ isLeftToRight: boolean,
227
+ xScale: ScaleLinear<number, number>,
228
+ yScale: ScaleLinear<number, number>,
229
+ _scale: number,
230
+ fontSize: number,
231
+ offset: number = 20,
232
+ ): Callout[] {
233
+ if (annotations.length === 0) {
234
+ return [];
235
+ }
236
+ const alignment = isLeftToRight ? Location.topleft : Location.topright;
237
+
238
+ const nodes = annotations.map((a) => {
239
+ const pos = a.pos ? a.pos : this.referenceSystem.project(a.md);
240
+ return {
241
+ title: a.title,
242
+ label: a.label,
243
+ color: a.color,
244
+ pos: { x: pos[0], y: pos[1] },
245
+ group: a.group,
246
+ alignment,
247
+ boundingBox: this.getAnnotationBoundingBox(a.title, a.label, pos, xScale, yScale, fontSize),
248
+ dx: offset,
249
+ dy: offset,
250
+ };
251
+ });
252
+
253
+ const top = [nodes[nodes.length - 1]];
254
+ const bottom: Callout[] = [];
255
+
256
+ // Initial best effort
257
+ this.chooseTopOrBottomPosition(nodes, bottom, top);
258
+
259
+ // Adjust position for top set
260
+ this.adjustTopPositions(top);
261
+
262
+ // Adjust position for bottom set
263
+ this.adjustBottomPositions(bottom);
264
+
265
+ return nodes;
266
+ }
267
+
268
+ getAnnotationBoundingBox(
269
+ title: string,
270
+ label: string,
271
+ pos: number[],
272
+ xScale: ScaleLinear<number, number>,
273
+ yScale: ScaleLinear<number, number>,
274
+ height: number,
275
+ ): { x: number; y: number; width: number; height: number } {
276
+ const { ctx } = this;
277
+ const ax1 = xScale(pos[0]);
278
+ const ay1 = yScale(pos[1]);
279
+
280
+ const labelWidth = ctx.measureText(label).width;
281
+ const titleWidth = ctx.measureText(title).width;
282
+ const width = Math.max(labelWidth, titleWidth);
283
+
284
+ const bbox = {
285
+ x: ax1,
286
+ y: ay1,
287
+ width,
288
+ height: height * 2 + 4,
289
+ };
290
+ return bbox;
291
+ }
292
+
293
+ chooseTopOrBottomPosition(nodes: Callout[], bottom: Callout[], top: Callout[]): void {
294
+ for (let i = nodes.length - 2; i >= 0; --i) {
295
+ const node = nodes[i];
296
+ const prevNode = top[0];
297
+
298
+ const overlap = isOverlapping(node.boundingBox, prevNode.boundingBox);
299
+ if (overlap) {
300
+ node.alignment = node.alignment === Location.topleft ? Location.bottomright : Location.bottomleft;
301
+ bottom.push(node);
302
+ if (i > 0) {
303
+ top.unshift(nodes[--i]);
304
+ }
305
+ } else {
306
+ top.unshift(node);
307
+ }
308
+ }
309
+ }
310
+
311
+ adjustTopPositions(top: Callout[]): void {
312
+ for (let i = top.length - 2; i >= 0; --i) {
313
+ const currentNode = top[i];
314
+ for (let j = top.length - 1; j > i; --j) {
315
+ const prevNode = top[j];
316
+ const overlap = getOverlapOffset(currentNode.boundingBox, prevNode.boundingBox);
317
+ if (overlap) {
318
+ currentNode.dy += overlap.dy;
319
+ currentNode.boundingBox.y -= overlap.dy;
320
+ }
321
+ }
322
+ }
323
+ }
324
+
325
+ adjustBottomPositions(bottom: Callout[]): void {
326
+ for (let i = bottom.length - 2; i >= 0; --i) {
327
+ const currentNode = bottom[i];
328
+ for (let j = bottom.length - 1; j > i; --j) {
329
+ const prevNode = bottom[j];
330
+ const overlap = getOverlapOffset(prevNode.boundingBox, currentNode.boundingBox);
331
+ if (overlap) {
332
+ currentNode.dy += overlap.dy;
333
+ currentNode.boundingBox.y += overlap.dy;
334
+ }
335
+ }
336
+ }
337
+ }
338
+ }
@@ -0,0 +1,44 @@
1
+ import { Mesh, MeshMaterial, IPoint, Renderer, Texture, WRAP_MODES } from 'pixi.js';
2
+ import { ComplexRopeGeometry } from './ComplexRopeGeometry';
3
+
4
+ export type ComplexRopeSegment = {
5
+ points: IPoint[];
6
+ diameter: number;
7
+ };
8
+
9
+ /**
10
+ * The ComplexRope allows you to draw a texture across several segments of points and then manipulate these points
11
+ */
12
+ export class ComplexRope extends Mesh {
13
+ /**
14
+ * re-calculate vertices by rope segment-points each frame
15
+ * @member {boolean}
16
+ */
17
+ public autoUpdate: boolean;
18
+
19
+ /**
20
+ * @param texture - The texture to use on the rope.
21
+ * @param segments - An array of segments with points and diaeter to construct this rope.
22
+ */
23
+ constructor(texture: Texture, segments: ComplexRopeSegment[]) {
24
+ const ropeGeometry = new ComplexRopeGeometry(segments);
25
+ const meshMaterial = new MeshMaterial(texture);
26
+
27
+ // attempt to set UV wrapping, will fail on non-power of two textures
28
+ texture.baseTexture.wrapMode = WRAP_MODES.REPEAT;
29
+
30
+ super(ropeGeometry, meshMaterial);
31
+
32
+ this.autoUpdate = true;
33
+ }
34
+
35
+ override _render(renderer: Renderer): void {
36
+ const geometry: ComplexRopeGeometry = this.geometry as ComplexRopeGeometry;
37
+
38
+ if (this.autoUpdate) {
39
+ geometry.update();
40
+ }
41
+
42
+ super._render(renderer);
43
+ }
44
+ }
@@ -0,0 +1,184 @@
1
+ import { MeshGeometry } from 'pixi.js';
2
+ import { sum, max } from 'd3-array';
3
+ import { ComplexRopeSegment } from './ComplexRope';
4
+
5
+ /**
6
+ * RopeGeometry allows you to draw a geometry across several several segments of points and then manipulate these points.
7
+ */
8
+ export class ComplexRopeGeometry extends MeshGeometry {
9
+ /** An array of segments with points and diameter that determine the rope. */
10
+ private segments: ComplexRopeSegment[];
11
+
12
+ /**
13
+ * @param segments - An array of segments with points and diameter to construct this rope.
14
+ */
15
+ constructor(segments: ComplexRopeSegment[]) {
16
+ const pointCount = sum(segments, (segment) => segment.points.length);
17
+
18
+ // eslint-disable-next-line no-magic-numbers
19
+ super(new Float32Array(pointCount * 4), new Float32Array(pointCount * 4), new Uint16Array((pointCount - 1) * 6));
20
+
21
+ this.segments = segments;
22
+
23
+ this.build();
24
+ }
25
+
26
+ /**
27
+ * The max width (i.e., thickness) of the rope.
28
+ * @readonly
29
+ */
30
+ get width(): number {
31
+ return max(this.segments, (segment) => segment.diameter);
32
+ }
33
+
34
+ /** Refreshes Rope indices and uvs */
35
+ private build(): void {
36
+ const segments = this.segments;
37
+
38
+ if (!segments) {
39
+ return;
40
+ }
41
+
42
+ const vertexBuffer = this.getBuffer('aVertexPosition');
43
+ const uvBuffer = this.getBuffer('aTextureCoord');
44
+ const indexBuffer = this.getIndex();
45
+
46
+ const pointCount = sum(segments, (segment) => segment.points.length);
47
+
48
+ // if too few points, or texture hasn't got UVs set yet just move on.
49
+ if (pointCount < 1) {
50
+ return;
51
+ }
52
+
53
+ // if the number of points has changed we will need to recreate the arraybuffers
54
+ if (vertexBuffer.data.length / 4 !== pointCount) {
55
+ vertexBuffer.data = new Float32Array(pointCount * 4);
56
+ uvBuffer.data = new Float32Array(pointCount * 4);
57
+ indexBuffer.data = new Uint16Array((pointCount - 1) * 6); // eslint-disable-line no-magic-numbers
58
+ }
59
+
60
+ const uvs = uvBuffer.data;
61
+ const indices = indexBuffer.data;
62
+
63
+ uvs[0] = 0;
64
+ uvs[1] = 0;
65
+ uvs[2] = 0;
66
+ uvs[3] = 1;
67
+
68
+ const segmentCount = segments.length;
69
+ const maxDiameter = max(segments, (segment) => segment.diameter);
70
+
71
+ let amount = 0;
72
+ let uvIndex = 0;
73
+ let indicesIndex = 0;
74
+ let indexCount = 0;
75
+
76
+ for (let i = 0; i < segmentCount; i++) {
77
+ let prev = segments[i].points[0];
78
+ const textureWidth = maxDiameter;
79
+ const radius = segments[i].diameter / maxDiameter / 2;
80
+
81
+ const total = segments[i].points.length; // - 1;
82
+
83
+ for (let j = 0; j < total; j++) {
84
+ // time to do some smart drawing!
85
+
86
+ // calculate pixel distance from previous point
87
+ const dx = prev.x - segments[i].points[j].x;
88
+ const dy = prev.y - segments[i].points[j].y;
89
+ const distance = Math.sqrt(dx * dx + dy * dy);
90
+
91
+ prev = segments[i].points[j];
92
+ amount += distance / textureWidth;
93
+
94
+ uvs[uvIndex] = amount;
95
+ uvs[uvIndex + 1] = 0.5 - radius;
96
+
97
+ uvs[uvIndex + 2] = amount;
98
+ uvs[uvIndex + 3] = 0.5 + radius;
99
+ uvIndex += 4;
100
+ }
101
+
102
+ for (let j = 0; j < total - 1; j++) {
103
+ indices[indexCount++] = indicesIndex;
104
+ indices[indexCount++] = indicesIndex + 1;
105
+ indices[indexCount++] = indicesIndex + 2;
106
+
107
+ indices[indexCount++] = indicesIndex + 2;
108
+ indices[indexCount++] = indicesIndex + 1;
109
+ indices[indexCount++] = indicesIndex + 3;
110
+ indicesIndex += 2;
111
+ }
112
+ indicesIndex += 2;
113
+ }
114
+
115
+ // ensure that the changes are uploaded
116
+ uvBuffer.update();
117
+ indexBuffer.update();
118
+
119
+ this.updateVertices();
120
+ }
121
+
122
+ /** refreshes vertices of Rope mesh */
123
+ public updateVertices(): void {
124
+ const segments = this.segments;
125
+ const pointCount = sum(segments, (segment) => segment.points.length);
126
+
127
+ if (pointCount < 1) {
128
+ return;
129
+ }
130
+
131
+ const segmentCount = segments.length;
132
+ let lastIndex = 0;
133
+ for (let i = 0; i < segmentCount; i++) {
134
+ let lastPoint = segments[i].points[0];
135
+ let nextPoint;
136
+ let perpX = 0;
137
+ let perpY = 0;
138
+
139
+ const vertices = this.buffers[0].data;
140
+ const total = segments[i].points.length;
141
+ let index = 0;
142
+ for (let j = 0; j < total; j++) {
143
+ const point = segments[i].points[j];
144
+ index = lastIndex + j * 4;
145
+
146
+ if (j < segments[i].points.length - 1) {
147
+ nextPoint = segments[i].points[j + 1];
148
+ } else {
149
+ nextPoint = point;
150
+ }
151
+
152
+ perpY = -(nextPoint.x - lastPoint.x);
153
+ perpX = nextPoint.y - lastPoint.y;
154
+
155
+ const perpLength = Math.sqrt(perpX * perpX + perpY * perpY);
156
+ const num = segments[i].diameter / 2;
157
+
158
+ perpX /= perpLength;
159
+ perpY /= perpLength;
160
+
161
+ perpX *= num;
162
+ perpY *= num;
163
+
164
+ vertices[index] = point.x + perpX;
165
+ vertices[index + 1] = point.y + perpY;
166
+ vertices[index + 2] = point.x - perpX;
167
+ vertices[index + 3] = point.y - perpY;
168
+ lastPoint = point;
169
+ }
170
+ lastIndex = index + 4;
171
+ }
172
+
173
+ this.buffers[0].update();
174
+ }
175
+
176
+ public update(): void {
177
+ // TODO: Possible optimiztion to be had here
178
+ // Figure out if/when it is enough to only update verticies with this.updateVertices()
179
+ // See PIXI.SimpleRope.update() for ideas
180
+
181
+ // build() sets indicies and uvs and then calls this.updateVertices()
182
+ this.build();
183
+ }
184
+ }
@@ -0,0 +1,41 @@
1
+ import { IPoint, Mesh, MeshMaterial, Renderer, RopeGeometry, Texture, WRAP_MODES } from 'pixi.js';
2
+ import { FixedWidthSimpleRopeGeometry } from './FixedWidthSimpleRopeGeometry';
3
+
4
+ /**
5
+ * The rope allows you to draw a texture across several points and then manipulate these points
6
+ * Width of rope is given in constructor
7
+ */
8
+ export class FixedWidthSimpleRope extends Mesh {
9
+ /**
10
+ * re-calculate vertices by rope points each frame
11
+ * @member {boolean}
12
+ */
13
+ public autoUpdate: boolean;
14
+
15
+ /**
16
+ * Note: The wrap mode of the texture is set to REPEAT if `textureScale` is positive.
17
+ * @param texture - The texture to use on the rope. (attempt to set UV wrapping, will fail on non-power of two textures)
18
+ * @param points - An array of {@link PIXI.Point} objects to construct this rope.
19
+ * @param width - Width of rope
20
+ */
21
+ constructor(texture: Texture, points: IPoint[], width: number) {
22
+ const ropeGeometry = new FixedWidthSimpleRopeGeometry(points, width);
23
+ const meshMaterial = new MeshMaterial(texture);
24
+
25
+ texture.baseTexture.wrapMode = WRAP_MODES.REPEAT;
26
+
27
+ super(ropeGeometry, meshMaterial);
28
+
29
+ this.autoUpdate = true;
30
+ }
31
+
32
+ override _render(renderer: Renderer): void {
33
+ const geometry: RopeGeometry = this.geometry as RopeGeometry;
34
+
35
+ if (this.autoUpdate) {
36
+ geometry.update();
37
+ }
38
+
39
+ super._render(renderer);
40
+ }
41
+ }