@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.
- package/README.md +35 -0
- package/cjs/geometry/Line.d.ts +21 -0
- package/cjs/geometry/Line.d.ts.map +1 -0
- package/cjs/geometry/Line.js +88 -0
- package/cjs/geometry/Point.d.ts +49 -0
- package/cjs/geometry/Point.d.ts.map +1 -0
- package/cjs/geometry/Point.js +94 -0
- package/cjs/geometry/Rectangle.d.ts +41 -0
- package/cjs/geometry/Rectangle.d.ts.map +1 -0
- package/cjs/geometry/Rectangle.js +65 -0
- package/cjs/geometry/index.d.ts +4 -0
- package/cjs/geometry/index.d.ts.map +1 -0
- package/cjs/geometry/index.js +26 -0
- package/cjs/getManHattanPath.d.ts +60 -0
- package/cjs/getManHattanPath.d.ts.map +1 -0
- package/cjs/getManHattanPath.js +285 -0
- package/cjs/index.d.ts +16 -0
- package/cjs/index.d.ts.map +1 -0
- package/cjs/index.js +117 -0
- package/cjs/obstacle/ObstacleMap.d.ts +28 -0
- package/cjs/obstacle/ObstacleMap.d.ts.map +1 -0
- package/cjs/obstacle/ObstacleMap.js +171 -0
- package/cjs/obstacle/index.d.ts +2 -0
- package/cjs/obstacle/index.d.ts.map +1 -0
- package/cjs/obstacle/index.js +12 -0
- package/cjs/options/defaults.d.ts +16 -0
- package/cjs/options/defaults.d.ts.map +1 -0
- package/cjs/options/defaults.js +39 -0
- package/cjs/options/index.d.ts +4 -0
- package/cjs/options/index.d.ts.map +1 -0
- package/cjs/options/index.js +38 -0
- package/cjs/options/resolver.d.ts +10 -0
- package/cjs/options/resolver.d.ts.map +1 -0
- package/cjs/options/resolver.js +118 -0
- package/cjs/options/types.d.ts +156 -0
- package/cjs/options/types.d.ts.map +1 -0
- package/cjs/options/types.js +5 -0
- package/cjs/pathfinder/SortedSet.d.ts +35 -0
- package/cjs/pathfinder/SortedSet.d.ts.map +1 -0
- package/cjs/pathfinder/SortedSet.js +95 -0
- package/cjs/pathfinder/findRoute.d.ts +8 -0
- package/cjs/pathfinder/findRoute.d.ts.map +1 -0
- package/cjs/pathfinder/findRoute.js +156 -0
- package/cjs/pathfinder/index.d.ts +3 -0
- package/cjs/pathfinder/index.d.ts.map +1 -0
- package/cjs/pathfinder/index.js +19 -0
- package/cjs/svg/index.d.ts +2 -0
- package/cjs/svg/index.d.ts.map +1 -0
- package/cjs/svg/index.js +18 -0
- package/cjs/svg/pathConverter.d.ts +10 -0
- package/cjs/svg/pathConverter.d.ts.map +1 -0
- package/cjs/svg/pathConverter.js +105 -0
- package/cjs/utils/direction.d.ts +24 -0
- package/cjs/utils/direction.d.ts.map +1 -0
- package/cjs/utils/direction.js +54 -0
- package/cjs/utils/grid.d.ts +26 -0
- package/cjs/utils/grid.d.ts.map +1 -0
- package/cjs/utils/grid.js +78 -0
- package/cjs/utils/index.d.ts +6 -0
- package/cjs/utils/index.d.ts.map +1 -0
- package/cjs/utils/index.js +60 -0
- package/cjs/utils/node.d.ts +27 -0
- package/cjs/utils/node.d.ts.map +1 -0
- package/cjs/utils/node.js +36 -0
- package/cjs/utils/rect.d.ts +9 -0
- package/cjs/utils/rect.d.ts.map +1 -0
- package/cjs/utils/rect.js +103 -0
- package/cjs/utils/route.d.ts +19 -0
- package/cjs/utils/route.d.ts.map +1 -0
- package/cjs/utils/route.js +76 -0
- package/esm/geometry/Line.d.ts +21 -0
- package/esm/geometry/Line.d.ts.map +1 -0
- package/esm/geometry/Line.js +96 -0
- package/esm/geometry/Point.d.ts +49 -0
- package/esm/geometry/Point.d.ts.map +1 -0
- package/esm/geometry/Point.js +117 -0
- package/esm/geometry/Rectangle.d.ts +41 -0
- package/esm/geometry/Rectangle.d.ts.map +1 -0
- package/esm/geometry/Rectangle.js +81 -0
- package/esm/geometry/index.d.ts +4 -0
- package/esm/geometry/index.d.ts.map +1 -0
- package/esm/geometry/index.js +3 -0
- package/esm/getManHattanPath.d.ts +60 -0
- package/esm/getManHattanPath.d.ts.map +1 -0
- package/esm/getManHattanPath.js +291 -0
- package/esm/index.d.ts +16 -0
- package/esm/index.d.ts.map +1 -0
- package/esm/index.js +24 -0
- package/esm/obstacle/ObstacleMap.d.ts +28 -0
- package/esm/obstacle/ObstacleMap.d.ts.map +1 -0
- package/esm/obstacle/ObstacleMap.js +183 -0
- package/esm/obstacle/index.d.ts +2 -0
- package/esm/obstacle/index.d.ts.map +1 -0
- package/esm/obstacle/index.js +1 -0
- package/esm/options/defaults.d.ts +16 -0
- package/esm/options/defaults.d.ts.map +1 -0
- package/esm/options/defaults.js +33 -0
- package/esm/options/index.d.ts +4 -0
- package/esm/options/index.d.ts.map +1 -0
- package/esm/options/index.js +3 -0
- package/esm/options/resolver.d.ts +10 -0
- package/esm/options/resolver.d.ts.map +1 -0
- package/esm/options/resolver.js +114 -0
- package/esm/options/types.d.ts +156 -0
- package/esm/options/types.d.ts.map +1 -0
- package/esm/options/types.js +1 -0
- package/esm/pathfinder/SortedSet.d.ts +35 -0
- package/esm/pathfinder/SortedSet.d.ts.map +1 -0
- package/esm/pathfinder/SortedSet.js +110 -0
- package/esm/pathfinder/findRoute.d.ts +8 -0
- package/esm/pathfinder/findRoute.d.ts.map +1 -0
- package/esm/pathfinder/findRoute.js +189 -0
- package/esm/pathfinder/index.d.ts +3 -0
- package/esm/pathfinder/index.d.ts.map +1 -0
- package/esm/pathfinder/index.js +2 -0
- package/esm/svg/index.d.ts +2 -0
- package/esm/svg/index.d.ts.map +1 -0
- package/esm/svg/index.js +1 -0
- package/esm/svg/pathConverter.d.ts +10 -0
- package/esm/svg/pathConverter.d.ts.map +1 -0
- package/esm/svg/pathConverter.js +107 -0
- package/esm/utils/direction.d.ts +24 -0
- package/esm/utils/direction.d.ts.map +1 -0
- package/esm/utils/direction.js +46 -0
- package/esm/utils/grid.d.ts +26 -0
- package/esm/utils/grid.d.ts.map +1 -0
- package/esm/utils/grid.js +70 -0
- package/esm/utils/index.d.ts +6 -0
- package/esm/utils/index.d.ts.map +1 -0
- package/esm/utils/index.js +5 -0
- package/esm/utils/node.d.ts +27 -0
- package/esm/utils/node.d.ts.map +1 -0
- package/esm/utils/node.js +30 -0
- package/esm/utils/rect.d.ts +9 -0
- package/esm/utils/rect.d.ts.map +1 -0
- package/esm/utils/rect.js +121 -0
- package/esm/utils/route.d.ts +19 -0
- package/esm/utils/route.d.ts.map +1 -0
- package/esm/utils/route.js +80 -0
- package/package.json +43 -0
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import type { ManhattanRouterOptions, NodeLookup } from './options';
|
|
2
|
+
/**
|
|
3
|
+
* Parameters for getManHattanPath function
|
|
4
|
+
*/
|
|
5
|
+
export interface GetManHattanPathParams {
|
|
6
|
+
/**
|
|
7
|
+
* Source node ID
|
|
8
|
+
*/
|
|
9
|
+
sourceNodeId: string;
|
|
10
|
+
/**
|
|
11
|
+
* Target node ID
|
|
12
|
+
*/
|
|
13
|
+
targetNodeId: string;
|
|
14
|
+
/**
|
|
15
|
+
* Source anchor position (where the edge starts)
|
|
16
|
+
*/
|
|
17
|
+
sourcePosition: {
|
|
18
|
+
x: number;
|
|
19
|
+
y: number;
|
|
20
|
+
};
|
|
21
|
+
/**
|
|
22
|
+
* Target anchor position (where the edge ends)
|
|
23
|
+
*/
|
|
24
|
+
targetPosition: {
|
|
25
|
+
x: number;
|
|
26
|
+
y: number;
|
|
27
|
+
};
|
|
28
|
+
/**
|
|
29
|
+
* ReactFlow node lookup map
|
|
30
|
+
*/
|
|
31
|
+
nodeLookup: NodeLookup;
|
|
32
|
+
/**
|
|
33
|
+
* Router options
|
|
34
|
+
*/
|
|
35
|
+
options?: ManhattanRouterOptions;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Generate Manhattan-routed path for ReactFlow edges
|
|
39
|
+
*
|
|
40
|
+
* @param params - Path generation parameters
|
|
41
|
+
* @returns SVG path string that can be used with ReactFlow's BaseEdge
|
|
42
|
+
*
|
|
43
|
+
* @example
|
|
44
|
+
* ```typescript
|
|
45
|
+
* const path = getManHattanPath({
|
|
46
|
+
* sourceNodeId: 'node1',
|
|
47
|
+
* targetNodeId: 'node2',
|
|
48
|
+
* sourcePosition: { x: 100, y: 100 },
|
|
49
|
+
* targetPosition: { x: 300, y: 300 },
|
|
50
|
+
* nodeLookup: nodes,
|
|
51
|
+
* options: {
|
|
52
|
+
* step: 10,
|
|
53
|
+
* startDirections: ['bottom'],
|
|
54
|
+
* endDirections: ['top']
|
|
55
|
+
* }
|
|
56
|
+
* })
|
|
57
|
+
* ```
|
|
58
|
+
*/
|
|
59
|
+
export declare function getManHattanPath(params: GetManHattanPathParams): string;
|
|
60
|
+
//# sourceMappingURL=getManHattanPath.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"getManHattanPath.d.ts","sourceRoot":"","sources":["../src/getManHattanPath.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,sBAAsB,EAAE,UAAU,EAAE,MAAM,WAAW,CAAA;AAOnE;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACrC;;OAEG;IACH,YAAY,EAAE,MAAM,CAAA;IAEpB;;OAEG;IACH,YAAY,EAAE,MAAM,CAAA;IAEpB;;OAEG;IACH,cAAc,EAAE;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;IAExC;;OAEG;IACH,cAAc,EAAE;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;IAExC;;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,CA4PvE"}
|
|
@@ -0,0 +1,291 @@
|
|
|
1
|
+
function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread(); }
|
|
2
|
+
function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
|
|
3
|
+
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); }
|
|
4
|
+
function _iterableToArray(iter) { if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter); }
|
|
5
|
+
function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) return _arrayLikeToArray(arr); }
|
|
6
|
+
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; }
|
|
7
|
+
import { Point, Rectangle } from "./geometry";
|
|
8
|
+
import { resolveOptions } from "./options";
|
|
9
|
+
import { ObstacleMap } from "./obstacle";
|
|
10
|
+
import { findRoute } from "./pathfinder";
|
|
11
|
+
import { pointsToPath, snapPathToGrid } from "./svg";
|
|
12
|
+
import { getNodeDimensions, getNodePosition } from "./utils";
|
|
13
|
+
|
|
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
|
+
export function getManHattanPath(params) {
|
|
41
|
+
var sourceNodeId = params.sourceNodeId,
|
|
42
|
+
targetNodeId = params.targetNodeId,
|
|
43
|
+
sourcePosition = params.sourcePosition,
|
|
44
|
+
targetPosition = params.targetPosition,
|
|
45
|
+
nodeLookup = params.nodeLookup,
|
|
46
|
+
_params$options = params.options,
|
|
47
|
+
userOptions = _params$options === void 0 ? {} : _params$options;
|
|
48
|
+
|
|
49
|
+
// Resolve options
|
|
50
|
+
var options = resolveOptions(userOptions);
|
|
51
|
+
|
|
52
|
+
// Get source and target nodes
|
|
53
|
+
var sourceNode = nodeLookup.get(sourceNodeId);
|
|
54
|
+
var 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
|
+
var start = new Point(sourcePosition.x, sourcePosition.y);
|
|
59
|
+
var end = new Point(targetPosition.x, targetPosition.y);
|
|
60
|
+
return pointsToPath([start, end], options.precision);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Get node dimensions using ReactFlow's priority logic
|
|
64
|
+
var sourceDimensions = getNodeDimensions(sourceNode);
|
|
65
|
+
var targetDimensions = getNodeDimensions(targetNode);
|
|
66
|
+
|
|
67
|
+
// Get absolute positions from internals
|
|
68
|
+
var sourcePos = getNodePosition(sourceNode);
|
|
69
|
+
var targetPos = getNodePosition(targetNode);
|
|
70
|
+
|
|
71
|
+
// Calculate bounding boxes
|
|
72
|
+
var sourceBBox = new Rectangle(sourcePos.x, sourcePos.y, sourceDimensions.width, sourceDimensions.height);
|
|
73
|
+
var targetBBox = new Rectangle(targetPos.x, targetPos.y, targetDimensions.width, targetDimensions.height);
|
|
74
|
+
|
|
75
|
+
// Create anchor points
|
|
76
|
+
var sourceAnchor = new Point(sourcePosition.x, sourcePosition.y);
|
|
77
|
+
var targetAnchor = new Point(targetPosition.x, targetPosition.y);
|
|
78
|
+
|
|
79
|
+
// Build obstacle map with anchor information
|
|
80
|
+
var obstacleMap = new ObstacleMap(options).build(nodeLookup, sourceNodeId, targetNodeId, sourceAnchor, targetAnchor);
|
|
81
|
+
|
|
82
|
+
// Find route
|
|
83
|
+
var route = 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(function (p) {
|
|
91
|
+
return "(".concat(p.x, ", ").concat(p.y, ")");
|
|
92
|
+
}));
|
|
93
|
+
console.log('[getManHattanPath] Source anchor:', "(".concat(sourceAnchor.x, ", ").concat(sourceAnchor.y, ")"));
|
|
94
|
+
console.log('[getManHattanPath] Target anchor:', "(".concat(targetAnchor.x, ", ").concat(targetAnchor.y, ")"));
|
|
95
|
+
|
|
96
|
+
// Remove extension points from route that were added by getRectPoints
|
|
97
|
+
// We will add our own with fixed step distance
|
|
98
|
+
var step = options.step;
|
|
99
|
+
var tolerance = 1;
|
|
100
|
+
|
|
101
|
+
// Check if first point is an extension point from source
|
|
102
|
+
if (route.length > 0) {
|
|
103
|
+
var firstPoint = route[0];
|
|
104
|
+
var onLeft = Math.abs(sourceAnchor.x - sourceBBox.x) < tolerance;
|
|
105
|
+
var onRight = Math.abs(sourceAnchor.x - (sourceBBox.x + sourceBBox.width)) < tolerance;
|
|
106
|
+
var onTop = Math.abs(sourceAnchor.y - sourceBBox.y) < tolerance;
|
|
107
|
+
var onBottom = Math.abs(sourceAnchor.y - (sourceBBox.y + sourceBBox.height)) < tolerance;
|
|
108
|
+
|
|
109
|
+
// Check if firstPoint is close to source anchor (indicating it's an extension point)
|
|
110
|
+
var distToFirst = sourceAnchor.manhattanDistance(firstPoint);
|
|
111
|
+
if (distToFirst < step * 2) {
|
|
112
|
+
// This is likely an extension point, remove it
|
|
113
|
+
if (onRight && firstPoint.x > sourceAnchor.x || onLeft && firstPoint.x < sourceAnchor.x || onBottom && firstPoint.y > sourceAnchor.y || onTop && firstPoint.y < sourceAnchor.y) {
|
|
114
|
+
route.shift();
|
|
115
|
+
console.log('[getManHattanPath] Removed extension point from route start');
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// Check if last point is an extension point from target
|
|
121
|
+
if (route.length > 0) {
|
|
122
|
+
var lastPoint = route[route.length - 1];
|
|
123
|
+
var _onLeft = Math.abs(targetAnchor.x - targetBBox.x) < tolerance;
|
|
124
|
+
var _onRight = Math.abs(targetAnchor.x - (targetBBox.x + targetBBox.width)) < tolerance;
|
|
125
|
+
var _onTop = Math.abs(targetAnchor.y - targetBBox.y) < tolerance;
|
|
126
|
+
var _onBottom = Math.abs(targetAnchor.y - (targetBBox.y + targetBBox.height)) < tolerance;
|
|
127
|
+
|
|
128
|
+
// Check if lastPoint is close to target anchor (indicating it's an extension point)
|
|
129
|
+
var distToLast = targetAnchor.manhattanDistance(lastPoint);
|
|
130
|
+
if (distToLast < step * 2) {
|
|
131
|
+
// This is likely an extension point, remove it
|
|
132
|
+
if (_onLeft && lastPoint.x < targetAnchor.x || _onRight && lastPoint.x > targetAnchor.x || _onTop && lastPoint.y < targetAnchor.y || _onBottom && lastPoint.y > targetAnchor.y) {
|
|
133
|
+
route.pop();
|
|
134
|
+
console.log('[getManHattanPath] Removed extension point from route end');
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// Insert extension point at source - always extend away from node edge by fixed step distance
|
|
140
|
+
if (route.length > 0) {
|
|
141
|
+
var _firstPoint = route[0];
|
|
142
|
+
|
|
143
|
+
// Determine which edge the source anchor is on
|
|
144
|
+
var _onLeft2 = Math.abs(sourceAnchor.x - sourceBBox.x) < tolerance;
|
|
145
|
+
var _onRight2 = Math.abs(sourceAnchor.x - (sourceBBox.x + sourceBBox.width)) < tolerance;
|
|
146
|
+
var _onTop2 = Math.abs(sourceAnchor.y - sourceBBox.y) < tolerance;
|
|
147
|
+
var _onBottom2 = Math.abs(sourceAnchor.y - (sourceBBox.y + sourceBBox.height)) < tolerance;
|
|
148
|
+
|
|
149
|
+
// Insert extension point and corner point to ensure orthogonal path
|
|
150
|
+
if (_onRight2) {
|
|
151
|
+
// Anchor on right edge - extend right by fixed step
|
|
152
|
+
var extendX = sourceAnchor.x + step;
|
|
153
|
+
var extensionPoint = new Point(extendX, sourceAnchor.y);
|
|
154
|
+
// Check if we need a corner point
|
|
155
|
+
if (Math.abs(extensionPoint.y - _firstPoint.y) > tolerance) {
|
|
156
|
+
route.unshift(new Point(extendX, _firstPoint.y)); // Corner point
|
|
157
|
+
}
|
|
158
|
+
route.unshift(extensionPoint); // Extension point (fixed distance)
|
|
159
|
+
console.log('[getManHattanPath] Inserted source extension (right):', "(".concat(extendX, ", ").concat(sourceAnchor.y, ")"));
|
|
160
|
+
} else if (_onLeft2) {
|
|
161
|
+
// Anchor on left edge - extend left by fixed step
|
|
162
|
+
var _extendX = sourceAnchor.x - step;
|
|
163
|
+
var _extensionPoint = new Point(_extendX, sourceAnchor.y);
|
|
164
|
+
if (Math.abs(_extensionPoint.y - _firstPoint.y) > tolerance) {
|
|
165
|
+
route.unshift(new Point(_extendX, _firstPoint.y));
|
|
166
|
+
}
|
|
167
|
+
route.unshift(_extensionPoint);
|
|
168
|
+
console.log('[getManHattanPath] Inserted source extension (left):', "(".concat(_extendX, ", ").concat(sourceAnchor.y, ")"));
|
|
169
|
+
} else if (_onBottom2) {
|
|
170
|
+
// Anchor on bottom edge - extend down by fixed step
|
|
171
|
+
var extendY = sourceAnchor.y + step;
|
|
172
|
+
var _extensionPoint2 = new Point(sourceAnchor.x, extendY);
|
|
173
|
+
if (Math.abs(_extensionPoint2.x - _firstPoint.x) > tolerance) {
|
|
174
|
+
route.unshift(new Point(_firstPoint.x, extendY));
|
|
175
|
+
}
|
|
176
|
+
route.unshift(_extensionPoint2);
|
|
177
|
+
console.log('[getManHattanPath] Inserted source extension (down):', "(".concat(sourceAnchor.x, ", ").concat(extendY, ")"));
|
|
178
|
+
} else if (_onTop2) {
|
|
179
|
+
// Anchor on top edge - extend up by fixed step
|
|
180
|
+
var _extendY = sourceAnchor.y - step;
|
|
181
|
+
var _extensionPoint3 = new Point(sourceAnchor.x, _extendY);
|
|
182
|
+
if (Math.abs(_extensionPoint3.x - _firstPoint.x) > tolerance) {
|
|
183
|
+
route.unshift(new Point(_firstPoint.x, _extendY));
|
|
184
|
+
}
|
|
185
|
+
route.unshift(_extensionPoint3);
|
|
186
|
+
console.log('[getManHattanPath] Inserted source extension (up):', "(".concat(sourceAnchor.x, ", ").concat(_extendY, ")"));
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// Insert extension point at target - always extend away from node edge by fixed step distance
|
|
191
|
+
if (route.length > 0) {
|
|
192
|
+
var _step = options.step;
|
|
193
|
+
var _tolerance = 1;
|
|
194
|
+
var _lastPoint = route[route.length - 1];
|
|
195
|
+
|
|
196
|
+
// Determine which edge the target anchor is on
|
|
197
|
+
var _onLeft3 = Math.abs(targetAnchor.x - targetBBox.x) < _tolerance;
|
|
198
|
+
var _onRight3 = Math.abs(targetAnchor.x - (targetBBox.x + targetBBox.width)) < _tolerance;
|
|
199
|
+
var _onTop3 = Math.abs(targetAnchor.y - targetBBox.y) < _tolerance;
|
|
200
|
+
var _onBottom3 = Math.abs(targetAnchor.y - (targetBBox.y + targetBBox.height)) < _tolerance;
|
|
201
|
+
|
|
202
|
+
// Insert extension point and corner point to ensure orthogonal path
|
|
203
|
+
if (_onLeft3) {
|
|
204
|
+
// Anchor on left edge - extend left by fixed step
|
|
205
|
+
var _extendX2 = targetAnchor.x - _step;
|
|
206
|
+
var _extensionPoint4 = new Point(_extendX2, targetAnchor.y);
|
|
207
|
+
if (Math.abs(_extensionPoint4.y - _lastPoint.y) > _tolerance) {
|
|
208
|
+
route.push(new Point(_extendX2, _lastPoint.y)); // Corner point
|
|
209
|
+
}
|
|
210
|
+
route.push(_extensionPoint4); // Extension point (fixed distance)
|
|
211
|
+
console.log('[getManHattanPath] Inserted target extension (left):', "(".concat(_extendX2, ", ").concat(targetAnchor.y, ")"));
|
|
212
|
+
} else if (_onRight3) {
|
|
213
|
+
// Anchor on right edge - extend right by fixed step
|
|
214
|
+
var _extendX3 = targetAnchor.x + _step;
|
|
215
|
+
var _extensionPoint5 = new Point(_extendX3, targetAnchor.y);
|
|
216
|
+
if (Math.abs(_extensionPoint5.y - _lastPoint.y) > _tolerance) {
|
|
217
|
+
route.push(new Point(_extendX3, _lastPoint.y));
|
|
218
|
+
}
|
|
219
|
+
route.push(_extensionPoint5);
|
|
220
|
+
console.log('[getManHattanPath] Inserted target extension (right):', "(".concat(_extendX3, ", ").concat(targetAnchor.y, ")"));
|
|
221
|
+
} else if (_onTop3) {
|
|
222
|
+
// Anchor on top edge - extend up by fixed step
|
|
223
|
+
var _extendY2 = targetAnchor.y - _step;
|
|
224
|
+
var _extensionPoint6 = new Point(targetAnchor.x, _extendY2);
|
|
225
|
+
if (Math.abs(_extensionPoint6.x - _lastPoint.x) > _tolerance) {
|
|
226
|
+
route.push(new Point(_lastPoint.x, _extendY2));
|
|
227
|
+
}
|
|
228
|
+
route.push(_extensionPoint6);
|
|
229
|
+
console.log('[getManHattanPath] Inserted target extension (up):', "(".concat(targetAnchor.x, ", ").concat(_extendY2, ")"));
|
|
230
|
+
} else if (_onBottom3) {
|
|
231
|
+
// Anchor on bottom edge - extend down by fixed step
|
|
232
|
+
var _extendY3 = targetAnchor.y + _step;
|
|
233
|
+
var _extensionPoint7 = new Point(targetAnchor.x, _extendY3);
|
|
234
|
+
if (Math.abs(_extensionPoint7.x - _lastPoint.x) > _tolerance) {
|
|
235
|
+
route.push(new Point(_lastPoint.x, _extendY3));
|
|
236
|
+
}
|
|
237
|
+
route.push(_extensionPoint7);
|
|
238
|
+
console.log('[getManHattanPath] Inserted target extension (down):', "(".concat(targetAnchor.x, ", ").concat(_extendY3, ")"));
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
// Add source and target anchors to route
|
|
243
|
+
var fullRoute = [sourceAnchor].concat(_toConsumableArray(route), [targetAnchor]);
|
|
244
|
+
console.log('[getManHattanPath] Full route:', fullRoute.map(function (p) {
|
|
245
|
+
return "(".concat(p.x, ", ").concat(p.y, ")");
|
|
246
|
+
}));
|
|
247
|
+
|
|
248
|
+
// Snap to grid if enabled
|
|
249
|
+
var finalRoute = fullRoute;
|
|
250
|
+
if (options.snapToGrid) {
|
|
251
|
+
// Use step size as grid size for snapping
|
|
252
|
+
finalRoute = snapPathToGrid(fullRoute, options.step);
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
// Simplify path by removing collinear points
|
|
256
|
+
finalRoute = simplifyPath(finalRoute);
|
|
257
|
+
console.log('[getManHattanPath] Simplified route:', finalRoute.map(function (p) {
|
|
258
|
+
return "(".concat(p.x, ", ").concat(p.y, ")");
|
|
259
|
+
}));
|
|
260
|
+
|
|
261
|
+
// Convert to SVG path string
|
|
262
|
+
return pointsToPath(finalRoute, options.precision, options.borderRadius);
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
/**
|
|
266
|
+
* Simplify path by removing collinear intermediate points
|
|
267
|
+
*/
|
|
268
|
+
function simplifyPath(points) {
|
|
269
|
+
if (points.length <= 2) {
|
|
270
|
+
return points;
|
|
271
|
+
}
|
|
272
|
+
var simplified = [points[0]];
|
|
273
|
+
for (var i = 1; i < points.length - 1; i++) {
|
|
274
|
+
var prev = simplified[simplified.length - 1];
|
|
275
|
+
var current = points[i];
|
|
276
|
+
var next = points[i + 1];
|
|
277
|
+
|
|
278
|
+
// Check if current point is collinear with prev and next
|
|
279
|
+
var isHorizontalLine = prev.y === current.y && current.y === next.y;
|
|
280
|
+
var isVerticalLine = prev.x === current.x && current.x === next.x;
|
|
281
|
+
|
|
282
|
+
// Only keep the point if it's not collinear (i.e., it's a corner)
|
|
283
|
+
if (!isHorizontalLine && !isVerticalLine) {
|
|
284
|
+
simplified.push(current);
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
// Always add the last point
|
|
289
|
+
simplified.push(points[points.length - 1]);
|
|
290
|
+
return simplified;
|
|
291
|
+
}
|
package/esm/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/esm/index.js
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
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
|
+
|
|
10
|
+
// Main function
|
|
11
|
+
export { getManHattanPath } from "./getManHattanPath";
|
|
12
|
+
|
|
13
|
+
// Types
|
|
14
|
+
|
|
15
|
+
// Geometry classes (for advanced usage)
|
|
16
|
+
export { Point, Rectangle, Line } from "./geometry";
|
|
17
|
+
|
|
18
|
+
// Utility functions (for advanced usage)
|
|
19
|
+
export { getGrid, align, snapToGrid, getDirectionAngle, getDirectionChange, getRectPoints, getCost, getKey, reconstructRoute, normalizePoint, getNodeDimensions, getNodePosition } from "./utils";
|
|
20
|
+
|
|
21
|
+
// Export types for utility functions
|
|
22
|
+
|
|
23
|
+
// SVG utilities (for advanced usage)
|
|
24
|
+
export { pointsToPath, snapPathToGrid } from "./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,183 @@
|
|
|
1
|
+
function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
|
|
2
|
+
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
|
|
3
|
+
function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, _toPropertyKey(descriptor.key), descriptor); } }
|
|
4
|
+
function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; }
|
|
5
|
+
function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
|
|
6
|
+
function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : String(i); }
|
|
7
|
+
function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != _typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
|
|
8
|
+
import { Point, Rectangle } from "../geometry";
|
|
9
|
+
import { getNodePosition, getNodeDimensions } from "../utils";
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* ObstacleMap class for managing obstacles in pathfinding
|
|
13
|
+
* Uses a grid-based spatial partitioning for efficient queries
|
|
14
|
+
*/
|
|
15
|
+
export var ObstacleMap = /*#__PURE__*/function () {
|
|
16
|
+
function ObstacleMap(options) {
|
|
17
|
+
_classCallCheck(this, ObstacleMap);
|
|
18
|
+
_defineProperty(this, "options", void 0);
|
|
19
|
+
_defineProperty(this, "mapGridSize", void 0);
|
|
20
|
+
_defineProperty(this, "map", void 0);
|
|
21
|
+
_defineProperty(this, "sourceAnchor", void 0);
|
|
22
|
+
_defineProperty(this, "targetAnchor", void 0);
|
|
23
|
+
this.options = options;
|
|
24
|
+
this.mapGridSize = 100;
|
|
25
|
+
this.map = new Map();
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Build obstacle map from node lookup
|
|
30
|
+
*/
|
|
31
|
+
_createClass(ObstacleMap, [{
|
|
32
|
+
key: "build",
|
|
33
|
+
value: function build(nodeLookup, sourceNodeId, targetNodeId, sourceAnchor, targetAnchor) {
|
|
34
|
+
var _this = this;
|
|
35
|
+
var _this$options = this.options,
|
|
36
|
+
excludeNodes = _this$options.excludeNodes,
|
|
37
|
+
excludeShapes = _this$options.excludeShapes,
|
|
38
|
+
excludeTerminals = _this$options.excludeTerminals,
|
|
39
|
+
paddingBox = _this$options.paddingBox;
|
|
40
|
+
|
|
41
|
+
// Store anchors for later use in isAccessible
|
|
42
|
+
this.sourceAnchor = sourceAnchor;
|
|
43
|
+
this.targetAnchor = targetAnchor;
|
|
44
|
+
|
|
45
|
+
// Iterate through all nodes
|
|
46
|
+
nodeLookup.forEach(function (node) {
|
|
47
|
+
// Check if node should be excluded
|
|
48
|
+
var isExcludedNode = excludeNodes.includes(node.id);
|
|
49
|
+
var isExcludedShape = node.type ? excludeShapes.includes(node.type) : false;
|
|
50
|
+
var isSourceTerminal = excludeTerminals.includes('source') && node.id === sourceNodeId;
|
|
51
|
+
var isTargetTerminal = excludeTerminals.includes('target') && node.id === targetNodeId;
|
|
52
|
+
var isSource = node.id === sourceNodeId;
|
|
53
|
+
var isTarget = node.id === targetNodeId;
|
|
54
|
+
|
|
55
|
+
// Skip if node should be excluded (but not source/target - we handle them specially)
|
|
56
|
+
if (isExcludedNode || isExcludedShape || isSourceTerminal || isTargetTerminal) {
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Calculate node bounding box with padding
|
|
61
|
+
var position = getNodePosition(node);
|
|
62
|
+
var dimensions = getNodeDimensions(node);
|
|
63
|
+
var bbox = new Rectangle(position.x, position.y, dimensions.width, dimensions.height).moveAndExpand(paddingBox);
|
|
64
|
+
|
|
65
|
+
// For source and target nodes, add them as full obstacles
|
|
66
|
+
// We'll handle anchor accessibility in isAccessible() method
|
|
67
|
+
if (isSource) {
|
|
68
|
+
console.log('[ObstacleMap] Adding source node as obstacle:');
|
|
69
|
+
console.log(' Node ID:', node.id);
|
|
70
|
+
console.log(' BBox:', "(".concat(bbox.x, ", ").concat(bbox.y, ", ").concat(bbox.width, ", ").concat(bbox.height, ")"));
|
|
71
|
+
console.log(' Anchor:', sourceAnchor ? "(".concat(sourceAnchor.x, ", ").concat(sourceAnchor.y, ")") : 'none');
|
|
72
|
+
} else if (isTarget) {
|
|
73
|
+
console.log('[ObstacleMap] Adding target node as obstacle:');
|
|
74
|
+
console.log(' Node ID:', node.id);
|
|
75
|
+
console.log(' BBox:', "(".concat(bbox.x, ", ").concat(bbox.y, ", ").concat(bbox.width, ", ").concat(bbox.height, ")"));
|
|
76
|
+
console.log(' Anchor:', targetAnchor ? "(".concat(targetAnchor.x, ", ").concat(targetAnchor.y, ")") : 'none');
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// Map bbox to grid cells
|
|
80
|
+
var origin = bbox.getOrigin().snapToGrid(_this.mapGridSize);
|
|
81
|
+
var corner = bbox.getCorner().snapToGrid(_this.mapGridSize);
|
|
82
|
+
for (var x = origin.x; x <= corner.x; x += _this.mapGridSize) {
|
|
83
|
+
for (var y = origin.y; y <= corner.y; y += _this.mapGridSize) {
|
|
84
|
+
var key = new Point(x, y).toString();
|
|
85
|
+
if (!_this.map.has(key)) {
|
|
86
|
+
_this.map.set(key, []);
|
|
87
|
+
}
|
|
88
|
+
_this.map.get(key).push(bbox);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
return this;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Shrink bbox to exclude the area around the anchor point
|
|
97
|
+
* This allows paths to start/end at the anchor but prevents crossing the node
|
|
98
|
+
*/
|
|
99
|
+
}, {
|
|
100
|
+
key: "shrinkBBoxAroundAnchor",
|
|
101
|
+
value: function shrinkBBoxAroundAnchor(bbox, anchor, nodePosition, nodeDimensions) {
|
|
102
|
+
var tolerance = 1;
|
|
103
|
+
var step = this.options.step || 10;
|
|
104
|
+
var margin = step * 3; // Increased margin for better clearance
|
|
105
|
+
|
|
106
|
+
// Determine which edge the anchor is on (relative to original node position)
|
|
107
|
+
var onLeft = Math.abs(anchor.x - nodePosition.x) < tolerance;
|
|
108
|
+
var onRight = Math.abs(anchor.x - (nodePosition.x + nodeDimensions.width)) < tolerance;
|
|
109
|
+
var onTop = Math.abs(anchor.y - nodePosition.y) < tolerance;
|
|
110
|
+
var onBottom = Math.abs(anchor.y - (nodePosition.y + nodeDimensions.height)) < tolerance;
|
|
111
|
+
console.log('[shrinkBBoxAroundAnchor] Edge detection:');
|
|
112
|
+
console.log(' anchor.x:', anchor.x, 'nodePosition.x:', nodePosition.x, 'diff:', Math.abs(anchor.x - nodePosition.x));
|
|
113
|
+
console.log(' anchor.x:', anchor.x, 'nodeRight:', nodePosition.x + nodeDimensions.width, 'diff:', Math.abs(anchor.x - (nodePosition.x + nodeDimensions.width)));
|
|
114
|
+
console.log(' onLeft:', onLeft, 'onRight:', onRight, 'onTop:', onTop, 'onBottom:', onBottom);
|
|
115
|
+
console.log(' margin:', margin);
|
|
116
|
+
|
|
117
|
+
// Shrink bbox based on anchor position
|
|
118
|
+
if (onLeft) {
|
|
119
|
+
// Anchor on left edge - exclude left portion
|
|
120
|
+
return new Rectangle(bbox.x + margin, bbox.y, Math.max(0, bbox.width - margin), bbox.height);
|
|
121
|
+
} else if (onRight) {
|
|
122
|
+
// Anchor on right edge - exclude right portion
|
|
123
|
+
return new Rectangle(bbox.x, bbox.y, Math.max(0, bbox.width - margin), bbox.height);
|
|
124
|
+
} else if (onTop) {
|
|
125
|
+
// Anchor on top edge - exclude top portion
|
|
126
|
+
return new Rectangle(bbox.x, bbox.y + margin, bbox.width, Math.max(0, bbox.height - margin));
|
|
127
|
+
} else if (onBottom) {
|
|
128
|
+
// Anchor on bottom edge - exclude bottom portion
|
|
129
|
+
return new Rectangle(bbox.x, bbox.y, bbox.width, Math.max(0, bbox.height - margin));
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// If anchor is not on an edge, return original bbox
|
|
133
|
+
return bbox;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Check if a point is accessible (not inside any obstacle)
|
|
138
|
+
*/
|
|
139
|
+
}, {
|
|
140
|
+
key: "isAccessible",
|
|
141
|
+
value: function isAccessible(point) {
|
|
142
|
+
var key = point.clone().snapToGrid(this.mapGridSize).toString();
|
|
143
|
+
var rects = this.map.get(key);
|
|
144
|
+
if (!rects) {
|
|
145
|
+
return true;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// Check if point is near an anchor - if so, allow it
|
|
149
|
+
var margin = (this.options.step || 10) * 3;
|
|
150
|
+
if (this.sourceAnchor) {
|
|
151
|
+
var distToSource = Math.abs(point.x - this.sourceAnchor.x) + Math.abs(point.y - this.sourceAnchor.y);
|
|
152
|
+
if (distToSource < margin) {
|
|
153
|
+
console.log("[isAccessible] Point (".concat(point.x, ", ").concat(point.y, "): accessible (near source anchor)"));
|
|
154
|
+
return true;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
if (this.targetAnchor) {
|
|
158
|
+
var distToTarget = Math.abs(point.x - this.targetAnchor.x) + Math.abs(point.y - this.targetAnchor.y);
|
|
159
|
+
if (distToTarget < margin) {
|
|
160
|
+
console.log("[isAccessible] Point (".concat(point.x, ", ").concat(point.y, "): accessible (near target anchor)"));
|
|
161
|
+
return true;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
var accessible = rects.every(function (rect) {
|
|
165
|
+
return !rect.containsPoint(point);
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
// Debug: log points on the direct path
|
|
169
|
+
if (point.y === 40 && point.x >= 0 && point.x <= 545) {
|
|
170
|
+
console.log("[isAccessible] Point (".concat(point.x, ", ").concat(point.y, "): ").concat(accessible ? 'accessible' : 'BLOCKED'));
|
|
171
|
+
if (!accessible) {
|
|
172
|
+
rects.forEach(function (rect, i) {
|
|
173
|
+
if (rect.containsPoint(point)) {
|
|
174
|
+
console.log(" Blocked by rect ".concat(i, ": (").concat(rect.x, ", ").concat(rect.y, ", ").concat(rect.width, ", ").concat(rect.height, ")"));
|
|
175
|
+
}
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
return accessible;
|
|
180
|
+
}
|
|
181
|
+
}]);
|
|
182
|
+
return ObstacleMap;
|
|
183
|
+
}();
|
|
@@ -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 @@
|
|
|
1
|
+
export { ObstacleMap } from "./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"}
|