diff --git a/src/libslic3r/SLA/SupportIslands/LineUtils.cpp b/src/libslic3r/SLA/SupportIslands/LineUtils.cpp index 8b056e9eb5..8c57cc694b 100644 --- a/src/libslic3r/SLA/SupportIslands/LineUtils.cpp +++ b/src/libslic3r/SLA/SupportIslands/LineUtils.cpp @@ -316,7 +316,8 @@ LineUtils::LineConnection LineUtils::create_line_connection(const Slic3r::Lines if (!inserts(prev_index, index)) { bool found_index = false; bool found_prev_index = false; - std::remove_if(not_finished.begin(), not_finished.end(), + not_finished.erase(std::remove_if(not_finished.begin(), + not_finished.end(), [&](const size_t ¬_finished_index) { if (!found_index && inserts(index, not_finished_index)) { found_index = true; @@ -327,7 +328,8 @@ LineUtils::LineConnection LineUtils::create_line_connection(const Slic3r::Lines return true; } return false; - }); + }), + not_finished.end()); if (!found_index) not_finished.push_back(index); if (!found_prev_index) not_finished.push_back(prev_index); } @@ -337,6 +339,16 @@ LineUtils::LineConnection LineUtils::create_line_connection(const Slic3r::Lines return line_connection; } +Slic3r::BoundingBox LineUtils::create_bounding_box(const Lines &lines) { + Points pts; + pts.reserve(lines.size()*2); + for (const Line &line : lines) { + pts.push_back(line.a); + pts.push_back(line.b); + } + return BoundingBox(pts); +} + std::map LineUtils::create_line_connection_over_b(const Lines &lines) { static const size_t bad_index = -1; @@ -352,24 +364,37 @@ std::map LineUtils::create_line_connection_over_b(const Lines &l return true; }; - std::vector not_finished; + std::vector not_finished_a; + std::vector not_finished_b; size_t prev_index = lines.size() - 1; for (size_t index = 0; index < lines.size(); ++index) { if (!inserts(prev_index, index)) { - bool found = false; - std::remove_if(not_finished.begin(), not_finished.end(), + bool found_b = false; + not_finished_b.erase(std::remove_if(not_finished_b.begin(), not_finished_b.end(), [&](const size_t ¬_finished_index) { - if (!found && inserts(prev_index, not_finished_index)) { - found = true; + if (!found_b && inserts(prev_index, not_finished_index)) { + found_b = true; return true; } return false; - }); - if(!found) not_finished.push_back(prev_index); + }),not_finished_b.end()); + if (!found_b) not_finished_a.push_back(prev_index); + + bool found_a = false; + not_finished_a.erase(std::remove_if(not_finished_a.begin(), not_finished_a.end(), + [&](const size_t ¬_finished_index) { + if (!found_a && inserts(not_finished_index, index)) { + found_a = true; + return true; + } + return false; + }),not_finished_a.end()); + if (!found_a) not_finished_b.push_back(index); } prev_index = index; } - assert(not_finished.empty()); + assert(not_finished_a.empty()); + assert(not_finished_b.empty()); return line_connection; } diff --git a/src/libslic3r/SLA/SupportIslands/LineUtils.hpp b/src/libslic3r/SLA/SupportIslands/LineUtils.hpp index b84c9cbbdb..fab94cd165 100644 --- a/src/libslic3r/SLA/SupportIslands/LineUtils.hpp +++ b/src/libslic3r/SLA/SupportIslands/LineUtils.hpp @@ -128,6 +128,13 @@ public: /// map of connected lines. static LineConnection create_line_connection(const Lines &lines); + /// + /// create bounding box around lines + /// + /// input lines + /// Bounding box + static BoundingBox create_bounding_box(const Lines &lines); + /// /// Create data structure from exPolygon lines to store connected line indexes /// diff --git a/src/libslic3r/SLA/SupportIslands/PointUtils.cpp b/src/libslic3r/SLA/SupportIslands/PointUtils.cpp index b49a3bc859..49b3b87e53 100644 --- a/src/libslic3r/SLA/SupportIslands/PointUtils.cpp +++ b/src/libslic3r/SLA/SupportIslands/PointUtils.cpp @@ -18,7 +18,7 @@ bool PointUtils::is_majorit_x(const Vec2d &point) Slic3r::Point PointUtils::perp(const Point &vector) { - return Point(-vector.x(), vector.y()); + return Point(-vector.y(), vector.x()); } bool PointUtils::is_same_direction(const Point &dir1, const Point &dir2) diff --git a/src/libslic3r/SLA/SupportIslands/SampleIslandUtils.cpp b/src/libslic3r/SLA/SupportIslands/SampleIslandUtils.cpp index d6daf970f7..f29cb4f892 100644 --- a/src/libslic3r/SLA/SupportIslands/SampleIslandUtils.cpp +++ b/src/libslic3r/SLA/SupportIslands/SampleIslandUtils.cpp @@ -783,18 +783,19 @@ SampleIslandUtils::Field SampleIslandUtils::create_field( auto add_wide_tiny_change = [&](const VoronoiGraph::Node::Neighbor *neighbor){ VoronoiGraph::Position position = VoronoiGraphUtils::get_position_with_distance(neighbor, min_width, lines); + Point p1, p2; + std::tie(p1, p2) = VoronoiGraphUtils::point_on_lines(position, lines); const VD::edge_type *edge = neighbor->edge; size_t i1 = edge->cell()->source_index(); size_t i2 = edge->twin()->cell()->source_index(); const Line &l1 = lines[i1]; - const Line &l2 = lines[i2]; - Point p1, p2; - std::tie(p1, p2) = VoronoiGraphUtils::point_on_lines(position, l1, l2); if (VoronoiGraphUtils::is_opposit_direction(edge, l1)) { // line1 is shorten on side line1.a --> line2 is shorten on side line2.b + assert(wide_tiny_changes.find(i2) == wide_tiny_changes.end()); wide_tiny_changes.insert({i2, WideTinyChange(p2, p1, i1)}); } else { // line1 is shorten on side line1.b + assert(wide_tiny_changes.find(i1) == wide_tiny_changes.end()); wide_tiny_changes.insert({i1, WideTinyChange(p1, p2, i2)}); } }; @@ -811,30 +812,32 @@ SampleIslandUtils::Field SampleIslandUtils::create_field( std::set field_line_indexes; while (!process.empty()) { const VoronoiGraph::Node *node = process.front(); + const VoronoiGraph::Node *prev_node = nullptr; process.pop(); if (done.find(node) != done.end()) continue; do { done.insert(node); - const auto &neighbors = node->neighbors; - node = nullptr; - for (const VoronoiGraph::Node::Neighbor &neighbor : neighbors) { - if (done.find(neighbor.node) != done.end()) continue; - const VD::edge_type *edge = neighbor.edge; + const VoronoiGraph::Node *next_node = nullptr; + for (const VoronoiGraph::Node::Neighbor &neighbor: node->neighbors) { + if (neighbor.node == prev_node) continue; + const VD::edge_type *edge = neighbor.edge; size_t index1 = edge->cell()->source_index(); size_t index2 = edge->twin()->cell()->source_index(); field_line_indexes.insert(index1); field_line_indexes.insert(index2); - if (neighbor.max_width < - config.min_width_for_outline_support) { + if (neighbor.max_width < config.min_width_for_outline_support) { add_wide_tiny_change(&neighbor); continue; } - if (node == nullptr) { - node = neighbor.node; + if (done.find(neighbor.node) != done.end()) continue; // loop back + if (next_node == nullptr) { + next_node = neighbor.node; } else { process.push(neighbor.node); } } + prev_node = node; + node = next_node; } while (node != nullptr); } diff --git a/src/libslic3r/SLA/SupportIslands/SupportIslandPoint.cpp b/src/libslic3r/SLA/SupportIslands/SupportIslandPoint.cpp new file mode 100644 index 0000000000..d12e2f8028 --- /dev/null +++ b/src/libslic3r/SLA/SupportIslands/SupportIslandPoint.cpp @@ -0,0 +1,32 @@ +#include "SupportIslandPoint.hpp" +#include "VoronoiGraphUtils.hpp" + +using namespace Slic3r::sla; + +SupportIslandPoint::SupportIslandPoint(Slic3r::Point point, Type type) + : point(std::move(point)), type(type) +{} + +coord_t SupportIslandPoint::move(const Point &destination) +{ + Point diff = destination - point; + point = destination; + // TODO: check move out of island !! + // + need island ExPolygon + return diff.x() + diff.y(); // Manhatn distance +} + +coord_t SupportCenterIslandPoint::move(const Point &destination) +{ + // TODO: For decide of move need information about + // + search distance for allowed move over VG(count or distance) + + // move only along VD + position = VoronoiGraphUtils::align(position, destination, max_distance); + + Point new_point = VoronoiGraphUtils::create_edge_point(position); + Point move = new_point - point; + point = new_point; + return abs(move.x()) + abs(move.y()); +} + diff --git a/src/libslic3r/SLA/SupportIslands/VoronoiGraphUtils.cpp b/src/libslic3r/SLA/SupportIslands/VoronoiGraphUtils.cpp index a4d68c934d..d9a9619d84 100644 --- a/src/libslic3r/SLA/SupportIslands/VoronoiGraphUtils.cpp +++ b/src/libslic3r/SLA/SupportIslands/VoronoiGraphUtils.cpp @@ -377,8 +377,17 @@ double VoronoiGraphUtils::calculate_length( double VoronoiGraphUtils::calculate_max_width( const VD::edge_type &edge, const Lines &lines) { - Point v0 = to_point(edge.vertex0()); - Point v1 = to_point(edge.vertex1()); + auto get_squared_distance = [&](const VD::vertex_type *vertex, + const Point &point) -> double { + Point point_v = to_point(vertex); + Vec2d vector = (point - point_v).cast(); + return vector.x() * vector.x() + vector.y() * vector.y(); + }; + auto max_width = [&](const Point& point)->double{ + return 2. * + sqrt(std::max(get_squared_distance(edge.vertex0(), point), + get_squared_distance(edge.vertex1(), point))); + }; if (edge.is_linear()) { // edge line could be initialized by 2 points @@ -393,11 +402,7 @@ double VoronoiGraphUtils::calculate_max_width( boost::polygon::SOURCE_CATEGORY_SEGMENT_END_POINT); source_point = source_line.b; } - Point vec0 = source_point - v0; - Point vec1 = source_point - v1; - double distance0 = sqrt(vec0.x() * vec0.x() + vec0.y() * vec0.y()); - double distance1 = sqrt(vec0.x() * vec0.x() + vec0.y() * vec0.y()); - return 2 * std::max(distance0, distance1); + return max_width(source_point); } assert(edge.cell()->contains_segment()); assert(!edge.twin()->cell()->contains_point()); @@ -405,6 +410,8 @@ double VoronoiGraphUtils::calculate_max_width( const Line &line = lines[edge.cell()->source_index()]; + Point v0 = to_point(edge.vertex0()); + Point v1 = to_point(edge.vertex1()); double distance0 = line.perp_distance_to(v0); double distance1 = line.perp_distance_to(v1); return 2 * std::max(distance0, distance1); @@ -413,11 +420,7 @@ double VoronoiGraphUtils::calculate_max_width( Parabola parabola = get_parabola(edge, lines); // distance to point and line is same // vector from edge vertex to parabola focus point - Point vec0 = parabola.focus - v0; - Point vec1 = parabola.focus - v1; - double distance0 = sqrt(vec0.x() * vec0.x() + vec0.y() * vec0.y()); - double distance1 = sqrt(vec0.x() * vec0.x() + vec0.y() * vec0.y()); - return 2 * std::max(distance0, distance1); + return max_width(parabola.focus); } VoronoiGraph VoronoiGraphUtils::create_skeleton(const VD &vd, const Lines &lines) @@ -881,35 +884,39 @@ VoronoiGraph::Position VoronoiGraphUtils::get_position_with_distance( return result; } -Slic3r::Point VoronoiGraphUtils::point_on_line( - const VoronoiGraph::Position &position, const Line &line) -{ - const VD::edge_type* edge = position.neighbor->edge; - assert(edge->is_linear()); - Point edge_point = create_edge_point(position); - Point dir = to_point(edge->vertex0()) - to_point(edge->vertex1()); - Line edge_line(edge_point, edge_point + PointUtils::perp(dir)); - std::optional intersection = LineUtils::intersection(line, edge_line); - assert(intersection.has_value()); - return intersection->cast(); -} - std::pair VoronoiGraphUtils::point_on_lines( - const VoronoiGraph::Position &position, - const Line & first, - const Line & second) + const VoronoiGraph::Position &position, const Lines &lines) { const VD::edge_type *edge = position.neighbor->edge; - assert(edge->is_linear()); + + // TODO: solve point on parabola + //assert(edge->is_linear()); + bool is_linear = edge->is_linear(); + Point edge_point = create_edge_point(position); Point dir = to_point(edge->vertex0()) - to_point(edge->vertex1()); - Line edge_line(edge_point, edge_point + PointUtils::perp(dir)); - std::optional first_intersection = LineUtils::intersection(first, edge_line); - assert(first_intersection.has_value()); - std::optional second_intersection = LineUtils::intersection(second, edge_line); - assert(second_intersection.has_value()); - return {first_intersection->cast(), - second_intersection->cast()}; + Line intersecting_line(edge_point, edge_point + PointUtils::perp(dir)); + + auto point_on_line = [&](const VD::edge_type *edge) -> Point { + assert(edge->is_finite()); + const VD::cell_type *cell = edge->cell(); + size_t line_index = cell->source_index(); + const Line &line = lines[line_index]; + using namespace boost::polygon; + bool is_single_point = cell->source_category() == + SOURCE_CATEGORY_SINGLE_POINT; + if (cell->source_category() == SOURCE_CATEGORY_SEGMENT_START_POINT) { + return line.a; + } + if (cell->source_category() == SOURCE_CATEGORY_SEGMENT_END_POINT) { + return line.b; + } + std::optional intersection = LineUtils::intersection(line, intersecting_line); + assert(intersection.has_value()); + return intersection->cast(); + }; + + return {point_on_line(edge), point_on_line(edge->twin())}; } VoronoiGraph::Position VoronoiGraphUtils::align( @@ -1074,18 +1081,34 @@ double VoronoiGraphUtils::get_max_width(const VoronoiGraph::Node *node) void VoronoiGraphUtils::draw(SVG & svg, const VoronoiGraph &graph, - coord_t width) + coord_t width, + bool pointer_caption) { + auto print_address = [&](const Point& p, const char* prefix, void * addr, const char* color){ + if (pointer_caption) { + std::stringstream ss; + ss << prefix << std::hex << (int) addr; + std::string s = ss.str(); + svg.draw_text(p, s.c_str(), color); + } + }; + for (const auto &[key, value] : graph.data) { - svg.draw(Point(key->x(), key->y()), "lightgray", width); + Point p(key->x(), key->y()); + svg.draw(p, "lightgray", width); + print_address(p, "v_",(void*)key, "lightgray"); for (const auto &n : value.neighbors) { - if (n.edge->vertex0() > n.edge->vertex1()) continue; Point from = to_point(n.edge->vertex0()); Point to = to_point(n.edge->vertex1()); + bool is_second = n.edge->vertex0() > n.edge->vertex1(); + Point center = (from + to) / 2; + Point p = center + ((is_second) ? Point(0., -2e6) : + Point(0., 2e6)); + print_address(p, "n_", (void *) &n, "gray"); + if (is_second) continue; + svg.draw_text(center + Point(-6e6, 0.), ("w="+std::to_string(n.max_width)).c_str(), "gray"); svg.draw(Line(from, to), "gray", width); - Point center = from + to; - center *= .5; // svg.draw_text(center, // (std::to_string(std::round(n.edge_length/3e5)/100.)).c_str(), "gray"); } diff --git a/src/libslic3r/SLA/SupportIslands/VoronoiGraphUtils.hpp b/src/libslic3r/SLA/SupportIslands/VoronoiGraphUtils.hpp index 3e2b01f1d1..3c2b512b9f 100644 --- a/src/libslic3r/SLA/SupportIslands/VoronoiGraphUtils.hpp +++ b/src/libslic3r/SLA/SupportIslands/VoronoiGraphUtils.hpp @@ -359,26 +359,18 @@ public: coord_t width, const Lines & lines); - /// - /// Calculate point on line correspond to edge position - /// - /// Position on edge - /// Line must be source of edge - /// Point lay on line defined by position on edge - static Point point_on_line(const VoronoiGraph::Position& position, const Line& line); - /// /// calculate both point on source lines correspond to edge postion /// Faster way to get both point_on_line /// /// Position on edge - /// Line must be source of edge - /// Line must be source of edge - /// pair of point lay on lines cirrespond to position + /// Source lines of VD + /// pair of point lay on outline lines correspond to position on edge + /// first -> source line of edge cell + /// second -> source line of edge twin cell static std::pair point_on_lines( const VoronoiGraph::Position &position, - const Line & first, - const Line & second); + const Lines & lines); /// /// align "position" close to point "to" @@ -418,7 +410,7 @@ public: static double get_max_width(const VoronoiGraph::Node *node); public: // draw function for debug - static void draw(SVG &svg, const VoronoiGraph &graph, coord_t width); + static void draw(SVG &svg, const VoronoiGraph &graph, coord_t width, bool pointer_caption = false); static void draw(SVG & svg, const VoronoiGraph::Nodes &path, coord_t width, diff --git a/tests/sla_print/sla_supptgen_tests.cpp b/tests/sla_print/sla_supptgen_tests.cpp index c71be6dc54..645da46011 100644 --- a/tests/sla_print/sla_supptgen_tests.cpp +++ b/tests/sla_print/sla_supptgen_tests.cpp @@ -218,6 +218,29 @@ Slic3r::Polygon create_V_shape(double height, double line_width, double angle = return polygons.front(); } +ExPolygon create_tiny_wide_test(double wide, double tiny) +{ + double hole_size = wide; + double width = (2 + 1) * wide + 2 * hole_size; + double height = wide + 2*tiny + 2*hole_size; + auto outline = PolygonUtils::create_rect( width, height); + auto hole = PolygonUtils::create_rect(hole_size, hole_size); + hole.reverse(); + auto hole2 = hole;// copy + auto hole3 = hole; // copy + auto hole4 = hole; // copy + + int hole_move_x = wide / 2 + hole_size / 2; + int hole_move_y = wide / 2 + hole_size / 2; + hole.translate({hole_move_x, hole_move_y}); + hole2.translate({-hole_move_x, hole_move_y}); + hole3.translate({hole_move_x, -hole_move_y}); + hole4.translate({-hole_move_x, -hole_move_y}); + ExPolygon result(outline); + result.holes = {hole, hole2, hole3, hole4}; + return result; +} + ExPolygons createTestIslands(double size) { bool useFrogLeg = false;