Add filter for end center line support instead of minimal distance.

This commit is contained in:
Filip Sykala 2021-05-07 07:12:08 +02:00 committed by Lukas Matena
parent 0c9dedcffa
commit 12b320624b
12 changed files with 593 additions and 147 deletions

View File

@ -279,6 +279,30 @@ std::optional<Slic3r::Vec2d> LineUtils::intersection(const Line &ray1, const Lin
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)
{
Vec2d a = line.a.cast<double>();

View File

@ -111,6 +111,17 @@ public:
/// <returns>intersection point when exist</returns>
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>
/// Create direction from point a to point b
/// Direction vector is represented as point

View File

@ -24,6 +24,11 @@ struct SampleConfig
// zero when head should be on outline
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)
// MUST be bigger than minimal_distance_from_outline
coord_t minimal_support_distance = 0;
@ -47,6 +52,7 @@ struct SampleConfig
// Must be smaller or equal to max_width_for_center_support_line
coord_t min_width_for_outline_support = 1.;
// Term criteria for end of alignment
// Minimal change in manhatn move of support position before termination
coord_t minimal_move = 1000; // in nanometers, devide from print resolution to quater pixel

View File

@ -27,7 +27,9 @@ public:
result.max_distance = max_distance / sample_multiplicator;
result.half_distance = result.max_distance / 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.half_distance;
@ -76,7 +78,7 @@ public:
// Align support points
// 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.max_align_distance = result.max_distance / 2;

View File

@ -20,9 +20,10 @@
// comment definition of NDEBUG to enable assert()
//#define NDEBUG
//#define SLA_SAMPLING_STORE_VORONOI_GRAPH_TO_SVG
//#define SLA_SAMPLING_STORE_FIELD_TO_SVG
//#define SLA_SAMPLING_STORE_POISSON_SAMPLING_TO_SVG
#define SLA_SAMPLE_ISLAND_UTILS_STORE_VORONOI_GRAPH_TO_SVG
#define SLA_SAMPLE_ISLAND_UTILS_STORE_INITIAL_SAMPLE_POSITION_TO_SVG
#define SLA_SAMPLE_ISLAND_UTILS_STORE_FIELD_TO_SVG
//#define SLA_SAMPLE_ISLAND_UTILS_STORE_ALIGN_ONCE_TO_SVG
#include <cassert>
@ -131,14 +132,21 @@ Slic3r::Points SampleIslandUtils::sample_expolygon(const ExPolygon &expoly,
return result;
}
std::unique_ptr<SupportIslandPoint> SampleIslandUtils::create_point(
SupportIslandPointPtr SampleIslandUtils::create_no_move_point(
const VoronoiGraph::Node::Neighbor *neighbor,
double ratio,
SupportIslandPoint::Type type)
{
VoronoiGraph::Position position(neighbor, ratio);
Slic3r::Point p = VoronoiGraphUtils::create_edge_point(position);
return std::make_unique<SupportIslandPoint>(p, type);
return create_no_move_point(position, 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(
@ -157,9 +165,8 @@ std::unique_ptr<SupportIslandPoint> SampleIslandUtils::create_point(
actual_distance += neighbor->length();
if (actual_distance >= distance) {
// over half point is on
double previous_distance = actual_distance - distance;
double over_ratio = previous_distance / neighbor->length();
double ratio = 1. - over_ratio;
double behind_position = actual_distance - distance;
double ratio = 1. - behind_position / neighbor->length();
return VoronoiGraph::Position(neighbor, ratio);
}
prev_node = node;
@ -171,7 +178,50 @@ std::unique_ptr<SupportIslandPoint> SampleIslandUtils::create_point(
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,
double distance,
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);
if (!position_opt.has_value()) return nullptr;
return create_point(position_opt->neighbor, position_opt->ratio, type);
return create_no_move_point(*position_opt, type);
}
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
std::reverse(reverse_path.begin(), reverse_path.end());
auto pos1 = create_position_on_path(path, side_distance);
auto pos2 = create_position_on_path(reverse_path, side_distance);
coord_t distance2 = max_side_distance; // copy
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(pos2.has_value());
SupportIslandPoint::Type type = SupportIslandPoint::Type::two_points;
SupportIslandPoints result;
result.reserve(2);
result.push_back(create_point(pos1->neighbor, pos1->ratio, type));
result.push_back(create_point(pos2->neighbor, pos2->ratio, type));
result.push_back(create_no_move_point(*pos1, type));
result.push_back(create_no_move_point(*pos2, type));
return result;
}
@ -225,7 +278,7 @@ SupportIslandPoints SampleIslandUtils::sample_side_branch(
reverse_path.push_back(first_node);
SupportIslandPoints result;
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));
return result;
}
@ -255,7 +308,8 @@ SupportIslandPoints SampleIslandUtils::sample_side_branch(
while (distance < neighbor->length()) {
double edge_ratio = distance / neighbor->length();
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;
}
@ -371,8 +425,6 @@ bool is_points_in_distance(const Slic3r::Point & p,
return true;
}
//#define VISUALIZE_SAMPLE_ISLAND_UTILS_ALIGN_ONCE
coord_t SampleIslandUtils::align_once(SupportIslandPoints &samples,
const ExPolygon & island,
const SampleConfig & config)
@ -381,22 +433,37 @@ coord_t SampleIslandUtils::align_once(SupportIslandPoints &samples,
using VD = Slic3r::Geometry::VoronoiDiagram;
VD vd;
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;
BoundingBox bbox(island);
SVG svg(("align_"+std::to_string(counter++)+".svg").c_str(), bbox);
svg.draw(island, "lightblue");
#endif // VISUALIZE_SAMPLE_ISLAND_UTILS_ALIGN_ONCE
SVG svg(("align_" + std::to_string(counter++) + ".svg").c_str(), bbox);
svg.draw(island, color_of_island );
#endif // SLA_SAMPLE_ISLAND_UTILS_STORE_ALIGN_ONCE_TO_SVG
// create voronoi diagram with points
construct_voronoi(points.begin(), points.end(), &vd);
coord_t max_move = 0;
for (const VD::cell_type &cell : vd.cells()) {
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;
Polygon polygon = VoronoiGraphUtils::to_polygon(cell, points, config.max_distance);
Polygons intersections = Slic3r::intersection(island, ExPolygon(polygon));
Polygon cell_polygon = VoronoiGraphUtils::to_polygon(cell, points, config.max_distance);
Polygons intersections = Slic3r::intersection(island, ExPolygon(cell_polygon));
const Polygon *island_cell = nullptr;
for (const Polygon &intersection : intersections) {
if (intersection.contains(sample->point)) {
@ -406,16 +473,32 @@ coord_t SampleIslandUtils::align_once(SupportIslandPoints &samples,
}
assert(island_cell != nullptr);
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));
#ifdef VISUALIZE_SAMPLE_ISLAND_UTILS_ALIGN_ONCE
svg.draw(polygon, "lightgray");
svg.draw(*island_cell, "gray");
svg.draw(sample.point, "black", config.head_radius);
svg.draw(Line(sample.point, center), "blue", config.head_radius / 5);
#endif // VISUALIZE_SAMPLE_ISLAND_UTILS_ALIGN_ONCE
#ifdef SLA_SAMPLE_ISLAND_UTILS_STORE_ALIGN_ONCE_TO_SVG
svg.draw(cell_polygon, color_point_cell);
svg.draw(*island_cell, color_island_cell_intersection);
svg.draw(Line(sample->point, center), color_wanted_point, config.head_radius / 5);
svg.draw(sample->point, color_old_point, config.head_radius);
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);
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;
}
@ -459,8 +542,8 @@ void SampleIslandUtils::sample_center_circle_end(
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.push_back(
create_point(&neighbor, 1., SupportIslandPoint::Type::center_circle_end));
result.push_back(create_no_move_point(
&neighbor, 1., SupportIslandPoint::Type::center_circle_end));
neighbor_distance = 0.;
count_supports -= 1;
if (count_supports == 0) {
@ -478,8 +561,7 @@ void SampleIslandUtils::sample_center_circle_end(
auto position = create_position_on_path(nodes, distance_from_neighbor);
assert(position.has_value());
result.push_back(
create_point(position->neighbor, position->ratio,
SupportIslandPoint::Type::center_circle_end2));
create_no_move_point(*position, SupportIslandPoint::Type::center_circle_end2));
double distance_support_to_node = fabs(neighbor.length() -
distance_from_neighbor);
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
const VoronoiGraph::Position &position = ptr->position;
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 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 = 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;
SVG svg("voronoiGraph" + std::to_string(counter++) + ".svg",
LineUtils::create_bounding_box(lines));
VoronoiGraphUtils::draw(svg, graph, lines, 1e6, true);
}
#endif // SLA_SAMPLING_STORE_VORONOI_GRAPH_TO_SVG
return sample_expath(longest_path, lines, config);
#endif // SLA_SAMPLE_ISLAND_UTILS_STORE_VORONOI_GRAPH_TO_SVG
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(
@ -787,16 +881,20 @@ SupportIslandPoints SampleIslandUtils::sample_expath(
double max_width = VoronoiGraphUtils::get_max_width(path);
if (max_width < config.max_width_for_center_support_line) {
// 2) Two support points
if (path.length < config.max_length_for_two_support_points)
return create_side_points(path.nodes,
config.minimal_distance_from_outline);
if (path.length < config.max_length_for_two_support_points) {
coord_t max_distance =
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
CenterLineConfiguration
/*CenterLineConfiguration
centerLineConfiguration(path.side_branches, config);
SupportIslandPoints samples = sample_center_line(path, centerLineConfiguration);
samples.front()->type = SupportIslandPoint::Type::center_line_end2;
return samples;
return samples;*/
}
// TODO: 3) Triangle of points
@ -812,26 +910,42 @@ SupportIslandPoints SampleIslandUtils::sample_expath(
SupportIslandPoints points; // result
if (neighbor->max_width() < config.max_width_for_center_support_line) {
// start sample center
done.insert(start_node);
coord_t support_in = config.minimal_distance_from_outline;
center_starts.push(CenterStart(neighbor, support_in));
coord_t width = 2 * config.minimal_distance_from_outline;
coord_t distance = config.maximal_distance_from_outline;
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 {
// start sample field
VoronoiGraph::Position field_start =
VoronoiGraphUtils::get_position_with_distance(
VoronoiGraphUtils::get_position_with_width(
neighbor, config.min_width_for_outline_support, lines);
sample_field(field_start, points, center_starts, done, lines, config);
}
// Main loop of sampling
while (!center_starts.empty()) {
std::optional<VoronoiGraph::Position> field_start = {};
std::vector<CenterStart> new_starts =
sample_center(center_starts.front(), config, done, points, lines, field_start);
center_starts.pop();
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);
}
std::optional<VoronoiGraph::Position> field_start =
sample_center(center_starts, done, points, lines, config);
while (field_start.has_value()) {
sample_field(*field_start, points, center_starts, done, lines, config);
field_start = sample_center(center_starts, done, points, lines, config);
}
return points;
}
@ -868,34 +982,54 @@ void SampleIslandUtils::sample_field(VoronoiGraph::Position &field_start,
});
}
std::vector<SampleIslandUtils::CenterStart> SampleIslandUtils::sample_center(
const CenterStart & start,
const SampleConfig & config,
std::optional<VoronoiGraph::Position> SampleIslandUtils::sample_center(
CenterStarts & new_starts,
std::set<const VoronoiGraph::Node *> &done,
SupportIslandPoints & results,
const Lines & lines,
std::optional<VoronoiGraph::Position> &field_start)
const SampleConfig & config)
{
const VoronoiGraph::Node::Neighbor *neighbor = start.neighbor;
const VoronoiGraph::Node *node = neighbor->node;
// already sampled line
if (done.find(node) != done.end()) return {};
VoronoiGraph::Nodes path = start.path;
std::vector<CenterStart> new_starts;
double support_in = start.support_in;
do {
double edge_length = neighbor->length();
const VoronoiGraph::Node::Neighbor *neighbor = nullptr;
VoronoiGraph::Nodes path;
coord_t support_in;
bool use_new_start = true;
bool is_continous = false;
while (use_new_start || neighbor->max_width() <= config.max_width_for_center_support_line) {
// !! do not check max width for new start, it could be wide to tiny change
if (use_new_start) {
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) {
double ratio = support_in / edge_length;
double ratio = support_in / neighbor->length();
VoronoiGraph::Position position(neighbor, ratio);
results.push_back(std::make_unique<SupportCenterIslandPoint>(
position, &config, SupportIslandPoint::Type::center_line));
support_in += config.max_distance;
is_continous = true;
}
support_in -= edge_length;
const VoronoiGraph::Node *node = neighbor->node;
path.push_back(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;
for (const auto &node_neighbor : node->neighbors) {
if (done.find(node_neighbor.node) != done.end()) continue;
@ -903,42 +1037,38 @@ std::vector<SampleIslandUtils::CenterStart> SampleIslandUtils::sample_center(
next_neighbor = &node_neighbor;
continue;
}
double next_support_in = (support_in < config.half_distance) ?
support_in : config.max_distance - support_in;
coord_t next_support_in = (support_in >= config.half_distance) ?
support_in : (config.max_distance - support_in);
new_starts.emplace_back(&node_neighbor, next_support_in, path); // search in side branch
}
if (next_neighbor == nullptr) {
// no neighbor to continue
if ((config.max_distance - support_in) >= config.minimal_support_distance) {
VoronoiGraph::Nodes path_reverse = path; // copy
std::reverse(path_reverse.begin(), path_reverse.end());
auto position_opt = create_position_on_path(
path_reverse, config.minimal_distance_from_outline);
assert(position_opt.has_value());
Point point = VoronoiGraphUtils::create_edge_point(
*position_opt);
results.push_back(std::make_unique<SupportIslandPoint>(
point, SupportIslandPoint::Type::center_line_end3));
VoronoiGraph::Nodes path_reverse = path; // copy
std::reverse(path_reverse.begin(), path_reverse.end());
coord_t width = 2 * config.minimal_distance_from_outline;
coord_t distance = config.maximal_distance_from_outline;
auto position_opt = create_position_on_path(path_reverse, lines, width, distance);
if (position_opt.has_value()) {
if (is_continous && config.max_distance < (support_in+distance) ) {
// one support point should be enough
// when max_distance > maximal_distance_from_outline
results.pop_back(); // remove support point
}
create_sample_center_end(*position_opt, results, new_starts, config);
}
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();
use_new_start = true;
} else {
neighbor = next_neighbor;
}
} while (neighbor->max_width() <= config.max_width_for_center_support_line);
}
// 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);
// sample rest of neighbor before field
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) {
double ratio = support_in / edge_length;
VoronoiGraph::Position position(neighbor, ratio);
@ -946,7 +1076,81 @@ std::vector<SampleIslandUtils::CenterStart> SampleIslandUtils::sample_center(
position, &config,SupportIslandPoint::Type::center_line));
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;
CenterStart tiny_start(neighbor, support_in, {source_node});
tiny_starts.push(tiny_start);
tiny_starts.push_back(tiny_start);
tiny_done.insert(source_node);
return true;
};
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);
add_wide_tiny_change(position, tiny_wide_neighbor->node);
@ -1078,7 +1282,8 @@ SampleIslandUtils::Field SampleIslandUtils::create_field(
field_line_indexes.insert(index2);
if (neighbor.min_width() < min_width) {
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))
continue;
}
@ -1194,7 +1399,7 @@ SampleIslandUtils::Field SampleIslandUtils::create_field(
field.source_indexe_for_change = source_indexe_for_change;
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";
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);
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;
}
@ -1406,6 +1611,7 @@ SupportIslandPoints SampleIslandUtils::sample_outline(
// initialize first index
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;
}

View File

@ -47,11 +47,21 @@ public:
/// <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 SupportIslandPointPtr create_point(
static SupportIslandPointPtr create_no_move_point(
const VoronoiGraph::Node::Neighbor *neighbor,
double ratio,
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>
/// Find point lay on path with distance from first point on path
/// </summary>
@ -63,7 +73,33 @@ public:
const VoronoiGraph::Nodes &path,
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,
double distance,
const SampleConfig & config,
@ -81,8 +117,19 @@ public:
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);
/// <summary>
/// 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
struct CenterLineConfiguration
@ -180,6 +227,7 @@ public:
/// <param name="config"> Sampling configuration
/// Maximal distance between neighbor points +
/// 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,
const ExPolygon & island,
const SampleConfig & config);
@ -192,7 +240,7 @@ public:
/// <param name="max_distance">Maximal search distance on VD for closest point</param>
/// <returns>Distance move of original point</returns>
static coord_t align_support(SupportIslandPoint &support, const Point &wanted, double max_distance);
/// <summary>
/// DTO hold information for start sampling VD in center
/// </summary>
@ -212,28 +260,44 @@ public:
: neighbor(neighbor), support_in(support_in), path(path)
{}
};
using CenterStarts = std::queue<CenterStart>;
using CenterStarts = std::vector<CenterStart>;
/// <summary>
/// Sample VG in center --> sample tiny part of island
/// Detection of wide neighbor which start field
/// Creating of new starts (from VG cross -> multi neighbors)
/// Sample until starts are empty or find new field(wide neighbor).
/// Creating of new starts (by VG cross -> multi neighbors)
/// </summary>
/// <param name="start">Start to sample</param>
/// <param name="config">Parameters for sampling</param>
/// <param name="done">Already done nodes</param>
/// <param name="done">Already done(processed) nodes</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="field_start">Output: Wide neighbor, start of field</param>
/// <returns>New start of sampling</returns>
static std::vector<CenterStart> sample_center(
const CenterStart & start,
const SampleConfig & config,
/// <param name="lines">Source line for VD. To decide position of change from tiny to wide part</param>
/// <param name="config">Parameters for sampling</param>
/// <returns>Wide neighbor, start of field when exists</returns>
static std::optional<VoronoiGraph::Position> sample_center(
CenterStarts & new_starts,
std::set<const VoronoiGraph::Node *> &done,
SupportIslandPoints & results,
const Lines &lines,
std::optional<VoronoiGraph::Position> &field_start);
const Lines & lines,
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>
/// DTO represents Wide parts of island to sample
/// extend polygon with information about source lines
@ -304,6 +368,7 @@ private:
// debug draw functions
public :
static bool is_visualization_disabled();
static void draw(SVG & svg,
const Field &field,
bool draw_border_line_indexes = false,

View File

@ -45,7 +45,8 @@ coord_t SupportIslandPoint::move(const Point &destination)
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::two_points,"two_points"},
{Type::center_line, "center_line"},
@ -59,8 +60,8 @@ std::string SupportIslandPoint::to_string(const Type &type)
{Type::outline, "outline"},
{Type::inner, "inner"},
{Type::undefined, "undefined"}};
auto it = type_to_tring.find(type);
if (it == type_to_tring.end()) return "UNDEFINED";
auto it = type_to_string.find(type);
if (it == type_to_string.end()) return undefined;
return it->second;
}

View File

@ -27,6 +27,8 @@ public:
static void sort_by(std::vector<T1> &data, std::function<T2(const T1 &)> &calc)
{
assert(!data.empty());
if (data.size() <= 1) return;
// initialize original index locations
std::vector<size_t> idx(data.size());
iota(idx.begin(), idx.end(), 0);

View File

@ -196,6 +196,15 @@ struct VoronoiGraph::Position
{}
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

View File

@ -255,7 +255,8 @@ Slic3r::Polygon VoronoiGraphUtils::to_polygon(const VD::cell_type & cell,
lines.push_back(*line);
} while ((edge = edge->next()) && edge != cell.incident_edge());
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
double min_distance = maximal_distance / 1000.;
size_t count_point = 6; // count added points
@ -865,17 +866,17 @@ VoronoiGraph::ExPath VoronoiGraphUtils::create_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();
for (const VoronoiGraph::Node::Neighbor &twin_neighbor : neighbor->node->neighbors) {
auto twin_edge = neighbor.edge->twin();
for (const VoronoiGraph::Node::Neighbor &twin_neighbor : neighbor.node->neighbors) {
if (twin_neighbor.edge == twin_edge) return &twin_neighbor;
}
assert(false);
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;
}
@ -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());
}
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)
{
VoronoiGraph::Position result(neighbor, 0.);
const VD::edge_type *edge = neighbor->edge;
if (edge->is_curved()) {
// Every point on curve has same distance from outline
// !!! NOT TRUE !!!
// Only same distance from point and line !!!
// TODO: Fix it
return result;
}
assert(edge->is_finite());
@ -1014,7 +1018,7 @@ VoronoiGraph::Position VoronoiGraphUtils::align(
const VoronoiGraph::Node::Neighbor* neighbor = position.neighbor;
double from_distance = neighbor->length() * position.ratio;
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);
}
double to_distance = neighbor->length() * (1 - position.ratio);
@ -1024,7 +1028,7 @@ VoronoiGraph::Position VoronoiGraphUtils::align(
}
if (process.empty()) {
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);
}
@ -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,
const VD::edge_type &edge,
const Lines & lines,

View File

@ -98,7 +98,7 @@ public:
static bool is_point_in_limits(const VD::vertex_type *vertex,
const Point & source,
double max_distance);
private:
/// <summary>
/// PRIVATE: function to help convert edge without vertex to line
/// </summary>
@ -109,13 +109,14 @@ public:
static Line create_line_between_source_points(
const Point &point1, const Point &point2, double maximal_distance);
public:
/// <summary>
/// Convert edge to line
/// only for line edge
/// crop infinite edge by maximal distance from source point
/// inspiration in VoronoiVisualUtils::clip_infinite_edge
/// </summary>
/// <param name="edge"></param>
/// <param name="edge">VD edge</param>
/// <param name="points">Source point for voronoi diagram</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>
@ -358,14 +359,14 @@ public:
/// </summary>
/// <param name="neighbor">neighbor</param>
/// <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>
/// Find source node of neighbor
/// </summary>
/// <param name="neighbor">neighbor</param>
/// <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>
/// 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="lines">Source lines for voronoi diagram</param>
/// <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,
coord_t width,
const Lines & lines);
@ -453,6 +454,17 @@ public:
/// <returns>True when neighbor node has only one neighbor</returns>
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
static void draw(SVG & svg,
const VoronoiGraph &graph,

View File

@ -460,7 +460,8 @@ SampleConfig create_sample_config(double size) {
cfg.max_distance = 3 * size + 0.1;
cfg.half_distance = cfg.max_distance/2;
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.minimal_support_distance = cfg.minimal_distance_from_outline + cfg.half_distance;
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.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.max_align_distance = 0;
return cfg;
@ -587,12 +588,7 @@ TEST_CASE("Small islands should be supported in center", "[SupGen], [VoronoiSkel
SampleConfig cfg = create_sample_config(size);
ExPolygons islands = createTestIslands(size);
// TODO: remove next 4 lines, debug sharp triangle
/*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};*/
islands = {islands[16]};
for (ExPolygon &island : islands) {
// information for debug which island cause problem
[[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>
TEST_CASE("Reorder destructive", "[Utils]"){
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
CHECK(false);
#endif // STORE_SAMPLE_INTO_SVG_FILES
CHECK(SampleIslandUtils::is_visualization_disabled());
}