From 89068c56f3236b65e392cdc8794c5bc1977e5556 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Mon, 30 Dec 2024 17:18:26 +0000 Subject: Pass lots more information during GeoData::walk --- game/geoData.cpp | 45 ++++++++++++++++++++++++--------------------- game/geoData.h | 22 ++++++++++++++++------ test/test-geoData.cpp | 11 +++++++---- 3 files changed, 47 insertions(+), 31 deletions(-) diff --git a/game/geoData.cpp b/game/geoData.cpp index fb3cb15..ce88e5b 100644 --- a/game/geoData.cpp +++ b/game/geoData.cpp @@ -236,12 +236,12 @@ GeoData::intersectRay(const Ray & ray, FaceHandle face) const GeoData::IntersectionResult out; walkUntil(PointFace {ray.start, face}, ray.start.xy() + (ray.direction.xy() * RelativePosition2D(upperExtent.xy() - lowerExtent.xy())), - [&out, &ray, this](FaceHandle face) { + [&out, &ray, this](const auto & step) { BaryPosition bari {}; RelativeDistance dist {}; - const auto t = triangle<3>(face); + const auto t = triangle<3>(step.current); if (ray.intersectTriangle(t.x, t.y, t.z, bari, dist)) { - out.emplace(t * bari, face); + out.emplace(t * bari, step.current); return true; } return false; @@ -250,7 +250,7 @@ GeoData::intersectRay(const Ray & ray, FaceHandle face) const } void -GeoData::walk(const PointFace & from, const GlobalPosition2D to, const std::function & op) const +GeoData::walk(const PointFace & from, const GlobalPosition2D to, Consumer op) const { walkUntil(from, to, [&op](const auto & fh) { op(fh); @@ -259,41 +259,44 @@ GeoData::walk(const PointFace & from, const GlobalPosition2D to, const std::func } void -GeoData::walkUntil(const PointFace & from, const GlobalPosition2D to, const std::function & op) const +GeoData::walkUntil(const PointFace & from, const GlobalPosition2D to, Tester op) const { - auto f = from.face(this); - if (!f.is_valid()) { + WalkStep step { + .current = from.face(this), + }; + if (!step.current.is_valid()) { const auto entryEdge = findEntry(from.point, to); if (!entryEdge.is_valid()) { return; } - f = opposite_face_handle(entryEdge); + step.current = opposite_face_handle(entryEdge); } - FaceHandle previousFace; - while (f.is_valid() && !op(f)) { - for (auto next = cfh_iter(f); next.is_valid(); ++next) { - f = opposite_face_handle(*next); - if (f.is_valid() && f != previousFace) { - const auto e1 = point(to_vertex_handle(*next)); - const auto e2 = point(to_vertex_handle(opposite_halfedge_handle(*next))); + while (step.current.is_valid() && !op(step)) { + step.previous = step.current; + for (const auto next : fh_range(step.current)) { + step.current = opposite_face_handle(next); + if (step.current.is_valid() && step.current != step.previous) { + const auto e1 = point(to_vertex_handle(next)); + const auto e2 = point(to_vertex_handle(opposite_halfedge_handle(next))); if (linesCrossLtR(from.point, to, e1, e2)) { - previousFace = f; + step.exitHalfedge = next; + step.exitPosition = linesIntersectAt(from.point.xy(), to.xy(), e1.xy(), e2.xy()).value(); break; } } - f.reset(); + step.current.reset(); } } } void -GeoData::boundaryWalk(const std::function & op) const +GeoData::boundaryWalk(Consumer op) const { boundaryWalk(op, findBoundaryStart()); } void -GeoData::boundaryWalk(const std::function & op, HalfedgeHandle start) const +GeoData::boundaryWalk(Consumer op, HalfedgeHandle start) const { assert(is_boundary(start)); boundaryWalkUntil( @@ -305,13 +308,13 @@ GeoData::boundaryWalk(const std::function & op, HalfedgeHa } void -GeoData::boundaryWalkUntil(const std::function & op) const +GeoData::boundaryWalkUntil(Tester op) const { boundaryWalkUntil(op, findBoundaryStart()); } void -GeoData::boundaryWalkUntil(const std::function & op, HalfedgeHandle start) const +GeoData::boundaryWalkUntil(Tester op, HalfedgeHandle start) const { assert(is_boundary(start)); if (!op(start)) { diff --git a/game/geoData.h b/game/geoData.h index b3ef22a..68ce9a2 100644 --- a/game/geoData.h +++ b/game/geoData.h @@ -64,13 +64,23 @@ public: [[nodiscard]] IntersectionResult intersectRay(const Ray &) const; [[nodiscard]] IntersectionResult intersectRay(const Ray &, FaceHandle start) const; - void walk(const PointFace & from, const GlobalPosition2D to, const std::function & op) const; - void walkUntil(const PointFace & from, const GlobalPosition2D to, const std::function & op) const; + struct WalkStep { + FaceHandle current; + FaceHandle previous {}; + HalfedgeHandle exitHalfedge {}; + GlobalPosition2D exitPosition {}; + }; + + template using Consumer = const std::function &; + template using Tester = const std::function &; + + void walk(const PointFace & from, const GlobalPosition2D to, Consumer op) const; + void walkUntil(const PointFace & from, const GlobalPosition2D to, Tester op) const; - void boundaryWalk(const std::function &) const; - void boundaryWalk(const std::function &, HalfedgeHandle start) const; - void boundaryWalkUntil(const std::function &) const; - void boundaryWalkUntil(const std::function &, HalfedgeHandle start) const; + void boundaryWalk(Consumer) const; + void boundaryWalk(Consumer, HalfedgeHandle start) const; + void boundaryWalkUntil(Tester) const; + void boundaryWalkUntil(Tester, HalfedgeHandle start) const; [[nodiscard]] HalfedgeHandle findEntry(const GlobalPosition2D from, const GlobalPosition2D to) const; diff --git a/test/test-geoData.cpp b/test/test-geoData.cpp index 589f675..dd68375 100644 --- a/test/test-geoData.cpp +++ b/test/test-geoData.cpp @@ -148,8 +148,11 @@ BOOST_DATA_TEST_CASE(walkTerrain, from, to, visits) { std::vector visited; - BOOST_CHECK_NO_THROW(fixedTerrtain.walk(from, to, [&visited](auto fh) { - visited.emplace_back(fh.idx()); + BOOST_CHECK_NO_THROW(fixedTerrtain.walk(from, to, [&visited](auto step) { + if (!visited.empty()) { + BOOST_CHECK_EQUAL(step.previous.idx(), visited.back()); + } + visited.emplace_back(step.current.idx()); })); BOOST_CHECK_EQUAL_COLLECTIONS(visited.begin(), visited.end(), visits.begin(), visits.end()); } @@ -181,8 +184,8 @@ BOOST_DATA_TEST_CASE(walkTerrainUntil, from, to, visits) { std::vector visited; - BOOST_CHECK_NO_THROW(fixedTerrtain.walkUntil(from, to, [&visited](auto fh) { - visited.emplace_back(fh.idx()); + BOOST_CHECK_NO_THROW(fixedTerrtain.walkUntil(from, to, [&visited](const auto & step) { + visited.emplace_back(step.current.idx()); return visited.size() >= 5; })); BOOST_CHECK_EQUAL_COLLECTIONS(visited.begin(), visited.end(), visits.begin(), visits.end()); -- cgit v1.2.3