Better healing for Glyph shape - remove duplicit points + self intersections

Add search of intersecting points (compared with CGAL)
Triangulation can [optionaly] accept multi points
This commit is contained in:
Filip Sykala - NTB T15p 2022-08-25 13:28:10 +02:00
parent 94f735168c
commit 63121cee2e
18 changed files with 892 additions and 241 deletions

View file

@ -6,7 +6,7 @@
#include <optional>
#include <libslic3r/AABBTreeIndirect.hpp>
#include <libslic3r/Utils.hpp> // for next_highest_power_of_2()
#include <libslic3r/IntersectionPoints.hpp>
using namespace Slic3r;
namespace Private{
@ -157,6 +157,119 @@ TEST_CASE("Convert glyph % to model", "[Emboss]")
CHECK(!its.indices.empty());
}
//#define VISUALIZE
#ifdef VISUALIZE
TEST_CASE("Visualize glyph from font", "[Emboss]")
{
std::string font_path = "C:/data/ALIENATO.TTF";
std::string text = "i";
Emboss::FontFileWithCache font(
Emboss::create_font_file(font_path.c_str()));
REQUIRE(font.has_value());
FontProp fp;
fp.size_in_mm = 8;
fp.emboss = 4;
ExPolygons shapes = Emboss::text2shapes(font, text.c_str(), fp);
// char letter = 'i';
// unsigned int font_index = 0; // collection
// float flatness = 5;
// auto glyph = Emboss::letter2glyph(*font.font_file, font_index, letter,
// flatness); ExPolygons shapes2 = glyph->shape; { SVG
//svg("C:/data/temp/stored_letter.svg", get_extents(shapes2));
//svg.draw(shapes2); } // debug shape
REQUIRE(!shapes.empty());
//{ SVG svg("C:/data/temp/shapes.svg"); svg.draw(shapes); } // debug shape
float z_depth = 100.f;
Emboss::ProjectZ projection(z_depth);
indexed_triangle_set its = Emboss::polygons2model(shapes, projection);
its_write_obj(its, "C:/data/temp/bad_glyph.obj");
CHECK(!its.indices.empty());
TriangleMesh tm(its);
auto s = tm.stats();
}
#endif // VISUALIZE
#include "test_utils.hpp"
#include "nanosvg/nanosvg.h" // load SVG file
#include "libslic3r/NSVGUtils.hpp"
void heal_and_check(const Polygons &polygons)
{
Pointfs intersections_prev = intersection_points(polygons);
Points polygons_points = to_points(polygons);
Points duplicits_prev = collect_duplications(polygons_points);
ExPolygons shape = Emboss::heal_shape(polygons);
// Is default shape for unhealabled shape?
bool is_default_shape =
shape.size() == 1 &&
shape.front().contour.points.size() == 4 &&
shape.front().holes.size() == 1 &&
shape.front().holes.front().points.size() == 4 ;
CHECK(!is_default_shape);
Pointfs intersections = intersection_points(shape);
Points shape_points = to_points(shape);
Points duplicits = collect_duplications(shape_points);
//{
// BoundingBox bb(polygons_points);
// // bb.scale(svg_scale);
// SVG svg("C:/data/temp/test_visualization.svg", bb);
// svg.draw(polygons, "gray"); // input
// svg.draw(shape, "green"); // output
// Points pts;
// pts.reserve(intersections.size());
// for (const Vec2d &intersection : intersections)
// pts.push_back(intersection.cast<int>());
// svg.draw(pts, "red", 10);
// svg.draw(duplicits, "orenge", 10);
//}
CHECK(intersections.empty());
CHECK(duplicits.empty());
}
void scale(Polygons &polygons, double multiplicator) {
for (Polygon &polygon : polygons)
for (Point &p : polygon) p *= multiplicator;
}
TEST_CASE("Heal of damaged polygons", "[Emboss]")
{
// Shape loaded from svg is letter 'i' from font 'ALIENATE.TTF'
std::string file_name = "contour_ALIENATO.TTF_glyph_i.svg";
std::string file_path = TEST_DATA_DIR PATH_SEPARATOR + file_name;
NSVGimage *image = nsvgParseFromFile(file_path.c_str(), "px", 96.0f);
Polygons polygons = NSVGUtils::to_polygons(image);
nsvgDelete(image);
heal_and_check(polygons);
Polygons scaled_shape = polygons; // copy
scale(scaled_shape, 1 / Emboss::SHAPE_SCALE);
heal_and_check(scaled_shape);
// different scale
scale(scaled_shape, 10.);
heal_and_check(scaled_shape);
// check reverse order of points
Polygons reverse_shape = polygons;
for (Polygon &p : reverse_shape)
std::reverse(p.points.begin(), p.points.end());
heal_and_check(scaled_shape);
#ifdef VISUALIZE
CHECK(false);
#endif // VISUALIZE
}
TEST_CASE("Convert text with glyph cache to model", "[Emboss]")
{
std::string font_path = get_font_filepath();

View file

@ -6,31 +6,21 @@
using namespace Slic3r;
namespace Private{
void store_trinagulation(const ExPolygons & shape,
void store_trinagulation(const ExPolygons &shape,
const std::vector<Vec3i> &triangles,
const char* file_name = "Triangulation_visualization.svg",
double scale = 1e5)
const char* file_name = "C:/data/temp/triangulation.svg",
double scale = 1e5)
{
BoundingBox bb;
for (const auto &expoly : shape) bb.merge(expoly.contour.points);
bb.scale(scale);
SVG svg_vis(file_name, bb);
svg_vis.draw(shape, "gray", .7f);
Points pts = to_points(shape);
svg_vis.draw(pts, "black", 4 * scale);
size_t count = count_points(shape);
Points points;
points.reserve(count);
auto insert_point = [](const Slic3r::Polygon &polygon, Points &points) {
for (const Point &p : polygon.points) points.emplace_back(p);
};
for (const ExPolygon &expolygon : shape) {
insert_point(expolygon.contour, points);
for (const Slic3r::Polygon &hole : expolygon.holes)
insert_point(hole, points);
}
for (const auto &t : triangles) {
Polygon triangle({points[t[0]], points[t[1]], points[t[2]]});
for (const Vec3i &t : triangles) {
Slic3r::Polygon triangle({pts[t[0]], pts[t[1]], pts[t[2]]});
triangle.scale(scale);
svg_vis.draw(triangle, "green");
}
@ -119,18 +109,19 @@ TEST_CASE("Triangulation M shape polygon", "[triangulation]")
}
// same point in triangulation are not Supported
//TEST_CASE("Triangulation 2 polygons with same point", "[triangulation][not supported]")
//{
// Slic3r::Polygon polygon1 = {
// Point(416, 346), Point(445, 362),
// Point(463, 389), Point(469, 427) /* This point */,
// Point(445, 491)
// };
// Slic3r::Polygon polygon2 = {
// Point(495, 488), Point(469, 427) /* This point */,
// Point(495, 364)
// };
// ExPolygons shape2d = {ExPolygon(polygon1), ExPolygon(polygon2)};
// std::vector<Vec3i> shape_triangles = Triangulation::triangulate(shape2d);
// store_trinagulation(shape2d, shape_triangles);
//}
TEST_CASE("Triangulation 2 polygons with same point", "[triangulation]")
{
Slic3r::Polygon polygon1 = {
Point(416, 346), Point(445, 362),
Point(463, 389), Point(469, 427) /* This point */,
Point(445, 491)
};
Slic3r::Polygon polygon2 = {
Point(495, 488), Point(469, 427) /* This point */,
Point(495, 364)
};
ExPolygons shape2d = {ExPolygon(polygon1), ExPolygon(polygon2)};
std::vector<Vec3i> shape_triangles = Triangulation::triangulate(shape2d);
//Private::store_trinagulation(shape2d, shape_triangles);
CHECK(shape_triangles.size() == 4);
}