diff --git a/src/libslic3r/SLA/SupportIslands/SampleIslandUtils.cpp b/src/libslic3r/SLA/SupportIslands/SampleIslandUtils.cpp index 2eeed558eb..1516c4f450 100644 --- a/src/libslic3r/SLA/SupportIslands/SampleIslandUtils.cpp +++ b/src/libslic3r/SLA/SupportIslands/SampleIslandUtils.cpp @@ -12,8 +12,20 @@ using namespace Slic3r::sla; -Slic3r::Point SampleIslandUtils::get_point_on_path( - const VoronoiGraph::Nodes &path, double distance) +SupportIslandPoint SampleIslandUtils::create_point( + const VoronoiGraph::Node::Neighbor *neighbor, + double ratio, + SupportIslandPoint::Type type) +{ + VoronoiGraph::Position position(neighbor, ratio); + Slic3r::Point p = VoronoiGraphUtils::get_edge_point(neighbor->edge, ratio); + return SupportIslandPoint(p, type, position); +} + +SupportIslandPoint SampleIslandUtils::create_point_on_path( + const VoronoiGraph::Nodes &path, + double distance, + SupportIslandPoint::Type type) { const VoronoiGraph::Node *prev_node = nullptr; double actual_distance = 0.; @@ -30,7 +42,7 @@ Slic3r::Point SampleIslandUtils::get_point_on_path( double previous_distance = actual_distance - distance; double over_ratio = previous_distance / neighbor->edge_length; double ratio = 1. - over_ratio; - return VoronoiGraphUtils::get_edge_point(neighbor->edge, ratio); + return create_point(neighbor, ratio, type); } prev_node = node; } @@ -40,14 +52,20 @@ Slic3r::Point SampleIslandUtils::get_point_on_path( return Point(0, 0); } +SupportIslandPoint SampleIslandUtils::create_middle_path_point( + const VoronoiGraph::Path &path, SupportIslandPoint::Type type) +{ + return create_point_on_path(path.nodes, path.length / 2, type); +} + SupportIslandPoints SampleIslandUtils::create_side_points( const VoronoiGraph::Nodes &path, double side_distance) { VoronoiGraph::Nodes reverse_path = path; // copy std::reverse(reverse_path.begin(), reverse_path.end()); return { - {get_point_on_path(path, side_distance), SupportIslandPoint::Type::two_points}, - {get_point_on_path(reverse_path, side_distance), SupportIslandPoint::Type::two_points} + create_point_on_path(path, side_distance, SupportIslandPoint::Type::two_points), + create_point_on_path(reverse_path, side_distance, SupportIslandPoint::Type::two_points) }; } @@ -64,7 +82,7 @@ SupportIslandPoints SampleIslandUtils::sample_side_branch( VoronoiGraph::Nodes reverse_path = side_path.nodes; std::reverse(reverse_path.begin(), reverse_path.end()); reverse_path.push_back(first_node); - return {get_point_on_path(reverse_path, cfg.side_distance)}; + return {create_point_on_path(reverse_path, cfg.side_distance)}; } // count of segment between points on main path size_t segment_count = static_cast( @@ -91,8 +109,9 @@ SupportIslandPoints SampleIslandUtils::sample_side_branch( } while (distance < neighbor->edge_length) { double edge_ratio = distance / neighbor->edge_length; - result.emplace_back(VoronoiGraphUtils::get_edge_point(neighbor->edge, edge_ratio), - SupportIslandPoint::Type::center_line); + result.emplace_back( + create_point(neighbor, edge_ratio, SupportIslandPoint::Type::center_line) + ); distance += sample_distance; } distance -= neighbor->edge_length; @@ -167,115 +186,284 @@ SupportIslandPoints SampleIslandUtils::sample_center_line( start_offset, cfg); if (path.circles.empty()) return result; - SupportIslandPoints result_circles = sample_center_circles(path, cfg); - result.insert(result.end(), result_circles.begin(), result_circles.end()); + sample_center_circles(path, cfg, result); + return result; } -SupportIslandPoints SampleIslandUtils::sample_center_circle( - const std::set& circle_set, - const VoronoiGraph::Nodes& path_nodes, - const CenterLineConfiguration & cfg - ) +void SampleIslandUtils::sample_center_circle_end( + const VoronoiGraph::Node::Neighbor &neighbor, + double & neighbor_distance, + const VoronoiGraph::Nodes & done_nodes, + double & node_distance, + const CenterLineConfiguration & cfg, + SupportIslandPoints & result) { - SupportIslandPoints result; - // DTO store information about distance to nearest support point - // and path from start point - struct NodeDistance + double distance = neighbor_distance + node_distance + neighbor.edge_length; + if (distance < cfg.max_sample_distance) { // no need add support point + if (neighbor_distance > node_distance + neighbor.edge_length) + neighbor_distance = node_distance + neighbor.edge_length; + if (node_distance > neighbor_distance + neighbor.edge_length) + node_distance = neighbor_distance + neighbor.edge_length; + return; + } + size_t count_supports = static_cast( + std::floor(distance / cfg.max_sample_distance)); + // distance between support points + double distance_between = distance / (count_supports + 1); + if (distance_between < neighbor_distance) { + // point is calculated to be in done path, SP will be on edge point + result.emplace_back(create_point(&neighbor, 1., SupportIslandPoint::Type::center_circle_end)); + neighbor_distance = 0.; + count_supports -= 1; + if (count_supports == 0) { + if (node_distance > neighbor.edge_length) + node_distance = neighbor.edge_length; + return; + } + distance = node_distance + neighbor.edge_length; + distance_between = distance / (count_supports + 1); + } + VoronoiGraph::Nodes nodes = done_nodes; // copy, could be more neighbor + nodes.insert(nodes.begin(), neighbor.node); + for (int i = 1; i <= count_supports; ++i) { + double distance_from_neighbor = i * (distance_between) - neighbor_distance; + result.emplace_back( + create_point_on_path(nodes, distance_from_neighbor, SupportIslandPoint::Type::center_circle_end2)); + double distance_support_to_node = fabs(neighbor.edge_length - + distance_from_neighbor); + if (node_distance > distance_support_to_node) + node_distance = distance_support_to_node; + } +} + +// DTO store information about distance to nearest support point +// and path from start point +struct NodeDistance +{ + VoronoiGraph::Nodes nodes; // from act node to start + double distance_from_support_point; + NodeDistance(const VoronoiGraph::Node *node, + double distance_from_support_point) + : nodes({node}) + , distance_from_support_point(distance_from_support_point) + {} +}; + +using SupportDistanceMap = std::map; +double get_distance_to_support_point(const VoronoiGraph::Node *node, + const SupportDistanceMap & support_distance_map, + double maximal_search) +{ + auto distance_item = support_distance_map.find(node); + if (distance_item != support_distance_map.end()) + return distance_item->second; + + // wide search for nearest support point by neighbors + struct Item { - VoronoiGraph::Nodes nodes; // from act node to start - double distance_from_support_point; - NodeDistance(const VoronoiGraph::Node *node, - double distance_from_support_point) - : nodes({node}) - , distance_from_support_point(distance_from_support_point) + const VoronoiGraph::Node *prev_node; + const VoronoiGraph::Node *node; + double act_distance; + bool exist_support_point; + Item(const VoronoiGraph::Node *prev_node, + const VoronoiGraph::Node *node, + double act_distance, + bool exist_support_point = false) + : prev_node(prev_node) + , node(node) + , act_distance(act_distance) + , exist_support_point(exist_support_point) {} }; + struct OrderDistanceFromNearest + { + bool operator()(const Item &first, const Item &second) + { + return first.act_distance > second.act_distance; + } + }; + std::priority_queue, OrderDistanceFromNearest> process; + for (const VoronoiGraph::Node::Neighbor &neighbor : node->neighbors) + process.emplace(node, neighbor.node, neighbor.edge_length); + + while (!process.empty()) { + Item i = process.top(); + if (i.exist_support_point) return i.act_distance; + process.pop(); + auto distance_item = support_distance_map.find(i.node); + if (distance_item != support_distance_map.end()) { + double distance = i.act_distance + distance_item->second; + if (distance > maximal_search) continue; + process.emplace(i.prev_node, i.node, distance, true); + continue; + } + for (const VoronoiGraph::Node::Neighbor &neighbor :i.node->neighbors) { + if (neighbor.node == i.prev_node) continue; + double distance = i.act_distance + neighbor.edge_length; + if (distance > maximal_search) continue; + process.emplace(i.node, neighbor.node, distance); + } + } + return maximal_search; +} + +SupportDistanceMap create_path_distances( + const std::set &circle_set, + const std::set &path_set, + const SupportDistanceMap & support_distance_map, + double maximal_search) +{ + SupportDistanceMap path_distances; + for (const VoronoiGraph::Node *node : circle_set) { + if (path_set.find(node) == path_set.end()) continue; // lay out of path + path_distances[node] = get_distance_to_support_point( + node, support_distance_map, maximal_search); + } + return path_distances; +} + +SupportDistanceMap create_support_distance_map(const SupportIslandPoints &support_points) +{ + SupportDistanceMap support_distance_map; + for (const SupportIslandPoint &support_point : support_points) { + const VoronoiGraph::Position &position = support_point.position; + const VoronoiGraph::Node *node = position.neighbor->node; + const VoronoiGraph::Node *twin_node = VoronoiGraphUtils::get_twin_node(position.neighbor); + double distance = (1 - position.ratio) * position.neighbor->edge_length; + double twin_distance = position.ratio * position.neighbor->edge_length; + + auto item = support_distance_map.find(node); + if (item == support_distance_map.end()) { + support_distance_map[node] = distance; + } else if (item->second > distance) + item->second = distance; + + auto twin_item = support_distance_map.find(twin_node); + if (twin_item == support_distance_map.end()) { + support_distance_map[twin_node] = twin_distance; + } else if (twin_item->second > twin_distance) + twin_item->second = twin_distance; + } + + return support_distance_map; +} + +template +const S &get_container_ref(const std::priority_queue &q) +{ + struct HackedQueue : private std::priority_queue + { + static const S &Container(const std::priority_queue &q) + { + return q.*&HackedQueue::c; + } + }; + return HackedQueue::Container(q); +} + +std::set create_path_set( + const VoronoiGraph::ExPath &path) +{ + std::queue side_branch_nodes; + std::set path_set; + for (const VoronoiGraph::Node *node : path.nodes) { + path_set.insert(node); + auto side_branch_item = path.side_branches.find(node); + if (side_branch_item == path.side_branches.end()) continue; + side_branch_nodes.push(node); + } + while (!side_branch_nodes.empty()) { + const VoronoiGraph::Node *node = side_branch_nodes.front(); + side_branch_nodes.pop(); + auto side_branch_item = path.side_branches.find(node); + const std::vector &side_branches = + get_container_ref(side_branch_item->second); + for (const VoronoiGraph::Path& side_branch : side_branches) + for (const VoronoiGraph::Node *node : side_branch.nodes) { + path_set.insert(node); + auto side_branch_item = path.side_branches.find(node); + if (side_branch_item == path.side_branches.end()) continue; + side_branch_nodes.push(node); + } + } + return path_set; +} + +void SampleIslandUtils::sample_center_circles( + const VoronoiGraph::ExPath & path, + const CenterLineConfiguration &cfg, + SupportIslandPoints& result) +{ + // vector of connected circle points + // for detection path from circle + std::vector> circles_sets = + create_circles_sets(path.circles, path.connected_circle); + std::set path_set = create_path_set(path); + SupportDistanceMap support_distance_map = create_support_distance_map(result); + for (const auto &circle_set : circles_sets) { + SupportDistanceMap path_distances = create_path_distances(circle_set, path_set, support_distance_map, cfg.max_sample_distance/2); + SupportIslandPoints circle_result = sample_center_circle(circle_set, path_distances, cfg); + result.insert(result.end(), circle_result.begin(), circle_result.end()); + } +} + +SupportIslandPoints SampleIslandUtils::sample_center_circle( + const std::set &circle_set, + std::map& path_distances, + const CenterLineConfiguration & cfg) +{ + SupportIslandPoints result; // depth search std::stack process; - // TODO: propagate distance from support point - // distance from nearest support point - double path_distance = cfg.max_sample_distance / 2; - // path can't be stored in done because it will skip begining of path - std::map path_distances; // path_nodes are already sampled - for (const VoronoiGraph::Node *node : path_nodes) { - // contain - if (circle_set.find(node) != circle_set.end()) { - process.push(NodeDistance(node, path_distance)); - path_distances[node] = path_distance; - } + for (const auto &path_distanc : path_distances) { + process.push(NodeDistance(path_distanc.first, path_distanc.second)); } - // TODO: sample circles out of main path - if (process.empty()) { // TODO: find side branch - } - - // when node is sampled in all side branches. + // when node is sampled in all side branches. // Value is distance to nearest support point - std::map done_distance; + std::map dones; while (!process.empty()) { NodeDistance nd = process.top(); // copy process.pop(); - const VoronoiGraph::Node *node = nd.nodes.front(); - const VoronoiGraph::Node *prev_node = - (nd.nodes.size() > 1) ? nd.nodes[1] : nullptr; - auto done_distance_item = done_distance.find(node); - if (done_distance_item != done_distance.end()) { + const VoronoiGraph::Node *node = nd.nodes.front(); + const VoronoiGraph::Node *prev_node = (nd.nodes.size() > 1) ? + nd.nodes[1] : + nullptr; + auto done_distance_item = dones.find(node); + if (done_distance_item != dones.end()) { if (done_distance_item->second > nd.distance_from_support_point) done_distance_item->second = nd.distance_from_support_point; - continue; + continue; } - done_distance[node] = nd.distance_from_support_point; - bool is_node_on_path = (path_distances.find(node) != path_distances.end()); - double &node_distance = done_distance[node]; // append to done node + // sign node as done with distance to nearest support + dones[node] = nd.distance_from_support_point; + double &node_distance = dones[node]; // append to done node + auto path_distance_item = path_distances.find(node); + bool is_node_on_path = (path_distance_item != path_distances.end()); + if (is_node_on_path && node_distance > path_distance_item->second) + node_distance = path_distance_item->second; for (const auto &neighbor : node->neighbors) { if (neighbor.node == prev_node) continue; - if (circle_set.find(neighbor.node) == circle_set.end()) continue; // out of circle points + if (circle_set.find(neighbor.node) == circle_set.end()) + continue; // out of circle points auto path_distance_item = path_distances.find(neighbor.node); - bool is_neighbor_on_path = (path_distance_item != path_distances.end()); - if (is_node_on_path && is_neighbor_on_path) continue; // already sampled - auto done_item = done_distance.find(neighbor.node); - bool is_done = done_item != done_distance.end(); - if (is_done || is_neighbor_on_path) { - double &done_distance = (is_done)? done_item->second : path_distance_item->second; - double distance = done_distance + - nd.distance_from_support_point + - neighbor.edge_length; - if (distance < cfg.max_sample_distance) continue; - size_t count_supports = static_cast( - std::floor(distance / cfg.max_sample_distance)); - // distance between support points - double distance_between = distance / (count_supports + 1); - if (distance_between < done_distance) { - // point is calculated to be in done path, SP will be on edge point - result.emplace_back( - VoronoiGraphUtils::get_edge_point(neighbor.edge, 1.), - SupportIslandPoint::Type::center_circle_end); - if (node_distance > neighbor.edge_length) - node_distance = neighbor.edge_length; - done_distance = 0.; - if (count_supports == 1) continue; - count_supports -= 1; - distance -= done_distance; - distance_between = distance / (count_supports + 1); - } - VoronoiGraph::Nodes nodes = nd.nodes; // copy, could be more neighbor - nodes.insert(nodes.begin(), neighbor.node); - for (int i = 1; i <= count_supports; ++i) { - double distance_from_neighbor = - i * (distance_between) -done_distance; - result.emplace_back( - get_point_on_path(nodes, distance_from_neighbor), - SupportIslandPoint::Type::center_circle_end2); - double distance_to_node = neighbor.edge_length - - distance_from_neighbor; - if (distance_to_node > 0. && - node_distance > distance_to_node) - node_distance = distance_to_node; - } - + bool is_neighbor_on_path = (path_distance_item != + path_distances.end()); + if (is_node_on_path && is_neighbor_on_path) + continue; // already sampled + + auto neighbor_done_item = dones.find(neighbor.node); + bool is_neighbor_done = neighbor_done_item != dones.end(); + if (is_neighbor_done || is_neighbor_on_path) { + double &neighbor_distance = (is_neighbor_done) ? + neighbor_done_item->second : + path_distance_item->second; + sample_center_circle_end(neighbor, neighbor_distance, + nd.nodes, node_distance, cfg, + result); continue; } @@ -289,8 +477,8 @@ SupportIslandPoints SampleIslandUtils::sample_center_circle( .distance_from_support_point - nd.distance_from_support_point; double ratio = distance_from_node / neighbor.edge_length; - result.emplace_back(VoronoiGraphUtils::get_edge_point(neighbor.edge, ratio), - SupportIslandPoint::Type::center_circle); + result.emplace_back( + create_point(&neighbor, ratio, SupportIslandPoint::Type::center_circle)); next_nd.distance_from_support_point -= cfg.max_sample_distance; } process.push(next_nd); @@ -299,33 +487,15 @@ SupportIslandPoints SampleIslandUtils::sample_center_circle( return result; } -SupportIslandPoints SampleIslandUtils::sample_center_circles( - const VoronoiGraph::ExPath &path, const CenterLineConfiguration &cfg) -{ - // vector of connected circle points - // for detection path from circle - std::vector> circles_sets = - create_circles_sets(path.circles, path.connected_circle); - if (circles_sets.size() == 1) - return sample_center_circle(circles_sets.front(), path.nodes, cfg); - - SupportIslandPoints result; - for (const auto &circle_set : circles_sets) { - SupportIslandPoints circle_result = sample_center_circle(circle_set, path.nodes, cfg); - result.insert(result.end(), circle_result.begin(), circle_result.end()); - } - return result; -} - SupportIslandPoints SampleIslandUtils::sample_expath( const VoronoiGraph::ExPath &path, const SampleConfig &config) { // 1) One support point if (path.length < config.max_length_for_one_support_point) { // create only one point in center - Point p = get_center_of_path(path.nodes, path.length); - SupportIslandPoint supportIslandPoint(p, SupportIslandPoint::Type::one_center_point); - return {supportIslandPoint}; + return { + create_middle_path_point(path, SupportIslandPoint::Type::one_center_point) + }; } double max_width = VoronoiGraphUtils::get_max_width(path); @@ -356,8 +526,7 @@ SupportIslandPoints SampleIslandUtils::sample_expath( // TODO: divide path to sampled parts SupportIslandPoints points; - points.push_back(VoronoiGraphUtils::get_offseted_point( - *path.nodes.front(), config.minimal_distance_from_outline)); + points.emplace_back(create_point_on_path(path.nodes, config.minimal_distance_from_outline)); return points; } diff --git a/src/libslic3r/SLA/SupportIslands/SampleIslandUtils.hpp b/src/libslic3r/SLA/SupportIslands/SampleIslandUtils.hpp index 4036d8b487..fc31f9295d 100644 --- a/src/libslic3r/SLA/SupportIslands/SampleIslandUtils.hpp +++ b/src/libslic3r/SLA/SupportIslands/SampleIslandUtils.hpp @@ -21,14 +21,28 @@ class SampleIslandUtils public: SampleIslandUtils() = delete; + /// + /// Create support point on edge defined by neighbor + /// + /// Source edge + /// Source distance ratio for position on edge + /// Type of point + /// created support island point + static SupportIslandPoint create_point( + const VoronoiGraph::Node::Neighbor *neighbor, + double ratio, + SupportIslandPoint::Type type = SupportIslandPoint::Type::undefined); + /// /// Find point lay on path with distance from first point on path /// /// Neighbor connected Nodes /// Distance to final point /// Points with distance to first node - static Point get_point_on_path(const VoronoiGraph::Nodes &path, - double distance); + static SupportIslandPoint create_point_on_path( + const VoronoiGraph::Nodes &path, + double distance, + SupportIslandPoint::Type type = SupportIslandPoint::Type::undefined); /// /// Find point lay in center of path @@ -38,11 +52,9 @@ public: /// Queue of neighbor nodes.(must be neighbor) /// length of path /// Point laying on voronoi diagram - static Point get_center_of_path(const VoronoiGraph::Nodes &path, - double path_length) - { - return get_point_on_path(path, path_length / 2); - } + static SupportIslandPoint create_middle_path_point( + const VoronoiGraph::Path &path, + SupportIslandPoint::Type type = SupportIslandPoint::Type::undefined); // create 2 points on both ends of path with side distance from border static SupportIslandPoints create_side_points(const VoronoiGraph::Nodes &path, double side_distance); @@ -78,11 +90,20 @@ public: // create points along path and its side branches(recursively) + colve circles static SupportIslandPoints sample_center_line(const VoronoiGraph::ExPath &path, const CenterLineConfiguration &cfg); // create point along multi circles in path - static SupportIslandPoints sample_center_circles(const VoronoiGraph::ExPath &path, const CenterLineConfiguration &cfg); + static void sample_center_circles(const VoronoiGraph::ExPath & path, + const CenterLineConfiguration &cfg, + SupportIslandPoints & result); static SupportIslandPoints sample_center_circle( - const std::set &circle_set, - const VoronoiGraph::Nodes & path_nodes, + const std::set & circle_set, + std::map &path_distances, const CenterLineConfiguration & cfg); + static void sample_center_circle_end( + const VoronoiGraph::Node::Neighbor &neighbor, + double & neighbor_distance, + const VoronoiGraph::Nodes & done_nodes, + double & node_distance, + const CenterLineConfiguration & cfg, + SupportIslandPoints & result); /// /// Decide how to sample path diff --git a/src/libslic3r/SLA/SupportIslands/SupportIslandPoint.hpp b/src/libslic3r/SLA/SupportIslands/SupportIslandPoint.hpp index af055fb412..aee5d9bf5b 100644 --- a/src/libslic3r/SLA/SupportIslands/SupportIslandPoint.hpp +++ b/src/libslic3r/SLA/SupportIslands/SupportIslandPoint.hpp @@ -2,6 +2,7 @@ #define slic3r_SLA_SuppotstIslands_SupportIslandPoint_hpp_ #include +#include "VoronoiGraph.hpp" namespace Slic3r::sla { @@ -21,11 +22,22 @@ struct SupportIslandPoint }; Slic3r::Point point; // 2 point in layer coordinate + + // Define position on voronoi graph + // Lose data when voronoi graph does NOT exist + VoronoiGraph::Position position; + Type type; - SupportIslandPoint(Slic3r::Point point, Type type = Type::undefined) - : point(std::move(point)), type(type) - {} + SupportIslandPoint(Slic3r::Point point, + Type type = Type::undefined, + VoronoiGraph::Position position = {}) + : point(std::move(point)), type(type), position(position) + { + if (position.neighbor == nullptr) { + int i = 5; + } + } }; using SupportIslandPoints = std::vector; diff --git a/src/libslic3r/SLA/SupportIslands/VoronoiGraph.hpp b/src/libslic3r/SLA/SupportIslands/VoronoiGraph.hpp index 4aa6470636..1bc66f915c 100644 --- a/src/libslic3r/SLA/SupportIslands/VoronoiGraph.hpp +++ b/src/libslic3r/SLA/SupportIslands/VoronoiGraph.hpp @@ -18,6 +18,7 @@ struct VoronoiGraph struct Path; struct ExPath; using Circle = Path; + struct Position; std::map data; }; @@ -48,6 +49,8 @@ struct VoronoiGraph::Node /// /// Surrond GraphNode data type. /// Extend information about voronoi edge. +/// TODO IMPROVE: extends neighbors for store more edges +/// (cumulate Nodes with 2 neighbors - No cross) /// struct VoronoiGraph::Node::Neighbor { @@ -154,5 +157,29 @@ public: ExPath() = default; }; +/// +/// DTO +/// Extend neighbor with ratio to edge +/// For point position on VoronoiGraph use VoronoiGraphUtils::get_edge_point +/// +struct VoronoiGraph::Position +{ + // neighbor is stored inside of voronoi diagram + const VoronoiGraph::Node::Neighbor* neighbor; + + // define position on neighbor edge + // Value should be in range from 0. to 1. (shrinked when used) + // Value 0 means position of edge->vertex0 + // Value 0.5 is on half edge way between edge->vertex0 and edge->vertex1 + // Value 1 means position of edge->vertex1 + double ratio; + + Position(const VoronoiGraph::Node::Neighbor *neighbor, double ratio) + : neighbor(neighbor), ratio(ratio) + {} + + Position(): neighbor(nullptr), ratio(0.) {} +}; + } // namespace Slic3r::sla #endif // slic3r_SLA_SuppotstIslands_VoronoiGraph_hpp_ diff --git a/src/libslic3r/SLA/SupportIslands/VoronoiGraphUtils.cpp b/src/libslic3r/SLA/SupportIslands/VoronoiGraphUtils.cpp index cde17364ac..61117e846a 100644 --- a/src/libslic3r/SLA/SupportIslands/VoronoiGraphUtils.cpp +++ b/src/libslic3r/SLA/SupportIslands/VoronoiGraphUtils.cpp @@ -201,25 +201,6 @@ VoronoiGraph VoronoiGraphUtils::getSkeleton(const VD &vd, const Lines &lines) return skeleton; } -Slic3r::Point VoronoiGraphUtils::get_offseted_point( - const VoronoiGraph::Node &node, double padding) -{ - assert(node.neighbors.size() == 1); - const VoronoiGraph::Node::Neighbor &neighbor = node.neighbors.front(); - const VD::edge_type & edge = *neighbor.edge; - const VD::vertex_type & v0 = *edge.vertex0(); - const VD::vertex_type & v1 = *edge.vertex1(); - Point dir(v0.x() - v1.x(), v0.y() - v1.y()); - if (node.vertex == &v0) - dir *= -1; - else - assert(node.vertex == &v1); - - double size = neighbor.edge_length / padding; - Point move(dir[0] / size, dir[1] / size); - return Point(node.vertex->x() + move[0], node.vertex->y() + move[1]); -} - const VoronoiGraph::Node::Neighbor *VoronoiGraphUtils::get_neighbor( const VoronoiGraph::Node *from, const VoronoiGraph::Node *to) { @@ -531,6 +512,16 @@ VoronoiGraph::ExPath VoronoiGraphUtils::create_longest_path( return longest_path; } +const VoronoiGraph::Node *VoronoiGraphUtils::get_twin_node(const VoronoiGraph::Node::Neighbor *neighbor) +{ + auto twin_edge = neighbor->edge->twin(); + for (const VoronoiGraph::Node::Neighbor n : neighbor->node->neighbors) { + if (n.edge == twin_edge) return n.node; + } + assert(false); + return nullptr; +} + Slic3r::Point VoronoiGraphUtils::get_edge_point(const VD::edge_type *edge, double ratio) { diff --git a/src/libslic3r/SLA/SupportIslands/VoronoiGraphUtils.hpp b/src/libslic3r/SLA/SupportIslands/VoronoiGraphUtils.hpp index dfc36ffffe..1263678bd0 100644 --- a/src/libslic3r/SLA/SupportIslands/VoronoiGraphUtils.hpp +++ b/src/libslic3r/SLA/SupportIslands/VoronoiGraphUtils.hpp @@ -185,6 +185,14 @@ public: static VoronoiGraph::ExPath create_longest_path( const VoronoiGraph::Node *start_node); + /// + /// Find source node of neighbor + /// + /// neighbor + /// start node + static const VoronoiGraph::Node *VoronoiGraphUtils::get_twin_node( + const VoronoiGraph::Node::Neighbor *neighbor); + /// /// Create point on edge defined by neighbor /// in distance defined by edge length ratio diff --git a/tests/sla_print/sla_supptgen_tests.cpp b/tests/sla_print/sla_supptgen_tests.cpp index bec6dcbb03..6f8be6ca17 100644 --- a/tests/sla_print/sla_supptgen_tests.cpp +++ b/tests/sla_print/sla_supptgen_tests.cpp @@ -162,7 +162,9 @@ Slic3r::Polygon square(double size) } Slic3r::Polygon rect(double x, double y){ - return {{.0, y}, {.0, .0}, {x, .0}, {x, y}}; + double x_2 = x / 2; + double y_2 = y / 2; + return {{-x_2, y_2}, {-x_2, -y_2}, {x_2, -y_2}, {x_2, y_2}}; } Slic3r::Polygon circle(double radius, size_t count_line_segments) { @@ -182,12 +184,14 @@ Slic3r::Polygon create_cross_roads(double size, double width) { auto r1 = rect( 5.3 * size, width); r1.rotate(3.14/4); + r1.translate(2 * size, width / 2); auto r2 = rect(6.1*size, 3/4.*width); r2.rotate(-3.14 / 5); + r2.translate(3 * size, width / 2); auto r3 = rect(7.9*size, 4/5.*width); - r3.translate(Point(-2*size, size)); + r3.translate(2*size, width/2); auto r4 = rect(5 / 6. * width, 5.7 * size); - r4.translate(Point(size,0.)); + r4.translate(-size,3*size); Polygons rr = union_(Polygons({r1, r2, r3, r4})); return rr.front(); } @@ -234,6 +238,22 @@ ExPolygon create_disc(double radius, double width, size_t count_line_segments) return ExPolygon(circle(radius + width_2, count_line_segments), hole); } +Slic3r::Polygon create_V_shape(double height, double line_width, double angle = M_PI/4) { + double angle_2 = angle / 2; + auto left_side = rect(line_width, height); + auto right_side = left_side; + right_side.rotate(-angle_2); + double small_move = cos(angle_2) * line_width / 2; + double side_move = sin(angle_2) * height / 2 + small_move; + right_side.translate(side_move,0); + left_side.rotate(angle_2); + left_side.translate(-side_move, 0); + auto bottom = rect(4 * small_move, line_width); + bottom.translate(0., -cos(angle_2) * height / 2 + line_width/2); + Polygons polygons = union_(Polygons({left_side, right_side, bottom})); + return polygons.front(); +} + ExPolygons createTestIslands(double size) { bool useFrogLeg = false; @@ -245,22 +265,6 @@ ExPolygons createTestIslands(double size) {3 * size / 7, 2 * size}, {2 * size / 7, size / 6}, {size / 7, size}}); - - size_t count_cirlce_lines = 16; // test stack overfrow - double r_CCW = size / 2; - double r_CW = r_CCW - size / 6; - // CCW: couter clock wise, CW: clock wise - Points circle_CCW, circle_CW; - circle_CCW.reserve(count_cirlce_lines); - circle_CW.reserve(count_cirlce_lines); - for (size_t i = 0; i < count_cirlce_lines; ++i) { - double alpha = (2 * M_PI * i) / count_cirlce_lines; - double sina = sin(alpha); - double cosa = cos(alpha); - circle_CCW.emplace_back(-r_CCW * sina, r_CCW * cosa); - circle_CW.emplace_back(r_CW * sina, r_CW * cosa); - } - ExPolygon double_circle(circle_CCW, circle_CW); ExPolygons result = { // one support point ExPolygon(equilateral_triangle(size)), @@ -270,13 +274,16 @@ ExPolygons createTestIslands(double size) ExPolygon(circle(size/2, 10)), create_square_with_4holes(size, size / 4), create_disc(size/4, size / 4, 10), + ExPolygon(create_V_shape(2*size/3, size / 4)), // two support points ExPolygon(isosceles_triangle(size / 2, 3 * size)), // small sharp triangle ExPolygon(rect(size / 2, 3 * size)), + ExPolygon(create_V_shape(1.5*size, size/3)), // tiny line support points ExPolygon(rect(size / 2, 10 * size)), // long line + ExPolygon(create_V_shape(size*4, size / 3)), ExPolygon(create_cross_roads(size, size / 3)), create_disc(3*size, size / 4, 30), create_square_with_4holes(5 * size, 5 * size / 2 - size / 3), @@ -437,6 +444,23 @@ TEST_CASE("Sampling speed test on FrogLegs", "[VoronoiSkeleton]") } } +/* +#include +#include +void cgal_test(const SupportIslandPoints &points, const ExPolygon &island) { + using Kernel = CGAL::Exact_predicates_inexact_constructions_kernel; + using Delaunay = CGAL::Delaunay_triangulation_2; + std::vector k_points; + k_points.reserve(points.size()); + std::transform(points.begin(), points.end(), std::back_inserter(k_points), + [](const SupportIslandPoint &p) { + return Kernel::Point_2(p.point.x(), p.point.y()); + }); + Delaunay dt; + dt.insert(k_points.begin(), k_points.end()); + std::cout << dt.number_of_vertices() << std::endl; +}*/ + TEST_CASE("Small islands should be supported in center", "[SupGen][VoronoiSkeleton]") { double size = 3e7; @@ -444,6 +468,7 @@ TEST_CASE("Small islands should be supported in center", "[SupGen][VoronoiSkelet ExPolygons islands = createTestIslands(size); for (auto &island : islands) { auto points = test_island_sampling(island, cfg); + //cgal_test(points, island); double angle = 3.14 / 3; // cca 60 degree island.rotate(angle);