@design-core/core 0.0.1 → 0.0.3

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 (254) hide show
  1. package/.eslintrc.json +14 -7
  2. package/.github/workflows/DesignCoreQA.yml +3 -1
  3. package/README.md +11 -4
  4. package/TODO.md +19 -0
  5. package/core/core/core.js +49 -42
  6. package/core/designCore.js +61 -2
  7. package/core/dimensions/alignedDimension.js +142 -0
  8. package/core/dimensions/angularDimension.js +550 -0
  9. package/core/dimensions/baseCircularDimension.js +244 -0
  10. package/core/dimensions/baseDimension.js +558 -0
  11. package/core/dimensions/baseLinearDimension.js +371 -0
  12. package/core/dimensions/diametricDimension.js +82 -0
  13. package/core/dimensions/dimension.js +298 -0
  14. package/core/dimensions/linearDimension.js +29 -0
  15. package/core/dimensions/radialDimension.js +78 -0
  16. package/core/dimensions/rotatedDimension.js +167 -0
  17. package/core/entities/arc.js +314 -60
  18. package/core/entities/arctext.js +642 -0
  19. package/core/entities/basePolyline.js +553 -94
  20. package/core/entities/circle.js +181 -54
  21. package/core/entities/entity.js +154 -74
  22. package/core/entities/hatch.js +807 -0
  23. package/core/entities/insert.js +200 -39
  24. package/core/entities/line.js +196 -134
  25. package/core/entities/lwpolyline.js +21 -44
  26. package/core/entities/point.js +194 -29
  27. package/core/entities/polyline.js +54 -7
  28. package/core/entities/rectangle.js +43 -13
  29. package/core/entities/solid.js +43 -6
  30. package/core/entities/text.js +324 -181
  31. package/core/lib/boundingBox.js +73 -13
  32. package/core/lib/canvas.js +256 -65
  33. package/core/lib/clipboard.js +198 -0
  34. package/core/lib/colour.js +144 -0
  35. package/core/lib/colours.js +367 -301
  36. package/core/lib/commandLine.js +16 -28
  37. package/core/lib/commandManager.js +115 -58
  38. package/core/lib/constants.js +23 -0
  39. package/core/lib/dxf/dxf.js +249 -34
  40. package/core/lib/dxf/dxfFile.js +23 -38
  41. package/core/lib/dxf/dxfIterator.js +17 -5
  42. package/core/lib/dxf/dxfRead.js +23 -7
  43. package/core/lib/dxf/dxfWrite.js +39 -129
  44. package/core/lib/dxf/handleManager.js +97 -0
  45. package/core/lib/dxf/sections/blocks.js +16 -2
  46. package/core/lib/dxf/sections/entities.js +17 -3
  47. package/core/lib/dxf/sections/header.js +10 -1
  48. package/core/lib/dxf/sections/objects.js +36 -0
  49. package/core/lib/dxf/sections/section.js +43 -5
  50. package/core/lib/dxf/sections/tables.js +17 -3
  51. package/core/lib/entityManager.js +178 -0
  52. package/core/lib/fileio.js +14 -4
  53. package/core/lib/headers.js +229 -0
  54. package/core/lib/input.js +46 -0
  55. package/core/lib/inputManager.js +199 -194
  56. package/core/lib/intersect.js +341 -468
  57. package/core/lib/logging.js +25 -1
  58. package/core/lib/matrix.js +6 -8
  59. package/core/lib/mouse.js +24 -79
  60. package/core/lib/patterns.js +690 -0
  61. package/core/lib/promptOptions.js +133 -0
  62. package/core/lib/scene.js +71 -174
  63. package/core/lib/selectionManager.js +74 -48
  64. package/core/lib/selectionWindow.js +24 -10
  65. package/core/lib/settings.js +18 -11
  66. package/core/lib/snapping.js +129 -21
  67. package/core/lib/stateManager.js +288 -0
  68. package/core/lib/strings.js +57 -5
  69. package/core/lib/utils.js +95 -11
  70. package/core/objects/dictionary.js +43 -0
  71. package/core/objects/dictionaryManager.js +80 -0
  72. package/core/properties/dimType.js +117 -0
  73. package/core/properties/flags.js +66 -0
  74. package/core/properties/property.js +26 -0
  75. package/core/properties/propertyManager.js +65 -19
  76. package/core/tables/appId.js +31 -0
  77. package/core/tables/appIdManager.js +44 -0
  78. package/core/tables/block.js +323 -0
  79. package/core/tables/blockManager.js +48 -0
  80. package/core/tables/blockRecord.js +29 -0
  81. package/core/tables/blockRecordManager.js +37 -0
  82. package/core/tables/dimStyle.js +627 -0
  83. package/core/tables/dimStyleManager.js +187 -0
  84. package/core/tables/endblk.js +28 -0
  85. package/core/tables/layer.js +219 -0
  86. package/core/tables/layerManager.js +47 -0
  87. package/core/tables/ltype.js +85 -0
  88. package/core/tables/ltypeManager.js +65 -0
  89. package/core/tables/style.js +145 -0
  90. package/core/tables/styleManager.js +55 -0
  91. package/core/tables/styleManagerBase.js +110 -0
  92. package/core/tables/tableManagerBase.js +354 -0
  93. package/core/tables/ucs.js +28 -0
  94. package/core/tables/ucsManager.js +44 -0
  95. package/core/tables/view.js +28 -0
  96. package/core/tables/viewManager.js +44 -0
  97. package/core/tables/vport.js +70 -0
  98. package/core/tables/vportManager.js +65 -0
  99. package/core/tools/chamfer.js +343 -0
  100. package/core/tools/chamferFilletBase.js +162 -0
  101. package/core/tools/copy.js +68 -40
  102. package/core/tools/copybase.js +65 -0
  103. package/core/tools/copyclip.js +59 -0
  104. package/core/tools/cornerEntity.js +138 -0
  105. package/core/tools/cutclip.js +72 -0
  106. package/core/tools/distance.js +37 -9
  107. package/core/tools/erase.js +43 -13
  108. package/core/tools/explode.js +117 -0
  109. package/core/tools/extend.js +71 -32
  110. package/core/tools/fillet.js +336 -0
  111. package/core/tools/identify.js +33 -6
  112. package/core/tools/matchProp.js +106 -0
  113. package/core/tools/mirror.js +141 -0
  114. package/core/tools/move.js +65 -32
  115. package/core/tools/offset.js +321 -0
  116. package/core/tools/pan.js +54 -0
  117. package/core/tools/pasteclip.js +93 -0
  118. package/core/tools/purge.js +90 -0
  119. package/core/tools/rotate.js +105 -70
  120. package/core/tools/scale.js +166 -0
  121. package/core/tools/tool.js +14 -4
  122. package/core/tools/trim.js +71 -32
  123. package/core/tools/zoom.js +152 -0
  124. package/package.json +3 -305
  125. package/test/dimensions/alignedDimension.test.js +211 -0
  126. package/test/dimensions/angularDimension.test.js +243 -0
  127. package/test/dimensions/baseDimension.test.js +239 -0
  128. package/test/dimensions/diametricDimension.test.js +203 -0
  129. package/test/dimensions/dimension.test.js +102 -0
  130. package/test/dimensions/radialDimension.test.js +203 -0
  131. package/test/dimensions/rotatedDimension.test.js +224 -0
  132. package/test/entities/arc.test.js +463 -41
  133. package/test/entities/arctext.test.js +329 -0
  134. package/test/entities/basePolyline.test.js +459 -10
  135. package/test/entities/circle.test.js +312 -7
  136. package/test/entities/entity.test.js +28 -9
  137. package/test/entities/hatch.test.js +606 -0
  138. package/test/entities/insert.test.js +90 -0
  139. package/test/entities/line.test.js +182 -6
  140. package/test/entities/point.test.js +375 -37
  141. package/test/entities/solid.test.js +156 -0
  142. package/test/entities/text.test.js +533 -7
  143. package/test/integration/exportIntegration.reference.dxf +1706 -0
  144. package/test/integration/exportIntegration.test.js +186 -0
  145. package/test/integration/importExportIntegration.test.js +126 -0
  146. package/test/integration/intersectionIntegration.test.js +880 -0
  147. package/test/integration/userInputIntegration.reference.dxf +1410 -0
  148. package/test/integration/userInputIntegration.test.js +269 -0
  149. package/test/lib/boundingBox.test.js +26 -2
  150. package/test/lib/canvas.test.js +613 -5
  151. package/test/lib/clipboard.test.js +70 -0
  152. package/test/lib/colour.test.js +114 -0
  153. package/test/lib/colours.test.js +63 -18
  154. package/test/lib/commandLine.test.js +159 -22
  155. package/test/lib/commandManager.test.js +4 -4
  156. package/test/lib/constants.test.js +9 -0
  157. package/test/lib/dxf/dxfFile.test.js +6 -2
  158. package/test/lib/dxf/dxfIterator.test.js +1 -1
  159. package/test/lib/dxf/dxfWrite.test.js +173 -0
  160. package/test/lib/dxf/handleManager.test.js +137 -0
  161. package/test/lib/dxf/sections/blocks.test.js +5 -5
  162. package/test/lib/dxf/sections/entities.test.js +4 -4
  163. package/test/lib/dxf/sections/header.test.js +18 -4
  164. package/test/lib/dxf/sections/objects.test.js +132 -0
  165. package/test/lib/dxf/sections/section.test.js +29 -29
  166. package/test/lib/dxf/sections/tables.test.js +3 -3
  167. package/test/lib/entityManager.test.js +163 -0
  168. package/test/lib/headers.test.js +233 -0
  169. package/test/lib/inputManager.test.js +1144 -5
  170. package/test/lib/intersect.test.js +454 -331
  171. package/test/lib/logging.test.js +1 -1
  172. package/test/lib/matrix.test.js +1 -1
  173. package/test/lib/mouse.test.js +327 -4
  174. package/test/lib/patterns.test.js +105 -0
  175. package/test/lib/promptOptions.test.js +179 -0
  176. package/test/lib/scene.test.js +16 -52
  177. package/test/lib/selectionManager.test.js +17 -5
  178. package/test/lib/settings.test.js +111 -5
  179. package/test/lib/snapping.test.js +142 -4
  180. package/test/lib/stateManager.test.js +155 -0
  181. package/test/lib/utils.test.js +81 -1
  182. package/test/objects/dictionary.test.js +81 -0
  183. package/test/objects/dictionaryManager.test.js +34 -0
  184. package/test/properties/dimType.test.js +62 -0
  185. package/test/properties/flags.test.js +164 -0
  186. package/test/properties/property.test.js +13 -0
  187. package/test/properties/propertyManager.test.js +10 -11
  188. package/test/tables/appId.test.js +46 -0
  189. package/test/tables/appIdManager.test.js +72 -0
  190. package/test/tables/block.test.js +157 -0
  191. package/test/tables/blockManager.test.js +52 -0
  192. package/test/tables/blockRecord.test.js +39 -0
  193. package/test/tables/blockRecordManager.test.js +60 -0
  194. package/test/tables/dimstyle.test.js +72 -0
  195. package/test/tables/endblk.test.js +30 -0
  196. package/test/tables/layer.test.js +95 -0
  197. package/test/tables/layerManager.test.js +172 -0
  198. package/test/{styles → tables}/ltype.test.js +7 -7
  199. package/test/{styles → tables}/ltypeManager.test.js +2 -2
  200. package/test/tables/style.test.js +44 -0
  201. package/test/tables/stylemanagerbase.test.js +220 -0
  202. package/test/tables/tableManagerBase.test.js +194 -0
  203. package/test/tables/ucs.test.js +37 -0
  204. package/test/tables/ucsManager.test.js +48 -0
  205. package/test/tables/view.test.js +37 -0
  206. package/test/tables/viewManager.test.js +48 -0
  207. package/test/tables/vport.test.js +117 -0
  208. package/test/tables/vportManager.test.js +54 -0
  209. package/test/test-helpers/test-helpers.js +66 -0
  210. package/test/tools/chamfer.test.js +970 -0
  211. package/test/tools/chamferFilletBase.test.js +446 -0
  212. package/test/tools/copy.test.js +22 -14
  213. package/test/tools/copybase.test.js +93 -0
  214. package/test/tools/copyclip.test.js +92 -0
  215. package/test/tools/cornerEntity.test.js +201 -0
  216. package/test/tools/cutclip.test.js +94 -0
  217. package/test/tools/distance.test.js +140 -18
  218. package/test/tools/erase.test.js +12 -12
  219. package/test/tools/explode.test.js +45 -0
  220. package/test/tools/extend.test.js +326 -44
  221. package/test/tools/fillet.test.js +831 -0
  222. package/test/tools/identify.test.js +115 -16
  223. package/test/tools/matchProp.test.js +84 -0
  224. package/test/tools/mirror.test.js +475 -0
  225. package/test/tools/move.test.js +75 -19
  226. package/test/tools/offset.test.js +748 -0
  227. package/test/tools/pan.test.js +72 -0
  228. package/test/tools/pasteclip.test.js +100 -0
  229. package/test/tools/purge.test.js +89 -0
  230. package/test/tools/rotate.test.js +89 -23
  231. package/test/tools/scale.test.js +529 -0
  232. package/test/tools/trim.test.js +419 -84
  233. package/test/tools/zoom.test.js +504 -0
  234. package/core/entities/alignedDimension.js +0 -279
  235. package/core/entities/angularDimension.js +0 -194
  236. package/core/entities/baseDimension.js +0 -227
  237. package/core/entities/block.js +0 -247
  238. package/core/entities/diametricDimension.js +0 -133
  239. package/core/entities/dimension.js +0 -202
  240. package/core/entities/radialDimension.js +0 -126
  241. package/core/styles/dimStyle.js +0 -719
  242. package/core/styles/dimStyleManager.js +0 -47
  243. package/core/styles/layer.js +0 -133
  244. package/core/styles/layerManager.js +0 -40
  245. package/core/styles/ltype.js +0 -86
  246. package/core/styles/ltypeManager.js +0 -50
  247. package/core/styles/style.js +0 -158
  248. package/core/styles/styleManager.js +0 -43
  249. package/core/styles/styleManagerBase.js +0 -299
  250. package/test/entities/block.test.js +0 -22
  251. package/test/styles/dimstyle.test.js +0 -19
  252. package/test/styles/layerManager.test.js +0 -150
  253. package/test/styles/style.test.js +0 -33
  254. package/test/styles/stylemanagerbase.test.js +0 -219
@@ -1,6 +1,41 @@
1
- import {Point} from '../entities/point.js';
1
+ import { Point } from '../entities/point.js';
2
+ import { Constants } from './constants.js';
3
+ import { Utils } from './utils.js';
2
4
 
5
+ /** Intersection Class */
3
6
  export class Intersection {
7
+ /**
8
+ * Enumeration of all possible intersection status values.
9
+ * Use these constants instead of magic strings when comparing or setting
10
+ * `Intersection#status`.
11
+ */
12
+ static Status = {
13
+ /** The geometries do not intersect. */
14
+ NONE: 'None',
15
+ /** The geometries intersect at one or more discrete points (arc/circle/polyline aggregate). */
16
+ INTERSECTION: 'Intersection',
17
+ /** Two line segments cross in their interiors (both intersection parameters strictly inside [0,1]). */
18
+ CROSSING: 'Crossing',
19
+ /** Two line segments cross in their interiors at exactly 90°. */
20
+ PERPENDICULAR: 'Perpendicular',
21
+ /** An endpoint of one segment lies in the interior of the other segment (T-intersection). */
22
+ TOUCHING: 'Touching',
23
+ /** The segments share an endpoint exactly. */
24
+ ENDPOINT: 'Endpoint',
25
+ /** The geometries are collinear and their intervals overlap (line-line). */
26
+ OVERLAPPING: 'Overlapping',
27
+ /** The geometries are collinear / coincident (used for concentric equal-radius arcs/circles). */
28
+ COINCIDENT: 'Coincident',
29
+ /** The geometries are parallel but distinct. */
30
+ PARALLEL: 'Parallel',
31
+ /** The geometries are tangent (touch at exactly one point). */
32
+ TANGENT: 'Tangent',
33
+ /** One geometry is fully inside the other with no intersection points. */
34
+ INSIDE: 'Inside',
35
+ /** The geometries are entirely separate with one outside the other. */
36
+ OUTSIDE: 'Outside',
37
+ };
38
+
4
39
  /**
5
40
  * Intersection constructor
6
41
  * @param {string} status - defined status of the intersection i.e inside or outside of shape
@@ -12,26 +47,144 @@ export class Intersection {
12
47
 
13
48
  /**
14
49
  * Append point to suggested intersecting points
15
- * @param {point} point
50
+ * @param {Point} point
16
51
  */
17
52
  appendPoint(point) {
53
+ // check if point already exists in the array
54
+ for (let i = 0; i < this.points.length; i++) {
55
+ if (this.points[i].isSame(point)) {
56
+ // point already exists - return
57
+ return;
58
+ }
59
+ }
60
+
61
+ // push point to points if it doesn't exist
18
62
  this.points.push(point);
19
63
  };
20
64
 
21
65
  /**
22
66
  * Append points to suggested intersecting points
23
- * @param {array} points
67
+ * @param {Array} points
24
68
  */
25
69
  appendPoints(points) {
26
- this.points = this.points.concat(points);
70
+ // Forward all points through appendPoint
71
+ points.forEach((point) => {
72
+ this.appendPoint(point);
73
+ });
27
74
  };
28
75
 
76
+ /**
77
+ * Find intersections between two polylines.
78
+ * Aggregates all segment-level results and collapses the status to a binary
79
+ * outcome: {@link Intersection.Status.NONE} or {@link Intersection.Status.INTERSECTION}.
80
+ * Use this method when you only need to know whether any intersection exists
81
+ * (e.g. selection / touch tests). For granular status detail (CROSSING, TOUCHING,
82
+ * ENDPOINT, OVERLAPPING, etc.) call {@link intersectSegmentSegment} directly.
83
+ * @param {Array} points1 - boundary points array
84
+ * @param {Array} points2 - selected points array
85
+ * @param {boolean} extend - extend the selected entity
86
+ * @return {Intersection}
87
+ */
88
+ static intersectPolylinePolyline(points1, points2, extend) {
89
+ const result = new Intersection(Intersection.Status.NONE);
90
+
91
+ for (let i = 0; i < points1.length - 1; i++) {
92
+ for (let j = 0; j < points2.length - 1; j++) {
93
+ const inter = this.intersectSegmentSegment(
94
+ points1[i], points1[i + 1],
95
+ points2[j], points2[j + 1],
96
+ false, extend,
97
+ );
98
+ result.appendPoints(inter.points);
99
+ // COINCIDENT (identical concentric circles) produces no discrete points,
100
+ // so it must be promoted to INTERSECTION explicitly.
101
+ if (inter.status === Intersection.Status.COINCIDENT) {
102
+ result.status = Intersection.Status.INTERSECTION;
103
+ }
104
+ }
105
+ }
106
+
107
+ if (result.points.length > 0) result.status = Intersection.Status.INTERSECTION;
108
+ return result;
109
+ }
110
+
111
+ /**
112
+ * Find intersections between two polyline segments.
113
+ * Returns the full granular status (CROSSING, PERPENDICULAR, TOUCHING, ENDPOINT,
114
+ * OVERLAPPING, TANGENT, etc.) needed by geometric operations such as trim and extend.
115
+ * @param {Point} b1 - segment one start point
116
+ * @param {Point} b2 - segment one end point
117
+ * @param {Point} b3 - segment two start point
118
+ * @param {Point} b4 - segment two end point
119
+ * @param {boolean} extendSegOne - extend segment one to infinite form
120
+ * @param {boolean} extendSegTwo - extend segment two to infinite form
121
+ * @return {Intersection}
122
+ */
123
+ static intersectSegmentSegment(b1, b2, b3, b4, extendSegOne, extendSegTwo) {
124
+ const seg1IsArc = b1.bulge !== 0 && b1.bulge !== undefined;
125
+ const seg2IsArc = b3.bulge !== 0 && b3.bulge !== undefined;
126
+
127
+ // line vs line
128
+ if (!seg1IsArc && !seg2IsArc) {
129
+ return this.#intersectLineLine({ start: b1, end: b2 }, { start: b3, end: b4 }, extendSegOne, extendSegTwo);
130
+ }
131
+
132
+ const arc1 = seg1IsArc ? this.#buildArc(b1, b2) : null;
133
+ const arc2 = seg2IsArc ? this.#buildArc(b3, b4) : null;
134
+
135
+ let candidatePoints;
136
+ let innerStatus;
137
+
138
+ if (seg1IsArc && seg2IsArc) {
139
+ // arc vs arc
140
+ const inter = this.intersectCircleCircle(arc1, arc2);
141
+ candidatePoints = inter.points;
142
+ innerStatus = inter.status;
143
+ } else if (seg1IsArc) {
144
+ // arc(seg1) vs line(seg2)
145
+ const inter = this.intersectCircleLine(arc1, { start: b3, end: b4 }, extendSegTwo);
146
+ candidatePoints = inter.points;
147
+ innerStatus = inter.status;
148
+ } else {
149
+ // line(seg1) vs arc(seg2)
150
+ const inter = this.intersectCircleLine(arc2, { start: b1, end: b2 }, extendSegOne);
151
+ candidatePoints = inter.points;
152
+ innerStatus = inter.status;
153
+ }
154
+
155
+ const result = new Intersection(innerStatus || Intersection.Status.NONE);
156
+
157
+ for (let i = 0; i < candidatePoints.length; i++) {
158
+ const pt = candidatePoints[i];
159
+ let valid = true;
160
+
161
+ // seg1 arc filter - skipped when extending seg1
162
+ if (seg1IsArc && !extendSegOne && !pt.isOnArc(arc1.startPoint, arc1.endPoint, arc1.centre, arc1.direction)) {
163
+ valid = false;
164
+ }
165
+
166
+ // seg2 arc filter - skipped when extending seg2
167
+ if (valid && seg2IsArc && !extendSegTwo) {
168
+ if (!pt.isOnArc(arc2.startPoint, arc2.endPoint, arc2.centre, arc2.direction)) {
169
+ valid = false;
170
+ }
171
+ }
172
+
173
+ if (valid) {
174
+ result.appendPoint(pt);
175
+ }
176
+ }
177
+
178
+ if (result.points.length > 0 && result.status !== Intersection.Status.TANGENT) result.status = Intersection.Status.INTERSECTION;
179
+ return result;
180
+ }
181
+
29
182
  /**
30
183
  * Find intersections between circle and line
31
- * @param {circle} circle
32
- * @param {line} line
184
+ * @param {Circle} circle
185
+ * @param {Line} line
33
186
  * @param {boolean} extend - extend the line as a ray
34
- * @returns
187
+ * @return {Intersect}
35
188
  */
36
189
  static intersectCircleLine(circle, line, extend) {
37
190
  const c = circle.centre;
@@ -42,47 +195,49 @@ export class Intersection {
42
195
 
43
196
 
44
197
  let result;
45
- const a = (a2.x - a1.x) * (a2.x - a1.x) +
46
- (a2.y - a1.y) * (a2.y - a1.y);
47
- const b = 2 * ((a2.x - a1.x) * (a1.x - c.x) +
48
- (a2.y - a1.y) * (a1.y - c.y));
49
- const cc = c.x * c.x + c.y * c.y + a1.x * a1.x + a1.y * a1.y -
50
- 2 * (c.x * a1.x + c.y * a1.y) - r * r;
51
- const deter = b * b - 4 * a * cc;
52
-
53
- if (deter < 0) {
54
- result = new Intersection('Outside');
55
- } else if (deter == 0) {
56
- result = new Intersection('Tangent');
57
- // NOTE: should calculate this point
198
+ const lineDir = a2.subtract(a1); // direction vector of the line segment
199
+ const centreToStart = a1.subtract(c); // vector from circle centre to line start
200
+ const quadA = lineDir.dot(lineDir); // squared length of the line segment
201
+ const quadB = 2 * lineDir.dot(centreToStart); // linear coefficient (projection term)
202
+ const quadC = centreToStart.dot(centreToStart) - r * r; // constant coefficient (signed distance²)
203
+ const discriminant = quadB * quadB - 4 * quadA * quadC;
204
+
205
+ if (discriminant < 0) {
206
+ result = new Intersection(Intersection.Status.OUTSIDE);
207
+ } else if (discriminant === 0) {
208
+ result = new Intersection(Intersection.Status.TANGENT);
209
+ const u = -quadB / (2 * quadA);
210
+ if (0 <= u && u <= 1 || extend) {
211
+ result.appendPoint(a1.lerp(a2, u));
212
+ }
58
213
  } else {
59
- const e = Math.sqrt(deter);
60
- const u1 = (-b + e) / (2 * a);
61
- const u2 = (-b - e) / (2 * a);
214
+ const sqrtDiscriminant = Math.sqrt(discriminant); // square root of discriminant — half-spread between the two roots
215
+ const lineParam1 = (-quadB + sqrtDiscriminant) / (2 * quadA); // parametric t for first intersection (0 = line start, 1 = line end)
216
+ const lineParam2 = (-quadB - sqrtDiscriminant) / (2 * quadA); // parametric t for second intersection (0 = line start, 1 = line end)
62
217
 
63
- if ((u1 < 0 || u1 > 1) && (u2 < 0 || u2 > 1)) {
64
- if ((u1 < 0 && u2 < 0) || (u1 > 1 && u2 > 1)) {
65
- result = new Intersection('Outside');
218
+ if ((lineParam1 < 0 || lineParam1 > 1) && (lineParam2 < 0 || lineParam2 > 1)) {
219
+ if ((lineParam1 < 0 && lineParam2 < 0) || (lineParam1 > 1 && lineParam2 > 1)) {
220
+ result = new Intersection(Intersection.Status.OUTSIDE);
66
221
  if (extend) {
67
- result.points.push(a1.lerp(a2, u1));
68
- result.points.push(a1.lerp(a2, u2));
222
+ result.appendPoint(a1.lerp(a2, lineParam1));
223
+ result.appendPoint(a1.lerp(a2, lineParam2));
69
224
  }
70
225
  } else {
71
- result = new Intersection('Inside');
226
+ result = new Intersection(Intersection.Status.INSIDE);
72
227
  if (extend) {
73
- result.points.push(a1.lerp(a2, u1));
74
- result.points.push(a1.lerp(a2, u2));
228
+ result.appendPoint(a1.lerp(a2, lineParam1));
229
+ result.appendPoint(a1.lerp(a2, lineParam2));
75
230
  }
76
231
  }
77
232
  } else {
78
- result = new Intersection('Intersection');
233
+ result = new Intersection(Intersection.Status.INTERSECTION);
79
234
 
80
- if (0 <= u1 && u1 <= 1 || extend) {
81
- result.points.push(a1.lerp(a2, u1));
235
+ if (0 <= lineParam1 && lineParam1 <= 1 || extend) {
236
+ result.appendPoint(a1.lerp(a2, lineParam1));
82
237
  }
83
238
 
84
- if (0 <= u2 && u2 <= 1 || extend) {
85
- result.points.push(a1.lerp(a2, u2));
239
+ if (0 <= lineParam2 && lineParam2 <= 1 || extend) {
240
+ result.appendPoint(a1.lerp(a2, lineParam2));
86
241
  }
87
242
  }
88
243
  }
@@ -90,23 +245,12 @@ export class Intersection {
90
245
  return result;
91
246
  };
92
247
 
93
- /**
94
- * Find intersections between circle and line
95
- * @param {line} line
96
- * @param {circle} circle
97
- * @param {boolean} extend - extend the line as a ray
98
- * @returns
99
- */
100
- static intersectLineCircle(line, circle, extend) {
101
- return this.intersectCircleLine(circle, line, extend);
102
- }
103
-
104
248
  /**
105
249
  * Find intersections between two circles
106
- * @param {circle} circle1
107
- * @param {circle} circle2
250
+ * @param {Circle} circle1
251
+ * @param {Circle} circle2
108
252
  * @param {boolean} extend - unused
109
- * @returns
253
+ * @return {Intersect}
110
254
  */
111
255
  static intersectCircleCircle(circle1, circle2, extend) {
112
256
  const c1 = circle1.centre;
@@ -122,457 +266,186 @@ export class Intersection {
122
266
  // Determine actual distance between circle circles
123
267
  const cDist = c1.distance(c2);
124
268
 
125
- if (cDist > rMax) {
126
- result = new Intersection('Outside');
269
+ if (cDist === 0) {
270
+ result = new Intersection(r1 === r2 ? Intersection.Status.COINCIDENT : Intersection.Status.INSIDE);
271
+ } else if (cDist > rMax) {
272
+ result = new Intersection(Intersection.Status.OUTSIDE);
127
273
  } else if (cDist < rMin) {
128
- result = new Intersection('Inside');
274
+ result = new Intersection(Intersection.Status.INSIDE);
129
275
  } else {
130
- result = new Intersection('Intersection');
131
-
132
- const a = (r1 * r1 - r2 * r2 + cDist * cDist) / (2 * cDist);
133
- const h = Math.sqrt(r1 * r1 - a * a);
134
- const p = c1.lerp(c2, a / cDist);
135
- const b = h / cDist;
136
-
137
- result.points.push(
138
- new Point(
139
- p.x - b * (c2.y - c1.y),
140
- p.y + b * (c2.x - c1.x),
141
- ),
142
- );
143
- result.points.push(
144
- new Point(
145
- p.x + b * (c2.y - c1.y),
146
- p.y - b * (c2.x - c1.x),
147
- ),
148
- );
276
+ result = new Intersection(Intersection.Status.INTERSECTION);
277
+
278
+ // Distance from c1 to the radical axis along the line of centres
279
+ const axialDist = (r1 * r1 - r2 * r2 + cDist * cDist) / (2 * cDist);
280
+ // Half the length of the chord connecting the two intersection points
281
+ const halfChordLength = Math.sqrt(r1 * r1 - axialDist * axialDist);
282
+ // Point on the line of centres where the perpendicular bisector of the chord passes through
283
+ const chordMidpoint = c1.lerp(c2, axialDist / cDist);
284
+ // Normalised scale factor for the perpendicular offset
285
+ const perpScale = halfChordLength / cDist;
286
+ // Perpendicular offset vector from chordMidpoint to each intersection point
287
+ const perpOffset = new Point(-(c2.y - c1.y), c2.x - c1.x).scale(perpScale);
288
+
289
+ result.appendPoint(chordMidpoint.add(perpOffset));
290
+ result.appendPoint(chordMidpoint.subtract(perpOffset));
149
291
  }
150
292
 
151
293
  return result;
152
294
  };
153
295
 
154
296
  /**
155
- * Find intersections between arc segment and rectangle
156
- * @param {arc} arc
157
- * @param {rectangle} rectangle
158
- * @param {boolean} extend
159
- * @returns
297
+ * Build arc object from two polyline points
298
+ * @param {Point} b1 - start point with bulge
299
+ * @param {Point} b2 - end point
300
+ * @return {Object} arc with centre, startPoint, endPoint, radius, direction
160
301
  */
161
- static intersectArcRectangle(arc, rectangle, extend) {
162
- const r1 = rectangle.start;
163
- const r2 = rectangle.end;
164
-
165
- const min = r1.min(r2);
166
- const max = r1.max(r2);
167
- const topRight = new Point(max.x, min.y);
168
- const bottomLeft = new Point(min.x, max.y);
169
-
170
-
171
- let rectPoints = {start: min, end: topRight};
172
- const inter1 = this.intersectArcLine(arc, rectPoints, extend);
173
-
174
- rectPoints = {start: topRight, end: max};
175
- const inter2 = this.intersectArcLine(arc, rectPoints, extend);
176
-
177
- rectPoints = {start: max, end: bottomLeft};
178
- const inter3 = this.intersectArcLine(arc, rectPoints, extend);
179
-
180
- rectPoints = {start: bottomLeft, end: min};
181
- const inter4 = this.intersectArcLine(arc, rectPoints, extend);
182
-
183
- const result = new Intersection('No Intersection');
184
-
185
- result.appendPoints(inter1.points);
186
- result.appendPoints(inter2.points);
187
- result.appendPoints(inter3.points);
188
- result.appendPoints(inter4.points);
189
-
190
- if (result.points.length > 0) {
191
- result.status = 'Intersection';
192
- } else {
193
- result.status = inter1.status;
194
- }
195
-
196
- return result;
197
- }
198
-
199
- /**
200
- * Find intersections between arc segment and line
201
- * @param {arc} arc
202
- * @param {line} line
203
- * @param {boolean} extend
204
- * @returns
205
- */
206
- static intersectArcLine(arc, line, extend) {
207
- const inter1 = this.intersectCircleLine(arc, line, extend);
208
- const result = new Intersection('No Intersection');
209
-
210
- if (!extend) {
211
- for (let i = 0; i < inter1.points.length; i++) {
212
- if (inter1.points[i].isOnArc(arc.startPoint, arc.endPoint, arc.centre, arc.direction)) {
213
- result.appendPoints(inter1.points[i]);
214
- }
215
- }
216
-
217
- if (result.points.length > 0) {
218
- result.status = 'Intersection';
219
- }
220
- }
221
-
222
- return result;
302
+ static #buildArc(b1, b2) {
303
+ const arc = {};
304
+ arc.centre = b1.bulgeCentrePoint(b2);
305
+ arc.startPoint = b1;
306
+ arc.endPoint = b2;
307
+ arc.radius = arc.centre.distance(b1);
308
+ arc.direction = b1.bulge;
309
+ return arc;
223
310
  }
224
311
 
225
312
  /**
226
- * Find intersections between line and arc segment
227
- * @param {line} line
228
- * @param {arc} arc
229
- * @param {boolean} extend
230
- * @returns
313
+ * Find intersections between two lines
314
+ * @param {Line} line1
315
+ * @param {Line} line2
316
+ * @param {boolean} extendSegOne
317
+ * @param {boolean} extendSegTwo
318
+ * @return {Intersection}
231
319
  */
232
- static intersectLineArc(line, arc, extend) {
233
- return this.intersectArcLine(arc, line, extend);
234
- }
320
+ static #intersectLineLine(line1, line2, extendSegOne, extendSegTwo) {
321
+ const aStart = line1.start;
322
+ const aEnd = line1.end;
323
+ const bStart = line2.start;
324
+ const bEnd = line2.end;
325
+ extendSegOne = extendSegOne || false;
326
+ extendSegTwo = extendSegTwo || false;
235
327
 
236
- /**
237
- * Find intersections between circle and arc segment
238
- * @param {circle} circle
239
- * @param {arc} arc
240
- * @param {boolean} extend
241
- * @returns
242
- */
243
- static intersectCircleArc(circle, arc, extend) {
244
- const inter1 = this.intersectCircleCircle(circle, arc, extend);
245
- const result = new Intersection('No Intersection');
246
-
247
- if (!extend) {
248
- for (let i = 0; i < inter1.points.length; i++) {
249
- if (inter1.points[i].isOnArc(arc.startPoint, arc.endPoint, arc.centre, arc.direction)) {
250
- result.points.push(inter1.points[i]);
251
- }
252
- }
328
+ let result;
253
329
 
254
- if (result.points.length > 0) {
255
- result.status = 'Intersection';
256
- }
330
+ // Check if any endpoints are coincident
331
+ if (aStart.isSame(bStart)) {
332
+ result = new Intersection(Intersection.Status.ENDPOINT);
333
+ result.appendPoint(new Point(aStart.x, aStart.y));
334
+ return result;
257
335
  }
258
336
 
259
- return result;
260
- }
261
-
262
- /**
263
- * Find intersections between
264
- * @param {arc} arc
265
- * @param {circle} circle
266
- * @param {boolean} extend
267
- * @returns
268
- */
269
- static intersectArcCircle(arc, circle, extend) {
270
- return this.intersectCircleArc(circle, arc, extend);
271
- }
272
-
273
- /**
274
- * Find intersections between circle and rectangle
275
- * @param {circle} circle
276
- * @param {rectangle} rectangle
277
- * @param {boolean} extend
278
- * @returns
279
- */
280
- static intersectCircleRectangle(circle, rectangle, extend) {
281
- const r1 = rectangle.start;
282
- const r2 = rectangle.end;
283
- extend = extend || false;
284
-
285
- const min = r1.min(r2);
286
- const max = r1.max(r2);
287
- const topRight = new Point(max.x, min.y);
288
- const bottomLeft = new Point(min.x, max.y);
289
-
290
- let rectPoints = {start: min, end: topRight};
291
- const inter1 = this.intersectCircleLine(circle, rectPoints);
292
-
293
- rectPoints = {start: topRight, end: max};
294
- const inter2 = this.intersectCircleLine(circle, rectPoints);
295
-
296
- rectPoints = {start: max, end: bottomLeft};
297
- const inter3 = this.intersectCircleLine(circle, rectPoints);
337
+ if (aStart.isSame(bEnd)) {
338
+ result = new Intersection(Intersection.Status.ENDPOINT);
339
+ result.appendPoint(new Point(aStart.x, aStart.y));
340
+ return result;
341
+ }
298
342
 
299
- rectPoints = {start: bottomLeft, end: min};
300
- const inter4 = this.intersectCircleLine(circle, rectPoints);
343
+ if (aEnd.isSame(bStart)) {
344
+ result = new Intersection(Intersection.Status.ENDPOINT);
345
+ result.appendPoint(new Point(aEnd.x, aEnd.y));
346
+ return result;
347
+ }
301
348
 
302
- const result = new Intersection('No Intersection');
349
+ if (aEnd.isSame(bEnd)) {
350
+ result = new Intersection(Intersection.Status.ENDPOINT);
351
+ result.appendPoint(new Point(aEnd.x, aEnd.y));
352
+ return result;
353
+ }
303
354
 
304
- result.appendPoints(inter1.points);
305
- result.appendPoints(inter2.points);
306
- result.appendPoints(inter3.points);
307
- result.appendPoints(inter4.points);
355
+ // Check if any endpoints of one line are on the other line
356
+ if (aStart.isOnLine(bStart, bEnd)) {
357
+ result = new Intersection(Intersection.Status.TOUCHING);
358
+ result.appendPoint(new Point(aStart.x, aStart.y));
359
+ return result;
360
+ }
308
361
 
309
- if (result.points.length > 0) {
310
- result.status = 'Intersection';
311
- } else {
312
- result.status = inter1.status;
362
+ if (aEnd.isOnLine(bStart, bEnd)) {
363
+ result = new Intersection(Intersection.Status.TOUCHING);
364
+ result.appendPoint(new Point(aEnd.x, aEnd.y));
365
+ return result;
313
366
  }
314
367
 
315
- return result;
316
- };
368
+ if (bStart.isOnLine(aStart, aEnd)) {
369
+ result = new Intersection(Intersection.Status.TOUCHING);
370
+ result.appendPoint(new Point(bStart.x, bStart.y));
371
+ return result;
372
+ }
317
373
 
318
- /**
319
- * Find intersections between two lines
320
- * @param {line} line1
321
- * @param {line} line2
322
- * @param {boolean} extend
323
- * @returns
324
- */
325
- static intersectLineLine(line1, line2, extend) {
326
- const a1 = line1.start;
327
- const a2 = line1.end;
328
- const b1 = line2.start;
329
- const b2 = line2.end;
330
- extend = extend || false;
374
+ if (bEnd.isOnLine(aStart, aEnd)) {
375
+ result = new Intersection(Intersection.Status.TOUCHING);
376
+ result.appendPoint(new Point(bEnd.x, bEnd.y));
377
+ return result;
378
+ }
331
379
 
332
- let result;
380
+ // Guard against zero-length (degenerate) segments.
381
+ // Endpoint and touching cases were already handled above; anything remaining
382
+ // means the point simply does not lie on the other segment.
383
+ if (aStart.isSame(aEnd) || bStart.isSame(bEnd)) {
384
+ return new Intersection(Intersection.Status.NONE);
385
+ }
333
386
 
334
- const uaT = (b2.x - b1.x) * (a1.y - b1.y) - (b2.y - b1.y) * (a1.x - b1.x);
335
- const ubT = (a2.x - a1.x) * (a1.y - b1.y) - (a2.y - a1.y) * (a1.x - b1.x);
336
- const uB = (b2.y - b1.y) * (a2.x - a1.x) - (b2.x - b1.x) * (a2.y - a1.y);
337
-
338
- if (uB != 0) {
339
- const ua = uaT / uB;
340
- const ub = ubT / uB;
341
-
342
- if ((0 <= ua && ua <= 1) && (0 <= ub && ub <= 1) || (0 <= ua && ua <= 1) && extend) {
343
- result = new Intersection('Intersection');
344
- result.points.push(
345
- new Point(
346
- a1.x + ua * (a2.x - a1.x),
347
- a1.y + ua * (a2.y - a1.y),
348
- ),
349
- );
387
+ // Direction vectors and offset between start points
388
+ const line1Dir = aEnd.subtract(aStart);
389
+ const line2Dir = bEnd.subtract(bStart);
390
+ const startDiff = aStart.subtract(bStart);
391
+
392
+ // Normalise the cross product to |sin(angle)| so the tolerance is scale-independent
393
+ const directionCross = line1Dir.cross(line2Dir);
394
+ const line1Len = line1Dir.length();
395
+ const line2Len = line2Dir.length();
396
+ const isParallel = Math.abs(directionCross) / (line1Len * line2Len) < Constants.Tolerance.EPSILON;
397
+
398
+ if (!isParallel) {
399
+ // Lines are not parallel
400
+ // lerp parameters: 0 = segment start, 1 = segment end
401
+ const line1Lerp = line2Dir.cross(startDiff) / directionCross;
402
+ const line2Lerp = line1Dir.cross(startDiff) / directionCross;
403
+
404
+ // If both lerp values are between 0 and 1, the intersection is within the line segments
405
+ const line1InRange = 0 <= line1Lerp && line1Lerp <= 1;
406
+ const line2InRange = 0 <= line2Lerp && line2Lerp <= 1;
407
+ const isWithinSegments = line1InRange && line2InRange;
408
+ const isExtended = (line1InRange || extendSegOne) && (line2InRange || extendSegTwo);
409
+
410
+ if (isWithinSegments || isExtended) {
411
+ const isPerpendicular = Utils.round(line1Dir.dot(line2Dir)) === 0;
412
+ result = new Intersection(isPerpendicular ? Intersection.Status.PERPENDICULAR : Intersection.Status.CROSSING);
413
+ result.appendPoint(aStart.lerp(aEnd, line1Lerp));
350
414
  } else {
351
- result = new Intersection('No Intersection');
415
+ result = new Intersection(Intersection.Status.NONE);
352
416
  }
353
417
  } else {
354
- if (uaT == 0 || ubT == 0) {
355
- result = new Intersection('Coincident');
356
- } else {
357
- result = new Intersection('Parallel');
358
- }
359
- }
360
-
361
- return result;
362
- };
363
-
364
- /**
365
- * Find intersections between lwpolyline and line
366
- * @param {polyline} polyline
367
- * @param {line} line
368
- * @param {boolean} extend
369
- * @returns
370
- */
371
- static intersectLwpolylineLine(polyline, line, extend) {
372
- return this.intersectPolylineLine(polyline, line, extend);
373
- }
374
-
375
- /**
376
- * Find intersections between polyline and line
377
- * @param {polyline} polyline
378
- * @param {line} line
379
- * @param {boolean} extend
380
- * @returns
381
- */
382
- static intersectPolylineLine(polyline, line, extend) {
383
- const result = new Intersection('No Intersection');
384
- const length = polyline.points.length;
385
-
386
- for (let i = 0; i < length - 1; i++) {
387
- const b1 = polyline.points[i];
388
- const b2 = polyline.points[(i + 1) % length];
389
-
390
-
391
- if (b1.bulge === 0) {
392
- const line2 = {start: b1, end: b2};
393
- const inter = this.intersectLineLine(line2, line, extend);
394
- result.appendPoints(inter.points);
418
+ // Lines are parallel or coincident
419
+ const startDiffLen = startDiff.length();
420
+ const isCollinear = startDiffLen < Constants.Tolerance.EPSILON ||
421
+ Math.abs(line2Dir.cross(startDiff)) / (line2Len * startDiffLen) < Constants.Tolerance.EPSILON;
422
+ if (isCollinear) {
423
+ // Lines are collinear — check whether the segments actually overlap
424
+ // Project all four endpoints onto the shared direction axis
425
+ const len2 = line1Dir.x * line1Dir.x + line1Dir.y * line1Dir.y;
426
+ const t0 = 0; // aStart projects to 0
427
+ const t1 = 1; // aEnd projects to 1 (parametric)
428
+ const t2 = (bStart.subtract(aStart).x * line1Dir.x + bStart.subtract(aStart).y * line1Dir.y) / len2;
429
+ const t3 = (bEnd.subtract(aStart).x * line1Dir.x + bEnd.subtract(aStart).y * line1Dir.y) / len2;
430
+
431
+ const bMin = Math.min(t2, t3);
432
+ const bMax = Math.max(t2, t3);
433
+
434
+ if (bMax < t0 || bMin > t1) {
435
+ // Segments are collinear but disjoint
436
+ result = new Intersection(Intersection.Status.NONE);
437
+ } else {
438
+ // Segments overlap — return the two endpoints of the shared interval
439
+ result = new Intersection(Intersection.Status.OVERLAPPING);
440
+ result.appendPoint(aStart.lerp(aEnd, Math.max(t0, bMin)));
441
+ result.appendPoint(aStart.lerp(aEnd, Math.min(t1, bMax)));
442
+ }
395
443
  } else {
396
- const arc = {};
397
- arc.centre = b1.bulgeCentrePoint(b2);
398
- arc.startPoint = b1;
399
- arc.endPoint = b2;
400
- arc.radius = arc.centre.distance(b1);
401
- arc.direction = b1.bulge;
402
-
403
- const interArc = this.intersectArcLine(arc, line, extend);
404
- result.appendPoints(interArc.points);
444
+ // Lines are parallel but not coincident
445
+ result = new Intersection(Intersection.Status.PARALLEL);
405
446
  }
406
447
  }
407
448
 
408
- if (result.points.length > 0) result.status = 'Intersection';
409
- return result;
410
- };
411
-
412
- /**
413
- * Find intersections between lwpolyline and rectangle
414
- * @param {polyline} polyline
415
- * @param {rectangle} rectangle
416
- * @param {boolean} extend
417
- * @returns
418
- */
419
- static intersectLwpolylineRectangle(polyline, rectangle, extend) {
420
- return this.intersectPolylineRectangle(polyline, rectangle, extend);
421
- }
422
-
423
- /**
424
- * Find intersections between polyline and rectangle
425
- * @param {polyline} polyline
426
- * @param {rectangle} rectangle
427
- * @param {boolean} extend
428
- * @returns
429
- */
430
- static intersectPolylineRectangle(polyline, rectangle, extend) {
431
- const r1 = rectangle.start;
432
- const r2 = rectangle.end;
433
- extend = extend || false;
434
-
435
- const min = r1.min(r2);
436
- const max = r1.max(r2);
437
- const topRight = new Point(max.x, min.y);
438
- const bottomLeft = new Point(min.x, max.y);
439
-
440
- let rectPoints = {start: min, end: topRight};
441
- const inter1 = this.intersectPolylineLine(polyline, rectPoints, extend);
442
-
443
- rectPoints = {start: topRight, end: max};
444
- const inter2 = this.intersectPolylineLine(polyline, rectPoints, extend);
445
-
446
- rectPoints = {start: max, end: bottomLeft};
447
- const inter3 = this.intersectPolylineLine(polyline, rectPoints, extend);
448
-
449
- rectPoints = {start: bottomLeft, end: min};
450
- const inter4 = this.intersectPolylineLine(polyline, rectPoints, extend);
451
-
452
- const result = new Intersection('No Intersection');
453
-
454
- result.appendPoints(inter1.points);
455
- result.appendPoints(inter2.points);
456
- result.appendPoints(inter3.points);
457
- result.appendPoints(inter4.points);
458
-
459
- if (result.points.length > 0) {
460
- result.status = 'Intersection';
461
- }
462
-
463
- return result;
464
- };
465
-
466
-
467
- /**
468
- * Find intersections between line and rectangle
469
- * @param {line} line
470
- * @param {rectangle} rectangle
471
- * @param {boolean} extend
472
- * @returns
473
- */
474
- static intersectLineRectangle(line, rectangle, extend) {
475
- const r1 = rectangle.start;
476
- const r2 = rectangle.end;
477
- extend = extend || false;
478
-
479
- const min = r1.min(r2);
480
- const max = r1.max(r2);
481
- const topRight = new Point(max.x, min.y);
482
- const bottomLeft = new Point(min.x, max.y);
483
-
484
- let rectPoints = {start: min, end: topRight};
485
- const inter1 = this.intersectLineLine(rectPoints, line, extend);
486
-
487
- rectPoints = {start: topRight, end: max};
488
- const inter2 = this.intersectLineLine(rectPoints, line, extend);
489
-
490
- rectPoints = {start: max, end: bottomLeft};
491
- const inter3 = this.intersectLineLine(rectPoints, line, extend);
492
-
493
- rectPoints = {start: bottomLeft, end: min};
494
- const inter4 = this.intersectLineLine(rectPoints, line, extend);
495
-
496
- const result = new Intersection('No Intersection');
497
-
498
- result.appendPoints(inter1.points);
499
- result.appendPoints(inter2.points);
500
- result.appendPoints(inter3.points);
501
- result.appendPoints(inter4.points);
502
-
503
- if (result.points.length > 0) {
504
- result.status = 'Intersection';
505
- }
506
-
507
- return result;
508
- };
509
-
510
- /**
511
- * Find intersections between rectangle and line
512
- * @param {rectangle} rectangle
513
- * @param {line} line
514
- * @param {boolean} extend
515
- * @returns
516
- */
517
- static intersectRectangleLine(rectangle, line, extend) {
518
- return this.intersectLineRectangle(line, rectangle, extend);
519
- }
520
-
521
- /**
522
- * Find intersections between text and rectangles
523
- * Text is represented by its bounding box
524
- * @param {text} text
525
- * @param {rectangle} rectangle
526
- * @param {boolean} extend
527
- * @returns
528
- */
529
- static intersectTextRectangle(text, rectangle, extend) {
530
- return this.intersectRectangleRectangle(text, rectangle, extend);
531
- }
532
-
533
- /**
534
- * Find intersections between two rectangles
535
- * @param {rectangle} rectangle1
536
- * @param {rectangle} rectangle2
537
- * @param {boolean} extend
538
- * @returns
539
- */
540
- static intersectRectangleRectangle(rectangle1, rectangle2, extend) {
541
- const a1 = rectangle1.start;
542
- const a2 = rectangle1.end;
543
- // const b1 = rectangle2.start;
544
- // const b2 = rectangle2.end;
545
- extend = extend || false;
546
-
547
-
548
- const min = a1.min(a2);
549
- const max = a1.max(a2);
550
- const topRight = new Point(max.x, min.y);
551
- const bottomLeft = new Point(min.x, max.y);
552
-
553
- let rectPoints = {start: min, end: topRight};
554
- const inter1 = this.intersectLineRectangle(rectPoints, rectangle2);
555
-
556
- rectPoints = {start: topRight, end: max};
557
- const inter2 = this.intersectLineRectangle(rectPoints, rectangle2);
558
-
559
- rectPoints = {start: max, end: bottomLeft};
560
- const inter3 = this.intersectLineRectangle(rectPoints, rectangle2);
561
-
562
- rectPoints = {start: bottomLeft, end: min};
563
- const inter4 = this.intersectLineRectangle(rectPoints, rectangle2);
564
-
565
- const result = new Intersection('No Intersection');
566
-
567
- result.appendPoints(inter1.points);
568
- result.appendPoints(inter2.points);
569
- result.appendPoints(inter3.points);
570
- result.appendPoints(inter4.points);
571
-
572
- if (result.points.length > 0) {
573
- result.status = 'Intersection';
574
- }
575
-
576
449
  return result;
577
450
  };
578
451
  }