@rxflow/manhattan 0.0.2 → 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 (176) hide show
  1. package/cjs/geometry/Line.d.ts +21 -0
  2. package/cjs/geometry/Line.d.ts.map +1 -0
  3. package/cjs/geometry/Line.js +88 -0
  4. package/cjs/geometry/Point.d.ts +49 -0
  5. package/cjs/geometry/Point.d.ts.map +1 -0
  6. package/cjs/geometry/Point.js +94 -0
  7. package/cjs/geometry/Rectangle.d.ts +41 -0
  8. package/cjs/geometry/Rectangle.d.ts.map +1 -0
  9. package/cjs/geometry/Rectangle.js +65 -0
  10. package/cjs/geometry/collision.d.ts +15 -0
  11. package/cjs/geometry/collision.d.ts.map +1 -0
  12. package/cjs/geometry/collision.js +81 -0
  13. package/cjs/geometry/index.d.ts +5 -0
  14. package/cjs/geometry/index.d.ts.map +1 -0
  15. package/cjs/geometry/index.js +45 -0
  16. package/cjs/getManHattanPath.d.ts +53 -0
  17. package/cjs/getManHattanPath.d.ts.map +1 -0
  18. package/cjs/getManHattanPath.js +449 -0
  19. package/cjs/index.d.ts +16 -0
  20. package/cjs/index.d.ts.map +1 -0
  21. package/cjs/index.js +117 -0
  22. package/cjs/obstacle/ObstacleMap.d.ts +66 -0
  23. package/cjs/obstacle/ObstacleMap.d.ts.map +1 -0
  24. package/cjs/obstacle/ObstacleMap.js +328 -0
  25. package/cjs/obstacle/QuadTree.d.ts +119 -0
  26. package/cjs/obstacle/QuadTree.d.ts.map +1 -0
  27. package/cjs/obstacle/QuadTree.js +334 -0
  28. package/cjs/obstacle/index.d.ts +2 -0
  29. package/cjs/obstacle/index.d.ts.map +1 -0
  30. package/cjs/obstacle/index.js +12 -0
  31. package/cjs/options/defaults.d.ts +16 -0
  32. package/cjs/options/defaults.d.ts.map +1 -0
  33. package/cjs/options/defaults.js +39 -0
  34. package/cjs/options/index.d.ts +4 -0
  35. package/cjs/options/index.d.ts.map +1 -0
  36. package/cjs/options/index.js +38 -0
  37. package/cjs/options/resolver.d.ts +10 -0
  38. package/cjs/options/resolver.d.ts.map +1 -0
  39. package/cjs/options/resolver.js +248 -0
  40. package/cjs/options/types.d.ts +210 -0
  41. package/cjs/options/types.d.ts.map +1 -0
  42. package/cjs/options/types.js +5 -0
  43. package/cjs/pathfinder/PathCache.d.ts +92 -0
  44. package/cjs/pathfinder/PathCache.d.ts.map +1 -0
  45. package/cjs/pathfinder/PathCache.js +249 -0
  46. package/cjs/pathfinder/SortedSet.d.ts +35 -0
  47. package/cjs/pathfinder/SortedSet.d.ts.map +1 -0
  48. package/cjs/pathfinder/SortedSet.js +95 -0
  49. package/cjs/pathfinder/findRoute.d.ts +8 -0
  50. package/cjs/pathfinder/findRoute.d.ts.map +1 -0
  51. package/cjs/pathfinder/findRoute.js +395 -0
  52. package/cjs/pathfinder/index.d.ts +4 -0
  53. package/cjs/pathfinder/index.d.ts.map +1 -0
  54. package/cjs/pathfinder/index.js +44 -0
  55. package/cjs/svg/index.d.ts +3 -0
  56. package/cjs/svg/index.d.ts.map +1 -0
  57. package/cjs/svg/index.js +31 -0
  58. package/cjs/svg/pathConverter.d.ts +23 -0
  59. package/cjs/svg/pathConverter.d.ts.map +1 -0
  60. package/cjs/svg/pathConverter.js +285 -0
  61. package/cjs/svg/pathParser.d.ts +11 -0
  62. package/cjs/svg/pathParser.d.ts.map +1 -0
  63. package/cjs/svg/pathParser.js +76 -0
  64. package/cjs/utils/AdaptiveStepCalculator.d.ts +90 -0
  65. package/cjs/utils/AdaptiveStepCalculator.d.ts.map +1 -0
  66. package/cjs/utils/AdaptiveStepCalculator.js +224 -0
  67. package/cjs/utils/ErrorRecovery.d.ts +182 -0
  68. package/cjs/utils/ErrorRecovery.d.ts.map +1 -0
  69. package/cjs/utils/ErrorRecovery.js +413 -0
  70. package/cjs/utils/GlobalGrid.d.ts +99 -0
  71. package/cjs/utils/GlobalGrid.d.ts.map +1 -0
  72. package/cjs/utils/GlobalGrid.js +224 -0
  73. package/cjs/utils/PerformanceMonitor.d.ts +139 -0
  74. package/cjs/utils/PerformanceMonitor.d.ts.map +1 -0
  75. package/cjs/utils/PerformanceMonitor.js +305 -0
  76. package/cjs/utils/direction.d.ts +24 -0
  77. package/cjs/utils/direction.d.ts.map +1 -0
  78. package/cjs/utils/direction.js +54 -0
  79. package/cjs/utils/getAnchorPoints.d.ts +15 -0
  80. package/cjs/utils/getAnchorPoints.d.ts.map +1 -0
  81. package/cjs/utils/getAnchorPoints.js +71 -0
  82. package/cjs/utils/grid.d.ts +42 -0
  83. package/cjs/utils/grid.d.ts.map +1 -0
  84. package/cjs/utils/grid.js +73 -0
  85. package/cjs/utils/heuristics.d.ts +61 -0
  86. package/cjs/utils/heuristics.d.ts.map +1 -0
  87. package/cjs/utils/heuristics.js +141 -0
  88. package/cjs/utils/index.d.ts +14 -0
  89. package/cjs/utils/index.d.ts.map +1 -0
  90. package/cjs/utils/index.js +148 -0
  91. package/cjs/utils/node.d.ts +27 -0
  92. package/cjs/utils/node.d.ts.map +1 -0
  93. package/cjs/utils/node.js +36 -0
  94. package/cjs/utils/pathProcessing.d.ts +45 -0
  95. package/cjs/utils/pathProcessing.d.ts.map +1 -0
  96. package/cjs/utils/pathProcessing.js +270 -0
  97. package/cjs/utils/pathValidation.d.ts +11 -0
  98. package/cjs/utils/pathValidation.d.ts.map +1 -0
  99. package/cjs/utils/pathValidation.js +129 -0
  100. package/cjs/utils/rect.d.ts +9 -0
  101. package/cjs/utils/rect.d.ts.map +1 -0
  102. package/cjs/utils/rect.js +110 -0
  103. package/cjs/utils/route.d.ts +19 -0
  104. package/cjs/utils/route.d.ts.map +1 -0
  105. package/cjs/utils/route.js +92 -0
  106. package/esm/geometry/Line.d.ts +21 -0
  107. package/esm/geometry/Line.d.ts.map +1 -0
  108. package/esm/geometry/Point.d.ts +49 -0
  109. package/esm/geometry/Point.d.ts.map +1 -0
  110. package/esm/geometry/Rectangle.d.ts +41 -0
  111. package/esm/geometry/Rectangle.d.ts.map +1 -0
  112. package/esm/geometry/collision.d.ts +15 -0
  113. package/esm/geometry/collision.d.ts.map +1 -0
  114. package/esm/geometry/index.d.ts +5 -0
  115. package/esm/geometry/index.d.ts.map +1 -0
  116. package/esm/getManHattanPath.d.ts +53 -0
  117. package/esm/getManHattanPath.d.ts.map +1 -0
  118. package/esm/index.d.ts +16 -0
  119. package/esm/index.d.ts.map +1 -0
  120. package/esm/obstacle/ObstacleMap.d.ts +66 -0
  121. package/esm/obstacle/ObstacleMap.d.ts.map +1 -0
  122. package/esm/obstacle/QuadTree.d.ts +119 -0
  123. package/esm/obstacle/QuadTree.d.ts.map +1 -0
  124. package/esm/obstacle/index.d.ts +2 -0
  125. package/esm/obstacle/index.d.ts.map +1 -0
  126. package/esm/options/defaults.d.ts +16 -0
  127. package/esm/options/defaults.d.ts.map +1 -0
  128. package/esm/options/index.d.ts +4 -0
  129. package/esm/options/index.d.ts.map +1 -0
  130. package/esm/options/resolver.d.ts +10 -0
  131. package/esm/options/resolver.d.ts.map +1 -0
  132. package/esm/options/types.d.ts +210 -0
  133. package/esm/options/types.d.ts.map +1 -0
  134. package/esm/pathfinder/PathCache.d.ts +92 -0
  135. package/esm/pathfinder/PathCache.d.ts.map +1 -0
  136. package/esm/pathfinder/SortedSet.d.ts +35 -0
  137. package/esm/pathfinder/SortedSet.d.ts.map +1 -0
  138. package/esm/pathfinder/findRoute.d.ts +8 -0
  139. package/esm/pathfinder/findRoute.d.ts.map +1 -0
  140. package/esm/pathfinder/index.d.ts +4 -0
  141. package/esm/pathfinder/index.d.ts.map +1 -0
  142. package/esm/svg/index.d.ts +3 -0
  143. package/esm/svg/index.d.ts.map +1 -0
  144. package/esm/svg/pathConverter.d.ts +23 -0
  145. package/esm/svg/pathConverter.d.ts.map +1 -0
  146. package/esm/svg/pathParser.d.ts +11 -0
  147. package/esm/svg/pathParser.d.ts.map +1 -0
  148. package/esm/utils/AdaptiveStepCalculator.d.ts +90 -0
  149. package/esm/utils/AdaptiveStepCalculator.d.ts.map +1 -0
  150. package/esm/utils/ErrorRecovery.d.ts +182 -0
  151. package/esm/utils/ErrorRecovery.d.ts.map +1 -0
  152. package/esm/utils/GlobalGrid.d.ts +99 -0
  153. package/esm/utils/GlobalGrid.d.ts.map +1 -0
  154. package/esm/utils/PerformanceMonitor.d.ts +139 -0
  155. package/esm/utils/PerformanceMonitor.d.ts.map +1 -0
  156. package/esm/utils/direction.d.ts +24 -0
  157. package/esm/utils/direction.d.ts.map +1 -0
  158. package/esm/utils/getAnchorPoints.d.ts +15 -0
  159. package/esm/utils/getAnchorPoints.d.ts.map +1 -0
  160. package/esm/utils/grid.d.ts +42 -0
  161. package/esm/utils/grid.d.ts.map +1 -0
  162. package/esm/utils/heuristics.d.ts +61 -0
  163. package/esm/utils/heuristics.d.ts.map +1 -0
  164. package/esm/utils/index.d.ts +14 -0
  165. package/esm/utils/index.d.ts.map +1 -0
  166. package/esm/utils/node.d.ts +27 -0
  167. package/esm/utils/node.d.ts.map +1 -0
  168. package/esm/utils/pathProcessing.d.ts +45 -0
  169. package/esm/utils/pathProcessing.d.ts.map +1 -0
  170. package/esm/utils/pathValidation.d.ts +11 -0
  171. package/esm/utils/pathValidation.d.ts.map +1 -0
  172. package/esm/utils/rect.d.ts +9 -0
  173. package/esm/utils/rect.d.ts.map +1 -0
  174. package/esm/utils/route.d.ts +19 -0
  175. package/esm/utils/route.d.ts.map +1 -0
  176. package/package.json +1 -1
@@ -0,0 +1,285 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.countCorners = countCorners;
7
+ exports.hasRoundedCorners = hasRoundedCorners;
8
+ exports.pointsToPath = pointsToPath;
9
+ exports.pointsToPathCubic = pointsToPathCubic;
10
+ exports.snapPathToGrid = snapPathToGrid;
11
+ /**
12
+ * Check if three points form a corner (direction change)
13
+ */
14
+ function isCorner(prev, current, next) {
15
+ const dx1 = current.x - prev.x;
16
+ const dy1 = current.y - prev.y;
17
+ const dx2 = next.x - current.x;
18
+ const dy2 = next.y - current.y;
19
+
20
+ // Check if direction changes (not collinear)
21
+ // For Manhattan paths, this means one segment is horizontal and the other is vertical
22
+ const isHorizontal1 = Math.abs(dy1) < 0.001;
23
+ const isVertical1 = Math.abs(dx1) < 0.001;
24
+ const isHorizontal2 = Math.abs(dy2) < 0.001;
25
+ const isVertical2 = Math.abs(dx2) < 0.001;
26
+
27
+ // Corner exists if one segment is horizontal and the other is vertical
28
+ return isHorizontal1 && isVertical2 || isVertical1 && isHorizontal2;
29
+ }
30
+
31
+ /**
32
+ * Calculate optimal border radius for a corner
33
+ * Ensures the radius doesn't exceed half the length of adjacent segments
34
+ */
35
+ function calculateOptimalRadius(prev, current, next, maxRadius) {
36
+ const dx1 = current.x - prev.x;
37
+ const dy1 = current.y - prev.y;
38
+ const dx2 = next.x - current.x;
39
+ const dy2 = next.y - current.y;
40
+ const dist1 = Math.sqrt(dx1 * dx1 + dy1 * dy1);
41
+ const dist2 = Math.sqrt(dx2 * dx2 + dy2 * dy2);
42
+
43
+ // Use the smaller of maxRadius or half the segment length
44
+ return Math.min(maxRadius, dist1 / 2, dist2 / 2);
45
+ }
46
+
47
+ /**
48
+ * Convert array of points to SVG path string
49
+ */
50
+ function pointsToPath(points, precision, borderRadius = 0) {
51
+ if (points.length === 0) {
52
+ return '';
53
+ }
54
+ const factor = Math.pow(10, precision);
55
+ const roundCoord = value => Math.round(value * factor) / factor;
56
+
57
+ // If no border radius or only 2 points, use simple line path
58
+ if (borderRadius === 0 || points.length <= 2) {
59
+ const firstPoint = points[0];
60
+ let path = `M ${roundCoord(firstPoint.x)} ${roundCoord(firstPoint.y)}`;
61
+ for (let i = 1; i < points.length; i++) {
62
+ const point = points[i];
63
+ path += ` L ${roundCoord(point.x)} ${roundCoord(point.y)}`;
64
+ }
65
+ return path;
66
+ }
67
+
68
+ // Start with M (moveTo) command for first point
69
+ const firstPoint = points[0];
70
+ let path = `M ${roundCoord(firstPoint.x)} ${roundCoord(firstPoint.y)}`;
71
+
72
+ // Process each segment with rounded corners
73
+ for (let i = 1; i < points.length - 1; i++) {
74
+ const prev = points[i - 1];
75
+ const current = points[i];
76
+ const next = points[i + 1];
77
+
78
+ // Check if this is actually a corner
79
+ if (!isCorner(prev, current, next)) {
80
+ // Not a corner, just draw a line to current point
81
+ path += ` L ${roundCoord(current.x)} ${roundCoord(current.y)}`;
82
+ continue;
83
+ }
84
+
85
+ // Calculate direction vectors
86
+ const dx1 = current.x - prev.x;
87
+ const dy1 = current.y - prev.y;
88
+ const dx2 = next.x - current.x;
89
+ const dy2 = next.y - current.y;
90
+
91
+ // Calculate distances
92
+ const dist1 = Math.sqrt(dx1 * dx1 + dy1 * dy1);
93
+ const dist2 = Math.sqrt(dx2 * dx2 + dy2 * dy2);
94
+
95
+ // Use the smaller of borderRadius or half the segment length
96
+ const radius = calculateOptimalRadius(prev, current, next, borderRadius);
97
+
98
+ // Skip if radius is too small
99
+ if (radius < 0.5) {
100
+ path += ` L ${roundCoord(current.x)} ${roundCoord(current.y)}`;
101
+ continue;
102
+ }
103
+
104
+ // Normalize direction vectors
105
+ const ndx1 = dx1 / dist1;
106
+ const ndy1 = dy1 / dist1;
107
+ const ndx2 = dx2 / dist2;
108
+ const ndy2 = dy2 / dist2;
109
+
110
+ // Calculate the point before the corner
111
+ const beforeCorner = {
112
+ x: current.x - ndx1 * radius,
113
+ y: current.y - ndy1 * radius
114
+ };
115
+
116
+ // Calculate the point after the corner
117
+ const afterCorner = {
118
+ x: current.x + ndx2 * radius,
119
+ y: current.y + ndy2 * radius
120
+ };
121
+
122
+ // Draw line to the point before corner
123
+ path += ` L ${roundCoord(beforeCorner.x)} ${roundCoord(beforeCorner.y)}`;
124
+
125
+ // Draw quadratic bezier curve for the rounded corner
126
+ // The control point is the actual corner point
127
+ path += ` Q ${roundCoord(current.x)} ${roundCoord(current.y)} ${roundCoord(afterCorner.x)} ${roundCoord(afterCorner.y)}`;
128
+ }
129
+
130
+ // Draw line to the last point
131
+ const lastPoint = points[points.length - 1];
132
+ path += ` L ${roundCoord(lastPoint.x)} ${roundCoord(lastPoint.y)}`;
133
+ return path;
134
+ }
135
+
136
+ /**
137
+ * Convert array of points to SVG path string with cubic bezier curves
138
+ * Provides smoother corners than quadratic bezier
139
+ */
140
+ function pointsToPathCubic(points, precision, borderRadius = 0) {
141
+ if (points.length === 0) {
142
+ return '';
143
+ }
144
+ const factor = Math.pow(10, precision);
145
+ const roundCoord = value => Math.round(value * factor) / factor;
146
+
147
+ // If no border radius or only 2 points, use simple line path
148
+ if (borderRadius === 0 || points.length <= 2) {
149
+ const firstPoint = points[0];
150
+ let path = `M ${roundCoord(firstPoint.x)} ${roundCoord(firstPoint.y)}`;
151
+ for (let i = 1; i < points.length; i++) {
152
+ const point = points[i];
153
+ path += ` L ${roundCoord(point.x)} ${roundCoord(point.y)}`;
154
+ }
155
+ return path;
156
+ }
157
+
158
+ // Start with M (moveTo) command for first point
159
+ const firstPoint = points[0];
160
+ let path = `M ${roundCoord(firstPoint.x)} ${roundCoord(firstPoint.y)}`;
161
+
162
+ // Process each segment with rounded corners using cubic bezier
163
+ for (let i = 1; i < points.length - 1; i++) {
164
+ const prev = points[i - 1];
165
+ const current = points[i];
166
+ const next = points[i + 1];
167
+
168
+ // Check if this is actually a corner
169
+ if (!isCorner(prev, current, next)) {
170
+ path += ` L ${roundCoord(current.x)} ${roundCoord(current.y)}`;
171
+ continue;
172
+ }
173
+
174
+ // Calculate direction vectors
175
+ const dx1 = current.x - prev.x;
176
+ const dy1 = current.y - prev.y;
177
+ const dx2 = next.x - current.x;
178
+ const dy2 = next.y - current.y;
179
+
180
+ // Calculate distances
181
+ const dist1 = Math.sqrt(dx1 * dx1 + dy1 * dy1);
182
+ const dist2 = Math.sqrt(dx2 * dx2 + dy2 * dy2);
183
+
184
+ // Use the smaller of borderRadius or half the segment length
185
+ const radius = calculateOptimalRadius(prev, current, next, borderRadius);
186
+
187
+ // Skip if radius is too small
188
+ if (radius < 0.5) {
189
+ path += ` L ${roundCoord(current.x)} ${roundCoord(current.y)}`;
190
+ continue;
191
+ }
192
+
193
+ // Normalize direction vectors
194
+ const ndx1 = dx1 / dist1;
195
+ const ndy1 = dy1 / dist1;
196
+ const ndx2 = dx2 / dist2;
197
+ const ndy2 = dy2 / dist2;
198
+
199
+ // Calculate the point before the corner
200
+ const beforeCorner = {
201
+ x: current.x - ndx1 * radius,
202
+ y: current.y - ndy1 * radius
203
+ };
204
+
205
+ // Calculate the point after the corner
206
+ const afterCorner = {
207
+ x: current.x + ndx2 * radius,
208
+ y: current.y + ndy2 * radius
209
+ };
210
+
211
+ // Draw line to the point before corner
212
+ path += ` L ${roundCoord(beforeCorner.x)} ${roundCoord(beforeCorner.y)}`;
213
+
214
+ // Draw cubic bezier curve for smoother rounded corner
215
+ // Control points are positioned to create a smooth arc
216
+ const cp1 = {
217
+ x: beforeCorner.x + ndx1 * radius * 0.55,
218
+ y: beforeCorner.y + ndy1 * radius * 0.55
219
+ };
220
+ const cp2 = {
221
+ x: afterCorner.x - ndx2 * radius * 0.55,
222
+ y: afterCorner.y - ndy2 * radius * 0.55
223
+ };
224
+ path += ` C ${roundCoord(cp1.x)} ${roundCoord(cp1.y)} ${roundCoord(cp2.x)} ${roundCoord(cp2.y)} ${roundCoord(afterCorner.x)} ${roundCoord(afterCorner.y)}`;
225
+ }
226
+
227
+ // Draw line to the last point
228
+ const lastPoint = points[points.length - 1];
229
+ path += ` L ${roundCoord(lastPoint.x)} ${roundCoord(lastPoint.y)}`;
230
+ return path;
231
+ }
232
+
233
+ /**
234
+ * Snap path to grid by aligning consecutive points
235
+ */
236
+ function snapPathToGrid(points, gridSize) {
237
+ if (points.length <= 1) {
238
+ return points;
239
+ }
240
+ const snappedPoints = [...points];
241
+
242
+ // Don't snap the first and last points (anchors)
243
+ // Don't snap the second and second-to-last points (extension points)
244
+ // Only snap intermediate segments
245
+ for (let i = 2; i < snappedPoints.length - 3; i++) {
246
+ const first = snappedPoints[i];
247
+ const second = snappedPoints[i + 1];
248
+ if (first.x === second.x) {
249
+ // Vertical line - snap X coordinate
250
+ const x = gridSize * Math.round(first.x / gridSize);
251
+ if (first.x !== x) {
252
+ first.x = x;
253
+ second.x = x;
254
+ }
255
+ } else if (first.y === second.y) {
256
+ // Horizontal line - snap Y coordinate
257
+ const y = gridSize * Math.round(first.y / gridSize);
258
+ if (first.y !== y) {
259
+ first.y = y;
260
+ second.y = y;
261
+ }
262
+ }
263
+ }
264
+ return snappedPoints;
265
+ }
266
+
267
+ /**
268
+ * Check if an SVG path contains rounded corners (Q or C commands)
269
+ */
270
+ function hasRoundedCorners(path) {
271
+ return /[QC]\s/.test(path);
272
+ }
273
+
274
+ /**
275
+ * Count the number of corners in a path
276
+ */
277
+ function countCorners(points) {
278
+ let corners = 0;
279
+ for (let i = 1; i < points.length - 1; i++) {
280
+ if (isCorner(points[i - 1], points[i], points[i + 1])) {
281
+ corners++;
282
+ }
283
+ }
284
+ return corners;
285
+ }
@@ -0,0 +1,11 @@
1
+ import { Point } from '../geometry';
2
+ /**
3
+ * Parse SVG path string to extract points
4
+ * Simplified parser that handles M, L, Q commands
5
+ */
6
+ export declare function parseSVGPath(pathString: string): Point[];
7
+ /**
8
+ * Simplify path by removing collinear intermediate points
9
+ */
10
+ export declare function simplifyPath(points: Point[]): Point[];
11
+ //# sourceMappingURL=pathParser.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pathParser.d.ts","sourceRoot":"","sources":["../../src/svg/pathParser.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAA;AAEnC;;;GAGG;AACH,wBAAgB,YAAY,CAAC,UAAU,EAAE,MAAM,GAAG,KAAK,EAAE,CA2CxD;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,KAAK,EAAE,GAAG,KAAK,EAAE,CA0BrD"}
@@ -0,0 +1,76 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.parseSVGPath = parseSVGPath;
7
+ exports.simplifyPath = simplifyPath;
8
+ var _geometry = require("../geometry");
9
+ /**
10
+ * Parse SVG path string to extract points
11
+ * Simplified parser that handles M, L, Q commands
12
+ */
13
+ function parseSVGPath(pathString) {
14
+ const points = [];
15
+ const commands = pathString.match(/[MLQ][^MLQ]*/g);
16
+ if (!commands) return points;
17
+ for (const command of commands) {
18
+ const type = command[0];
19
+ const coords = command.slice(1).trim().split(/[\s,]+/).map(Number);
20
+ if (type === 'M' || type === 'L') {
21
+ // MoveTo or LineTo: x, y
22
+ if (coords.length >= 2) {
23
+ points.push(new _geometry.Point(coords[0], coords[1]));
24
+ }
25
+ } else if (type === 'Q') {
26
+ // Quadratic Bezier: cx, cy, x, y
27
+ // We sample points along the curve for collision detection
28
+ if (coords.length >= 4) {
29
+ const prevPoint = points[points.length - 1];
30
+ if (prevPoint) {
31
+ const cx = coords[0];
32
+ const cy = coords[1];
33
+ const x = coords[2];
34
+ const y = coords[3];
35
+
36
+ // Sample 10 points along the bezier curve for better accuracy
37
+ // This ensures we don't miss intersections with obstacles
38
+ for (let t = 0.1; t <= 1; t += 0.1) {
39
+ const bx = (1 - t) * (1 - t) * prevPoint.x + 2 * (1 - t) * t * cx + t * t * x;
40
+ const by = (1 - t) * (1 - t) * prevPoint.y + 2 * (1 - t) * t * cy + t * t * y;
41
+ points.push(new _geometry.Point(bx, by));
42
+ }
43
+ }
44
+ }
45
+ }
46
+ }
47
+ return points;
48
+ }
49
+
50
+ /**
51
+ * Simplify path by removing collinear intermediate points
52
+ */
53
+ function simplifyPath(points) {
54
+ if (points.length <= 2) {
55
+ return points;
56
+ }
57
+ const simplified = [points[0]];
58
+ for (let i = 1; i < points.length - 1; i++) {
59
+ const prev = simplified[simplified.length - 1];
60
+ const current = points[i];
61
+ const next = points[i + 1];
62
+
63
+ // Check if current point is collinear with prev and next
64
+ const isHorizontalLine = prev.y === current.y && current.y === next.y;
65
+ const isVerticalLine = prev.x === current.x && current.x === next.x;
66
+
67
+ // Only keep the point if it's not collinear (i.e., it's a corner)
68
+ if (!isHorizontalLine && !isVerticalLine) {
69
+ simplified.push(current);
70
+ }
71
+ }
72
+
73
+ // Always add the last point
74
+ simplified.push(points[points.length - 1]);
75
+ return simplified;
76
+ }
@@ -0,0 +1,90 @@
1
+ /**
2
+ * AdaptiveStepCalculator - 自适应步长计算器
3
+ *
4
+ * 根据场景自动调整网格步长,平衡性能和路径质量
5
+ * - 高密度区域使用小步长,提高路径精度
6
+ * - 长距离路径使用大步长,提高计算性能
7
+ *
8
+ * Feature: manhattan-optimization
9
+ * Requirements: 2.3, 2.4
10
+ */
11
+ import type { InternalNode, NodeLookup } from '../options/types';
12
+ import { Point } from '../geometry';
13
+ /**
14
+ * 自适应步长配置
15
+ */
16
+ export interface AdaptiveStepConfig {
17
+ /** 是否启用自适应步长 */
18
+ enabled: boolean;
19
+ /** 最小步长 */
20
+ minStep: number;
21
+ /** 最大步长 */
22
+ maxStep: number;
23
+ /** 基于密度的调整配置 */
24
+ densityBased: {
25
+ enabled: boolean;
26
+ /** 节点密度阈值(节点数/10000平方像素) */
27
+ threshold: number;
28
+ };
29
+ /** 基于距离的调整配置 */
30
+ distanceBased: {
31
+ enabled: boolean;
32
+ /** 短路径阈值(像素) */
33
+ shortPathThreshold: number;
34
+ /** 长路径阈值(像素) */
35
+ longPathThreshold: number;
36
+ };
37
+ }
38
+ /**
39
+ * 默认自适应步长配置
40
+ */
41
+ export declare const DEFAULT_ADAPTIVE_STEP_CONFIG: AdaptiveStepConfig;
42
+ /**
43
+ * 自适应步长计算器
44
+ */
45
+ export declare class AdaptiveStepCalculator {
46
+ private config;
47
+ constructor(config?: Partial<AdaptiveStepConfig>);
48
+ /**
49
+ * 合并配置与默认值
50
+ */
51
+ private mergeConfig;
52
+ /**
53
+ * 计算节点密度
54
+ * @param nodeLookup 节点查找表
55
+ * @returns 密度值(节点数/10000平方像素)
56
+ */
57
+ calculateNodeDensity(nodeLookup: NodeLookup): number;
58
+ /**
59
+ * 计算两点之间的曼哈顿距离
60
+ */
61
+ calculateDistance(source: Point | {
62
+ x: number;
63
+ y: number;
64
+ }, target: Point | {
65
+ x: number;
66
+ y: number;
67
+ }): number;
68
+ /**
69
+ * 基于距离计算步长
70
+ */
71
+ calculateDistanceBasedStep(distance: number): number;
72
+ /**
73
+ * 基于密度计算步长
74
+ */
75
+ calculateDensityBasedStep(density: number): number;
76
+ /**
77
+ * 计算自适应步长
78
+ * 综合考虑距离和密度因素
79
+ */
80
+ calculateStep(sourceNode: InternalNode, targetNode: InternalNode, nodeLookup: NodeLookup): number;
81
+ /**
82
+ * 获取当前配置
83
+ */
84
+ getConfig(): AdaptiveStepConfig;
85
+ /**
86
+ * 更新配置
87
+ */
88
+ updateConfig(config: Partial<AdaptiveStepConfig>): void;
89
+ }
90
+ //# sourceMappingURL=AdaptiveStepCalculator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AdaptiveStepCalculator.d.ts","sourceRoot":"","sources":["../../src/utils/AdaptiveStepCalculator.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAChE,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAA;AAEnC;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,gBAAgB;IAChB,OAAO,EAAE,OAAO,CAAA;IAChB,WAAW;IACX,OAAO,EAAE,MAAM,CAAA;IACf,WAAW;IACX,OAAO,EAAE,MAAM,CAAA;IACf,gBAAgB;IAChB,YAAY,EAAE;QACZ,OAAO,EAAE,OAAO,CAAA;QAChB,4BAA4B;QAC5B,SAAS,EAAE,MAAM,CAAA;KAClB,CAAA;IACD,gBAAgB;IAChB,aAAa,EAAE;QACb,OAAO,EAAE,OAAO,CAAA;QAChB,gBAAgB;QAChB,kBAAkB,EAAE,MAAM,CAAA;QAC1B,gBAAgB;QAChB,iBAAiB,EAAE,MAAM,CAAA;KAC1B,CAAA;CACF;AAED;;GAEG;AACH,eAAO,MAAM,4BAA4B,EAAE,kBAa1C,CAAA;AAED;;GAEG;AACH,qBAAa,sBAAsB;IACjC,OAAO,CAAC,MAAM,CAAoB;gBAEtB,MAAM,GAAE,OAAO,CAAC,kBAAkB,CAAM;IAIpD;;OAEG;IACH,OAAO,CAAC,WAAW;IAiBnB;;;;OAIG;IACH,oBAAoB,CAAC,UAAU,EAAE,UAAU,GAAG,MAAM;IA2BpD;;OAEG;IACH,iBAAiB,CAAC,MAAM,EAAE,KAAK,GAAG;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAA;KAAE,EAAE,MAAM,EAAE,KAAK,GAAG;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,MAAM;IAI7G;;OAEG;IACH,0BAA0B,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM;IAsBpD;;OAEG;IACH,yBAAyB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM;IAsBlD;;;OAGG;IACH,aAAa,CACX,UAAU,EAAE,YAAY,EACxB,UAAU,EAAE,YAAY,EACxB,UAAU,EAAE,UAAU,GACrB,MAAM;IAyCT;;OAEG;IACH,SAAS,IAAI,kBAAkB;IAI/B;;OAEG;IACH,YAAY,CAAC,MAAM,EAAE,OAAO,CAAC,kBAAkB,CAAC,GAAG,IAAI;CAGxD"}
@@ -0,0 +1,224 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.DEFAULT_ADAPTIVE_STEP_CONFIG = exports.AdaptiveStepCalculator = void 0;
7
+ /**
8
+ * AdaptiveStepCalculator - 自适应步长计算器
9
+ *
10
+ * 根据场景自动调整网格步长,平衡性能和路径质量
11
+ * - 高密度区域使用小步长,提高路径精度
12
+ * - 长距离路径使用大步长,提高计算性能
13
+ *
14
+ * Feature: manhattan-optimization
15
+ * Requirements: 2.3, 2.4
16
+ */
17
+
18
+ /**
19
+ * 自适应步长配置
20
+ */
21
+
22
+ /**
23
+ * 默认自适应步长配置
24
+ */
25
+ const DEFAULT_ADAPTIVE_STEP_CONFIG = exports.DEFAULT_ADAPTIVE_STEP_CONFIG = {
26
+ enabled: false,
27
+ minStep: 5,
28
+ maxStep: 20,
29
+ densityBased: {
30
+ enabled: true,
31
+ threshold: 0.5 // 每10000平方像素0.5个节点
32
+ },
33
+ distanceBased: {
34
+ enabled: true,
35
+ shortPathThreshold: 200,
36
+ longPathThreshold: 800
37
+ }
38
+ };
39
+
40
+ /**
41
+ * 自适应步长计算器
42
+ */
43
+ class AdaptiveStepCalculator {
44
+ config;
45
+ constructor(config = {}) {
46
+ this.config = this.mergeConfig(config);
47
+ }
48
+
49
+ /**
50
+ * 合并配置与默认值
51
+ */
52
+ mergeConfig(config) {
53
+ return {
54
+ enabled: config.enabled ?? DEFAULT_ADAPTIVE_STEP_CONFIG.enabled,
55
+ minStep: config.minStep ?? DEFAULT_ADAPTIVE_STEP_CONFIG.minStep,
56
+ maxStep: config.maxStep ?? DEFAULT_ADAPTIVE_STEP_CONFIG.maxStep,
57
+ densityBased: {
58
+ enabled: config.densityBased?.enabled ?? DEFAULT_ADAPTIVE_STEP_CONFIG.densityBased.enabled,
59
+ threshold: config.densityBased?.threshold ?? DEFAULT_ADAPTIVE_STEP_CONFIG.densityBased.threshold
60
+ },
61
+ distanceBased: {
62
+ enabled: config.distanceBased?.enabled ?? DEFAULT_ADAPTIVE_STEP_CONFIG.distanceBased.enabled,
63
+ shortPathThreshold: config.distanceBased?.shortPathThreshold ?? DEFAULT_ADAPTIVE_STEP_CONFIG.distanceBased.shortPathThreshold,
64
+ longPathThreshold: config.distanceBased?.longPathThreshold ?? DEFAULT_ADAPTIVE_STEP_CONFIG.distanceBased.longPathThreshold
65
+ }
66
+ };
67
+ }
68
+
69
+ /**
70
+ * 计算节点密度
71
+ * @param nodeLookup 节点查找表
72
+ * @returns 密度值(节点数/10000平方像素)
73
+ */
74
+ calculateNodeDensity(nodeLookup) {
75
+ if (nodeLookup.size === 0) return 0;
76
+ let minX = Infinity,
77
+ minY = Infinity;
78
+ let maxX = -Infinity,
79
+ maxY = -Infinity;
80
+ for (const node of nodeLookup.values()) {
81
+ const pos = node.internals?.positionAbsolute ?? node.position;
82
+ const width = node.measured?.width ?? node.width ?? 100;
83
+ const height = node.measured?.height ?? node.height ?? 50;
84
+ minX = Math.min(minX, pos.x);
85
+ minY = Math.min(minY, pos.y);
86
+ maxX = Math.max(maxX, pos.x + width);
87
+ maxY = Math.max(maxY, pos.y + height);
88
+ }
89
+
90
+ // 计算边界框面积(以10000平方像素为单位)
91
+ const width = maxX - minX;
92
+ const height = maxY - minY;
93
+ const area = width * height / 10000;
94
+ if (area <= 0) return 0;
95
+ return nodeLookup.size / area;
96
+ }
97
+
98
+ /**
99
+ * 计算两点之间的曼哈顿距离
100
+ */
101
+ calculateDistance(source, target) {
102
+ return Math.abs(target.x - source.x) + Math.abs(target.y - source.y);
103
+ }
104
+
105
+ /**
106
+ * 基于距离计算步长
107
+ */
108
+ calculateDistanceBasedStep(distance) {
109
+ const {
110
+ minStep,
111
+ maxStep,
112
+ distanceBased
113
+ } = this.config;
114
+ if (!distanceBased.enabled) {
115
+ return minStep;
116
+ }
117
+ const {
118
+ shortPathThreshold,
119
+ longPathThreshold
120
+ } = distanceBased;
121
+ if (distance <= shortPathThreshold) {
122
+ return minStep;
123
+ }
124
+ if (distance >= longPathThreshold) {
125
+ return maxStep;
126
+ }
127
+
128
+ // 线性插值
129
+ const ratio = (distance - shortPathThreshold) / (longPathThreshold - shortPathThreshold);
130
+ return Math.round(minStep + ratio * (maxStep - minStep));
131
+ }
132
+
133
+ /**
134
+ * 基于密度计算步长
135
+ */
136
+ calculateDensityBasedStep(density) {
137
+ const {
138
+ minStep,
139
+ maxStep,
140
+ densityBased
141
+ } = this.config;
142
+ if (!densityBased.enabled) {
143
+ return maxStep;
144
+ }
145
+
146
+ // 高密度使用小步长
147
+ if (density >= densityBased.threshold) {
148
+ return minStep;
149
+ }
150
+
151
+ // 低密度使用大步长
152
+ if (density <= densityBased.threshold / 2) {
153
+ return maxStep;
154
+ }
155
+
156
+ // 线性插值
157
+ const ratio = (densityBased.threshold - density) / (densityBased.threshold / 2);
158
+ return Math.round(minStep + ratio * (maxStep - minStep));
159
+ }
160
+
161
+ /**
162
+ * 计算自适应步长
163
+ * 综合考虑距离和密度因素
164
+ */
165
+ calculateStep(sourceNode, targetNode, nodeLookup) {
166
+ if (!this.config.enabled) {
167
+ return this.config.minStep;
168
+ }
169
+
170
+ // 获取源和目标位置
171
+ const sourcePos = sourceNode.internals?.positionAbsolute ?? sourceNode.position;
172
+ const targetPos = targetNode.internals?.positionAbsolute ?? targetNode.position;
173
+
174
+ // 计算节点中心点
175
+ const sourceWidth = sourceNode.measured?.width ?? sourceNode.width ?? 100;
176
+ const sourceHeight = sourceNode.measured?.height ?? sourceNode.height ?? 50;
177
+ const targetWidth = targetNode.measured?.width ?? targetNode.width ?? 100;
178
+ const targetHeight = targetNode.measured?.height ?? targetNode.height ?? 50;
179
+ const sourceCenter = {
180
+ x: sourcePos.x + sourceWidth / 2,
181
+ y: sourcePos.y + sourceHeight / 2
182
+ };
183
+ const targetCenter = {
184
+ x: targetPos.x + targetWidth / 2,
185
+ y: targetPos.y + targetHeight / 2
186
+ };
187
+
188
+ // 计算距离
189
+ const distance = this.calculateDistance(sourceCenter, targetCenter);
190
+
191
+ // 计算密度
192
+ const density = this.calculateNodeDensity(nodeLookup);
193
+
194
+ // 获取基于距离和密度的步长
195
+ const distanceStep = this.calculateDistanceBasedStep(distance);
196
+ const densityStep = this.calculateDensityBasedStep(density);
197
+
198
+ // 取两者中较小的值(更保守的选择)
199
+ const step = Math.min(distanceStep, densityStep);
200
+
201
+ // 确保步长在有效范围内
202
+ return Math.max(this.config.minStep, Math.min(this.config.maxStep, step));
203
+ }
204
+
205
+ /**
206
+ * 获取当前配置
207
+ */
208
+ getConfig() {
209
+ return {
210
+ ...this.config
211
+ };
212
+ }
213
+
214
+ /**
215
+ * 更新配置
216
+ */
217
+ updateConfig(config) {
218
+ this.config = this.mergeConfig({
219
+ ...this.config,
220
+ ...config
221
+ });
222
+ }
223
+ }
224
+ exports.AdaptiveStepCalculator = AdaptiveStepCalculator;