@rxflow/manhattan 0.0.2-alpha.8 → 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/README.md +214 -10
- package/cjs/getManHattanPath.d.ts.map +1 -1
- package/cjs/getManHattanPath.js +77 -46
- package/cjs/obstacle/ObstacleMap.d.ts +41 -9
- package/cjs/obstacle/ObstacleMap.d.ts.map +1 -1
- package/cjs/obstacle/ObstacleMap.js +201 -96
- 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/options/defaults.d.ts +1 -1
- package/cjs/options/defaults.d.ts.map +1 -1
- package/cjs/options/resolver.d.ts.map +1 -1
- package/cjs/options/resolver.js +145 -17
- package/cjs/options/types.d.ts +41 -0
- package/cjs/options/types.d.ts.map +1 -1
- 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/findRoute.d.ts.map +1 -1
- package/cjs/pathfinder/findRoute.js +96 -31
- package/cjs/pathfinder/index.d.ts +1 -0
- package/cjs/pathfinder/index.d.ts.map +1 -1
- package/cjs/pathfinder/index.js +26 -1
- package/cjs/svg/pathConverter.d.ts +13 -0
- package/cjs/svg/pathConverter.d.ts.map +1 -1
- package/cjs/svg/pathConverter.js +170 -1
- 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/getAnchorPoints.d.ts.map +1 -1
- package/cjs/utils/getAnchorPoints.js +0 -4
- package/cjs/utils/grid.d.ts +15 -0
- package/cjs/utils/grid.d.ts.map +1 -1
- package/cjs/utils/grid.js +19 -12
- 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 +6 -0
- package/cjs/utils/index.d.ts.map +1 -1
- package/cjs/utils/index.js +66 -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.map +1 -1
- package/cjs/utils/pathValidation.js +0 -1
- package/cjs/utils/rect.d.ts.map +1 -1
- package/cjs/utils/rect.js +7 -0
- package/cjs/utils/route.d.ts.map +1 -1
- package/cjs/utils/route.js +18 -2
- package/esm/getManHattanPath.d.ts.map +1 -1
- package/esm/getManHattanPath.js +92 -69
- package/esm/obstacle/ObstacleMap.d.ts +41 -9
- package/esm/obstacle/ObstacleMap.d.ts.map +1 -1
- package/esm/obstacle/ObstacleMap.js +218 -99
- package/esm/obstacle/QuadTree.d.ts +119 -0
- package/esm/obstacle/QuadTree.d.ts.map +1 -0
- package/esm/obstacle/QuadTree.js +488 -0
- package/esm/options/defaults.d.ts +1 -1
- package/esm/options/defaults.d.ts.map +1 -1
- package/esm/options/resolver.d.ts.map +1 -1
- package/esm/options/resolver.js +147 -18
- package/esm/options/types.d.ts +41 -0
- package/esm/options/types.d.ts.map +1 -1
- package/esm/pathfinder/PathCache.d.ts +92 -0
- package/esm/pathfinder/PathCache.d.ts.map +1 -0
- package/esm/pathfinder/PathCache.js +278 -0
- package/esm/pathfinder/findRoute.d.ts.map +1 -1
- package/esm/pathfinder/findRoute.js +98 -44
- package/esm/pathfinder/index.d.ts +1 -0
- package/esm/pathfinder/index.d.ts.map +1 -1
- package/esm/pathfinder/index.js +2 -1
- package/esm/svg/pathConverter.d.ts +13 -0
- package/esm/svg/pathConverter.d.ts.map +1 -1
- package/esm/svg/pathConverter.js +170 -1
- package/esm/utils/AdaptiveStepCalculator.d.ts +90 -0
- package/esm/utils/AdaptiveStepCalculator.d.ts.map +1 -0
- package/esm/utils/AdaptiveStepCalculator.js +252 -0
- package/esm/utils/ErrorRecovery.d.ts +182 -0
- package/esm/utils/ErrorRecovery.d.ts.map +1 -0
- package/esm/utils/ErrorRecovery.js +499 -0
- package/esm/utils/GlobalGrid.d.ts +99 -0
- package/esm/utils/GlobalGrid.d.ts.map +1 -0
- package/esm/utils/GlobalGrid.js +259 -0
- package/esm/utils/PerformanceMonitor.d.ts +139 -0
- package/esm/utils/PerformanceMonitor.d.ts.map +1 -0
- package/esm/utils/PerformanceMonitor.js +360 -0
- package/esm/utils/getAnchorPoints.d.ts.map +1 -1
- package/esm/utils/getAnchorPoints.js +0 -4
- package/esm/utils/grid.d.ts +15 -0
- package/esm/utils/grid.d.ts.map +1 -1
- package/esm/utils/grid.js +18 -13
- package/esm/utils/heuristics.d.ts +61 -0
- package/esm/utils/heuristics.d.ts.map +1 -0
- package/esm/utils/heuristics.js +144 -0
- package/esm/utils/index.d.ts +6 -0
- package/esm/utils/index.d.ts.map +1 -1
- package/esm/utils/index.js +7 -1
- package/esm/utils/pathProcessing.d.ts +45 -0
- package/esm/utils/pathProcessing.d.ts.map +1 -0
- package/esm/utils/pathProcessing.js +270 -0
- package/esm/utils/pathValidation.d.ts.map +1 -1
- package/esm/utils/pathValidation.js +0 -1
- package/esm/utils/rect.d.ts.map +1 -1
- package/esm/utils/rect.js +11 -4
- package/esm/utils/route.d.ts.map +1 -1
- package/esm/utils/route.js +18 -2
- package/package.json +10 -2
package/README.md
CHANGED
|
@@ -2,33 +2,237 @@
|
|
|
2
2
|
|
|
3
3
|
Manhattan 路由算法,用于 ReactFlow 生成正交路径,支持障碍物避让。
|
|
4
4
|
|
|
5
|
+
## 特性
|
|
6
|
+
|
|
7
|
+
- **A* 寻路算法** - 高效的路径搜索,支持早期终止优化
|
|
8
|
+
- **正交路径生成** - 生成符合 Manhattan 风格的直角路径
|
|
9
|
+
- **障碍物避让** - 自动绕过节点障碍物
|
|
10
|
+
- **四叉树优化** - 使用 QuadTree 加速空间查询
|
|
11
|
+
- **自适应步长** - 根据节点密度和距离自动调整网格步长
|
|
12
|
+
- **路径缓存** - LRU 缓存机制提升重复查询性能
|
|
13
|
+
- **全局网格对齐** - 确保所有路径点对齐到全局网格
|
|
14
|
+
- **圆角支持** - 可配置的路径转角圆角半径
|
|
15
|
+
- **性能监控** - 内置性能指标收集和日志
|
|
16
|
+
|
|
5
17
|
## 安装
|
|
6
18
|
|
|
7
19
|
```bash
|
|
8
20
|
npm install @rxflow/manhattan
|
|
9
21
|
# or
|
|
10
22
|
pnpm add @rxflow/manhattan
|
|
23
|
+
yarn add @rxflow/manhattan
|
|
11
24
|
```
|
|
12
25
|
|
|
13
|
-
##
|
|
26
|
+
## 基本使用
|
|
14
27
|
|
|
15
28
|
```tsx
|
|
16
29
|
import { getManHattanPath } from '@rxflow/manhattan';
|
|
30
|
+
import { useReactFlow } from '@xyflow/react';
|
|
31
|
+
|
|
32
|
+
function CustomEdge({ id, sourceX, sourceY, targetX, targetY, sourcePosition, targetPosition, source, target }) {
|
|
33
|
+
const { getNodes } = useReactFlow();
|
|
34
|
+
const nodeLookup = new Map(getNodes().map(n => [n.id, n]));
|
|
35
|
+
|
|
36
|
+
const path = getManHattanPath({
|
|
37
|
+
sourceNodeId: source,
|
|
38
|
+
targetNodeId: target,
|
|
39
|
+
sourceX,
|
|
40
|
+
sourceY,
|
|
41
|
+
targetX,
|
|
42
|
+
targetY,
|
|
43
|
+
sourcePosition,
|
|
44
|
+
targetPosition,
|
|
45
|
+
nodeLookup,
|
|
46
|
+
options: {
|
|
47
|
+
step: 10,
|
|
48
|
+
borderRadius: 5,
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
return <path d={path} />;
|
|
53
|
+
}
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## API
|
|
57
|
+
|
|
58
|
+
### getManHattanPath(params)
|
|
59
|
+
|
|
60
|
+
生成 Manhattan 风格的 SVG 路径字符串。
|
|
61
|
+
|
|
62
|
+
#### 参数
|
|
63
|
+
|
|
64
|
+
| 参数 | 类型 | 必填 | 描述 |
|
|
65
|
+
|------|------|------|------|
|
|
66
|
+
| sourceNodeId | string | ✓ | 源节点 ID |
|
|
67
|
+
| targetNodeId | string | ✓ | 目标节点 ID |
|
|
68
|
+
| sourceX | number | ✓ | 源锚点 X 坐标 |
|
|
69
|
+
| sourceY | number | ✓ | 源锚点 Y 坐标 |
|
|
70
|
+
| targetX | number | ✓ | 目标锚点 X 坐标 |
|
|
71
|
+
| targetY | number | ✓ | 目标锚点 Y 坐标 |
|
|
72
|
+
| sourcePosition | Position | ✓ | 源锚点位置 (top/right/bottom/left) |
|
|
73
|
+
| targetPosition | Position | ✓ | 目标锚点位置 |
|
|
74
|
+
| nodeLookup | NodeLookup | ✓ | ReactFlow 节点查找 Map |
|
|
75
|
+
| options | ManhattanRouterOptions | - | 路由配置选项 |
|
|
76
|
+
|
|
77
|
+
#### 返回值
|
|
78
|
+
|
|
79
|
+
返回 SVG 路径字符串,可直接用于 `<path d={...} />` 元素。
|
|
17
80
|
|
|
81
|
+
### ManhattanRouterOptions
|
|
82
|
+
|
|
83
|
+
| 选项 | 类型 | 默认值 | 描述 |
|
|
84
|
+
|------|------|--------|------|
|
|
85
|
+
| step | number | 10 | 网格步长(像素) |
|
|
86
|
+
| maxLoopCount | number | 2000 | 最大迭代次数 |
|
|
87
|
+
| precision | number | 1 | 坐标精度(小数位数) |
|
|
88
|
+
| borderRadius | number | 5 | 转角圆角半径 |
|
|
89
|
+
| extensionDistance | number | 20 | 路径延伸距离 |
|
|
90
|
+
| padding | number \| object | 20 | 节点边界框内边距 |
|
|
91
|
+
| startDirections | Direction[] | ['top', 'right', 'bottom', 'left'] | 允许的起始方向 |
|
|
92
|
+
| endDirections | Direction[] | ['top', 'right', 'bottom', 'left'] | 允许的结束方向 |
|
|
93
|
+
| excludeNodes | string[] | [] | 排除的节点 ID |
|
|
94
|
+
| excludeShapes | string[] | [] | 排除的节点类型 |
|
|
95
|
+
| adaptiveStep | AdaptiveStepConfig | - | 自适应步长配置 |
|
|
96
|
+
| performance | PerformanceConfig | - | 性能优化配置 |
|
|
97
|
+
| debug | DebugConfig | - | 调试配置 |
|
|
98
|
+
|
|
99
|
+
### AdaptiveStepConfig
|
|
100
|
+
|
|
101
|
+
```typescript
|
|
102
|
+
interface AdaptiveStepConfig {
|
|
103
|
+
enabled: boolean; // 是否启用自适应步长
|
|
104
|
+
minStep: number; // 最小步长 (默认: 5)
|
|
105
|
+
maxStep: number; // 最大步长 (默认: 50)
|
|
106
|
+
densityThreshold: number; // 密度阈值 (默认: 0.3)
|
|
107
|
+
distanceThreshold: number; // 距离阈值 (默认: 500)
|
|
108
|
+
}
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
### PerformanceConfig
|
|
112
|
+
|
|
113
|
+
```typescript
|
|
114
|
+
interface PerformanceConfig {
|
|
115
|
+
enableCache: boolean; // 启用路径缓存
|
|
116
|
+
cacheSize: number; // 缓存大小 (默认: 100)
|
|
117
|
+
enableQuadTree: boolean; // 启用四叉树优化
|
|
118
|
+
earlyTermination: boolean; // 启用早期终止
|
|
119
|
+
}
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
### DebugConfig
|
|
123
|
+
|
|
124
|
+
```typescript
|
|
125
|
+
interface DebugConfig {
|
|
126
|
+
enableLogging: boolean; // 启用日志
|
|
127
|
+
enableMetrics: boolean; // 启用性能指标
|
|
128
|
+
logLevel: 'error' | 'warn' | 'info' | 'debug';
|
|
129
|
+
}
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
## 高级用法
|
|
133
|
+
|
|
134
|
+
### 自定义障碍物排除
|
|
135
|
+
|
|
136
|
+
```typescript
|
|
18
137
|
const path = getManHattanPath({
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
138
|
+
// ...基本参数
|
|
139
|
+
options: {
|
|
140
|
+
excludeNodes: ['node-3', 'node-4'], // 排除特定节点
|
|
141
|
+
excludeShapes: ['group'], // 排除特定类型
|
|
142
|
+
excludeTerminals: ['source'], // 排除源/目标节点
|
|
143
|
+
}
|
|
23
144
|
});
|
|
24
145
|
```
|
|
25
146
|
|
|
26
|
-
|
|
147
|
+
### 性能优化配置
|
|
27
148
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
149
|
+
```typescript
|
|
150
|
+
const path = getManHattanPath({
|
|
151
|
+
// ...基本参数
|
|
152
|
+
options: {
|
|
153
|
+
performance: {
|
|
154
|
+
enableCache: true,
|
|
155
|
+
cacheSize: 200,
|
|
156
|
+
enableQuadTree: true,
|
|
157
|
+
earlyTermination: true,
|
|
158
|
+
},
|
|
159
|
+
adaptiveStep: {
|
|
160
|
+
enabled: true,
|
|
161
|
+
minStep: 5,
|
|
162
|
+
maxStep: 30,
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
});
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
### 调试模式
|
|
169
|
+
|
|
170
|
+
```typescript
|
|
171
|
+
const path = getManHattanPath({
|
|
172
|
+
// ...基本参数
|
|
173
|
+
options: {
|
|
174
|
+
debug: {
|
|
175
|
+
enableLogging: true,
|
|
176
|
+
enableMetrics: true,
|
|
177
|
+
logLevel: 'debug',
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
});
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
## 工具类
|
|
184
|
+
|
|
185
|
+
### GlobalGrid
|
|
186
|
+
|
|
187
|
+
全局网格对齐工具,确保所有路径点对齐到统一网格。
|
|
188
|
+
|
|
189
|
+
```typescript
|
|
190
|
+
import { GlobalGrid } from '@rxflow/manhattan';
|
|
191
|
+
|
|
192
|
+
const grid = new GlobalGrid(10);
|
|
193
|
+
const snapped = grid.snapToGrid({ x: 15, y: 23 }); // { x: 20, y: 20 }
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
### ObstacleMap
|
|
197
|
+
|
|
198
|
+
障碍物地图,用于空间查询和碰撞检测。
|
|
199
|
+
|
|
200
|
+
```typescript
|
|
201
|
+
import { ObstacleMap } from '@rxflow/manhattan';
|
|
202
|
+
|
|
203
|
+
const map = new ObstacleMap(options);
|
|
204
|
+
map.build(nodeLookup, sourceId, targetId, sourceAnchor, targetAnchor);
|
|
205
|
+
const accessible = map.isAccessible(point);
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
### ErrorRecovery
|
|
209
|
+
|
|
210
|
+
错误恢复工具,提供回退路径生成。
|
|
211
|
+
|
|
212
|
+
```typescript
|
|
213
|
+
import { ErrorRecovery } from '@rxflow/manhattan';
|
|
214
|
+
|
|
215
|
+
const fallback = ErrorRecovery.generateFallbackPath(start, end);
|
|
216
|
+
const validated = ErrorRecovery.validateAndFixConfig(config);
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
## 架构
|
|
220
|
+
|
|
221
|
+
```
|
|
222
|
+
@rxflow/manhattan
|
|
223
|
+
├── getManHattanPath.ts # 主入口函数
|
|
224
|
+
├── geometry/ # 几何类 (Point, Rectangle)
|
|
225
|
+
├── obstacle/ # 障碍物处理 (ObstacleMap, QuadTree)
|
|
226
|
+
├── pathfinder/ # A* 寻路算法
|
|
227
|
+
├── options/ # 配置解析
|
|
228
|
+
├── svg/ # SVG 路径转换
|
|
229
|
+
└── utils/ # 工具函数
|
|
230
|
+
├── GlobalGrid.ts # 全局网格
|
|
231
|
+
├── AdaptiveStepCalculator.ts # 自适应步长
|
|
232
|
+
├── PerformanceMonitor.ts # 性能监控
|
|
233
|
+
├── ErrorRecovery.ts # 错误恢复
|
|
234
|
+
└── heuristics.ts # 启发式函数
|
|
235
|
+
```
|
|
32
236
|
|
|
33
237
|
## License
|
|
34
238
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"getManHattanPath.d.ts","sourceRoot":"","sources":["../src/getManHattanPath.ts"],"names":[],"mappings":"AAAA,OAAO,EAAqB,QAAQ,EAAE,MAAM,eAAe,CAAA;AAG3D,OAAO,KAAK,EAAE,sBAAsB,EAAE,UAAU,
|
|
1
|
+
{"version":3,"file":"getManHattanPath.d.ts","sourceRoot":"","sources":["../src/getManHattanPath.ts"],"names":[],"mappings":"AAAA,OAAO,EAAqB,QAAQ,EAAE,MAAM,eAAe,CAAA;AAG3D,OAAO,KAAK,EAAE,sBAAsB,EAAE,UAAU,EAAE,MAAM,WAAW,CAAA;AAMnE;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACrC;;OAEG;IACH,YAAY,EAAE,MAAM,CAAA;IAEpB;;OAEG;IACH,YAAY,EAAE,MAAM,CAAC;IAErB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAEhB,cAAc,EAAE,QAAQ,CAAC;IACzB,cAAc,EAAE,QAAQ,CAAC;IACzB;;OAEG;IACH,UAAU,EAAE,UAAU,CAAA;IAEtB;;OAEG;IACH,OAAO,CAAC,EAAE,sBAAsB,CAAA;CACjC;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,sBAAsB,GAAG,MAAM,CAydvE"}
|
package/cjs/getManHattanPath.js
CHANGED
|
@@ -69,10 +69,12 @@ function getManHattanPath(params) {
|
|
|
69
69
|
const targetNode = nodeLookup.get(targetNodeId);
|
|
70
70
|
if (!sourceNode || !targetNode) {
|
|
71
71
|
// Fallback to simple straight line if nodes not found
|
|
72
|
-
console.warn('Source or target node not found in nodeLookup');
|
|
72
|
+
console.warn('[getManHattanPath] Source or target node not found in nodeLookup');
|
|
73
73
|
const start = new _geometry.Point(sourceX, sourceY);
|
|
74
74
|
const end = new _geometry.Point(targetX, targetY);
|
|
75
|
-
|
|
75
|
+
// Use ErrorRecovery to generate a proper fallback path
|
|
76
|
+
const fallbackPath = _utils.ErrorRecovery.generateFallbackPath(start, end);
|
|
77
|
+
return (0, _svg.pointsToPath)(fallbackPath, options.precision, options.borderRadius);
|
|
76
78
|
}
|
|
77
79
|
|
|
78
80
|
// Get node dimensions using ReactFlow's priority logic
|
|
@@ -107,10 +109,8 @@ function getManHattanPath(params) {
|
|
|
107
109
|
|
|
108
110
|
// Check if smooth step path intersects with any obstacles
|
|
109
111
|
if (smoothStepPoints.length > 0 && !(0, _utils.pathIntersectsObstacles)(smoothStepPoints, nodeLookup)) {
|
|
110
|
-
console.log('[getManHattanPath] Using ReactFlow getSmoothStepPath (no obstacles)');
|
|
111
112
|
return smoothStepPath;
|
|
112
113
|
}
|
|
113
|
-
console.log('[getManHattanPath] SmoothStepPath intersects obstacles, using Manhattan routing');
|
|
114
114
|
|
|
115
115
|
// Build obstacle map with anchor information
|
|
116
116
|
const obstacleMap = new _obstacle.ObstacleMap(options).build(nodeLookup, sourceNodeId, targetNodeId, sourceAnchor, targetAnchor);
|
|
@@ -118,23 +118,80 @@ function getManHattanPath(params) {
|
|
|
118
118
|
// Find route
|
|
119
119
|
let route = (0, _pathfinder.findRoute)(sourceBBox, targetBBox, sourceAnchor, targetAnchor, obstacleMap, options);
|
|
120
120
|
|
|
121
|
-
// Fallback to
|
|
121
|
+
// Fallback to Z-shaped path if no route found
|
|
122
122
|
if (!route) {
|
|
123
|
-
console.warn('Unable to find Manhattan route, using
|
|
124
|
-
route =
|
|
123
|
+
console.warn('[getManHattanPath] Unable to find Manhattan route, using fallback path');
|
|
124
|
+
route = _utils.ErrorRecovery.generateFallbackPath(sourceAnchor, targetAnchor);
|
|
125
125
|
}
|
|
126
|
-
console.log('[getManHattanPath] Route from findRoute:', route.map(p => `(${p.x}, ${p.y})`));
|
|
127
|
-
console.log('[getManHattanPath] Source anchor:', `(${sourceAnchor.x}, ${sourceAnchor.y})`);
|
|
128
|
-
console.log('[getManHattanPath] Target anchor:', `(${targetAnchor.x}, ${targetAnchor.y})`);
|
|
129
126
|
|
|
130
127
|
// If using smart point generation (sourcePosition/targetPosition specified),
|
|
131
128
|
// the route already contains the correct extension points, so skip manual processing
|
|
132
129
|
const useSmartPoints = sourcePosition || targetPosition;
|
|
133
130
|
if (useSmartPoints) {
|
|
134
|
-
|
|
131
|
+
// Post-process route to fix X coordinates for horizontal anchors
|
|
132
|
+
// This ensures the extension distance is fixed and not affected by grid alignment
|
|
133
|
+
const isSourceHorizontal = sourcePosition === _react.Position.Left || sourcePosition === _react.Position.Right;
|
|
134
|
+
const isTargetHorizontal = targetPosition === _react.Position.Left || targetPosition === _react.Position.Right;
|
|
135
|
+
if (isSourceHorizontal && isTargetHorizontal && route.length > 0) {
|
|
136
|
+
// Calculate expected extension X coordinates
|
|
137
|
+
const sourceExtensionX = sourcePosition === _react.Position.Right ? sourceAnchor.x + options.extensionDistance : sourceAnchor.x - options.extensionDistance;
|
|
138
|
+
const targetExtensionX = targetPosition === _react.Position.Left ? targetAnchor.x - options.extensionDistance : targetAnchor.x + options.extensionDistance;
|
|
139
|
+
|
|
140
|
+
// Find the horizontal segment (where Y stays constant but X changes significantly)
|
|
141
|
+
// This divides the path into source-side and target-side
|
|
142
|
+
let horizontalSegmentStart = -1;
|
|
143
|
+
let horizontalSegmentEnd = -1;
|
|
144
|
+
for (let i = 0; i < route.length - 1; i++) {
|
|
145
|
+
const curr = route[i];
|
|
146
|
+
const next = route[i + 1];
|
|
147
|
+
const isHorizontalMove = Math.abs(curr.y - next.y) < 1 && Math.abs(curr.x - next.x) > options.step;
|
|
148
|
+
if (isHorizontalMove) {
|
|
149
|
+
horizontalSegmentStart = i;
|
|
150
|
+
horizontalSegmentEnd = i + 1;
|
|
151
|
+
break;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// Fix route points
|
|
156
|
+
for (let i = 0; i < route.length; i++) {
|
|
157
|
+
const point = route[i];
|
|
158
|
+
if (horizontalSegmentStart >= 0) {
|
|
159
|
+
if (i <= horizontalSegmentStart) {
|
|
160
|
+
// Source side - all vertical segment points should use sourceExtensionX
|
|
161
|
+
route[i] = new _geometry.Point(sourceExtensionX, point.y);
|
|
162
|
+
} else if (i >= horizontalSegmentEnd) {
|
|
163
|
+
// Target side - all vertical segment points should use targetExtensionX
|
|
164
|
+
route[i] = new _geometry.Point(targetExtensionX, point.y);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// Remove redundant points (consecutive points on same line)
|
|
170
|
+
const optimized = [];
|
|
171
|
+
for (let i = 0; i < route.length; i++) {
|
|
172
|
+
const point = route[i];
|
|
173
|
+
if (optimized.length < 2) {
|
|
174
|
+
optimized.push(point);
|
|
175
|
+
} else {
|
|
176
|
+
const prev = optimized[optimized.length - 1];
|
|
177
|
+
const prevPrev = optimized[optimized.length - 2];
|
|
178
|
+
|
|
179
|
+
// Check if prev is on the same line as prevPrev and point
|
|
180
|
+
const sameX = Math.abs(prevPrev.x - prev.x) < 1 && Math.abs(prev.x - point.x) < 1;
|
|
181
|
+
const sameY = Math.abs(prevPrev.y - prev.y) < 1 && Math.abs(prev.y - point.y) < 1;
|
|
182
|
+
if (sameX || sameY) {
|
|
183
|
+
// prev is redundant, replace it with current point
|
|
184
|
+
optimized[optimized.length - 1] = point;
|
|
185
|
+
} else {
|
|
186
|
+
optimized.push(point);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
route = optimized;
|
|
191
|
+
}
|
|
192
|
+
|
|
135
193
|
// Add source and target anchors to route
|
|
136
194
|
const finalRoute = [sourceAnchor, ...route, targetAnchor];
|
|
137
|
-
console.log('[getManHattanPath] Final route:', finalRoute.map(p => `(${p.x}, ${p.y})`));
|
|
138
195
|
return (0, _svg.pointsToPath)(finalRoute, options.precision, options.borderRadius);
|
|
139
196
|
}
|
|
140
197
|
|
|
@@ -157,7 +214,6 @@ function getManHattanPath(params) {
|
|
|
157
214
|
// This is likely an extension point, remove it
|
|
158
215
|
if (onRight && firstPoint.x > sourceAnchor.x || onLeft && firstPoint.x < sourceAnchor.x || onBottom && firstPoint.y > sourceAnchor.y || onTop && firstPoint.y < sourceAnchor.y) {
|
|
159
216
|
route.shift();
|
|
160
|
-
console.log('[getManHattanPath] Removed extension point from route start');
|
|
161
217
|
}
|
|
162
218
|
}
|
|
163
219
|
}
|
|
@@ -176,7 +232,6 @@ function getManHattanPath(params) {
|
|
|
176
232
|
// This is likely an extension point, remove it
|
|
177
233
|
if (onLeft && lastPoint.x < targetAnchor.x || onRight && lastPoint.x > targetAnchor.x || onTop && lastPoint.y < targetAnchor.y || onBottom && lastPoint.y > targetAnchor.y) {
|
|
178
234
|
route.pop();
|
|
179
|
-
console.log('[getManHattanPath] Removed extension point from route end');
|
|
180
235
|
}
|
|
181
236
|
}
|
|
182
237
|
}
|
|
@@ -202,7 +257,6 @@ function getManHattanPath(params) {
|
|
|
202
257
|
route.unshift(new _geometry.Point(extendX, firstPoint.y)); // Corner point
|
|
203
258
|
}
|
|
204
259
|
route.unshift(extensionPoint); // Extension point (fixed distance)
|
|
205
|
-
console.log('[getManHattanPath] Inserted source extension (right):', `(${extendX}, ${sourceAnchor.y})`);
|
|
206
260
|
} else if (onLeft) {
|
|
207
261
|
// Anchor on left edge - extend left by step + borderRadius
|
|
208
262
|
const extendX = sourceAnchor.x - extensionDistance;
|
|
@@ -211,7 +265,6 @@ function getManHattanPath(params) {
|
|
|
211
265
|
route.unshift(new _geometry.Point(extendX, firstPoint.y));
|
|
212
266
|
}
|
|
213
267
|
route.unshift(extensionPoint);
|
|
214
|
-
console.log('[getManHattanPath] Inserted source extension (left):', `(${extendX}, ${sourceAnchor.y})`);
|
|
215
268
|
} else if (onBottom) {
|
|
216
269
|
// Anchor on bottom edge - extend down by step + borderRadius
|
|
217
270
|
const extendY = sourceAnchor.y + extensionDistance;
|
|
@@ -220,7 +273,6 @@ function getManHattanPath(params) {
|
|
|
220
273
|
route.unshift(new _geometry.Point(firstPoint.x, extendY));
|
|
221
274
|
}
|
|
222
275
|
route.unshift(extensionPoint);
|
|
223
|
-
console.log('[getManHattanPath] Inserted source extension (down):', `(${sourceAnchor.x}, ${extendY})`);
|
|
224
276
|
} else if (onTop) {
|
|
225
277
|
// Anchor on top edge - extend up by step + borderRadius
|
|
226
278
|
const extendY = sourceAnchor.y - extensionDistance;
|
|
@@ -229,33 +281,25 @@ function getManHattanPath(params) {
|
|
|
229
281
|
route.unshift(new _geometry.Point(firstPoint.x, extendY));
|
|
230
282
|
}
|
|
231
283
|
route.unshift(extensionPoint);
|
|
232
|
-
console.log('[getManHattanPath] Inserted source extension (up):', `(${sourceAnchor.x}, ${extendY})`);
|
|
233
284
|
}
|
|
234
285
|
}
|
|
235
286
|
|
|
236
287
|
// Remove redundant points after source extension
|
|
237
288
|
// If the first route point has the same x or y coordinate as the source anchor, it's redundant
|
|
238
|
-
if (route.length >
|
|
239
|
-
const firstRoutePoint = route[0]; // Extension point
|
|
240
|
-
const secondRoutePoint = route[1]; // Corner point (if exists)
|
|
289
|
+
if (route.length > 3) {
|
|
241
290
|
const thirdRoutePoint = route[2]; // Original A* point
|
|
242
|
-
|
|
243
291
|
// Check if the third point (original A* point) is redundant
|
|
244
292
|
// It's redundant if it's on the same line as the corner point and can be skipped
|
|
245
293
|
const sameX = Math.abs(thirdRoutePoint.x - sourceAnchor.x) < tolerance;
|
|
246
294
|
const sameY = Math.abs(thirdRoutePoint.y - sourceAnchor.y) < tolerance;
|
|
247
295
|
if (sameX || sameY) {
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
if (cornerToThird && thirdToFourth) {
|
|
256
|
-
console.log('[getManHattanPath] Removing redundant point:', `(${thirdRoutePoint.x}, ${thirdRoutePoint.y})`);
|
|
257
|
-
route.splice(2, 1); // Remove the third point
|
|
258
|
-
}
|
|
296
|
+
const secondRoutePoint = route[1]; // Corner point (if exists)
|
|
297
|
+
const fourthPoint = route[3];
|
|
298
|
+
// If corner point and fourth point form a straight line, remove the third point
|
|
299
|
+
const cornerToThird = Math.abs(secondRoutePoint.x - thirdRoutePoint.x) < tolerance || Math.abs(secondRoutePoint.y - thirdRoutePoint.y) < tolerance;
|
|
300
|
+
const thirdToFourth = Math.abs(thirdRoutePoint.x - fourthPoint.x) < tolerance || Math.abs(thirdRoutePoint.y - fourthPoint.y) < tolerance;
|
|
301
|
+
if (cornerToThird && thirdToFourth) {
|
|
302
|
+
route.splice(2, 1); // Remove the third point
|
|
259
303
|
}
|
|
260
304
|
}
|
|
261
305
|
}
|
|
@@ -265,8 +309,6 @@ function getManHattanPath(params) {
|
|
|
265
309
|
// where the middle segment goes to target edge and then moves along it
|
|
266
310
|
// Use target bbox with padding (same as ObstacleMap)
|
|
267
311
|
const targetBBoxWithPadding = targetBBox.moveAndExpand(options.paddingBox);
|
|
268
|
-
console.log('[getManHattanPath] Route before zigzag check:', route.map(p => `(${p.x}, ${p.y})`));
|
|
269
|
-
console.log('[getManHattanPath] Target BBox with padding:', `x=${targetBBoxWithPadding.x}, y=${targetBBoxWithPadding.y}`);
|
|
270
312
|
if (route.length >= 3) {
|
|
271
313
|
let i = 0;
|
|
272
314
|
while (i < route.length - 2) {
|
|
@@ -280,17 +322,14 @@ function getManHattanPath(params) {
|
|
|
280
322
|
const p2OnTargetTopEdge = Math.abs(p2.y - targetBBoxWithPadding.y) < tolerance;
|
|
281
323
|
const p2OnTargetBottomEdge = Math.abs(p2.y - (targetBBoxWithPadding.y + targetBBoxWithPadding.height)) < tolerance;
|
|
282
324
|
const p2OnTargetEdge = p2OnTargetLeftEdge || p2OnTargetRightEdge || p2OnTargetTopEdge || p2OnTargetBottomEdge;
|
|
283
|
-
console.log(`[getManHattanPath] Checking i=${i}: p2=(${p2.x}, ${p2.y}), onEdge=${p2OnTargetEdge}`);
|
|
284
325
|
if (p2OnTargetEdge) {
|
|
285
326
|
// Check if p1 -> p2 -> p3 forms a zigzag
|
|
286
327
|
const p1ToP2Horizontal = Math.abs(p1.y - p2.y) < tolerance;
|
|
287
328
|
const p2ToP3Vertical = Math.abs(p2.x - p3.x) < tolerance;
|
|
288
329
|
const p1ToP2Vertical = Math.abs(p1.x - p2.x) < tolerance;
|
|
289
330
|
const p2ToP3Horizontal = Math.abs(p2.y - p3.y) < tolerance;
|
|
290
|
-
console.log(`[getManHattanPath] Zigzag pattern: H->V=${p1ToP2Horizontal && p2ToP3Vertical}, V->H=${p1ToP2Vertical && p2ToP3Horizontal}`);
|
|
291
331
|
if (p1ToP2Horizontal && p2ToP3Vertical || p1ToP2Vertical && p2ToP3Horizontal) {
|
|
292
332
|
// We have a zigzag at target edge, remove p2 and p3
|
|
293
|
-
console.log('[getManHattanPath] Removing zigzag at target edge:', `(${p2.x}, ${p2.y})`, `and (${p3.x}, ${p3.y})`);
|
|
294
333
|
route.splice(i + 1, 2); // Remove p2 and p3
|
|
295
334
|
continue;
|
|
296
335
|
}
|
|
@@ -319,7 +358,6 @@ function getManHattanPath(params) {
|
|
|
319
358
|
route.push(new _geometry.Point(extendX, lastPoint.y)); // Corner point
|
|
320
359
|
}
|
|
321
360
|
route.push(extensionPoint); // Extension point (fixed distance)
|
|
322
|
-
console.log('[getManHattanPath] Inserted target extension (left):', `(${extendX}, ${targetAnchor.y})`);
|
|
323
361
|
} else if (onRight) {
|
|
324
362
|
// Anchor on right edge - extend right by step + borderRadius
|
|
325
363
|
const extendX = targetAnchor.x + extensionDistance;
|
|
@@ -328,7 +366,6 @@ function getManHattanPath(params) {
|
|
|
328
366
|
route.push(new _geometry.Point(extendX, lastPoint.y));
|
|
329
367
|
}
|
|
330
368
|
route.push(extensionPoint);
|
|
331
|
-
console.log('[getManHattanPath] Inserted target extension (right):', `(${extendX}, ${targetAnchor.y})`);
|
|
332
369
|
} else if (onTop) {
|
|
333
370
|
// Anchor on top edge - extend up by step + borderRadius
|
|
334
371
|
const extendY = targetAnchor.y - extensionDistance;
|
|
@@ -337,7 +374,6 @@ function getManHattanPath(params) {
|
|
|
337
374
|
route.push(new _geometry.Point(lastPoint.x, extendY));
|
|
338
375
|
}
|
|
339
376
|
route.push(extensionPoint);
|
|
340
|
-
console.log('[getManHattanPath] Inserted target extension (up):', `(${targetAnchor.x}, ${extendY})`);
|
|
341
377
|
} else if (onBottom) {
|
|
342
378
|
// Anchor on bottom edge - extend down by step + borderRadius
|
|
343
379
|
const extendY = targetAnchor.y + extensionDistance;
|
|
@@ -346,7 +382,6 @@ function getManHattanPath(params) {
|
|
|
346
382
|
route.push(new _geometry.Point(lastPoint.x, extendY));
|
|
347
383
|
}
|
|
348
384
|
route.push(extensionPoint);
|
|
349
|
-
console.log('[getManHattanPath] Inserted target extension (down):', `(${targetAnchor.x}, ${extendY})`);
|
|
350
385
|
}
|
|
351
386
|
}
|
|
352
387
|
|
|
@@ -354,7 +389,6 @@ function getManHattanPath(params) {
|
|
|
354
389
|
// Similar logic for target side
|
|
355
390
|
if (route.length > 2) {
|
|
356
391
|
const lastIdx = route.length - 1;
|
|
357
|
-
const lastRoutePoint = route[lastIdx]; // Extension point
|
|
358
392
|
const secondLastPoint = route[lastIdx - 1]; // Corner point (if exists)
|
|
359
393
|
const thirdLastPoint = route[lastIdx - 2]; // Original A* point
|
|
360
394
|
|
|
@@ -367,7 +401,6 @@ function getManHattanPath(params) {
|
|
|
367
401
|
const fourthToThird = Math.abs(fourthLastPoint.x - thirdLastPoint.x) < tolerance || Math.abs(fourthLastPoint.y - thirdLastPoint.y) < tolerance;
|
|
368
402
|
const thirdToSecond = Math.abs(thirdLastPoint.x - secondLastPoint.x) < tolerance || Math.abs(thirdLastPoint.y - secondLastPoint.y) < tolerance;
|
|
369
403
|
if (fourthToThird && thirdToSecond) {
|
|
370
|
-
console.log('[getManHattanPath] Removing redundant point:', `(${thirdLastPoint.x}, ${thirdLastPoint.y})`);
|
|
371
404
|
route.splice(lastIdx - 2, 1); // Remove the third-to-last point
|
|
372
405
|
}
|
|
373
406
|
}
|
|
@@ -400,7 +433,6 @@ function getManHattanPath(params) {
|
|
|
400
433
|
const p3ToP4Horizontal = Math.abs(p3.y - p4.y) < tolerance;
|
|
401
434
|
if (p3ToP4Horizontal) {
|
|
402
435
|
// Pattern: horizontal -> vertical -> horizontal (zigzag)
|
|
403
|
-
console.log('[getManHattanPath] Removing zigzag at target edge:', `(${p2.x}, ${p2.y})`, `and (${p3.x}, ${p3.y})`);
|
|
404
436
|
route.splice(i + 1, 2); // Remove p2 and p3
|
|
405
437
|
continue;
|
|
406
438
|
}
|
|
@@ -411,7 +443,6 @@ function getManHattanPath(params) {
|
|
|
411
443
|
|
|
412
444
|
// Add source and target anchors to route
|
|
413
445
|
const finalRoute = [sourceAnchor, ...route, targetAnchor];
|
|
414
|
-
console.log('[getManHattanPath] Final route:', finalRoute.map(p => `(${p.x}, ${p.y})`));
|
|
415
446
|
|
|
416
447
|
// Convert to SVG path string
|
|
417
448
|
return (0, _svg.pointsToPath)(finalRoute, options.precision, options.borderRadius);
|
|
@@ -2,29 +2,61 @@ import { Point } from '../geometry';
|
|
|
2
2
|
import type { ResolvedOptions, NodeLookup } from '../options';
|
|
3
3
|
/**
|
|
4
4
|
* ObstacleMap class for managing obstacles in pathfinding
|
|
5
|
-
*
|
|
5
|
+
* Feature: manhattan-optimization
|
|
6
|
+
*
|
|
7
|
+
* Uses QuadTree for efficient spatial queries (O(log n) instead of O(n))
|
|
8
|
+
* Includes query caching for repeated accessibility checks
|
|
6
9
|
*/
|
|
7
10
|
export declare class ObstacleMap {
|
|
8
11
|
private options;
|
|
9
|
-
private
|
|
10
|
-
private
|
|
12
|
+
private quadTree;
|
|
13
|
+
private obstacles;
|
|
11
14
|
private sourceAnchor?;
|
|
12
15
|
private targetAnchor?;
|
|
16
|
+
private accessibilityCache;
|
|
17
|
+
private cacheHits;
|
|
18
|
+
private cacheMisses;
|
|
13
19
|
constructor(options: ResolvedOptions);
|
|
14
20
|
/**
|
|
15
|
-
*
|
|
21
|
+
* Get cache statistics for performance monitoring
|
|
16
22
|
*/
|
|
17
|
-
|
|
23
|
+
getCacheStats(): {
|
|
24
|
+
hits: number;
|
|
25
|
+
misses: number;
|
|
26
|
+
hitRate: number;
|
|
27
|
+
};
|
|
28
|
+
/**
|
|
29
|
+
* Clear the accessibility cache
|
|
30
|
+
*/
|
|
31
|
+
clearCache(): void;
|
|
18
32
|
/**
|
|
19
|
-
*
|
|
20
|
-
* This allows paths to start/end at the anchor but prevents crossing the node
|
|
33
|
+
* Build obstacle map from node lookup using QuadTree
|
|
21
34
|
*/
|
|
22
|
-
|
|
35
|
+
build(nodeLookup: NodeLookup, sourceNodeId: string, targetNodeId: string, sourceAnchor?: Point, targetAnchor?: Point): ObstacleMap;
|
|
23
36
|
/**
|
|
24
37
|
* Check if a point is accessible (not inside any obstacle)
|
|
25
|
-
* Uses
|
|
38
|
+
* Uses QuadTree for efficient spatial queries with caching
|
|
26
39
|
*/
|
|
27
40
|
isAccessible(point: Point, checkRadius?: number): boolean;
|
|
41
|
+
/**
|
|
42
|
+
* Check if an anchor point has sufficient clearance around it
|
|
43
|
+
* This ensures the path can start/end at the anchor without being blocked
|
|
44
|
+
*/
|
|
45
|
+
hasAnchorClearance(anchor: Point, direction: 'top' | 'right' | 'bottom' | 'left'): boolean;
|
|
46
|
+
/**
|
|
47
|
+
* Check accessibility without using cache (for internal use)
|
|
48
|
+
*/
|
|
49
|
+
private isAccessibleWithoutCache;
|
|
50
|
+
/**
|
|
51
|
+
* Find the nearest accessible point from an anchor in a given direction
|
|
52
|
+
* Uses binary search for efficiency
|
|
53
|
+
*/
|
|
54
|
+
findNearestAccessiblePoint(anchor: Point, direction: 'top' | 'right' | 'bottom' | 'left', maxDistance: number): Point | null;
|
|
55
|
+
/**
|
|
56
|
+
* Batch check accessibility for multiple points (optimized)
|
|
57
|
+
* Returns array of booleans in same order as input points
|
|
58
|
+
*/
|
|
59
|
+
areAccessible(points: Point[]): boolean[];
|
|
28
60
|
/**
|
|
29
61
|
* Check accessibility using binary search optimization
|
|
30
62
|
* Tries step -> step/2 -> step/4 -> ... -> 1px
|
|
@@ -1 +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;
|
|
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;AAI7D;;;;;;GAMG;AACH,qBAAa,WAAW;IACtB,OAAO,CAAC,OAAO,CAAiB;IAChC,OAAO,CAAC,QAAQ,CAAgC;IAChD,OAAO,CAAC,SAAS,CAAmD;IACpE,OAAO,CAAC,YAAY,CAAC,CAAO;IAC5B,OAAO,CAAC,YAAY,CAAC,CAAO;IAG5B,OAAO,CAAC,kBAAkB,CAAkC;IAC5D,OAAO,CAAC,SAAS,CAAY;IAC7B,OAAO,CAAC,WAAW,CAAY;gBAEnB,OAAO,EAAE,eAAe;IAIpC;;OAEG;IACH,aAAa,IAAI;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE;IASlE;;OAEG;IACH,UAAU,IAAI,IAAI;IAMlB;;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;IA8Cd;;;OAGG;IACH,YAAY,CAAC,KAAK,EAAE,KAAK,EAAE,WAAW,GAAE,MAAU,GAAG,OAAO;IAoD5D;;;OAGG;IACH,kBAAkB,CAAC,MAAM,EAAE,KAAK,EAAE,SAAS,EAAE,KAAK,GAAG,OAAO,GAAG,QAAQ,GAAG,MAAM,GAAG,OAAO;IA0C1F;;OAEG;IACH,OAAO,CAAC,wBAAwB;IAShC;;;OAGG;IACH,0BAA0B,CACxB,MAAM,EAAE,KAAK,EACb,SAAS,EAAE,KAAK,GAAG,OAAO,GAAG,QAAQ,GAAG,MAAM,EAC9C,WAAW,EAAE,MAAM,GAClB,KAAK,GAAG,IAAI;IAyDf;;;OAGG;IACH,aAAa,CAAC,MAAM,EAAE,KAAK,EAAE,GAAG,OAAO,EAAE;IAIzC;;;OAGG;IACH,OAAO,CAAC,4BAA4B;CAqCrC"}
|