Unify behavior of union for import and add volume

Add cache for final ExPolygons
This commit is contained in:
Filip Sykala - NTB T15p 2023-10-27 08:55:47 +02:00
parent e043a04207
commit fa09f03c6a
7 changed files with 52 additions and 42 deletions

View File

@ -448,7 +448,10 @@ HealedExPolygons Emboss::heal_polygons(const Polygons &shape, bool is_non_zero,
Polygons polygons = to_polygons(paths); Polygons polygons = to_polygons(paths);
polygons.erase(std::remove_if(polygons.begin(), polygons.end(), polygons.erase(std::remove_if(polygons.begin(), polygons.end(),
[](const Polygon &p) { return p.size() < 3; }), polygons.end()); [](const Polygon &p) { return p.size() < 3; }), polygons.end());
if (polygons.empty())
return {{}, false};
// Do not remove all duplicates but do it better way // Do not remove all duplicates but do it better way
// Overlap all duplicit points by rectangle 3x3 // Overlap all duplicit points by rectangle 3x3
Points duplicits = collect_duplicates(to_points(polygons)); Points duplicits = collect_duplicates(to_points(polygons));
@ -1280,23 +1283,8 @@ ExPolygons letter2shapes(
const int CANCEL_CHECK = 10; const int CANCEL_CHECK = 10;
} // namespace } // namespace
/// Union shape defined by glyphs namespace {
HealedExPolygons Slic3r::union_ex(const ExPolygonsWithIds &shapes, unsigned max_heal_iteration) HealedExPolygons union_with_delta(const ExPolygonsWithIds &shapes, float delta, unsigned max_heal_iteration)
{
// unify to one expolygon
ExPolygons result;
for (const ExPolygonsWithId &shape : shapes) {
if (shape.expoly.empty())
continue;
expolygons_append(result, shape.expoly);
}
result = union_ex(result);
bool is_healed = heal_expolygons(result, max_heal_iteration);
return {result, is_healed};
}
HealedExPolygons Slic3r::union_with_delta(const ExPolygonsWithIds &shapes, float delta, unsigned max_heal_iteration)
{ {
// unify to one expolygons // unify to one expolygons
ExPolygons expolygons; ExPolygons expolygons;
@ -1306,10 +1294,26 @@ HealedExPolygons Slic3r::union_with_delta(const ExPolygonsWithIds &shapes, float
expolygons_append(expolygons, offset_ex(shape.expoly, delta)); expolygons_append(expolygons, offset_ex(shape.expoly, delta));
} }
ExPolygons result = union_ex(expolygons); ExPolygons result = union_ex(expolygons);
result = offset_ex(result, -delta); result = offset_ex(result, -delta);
bool is_healed = heal_expolygons(result, max_heal_iteration); bool is_healed = heal_expolygons(result, max_heal_iteration);
return {result, is_healed}; return {result, is_healed};
} }
} // namespace
ExPolygons Slic3r::union_with_delta(EmbossShape &shape, float delta, unsigned max_heal_iteration)
{
if (!shape.final_shape.empty())
return shape.final_shape;
HealedExPolygons result = ::union_with_delta(shape.shapes_with_ids, delta, max_heal_iteration);
shape.is_healed = result.is_healed;
for (const ExPolygonsWithId &e : shape.shapes_with_ids)
if (!e.is_healed)
shape.is_healed = false;
shape.final_shape = std::move(result.expolygons); // cached
return shape.final_shape;
}
void Slic3r::translate(ExPolygonsWithIds &expolygons_with_ids, const Point &p) void Slic3r::translate(ExPolygonsWithIds &expolygons_with_ids, const Point &p)
{ {
@ -1337,7 +1341,7 @@ HealedExPolygons Emboss::text2shapes(FontFileWithCache &font_with_cache, const c
ExPolygonsWithIds vshapes = text2vshapes(font_with_cache, text_w, font_prop, was_canceled); ExPolygonsWithIds vshapes = text2vshapes(font_with_cache, text_w, font_prop, was_canceled);
float delta = static_cast<float>(1. / SHAPE_SCALE); float delta = static_cast<float>(1. / SHAPE_SCALE);
return union_with_delta(vshapes, delta, MAX_HEAL_ITERATION_OF_TEXT); return ::union_with_delta(vshapes, delta, MAX_HEAL_ITERATION_OF_TEXT);
} }
namespace { namespace {

View File

@ -31,6 +31,9 @@ struct HealedExPolygons{
/// </summary> /// </summary>
namespace Emboss namespace Emboss
{ {
static const float UNION_DELTA = 50.0f; // [approx in nano meters depends on volume scale]
static const unsigned UNION_MAX_ITERATIN = 10; // [count]
/// <summary> /// <summary>
/// Collect fonts registred inside OS /// Collect fonts registred inside OS
/// </summary> /// </summary>
@ -474,9 +477,8 @@ namespace Emboss
void translate(ExPolygonsWithIds &e, const Point &p); void translate(ExPolygonsWithIds &e, const Point &p);
BoundingBox get_extents(const ExPolygonsWithIds &e); BoundingBox get_extents(const ExPolygonsWithIds &e);
void center(ExPolygonsWithIds &e); void center(ExPolygonsWithIds &e);
HealedExPolygons union_ex(const ExPolygonsWithIds &shapes, unsigned max_heal_iteration);
// delta .. safe offset before union (use as boolean close) // delta .. safe offset before union (use as boolean close)
// NOTE: remove unprintable spaces between neighbor curves (made by linearization of curve) // NOTE: remove unprintable spaces between neighbor curves (made by linearization of curve)
HealedExPolygons union_with_delta(const ExPolygonsWithIds &shapes, float delta, unsigned max_heal_iteration); ExPolygons union_with_delta(EmbossShape &shape, float delta, unsigned max_heal_iteration);
} // namespace Slic3r } // namespace Slic3r
#endif // slic3r_Emboss_hpp_ #endif // slic3r_Emboss_hpp_

View File

@ -74,6 +74,7 @@ struct EmbossShape
{ {
// shapes to to emboss separately over surface // shapes to to emboss separately over surface
ExPolygonsWithIds shapes_with_ids; ExPolygonsWithIds shapes_with_ids;
ExPolygons final_shape; // When not set it is calculated from ExPolygonsWithIds
// scale of shape, multiplier to get 3d point in mm from integer shape // scale of shape, multiplier to get 3d point in mm from integer shape
double scale = SCALING_FACTOR; double scale = SCALING_FACTOR;

View File

@ -3899,7 +3899,7 @@ std::optional<EmbossShape> read_emboss_shape(const char **attributes, unsigned i
ExPolygonsWithIds shapes; // TODO: need to implement ExPolygonsWithIds shapes; // TODO: need to implement
EmbossShape::SvgFile svg{file_path, file_path_3mf}; EmbossShape::SvgFile svg{file_path, file_path_3mf};
return EmbossShape{shapes, scale, std::move(projection), std::move(fix_tr_mat), std::move(svg), is_healed}; return EmbossShape{shapes, {}, scale, std::move(projection), std::move(fix_tr_mat), std::move(svg), is_healed};
} }

View File

@ -70,11 +70,8 @@ bool load_svg(const std::string &input_file, Model &output_model)
emboss_shape.svg_file = std::move(svg_file); emboss_shape.svg_file = std::move(svg_file);
// unify to one expolygons // unify to one expolygons
double delta = 1e-3; // in mm // EmbossJob.cpp --> ExPolygons create_shape(DataBase &input, Fnc was_canceled) {
unsigned max_heal_iteration = 10; ExPolygons union_shape = union_with_delta(emboss_shape, Emboss::UNION_DELTA, Emboss::UNION_MAX_ITERATIN);
HealedExPolygons union_shape = union_with_delta(emboss_shape.shapes_with_ids, delta, max_heal_iteration);
if (!union_shape.is_healed)
BOOST_LOG_TRIVIAL(warning) << "SVG file(\"" << input_file << "\") couldn't be fully healed.";
// create projection // create projection
double scale = emboss_shape.scale; double scale = emboss_shape.scale;
@ -84,7 +81,7 @@ bool load_svg(const std::string &input_file, Model &output_model)
Emboss::ProjectTransform project(std::move(projectZ), tr); Emboss::ProjectTransform project(std::move(projectZ), tr);
// convert 2d shape to 3d triangles // convert 2d shape to 3d triangles
indexed_triangle_set its = Emboss::polygons2model(union_shape.expolygons, project); indexed_triangle_set its = Emboss::polygons2model(union_shape, project);
TriangleMesh triangl_mesh(std::move(its)); TriangleMesh triangl_mesh(std::move(its));
// add mesh to model // add mesh to model

View File

@ -907,6 +907,19 @@ void draw_filled(const ExPolygons &shape, const std::array<unsigned char, N>& co
} }
} }
/// Union shape defined by glyphs
ExPolygons union_ex(const ExPolygonsWithIds &shapes)
{
// unify to one expolygon
ExPolygons result;
for (const ExPolygonsWithId &shape : shapes) {
if (shape.expoly.empty())
continue;
expolygons_append(result, shape.expoly);
}
return union_ex(result);
}
// init texture by draw expolygons into texture // init texture by draw expolygons into texture
bool init_texture(Texture &texture, const ExPolygonsWithIds& shapes_with_ids, unsigned max_size_px, const std::vector<std::string>& shape_warnings){ bool init_texture(Texture &texture, const ExPolygonsWithIds& shapes_with_ids, unsigned max_size_px, const std::vector<std::string>& shape_warnings){
BoundingBox bb = get_extents(shapes_with_ids); BoundingBox bb = get_extents(shapes_with_ids);
@ -933,10 +946,7 @@ bool init_texture(Texture &texture, const ExPolygonsWithIds& shapes_with_ids, un
std::vector<unsigned char> data(n_pixels * channels_count, {0}); std::vector<unsigned char> data(n_pixels * channels_count, {0});
// Union All shapes // Union All shapes
ExPolygons shape; ExPolygons shape = union_ex(shapes_with_ids);
for (const ExPolygonsWithId &shapes_with_id : shapes_with_ids)
expolygons_append(shape, shapes_with_id.expoly);
shape = union_ex(shape);
// align to texture // align to texture
translate(shape, -bb.min); translate(shape, -bb.min);

View File

@ -793,14 +793,10 @@ bool check(const UpdateSurfaceVolumeData &input, bool is_main_thread)
template<typename Fnc> template<typename Fnc>
ExPolygons create_shape(DataBase &input, Fnc was_canceled) { ExPolygons create_shape(DataBase &input, Fnc was_canceled) {
EmbossShape &es = input.create_shape(); EmbossShape &es = input.create_shape();
float delta = 50.f; // TODO: improve to use real size of volume
unsigned max_heal_iteration = 10; // ... need world matrix for volume
HealedExPolygons result = union_with_delta(es.shapes_with_ids, delta, max_heal_iteration); // ... printer resolution will be fine too
es.is_healed = result.is_healed; return union_with_delta(es, UNION_DELTA, UNION_MAX_ITERATIN);
for (const ExPolygonsWithId &e : es.shapes_with_ids)
if (!e.is_healed)
es.is_healed = false;
return result.expolygons;
} }
//#define STORE_SAMPLING //#define STORE_SAMPLING