Skip to content

Commit 21745f9

Browse files
committed
Optimize scenario pathfinding helpers
1 parent 278be5d commit 21745f9

1 file changed

Lines changed: 92 additions & 20 deletions

File tree

src/domain/ScenarioSimulationInternal.cpp

Lines changed: 92 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,33 @@ bool segmentsIntersect(const Point2D& firstStart, const Point2D& firstEnd, const
195195
|| pointOnSegment(firstEnd, secondStart, secondEnd);
196196
}
197197

198+
bool segmentBoundsOverlap(
199+
const Point2D& firstStart,
200+
const Point2D& firstEnd,
201+
const Point2D& secondStart,
202+
const Point2D& secondEnd,
203+
double padding = 0.0) {
204+
const auto firstMinX = std::min(firstStart.x, firstEnd.x) - padding;
205+
const auto firstMaxX = std::max(firstStart.x, firstEnd.x) + padding;
206+
const auto firstMinY = std::min(firstStart.y, firstEnd.y) - padding;
207+
const auto firstMaxY = std::max(firstStart.y, firstEnd.y) + padding;
208+
const auto secondMinX = std::min(secondStart.x, secondEnd.x);
209+
const auto secondMaxX = std::max(secondStart.x, secondEnd.x);
210+
const auto secondMinY = std::min(secondStart.y, secondEnd.y);
211+
const auto secondMaxY = std::max(secondStart.y, secondEnd.y);
212+
return firstMinX <= secondMaxX
213+
&& firstMaxX >= secondMinX
214+
&& firstMinY <= secondMaxY
215+
&& firstMaxY >= secondMinY;
216+
}
217+
218+
bool pointWithinSegmentBounds(const Point2D& point, const Point2D& start, const Point2D& end, double padding) {
219+
return point.x >= std::min(start.x, end.x) - padding
220+
&& point.x <= std::max(start.x, end.x) + padding
221+
&& point.y >= std::min(start.y, end.y) - padding
222+
&& point.y <= std::max(start.y, end.y) + padding;
223+
}
224+
198225
double distancePointToSegment(const Point2D& point, const Point2D& start, const Point2D& end) {
199226
return distanceBetween(point, closestPointOnSegment(point, start, end));
200227
}
@@ -474,11 +501,16 @@ bool movementCrossesBarrier(const FacilityLayout2D& layout, const Point2D& from,
474501

475502
const auto& vertices = barrier.geometry.vertices;
476503
for (std::size_t index = 0; index + 1 < vertices.size(); ++index) {
504+
if (!segmentBoundsOverlap(from, to, vertices[index], vertices[index + 1])) {
505+
continue;
506+
}
477507
if (segmentsIntersect(from, to, vertices[index], vertices[index + 1])) {
478508
return true;
479509
}
480510
}
481-
if (barrier.geometry.closed && segmentsIntersect(from, to, vertices.back(), vertices.front())) {
511+
if (barrier.geometry.closed
512+
&& segmentBoundsOverlap(from, to, vertices.back(), vertices.front())
513+
&& segmentsIntersect(from, to, vertices.back(), vertices.front())) {
482514
return true;
483515
}
484516
if (barrier.geometry.closed && pointInRing(vertices, to)) {
@@ -513,11 +545,16 @@ bool pointHasClearance(const FacilityLayout2D& layout, const Point2D& point, dou
513545

514546
const auto& vertices = barrier.geometry.vertices;
515547
for (std::size_t index = 0; index + 1 < vertices.size(); ++index) {
548+
if (!pointWithinSegmentBounds(point, vertices[index], vertices[index + 1], clearance)) {
549+
continue;
550+
}
516551
if (distancePointToSegment(point, vertices[index], vertices[index + 1]) < clearance) {
517552
return false;
518553
}
519554
}
520-
if (barrier.geometry.closed && distancePointToSegment(point, vertices.back(), vertices.front()) < clearance) {
555+
if (barrier.geometry.closed
556+
&& pointWithinSegmentBounds(point, vertices.back(), vertices.front(), clearance)
557+
&& distancePointToSegment(point, vertices.back(), vertices.front()) < clearance) {
521558
return false;
522559
}
523560
}
@@ -536,11 +573,16 @@ bool lineOfSightClear(const FacilityLayout2D& layout, const Point2D& from, const
536573

537574
const auto& vertices = barrier.geometry.vertices;
538575
for (std::size_t index = 0; index + 1 < vertices.size(); ++index) {
576+
if (!segmentBoundsOverlap(from, to, vertices[index], vertices[index + 1], clearance)) {
577+
continue;
578+
}
539579
if (segmentDistance(from, to, vertices[index], vertices[index + 1]) < clearance) {
540580
return false;
541581
}
542582
}
543-
if (barrier.geometry.closed && segmentDistance(from, to, vertices.back(), vertices.front()) < clearance) {
583+
if (barrier.geometry.closed
584+
&& segmentBoundsOverlap(from, to, vertices.back(), vertices.front(), clearance)
585+
&& segmentDistance(from, to, vertices.back(), vertices.front()) < clearance) {
544586
return false;
545587
}
546588
}
@@ -578,14 +620,16 @@ bool nearlySamePoint(const Point2D& lhs, const Point2D& rhs) {
578620
}
579621

580622
std::vector<Point2D> buildVisibilityPath(const FacilityLayout2D& layout, const Point2D& start, const Point2D& goal, double clearance) {
581-
if (lineOfSightClear(layout, start, goal, clearance)) {
582-
return {goal};
583-
}
584-
585623
std::vector<VisibilityNode> nodes;
586624
nodes.push_back({.point = start});
587625
nodes.push_back({.point = goal});
588626

627+
std::size_t candidateCapacity = nodes.size();
628+
for (const auto& barrier : layout.barriers) {
629+
candidateCapacity += barrier.blocksMovement ? barrier.geometry.vertices.size() * 8 : 0;
630+
}
631+
nodes.reserve(candidateCapacity);
632+
589633
auto addCandidate = [&](const Point2D& candidate) {
590634
if (std::any_of(nodes.begin(), nodes.end(), [&](const auto& node) {
591635
return nearlySamePoint(node.point, candidate);
@@ -718,19 +762,43 @@ std::optional<std::vector<Point2D>> buildGridPath(
718762
auto nearestVisibleCell = [&](const Point2D& point) -> std::optional<std::size_t> {
719763
std::optional<std::size_t> best;
720764
double bestDistance = std::numeric_limits<double>::infinity();
721-
for (int y = 0; y < height; ++y) {
722-
for (int x = 0; x < width; ++x) {
723-
const auto index = toIndex(x, y);
724-
if (!walkable[index]) {
725-
continue;
765+
const auto centerX = std::clamp(static_cast<int>(std::llround((point.x - minX) / kGridResolution)), 0, width - 1);
766+
const auto centerY = std::clamp(static_cast<int>(std::llround((point.y - minY) / kGridResolution)), 0, height - 1);
767+
const auto maxRing = std::max({centerX, width - 1 - centerX, centerY, height - 1 - centerY});
768+
769+
auto considerCell = [&](int x, int y) {
770+
if (x < 0 || y < 0 || x >= width || y >= height) {
771+
return;
772+
}
773+
const auto index = toIndex(x, y);
774+
if (!walkable[index]) {
775+
return;
776+
}
777+
const auto candidate = toPoint(x, y);
778+
const auto distance = distanceBetween(point, candidate);
779+
if (distance >= bestDistance || !lineOfSightClear(layout, point, candidate, clearance)) {
780+
return;
781+
}
782+
best = index;
783+
bestDistance = distance;
784+
};
785+
786+
for (int ring = 0; ring <= maxRing; ++ring) {
787+
if (ring == 0) {
788+
considerCell(centerX, centerY);
789+
} else {
790+
for (int x = centerX - ring; x <= centerX + ring; ++x) {
791+
considerCell(x, centerY - ring);
792+
considerCell(x, centerY + ring);
726793
}
727-
const auto candidate = toPoint(x, y);
728-
const auto distance = distanceBetween(point, candidate);
729-
if (distance >= bestDistance || !lineOfSightClear(layout, point, candidate, clearance)) {
730-
continue;
794+
for (int y = centerY - ring + 1; y <= centerY + ring - 1; ++y) {
795+
considerCell(centerX - ring, y);
796+
considerCell(centerX + ring, y);
731797
}
732-
best = index;
733-
bestDistance = distance;
798+
}
799+
800+
if (best.has_value() && static_cast<double>(std::max(0, ring - 1)) * kGridResolution > bestDistance) {
801+
break;
734802
}
735803
}
736804
return best;
@@ -829,10 +897,14 @@ std::optional<std::vector<Point2D>> buildGridPath(
829897
}
830898

831899
std::vector<Point2D> buildPath(const FacilityLayout2D& layout, const Point2D& start, const Point2D& goal, double clearance) {
900+
if (lineOfSightClear(layout, start, goal, clearance)) {
901+
return {goal};
902+
}
903+
832904
auto path = buildVisibilityPath(layout, start, goal, clearance);
833-
if (path.size() == 1 && !lineOfSightClear(layout, start, goal, clearance)) {
905+
if (path.size() == 1) {
834906
if (auto gridPath = buildGridPath(layout, start, goal, clearance); gridPath.has_value() && !gridPath->empty()) {
835-
path = *gridPath;
907+
return *gridPath;
836908
}
837909
}
838910
return path;

0 commit comments

Comments
 (0)