@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,328 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.ObstacleMap = void 0;
|
|
7
|
+
var _geometry = require("../geometry");
|
|
8
|
+
var _utils = require("../utils");
|
|
9
|
+
var _QuadTree = require("./QuadTree");
|
|
10
|
+
/**
|
|
11
|
+
* ObstacleMap class for managing obstacles in pathfinding
|
|
12
|
+
* Feature: manhattan-optimization
|
|
13
|
+
*
|
|
14
|
+
* Uses QuadTree for efficient spatial queries (O(log n) instead of O(n))
|
|
15
|
+
* Includes query caching for repeated accessibility checks
|
|
16
|
+
*/
|
|
17
|
+
class ObstacleMap {
|
|
18
|
+
options;
|
|
19
|
+
quadTree = null;
|
|
20
|
+
obstacles = [];
|
|
21
|
+
sourceAnchor;
|
|
22
|
+
targetAnchor;
|
|
23
|
+
|
|
24
|
+
// Query cache for repeated accessibility checks
|
|
25
|
+
accessibilityCache = new Map();
|
|
26
|
+
cacheHits = 0;
|
|
27
|
+
cacheMisses = 0;
|
|
28
|
+
constructor(options) {
|
|
29
|
+
this.options = options;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Get cache statistics for performance monitoring
|
|
34
|
+
*/
|
|
35
|
+
getCacheStats() {
|
|
36
|
+
const total = this.cacheHits + this.cacheMisses;
|
|
37
|
+
return {
|
|
38
|
+
hits: this.cacheHits,
|
|
39
|
+
misses: this.cacheMisses,
|
|
40
|
+
hitRate: total > 0 ? this.cacheHits / total : 0
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Clear the accessibility cache
|
|
46
|
+
*/
|
|
47
|
+
clearCache() {
|
|
48
|
+
this.accessibilityCache.clear();
|
|
49
|
+
this.cacheHits = 0;
|
|
50
|
+
this.cacheMisses = 0;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Build obstacle map from node lookup using QuadTree
|
|
55
|
+
*/
|
|
56
|
+
build(nodeLookup, sourceNodeId, targetNodeId, sourceAnchor, targetAnchor) {
|
|
57
|
+
const {
|
|
58
|
+
excludeNodes,
|
|
59
|
+
excludeShapes,
|
|
60
|
+
excludeTerminals,
|
|
61
|
+
paddingBox
|
|
62
|
+
} = this.options;
|
|
63
|
+
|
|
64
|
+
// Store anchors for later use in isAccessible
|
|
65
|
+
this.sourceAnchor = sourceAnchor;
|
|
66
|
+
this.targetAnchor = targetAnchor;
|
|
67
|
+
|
|
68
|
+
// Clear previous data
|
|
69
|
+
this.obstacles = [];
|
|
70
|
+
this.clearCache();
|
|
71
|
+
|
|
72
|
+
// Collect all obstacles
|
|
73
|
+
nodeLookup.forEach(node => {
|
|
74
|
+
// Check if node should be excluded
|
|
75
|
+
const isExcludedNode = excludeNodes.includes(node.id);
|
|
76
|
+
const isExcludedShape = node.type ? excludeShapes.includes(node.type) : false;
|
|
77
|
+
const isSourceTerminal = excludeTerminals.includes('source') && node.id === sourceNodeId;
|
|
78
|
+
const isTargetTerminal = excludeTerminals.includes('target') && node.id === targetNodeId;
|
|
79
|
+
|
|
80
|
+
// Skip if node should be excluded
|
|
81
|
+
if (isExcludedNode || isExcludedShape || isSourceTerminal || isTargetTerminal) {
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// Calculate node bounding box with padding
|
|
86
|
+
const position = (0, _utils.getNodePosition)(node);
|
|
87
|
+
const dimensions = (0, _utils.getNodeDimensions)(node);
|
|
88
|
+
const bbox = new _geometry.Rectangle(position.x, position.y, dimensions.width, dimensions.height).moveAndExpand(paddingBox);
|
|
89
|
+
this.obstacles.push({
|
|
90
|
+
bounds: bbox,
|
|
91
|
+
nodeId: node.id
|
|
92
|
+
});
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
// Build QuadTree from obstacles
|
|
96
|
+
this.quadTree = (0, _QuadTree.createQuadTreeFromRects)(this.obstacles.map(o => ({
|
|
97
|
+
bounds: o.bounds,
|
|
98
|
+
data: o.nodeId
|
|
99
|
+
})));
|
|
100
|
+
return this;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Check if a point is accessible (not inside any obstacle)
|
|
105
|
+
* Uses QuadTree for efficient spatial queries with caching
|
|
106
|
+
*/
|
|
107
|
+
isAccessible(point, checkRadius = 0) {
|
|
108
|
+
// Generate cache key
|
|
109
|
+
const cacheKey = `${point.x},${point.y},${checkRadius}`;
|
|
110
|
+
|
|
111
|
+
// Check cache first
|
|
112
|
+
if (this.accessibilityCache.has(cacheKey)) {
|
|
113
|
+
this.cacheHits++;
|
|
114
|
+
return this.accessibilityCache.get(cacheKey);
|
|
115
|
+
}
|
|
116
|
+
this.cacheMisses++;
|
|
117
|
+
|
|
118
|
+
// Check if point is near an anchor - if so, allow it
|
|
119
|
+
const margin = (this.options.step || 10) * 3;
|
|
120
|
+
if (this.sourceAnchor) {
|
|
121
|
+
const distToSource = Math.abs(point.x - this.sourceAnchor.x) + Math.abs(point.y - this.sourceAnchor.y);
|
|
122
|
+
if (distToSource < margin) {
|
|
123
|
+
this.accessibilityCache.set(cacheKey, true);
|
|
124
|
+
return true;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
if (this.targetAnchor) {
|
|
128
|
+
const distToTarget = Math.abs(point.x - this.targetAnchor.x) + Math.abs(point.y - this.targetAnchor.y);
|
|
129
|
+
if (distToTarget < margin) {
|
|
130
|
+
this.accessibilityCache.set(cacheKey, true);
|
|
131
|
+
return true;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// If no QuadTree, point is accessible
|
|
136
|
+
if (!this.quadTree) {
|
|
137
|
+
this.accessibilityCache.set(cacheKey, true);
|
|
138
|
+
return true;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// Query QuadTree for obstacles at this point
|
|
142
|
+
const obstacles = this.quadTree.queryPoint(point);
|
|
143
|
+
|
|
144
|
+
// If checkRadius is specified, use binary search to find accessible points
|
|
145
|
+
if (checkRadius > 0 && obstacles.length > 0) {
|
|
146
|
+
const result = this.isAccessibleWithBinarySearch(point, checkRadius, obstacles.map(o => o.bounds));
|
|
147
|
+
this.accessibilityCache.set(cacheKey, result);
|
|
148
|
+
return result;
|
|
149
|
+
}
|
|
150
|
+
const accessible = obstacles.length === 0;
|
|
151
|
+
this.accessibilityCache.set(cacheKey, accessible);
|
|
152
|
+
return accessible;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Check if an anchor point has sufficient clearance around it
|
|
157
|
+
* This ensures the path can start/end at the anchor without being blocked
|
|
158
|
+
*/
|
|
159
|
+
hasAnchorClearance(anchor, direction) {
|
|
160
|
+
const step = this.options.step || 10;
|
|
161
|
+
const clearanceDistance = step * 2;
|
|
162
|
+
|
|
163
|
+
// Direction vectors
|
|
164
|
+
const directionVectors = {
|
|
165
|
+
top: {
|
|
166
|
+
dx: 0,
|
|
167
|
+
dy: -1
|
|
168
|
+
},
|
|
169
|
+
right: {
|
|
170
|
+
dx: 1,
|
|
171
|
+
dy: 0
|
|
172
|
+
},
|
|
173
|
+
bottom: {
|
|
174
|
+
dx: 0,
|
|
175
|
+
dy: 1
|
|
176
|
+
},
|
|
177
|
+
left: {
|
|
178
|
+
dx: -1,
|
|
179
|
+
dy: 0
|
|
180
|
+
}
|
|
181
|
+
};
|
|
182
|
+
const dir = directionVectors[direction];
|
|
183
|
+
if (!dir) return true;
|
|
184
|
+
|
|
185
|
+
// Check points along the direction
|
|
186
|
+
for (let dist = step; dist <= clearanceDistance; dist += step) {
|
|
187
|
+
const testPoint = new _geometry.Point(anchor.x + dir.dx * dist, anchor.y + dir.dy * dist);
|
|
188
|
+
|
|
189
|
+
// Temporarily remove anchor from consideration
|
|
190
|
+
const originalSourceAnchor = this.sourceAnchor;
|
|
191
|
+
const originalTargetAnchor = this.targetAnchor;
|
|
192
|
+
this.sourceAnchor = undefined;
|
|
193
|
+
this.targetAnchor = undefined;
|
|
194
|
+
const accessible = this.isAccessibleWithoutCache(testPoint);
|
|
195
|
+
|
|
196
|
+
// Restore anchors
|
|
197
|
+
this.sourceAnchor = originalSourceAnchor;
|
|
198
|
+
this.targetAnchor = originalTargetAnchor;
|
|
199
|
+
if (!accessible) {
|
|
200
|
+
return false;
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
return true;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* Check accessibility without using cache (for internal use)
|
|
208
|
+
*/
|
|
209
|
+
isAccessibleWithoutCache(point) {
|
|
210
|
+
if (!this.quadTree) {
|
|
211
|
+
return true;
|
|
212
|
+
}
|
|
213
|
+
const obstacles = this.quadTree.queryPoint(point);
|
|
214
|
+
return obstacles.length === 0;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* Find the nearest accessible point from an anchor in a given direction
|
|
219
|
+
* Uses binary search for efficiency
|
|
220
|
+
*/
|
|
221
|
+
findNearestAccessiblePoint(anchor, direction, maxDistance) {
|
|
222
|
+
const directionVectors = {
|
|
223
|
+
top: {
|
|
224
|
+
dx: 0,
|
|
225
|
+
dy: -1
|
|
226
|
+
},
|
|
227
|
+
right: {
|
|
228
|
+
dx: 1,
|
|
229
|
+
dy: 0
|
|
230
|
+
},
|
|
231
|
+
bottom: {
|
|
232
|
+
dx: 0,
|
|
233
|
+
dy: 1
|
|
234
|
+
},
|
|
235
|
+
left: {
|
|
236
|
+
dx: -1,
|
|
237
|
+
dy: 0
|
|
238
|
+
}
|
|
239
|
+
};
|
|
240
|
+
const dir = directionVectors[direction];
|
|
241
|
+
if (!dir) return null;
|
|
242
|
+
const step = this.options.step || 10;
|
|
243
|
+
|
|
244
|
+
// First, find an accessible point using linear search
|
|
245
|
+
let foundDistance = -1;
|
|
246
|
+
for (let dist = step; dist <= maxDistance; dist += step) {
|
|
247
|
+
const testPoint = new _geometry.Point(anchor.x + dir.dx * dist, anchor.y + dir.dy * dist);
|
|
248
|
+
if (this.isAccessible(testPoint)) {
|
|
249
|
+
foundDistance = dist;
|
|
250
|
+
break;
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
if (foundDistance < 0) {
|
|
254
|
+
return null;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
// Binary search to find the closest accessible point
|
|
258
|
+
let left = Math.max(0, foundDistance - step);
|
|
259
|
+
let right = foundDistance;
|
|
260
|
+
let bestDistance = foundDistance;
|
|
261
|
+
while (right - left > 1) {
|
|
262
|
+
const mid = Math.floor((left + right) / 2);
|
|
263
|
+
const testPoint = new _geometry.Point(anchor.x + dir.dx * mid, anchor.y + dir.dy * mid);
|
|
264
|
+
if (this.isAccessible(testPoint)) {
|
|
265
|
+
bestDistance = mid;
|
|
266
|
+
right = mid;
|
|
267
|
+
} else {
|
|
268
|
+
left = mid;
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
return new _geometry.Point(anchor.x + dir.dx * bestDistance, anchor.y + dir.dy * bestDistance);
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
/**
|
|
275
|
+
* Batch check accessibility for multiple points (optimized)
|
|
276
|
+
* Returns array of booleans in same order as input points
|
|
277
|
+
*/
|
|
278
|
+
areAccessible(points) {
|
|
279
|
+
return points.map(point => this.isAccessible(point));
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
/**
|
|
283
|
+
* Check accessibility using binary search optimization
|
|
284
|
+
* Tries step -> step/2 -> step/4 -> ... -> 1px
|
|
285
|
+
*/
|
|
286
|
+
isAccessibleWithBinarySearch(point, maxRadius, rects) {
|
|
287
|
+
// First check the point itself
|
|
288
|
+
if (rects.every(rect => !rect.containsPoint(point))) {
|
|
289
|
+
return true;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
// Binary search: start with step, then halve until we reach 1px
|
|
293
|
+
let radius = maxRadius;
|
|
294
|
+
const offsets = [{
|
|
295
|
+
dx: 1,
|
|
296
|
+
dy: 0
|
|
297
|
+
},
|
|
298
|
+
// right
|
|
299
|
+
{
|
|
300
|
+
dx: -1,
|
|
301
|
+
dy: 0
|
|
302
|
+
},
|
|
303
|
+
// left
|
|
304
|
+
{
|
|
305
|
+
dx: 0,
|
|
306
|
+
dy: 1
|
|
307
|
+
},
|
|
308
|
+
// down
|
|
309
|
+
{
|
|
310
|
+
dx: 0,
|
|
311
|
+
dy: -1
|
|
312
|
+
} // up
|
|
313
|
+
];
|
|
314
|
+
while (radius >= 1) {
|
|
315
|
+
for (const offset of offsets) {
|
|
316
|
+
const testPoint = new _geometry.Point(point.x + offset.dx * radius, point.y + offset.dy * radius);
|
|
317
|
+
if (rects.every(rect => !rect.containsPoint(testPoint))) {
|
|
318
|
+
return true;
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
// Halve the radius for next iteration
|
|
323
|
+
radius = Math.floor(radius / 2);
|
|
324
|
+
}
|
|
325
|
+
return false;
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
exports.ObstacleMap = ObstacleMap;
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* QuadTree implementation for efficient spatial queries
|
|
3
|
+
* Feature: manhattan-optimization
|
|
4
|
+
*
|
|
5
|
+
* A QuadTree is a tree data structure that recursively subdivides 2D space
|
|
6
|
+
* into four quadrants. This enables O(log n) spatial queries instead of O(n).
|
|
7
|
+
*/
|
|
8
|
+
import { Point, Rectangle } from '../geometry';
|
|
9
|
+
/**
|
|
10
|
+
* Item stored in the QuadTree
|
|
11
|
+
*/
|
|
12
|
+
export interface QuadTreeItem<T> {
|
|
13
|
+
bounds: Rectangle;
|
|
14
|
+
data: T;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* QuadTree configuration
|
|
18
|
+
*/
|
|
19
|
+
export interface QuadTreeConfig {
|
|
20
|
+
/** Maximum items per node before splitting */
|
|
21
|
+
maxItems: number;
|
|
22
|
+
/** Maximum depth of the tree */
|
|
23
|
+
maxDepth: number;
|
|
24
|
+
/** Minimum node size (prevents infinite subdivision) */
|
|
25
|
+
minSize: number;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* QuadTree node for spatial partitioning
|
|
29
|
+
*/
|
|
30
|
+
export declare class QuadTree<T> {
|
|
31
|
+
private bounds;
|
|
32
|
+
private items;
|
|
33
|
+
private children;
|
|
34
|
+
private depth;
|
|
35
|
+
private config;
|
|
36
|
+
constructor(bounds: Rectangle, config?: Partial<QuadTreeConfig>, depth?: number);
|
|
37
|
+
/**
|
|
38
|
+
* Insert an item into the QuadTree
|
|
39
|
+
*/
|
|
40
|
+
insert(item: QuadTreeItem<T>): boolean;
|
|
41
|
+
/**
|
|
42
|
+
* Insert an item with just bounds and data
|
|
43
|
+
*/
|
|
44
|
+
insertRect(bounds: Rectangle, data: T): boolean;
|
|
45
|
+
/**
|
|
46
|
+
* Query all items that intersect with the given bounds
|
|
47
|
+
*/
|
|
48
|
+
query(bounds: Rectangle): QuadTreeItem<T>[];
|
|
49
|
+
/**
|
|
50
|
+
* Query all items that contain the given point
|
|
51
|
+
*/
|
|
52
|
+
queryPoint(point: Point): QuadTreeItem<T>[];
|
|
53
|
+
/**
|
|
54
|
+
* Get all items in the tree
|
|
55
|
+
*/
|
|
56
|
+
getAllItems(): QuadTreeItem<T>[];
|
|
57
|
+
/**
|
|
58
|
+
* Clear all items from the tree
|
|
59
|
+
*/
|
|
60
|
+
clear(): void;
|
|
61
|
+
/**
|
|
62
|
+
* Get the total number of items in the tree
|
|
63
|
+
*/
|
|
64
|
+
get size(): number;
|
|
65
|
+
/**
|
|
66
|
+
* Get the depth of the tree
|
|
67
|
+
*/
|
|
68
|
+
getMaxDepth(): number;
|
|
69
|
+
/**
|
|
70
|
+
* Internal query implementation
|
|
71
|
+
*/
|
|
72
|
+
private queryInternal;
|
|
73
|
+
/**
|
|
74
|
+
* Internal point query implementation
|
|
75
|
+
*/
|
|
76
|
+
private queryPointInternal;
|
|
77
|
+
/**
|
|
78
|
+
* Check if this node should split
|
|
79
|
+
*/
|
|
80
|
+
private shouldSplit;
|
|
81
|
+
/**
|
|
82
|
+
* Split this node into four children
|
|
83
|
+
*/
|
|
84
|
+
private split;
|
|
85
|
+
/**
|
|
86
|
+
* Insert item into appropriate children
|
|
87
|
+
*/
|
|
88
|
+
private insertIntoChildren;
|
|
89
|
+
/**
|
|
90
|
+
* Check if a rectangle intersects this node's bounds
|
|
91
|
+
*/
|
|
92
|
+
private intersects;
|
|
93
|
+
/**
|
|
94
|
+
* Check if two rectangles intersect
|
|
95
|
+
*/
|
|
96
|
+
private rectanglesIntersect;
|
|
97
|
+
/**
|
|
98
|
+
* Check if this node's bounds contain a point
|
|
99
|
+
*/
|
|
100
|
+
private containsPoint;
|
|
101
|
+
/**
|
|
102
|
+
* Get statistics about the tree
|
|
103
|
+
*/
|
|
104
|
+
getStats(): {
|
|
105
|
+
totalItems: number;
|
|
106
|
+
maxDepth: number;
|
|
107
|
+
nodeCount: number;
|
|
108
|
+
itemsPerNode: number;
|
|
109
|
+
};
|
|
110
|
+
private collectStats;
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Create a QuadTree with bounds that cover all given rectangles
|
|
114
|
+
*/
|
|
115
|
+
export declare function createQuadTreeFromRects<T>(items: Array<{
|
|
116
|
+
bounds: Rectangle;
|
|
117
|
+
data: T;
|
|
118
|
+
}>, config?: Partial<QuadTreeConfig>): QuadTree<T>;
|
|
119
|
+
//# sourceMappingURL=QuadTree.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"QuadTree.d.ts","sourceRoot":"","sources":["../../src/obstacle/QuadTree.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AAE9C;;GAEG;AACH,MAAM,WAAW,YAAY,CAAC,CAAC;IAC7B,MAAM,EAAE,SAAS,CAAA;IACjB,IAAI,EAAE,CAAC,CAAA;CACR;AAED;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,8CAA8C;IAC9C,QAAQ,EAAE,MAAM,CAAA;IAChB,gCAAgC;IAChC,QAAQ,EAAE,MAAM,CAAA;IAChB,wDAAwD;IACxD,OAAO,EAAE,MAAM,CAAA;CAChB;AAWD;;GAEG;AACH,qBAAa,QAAQ,CAAC,CAAC;IACrB,OAAO,CAAC,MAAM,CAAW;IACzB,OAAO,CAAC,KAAK,CAAmB;IAChC,OAAO,CAAC,QAAQ,CAAsB;IACtC,OAAO,CAAC,KAAK,CAAQ;IACrB,OAAO,CAAC,MAAM,CAAgB;gBAG5B,MAAM,EAAE,SAAS,EACjB,MAAM,GAAE,OAAO,CAAC,cAAc,CAAM,EACpC,KAAK,GAAE,MAAU;IASnB;;OAEG;IACH,MAAM,CAAC,IAAI,EAAE,YAAY,CAAC,CAAC,CAAC,GAAG,OAAO;IAsBtC;;OAEG;IACH,UAAU,CAAC,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,GAAG,OAAO;IAI/C;;OAEG;IACH,KAAK,CAAC,MAAM,EAAE,SAAS,GAAG,YAAY,CAAC,CAAC,CAAC,EAAE;IAM3C;;OAEG;IACH,UAAU,CAAC,KAAK,EAAE,KAAK,GAAG,YAAY,CAAC,CAAC,CAAC,EAAE;IAM3C;;OAEG;IACH,WAAW,IAAI,YAAY,CAAC,CAAC,CAAC,EAAE;IAYhC;;OAEG;IACH,KAAK,IAAI,IAAI;IAKb;;OAEG;IACH,IAAI,IAAI,IAAI,MAAM,CAUjB;IAED;;OAEG;IACH,WAAW,IAAI,MAAM;IAarB;;OAEG;IACH,OAAO,CAAC,aAAa;IAqBrB;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAqB1B;;OAEG;IACH,OAAO,CAAC,WAAW;IASnB;;OAEG;IACH,OAAO,CAAC,KAAK;IA2Cb;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAqB1B;;OAEG;IACH,OAAO,CAAC,UAAU;IAIlB;;OAEG;IACH,OAAO,CAAC,mBAAmB;IAS3B;;OAEG;IACH,OAAO,CAAC,aAAa;IASrB;;OAEG;IACH,QAAQ,IAAI;QACV,UAAU,EAAE,MAAM,CAAA;QAClB,QAAQ,EAAE,MAAM,CAAA;QAChB,SAAS,EAAE,MAAM,CAAA;QACjB,YAAY,EAAE,MAAM,CAAA;KACrB;IAcD,OAAO,CAAC,YAAY;CAerB;AAED;;GAEG;AACH,wBAAgB,uBAAuB,CAAC,CAAC,EACvC,KAAK,EAAE,KAAK,CAAC;IAAE,MAAM,EAAE,SAAS,CAAC;IAAC,IAAI,EAAE,CAAC,CAAA;CAAE,CAAC,EAC5C,MAAM,CAAC,EAAE,OAAO,CAAC,cAAc,CAAC,GAC/B,QAAQ,CAAC,CAAC,CAAC,CAkCb"}
|