Skip to content
Snippets Groups Projects
Commit d0291129 authored by Philip Trettner's avatar Philip Trettner
Browse files

Merge branch 'agrabowy' into 'develop'

Visual demonstration of object properties

See merge request !41
parents 4c42645a c1c7303b
No related branches found
No related tags found
1 merge request!41Visual demonstration of object properties
Pipeline #16756 failed
typed-geometry @ 3f362346
Subproject commit a6c6371f1bac47f0f269032549adb1873d1f32e4 Subproject commit 3f36234671dc3fbead5b0398912809e4c803df2c
#include <typed-geometry/tg.hh>
#include <glow-extras/glfw/GlfwContext.hh>
#include <glow-extras/viewer/view.hh>
template <class Rng, class Obj>
void test_obj(Rng& rng, Obj const& obj)
{
auto const domainD = tg::object_traits<Obj>::domain_dimension;
auto const objectD = tg::object_traits<Obj>::object_dimension;
auto const solidD = [&] {
if constexpr (tg::object_traits<Obj>::is_boundary)
return objectD + 1;
return objectD;
}();
using TraitsT = typename tg::object_traits<Obj>::tag_t;
tg::aabb<domainD, float> aabbBigger;
auto nameString = tg::to_string("");
auto g = gv::grid();
if constexpr (tg::object_traits<Obj>::is_finite)
{
float size;
if constexpr (objectD == 3)
size = 1000.f + volume_of(obj);
else if constexpr (objectD == 2)
size = 500.f + area_of(obj);
else if constexpr (tg::object_traits<Obj>::is_boundary)
size = 100.f + perimeter_of(obj);
else
size = 100.f + length(obj);
auto uniformPts = std::vector<tg::pos3>();
for (auto i = 0; i < size; ++i)
uniformPts.emplace_back(uniform(rng, obj));
auto const aabb = aabb_of(obj);
aabbBigger = tg::aabb(aabb.min - 0.25f, aabb.max + 0.25f);
tg::aabb3 aabb3;
if constexpr (domainD == 3)
aabb3 = aabb;
else
aabb3 = tg::aabb3(tg::pos3(aabb.min), tg::pos3(aabb.max));
auto v = gv::view();
// uniform
gv::view(uniformPts, tg::to_string(obj));
// any_point
gv::view(gv::points(tg::pos3(any_point(obj))).point_size_px(12.f), tg::color4::red);
// centroid
auto const centroid = centroid_of(obj);
if (any_point(obj) == centroid)
gv::view(gv::points(tg::pos3(centroid)).point_size_px(13.f), tg::color4::yellow);
else
gv::view(gv::points(tg::pos3(centroid)).point_size_px(12.f), tg::color4::green);
// aabb_of
gv::view(gv::lines(aabb3));
// normal_of
if constexpr (domainD == 3 && solidD == 2)
gv::view(tg::segment3(centroid, centroid + normal_of(obj)), tg::color4::green);
}
else // infinite objects
{
auto const p = any_point(obj);
aabbBigger = tg::aabb<domainD, float>(p - 10.f, p + 10.f);
nameString = " for " + tg::to_string(obj);
}
// common visualization for finite and infinite objects
{
auto pointsInside = std::vector<tg::pos3>();
auto pointsOutside = std::vector<tg::pos3>();
auto const numPts = tg::pow(20.f, domainD);
auto const tolerance = objectD < domainD ? 0.1f : 0.f;
for (auto i = 0; i < numPts; ++i)
{
auto const p = uniform(rng, aabbBigger);
if (contains(obj, p, tolerance))
pointsInside.emplace_back(p);
else
pointsOutside.emplace_back(p);
}
// contains
auto v = gv::view();
view(pointsInside, gv::maybe_empty, tg::color4::green, "contains (+-" + tg::to_string(tolerance) + ")" + nameString);
gv::view(gv::points(pointsOutside).point_size_px(5.f));
}
if constexpr (!std::is_same_v<Obj, tg::ellipse<solidD, float, domainD, TraitsT>>)
{
auto points = std::vector<tg::pos3>();
auto lines = std::vector<tg::segment3>();
auto const numPts = tg::pow(20.f, domainD);
for (auto i = 0; i < numPts; ++i)
{
auto const p = uniform(rng, aabbBigger);
auto const pProj = tg::pos3(project(p, obj));
points.emplace_back(pProj);
if (!contains(obj, p))
lines.emplace_back(tg::pos3(p), pProj);
}
// project
auto v = gv::view();
gv::view(points, "project");
gv::view(lines);
}
if constexpr (objectD >= domainD - 1)
{
auto linesGray = std::vector<tg::segment3>();
auto linesGreen = std::vector<tg::segment3>();
auto linesRed = std::vector<tg::segment3>();
auto pointsGray = std::vector<tg::pos3>();
auto pointsGreen = std::vector<tg::pos3>();
auto pointsRed = std::vector<tg::pos3>();
auto const numPts = tg::pow(10.f, domainD);
for (auto i = 0; i < numPts; ++i)
{
auto const p = uniform(rng, aabbBigger);
auto const d = tg::uniform<tg::dir<domainD, float>>(rng);
auto const r = tg::ray(p, d);
if (intersects(r, obj))
{
if constexpr (std::is_same_v<decltype(tg::intersection_parameter(r, obj)), tg::optional<tg::hit_interval<float>>>)
{
auto const ts = tg::intersection_parameter(r, obj).value();
if (ts.start > 0.f)
{
pointsGray.emplace_back(p);
linesGray.emplace_back(tg::pos3(p), tg::pos3(r[ts.start]));
}
pointsGreen.emplace_back(r[ts.start]);
if (ts.end == tg::max<float>())
linesGreen.emplace_back(tg::pos3(r[ts.start]), tg::pos3(r[ts.start] + d));
else
{
linesGreen.emplace_back(tg::pos3(r[ts.start]), tg::pos3(r[ts.end]));
pointsGreen.emplace_back(r[ts.end]);
linesGray.emplace_back(tg::pos3(r[ts.end]), tg::pos3(r[ts.end] + d));
}
}
else
{
auto const ts = tg::intersection_parameter(r, obj);
pointsGray.emplace_back(p);
for (auto const& t : ts)
pointsGreen.emplace_back(r[t]);
linesGray.emplace_back(tg::pos3(p), tg::pos3(r[ts.last()] + d));
}
}
else
{
pointsRed.emplace_back(p);
linesRed.emplace_back(tg::pos3(p), tg::pos3(p + d));
}
}
// ray intersection
auto v = gv::view();
gv::view(linesGray, "ray intersection", tg::aabb3(tg::pos3(aabbBigger.min), tg::pos3(aabbBigger.max)));
view(linesGreen, gv::maybe_empty, tg::color4::green);
gv::view(linesRed, tg::color4::red);
gv::view(pointsGray);
gv::view(pointsGreen, tg::color4::green);
gv::view(pointsRed, tg::color4::red);
}
}
int main()
{
auto const test_obj_and_boundary = [](auto& rng, auto const& o) {
test_obj(rng, o);
test_obj(rng, boundary_of(o));
};
auto const test_obj_and_boundary_no_caps = [](auto& rng, auto const& o) {
test_obj(rng, o);
test_obj(rng, boundary_of(o));
test_obj(rng, boundary_no_caps_of(o));
};
glow::glfw::GlfwContext ctx;
tg::rng rng;
auto const r = uniform(rng, 0.0f, 10.0f);
auto const h = uniform(rng, 0.0f, 10.0f);
auto const a = uniform(rng, 5_deg, 180_deg); // sensible range for a convex inf_cone
auto const n2 = tg::uniform<tg::dir2>(rng);
auto const n3 = tg::uniform<tg::dir3>(rng);
auto const range2 = tg::aabb2(tg::pos2(-10), tg::pos2(10));
auto const range3 = tg::aabb3(tg::pos3(-10), tg::pos3(10));
auto const pos20 = uniform(rng, range2);
auto const pos21 = uniform(rng, range2);
auto const pos22 = uniform(rng, range2);
auto const pos30 = uniform(rng, range3);
auto const pos31 = uniform(rng, range3);
auto const pos32 = uniform(rng, range3);
auto const axis0 = tg::segment3(pos30, pos31);
auto const disk0 = tg::sphere2in3(pos30, r, n3);
auto const d1 = tg::uniform<tg::dir1>(rng);
auto m1 = tg::mat1();
m1[0] = d1 * uniform(rng, 1.0f, 3.0f);
auto const d20 = tg::uniform<tg::dir2>(rng);
auto const d21 = perpendicular(d20);
auto m2 = tg::mat2();
m2[0] = d20 * uniform(rng, 1.0f, 3.0f);
m2[1] = d21 * uniform(rng, 1.0f, 3.0f);
auto const d30 = tg::uniform<tg::dir3>(rng);
auto const d31 = any_normal(d30);
auto const d32 = normalize(cross(d30, d31));
auto m3 = tg::mat3();
m3[0] = d30 * uniform(rng, 1.0f, 3.0f);
m3[1] = d31 * uniform(rng, 1.0f, 3.0f);
m3[2] = d32 * uniform(rng, 1.0f, 3.0f);
auto m23 = tg::mat2x3();
m23[0] = d30 * uniform(rng, 1.0f, 3.0f);
m23[1] = d31 * uniform(rng, 1.0f, 3.0f);
// aabb
test_obj_and_boundary(rng, aabb_of(pos20, pos21));
test_obj_and_boundary(rng, aabb_of(pos30, pos31));
// box
test_obj_and_boundary(rng, tg::box2(pos20, m2));
test_obj_and_boundary(rng, tg::box3(pos30, m3));
test_obj_and_boundary(rng, tg::box2in3(pos30, m23));
// capsule
test_obj_and_boundary(rng, tg::capsule3(axis0, r));
// cylinder
test_obj_and_boundary_no_caps(rng, tg::cylinder3(axis0, r));
// ellipse
test_obj_and_boundary(rng, tg::ellipse2(pos20, m2));
test_obj_and_boundary(rng, tg::ellipse3(pos30, m3));
test_obj_and_boundary(rng, tg::ellipse2in3(pos30, m23));
// halfspace
test_obj(rng, tg::halfspace2(n2, h));
test_obj(rng, tg::halfspace3(n3, h));
// hemisphere
test_obj_and_boundary_no_caps(rng, tg::hemisphere2(pos20, r, n2));
test_obj_and_boundary_no_caps(rng, tg::hemisphere3(pos30, r, n3));
// inf_cone
test_obj_and_boundary(rng, tg::inf_cone2(pos20, n2, a));
test_obj_and_boundary(rng, tg::inf_cone3(pos30, n3, a));
// inf_cylinder
test_obj_and_boundary(rng, tg::inf_cylinder2(tg::line2(pos20, n2), r));
test_obj_and_boundary(rng, tg::inf_cylinder3(tg::line3(pos30, n3), r));
// line
test_obj(rng, tg::line2(pos20, n2));
test_obj(rng, tg::line3(pos30, n3));
// plane
test_obj(rng, tg::plane2(n2, h));
test_obj(rng, tg::plane3(n3, h));
// pyramid
test_obj_and_boundary_no_caps(rng, tg::pyramid<tg::box2in3>(tg::box2in3(pos30, m23), h));
test_obj_and_boundary_no_caps(rng, tg::pyramid<tg::sphere2in3>(disk0, h)); // == cone
test_obj_and_boundary_no_caps(rng, tg::pyramid<tg::triangle3>(tg::triangle3(pos30, pos31, pos32), h));
test_obj(rng, tg::pyramid_boundary_no_caps<tg::quad3>(tg::quad3(pos30, pos31, pos32, pos32 + (pos30 - pos31)), h));
// test_obj_and_boundary_no_caps(tg::pyramid<tg::quad3>(tg::quad3(pos30, pos31, pos32, pos32 + (pos30 - pos31)), h));
// TODO: quad
// test_obj(rng, tg::quad2(pos20, pos21, pos22, pos23));
// test_obj(rng, tg::quad3(pos30, pos31, pos32, pos32 + (pos31 - pos30)));
// ray
test_obj(rng, tg::ray2(pos20, n2));
test_obj(rng, tg::ray3(pos30, n3));
// segment
test_obj(rng, tg::segment2(pos20, pos21));
test_obj(rng, tg::segment3(pos30, pos31));
// sphere
test_obj_and_boundary(rng, tg::sphere2(pos20, r));
test_obj_and_boundary(rng, tg::sphere3(pos30, r));
test_obj_and_boundary(rng, tg::sphere2in3(pos30, r, n3));
// triangle
test_obj(rng, tg::triangle2(pos20, pos21, pos22));
test_obj(rng, tg::triangle3(pos30, pos31, pos32));
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment