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.erase(std::remove_if(polygons.begin(), 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
// Overlap all duplicit points by rectangle 3x3
Points duplicits = collect_duplicates(to_points(polygons));
@ -1280,23 +1283,8 @@ ExPolygons letter2shapes(
const int CANCEL_CHECK = 10;
} // namespace
/// Union shape defined by glyphs
HealedExPolygons Slic3r::union_ex(const ExPolygonsWithIds &shapes, 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)
namespace {
HealedExPolygons union_with_delta(const ExPolygonsWithIds &shapes, float delta, unsigned max_heal_iteration)
{
// unify to one 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 result = union_ex(expolygons);
result = offset_ex(result, -delta);
bool is_healed = heal_expolygons(result, max_heal_iteration);
result = offset_ex(result, -delta);
bool is_healed = heal_expolygons(result, max_heal_iteration);
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)
{
@ -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);
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 {

View File

@ -31,6 +31,9 @@ struct HealedExPolygons{
/// </summary>
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>
/// Collect fonts registred inside OS
/// </summary>
@ -474,9 +477,8 @@ namespace Emboss
void translate(ExPolygonsWithIds &e, const Point &p);
BoundingBox get_extents(const 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)
// 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
#endif // slic3r_Emboss_hpp_

View File

@ -74,6 +74,7 @@ struct EmbossShape
{
// shapes to to emboss separately over surface
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
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
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);
// unify to one expolygons
double delta = 1e-3; // in mm
unsigned max_heal_iteration = 10;
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.";
// EmbossJob.cpp --> ExPolygons create_shape(DataBase &input, Fnc was_canceled) {
ExPolygons union_shape = union_with_delta(emboss_shape, Emboss::UNION_DELTA, Emboss::UNION_MAX_ITERATIN);
// create projection
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);
// 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));
// 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
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);
@ -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});
// Union All shapes
ExPolygons shape;
for (const ExPolygonsWithId &shapes_with_id : shapes_with_ids)
expolygons_append(shape, shapes_with_id.expoly);
shape = union_ex(shape);
ExPolygons shape = union_ex(shapes_with_ids);
// align to texture
translate(shape, -bb.min);

View File

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