@rxflow/manhattan 0.0.2-alpha.8 → 0.0.2

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.
Files changed (157) hide show
  1. package/README.md +214 -10
  2. package/esm/getManHattanPath.js +92 -69
  3. package/esm/obstacle/ObstacleMap.js +218 -99
  4. package/esm/obstacle/QuadTree.js +488 -0
  5. package/esm/options/resolver.js +147 -18
  6. package/esm/pathfinder/PathCache.js +278 -0
  7. package/esm/pathfinder/findRoute.js +98 -44
  8. package/esm/pathfinder/index.js +2 -1
  9. package/esm/svg/pathConverter.js +170 -1
  10. package/esm/utils/AdaptiveStepCalculator.js +252 -0
  11. package/esm/utils/ErrorRecovery.js +499 -0
  12. package/esm/utils/GlobalGrid.js +259 -0
  13. package/esm/utils/PerformanceMonitor.js +360 -0
  14. package/esm/utils/getAnchorPoints.js +0 -4
  15. package/esm/utils/grid.js +18 -13
  16. package/esm/utils/heuristics.js +144 -0
  17. package/esm/utils/index.js +7 -1
  18. package/esm/utils/pathProcessing.js +270 -0
  19. package/esm/utils/pathValidation.js +0 -1
  20. package/esm/utils/rect.js +11 -4
  21. package/esm/utils/route.js +18 -2
  22. package/package.json +10 -2
  23. package/cjs/geometry/Line.d.ts +0 -21
  24. package/cjs/geometry/Line.d.ts.map +0 -1
  25. package/cjs/geometry/Line.js +0 -88
  26. package/cjs/geometry/Point.d.ts +0 -49
  27. package/cjs/geometry/Point.d.ts.map +0 -1
  28. package/cjs/geometry/Point.js +0 -94
  29. package/cjs/geometry/Rectangle.d.ts +0 -41
  30. package/cjs/geometry/Rectangle.d.ts.map +0 -1
  31. package/cjs/geometry/Rectangle.js +0 -65
  32. package/cjs/geometry/collision.d.ts +0 -15
  33. package/cjs/geometry/collision.d.ts.map +0 -1
  34. package/cjs/geometry/collision.js +0 -81
  35. package/cjs/geometry/index.d.ts +0 -5
  36. package/cjs/geometry/index.d.ts.map +0 -1
  37. package/cjs/geometry/index.js +0 -45
  38. package/cjs/getManHattanPath.d.ts +0 -53
  39. package/cjs/getManHattanPath.d.ts.map +0 -1
  40. package/cjs/getManHattanPath.js +0 -418
  41. package/cjs/index.d.ts +0 -16
  42. package/cjs/index.d.ts.map +0 -1
  43. package/cjs/index.js +0 -117
  44. package/cjs/obstacle/ObstacleMap.d.ts +0 -34
  45. package/cjs/obstacle/ObstacleMap.d.ts.map +0 -1
  46. package/cjs/obstacle/ObstacleMap.js +0 -223
  47. package/cjs/obstacle/index.d.ts +0 -2
  48. package/cjs/obstacle/index.d.ts.map +0 -1
  49. package/cjs/obstacle/index.js +0 -12
  50. package/cjs/options/defaults.d.ts +0 -16
  51. package/cjs/options/defaults.d.ts.map +0 -1
  52. package/cjs/options/defaults.js +0 -39
  53. package/cjs/options/index.d.ts +0 -4
  54. package/cjs/options/index.d.ts.map +0 -1
  55. package/cjs/options/index.js +0 -38
  56. package/cjs/options/resolver.d.ts +0 -10
  57. package/cjs/options/resolver.d.ts.map +0 -1
  58. package/cjs/options/resolver.js +0 -120
  59. package/cjs/options/types.d.ts +0 -169
  60. package/cjs/options/types.d.ts.map +0 -1
  61. package/cjs/options/types.js +0 -5
  62. package/cjs/pathfinder/SortedSet.d.ts +0 -35
  63. package/cjs/pathfinder/SortedSet.d.ts.map +0 -1
  64. package/cjs/pathfinder/SortedSet.js +0 -95
  65. package/cjs/pathfinder/findRoute.d.ts +0 -8
  66. package/cjs/pathfinder/findRoute.d.ts.map +0 -1
  67. package/cjs/pathfinder/findRoute.js +0 -330
  68. package/cjs/pathfinder/index.d.ts +0 -3
  69. package/cjs/pathfinder/index.d.ts.map +0 -1
  70. package/cjs/pathfinder/index.js +0 -19
  71. package/cjs/svg/index.d.ts +0 -3
  72. package/cjs/svg/index.d.ts.map +0 -1
  73. package/cjs/svg/index.js +0 -31
  74. package/cjs/svg/pathConverter.d.ts +0 -10
  75. package/cjs/svg/pathConverter.d.ts.map +0 -1
  76. package/cjs/svg/pathConverter.js +0 -116
  77. package/cjs/svg/pathParser.d.ts +0 -11
  78. package/cjs/svg/pathParser.d.ts.map +0 -1
  79. package/cjs/svg/pathParser.js +0 -76
  80. package/cjs/utils/direction.d.ts +0 -24
  81. package/cjs/utils/direction.d.ts.map +0 -1
  82. package/cjs/utils/direction.js +0 -54
  83. package/cjs/utils/getAnchorPoints.d.ts +0 -15
  84. package/cjs/utils/getAnchorPoints.d.ts.map +0 -1
  85. package/cjs/utils/getAnchorPoints.js +0 -75
  86. package/cjs/utils/grid.d.ts +0 -27
  87. package/cjs/utils/grid.d.ts.map +0 -1
  88. package/cjs/utils/grid.js +0 -66
  89. package/cjs/utils/index.d.ts +0 -8
  90. package/cjs/utils/index.d.ts.map +0 -1
  91. package/cjs/utils/index.js +0 -82
  92. package/cjs/utils/node.d.ts +0 -27
  93. package/cjs/utils/node.d.ts.map +0 -1
  94. package/cjs/utils/node.js +0 -36
  95. package/cjs/utils/pathValidation.d.ts +0 -11
  96. package/cjs/utils/pathValidation.d.ts.map +0 -1
  97. package/cjs/utils/pathValidation.js +0 -130
  98. package/cjs/utils/rect.d.ts +0 -9
  99. package/cjs/utils/rect.d.ts.map +0 -1
  100. package/cjs/utils/rect.js +0 -103
  101. package/cjs/utils/route.d.ts +0 -19
  102. package/cjs/utils/route.d.ts.map +0 -1
  103. package/cjs/utils/route.js +0 -76
  104. package/esm/geometry/Line.d.ts +0 -21
  105. package/esm/geometry/Line.d.ts.map +0 -1
  106. package/esm/geometry/Point.d.ts +0 -49
  107. package/esm/geometry/Point.d.ts.map +0 -1
  108. package/esm/geometry/Rectangle.d.ts +0 -41
  109. package/esm/geometry/Rectangle.d.ts.map +0 -1
  110. package/esm/geometry/collision.d.ts +0 -15
  111. package/esm/geometry/collision.d.ts.map +0 -1
  112. package/esm/geometry/index.d.ts +0 -5
  113. package/esm/geometry/index.d.ts.map +0 -1
  114. package/esm/getManHattanPath.d.ts +0 -53
  115. package/esm/getManHattanPath.d.ts.map +0 -1
  116. package/esm/index.d.ts +0 -16
  117. package/esm/index.d.ts.map +0 -1
  118. package/esm/obstacle/ObstacleMap.d.ts +0 -34
  119. package/esm/obstacle/ObstacleMap.d.ts.map +0 -1
  120. package/esm/obstacle/index.d.ts +0 -2
  121. package/esm/obstacle/index.d.ts.map +0 -1
  122. package/esm/options/defaults.d.ts +0 -16
  123. package/esm/options/defaults.d.ts.map +0 -1
  124. package/esm/options/index.d.ts +0 -4
  125. package/esm/options/index.d.ts.map +0 -1
  126. package/esm/options/resolver.d.ts +0 -10
  127. package/esm/options/resolver.d.ts.map +0 -1
  128. package/esm/options/types.d.ts +0 -169
  129. package/esm/options/types.d.ts.map +0 -1
  130. package/esm/pathfinder/SortedSet.d.ts +0 -35
  131. package/esm/pathfinder/SortedSet.d.ts.map +0 -1
  132. package/esm/pathfinder/findRoute.d.ts +0 -8
  133. package/esm/pathfinder/findRoute.d.ts.map +0 -1
  134. package/esm/pathfinder/index.d.ts +0 -3
  135. package/esm/pathfinder/index.d.ts.map +0 -1
  136. package/esm/svg/index.d.ts +0 -3
  137. package/esm/svg/index.d.ts.map +0 -1
  138. package/esm/svg/pathConverter.d.ts +0 -10
  139. package/esm/svg/pathConverter.d.ts.map +0 -1
  140. package/esm/svg/pathParser.d.ts +0 -11
  141. package/esm/svg/pathParser.d.ts.map +0 -1
  142. package/esm/utils/direction.d.ts +0 -24
  143. package/esm/utils/direction.d.ts.map +0 -1
  144. package/esm/utils/getAnchorPoints.d.ts +0 -15
  145. package/esm/utils/getAnchorPoints.d.ts.map +0 -1
  146. package/esm/utils/grid.d.ts +0 -27
  147. package/esm/utils/grid.d.ts.map +0 -1
  148. package/esm/utils/index.d.ts +0 -8
  149. package/esm/utils/index.d.ts.map +0 -1
  150. package/esm/utils/node.d.ts +0 -27
  151. package/esm/utils/node.d.ts.map +0 -1
  152. package/esm/utils/pathValidation.d.ts +0 -11
  153. package/esm/utils/pathValidation.d.ts.map +0 -1
  154. package/esm/utils/rect.d.ts +0 -9
  155. package/esm/utils/rect.d.ts.map +0 -1
  156. package/esm/utils/route.d.ts +0 -19
  157. package/esm/utils/route.d.ts.map +0 -1
@@ -1,35 +0,0 @@
1
- /**
2
- * SortedSet class for managing open and closed sets in A* algorithm
3
- * Maintains items sorted by their values
4
- */
5
- export declare class SortedSet {
6
- private items;
7
- private hash;
8
- private values;
9
- constructor();
10
- /**
11
- * Add an item with its value, maintaining sorted order
12
- */
13
- add(item: string, value: number): void;
14
- /**
15
- * Pop the item with minimum value and mark it as closed
16
- */
17
- pop(): string | undefined;
18
- /**
19
- * Check if item is in open set
20
- */
21
- isOpen(item: string): boolean;
22
- /**
23
- * Check if item is in closed set
24
- */
25
- isClose(item: string): boolean;
26
- /**
27
- * Check if open set is empty
28
- */
29
- isEmpty(): boolean;
30
- /**
31
- * Find sorted insertion index for an item
32
- */
33
- private sortedIndexBy;
34
- }
35
- //# sourceMappingURL=SortedSet.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"SortedSet.d.ts","sourceRoot":"","sources":["../../src/pathfinder/SortedSet.ts"],"names":[],"mappings":"AAGA;;;GAGG;AACH,qBAAa,SAAS;IACpB,OAAO,CAAC,KAAK,CAAU;IACvB,OAAO,CAAC,IAAI,CAAqB;IACjC,OAAO,CAAC,MAAM,CAAqB;;IAQnC;;OAEG;IACH,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI;IAkBtC;;OAEG;IACH,GAAG,IAAI,MAAM,GAAG,SAAS;IAQzB;;OAEG;IACH,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IAI7B;;OAEG;IACH,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IAI9B;;OAEG;IACH,OAAO,IAAI,OAAO;IAIlB;;OAEG;IACH,OAAO,CAAC,aAAa;CAiBtB"}
@@ -1,95 +0,0 @@
1
- "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
6
- exports.SortedSet = void 0;
7
- const OPEN = 1;
8
- const CLOSE = 2;
9
-
10
- /**
11
- * SortedSet class for managing open and closed sets in A* algorithm
12
- * Maintains items sorted by their values
13
- */
14
- class SortedSet {
15
- items;
16
- hash;
17
- values;
18
- constructor() {
19
- this.items = [];
20
- this.hash = new Map();
21
- this.values = new Map();
22
- }
23
-
24
- /**
25
- * Add an item with its value, maintaining sorted order
26
- */
27
- add(item, value) {
28
- if (this.hash.get(item)) {
29
- // Item removal - remove from items array
30
- const index = this.items.indexOf(item);
31
- if (index !== -1) {
32
- this.items.splice(index, 1);
33
- }
34
- } else {
35
- this.hash.set(item, OPEN);
36
- }
37
- this.values.set(item, value);
38
-
39
- // Find insertion index using binary search
40
- const index = this.sortedIndexBy(item);
41
- this.items.splice(index, 0, item);
42
- }
43
-
44
- /**
45
- * Pop the item with minimum value and mark it as closed
46
- */
47
- pop() {
48
- const item = this.items.shift();
49
- if (item) {
50
- this.hash.set(item, CLOSE);
51
- }
52
- return item;
53
- }
54
-
55
- /**
56
- * Check if item is in open set
57
- */
58
- isOpen(item) {
59
- return this.hash.get(item) === OPEN;
60
- }
61
-
62
- /**
63
- * Check if item is in closed set
64
- */
65
- isClose(item) {
66
- return this.hash.get(item) === CLOSE;
67
- }
68
-
69
- /**
70
- * Check if open set is empty
71
- */
72
- isEmpty() {
73
- return this.items.length === 0;
74
- }
75
-
76
- /**
77
- * Find sorted insertion index for an item
78
- */
79
- sortedIndexBy(item) {
80
- const value = this.values.get(item);
81
- let low = 0;
82
- let high = this.items.length;
83
- while (low < high) {
84
- const mid = low + high >>> 1;
85
- const midValue = this.values.get(this.items[mid]);
86
- if (midValue < value) {
87
- low = mid + 1;
88
- } else {
89
- high = mid;
90
- }
91
- }
92
- return low;
93
- }
94
- }
95
- exports.SortedSet = SortedSet;
@@ -1,8 +0,0 @@
1
- import { Point, Rectangle } from '../geometry';
2
- import type { ResolvedOptions } from '../options';
3
- import type { ObstacleMap } from '../obstacle';
4
- /**
5
- * Find route between two points using A* algorithm
6
- */
7
- export declare function findRoute(sourceBBox: Rectangle, targetBBox: Rectangle, sourceAnchor: Point, targetAnchor: Point, map: ObstacleMap, options: ResolvedOptions): Point[] | null;
8
- //# sourceMappingURL=findRoute.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"findRoute.d.ts","sourceRoot":"","sources":["../../src/pathfinder/findRoute.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AAC9C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;AACjD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AA+I9C;;GAEG;AACH,wBAAgB,SAAS,CACvB,UAAU,EAAE,SAAS,EACrB,UAAU,EAAE,SAAS,EACrB,YAAY,EAAE,KAAK,EACnB,YAAY,EAAE,KAAK,EACnB,GAAG,EAAE,WAAW,EAChB,OAAO,EAAE,eAAe,GACvB,KAAK,EAAE,GAAG,IAAI,CAiThB"}
@@ -1,330 +0,0 @@
1
- "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
6
- exports.findRoute = findRoute;
7
- var _geometry = require("../geometry");
8
- var _SortedSet = require("./SortedSet");
9
- var _utils = require("../utils");
10
- /**
11
- * Generate smart points based on position using extensionDistance and binary search
12
- *
13
- * Algorithm:
14
- * 1. First try extensionDistance in the specified direction
15
- * 2. If blocked, use binary search starting from step, halving until finding accessible point
16
- * 3. For target points, approach from opposite direction
17
- */
18
- function generateSmartPoints(anchor, bbox, position, grid, map, options, isTarget = false) {
19
- const directionMap = {
20
- 'right': {
21
- x: 1,
22
- y: 0
23
- },
24
- 'left': {
25
- x: -1,
26
- y: 0
27
- },
28
- 'top': {
29
- x: 0,
30
- y: -1
31
- },
32
- 'bottom': {
33
- x: 0,
34
- y: 1
35
- }
36
- };
37
- const direction = directionMap[position];
38
- if (!direction) {
39
- console.warn(`[generateSmartPoints] Unknown position: ${position}, falling back to anchor`);
40
- return [anchor];
41
- }
42
-
43
- // Both source and target extend in the specified direction
44
- // - Source: extends away from node in sourcePosition direction
45
- // - Target: extends away from node in targetPosition direction (path approaches from this direction)
46
- const actualDirection = direction;
47
- const points = [];
48
-
49
- // 1. First try extensionDistance
50
- const extensionPoint = new _geometry.Point(anchor.x + actualDirection.x * options.extensionDistance, anchor.y + actualDirection.y * options.extensionDistance).round(options.precision);
51
- console.log(`[generateSmartPoints] ${isTarget ? 'Target' : 'Source'} position=${position}, trying extension point: (${extensionPoint.x}, ${extensionPoint.y})`);
52
- if (map.isAccessible(extensionPoint)) {
53
- points.push(extensionPoint);
54
- console.log(`[generateSmartPoints] Extension point is accessible`);
55
- return points;
56
- }
57
- console.log(`[generateSmartPoints] Extension point blocked, using step-based search`);
58
-
59
- // 2. Step-based search with binary refinement
60
- // First, extend outward by step increments until we find an accessible point
61
- let stepMultiplier = 1;
62
- let maxSteps = 20; // Prevent infinite loop
63
- let foundAccessibleDistance = -1;
64
- console.log(`[generateSmartPoints] Starting outward search with step=${options.step}`);
65
- while (stepMultiplier <= maxSteps) {
66
- const distance = stepMultiplier * options.step;
67
- const testPoint = new _geometry.Point(anchor.x + actualDirection.x * distance, anchor.y + actualDirection.y * distance).round(options.precision);
68
- console.log(`[generateSmartPoints] Testing ${stepMultiplier}*step (distance=${distance}): (${testPoint.x}, ${testPoint.y})`);
69
- if (map.isAccessible(testPoint)) {
70
- foundAccessibleDistance = distance;
71
- console.log(`[generateSmartPoints] Found accessible point at ${stepMultiplier}*step (distance=${distance})`);
72
- break;
73
- }
74
- stepMultiplier++;
75
- }
76
-
77
- // 3. If we found an accessible point, refine by binary search within the last step interval
78
- if (foundAccessibleDistance > 0) {
79
- const outerDistance = foundAccessibleDistance;
80
- const innerDistance = foundAccessibleDistance - options.step;
81
- console.log(`[generateSmartPoints] Refining between ${innerDistance} and ${outerDistance}`);
82
-
83
- // Binary search within the last step interval to find the closest accessible point
84
- let left = innerDistance;
85
- let right = outerDistance;
86
- let bestDistance = outerDistance;
87
-
88
- // Binary search with precision of 1px
89
- while (right - left > 1) {
90
- const mid = (left + right) / 2;
91
- const testPoint = new _geometry.Point(anchor.x + actualDirection.x * mid, anchor.y + actualDirection.y * mid).round(options.precision);
92
- console.log(`[generateSmartPoints] Binary search testing distance ${mid.toFixed(1)}: (${testPoint.x}, ${testPoint.y})`);
93
- if (map.isAccessible(testPoint)) {
94
- bestDistance = mid;
95
- right = mid;
96
- console.log(`[generateSmartPoints] Point accessible, searching closer (right=${right})`);
97
- } else {
98
- left = mid;
99
- console.log(`[generateSmartPoints] Point blocked, searching further (left=${left})`);
100
- }
101
- }
102
-
103
- // Use the best distance found
104
- const finalPoint = new _geometry.Point(anchor.x + actualDirection.x * bestDistance, anchor.y + actualDirection.y * bestDistance).round(options.precision);
105
- points.push(finalPoint);
106
- console.log(`[generateSmartPoints] Final point at distance ${bestDistance}: (${finalPoint.x}, ${finalPoint.y})`);
107
- } else {
108
- // 4. If no accessible point found after maxSteps, use anchor as fallback
109
- console.log(`[generateSmartPoints] No accessible point found after ${maxSteps} steps, using anchor: (${anchor.x}, ${anchor.y})`);
110
- points.push(anchor);
111
- }
112
- return points;
113
- }
114
-
115
- /**
116
- * Find route between two points using A* algorithm
117
- */
118
- function findRoute(sourceBBox, targetBBox, sourceAnchor, targetAnchor, map, options) {
119
- const precision = options.precision;
120
-
121
- // Round anchor points
122
- const sourceEndpoint = (0, _utils.round)(sourceAnchor.clone(), precision);
123
- const targetEndpoint = (0, _utils.round)(targetAnchor.clone(), precision);
124
-
125
- // Get grid for this route
126
- const grid = (0, _utils.getGrid)(options.step, sourceEndpoint, targetEndpoint);
127
-
128
- // Get pathfinding points
129
- const startPoint = sourceEndpoint;
130
- const endPoint = targetEndpoint;
131
-
132
- // Get start and end points around rectangles
133
- // Use smart point generation based on position if available
134
- let startPoints;
135
- let endPoints;
136
-
137
- // Generate smart start points based on sourcePosition
138
- if (options.sourcePosition) {
139
- startPoints = generateSmartPoints(startPoint, sourceBBox, options.sourcePosition, grid, map, options, false);
140
- console.log('[findRoute] Start points from smart generation:', startPoints.map(p => `(${p.x}, ${p.y})`));
141
- } else {
142
- startPoints = (0, _utils.getRectPoints)(startPoint, sourceBBox, options.startDirections, grid, options);
143
- console.log('[findRoute] Start points from getRectPoints:', startPoints.map(p => `(${p.x}, ${p.y})`));
144
- // Take into account only accessible rect points
145
- startPoints = startPoints.filter(p => map.isAccessible(p));
146
- }
147
-
148
- // Generate smart end points based on targetPosition
149
- if (options.targetPosition) {
150
- endPoints = generateSmartPoints(targetEndpoint, targetBBox, options.targetPosition, grid, map, options, true);
151
- console.log('[findRoute] End points from smart generation:', endPoints.map(p => `(${p.x}, ${p.y})`));
152
- } else {
153
- endPoints = (0, _utils.getRectPoints)(targetEndpoint, targetBBox, options.endDirections, grid, options);
154
- console.log('[findRoute] End points from getRectPoints:', endPoints.map(p => `(${p.x}, ${p.y})`));
155
- // Take into account only accessible rect points
156
- endPoints = endPoints.filter(p => map.isAccessible(p));
157
- }
158
- console.log('[findRoute] Start points after filter:', startPoints.map(p => `(${p.x}, ${p.y})`));
159
- console.log('[findRoute] End points after filter:', endPoints.map(p => `(${p.x}, ${p.y})`));
160
-
161
- // Ensure we always have at least the anchor points
162
- // This handles edge cases where anchor is on the node boundary
163
- if (startPoints.length === 0) {
164
- startPoints = [(0, _utils.round)(startPoint, precision)];
165
- }
166
- if (endPoints.length === 0) {
167
- endPoints = [(0, _utils.round)(endPoint, precision)];
168
- }
169
-
170
- // Initialize A* data structures
171
- const openSet = new _SortedSet.SortedSet();
172
- const points = new Map();
173
- const parents = new Map();
174
- const costs = new Map();
175
-
176
- // Add all start points to open set
177
- for (const startPoint of startPoints) {
178
- const key = (0, _utils.getKey)(startPoint);
179
- openSet.add(key, (0, _utils.getCost)(startPoint, endPoints));
180
- points.set(key, startPoint);
181
- costs.set(key, 0);
182
- }
183
- const previousRouteDirectionAngle = options.previousDirectionAngle;
184
- const isPathBeginning = previousRouteDirectionAngle === undefined;
185
-
186
- // Get directions with grid offsets
187
- const directions = (0, _utils.getGridOffsets)(grid, options);
188
- const numDirections = directions.length;
189
-
190
- // Create set of end point keys for quick lookup
191
- const endPointsKeys = new Set(endPoints.map(p => (0, _utils.getKey)(p)));
192
-
193
- // Check if start and end points are the same
194
- const sameStartEndPoints = startPoints.length === endPoints.length && startPoints.every((sp, i) => sp.equals(endPoints[i]));
195
-
196
- // Main A* loop
197
- let loopsRemaining = options.maxLoopCount;
198
- while (!openSet.isEmpty() && loopsRemaining > 0) {
199
- // Get the closest item and mark it CLOSED
200
- const currentKey = openSet.pop();
201
- if (!currentKey) break;
202
- const currentPoint = points.get(currentKey);
203
- const currentParent = parents.get(currentKey);
204
- const currentCost = costs.get(currentKey);
205
- const isStartPoint = currentPoint.equals(startPoint);
206
- const isRouteBeginning = currentParent === undefined;
207
-
208
- // Calculate previous direction angle
209
- let previousDirectionAngle;
210
- if (!isRouteBeginning) {
211
- previousDirectionAngle = (0, _utils.getDirectionAngle)(currentParent, currentPoint, numDirections, grid, options);
212
- } else if (!isPathBeginning) {
213
- previousDirectionAngle = previousRouteDirectionAngle;
214
- } else if (!isStartPoint) {
215
- previousDirectionAngle = (0, _utils.getDirectionAngle)(startPoint, currentPoint, numDirections, grid, options);
216
- } else {
217
- previousDirectionAngle = null;
218
- }
219
-
220
- // Check if we reached any endpoint
221
- const skipEndCheck = isRouteBeginning && sameStartEndPoints;
222
- if (!skipEndCheck && endPointsKeys.has(currentKey)) {
223
- options.previousDirectionAngle = previousDirectionAngle;
224
- return (0, _utils.reconstructRoute)(parents, points, currentPoint, startPoint, endPoint);
225
- }
226
-
227
- // Explore neighbors in all directions
228
- for (const direction of directions) {
229
- const directionAngle = direction.angle;
230
- const directionChange = (0, _utils.getDirectionChange)(previousDirectionAngle ?? 0, directionAngle);
231
-
232
- // Don't use the point if direction changed too rapidly
233
- if (!(isPathBeginning && isStartPoint) && directionChange > options.maxDirectionChange) {
234
- continue;
235
- }
236
-
237
- // Calculate neighbor point and align to global grid
238
- const rawNeighbor = currentPoint.clone().translate(direction.gridOffsetX || 0, direction.gridOffsetY || 0);
239
-
240
- // Align to global grid for consistent path alignment
241
- const neighborPoint = new _geometry.Point(Math.round(rawNeighbor.x / grid.x) * grid.x, Math.round(rawNeighbor.y / grid.y) * grid.y).round(precision);
242
- const neighborKey = (0, _utils.getKey)(neighborPoint);
243
-
244
- // Skip if closed or not accessible
245
- if (openSet.isClose(neighborKey) || !map.isAccessible(neighborPoint)) {
246
- continue;
247
- }
248
-
249
- // Check if we can reach any end point directly from this neighbor
250
- // This allows connecting to end points that are not on the grid
251
- let canReachEndPoint = false;
252
- let reachableEndPoint = null;
253
- for (const endPt of endPoints) {
254
- const distanceToEnd = neighborPoint.manhattanDistance(endPt);
255
-
256
- // If close enough to end point (within step distance), try direct connection
257
- if (distanceToEnd < options.step * 1.5) {
258
- // Check if we can move directly to the end point
259
- const dx = endPt.x - neighborPoint.x;
260
- const dy = endPt.y - neighborPoint.y;
261
-
262
- // Allow direct connection if it's orthogonal or close to orthogonal
263
- const isOrthogonal = Math.abs(dx) < 0.1 || Math.abs(dy) < 0.1;
264
- if (isOrthogonal && map.isAccessible(endPt)) {
265
- canReachEndPoint = true;
266
- reachableEndPoint = endPt;
267
- break;
268
- }
269
- }
270
- }
271
-
272
- // If we can reach an end point directly, add it as the final step
273
- if (canReachEndPoint && reachableEndPoint) {
274
- const endKey = (0, _utils.getKey)(reachableEndPoint);
275
- const endCost = neighborPoint.manhattanDistance(reachableEndPoint);
276
- const totalCost = currentCost + direction.cost + endCost;
277
- if (!openSet.isOpen(endKey) || totalCost < (costs.get(endKey) || Infinity)) {
278
- points.set(endKey, reachableEndPoint);
279
- parents.set(endKey, neighborPoint);
280
- costs.set(endKey, totalCost);
281
-
282
- // Also add the neighbor point if not already added
283
- if (!points.has(neighborKey)) {
284
- points.set(neighborKey, neighborPoint);
285
- parents.set(neighborKey, currentPoint);
286
- costs.set(neighborKey, currentCost + direction.cost);
287
- }
288
-
289
- // Check if this is our target end point
290
- if (endPointsKeys.has(endKey)) {
291
- options.previousDirectionAngle = directionAngle;
292
- return (0, _utils.reconstructRoute)(parents, points, reachableEndPoint, startPoint, endPoint);
293
- }
294
- }
295
- }
296
-
297
- // Check if neighbor is an end point (exact match)
298
- if (endPointsKeys.has(neighborKey)) {
299
- const isEndPoint = neighborPoint.equals(endPoint);
300
- if (!isEndPoint) {
301
- const endDirectionAngle = (0, _utils.getDirectionAngle)(neighborPoint, endPoint, numDirections, grid, options);
302
- const endDirectionChange = (0, _utils.getDirectionChange)(directionAngle, endDirectionAngle);
303
- if (endDirectionChange > options.maxDirectionChange) {
304
- continue;
305
- }
306
- }
307
- }
308
-
309
- // Calculate costs
310
- const neighborCost = direction.cost;
311
- const neighborPenalty = isStartPoint ? 0 : options.penalties[directionChange] || 0;
312
- const costFromStart = currentCost + neighborCost + neighborPenalty;
313
-
314
- // Update if not in open set or found better path
315
- if (!openSet.isOpen(neighborKey) || costFromStart < (costs.get(neighborKey) || Infinity)) {
316
- points.set(neighborKey, neighborPoint);
317
- parents.set(neighborKey, currentPoint);
318
- costs.set(neighborKey, costFromStart);
319
- openSet.add(neighborKey, costFromStart + (0, _utils.getCost)(neighborPoint, endPoints));
320
- }
321
- }
322
- loopsRemaining -= 1;
323
- }
324
-
325
- // No path found, try fallback
326
- if (options.fallbackRoute) {
327
- return options.fallbackRoute(startPoint, endPoint);
328
- }
329
- return null;
330
- }
@@ -1,3 +0,0 @@
1
- export { SortedSet } from './SortedSet';
2
- export { findRoute } from './findRoute';
3
- //# sourceMappingURL=index.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/pathfinder/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AACvC,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA"}
@@ -1,19 +0,0 @@
1
- "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
6
- Object.defineProperty(exports, "SortedSet", {
7
- enumerable: true,
8
- get: function () {
9
- return _SortedSet.SortedSet;
10
- }
11
- });
12
- Object.defineProperty(exports, "findRoute", {
13
- enumerable: true,
14
- get: function () {
15
- return _findRoute.findRoute;
16
- }
17
- });
18
- var _SortedSet = require("./SortedSet");
19
- var _findRoute = require("./findRoute");
@@ -1,3 +0,0 @@
1
- export { pointsToPath, snapPathToGrid } from './pathConverter';
2
- export { parseSVGPath, simplifyPath } from './pathParser';
3
- //# sourceMappingURL=index.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/svg/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAA;AAC9D,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,cAAc,CAAA"}
package/cjs/svg/index.js DELETED
@@ -1,31 +0,0 @@
1
- "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
6
- Object.defineProperty(exports, "parseSVGPath", {
7
- enumerable: true,
8
- get: function () {
9
- return _pathParser.parseSVGPath;
10
- }
11
- });
12
- Object.defineProperty(exports, "pointsToPath", {
13
- enumerable: true,
14
- get: function () {
15
- return _pathConverter.pointsToPath;
16
- }
17
- });
18
- Object.defineProperty(exports, "simplifyPath", {
19
- enumerable: true,
20
- get: function () {
21
- return _pathParser.simplifyPath;
22
- }
23
- });
24
- Object.defineProperty(exports, "snapPathToGrid", {
25
- enumerable: true,
26
- get: function () {
27
- return _pathConverter.snapPathToGrid;
28
- }
29
- });
30
- var _pathConverter = require("./pathConverter");
31
- var _pathParser = require("./pathParser");
@@ -1,10 +0,0 @@
1
- import { Point } from '../geometry';
2
- /**
3
- * Convert array of points to SVG path string
4
- */
5
- export declare function pointsToPath(points: Point[], precision: number, borderRadius?: number): string;
6
- /**
7
- * Snap path to grid by aligning consecutive points
8
- */
9
- export declare function snapPathToGrid(points: Point[], gridSize: number): Point[];
10
- //# sourceMappingURL=pathConverter.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"pathConverter.d.ts","sourceRoot":"","sources":["../../src/svg/pathConverter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAA;AAEnC;;GAEG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,KAAK,EAAE,EAAE,SAAS,EAAE,MAAM,EAAE,YAAY,GAAE,MAAU,GAAG,MAAM,CA2EjG;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,KAAK,EAAE,EAAE,QAAQ,EAAE,MAAM,GAAG,KAAK,EAAE,CAgCzE"}
@@ -1,116 +0,0 @@
1
- "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
6
- exports.pointsToPath = pointsToPath;
7
- exports.snapPathToGrid = snapPathToGrid;
8
- /**
9
- * Convert array of points to SVG path string
10
- */
11
- function pointsToPath(points, precision, borderRadius = 0) {
12
- if (points.length === 0) {
13
- return '';
14
- }
15
- const factor = Math.pow(10, precision);
16
- const roundCoord = value => Math.round(value * factor) / factor;
17
-
18
- // If no border radius or only 2 points, use simple line path
19
- if (borderRadius === 0 || points.length <= 2) {
20
- const firstPoint = points[0];
21
- let path = `M ${roundCoord(firstPoint.x)} ${roundCoord(firstPoint.y)}`;
22
- for (let i = 1; i < points.length; i++) {
23
- const point = points[i];
24
- path += ` L ${roundCoord(point.x)} ${roundCoord(point.y)}`;
25
- }
26
- return path;
27
- }
28
-
29
- // Start with M (moveTo) command for first point
30
- const firstPoint = points[0];
31
- let path = `M ${roundCoord(firstPoint.x)} ${roundCoord(firstPoint.y)}`;
32
-
33
- // Process each segment with rounded corners
34
- for (let i = 1; i < points.length - 1; i++) {
35
- const prev = points[i - 1];
36
- const current = points[i];
37
- const next = points[i + 1];
38
-
39
- // Calculate direction vectors
40
- const dx1 = current.x - prev.x;
41
- const dy1 = current.y - prev.y;
42
- const dx2 = next.x - current.x;
43
- const dy2 = next.y - current.y;
44
-
45
- // Calculate distances
46
- const dist1 = Math.sqrt(dx1 * dx1 + dy1 * dy1);
47
- const dist2 = Math.sqrt(dx2 * dx2 + dy2 * dy2);
48
-
49
- // Use the smaller of borderRadius or half the segment length
50
- const radius = Math.min(borderRadius, dist1 / 2, dist2 / 2);
51
-
52
- // Normalize direction vectors
53
- const ndx1 = dx1 / dist1;
54
- const ndy1 = dy1 / dist1;
55
- const ndx2 = dx2 / dist2;
56
- const ndy2 = dy2 / dist2;
57
-
58
- // Calculate the point before the corner
59
- const beforeCorner = {
60
- x: current.x - ndx1 * radius,
61
- y: current.y - ndy1 * radius
62
- };
63
-
64
- // Calculate the point after the corner
65
- const afterCorner = {
66
- x: current.x + ndx2 * radius,
67
- y: current.y + ndy2 * radius
68
- };
69
-
70
- // Draw line to the point before corner
71
- path += ` L ${roundCoord(beforeCorner.x)} ${roundCoord(beforeCorner.y)}`;
72
-
73
- // Draw quadratic bezier curve for the rounded corner
74
- // The control point is the actual corner point
75
- path += ` Q ${roundCoord(current.x)} ${roundCoord(current.y)} ${roundCoord(afterCorner.x)} ${roundCoord(afterCorner.y)}`;
76
- }
77
-
78
- // Draw line to the last point
79
- const lastPoint = points[points.length - 1];
80
- path += ` L ${roundCoord(lastPoint.x)} ${roundCoord(lastPoint.y)}`;
81
- return path;
82
- }
83
-
84
- /**
85
- * Snap path to grid by aligning consecutive points
86
- */
87
- function snapPathToGrid(points, gridSize) {
88
- if (points.length <= 1) {
89
- return points;
90
- }
91
- const snappedPoints = [...points];
92
-
93
- // Don't snap the first and last points (anchors)
94
- // Don't snap the second and second-to-last points (extension points)
95
- // Only snap intermediate segments
96
- for (let i = 2; i < snappedPoints.length - 3; i++) {
97
- const first = snappedPoints[i];
98
- const second = snappedPoints[i + 1];
99
- if (first.x === second.x) {
100
- // Vertical line - snap X coordinate
101
- const x = gridSize * Math.round(first.x / gridSize);
102
- if (first.x !== x) {
103
- first.x = x;
104
- second.x = x;
105
- }
106
- } else if (first.y === second.y) {
107
- // Horizontal line - snap Y coordinate
108
- const y = gridSize * Math.round(first.y / gridSize);
109
- if (first.y !== y) {
110
- first.y = y;
111
- second.y = y;
112
- }
113
- }
114
- }
115
- return snappedPoints;
116
- }