@rxflow/manhattan 0.0.1-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (140) hide show
  1. package/README.md +35 -0
  2. package/cjs/geometry/Line.d.ts +21 -0
  3. package/cjs/geometry/Line.d.ts.map +1 -0
  4. package/cjs/geometry/Line.js +88 -0
  5. package/cjs/geometry/Point.d.ts +49 -0
  6. package/cjs/geometry/Point.d.ts.map +1 -0
  7. package/cjs/geometry/Point.js +94 -0
  8. package/cjs/geometry/Rectangle.d.ts +41 -0
  9. package/cjs/geometry/Rectangle.d.ts.map +1 -0
  10. package/cjs/geometry/Rectangle.js +65 -0
  11. package/cjs/geometry/index.d.ts +4 -0
  12. package/cjs/geometry/index.d.ts.map +1 -0
  13. package/cjs/geometry/index.js +26 -0
  14. package/cjs/getManHattanPath.d.ts +60 -0
  15. package/cjs/getManHattanPath.d.ts.map +1 -0
  16. package/cjs/getManHattanPath.js +285 -0
  17. package/cjs/index.d.ts +16 -0
  18. package/cjs/index.d.ts.map +1 -0
  19. package/cjs/index.js +117 -0
  20. package/cjs/obstacle/ObstacleMap.d.ts +28 -0
  21. package/cjs/obstacle/ObstacleMap.d.ts.map +1 -0
  22. package/cjs/obstacle/ObstacleMap.js +171 -0
  23. package/cjs/obstacle/index.d.ts +2 -0
  24. package/cjs/obstacle/index.d.ts.map +1 -0
  25. package/cjs/obstacle/index.js +12 -0
  26. package/cjs/options/defaults.d.ts +16 -0
  27. package/cjs/options/defaults.d.ts.map +1 -0
  28. package/cjs/options/defaults.js +39 -0
  29. package/cjs/options/index.d.ts +4 -0
  30. package/cjs/options/index.d.ts.map +1 -0
  31. package/cjs/options/index.js +38 -0
  32. package/cjs/options/resolver.d.ts +10 -0
  33. package/cjs/options/resolver.d.ts.map +1 -0
  34. package/cjs/options/resolver.js +118 -0
  35. package/cjs/options/types.d.ts +156 -0
  36. package/cjs/options/types.d.ts.map +1 -0
  37. package/cjs/options/types.js +5 -0
  38. package/cjs/pathfinder/SortedSet.d.ts +35 -0
  39. package/cjs/pathfinder/SortedSet.d.ts.map +1 -0
  40. package/cjs/pathfinder/SortedSet.js +95 -0
  41. package/cjs/pathfinder/findRoute.d.ts +8 -0
  42. package/cjs/pathfinder/findRoute.d.ts.map +1 -0
  43. package/cjs/pathfinder/findRoute.js +156 -0
  44. package/cjs/pathfinder/index.d.ts +3 -0
  45. package/cjs/pathfinder/index.d.ts.map +1 -0
  46. package/cjs/pathfinder/index.js +19 -0
  47. package/cjs/svg/index.d.ts +2 -0
  48. package/cjs/svg/index.d.ts.map +1 -0
  49. package/cjs/svg/index.js +18 -0
  50. package/cjs/svg/pathConverter.d.ts +10 -0
  51. package/cjs/svg/pathConverter.d.ts.map +1 -0
  52. package/cjs/svg/pathConverter.js +105 -0
  53. package/cjs/utils/direction.d.ts +24 -0
  54. package/cjs/utils/direction.d.ts.map +1 -0
  55. package/cjs/utils/direction.js +54 -0
  56. package/cjs/utils/grid.d.ts +26 -0
  57. package/cjs/utils/grid.d.ts.map +1 -0
  58. package/cjs/utils/grid.js +78 -0
  59. package/cjs/utils/index.d.ts +6 -0
  60. package/cjs/utils/index.d.ts.map +1 -0
  61. package/cjs/utils/index.js +60 -0
  62. package/cjs/utils/node.d.ts +27 -0
  63. package/cjs/utils/node.d.ts.map +1 -0
  64. package/cjs/utils/node.js +36 -0
  65. package/cjs/utils/rect.d.ts +9 -0
  66. package/cjs/utils/rect.d.ts.map +1 -0
  67. package/cjs/utils/rect.js +103 -0
  68. package/cjs/utils/route.d.ts +19 -0
  69. package/cjs/utils/route.d.ts.map +1 -0
  70. package/cjs/utils/route.js +76 -0
  71. package/esm/geometry/Line.d.ts +21 -0
  72. package/esm/geometry/Line.d.ts.map +1 -0
  73. package/esm/geometry/Line.js +96 -0
  74. package/esm/geometry/Point.d.ts +49 -0
  75. package/esm/geometry/Point.d.ts.map +1 -0
  76. package/esm/geometry/Point.js +117 -0
  77. package/esm/geometry/Rectangle.d.ts +41 -0
  78. package/esm/geometry/Rectangle.d.ts.map +1 -0
  79. package/esm/geometry/Rectangle.js +81 -0
  80. package/esm/geometry/index.d.ts +4 -0
  81. package/esm/geometry/index.d.ts.map +1 -0
  82. package/esm/geometry/index.js +3 -0
  83. package/esm/getManHattanPath.d.ts +60 -0
  84. package/esm/getManHattanPath.d.ts.map +1 -0
  85. package/esm/getManHattanPath.js +291 -0
  86. package/esm/index.d.ts +16 -0
  87. package/esm/index.d.ts.map +1 -0
  88. package/esm/index.js +24 -0
  89. package/esm/obstacle/ObstacleMap.d.ts +28 -0
  90. package/esm/obstacle/ObstacleMap.d.ts.map +1 -0
  91. package/esm/obstacle/ObstacleMap.js +183 -0
  92. package/esm/obstacle/index.d.ts +2 -0
  93. package/esm/obstacle/index.d.ts.map +1 -0
  94. package/esm/obstacle/index.js +1 -0
  95. package/esm/options/defaults.d.ts +16 -0
  96. package/esm/options/defaults.d.ts.map +1 -0
  97. package/esm/options/defaults.js +33 -0
  98. package/esm/options/index.d.ts +4 -0
  99. package/esm/options/index.d.ts.map +1 -0
  100. package/esm/options/index.js +3 -0
  101. package/esm/options/resolver.d.ts +10 -0
  102. package/esm/options/resolver.d.ts.map +1 -0
  103. package/esm/options/resolver.js +114 -0
  104. package/esm/options/types.d.ts +156 -0
  105. package/esm/options/types.d.ts.map +1 -0
  106. package/esm/options/types.js +1 -0
  107. package/esm/pathfinder/SortedSet.d.ts +35 -0
  108. package/esm/pathfinder/SortedSet.d.ts.map +1 -0
  109. package/esm/pathfinder/SortedSet.js +110 -0
  110. package/esm/pathfinder/findRoute.d.ts +8 -0
  111. package/esm/pathfinder/findRoute.d.ts.map +1 -0
  112. package/esm/pathfinder/findRoute.js +189 -0
  113. package/esm/pathfinder/index.d.ts +3 -0
  114. package/esm/pathfinder/index.d.ts.map +1 -0
  115. package/esm/pathfinder/index.js +2 -0
  116. package/esm/svg/index.d.ts +2 -0
  117. package/esm/svg/index.d.ts.map +1 -0
  118. package/esm/svg/index.js +1 -0
  119. package/esm/svg/pathConverter.d.ts +10 -0
  120. package/esm/svg/pathConverter.d.ts.map +1 -0
  121. package/esm/svg/pathConverter.js +107 -0
  122. package/esm/utils/direction.d.ts +24 -0
  123. package/esm/utils/direction.d.ts.map +1 -0
  124. package/esm/utils/direction.js +46 -0
  125. package/esm/utils/grid.d.ts +26 -0
  126. package/esm/utils/grid.d.ts.map +1 -0
  127. package/esm/utils/grid.js +70 -0
  128. package/esm/utils/index.d.ts +6 -0
  129. package/esm/utils/index.d.ts.map +1 -0
  130. package/esm/utils/index.js +5 -0
  131. package/esm/utils/node.d.ts +27 -0
  132. package/esm/utils/node.d.ts.map +1 -0
  133. package/esm/utils/node.js +30 -0
  134. package/esm/utils/rect.d.ts +9 -0
  135. package/esm/utils/rect.d.ts.map +1 -0
  136. package/esm/utils/rect.js +121 -0
  137. package/esm/utils/route.d.ts +19 -0
  138. package/esm/utils/route.d.ts.map +1 -0
  139. package/esm/utils/route.js +80 -0
  140. package/package.json +43 -0
@@ -0,0 +1,285 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.getManHattanPath = getManHattanPath;
7
+ var _geometry = require("./geometry");
8
+ var _options = require("./options");
9
+ var _obstacle = require("./obstacle");
10
+ var _pathfinder = require("./pathfinder");
11
+ var _svg = require("./svg");
12
+ var _utils = require("./utils");
13
+ /**
14
+ * Parameters for getManHattanPath function
15
+ */
16
+
17
+ /**
18
+ * Generate Manhattan-routed path for ReactFlow edges
19
+ *
20
+ * @param params - Path generation parameters
21
+ * @returns SVG path string that can be used with ReactFlow's BaseEdge
22
+ *
23
+ * @example
24
+ * ```typescript
25
+ * const path = getManHattanPath({
26
+ * sourceNodeId: 'node1',
27
+ * targetNodeId: 'node2',
28
+ * sourcePosition: { x: 100, y: 100 },
29
+ * targetPosition: { x: 300, y: 300 },
30
+ * nodeLookup: nodes,
31
+ * options: {
32
+ * step: 10,
33
+ * startDirections: ['bottom'],
34
+ * endDirections: ['top']
35
+ * }
36
+ * })
37
+ * ```
38
+ */
39
+ function getManHattanPath(params) {
40
+ const {
41
+ sourceNodeId,
42
+ targetNodeId,
43
+ sourcePosition,
44
+ targetPosition,
45
+ nodeLookup,
46
+ options: userOptions = {}
47
+ } = params;
48
+
49
+ // Resolve options
50
+ const options = (0, _options.resolveOptions)(userOptions);
51
+
52
+ // Get source and target nodes
53
+ const sourceNode = nodeLookup.get(sourceNodeId);
54
+ const targetNode = nodeLookup.get(targetNodeId);
55
+ if (!sourceNode || !targetNode) {
56
+ // Fallback to simple straight line if nodes not found
57
+ console.warn('Source or target node not found in nodeLookup');
58
+ const start = new _geometry.Point(sourcePosition.x, sourcePosition.y);
59
+ const end = new _geometry.Point(targetPosition.x, targetPosition.y);
60
+ return (0, _svg.pointsToPath)([start, end], options.precision);
61
+ }
62
+
63
+ // Get node dimensions using ReactFlow's priority logic
64
+ const sourceDimensions = (0, _utils.getNodeDimensions)(sourceNode);
65
+ const targetDimensions = (0, _utils.getNodeDimensions)(targetNode);
66
+
67
+ // Get absolute positions from internals
68
+ const sourcePos = (0, _utils.getNodePosition)(sourceNode);
69
+ const targetPos = (0, _utils.getNodePosition)(targetNode);
70
+
71
+ // Calculate bounding boxes
72
+ const sourceBBox = new _geometry.Rectangle(sourcePos.x, sourcePos.y, sourceDimensions.width, sourceDimensions.height);
73
+ const targetBBox = new _geometry.Rectangle(targetPos.x, targetPos.y, targetDimensions.width, targetDimensions.height);
74
+
75
+ // Create anchor points
76
+ const sourceAnchor = new _geometry.Point(sourcePosition.x, sourcePosition.y);
77
+ const targetAnchor = new _geometry.Point(targetPosition.x, targetPosition.y);
78
+
79
+ // Build obstacle map with anchor information
80
+ const obstacleMap = new _obstacle.ObstacleMap(options).build(nodeLookup, sourceNodeId, targetNodeId, sourceAnchor, targetAnchor);
81
+
82
+ // Find route
83
+ let route = (0, _pathfinder.findRoute)(sourceBBox, targetBBox, sourceAnchor, targetAnchor, obstacleMap, options);
84
+
85
+ // Fallback to straight line if no route found
86
+ if (!route) {
87
+ console.warn('Unable to find Manhattan route, using straight line fallback');
88
+ route = [sourceAnchor, targetAnchor];
89
+ }
90
+ console.log('[getManHattanPath] Route from findRoute:', route.map(p => `(${p.x}, ${p.y})`));
91
+ console.log('[getManHattanPath] Source anchor:', `(${sourceAnchor.x}, ${sourceAnchor.y})`);
92
+ console.log('[getManHattanPath] Target anchor:', `(${targetAnchor.x}, ${targetAnchor.y})`);
93
+
94
+ // Remove extension points from route that were added by getRectPoints
95
+ // We will add our own with fixed step distance
96
+ const step = options.step;
97
+ const tolerance = 1;
98
+
99
+ // Check if first point is an extension point from source
100
+ if (route.length > 0) {
101
+ const firstPoint = route[0];
102
+ const onLeft = Math.abs(sourceAnchor.x - sourceBBox.x) < tolerance;
103
+ const onRight = Math.abs(sourceAnchor.x - (sourceBBox.x + sourceBBox.width)) < tolerance;
104
+ const onTop = Math.abs(sourceAnchor.y - sourceBBox.y) < tolerance;
105
+ const onBottom = Math.abs(sourceAnchor.y - (sourceBBox.y + sourceBBox.height)) < tolerance;
106
+
107
+ // Check if firstPoint is close to source anchor (indicating it's an extension point)
108
+ const distToFirst = sourceAnchor.manhattanDistance(firstPoint);
109
+ if (distToFirst < step * 2) {
110
+ // This is likely an extension point, remove it
111
+ if (onRight && firstPoint.x > sourceAnchor.x || onLeft && firstPoint.x < sourceAnchor.x || onBottom && firstPoint.y > sourceAnchor.y || onTop && firstPoint.y < sourceAnchor.y) {
112
+ route.shift();
113
+ console.log('[getManHattanPath] Removed extension point from route start');
114
+ }
115
+ }
116
+ }
117
+
118
+ // Check if last point is an extension point from target
119
+ if (route.length > 0) {
120
+ const lastPoint = route[route.length - 1];
121
+ const onLeft = Math.abs(targetAnchor.x - targetBBox.x) < tolerance;
122
+ const onRight = Math.abs(targetAnchor.x - (targetBBox.x + targetBBox.width)) < tolerance;
123
+ const onTop = Math.abs(targetAnchor.y - targetBBox.y) < tolerance;
124
+ const onBottom = Math.abs(targetAnchor.y - (targetBBox.y + targetBBox.height)) < tolerance;
125
+
126
+ // Check if lastPoint is close to target anchor (indicating it's an extension point)
127
+ const distToLast = targetAnchor.manhattanDistance(lastPoint);
128
+ if (distToLast < step * 2) {
129
+ // This is likely an extension point, remove it
130
+ if (onLeft && lastPoint.x < targetAnchor.x || onRight && lastPoint.x > targetAnchor.x || onTop && lastPoint.y < targetAnchor.y || onBottom && lastPoint.y > targetAnchor.y) {
131
+ route.pop();
132
+ console.log('[getManHattanPath] Removed extension point from route end');
133
+ }
134
+ }
135
+ }
136
+
137
+ // Insert extension point at source - always extend away from node edge by fixed step distance
138
+ if (route.length > 0) {
139
+ const firstPoint = route[0];
140
+
141
+ // Determine which edge the source anchor is on
142
+ const onLeft = Math.abs(sourceAnchor.x - sourceBBox.x) < tolerance;
143
+ const onRight = Math.abs(sourceAnchor.x - (sourceBBox.x + sourceBBox.width)) < tolerance;
144
+ const onTop = Math.abs(sourceAnchor.y - sourceBBox.y) < tolerance;
145
+ const onBottom = Math.abs(sourceAnchor.y - (sourceBBox.y + sourceBBox.height)) < tolerance;
146
+
147
+ // Insert extension point and corner point to ensure orthogonal path
148
+ if (onRight) {
149
+ // Anchor on right edge - extend right by fixed step
150
+ const extendX = sourceAnchor.x + step;
151
+ const extensionPoint = new _geometry.Point(extendX, sourceAnchor.y);
152
+ // Check if we need a corner point
153
+ if (Math.abs(extensionPoint.y - firstPoint.y) > tolerance) {
154
+ route.unshift(new _geometry.Point(extendX, firstPoint.y)); // Corner point
155
+ }
156
+ route.unshift(extensionPoint); // Extension point (fixed distance)
157
+ console.log('[getManHattanPath] Inserted source extension (right):', `(${extendX}, ${sourceAnchor.y})`);
158
+ } else if (onLeft) {
159
+ // Anchor on left edge - extend left by fixed step
160
+ const extendX = sourceAnchor.x - step;
161
+ const extensionPoint = new _geometry.Point(extendX, sourceAnchor.y);
162
+ if (Math.abs(extensionPoint.y - firstPoint.y) > tolerance) {
163
+ route.unshift(new _geometry.Point(extendX, firstPoint.y));
164
+ }
165
+ route.unshift(extensionPoint);
166
+ console.log('[getManHattanPath] Inserted source extension (left):', `(${extendX}, ${sourceAnchor.y})`);
167
+ } else if (onBottom) {
168
+ // Anchor on bottom edge - extend down by fixed step
169
+ const extendY = sourceAnchor.y + step;
170
+ const extensionPoint = new _geometry.Point(sourceAnchor.x, extendY);
171
+ if (Math.abs(extensionPoint.x - firstPoint.x) > tolerance) {
172
+ route.unshift(new _geometry.Point(firstPoint.x, extendY));
173
+ }
174
+ route.unshift(extensionPoint);
175
+ console.log('[getManHattanPath] Inserted source extension (down):', `(${sourceAnchor.x}, ${extendY})`);
176
+ } else if (onTop) {
177
+ // Anchor on top edge - extend up by fixed step
178
+ const extendY = sourceAnchor.y - step;
179
+ const extensionPoint = new _geometry.Point(sourceAnchor.x, extendY);
180
+ if (Math.abs(extensionPoint.x - firstPoint.x) > tolerance) {
181
+ route.unshift(new _geometry.Point(firstPoint.x, extendY));
182
+ }
183
+ route.unshift(extensionPoint);
184
+ console.log('[getManHattanPath] Inserted source extension (up):', `(${sourceAnchor.x}, ${extendY})`);
185
+ }
186
+ }
187
+
188
+ // Insert extension point at target - always extend away from node edge by fixed step distance
189
+ if (route.length > 0) {
190
+ const step = options.step;
191
+ const tolerance = 1;
192
+ const lastPoint = route[route.length - 1];
193
+
194
+ // Determine which edge the target anchor is on
195
+ const onLeft = Math.abs(targetAnchor.x - targetBBox.x) < tolerance;
196
+ const onRight = Math.abs(targetAnchor.x - (targetBBox.x + targetBBox.width)) < tolerance;
197
+ const onTop = Math.abs(targetAnchor.y - targetBBox.y) < tolerance;
198
+ const onBottom = Math.abs(targetAnchor.y - (targetBBox.y + targetBBox.height)) < tolerance;
199
+
200
+ // Insert extension point and corner point to ensure orthogonal path
201
+ if (onLeft) {
202
+ // Anchor on left edge - extend left by fixed step
203
+ const extendX = targetAnchor.x - step;
204
+ const extensionPoint = new _geometry.Point(extendX, targetAnchor.y);
205
+ if (Math.abs(extensionPoint.y - lastPoint.y) > tolerance) {
206
+ route.push(new _geometry.Point(extendX, lastPoint.y)); // Corner point
207
+ }
208
+ route.push(extensionPoint); // Extension point (fixed distance)
209
+ console.log('[getManHattanPath] Inserted target extension (left):', `(${extendX}, ${targetAnchor.y})`);
210
+ } else if (onRight) {
211
+ // Anchor on right edge - extend right by fixed step
212
+ const extendX = targetAnchor.x + step;
213
+ const extensionPoint = new _geometry.Point(extendX, targetAnchor.y);
214
+ if (Math.abs(extensionPoint.y - lastPoint.y) > tolerance) {
215
+ route.push(new _geometry.Point(extendX, lastPoint.y));
216
+ }
217
+ route.push(extensionPoint);
218
+ console.log('[getManHattanPath] Inserted target extension (right):', `(${extendX}, ${targetAnchor.y})`);
219
+ } else if (onTop) {
220
+ // Anchor on top edge - extend up by fixed step
221
+ const extendY = targetAnchor.y - step;
222
+ const extensionPoint = new _geometry.Point(targetAnchor.x, extendY);
223
+ if (Math.abs(extensionPoint.x - lastPoint.x) > tolerance) {
224
+ route.push(new _geometry.Point(lastPoint.x, extendY));
225
+ }
226
+ route.push(extensionPoint);
227
+ console.log('[getManHattanPath] Inserted target extension (up):', `(${targetAnchor.x}, ${extendY})`);
228
+ } else if (onBottom) {
229
+ // Anchor on bottom edge - extend down by fixed step
230
+ const extendY = targetAnchor.y + step;
231
+ const extensionPoint = new _geometry.Point(targetAnchor.x, extendY);
232
+ if (Math.abs(extensionPoint.x - lastPoint.x) > tolerance) {
233
+ route.push(new _geometry.Point(lastPoint.x, extendY));
234
+ }
235
+ route.push(extensionPoint);
236
+ console.log('[getManHattanPath] Inserted target extension (down):', `(${targetAnchor.x}, ${extendY})`);
237
+ }
238
+ }
239
+
240
+ // Add source and target anchors to route
241
+ const fullRoute = [sourceAnchor, ...route, targetAnchor];
242
+ console.log('[getManHattanPath] Full route:', fullRoute.map(p => `(${p.x}, ${p.y})`));
243
+
244
+ // Snap to grid if enabled
245
+ let finalRoute = fullRoute;
246
+ if (options.snapToGrid) {
247
+ // Use step size as grid size for snapping
248
+ finalRoute = (0, _svg.snapPathToGrid)(fullRoute, options.step);
249
+ }
250
+
251
+ // Simplify path by removing collinear points
252
+ finalRoute = simplifyPath(finalRoute);
253
+ console.log('[getManHattanPath] Simplified route:', finalRoute.map(p => `(${p.x}, ${p.y})`));
254
+
255
+ // Convert to SVG path string
256
+ return (0, _svg.pointsToPath)(finalRoute, options.precision, options.borderRadius);
257
+ }
258
+
259
+ /**
260
+ * Simplify path by removing collinear intermediate points
261
+ */
262
+ function simplifyPath(points) {
263
+ if (points.length <= 2) {
264
+ return points;
265
+ }
266
+ const simplified = [points[0]];
267
+ for (let i = 1; i < points.length - 1; i++) {
268
+ const prev = simplified[simplified.length - 1];
269
+ const current = points[i];
270
+ const next = points[i + 1];
271
+
272
+ // Check if current point is collinear with prev and next
273
+ const isHorizontalLine = prev.y === current.y && current.y === next.y;
274
+ const isVerticalLine = prev.x === current.x && current.x === next.x;
275
+
276
+ // Only keep the point if it's not collinear (i.e., it's a corner)
277
+ if (!isHorizontalLine && !isVerticalLine) {
278
+ simplified.push(current);
279
+ }
280
+ }
281
+
282
+ // Always add the last point
283
+ simplified.push(points[points.length - 1]);
284
+ return simplified;
285
+ }
package/cjs/index.d.ts ADDED
@@ -0,0 +1,16 @@
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
@@ -0,0 +1 @@
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 ADDED
@@ -0,0 +1,117 @@
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");
@@ -0,0 +1,28 @@
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
+ */
26
+ isAccessible(point: Point): boolean;
27
+ }
28
+ //# sourceMappingURL=ObstacleMap.d.ts.map
@@ -0,0 +1 @@
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;;OAEG;IACH,YAAY,CAAC,KAAK,EAAE,KAAK,GAAG,OAAO;CA2CpC"}
@@ -0,0 +1,171 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.ObstacleMap = void 0;
7
+ var _geometry = require("../geometry");
8
+ var _utils = require("../utils");
9
+ /**
10
+ * ObstacleMap class for managing obstacles in pathfinding
11
+ * Uses a grid-based spatial partitioning for efficient queries
12
+ */
13
+ class ObstacleMap {
14
+ options;
15
+ mapGridSize;
16
+ map;
17
+ sourceAnchor;
18
+ targetAnchor;
19
+ constructor(options) {
20
+ this.options = options;
21
+ this.mapGridSize = 100;
22
+ this.map = new Map();
23
+ }
24
+
25
+ /**
26
+ * Build obstacle map from node lookup
27
+ */
28
+ build(nodeLookup, sourceNodeId, targetNodeId, sourceAnchor, targetAnchor) {
29
+ const {
30
+ excludeNodes,
31
+ excludeShapes,
32
+ excludeTerminals,
33
+ paddingBox
34
+ } = this.options;
35
+
36
+ // Store anchors for later use in isAccessible
37
+ this.sourceAnchor = sourceAnchor;
38
+ this.targetAnchor = targetAnchor;
39
+
40
+ // Iterate through all nodes
41
+ nodeLookup.forEach(node => {
42
+ // Check if node should be excluded
43
+ const isExcludedNode = excludeNodes.includes(node.id);
44
+ const isExcludedShape = node.type ? excludeShapes.includes(node.type) : false;
45
+ const isSourceTerminal = excludeTerminals.includes('source') && node.id === sourceNodeId;
46
+ const isTargetTerminal = excludeTerminals.includes('target') && node.id === targetNodeId;
47
+ const isSource = node.id === sourceNodeId;
48
+ const isTarget = node.id === targetNodeId;
49
+
50
+ // Skip if node should be excluded (but not source/target - we handle them specially)
51
+ if (isExcludedNode || isExcludedShape || isSourceTerminal || isTargetTerminal) {
52
+ return;
53
+ }
54
+
55
+ // Calculate node bounding box with padding
56
+ const position = (0, _utils.getNodePosition)(node);
57
+ const dimensions = (0, _utils.getNodeDimensions)(node);
58
+ let bbox = new _geometry.Rectangle(position.x, position.y, dimensions.width, dimensions.height).moveAndExpand(paddingBox);
59
+
60
+ // For source and target nodes, add them as full obstacles
61
+ // We'll handle anchor accessibility in isAccessible() method
62
+ if (isSource) {
63
+ console.log('[ObstacleMap] Adding source node as obstacle:');
64
+ console.log(' Node ID:', node.id);
65
+ console.log(' BBox:', `(${bbox.x}, ${bbox.y}, ${bbox.width}, ${bbox.height})`);
66
+ console.log(' Anchor:', sourceAnchor ? `(${sourceAnchor.x}, ${sourceAnchor.y})` : 'none');
67
+ } else if (isTarget) {
68
+ console.log('[ObstacleMap] Adding target node as obstacle:');
69
+ console.log(' Node ID:', node.id);
70
+ console.log(' BBox:', `(${bbox.x}, ${bbox.y}, ${bbox.width}, ${bbox.height})`);
71
+ console.log(' Anchor:', targetAnchor ? `(${targetAnchor.x}, ${targetAnchor.y})` : 'none');
72
+ }
73
+
74
+ // Map bbox to grid cells
75
+ const origin = bbox.getOrigin().snapToGrid(this.mapGridSize);
76
+ const corner = bbox.getCorner().snapToGrid(this.mapGridSize);
77
+ for (let x = origin.x; x <= corner.x; x += this.mapGridSize) {
78
+ for (let y = origin.y; y <= corner.y; y += this.mapGridSize) {
79
+ const key = new _geometry.Point(x, y).toString();
80
+ if (!this.map.has(key)) {
81
+ this.map.set(key, []);
82
+ }
83
+ this.map.get(key).push(bbox);
84
+ }
85
+ }
86
+ });
87
+ return this;
88
+ }
89
+
90
+ /**
91
+ * Shrink bbox to exclude the area around the anchor point
92
+ * This allows paths to start/end at the anchor but prevents crossing the node
93
+ */
94
+ shrinkBBoxAroundAnchor(bbox, anchor, nodePosition, nodeDimensions) {
95
+ const tolerance = 1;
96
+ const step = this.options.step || 10;
97
+ const margin = step * 3; // Increased margin for better clearance
98
+
99
+ // Determine which edge the anchor is on (relative to original node position)
100
+ const onLeft = Math.abs(anchor.x - nodePosition.x) < tolerance;
101
+ const onRight = Math.abs(anchor.x - (nodePosition.x + nodeDimensions.width)) < tolerance;
102
+ const onTop = Math.abs(anchor.y - nodePosition.y) < tolerance;
103
+ const onBottom = Math.abs(anchor.y - (nodePosition.y + nodeDimensions.height)) < tolerance;
104
+ console.log('[shrinkBBoxAroundAnchor] Edge detection:');
105
+ console.log(' anchor.x:', anchor.x, 'nodePosition.x:', nodePosition.x, 'diff:', Math.abs(anchor.x - nodePosition.x));
106
+ console.log(' anchor.x:', anchor.x, 'nodeRight:', nodePosition.x + nodeDimensions.width, 'diff:', Math.abs(anchor.x - (nodePosition.x + nodeDimensions.width)));
107
+ console.log(' onLeft:', onLeft, 'onRight:', onRight, 'onTop:', onTop, 'onBottom:', onBottom);
108
+ console.log(' margin:', margin);
109
+
110
+ // Shrink bbox based on anchor position
111
+ if (onLeft) {
112
+ // Anchor on left edge - exclude left portion
113
+ return new _geometry.Rectangle(bbox.x + margin, bbox.y, Math.max(0, bbox.width - margin), bbox.height);
114
+ } else if (onRight) {
115
+ // Anchor on right edge - exclude right portion
116
+ return new _geometry.Rectangle(bbox.x, bbox.y, Math.max(0, bbox.width - margin), bbox.height);
117
+ } else if (onTop) {
118
+ // Anchor on top edge - exclude top portion
119
+ return new _geometry.Rectangle(bbox.x, bbox.y + margin, bbox.width, Math.max(0, bbox.height - margin));
120
+ } else if (onBottom) {
121
+ // Anchor on bottom edge - exclude bottom portion
122
+ return new _geometry.Rectangle(bbox.x, bbox.y, bbox.width, Math.max(0, bbox.height - margin));
123
+ }
124
+
125
+ // If anchor is not on an edge, return original bbox
126
+ return bbox;
127
+ }
128
+
129
+ /**
130
+ * Check if a point is accessible (not inside any obstacle)
131
+ */
132
+ isAccessible(point) {
133
+ const key = point.clone().snapToGrid(this.mapGridSize).toString();
134
+ const rects = this.map.get(key);
135
+ if (!rects) {
136
+ return true;
137
+ }
138
+
139
+ // Check if point is near an anchor - if so, allow it
140
+ const margin = (this.options.step || 10) * 3;
141
+ if (this.sourceAnchor) {
142
+ const distToSource = Math.abs(point.x - this.sourceAnchor.x) + Math.abs(point.y - this.sourceAnchor.y);
143
+ if (distToSource < margin) {
144
+ console.log(`[isAccessible] Point (${point.x}, ${point.y}): accessible (near source anchor)`);
145
+ return true;
146
+ }
147
+ }
148
+ if (this.targetAnchor) {
149
+ const distToTarget = Math.abs(point.x - this.targetAnchor.x) + Math.abs(point.y - this.targetAnchor.y);
150
+ if (distToTarget < margin) {
151
+ console.log(`[isAccessible] Point (${point.x}, ${point.y}): accessible (near target anchor)`);
152
+ return true;
153
+ }
154
+ }
155
+ const accessible = rects.every(rect => !rect.containsPoint(point));
156
+
157
+ // Debug: log points on the direct path
158
+ if (point.y === 40 && point.x >= 0 && point.x <= 545) {
159
+ console.log(`[isAccessible] Point (${point.x}, ${point.y}): ${accessible ? 'accessible' : 'BLOCKED'}`);
160
+ if (!accessible) {
161
+ rects.forEach((rect, i) => {
162
+ if (rect.containsPoint(point)) {
163
+ console.log(` Blocked by rect ${i}: (${rect.x}, ${rect.y}, ${rect.width}, ${rect.height})`);
164
+ }
165
+ });
166
+ }
167
+ }
168
+ return accessible;
169
+ }
170
+ }
171
+ exports.ObstacleMap = ObstacleMap;
@@ -0,0 +1,2 @@
1
+ export { ObstacleMap } from './ObstacleMap';
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/obstacle/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAA"}
@@ -0,0 +1,12 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ Object.defineProperty(exports, "ObstacleMap", {
7
+ enumerable: true,
8
+ get: function () {
9
+ return _ObstacleMap.ObstacleMap;
10
+ }
11
+ });
12
+ var _ObstacleMap = require("./ObstacleMap");
@@ -0,0 +1,16 @@
1
+ import { Point } from '../geometry';
2
+ import type { ManhattanRouterOptions } from './types';
3
+ /**
4
+ * Default configuration for Manhattan router
5
+ */
6
+ export declare const defaults: Required<Omit<ManhattanRouterOptions, 'fallbackRoute'>>;
7
+ /**
8
+ * Direction map - maps direction names to unit vectors
9
+ */
10
+ export declare const directionMap: {
11
+ top: Point;
12
+ right: Point;
13
+ bottom: Point;
14
+ left: Point;
15
+ };
16
+ //# sourceMappingURL=defaults.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"defaults.d.ts","sourceRoot":"","sources":["../../src/options/defaults.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAA;AACnC,OAAO,KAAK,EAAE,sBAAsB,EAAa,MAAM,SAAS,CAAA;AAEhE;;GAEG;AACH,eAAO,MAAM,QAAQ,EAAE,QAAQ,CAAC,IAAI,CAAC,sBAAsB,EAAE,eAAe,CAAC,CAkB5E,CAAA;AAED;;GAEG;AACH,eAAO,MAAM,YAAY;;;;;CAKxB,CAAA"}