@eturnity/eturnity_maths 9.7.0 → 9.10.0

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 (32) hide show
  1. package/package.json +1 -1
  2. package/src/coords.js +44 -11
  3. package/src/geometry.js +47 -14
  4. package/src/geometryShortDistance.js +442 -0
  5. package/src/index.js +3 -0
  6. package/src/intersectionCheck.js +165 -0
  7. package/src/intersectionPolygon.js +24 -1
  8. package/src/matrix.js +15 -1
  9. package/src/objects/Circle.js +55 -5
  10. package/src/objects/Line.js +530 -264
  11. package/src/objects/Measurement.js +335 -0
  12. package/src/objects/Plane.js +176 -0
  13. package/src/objects/Point.js +16 -7
  14. package/src/objects/Polygon.js +130 -2
  15. package/src/objects/derivedState/nodesEdgesCreation.js +112 -35
  16. package/src/objects/derivedState/updateComputedGeometryPolygon.js +1 -0
  17. package/src/objects/graph/graphCreation.js +5 -5
  18. package/src/objects/hydrate.js +229 -0
  19. package/src/objects/index.js +2 -0
  20. package/src/plane.js +76 -0
  21. package/src/splitMergePolygons.js +8 -8
  22. package/src/tests/Line/isTouchingLine.spec.js +233 -0
  23. package/src/tests/Plane/CoordinateChange.spec.js +32 -0
  24. package/src/tests/coords/toRealityRefFunction.spec.js +25 -0
  25. package/src/tests/geometry/getAngleInDegFrom2DENUVector.spec.js +60 -0
  26. package/src/tests/geometry/projectionOnPlaneFollowingVector.spec.js +215 -0
  27. package/src/tests/geometryShortDistance/areObjectsIntersecting.spec.js +426 -0
  28. package/src/tests/geometryShortDistance/findClosestPoint.spec.js +53 -0
  29. package/src/tests/geometryShortDistance/getShortestSegmentCircleCircle.spec.js +126 -0
  30. package/src/tests/geometryShortDistance/getShortestSegmentLineCircle.spec.js +124 -0
  31. package/src/tests/geometryShortDistance/getShortestSegmentPointLine.spec.js +133 -0
  32. package/src/tests/geometryShortDistance/getShortestSegmentPointPoint.spec.js +115 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eturnity/eturnity_maths",
3
- "version": "9.7.0",
3
+ "version": "9.10.0",
4
4
  "author": "Eturnity Team",
5
5
  "main": "src/index.js",
6
6
  "private": false,
package/src/coords.js CHANGED
@@ -1,13 +1,33 @@
1
- export function toRealityRefFunction(canvasSize, mmPerPx, layoutOffset) {
1
+ import { multiplyMatrices } from './matrix'
2
+ import { Point } from './objects/Point'
3
+ import { defaultPlane } from './objects/Plane'
4
+ export function toRealityRefFunction(
5
+ canvasSize,
6
+ mmPerPx,
7
+ layoutOffset,
8
+ plane = defaultPlane
9
+ ) {
2
10
  return (point) => {
3
- let realityX = (point.x - layoutOffset.x) * mmPerPx
4
- // let realityY = -(point.y - layoutOffset.y - (canvasSize.height*layoutOffset.zoom)/(100 * 2)) * mmPerPx
5
- let realityY = -(point.y - layoutOffset.y) * mmPerPx
6
-
7
- return { x: realityX, y: realityY, z: point.z }
11
+ let xMm = (point.x - layoutOffset.x) * mmPerPx
12
+ let yMm = -(point.y - layoutOffset.y) * mmPerPx
13
+ let zMm = 0
14
+ if (plane) {
15
+ const pointInRealityCoordinates = plane.toRealityCoordinates({
16
+ x: xMm,
17
+ y: yMm,
18
+ z: zMm,
19
+ })
20
+ return pointInRealityCoordinates
21
+ }
22
+ return { x: xMm, y: yMm, z: point.z }
8
23
  }
9
24
  }
10
- export function toCanvasRefFunction(canvasSize, mmPerPx, layoutOffset) {
25
+ export function toCanvasRefFunction(
26
+ canvasSize,
27
+ mmPerPx,
28
+ layoutOffset,
29
+ plane = defaultPlane
30
+ ) {
11
31
  return (point) => {
12
32
  if (!point) {
13
33
  console.error('no point', point)
@@ -16,9 +36,22 @@ export function toCanvasRefFunction(canvasSize, mmPerPx, layoutOffset) {
16
36
  console.error('no canvas Size')
17
37
  return null
18
38
  }
19
- let canvasX = layoutOffset.x + point.x / mmPerPx
20
- let canvasY = layoutOffset.y - point.y / mmPerPx
21
-
22
- return { x: canvasX, y: canvasY, z: point.z }
39
+ let xMm = point.x
40
+ let yMm = point.y
41
+ if (point.z === undefined || isNaN(point.z)) {
42
+ point.z = 0
43
+ }
44
+ if (plane) {
45
+ const pointInPlaneCoordinates = plane.toPlaneCoordinates({
46
+ x: point.x,
47
+ y: point.y,
48
+ z: point.z,
49
+ })
50
+ xMm = pointInPlaneCoordinates.x
51
+ yMm = pointInPlaneCoordinates.y
52
+ }
53
+ let canvasX = layoutOffset.x + xMm / mmPerPx
54
+ let canvasY = layoutOffset.y - yMm / mmPerPx
55
+ return new Point(canvasX, canvasY, 0)
23
56
  }
24
57
  }
package/src/geometry.js CHANGED
@@ -102,8 +102,8 @@ export function getSnapedValue(value, snaps, tolerance) {
102
102
  return closeSnapsItem.value
103
103
  }
104
104
  export function getAngleInDegFrom2DENUVector(v) {
105
- const angle = Math.atan2(v.y, -v.x)
106
- return ((angle * 180) / Math.PI + 90 + 360) % 360
105
+ const angle = Math.atan2(v.x, v.y)
106
+ return ((angle * 180) / Math.PI + 360) % 360
107
107
  }
108
108
  export function getAngleInDegFromCanvasVector(v) {
109
109
  const angle = Math.atan2(v.y, v.x)
@@ -135,8 +135,15 @@ export function getParallelLinePassingByPoint(A, B, C) {
135
135
  const D = new Point(C.x + B.x - A.x, C.y + B.y - A.y, C.z + B.z - A.z)
136
136
  return new Line(C, D, '')
137
137
  }
138
-
139
- export function getDataAboutTwo3DLines(A, u, B, v) {
138
+ export function getDistanceBetweenTwoParallelInfiniteLines(line0, line1) {
139
+ const A = line0.outline[0]
140
+ const u = line0.getDirectionVector()
141
+ const B = line1.outline[0]
142
+ const AB = substractVector(B, A)
143
+ const distance = vectorLength(crossProduct(AB, u))
144
+ return distance
145
+ }
146
+ export function getDataAboutTwo3DLines(A, u, B, v, isInfinite = true) {
140
147
  let w = crossProduct(u, v)
141
148
  let m = [
142
149
  [u.x, v.x, w.x],
@@ -150,12 +157,17 @@ export function getDataAboutTwo3DLines(A, u, B, v) {
150
157
  let AB = substractVector(B, A)
151
158
  let [t1, t2, t3] = multiplyMatrices(mInv, [[AB.x], [AB.y], [AB.z]])
152
159
  //M point on Au
160
+ if (!isInfinite) {
161
+ t1 = Math.max(0, Math.min(t1, 1))
162
+ t2 = Math.max(0, Math.min(t2, -1))
163
+ }
153
164
  let M = addVector(A, multiplyVector(t1, u))
154
165
  //N point on Bv
155
166
  let N = addVector(B, multiplyVector(-t2, v))
156
167
  let distance = get3DDistanceBetweenPoints(M, N)
157
168
  return { m, mInv, M, N, A, B, u, v, w, distance, t1, t2, t3 }
158
169
  }
170
+
159
171
  export function vectorFromAngleInDegCanvas(angle) {
160
172
  return {
161
173
  x: Math.sin((angle * Math.PI) / 180),
@@ -540,7 +552,6 @@ export function isOnBorderOfPolygon(point, vs) {
540
552
  export function isStrictlyInsidePolygon(point, vs) {
541
553
  return isInsidePolygon(point, vs) && !isOnBorderOfPolygon(point, vs)
542
554
  }
543
-
544
555
  export function isInsidePolygon(point, vs) {
545
556
  // ray-casting algorithm based on
546
557
  // https://wrf.ecse.rpi.edu/Research/Short_Notes/pnpoly.html/pnpoly.html
@@ -676,7 +687,7 @@ export function get2PolygonsOutlineFrom3Paths(path1, path2, path3) {
676
687
  return [poly1, poly2]
677
688
  }
678
689
 
679
- export function getPointOnLine(M, A, B) {
690
+ export function getPointOnLine(M, A, B, isIncludedInSegment = false) {
680
691
  function zValueNotDefined(P) {
681
692
  return P.z == undefined || isNaN(P.z)
682
693
  }
@@ -705,9 +716,12 @@ export function getPointOnLine(M, A, B) {
705
716
  P = M
706
717
  } else {
707
718
  // in case of 0 length line
708
- const distanceAP = dot / distanceAB
709
- P.x = A.x + (distanceAP * AB.x) / distanceAB
710
- P.y = A.y + (distanceAP * AB.y) / distanceAB
719
+ let normalizedDot = dot / (distanceAB * distanceAB)
720
+ if (isIncludedInSegment) {
721
+ normalizedDot = Math.max(0, Math.min(normalizedDot, 1))
722
+ }
723
+ P.x = A.x + normalizedDot * AB.x
724
+ P.y = A.y + normalizedDot * AB.y
711
725
  }
712
726
  } else {
713
727
  //make 3D projection on line
@@ -731,10 +745,13 @@ export function getPointOnLine(M, A, B) {
731
745
  P = M
732
746
  } else {
733
747
  // in case of 0 length line
734
- const distanceAP = dot / distanceAB
735
- P.x = A.x + (distanceAP * AB.x) / distanceAB
736
- P.y = A.y + (distanceAP * AB.y) / distanceAB
737
- P.z = A.z + (distanceAP * AB.z) / distanceAB
748
+ let normalizedDot = dot / (distanceAB * distanceAB)
749
+ if (isIncludedInSegment) {
750
+ normalizedDot = Math.max(0, Math.min(normalizedDot, 1))
751
+ }
752
+ P.x = A.x + normalizedDot * AB.x
753
+ P.y = A.y + normalizedDot * AB.y
754
+ P.z = A.z + normalizedDot * AB.z
738
755
  }
739
756
  }
740
757
  //projection of the point to the line
@@ -768,7 +785,7 @@ export function isPointBetweenSegment(A, B, C) {
768
785
  const AB = getDistanceBetweenPoints(A, B)
769
786
  const AC = getDistanceBetweenPoints(A, C)
770
787
  const BC = getDistanceBetweenPoints(C, B)
771
- const isBetween = AB < BC && AC < BC
788
+ const isBetween = AB <= BC && AC <= BC
772
789
  return isBetween
773
790
  }
774
791
  export function get3pointNotAlignedFromOutline(outline) {
@@ -870,6 +887,22 @@ export function verticalProjectionOnPlane(p, n, o) {
870
887
  const projectedPoint = { ...p, z: projectedHeight }
871
888
  return projectedPoint
872
889
  }
890
+ export function projectionOnPlaneFollowingVector(p, n, o, v) {
891
+ // if p belongs to (n,o) plane return p
892
+ const opn = dotProduct(substractVector(p, o), n)
893
+ if (opn == 0) {
894
+ return p
895
+ }
896
+ //if n and v are normal to each other, return error
897
+ const nv = dotProduct(n, v)
898
+ if (nv == 0) {
899
+ console.warn('projection plane and vector are coplanar')
900
+ throw new Error('Cannot project: normal vector and direction vector are perpendicular')
901
+ }
902
+ const lambda = -opn / nv
903
+ const projectedPoint = addVector(p, multiplyVector(lambda, v))
904
+ return projectedPoint
905
+ }
873
906
 
874
907
  export function calcPolygonArea(vertices) {
875
908
  var total = 0
@@ -0,0 +1,442 @@
1
+ import {
2
+ getDistanceBetweenPoints,
3
+ get3DDistanceBetweenPoints,
4
+ isSamePoint3D,
5
+ getDataAboutTwo3DLines,
6
+ verticalProjectionOnPlane,
7
+ getDistanceBetweenTwoParallelInfiniteLines,
8
+ } from './geometry'
9
+ import { areAlmostCollinear, substractVector, dotProduct } from './vector'
10
+ import { Point } from './objects/Point'
11
+ import { Line } from './objects/Line'
12
+ import { Circle } from './objects/Circle'
13
+ import { Polygon } from './objects/Polygon'
14
+ import { areObjectsIntersecting } from './intersectionCheck'
15
+ import { defaultPlane } from './objects/Plane'
16
+ /**
17
+ * Returns the shortest segment between two objects
18
+ * @param {Object} obj0 - First object (Point, Line, Circle, or Polygon)
19
+ * @param {Object} obj1 - Second object (Point, Line, Circle, or Polygon)
20
+ * @param {Object} point - Reference point (used to disambiguate when multiple segments exist)
21
+ * @returns {Array} [pointOnObj0, pointOnObj1] - Two points forming the shortest segment
22
+ */
23
+ export function getShortestSegmentBetweenObjects(
24
+ obj0,
25
+ obj1,
26
+ point,
27
+ projectionPlane = defaultPlane
28
+ ) {
29
+ // Check if objects intersect
30
+ if (areObjectsIntersecting(obj0, obj1)) {
31
+ if (point) {
32
+ point = new Point(point.x, point.y, point.z)
33
+ return getShortestSegmentBetweenObjects(
34
+ obj0,
35
+ point,
36
+ null,
37
+ projectionPlane
38
+ )
39
+ } else if (obj1.type === 'point') {
40
+ return [obj1, obj1]
41
+ } else if (obj0.type === 'point') {
42
+ return [obj0, obj0]
43
+ } else {
44
+ return null
45
+ }
46
+ }
47
+
48
+ // Handle Point cases
49
+ if (obj0.type === 'point' && obj1.type === 'point') {
50
+ return getShortestSegmentPointPoint(obj0, obj1, point, projectionPlane)
51
+ }
52
+ if (obj0.type === 'point' && obj1.type === 'line') {
53
+ return getShortestSegmentPointLine(obj0, obj1, point, projectionPlane)
54
+ }
55
+ if (obj0.type === 'point' && obj1.type === 'circle') {
56
+ return getShortestSegmentPointCircle(obj0, obj1, point, projectionPlane)
57
+ }
58
+ if (obj0.type === 'point' && obj1.type === 'polygon') {
59
+ return getShortestSegmentPointPolygon(obj0, obj1, point, projectionPlane)
60
+ }
61
+
62
+ // Handle Line cases
63
+ if (obj0.type === 'line' && obj1.type === 'point') {
64
+ const result = getShortestSegmentPointLine(
65
+ obj1,
66
+ obj0,
67
+ point,
68
+ projectionPlane
69
+ )
70
+ if (result) {
71
+ return [result[1], result[0]]
72
+ }
73
+ }
74
+ if (obj0.type === 'line' && obj1.type === 'line') {
75
+ return getShortestSegmentLineLine(obj0, obj1, point, projectionPlane)
76
+ }
77
+ if (obj0.type === 'line' && obj1.type === 'circle') {
78
+ return getShortestSegmentLineCircle(obj0, obj1, point, projectionPlane)
79
+ }
80
+ if (obj0.type === 'line' && obj1.type === 'polygon') {
81
+ return getShortestSegmentLinePolygon(obj0, obj1, point, projectionPlane)
82
+ }
83
+ // Handle Circle cases
84
+ if (obj0.type === 'circle' && obj1.type === 'point') {
85
+ const result = getShortestSegmentPointCircle(
86
+ obj1,
87
+ obj0,
88
+ point,
89
+ projectionPlane
90
+ )
91
+ if (result) {
92
+ return [result[1], result[0]]
93
+ }
94
+ }
95
+ if (obj0.type === 'circle' && obj1.type === 'line') {
96
+ const result = getShortestSegmentLineCircle(
97
+ obj1,
98
+ obj0,
99
+ point,
100
+ projectionPlane
101
+ )
102
+ if (result) {
103
+ return [result[1], result[0]]
104
+ }
105
+ return [result[1], result[0]]
106
+ }
107
+ if (obj0.type === 'circle' && obj1.type === 'circle') {
108
+ return getShortestSegmentCircleCircle(obj0, obj1, point, projectionPlane)
109
+ }
110
+
111
+ if (obj0.type === 'circle' && obj1.type === 'polygon') {
112
+ return getShortestSegmentCirclePolygon(obj0, obj1, point, projectionPlane)
113
+ }
114
+ //handle polygon cases
115
+ if (obj0.type === 'polygon' && obj1.type === 'point') {
116
+ const result = getShortestSegmentPointPolygon(
117
+ obj1,
118
+ obj0,
119
+ point,
120
+ projectionPlane
121
+ )
122
+ if (result) {
123
+ return [result[1], result[0]]
124
+ }
125
+ }
126
+ if (obj0.type === 'polygon' && obj1.type === 'line') {
127
+ const result = getShortestSegmentLinePolygon(
128
+ obj1,
129
+ obj0,
130
+ point,
131
+ projectionPlane
132
+ )
133
+ if (result) {
134
+ return [result[1], result[0]]
135
+ } else {
136
+ return null
137
+ }
138
+ }
139
+ if (obj0.type === 'polygon' && obj1.type === 'circle') {
140
+ const result = getShortestSegmentCirclePolygon(
141
+ obj1,
142
+ obj0,
143
+ point,
144
+ projectionPlane
145
+ )
146
+ return [result[1], result[0]]
147
+ }
148
+ if (obj0.type === 'polygon' && obj1.type === 'polygon') {
149
+ return getShortestSegmentPolygonPolygon(obj0, obj1, point, projectionPlane)
150
+ }
151
+
152
+ console.error('Unsupported object types get shortest:', obj0.type, obj1.type)
153
+ console.trace()
154
+ return [point, point]
155
+ }
156
+
157
+ /**
158
+ * Check if two objects intersect
159
+ * @param {Object} obj0 - First object
160
+ * @param {Object} obj1 - Second object
161
+ * @returns {Boolean} True if objects intersect
162
+ */
163
+
164
+ /**
165
+ * Get shortest segment between two points
166
+ * @param {Point} p0 - First point
167
+ * @param {Point} p1 - Second point
168
+ * @param {Object} refPoint - Reference point
169
+ * @returns {Array} [point0, point1]
170
+ */
171
+ export function getShortestSegmentPointPoint(
172
+ p0,
173
+ p1,
174
+ refPoint,
175
+ projectionPlane = defaultPlane
176
+ ) {
177
+ // The segment is just the two points
178
+ return [p0, p1]
179
+ }
180
+
181
+ /**
182
+ * Get shortest segment between point and line
183
+ * @param {Point} point - Point object
184
+ * @param {Line} line - Line object
185
+ * @param {Object} refPoint - Reference point
186
+ * @returns {Array} [pointOnPoint, pointOnLine]
187
+ */
188
+ export function getShortestSegmentPointLine(
189
+ point,
190
+ line,
191
+ refPoint,
192
+ projectionPlane = defaultPlane
193
+ ) {
194
+ return [
195
+ point,
196
+ line.getProjectedPointFromPlane(point, {
197
+ isIncludedInSegment: false,
198
+ plane: projectionPlane,
199
+ }),
200
+ ]
201
+ }
202
+
203
+ /**
204
+ * Get shortest segment between point and circle
205
+ * @param {Point} point - Point object
206
+ * @param {Circle} circle - Circle object
207
+ * @param {Object} refPoint - Reference point
208
+ * @returns {Array} [pointOnPoint, pointOnCircle]
209
+ */
210
+ export function getShortestSegmentPointCircle(
211
+ point,
212
+ circle,
213
+ refPoint,
214
+ projectionPlane = defaultPlane
215
+ ) {
216
+ if (get3DDistanceBetweenPoints(point, circle.center) <= circle.radius) {
217
+ return circle.getCircleDiameterPoints(point, { plane: projectionPlane })
218
+ }
219
+ return [
220
+ point,
221
+ circle.getProjectedPointFromPlane(point, { plane: projectionPlane }),
222
+ ]
223
+ }
224
+
225
+ /**
226
+ * Get shortest segment between point and polygon
227
+ * @param {Point} point - Point object
228
+ * @param {Polygon} polygon - Polygon object
229
+ * @param {Object} refPoint - Reference point
230
+ * @returns {Array} [pointOnPoint, pointOnPolygon]
231
+ */
232
+ export function getShortestSegmentPointPolygon(
233
+ point,
234
+ polygon,
235
+ refPoint,
236
+ projectionPlane = defaultPlane
237
+ ) {
238
+ // TODO: Find the point on the polygon (vertex or edge) closest to the point
239
+ // TODO: If multiple solutions exist, choose the one closest to refPoint
240
+ const P = verticalProjectionOnPlane(
241
+ point,
242
+ polygon.normalVector,
243
+ polygon.outline[0]
244
+ )
245
+ const pointInPlane = new Point(P.x, P.y, P.z)
246
+ const closestEdge = polygon.getClosestPolygonEdgeFromPlane(
247
+ pointInPlane,
248
+ projectionPlane
249
+ )
250
+
251
+ if (refPoint) {
252
+ const projectedPointOnPolygonEdge = closestEdge.getProjectedPointFromPlane(
253
+ refPoint,
254
+ true,
255
+ projectionPlane
256
+ )
257
+ // const closestPoint = findClosestPoint(projectedPoints, refPoint)
258
+ return [pointInPlane, projectedPointOnPolygonEdge]
259
+ } else {
260
+ const projectedPointOnPolygonEdge = closestEdge.getProjectedPointFromPlane(
261
+ pointInPlane,
262
+ true,
263
+ projectionPlane
264
+ )
265
+
266
+ return [pointInPlane, projectedPointOnPolygonEdge]
267
+ }
268
+ }
269
+
270
+ /**
271
+ * Get shortest segment between two lines
272
+ * @param {Line} line0 - First line
273
+ * @param {Line} line1 - Second line
274
+ * @param {Object} refPoint - Reference point
275
+ * @returns {Array} [pointOnLine0, pointOnLine1]
276
+ */
277
+ export function getShortestSegmentLineLine(
278
+ line0,
279
+ line1,
280
+ refPoint,
281
+ projectionPlane = defaultPlane
282
+ ) {
283
+ if (line0.id == line1.id) {
284
+ return [line0.outline[0], line0.outline[1]]
285
+ }
286
+ const A = line0.outline[0]
287
+ const u = substractVector(line0.outline[1], line0.outline[0])
288
+ const B = line1.outline[0]
289
+ const v = substractVector(line1.outline[1], line1.outline[0])
290
+ let P1 = line0.getProjectedPointFromPlane(refPoint, {
291
+ isIncludedInSegment: false,
292
+ plane: projectionPlane,
293
+ })
294
+ const P2 = line1.getIntersectionWithPointVectorLineFromPlane(
295
+ P1,
296
+ line0.getNormalVectorInPlane(projectionPlane),
297
+ projectionPlane
298
+ )
299
+ if (P2 && P1) {
300
+ return [P1, P2]
301
+ }
302
+ return null
303
+ }
304
+
305
+ /**
306
+ * Get shortest segment between line and circle
307
+ * @param {Line} line - Line object
308
+ * @param {Circle} circle - Circle object
309
+ * @param {Object} refPoint - Reference point
310
+ * @returns {Array} [pointOnLine, pointOnCircle]
311
+ */
312
+ export function getShortestSegmentLineCircle(
313
+ line,
314
+ circle,
315
+ refPoint,
316
+ projectionPlane = defaultPlane
317
+ ) {
318
+ const A = line.getProjectedPointFromPlane(circle.center, {
319
+ isIncludedInSegment: false,
320
+ plane: projectionPlane,
321
+ })
322
+ const B = circle.getProjectedPointFromPlane(A, { plane: projectionPlane })
323
+ return [A, B]
324
+ }
325
+
326
+ /**
327
+ * Get shortest segment between line and polygon
328
+ * @param {Line} line - Line object
329
+ * @param {Polygon} polygon - Polygon object
330
+ * @param {Object} refPoint - Reference point
331
+ * @returns {Array} [pointOnLine, pointOnPolygon] or null
332
+ */
333
+ export function getShortestSegmentLinePolygon(
334
+ line,
335
+ polygon,
336
+ refPoint,
337
+ projectionPlane = defaultPlane
338
+ ) {
339
+ const polygonEdges = polygon.outline.map((p, index) => {
340
+ const nextP = polygon.outline[(index + 1) % polygon.outline.length]
341
+ return new Line(p, nextP)
342
+ })
343
+ let polygonEdgesData = polygonEdges
344
+ .map((edge) => {
345
+ const data = getShortestSegmentLineLine(
346
+ line,
347
+ edge,
348
+ refPoint,
349
+ projectionPlane
350
+ )
351
+ if (!!data) {
352
+ const [M, N] = data
353
+ const distance = getDistanceBetweenPoints(M, N)
354
+ return { distance, M, N }
355
+ } else {
356
+ return null
357
+ }
358
+ })
359
+ .filter((data) => !!data)
360
+ polygonEdgesData.sort((a, b) => a.distance - b.distance)
361
+ if (polygonEdgesData.length) {
362
+ //intersection between a line orthogonal to the line and one of the polygon edges
363
+ return [polygonEdgesData[0].M, polygonEdgesData[0].N]
364
+ } else {
365
+ //get the polygon outline closest to the line and its projection on the line
366
+ const polygonOutline = polygon.outline
367
+ const distances = polygonOutline.map((p) => {
368
+ return line.getHorizontalDistanceToPoint(p)
369
+ })
370
+ const minDistance = Math.min(...distances)
371
+ const minIndex = distances.indexOf(minDistance)
372
+ const minPoint = polygonOutline[minIndex]
373
+ const projectionPoint = line.getProjectedPointFromPlane(minPoint, {
374
+ isIncludedInSegment: true,
375
+ plane: projectionPlane,
376
+ })
377
+ return [projectionPoint, minPoint]
378
+ }
379
+ }
380
+
381
+ /**
382
+ * Get shortest segment between two circles
383
+ * @param {Circle} circle0 - First circle
384
+ * @param {Circle} circle1 - Second circle
385
+ * @param {Object} refPoint - Reference point
386
+ * @returns {Array} [pointOnCircle0, pointOnCircle1]
387
+ */
388
+ export function getShortestSegmentCircleCircle(
389
+ circle0,
390
+ circle1,
391
+ refPoint,
392
+ projectionPlane = defaultPlane
393
+ ) {
394
+ return [circle0.center, circle1.center]
395
+ }
396
+
397
+ /**
398
+ * Get shortest segment between circle and polygon
399
+ * @param {Circle} circle - Circle object
400
+ * @param {Polygon} polygon - Polygon object
401
+ * @param {Object} refPoint - Reference point
402
+ * @returns {Array} [pointOnCircle, pointOnPolygon]
403
+ */
404
+ export function getShortestSegmentCirclePolygon(
405
+ circle,
406
+ polygon,
407
+ refPoint,
408
+ projectionPlane = defaultPlane
409
+ ) {
410
+ return getShortestSegmentPointPolygon(circle.center, polygon, refPoint)
411
+ }
412
+
413
+ /**
414
+ * Get shortest segment between two polygons
415
+ * @param {Polygon} polygon0 - First polygon
416
+ * @param {Polygon} polygon1 - Second polygon
417
+ * @param {Object} refPoint - Reference point
418
+ * @returns {Array} [pointOnPolygon0, pointOnPolygon1]
419
+ */
420
+ export function getShortestSegmentPolygonPolygon(
421
+ polygon0,
422
+ polygon1,
423
+ refPoint,
424
+ projectionPlane = defaultPlane
425
+ ) {
426
+ const pointsP0 = polygon0.getProjectedPoints(refPoint, true)
427
+ const closestPoint0 = findClosestPoint(pointsP0, refPoint)
428
+ const pointsP1 = polygon1.getProjectedPoints(closestPoint0, true)
429
+ const closestPoint1 = findClosestPoint(pointsP1, refPoint)
430
+ return [closestPoint0, closestPoint1]
431
+ }
432
+
433
+ export function findClosestPoint(
434
+ points,
435
+ refPoint,
436
+ projectionPlane = defaultPlane
437
+ ) {
438
+ const distances = points.map((p) => getDistanceBetweenPoints(refPoint, p))
439
+ const minDistance = Math.min(...distances)
440
+ const minIndex = distances.indexOf(minDistance)
441
+ return points[minIndex]
442
+ }
package/src/index.js CHANGED
@@ -1,6 +1,8 @@
1
1
  export * from './coords'
2
2
  export * from './geo'
3
3
  export * from './geometry'
4
+ export * from './geometryShortDistance'
5
+ export * from './intersectionCheck'
4
6
  export * from './matrix'
5
7
  export * from './vector'
6
8
  export * from './snap'
@@ -14,3 +16,4 @@ export * from './spherical'
14
16
  export * from './SHPSolver'
15
17
  export * from './panelFunctions'
16
18
  export * from './stringPatchMatching'
19
+ export * from './plane'