@jscad/modeling 3.0.1-alpha.0 → 3.0.2-alpha.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/CHANGELOG.md +14 -0
  2. package/dist/jscad-modeling.es.js +2 -2
  3. package/dist/jscad-modeling.min.js +2 -2
  4. package/package.json +2 -2
  5. package/src/geometries/path2/appendBezier.js +1 -1
  6. package/src/geometries/poly3/index.js +1 -1
  7. package/src/geometries/poly3/measureBoundingBox.js +2 -0
  8. package/src/geometries/poly3/measureBoundingSphere.d.ts +2 -1
  9. package/src/geometries/poly3/measureBoundingSphere.js +25 -8
  10. package/src/geometries/poly3/measureBoundingSphere.test.js +12 -8
  11. package/src/index.js +41 -0
  12. package/src/measurements/measureBoundingSphere.js +2 -6
  13. package/src/operations/booleans/martinez/compareEvents.js +2 -7
  14. package/src/operations/booleans/martinez/connectEdges.js +30 -41
  15. package/src/operations/booleans/martinez/contour.js +1 -1
  16. package/src/operations/booleans/martinez/divideSegment.js +12 -11
  17. package/src/operations/booleans/martinez/fillQueue.js +24 -28
  18. package/src/operations/booleans/martinez/index.js +2 -1
  19. package/src/operations/booleans/martinez/possibleIntersection.js +41 -30
  20. package/src/operations/booleans/martinez/segmentIntersection.js +7 -9
  21. package/src/operations/booleans/martinez/splaytree.js +59 -457
  22. package/src/operations/booleans/martinez/subdivideSegments.js +4 -4
  23. package/src/operations/booleans/martinez/sweepEvent.js +3 -17
  24. package/src/operations/booleans/trees/Node.js +25 -27
  25. package/src/operations/booleans/trees/PolygonTreeNode.js +153 -106
  26. package/src/operations/booleans/trees/Tree.js +9 -4
  27. package/src/operations/booleans/trees/splitLineSegmentByPlane.js +5 -3
  28. package/src/operations/booleans/trees/splitPolygonByPlane.js +39 -34
  29. package/src/operations/extrusions/extrudeWalls.js +3 -1
  30. package/src/operations/hulls/hullPoints2.js +20 -28
  31. package/src/operations/modifiers/mergePolygons.js +2 -3
  32. package/src/operations/modifiers/reTesselateCoplanarPolygons.js +7 -7
@@ -15,36 +15,40 @@ import {
15
15
  } from './edgeType.js'
16
16
 
17
17
  /**
18
+ * and split the segments if an intersection is detected.
18
19
  * @param {SweepEvent} se1
19
20
  * @param {SweepEvent} se2
20
21
  * @param {Queue} queue
21
- * @return {number}
22
+ * @return
23
+ * 0=no intersection
24
+ * 1=intersect point
25
+ * 2=overlap, left points cooinciding
26
+ * 3=overlap, right points cooinciding
27
+ * 4=segments overlap
28
+ * 5=segment within segment
22
29
  */
23
30
  export const possibleIntersection = (se1, se2, queue) => {
24
- // that disallows self-intersecting polygons,
25
- // did cost us half a day, so I'll leave it
26
- // out of respect
27
- // if (se1.isSubject === se2.isSubject) return
31
+ // null = no intersection
32
+ // array[1] = point of intersection
33
+ // array[2] = line overlaps, segment of overlap, i.e. two points
28
34
  const inter = segmentIntersection(
29
35
  se1.point, se1.otherEvent.point,
30
36
  se2.point, se2.otherEvent.point
31
37
  )
32
38
 
33
39
  const nIntersections = inter ? inter.length : 0
34
- if (nIntersections === 0) return 0 // no intersection
35
40
 
36
- // the line segments intersect at an endpoint of both line segments
41
+ // no intersection of segments
42
+ if (nIntersections === 0) return 0
43
+
44
+ // single point of intersection, check the end points
37
45
  if ((nIntersections === 1) &&
38
46
  (equals(se1.point, se2.point) ||
39
47
  equals(se1.otherEvent.point, se2.otherEvent.point))) {
40
48
  return 0
41
49
  }
42
50
 
43
- if (nIntersections === 2 && se1.isSubject === se2.isSubject) {
44
- return 0
45
- }
46
-
47
- // The line segments associated to se1 and se2 intersect
51
+ // single point of intersection, divide the segments
48
52
  if (nIntersections === 1) {
49
53
  // if the intersection point is not an endpoint of se1
50
54
  if (!equals(se1.point, inter[0]) && !equals(se1.otherEvent.point, inter[0])) {
@@ -58,56 +62,63 @@ export const possibleIntersection = (se1, se2, queue) => {
58
62
  return 1
59
63
  }
60
64
 
61
- // The line segments associated to se1 and se2 overlap
62
- const events = []
65
+ // segments overlap, check for same subject/clipping
66
+ if (nIntersections === 2 && se1.isSubject === se2.isSubject) {
67
+ return 0
68
+ }
69
+
70
+ // segments overlap, determine the overlap, and divide segments
71
+ // FIXME eliminate this stack
72
+ const segmentEvents = []
63
73
  let leftCoincide = false
64
74
  let rightCoincide = false
65
75
 
66
76
  if (equals(se1.point, se2.point)) {
67
77
  leftCoincide = true // linked
68
78
  } else if (compareEvents(se1, se2) === 1) {
69
- events.push(se2, se1)
79
+ segmentEvents.push(se2, se1)
70
80
  } else {
71
- events.push(se1, se2)
81
+ segmentEvents.push(se1, se2)
72
82
  }
73
83
 
74
84
  if (equals(se1.otherEvent.point, se2.otherEvent.point)) {
75
85
  rightCoincide = true
76
86
  } else if (compareEvents(se1.otherEvent, se2.otherEvent) === 1) {
77
- events.push(se2.otherEvent, se1.otherEvent)
87
+ segmentEvents.push(se2.otherEvent, se1.otherEvent)
78
88
  } else {
79
- events.push(se1.otherEvent, se2.otherEvent)
89
+ segmentEvents.push(se1.otherEvent, se2.otherEvent)
80
90
  }
81
91
 
82
- if ((leftCoincide && rightCoincide) || leftCoincide) {
92
+ if (leftCoincide) {
83
93
  // both line segments are equal or share the left endpoint
94
+ // FIXME: this setting of type should be done outside this function
84
95
  se2.type = NON_CONTRIBUTING
85
96
  se1.type = (se2.inOut === se1.inOut) ? SAME_TRANSITION : DIFFERENT_TRANSITION
86
97
 
87
- if (leftCoincide && !rightCoincide) {
88
- // honestly no idea, but changing events selection from [2, 1]
98
+ if (!rightCoincide) {
99
+ // honestly no idea, but changing segmentEvents selection from [2, 1]
89
100
  // to [0, 1] fixes the overlapping self-intersecting polygons issue
90
- divideSegment(events[1].otherEvent, events[0].point, queue)
101
+ divideSegment(segmentEvents[1].otherEvent, segmentEvents[0].point, queue)
91
102
  }
92
103
  return 2
93
104
  }
94
105
 
95
106
  // the line segments share the right endpoint
96
107
  if (rightCoincide) {
97
- divideSegment(events[0], events[1].point, queue)
108
+ divideSegment(segmentEvents[0], segmentEvents[1].point, queue)
98
109
  return 3
99
110
  }
100
111
 
101
112
  // no line segment includes totally the other one
102
- if (events[0] !== events[3].otherEvent) {
103
- divideSegment(events[0], events[1].point, queue)
104
- divideSegment(events[1], events[2].point, queue)
105
- return 3
113
+ if (segmentEvents[0] !== segmentEvents[3].otherEvent) {
114
+ divideSegment(segmentEvents[0], segmentEvents[1].point, queue)
115
+ divideSegment(segmentEvents[1], segmentEvents[2].point, queue)
116
+ return 4
106
117
  }
107
118
 
108
119
  // one line segment includes the other one
109
- divideSegment(events[0], events[1].point, queue)
110
- divideSegment(events[3].otherEvent, events[2].point, queue)
120
+ divideSegment(segmentEvents[0], segmentEvents[1].point, queue)
121
+ divideSegment(segmentEvents[3].otherEvent, segmentEvents[2].point, queue)
111
122
 
112
- return 3
123
+ return 5
113
124
  }
@@ -34,7 +34,7 @@ const crossProduct = (a, b) => (a[0] * b[1]) - (a[1] * b[0])
34
34
  * intersection. If they overlap, the two end points of the overlapping segment.
35
35
  * Otherwise, null.
36
36
  */
37
- export const segmentIntersection = (a1, a2, b1, b2, noEndpointTouch) => {
37
+ export const segmentIntersection = (a1, a2, b1, b2, noEndpointTouch = false) => {
38
38
  // The algorithm expects our lines in the form P + sd, where P is a point,
39
39
  // s is on the interval [0, 1], and d is a vector.
40
40
  // We are passed two points. P can be the first point of each pair. The
@@ -51,11 +51,9 @@ export const segmentIntersection = (a1, a2, b1, b2, noEndpointTouch) => {
51
51
  ]
52
52
 
53
53
  // The rest is pretty much a straight port of the algorithm.
54
- const e = [b1[0] - a1[0], b1[1] - a1[1]]
54
+ const v1 = [b1[0] - a1[0], b1[1] - a1[1]]
55
55
  let kross = crossProduct(va, vb)
56
56
  let sqrKross = kross * kross
57
- const sqrLenA = dotProduct(va, va)
58
- // const sqrLenB = dotProduct(vb, vb)
59
57
 
60
58
  // Check for line intersection. This works because of the properties of the
61
59
  // cross product -- specifically, two vectors are parallel if and only if the
@@ -66,12 +64,12 @@ export const segmentIntersection = (a1, a2, b1, b2, noEndpointTouch) => {
66
64
  // If they're not parallel, then (because these are line segments) they
67
65
  // still might not actually intersect. This code checks that the
68
66
  // intersection point of the lines is actually on both line segments.
69
- const s = crossProduct(e, vb) / kross
67
+ const s = crossProduct(v1, vb) / kross
70
68
  if (s < 0 || s > 1) {
71
69
  // not on line segment a
72
70
  return null
73
71
  }
74
- const t = crossProduct(e, va) / kross
72
+ const t = crossProduct(v1, va) / kross
75
73
  if (t < 0 || t > 1) {
76
74
  // not on line segment b
77
75
  return null
@@ -93,8 +91,7 @@ export const segmentIntersection = (a1, a2, b1, b2, noEndpointTouch) => {
93
91
  // the (vector) difference between the two initial points. If this is parallel
94
92
  // with the line itself, then the two lines are the same line, and there will
95
93
  // be overlap.
96
- // const sqrLenE = dotProduct(e, e)
97
- kross = crossProduct(e, va)
94
+ kross = crossProduct(v1, va)
98
95
  sqrKross = kross * kross
99
96
 
100
97
  if (sqrKross > 0 /* EPS * sqLenB * sqLenE */) {
@@ -102,7 +99,8 @@ export const segmentIntersection = (a1, a2, b1, b2, noEndpointTouch) => {
102
99
  return null
103
100
  }
104
101
 
105
- const sa = dotProduct(va, e) / sqrLenA
102
+ const sqrLenA = dotProduct(va, va)
103
+ const sa = dotProduct(va, v1) / sqrLenA
106
104
  const sb = sa + dotProduct(va, vb) / sqrLenA
107
105
  const smin = Math.min(sa, sb)
108
106
  const smax = Math.max(sa, sb)