@esengine/pathfinding 12.1.2 → 13.0.0
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/dist/{IIncrementalPathfinding-3qs7e_pO.d.ts → KDTree-Bw4Faf2O.d.ts} +371 -1
- package/dist/{chunk-TPT7Q3E3.js → chunk-OA7ZZQMH.js} +906 -2
- package/dist/chunk-OA7ZZQMH.js.map +1 -0
- package/dist/ecs.d.ts +382 -2
- package/dist/ecs.js +687 -2
- package/dist/ecs.js.map +1 -1
- package/dist/index.d.ts +28 -3
- package/dist/index.js +17 -3
- package/dist/index.js.map +1 -1
- package/package.json +5 -5
- package/dist/chunk-TPT7Q3E3.js.map +0 -1
|
@@ -1612,6 +1612,903 @@ function createCombinedSmoother(curveSegments, tension) {
|
|
|
1612
1612
|
}
|
|
1613
1613
|
__name(createCombinedSmoother, "createCombinedSmoother");
|
|
1614
1614
|
|
|
1615
|
+
// src/avoidance/ILocalAvoidance.ts
|
|
1616
|
+
var DEFAULT_ORCA_CONFIG = {
|
|
1617
|
+
defaultTimeHorizon: 2,
|
|
1618
|
+
defaultTimeHorizonObst: 1,
|
|
1619
|
+
timeStep: 1 / 60,
|
|
1620
|
+
epsilon: 1e-5
|
|
1621
|
+
};
|
|
1622
|
+
var DEFAULT_AGENT_PARAMS = {
|
|
1623
|
+
radius: 0.5,
|
|
1624
|
+
maxSpeed: 5,
|
|
1625
|
+
neighborDist: 15,
|
|
1626
|
+
maxNeighbors: 10,
|
|
1627
|
+
timeHorizon: 2,
|
|
1628
|
+
timeHorizonObst: 1
|
|
1629
|
+
};
|
|
1630
|
+
|
|
1631
|
+
// src/avoidance/LinearProgram.ts
|
|
1632
|
+
import { Vector2 } from "@esengine/ecs-framework-math";
|
|
1633
|
+
var EPSILON = 1e-5;
|
|
1634
|
+
var { dot, det, lengthSq } = Vector2;
|
|
1635
|
+
function linearProgram1(lines, lineNo, radius, optVelocity, directionOpt, result) {
|
|
1636
|
+
const line = lines[lineNo];
|
|
1637
|
+
const dotProduct = dot(line.point, line.direction);
|
|
1638
|
+
const discriminant = dotProduct * dotProduct + radius * radius - lengthSq(line.point);
|
|
1639
|
+
if (discriminant < 0) {
|
|
1640
|
+
return false;
|
|
1641
|
+
}
|
|
1642
|
+
const sqrtDiscriminant = Math.sqrt(discriminant);
|
|
1643
|
+
let tLeft = -dotProduct - sqrtDiscriminant;
|
|
1644
|
+
let tRight = -dotProduct + sqrtDiscriminant;
|
|
1645
|
+
for (let i = 0; i < lineNo; i++) {
|
|
1646
|
+
const constraint = lines[i];
|
|
1647
|
+
const denominator = det(line.direction, constraint.direction);
|
|
1648
|
+
const numerator = det(constraint.direction, {
|
|
1649
|
+
x: line.point.x - constraint.point.x,
|
|
1650
|
+
y: line.point.y - constraint.point.y
|
|
1651
|
+
});
|
|
1652
|
+
if (Math.abs(denominator) <= EPSILON) {
|
|
1653
|
+
if (numerator < 0) {
|
|
1654
|
+
return false;
|
|
1655
|
+
}
|
|
1656
|
+
continue;
|
|
1657
|
+
}
|
|
1658
|
+
const t2 = numerator / denominator;
|
|
1659
|
+
if (denominator >= 0) {
|
|
1660
|
+
tRight = Math.min(tRight, t2);
|
|
1661
|
+
} else {
|
|
1662
|
+
tLeft = Math.max(tLeft, t2);
|
|
1663
|
+
}
|
|
1664
|
+
if (tLeft > tRight) {
|
|
1665
|
+
return false;
|
|
1666
|
+
}
|
|
1667
|
+
}
|
|
1668
|
+
let t;
|
|
1669
|
+
if (directionOpt) {
|
|
1670
|
+
if (dot(optVelocity, line.direction) > 0) {
|
|
1671
|
+
t = tRight;
|
|
1672
|
+
} else {
|
|
1673
|
+
t = tLeft;
|
|
1674
|
+
}
|
|
1675
|
+
} else {
|
|
1676
|
+
t = dot(line.direction, {
|
|
1677
|
+
x: optVelocity.x - line.point.x,
|
|
1678
|
+
y: optVelocity.y - line.point.y
|
|
1679
|
+
});
|
|
1680
|
+
if (t < tLeft) {
|
|
1681
|
+
t = tLeft;
|
|
1682
|
+
} else if (t > tRight) {
|
|
1683
|
+
t = tRight;
|
|
1684
|
+
}
|
|
1685
|
+
}
|
|
1686
|
+
result.x = line.point.x + t * line.direction.x;
|
|
1687
|
+
result.y = line.point.y + t * line.direction.y;
|
|
1688
|
+
return true;
|
|
1689
|
+
}
|
|
1690
|
+
__name(linearProgram1, "linearProgram1");
|
|
1691
|
+
function linearProgram2(lines, radius, optVelocity, directionOpt, result) {
|
|
1692
|
+
if (directionOpt) {
|
|
1693
|
+
result.x = optVelocity.x * radius;
|
|
1694
|
+
result.y = optVelocity.y * radius;
|
|
1695
|
+
} else if (lengthSq(optVelocity) > radius * radius) {
|
|
1696
|
+
const len2 = Math.sqrt(lengthSq(optVelocity));
|
|
1697
|
+
result.x = optVelocity.x / len2 * radius;
|
|
1698
|
+
result.y = optVelocity.y / len2 * radius;
|
|
1699
|
+
} else {
|
|
1700
|
+
result.x = optVelocity.x;
|
|
1701
|
+
result.y = optVelocity.y;
|
|
1702
|
+
}
|
|
1703
|
+
for (let i = 0; i < lines.length; i++) {
|
|
1704
|
+
const line = lines[i];
|
|
1705
|
+
const detVal = det(line.direction, {
|
|
1706
|
+
x: line.point.x - result.x,
|
|
1707
|
+
y: line.point.y - result.y
|
|
1708
|
+
});
|
|
1709
|
+
if (detVal > 0) {
|
|
1710
|
+
const tempResult = result.clone();
|
|
1711
|
+
if (!linearProgram1(lines, i, radius, optVelocity, directionOpt, result)) {
|
|
1712
|
+
result.copy(tempResult);
|
|
1713
|
+
return i;
|
|
1714
|
+
}
|
|
1715
|
+
}
|
|
1716
|
+
}
|
|
1717
|
+
return lines.length;
|
|
1718
|
+
}
|
|
1719
|
+
__name(linearProgram2, "linearProgram2");
|
|
1720
|
+
function linearProgram3(lines, numObstLines, beginLine, radius, result) {
|
|
1721
|
+
let distance = 0;
|
|
1722
|
+
for (let i = beginLine; i < lines.length; i++) {
|
|
1723
|
+
const line = lines[i];
|
|
1724
|
+
if (det(line.direction, {
|
|
1725
|
+
x: line.point.x - result.x,
|
|
1726
|
+
y: line.point.y - result.y
|
|
1727
|
+
}) > distance) {
|
|
1728
|
+
const projLines = [];
|
|
1729
|
+
for (let j = 0; j < numObstLines; j++) {
|
|
1730
|
+
projLines.push(lines[j]);
|
|
1731
|
+
}
|
|
1732
|
+
for (let j = numObstLines; j < i; j++) {
|
|
1733
|
+
const line1 = lines[j];
|
|
1734
|
+
const line2 = lines[i];
|
|
1735
|
+
let newLine;
|
|
1736
|
+
const determinant = det(line1.direction, line2.direction);
|
|
1737
|
+
if (Math.abs(determinant) <= EPSILON) {
|
|
1738
|
+
if (dot(line1.direction, line2.direction) > 0) {
|
|
1739
|
+
continue;
|
|
1740
|
+
}
|
|
1741
|
+
newLine = {
|
|
1742
|
+
point: {
|
|
1743
|
+
x: 0.5 * (line1.point.x + line2.point.x),
|
|
1744
|
+
y: 0.5 * (line1.point.y + line2.point.y)
|
|
1745
|
+
},
|
|
1746
|
+
direction: {
|
|
1747
|
+
x: 0,
|
|
1748
|
+
y: 0
|
|
1749
|
+
}
|
|
1750
|
+
};
|
|
1751
|
+
} else {
|
|
1752
|
+
const diff = {
|
|
1753
|
+
x: line1.point.x - line2.point.x,
|
|
1754
|
+
y: line1.point.y - line2.point.y
|
|
1755
|
+
};
|
|
1756
|
+
const t = det(line2.direction, diff) / determinant;
|
|
1757
|
+
newLine = {
|
|
1758
|
+
point: {
|
|
1759
|
+
x: line1.point.x + t * line1.direction.x,
|
|
1760
|
+
y: line1.point.y + t * line1.direction.y
|
|
1761
|
+
},
|
|
1762
|
+
direction: {
|
|
1763
|
+
x: 0,
|
|
1764
|
+
y: 0
|
|
1765
|
+
}
|
|
1766
|
+
};
|
|
1767
|
+
}
|
|
1768
|
+
const dirDiff = {
|
|
1769
|
+
x: line1.direction.x - line2.direction.x,
|
|
1770
|
+
y: line1.direction.y - line2.direction.y
|
|
1771
|
+
};
|
|
1772
|
+
const dirLen = Math.sqrt(lengthSq(dirDiff));
|
|
1773
|
+
if (dirLen > EPSILON) {
|
|
1774
|
+
newLine.direction.x = dirDiff.x / dirLen;
|
|
1775
|
+
newLine.direction.y = dirDiff.y / dirLen;
|
|
1776
|
+
}
|
|
1777
|
+
projLines.push(newLine);
|
|
1778
|
+
}
|
|
1779
|
+
const tempResult = result.clone();
|
|
1780
|
+
const optVelocity = {
|
|
1781
|
+
x: -lines[i].direction.y,
|
|
1782
|
+
y: lines[i].direction.x
|
|
1783
|
+
};
|
|
1784
|
+
if (linearProgram2(projLines, radius, optVelocity, true, result) < projLines.length) {
|
|
1785
|
+
result.copy(tempResult);
|
|
1786
|
+
}
|
|
1787
|
+
distance = det(lines[i].direction, {
|
|
1788
|
+
x: lines[i].point.x - result.x,
|
|
1789
|
+
y: lines[i].point.y - result.y
|
|
1790
|
+
});
|
|
1791
|
+
}
|
|
1792
|
+
}
|
|
1793
|
+
}
|
|
1794
|
+
__name(linearProgram3, "linearProgram3");
|
|
1795
|
+
function solveORCALinearProgram(lines, numObstLines, maxSpeed, preferredVelocity) {
|
|
1796
|
+
const result = new Vector2();
|
|
1797
|
+
const lineFail = linearProgram2(lines, maxSpeed, preferredVelocity, false, result);
|
|
1798
|
+
if (lineFail < lines.length) {
|
|
1799
|
+
linearProgram3(lines, numObstLines, lineFail, maxSpeed, result);
|
|
1800
|
+
}
|
|
1801
|
+
return result;
|
|
1802
|
+
}
|
|
1803
|
+
__name(solveORCALinearProgram, "solveORCALinearProgram");
|
|
1804
|
+
|
|
1805
|
+
// src/avoidance/ORCASolver.ts
|
|
1806
|
+
import { Vector2 as Vector22 } from "@esengine/ecs-framework-math";
|
|
1807
|
+
|
|
1808
|
+
// src/avoidance/ObstacleBuilder.ts
|
|
1809
|
+
var EPSILON2 = 1e-5;
|
|
1810
|
+
function leftOf(p1, p2, p3) {
|
|
1811
|
+
return (p1.x - p3.x) * (p2.y - p1.y) - (p1.y - p3.y) * (p2.x - p1.x);
|
|
1812
|
+
}
|
|
1813
|
+
__name(leftOf, "leftOf");
|
|
1814
|
+
function createObstacleVertices(vertices, startId = 0) {
|
|
1815
|
+
const n = vertices.length;
|
|
1816
|
+
if (n < 2) {
|
|
1817
|
+
return [];
|
|
1818
|
+
}
|
|
1819
|
+
const obstacleVertices = [];
|
|
1820
|
+
for (let i = 0; i < n; i++) {
|
|
1821
|
+
obstacleVertices.push({
|
|
1822
|
+
point: {
|
|
1823
|
+
x: vertices[i].x,
|
|
1824
|
+
y: vertices[i].y
|
|
1825
|
+
},
|
|
1826
|
+
direction: {
|
|
1827
|
+
x: 0,
|
|
1828
|
+
y: 0
|
|
1829
|
+
},
|
|
1830
|
+
next: null,
|
|
1831
|
+
previous: null,
|
|
1832
|
+
isConvex: false,
|
|
1833
|
+
id: startId + i
|
|
1834
|
+
});
|
|
1835
|
+
}
|
|
1836
|
+
for (let i = 0; i < n; i++) {
|
|
1837
|
+
const curr = obstacleVertices[i];
|
|
1838
|
+
const next = obstacleVertices[(i + 1) % n];
|
|
1839
|
+
const prev = obstacleVertices[(i + n - 1) % n];
|
|
1840
|
+
curr.next = next;
|
|
1841
|
+
curr.previous = prev;
|
|
1842
|
+
const dx = next.point.x - curr.point.x;
|
|
1843
|
+
const dy = next.point.y - curr.point.y;
|
|
1844
|
+
const edgeLen = Math.sqrt(dx * dx + dy * dy);
|
|
1845
|
+
if (edgeLen > EPSILON2) {
|
|
1846
|
+
curr.direction = {
|
|
1847
|
+
x: dx / edgeLen,
|
|
1848
|
+
y: dy / edgeLen
|
|
1849
|
+
};
|
|
1850
|
+
} else {
|
|
1851
|
+
curr.direction = {
|
|
1852
|
+
x: 1,
|
|
1853
|
+
y: 0
|
|
1854
|
+
};
|
|
1855
|
+
}
|
|
1856
|
+
}
|
|
1857
|
+
for (let i = 0; i < n; i++) {
|
|
1858
|
+
const curr = obstacleVertices[i];
|
|
1859
|
+
const prev = curr.previous;
|
|
1860
|
+
const next = curr.next;
|
|
1861
|
+
curr.isConvex = leftOf(prev.point, curr.point, next.point) >= 0;
|
|
1862
|
+
}
|
|
1863
|
+
return obstacleVertices;
|
|
1864
|
+
}
|
|
1865
|
+
__name(createObstacleVertices, "createObstacleVertices");
|
|
1866
|
+
function buildObstacleVertices(obstacles) {
|
|
1867
|
+
const allVertices = [];
|
|
1868
|
+
let nextId = 0;
|
|
1869
|
+
for (const obstacle of obstacles) {
|
|
1870
|
+
const vertices = createObstacleVertices(obstacle.vertices, nextId);
|
|
1871
|
+
allVertices.push(...vertices);
|
|
1872
|
+
nextId += vertices.length;
|
|
1873
|
+
}
|
|
1874
|
+
return allVertices;
|
|
1875
|
+
}
|
|
1876
|
+
__name(buildObstacleVertices, "buildObstacleVertices");
|
|
1877
|
+
|
|
1878
|
+
// src/avoidance/ORCASolver.ts
|
|
1879
|
+
var EPSILON3 = 1e-5;
|
|
1880
|
+
var { det: det2, dot: dot2, lengthSq: lengthSq2, len } = Vector22;
|
|
1881
|
+
function normalize(v) {
|
|
1882
|
+
const length = len(v);
|
|
1883
|
+
if (length < EPSILON3) {
|
|
1884
|
+
return {
|
|
1885
|
+
x: 0,
|
|
1886
|
+
y: 0
|
|
1887
|
+
};
|
|
1888
|
+
}
|
|
1889
|
+
return {
|
|
1890
|
+
x: v.x / length,
|
|
1891
|
+
y: v.y / length
|
|
1892
|
+
};
|
|
1893
|
+
}
|
|
1894
|
+
__name(normalize, "normalize");
|
|
1895
|
+
var _ORCASolver = class _ORCASolver {
|
|
1896
|
+
constructor(config = {}) {
|
|
1897
|
+
__publicField(this, "config");
|
|
1898
|
+
this.config = {
|
|
1899
|
+
...DEFAULT_ORCA_CONFIG,
|
|
1900
|
+
...config
|
|
1901
|
+
};
|
|
1902
|
+
}
|
|
1903
|
+
/**
|
|
1904
|
+
* @zh 计算代理的新速度
|
|
1905
|
+
* @en Compute new velocity for agent
|
|
1906
|
+
*
|
|
1907
|
+
* @param agent - @zh 当前代理 @en Current agent
|
|
1908
|
+
* @param neighbors - @zh 邻近代理列表 @en List of neighboring agents
|
|
1909
|
+
* @param obstacles - @zh 障碍物列表 @en List of obstacles
|
|
1910
|
+
* @param deltaTime - @zh 时间步长 @en Time step
|
|
1911
|
+
* @returns @zh 计算得到的新速度 @en Computed new velocity
|
|
1912
|
+
*/
|
|
1913
|
+
computeNewVelocity(agent, neighbors, obstacles, deltaTime) {
|
|
1914
|
+
const orcaLines = [];
|
|
1915
|
+
const obstacleVertices = buildObstacleVertices(obstacles);
|
|
1916
|
+
const numObstLines = this.createObstacleORCALines(agent, obstacleVertices, orcaLines);
|
|
1917
|
+
this.createAgentORCALines(agent, neighbors, deltaTime, orcaLines);
|
|
1918
|
+
return solveORCALinearProgram(orcaLines, numObstLines, agent.maxSpeed, agent.preferredVelocity);
|
|
1919
|
+
}
|
|
1920
|
+
/**
|
|
1921
|
+
* @zh 创建代理间的 ORCA 约束线
|
|
1922
|
+
* @en Create ORCA constraint lines for agent-agent avoidance
|
|
1923
|
+
*/
|
|
1924
|
+
createAgentORCALines(agent, neighbors, deltaTime, orcaLines) {
|
|
1925
|
+
const invTimeHorizon = 1 / agent.timeHorizon;
|
|
1926
|
+
for (const other of neighbors) {
|
|
1927
|
+
if (other.id === agent.id) continue;
|
|
1928
|
+
const relativePosition = {
|
|
1929
|
+
x: other.position.x - agent.position.x,
|
|
1930
|
+
y: other.position.y - agent.position.y
|
|
1931
|
+
};
|
|
1932
|
+
const relativeVelocity = {
|
|
1933
|
+
x: agent.velocity.x - other.velocity.x,
|
|
1934
|
+
y: agent.velocity.y - other.velocity.y
|
|
1935
|
+
};
|
|
1936
|
+
const distSq = lengthSq2(relativePosition);
|
|
1937
|
+
const combinedRadius = agent.radius + other.radius;
|
|
1938
|
+
const combinedRadiusSq = combinedRadius * combinedRadius;
|
|
1939
|
+
const line = {
|
|
1940
|
+
point: {
|
|
1941
|
+
x: 0,
|
|
1942
|
+
y: 0
|
|
1943
|
+
},
|
|
1944
|
+
direction: {
|
|
1945
|
+
x: 0,
|
|
1946
|
+
y: 0
|
|
1947
|
+
}
|
|
1948
|
+
};
|
|
1949
|
+
let u;
|
|
1950
|
+
if (distSq > combinedRadiusSq) {
|
|
1951
|
+
const w = {
|
|
1952
|
+
x: relativeVelocity.x - invTimeHorizon * relativePosition.x,
|
|
1953
|
+
y: relativeVelocity.y - invTimeHorizon * relativePosition.y
|
|
1954
|
+
};
|
|
1955
|
+
const wLengthSq = lengthSq2(w);
|
|
1956
|
+
const dotProduct1 = dot2(w, relativePosition);
|
|
1957
|
+
if (dotProduct1 < 0 && dotProduct1 * dotProduct1 > combinedRadiusSq * wLengthSq) {
|
|
1958
|
+
const wLength = Math.sqrt(wLengthSq);
|
|
1959
|
+
const unitW = normalize(w);
|
|
1960
|
+
line.direction = {
|
|
1961
|
+
x: unitW.y,
|
|
1962
|
+
y: -unitW.x
|
|
1963
|
+
};
|
|
1964
|
+
u = {
|
|
1965
|
+
x: (combinedRadius * invTimeHorizon - wLength) * unitW.x,
|
|
1966
|
+
y: (combinedRadius * invTimeHorizon - wLength) * unitW.y
|
|
1967
|
+
};
|
|
1968
|
+
} else {
|
|
1969
|
+
const leg = Math.sqrt(distSq - combinedRadiusSq);
|
|
1970
|
+
if (det2(relativePosition, w) > 0) {
|
|
1971
|
+
line.direction = {
|
|
1972
|
+
x: (relativePosition.x * leg - relativePosition.y * combinedRadius) / distSq,
|
|
1973
|
+
y: (relativePosition.x * combinedRadius + relativePosition.y * leg) / distSq
|
|
1974
|
+
};
|
|
1975
|
+
} else {
|
|
1976
|
+
line.direction = {
|
|
1977
|
+
x: -(relativePosition.x * leg + relativePosition.y * combinedRadius) / distSq,
|
|
1978
|
+
y: -(-relativePosition.x * combinedRadius + relativePosition.y * leg) / distSq
|
|
1979
|
+
};
|
|
1980
|
+
}
|
|
1981
|
+
const dotProduct2 = dot2(relativeVelocity, line.direction);
|
|
1982
|
+
u = {
|
|
1983
|
+
x: dotProduct2 * line.direction.x - relativeVelocity.x,
|
|
1984
|
+
y: dotProduct2 * line.direction.y - relativeVelocity.y
|
|
1985
|
+
};
|
|
1986
|
+
}
|
|
1987
|
+
} else {
|
|
1988
|
+
const invTimeStep = 1 / deltaTime;
|
|
1989
|
+
const w = {
|
|
1990
|
+
x: relativeVelocity.x - invTimeStep * relativePosition.x,
|
|
1991
|
+
y: relativeVelocity.y - invTimeStep * relativePosition.y
|
|
1992
|
+
};
|
|
1993
|
+
const wLength = len(w);
|
|
1994
|
+
const unitW = wLength > EPSILON3 ? {
|
|
1995
|
+
x: w.x / wLength,
|
|
1996
|
+
y: w.y / wLength
|
|
1997
|
+
} : {
|
|
1998
|
+
x: 1,
|
|
1999
|
+
y: 0
|
|
2000
|
+
};
|
|
2001
|
+
line.direction = {
|
|
2002
|
+
x: unitW.y,
|
|
2003
|
+
y: -unitW.x
|
|
2004
|
+
};
|
|
2005
|
+
u = {
|
|
2006
|
+
x: (combinedRadius * invTimeStep - wLength) * unitW.x,
|
|
2007
|
+
y: (combinedRadius * invTimeStep - wLength) * unitW.y
|
|
2008
|
+
};
|
|
2009
|
+
}
|
|
2010
|
+
line.point = {
|
|
2011
|
+
x: agent.velocity.x + 0.5 * u.x,
|
|
2012
|
+
y: agent.velocity.y + 0.5 * u.y
|
|
2013
|
+
};
|
|
2014
|
+
orcaLines.push(line);
|
|
2015
|
+
}
|
|
2016
|
+
}
|
|
2017
|
+
/**
|
|
2018
|
+
* @zh 创建障碍物的 ORCA 约束线
|
|
2019
|
+
* @en Create ORCA constraint lines for obstacle avoidance
|
|
2020
|
+
*/
|
|
2021
|
+
createObstacleORCALines(agent, obstacleVertices, orcaLines) {
|
|
2022
|
+
const invTimeHorizonObst = 1 / agent.timeHorizonObst;
|
|
2023
|
+
const radiusSq = agent.radius * agent.radius;
|
|
2024
|
+
let numObstLines = 0;
|
|
2025
|
+
for (const obstacle1 of obstacleVertices) {
|
|
2026
|
+
const obstacle2 = obstacle1.next;
|
|
2027
|
+
const relativePosition1 = {
|
|
2028
|
+
x: obstacle1.point.x - agent.position.x,
|
|
2029
|
+
y: obstacle1.point.y - agent.position.y
|
|
2030
|
+
};
|
|
2031
|
+
const relativePosition2 = {
|
|
2032
|
+
x: obstacle2.point.x - agent.position.x,
|
|
2033
|
+
y: obstacle2.point.y - agent.position.y
|
|
2034
|
+
};
|
|
2035
|
+
const obstacleVector = {
|
|
2036
|
+
x: obstacle2.point.x - obstacle1.point.x,
|
|
2037
|
+
y: obstacle2.point.y - obstacle1.point.y
|
|
2038
|
+
};
|
|
2039
|
+
const signedDistToEdge = det2(obstacleVector, relativePosition1);
|
|
2040
|
+
if (signedDistToEdge < -EPSILON3) {
|
|
2041
|
+
continue;
|
|
2042
|
+
}
|
|
2043
|
+
let alreadyCovered = false;
|
|
2044
|
+
for (const existingLine of orcaLines) {
|
|
2045
|
+
const scaledRelPos1 = {
|
|
2046
|
+
x: invTimeHorizonObst * relativePosition1.x - existingLine.point.x,
|
|
2047
|
+
y: invTimeHorizonObst * relativePosition1.y - existingLine.point.y
|
|
2048
|
+
};
|
|
2049
|
+
const scaledRelPos2 = {
|
|
2050
|
+
x: invTimeHorizonObst * relativePosition2.x - existingLine.point.x,
|
|
2051
|
+
y: invTimeHorizonObst * relativePosition2.y - existingLine.point.y
|
|
2052
|
+
};
|
|
2053
|
+
if (det2(scaledRelPos1, existingLine.direction) - invTimeHorizonObst * agent.radius >= -EPSILON3 && det2(scaledRelPos2, existingLine.direction) - invTimeHorizonObst * agent.radius >= -EPSILON3) {
|
|
2054
|
+
alreadyCovered = true;
|
|
2055
|
+
break;
|
|
2056
|
+
}
|
|
2057
|
+
}
|
|
2058
|
+
if (alreadyCovered) {
|
|
2059
|
+
continue;
|
|
2060
|
+
}
|
|
2061
|
+
const distSq1 = lengthSq2(relativePosition1);
|
|
2062
|
+
const distSq2 = lengthSq2(relativePosition2);
|
|
2063
|
+
const obstacleVectorSq = lengthSq2(obstacleVector);
|
|
2064
|
+
const s = obstacleVectorSq > EPSILON3 ? -dot2(relativePosition1, obstacleVector) / obstacleVectorSq : 0;
|
|
2065
|
+
const distSqLineToEdge = lengthSq2({
|
|
2066
|
+
x: -relativePosition1.x - s * obstacleVector.x,
|
|
2067
|
+
y: -relativePosition1.y - s * obstacleVector.y
|
|
2068
|
+
});
|
|
2069
|
+
const line = {
|
|
2070
|
+
point: {
|
|
2071
|
+
x: 0,
|
|
2072
|
+
y: 0
|
|
2073
|
+
},
|
|
2074
|
+
direction: {
|
|
2075
|
+
x: 0,
|
|
2076
|
+
y: 0
|
|
2077
|
+
}
|
|
2078
|
+
};
|
|
2079
|
+
if (s < 0 && distSq1 <= radiusSq) {
|
|
2080
|
+
if (obstacle1.isConvex) {
|
|
2081
|
+
line.point = {
|
|
2082
|
+
x: 0,
|
|
2083
|
+
y: 0
|
|
2084
|
+
};
|
|
2085
|
+
line.direction = normalize({
|
|
2086
|
+
x: -relativePosition1.y,
|
|
2087
|
+
y: relativePosition1.x
|
|
2088
|
+
});
|
|
2089
|
+
orcaLines.push(line);
|
|
2090
|
+
numObstLines++;
|
|
2091
|
+
}
|
|
2092
|
+
continue;
|
|
2093
|
+
}
|
|
2094
|
+
if (s > 1 && distSq2 <= radiusSq) {
|
|
2095
|
+
if (obstacle2.isConvex && det2(relativePosition2, obstacle2.direction) >= 0) {
|
|
2096
|
+
line.point = {
|
|
2097
|
+
x: 0,
|
|
2098
|
+
y: 0
|
|
2099
|
+
};
|
|
2100
|
+
line.direction = normalize({
|
|
2101
|
+
x: -relativePosition2.y,
|
|
2102
|
+
y: relativePosition2.x
|
|
2103
|
+
});
|
|
2104
|
+
orcaLines.push(line);
|
|
2105
|
+
numObstLines++;
|
|
2106
|
+
}
|
|
2107
|
+
continue;
|
|
2108
|
+
}
|
|
2109
|
+
if (s >= 0 && s <= 1 && distSqLineToEdge <= radiusSq) {
|
|
2110
|
+
line.point = {
|
|
2111
|
+
x: 0,
|
|
2112
|
+
y: 0
|
|
2113
|
+
};
|
|
2114
|
+
line.direction = {
|
|
2115
|
+
x: -obstacle1.direction.x,
|
|
2116
|
+
y: -obstacle1.direction.y
|
|
2117
|
+
};
|
|
2118
|
+
orcaLines.push(line);
|
|
2119
|
+
numObstLines++;
|
|
2120
|
+
continue;
|
|
2121
|
+
}
|
|
2122
|
+
let obs1 = obstacle1;
|
|
2123
|
+
let obs2 = obstacle2;
|
|
2124
|
+
let leftLegDirection;
|
|
2125
|
+
let rightLegDirection;
|
|
2126
|
+
if (s < 0 && distSqLineToEdge <= radiusSq) {
|
|
2127
|
+
if (!obstacle1.isConvex) continue;
|
|
2128
|
+
obs2 = obstacle1;
|
|
2129
|
+
const leg1 = Math.sqrt(Math.max(0, distSq1 - radiusSq));
|
|
2130
|
+
leftLegDirection = {
|
|
2131
|
+
x: (relativePosition1.x * leg1 - relativePosition1.y * agent.radius) / distSq1,
|
|
2132
|
+
y: (relativePosition1.x * agent.radius + relativePosition1.y * leg1) / distSq1
|
|
2133
|
+
};
|
|
2134
|
+
rightLegDirection = {
|
|
2135
|
+
x: (relativePosition1.x * leg1 + relativePosition1.y * agent.radius) / distSq1,
|
|
2136
|
+
y: (-relativePosition1.x * agent.radius + relativePosition1.y * leg1) / distSq1
|
|
2137
|
+
};
|
|
2138
|
+
} else if (s > 1 && distSqLineToEdge <= radiusSq) {
|
|
2139
|
+
if (!obstacle2.isConvex) continue;
|
|
2140
|
+
obs1 = obstacle2;
|
|
2141
|
+
const leg2 = Math.sqrt(Math.max(0, distSq2 - radiusSq));
|
|
2142
|
+
leftLegDirection = {
|
|
2143
|
+
x: (relativePosition2.x * leg2 - relativePosition2.y * agent.radius) / distSq2,
|
|
2144
|
+
y: (relativePosition2.x * agent.radius + relativePosition2.y * leg2) / distSq2
|
|
2145
|
+
};
|
|
2146
|
+
rightLegDirection = {
|
|
2147
|
+
x: (relativePosition2.x * leg2 + relativePosition2.y * agent.radius) / distSq2,
|
|
2148
|
+
y: (-relativePosition2.x * agent.radius + relativePosition2.y * leg2) / distSq2
|
|
2149
|
+
};
|
|
2150
|
+
} else {
|
|
2151
|
+
if (obstacle1.isConvex) {
|
|
2152
|
+
const leg1 = Math.sqrt(Math.max(0, distSq1 - radiusSq));
|
|
2153
|
+
leftLegDirection = {
|
|
2154
|
+
x: (relativePosition1.x * leg1 - relativePosition1.y * agent.radius) / distSq1,
|
|
2155
|
+
y: (relativePosition1.x * agent.radius + relativePosition1.y * leg1) / distSq1
|
|
2156
|
+
};
|
|
2157
|
+
} else {
|
|
2158
|
+
leftLegDirection = {
|
|
2159
|
+
x: -obstacle1.direction.x,
|
|
2160
|
+
y: -obstacle1.direction.y
|
|
2161
|
+
};
|
|
2162
|
+
}
|
|
2163
|
+
if (obstacle2.isConvex) {
|
|
2164
|
+
const leg2 = Math.sqrt(Math.max(0, distSq2 - radiusSq));
|
|
2165
|
+
rightLegDirection = {
|
|
2166
|
+
x: (relativePosition2.x * leg2 + relativePosition2.y * agent.radius) / distSq2,
|
|
2167
|
+
y: (-relativePosition2.x * agent.radius + relativePosition2.y * leg2) / distSq2
|
|
2168
|
+
};
|
|
2169
|
+
} else {
|
|
2170
|
+
rightLegDirection = {
|
|
2171
|
+
x: obstacle1.direction.x,
|
|
2172
|
+
y: obstacle1.direction.y
|
|
2173
|
+
};
|
|
2174
|
+
}
|
|
2175
|
+
}
|
|
2176
|
+
const leftNeighbor = obs1.previous;
|
|
2177
|
+
let isLeftLegForeign = false;
|
|
2178
|
+
let isRightLegForeign = false;
|
|
2179
|
+
if (obs1.isConvex) {
|
|
2180
|
+
const negLeftNeighborDir = {
|
|
2181
|
+
x: -leftNeighbor.direction.x,
|
|
2182
|
+
y: -leftNeighbor.direction.y
|
|
2183
|
+
};
|
|
2184
|
+
if (det2(leftLegDirection, negLeftNeighborDir) >= 0) {
|
|
2185
|
+
leftLegDirection = negLeftNeighborDir;
|
|
2186
|
+
isLeftLegForeign = true;
|
|
2187
|
+
}
|
|
2188
|
+
}
|
|
2189
|
+
if (obs2.isConvex) {
|
|
2190
|
+
if (det2(rightLegDirection, obs2.direction) <= 0) {
|
|
2191
|
+
rightLegDirection = {
|
|
2192
|
+
x: obs2.direction.x,
|
|
2193
|
+
y: obs2.direction.y
|
|
2194
|
+
};
|
|
2195
|
+
isRightLegForeign = true;
|
|
2196
|
+
}
|
|
2197
|
+
}
|
|
2198
|
+
const leftCutoff = {
|
|
2199
|
+
x: invTimeHorizonObst * (obs1.point.x - agent.position.x),
|
|
2200
|
+
y: invTimeHorizonObst * (obs1.point.y - agent.position.y)
|
|
2201
|
+
};
|
|
2202
|
+
const rightCutoff = {
|
|
2203
|
+
x: invTimeHorizonObst * (obs2.point.x - agent.position.x),
|
|
2204
|
+
y: invTimeHorizonObst * (obs2.point.y - agent.position.y)
|
|
2205
|
+
};
|
|
2206
|
+
const cutoffVector = {
|
|
2207
|
+
x: rightCutoff.x - leftCutoff.x,
|
|
2208
|
+
y: rightCutoff.y - leftCutoff.y
|
|
2209
|
+
};
|
|
2210
|
+
const sameVertex = obs1 === obs2;
|
|
2211
|
+
const cutoffVectorSq = lengthSq2(cutoffVector);
|
|
2212
|
+
const t = sameVertex ? 0.5 : cutoffVectorSq > EPSILON3 ? dot2({
|
|
2213
|
+
x: agent.velocity.x - leftCutoff.x,
|
|
2214
|
+
y: agent.velocity.y - leftCutoff.y
|
|
2215
|
+
}, cutoffVector) / cutoffVectorSq : 0.5;
|
|
2216
|
+
const tLeft = dot2({
|
|
2217
|
+
x: agent.velocity.x - leftCutoff.x,
|
|
2218
|
+
y: agent.velocity.y - leftCutoff.y
|
|
2219
|
+
}, leftLegDirection);
|
|
2220
|
+
const tRight = dot2({
|
|
2221
|
+
x: agent.velocity.x - rightCutoff.x,
|
|
2222
|
+
y: agent.velocity.y - rightCutoff.y
|
|
2223
|
+
}, rightLegDirection);
|
|
2224
|
+
if (t < 0 && tLeft < 0 || sameVertex && tLeft < 0 && tRight < 0) {
|
|
2225
|
+
const unitW = normalize({
|
|
2226
|
+
x: agent.velocity.x - leftCutoff.x,
|
|
2227
|
+
y: agent.velocity.y - leftCutoff.y
|
|
2228
|
+
});
|
|
2229
|
+
line.direction = {
|
|
2230
|
+
x: unitW.y,
|
|
2231
|
+
y: -unitW.x
|
|
2232
|
+
};
|
|
2233
|
+
line.point = {
|
|
2234
|
+
x: leftCutoff.x + agent.radius * invTimeHorizonObst * unitW.x,
|
|
2235
|
+
y: leftCutoff.y + agent.radius * invTimeHorizonObst * unitW.y
|
|
2236
|
+
};
|
|
2237
|
+
orcaLines.push(line);
|
|
2238
|
+
numObstLines++;
|
|
2239
|
+
continue;
|
|
2240
|
+
}
|
|
2241
|
+
if (t > 1 && tRight < 0) {
|
|
2242
|
+
const unitW = normalize({
|
|
2243
|
+
x: agent.velocity.x - rightCutoff.x,
|
|
2244
|
+
y: agent.velocity.y - rightCutoff.y
|
|
2245
|
+
});
|
|
2246
|
+
line.direction = {
|
|
2247
|
+
x: unitW.y,
|
|
2248
|
+
y: -unitW.x
|
|
2249
|
+
};
|
|
2250
|
+
line.point = {
|
|
2251
|
+
x: rightCutoff.x + agent.radius * invTimeHorizonObst * unitW.x,
|
|
2252
|
+
y: rightCutoff.y + agent.radius * invTimeHorizonObst * unitW.y
|
|
2253
|
+
};
|
|
2254
|
+
orcaLines.push(line);
|
|
2255
|
+
numObstLines++;
|
|
2256
|
+
continue;
|
|
2257
|
+
}
|
|
2258
|
+
const distSqCutoff = t < 0 || t > 1 || sameVertex ? Infinity : lengthSq2({
|
|
2259
|
+
x: agent.velocity.x - (leftCutoff.x + t * cutoffVector.x),
|
|
2260
|
+
y: agent.velocity.y - (leftCutoff.y + t * cutoffVector.y)
|
|
2261
|
+
});
|
|
2262
|
+
const distSqLeft = tLeft < 0 ? Infinity : lengthSq2({
|
|
2263
|
+
x: agent.velocity.x - (leftCutoff.x + tLeft * leftLegDirection.x),
|
|
2264
|
+
y: agent.velocity.y - (leftCutoff.y + tLeft * leftLegDirection.y)
|
|
2265
|
+
});
|
|
2266
|
+
const distSqRight = tRight < 0 ? Infinity : lengthSq2({
|
|
2267
|
+
x: agent.velocity.x - (rightCutoff.x + tRight * rightLegDirection.x),
|
|
2268
|
+
y: agent.velocity.y - (rightCutoff.y + tRight * rightLegDirection.y)
|
|
2269
|
+
});
|
|
2270
|
+
if (distSqCutoff <= distSqLeft && distSqCutoff <= distSqRight) {
|
|
2271
|
+
line.direction = {
|
|
2272
|
+
x: -obs1.direction.x,
|
|
2273
|
+
y: -obs1.direction.y
|
|
2274
|
+
};
|
|
2275
|
+
line.point = {
|
|
2276
|
+
x: leftCutoff.x + agent.radius * invTimeHorizonObst * -line.direction.y,
|
|
2277
|
+
y: leftCutoff.y + agent.radius * invTimeHorizonObst * line.direction.x
|
|
2278
|
+
};
|
|
2279
|
+
orcaLines.push(line);
|
|
2280
|
+
numObstLines++;
|
|
2281
|
+
continue;
|
|
2282
|
+
}
|
|
2283
|
+
if (distSqLeft <= distSqRight) {
|
|
2284
|
+
if (isLeftLegForeign) {
|
|
2285
|
+
continue;
|
|
2286
|
+
}
|
|
2287
|
+
line.direction = {
|
|
2288
|
+
x: leftLegDirection.x,
|
|
2289
|
+
y: leftLegDirection.y
|
|
2290
|
+
};
|
|
2291
|
+
line.point = {
|
|
2292
|
+
x: leftCutoff.x + agent.radius * invTimeHorizonObst * -line.direction.y,
|
|
2293
|
+
y: leftCutoff.y + agent.radius * invTimeHorizonObst * line.direction.x
|
|
2294
|
+
};
|
|
2295
|
+
orcaLines.push(line);
|
|
2296
|
+
numObstLines++;
|
|
2297
|
+
continue;
|
|
2298
|
+
}
|
|
2299
|
+
if (isRightLegForeign) {
|
|
2300
|
+
continue;
|
|
2301
|
+
}
|
|
2302
|
+
line.direction = {
|
|
2303
|
+
x: -rightLegDirection.x,
|
|
2304
|
+
y: -rightLegDirection.y
|
|
2305
|
+
};
|
|
2306
|
+
line.point = {
|
|
2307
|
+
x: rightCutoff.x + agent.radius * invTimeHorizonObst * -line.direction.y,
|
|
2308
|
+
y: rightCutoff.y + agent.radius * invTimeHorizonObst * line.direction.x
|
|
2309
|
+
};
|
|
2310
|
+
orcaLines.push(line);
|
|
2311
|
+
numObstLines++;
|
|
2312
|
+
}
|
|
2313
|
+
return numObstLines;
|
|
2314
|
+
}
|
|
2315
|
+
};
|
|
2316
|
+
__name(_ORCASolver, "ORCASolver");
|
|
2317
|
+
var ORCASolver = _ORCASolver;
|
|
2318
|
+
function createORCASolver(config) {
|
|
2319
|
+
return new ORCASolver(config);
|
|
2320
|
+
}
|
|
2321
|
+
__name(createORCASolver, "createORCASolver");
|
|
2322
|
+
|
|
2323
|
+
// src/avoidance/KDTree.ts
|
|
2324
|
+
var _KDTree = class _KDTree {
|
|
2325
|
+
constructor() {
|
|
2326
|
+
__publicField(this, "agents", []);
|
|
2327
|
+
__publicField(this, "agentIndices", []);
|
|
2328
|
+
__publicField(this, "nodes", []);
|
|
2329
|
+
/**
|
|
2330
|
+
* @zh 最大叶节点大小
|
|
2331
|
+
* @en Maximum leaf size
|
|
2332
|
+
*/
|
|
2333
|
+
__publicField(this, "maxLeafSize", 10);
|
|
2334
|
+
}
|
|
2335
|
+
/**
|
|
2336
|
+
* @zh 构建 KD-Tree
|
|
2337
|
+
* @en Build KD-Tree
|
|
2338
|
+
*/
|
|
2339
|
+
build(agents) {
|
|
2340
|
+
this.agents = agents;
|
|
2341
|
+
this.agentIndices = [];
|
|
2342
|
+
this.nodes = [];
|
|
2343
|
+
if (agents.length === 0) {
|
|
2344
|
+
return;
|
|
2345
|
+
}
|
|
2346
|
+
for (let i = 0; i < agents.length; i++) {
|
|
2347
|
+
this.agentIndices.push(i);
|
|
2348
|
+
}
|
|
2349
|
+
this.buildRecursive(0, agents.length, 0);
|
|
2350
|
+
}
|
|
2351
|
+
/**
|
|
2352
|
+
* @zh 递归构建 KD-Tree
|
|
2353
|
+
* @en Recursively build KD-Tree
|
|
2354
|
+
*/
|
|
2355
|
+
buildRecursive(begin, end, depth) {
|
|
2356
|
+
const nodeIndex = this.nodes.length;
|
|
2357
|
+
const node = {
|
|
2358
|
+
agentIndex: -1,
|
|
2359
|
+
splitValue: 0,
|
|
2360
|
+
left: -1,
|
|
2361
|
+
right: -1,
|
|
2362
|
+
begin,
|
|
2363
|
+
end,
|
|
2364
|
+
minX: Infinity,
|
|
2365
|
+
minY: Infinity,
|
|
2366
|
+
maxX: -Infinity,
|
|
2367
|
+
maxY: -Infinity
|
|
2368
|
+
};
|
|
2369
|
+
this.nodes.push(node);
|
|
2370
|
+
for (let i = begin; i < end; i++) {
|
|
2371
|
+
const agent = this.agents[this.agentIndices[i]];
|
|
2372
|
+
node.minX = Math.min(node.minX, agent.position.x);
|
|
2373
|
+
node.minY = Math.min(node.minY, agent.position.y);
|
|
2374
|
+
node.maxX = Math.max(node.maxX, agent.position.x);
|
|
2375
|
+
node.maxY = Math.max(node.maxY, agent.position.y);
|
|
2376
|
+
}
|
|
2377
|
+
const count = end - begin;
|
|
2378
|
+
if (count <= this.maxLeafSize) {
|
|
2379
|
+
return nodeIndex;
|
|
2380
|
+
}
|
|
2381
|
+
const splitDim = depth % 2;
|
|
2382
|
+
if (splitDim === 0) {
|
|
2383
|
+
this.sortByX(begin, end);
|
|
2384
|
+
} else {
|
|
2385
|
+
this.sortByY(begin, end);
|
|
2386
|
+
}
|
|
2387
|
+
const mid = Math.floor((begin + end) / 2);
|
|
2388
|
+
const midAgent = this.agents[this.agentIndices[mid]];
|
|
2389
|
+
node.splitValue = splitDim === 0 ? midAgent.position.x : midAgent.position.y;
|
|
2390
|
+
node.left = this.buildRecursive(begin, mid, depth + 1);
|
|
2391
|
+
node.right = this.buildRecursive(mid, end, depth + 1);
|
|
2392
|
+
return nodeIndex;
|
|
2393
|
+
}
|
|
2394
|
+
/**
|
|
2395
|
+
* @zh 按 X 坐标排序
|
|
2396
|
+
* @en Sort by X coordinate
|
|
2397
|
+
*/
|
|
2398
|
+
sortByX(begin, end) {
|
|
2399
|
+
const indices = this.agentIndices;
|
|
2400
|
+
const agents = this.agents;
|
|
2401
|
+
for (let i = begin + 1; i < end; i++) {
|
|
2402
|
+
const key = indices[i];
|
|
2403
|
+
const keyX = agents[key].position.x;
|
|
2404
|
+
let j = i - 1;
|
|
2405
|
+
while (j >= begin && agents[indices[j]].position.x > keyX) {
|
|
2406
|
+
indices[j + 1] = indices[j];
|
|
2407
|
+
j--;
|
|
2408
|
+
}
|
|
2409
|
+
indices[j + 1] = key;
|
|
2410
|
+
}
|
|
2411
|
+
}
|
|
2412
|
+
/**
|
|
2413
|
+
* @zh 按 Y 坐标排序
|
|
2414
|
+
* @en Sort by Y coordinate
|
|
2415
|
+
*/
|
|
2416
|
+
sortByY(begin, end) {
|
|
2417
|
+
const indices = this.agentIndices;
|
|
2418
|
+
const agents = this.agents;
|
|
2419
|
+
for (let i = begin + 1; i < end; i++) {
|
|
2420
|
+
const key = indices[i];
|
|
2421
|
+
const keyY = agents[key].position.y;
|
|
2422
|
+
let j = i - 1;
|
|
2423
|
+
while (j >= begin && agents[indices[j]].position.y > keyY) {
|
|
2424
|
+
indices[j + 1] = indices[j];
|
|
2425
|
+
j--;
|
|
2426
|
+
}
|
|
2427
|
+
indices[j + 1] = key;
|
|
2428
|
+
}
|
|
2429
|
+
}
|
|
2430
|
+
/**
|
|
2431
|
+
* @zh 查询邻居
|
|
2432
|
+
* @en Query neighbors
|
|
2433
|
+
*/
|
|
2434
|
+
queryNeighbors(position, radius, maxResults, excludeId) {
|
|
2435
|
+
const results = [];
|
|
2436
|
+
const radiusSq = radius * radius;
|
|
2437
|
+
if (this.nodes.length === 0) {
|
|
2438
|
+
return results;
|
|
2439
|
+
}
|
|
2440
|
+
this.queryRecursive(0, position, radiusSq, maxResults, excludeId, results);
|
|
2441
|
+
results.sort((a, b) => a.distanceSq - b.distanceSq);
|
|
2442
|
+
if (results.length > maxResults) {
|
|
2443
|
+
results.length = maxResults;
|
|
2444
|
+
}
|
|
2445
|
+
return results;
|
|
2446
|
+
}
|
|
2447
|
+
/**
|
|
2448
|
+
* @zh 递归查询
|
|
2449
|
+
* @en Recursive query
|
|
2450
|
+
*/
|
|
2451
|
+
queryRecursive(nodeIndex, position, radiusSq, maxResults, excludeId, results) {
|
|
2452
|
+
const node = this.nodes[nodeIndex];
|
|
2453
|
+
if (!node) return;
|
|
2454
|
+
const closestX = Math.max(node.minX, Math.min(position.x, node.maxX));
|
|
2455
|
+
const closestY = Math.max(node.minY, Math.min(position.y, node.maxY));
|
|
2456
|
+
const dx = position.x - closestX;
|
|
2457
|
+
const dy = position.y - closestY;
|
|
2458
|
+
const distSqToBBox = dx * dx + dy * dy;
|
|
2459
|
+
if (distSqToBBox > radiusSq) {
|
|
2460
|
+
return;
|
|
2461
|
+
}
|
|
2462
|
+
if (node.left === -1 && node.right === -1) {
|
|
2463
|
+
for (let i = node.begin; i < node.end; i++) {
|
|
2464
|
+
const agentIndex = this.agentIndices[i];
|
|
2465
|
+
const agent = this.agents[agentIndex];
|
|
2466
|
+
if (excludeId !== void 0 && agent.id === excludeId) {
|
|
2467
|
+
continue;
|
|
2468
|
+
}
|
|
2469
|
+
const adx = position.x - agent.position.x;
|
|
2470
|
+
const ady = position.y - agent.position.y;
|
|
2471
|
+
const distSq = adx * adx + ady * ady;
|
|
2472
|
+
if (distSq < radiusSq) {
|
|
2473
|
+
results.push({
|
|
2474
|
+
agent,
|
|
2475
|
+
distanceSq: distSq
|
|
2476
|
+
});
|
|
2477
|
+
}
|
|
2478
|
+
}
|
|
2479
|
+
return;
|
|
2480
|
+
}
|
|
2481
|
+
if (node.left !== -1) {
|
|
2482
|
+
this.queryRecursive(node.left, position, radiusSq, maxResults, excludeId, results);
|
|
2483
|
+
}
|
|
2484
|
+
if (node.right !== -1) {
|
|
2485
|
+
this.queryRecursive(node.right, position, radiusSq, maxResults, excludeId, results);
|
|
2486
|
+
}
|
|
2487
|
+
}
|
|
2488
|
+
/**
|
|
2489
|
+
* @zh 清空索引
|
|
2490
|
+
* @en Clear the index
|
|
2491
|
+
*/
|
|
2492
|
+
clear() {
|
|
2493
|
+
this.agents = [];
|
|
2494
|
+
this.agentIndices = [];
|
|
2495
|
+
this.nodes = [];
|
|
2496
|
+
}
|
|
2497
|
+
/**
|
|
2498
|
+
* @zh 获取代理数量
|
|
2499
|
+
* @en Get agent count
|
|
2500
|
+
*/
|
|
2501
|
+
get agentCount() {
|
|
2502
|
+
return this.agents.length;
|
|
2503
|
+
}
|
|
2504
|
+
};
|
|
2505
|
+
__name(_KDTree, "KDTree");
|
|
2506
|
+
var KDTree = _KDTree;
|
|
2507
|
+
function createKDTree() {
|
|
2508
|
+
return new KDTree();
|
|
2509
|
+
}
|
|
2510
|
+
__name(createKDTree, "createKDTree");
|
|
2511
|
+
|
|
1615
2512
|
export {
|
|
1616
2513
|
createPoint,
|
|
1617
2514
|
EMPTY_PATH_RESULT,
|
|
@@ -1643,6 +2540,13 @@ export {
|
|
|
1643
2540
|
CombinedSmoother,
|
|
1644
2541
|
createLineOfSightSmoother,
|
|
1645
2542
|
createCatmullRomSmoother,
|
|
1646
|
-
createCombinedSmoother
|
|
2543
|
+
createCombinedSmoother,
|
|
2544
|
+
DEFAULT_ORCA_CONFIG,
|
|
2545
|
+
DEFAULT_AGENT_PARAMS,
|
|
2546
|
+
solveORCALinearProgram,
|
|
2547
|
+
ORCASolver,
|
|
2548
|
+
createORCASolver,
|
|
2549
|
+
KDTree,
|
|
2550
|
+
createKDTree
|
|
1647
2551
|
};
|
|
1648
|
-
//# sourceMappingURL=chunk-
|
|
2552
|
+
//# sourceMappingURL=chunk-OA7ZZQMH.js.map
|