@rxflow/manhattan 0.0.1-alpha.10 → 0.0.1-alpha.12

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 (49) hide show
  1. package/cjs/geometry/Rectangle.d.ts +1 -1
  2. package/cjs/geometry/Rectangle.js +2 -2
  3. package/cjs/getManHattanPath.d.ts.map +1 -1
  4. package/cjs/getManHattanPath.js +153 -20
  5. package/cjs/obstacle/ObstacleMap.d.ts +7 -1
  6. package/cjs/obstacle/ObstacleMap.d.ts.map +1 -1
  7. package/cjs/obstacle/ObstacleMap.js +53 -1
  8. package/cjs/options/defaults.d.ts +1 -1
  9. package/cjs/options/defaults.d.ts.map +1 -1
  10. package/cjs/options/defaults.js +1 -1
  11. package/cjs/options/resolver.d.ts.map +1 -1
  12. package/cjs/options/resolver.js +4 -2
  13. package/cjs/options/types.d.ts +19 -6
  14. package/cjs/options/types.d.ts.map +1 -1
  15. package/cjs/pathfinder/findRoute.d.ts.map +1 -1
  16. package/cjs/pathfinder/findRoute.js +184 -13
  17. package/cjs/svg/pathConverter.d.ts.map +1 -1
  18. package/cjs/svg/pathConverter.js +23 -12
  19. package/cjs/utils/getAnchorPoints.d.ts +15 -0
  20. package/cjs/utils/getAnchorPoints.d.ts.map +1 -0
  21. package/cjs/utils/getAnchorPoints.js +75 -0
  22. package/cjs/utils/index.d.ts +1 -0
  23. package/cjs/utils/index.d.ts.map +1 -1
  24. package/cjs/utils/index.js +11 -0
  25. package/esm/geometry/Rectangle.d.ts +1 -1
  26. package/esm/geometry/Rectangle.js +2 -2
  27. package/esm/getManHattanPath.d.ts.map +1 -1
  28. package/esm/getManHattanPath.js +162 -22
  29. package/esm/obstacle/ObstacleMap.d.ts +7 -1
  30. package/esm/obstacle/ObstacleMap.d.ts.map +1 -1
  31. package/esm/obstacle/ObstacleMap.js +78 -0
  32. package/esm/options/defaults.d.ts +1 -1
  33. package/esm/options/defaults.d.ts.map +1 -1
  34. package/esm/options/defaults.js +1 -1
  35. package/esm/options/resolver.d.ts.map +1 -1
  36. package/esm/options/resolver.js +5 -3
  37. package/esm/options/types.d.ts +19 -6
  38. package/esm/options/types.d.ts.map +1 -1
  39. package/esm/pathfinder/findRoute.d.ts.map +1 -1
  40. package/esm/pathfinder/findRoute.js +206 -21
  41. package/esm/svg/pathConverter.d.ts.map +1 -1
  42. package/esm/svg/pathConverter.js +23 -12
  43. package/esm/utils/getAnchorPoints.d.ts +15 -0
  44. package/esm/utils/getAnchorPoints.d.ts.map +1 -0
  45. package/esm/utils/getAnchorPoints.js +69 -0
  46. package/esm/utils/index.d.ts +1 -0
  47. package/esm/utils/index.d.ts.map +1 -1
  48. package/esm/utils/index.js +2 -1
  49. package/package.json +1 -1
@@ -1,8 +1,115 @@
1
1
  function _createForOfIteratorHelper(o, allowArrayLike) { var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; if (!it) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = it.call(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it.return != null) it.return(); } finally { if (didErr) throw err; } } }; }
2
2
  function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
3
3
  function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; }
4
+ import { Point } from "../geometry";
4
5
  import { SortedSet } from "./SortedSet";
5
- import { getGrid, align, round, getDirectionAngle, getDirectionChange, getGridOffsets, getRectPoints, getCost, getKey, reconstructRoute } from "../utils";
6
+ import { getGrid, round, getDirectionAngle, getDirectionChange, getGridOffsets, getRectPoints, getCost, getKey, reconstructRoute } from "../utils";
7
+
8
+ /**
9
+ * Generate smart points based on position using extensionDistance and binary search
10
+ *
11
+ * Algorithm:
12
+ * 1. First try extensionDistance in the specified direction
13
+ * 2. If blocked, use binary search starting from step, halving until finding accessible point
14
+ * 3. For target points, approach from opposite direction
15
+ */
16
+ function generateSmartPoints(anchor, bbox, position, grid, map, options) {
17
+ var isTarget = arguments.length > 6 && arguments[6] !== undefined ? arguments[6] : false;
18
+ var directionMap = {
19
+ 'right': {
20
+ x: 1,
21
+ y: 0
22
+ },
23
+ 'left': {
24
+ x: -1,
25
+ y: 0
26
+ },
27
+ 'top': {
28
+ x: 0,
29
+ y: -1
30
+ },
31
+ 'bottom': {
32
+ x: 0,
33
+ y: 1
34
+ }
35
+ };
36
+ var direction = directionMap[position];
37
+ if (!direction) {
38
+ console.warn("[generateSmartPoints] Unknown position: ".concat(position, ", falling back to anchor"));
39
+ return [anchor];
40
+ }
41
+
42
+ // Both source and target extend in the specified direction
43
+ // - Source: extends away from node in sourcePosition direction
44
+ // - Target: extends away from node in targetPosition direction (path approaches from this direction)
45
+ var actualDirection = direction;
46
+ var points = [];
47
+
48
+ // 1. First try extensionDistance
49
+ var extensionPoint = new Point(anchor.x + actualDirection.x * options.extensionDistance, anchor.y + actualDirection.y * options.extensionDistance).round(options.precision);
50
+ console.log("[generateSmartPoints] ".concat(isTarget ? 'Target' : 'Source', " position=").concat(position, ", trying extension point: (").concat(extensionPoint.x, ", ").concat(extensionPoint.y, ")"));
51
+ if (map.isAccessible(extensionPoint)) {
52
+ points.push(extensionPoint);
53
+ console.log("[generateSmartPoints] Extension point is accessible");
54
+ return points;
55
+ }
56
+ console.log("[generateSmartPoints] Extension point blocked, using step-based search");
57
+
58
+ // 2. Step-based search with binary refinement
59
+ // First, extend outward by step increments until we find an accessible point
60
+ var stepMultiplier = 1;
61
+ var maxSteps = 20; // Prevent infinite loop
62
+ var foundAccessibleDistance = -1;
63
+ console.log("[generateSmartPoints] Starting outward search with step=".concat(options.step));
64
+ while (stepMultiplier <= maxSteps) {
65
+ var distance = stepMultiplier * options.step;
66
+ var testPoint = new Point(anchor.x + actualDirection.x * distance, anchor.y + actualDirection.y * distance).round(options.precision);
67
+ console.log("[generateSmartPoints] Testing ".concat(stepMultiplier, "*step (distance=").concat(distance, "): (").concat(testPoint.x, ", ").concat(testPoint.y, ")"));
68
+ if (map.isAccessible(testPoint)) {
69
+ foundAccessibleDistance = distance;
70
+ console.log("[generateSmartPoints] Found accessible point at ".concat(stepMultiplier, "*step (distance=").concat(distance, ")"));
71
+ break;
72
+ }
73
+ stepMultiplier++;
74
+ }
75
+
76
+ // 3. If we found an accessible point, refine by binary search within the last step interval
77
+ if (foundAccessibleDistance > 0) {
78
+ var outerDistance = foundAccessibleDistance;
79
+ var innerDistance = foundAccessibleDistance - options.step;
80
+ console.log("[generateSmartPoints] Refining between ".concat(innerDistance, " and ").concat(outerDistance));
81
+
82
+ // Binary search within the last step interval to find the closest accessible point
83
+ var left = innerDistance;
84
+ var right = outerDistance;
85
+ var bestDistance = outerDistance;
86
+
87
+ // Binary search with precision of 1px
88
+ while (right - left > 1) {
89
+ var mid = (left + right) / 2;
90
+ var _testPoint = new Point(anchor.x + actualDirection.x * mid, anchor.y + actualDirection.y * mid).round(options.precision);
91
+ console.log("[generateSmartPoints] Binary search testing distance ".concat(mid.toFixed(1), ": (").concat(_testPoint.x, ", ").concat(_testPoint.y, ")"));
92
+ if (map.isAccessible(_testPoint)) {
93
+ bestDistance = mid;
94
+ right = mid;
95
+ console.log("[generateSmartPoints] Point accessible, searching closer (right=".concat(right, ")"));
96
+ } else {
97
+ left = mid;
98
+ console.log("[generateSmartPoints] Point blocked, searching further (left=".concat(left, ")"));
99
+ }
100
+ }
101
+
102
+ // Use the best distance found
103
+ var finalPoint = new Point(anchor.x + actualDirection.x * bestDistance, anchor.y + actualDirection.y * bestDistance).round(options.precision);
104
+ points.push(finalPoint);
105
+ console.log("[generateSmartPoints] Final point at distance ".concat(bestDistance, ": (").concat(finalPoint.x, ", ").concat(finalPoint.y, ")"));
106
+ } else {
107
+ // 4. If no accessible point found after maxSteps, use anchor as fallback
108
+ console.log("[generateSmartPoints] No accessible point found after ".concat(maxSteps, " steps, using anchor: (").concat(anchor.x, ", ").concat(anchor.y, ")"));
109
+ points.push(anchor);
110
+ }
111
+ return points;
112
+ }
6
113
 
7
114
  /**
8
115
  * Find route between two points using A* algorithm
@@ -22,22 +129,43 @@ export function findRoute(sourceBBox, targetBBox, sourceAnchor, targetAnchor, ma
22
129
  var endPoint = targetEndpoint;
23
130
 
24
131
  // Get start and end points around rectangles
25
- var startPoints = getRectPoints(startPoint, sourceBBox, options.startDirections, grid, options);
26
- var endPoints = getRectPoints(targetEndpoint, targetBBox, options.endDirections, grid, options);
27
- console.log('[findRoute] Start points from getRectPoints:', startPoints.map(function (p) {
28
- return "(".concat(p.x, ", ").concat(p.y, ")");
29
- }));
30
- console.log('[findRoute] End points from getRectPoints:', endPoints.map(function (p) {
31
- return "(".concat(p.x, ", ").concat(p.y, ")");
32
- }));
132
+ // Use smart point generation based on position if available
133
+ var startPoints;
134
+ var endPoints;
33
135
 
34
- // Take into account only accessible rect points
35
- startPoints = startPoints.filter(function (p) {
36
- return map.isAccessible(p);
37
- });
38
- endPoints = endPoints.filter(function (p) {
39
- return map.isAccessible(p);
40
- });
136
+ // Generate smart start points based on sourcePosition
137
+ if (options.sourcePosition) {
138
+ startPoints = generateSmartPoints(startPoint, sourceBBox, options.sourcePosition, grid, map, options, false);
139
+ console.log('[findRoute] Start points from smart generation:', startPoints.map(function (p) {
140
+ return "(".concat(p.x, ", ").concat(p.y, ")");
141
+ }));
142
+ } else {
143
+ startPoints = getRectPoints(startPoint, sourceBBox, options.startDirections, grid, options);
144
+ console.log('[findRoute] Start points from getRectPoints:', startPoints.map(function (p) {
145
+ return "(".concat(p.x, ", ").concat(p.y, ")");
146
+ }));
147
+ // Take into account only accessible rect points
148
+ startPoints = startPoints.filter(function (p) {
149
+ return map.isAccessible(p);
150
+ });
151
+ }
152
+
153
+ // Generate smart end points based on targetPosition
154
+ if (options.targetPosition) {
155
+ endPoints = generateSmartPoints(targetEndpoint, targetBBox, options.targetPosition, grid, map, options, true);
156
+ console.log('[findRoute] End points from smart generation:', endPoints.map(function (p) {
157
+ return "(".concat(p.x, ", ").concat(p.y, ")");
158
+ }));
159
+ } else {
160
+ endPoints = getRectPoints(targetEndpoint, targetBBox, options.endDirections, grid, options);
161
+ console.log('[findRoute] End points from getRectPoints:', endPoints.map(function (p) {
162
+ return "(".concat(p.x, ", ").concat(p.y, ")");
163
+ }));
164
+ // Take into account only accessible rect points
165
+ endPoints = endPoints.filter(function (p) {
166
+ return map.isAccessible(p);
167
+ });
168
+ }
41
169
  console.log('[findRoute] Start points after filter:', startPoints.map(function (p) {
42
170
  return "(".concat(p.x, ", ").concat(p.y, ")");
43
171
  }));
@@ -48,10 +176,10 @@ export function findRoute(sourceBBox, targetBBox, sourceAnchor, targetAnchor, ma
48
176
  // Ensure we always have at least the anchor points
49
177
  // This handles edge cases where anchor is on the node boundary
50
178
  if (startPoints.length === 0) {
51
- startPoints = [align(startPoint, grid, precision)];
179
+ startPoints = [round(startPoint, precision)];
52
180
  }
53
181
  if (endPoints.length === 0) {
54
- endPoints = [align(endPoint, grid, precision)];
182
+ endPoints = [round(endPoint, precision)];
55
183
  }
56
184
 
57
185
  // Initialize A* data structures
@@ -139,8 +267,8 @@ export function findRoute(sourceBBox, targetBBox, sourceAnchor, targetAnchor, ma
139
267
  continue;
140
268
  }
141
269
 
142
- // Calculate neighbor point
143
- var neighborPoint = align(currentPoint.clone().translate(direction.gridOffsetX || 0, direction.gridOffsetY || 0), grid, precision);
270
+ // Calculate neighbor point (no grid alignment)
271
+ var neighborPoint = round(currentPoint.clone().translate(direction.gridOffsetX || 0, direction.gridOffsetY || 0), precision);
144
272
  var neighborKey = getKey(neighborPoint);
145
273
 
146
274
  // Skip if closed or not accessible
@@ -148,7 +276,64 @@ export function findRoute(sourceBBox, targetBBox, sourceAnchor, targetAnchor, ma
148
276
  continue;
149
277
  }
150
278
 
151
- // Check if neighbor is an end point
279
+ // Check if we can reach any end point directly from this neighbor
280
+ // This allows connecting to end points that are not on the grid
281
+ var canReachEndPoint = false;
282
+ var reachableEndPoint = null;
283
+ var _iterator3 = _createForOfIteratorHelper(endPoints),
284
+ _step3;
285
+ try {
286
+ for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
287
+ var endPt = _step3.value;
288
+ var distanceToEnd = neighborPoint.manhattanDistance(endPt);
289
+
290
+ // If close enough to end point (within step distance), try direct connection
291
+ if (distanceToEnd < options.step * 1.5) {
292
+ // Check if we can move directly to the end point
293
+ var dx = endPt.x - neighborPoint.x;
294
+ var dy = endPt.y - neighborPoint.y;
295
+
296
+ // Allow direct connection if it's orthogonal or close to orthogonal
297
+ var isOrthogonal = Math.abs(dx) < 0.1 || Math.abs(dy) < 0.1;
298
+ if (isOrthogonal && map.isAccessible(endPt)) {
299
+ canReachEndPoint = true;
300
+ reachableEndPoint = endPt;
301
+ break;
302
+ }
303
+ }
304
+ }
305
+
306
+ // If we can reach an end point directly, add it as the final step
307
+ } catch (err) {
308
+ _iterator3.e(err);
309
+ } finally {
310
+ _iterator3.f();
311
+ }
312
+ if (canReachEndPoint && reachableEndPoint) {
313
+ var endKey = getKey(reachableEndPoint);
314
+ var endCost = neighborPoint.manhattanDistance(reachableEndPoint);
315
+ var totalCost = currentCost + direction.cost + endCost;
316
+ if (!openSet.isOpen(endKey) || totalCost < (costs.get(endKey) || Infinity)) {
317
+ points.set(endKey, reachableEndPoint);
318
+ parents.set(endKey, neighborPoint);
319
+ costs.set(endKey, totalCost);
320
+
321
+ // Also add the neighbor point if not already added
322
+ if (!points.has(neighborKey)) {
323
+ points.set(neighborKey, neighborPoint);
324
+ parents.set(neighborKey, currentPoint);
325
+ costs.set(neighborKey, currentCost + direction.cost);
326
+ }
327
+
328
+ // Check if this is our target end point
329
+ if (endPointsKeys.has(endKey)) {
330
+ options.previousDirectionAngle = directionAngle;
331
+ return reconstructRoute(parents, points, reachableEndPoint, startPoint, endPoint);
332
+ }
333
+ }
334
+ }
335
+
336
+ // Check if neighbor is an end point (exact match)
152
337
  if (endPointsKeys.has(neighborKey)) {
153
338
  var isEndPoint = neighborPoint.equals(endPoint);
154
339
  if (!isEndPoint) {
@@ -1 +1 @@
1
- {"version":3,"file":"pathConverter.d.ts","sourceRoot":"","sources":["../../src/svg/pathConverter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAA;AAEnC;;GAEG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,KAAK,EAAE,EAAE,SAAS,EAAE,MAAM,EAAE,YAAY,GAAE,MAAU,GAAG,MAAM,CAgEjG;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,KAAK,EAAE,EAAE,QAAQ,EAAE,MAAM,GAAG,KAAK,EAAE,CAgCzE"}
1
+ {"version":3,"file":"pathConverter.d.ts","sourceRoot":"","sources":["../../src/svg/pathConverter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAA;AAEnC;;GAEG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,KAAK,EAAE,EAAE,SAAS,EAAE,MAAM,EAAE,YAAY,GAAE,MAAU,GAAG,MAAM,CA2EjG;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,KAAK,EAAE,EAAE,QAAQ,EAAE,MAAM,GAAG,KAAK,EAAE,CAgCzE"}
@@ -38,31 +38,42 @@ export function pointsToPath(points, precision) {
38
38
  var current = points[_i];
39
39
  var next = points[_i + 1];
40
40
 
41
- // Calculate the distance from prev to current and current to next
42
- var distToPrev = Math.sqrt(Math.pow(current.x - prev.x, 2) + Math.pow(current.y - prev.y, 2));
43
- var distToNext = Math.sqrt(Math.pow(next.x - current.x, 2) + Math.pow(next.y - current.y, 2));
41
+ // Calculate direction vectors
42
+ var dx1 = current.x - prev.x;
43
+ var dy1 = current.y - prev.y;
44
+ var dx2 = next.x - current.x;
45
+ var dy2 = next.y - current.y;
46
+
47
+ // Calculate distances
48
+ var dist1 = Math.sqrt(dx1 * dx1 + dy1 * dy1);
49
+ var dist2 = Math.sqrt(dx2 * dx2 + dy2 * dy2);
44
50
 
45
51
  // Use the smaller of borderRadius or half the segment length
46
- var radius = Math.min(borderRadius, distToPrev / 2, distToNext / 2);
52
+ var radius = Math.min(borderRadius, dist1 / 2, dist2 / 2);
53
+
54
+ // Normalize direction vectors
55
+ var ndx1 = dx1 / dist1;
56
+ var ndy1 = dy1 / dist1;
57
+ var ndx2 = dx2 / dist2;
58
+ var ndy2 = dy2 / dist2;
47
59
 
48
- // Calculate the point before the corner (on the line from prev to current)
49
- var beforeCornerRatio = (distToPrev - radius) / distToPrev;
60
+ // Calculate the point before the corner
50
61
  var beforeCorner = {
51
- x: prev.x + (current.x - prev.x) * beforeCornerRatio,
52
- y: prev.y + (current.y - prev.y) * beforeCornerRatio
62
+ x: current.x - ndx1 * radius,
63
+ y: current.y - ndy1 * radius
53
64
  };
54
65
 
55
- // Calculate the point after the corner (on the line from current to next)
56
- var afterCornerRatio = radius / distToNext;
66
+ // Calculate the point after the corner
57
67
  var afterCorner = {
58
- x: current.x + (next.x - current.x) * afterCornerRatio,
59
- y: current.y + (next.y - current.y) * afterCornerRatio
68
+ x: current.x + ndx2 * radius,
69
+ y: current.y + ndy2 * radius
60
70
  };
61
71
 
62
72
  // Draw line to the point before corner
63
73
  path += " L ".concat(roundCoord(beforeCorner.x), " ").concat(roundCoord(beforeCorner.y));
64
74
 
65
75
  // Draw quadratic bezier curve for the rounded corner
76
+ // The control point is the actual corner point
66
77
  path += " Q ".concat(roundCoord(current.x), " ").concat(roundCoord(current.y), " ").concat(roundCoord(afterCorner.x), " ").concat(roundCoord(afterCorner.y));
67
78
  }
68
79
 
@@ -0,0 +1,15 @@
1
+ import { Point } from '../geometry';
2
+ import type { ObstacleMap } from '../obstacle';
3
+ import type { Direction } from '../options';
4
+ /**
5
+ * Get accessible anchor points using binary search optimization
6
+ *
7
+ * @param anchor - The anchor point (on node edge)
8
+ * @param position - The position/direction (right, left, top, bottom)
9
+ * @param extensionDistance - The preferred extension distance
10
+ * @param step - The step size for binary search
11
+ * @param obstacleMap - The obstacle map for accessibility checking
12
+ * @returns Array of accessible points, prioritized by distance
13
+ */
14
+ export declare function getAnchorPoints(anchor: Point, position: Direction, extensionDistance: number, step: number, obstacleMap: ObstacleMap): Point[];
15
+ //# sourceMappingURL=getAnchorPoints.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"getAnchorPoints.d.ts","sourceRoot":"","sources":["../../src/utils/getAnchorPoints.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAA;AACnC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AAC9C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAA;AAE3C;;;;;;;;;GASG;AACH,wBAAgB,eAAe,CAC7B,MAAM,EAAE,KAAK,EACb,QAAQ,EAAE,SAAS,EACnB,iBAAiB,EAAE,MAAM,EACzB,IAAI,EAAE,MAAM,EACZ,WAAW,EAAE,WAAW,GACvB,KAAK,EAAE,CA0DT"}
@@ -0,0 +1,69 @@
1
+ import { Point } from "../geometry";
2
+ /**
3
+ * Get accessible anchor points using binary search optimization
4
+ *
5
+ * @param anchor - The anchor point (on node edge)
6
+ * @param position - The position/direction (right, left, top, bottom)
7
+ * @param extensionDistance - The preferred extension distance
8
+ * @param step - The step size for binary search
9
+ * @param obstacleMap - The obstacle map for accessibility checking
10
+ * @returns Array of accessible points, prioritized by distance
11
+ */
12
+ export function getAnchorPoints(anchor, position, extensionDistance, step, obstacleMap) {
13
+ var points = [];
14
+
15
+ // Determine direction vector based on position
16
+ var directionMap = {
17
+ 'right': {
18
+ dx: 1,
19
+ dy: 0
20
+ },
21
+ 'left': {
22
+ dx: -1,
23
+ dy: 0
24
+ },
25
+ 'top': {
26
+ dx: 0,
27
+ dy: -1
28
+ },
29
+ 'bottom': {
30
+ dx: 0,
31
+ dy: 1
32
+ }
33
+ };
34
+ var dir = directionMap[position];
35
+ if (!dir) {
36
+ console.warn("[getAnchorPoints] Invalid position: ".concat(position));
37
+ return [anchor];
38
+ }
39
+ console.log("[getAnchorPoints] Finding points for position '".concat(position, "' from (").concat(anchor.x, ", ").concat(anchor.y, ")"));
40
+
41
+ // 1. First try extensionDistance
42
+ var extensionPoint = new Point(anchor.x + dir.dx * extensionDistance, anchor.y + dir.dy * extensionDistance);
43
+ if (obstacleMap.isAccessible(extensionPoint)) {
44
+ console.log("[getAnchorPoints] Extension point (".concat(extensionPoint.x, ", ").concat(extensionPoint.y, ") is accessible"));
45
+ points.push(extensionPoint);
46
+ return points;
47
+ }
48
+ console.log("[getAnchorPoints] Extension point (".concat(extensionPoint.x, ", ").concat(extensionPoint.y, ") is blocked, trying binary search"));
49
+
50
+ // 2. If extensionDistance point is blocked, use binary search with step
51
+ // Try: step -> step/2 -> step/4 -> ... -> 1px
52
+ var distance = step;
53
+ while (distance >= 1) {
54
+ var testPoint = new Point(anchor.x + dir.dx * distance, anchor.y + dir.dy * distance);
55
+ if (obstacleMap.isAccessible(testPoint)) {
56
+ console.log("[getAnchorPoints] Found accessible point at distance ".concat(distance, "px: (").concat(testPoint.x, ", ").concat(testPoint.y, ")"));
57
+ points.push(testPoint);
58
+ return points;
59
+ }
60
+
61
+ // Halve the distance for next iteration
62
+ distance = Math.floor(distance / 2);
63
+ }
64
+
65
+ // 3. If still no accessible point found, return the anchor itself
66
+ console.warn("[getAnchorPoints] No accessible point found, using anchor itself: (".concat(anchor.x, ", ").concat(anchor.y, ")"));
67
+ points.push(anchor);
68
+ return points;
69
+ }
@@ -4,4 +4,5 @@ export * from './rect';
4
4
  export * from './route';
5
5
  export * from './node';
6
6
  export * from './pathValidation';
7
+ export * from './getAnchorPoints';
7
8
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA,cAAc,QAAQ,CAAA;AACtB,cAAc,aAAa,CAAA;AAC3B,cAAc,QAAQ,CAAA;AACtB,cAAc,SAAS,CAAA;AACvB,cAAc,QAAQ,CAAA;AACtB,cAAc,kBAAkB,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA,cAAc,QAAQ,CAAA;AACtB,cAAc,aAAa,CAAA;AAC3B,cAAc,QAAQ,CAAA;AACtB,cAAc,SAAS,CAAA;AACvB,cAAc,QAAQ,CAAA;AACtB,cAAc,kBAAkB,CAAA;AAChC,cAAc,mBAAmB,CAAA"}
@@ -3,4 +3,5 @@ export * from "./direction";
3
3
  export * from "./rect";
4
4
  export * from "./route";
5
5
  export * from "./node";
6
- export * from "./pathValidation";
6
+ export * from "./pathValidation";
7
+ export * from "./getAnchorPoints";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rxflow/manhattan",
3
- "version": "0.0.1-alpha.10",
3
+ "version": "0.0.1-alpha.12",
4
4
  "description": "Manhattan routing algorithm for ReactFlow - generates orthogonal paths with obstacle avoidance",
5
5
  "keywords": [
6
6
  "reactflow",