@rxflow/manhattan 0.0.2-alpha.7 → 0.0.2

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 (157) hide show
  1. package/README.md +214 -10
  2. package/esm/getManHattanPath.js +92 -69
  3. package/esm/obstacle/ObstacleMap.js +218 -99
  4. package/esm/obstacle/QuadTree.js +488 -0
  5. package/esm/options/resolver.js +147 -18
  6. package/esm/pathfinder/PathCache.js +278 -0
  7. package/esm/pathfinder/findRoute.js +98 -44
  8. package/esm/pathfinder/index.js +2 -1
  9. package/esm/svg/pathConverter.js +170 -1
  10. package/esm/utils/AdaptiveStepCalculator.js +252 -0
  11. package/esm/utils/ErrorRecovery.js +499 -0
  12. package/esm/utils/GlobalGrid.js +259 -0
  13. package/esm/utils/PerformanceMonitor.js +360 -0
  14. package/esm/utils/getAnchorPoints.js +0 -4
  15. package/esm/utils/grid.js +18 -13
  16. package/esm/utils/heuristics.js +144 -0
  17. package/esm/utils/index.js +7 -1
  18. package/esm/utils/pathProcessing.js +270 -0
  19. package/esm/utils/pathValidation.js +0 -1
  20. package/esm/utils/rect.js +11 -4
  21. package/esm/utils/route.js +18 -2
  22. package/package.json +10 -2
  23. package/cjs/geometry/Line.d.ts +0 -21
  24. package/cjs/geometry/Line.d.ts.map +0 -1
  25. package/cjs/geometry/Line.js +0 -88
  26. package/cjs/geometry/Point.d.ts +0 -49
  27. package/cjs/geometry/Point.d.ts.map +0 -1
  28. package/cjs/geometry/Point.js +0 -94
  29. package/cjs/geometry/Rectangle.d.ts +0 -41
  30. package/cjs/geometry/Rectangle.d.ts.map +0 -1
  31. package/cjs/geometry/Rectangle.js +0 -65
  32. package/cjs/geometry/collision.d.ts +0 -15
  33. package/cjs/geometry/collision.d.ts.map +0 -1
  34. package/cjs/geometry/collision.js +0 -81
  35. package/cjs/geometry/index.d.ts +0 -5
  36. package/cjs/geometry/index.d.ts.map +0 -1
  37. package/cjs/geometry/index.js +0 -45
  38. package/cjs/getManHattanPath.d.ts +0 -53
  39. package/cjs/getManHattanPath.d.ts.map +0 -1
  40. package/cjs/getManHattanPath.js +0 -418
  41. package/cjs/index.d.ts +0 -16
  42. package/cjs/index.d.ts.map +0 -1
  43. package/cjs/index.js +0 -117
  44. package/cjs/obstacle/ObstacleMap.d.ts +0 -34
  45. package/cjs/obstacle/ObstacleMap.d.ts.map +0 -1
  46. package/cjs/obstacle/ObstacleMap.js +0 -223
  47. package/cjs/obstacle/index.d.ts +0 -2
  48. package/cjs/obstacle/index.d.ts.map +0 -1
  49. package/cjs/obstacle/index.js +0 -12
  50. package/cjs/options/defaults.d.ts +0 -16
  51. package/cjs/options/defaults.d.ts.map +0 -1
  52. package/cjs/options/defaults.js +0 -39
  53. package/cjs/options/index.d.ts +0 -4
  54. package/cjs/options/index.d.ts.map +0 -1
  55. package/cjs/options/index.js +0 -38
  56. package/cjs/options/resolver.d.ts +0 -10
  57. package/cjs/options/resolver.d.ts.map +0 -1
  58. package/cjs/options/resolver.js +0 -120
  59. package/cjs/options/types.d.ts +0 -169
  60. package/cjs/options/types.d.ts.map +0 -1
  61. package/cjs/options/types.js +0 -5
  62. package/cjs/pathfinder/SortedSet.d.ts +0 -35
  63. package/cjs/pathfinder/SortedSet.d.ts.map +0 -1
  64. package/cjs/pathfinder/SortedSet.js +0 -95
  65. package/cjs/pathfinder/findRoute.d.ts +0 -8
  66. package/cjs/pathfinder/findRoute.d.ts.map +0 -1
  67. package/cjs/pathfinder/findRoute.js +0 -330
  68. package/cjs/pathfinder/index.d.ts +0 -3
  69. package/cjs/pathfinder/index.d.ts.map +0 -1
  70. package/cjs/pathfinder/index.js +0 -19
  71. package/cjs/svg/index.d.ts +0 -3
  72. package/cjs/svg/index.d.ts.map +0 -1
  73. package/cjs/svg/index.js +0 -31
  74. package/cjs/svg/pathConverter.d.ts +0 -10
  75. package/cjs/svg/pathConverter.d.ts.map +0 -1
  76. package/cjs/svg/pathConverter.js +0 -116
  77. package/cjs/svg/pathParser.d.ts +0 -11
  78. package/cjs/svg/pathParser.d.ts.map +0 -1
  79. package/cjs/svg/pathParser.js +0 -76
  80. package/cjs/utils/direction.d.ts +0 -24
  81. package/cjs/utils/direction.d.ts.map +0 -1
  82. package/cjs/utils/direction.js +0 -54
  83. package/cjs/utils/getAnchorPoints.d.ts +0 -15
  84. package/cjs/utils/getAnchorPoints.d.ts.map +0 -1
  85. package/cjs/utils/getAnchorPoints.js +0 -75
  86. package/cjs/utils/grid.d.ts +0 -27
  87. package/cjs/utils/grid.d.ts.map +0 -1
  88. package/cjs/utils/grid.js +0 -66
  89. package/cjs/utils/index.d.ts +0 -8
  90. package/cjs/utils/index.d.ts.map +0 -1
  91. package/cjs/utils/index.js +0 -82
  92. package/cjs/utils/node.d.ts +0 -27
  93. package/cjs/utils/node.d.ts.map +0 -1
  94. package/cjs/utils/node.js +0 -36
  95. package/cjs/utils/pathValidation.d.ts +0 -11
  96. package/cjs/utils/pathValidation.d.ts.map +0 -1
  97. package/cjs/utils/pathValidation.js +0 -130
  98. package/cjs/utils/rect.d.ts +0 -9
  99. package/cjs/utils/rect.d.ts.map +0 -1
  100. package/cjs/utils/rect.js +0 -103
  101. package/cjs/utils/route.d.ts +0 -19
  102. package/cjs/utils/route.d.ts.map +0 -1
  103. package/cjs/utils/route.js +0 -76
  104. package/esm/geometry/Line.d.ts +0 -21
  105. package/esm/geometry/Line.d.ts.map +0 -1
  106. package/esm/geometry/Point.d.ts +0 -49
  107. package/esm/geometry/Point.d.ts.map +0 -1
  108. package/esm/geometry/Rectangle.d.ts +0 -41
  109. package/esm/geometry/Rectangle.d.ts.map +0 -1
  110. package/esm/geometry/collision.d.ts +0 -15
  111. package/esm/geometry/collision.d.ts.map +0 -1
  112. package/esm/geometry/index.d.ts +0 -5
  113. package/esm/geometry/index.d.ts.map +0 -1
  114. package/esm/getManHattanPath.d.ts +0 -53
  115. package/esm/getManHattanPath.d.ts.map +0 -1
  116. package/esm/index.d.ts +0 -16
  117. package/esm/index.d.ts.map +0 -1
  118. package/esm/obstacle/ObstacleMap.d.ts +0 -34
  119. package/esm/obstacle/ObstacleMap.d.ts.map +0 -1
  120. package/esm/obstacle/index.d.ts +0 -2
  121. package/esm/obstacle/index.d.ts.map +0 -1
  122. package/esm/options/defaults.d.ts +0 -16
  123. package/esm/options/defaults.d.ts.map +0 -1
  124. package/esm/options/index.d.ts +0 -4
  125. package/esm/options/index.d.ts.map +0 -1
  126. package/esm/options/resolver.d.ts +0 -10
  127. package/esm/options/resolver.d.ts.map +0 -1
  128. package/esm/options/types.d.ts +0 -169
  129. package/esm/options/types.d.ts.map +0 -1
  130. package/esm/pathfinder/SortedSet.d.ts +0 -35
  131. package/esm/pathfinder/SortedSet.d.ts.map +0 -1
  132. package/esm/pathfinder/findRoute.d.ts +0 -8
  133. package/esm/pathfinder/findRoute.d.ts.map +0 -1
  134. package/esm/pathfinder/index.d.ts +0 -3
  135. package/esm/pathfinder/index.d.ts.map +0 -1
  136. package/esm/svg/index.d.ts +0 -3
  137. package/esm/svg/index.d.ts.map +0 -1
  138. package/esm/svg/pathConverter.d.ts +0 -10
  139. package/esm/svg/pathConverter.d.ts.map +0 -1
  140. package/esm/svg/pathParser.d.ts +0 -11
  141. package/esm/svg/pathParser.d.ts.map +0 -1
  142. package/esm/utils/direction.d.ts +0 -24
  143. package/esm/utils/direction.d.ts.map +0 -1
  144. package/esm/utils/getAnchorPoints.d.ts +0 -15
  145. package/esm/utils/getAnchorPoints.d.ts.map +0 -1
  146. package/esm/utils/grid.d.ts +0 -27
  147. package/esm/utils/grid.d.ts.map +0 -1
  148. package/esm/utils/index.d.ts +0 -8
  149. package/esm/utils/index.d.ts.map +0 -1
  150. package/esm/utils/node.d.ts +0 -27
  151. package/esm/utils/node.d.ts.map +0 -1
  152. package/esm/utils/pathValidation.d.ts +0 -11
  153. package/esm/utils/pathValidation.d.ts.map +0 -1
  154. package/esm/utils/rect.d.ts +0 -9
  155. package/esm/utils/rect.d.ts.map +0 -1
  156. package/esm/utils/route.d.ts +0 -19
  157. package/esm/utils/route.d.ts.map +0 -1
@@ -1,418 +0,0 @@
1
- "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
6
- exports.getManHattanPath = getManHattanPath;
7
- var _react = require("@xyflow/react");
8
- var _geometry = require("./geometry");
9
- var _obstacle = require("./obstacle");
10
- var _options = require("./options");
11
- var _pathfinder = require("./pathfinder");
12
- var _svg = require("./svg");
13
- var _utils = require("./utils");
14
- /**
15
- * Parameters for getManHattanPath function
16
- */
17
-
18
- /**
19
- * Generate Manhattan-routed path for ReactFlow edges
20
- *
21
- * @param params - Path generation parameters
22
- * @returns SVG path string that can be used with ReactFlow's BaseEdge
23
- *
24
- * @example
25
- * ```typescript
26
- * const path = getManHattanPath({
27
- * sourceNodeId: 'node1',
28
- * targetNodeId: 'node2',
29
- * sourcePosition: { x: 100, y: 100 },
30
- * targetPosition: { x: 300, y: 300 },
31
- * nodeLookup: nodes,
32
- * options: {
33
- * step: 10,
34
- * startDirections: ['bottom'],
35
- * endDirections: ['top']
36
- * }
37
- * })
38
- * ```
39
- */
40
- function getManHattanPath(params) {
41
- const {
42
- sourceNodeId,
43
- targetNodeId,
44
- sourcePosition,
45
- targetPosition,
46
- nodeLookup,
47
- sourceX,
48
- sourceY,
49
- targetX,
50
- targetY,
51
- options: userOptions = {}
52
- } = params;
53
-
54
- // Resolve options and add position information
55
- const options = (0, _options.resolveOptions)({
56
- ...userOptions,
57
- sourcePosition,
58
- targetPosition
59
- });
60
-
61
- // Direction control is automatically handled by getRectPoints:
62
- // - When anchor is on an edge, only outward directions are allowed (via isDirectionOutward)
63
- // - For sourcePosition="right": anchor on right edge -> only extends right
64
- // - For targetPosition="left": anchor on left edge -> path approaches from right (outward from left)
65
- // This ensures paths follow the sourcePosition and targetPosition constraints
66
-
67
- // Get source and target nodes
68
- const sourceNode = nodeLookup.get(sourceNodeId);
69
- const targetNode = nodeLookup.get(targetNodeId);
70
- if (!sourceNode || !targetNode) {
71
- // Fallback to simple straight line if nodes not found
72
- console.warn('Source or target node not found in nodeLookup');
73
- const start = new _geometry.Point(sourceX, sourceY);
74
- const end = new _geometry.Point(targetX, targetY);
75
- return (0, _svg.pointsToPath)([start, end], options.precision);
76
- }
77
-
78
- // Get node dimensions using ReactFlow's priority logic
79
- const sourceDimensions = (0, _utils.getNodeDimensions)(sourceNode);
80
- const targetDimensions = (0, _utils.getNodeDimensions)(targetNode);
81
-
82
- // Get absolute positions from internals
83
- const sourcePos = (0, _utils.getNodePosition)(sourceNode);
84
- const targetPos = (0, _utils.getNodePosition)(targetNode);
85
-
86
- // Calculate bounding boxes
87
- const sourceBBox = new _geometry.Rectangle(sourcePos.x, sourcePos.y, sourceDimensions.width, sourceDimensions.height);
88
- const targetBBox = new _geometry.Rectangle(targetPos.x, targetPos.y, targetDimensions.width, targetDimensions.height);
89
-
90
- // Create anchor points
91
- const sourceAnchor = new _geometry.Point(sourceX, sourceY);
92
- const targetAnchor = new _geometry.Point(targetX, targetY);
93
-
94
- // Try ReactFlow's getSmoothStepPath first
95
- const [smoothStepPath] = (0, _react.getSmoothStepPath)({
96
- sourceX,
97
- sourceY,
98
- targetX,
99
- targetY,
100
- sourcePosition,
101
- targetPosition,
102
- borderRadius: options.borderRadius
103
- });
104
-
105
- // Parse the smooth step path to extract points
106
- const smoothStepPoints = (0, _svg.parseSVGPath)(smoothStepPath);
107
-
108
- // Check if smooth step path intersects with any obstacles
109
- if (smoothStepPoints.length > 0 && !(0, _utils.pathIntersectsObstacles)(smoothStepPoints, nodeLookup)) {
110
- console.log('[getManHattanPath] Using ReactFlow getSmoothStepPath (no obstacles)');
111
- return smoothStepPath;
112
- }
113
- console.log('[getManHattanPath] SmoothStepPath intersects obstacles, using Manhattan routing');
114
-
115
- // Build obstacle map with anchor information
116
- const obstacleMap = new _obstacle.ObstacleMap(options).build(nodeLookup, sourceNodeId, targetNodeId, sourceAnchor, targetAnchor);
117
-
118
- // Find route
119
- let route = (0, _pathfinder.findRoute)(sourceBBox, targetBBox, sourceAnchor, targetAnchor, obstacleMap, options);
120
-
121
- // Fallback to straight line if no route found
122
- if (!route) {
123
- console.warn('Unable to find Manhattan route, using straight line fallback');
124
- route = [sourceAnchor, targetAnchor];
125
- }
126
- console.log('[getManHattanPath] Route from findRoute:', route.map(p => `(${p.x}, ${p.y})`));
127
- console.log('[getManHattanPath] Source anchor:', `(${sourceAnchor.x}, ${sourceAnchor.y})`);
128
- console.log('[getManHattanPath] Target anchor:', `(${targetAnchor.x}, ${targetAnchor.y})`);
129
-
130
- // If using smart point generation (sourcePosition/targetPosition specified),
131
- // the route already contains the correct extension points, so skip manual processing
132
- const useSmartPoints = sourcePosition || targetPosition;
133
- if (useSmartPoints) {
134
- console.log('[getManHattanPath] Using smart points, skipping manual extension point processing');
135
- // Add source and target anchors to route
136
- const finalRoute = [sourceAnchor, ...route, targetAnchor];
137
- console.log('[getManHattanPath] Final route:', finalRoute.map(p => `(${p.x}, ${p.y})`));
138
- return (0, _svg.pointsToPath)(finalRoute, options.precision, options.borderRadius);
139
- }
140
-
141
- // Remove extension points from route that were added by getRectPoints
142
- // We will add our own with fixed step distance
143
- const step = options.step;
144
- const tolerance = 1;
145
-
146
- // Check if first point is an extension point from source
147
- if (route.length > 0) {
148
- const firstPoint = route[0];
149
- const onLeft = Math.abs(sourceAnchor.x - sourceBBox.x) < tolerance;
150
- const onRight = Math.abs(sourceAnchor.x - (sourceBBox.x + sourceBBox.width)) < tolerance;
151
- const onTop = Math.abs(sourceAnchor.y - sourceBBox.y) < tolerance;
152
- const onBottom = Math.abs(sourceAnchor.y - (sourceBBox.y + sourceBBox.height)) < tolerance;
153
-
154
- // Check if firstPoint is close to source anchor (indicating it's an extension point)
155
- const distToFirst = sourceAnchor.manhattanDistance(firstPoint);
156
- if (distToFirst < step * 2) {
157
- // This is likely an extension point, remove it
158
- if (onRight && firstPoint.x > sourceAnchor.x || onLeft && firstPoint.x < sourceAnchor.x || onBottom && firstPoint.y > sourceAnchor.y || onTop && firstPoint.y < sourceAnchor.y) {
159
- route.shift();
160
- console.log('[getManHattanPath] Removed extension point from route start');
161
- }
162
- }
163
- }
164
-
165
- // Check if last point is an extension point from target
166
- if (route.length > 0) {
167
- const lastPoint = route[route.length - 1];
168
- const onLeft = Math.abs(targetAnchor.x - targetBBox.x) < tolerance;
169
- const onRight = Math.abs(targetAnchor.x - (targetBBox.x + targetBBox.width)) < tolerance;
170
- const onTop = Math.abs(targetAnchor.y - targetBBox.y) < tolerance;
171
- const onBottom = Math.abs(targetAnchor.y - (targetBBox.y + targetBBox.height)) < tolerance;
172
-
173
- // Check if lastPoint is close to target anchor (indicating it's an extension point)
174
- const distToLast = targetAnchor.manhattanDistance(lastPoint);
175
- if (distToLast < step * 2) {
176
- // This is likely an extension point, remove it
177
- if (onLeft && lastPoint.x < targetAnchor.x || onRight && lastPoint.x > targetAnchor.x || onTop && lastPoint.y < targetAnchor.y || onBottom && lastPoint.y > targetAnchor.y) {
178
- route.pop();
179
- console.log('[getManHattanPath] Removed extension point from route end');
180
- }
181
- }
182
- }
183
-
184
- // Insert extension point at source - always extend away from node edge by fixed distance
185
- if (route.length > 0) {
186
- const extensionDistance = options.extensionDistance;
187
- const firstPoint = route[0];
188
-
189
- // Determine which edge the source anchor is on
190
- const onLeft = Math.abs(sourceAnchor.x - sourceBBox.x) < tolerance;
191
- const onRight = Math.abs(sourceAnchor.x - (sourceBBox.x + sourceBBox.width)) < tolerance;
192
- const onTop = Math.abs(sourceAnchor.y - sourceBBox.y) < tolerance;
193
- const onBottom = Math.abs(sourceAnchor.y - (sourceBBox.y + sourceBBox.height)) < tolerance;
194
-
195
- // Insert extension point and corner point to ensure orthogonal path
196
- if (onRight) {
197
- // Anchor on right edge - extend right by step + borderRadius
198
- const extendX = sourceAnchor.x + extensionDistance;
199
- const extensionPoint = new _geometry.Point(extendX, sourceAnchor.y);
200
- // Check if we need a corner point
201
- if (Math.abs(extensionPoint.y - firstPoint.y) > tolerance) {
202
- route.unshift(new _geometry.Point(extendX, firstPoint.y)); // Corner point
203
- }
204
- route.unshift(extensionPoint); // Extension point (fixed distance)
205
- console.log('[getManHattanPath] Inserted source extension (right):', `(${extendX}, ${sourceAnchor.y})`);
206
- } else if (onLeft) {
207
- // Anchor on left edge - extend left by step + borderRadius
208
- const extendX = sourceAnchor.x - extensionDistance;
209
- const extensionPoint = new _geometry.Point(extendX, sourceAnchor.y);
210
- if (Math.abs(extensionPoint.y - firstPoint.y) > tolerance) {
211
- route.unshift(new _geometry.Point(extendX, firstPoint.y));
212
- }
213
- route.unshift(extensionPoint);
214
- console.log('[getManHattanPath] Inserted source extension (left):', `(${extendX}, ${sourceAnchor.y})`);
215
- } else if (onBottom) {
216
- // Anchor on bottom edge - extend down by step + borderRadius
217
- const extendY = sourceAnchor.y + extensionDistance;
218
- const extensionPoint = new _geometry.Point(sourceAnchor.x, extendY);
219
- if (Math.abs(extensionPoint.x - firstPoint.x) > tolerance) {
220
- route.unshift(new _geometry.Point(firstPoint.x, extendY));
221
- }
222
- route.unshift(extensionPoint);
223
- console.log('[getManHattanPath] Inserted source extension (down):', `(${sourceAnchor.x}, ${extendY})`);
224
- } else if (onTop) {
225
- // Anchor on top edge - extend up by step + borderRadius
226
- const extendY = sourceAnchor.y - extensionDistance;
227
- const extensionPoint = new _geometry.Point(sourceAnchor.x, extendY);
228
- if (Math.abs(extensionPoint.x - firstPoint.x) > tolerance) {
229
- route.unshift(new _geometry.Point(firstPoint.x, extendY));
230
- }
231
- route.unshift(extensionPoint);
232
- console.log('[getManHattanPath] Inserted source extension (up):', `(${sourceAnchor.x}, ${extendY})`);
233
- }
234
- }
235
-
236
- // Remove redundant points after source extension
237
- // If the first route point has the same x or y coordinate as the source anchor, it's redundant
238
- if (route.length > 2) {
239
- const firstRoutePoint = route[0]; // Extension point
240
- const secondRoutePoint = route[1]; // Corner point (if exists)
241
- const thirdRoutePoint = route[2]; // Original A* point
242
-
243
- // Check if the third point (original A* point) is redundant
244
- // It's redundant if it's on the same line as the corner point and can be skipped
245
- const sameX = Math.abs(thirdRoutePoint.x - sourceAnchor.x) < tolerance;
246
- const sameY = Math.abs(thirdRoutePoint.y - sourceAnchor.y) < tolerance;
247
- if (sameX || sameY) {
248
- // The third point is aligned with the source anchor, likely redundant
249
- // Check if we can skip it by connecting corner point directly to the next point
250
- if (route.length > 3) {
251
- const fourthPoint = route[3];
252
- // If corner point and fourth point form a straight line, remove the third point
253
- const cornerToThird = Math.abs(secondRoutePoint.x - thirdRoutePoint.x) < tolerance || Math.abs(secondRoutePoint.y - thirdRoutePoint.y) < tolerance;
254
- const thirdToFourth = Math.abs(thirdRoutePoint.x - fourthPoint.x) < tolerance || Math.abs(thirdRoutePoint.y - fourthPoint.y) < tolerance;
255
- if (cornerToThird && thirdToFourth) {
256
- console.log('[getManHattanPath] Removing redundant point:', `(${thirdRoutePoint.x}, ${thirdRoutePoint.y})`);
257
- route.splice(2, 1); // Remove the third point
258
- }
259
- }
260
- }
261
- }
262
-
263
- // Optimize zigzag patterns BEFORE inserting target extension
264
- // Check for patterns like: (1360, 16) -> (815, 16) -> (815, -134)
265
- // where the middle segment goes to target edge and then moves along it
266
- // Use target bbox with padding (same as ObstacleMap)
267
- const targetBBoxWithPadding = targetBBox.moveAndExpand(options.paddingBox);
268
- console.log('[getManHattanPath] Route before zigzag check:', route.map(p => `(${p.x}, ${p.y})`));
269
- console.log('[getManHattanPath] Target BBox with padding:', `x=${targetBBoxWithPadding.x}, y=${targetBBoxWithPadding.y}`);
270
- if (route.length >= 3) {
271
- let i = 0;
272
- while (i < route.length - 2) {
273
- const p1 = route[i];
274
- const p2 = route[i + 1];
275
- const p3 = route[i + 2];
276
-
277
- // Check if p2 is on the target bbox edge (with padding)
278
- const p2OnTargetLeftEdge = Math.abs(p2.x - targetBBoxWithPadding.x) < tolerance;
279
- const p2OnTargetRightEdge = Math.abs(p2.x - (targetBBoxWithPadding.x + targetBBoxWithPadding.width)) < tolerance;
280
- const p2OnTargetTopEdge = Math.abs(p2.y - targetBBoxWithPadding.y) < tolerance;
281
- const p2OnTargetBottomEdge = Math.abs(p2.y - (targetBBoxWithPadding.y + targetBBoxWithPadding.height)) < tolerance;
282
- const p2OnTargetEdge = p2OnTargetLeftEdge || p2OnTargetRightEdge || p2OnTargetTopEdge || p2OnTargetBottomEdge;
283
- console.log(`[getManHattanPath] Checking i=${i}: p2=(${p2.x}, ${p2.y}), onEdge=${p2OnTargetEdge}`);
284
- if (p2OnTargetEdge) {
285
- // Check if p1 -> p2 -> p3 forms a zigzag
286
- const p1ToP2Horizontal = Math.abs(p1.y - p2.y) < tolerance;
287
- const p2ToP3Vertical = Math.abs(p2.x - p3.x) < tolerance;
288
- const p1ToP2Vertical = Math.abs(p1.x - p2.x) < tolerance;
289
- const p2ToP3Horizontal = Math.abs(p2.y - p3.y) < tolerance;
290
- console.log(`[getManHattanPath] Zigzag pattern: H->V=${p1ToP2Horizontal && p2ToP3Vertical}, V->H=${p1ToP2Vertical && p2ToP3Horizontal}`);
291
- if (p1ToP2Horizontal && p2ToP3Vertical || p1ToP2Vertical && p2ToP3Horizontal) {
292
- // We have a zigzag at target edge, remove p2 and p3
293
- console.log('[getManHattanPath] Removing zigzag at target edge:', `(${p2.x}, ${p2.y})`, `and (${p3.x}, ${p3.y})`);
294
- route.splice(i + 1, 2); // Remove p2 and p3
295
- continue;
296
- }
297
- }
298
- i++;
299
- }
300
- }
301
-
302
- // Insert extension point at target - always extend away from node edge by fixed distance
303
- if (route.length > 0) {
304
- const extensionDistance = options.extensionDistance;
305
- const lastPoint = route[route.length - 1];
306
-
307
- // Determine which edge the target anchor is on
308
- const onLeft = Math.abs(targetAnchor.x - targetBBox.x) < tolerance;
309
- const onRight = Math.abs(targetAnchor.x - (targetBBox.x + targetBBox.width)) < tolerance;
310
- const onTop = Math.abs(targetAnchor.y - targetBBox.y) < tolerance;
311
- const onBottom = Math.abs(targetAnchor.y - (targetBBox.y + targetBBox.height)) < tolerance;
312
-
313
- // Insert extension point and corner point to ensure orthogonal path
314
- if (onLeft) {
315
- // Anchor on left edge - extend left by step + borderRadius
316
- const extendX = targetAnchor.x - extensionDistance;
317
- const extensionPoint = new _geometry.Point(extendX, targetAnchor.y);
318
- if (Math.abs(extensionPoint.y - lastPoint.y) > tolerance) {
319
- route.push(new _geometry.Point(extendX, lastPoint.y)); // Corner point
320
- }
321
- route.push(extensionPoint); // Extension point (fixed distance)
322
- console.log('[getManHattanPath] Inserted target extension (left):', `(${extendX}, ${targetAnchor.y})`);
323
- } else if (onRight) {
324
- // Anchor on right edge - extend right by step + borderRadius
325
- const extendX = targetAnchor.x + extensionDistance;
326
- const extensionPoint = new _geometry.Point(extendX, targetAnchor.y);
327
- if (Math.abs(extensionPoint.y - lastPoint.y) > tolerance) {
328
- route.push(new _geometry.Point(extendX, lastPoint.y));
329
- }
330
- route.push(extensionPoint);
331
- console.log('[getManHattanPath] Inserted target extension (right):', `(${extendX}, ${targetAnchor.y})`);
332
- } else if (onTop) {
333
- // Anchor on top edge - extend up by step + borderRadius
334
- const extendY = targetAnchor.y - extensionDistance;
335
- const extensionPoint = new _geometry.Point(targetAnchor.x, extendY);
336
- if (Math.abs(extensionPoint.x - lastPoint.x) > tolerance) {
337
- route.push(new _geometry.Point(lastPoint.x, extendY));
338
- }
339
- route.push(extensionPoint);
340
- console.log('[getManHattanPath] Inserted target extension (up):', `(${targetAnchor.x}, ${extendY})`);
341
- } else if (onBottom) {
342
- // Anchor on bottom edge - extend down by step + borderRadius
343
- const extendY = targetAnchor.y + extensionDistance;
344
- const extensionPoint = new _geometry.Point(targetAnchor.x, extendY);
345
- if (Math.abs(extensionPoint.x - lastPoint.x) > tolerance) {
346
- route.push(new _geometry.Point(lastPoint.x, extendY));
347
- }
348
- route.push(extensionPoint);
349
- console.log('[getManHattanPath] Inserted target extension (down):', `(${targetAnchor.x}, ${extendY})`);
350
- }
351
- }
352
-
353
- // Remove redundant points before target extension
354
- // Similar logic for target side
355
- if (route.length > 2) {
356
- const lastIdx = route.length - 1;
357
- const lastRoutePoint = route[lastIdx]; // Extension point
358
- const secondLastPoint = route[lastIdx - 1]; // Corner point (if exists)
359
- const thirdLastPoint = route[lastIdx - 2]; // Original A* point
360
-
361
- // Check if the third-to-last point is redundant
362
- const sameX = Math.abs(thirdLastPoint.x - targetAnchor.x) < tolerance;
363
- const sameY = Math.abs(thirdLastPoint.y - targetAnchor.y) < tolerance;
364
- if (sameX || sameY) {
365
- if (route.length > 3) {
366
- const fourthLastPoint = route[lastIdx - 3];
367
- const fourthToThird = Math.abs(fourthLastPoint.x - thirdLastPoint.x) < tolerance || Math.abs(fourthLastPoint.y - thirdLastPoint.y) < tolerance;
368
- const thirdToSecond = Math.abs(thirdLastPoint.x - secondLastPoint.x) < tolerance || Math.abs(thirdLastPoint.y - secondLastPoint.y) < tolerance;
369
- if (fourthToThird && thirdToSecond) {
370
- console.log('[getManHattanPath] Removing redundant point:', `(${thirdLastPoint.x}, ${thirdLastPoint.y})`);
371
- route.splice(lastIdx - 2, 1); // Remove the third-to-last point
372
- }
373
- }
374
- }
375
- }
376
-
377
- // Additional optimization: Remove unnecessary zigzag patterns near target
378
- // Check for patterns like: (1360, 16) -> (815, 16) -> (815, -134) -> (800, -134)
379
- // where (815, 16) and (815, -134) form a zigzag at the target edge
380
- let i = 0;
381
- while (i < route.length - 2) {
382
- const p1 = route[i];
383
- const p2 = route[i + 1];
384
- const p3 = route[i + 2];
385
-
386
- // Check if p2 is on the target bbox edge
387
- const p2OnTargetLeftEdge = Math.abs(p2.x - targetBBox.x) < tolerance;
388
- const p2OnTargetRightEdge = Math.abs(p2.x - (targetBBox.x + targetBBox.width)) < tolerance;
389
- const p2OnTargetTopEdge = Math.abs(p2.y - targetBBox.y) < tolerance;
390
- const p2OnTargetBottomEdge = Math.abs(p2.y - (targetBBox.y + targetBBox.height)) < tolerance;
391
- const p2OnTargetEdge = p2OnTargetLeftEdge || p2OnTargetRightEdge || p2OnTargetTopEdge || p2OnTargetBottomEdge;
392
- if (p2OnTargetEdge) {
393
- // Check if p1 -> p2 -> p3 forms a zigzag
394
- const p1ToP2Horizontal = Math.abs(p1.y - p2.y) < tolerance;
395
- const p2ToP3Vertical = Math.abs(p2.x - p3.x) < tolerance;
396
- if (p1ToP2Horizontal && p2ToP3Vertical && i < route.length - 3) {
397
- // We have horizontal -> vertical at target edge
398
- // Check if we can skip p2 and p3
399
- const p4 = route[i + 3];
400
- const p3ToP4Horizontal = Math.abs(p3.y - p4.y) < tolerance;
401
- if (p3ToP4Horizontal) {
402
- // Pattern: horizontal -> vertical -> horizontal (zigzag)
403
- console.log('[getManHattanPath] Removing zigzag at target edge:', `(${p2.x}, ${p2.y})`, `and (${p3.x}, ${p3.y})`);
404
- route.splice(i + 1, 2); // Remove p2 and p3
405
- continue;
406
- }
407
- }
408
- }
409
- i++;
410
- }
411
-
412
- // Add source and target anchors to route
413
- const finalRoute = [sourceAnchor, ...route, targetAnchor];
414
- console.log('[getManHattanPath] Final route:', finalRoute.map(p => `(${p.x}, ${p.y})`));
415
-
416
- // Convert to SVG path string
417
- return (0, _svg.pointsToPath)(finalRoute, options.precision, options.borderRadius);
418
- }
package/cjs/index.d.ts DELETED
@@ -1,16 +0,0 @@
1
- /**
2
- * ReactFlow Manhattan Router
3
- *
4
- * A Manhattan routing algorithm adapted for ReactFlow from AntV X6.
5
- * Generates orthogonal (right-angle) paths that intelligently avoid obstacles.
6
- *
7
- * @packageDocumentation
8
- */
9
- export { getManHattanPath } from './getManHattanPath';
10
- export type { GetManHattanPathParams } from './getManHattanPath';
11
- export type { Direction, InternalNode, NodeLookup, ManhattanRouterOptions, ResolvedOptions, } from './options';
12
- export { Point, Rectangle, Line } from './geometry';
13
- export { getGrid, align, snapToGrid, getDirectionAngle, getDirectionChange, getRectPoints, getCost, getKey, reconstructRoute, normalizePoint, getNodeDimensions, getNodePosition, } from './utils';
14
- export type { NodeDimensions } from './utils';
15
- export { pointsToPath, snapPathToGrid } from './svg';
16
- //# sourceMappingURL=index.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAA;AACrD,YAAY,EAAE,sBAAsB,EAAE,MAAM,oBAAoB,CAAA;AAGhE,YAAY,EACV,SAAS,EACT,YAAY,EACZ,UAAU,EACV,sBAAsB,EACtB,eAAe,GAChB,MAAM,WAAW,CAAA;AAGlB,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,YAAY,CAAA;AAGnD,OAAO,EACL,OAAO,EACP,KAAK,EACL,UAAU,EACV,iBAAiB,EACjB,kBAAkB,EAClB,aAAa,EACb,OAAO,EACP,MAAM,EACN,gBAAgB,EAChB,cAAc,EACd,iBAAiB,EACjB,eAAe,GAChB,MAAM,SAAS,CAAA;AAGhB,YAAY,EAAE,cAAc,EAAE,MAAM,SAAS,CAAA;AAG7C,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,OAAO,CAAA"}
package/cjs/index.js DELETED
@@ -1,117 +0,0 @@
1
- "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
6
- Object.defineProperty(exports, "Line", {
7
- enumerable: true,
8
- get: function () {
9
- return _geometry.Line;
10
- }
11
- });
12
- Object.defineProperty(exports, "Point", {
13
- enumerable: true,
14
- get: function () {
15
- return _geometry.Point;
16
- }
17
- });
18
- Object.defineProperty(exports, "Rectangle", {
19
- enumerable: true,
20
- get: function () {
21
- return _geometry.Rectangle;
22
- }
23
- });
24
- Object.defineProperty(exports, "align", {
25
- enumerable: true,
26
- get: function () {
27
- return _utils.align;
28
- }
29
- });
30
- Object.defineProperty(exports, "getCost", {
31
- enumerable: true,
32
- get: function () {
33
- return _utils.getCost;
34
- }
35
- });
36
- Object.defineProperty(exports, "getDirectionAngle", {
37
- enumerable: true,
38
- get: function () {
39
- return _utils.getDirectionAngle;
40
- }
41
- });
42
- Object.defineProperty(exports, "getDirectionChange", {
43
- enumerable: true,
44
- get: function () {
45
- return _utils.getDirectionChange;
46
- }
47
- });
48
- Object.defineProperty(exports, "getGrid", {
49
- enumerable: true,
50
- get: function () {
51
- return _utils.getGrid;
52
- }
53
- });
54
- Object.defineProperty(exports, "getKey", {
55
- enumerable: true,
56
- get: function () {
57
- return _utils.getKey;
58
- }
59
- });
60
- Object.defineProperty(exports, "getManHattanPath", {
61
- enumerable: true,
62
- get: function () {
63
- return _getManHattanPath.getManHattanPath;
64
- }
65
- });
66
- Object.defineProperty(exports, "getNodeDimensions", {
67
- enumerable: true,
68
- get: function () {
69
- return _utils.getNodeDimensions;
70
- }
71
- });
72
- Object.defineProperty(exports, "getNodePosition", {
73
- enumerable: true,
74
- get: function () {
75
- return _utils.getNodePosition;
76
- }
77
- });
78
- Object.defineProperty(exports, "getRectPoints", {
79
- enumerable: true,
80
- get: function () {
81
- return _utils.getRectPoints;
82
- }
83
- });
84
- Object.defineProperty(exports, "normalizePoint", {
85
- enumerable: true,
86
- get: function () {
87
- return _utils.normalizePoint;
88
- }
89
- });
90
- Object.defineProperty(exports, "pointsToPath", {
91
- enumerable: true,
92
- get: function () {
93
- return _svg.pointsToPath;
94
- }
95
- });
96
- Object.defineProperty(exports, "reconstructRoute", {
97
- enumerable: true,
98
- get: function () {
99
- return _utils.reconstructRoute;
100
- }
101
- });
102
- Object.defineProperty(exports, "snapPathToGrid", {
103
- enumerable: true,
104
- get: function () {
105
- return _svg.snapPathToGrid;
106
- }
107
- });
108
- Object.defineProperty(exports, "snapToGrid", {
109
- enumerable: true,
110
- get: function () {
111
- return _utils.snapToGrid;
112
- }
113
- });
114
- var _getManHattanPath = require("./getManHattanPath");
115
- var _geometry = require("./geometry");
116
- var _utils = require("./utils");
117
- var _svg = require("./svg");
@@ -1,34 +0,0 @@
1
- import { Point } from '../geometry';
2
- import type { ResolvedOptions, NodeLookup } from '../options';
3
- /**
4
- * ObstacleMap class for managing obstacles in pathfinding
5
- * Uses a grid-based spatial partitioning for efficient queries
6
- */
7
- export declare class ObstacleMap {
8
- private options;
9
- private mapGridSize;
10
- private map;
11
- private sourceAnchor?;
12
- private targetAnchor?;
13
- constructor(options: ResolvedOptions);
14
- /**
15
- * Build obstacle map from node lookup
16
- */
17
- build(nodeLookup: NodeLookup, sourceNodeId: string, targetNodeId: string, sourceAnchor?: Point, targetAnchor?: Point): ObstacleMap;
18
- /**
19
- * Shrink bbox to exclude the area around the anchor point
20
- * This allows paths to start/end at the anchor but prevents crossing the node
21
- */
22
- private shrinkBBoxAroundAnchor;
23
- /**
24
- * Check if a point is accessible (not inside any obstacle)
25
- * Uses binary search optimization: step -> step/2 -> step/4 -> ... -> 1px
26
- */
27
- isAccessible(point: Point, checkRadius?: number): boolean;
28
- /**
29
- * Check accessibility using binary search optimization
30
- * Tries step -> step/2 -> step/4 -> ... -> 1px
31
- */
32
- private isAccessibleWithBinarySearch;
33
- }
34
- //# sourceMappingURL=ObstacleMap.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"ObstacleMap.d.ts","sourceRoot":"","sources":["../../src/obstacle/ObstacleMap.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAa,MAAM,aAAa,CAAA;AAC9C,OAAO,KAAK,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;AAG7D;;;GAGG;AACH,qBAAa,WAAW;IACtB,OAAO,CAAC,OAAO,CAAiB;IAChC,OAAO,CAAC,WAAW,CAAQ;IAC3B,OAAO,CAAC,GAAG,CAA0B;IACrC,OAAO,CAAC,YAAY,CAAC,CAAO;IAC5B,OAAO,CAAC,YAAY,CAAC,CAAO;gBAEhB,OAAO,EAAE,eAAe;IAMpC;;OAEG;IACH,KAAK,CACH,UAAU,EAAE,UAAU,EACtB,YAAY,EAAE,MAAM,EACpB,YAAY,EAAE,MAAM,EACpB,YAAY,CAAC,EAAE,KAAK,EACpB,YAAY,CAAC,EAAE,KAAK,GACnB,WAAW;IAiEd;;;OAGG;IACH,OAAO,CAAC,sBAAsB;IA6D9B;;;OAGG;IACH,YAAY,CAAC,KAAK,EAAE,KAAK,EAAE,WAAW,GAAE,MAAU,GAAG,OAAO;IAiD5D;;;OAGG;IACH,OAAO,CAAC,4BAA4B;CAqCrC"}