Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 41 additions & 27 deletions navmap_core/bench/navmap_bench.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -190,44 +190,58 @@ int main(int argc, char ** argv)
const double us = median_us(R, n, body);
std::snprintf(col[ci++], sizeof(col[0]), "%.1f (%zu)", us, cells / (R * n));
};
run(M, [&](int k) {
navmap::for_each_in_disc(nm, seeds[k], pts[k], 0.5f, count,
navmap::Metric::EUCLIDEAN, &sc);
});
run(M / 10, [&](int k) {
navmap::for_each_in_disc(nm, seeds[k], pts[k], 2.0f, count,
navmap::Metric::EUCLIDEAN, &sc);
});
run(M, [&](int k) {
navmap::for_each_in_disc(nm, seeds[k], pts[k], 0.5f, count,
navmap::Metric::GEODESIC, &sc);
});
run(M / 10, [&](int k) {
navmap::for_each_in_disc(nm, seeds[k], pts[k], 2.0f, count,
navmap::Metric::GEODESIC, &sc);
});
run(M, [&](int k) {
run(
M, [&](int k) {
navmap::for_each_in_disc(
nm, seeds[k], pts[k], 0.5f, count,
navmap::Metric::EUCLIDEAN, &sc);
});
run(
M / 10, [&](int k) {
navmap::for_each_in_disc(
nm, seeds[k], pts[k], 2.0f, count,
navmap::Metric::EUCLIDEAN, &sc);
});
run(
M, [&](int k) {
navmap::for_each_in_disc(
nm, seeds[k], pts[k], 0.5f, count,
navmap::Metric::GEODESIC, &sc);
});
run(
M / 10, [&](int k) {
navmap::for_each_in_disc(
nm, seeds[k], pts[k], 2.0f, count,
navmap::Metric::GEODESIC, &sc);
});
run(
M, [&](int k) {
navmap::AABB b;
b.expand(pts[k] - Eigen::Vector3f(1, 1, 1));
b.expand(pts[k] + Eigen::Vector3f(1, 1, 1));
navmap::for_each_in_aabb(nm, b, count, &sc);
});
run(M, [&](int k) {
run(
M, [&](int k) {
const float x = pts[k].x(), y = pts[k].y();
navmap::for_each_in_polygon(
nm, seeds[k], {{x - 0.5f, y - 0.5f}, {x + 0.5f, y - 0.5f}, {x + 0.5f, y + 0.5f},
{x - 0.5f, y + 0.5f}}, count, &sc);
});
run(M, [&](int k) {
navmap::for_each_on_segment(nm, seeds[k], pts[k],
pts[(k + 1) % M].head<2>().isZero() ? pts[k] :
Eigen::Vector3f(pts[k] + 5.0f * (pts[(k + 1) % M] - pts[k]).normalized()),
[&](NavCelId, float, float) {++cells;});
run(
M, [&](int k) {
navmap::for_each_on_segment(
nm, seeds[k], pts[k],
pts[(k + 1) % M].head<2>().isZero() ? pts[k] :
Eigen::Vector3f(pts[k] + 5.0f * (pts[(k + 1) % M] - pts[k]).normalized()),
[&](NavCelId, float, float) {++cells;});
});
run(
M / 10, [&](int k) {
navmap::for_each_by_distance(
nm, seeds[k], pts[k], 2.0f,
[&](NavCelId, float) {++cells;}, &sc);
});
run(M / 10, [&](int k) {
navmap::for_each_by_distance(nm, seeds[k], pts[k], 2.0f,
[&](NavCelId, float) {++cells;}, &sc);
});
std::printf("%9zu", nm.navcels.size());
for (auto & c : col) {
std::printf(" %16s", c);
Expand Down
4 changes: 2 additions & 2 deletions navmap_core/include/navmap_core/Iterators.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -265,8 +265,8 @@ std::size_t grow(
sc.heap.push_back(e);
std::push_heap(sc.heap.begin(), sc.heap.end(), cmp);
};
auto visible = [&](NavCelId from, const Eigen::Vector3f & p, const Eigen::Vector3f & q,
NavCelId target) {
using V3 = Eigen::Vector3f;
auto visible = [&](NavCelId from, const V3 & p, const V3 & q, NavCelId target) {
NavCelId last = kNoCel;
const bool reached = for_each_on_segment_impl(
nm, from, p, q, [&](NavCelId x, float, float) {last = x;});
Expand Down
4 changes: 2 additions & 2 deletions navmap_core/tests/test_adjacency.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ TEST(NavMap_Adjacency, OnlyTheNonManifoldEdgeIsAffected)
const NavCelId t3 = nm.add_navcel(b, f, c); // regular neighbor of t0 on b-c
for (auto t : {t0, t1, t2, t3}) {
nm.add_navcel_to_surface(s, t);
}
}
nm.rebuild_geometry_accels();

EXPECT_EQ(nm.nonmanifold_edges(), 1u);
Expand Down Expand Up @@ -159,7 +159,7 @@ TEST(NavMap_Adjacency, LargeGridIsManifoldAndSymmetric)
std::size_t links = 0;
for (NavCelId cid = 0; cid < nm.navcels.size(); ++cid) {
links += nm.navcel_neighbors(cid).size();
}
}
// Interior edges: 3 n^2 - 2 n, each linked from both sides.
EXPECT_EQ(links, 2u * (3u * n * n - 2u * n));
}
8 changes: 5 additions & 3 deletions navmap_core/tests/test_combine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,9 @@ NavMap strip(std::size_t n)
}
for (std::size_t k = 0; k < n; ++k) {
const uint32_t i = static_cast<uint32_t>(k / 2) * 2;
const NavCelId c = (k % 2 == 0) ? nm.add_navcel(i, i + 2, i + 3) : nm.add_navcel(i, i + 3,
i + 1);
const NavCelId c = (k % 2 == 0) ? nm.add_navcel(i, i + 2, i + 3) : nm.add_navcel(
i, i + 3,
i + 1);
nm.add_navcel_to_surface(s, c);
}
nm.rebuild_geometry_accels();
Expand Down Expand Up @@ -148,7 +149,8 @@ TEST(Combine, OnlyTheGivenCells)
{
CombineOptions o;
o.cells = {1, 3, 99}; // out of range ids are ignored
EXPECT_EQ(cost({0, 0, 0, 0}, {9, 9, 9, 9}, CombineOp::OVERWRITE, o),
EXPECT_EQ(
cost({0, 0, 0, 0}, {9, 9, 9, 9}, CombineOp::OVERWRITE, o),
(std::vector<uint8_t>{0, 9, 0, 9}));
}

Expand Down
12 changes: 6 additions & 6 deletions navmap_core/tests/test_distance_field.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ TEST(NavMap_DistanceField, SeedCellsGiveStraightLineDistance)
}
for (NavCelId s : seeds) {
EXPECT_FLOAT_EQ(d[s], 0.0f);
}
}

// Seeds and boundary together: the nearest of both.
const auto both = nm.distance_field(seeds, true);
Expand Down Expand Up @@ -162,10 +162,10 @@ TEST(NavMap_DistanceField, StackedFloorsDoNotSeeEachOther)
const auto d = nm.distance_field({low}, false);
for (auto c : nm.surfaces[1].navcels) {
EXPECT_EQ(d[c], kInf);
}
}
for (auto c : nm.surfaces[0].navcels) {
EXPECT_LT(d[c], kInf);
}
}

// Boundary of the upper floor only reaches the upper floor's own cells.
const NavCelId high = cell_near(nm, 2.6f, 2.6f, 2.5f);
Expand Down Expand Up @@ -199,7 +199,7 @@ TEST(NavMap_DistanceField, InteriorHoleEdgesAreBoundary)
const auto ref = brute(nm, {}, true);
for (NavCelId c = 0; c < nm.navcels.size(); ++c) {
EXPECT_NEAR(d[c], ref[c], 1e-4f) << c;
}
}
// Next to the 1x1 m hole (x, y in [4.5, 5.5]).
EXPECT_LT(d[cell_near(nm, 4.2f, 5.0f, 0.0f)], 0.31f);
}
Expand Down Expand Up @@ -244,11 +244,11 @@ TEST(NavMap_DistanceField, DegenerateInputs)
nm.rebuild_geometry_accels();
for (float v : nm.distance_field({}, false)) {
EXPECT_EQ(v, kInf);
}
}
const auto d = nm.distance_field({9999}, false); // out of range: ignored
for (float v : d) {
EXPECT_EQ(v, kInf);
}
}
const auto z = nm.distance_field({0}, false, 0.0f); // only the seed itself
EXPECT_FLOAT_EQ(z[0], 0.0f);
EXPECT_EQ(std::count_if(z.begin(), z.end(), [](float v) {return v < kInf;}), 1);
Expand Down
9 changes: 6 additions & 3 deletions navmap_core/tests/test_geometry.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -156,15 +156,18 @@ TEST(Geometry_RayTriangle, RaysThroughASharedEdgeAlwaysHit) {
for (const float off : {0.0f, 5.0f, 100.0f, 1000.0f}) {
for (const float size : {0.1f, 3.0f, 30.0f}) {
const Vec3 a(off, off, 4.7f), b(off + size, off - 0.3f * size, 4.7f);
const Vec3 c(off + 0.4f * size, off + 0.9f * size, 4.701f), d(off + 1.3f * size, off + size,
const Vec3 c(off + 0.4f * size, off + 0.9f * size, 4.701f), d(
off + 1.3f * size, off + size,
4.702f);
for (int i = 1; i < 500; ++i) {
const float s = i / 500.0f;
const Vec3 p = b + s * (c - b); // on the shared edge b-c
float t, u, v;
const bool h1 = navmap::ray_triangle_intersect(p + Vec3(0, 0, 1), Vec3(0, 0, -1), a, b, c,
const bool h1 = navmap::ray_triangle_intersect(
p + Vec3(0, 0, 1), Vec3(0, 0, -1), a, b, c,
t, u, v);
const bool h2 = navmap::ray_triangle_intersect(p + Vec3(0, 0, 1), Vec3(0, 0, -1), b, d, c,
const bool h2 = navmap::ray_triangle_intersect(
p + Vec3(0, 0, 1), Vec3(0, 0, -1), b, d, c,
t, u, v);
ASSERT_TRUE(h1 || h2) << "offset " << off << " size " << size << " s " << s;
}
Expand Down
10 changes: 6 additions & 4 deletions navmap_core/tests/test_incremental.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -61,10 +61,11 @@ void add_grid(
std::vector<NavMap> maps()
{
std::vector<NavMap> out(3);
add_grid(out[0], 20, 20, 0.5f, [](float, float) {return 0.0f;},
add_grid(
out[0], 20, 20, 0.5f, [](float, float) {return 0.0f;},
[](int i, int j) {
return (i == 8 && j > 3 && j < 15) || (i > 12 && i < 15 && j > 12 && j < 15);
});
});
add_grid(out[1], 16, 16, 0.5f, [](float, float) {return 0.0f;});
add_grid(out[1], 16, 16, 0.5f, [](float, float) {return 3.0f;});
add_grid(out[2], 30, 6, 0.4f, [](float x, float) {return 0.25f * x;});
Expand Down Expand Up @@ -106,7 +107,8 @@ std::vector<float> brute(
for (NavCelId c = 0; c < nm.navcels.size(); ++c) {
for (int e = 0; e < 3; ++e) {
if (nm.navcels[c].neighbor[e] != std::numeric_limits<NavCelId>::max()) {continue;}
all.push_back({nm.positions.at(nm.navcels[c].v[e]),
all.push_back(
{nm.positions.at(nm.navcels[c].v[e]),
nm.positions.at(nm.navcels[c].v[(e + 1) % 3]), c});
}
}
Expand Down Expand Up @@ -240,7 +242,7 @@ TEST(DistanceFieldIncremental, AddingAndRemovingTheSameCellAndEdgeIds)
df.update({}, {5});
for (float d : df.distances()) {
EXPECT_TRUE(std::isinf(d));
}
}
// A seed on the upper floor never reaches the lower one
NavCelId upper = 0;
for (NavCelId c = 0; c < nm.navcels.size(); ++c) {
Expand Down
64 changes: 40 additions & 24 deletions navmap_core/tests/test_iterators.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -233,21 +233,25 @@ TEST(Iterators, DiscEdgeValues)
const NavCelId seed = seed_at(nm, c);
for (const Metric m : {Metric::EUCLIDEAN, Metric::GEODESIC}) {
// Radius 0, or below the seed's centroid: just the seed
EXPECT_EQ(collect([&](auto f) {return navmap::for_each_in_disc(nm, seed, c, 0.0f, f, m);}),
EXPECT_EQ(
collect([&](auto f) {return navmap::for_each_in_disc(nm, seed, c, 0.0f, f, m);}),
std::set<NavCelId>{seed});
// Negative or NaN radius, bad seed: nothing
EXPECT_EQ(navmap::for_each_in_disc(nm, seed, c, -1.0f, [](NavCelId) {}, m), 0u);
EXPECT_EQ(navmap::for_each_in_disc(nm, seed, c, NAN, [](NavCelId) {}, m), 0u);
EXPECT_EQ(navmap::for_each_in_disc(nm, NavCelId{100000}, c, 1.0f, [](NavCelId) {}, m), 0u);
// Off the map: nothing
EXPECT_EQ(navmap::for_each_in_disc(nm, Eigen::Vector3f(50, 50, 0), 3.0f, [](NavCelId) {}, m),
EXPECT_EQ(
navmap::for_each_in_disc(nm, Eigen::Vector3f(50, 50, 0), 3.0f, [](NavCelId) {}, m),
0u);
// Early stop
int calls = 0;
EXPECT_EQ(navmap::for_each_in_disc(nm, seed, c, 3.0f, [&](NavCelId) {return ++calls < 5;}, m),
EXPECT_EQ(
navmap::for_each_in_disc(nm, seed, c, 3.0f, [&](NavCelId) {return ++calls < 5;}, m),
5u);
}
EXPECT_EQ(navmap::for_each_in_disc(NavMap{}, Eigen::Vector3f(0, 0, 0), 1.0f, [](NavCelId) {}),
EXPECT_EQ(
navmap::for_each_in_disc(NavMap{}, Eigen::Vector3f(0, 0, 0), 1.0f, [](NavCelId) {}),
0u);
}

Expand Down Expand Up @@ -276,7 +280,7 @@ TEST(Iterators, GeodesicDiscDoesNotCrossAWallThatEuclideanSees)
EXPECT_FALSE(g_far.count(b));
for (NavCelId x : g_far) {
EXPECT_TRUE(e_far.count(x)) << x;
} // geodesic >= Euclidean
} // geodesic >= Euclidean
}

TEST(Iterators, GeodesicDistanceAroundAWallIsTheShortestDetour)
Expand All @@ -289,7 +293,8 @@ TEST(Iterators, GeodesicDistanceAroundAWallIsTheShortestDetour)
const Eigen::Vector3f c(4.75f, 2.0f, 0.0f);
const NavCelId seed = seed_at(nm, c), b = seed_at(nm, {5.75f, 2.0f, 0.0f});
float db = -1.0f;
navmap::for_each_by_distance(nm, seed, c, 30.0f, [&](NavCelId x, float d) {
navmap::for_each_by_distance(
nm, seed, c, 30.0f, [&](NavCelId x, float d) {
if (x == b) {db = d;}
});
const Eigen::Vector3f pb = nm.navcel_centroid(b);
Expand All @@ -308,7 +313,8 @@ TEST(Iterators, RingIsTheDiscMinusItsInnerPartAndCrossesIt)
const auto ring = collect(
[&](auto f) {return navmap::for_each_in_ring(nm, seed, c, 2.0f, 3.0f, f, m);});
std::set<NavCelId> want;
navmap::for_each_by_distance(nm, seed, c, 3.0f, [&](NavCelId x, float d) {
navmap::for_each_by_distance(
nm, seed, c, 3.0f, [&](NavCelId x, float d) {
if (m == Metric::GEODESIC ? d >= 2.0f : (nm.navcel_centroid(x) - c).norm() >= 2.0f) {
want.insert(x);
}
Expand Down Expand Up @@ -336,9 +342,10 @@ TEST(Iterators, ByDistanceIsOrderedCompleteAndNeverShorterThanAStraightLine)
const Eigen::Vector3f c(3.3f, 6.1f, 0.0f);
const NavCelId seed = seed_at(nm, c);
std::vector<std::pair<NavCelId, float>> seq;
const std::size_t n = navmap::for_each_by_distance(nm, seed, c, 4.0f, [&](NavCelId x, float d) {
seq.emplace_back(x, d);
});
const std::size_t n = navmap::for_each_by_distance(
nm, seed, c, 4.0f, [&](NavCelId x, float d) {
seq.emplace_back(x, d);
});
ASSERT_EQ(n, seq.size());
ASSERT_FALSE(seq.empty());
EXPECT_EQ(seq.front().first, seed);
Expand All @@ -362,9 +369,11 @@ TEST(Iterators, ByDistanceIsOrderedCompleteAndNeverShorterThanAStraightLine)
if ((nm.navcel_centroid(x) - c).norm() <= 3.0f) {EXPECT_TRUE(ids.count(x)) << x;}
}
int calls = 0;
EXPECT_EQ(navmap::for_each_by_distance(nm, seed, c, 4.0f, [&](NavCelId, float) {
return ++calls < 3;
}), 3u);
EXPECT_EQ(
navmap::for_each_by_distance(
nm, seed, c, 4.0f, [&](NavCelId, float) {
return ++calls < 3;
}), 3u);
}

TEST(Iterators, ByDistanceOnASlopeMeasuresAlongTheSurface)
Expand All @@ -377,7 +386,8 @@ TEST(Iterators, ByDistanceOnASlopeMeasuresAlongTheSurface)
const Eigen::Vector3f c(1.0f, 0.5f, k * 1.0f), far(5.0f, 0.5f, k * 5.0f);
const NavCelId seed = seed_at(nm, c), target = seed_at(nm, far);
float d_target = -1.0f;
navmap::for_each_by_distance(nm, seed, c, 10.0f, [&](NavCelId x, float d) {
navmap::for_each_by_distance(
nm, seed, c, 10.0f, [&](NavCelId x, float d) {
if (x == target) {d_target = d;}
});
const float straight = (nm.navcel_centroid(target) - c).norm();
Expand Down Expand Up @@ -414,9 +424,10 @@ TEST(Iterators, PolygonStaysOnTheSeedLevelAndHandlesDegenerateInput)
const NavMap nm = two_floors();
const std::vector<Eigen::Vector2f> sq{{2, 2}, {6, 2}, {6, 6}, {2, 6}};
for (const float z : {0.0f, 3.0f}) {
const auto got = collect([&](auto f) {
return navmap::for_each_in_polygon(nm, Eigen::Vector3f(4, 4, z), sq, f);
});
const auto got = collect(
[&](auto f) {
return navmap::for_each_in_polygon(nm, Eigen::Vector3f(4, 4, z), sq, f);
});
EXPECT_EQ(got.size(), 2u * 8u * 8u);
for (NavCelId x : got) {
EXPECT_NEAR(nm.navcel_centroid(x).z(), z, 1e-5f);
Expand All @@ -426,9 +437,11 @@ TEST(Iterators, PolygonStaysOnTheSeedLevelAndHandlesDegenerateInput)
EXPECT_EQ(navmap::for_each_in_polygon(nm, seed, {{0, 0}, {1, 1}}, [](NavCelId) {}), 0u);
EXPECT_EQ(navmap::for_each_in_polygon(nm, seed, {}, [](NavCelId) {}), 0u);
// A polygon away from the seed is not reached (regions grow from the seed)
EXPECT_EQ(navmap::for_each_in_polygon(
EXPECT_EQ(
navmap::for_each_in_polygon(
nm, seed, {{8, 8}, {9, 8}, {9, 9}, {8, 9}}, [](NavCelId) {}), 0u);
EXPECT_EQ(navmap::for_each_in_polygon(
EXPECT_EQ(
navmap::for_each_in_polygon(
nm, Eigen::Vector3f(50, 50, 0), sq, [](NavCelId) {}), 0u);
int calls = 0;
EXPECT_EQ(navmap::for_each_in_polygon(nm, seed, sq, [&](NavCelId) {return ++calls < 4;}), 4u);
Expand All @@ -448,9 +461,10 @@ struct Walk
Walk walk(const NavMap & nm, const Eigen::Vector3f & a, const Eigen::Vector3f & b)
{
Walk w;
w.reached = navmap::for_each_on_segment(nm, a, b, [&](NavCelId c, float t0, float t1) {
w.cells.emplace_back(c, t0, t1);
});
w.reached = navmap::for_each_on_segment(
nm, a, b, [&](NavCelId c, float t0, float t1) {
w.cells.emplace_back(c, t0, t1);
});
return w;
}

Expand Down Expand Up @@ -537,8 +551,10 @@ TEST(Iterators, SegmentWalkStopsAtBordersAndHoles)
EXPECT_FALSE(walk(nm, {-3, 1, 0}, {2, 1, 0}).reached);
// Early stop
int calls = 0;
EXPECT_FALSE(navmap::for_each_on_segment(nm, Eigen::Vector3f(1, 1, 0), Eigen::Vector3f(9, 1, 0),
[&](NavCelId, float, float) {return ++calls < 3;}));
EXPECT_FALSE(
navmap::for_each_on_segment(
nm, Eigen::Vector3f(1, 1, 0), Eigen::Vector3f(9, 1, 0),
[&](NavCelId, float, float) {return ++calls < 3;}));
EXPECT_EQ(calls, 3);
}

Expand Down
Loading
Loading