mirror of
https://git.mirrors.martin98.com/https://github.com/prusa3d/PrusaSlicer.git
synced 2025-08-12 21:28:59 +08:00
Propagate warnings about unhealed shape to UI.
This commit is contained in:
parent
4724d6791a
commit
82182ac8b8
@ -30,6 +30,7 @@ const double ASCENT_CENTER = 1/3.; // 0.5 is above small letter
|
||||
// every glyph's shape point is divided by SHAPE_SCALE - increase precission of fixed point value
|
||||
// stored in fonts (to be able represents curve by sequence of lines)
|
||||
static constexpr double SHAPE_SCALE = 0.001; // SCALING_FACTOR promile is fine enough
|
||||
static unsigned MAX_HEAL_ITERATION_OF_TEXT = 10;
|
||||
|
||||
using namespace Slic3r;
|
||||
using namespace Emboss;
|
||||
@ -432,7 +433,7 @@ bool Emboss::divide_segments_for_close_point(ExPolygons &expolygons, double dist
|
||||
return true;
|
||||
}
|
||||
|
||||
std::pair<ExPolygons, bool> Emboss::heal_polygons(const Polygons &shape, bool is_non_zero, unsigned int max_iteration)
|
||||
HealedExPolygons Emboss::heal_polygons(const Polygons &shape, bool is_non_zero, unsigned int max_iteration)
|
||||
{
|
||||
const double clean_distance = 1.415; // little grater than sqrt(2)
|
||||
ClipperLib::PolyFillType fill_type = is_non_zero ?
|
||||
@ -621,7 +622,7 @@ bool heal_dupl_inter(ExPolygons &shape, unsigned max_iteration)
|
||||
if (fill_trouble_holes(holes, duplicate_points, intersection_points, shape)) {
|
||||
holes.clear();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
holes.clear();
|
||||
holes.reserve(intersections.size() + duplicate_points.size());
|
||||
@ -785,7 +786,7 @@ std::optional<Glyph> get_glyph(const stbtt_fontinfo &font_info, int unicode_lett
|
||||
// https://docs.microsoft.com/en-us/typography/opentype/spec/ttch01
|
||||
// https://developer.apple.com/fonts/TrueType-Reference-Manual/RM01/Chap1.html
|
||||
bool is_non_zero = true;
|
||||
glyph.shape = Emboss::heal_polygons(glyph_polygons, is_non_zero, max_iteration).first;
|
||||
glyph.shape = Emboss::heal_polygons(glyph_polygons, is_non_zero, max_iteration);
|
||||
}
|
||||
return glyph;
|
||||
}
|
||||
@ -1279,7 +1280,7 @@ const int CANCEL_CHECK = 10;
|
||||
} // namespace
|
||||
|
||||
/// Union shape defined by glyphs
|
||||
ExPolygons Slic3r::union_ex(const ExPolygonsWithIds &shapes)
|
||||
HealedExPolygons Slic3r::union_ex(const ExPolygonsWithIds &shapes, unsigned max_heal_iteration)
|
||||
{
|
||||
// unify to one expolygon
|
||||
ExPolygons result;
|
||||
@ -1289,11 +1290,12 @@ ExPolygons Slic3r::union_ex(const ExPolygonsWithIds &shapes)
|
||||
expolygons_append(result, shape.expoly);
|
||||
}
|
||||
result = union_ex(result);
|
||||
bool is_healed = heal_expolygons(result);
|
||||
return result;
|
||||
|
||||
bool is_healed = heal_expolygons(result, max_heal_iteration);
|
||||
return {result, is_healed};
|
||||
}
|
||||
|
||||
ExPolygons Slic3r::union_with_delta(const ExPolygonsWithIds &shapes, float delta)
|
||||
HealedExPolygons Slic3r::union_with_delta(const ExPolygonsWithIds &shapes, float delta, unsigned max_heal_iteration)
|
||||
{
|
||||
// unify to one expolygons
|
||||
ExPolygons expolygons;
|
||||
@ -1303,22 +1305,22 @@ ExPolygons Slic3r::union_with_delta(const ExPolygonsWithIds &shapes, float delta
|
||||
expolygons_append(expolygons, offset_ex(shape.expoly, delta));
|
||||
}
|
||||
ExPolygons result = union_ex(expolygons);
|
||||
result = offset_ex(result, -delta);
|
||||
bool is_healed = heal_expolygons(result);
|
||||
return result;
|
||||
result = offset_ex(result, -delta);
|
||||
bool is_healed = heal_expolygons(result, max_heal_iteration);
|
||||
return {result, is_healed};
|
||||
}
|
||||
|
||||
void Slic3r::translate(ExPolygonsWithIds &e, const Point &p)
|
||||
void Slic3r::translate(ExPolygonsWithIds &expolygons_with_ids, const Point &p)
|
||||
{
|
||||
for (auto &[id, expoly] : e)
|
||||
translate(expoly, p);
|
||||
for (ExPolygonsWithId &expolygons_with_id : expolygons_with_ids)
|
||||
translate(expolygons_with_id.expoly, p);
|
||||
}
|
||||
|
||||
BoundingBox Slic3r::get_extents(const ExPolygonsWithIds &e)
|
||||
BoundingBox Slic3r::get_extents(const ExPolygonsWithIds &expolygons_with_ids)
|
||||
{
|
||||
BoundingBox bb;
|
||||
for (auto &[id, expoly] : e)
|
||||
bb.merge(get_extents(expoly));
|
||||
for (const ExPolygonsWithId &expolygons_with_id : expolygons_with_ids)
|
||||
bb.merge(get_extents(expolygons_with_id.expoly));
|
||||
return bb;
|
||||
}
|
||||
|
||||
@ -1328,11 +1330,13 @@ void Slic3r::center(ExPolygonsWithIds &e)
|
||||
translate(e, -bb.center());
|
||||
}
|
||||
|
||||
ExPolygons Emboss::text2shapes(FontFileWithCache &font_with_cache, const char *text, const FontProp &font_prop, const std::function<bool()>& was_canceled)
|
||||
HealedExPolygons Emboss::text2shapes(FontFileWithCache &font_with_cache, const char *text, const FontProp &font_prop, const std::function<bool()>& was_canceled)
|
||||
{
|
||||
std::wstring text_w = boost::nowide::widen(text);
|
||||
ExPolygonsWithIds vshapes = text2vshapes(font_with_cache, text_w, font_prop, was_canceled);
|
||||
return union_ex(vshapes);
|
||||
|
||||
float delta = static_cast<float>(1. / SHAPE_SCALE);
|
||||
return union_with_delta(vshapes, delta, MAX_HEAL_ITERATION_OF_TEXT);
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
@ -18,6 +18,13 @@
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
// Extend expolygons with information whether it was successfull healed
|
||||
struct HealedExPolygons{
|
||||
ExPolygons expolygons;
|
||||
bool is_healed;
|
||||
operator ExPolygons&() { return expolygons; }
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// class with only static function add ability to engraved OR raised
|
||||
/// text OR polygons onto model surface
|
||||
@ -153,7 +160,7 @@ namespace Emboss
|
||||
/// <param name="font_prop">User defined property of the font</param>
|
||||
/// <param name="was_canceled">Way to interupt processing</param>
|
||||
/// <returns>Inner polygon cw(outer ccw)</returns>
|
||||
ExPolygons text2shapes (FontFileWithCache &font, const char *text, const FontProp &font_prop, const std::function<bool()> &was_canceled = []() {return false;});
|
||||
HealedExPolygons text2shapes (FontFileWithCache &font, const char *text, const FontProp &font_prop, const std::function<bool()> &was_canceled = []() {return false;});
|
||||
ExPolygonsWithIds text2vshapes(FontFileWithCache &font, const std::wstring& text, const FontProp &font_prop, const std::function<bool()>& was_canceled = []() {return false;});
|
||||
|
||||
const unsigned ENTER_UNICODE = static_cast<unsigned>('\n');
|
||||
@ -169,7 +176,7 @@ namespace Emboss
|
||||
/// <param name="is_non_zero">Fill type ClipperLib::pftNonZero for overlapping otherwise </param>
|
||||
/// <param name="max_iteration">Look at heal_expolygon()::max_iteration</param>
|
||||
/// <returns>Healed shapes with flag is fully healed</returns>
|
||||
std::pair<ExPolygons, bool> heal_polygons(const Polygons &shape, bool is_non_zero = true, unsigned max_iteration = 10);
|
||||
HealedExPolygons heal_polygons(const Polygons &shape, bool is_non_zero = true, unsigned max_iteration = 10);
|
||||
|
||||
/// <summary>
|
||||
/// NOTE: call Slic3r::union_ex before this call
|
||||
@ -467,9 +474,9 @@ namespace Emboss
|
||||
void translate(ExPolygonsWithIds &e, const Point &p);
|
||||
BoundingBox get_extents(const ExPolygonsWithIds &e);
|
||||
void center(ExPolygonsWithIds &e);
|
||||
ExPolygons union_ex(const ExPolygonsWithIds &shapes);
|
||||
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)
|
||||
ExPolygons union_with_delta(const ExPolygonsWithIds &shapes, float delta);
|
||||
HealedExPolygons union_with_delta(const ExPolygonsWithIds &shapes, float delta, unsigned max_heal_iteration);
|
||||
} // namespace Slic3r
|
||||
#endif // slic3r_Emboss_hpp_
|
||||
|
@ -61,6 +61,9 @@ struct ExPolygonsWithId
|
||||
// shape defined by integer point contain only lines
|
||||
// Curves are converted to sequence of lines
|
||||
ExPolygons expoly;
|
||||
|
||||
// flag whether expolygons are fully healed(without duplication)
|
||||
bool is_healed = true;
|
||||
};
|
||||
using ExPolygonsWithIds = std::vector<ExPolygonsWithId>;
|
||||
|
||||
@ -103,7 +106,11 @@ struct EmbossShape
|
||||
std::shared_ptr<std::string> file_data = nullptr;
|
||||
};
|
||||
SvgFile svg_file;
|
||||
|
||||
|
||||
// flag whether during cration of union expolygon final shape was fully correct
|
||||
// correct mean without selfintersection and duplicate(double) points
|
||||
bool is_healed = true;
|
||||
|
||||
// undo / redo stack recovery
|
||||
template<class Archive> void save(Archive &ar) const
|
||||
{
|
||||
|
@ -181,6 +181,7 @@ static constexpr const char *FONT_WEIGHT_ATTR = "weight";
|
||||
// Store / load of EmbossShape
|
||||
static constexpr const char *SHAPE_TAG = "slic3rpe:shape";
|
||||
static constexpr const char *SHAPE_SCALE_ATTR = "scale";
|
||||
static constexpr const char *UNHEALED_ATTR = "unhealed";
|
||||
static constexpr const char *SVG_FILE_PATH_ATTR = "filepath";
|
||||
static constexpr const char *SVG_FILE_PATH_IN_3MF_ATTR = "filepath3mf";
|
||||
|
||||
@ -3855,12 +3856,15 @@ void to_xml(std::stringstream &stream, const EmbossShape &es, const ModelVolume
|
||||
|
||||
stream << SHAPE_SCALE_ATTR << "=\"" << es.scale << "\" ";
|
||||
|
||||
if (!es.is_healed)
|
||||
stream << UNHEALED_ATTR << "=\"" << 1 << "\" ";
|
||||
|
||||
// projection
|
||||
const EmbossProjection &p = es.projection;
|
||||
stream << DEPTH_ATTR << "=\"" << p.depth << "\" ";
|
||||
if (p.use_surface)
|
||||
stream << USE_SURFACE_ATTR << "=\"" << 1 << "\" ";
|
||||
|
||||
|
||||
// FIX of baked transformation
|
||||
Transform3d fix = create_fix(es.fix_3mf_tr, volume);
|
||||
stream << TRANSFORM_ATTR << "=\"";
|
||||
@ -3872,6 +3876,8 @@ void to_xml(std::stringstream &stream, const EmbossShape &es, const ModelVolume
|
||||
|
||||
std::optional<EmbossShape> read_emboss_shape(const char **attributes, unsigned int num_attributes) {
|
||||
double scale = get_attribute_value_float(attributes, num_attributes, SHAPE_SCALE_ATTR);
|
||||
int unhealed = get_attribute_value_int(attributes, num_attributes, UNHEALED_ATTR);
|
||||
bool is_healed = unhealed != 1;
|
||||
|
||||
EmbossProjection projection;
|
||||
projection.depth = get_attribute_value_float(attributes, num_attributes, DEPTH_ATTR);
|
||||
@ -3893,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)};
|
||||
return EmbossShape{shapes, scale, std::move(projection), std::move(fix_tr_mat), std::move(svg), is_healed};
|
||||
}
|
||||
|
||||
|
||||
|
@ -18,8 +18,8 @@ struct LinesPath{
|
||||
Polygons polygons;
|
||||
Polylines polylines; };
|
||||
LinesPath linearize_path(NSVGpath *first_path, const NSVGLineParams ¶m);
|
||||
ExPolygons fill_to_expolygons(const LinesPath &lines_path, const NSVGshape &shape, const NSVGLineParams ¶m);
|
||||
ExPolygons stroke_to_expolygons(const LinesPath &lines_path, const NSVGshape &shape, const NSVGLineParams ¶m);
|
||||
HealedExPolygons fill_to_expolygons(const LinesPath &lines_path, const NSVGshape &shape, const NSVGLineParams ¶m);
|
||||
HealedExPolygons stroke_to_expolygons(const LinesPath &lines_path, const NSVGshape &shape, const NSVGLineParams ¶m);
|
||||
} // namespace
|
||||
|
||||
namespace Slic3r {
|
||||
@ -45,11 +45,13 @@ ExPolygonsWithIds create_shape_with_ids(const NSVGimage &image, const NSVGLinePa
|
||||
|
||||
if (is_fill_used) {
|
||||
unsigned unique_id = static_cast<unsigned>(2 * shape_id);
|
||||
result.push_back({unique_id, fill_to_expolygons(lines_path, shape, param)});
|
||||
HealedExPolygons expoly = fill_to_expolygons(lines_path, shape, param);
|
||||
result.push_back({unique_id, expoly.expolygons, expoly.is_healed});
|
||||
}
|
||||
if (is_stroke_used) {
|
||||
unsigned unique_id = static_cast<unsigned>(2 * shape_id + 1);
|
||||
result.push_back({unique_id, stroke_to_expolygons(lines_path, shape, param)});
|
||||
HealedExPolygons expoly = stroke_to_expolygons(lines_path, shape, param);
|
||||
result.push_back({unique_id, expoly.expolygons, expoly.is_healed});
|
||||
}
|
||||
}
|
||||
|
||||
@ -352,7 +354,7 @@ LinesPath linearize_path(NSVGpath *first_path, const NSVGLineParams ¶m)
|
||||
return result;
|
||||
}
|
||||
|
||||
ExPolygons fill_to_expolygons(const LinesPath &lines_path, const NSVGshape &shape, const NSVGLineParams ¶m)
|
||||
HealedExPolygons fill_to_expolygons(const LinesPath &lines_path, const NSVGshape &shape, const NSVGLineParams ¶m)
|
||||
{
|
||||
Polygons fill = lines_path.polygons; // copy
|
||||
|
||||
@ -366,7 +368,7 @@ ExPolygons fill_to_expolygons(const LinesPath &lines_path, const NSVGshape &shap
|
||||
if (shape.fillRule == NSVGfillRule::NSVG_FILLRULE_EVENODD)
|
||||
is_non_zero = false;
|
||||
|
||||
return Emboss::heal_polygons(fill, is_non_zero, param.max_heal_iteration).first;
|
||||
return Emboss::heal_polygons(fill, is_non_zero, param.max_heal_iteration);
|
||||
}
|
||||
|
||||
struct DashesParam{
|
||||
@ -475,7 +477,7 @@ Polylines to_dashes(const Polyline &polyline, const DashesParam& param)
|
||||
return dashes;
|
||||
}
|
||||
|
||||
ExPolygons stroke_to_expolygons(const LinesPath &lines_path, const NSVGshape &shape, const NSVGLineParams ¶m)
|
||||
HealedExPolygons stroke_to_expolygons(const LinesPath &lines_path, const NSVGshape &shape, const NSVGLineParams ¶m)
|
||||
{
|
||||
// convert stroke to polygon
|
||||
ClipperLib::JoinType join_type = ClipperLib::JoinType::jtSquare;
|
||||
@ -515,7 +517,7 @@ ExPolygons stroke_to_expolygons(const LinesPath &lines_path, const NSVGshape &sh
|
||||
}
|
||||
|
||||
bool is_non_zero = true;
|
||||
return Emboss::heal_polygons(result, is_non_zero, param.max_heal_iteration).first;
|
||||
return Emboss::heal_polygons(result, is_non_zero, param.max_heal_iteration);
|
||||
}
|
||||
|
||||
} // namespace
|
@ -777,8 +777,57 @@ void wu_draw_line(Linef line,
|
||||
}
|
||||
}
|
||||
|
||||
template<unsigned int N> // N .. count of channels per pixel
|
||||
void draw_side_outline(const ExPolygons &shape, const std::array<unsigned char, N> &color, std::vector<unsigned char> &data, size_t data_width, double scale)
|
||||
{
|
||||
int count_lines = data.size() / (N * data_width);
|
||||
size_t data_line = N * data_width;
|
||||
auto get_offset = [count_lines, data_line](int x, int y) {
|
||||
// NOTE: y has opposit direction in texture
|
||||
return (count_lines - y - 1) * data_line + x * N;
|
||||
};
|
||||
|
||||
// overlap color
|
||||
auto draw = [&data, data_width, count_lines, get_offset, &color](int x, int y, float brightess) {
|
||||
if (x < 0 || y < 0 || x >= data_width || y >= count_lines)
|
||||
return; // out of image
|
||||
size_t offset = get_offset(x, y);
|
||||
bool change_color = false;
|
||||
for (size_t i = 0; i < N - 1; ++i) {
|
||||
if(data[offset + i] != color[i]){
|
||||
data[offset + i] = color[i];
|
||||
change_color = true;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned char &alpha = data[offset + N - 1];
|
||||
if (alpha == 0 || change_color){
|
||||
alpha = static_cast<unsigned char>(std::round(brightess * 255));
|
||||
} else if (alpha != 255){
|
||||
alpha = static_cast<unsigned char>(std::min(255, int(alpha) + static_cast<int>(std::round(brightess * 255))));
|
||||
}
|
||||
};
|
||||
|
||||
BoundingBox bb_unscaled = get_extents(shape);
|
||||
Linesf lines = to_linesf(shape);
|
||||
BoundingBoxf bb(bb_unscaled.min.cast<double>(), bb_unscaled.max.cast<double>());
|
||||
|
||||
// scale lines to pixels
|
||||
if (!is_approx(scale, 1.)) {
|
||||
for (Linef &line : lines) {
|
||||
line.a *= scale;
|
||||
line.b *= scale;
|
||||
}
|
||||
bb.min *= scale;
|
||||
bb.max *= scale;
|
||||
}
|
||||
|
||||
for (const Linef &line : lines)
|
||||
wu_draw_line_side(line, draw);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Draw filled ExPolygon into data
|
||||
/// Draw filled ExPolygon into data
|
||||
/// line by line inspired by: http://alienryderflex.com/polygon_fill/
|
||||
/// </summary>
|
||||
/// <typeparam name="N">Count channels for one pixel(RGBA = 4)</typeparam>
|
||||
@ -809,7 +858,6 @@ void draw_filled(const ExPolygons &shape, const std::array<unsigned char, N>& co
|
||||
bb.min *= scale;
|
||||
bb.max *= scale;
|
||||
}
|
||||
auto tree = Slic3r::AABBTreeLines::build_aabb_tree_over_indexed_lines(lines);
|
||||
|
||||
int count_lines = data.size() / (N * data_width);
|
||||
size_t data_line = N * data_width;
|
||||
@ -839,8 +887,11 @@ void draw_filled(const ExPolygons &shape, const std::array<unsigned char, N>& co
|
||||
alpha = static_cast<unsigned char>(std::min(255, int(alpha) + static_cast<int>(std::round(brightess * 255))));
|
||||
}
|
||||
};
|
||||
for (const Linef& line: lines) wu_draw_line_side(line, draw);
|
||||
|
||||
for (const Linef& line: lines)
|
||||
wu_draw_line_side(line, draw);
|
||||
|
||||
auto tree = Slic3r::AABBTreeLines::build_aabb_tree_over_indexed_lines(lines);
|
||||
|
||||
// range for intersection line
|
||||
double x1 = bb.min.x() - 1.f;
|
||||
@ -883,7 +934,7 @@ void draw_filled(const ExPolygons &shape, const std::array<unsigned char, N>& co
|
||||
}
|
||||
|
||||
// init texture by draw expolygons into texture
|
||||
bool init_texture(Texture &texture, const ExPolygonsWithIds& shapes_with_ids, unsigned max_size_px){
|
||||
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);
|
||||
Point bb_size = bb.size();
|
||||
double bb_width = bb_size.x(); // [in mm]
|
||||
@ -914,12 +965,35 @@ bool init_texture(Texture &texture, const ExPolygonsWithIds& shapes_with_ids, un
|
||||
shape = union_ex(shape);
|
||||
|
||||
// align to texture
|
||||
for (ExPolygon& expolygon: shape)
|
||||
expolygon.translate(-bb.min);
|
||||
|
||||
translate(shape, -bb.min);
|
||||
size_t texture_width = static_cast<size_t>(texture.width);
|
||||
unsigned char alpha = 255; // without transparency
|
||||
std::array<unsigned char, 4> color{201, 201, 201, alpha};
|
||||
draw_filled<4>(shape, color, data, (size_t)texture.width, scale);
|
||||
std::array<unsigned char, 4> color_shape{201, 201, 201, alpha}; // from degin by @JosefZachar
|
||||
std::array<unsigned char, 4> color_error{237, 28, 36, alpha}; // from icon: resources/icons/flag_red.svg
|
||||
std::array<unsigned char, 4> color_warning{237, 107, 33, alpha}; // icons orange
|
||||
// draw unhealedable shape
|
||||
for (const ExPolygonsWithId &shapes_with_id : shapes_with_ids)
|
||||
if (!shapes_with_id.is_healed) {
|
||||
ExPolygons bad_shape = shapes_with_id.expoly; // copy
|
||||
translate(bad_shape, -bb.min); // align to texture
|
||||
draw_side_outline<4>(bad_shape, color_error, data, texture_width, scale);
|
||||
}
|
||||
// Draw shape with warning
|
||||
if (!shape_warnings.empty()) {
|
||||
for (const ExPolygonsWithId &shapes_with_id : shapes_with_ids){
|
||||
assert(shapes_with_id.id < shape_warnings.size());
|
||||
if (shapes_with_id.id >= shape_warnings.size())
|
||||
continue;
|
||||
if (shape_warnings[shapes_with_id.id].empty())
|
||||
continue; // no warnings for shape
|
||||
ExPolygons warn_shape = shapes_with_id.expoly; // copy
|
||||
translate(warn_shape, -bb.min); // align to texture
|
||||
draw_side_outline<4>(warn_shape, color_warning, data, texture_width, scale);
|
||||
}
|
||||
}
|
||||
|
||||
// Draw rest of shape
|
||||
draw_filled<4>(shape, color_shape, data, texture_width, scale);
|
||||
|
||||
// sends data to gpu
|
||||
glsafe(::glPixelStorei(GL_UNPACK_ALIGNMENT, 1));
|
||||
@ -1027,14 +1101,33 @@ std::string create_stroke_warning(const NSVGshape &shape) {
|
||||
/// <param name="image">Input svg loaded to shapes</param>
|
||||
/// <returns>Vector of warnings with same size as EmbossShape::shapes_with_ids
|
||||
/// or Empty when no warnings -> for fast checking that every thing is all right(more common case) </returns>
|
||||
std::vector<std::string> create_shape_warnings(const NSVGimage &image, float scale){
|
||||
std::vector<std::string> create_shape_warnings(const EmbossShape &shape, float scale){
|
||||
assert(shape.svg_file.image != nullptr);
|
||||
if (shape.svg_file.image == nullptr)
|
||||
return {std::string{"Uninitialized SVG image"}};
|
||||
|
||||
const NSVGimage &image = *shape.svg_file.image;
|
||||
std::vector<std::string> result;
|
||||
auto add_warning = [&result, &image](size_t index, const std::string &message) {
|
||||
if (result.empty())
|
||||
result = std::vector<std::string>(get_shapes_count(image) * 2);
|
||||
result[index] = message;
|
||||
std::string &res = result[index];
|
||||
if (res.empty())
|
||||
res = message;
|
||||
else
|
||||
res += '\n' + message;
|
||||
};
|
||||
|
||||
if (!shape.is_healed) {
|
||||
for (const ExPolygonsWithId &i : shape.shapes_with_ids)
|
||||
if (!i.is_healed)
|
||||
add_warning(i.id, _u8L("Path can't be healed from selfintersection and multiple points."));
|
||||
|
||||
// This waning is not connected to NSVGshape. It is about union of paths, but Zero index is shown first
|
||||
size_t index = 0;
|
||||
add_warning(index, _u8L("Final shape constains selfintersection or multiple points with same coordinate"));
|
||||
}
|
||||
|
||||
size_t shape_index = 0;
|
||||
for (NSVGshape *shape = image.shapes; shape != NULL; shape = shape->next, ++shape_index) {
|
||||
if (!(shape->flags & NSVG_FLAGS_VISIBLE)){
|
||||
@ -1114,8 +1207,8 @@ void GLGizmoSVG::set_volume_by_selection()
|
||||
|
||||
m_volume = volume;
|
||||
m_volume_id = volume->id();
|
||||
m_volume_shape = *volume->emboss_shape; // copy
|
||||
m_shape_warnings = create_shape_warnings(image, get_scale_for_tolerance());
|
||||
m_volume_shape = es; // copy
|
||||
m_shape_warnings = create_shape_warnings(es, get_scale_for_tolerance());
|
||||
|
||||
// Calculate current angle of up vector
|
||||
m_angle = calculate_angle(selection);
|
||||
@ -1303,7 +1396,7 @@ void GLGizmoSVG::draw_preview(){
|
||||
// drag&drop is out of rendering scope so texture must be created on this place
|
||||
if (m_texture.id == 0) {
|
||||
const ExPolygonsWithIds &shapes = m_volume->emboss_shape->shapes_with_ids;
|
||||
init_texture(m_texture, shapes, m_gui_cfg->texture_max_size_px);
|
||||
init_texture(m_texture, shapes, m_gui_cfg->texture_max_size_px, m_shape_warnings);
|
||||
}
|
||||
|
||||
//::draw(m_volume_shape.shapes_with_ids, m_gui_cfg->texture_max_size_px);
|
||||
@ -1535,8 +1628,8 @@ void GLGizmoSVG::draw_filename(){
|
||||
EmbossShape es_ = select_shape(m_volume_shape.svg_file.path, tes_tol);
|
||||
m_volume_shape.svg_file = std::move(es_.svg_file);
|
||||
m_volume_shape.shapes_with_ids = std::move(es_.shapes_with_ids);
|
||||
m_shape_warnings = create_shape_warnings(*m_volume_shape.svg_file.image, scale);
|
||||
init_texture(m_texture, m_volume_shape.shapes_with_ids, m_gui_cfg->texture_max_size_px);
|
||||
m_shape_warnings = create_shape_warnings(m_volume_shape, scale);
|
||||
init_texture(m_texture, m_volume_shape.shapes_with_ids, m_gui_cfg->texture_max_size_px, m_shape_warnings);
|
||||
process();
|
||||
}
|
||||
}
|
||||
|
@ -78,7 +78,7 @@ void CreateFontImageJob::process(Ctl &ctl)
|
||||
|
||||
// normalize height of font
|
||||
BoundingBox bounding_box;
|
||||
for (ExPolygon &shape : shapes)
|
||||
for (const ExPolygon &shape : shapes)
|
||||
bounding_box.merge(BoundingBox(shape.contour.points));
|
||||
if (bounding_box.size().x() < 1 || bounding_box.size().y() < 1) {
|
||||
m_input.cancel->store(true);
|
||||
|
@ -791,9 +791,15 @@ bool check(const UpdateSurfaceVolumeData &input, bool is_main_thread)
|
||||
|
||||
template<typename Fnc>
|
||||
ExPolygons create_shape(DataBase &input, Fnc was_canceled) {
|
||||
const EmbossShape &es = input.create_shape();
|
||||
EmbossShape &es = input.create_shape();
|
||||
float delta = 50.f;
|
||||
return union_with_delta(es.shapes_with_ids, delta);
|
||||
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;
|
||||
}
|
||||
|
||||
//#define STORE_SAMPLING
|
||||
|
Loading…
x
Reference in New Issue
Block a user