mirror of
https://git.mirrors.martin98.com/https://github.com/prusa3d/PrusaSlicer.git
synced 2025-08-16 12:45:54 +08:00
Add filter for end center line support instead of minimal distance.
This commit is contained in:
parent
0c9dedcffa
commit
12b320624b
@ -279,6 +279,30 @@ std::optional<Slic3r::Vec2d> LineUtils::intersection(const Line &ray1, const Lin
|
|||||||
return (ray1.a.cast<double>() + t * v1);
|
return (ray1.a.cast<double>() + t * v1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool LineUtils::belongs(const Line &line, const Point &point, double benevolence)
|
||||||
|
{
|
||||||
|
const Point &a = line.a;
|
||||||
|
const Point &b = line.b;
|
||||||
|
auto is_in_interval = [](coord_t value, coord_t from, coord_t to) -> bool
|
||||||
|
{
|
||||||
|
if (from > to) {
|
||||||
|
if (from > value || to < value) return false;
|
||||||
|
} else {
|
||||||
|
if (from < value || to > value) return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!is_in_interval(point.x(), a.x(), b.x()) ||
|
||||||
|
!is_in_interval(point.y(), a.y(), b.y()) )
|
||||||
|
{ // out of interval
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
double distance = line.perp_distance_to(point);
|
||||||
|
if (distance < benevolence) return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
double LineUtils::foot(const Line &line, const Point &point)
|
double LineUtils::foot(const Line &line, const Point &point)
|
||||||
{
|
{
|
||||||
Vec2d a = line.a.cast<double>();
|
Vec2d a = line.a.cast<double>();
|
||||||
|
@ -111,6 +111,17 @@ public:
|
|||||||
/// <returns>intersection point when exist</returns>
|
/// <returns>intersection point when exist</returns>
|
||||||
static std::optional<Vec2d> intersection(const Line &ray1, const Line &ray2);
|
static std::optional<Vec2d> intersection(const Line &ray1, const Line &ray2);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Check when point lays on line and belongs line range(from point a to point b)
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="line">source line</param>
|
||||||
|
/// <param name="point">point to check</param>
|
||||||
|
/// <param name="point">maximal distance from line to belongs line</param>
|
||||||
|
/// <returns>True when points lay between line.a and line.b</returns>
|
||||||
|
static bool belongs(const Line & line,
|
||||||
|
const Point &point,
|
||||||
|
double benevolence = 1.);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Create direction from point a to point b
|
/// Create direction from point a to point b
|
||||||
/// Direction vector is represented as point
|
/// Direction vector is represented as point
|
||||||
|
@ -24,6 +24,11 @@ struct SampleConfig
|
|||||||
// zero when head should be on outline
|
// zero when head should be on outline
|
||||||
coord_t minimal_distance_from_outline = 0; // [nano meter]
|
coord_t minimal_distance_from_outline = 0; // [nano meter]
|
||||||
|
|
||||||
|
// Measured as sum of VD edge length from outline
|
||||||
|
// Used only when there is no space for outline offset on first/last point
|
||||||
|
// Must be bigger than minimal_distance_from_outline
|
||||||
|
coord_t maximal_distance_from_outline = 1.;// [nano meter]
|
||||||
|
|
||||||
// Distinguish when to add support point on VD outline point(center line sample)
|
// Distinguish when to add support point on VD outline point(center line sample)
|
||||||
// MUST be bigger than minimal_distance_from_outline
|
// MUST be bigger than minimal_distance_from_outline
|
||||||
coord_t minimal_support_distance = 0;
|
coord_t minimal_support_distance = 0;
|
||||||
@ -47,6 +52,7 @@ struct SampleConfig
|
|||||||
// Must be smaller or equal to max_width_for_center_support_line
|
// Must be smaller or equal to max_width_for_center_support_line
|
||||||
coord_t min_width_for_outline_support = 1.;
|
coord_t min_width_for_outline_support = 1.;
|
||||||
|
|
||||||
|
|
||||||
// Term criteria for end of alignment
|
// Term criteria for end of alignment
|
||||||
// Minimal change in manhatn move of support position before termination
|
// Minimal change in manhatn move of support position before termination
|
||||||
coord_t minimal_move = 1000; // in nanometers, devide from print resolution to quater pixel
|
coord_t minimal_move = 1000; // in nanometers, devide from print resolution to quater pixel
|
||||||
|
@ -27,7 +27,9 @@ public:
|
|||||||
result.max_distance = max_distance / sample_multiplicator;
|
result.max_distance = max_distance / sample_multiplicator;
|
||||||
result.half_distance = result.max_distance / 2;
|
result.half_distance = result.max_distance / 2;
|
||||||
result.head_radius = head_diameter / 2;
|
result.head_radius = head_diameter / 2;
|
||||||
result.minimal_distance_from_outline = head_diameter / 2.;
|
result.minimal_distance_from_outline = result.head_radius;
|
||||||
|
result.maximal_distance_from_outline = result.half_distance;
|
||||||
|
assert(result.minimal_distance_from_outline < result.maximal_distance_from_outline);
|
||||||
result.minimal_support_distance = result.minimal_distance_from_outline +
|
result.minimal_support_distance = result.minimal_distance_from_outline +
|
||||||
result.half_distance;
|
result.half_distance;
|
||||||
|
|
||||||
@ -76,7 +78,7 @@ public:
|
|||||||
|
|
||||||
// Align support points
|
// Align support points
|
||||||
// TODO: propagate print resolution
|
// TODO: propagate print resolution
|
||||||
result.minimal_move = 1000; // [in nanometers], devide from print resolution to quater pixel
|
result.minimal_move = 10000.;// [in nanometers --> 0.01mm ], devide from print resolution to quater pixel
|
||||||
result.count_iteration = 100; // speed VS precission
|
result.count_iteration = 100; // speed VS precission
|
||||||
result.max_align_distance = result.max_distance / 2;
|
result.max_align_distance = result.max_distance / 2;
|
||||||
|
|
||||||
|
@ -20,9 +20,10 @@
|
|||||||
// comment definition of NDEBUG to enable assert()
|
// comment definition of NDEBUG to enable assert()
|
||||||
//#define NDEBUG
|
//#define NDEBUG
|
||||||
|
|
||||||
//#define SLA_SAMPLING_STORE_VORONOI_GRAPH_TO_SVG
|
#define SLA_SAMPLE_ISLAND_UTILS_STORE_VORONOI_GRAPH_TO_SVG
|
||||||
//#define SLA_SAMPLING_STORE_FIELD_TO_SVG
|
#define SLA_SAMPLE_ISLAND_UTILS_STORE_INITIAL_SAMPLE_POSITION_TO_SVG
|
||||||
//#define SLA_SAMPLING_STORE_POISSON_SAMPLING_TO_SVG
|
#define SLA_SAMPLE_ISLAND_UTILS_STORE_FIELD_TO_SVG
|
||||||
|
//#define SLA_SAMPLE_ISLAND_UTILS_STORE_ALIGN_ONCE_TO_SVG
|
||||||
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
|
||||||
@ -131,14 +132,21 @@ Slic3r::Points SampleIslandUtils::sample_expolygon(const ExPolygon &expoly,
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<SupportIslandPoint> SampleIslandUtils::create_point(
|
SupportIslandPointPtr SampleIslandUtils::create_no_move_point(
|
||||||
const VoronoiGraph::Node::Neighbor *neighbor,
|
const VoronoiGraph::Node::Neighbor *neighbor,
|
||||||
double ratio,
|
double ratio,
|
||||||
SupportIslandPoint::Type type)
|
SupportIslandPoint::Type type)
|
||||||
{
|
{
|
||||||
VoronoiGraph::Position position(neighbor, ratio);
|
VoronoiGraph::Position position(neighbor, ratio);
|
||||||
Slic3r::Point p = VoronoiGraphUtils::create_edge_point(position);
|
return create_no_move_point(position, type);
|
||||||
return std::make_unique<SupportIslandPoint>(p, type);
|
}
|
||||||
|
|
||||||
|
SupportIslandPointPtr SampleIslandUtils::create_no_move_point(
|
||||||
|
const VoronoiGraph::Position &position,
|
||||||
|
SupportIslandPoint::Type type)
|
||||||
|
{
|
||||||
|
Point point = VoronoiGraphUtils::create_edge_point(position);
|
||||||
|
return std::make_unique<SupportIslandNoMovePoint>(point, type);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<VoronoiGraph::Position> SampleIslandUtils::create_position_on_path(
|
std::optional<VoronoiGraph::Position> SampleIslandUtils::create_position_on_path(
|
||||||
@ -157,9 +165,8 @@ std::unique_ptr<SupportIslandPoint> SampleIslandUtils::create_point(
|
|||||||
actual_distance += neighbor->length();
|
actual_distance += neighbor->length();
|
||||||
if (actual_distance >= distance) {
|
if (actual_distance >= distance) {
|
||||||
// over half point is on
|
// over half point is on
|
||||||
double previous_distance = actual_distance - distance;
|
double behind_position = actual_distance - distance;
|
||||||
double over_ratio = previous_distance / neighbor->length();
|
double ratio = 1. - behind_position / neighbor->length();
|
||||||
double ratio = 1. - over_ratio;
|
|
||||||
return VoronoiGraph::Position(neighbor, ratio);
|
return VoronoiGraph::Position(neighbor, ratio);
|
||||||
}
|
}
|
||||||
prev_node = node;
|
prev_node = node;
|
||||||
@ -171,7 +178,50 @@ std::unique_ptr<SupportIslandPoint> SampleIslandUtils::create_point(
|
|||||||
return {}; // unreachable
|
return {}; // unreachable
|
||||||
}
|
}
|
||||||
|
|
||||||
SupportIslandPointPtr SampleIslandUtils::create_point_on_path(
|
std::optional<VoronoiGraph::Position>
|
||||||
|
SampleIslandUtils::create_position_on_path(const VoronoiGraph::Nodes &path,
|
||||||
|
const Lines & lines,
|
||||||
|
coord_t width,
|
||||||
|
coord_t &max_distance)
|
||||||
|
{
|
||||||
|
const VoronoiGraph::Node *prev_node = nullptr;
|
||||||
|
coord_t actual_distance = 0;
|
||||||
|
for (const VoronoiGraph::Node *node : path) {
|
||||||
|
if (prev_node == nullptr) { // first call
|
||||||
|
prev_node = node;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const VoronoiGraph::Node::Neighbor *neighbor =
|
||||||
|
VoronoiGraphUtils::get_neighbor(prev_node, node);
|
||||||
|
|
||||||
|
if (width <= neighbor->max_width()) {
|
||||||
|
VoronoiGraph::Position position = VoronoiGraphUtils::get_position_with_width(neighbor, width, lines);
|
||||||
|
// set max distance to actual distance
|
||||||
|
coord_t rest_distance = position.calc_distance();
|
||||||
|
coord_t distance = actual_distance + rest_distance;
|
||||||
|
if (max_distance > distance) {
|
||||||
|
max_distance = distance;
|
||||||
|
return position;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
actual_distance += static_cast<coord_t>(neighbor->length());
|
||||||
|
if (actual_distance >= max_distance) {
|
||||||
|
// over half point is on
|
||||||
|
coord_t behind_position = actual_distance - max_distance;
|
||||||
|
double ratio = 1. - behind_position / neighbor->length();
|
||||||
|
return VoronoiGraph::Position(neighbor, ratio);
|
||||||
|
}
|
||||||
|
prev_node = node;
|
||||||
|
}
|
||||||
|
|
||||||
|
// distance must be inside path
|
||||||
|
// this means bad input params
|
||||||
|
assert(false);
|
||||||
|
return {}; // unreachable
|
||||||
|
}
|
||||||
|
|
||||||
|
SupportIslandPointPtr SampleIslandUtils::create_center_island_point(
|
||||||
const VoronoiGraph::Nodes &path,
|
const VoronoiGraph::Nodes &path,
|
||||||
double distance,
|
double distance,
|
||||||
const SampleConfig & config,
|
const SampleConfig & config,
|
||||||
@ -187,24 +237,27 @@ SupportIslandPointPtr SampleIslandUtils::create_middle_path_point(
|
|||||||
{
|
{
|
||||||
auto position_opt = create_position_on_path(path.nodes, path.length / 2);
|
auto position_opt = create_position_on_path(path.nodes, path.length / 2);
|
||||||
if (!position_opt.has_value()) return nullptr;
|
if (!position_opt.has_value()) return nullptr;
|
||||||
|
return create_no_move_point(*position_opt, type);
|
||||||
return create_point(position_opt->neighbor, position_opt->ratio, type);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SupportIslandPoints SampleIslandUtils::create_side_points(
|
SupportIslandPoints SampleIslandUtils::create_side_points(
|
||||||
const VoronoiGraph::Nodes &path, double side_distance)
|
const VoronoiGraph::Nodes &path,
|
||||||
|
const Lines& lines,
|
||||||
|
coord_t width,
|
||||||
|
coord_t max_side_distance)
|
||||||
{
|
{
|
||||||
VoronoiGraph::Nodes reverse_path = path; // copy
|
VoronoiGraph::Nodes reverse_path = path; // copy
|
||||||
std::reverse(reverse_path.begin(), reverse_path.end());
|
std::reverse(reverse_path.begin(), reverse_path.end());
|
||||||
auto pos1 = create_position_on_path(path, side_distance);
|
coord_t distance2 = max_side_distance; // copy
|
||||||
auto pos2 = create_position_on_path(reverse_path, side_distance);
|
auto pos1 = create_position_on_path(path, lines, width, max_side_distance);
|
||||||
|
auto pos2 = create_position_on_path(reverse_path, lines, width, distance2);
|
||||||
assert(pos1.has_value());
|
assert(pos1.has_value());
|
||||||
assert(pos2.has_value());
|
assert(pos2.has_value());
|
||||||
SupportIslandPoint::Type type = SupportIslandPoint::Type::two_points;
|
SupportIslandPoint::Type type = SupportIslandPoint::Type::two_points;
|
||||||
SupportIslandPoints result;
|
SupportIslandPoints result;
|
||||||
result.reserve(2);
|
result.reserve(2);
|
||||||
result.push_back(create_point(pos1->neighbor, pos1->ratio, type));
|
result.push_back(create_no_move_point(*pos1, type));
|
||||||
result.push_back(create_point(pos2->neighbor, pos2->ratio, type));
|
result.push_back(create_no_move_point(*pos2, type));
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -225,7 +278,7 @@ SupportIslandPoints SampleIslandUtils::sample_side_branch(
|
|||||||
reverse_path.push_back(first_node);
|
reverse_path.push_back(first_node);
|
||||||
SupportIslandPoints result;
|
SupportIslandPoints result;
|
||||||
result.push_back(
|
result.push_back(
|
||||||
create_point_on_path(reverse_path, side_distance, cfg.sample_config,
|
create_center_island_point(reverse_path, side_distance, cfg.sample_config,
|
||||||
SupportIslandPoint::Type::center_line_end));
|
SupportIslandPoint::Type::center_line_end));
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -255,7 +308,8 @@ SupportIslandPoints SampleIslandUtils::sample_side_branch(
|
|||||||
while (distance < neighbor->length()) {
|
while (distance < neighbor->length()) {
|
||||||
double edge_ratio = distance / neighbor->length();
|
double edge_ratio = distance / neighbor->length();
|
||||||
result.push_back(
|
result.push_back(
|
||||||
create_point(neighbor, edge_ratio, SupportIslandPoint::Type::center_line)
|
create_no_move_point(neighbor, edge_ratio,
|
||||||
|
SupportIslandPoint::Type::center_line)
|
||||||
);
|
);
|
||||||
distance += sample_distance;
|
distance += sample_distance;
|
||||||
}
|
}
|
||||||
@ -371,8 +425,6 @@ bool is_points_in_distance(const Slic3r::Point & p,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
//#define VISUALIZE_SAMPLE_ISLAND_UTILS_ALIGN_ONCE
|
|
||||||
|
|
||||||
coord_t SampleIslandUtils::align_once(SupportIslandPoints &samples,
|
coord_t SampleIslandUtils::align_once(SupportIslandPoints &samples,
|
||||||
const ExPolygon & island,
|
const ExPolygon & island,
|
||||||
const SampleConfig & config)
|
const SampleConfig & config)
|
||||||
@ -381,22 +433,37 @@ coord_t SampleIslandUtils::align_once(SupportIslandPoints &samples,
|
|||||||
using VD = Slic3r::Geometry::VoronoiDiagram;
|
using VD = Slic3r::Geometry::VoronoiDiagram;
|
||||||
VD vd;
|
VD vd;
|
||||||
Slic3r::Points points = SampleIslandUtils::to_points(samples);
|
Slic3r::Points points = SampleIslandUtils::to_points(samples);
|
||||||
|
coord_t max_move = 0;
|
||||||
|
|
||||||
#ifdef VISUALIZE_SAMPLE_ISLAND_UTILS_ALIGN_ONCE
|
#ifdef SLA_SAMPLE_ISLAND_UTILS_STORE_ALIGN_ONCE_TO_SVG
|
||||||
|
std::string color_of_island = "#FF8080"; // LightRed. Should not be visible - cell color should overlap
|
||||||
|
std::string color_point_cell = "lightgray"; // bigger than island but NOT self overlap
|
||||||
|
std::string color_island_cell_intersection = "gray"; // Should full overlap island !!
|
||||||
|
std::string color_old_point = "lightblue"; // Center of island cell intersection
|
||||||
|
std::string color_wanted_point = "darkblue"; // Center of island cell intersection
|
||||||
|
std::string color_new_point = "blue"; // Center of island cell intersection
|
||||||
|
std::string color_static_point = "black";
|
||||||
static int counter = 0;
|
static int counter = 0;
|
||||||
BoundingBox bbox(island);
|
BoundingBox bbox(island);
|
||||||
SVG svg(("align_"+std::to_string(counter++)+".svg").c_str(), bbox);
|
|
||||||
svg.draw(island, "lightblue");
|
SVG svg(("align_" + std::to_string(counter++) + ".svg").c_str(), bbox);
|
||||||
#endif // VISUALIZE_SAMPLE_ISLAND_UTILS_ALIGN_ONCE
|
svg.draw(island, color_of_island );
|
||||||
|
#endif // SLA_SAMPLE_ISLAND_UTILS_STORE_ALIGN_ONCE_TO_SVG
|
||||||
|
|
||||||
// create voronoi diagram with points
|
// create voronoi diagram with points
|
||||||
construct_voronoi(points.begin(), points.end(), &vd);
|
construct_voronoi(points.begin(), points.end(), &vd);
|
||||||
coord_t max_move = 0;
|
|
||||||
for (const VD::cell_type &cell : vd.cells()) {
|
for (const VD::cell_type &cell : vd.cells()) {
|
||||||
SupportIslandPointPtr &sample = samples[cell.source_index()];
|
SupportIslandPointPtr &sample = samples[cell.source_index()];
|
||||||
|
|
||||||
|
#ifdef SLA_SAMPLE_ISLAND_UTILS_STORE_ALIGN_ONCE_TO_SVG
|
||||||
|
if (!sample->can_move()) {
|
||||||
|
svg.draw(sample->point, color_static_point, config.head_radius);
|
||||||
|
svg.draw_text(sample->point+Point(config.head_radius,0), SupportIslandPoint::to_string(sample->type).c_str(), color_static_point.c_str());
|
||||||
|
}
|
||||||
|
#endif // SLA_SAMPLE_ISLAND_UTILS_STORE_ALIGN_ONCE_TO_SVG
|
||||||
if (!sample->can_move()) continue;
|
if (!sample->can_move()) continue;
|
||||||
Polygon polygon = VoronoiGraphUtils::to_polygon(cell, points, config.max_distance);
|
Polygon cell_polygon = VoronoiGraphUtils::to_polygon(cell, points, config.max_distance);
|
||||||
Polygons intersections = Slic3r::intersection(island, ExPolygon(polygon));
|
Polygons intersections = Slic3r::intersection(island, ExPolygon(cell_polygon));
|
||||||
const Polygon *island_cell = nullptr;
|
const Polygon *island_cell = nullptr;
|
||||||
for (const Polygon &intersection : intersections) {
|
for (const Polygon &intersection : intersections) {
|
||||||
if (intersection.contains(sample->point)) {
|
if (intersection.contains(sample->point)) {
|
||||||
@ -406,16 +473,32 @@ coord_t SampleIslandUtils::align_once(SupportIslandPoints &samples,
|
|||||||
}
|
}
|
||||||
assert(island_cell != nullptr);
|
assert(island_cell != nullptr);
|
||||||
Point center = island_cell->centroid();
|
Point center = island_cell->centroid();
|
||||||
|
{
|
||||||
|
SVG cell_svg("island_cell.svg", island_cell->points);
|
||||||
|
cell_svg.draw(cell_polygon, "lightgray");
|
||||||
|
cell_svg.draw(points, "darkgray", config.head_radius);
|
||||||
|
cell_svg.draw(*island_cell, "gray");
|
||||||
|
cell_svg.draw(sample->point, "green", config.head_radius);
|
||||||
|
cell_svg.draw(center, "black", config.head_radius);
|
||||||
|
}
|
||||||
assert(is_points_in_distance(center, island_cell->points, config.max_distance));
|
assert(is_points_in_distance(center, island_cell->points, config.max_distance));
|
||||||
#ifdef VISUALIZE_SAMPLE_ISLAND_UTILS_ALIGN_ONCE
|
#ifdef SLA_SAMPLE_ISLAND_UTILS_STORE_ALIGN_ONCE_TO_SVG
|
||||||
svg.draw(polygon, "lightgray");
|
svg.draw(cell_polygon, color_point_cell);
|
||||||
svg.draw(*island_cell, "gray");
|
svg.draw(*island_cell, color_island_cell_intersection);
|
||||||
svg.draw(sample.point, "black", config.head_radius);
|
svg.draw(Line(sample->point, center), color_wanted_point, config.head_radius / 5);
|
||||||
svg.draw(Line(sample.point, center), "blue", config.head_radius / 5);
|
svg.draw(sample->point, color_old_point, config.head_radius);
|
||||||
#endif // VISUALIZE_SAMPLE_ISLAND_UTILS_ALIGN_ONCE
|
svg.draw(center, color_wanted_point, config.head_radius); // wanted position
|
||||||
|
#endif // SLA_SAMPLE_ISLAND_UTILS_STORE_ALIGN_ONCE_TO_SVG
|
||||||
coord_t act_move = sample->move(center);
|
coord_t act_move = sample->move(center);
|
||||||
if (max_move < act_move) max_move = act_move;
|
if (max_move < act_move) max_move = act_move;
|
||||||
|
#ifdef SLA_SAMPLE_ISLAND_UTILS_STORE_ALIGN_ONCE_TO_SVG
|
||||||
|
svg.draw(sample->point, color_new_point, config.head_radius);
|
||||||
|
svg.draw_text(sample->point+Point(config.head_radius,0), SupportIslandPoint::to_string(sample->type).c_str(), color_new_point.c_str());
|
||||||
|
#endif // SLA_SAMPLE_ISLAND_UTILS_STORE_ALIGN_ONCE_TO_SVG
|
||||||
}
|
}
|
||||||
|
#ifdef SLA_SAMPLE_ISLAND_UTILS_STORE_ALIGN_ONCE_TO_SVG
|
||||||
|
svg.Close();
|
||||||
|
#endif // SLA_SAMPLE_ISLAND_UTILS_STORE_ALIGN_ONCE_TO_SVG
|
||||||
return max_move;
|
return max_move;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -459,8 +542,8 @@ void SampleIslandUtils::sample_center_circle_end(
|
|||||||
double distance_between = distance / (count_supports + 1);
|
double distance_between = distance / (count_supports + 1);
|
||||||
if (distance_between < neighbor_distance) {
|
if (distance_between < neighbor_distance) {
|
||||||
// point is calculated to be in done path, SP will be on edge point
|
// point is calculated to be in done path, SP will be on edge point
|
||||||
result.push_back(
|
result.push_back(create_no_move_point(
|
||||||
create_point(&neighbor, 1., SupportIslandPoint::Type::center_circle_end));
|
&neighbor, 1., SupportIslandPoint::Type::center_circle_end));
|
||||||
neighbor_distance = 0.;
|
neighbor_distance = 0.;
|
||||||
count_supports -= 1;
|
count_supports -= 1;
|
||||||
if (count_supports == 0) {
|
if (count_supports == 0) {
|
||||||
@ -478,8 +561,7 @@ void SampleIslandUtils::sample_center_circle_end(
|
|||||||
auto position = create_position_on_path(nodes, distance_from_neighbor);
|
auto position = create_position_on_path(nodes, distance_from_neighbor);
|
||||||
assert(position.has_value());
|
assert(position.has_value());
|
||||||
result.push_back(
|
result.push_back(
|
||||||
create_point(position->neighbor, position->ratio,
|
create_no_move_point(*position, SupportIslandPoint::Type::center_circle_end2));
|
||||||
SupportIslandPoint::Type::center_circle_end2));
|
|
||||||
double distance_support_to_node = fabs(neighbor.length() -
|
double distance_support_to_node = fabs(neighbor.length() -
|
||||||
distance_from_neighbor);
|
distance_from_neighbor);
|
||||||
if (node_distance > distance_support_to_node)
|
if (node_distance > distance_support_to_node)
|
||||||
@ -581,7 +663,7 @@ SupportDistanceMap create_support_distance_map(const SupportIslandPoints &suppor
|
|||||||
auto ptr = dynamic_cast<SupportCenterIslandPoint*>(support_point.get()); // bad use
|
auto ptr = dynamic_cast<SupportCenterIslandPoint*>(support_point.get()); // bad use
|
||||||
const VoronoiGraph::Position &position = ptr->position;
|
const VoronoiGraph::Position &position = ptr->position;
|
||||||
const VoronoiGraph::Node *node = position.neighbor->node;
|
const VoronoiGraph::Node *node = position.neighbor->node;
|
||||||
const VoronoiGraph::Node *twin_node = VoronoiGraphUtils::get_twin_node(position.neighbor);
|
const VoronoiGraph::Node *twin_node = VoronoiGraphUtils::get_twin_node(*position.neighbor);
|
||||||
double distance = (1 - position.ratio) * position.neighbor->length();
|
double distance = (1 - position.ratio) * position.neighbor->length();
|
||||||
double twin_distance = position.ratio * position.neighbor->length();
|
double twin_distance = position.ratio * position.neighbor->length();
|
||||||
|
|
||||||
@ -759,15 +841,27 @@ SupportIslandPoints SampleIslandUtils::sample_voronoi_graph(
|
|||||||
longest_path = VoronoiGraphUtils::create_longest_path(start_node);
|
longest_path = VoronoiGraphUtils::create_longest_path(start_node);
|
||||||
// longest_path = create_longest_path_recursive(start_node);
|
// longest_path = create_longest_path_recursive(start_node);
|
||||||
|
|
||||||
#ifdef SLA_SAMPLING_STORE_VORONOI_GRAPH_TO_SVG
|
#ifdef SLA_SAMPLE_ISLAND_UTILS_STORE_VORONOI_GRAPH_TO_SVG
|
||||||
{
|
{
|
||||||
static int counter = 0;
|
static int counter = 0;
|
||||||
SVG svg("voronoiGraph" + std::to_string(counter++) + ".svg",
|
SVG svg("voronoiGraph" + std::to_string(counter++) + ".svg",
|
||||||
LineUtils::create_bounding_box(lines));
|
LineUtils::create_bounding_box(lines));
|
||||||
VoronoiGraphUtils::draw(svg, graph, lines, 1e6, true);
|
VoronoiGraphUtils::draw(svg, graph, lines, 1e6, true);
|
||||||
}
|
}
|
||||||
#endif // SLA_SAMPLING_STORE_VORONOI_GRAPH_TO_SVG
|
#endif // SLA_SAMPLE_ISLAND_UTILS_STORE_VORONOI_GRAPH_TO_SVG
|
||||||
return sample_expath(longest_path, lines, config);
|
|
||||||
|
SupportIslandPoints points = sample_expath(longest_path, lines, config);
|
||||||
|
|
||||||
|
#ifdef SLA_SAMPLE_ISLAND_UTILS_STORE_INITIAL_SAMPLE_POSITION_TO_SVG
|
||||||
|
{
|
||||||
|
static int counter = 0;
|
||||||
|
SVG svg("initial_sample_positions" + std::to_string(counter++) + ".svg",
|
||||||
|
LineUtils::create_bounding_box(lines));
|
||||||
|
svg.draw(lines, "gray", config.head_radius/ 10);
|
||||||
|
draw(svg, points, config.head_radius, "black", true);
|
||||||
|
}
|
||||||
|
#endif // SLA_SAMPLE_ISLAND_UTILS_STORE_INITIAL_SAMPLE_POSITION_TO_SVG
|
||||||
|
return points;
|
||||||
}
|
}
|
||||||
|
|
||||||
SupportIslandPoints SampleIslandUtils::sample_expath(
|
SupportIslandPoints SampleIslandUtils::sample_expath(
|
||||||
@ -787,16 +881,20 @@ SupportIslandPoints SampleIslandUtils::sample_expath(
|
|||||||
double max_width = VoronoiGraphUtils::get_max_width(path);
|
double max_width = VoronoiGraphUtils::get_max_width(path);
|
||||||
if (max_width < config.max_width_for_center_support_line) {
|
if (max_width < config.max_width_for_center_support_line) {
|
||||||
// 2) Two support points
|
// 2) Two support points
|
||||||
if (path.length < config.max_length_for_two_support_points)
|
if (path.length < config.max_length_for_two_support_points) {
|
||||||
return create_side_points(path.nodes,
|
coord_t max_distance =
|
||||||
config.minimal_distance_from_outline);
|
std::min(config.half_distance, static_cast<coord_t>(path.length / 2));
|
||||||
|
return create_side_points(path.nodes, lines,
|
||||||
|
2 * config.minimal_distance_from_outline,
|
||||||
|
max_distance);
|
||||||
|
}
|
||||||
|
|
||||||
// othewise sample path
|
// othewise sample path
|
||||||
CenterLineConfiguration
|
/*CenterLineConfiguration
|
||||||
centerLineConfiguration(path.side_branches, config);
|
centerLineConfiguration(path.side_branches, config);
|
||||||
SupportIslandPoints samples = sample_center_line(path, centerLineConfiguration);
|
SupportIslandPoints samples = sample_center_line(path, centerLineConfiguration);
|
||||||
samples.front()->type = SupportIslandPoint::Type::center_line_end2;
|
samples.front()->type = SupportIslandPoint::Type::center_line_end2;
|
||||||
return samples;
|
return samples;*/
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: 3) Triangle of points
|
// TODO: 3) Triangle of points
|
||||||
@ -812,26 +910,42 @@ SupportIslandPoints SampleIslandUtils::sample_expath(
|
|||||||
SupportIslandPoints points; // result
|
SupportIslandPoints points; // result
|
||||||
if (neighbor->max_width() < config.max_width_for_center_support_line) {
|
if (neighbor->max_width() < config.max_width_for_center_support_line) {
|
||||||
// start sample center
|
// start sample center
|
||||||
done.insert(start_node);
|
coord_t width = 2 * config.minimal_distance_from_outline;
|
||||||
coord_t support_in = config.minimal_distance_from_outline;
|
coord_t distance = config.maximal_distance_from_outline;
|
||||||
center_starts.push(CenterStart(neighbor, support_in));
|
auto position = create_position_on_path(path.nodes, lines, width, distance);
|
||||||
|
if (position.has_value()) {
|
||||||
|
points.push_back(create_no_move_point(
|
||||||
|
*position, SupportIslandPoint::Type::center_line_start));
|
||||||
|
VoronoiGraph::Nodes start_path;
|
||||||
|
for (const auto &node : path.nodes) {
|
||||||
|
if (node == position->neighbor->node) break;
|
||||||
|
done.insert(node);
|
||||||
|
start_path.push_back(node);
|
||||||
|
}
|
||||||
|
coord_t already_supported = position->calc_distance();
|
||||||
|
coord_t support_in = config.max_distance + already_supported;
|
||||||
|
center_starts.emplace_back(position->neighbor, support_in, start_path);
|
||||||
|
} else {
|
||||||
|
assert(position.has_value());
|
||||||
|
done.insert(start_node);
|
||||||
|
coord_t support_in = config.minimal_distance_from_outline;
|
||||||
|
center_starts.emplace_back(neighbor, support_in);
|
||||||
|
}
|
||||||
|
// IMPROVE: check side branches on start path
|
||||||
} else {
|
} else {
|
||||||
// start sample field
|
// start sample field
|
||||||
VoronoiGraph::Position field_start =
|
VoronoiGraph::Position field_start =
|
||||||
VoronoiGraphUtils::get_position_with_distance(
|
VoronoiGraphUtils::get_position_with_width(
|
||||||
neighbor, config.min_width_for_outline_support, lines);
|
neighbor, config.min_width_for_outline_support, lines);
|
||||||
sample_field(field_start, points, center_starts, done, lines, config);
|
sample_field(field_start, points, center_starts, done, lines, config);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Main loop of sampling
|
// Main loop of sampling
|
||||||
while (!center_starts.empty()) {
|
std::optional<VoronoiGraph::Position> field_start =
|
||||||
std::optional<VoronoiGraph::Position> field_start = {};
|
sample_center(center_starts, done, points, lines, config);
|
||||||
std::vector<CenterStart> new_starts =
|
while (field_start.has_value()) {
|
||||||
sample_center(center_starts.front(), config, done, points, lines, field_start);
|
sample_field(*field_start, points, center_starts, done, lines, config);
|
||||||
center_starts.pop();
|
field_start = sample_center(center_starts, done, points, lines, config);
|
||||||
for (const CenterStart &start : new_starts) center_starts.push(start);
|
|
||||||
if (field_start.has_value()){ // exist new field start?
|
|
||||||
sample_field(*field_start, points, center_starts, done, lines, config);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return points;
|
return points;
|
||||||
}
|
}
|
||||||
@ -868,34 +982,54 @@ void SampleIslandUtils::sample_field(VoronoiGraph::Position &field_start,
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<SampleIslandUtils::CenterStart> SampleIslandUtils::sample_center(
|
std::optional<VoronoiGraph::Position> SampleIslandUtils::sample_center(
|
||||||
const CenterStart & start,
|
CenterStarts & new_starts,
|
||||||
const SampleConfig & config,
|
|
||||||
std::set<const VoronoiGraph::Node *> &done,
|
std::set<const VoronoiGraph::Node *> &done,
|
||||||
SupportIslandPoints & results,
|
SupportIslandPoints & results,
|
||||||
const Lines & lines,
|
const Lines & lines,
|
||||||
std::optional<VoronoiGraph::Position> &field_start)
|
const SampleConfig & config)
|
||||||
{
|
{
|
||||||
const VoronoiGraph::Node::Neighbor *neighbor = start.neighbor;
|
const VoronoiGraph::Node::Neighbor *neighbor = nullptr;
|
||||||
const VoronoiGraph::Node *node = neighbor->node;
|
VoronoiGraph::Nodes path;
|
||||||
// already sampled line
|
coord_t support_in;
|
||||||
if (done.find(node) != done.end()) return {};
|
bool use_new_start = true;
|
||||||
VoronoiGraph::Nodes path = start.path;
|
bool is_continous = false;
|
||||||
std::vector<CenterStart> new_starts;
|
while (use_new_start || neighbor->max_width() <= config.max_width_for_center_support_line) {
|
||||||
double support_in = start.support_in;
|
// !! do not check max width for new start, it could be wide to tiny change
|
||||||
do {
|
if (use_new_start) {
|
||||||
double edge_length = neighbor->length();
|
use_new_start = false;
|
||||||
|
// skip done starts
|
||||||
|
if (new_starts.empty()) return {}; // no start
|
||||||
|
while (done.find(new_starts.back().neighbor->node) != done.end()) {
|
||||||
|
new_starts.pop_back();
|
||||||
|
if (new_starts.empty()) return {};
|
||||||
|
}
|
||||||
|
// fill new start
|
||||||
|
const CenterStart & new_start = new_starts.back();
|
||||||
|
neighbor = new_start.neighbor;
|
||||||
|
path = new_start.path; // copy
|
||||||
|
support_in = new_start.support_in;
|
||||||
|
new_starts.pop_back();
|
||||||
|
is_continous = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// add support on actual neighbor edge
|
||||||
|
coord_t edge_length = static_cast<coord_t>(neighbor->length());
|
||||||
while (edge_length >= support_in) {
|
while (edge_length >= support_in) {
|
||||||
double ratio = support_in / edge_length;
|
double ratio = support_in / neighbor->length();
|
||||||
VoronoiGraph::Position position(neighbor, ratio);
|
VoronoiGraph::Position position(neighbor, ratio);
|
||||||
results.push_back(std::make_unique<SupportCenterIslandPoint>(
|
results.push_back(std::make_unique<SupportCenterIslandPoint>(
|
||||||
position, &config, SupportIslandPoint::Type::center_line));
|
position, &config, SupportIslandPoint::Type::center_line));
|
||||||
support_in += config.max_distance;
|
support_in += config.max_distance;
|
||||||
|
is_continous = true;
|
||||||
}
|
}
|
||||||
support_in -= edge_length;
|
support_in -= edge_length;
|
||||||
|
|
||||||
const VoronoiGraph::Node *node = neighbor->node;
|
const VoronoiGraph::Node *node = neighbor->node;
|
||||||
path.push_back(node);
|
|
||||||
done.insert(node);
|
done.insert(node);
|
||||||
|
// IMPROVE: A) limit length of path to config.minimal_support_distance
|
||||||
|
// IMPROVE: B) store node in reverse order
|
||||||
|
path.push_back(node);
|
||||||
const VoronoiGraph::Node::Neighbor *next_neighbor = nullptr;
|
const VoronoiGraph::Node::Neighbor *next_neighbor = nullptr;
|
||||||
for (const auto &node_neighbor : node->neighbors) {
|
for (const auto &node_neighbor : node->neighbors) {
|
||||||
if (done.find(node_neighbor.node) != done.end()) continue;
|
if (done.find(node_neighbor.node) != done.end()) continue;
|
||||||
@ -903,42 +1037,38 @@ std::vector<SampleIslandUtils::CenterStart> SampleIslandUtils::sample_center(
|
|||||||
next_neighbor = &node_neighbor;
|
next_neighbor = &node_neighbor;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
double next_support_in = (support_in < config.half_distance) ?
|
coord_t next_support_in = (support_in >= config.half_distance) ?
|
||||||
support_in : config.max_distance - support_in;
|
support_in : (config.max_distance - support_in);
|
||||||
new_starts.emplace_back(&node_neighbor, next_support_in, path); // search in side branch
|
new_starts.emplace_back(&node_neighbor, next_support_in, path); // search in side branch
|
||||||
}
|
}
|
||||||
if (next_neighbor == nullptr) {
|
if (next_neighbor == nullptr) {
|
||||||
// no neighbor to continue
|
// no neighbor to continue
|
||||||
if ((config.max_distance - support_in) >= config.minimal_support_distance) {
|
VoronoiGraph::Nodes path_reverse = path; // copy
|
||||||
VoronoiGraph::Nodes path_reverse = path; // copy
|
std::reverse(path_reverse.begin(), path_reverse.end());
|
||||||
std::reverse(path_reverse.begin(), path_reverse.end());
|
coord_t width = 2 * config.minimal_distance_from_outline;
|
||||||
auto position_opt = create_position_on_path(
|
coord_t distance = config.maximal_distance_from_outline;
|
||||||
path_reverse, config.minimal_distance_from_outline);
|
auto position_opt = create_position_on_path(path_reverse, lines, width, distance);
|
||||||
assert(position_opt.has_value());
|
if (position_opt.has_value()) {
|
||||||
Point point = VoronoiGraphUtils::create_edge_point(
|
if (is_continous && config.max_distance < (support_in+distance) ) {
|
||||||
*position_opt);
|
// one support point should be enough
|
||||||
results.push_back(std::make_unique<SupportIslandPoint>(
|
// when max_distance > maximal_distance_from_outline
|
||||||
point, SupportIslandPoint::Type::center_line_end3));
|
results.pop_back(); // remove support point
|
||||||
|
}
|
||||||
|
create_sample_center_end(*position_opt, results, new_starts, config);
|
||||||
}
|
}
|
||||||
|
use_new_start = true;
|
||||||
if (new_starts.empty()) return {};
|
|
||||||
const CenterStart &new_start = new_starts.back();
|
|
||||||
neighbor = new_start.neighbor;
|
|
||||||
support_in = new_start.support_in;
|
|
||||||
path = new_start.path;
|
|
||||||
new_starts.pop_back();
|
|
||||||
} else {
|
} else {
|
||||||
neighbor = next_neighbor;
|
neighbor = next_neighbor;
|
||||||
}
|
}
|
||||||
} while (neighbor->max_width() <= config.max_width_for_center_support_line);
|
}
|
||||||
|
|
||||||
// create field start
|
// create field start
|
||||||
field_start = VoronoiGraphUtils::get_position_with_distance(
|
auto result = VoronoiGraphUtils::get_position_with_width(
|
||||||
neighbor, config.min_width_for_outline_support, lines);
|
neighbor, config.min_width_for_outline_support, lines);
|
||||||
|
|
||||||
// sample rest of neighbor before field
|
// sample rest of neighbor before field
|
||||||
double edge_length = neighbor->length();
|
double edge_length = neighbor->length();
|
||||||
double sample_length = edge_length * field_start->ratio;
|
double sample_length = edge_length * result.ratio;
|
||||||
while (sample_length > support_in) {
|
while (sample_length > support_in) {
|
||||||
double ratio = support_in / edge_length;
|
double ratio = support_in / edge_length;
|
||||||
VoronoiGraph::Position position(neighbor, ratio);
|
VoronoiGraph::Position position(neighbor, ratio);
|
||||||
@ -946,7 +1076,81 @@ std::vector<SampleIslandUtils::CenterStart> SampleIslandUtils::sample_center(
|
|||||||
position, &config,SupportIslandPoint::Type::center_line));
|
position, &config,SupportIslandPoint::Type::center_line));
|
||||||
support_in += config.max_distance;
|
support_in += config.max_distance;
|
||||||
}
|
}
|
||||||
return new_starts;
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SampleIslandUtils::create_sample_center_end(
|
||||||
|
const VoronoiGraph::Position &position,
|
||||||
|
SupportIslandPoints & results,
|
||||||
|
CenterStarts & new_starts,
|
||||||
|
const SampleConfig & config)
|
||||||
|
{
|
||||||
|
const SupportIslandPoint::Type no_move_type =
|
||||||
|
SupportIslandPoint::Type::center_line_end3;
|
||||||
|
const coord_t minimal_support_distance = config.minimal_support_distance;
|
||||||
|
Point point = VoronoiGraphUtils::create_edge_point(position);
|
||||||
|
// raw pointers are function scope ONLY
|
||||||
|
std::vector<const SupportIslandPoint *> near_no_move;
|
||||||
|
for (const auto &res : results) {
|
||||||
|
if (res->type != no_move_type) continue;
|
||||||
|
Point diff = point - res->point;
|
||||||
|
if (abs(diff.x()) > minimal_support_distance) continue;
|
||||||
|
if (abs(diff.y()) > minimal_support_distance) continue;
|
||||||
|
near_no_move.push_back(
|
||||||
|
&*res); // create raw pointer, used only in function scope
|
||||||
|
}
|
||||||
|
|
||||||
|
std::map<const VoronoiGraph::Node::Neighbor *, coord_t> distances;
|
||||||
|
std::function<void(const VoronoiGraph::Node::Neighbor &, coord_t)>
|
||||||
|
collect_distances = [&](const auto &neighbor, coord_t act_distance) {
|
||||||
|
distances[&neighbor] = act_distance;
|
||||||
|
};
|
||||||
|
VoronoiGraphUtils::for_neighbor_at_distance(position, minimal_support_distance, collect_distances);
|
||||||
|
|
||||||
|
bool exist_no_move = false;
|
||||||
|
if (!near_no_move.empty()) {
|
||||||
|
for (const auto &item : distances) {
|
||||||
|
const VoronoiGraph::Node::Neighbor &neighbor = *item.first;
|
||||||
|
// TODO: create belongs for parabola, when start sampling at parabola
|
||||||
|
Line edge(VoronoiGraphUtils::to_point(neighbor.edge->vertex0()),
|
||||||
|
VoronoiGraphUtils::to_point(neighbor.edge->vertex1()));
|
||||||
|
for (const auto &support_point : near_no_move) {
|
||||||
|
if (LineUtils::belongs(edge, support_point->point)) {
|
||||||
|
exist_no_move = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (exist_no_move) break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!exist_no_move) {
|
||||||
|
// fix value of support_in
|
||||||
|
// for new_starts in sampled path
|
||||||
|
// by distance to position
|
||||||
|
for (CenterStart &new_start : new_starts) {
|
||||||
|
auto item = distances.find(new_start.neighbor);
|
||||||
|
if (item != distances.end()) {
|
||||||
|
coord_t support_distance = item->second;
|
||||||
|
coord_t new_support_in = config.max_distance - item->second;
|
||||||
|
new_start.support_in = std::max(new_start.support_in,
|
||||||
|
new_support_in);
|
||||||
|
} else {
|
||||||
|
const VoronoiGraph::Node::Neighbor *twin =
|
||||||
|
VoronoiGraphUtils::get_twin(*new_start.neighbor);
|
||||||
|
auto item = distances.find(twin);
|
||||||
|
if (item != distances.end()) {
|
||||||
|
coord_t support_distance = item->second + twin->length();
|
||||||
|
coord_t new_support_in = config.max_distance -
|
||||||
|
support_distance;
|
||||||
|
new_start.support_in = std::max(new_start.support_in,
|
||||||
|
new_support_in);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
results.push_back(
|
||||||
|
std::make_unique<SupportIslandNoMovePoint>(point, no_move_type));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1039,13 +1243,13 @@ SampleIslandUtils::Field SampleIslandUtils::create_field(
|
|||||||
}
|
}
|
||||||
coord_t support_in = neighbor->length() * position.ratio + config.max_distance/2;
|
coord_t support_in = neighbor->length() * position.ratio + config.max_distance/2;
|
||||||
CenterStart tiny_start(neighbor, support_in, {source_node});
|
CenterStart tiny_start(neighbor, support_in, {source_node});
|
||||||
tiny_starts.push(tiny_start);
|
tiny_starts.push_back(tiny_start);
|
||||||
tiny_done.insert(source_node);
|
tiny_done.insert(source_node);
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
const VoronoiGraph::Node::Neighbor *tiny_wide_neighbor = field_start.neighbor;
|
const VoronoiGraph::Node::Neighbor *tiny_wide_neighbor = field_start.neighbor;
|
||||||
const VoronoiGraph::Node::Neighbor *wide_tiny_neighbor = VoronoiGraphUtils::get_twin(tiny_wide_neighbor);
|
const VoronoiGraph::Node::Neighbor *wide_tiny_neighbor = VoronoiGraphUtils::get_twin(*tiny_wide_neighbor);
|
||||||
VoronoiGraph::Position position(wide_tiny_neighbor, 1. - field_start.ratio);
|
VoronoiGraph::Position position(wide_tiny_neighbor, 1. - field_start.ratio);
|
||||||
add_wide_tiny_change(position, tiny_wide_neighbor->node);
|
add_wide_tiny_change(position, tiny_wide_neighbor->node);
|
||||||
|
|
||||||
@ -1078,7 +1282,8 @@ SampleIslandUtils::Field SampleIslandUtils::create_field(
|
|||||||
field_line_indexes.insert(index2);
|
field_line_indexes.insert(index2);
|
||||||
if (neighbor.min_width() < min_width) {
|
if (neighbor.min_width() < min_width) {
|
||||||
VoronoiGraph::Position position =
|
VoronoiGraph::Position position =
|
||||||
VoronoiGraphUtils::get_position_with_distance(&neighbor, min_width, lines);
|
VoronoiGraphUtils::get_position_with_width(
|
||||||
|
&neighbor, min_width, lines);
|
||||||
if(add_wide_tiny_change(position, node))
|
if(add_wide_tiny_change(position, node))
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -1194,7 +1399,7 @@ SampleIslandUtils::Field SampleIslandUtils::create_field(
|
|||||||
field.source_indexe_for_change = source_indexe_for_change;
|
field.source_indexe_for_change = source_indexe_for_change;
|
||||||
field.source_indexes = std::move(source_indexes);
|
field.source_indexes = std::move(source_indexes);
|
||||||
|
|
||||||
#ifdef SLA_SAMPLING_STORE_FIELD_TO_SVG
|
#ifdef SLA_SAMPLE_ISLAND_UTILS_STORE_FIELD_TO_SVG
|
||||||
{
|
{
|
||||||
const char *source_line_color = "black";
|
const char *source_line_color = "black";
|
||||||
bool draw_source_line_indexes = true;
|
bool draw_source_line_indexes = true;
|
||||||
@ -1207,7 +1412,7 @@ SampleIslandUtils::Field SampleIslandUtils::create_field(
|
|||||||
LineUtils::draw(svg, lines, source_line_color, 0., draw_source_line_indexes);
|
LineUtils::draw(svg, lines, source_line_color, 0., draw_source_line_indexes);
|
||||||
draw(svg, field, draw_border_line_indexes, draw_field_source_indexes);
|
draw(svg, field, draw_border_line_indexes, draw_field_source_indexes);
|
||||||
}
|
}
|
||||||
#endif //SLA_SAMPLING_STORE_FIELD_TO_SVG
|
#endif //SLA_SAMPLE_ISLAND_UTILS_STORE_FIELD_TO_SVG
|
||||||
return field;
|
return field;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1406,6 +1611,7 @@ SupportIslandPoints SampleIslandUtils::sample_outline(
|
|||||||
// initialize first index
|
// initialize first index
|
||||||
if (inner_first == inner_invalid) inner_first = inner_last;
|
if (inner_first == inner_invalid) inner_first = inner_last;
|
||||||
}
|
}
|
||||||
|
add_lines_samples(inner_lines, inner_first, inner_last);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1458,3 +1664,23 @@ void SampleIslandUtils::draw(SVG & svg,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool SampleIslandUtils::is_visualization_disabled()
|
||||||
|
{
|
||||||
|
#ifndef NDEBUG
|
||||||
|
return false;
|
||||||
|
#endif
|
||||||
|
#ifdef SLA_SAMPLE_ISLAND_UTILS_STORE_VORONOI_GRAPH_TO_SVG
|
||||||
|
return false;
|
||||||
|
#endif
|
||||||
|
#ifdef SLA_SAMPLE_ISLAND_UTILS_STORE_INITIAL_SAMPLE_POSITION_TO_SVG
|
||||||
|
return false;
|
||||||
|
#endif
|
||||||
|
#ifdef SLA_SAMPLE_ISLAND_UTILS_STORE_FIELD_TO_SVG
|
||||||
|
return false;
|
||||||
|
#endif
|
||||||
|
#ifdef SLA_SAMPLE_ISLAND_UTILS_STORE_ALIGN_ONCE_TO_SVG
|
||||||
|
return false;
|
||||||
|
#endif
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
@ -47,11 +47,21 @@ public:
|
|||||||
/// <param name="ratio">Source distance ratio for position on edge</param>
|
/// <param name="ratio">Source distance ratio for position on edge</param>
|
||||||
/// <param name="type">Type of point</param>
|
/// <param name="type">Type of point</param>
|
||||||
/// <returns>created support island point</returns>
|
/// <returns>created support island point</returns>
|
||||||
static SupportIslandPointPtr create_point(
|
static SupportIslandPointPtr create_no_move_point(
|
||||||
const VoronoiGraph::Node::Neighbor *neighbor,
|
const VoronoiGraph::Node::Neighbor *neighbor,
|
||||||
double ratio,
|
double ratio,
|
||||||
SupportIslandPoint::Type type = SupportIslandPoint::Type::undefined);
|
SupportIslandPoint::Type type = SupportIslandPoint::Type::undefined);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Create unique static support point
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="position">Define position on VD</param>
|
||||||
|
/// <param name="type">Type of support point</param>
|
||||||
|
/// <returns>new created support point</returns>
|
||||||
|
static SupportIslandPointPtr create_no_move_point(
|
||||||
|
const VoronoiGraph::Position &position,
|
||||||
|
SupportIslandPoint::Type type);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Find point lay on path with distance from first point on path
|
/// Find point lay on path with distance from first point on path
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -63,7 +73,33 @@ public:
|
|||||||
const VoronoiGraph::Nodes &path,
|
const VoronoiGraph::Nodes &path,
|
||||||
double distance);
|
double distance);
|
||||||
|
|
||||||
static SupportIslandPointPtr create_point_on_path(
|
/// <summary>
|
||||||
|
/// Find first point lay on sequence of node
|
||||||
|
/// where widht are equal second params OR
|
||||||
|
/// distance from first node is exactly max distance
|
||||||
|
/// Depends which occure first
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="path">Sequence of nodes, should be longer than max distance</param>
|
||||||
|
/// <param name="lines">Source lines for VG --> params for parabola.</param>
|
||||||
|
/// <param name="width">Width of island(2x distance to outline)</param>
|
||||||
|
/// <param name="max_distance">Maximal distance from first node on path.
|
||||||
|
/// At end is set to actual distance from first node.</param>
|
||||||
|
/// <returns>Position when exists</returns>
|
||||||
|
static std::optional<VoronoiGraph::Position> create_position_on_path(
|
||||||
|
const VoronoiGraph::Nodes &path,
|
||||||
|
const Lines & lines,
|
||||||
|
coord_t width,
|
||||||
|
coord_t & max_distance);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Create SupportCenterIslandPoint laying on Voronoi Graph
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="path">VD path</param>
|
||||||
|
/// <param name="distance">Distance on path</param>
|
||||||
|
/// <param name="config">Configuration</param>
|
||||||
|
/// <param name="type">Type of point</param>
|
||||||
|
/// <returns>Support island point</returns>
|
||||||
|
static SupportIslandPointPtr create_center_island_point(
|
||||||
const VoronoiGraph::Nodes &path,
|
const VoronoiGraph::Nodes &path,
|
||||||
double distance,
|
double distance,
|
||||||
const SampleConfig & config,
|
const SampleConfig & config,
|
||||||
@ -81,8 +117,19 @@ public:
|
|||||||
const VoronoiGraph::Path &path,
|
const VoronoiGraph::Path &path,
|
||||||
SupportIslandPoint::Type type = SupportIslandPoint::Type::undefined);
|
SupportIslandPoint::Type type = SupportIslandPoint::Type::undefined);
|
||||||
|
|
||||||
// create 2 points on both ends of path with side distance from border
|
/// <summary>
|
||||||
static SupportIslandPoints create_side_points(const VoronoiGraph::Nodes &path, double side_distance);
|
/// create points on both ends of path with side distance from border
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="path">Longest path over island.</param>
|
||||||
|
/// <param name="lines">Source lines for VG --> outline of island.</param>
|
||||||
|
/// <param name="width">Wanted width on position</param>
|
||||||
|
/// <param name="max_side_distance">Maximal distance from side</param>
|
||||||
|
/// <returns>2x Static Support point(lay os sides of path)</returns>
|
||||||
|
static SupportIslandPoints create_side_points(
|
||||||
|
const VoronoiGraph::Nodes & path,
|
||||||
|
const Lines & lines,
|
||||||
|
coord_t width,
|
||||||
|
coord_t max_side_distance);
|
||||||
|
|
||||||
// DTO with data for sampling line in center
|
// DTO with data for sampling line in center
|
||||||
struct CenterLineConfiguration
|
struct CenterLineConfiguration
|
||||||
@ -180,6 +227,7 @@ public:
|
|||||||
/// <param name="config"> Sampling configuration
|
/// <param name="config"> Sampling configuration
|
||||||
/// Maximal distance between neighbor points +
|
/// Maximal distance between neighbor points +
|
||||||
/// Term criteria for align: Minimal sample move and Maximal count of iteration</param>
|
/// Term criteria for align: Minimal sample move and Maximal count of iteration</param>
|
||||||
|
/// <returns>Maximal distance of move during aligning.</returns>
|
||||||
static coord_t align_once(SupportIslandPoints &samples,
|
static coord_t align_once(SupportIslandPoints &samples,
|
||||||
const ExPolygon & island,
|
const ExPolygon & island,
|
||||||
const SampleConfig & config);
|
const SampleConfig & config);
|
||||||
@ -192,7 +240,7 @@ public:
|
|||||||
/// <param name="max_distance">Maximal search distance on VD for closest point</param>
|
/// <param name="max_distance">Maximal search distance on VD for closest point</param>
|
||||||
/// <returns>Distance move of original point</returns>
|
/// <returns>Distance move of original point</returns>
|
||||||
static coord_t align_support(SupportIslandPoint &support, const Point &wanted, double max_distance);
|
static coord_t align_support(SupportIslandPoint &support, const Point &wanted, double max_distance);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// DTO hold information for start sampling VD in center
|
/// DTO hold information for start sampling VD in center
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -212,28 +260,44 @@ public:
|
|||||||
: neighbor(neighbor), support_in(support_in), path(path)
|
: neighbor(neighbor), support_in(support_in), path(path)
|
||||||
{}
|
{}
|
||||||
};
|
};
|
||||||
using CenterStarts = std::queue<CenterStart>;
|
using CenterStarts = std::vector<CenterStart>;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Sample VG in center --> sample tiny part of island
|
/// Sample VG in center --> sample tiny part of island
|
||||||
/// Detection of wide neighbor which start field
|
/// Sample until starts are empty or find new field(wide neighbor).
|
||||||
/// Creating of new starts (from VG cross -> multi neighbors)
|
/// Creating of new starts (by VG cross -> multi neighbors)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="start">Start to sample</param>
|
/// <param name="start">Start to sample</param>
|
||||||
/// <param name="config">Parameters for sampling</param>
|
/// <param name="done">Already done(processed) nodes</param>
|
||||||
/// <param name="done">Already done nodes</param>
|
|
||||||
/// <param name="results">Result of sampling</param>
|
/// <param name="results">Result of sampling</param>
|
||||||
/// <param name="liness">Source line for VD. To decide position of change from tiny to wide part</param>
|
/// <param name="lines">Source line for VD. To decide position of change from tiny to wide part</param>
|
||||||
/// <param name="field_start">Output: Wide neighbor, start of field</param>
|
/// <param name="config">Parameters for sampling</param>
|
||||||
/// <returns>New start of sampling</returns>
|
/// <returns>Wide neighbor, start of field when exists</returns>
|
||||||
static std::vector<CenterStart> sample_center(
|
static std::optional<VoronoiGraph::Position> sample_center(
|
||||||
const CenterStart & start,
|
CenterStarts & new_starts,
|
||||||
const SampleConfig & config,
|
|
||||||
std::set<const VoronoiGraph::Node *> &done,
|
std::set<const VoronoiGraph::Node *> &done,
|
||||||
SupportIslandPoints & results,
|
SupportIslandPoints & results,
|
||||||
const Lines &lines,
|
const Lines & lines,
|
||||||
std::optional<VoronoiGraph::Position> &field_start);
|
const SampleConfig & config);
|
||||||
|
|
||||||
|
private:
|
||||||
|
/// <summary>
|
||||||
|
/// Check near supports if no exists there add to results
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="position">Potentional new static point position</param>
|
||||||
|
/// <param name="results">Results to check near and optionaly append newone</param>
|
||||||
|
/// <param name="new_starts">When append new support point
|
||||||
|
/// than fix value of support_in for near new_start</param>
|
||||||
|
/// <param name="config">Parameters for sampling,
|
||||||
|
/// minimal_support_distance - search distance in VD
|
||||||
|
/// max_distance - for fix new_start</param>
|
||||||
|
static void create_sample_center_end(
|
||||||
|
const VoronoiGraph::Position &position,
|
||||||
|
SupportIslandPoints & results,
|
||||||
|
CenterStarts & new_starts,
|
||||||
|
const SampleConfig & config);
|
||||||
|
|
||||||
|
public :
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// DTO represents Wide parts of island to sample
|
/// DTO represents Wide parts of island to sample
|
||||||
/// extend polygon with information about source lines
|
/// extend polygon with information about source lines
|
||||||
@ -304,6 +368,7 @@ private:
|
|||||||
|
|
||||||
// debug draw functions
|
// debug draw functions
|
||||||
public :
|
public :
|
||||||
|
static bool is_visualization_disabled();
|
||||||
static void draw(SVG & svg,
|
static void draw(SVG & svg,
|
||||||
const Field &field,
|
const Field &field,
|
||||||
bool draw_border_line_indexes = false,
|
bool draw_border_line_indexes = false,
|
||||||
|
@ -45,7 +45,8 @@ coord_t SupportIslandPoint::move(const Point &destination)
|
|||||||
|
|
||||||
std::string SupportIslandPoint::to_string(const Type &type)
|
std::string SupportIslandPoint::to_string(const Type &type)
|
||||||
{
|
{
|
||||||
static std::map<Type, std::string> type_to_tring=
|
static const std::string undefined = "UNDEFINED";
|
||||||
|
static std::map<Type, std::string> type_to_string=
|
||||||
{{Type::one_center_point, "one_center_point"},
|
{{Type::one_center_point, "one_center_point"},
|
||||||
{Type::two_points,"two_points"},
|
{Type::two_points,"two_points"},
|
||||||
{Type::center_line, "center_line"},
|
{Type::center_line, "center_line"},
|
||||||
@ -59,8 +60,8 @@ std::string SupportIslandPoint::to_string(const Type &type)
|
|||||||
{Type::outline, "outline"},
|
{Type::outline, "outline"},
|
||||||
{Type::inner, "inner"},
|
{Type::inner, "inner"},
|
||||||
{Type::undefined, "undefined"}};
|
{Type::undefined, "undefined"}};
|
||||||
auto it = type_to_tring.find(type);
|
auto it = type_to_string.find(type);
|
||||||
if (it == type_to_tring.end()) return "UNDEFINED";
|
if (it == type_to_string.end()) return undefined;
|
||||||
return it->second;
|
return it->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,6 +27,8 @@ public:
|
|||||||
static void sort_by(std::vector<T1> &data, std::function<T2(const T1 &)> &calc)
|
static void sort_by(std::vector<T1> &data, std::function<T2(const T1 &)> &calc)
|
||||||
{
|
{
|
||||||
assert(!data.empty());
|
assert(!data.empty());
|
||||||
|
if (data.size() <= 1) return;
|
||||||
|
|
||||||
// initialize original index locations
|
// initialize original index locations
|
||||||
std::vector<size_t> idx(data.size());
|
std::vector<size_t> idx(data.size());
|
||||||
iota(idx.begin(), idx.end(), 0);
|
iota(idx.begin(), idx.end(), 0);
|
||||||
|
@ -196,6 +196,15 @@ struct VoronoiGraph::Position
|
|||||||
{}
|
{}
|
||||||
|
|
||||||
Position(): neighbor(nullptr), ratio(0.) {}
|
Position(): neighbor(nullptr), ratio(0.) {}
|
||||||
|
|
||||||
|
coord_t calc_distance() const {
|
||||||
|
return static_cast<coord_t>(neighbor->length() * ratio);
|
||||||
|
}
|
||||||
|
|
||||||
|
coord_t calc_rest_distance() const
|
||||||
|
{
|
||||||
|
return static_cast<coord_t>(neighbor->length() * (1. - ratio));
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Slic3r::sla
|
} // namespace Slic3r::sla
|
||||||
|
@ -255,7 +255,8 @@ Slic3r::Polygon VoronoiGraphUtils::to_polygon(const VD::cell_type & cell,
|
|||||||
lines.push_back(*line);
|
lines.push_back(*line);
|
||||||
} while ((edge = edge->next()) && edge != cell.incident_edge());
|
} while ((edge = edge->next()) && edge != cell.incident_edge());
|
||||||
assert(!lines.empty());
|
assert(!lines.empty());
|
||||||
LineUtils::sort_CCW(lines, center);
|
if (lines.size() > 1)
|
||||||
|
LineUtils::sort_CCW(lines, center);
|
||||||
// preccission to decide when not connect neighbor points
|
// preccission to decide when not connect neighbor points
|
||||||
double min_distance = maximal_distance / 1000.;
|
double min_distance = maximal_distance / 1000.;
|
||||||
size_t count_point = 6; // count added points
|
size_t count_point = 6; // count added points
|
||||||
@ -865,17 +866,17 @@ VoronoiGraph::ExPath VoronoiGraphUtils::create_longest_path(
|
|||||||
return longest_path;
|
return longest_path;
|
||||||
}
|
}
|
||||||
|
|
||||||
const VoronoiGraph::Node::Neighbor *VoronoiGraphUtils::get_twin(const VoronoiGraph::Node::Neighbor *neighbor)
|
const VoronoiGraph::Node::Neighbor *VoronoiGraphUtils::get_twin(const VoronoiGraph::Node::Neighbor& neighbor)
|
||||||
{
|
{
|
||||||
auto twin_edge = neighbor->edge->twin();
|
auto twin_edge = neighbor.edge->twin();
|
||||||
for (const VoronoiGraph::Node::Neighbor &twin_neighbor : neighbor->node->neighbors) {
|
for (const VoronoiGraph::Node::Neighbor &twin_neighbor : neighbor.node->neighbors) {
|
||||||
if (twin_neighbor.edge == twin_edge) return &twin_neighbor;
|
if (twin_neighbor.edge == twin_edge) return &twin_neighbor;
|
||||||
}
|
}
|
||||||
assert(false);
|
assert(false);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
const VoronoiGraph::Node *VoronoiGraphUtils::get_twin_node(const VoronoiGraph::Node::Neighbor *neighbor)
|
const VoronoiGraph::Node *VoronoiGraphUtils::get_twin_node(const VoronoiGraph::Node::Neighbor &neighbor)
|
||||||
{
|
{
|
||||||
return get_twin(neighbor)->node;
|
return get_twin(neighbor)->node;
|
||||||
}
|
}
|
||||||
@ -919,13 +920,16 @@ Slic3r::Point VoronoiGraphUtils::create_edge_point(const VD::edge_type *edge,
|
|||||||
return Point(v0->x() + dir.x(), v0->y() + dir.y());
|
return Point(v0->x() + dir.x(), v0->y() + dir.y());
|
||||||
}
|
}
|
||||||
|
|
||||||
VoronoiGraph::Position VoronoiGraphUtils::get_position_with_distance(
|
VoronoiGraph::Position VoronoiGraphUtils::get_position_with_width(
|
||||||
const VoronoiGraph::Node::Neighbor *neighbor, coord_t width, const Slic3r::Lines &lines)
|
const VoronoiGraph::Node::Neighbor *neighbor, coord_t width, const Slic3r::Lines &lines)
|
||||||
{
|
{
|
||||||
VoronoiGraph::Position result(neighbor, 0.);
|
VoronoiGraph::Position result(neighbor, 0.);
|
||||||
const VD::edge_type *edge = neighbor->edge;
|
const VD::edge_type *edge = neighbor->edge;
|
||||||
if (edge->is_curved()) {
|
if (edge->is_curved()) {
|
||||||
// Every point on curve has same distance from outline
|
// Every point on curve has same distance from outline
|
||||||
|
// !!! NOT TRUE !!!
|
||||||
|
// Only same distance from point and line !!!
|
||||||
|
// TODO: Fix it
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
assert(edge->is_finite());
|
assert(edge->is_finite());
|
||||||
@ -1014,7 +1018,7 @@ VoronoiGraph::Position VoronoiGraphUtils::align(
|
|||||||
const VoronoiGraph::Node::Neighbor* neighbor = position.neighbor;
|
const VoronoiGraph::Node::Neighbor* neighbor = position.neighbor;
|
||||||
double from_distance = neighbor->length() * position.ratio;
|
double from_distance = neighbor->length() * position.ratio;
|
||||||
if (from_distance < max_distance) {
|
if (from_distance < max_distance) {
|
||||||
const VoronoiGraph::Node *from_node = VoronoiGraphUtils::get_twin_node(neighbor);
|
const VoronoiGraph::Node *from_node = VoronoiGraphUtils::get_twin_node(*neighbor);
|
||||||
process.emplace(from_node, from_distance);
|
process.emplace(from_node, from_distance);
|
||||||
}
|
}
|
||||||
double to_distance = neighbor->length() * (1 - position.ratio);
|
double to_distance = neighbor->length() * (1 - position.ratio);
|
||||||
@ -1024,7 +1028,7 @@ VoronoiGraph::Position VoronoiGraphUtils::align(
|
|||||||
}
|
}
|
||||||
if (process.empty()) {
|
if (process.empty()) {
|
||||||
const VoronoiGraph::Node *node = (position.ratio < 0.5) ?
|
const VoronoiGraph::Node *node = (position.ratio < 0.5) ?
|
||||||
VoronoiGraphUtils::get_twin_node(neighbor) : neighbor->node;
|
VoronoiGraphUtils::get_twin_node(*neighbor) : neighbor->node;
|
||||||
process.emplace(node, max_distance);
|
process.emplace(node, max_distance);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1196,6 +1200,56 @@ void VoronoiGraphUtils::draw(SVG & svg,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void VoronoiGraphUtils::for_neighbor_at_distance(
|
||||||
|
const VoronoiGraph::Position & position,
|
||||||
|
coord_t max_distance,
|
||||||
|
std::function<void(const VoronoiGraph::Node::Neighbor &, coord_t)> fnc)
|
||||||
|
{
|
||||||
|
coord_t act_distance = position.calc_distance();
|
||||||
|
const VoronoiGraph::Node *act_node = position.neighbor->node;
|
||||||
|
const VoronoiGraph::Node *twin_node = get_twin_node(*position.neighbor);
|
||||||
|
std::set<const VoronoiGraph::Node *> done;
|
||||||
|
done.insert(twin_node);
|
||||||
|
done.insert(act_node);
|
||||||
|
std::queue<std::pair<const VoronoiGraph::Node *, coord_t>> process;
|
||||||
|
coord_t distance = position.calc_rest_distance();
|
||||||
|
if (distance < max_distance)
|
||||||
|
process.push({twin_node, distance});
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
const VoronoiGraph::Node *next_node = nullptr;
|
||||||
|
coord_t next_distance = 0;
|
||||||
|
for (const auto &neighbor : act_node->neighbors) {
|
||||||
|
if (done.find(neighbor.node) != done.end())
|
||||||
|
continue; // already checked
|
||||||
|
done.insert(neighbor.node);
|
||||||
|
|
||||||
|
fnc(neighbor, act_distance);
|
||||||
|
|
||||||
|
coord_t length = static_cast<coord_t>(neighbor.length());
|
||||||
|
coord_t distance = act_distance + length;
|
||||||
|
if (distance >= max_distance) continue;
|
||||||
|
if (next_node == nullptr) {
|
||||||
|
next_node = neighbor.node;
|
||||||
|
next_distance = distance;
|
||||||
|
} else {
|
||||||
|
process.push({neighbor.node, distance});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (next_node != nullptr) { // exist next node
|
||||||
|
act_node = next_node;
|
||||||
|
act_distance = next_distance;
|
||||||
|
} else if (!process.empty()) { // exist next process
|
||||||
|
act_node = process.front().first;
|
||||||
|
act_distance = process.front().second;
|
||||||
|
process.pop();
|
||||||
|
} else { // no next node neither process
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
void VoronoiGraphUtils::draw(SVG & svg,
|
void VoronoiGraphUtils::draw(SVG & svg,
|
||||||
const VD::edge_type &edge,
|
const VD::edge_type &edge,
|
||||||
const Lines & lines,
|
const Lines & lines,
|
||||||
|
@ -98,7 +98,7 @@ public:
|
|||||||
static bool is_point_in_limits(const VD::vertex_type *vertex,
|
static bool is_point_in_limits(const VD::vertex_type *vertex,
|
||||||
const Point & source,
|
const Point & source,
|
||||||
double max_distance);
|
double max_distance);
|
||||||
|
private:
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// PRIVATE: function to help convert edge without vertex to line
|
/// PRIVATE: function to help convert edge without vertex to line
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -109,13 +109,14 @@ public:
|
|||||||
static Line create_line_between_source_points(
|
static Line create_line_between_source_points(
|
||||||
const Point &point1, const Point &point2, double maximal_distance);
|
const Point &point1, const Point &point2, double maximal_distance);
|
||||||
|
|
||||||
|
public:
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Convert edge to line
|
/// Convert edge to line
|
||||||
/// only for line edge
|
/// only for line edge
|
||||||
/// crop infinite edge by maximal distance from source point
|
/// crop infinite edge by maximal distance from source point
|
||||||
/// inspiration in VoronoiVisualUtils::clip_infinite_edge
|
/// inspiration in VoronoiVisualUtils::clip_infinite_edge
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="edge"></param>
|
/// <param name="edge">VD edge</param>
|
||||||
/// <param name="points">Source point for voronoi diagram</param>
|
/// <param name="points">Source point for voronoi diagram</param>
|
||||||
/// <param name="maximal_distance">Maximal distance from source point</param>
|
/// <param name="maximal_distance">Maximal distance from source point</param>
|
||||||
/// <returns>Croped line, when all line segment is out of max distance return empty optional</returns>
|
/// <returns>Croped line, when all line segment is out of max distance return empty optional</returns>
|
||||||
@ -358,14 +359,14 @@ public:
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="neighbor">neighbor</param>
|
/// <param name="neighbor">neighbor</param>
|
||||||
/// <returns>Twin neighbor</returns>
|
/// <returns>Twin neighbor</returns>
|
||||||
static const VoronoiGraph::Node::Neighbor *get_twin(const VoronoiGraph::Node::Neighbor *neighbor);
|
static const VoronoiGraph::Node::Neighbor *get_twin(const VoronoiGraph::Node::Neighbor& neighbor);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Find source node of neighbor
|
/// Find source node of neighbor
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="neighbor">neighbor</param>
|
/// <param name="neighbor">neighbor</param>
|
||||||
/// <returns>start node</returns>
|
/// <returns>start node</returns>
|
||||||
static const VoronoiGraph::Node *get_twin_node(const VoronoiGraph::Node::Neighbor *neighbor);
|
static const VoronoiGraph::Node *get_twin_node(const VoronoiGraph::Node::Neighbor& neighbor);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Check if neighbor is in opposit direction to line direction
|
/// Check if neighbor is in opposit direction to line direction
|
||||||
@ -391,7 +392,7 @@ public:
|
|||||||
/// <param name="width">Specify place on edge</param>
|
/// <param name="width">Specify place on edge</param>
|
||||||
/// <param name="lines">Source lines for voronoi diagram</param>
|
/// <param name="lines">Source lines for voronoi diagram</param>
|
||||||
/// <returns>Position on given edge</returns>
|
/// <returns>Position on given edge</returns>
|
||||||
static VoronoiGraph::Position get_position_with_distance(
|
static VoronoiGraph::Position get_position_with_width(
|
||||||
const VoronoiGraph::Node::Neighbor *neighbor,
|
const VoronoiGraph::Node::Neighbor *neighbor,
|
||||||
coord_t width,
|
coord_t width,
|
||||||
const Lines & lines);
|
const Lines & lines);
|
||||||
@ -453,6 +454,17 @@ public:
|
|||||||
/// <returns>True when neighbor node has only one neighbor</returns>
|
/// <returns>True when neighbor node has only one neighbor</returns>
|
||||||
static bool is_last_neighbor(const VoronoiGraph::Node::Neighbor *neighbor);
|
static bool is_last_neighbor(const VoronoiGraph::Node::Neighbor *neighbor);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Loop over neighbor in max distance from position
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="position">Start of loop</param>
|
||||||
|
/// <param name="max_distance">Termination of loop</param>
|
||||||
|
/// <param name="fnc">function to process neighbor with actual distance</param>
|
||||||
|
static void for_neighbor_at_distance(
|
||||||
|
const VoronoiGraph::Position &position,
|
||||||
|
coord_t max_distance,
|
||||||
|
std::function<void(const VoronoiGraph::Node::Neighbor &, coord_t)> fnc);
|
||||||
|
|
||||||
public: // draw function for debug
|
public: // draw function for debug
|
||||||
static void draw(SVG & svg,
|
static void draw(SVG & svg,
|
||||||
const VoronoiGraph &graph,
|
const VoronoiGraph &graph,
|
||||||
|
@ -460,7 +460,8 @@ SampleConfig create_sample_config(double size) {
|
|||||||
cfg.max_distance = 3 * size + 0.1;
|
cfg.max_distance = 3 * size + 0.1;
|
||||||
cfg.half_distance = cfg.max_distance/2;
|
cfg.half_distance = cfg.max_distance/2;
|
||||||
cfg.head_radius = size / 4;
|
cfg.head_radius = size / 4;
|
||||||
cfg.minimal_distance_from_outline = cfg.head_radius + size/10;
|
cfg.minimal_distance_from_outline = cfg.head_radius;
|
||||||
|
cfg.maximal_distance_from_outline = cfg.half_distance;
|
||||||
cfg.min_side_branch_length = 2 * cfg.minimal_distance_from_outline;
|
cfg.min_side_branch_length = 2 * cfg.minimal_distance_from_outline;
|
||||||
cfg.minimal_support_distance = cfg.minimal_distance_from_outline + cfg.half_distance;
|
cfg.minimal_support_distance = cfg.minimal_distance_from_outline + cfg.half_distance;
|
||||||
cfg.max_length_for_one_support_point = 2*size;
|
cfg.max_length_for_one_support_point = 2*size;
|
||||||
@ -469,7 +470,7 @@ SampleConfig create_sample_config(double size) {
|
|||||||
cfg.min_width_for_outline_support = cfg.max_width_for_center_support_line;
|
cfg.min_width_for_outline_support = cfg.max_width_for_center_support_line;
|
||||||
cfg.outline_sample_distance = cfg.max_distance;
|
cfg.outline_sample_distance = cfg.max_distance;
|
||||||
|
|
||||||
cfg.minimal_move = std::max(1000., size/1000);
|
cfg.minimal_move = std::max(10000., size/40);
|
||||||
cfg.count_iteration = 100;
|
cfg.count_iteration = 100;
|
||||||
cfg.max_align_distance = 0;
|
cfg.max_align_distance = 0;
|
||||||
return cfg;
|
return cfg;
|
||||||
@ -587,12 +588,7 @@ TEST_CASE("Small islands should be supported in center", "[SupGen], [VoronoiSkel
|
|||||||
SampleConfig cfg = create_sample_config(size);
|
SampleConfig cfg = create_sample_config(size);
|
||||||
ExPolygons islands = createTestIslands(size);
|
ExPolygons islands = createTestIslands(size);
|
||||||
|
|
||||||
// TODO: remove next 4 lines, debug sharp triangle
|
islands = {islands[16]};
|
||||||
/*auto triangle = PolygonUtils::create_isosceles_triangle(8. * size, 40. * size);
|
|
||||||
islands = {ExPolygon(triangle)};
|
|
||||||
auto test_island = create_tiny_wide_test_2(3 * size, 2 / 3. * size);
|
|
||||||
islands = {test_island};*/
|
|
||||||
|
|
||||||
for (ExPolygon &island : islands) {
|
for (ExPolygon &island : islands) {
|
||||||
// information for debug which island cause problem
|
// information for debug which island cause problem
|
||||||
[[maybe_unused]] size_t debug_index = &island - &islands.front();
|
[[maybe_unused]] size_t debug_index = &island - &islands.front();
|
||||||
@ -712,6 +708,43 @@ TEST_CASE("Compare sampling test", "[hide]")
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// source: https://en.wikipedia.org/wiki/Centroid
|
||||||
|
Slic3r::Point centroid(const Slic3r::Polygon &polygon) {
|
||||||
|
double sum_x = 0.;
|
||||||
|
double sum_y = 0.;
|
||||||
|
double signed_area = 0.;
|
||||||
|
auto add = [&](const Point &p1, const Point &p2) {
|
||||||
|
Vec2d p1d = p1.cast<double>();
|
||||||
|
double area = p1d.x() * p2.y() - p1d.y() * p2.x();
|
||||||
|
sum_x += (p1d.x() + p2.x()) * area;
|
||||||
|
sum_y += (p1d.y() + p2.y()) * area;
|
||||||
|
signed_area += area;
|
||||||
|
};
|
||||||
|
const Points &points = polygon.points;
|
||||||
|
for (size_t i = 1; i < points.size(); i++) {
|
||||||
|
add(points[i - 1], points[i]);
|
||||||
|
}
|
||||||
|
add(points.back(), points.front());
|
||||||
|
double area6 = signed_area * 3;
|
||||||
|
return Point(sum_x / area6, sum_y / area6);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Trapezoid centroid should be inside of trapezoid", "[Utils]")
|
||||||
|
{
|
||||||
|
Slic3r::Polygon polygon({
|
||||||
|
Point(4702134, 1124765853),
|
||||||
|
Point(-4702134, 1124765853),
|
||||||
|
Point(-9404268, 1049531706),
|
||||||
|
Point(9404268, 1049531706)
|
||||||
|
});
|
||||||
|
|
||||||
|
Point my_centroid = centroid(polygon);
|
||||||
|
CHECK(polygon.contains(my_centroid));
|
||||||
|
|
||||||
|
Point centroid = polygon.centroid();
|
||||||
|
CHECK(polygon.contains(centroid));
|
||||||
|
}
|
||||||
|
|
||||||
#include <libslic3r/SLA/SupportIslands/VectorUtils.hpp>
|
#include <libslic3r/SLA/SupportIslands/VectorUtils.hpp>
|
||||||
TEST_CASE("Reorder destructive", "[Utils]"){
|
TEST_CASE("Reorder destructive", "[Utils]"){
|
||||||
std::vector<int> data {0, 1, 3, 2, 4, 7, 6, 5, 8};
|
std::vector<int> data {0, 1, 3, 2, 4, 7, 6, 5, 8};
|
||||||
@ -773,5 +806,6 @@ TEST_CASE("Disable visualization", "[hide]")
|
|||||||
#ifdef STORE_SAMPLE_INTO_SVG_FILES
|
#ifdef STORE_SAMPLE_INTO_SVG_FILES
|
||||||
CHECK(false);
|
CHECK(false);
|
||||||
#endif // STORE_SAMPLE_INTO_SVG_FILES
|
#endif // STORE_SAMPLE_INTO_SVG_FILES
|
||||||
|
CHECK(SampleIslandUtils::is_visualization_disabled());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user