#include #include #include // only debug visualization #include #include using namespace Slic3r; namespace Private{ // calculate multiplication of ray dir to intersect - inspired by // segment_segment_intersection when ray dir is normalized retur distance from // ray point to intersection No value mean no intersection std::optional ray_segment_intersection(const Vec2d &r_point, const Vec2d &r_dir, const Vec2d &s0, const Vec2d &s1) { auto denominate = [](const Vec2d &v0, const Vec2d &v1) -> double { return v0.x() * v1.y() - v1.x() * v0.y(); }; Vec2d segment_dir = s1 - s0; double d = denominate(segment_dir, r_dir); if (std::abs(d) < std::numeric_limits::epsilon()) // Line and ray are collinear. return {}; Vec2d s12 = s0 - r_point; double s_number = denominate(r_dir, s12); bool change_sign = false; if (d < 0.) { change_sign = true; d = -d; s_number = -s_number; } if (s_number < 0. || s_number > d) // Intersection outside of segment. return {}; double r_number = denominate(segment_dir, s12); if (change_sign) r_number = -r_number; if (r_number < 0.) // Intersection before ray start. return {}; return r_number / d; } Vec2d get_intersection(const Vec2d & point, const Vec2d & dir, const std::array &triangle) { std::optional t; for (size_t i = 0; i < 3; ++i) { size_t i2 = i + 1; if (i2 == 3) i2 = 0; if (!t.has_value()) { t = ray_segment_intersection(point, dir, triangle[i], triangle[i2]); continue; } // small distance could be preccission inconsistance std::optional t2 = ray_segment_intersection(point, dir, triangle[i], triangle[i2]); if (t2.has_value() && *t2 > *t) t = t2; } assert(t.has_value()); // Not found intersection. return point + dir * (*t); } Vec3d calc_hit_point(const igl::Hit & h, const Vec3i & triangle, const std::vector &vertices) { double c1 = h.u; double c2 = h.v; double c0 = 1.0 - c1 - c2; Vec3d v0 = vertices[triangle[0]].cast(); Vec3d v1 = vertices[triangle[1]].cast(); Vec3d v2 = vertices[triangle[2]].cast(); return v0 * c0 + v1 * c1 + v2 * c2; } Vec3d calc_hit_point(const igl::Hit &h, indexed_triangle_set &its) { return calc_hit_point(h, its.indices[h.id], its.vertices); } } // namespace Private #include TEST_CASE("Emboss text", "[Emboss]") { std::string font_path = std::string(TEST_DATA_DIR) + "/fonts/NotoSans-Regular.ttf"; char letter = '%'; float flatness = 2.; std::optional font = Emboss::load_font(font_path.c_str()); REQUIRE(font.has_value()); std::optional glyph = Emboss::letter2glyph(*font, letter, flatness); REQUIRE(glyph.has_value()); ExPolygons shape = glyph->shape; REQUIRE(!shape.empty()); float z_depth = 1.f; Emboss::ProjectZ projection(z_depth); indexed_triangle_set its = Emboss::polygons2model(shape, projection); CHECK(!its.indices.empty()); } TEST_CASE("Test hit point", "[AABBTreeIndirect]") { indexed_triangle_set its; its.vertices = { Vec3f(1, 1, 1), Vec3f(2, 10, 2), Vec3f(10, 0, 2), }; its.indices = {Vec3i(0, 2, 1)}; auto tree = AABBTreeIndirect::build_aabb_tree_over_indexed_triangle_set( its.vertices, its.indices); Vec3d ray_point(8, 1, 0); Vec3d ray_dir(0, 0, 1); igl::Hit hit; AABBTreeIndirect::intersect_ray_first_hit(its.vertices, its.indices, tree, ray_point, ray_dir, hit); Vec3d hp = Private::calc_hit_point(hit, its); CHECK(abs(hp.x() - ray_point.x()) < .1); CHECK(abs(hp.y() - ray_point.y()) < .1); } TEST_CASE("ray segment intersection", "[MeshBoolean]") { Vec2d r_point(1, 1); Vec2d r_dir(1, 0); // colinear CHECK(!Private::ray_segment_intersection(r_point, r_dir, Vec2d(0, 0), Vec2d(2, 0)).has_value()); CHECK(!Private::ray_segment_intersection(r_point, r_dir, Vec2d(2, 0), Vec2d(0, 0)).has_value()); // before ray CHECK(!Private::ray_segment_intersection(r_point, r_dir, Vec2d(0, 0), Vec2d(0, 2)).has_value()); CHECK(!Private::ray_segment_intersection(r_point, r_dir, Vec2d(0, 2), Vec2d(0, 0)).has_value()); // above ray CHECK(!Private::ray_segment_intersection(r_point, r_dir, Vec2d(2, 2), Vec2d(2, 3)).has_value()); CHECK(!Private::ray_segment_intersection(r_point, r_dir, Vec2d(2, 3), Vec2d(2, 2)).has_value()); // belove ray CHECK(!Private::ray_segment_intersection(r_point, r_dir, Vec2d(2, 0), Vec2d(2, -1)).has_value()); CHECK(!Private::ray_segment_intersection(r_point, r_dir, Vec2d(2, -1), Vec2d(2, 0)).has_value()); // intersection at [2,1] distance 1 auto t1 = Private::ray_segment_intersection(r_point, r_dir, Vec2d(2, 0), Vec2d(2, 2)); REQUIRE(t1.has_value()); auto t2 = Private::ray_segment_intersection(r_point, r_dir, Vec2d(2, 2), Vec2d(2, 0)); REQUIRE(t2.has_value()); CHECK(abs(*t1 - *t2) < std::numeric_limits::epsilon()); } TEST_CASE("triangle intersection", "[]") { Vec2d point(1, 1); Vec2d dir(-1, 0); std::array triangle = {Vec2d(0, 0), Vec2d(5, 0), Vec2d(0, 5)}; Vec2d i = Private::get_intersection(point, dir, triangle); CHECK(abs(i.x()) < std::numeric_limits::epsilon()); CHECK(abs(i.y() - 1.) < std::numeric_limits::epsilon()); }