Position of Support Point is connected with voronoi graph

This commit is contained in:
Filip Sykala 2021-03-12 07:49:44 +01:00 committed by Lukas Matena
parent dd61478fd6
commit 51dfdd8f38
7 changed files with 423 additions and 170 deletions

View File

@ -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<size_t>(
@ -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<const VoronoiGraph::Node *>& 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<size_t>(
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<const VoronoiGraph::Node*, double>;
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<Item, std::vector<Item>, 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<const VoronoiGraph::Node *> &circle_set,
const std::set<const VoronoiGraph::Node *> &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<class T, class S, class C>
const S &get_container_ref(const std::priority_queue<T, S, C> &q)
{
struct HackedQueue : private std::priority_queue<T, S, C>
{
static const S &Container(const std::priority_queue<T, S, C> &q)
{
return q.*&HackedQueue::c;
}
};
return HackedQueue::Container(q);
}
std::set<const VoronoiGraph::Node *> create_path_set(
const VoronoiGraph::ExPath &path)
{
std::queue<const VoronoiGraph::Node *> side_branch_nodes;
std::set<const VoronoiGraph::Node *> 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<VoronoiGraph::Path> &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<std::set<const VoronoiGraph::Node *>> circles_sets =
create_circles_sets(path.circles, path.connected_circle);
std::set<const VoronoiGraph::Node *> 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<const VoronoiGraph::Node *> &circle_set,
std::map<const VoronoiGraph::Node *, double>& path_distances,
const CenterLineConfiguration & cfg)
{
SupportIslandPoints result;
// depth search
std::stack<NodeDistance> 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<const VoronoiGraph::Node *, double> 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<const VoronoiGraph::Node *, double> done_distance;
std::map<const VoronoiGraph::Node *, double> 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<size_t>(
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<std::set<const VoronoiGraph::Node *>> 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;
}

View File

@ -21,14 +21,28 @@ class SampleIslandUtils
public:
SampleIslandUtils() = delete;
/// <summary>
/// Create support point on edge defined by neighbor
/// </summary>
/// <param name="neighbor">Source edge</param>
/// <param name="ratio">Source distance ratio for position on edge</param>
/// <param name="type">Type of point</param>
/// <returns>created support island point</returns>
static SupportIslandPoint create_point(
const VoronoiGraph::Node::Neighbor *neighbor,
double ratio,
SupportIslandPoint::Type type = SupportIslandPoint::Type::undefined);
/// <summary>
/// Find point lay on path with distance from first point on path
/// </summary>
/// <param name="path">Neighbor connected Nodes</param>
/// <param name="distance">Distance to final point</param>
/// <returns>Points with distance to first node</returns>
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);
/// <summary>
/// Find point lay in center of path
@ -38,11 +52,9 @@ public:
/// <param name="path">Queue of neighbor nodes.(must be neighbor)</param>
/// <param name="path_length">length of path</param>
/// <returns>Point laying on voronoi diagram</returns>
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<const VoronoiGraph::Node *> &circle_set,
const VoronoiGraph::Nodes & path_nodes,
const std::set<const VoronoiGraph::Node *> & circle_set,
std::map<const VoronoiGraph::Node *, double> &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);
/// <summary>
/// Decide how to sample path

View File

@ -2,6 +2,7 @@
#define slic3r_SLA_SuppotstIslands_SupportIslandPoint_hpp_
#include <libslic3r/Point.hpp>
#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<SupportIslandPoint>;

View File

@ -18,6 +18,7 @@ struct VoronoiGraph
struct Path;
struct ExPath;
using Circle = Path;
struct Position;
std::map<const VD::vertex_type *, Node> data;
};
@ -48,6 +49,8 @@ struct VoronoiGraph::Node
/// <summary>
/// Surrond GraphNode data type.
/// Extend information about voronoi edge.
/// TODO IMPROVE: extends neighbors for store more edges
/// (cumulate Nodes with 2 neighbors - No cross)
/// </summary>
struct VoronoiGraph::Node::Neighbor
{
@ -154,5 +157,29 @@ public:
ExPath() = default;
};
/// <summary>
/// DTO
/// Extend neighbor with ratio to edge
/// For point position on VoronoiGraph use VoronoiGraphUtils::get_edge_point
/// </summary>
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_

View File

@ -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)
{

View File

@ -185,6 +185,14 @@ public:
static VoronoiGraph::ExPath create_longest_path(
const VoronoiGraph::Node *start_node);
/// <summary>
/// Find source node of neighbor
/// </summary>
/// <param name="neighbor">neighbor</param>
/// <returns>start node</returns>
static const VoronoiGraph::Node *VoronoiGraphUtils::get_twin_node(
const VoronoiGraph::Node::Neighbor *neighbor);
/// <summary>
/// Create point on edge defined by neighbor
/// in distance defined by edge length ratio

View File

@ -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 <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include <CGAL/Delaunay_triangulation_2.h>
void cgal_test(const SupportIslandPoints &points, const ExPolygon &island) {
using Kernel = CGAL::Exact_predicates_inexact_constructions_kernel;
using Delaunay = CGAL::Delaunay_triangulation_2<Kernel>;
std::vector<Kernel::Point_2> 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);