@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.
- package/cjs/geometry/Rectangle.d.ts +1 -1
- package/cjs/geometry/Rectangle.js +2 -2
- package/cjs/getManHattanPath.d.ts.map +1 -1
- package/cjs/getManHattanPath.js +153 -20
- package/cjs/obstacle/ObstacleMap.d.ts +7 -1
- package/cjs/obstacle/ObstacleMap.d.ts.map +1 -1
- package/cjs/obstacle/ObstacleMap.js +53 -1
- package/cjs/options/defaults.d.ts +1 -1
- package/cjs/options/defaults.d.ts.map +1 -1
- package/cjs/options/defaults.js +1 -1
- package/cjs/options/resolver.d.ts.map +1 -1
- package/cjs/options/resolver.js +4 -2
- package/cjs/options/types.d.ts +19 -6
- package/cjs/options/types.d.ts.map +1 -1
- package/cjs/pathfinder/findRoute.d.ts.map +1 -1
- package/cjs/pathfinder/findRoute.js +184 -13
- package/cjs/svg/pathConverter.d.ts.map +1 -1
- package/cjs/svg/pathConverter.js +23 -12
- package/cjs/utils/getAnchorPoints.d.ts +15 -0
- package/cjs/utils/getAnchorPoints.d.ts.map +1 -0
- package/cjs/utils/getAnchorPoints.js +75 -0
- package/cjs/utils/index.d.ts +1 -0
- package/cjs/utils/index.d.ts.map +1 -1
- package/cjs/utils/index.js +11 -0
- package/esm/geometry/Rectangle.d.ts +1 -1
- package/esm/geometry/Rectangle.js +2 -2
- package/esm/getManHattanPath.d.ts.map +1 -1
- package/esm/getManHattanPath.js +162 -22
- package/esm/obstacle/ObstacleMap.d.ts +7 -1
- package/esm/obstacle/ObstacleMap.d.ts.map +1 -1
- package/esm/obstacle/ObstacleMap.js +78 -0
- package/esm/options/defaults.d.ts +1 -1
- package/esm/options/defaults.d.ts.map +1 -1
- package/esm/options/defaults.js +1 -1
- package/esm/options/resolver.d.ts.map +1 -1
- package/esm/options/resolver.js +5 -3
- package/esm/options/types.d.ts +19 -6
- package/esm/options/types.d.ts.map +1 -1
- package/esm/pathfinder/findRoute.d.ts.map +1 -1
- package/esm/pathfinder/findRoute.js +206 -21
- package/esm/svg/pathConverter.d.ts.map +1 -1
- package/esm/svg/pathConverter.js +23 -12
- package/esm/utils/getAnchorPoints.d.ts +15 -0
- package/esm/utils/getAnchorPoints.d.ts.map +1 -0
- package/esm/utils/getAnchorPoints.js +69 -0
- package/esm/utils/index.d.ts +1 -0
- package/esm/utils/index.d.ts.map +1 -1
- package/esm/utils/index.js +2 -1
- 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,
|
|
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
|
-
|
|
26
|
-
var
|
|
27
|
-
|
|
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
|
-
//
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
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 = [
|
|
179
|
+
startPoints = [round(startPoint, precision)];
|
|
52
180
|
}
|
|
53
181
|
if (endPoints.length === 0) {
|
|
54
|
-
endPoints = [
|
|
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 =
|
|
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
|
|
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,
|
|
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"}
|
package/esm/svg/pathConverter.js
CHANGED
|
@@ -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
|
|
42
|
-
var
|
|
43
|
-
var
|
|
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,
|
|
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
|
|
49
|
-
var beforeCornerRatio = (distToPrev - radius) / distToPrev;
|
|
60
|
+
// Calculate the point before the corner
|
|
50
61
|
var beforeCorner = {
|
|
51
|
-
x:
|
|
52
|
-
y:
|
|
62
|
+
x: current.x - ndx1 * radius,
|
|
63
|
+
y: current.y - ndy1 * radius
|
|
53
64
|
};
|
|
54
65
|
|
|
55
|
-
// Calculate the point after the corner
|
|
56
|
-
var afterCornerRatio = radius / distToNext;
|
|
66
|
+
// Calculate the point after the corner
|
|
57
67
|
var afterCorner = {
|
|
58
|
-
x: current.x +
|
|
59
|
-
y: current.y +
|
|
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
|
+
}
|
package/esm/utils/index.d.ts
CHANGED
package/esm/utils/index.d.ts.map
CHANGED
|
@@ -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"}
|
package/esm/utils/index.js
CHANGED
package/package.json
CHANGED