@rxflow/manhattan 0.0.2 → 0.0.3
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/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/collision.d.ts +15 -0
- package/cjs/geometry/collision.d.ts.map +1 -0
- package/cjs/geometry/collision.js +81 -0
- package/cjs/geometry/index.d.ts +5 -0
- package/cjs/geometry/index.d.ts.map +1 -0
- package/cjs/geometry/index.js +45 -0
- package/cjs/getManHattanPath.d.ts +53 -0
- package/cjs/getManHattanPath.d.ts.map +1 -0
- package/cjs/getManHattanPath.js +449 -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 +66 -0
- package/cjs/obstacle/ObstacleMap.d.ts.map +1 -0
- package/cjs/obstacle/ObstacleMap.js +328 -0
- package/cjs/obstacle/QuadTree.d.ts +119 -0
- package/cjs/obstacle/QuadTree.d.ts.map +1 -0
- package/cjs/obstacle/QuadTree.js +334 -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 +248 -0
- package/cjs/options/types.d.ts +210 -0
- package/cjs/options/types.d.ts.map +1 -0
- package/cjs/options/types.js +5 -0
- package/cjs/pathfinder/PathCache.d.ts +92 -0
- package/cjs/pathfinder/PathCache.d.ts.map +1 -0
- package/cjs/pathfinder/PathCache.js +249 -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 +395 -0
- package/cjs/pathfinder/index.d.ts +4 -0
- package/cjs/pathfinder/index.d.ts.map +1 -0
- package/cjs/pathfinder/index.js +44 -0
- package/cjs/svg/index.d.ts +3 -0
- package/cjs/svg/index.d.ts.map +1 -0
- package/cjs/svg/index.js +31 -0
- package/cjs/svg/pathConverter.d.ts +23 -0
- package/cjs/svg/pathConverter.d.ts.map +1 -0
- package/cjs/svg/pathConverter.js +285 -0
- package/cjs/svg/pathParser.d.ts +11 -0
- package/cjs/svg/pathParser.d.ts.map +1 -0
- package/cjs/svg/pathParser.js +76 -0
- package/cjs/utils/AdaptiveStepCalculator.d.ts +90 -0
- package/cjs/utils/AdaptiveStepCalculator.d.ts.map +1 -0
- package/cjs/utils/AdaptiveStepCalculator.js +224 -0
- package/cjs/utils/ErrorRecovery.d.ts +182 -0
- package/cjs/utils/ErrorRecovery.d.ts.map +1 -0
- package/cjs/utils/ErrorRecovery.js +413 -0
- package/cjs/utils/GlobalGrid.d.ts +99 -0
- package/cjs/utils/GlobalGrid.d.ts.map +1 -0
- package/cjs/utils/GlobalGrid.js +224 -0
- package/cjs/utils/PerformanceMonitor.d.ts +139 -0
- package/cjs/utils/PerformanceMonitor.d.ts.map +1 -0
- package/cjs/utils/PerformanceMonitor.js +305 -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/getAnchorPoints.d.ts +15 -0
- package/cjs/utils/getAnchorPoints.d.ts.map +1 -0
- package/cjs/utils/getAnchorPoints.js +71 -0
- package/cjs/utils/grid.d.ts +42 -0
- package/cjs/utils/grid.d.ts.map +1 -0
- package/cjs/utils/grid.js +73 -0
- package/cjs/utils/heuristics.d.ts +61 -0
- package/cjs/utils/heuristics.d.ts.map +1 -0
- package/cjs/utils/heuristics.js +141 -0
- package/cjs/utils/index.d.ts +14 -0
- package/cjs/utils/index.d.ts.map +1 -0
- package/cjs/utils/index.js +148 -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/pathProcessing.d.ts +45 -0
- package/cjs/utils/pathProcessing.d.ts.map +1 -0
- package/cjs/utils/pathProcessing.js +270 -0
- package/cjs/utils/pathValidation.d.ts +11 -0
- package/cjs/utils/pathValidation.d.ts.map +1 -0
- package/cjs/utils/pathValidation.js +129 -0
- package/cjs/utils/rect.d.ts +9 -0
- package/cjs/utils/rect.d.ts.map +1 -0
- package/cjs/utils/rect.js +110 -0
- package/cjs/utils/route.d.ts +19 -0
- package/cjs/utils/route.d.ts.map +1 -0
- package/cjs/utils/route.js +92 -0
- package/esm/geometry/Line.d.ts +21 -0
- package/esm/geometry/Line.d.ts.map +1 -0
- package/esm/geometry/Point.d.ts +49 -0
- package/esm/geometry/Point.d.ts.map +1 -0
- package/esm/geometry/Rectangle.d.ts +41 -0
- package/esm/geometry/Rectangle.d.ts.map +1 -0
- package/esm/geometry/collision.d.ts +15 -0
- package/esm/geometry/collision.d.ts.map +1 -0
- package/esm/geometry/index.d.ts +5 -0
- package/esm/geometry/index.d.ts.map +1 -0
- package/esm/getManHattanPath.d.ts +53 -0
- package/esm/getManHattanPath.d.ts.map +1 -0
- package/esm/index.d.ts +16 -0
- package/esm/index.d.ts.map +1 -0
- package/esm/obstacle/ObstacleMap.d.ts +66 -0
- package/esm/obstacle/ObstacleMap.d.ts.map +1 -0
- package/esm/obstacle/QuadTree.d.ts +119 -0
- package/esm/obstacle/QuadTree.d.ts.map +1 -0
- package/esm/obstacle/index.d.ts +2 -0
- package/esm/obstacle/index.d.ts.map +1 -0
- package/esm/options/defaults.d.ts +16 -0
- package/esm/options/defaults.d.ts.map +1 -0
- package/esm/options/index.d.ts +4 -0
- package/esm/options/index.d.ts.map +1 -0
- package/esm/options/resolver.d.ts +10 -0
- package/esm/options/resolver.d.ts.map +1 -0
- package/esm/options/types.d.ts +210 -0
- package/esm/options/types.d.ts.map +1 -0
- package/esm/pathfinder/PathCache.d.ts +92 -0
- package/esm/pathfinder/PathCache.d.ts.map +1 -0
- package/esm/pathfinder/SortedSet.d.ts +35 -0
- package/esm/pathfinder/SortedSet.d.ts.map +1 -0
- package/esm/pathfinder/findRoute.d.ts +8 -0
- package/esm/pathfinder/findRoute.d.ts.map +1 -0
- package/esm/pathfinder/index.d.ts +4 -0
- package/esm/pathfinder/index.d.ts.map +1 -0
- package/esm/svg/index.d.ts +3 -0
- package/esm/svg/index.d.ts.map +1 -0
- package/esm/svg/pathConverter.d.ts +23 -0
- package/esm/svg/pathConverter.d.ts.map +1 -0
- package/esm/svg/pathParser.d.ts +11 -0
- package/esm/svg/pathParser.d.ts.map +1 -0
- package/esm/utils/AdaptiveStepCalculator.d.ts +90 -0
- package/esm/utils/AdaptiveStepCalculator.d.ts.map +1 -0
- package/esm/utils/ErrorRecovery.d.ts +182 -0
- package/esm/utils/ErrorRecovery.d.ts.map +1 -0
- package/esm/utils/GlobalGrid.d.ts +99 -0
- package/esm/utils/GlobalGrid.d.ts.map +1 -0
- package/esm/utils/PerformanceMonitor.d.ts +139 -0
- package/esm/utils/PerformanceMonitor.d.ts.map +1 -0
- package/esm/utils/direction.d.ts +24 -0
- package/esm/utils/direction.d.ts.map +1 -0
- package/esm/utils/getAnchorPoints.d.ts +15 -0
- package/esm/utils/getAnchorPoints.d.ts.map +1 -0
- package/esm/utils/grid.d.ts +42 -0
- package/esm/utils/grid.d.ts.map +1 -0
- package/esm/utils/heuristics.d.ts +61 -0
- package/esm/utils/heuristics.d.ts.map +1 -0
- package/esm/utils/index.d.ts +14 -0
- package/esm/utils/index.d.ts.map +1 -0
- package/esm/utils/node.d.ts +27 -0
- package/esm/utils/node.d.ts.map +1 -0
- package/esm/utils/pathProcessing.d.ts +45 -0
- package/esm/utils/pathProcessing.d.ts.map +1 -0
- package/esm/utils/pathValidation.d.ts +11 -0
- package/esm/utils/pathValidation.d.ts.map +1 -0
- package/esm/utils/rect.d.ts +9 -0
- package/esm/utils/rect.d.ts.map +1 -0
- package/esm/utils/route.d.ts +19 -0
- package/esm/utils/route.d.ts.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,285 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.countCorners = countCorners;
|
|
7
|
+
exports.hasRoundedCorners = hasRoundedCorners;
|
|
8
|
+
exports.pointsToPath = pointsToPath;
|
|
9
|
+
exports.pointsToPathCubic = pointsToPathCubic;
|
|
10
|
+
exports.snapPathToGrid = snapPathToGrid;
|
|
11
|
+
/**
|
|
12
|
+
* Check if three points form a corner (direction change)
|
|
13
|
+
*/
|
|
14
|
+
function isCorner(prev, current, next) {
|
|
15
|
+
const dx1 = current.x - prev.x;
|
|
16
|
+
const dy1 = current.y - prev.y;
|
|
17
|
+
const dx2 = next.x - current.x;
|
|
18
|
+
const dy2 = next.y - current.y;
|
|
19
|
+
|
|
20
|
+
// Check if direction changes (not collinear)
|
|
21
|
+
// For Manhattan paths, this means one segment is horizontal and the other is vertical
|
|
22
|
+
const isHorizontal1 = Math.abs(dy1) < 0.001;
|
|
23
|
+
const isVertical1 = Math.abs(dx1) < 0.001;
|
|
24
|
+
const isHorizontal2 = Math.abs(dy2) < 0.001;
|
|
25
|
+
const isVertical2 = Math.abs(dx2) < 0.001;
|
|
26
|
+
|
|
27
|
+
// Corner exists if one segment is horizontal and the other is vertical
|
|
28
|
+
return isHorizontal1 && isVertical2 || isVertical1 && isHorizontal2;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Calculate optimal border radius for a corner
|
|
33
|
+
* Ensures the radius doesn't exceed half the length of adjacent segments
|
|
34
|
+
*/
|
|
35
|
+
function calculateOptimalRadius(prev, current, next, maxRadius) {
|
|
36
|
+
const dx1 = current.x - prev.x;
|
|
37
|
+
const dy1 = current.y - prev.y;
|
|
38
|
+
const dx2 = next.x - current.x;
|
|
39
|
+
const dy2 = next.y - current.y;
|
|
40
|
+
const dist1 = Math.sqrt(dx1 * dx1 + dy1 * dy1);
|
|
41
|
+
const dist2 = Math.sqrt(dx2 * dx2 + dy2 * dy2);
|
|
42
|
+
|
|
43
|
+
// Use the smaller of maxRadius or half the segment length
|
|
44
|
+
return Math.min(maxRadius, dist1 / 2, dist2 / 2);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Convert array of points to SVG path string
|
|
49
|
+
*/
|
|
50
|
+
function pointsToPath(points, precision, borderRadius = 0) {
|
|
51
|
+
if (points.length === 0) {
|
|
52
|
+
return '';
|
|
53
|
+
}
|
|
54
|
+
const factor = Math.pow(10, precision);
|
|
55
|
+
const roundCoord = value => Math.round(value * factor) / factor;
|
|
56
|
+
|
|
57
|
+
// If no border radius or only 2 points, use simple line path
|
|
58
|
+
if (borderRadius === 0 || points.length <= 2) {
|
|
59
|
+
const firstPoint = points[0];
|
|
60
|
+
let path = `M ${roundCoord(firstPoint.x)} ${roundCoord(firstPoint.y)}`;
|
|
61
|
+
for (let i = 1; i < points.length; i++) {
|
|
62
|
+
const point = points[i];
|
|
63
|
+
path += ` L ${roundCoord(point.x)} ${roundCoord(point.y)}`;
|
|
64
|
+
}
|
|
65
|
+
return path;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// Start with M (moveTo) command for first point
|
|
69
|
+
const firstPoint = points[0];
|
|
70
|
+
let path = `M ${roundCoord(firstPoint.x)} ${roundCoord(firstPoint.y)}`;
|
|
71
|
+
|
|
72
|
+
// Process each segment with rounded corners
|
|
73
|
+
for (let i = 1; i < points.length - 1; i++) {
|
|
74
|
+
const prev = points[i - 1];
|
|
75
|
+
const current = points[i];
|
|
76
|
+
const next = points[i + 1];
|
|
77
|
+
|
|
78
|
+
// Check if this is actually a corner
|
|
79
|
+
if (!isCorner(prev, current, next)) {
|
|
80
|
+
// Not a corner, just draw a line to current point
|
|
81
|
+
path += ` L ${roundCoord(current.x)} ${roundCoord(current.y)}`;
|
|
82
|
+
continue;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// Calculate direction vectors
|
|
86
|
+
const dx1 = current.x - prev.x;
|
|
87
|
+
const dy1 = current.y - prev.y;
|
|
88
|
+
const dx2 = next.x - current.x;
|
|
89
|
+
const dy2 = next.y - current.y;
|
|
90
|
+
|
|
91
|
+
// Calculate distances
|
|
92
|
+
const dist1 = Math.sqrt(dx1 * dx1 + dy1 * dy1);
|
|
93
|
+
const dist2 = Math.sqrt(dx2 * dx2 + dy2 * dy2);
|
|
94
|
+
|
|
95
|
+
// Use the smaller of borderRadius or half the segment length
|
|
96
|
+
const radius = calculateOptimalRadius(prev, current, next, borderRadius);
|
|
97
|
+
|
|
98
|
+
// Skip if radius is too small
|
|
99
|
+
if (radius < 0.5) {
|
|
100
|
+
path += ` L ${roundCoord(current.x)} ${roundCoord(current.y)}`;
|
|
101
|
+
continue;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// Normalize direction vectors
|
|
105
|
+
const ndx1 = dx1 / dist1;
|
|
106
|
+
const ndy1 = dy1 / dist1;
|
|
107
|
+
const ndx2 = dx2 / dist2;
|
|
108
|
+
const ndy2 = dy2 / dist2;
|
|
109
|
+
|
|
110
|
+
// Calculate the point before the corner
|
|
111
|
+
const beforeCorner = {
|
|
112
|
+
x: current.x - ndx1 * radius,
|
|
113
|
+
y: current.y - ndy1 * radius
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
// Calculate the point after the corner
|
|
117
|
+
const afterCorner = {
|
|
118
|
+
x: current.x + ndx2 * radius,
|
|
119
|
+
y: current.y + ndy2 * radius
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
// Draw line to the point before corner
|
|
123
|
+
path += ` L ${roundCoord(beforeCorner.x)} ${roundCoord(beforeCorner.y)}`;
|
|
124
|
+
|
|
125
|
+
// Draw quadratic bezier curve for the rounded corner
|
|
126
|
+
// The control point is the actual corner point
|
|
127
|
+
path += ` Q ${roundCoord(current.x)} ${roundCoord(current.y)} ${roundCoord(afterCorner.x)} ${roundCoord(afterCorner.y)}`;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// Draw line to the last point
|
|
131
|
+
const lastPoint = points[points.length - 1];
|
|
132
|
+
path += ` L ${roundCoord(lastPoint.x)} ${roundCoord(lastPoint.y)}`;
|
|
133
|
+
return path;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Convert array of points to SVG path string with cubic bezier curves
|
|
138
|
+
* Provides smoother corners than quadratic bezier
|
|
139
|
+
*/
|
|
140
|
+
function pointsToPathCubic(points, precision, borderRadius = 0) {
|
|
141
|
+
if (points.length === 0) {
|
|
142
|
+
return '';
|
|
143
|
+
}
|
|
144
|
+
const factor = Math.pow(10, precision);
|
|
145
|
+
const roundCoord = value => Math.round(value * factor) / factor;
|
|
146
|
+
|
|
147
|
+
// If no border radius or only 2 points, use simple line path
|
|
148
|
+
if (borderRadius === 0 || points.length <= 2) {
|
|
149
|
+
const firstPoint = points[0];
|
|
150
|
+
let path = `M ${roundCoord(firstPoint.x)} ${roundCoord(firstPoint.y)}`;
|
|
151
|
+
for (let i = 1; i < points.length; i++) {
|
|
152
|
+
const point = points[i];
|
|
153
|
+
path += ` L ${roundCoord(point.x)} ${roundCoord(point.y)}`;
|
|
154
|
+
}
|
|
155
|
+
return path;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// Start with M (moveTo) command for first point
|
|
159
|
+
const firstPoint = points[0];
|
|
160
|
+
let path = `M ${roundCoord(firstPoint.x)} ${roundCoord(firstPoint.y)}`;
|
|
161
|
+
|
|
162
|
+
// Process each segment with rounded corners using cubic bezier
|
|
163
|
+
for (let i = 1; i < points.length - 1; i++) {
|
|
164
|
+
const prev = points[i - 1];
|
|
165
|
+
const current = points[i];
|
|
166
|
+
const next = points[i + 1];
|
|
167
|
+
|
|
168
|
+
// Check if this is actually a corner
|
|
169
|
+
if (!isCorner(prev, current, next)) {
|
|
170
|
+
path += ` L ${roundCoord(current.x)} ${roundCoord(current.y)}`;
|
|
171
|
+
continue;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// Calculate direction vectors
|
|
175
|
+
const dx1 = current.x - prev.x;
|
|
176
|
+
const dy1 = current.y - prev.y;
|
|
177
|
+
const dx2 = next.x - current.x;
|
|
178
|
+
const dy2 = next.y - current.y;
|
|
179
|
+
|
|
180
|
+
// Calculate distances
|
|
181
|
+
const dist1 = Math.sqrt(dx1 * dx1 + dy1 * dy1);
|
|
182
|
+
const dist2 = Math.sqrt(dx2 * dx2 + dy2 * dy2);
|
|
183
|
+
|
|
184
|
+
// Use the smaller of borderRadius or half the segment length
|
|
185
|
+
const radius = calculateOptimalRadius(prev, current, next, borderRadius);
|
|
186
|
+
|
|
187
|
+
// Skip if radius is too small
|
|
188
|
+
if (radius < 0.5) {
|
|
189
|
+
path += ` L ${roundCoord(current.x)} ${roundCoord(current.y)}`;
|
|
190
|
+
continue;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// Normalize direction vectors
|
|
194
|
+
const ndx1 = dx1 / dist1;
|
|
195
|
+
const ndy1 = dy1 / dist1;
|
|
196
|
+
const ndx2 = dx2 / dist2;
|
|
197
|
+
const ndy2 = dy2 / dist2;
|
|
198
|
+
|
|
199
|
+
// Calculate the point before the corner
|
|
200
|
+
const beforeCorner = {
|
|
201
|
+
x: current.x - ndx1 * radius,
|
|
202
|
+
y: current.y - ndy1 * radius
|
|
203
|
+
};
|
|
204
|
+
|
|
205
|
+
// Calculate the point after the corner
|
|
206
|
+
const afterCorner = {
|
|
207
|
+
x: current.x + ndx2 * radius,
|
|
208
|
+
y: current.y + ndy2 * radius
|
|
209
|
+
};
|
|
210
|
+
|
|
211
|
+
// Draw line to the point before corner
|
|
212
|
+
path += ` L ${roundCoord(beforeCorner.x)} ${roundCoord(beforeCorner.y)}`;
|
|
213
|
+
|
|
214
|
+
// Draw cubic bezier curve for smoother rounded corner
|
|
215
|
+
// Control points are positioned to create a smooth arc
|
|
216
|
+
const cp1 = {
|
|
217
|
+
x: beforeCorner.x + ndx1 * radius * 0.55,
|
|
218
|
+
y: beforeCorner.y + ndy1 * radius * 0.55
|
|
219
|
+
};
|
|
220
|
+
const cp2 = {
|
|
221
|
+
x: afterCorner.x - ndx2 * radius * 0.55,
|
|
222
|
+
y: afterCorner.y - ndy2 * radius * 0.55
|
|
223
|
+
};
|
|
224
|
+
path += ` C ${roundCoord(cp1.x)} ${roundCoord(cp1.y)} ${roundCoord(cp2.x)} ${roundCoord(cp2.y)} ${roundCoord(afterCorner.x)} ${roundCoord(afterCorner.y)}`;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
// Draw line to the last point
|
|
228
|
+
const lastPoint = points[points.length - 1];
|
|
229
|
+
path += ` L ${roundCoord(lastPoint.x)} ${roundCoord(lastPoint.y)}`;
|
|
230
|
+
return path;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/**
|
|
234
|
+
* Snap path to grid by aligning consecutive points
|
|
235
|
+
*/
|
|
236
|
+
function snapPathToGrid(points, gridSize) {
|
|
237
|
+
if (points.length <= 1) {
|
|
238
|
+
return points;
|
|
239
|
+
}
|
|
240
|
+
const snappedPoints = [...points];
|
|
241
|
+
|
|
242
|
+
// Don't snap the first and last points (anchors)
|
|
243
|
+
// Don't snap the second and second-to-last points (extension points)
|
|
244
|
+
// Only snap intermediate segments
|
|
245
|
+
for (let i = 2; i < snappedPoints.length - 3; i++) {
|
|
246
|
+
const first = snappedPoints[i];
|
|
247
|
+
const second = snappedPoints[i + 1];
|
|
248
|
+
if (first.x === second.x) {
|
|
249
|
+
// Vertical line - snap X coordinate
|
|
250
|
+
const x = gridSize * Math.round(first.x / gridSize);
|
|
251
|
+
if (first.x !== x) {
|
|
252
|
+
first.x = x;
|
|
253
|
+
second.x = x;
|
|
254
|
+
}
|
|
255
|
+
} else if (first.y === second.y) {
|
|
256
|
+
// Horizontal line - snap Y coordinate
|
|
257
|
+
const y = gridSize * Math.round(first.y / gridSize);
|
|
258
|
+
if (first.y !== y) {
|
|
259
|
+
first.y = y;
|
|
260
|
+
second.y = y;
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
return snappedPoints;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
/**
|
|
268
|
+
* Check if an SVG path contains rounded corners (Q or C commands)
|
|
269
|
+
*/
|
|
270
|
+
function hasRoundedCorners(path) {
|
|
271
|
+
return /[QC]\s/.test(path);
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
/**
|
|
275
|
+
* Count the number of corners in a path
|
|
276
|
+
*/
|
|
277
|
+
function countCorners(points) {
|
|
278
|
+
let corners = 0;
|
|
279
|
+
for (let i = 1; i < points.length - 1; i++) {
|
|
280
|
+
if (isCorner(points[i - 1], points[i], points[i + 1])) {
|
|
281
|
+
corners++;
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
return corners;
|
|
285
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { Point } from '../geometry';
|
|
2
|
+
/**
|
|
3
|
+
* Parse SVG path string to extract points
|
|
4
|
+
* Simplified parser that handles M, L, Q commands
|
|
5
|
+
*/
|
|
6
|
+
export declare function parseSVGPath(pathString: string): Point[];
|
|
7
|
+
/**
|
|
8
|
+
* Simplify path by removing collinear intermediate points
|
|
9
|
+
*/
|
|
10
|
+
export declare function simplifyPath(points: Point[]): Point[];
|
|
11
|
+
//# sourceMappingURL=pathParser.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pathParser.d.ts","sourceRoot":"","sources":["../../src/svg/pathParser.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAA;AAEnC;;;GAGG;AACH,wBAAgB,YAAY,CAAC,UAAU,EAAE,MAAM,GAAG,KAAK,EAAE,CA2CxD;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,KAAK,EAAE,GAAG,KAAK,EAAE,CA0BrD"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.parseSVGPath = parseSVGPath;
|
|
7
|
+
exports.simplifyPath = simplifyPath;
|
|
8
|
+
var _geometry = require("../geometry");
|
|
9
|
+
/**
|
|
10
|
+
* Parse SVG path string to extract points
|
|
11
|
+
* Simplified parser that handles M, L, Q commands
|
|
12
|
+
*/
|
|
13
|
+
function parseSVGPath(pathString) {
|
|
14
|
+
const points = [];
|
|
15
|
+
const commands = pathString.match(/[MLQ][^MLQ]*/g);
|
|
16
|
+
if (!commands) return points;
|
|
17
|
+
for (const command of commands) {
|
|
18
|
+
const type = command[0];
|
|
19
|
+
const coords = command.slice(1).trim().split(/[\s,]+/).map(Number);
|
|
20
|
+
if (type === 'M' || type === 'L') {
|
|
21
|
+
// MoveTo or LineTo: x, y
|
|
22
|
+
if (coords.length >= 2) {
|
|
23
|
+
points.push(new _geometry.Point(coords[0], coords[1]));
|
|
24
|
+
}
|
|
25
|
+
} else if (type === 'Q') {
|
|
26
|
+
// Quadratic Bezier: cx, cy, x, y
|
|
27
|
+
// We sample points along the curve for collision detection
|
|
28
|
+
if (coords.length >= 4) {
|
|
29
|
+
const prevPoint = points[points.length - 1];
|
|
30
|
+
if (prevPoint) {
|
|
31
|
+
const cx = coords[0];
|
|
32
|
+
const cy = coords[1];
|
|
33
|
+
const x = coords[2];
|
|
34
|
+
const y = coords[3];
|
|
35
|
+
|
|
36
|
+
// Sample 10 points along the bezier curve for better accuracy
|
|
37
|
+
// This ensures we don't miss intersections with obstacles
|
|
38
|
+
for (let t = 0.1; t <= 1; t += 0.1) {
|
|
39
|
+
const bx = (1 - t) * (1 - t) * prevPoint.x + 2 * (1 - t) * t * cx + t * t * x;
|
|
40
|
+
const by = (1 - t) * (1 - t) * prevPoint.y + 2 * (1 - t) * t * cy + t * t * y;
|
|
41
|
+
points.push(new _geometry.Point(bx, by));
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
return points;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Simplify path by removing collinear intermediate points
|
|
52
|
+
*/
|
|
53
|
+
function simplifyPath(points) {
|
|
54
|
+
if (points.length <= 2) {
|
|
55
|
+
return points;
|
|
56
|
+
}
|
|
57
|
+
const simplified = [points[0]];
|
|
58
|
+
for (let i = 1; i < points.length - 1; i++) {
|
|
59
|
+
const prev = simplified[simplified.length - 1];
|
|
60
|
+
const current = points[i];
|
|
61
|
+
const next = points[i + 1];
|
|
62
|
+
|
|
63
|
+
// Check if current point is collinear with prev and next
|
|
64
|
+
const isHorizontalLine = prev.y === current.y && current.y === next.y;
|
|
65
|
+
const isVerticalLine = prev.x === current.x && current.x === next.x;
|
|
66
|
+
|
|
67
|
+
// Only keep the point if it's not collinear (i.e., it's a corner)
|
|
68
|
+
if (!isHorizontalLine && !isVerticalLine) {
|
|
69
|
+
simplified.push(current);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Always add the last point
|
|
74
|
+
simplified.push(points[points.length - 1]);
|
|
75
|
+
return simplified;
|
|
76
|
+
}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AdaptiveStepCalculator - 自适应步长计算器
|
|
3
|
+
*
|
|
4
|
+
* 根据场景自动调整网格步长,平衡性能和路径质量
|
|
5
|
+
* - 高密度区域使用小步长,提高路径精度
|
|
6
|
+
* - 长距离路径使用大步长,提高计算性能
|
|
7
|
+
*
|
|
8
|
+
* Feature: manhattan-optimization
|
|
9
|
+
* Requirements: 2.3, 2.4
|
|
10
|
+
*/
|
|
11
|
+
import type { InternalNode, NodeLookup } from '../options/types';
|
|
12
|
+
import { Point } from '../geometry';
|
|
13
|
+
/**
|
|
14
|
+
* 自适应步长配置
|
|
15
|
+
*/
|
|
16
|
+
export interface AdaptiveStepConfig {
|
|
17
|
+
/** 是否启用自适应步长 */
|
|
18
|
+
enabled: boolean;
|
|
19
|
+
/** 最小步长 */
|
|
20
|
+
minStep: number;
|
|
21
|
+
/** 最大步长 */
|
|
22
|
+
maxStep: number;
|
|
23
|
+
/** 基于密度的调整配置 */
|
|
24
|
+
densityBased: {
|
|
25
|
+
enabled: boolean;
|
|
26
|
+
/** 节点密度阈值(节点数/10000平方像素) */
|
|
27
|
+
threshold: number;
|
|
28
|
+
};
|
|
29
|
+
/** 基于距离的调整配置 */
|
|
30
|
+
distanceBased: {
|
|
31
|
+
enabled: boolean;
|
|
32
|
+
/** 短路径阈值(像素) */
|
|
33
|
+
shortPathThreshold: number;
|
|
34
|
+
/** 长路径阈值(像素) */
|
|
35
|
+
longPathThreshold: number;
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* 默认自适应步长配置
|
|
40
|
+
*/
|
|
41
|
+
export declare const DEFAULT_ADAPTIVE_STEP_CONFIG: AdaptiveStepConfig;
|
|
42
|
+
/**
|
|
43
|
+
* 自适应步长计算器
|
|
44
|
+
*/
|
|
45
|
+
export declare class AdaptiveStepCalculator {
|
|
46
|
+
private config;
|
|
47
|
+
constructor(config?: Partial<AdaptiveStepConfig>);
|
|
48
|
+
/**
|
|
49
|
+
* 合并配置与默认值
|
|
50
|
+
*/
|
|
51
|
+
private mergeConfig;
|
|
52
|
+
/**
|
|
53
|
+
* 计算节点密度
|
|
54
|
+
* @param nodeLookup 节点查找表
|
|
55
|
+
* @returns 密度值(节点数/10000平方像素)
|
|
56
|
+
*/
|
|
57
|
+
calculateNodeDensity(nodeLookup: NodeLookup): number;
|
|
58
|
+
/**
|
|
59
|
+
* 计算两点之间的曼哈顿距离
|
|
60
|
+
*/
|
|
61
|
+
calculateDistance(source: Point | {
|
|
62
|
+
x: number;
|
|
63
|
+
y: number;
|
|
64
|
+
}, target: Point | {
|
|
65
|
+
x: number;
|
|
66
|
+
y: number;
|
|
67
|
+
}): number;
|
|
68
|
+
/**
|
|
69
|
+
* 基于距离计算步长
|
|
70
|
+
*/
|
|
71
|
+
calculateDistanceBasedStep(distance: number): number;
|
|
72
|
+
/**
|
|
73
|
+
* 基于密度计算步长
|
|
74
|
+
*/
|
|
75
|
+
calculateDensityBasedStep(density: number): number;
|
|
76
|
+
/**
|
|
77
|
+
* 计算自适应步长
|
|
78
|
+
* 综合考虑距离和密度因素
|
|
79
|
+
*/
|
|
80
|
+
calculateStep(sourceNode: InternalNode, targetNode: InternalNode, nodeLookup: NodeLookup): number;
|
|
81
|
+
/**
|
|
82
|
+
* 获取当前配置
|
|
83
|
+
*/
|
|
84
|
+
getConfig(): AdaptiveStepConfig;
|
|
85
|
+
/**
|
|
86
|
+
* 更新配置
|
|
87
|
+
*/
|
|
88
|
+
updateConfig(config: Partial<AdaptiveStepConfig>): void;
|
|
89
|
+
}
|
|
90
|
+
//# sourceMappingURL=AdaptiveStepCalculator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AdaptiveStepCalculator.d.ts","sourceRoot":"","sources":["../../src/utils/AdaptiveStepCalculator.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAChE,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAA;AAEnC;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,gBAAgB;IAChB,OAAO,EAAE,OAAO,CAAA;IAChB,WAAW;IACX,OAAO,EAAE,MAAM,CAAA;IACf,WAAW;IACX,OAAO,EAAE,MAAM,CAAA;IACf,gBAAgB;IAChB,YAAY,EAAE;QACZ,OAAO,EAAE,OAAO,CAAA;QAChB,4BAA4B;QAC5B,SAAS,EAAE,MAAM,CAAA;KAClB,CAAA;IACD,gBAAgB;IAChB,aAAa,EAAE;QACb,OAAO,EAAE,OAAO,CAAA;QAChB,gBAAgB;QAChB,kBAAkB,EAAE,MAAM,CAAA;QAC1B,gBAAgB;QAChB,iBAAiB,EAAE,MAAM,CAAA;KAC1B,CAAA;CACF;AAED;;GAEG;AACH,eAAO,MAAM,4BAA4B,EAAE,kBAa1C,CAAA;AAED;;GAEG;AACH,qBAAa,sBAAsB;IACjC,OAAO,CAAC,MAAM,CAAoB;gBAEtB,MAAM,GAAE,OAAO,CAAC,kBAAkB,CAAM;IAIpD;;OAEG;IACH,OAAO,CAAC,WAAW;IAiBnB;;;;OAIG;IACH,oBAAoB,CAAC,UAAU,EAAE,UAAU,GAAG,MAAM;IA2BpD;;OAEG;IACH,iBAAiB,CAAC,MAAM,EAAE,KAAK,GAAG;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAA;KAAE,EAAE,MAAM,EAAE,KAAK,GAAG;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,MAAM;IAI7G;;OAEG;IACH,0BAA0B,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM;IAsBpD;;OAEG;IACH,yBAAyB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM;IAsBlD;;;OAGG;IACH,aAAa,CACX,UAAU,EAAE,YAAY,EACxB,UAAU,EAAE,YAAY,EACxB,UAAU,EAAE,UAAU,GACrB,MAAM;IAyCT;;OAEG;IACH,SAAS,IAAI,kBAAkB;IAI/B;;OAEG;IACH,YAAY,CAAC,MAAM,EAAE,OAAO,CAAC,kBAAkB,CAAC,GAAG,IAAI;CAGxD"}
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.DEFAULT_ADAPTIVE_STEP_CONFIG = exports.AdaptiveStepCalculator = void 0;
|
|
7
|
+
/**
|
|
8
|
+
* AdaptiveStepCalculator - 自适应步长计算器
|
|
9
|
+
*
|
|
10
|
+
* 根据场景自动调整网格步长,平衡性能和路径质量
|
|
11
|
+
* - 高密度区域使用小步长,提高路径精度
|
|
12
|
+
* - 长距离路径使用大步长,提高计算性能
|
|
13
|
+
*
|
|
14
|
+
* Feature: manhattan-optimization
|
|
15
|
+
* Requirements: 2.3, 2.4
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* 自适应步长配置
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* 默认自适应步长配置
|
|
24
|
+
*/
|
|
25
|
+
const DEFAULT_ADAPTIVE_STEP_CONFIG = exports.DEFAULT_ADAPTIVE_STEP_CONFIG = {
|
|
26
|
+
enabled: false,
|
|
27
|
+
minStep: 5,
|
|
28
|
+
maxStep: 20,
|
|
29
|
+
densityBased: {
|
|
30
|
+
enabled: true,
|
|
31
|
+
threshold: 0.5 // 每10000平方像素0.5个节点
|
|
32
|
+
},
|
|
33
|
+
distanceBased: {
|
|
34
|
+
enabled: true,
|
|
35
|
+
shortPathThreshold: 200,
|
|
36
|
+
longPathThreshold: 800
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* 自适应步长计算器
|
|
42
|
+
*/
|
|
43
|
+
class AdaptiveStepCalculator {
|
|
44
|
+
config;
|
|
45
|
+
constructor(config = {}) {
|
|
46
|
+
this.config = this.mergeConfig(config);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* 合并配置与默认值
|
|
51
|
+
*/
|
|
52
|
+
mergeConfig(config) {
|
|
53
|
+
return {
|
|
54
|
+
enabled: config.enabled ?? DEFAULT_ADAPTIVE_STEP_CONFIG.enabled,
|
|
55
|
+
minStep: config.minStep ?? DEFAULT_ADAPTIVE_STEP_CONFIG.minStep,
|
|
56
|
+
maxStep: config.maxStep ?? DEFAULT_ADAPTIVE_STEP_CONFIG.maxStep,
|
|
57
|
+
densityBased: {
|
|
58
|
+
enabled: config.densityBased?.enabled ?? DEFAULT_ADAPTIVE_STEP_CONFIG.densityBased.enabled,
|
|
59
|
+
threshold: config.densityBased?.threshold ?? DEFAULT_ADAPTIVE_STEP_CONFIG.densityBased.threshold
|
|
60
|
+
},
|
|
61
|
+
distanceBased: {
|
|
62
|
+
enabled: config.distanceBased?.enabled ?? DEFAULT_ADAPTIVE_STEP_CONFIG.distanceBased.enabled,
|
|
63
|
+
shortPathThreshold: config.distanceBased?.shortPathThreshold ?? DEFAULT_ADAPTIVE_STEP_CONFIG.distanceBased.shortPathThreshold,
|
|
64
|
+
longPathThreshold: config.distanceBased?.longPathThreshold ?? DEFAULT_ADAPTIVE_STEP_CONFIG.distanceBased.longPathThreshold
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* 计算节点密度
|
|
71
|
+
* @param nodeLookup 节点查找表
|
|
72
|
+
* @returns 密度值(节点数/10000平方像素)
|
|
73
|
+
*/
|
|
74
|
+
calculateNodeDensity(nodeLookup) {
|
|
75
|
+
if (nodeLookup.size === 0) return 0;
|
|
76
|
+
let minX = Infinity,
|
|
77
|
+
minY = Infinity;
|
|
78
|
+
let maxX = -Infinity,
|
|
79
|
+
maxY = -Infinity;
|
|
80
|
+
for (const node of nodeLookup.values()) {
|
|
81
|
+
const pos = node.internals?.positionAbsolute ?? node.position;
|
|
82
|
+
const width = node.measured?.width ?? node.width ?? 100;
|
|
83
|
+
const height = node.measured?.height ?? node.height ?? 50;
|
|
84
|
+
minX = Math.min(minX, pos.x);
|
|
85
|
+
minY = Math.min(minY, pos.y);
|
|
86
|
+
maxX = Math.max(maxX, pos.x + width);
|
|
87
|
+
maxY = Math.max(maxY, pos.y + height);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// 计算边界框面积(以10000平方像素为单位)
|
|
91
|
+
const width = maxX - minX;
|
|
92
|
+
const height = maxY - minY;
|
|
93
|
+
const area = width * height / 10000;
|
|
94
|
+
if (area <= 0) return 0;
|
|
95
|
+
return nodeLookup.size / area;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* 计算两点之间的曼哈顿距离
|
|
100
|
+
*/
|
|
101
|
+
calculateDistance(source, target) {
|
|
102
|
+
return Math.abs(target.x - source.x) + Math.abs(target.y - source.y);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* 基于距离计算步长
|
|
107
|
+
*/
|
|
108
|
+
calculateDistanceBasedStep(distance) {
|
|
109
|
+
const {
|
|
110
|
+
minStep,
|
|
111
|
+
maxStep,
|
|
112
|
+
distanceBased
|
|
113
|
+
} = this.config;
|
|
114
|
+
if (!distanceBased.enabled) {
|
|
115
|
+
return minStep;
|
|
116
|
+
}
|
|
117
|
+
const {
|
|
118
|
+
shortPathThreshold,
|
|
119
|
+
longPathThreshold
|
|
120
|
+
} = distanceBased;
|
|
121
|
+
if (distance <= shortPathThreshold) {
|
|
122
|
+
return minStep;
|
|
123
|
+
}
|
|
124
|
+
if (distance >= longPathThreshold) {
|
|
125
|
+
return maxStep;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// 线性插值
|
|
129
|
+
const ratio = (distance - shortPathThreshold) / (longPathThreshold - shortPathThreshold);
|
|
130
|
+
return Math.round(minStep + ratio * (maxStep - minStep));
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* 基于密度计算步长
|
|
135
|
+
*/
|
|
136
|
+
calculateDensityBasedStep(density) {
|
|
137
|
+
const {
|
|
138
|
+
minStep,
|
|
139
|
+
maxStep,
|
|
140
|
+
densityBased
|
|
141
|
+
} = this.config;
|
|
142
|
+
if (!densityBased.enabled) {
|
|
143
|
+
return maxStep;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// 高密度使用小步长
|
|
147
|
+
if (density >= densityBased.threshold) {
|
|
148
|
+
return minStep;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// 低密度使用大步长
|
|
152
|
+
if (density <= densityBased.threshold / 2) {
|
|
153
|
+
return maxStep;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// 线性插值
|
|
157
|
+
const ratio = (densityBased.threshold - density) / (densityBased.threshold / 2);
|
|
158
|
+
return Math.round(minStep + ratio * (maxStep - minStep));
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* 计算自适应步长
|
|
163
|
+
* 综合考虑距离和密度因素
|
|
164
|
+
*/
|
|
165
|
+
calculateStep(sourceNode, targetNode, nodeLookup) {
|
|
166
|
+
if (!this.config.enabled) {
|
|
167
|
+
return this.config.minStep;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// 获取源和目标位置
|
|
171
|
+
const sourcePos = sourceNode.internals?.positionAbsolute ?? sourceNode.position;
|
|
172
|
+
const targetPos = targetNode.internals?.positionAbsolute ?? targetNode.position;
|
|
173
|
+
|
|
174
|
+
// 计算节点中心点
|
|
175
|
+
const sourceWidth = sourceNode.measured?.width ?? sourceNode.width ?? 100;
|
|
176
|
+
const sourceHeight = sourceNode.measured?.height ?? sourceNode.height ?? 50;
|
|
177
|
+
const targetWidth = targetNode.measured?.width ?? targetNode.width ?? 100;
|
|
178
|
+
const targetHeight = targetNode.measured?.height ?? targetNode.height ?? 50;
|
|
179
|
+
const sourceCenter = {
|
|
180
|
+
x: sourcePos.x + sourceWidth / 2,
|
|
181
|
+
y: sourcePos.y + sourceHeight / 2
|
|
182
|
+
};
|
|
183
|
+
const targetCenter = {
|
|
184
|
+
x: targetPos.x + targetWidth / 2,
|
|
185
|
+
y: targetPos.y + targetHeight / 2
|
|
186
|
+
};
|
|
187
|
+
|
|
188
|
+
// 计算距离
|
|
189
|
+
const distance = this.calculateDistance(sourceCenter, targetCenter);
|
|
190
|
+
|
|
191
|
+
// 计算密度
|
|
192
|
+
const density = this.calculateNodeDensity(nodeLookup);
|
|
193
|
+
|
|
194
|
+
// 获取基于距离和密度的步长
|
|
195
|
+
const distanceStep = this.calculateDistanceBasedStep(distance);
|
|
196
|
+
const densityStep = this.calculateDensityBasedStep(density);
|
|
197
|
+
|
|
198
|
+
// 取两者中较小的值(更保守的选择)
|
|
199
|
+
const step = Math.min(distanceStep, densityStep);
|
|
200
|
+
|
|
201
|
+
// 确保步长在有效范围内
|
|
202
|
+
return Math.max(this.config.minStep, Math.min(this.config.maxStep, step));
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* 获取当前配置
|
|
207
|
+
*/
|
|
208
|
+
getConfig() {
|
|
209
|
+
return {
|
|
210
|
+
...this.config
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* 更新配置
|
|
216
|
+
*/
|
|
217
|
+
updateConfig(config) {
|
|
218
|
+
this.config = this.mergeConfig({
|
|
219
|
+
...this.config,
|
|
220
|
+
...config
|
|
221
|
+
});
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
exports.AdaptiveStepCalculator = AdaptiveStepCalculator;
|