@rxflow/manhattan 0.0.1-alpha.9 → 0.0.1

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 (55) 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 +187 -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/grid.d.ts +1 -0
  23. package/cjs/utils/grid.d.ts.map +1 -1
  24. package/cjs/utils/grid.js +3 -1
  25. package/cjs/utils/index.d.ts +1 -0
  26. package/cjs/utils/index.d.ts.map +1 -1
  27. package/cjs/utils/index.js +11 -0
  28. package/esm/geometry/Rectangle.d.ts +1 -1
  29. package/esm/geometry/Rectangle.js +2 -2
  30. package/esm/getManHattanPath.d.ts.map +1 -1
  31. package/esm/getManHattanPath.js +162 -22
  32. package/esm/obstacle/ObstacleMap.d.ts +7 -1
  33. package/esm/obstacle/ObstacleMap.d.ts.map +1 -1
  34. package/esm/obstacle/ObstacleMap.js +78 -0
  35. package/esm/options/defaults.d.ts +1 -1
  36. package/esm/options/defaults.d.ts.map +1 -1
  37. package/esm/options/defaults.js +1 -1
  38. package/esm/options/resolver.d.ts.map +1 -1
  39. package/esm/options/resolver.js +5 -3
  40. package/esm/options/types.d.ts +19 -6
  41. package/esm/options/types.d.ts.map +1 -1
  42. package/esm/pathfinder/findRoute.d.ts.map +1 -1
  43. package/esm/pathfinder/findRoute.js +209 -21
  44. package/esm/svg/pathConverter.d.ts.map +1 -1
  45. package/esm/svg/pathConverter.js +23 -12
  46. package/esm/utils/getAnchorPoints.d.ts +15 -0
  47. package/esm/utils/getAnchorPoints.d.ts.map +1 -0
  48. package/esm/utils/getAnchorPoints.js +69 -0
  49. package/esm/utils/grid.d.ts +1 -0
  50. package/esm/utils/grid.d.ts.map +1 -1
  51. package/esm/utils/grid.js +3 -1
  52. package/esm/utils/index.d.ts +1 -0
  53. package/esm/utils/index.d.ts.map +1 -1
  54. package/esm/utils/index.js +2 -1
  55. package/package.json +1 -1
@@ -4,8 +4,114 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.findRoute = findRoute;
7
+ var _geometry = require("../geometry");
7
8
  var _SortedSet = require("./SortedSet");
8
9
  var _utils = require("../utils");
10
+ /**
11
+ * Generate smart points based on position using extensionDistance and binary search
12
+ *
13
+ * Algorithm:
14
+ * 1. First try extensionDistance in the specified direction
15
+ * 2. If blocked, use binary search starting from step, halving until finding accessible point
16
+ * 3. For target points, approach from opposite direction
17
+ */
18
+ function generateSmartPoints(anchor, bbox, position, grid, map, options, isTarget = false) {
19
+ const directionMap = {
20
+ 'right': {
21
+ x: 1,
22
+ y: 0
23
+ },
24
+ 'left': {
25
+ x: -1,
26
+ y: 0
27
+ },
28
+ 'top': {
29
+ x: 0,
30
+ y: -1
31
+ },
32
+ 'bottom': {
33
+ x: 0,
34
+ y: 1
35
+ }
36
+ };
37
+ const direction = directionMap[position];
38
+ if (!direction) {
39
+ console.warn(`[generateSmartPoints] Unknown position: ${position}, falling back to anchor`);
40
+ return [anchor];
41
+ }
42
+
43
+ // Both source and target extend in the specified direction
44
+ // - Source: extends away from node in sourcePosition direction
45
+ // - Target: extends away from node in targetPosition direction (path approaches from this direction)
46
+ const actualDirection = direction;
47
+ const points = [];
48
+
49
+ // 1. First try extensionDistance
50
+ const extensionPoint = new _geometry.Point(anchor.x + actualDirection.x * options.extensionDistance, anchor.y + actualDirection.y * options.extensionDistance).round(options.precision);
51
+ console.log(`[generateSmartPoints] ${isTarget ? 'Target' : 'Source'} position=${position}, trying extension point: (${extensionPoint.x}, ${extensionPoint.y})`);
52
+ if (map.isAccessible(extensionPoint)) {
53
+ points.push(extensionPoint);
54
+ console.log(`[generateSmartPoints] Extension point is accessible`);
55
+ return points;
56
+ }
57
+ console.log(`[generateSmartPoints] Extension point blocked, using step-based search`);
58
+
59
+ // 2. Step-based search with binary refinement
60
+ // First, extend outward by step increments until we find an accessible point
61
+ let stepMultiplier = 1;
62
+ let maxSteps = 20; // Prevent infinite loop
63
+ let foundAccessibleDistance = -1;
64
+ console.log(`[generateSmartPoints] Starting outward search with step=${options.step}`);
65
+ while (stepMultiplier <= maxSteps) {
66
+ const distance = stepMultiplier * options.step;
67
+ const testPoint = new _geometry.Point(anchor.x + actualDirection.x * distance, anchor.y + actualDirection.y * distance).round(options.precision);
68
+ console.log(`[generateSmartPoints] Testing ${stepMultiplier}*step (distance=${distance}): (${testPoint.x}, ${testPoint.y})`);
69
+ if (map.isAccessible(testPoint)) {
70
+ foundAccessibleDistance = distance;
71
+ console.log(`[generateSmartPoints] Found accessible point at ${stepMultiplier}*step (distance=${distance})`);
72
+ break;
73
+ }
74
+ stepMultiplier++;
75
+ }
76
+
77
+ // 3. If we found an accessible point, refine by binary search within the last step interval
78
+ if (foundAccessibleDistance > 0) {
79
+ const outerDistance = foundAccessibleDistance;
80
+ const innerDistance = foundAccessibleDistance - options.step;
81
+ console.log(`[generateSmartPoints] Refining between ${innerDistance} and ${outerDistance}`);
82
+
83
+ // Binary search within the last step interval to find the closest accessible point
84
+ let left = innerDistance;
85
+ let right = outerDistance;
86
+ let bestDistance = outerDistance;
87
+
88
+ // Binary search with precision of 1px
89
+ while (right - left > 1) {
90
+ const mid = (left + right) / 2;
91
+ const testPoint = new _geometry.Point(anchor.x + actualDirection.x * mid, anchor.y + actualDirection.y * mid).round(options.precision);
92
+ console.log(`[generateSmartPoints] Binary search testing distance ${mid.toFixed(1)}: (${testPoint.x}, ${testPoint.y})`);
93
+ if (map.isAccessible(testPoint)) {
94
+ bestDistance = mid;
95
+ right = mid;
96
+ console.log(`[generateSmartPoints] Point accessible, searching closer (right=${right})`);
97
+ } else {
98
+ left = mid;
99
+ console.log(`[generateSmartPoints] Point blocked, searching further (left=${left})`);
100
+ }
101
+ }
102
+
103
+ // Use the best distance found
104
+ const finalPoint = new _geometry.Point(anchor.x + actualDirection.x * bestDistance, anchor.y + actualDirection.y * bestDistance).round(options.precision);
105
+ points.push(finalPoint);
106
+ console.log(`[generateSmartPoints] Final point at distance ${bestDistance}: (${finalPoint.x}, ${finalPoint.y})`);
107
+ } else {
108
+ // 4. If no accessible point found after maxSteps, use anchor as fallback
109
+ console.log(`[generateSmartPoints] No accessible point found after ${maxSteps} steps, using anchor: (${anchor.x}, ${anchor.y})`);
110
+ points.push(anchor);
111
+ }
112
+ return points;
113
+ }
114
+
9
115
  /**
10
116
  * Find route between two points using A* algorithm
11
117
  */
@@ -24,24 +130,41 @@ function findRoute(sourceBBox, targetBBox, sourceAnchor, targetAnchor, map, opti
24
130
  const endPoint = targetEndpoint;
25
131
 
26
132
  // Get start and end points around rectangles
27
- let startPoints = (0, _utils.getRectPoints)(startPoint, sourceBBox, options.startDirections, grid, options);
28
- let endPoints = (0, _utils.getRectPoints)(targetEndpoint, targetBBox, options.endDirections, grid, options);
29
- console.log('[findRoute] Start points from getRectPoints:', startPoints.map(p => `(${p.x}, ${p.y})`));
30
- console.log('[findRoute] End points from getRectPoints:', endPoints.map(p => `(${p.x}, ${p.y})`));
31
-
32
- // Take into account only accessible rect points
33
- startPoints = startPoints.filter(p => map.isAccessible(p));
34
- endPoints = endPoints.filter(p => map.isAccessible(p));
133
+ // Use smart point generation based on position if available
134
+ let startPoints;
135
+ let endPoints;
136
+
137
+ // Generate smart start points based on sourcePosition
138
+ if (options.sourcePosition) {
139
+ startPoints = generateSmartPoints(startPoint, sourceBBox, options.sourcePosition, grid, map, options, false);
140
+ console.log('[findRoute] Start points from smart generation:', startPoints.map(p => `(${p.x}, ${p.y})`));
141
+ } else {
142
+ startPoints = (0, _utils.getRectPoints)(startPoint, sourceBBox, options.startDirections, grid, options);
143
+ console.log('[findRoute] Start points from getRectPoints:', startPoints.map(p => `(${p.x}, ${p.y})`));
144
+ // Take into account only accessible rect points
145
+ startPoints = startPoints.filter(p => map.isAccessible(p));
146
+ }
147
+
148
+ // Generate smart end points based on targetPosition
149
+ if (options.targetPosition) {
150
+ endPoints = generateSmartPoints(targetEndpoint, targetBBox, options.targetPosition, grid, map, options, true);
151
+ console.log('[findRoute] End points from smart generation:', endPoints.map(p => `(${p.x}, ${p.y})`));
152
+ } else {
153
+ endPoints = (0, _utils.getRectPoints)(targetEndpoint, targetBBox, options.endDirections, grid, options);
154
+ console.log('[findRoute] End points from getRectPoints:', endPoints.map(p => `(${p.x}, ${p.y})`));
155
+ // Take into account only accessible rect points
156
+ endPoints = endPoints.filter(p => map.isAccessible(p));
157
+ }
35
158
  console.log('[findRoute] Start points after filter:', startPoints.map(p => `(${p.x}, ${p.y})`));
36
159
  console.log('[findRoute] End points after filter:', endPoints.map(p => `(${p.x}, ${p.y})`));
37
160
 
38
161
  // Ensure we always have at least the anchor points
39
162
  // This handles edge cases where anchor is on the node boundary
40
163
  if (startPoints.length === 0) {
41
- startPoints = [(0, _utils.align)(startPoint, grid, precision)];
164
+ startPoints = [(0, _utils.round)(startPoint, precision)];
42
165
  }
43
166
  if (endPoints.length === 0) {
44
- endPoints = [(0, _utils.align)(endPoint, grid, precision)];
167
+ endPoints = [(0, _utils.round)(endPoint, precision)];
45
168
  }
46
169
 
47
170
  // Initialize A* data structures
@@ -111,8 +234,11 @@ function findRoute(sourceBBox, targetBBox, sourceAnchor, targetAnchor, map, opti
111
234
  continue;
112
235
  }
113
236
 
114
- // Calculate neighbor point
115
- const neighborPoint = (0, _utils.align)(currentPoint.clone().translate(direction.gridOffsetX || 0, direction.gridOffsetY || 0), grid, precision);
237
+ // Calculate neighbor point and align to global grid
238
+ const rawNeighbor = currentPoint.clone().translate(direction.gridOffsetX || 0, direction.gridOffsetY || 0);
239
+
240
+ // Align to global grid for consistent path alignment
241
+ const neighborPoint = new _geometry.Point(Math.round(rawNeighbor.x / grid.x) * grid.x, Math.round(rawNeighbor.y / grid.y) * grid.y).round(precision);
116
242
  const neighborKey = (0, _utils.getKey)(neighborPoint);
117
243
 
118
244
  // Skip if closed or not accessible
@@ -120,7 +246,55 @@ function findRoute(sourceBBox, targetBBox, sourceAnchor, targetAnchor, map, opti
120
246
  continue;
121
247
  }
122
248
 
123
- // Check if neighbor is an end point
249
+ // Check if we can reach any end point directly from this neighbor
250
+ // This allows connecting to end points that are not on the grid
251
+ let canReachEndPoint = false;
252
+ let reachableEndPoint = null;
253
+ for (const endPt of endPoints) {
254
+ const distanceToEnd = neighborPoint.manhattanDistance(endPt);
255
+
256
+ // If close enough to end point (within step distance), try direct connection
257
+ if (distanceToEnd < options.step * 1.5) {
258
+ // Check if we can move directly to the end point
259
+ const dx = endPt.x - neighborPoint.x;
260
+ const dy = endPt.y - neighborPoint.y;
261
+
262
+ // Allow direct connection if it's orthogonal or close to orthogonal
263
+ const isOrthogonal = Math.abs(dx) < 0.1 || Math.abs(dy) < 0.1;
264
+ if (isOrthogonal && map.isAccessible(endPt)) {
265
+ canReachEndPoint = true;
266
+ reachableEndPoint = endPt;
267
+ break;
268
+ }
269
+ }
270
+ }
271
+
272
+ // If we can reach an end point directly, add it as the final step
273
+ if (canReachEndPoint && reachableEndPoint) {
274
+ const endKey = (0, _utils.getKey)(reachableEndPoint);
275
+ const endCost = neighborPoint.manhattanDistance(reachableEndPoint);
276
+ const totalCost = currentCost + direction.cost + endCost;
277
+ if (!openSet.isOpen(endKey) || totalCost < (costs.get(endKey) || Infinity)) {
278
+ points.set(endKey, reachableEndPoint);
279
+ parents.set(endKey, neighborPoint);
280
+ costs.set(endKey, totalCost);
281
+
282
+ // Also add the neighbor point if not already added
283
+ if (!points.has(neighborKey)) {
284
+ points.set(neighborKey, neighborPoint);
285
+ parents.set(neighborKey, currentPoint);
286
+ costs.set(neighborKey, currentCost + direction.cost);
287
+ }
288
+
289
+ // Check if this is our target end point
290
+ if (endPointsKeys.has(endKey)) {
291
+ options.previousDirectionAngle = directionAngle;
292
+ return (0, _utils.reconstructRoute)(parents, points, reachableEndPoint, startPoint, endPoint);
293
+ }
294
+ }
295
+ }
296
+
297
+ // Check if neighbor is an end point (exact match)
124
298
  if (endPointsKeys.has(neighborKey)) {
125
299
  const isEndPoint = neighborPoint.equals(endPoint);
126
300
  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"}
@@ -36,31 +36,42 @@ function pointsToPath(points, precision, borderRadius = 0) {
36
36
  const current = points[i];
37
37
  const next = points[i + 1];
38
38
 
39
- // Calculate the distance from prev to current and current to next
40
- const distToPrev = Math.sqrt(Math.pow(current.x - prev.x, 2) + Math.pow(current.y - prev.y, 2));
41
- const distToNext = Math.sqrt(Math.pow(next.x - current.x, 2) + Math.pow(next.y - current.y, 2));
39
+ // Calculate direction vectors
40
+ const dx1 = current.x - prev.x;
41
+ const dy1 = current.y - prev.y;
42
+ const dx2 = next.x - current.x;
43
+ const dy2 = next.y - current.y;
44
+
45
+ // Calculate distances
46
+ const dist1 = Math.sqrt(dx1 * dx1 + dy1 * dy1);
47
+ const dist2 = Math.sqrt(dx2 * dx2 + dy2 * dy2);
42
48
 
43
49
  // Use the smaller of borderRadius or half the segment length
44
- const radius = Math.min(borderRadius, distToPrev / 2, distToNext / 2);
50
+ const radius = Math.min(borderRadius, dist1 / 2, dist2 / 2);
51
+
52
+ // Normalize direction vectors
53
+ const ndx1 = dx1 / dist1;
54
+ const ndy1 = dy1 / dist1;
55
+ const ndx2 = dx2 / dist2;
56
+ const ndy2 = dy2 / dist2;
45
57
 
46
- // Calculate the point before the corner (on the line from prev to current)
47
- const beforeCornerRatio = (distToPrev - radius) / distToPrev;
58
+ // Calculate the point before the corner
48
59
  const beforeCorner = {
49
- x: prev.x + (current.x - prev.x) * beforeCornerRatio,
50
- y: prev.y + (current.y - prev.y) * beforeCornerRatio
60
+ x: current.x - ndx1 * radius,
61
+ y: current.y - ndy1 * radius
51
62
  };
52
63
 
53
- // Calculate the point after the corner (on the line from current to next)
54
- const afterCornerRatio = radius / distToNext;
64
+ // Calculate the point after the corner
55
65
  const afterCorner = {
56
- x: current.x + (next.x - current.x) * afterCornerRatio,
57
- y: current.y + (next.y - current.y) * afterCornerRatio
66
+ x: current.x + ndx2 * radius,
67
+ y: current.y + ndy2 * radius
58
68
  };
59
69
 
60
70
  // Draw line to the point before corner
61
71
  path += ` L ${roundCoord(beforeCorner.x)} ${roundCoord(beforeCorner.y)}`;
62
72
 
63
73
  // Draw quadratic bezier curve for the rounded corner
74
+ // The control point is the actual corner point
64
75
  path += ` Q ${roundCoord(current.x)} ${roundCoord(current.y)} ${roundCoord(afterCorner.x)} ${roundCoord(afterCorner.y)}`;
65
76
  }
66
77
 
@@ -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,75 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.getAnchorPoints = getAnchorPoints;
7
+ var _geometry = require("../geometry");
8
+ /**
9
+ * Get accessible anchor points using binary search optimization
10
+ *
11
+ * @param anchor - The anchor point (on node edge)
12
+ * @param position - The position/direction (right, left, top, bottom)
13
+ * @param extensionDistance - The preferred extension distance
14
+ * @param step - The step size for binary search
15
+ * @param obstacleMap - The obstacle map for accessibility checking
16
+ * @returns Array of accessible points, prioritized by distance
17
+ */
18
+ function getAnchorPoints(anchor, position, extensionDistance, step, obstacleMap) {
19
+ const points = [];
20
+
21
+ // Determine direction vector based on position
22
+ const directionMap = {
23
+ 'right': {
24
+ dx: 1,
25
+ dy: 0
26
+ },
27
+ 'left': {
28
+ dx: -1,
29
+ dy: 0
30
+ },
31
+ 'top': {
32
+ dx: 0,
33
+ dy: -1
34
+ },
35
+ 'bottom': {
36
+ dx: 0,
37
+ dy: 1
38
+ }
39
+ };
40
+ const dir = directionMap[position];
41
+ if (!dir) {
42
+ console.warn(`[getAnchorPoints] Invalid position: ${position}`);
43
+ return [anchor];
44
+ }
45
+ console.log(`[getAnchorPoints] Finding points for position '${position}' from (${anchor.x}, ${anchor.y})`);
46
+
47
+ // 1. First try extensionDistance
48
+ const extensionPoint = new _geometry.Point(anchor.x + dir.dx * extensionDistance, anchor.y + dir.dy * extensionDistance);
49
+ if (obstacleMap.isAccessible(extensionPoint)) {
50
+ console.log(`[getAnchorPoints] Extension point (${extensionPoint.x}, ${extensionPoint.y}) is accessible`);
51
+ points.push(extensionPoint);
52
+ return points;
53
+ }
54
+ console.log(`[getAnchorPoints] Extension point (${extensionPoint.x}, ${extensionPoint.y}) is blocked, trying binary search`);
55
+
56
+ // 2. If extensionDistance point is blocked, use binary search with step
57
+ // Try: step -> step/2 -> step/4 -> ... -> 1px
58
+ let distance = step;
59
+ while (distance >= 1) {
60
+ const testPoint = new _geometry.Point(anchor.x + dir.dx * distance, anchor.y + dir.dy * distance);
61
+ if (obstacleMap.isAccessible(testPoint)) {
62
+ console.log(`[getAnchorPoints] Found accessible point at distance ${distance}px: (${testPoint.x}, ${testPoint.y})`);
63
+ points.push(testPoint);
64
+ return points;
65
+ }
66
+
67
+ // Halve the distance for next iteration
68
+ distance = Math.floor(distance / 2);
69
+ }
70
+
71
+ // 3. If still no accessible point found, return the anchor itself
72
+ console.warn(`[getAnchorPoints] No accessible point found, using anchor itself: (${anchor.x}, ${anchor.y})`);
73
+ points.push(anchor);
74
+ return points;
75
+ }
@@ -9,6 +9,7 @@ export interface Grid {
9
9
  }
10
10
  /**
11
11
  * Get grid size in x and y dimensions, adapted to source and target positions
12
+ * Uses global grid system with origin at (0, 0) for path alignment
12
13
  */
13
14
  export declare function getGrid(step: number, source: Point, target: Point): Grid;
14
15
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"grid.d.ts","sourceRoot":"","sources":["../../src/utils/grid.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAA;AAEnC;;GAEG;AACH,MAAM,WAAW,IAAI;IACnB,MAAM,EAAE,KAAK,CAAA;IACb,CAAC,EAAE,MAAM,CAAA;IACT,CAAC,EAAE,MAAM,CAAA;CACV;AAWD;;GAEG;AACH,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,GAAG,IAAI,CAMxE;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAElE;AAYD;;GAEG;AACH,wBAAgB,KAAK,CAAC,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,GAAG,KAAK,CAExE;AAED;;GAEG;AACH,wBAAgB,KAAK,CAAC,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,GAAG,KAAK,CAE5D"}
1
+ {"version":3,"file":"grid.d.ts","sourceRoot":"","sources":["../../src/utils/grid.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAA;AAEnC;;GAEG;AACH,MAAM,WAAW,IAAI;IACnB,MAAM,EAAE,KAAK,CAAA;IACb,CAAC,EAAE,MAAM,CAAA;IACT,CAAC,EAAE,MAAM,CAAA;CACV;AAWD;;;GAGG;AACH,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,GAAG,IAAI,CAMxE;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAElE;AAYD;;GAEG;AACH,wBAAgB,KAAK,CAAC,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,GAAG,KAAK,CAExE;AAED;;GAEG;AACH,wBAAgB,KAAK,CAAC,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,GAAG,KAAK,CAE5D"}
package/cjs/utils/grid.js CHANGED
@@ -23,10 +23,12 @@ function getGridDimension(diff, step) {
23
23
 
24
24
  /**
25
25
  * Get grid size in x and y dimensions, adapted to source and target positions
26
+ * Uses global grid system with origin at (0, 0) for path alignment
26
27
  */
27
28
  function getGrid(step, source, target) {
28
29
  return {
29
- source: source.clone(),
30
+ source: new _geometry.Point(0, 0),
31
+ // Use global origin for consistent grid alignment
30
32
  x: getGridDimension(target.x - source.x, step),
31
33
  y: getGridDimension(target.y - source.y, step)
32
34
  };
@@ -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"}
@@ -68,4 +68,15 @@ Object.keys(_pathValidation).forEach(function (key) {
68
68
  return _pathValidation[key];
69
69
  }
70
70
  });
71
+ });
72
+ var _getAnchorPoints = require("./getAnchorPoints");
73
+ Object.keys(_getAnchorPoints).forEach(function (key) {
74
+ if (key === "default" || key === "__esModule") return;
75
+ if (key in exports && exports[key] === _getAnchorPoints[key]) return;
76
+ Object.defineProperty(exports, key, {
77
+ enumerable: true,
78
+ get: function () {
79
+ return _getAnchorPoints[key];
80
+ }
81
+ });
71
82
  });
@@ -25,7 +25,7 @@ export declare class Rectangle {
25
25
  */
26
26
  getCorner(): Point;
27
27
  /**
28
- * Check if a point is contained within this rectangle
28
+ * Check if a point is contained within this rectangle (interior only, excluding edges)
29
29
  */
30
30
  containsPoint(point: Point): boolean;
31
31
  /**
@@ -60,12 +60,12 @@ export var Rectangle = /*#__PURE__*/function () {
60
60
  }
61
61
 
62
62
  /**
63
- * Check if a point is contained within this rectangle
63
+ * Check if a point is contained within this rectangle (interior only, excluding edges)
64
64
  */
65
65
  }, {
66
66
  key: "containsPoint",
67
67
  value: function containsPoint(point) {
68
- return point.x >= this.x && point.x <= this.x + this.width && point.y >= this.y && point.y <= this.y + this.height;
68
+ return point.x > this.x && point.x < this.x + this.width && point.y > this.y && point.y < this.y + this.height;
69
69
  }
70
70
 
71
71
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"getManHattanPath.d.ts","sourceRoot":"","sources":["../src/getManHattanPath.ts"],"names":[],"mappings":"AAAA,OAAO,EAAqB,QAAQ,EAAE,MAAM,eAAe,CAAA;AAG3D,OAAO,KAAK,EAAE,sBAAsB,EAAE,UAAU,EAAE,MAAM,WAAW,CAAA;AAMnE;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACrC;;OAEG;IACH,YAAY,EAAE,MAAM,CAAA;IAEpB;;OAEG;IACH,YAAY,EAAE,MAAM,CAAC;IAErB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAEhB,cAAc,EAAE,QAAQ,CAAC;IACzB,cAAc,EAAE,QAAQ,CAAC;IACzB;;OAEG;IACH,UAAU,EAAE,UAAU,CAAA;IAEtB;;OAEG;IACH,OAAO,CAAC,EAAE,sBAAsB,CAAA;CACjC;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,sBAAsB,GAAG,MAAM,CAwRvE"}
1
+ {"version":3,"file":"getManHattanPath.d.ts","sourceRoot":"","sources":["../src/getManHattanPath.ts"],"names":[],"mappings":"AAAA,OAAO,EAAqB,QAAQ,EAAE,MAAM,eAAe,CAAA;AAG3D,OAAO,KAAK,EAAE,sBAAsB,EAAE,UAAU,EAAa,MAAM,WAAW,CAAA;AAM9E;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACrC;;OAEG;IACH,YAAY,EAAE,MAAM,CAAA;IAEpB;;OAEG;IACH,YAAY,EAAE,MAAM,CAAC;IAErB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAEhB,cAAc,EAAE,QAAQ,CAAC;IACzB,cAAc,EAAE,QAAQ,CAAC;IACzB;;OAEG;IACH,UAAU,EAAE,UAAU,CAAA;IAEtB;;OAEG;IACH,OAAO,CAAC,EAAE,sBAAsB,CAAA;CACjC;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,sBAAsB,GAAG,MAAM,CAgbvE"}