mirror of
https://git.mirrors.martin98.com/https://github.com/prusa3d/PrusaSlicer.git
synced 2025-08-13 20:25:59 +08:00
Position of Support Point is connected with voronoi graph
This commit is contained in:
parent
dd61478fd6
commit
51dfdd8f38
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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>;
|
||||
|
@ -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_
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user