Align of SP

This commit is contained in:
Filip Sykala 2021-03-24 05:51:16 +01:00 committed by Lukas Matena
parent e27734266f
commit 60a0ac46c2
14 changed files with 447 additions and 86 deletions

View File

@ -1,24 +1,18 @@
#include "LineUtils.hpp"
#include <libslic3r/Geometry.hpp>
#include <functional>
#include "VectorUtils.hpp"
using namespace Slic3r::sla;
// sort counter clock wise lines
void LineUtils::sort_CCW(Lines &lines, const Point& center)
{
using namespace Slic3r;
std::sort(lines.begin(), lines.end(), [&](const Line &l1, const Line &l2) {
Point p1 = l1.a - center;
Point p2 = l2.a - center;
if (p1.y() < 0) {
if (p2.y() > 0) return false;
return p1.x() < p2.x();
} else {
if (p2.y() < 0) return true;
return p1.x() > p2.x();
}
});
std::function<double(const Line &)> calc = [&center](const Line &line) {
Point p = line.a - center;
return std::atan2(p.y(), p.x());
};
VectorUtils::sort_by(lines, calc);
}
bool LineUtils::is_parallel_y(const Line &line) {

View File

@ -18,10 +18,10 @@ public:
LineUtils() = delete;
/// <summary>
/// Sort lines to be in counter clock wise order
/// Sort lines to be in counter clock wise order only by point Line::a and function std::atan2
/// </summary>
/// <param name="lines">Lines to sort</param>
/// <param name="center">Center for order</param>
/// <param name="lines">Lines to be sort</param>
/// <param name="center">Center for CCW order</param>
static void sort_CCW(Lines &lines, const Point &center);
/// <summary>

View File

@ -1,4 +1,5 @@
#include "PolygonUtils.hpp"
#include "libslic3r/Geometry.hpp"
using namespace Slic3r::sla;
@ -52,4 +53,14 @@ Slic3r::Polygon PolygonUtils::create_rect(double width, double height)
double x_2 = width / 2;
double y_2 = height / 2;
return {{-x_2, y_2}, {-x_2, -y_2}, {x_2, -y_2}, {x_2, y_2}};
}
bool PolygonUtils::is_ccw(const Polygon &polygon, const Point &center) {
const Point *prev = &polygon.points.back();
for (const Point &point : polygon.points) {
Geometry::Orientation o = Geometry::orient(center, *prev, point);
if (o != Geometry::Orientation::ORIENTATION_CCW) return false;
prev = &point;
}
return true;
}

View File

@ -63,6 +63,14 @@ public:
/// <param name="height">height</param>
/// <returns>Rectangle</returns>
static Polygon create_rect(double width, double height);
/// <summary>
/// check if all pairs on polygon create with center ccw triangle
/// </summary>
/// <param name="polygon">input polygon to check</param>
/// <param name="center">center point inside polygon</param>
/// <returns>True when all points in polygon are CCW with center</returns>
static bool is_ccw(const Polygon &polygon, const Point &center);
};
} // namespace Slic3r::sla
#endif // slic3r_SLA_SuppotstIslands_PolygonUtils_hpp_

View File

@ -35,9 +35,13 @@ struct SampleConfig
// Term criteria for end of alignment
// Minimal change in manhatn move of support position before termination
coord_t minimal_move = 1;
coord_t minimal_move = 1000; // in nanometers, devide from print resolution to quater pixel
// Maximal count of align iteration
size_t count_iteration = 100;
// Maximal distance over Voronoi diagram edges to find closest point during aligning Support point
double max_align_distance = 0;
};
} // namespace Slic3r::sla
#endif // slic3r_SLA_SuppotstIslands_SampleConfig_hpp_

View File

@ -65,6 +65,12 @@ public:
result.max_width_for_zig_zag_supportr_line = max_width_for_zig_zag_supportr_line;
assert(result.max_width_for_zig_zag_supportr_line < result.max_width_for_center_supportr_line);
// Align support points
// TODO: propagate print resolution
result.minimal_move = 1000; // [in nanometers], devide from print resolution to quater pixel
result.count_iteration = 100; // speed VS precission
result.max_align_distance = result.max_distance / 2;
return result;
}
};

View File

@ -6,21 +6,27 @@
#include "EvaluateNeighbor.hpp"
#include "ParabolaUtils.hpp"
#include "VoronoiGraphUtils.hpp"
#include "VectorUtils.hpp"
#include <magic_enum/magic_enum.hpp>
#include <libslic3r/VoronoiVisualUtils.hpp>
#include <libslic3r/ClipperUtils.hpp> // allign
// comment to enable assert()
// #define NDEBUG
#include <cassert>
using namespace Slic3r::sla;
SupportIslandPoint SampleIslandUtils::create_point(
const VoronoiGraph::Node::Neighbor *neighbor,
double ratio,
SupportIslandPoint::Type type)
{
VoronoiGraph::Position position(neighbor, ratio);
Slic3r::Point p = VoronoiGraphUtils::get_edge_point(neighbor->edge, ratio);
Slic3r::Point p = VoronoiGraphUtils::create_edge_point(position);
return SupportIslandPoint(p, type, position);
}
@ -86,7 +92,7 @@ SupportIslandPoints SampleIslandUtils::sample_side_branch(
VoronoiGraph::Nodes reverse_path = side_path.nodes;
std::reverse(reverse_path.begin(), reverse_path.end());
reverse_path.push_back(first_node);
return {create_point_on_path(reverse_path, cfg.side_distance)};
return {create_point_on_path(reverse_path, cfg.side_distance, SupportIslandPoint::Type::center_line_end)};
}
// count of segment between points on main path
size_t segment_count = static_cast<size_t>(
@ -122,6 +128,7 @@ SupportIslandPoints SampleIslandUtils::sample_side_branch(
prev_node = node;
}
assert(fabs(distance - (sample_distance - cfg.side_distance)) < 1e-5);
result.back().type = SupportIslandPoint::Type::center_line_end;
return result;
}
@ -180,34 +187,54 @@ std::vector<std::set<const VoronoiGraph::Node *>> create_circles_sets(
Slic3r::Points SampleIslandUtils::to_points(const SupportIslandPoints &support_points)
{
Slic3r::Points points;
points.reserve(support_points.size());
std::transform(support_points.begin(), support_points.end(),
std::back_inserter(points),
[](const SupportIslandPoint &p) {
return p.point; });
return points;
std::function<Point(const SupportIslandPoint &)> transform_func = &SupportIslandPoint::point;
return VectorUtils::transform(support_points, transform_func);
}
void SampleIslandUtils::align_samples(SupportIslandPoints &samples,
const ExPolygon & island,
const SampleConfig & config)
{
assert(samples.size() > 2);
size_t count_iteration = config.count_iteration; // copy
coord_t max_move = 0;
while (--count_iteration > 1) {
coord_t max_move = align_once(samples, island, config);
max_move = align_once(samples, island, config);
if (max_move < config.minimal_move) break;
}
//std::cout << "Align use " << config.count_iteration - count_iteration
// << " iteration and finish with precision " << max_move << "nano meters" << std::endl;
}
bool is_points_in_distance(const Slic3r::Point & p,
const Slic3r::Points &points,
double max_distance)
{
for (const auto &p2 : points) {
double d = (p - p2).cast<double>().norm();
if (d > max_distance) return false;
}
return true;
}
//#define VISUALIZE_SAMPLE_ISLAND_UTILS_ALIGN_ONCE
coord_t SampleIslandUtils::align_once(SupportIslandPoints &samples,
const ExPolygon & island,
const SampleConfig & config)
{
assert(samples.size() > 2);
using VD = Slic3r::Geometry::VoronoiDiagram;
VD vd;
Slic3r::Points points = SampleIslandUtils::to_points(samples);
#ifdef VISUALIZE_SAMPLE_ISLAND_UTILS_ALIGN_ONCE
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
// create voronoi diagram with points
construct_voronoi(points.begin(), points.end(), &vd);
coord_t max_move = 0;
@ -223,16 +250,35 @@ coord_t SampleIslandUtils::align_once(SupportIslandPoints &samples,
break;
}
}
assert(island_cell != nullptr);
Point center = island_cell->centroid();
Point move = center - sample.point;
coord_t act_move = move.x() + move.y(); // manhatn distance
assert(island_cell != nullptr);
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
coord_t act_move = align_support(sample, center, config.max_align_distance);
if (max_move < act_move) max_move = act_move;
}
return max_move;
}
coord_t SampleIslandUtils::align_support(SupportIslandPoint &support,
const Point & wanted,
double max_distance)
{
//move only along VD
VoronoiGraph::Position position =
VoronoiGraphUtils::align(support.position, wanted, max_distance);
Point new_point = VoronoiGraphUtils::create_edge_point(position);
Point move = new_point - support.point;
support.position= position;
support.point = new_point;
return abs(move.x()) + abs(move.y());
}
SupportIslandPoints SampleIslandUtils::sample_center_line(
const VoronoiGraph::ExPath &path, const CenterLineConfiguration &cfg)
{
@ -570,8 +616,9 @@ SupportIslandPoints SampleIslandUtils::sample_expath(
2 * config.minimal_distance_from_outline,
config.max_distance,
config.minimal_distance_from_outline);
return sample_center_line(path, centerLineConfiguration);
SupportIslandPoints samples = sample_center_line(path, centerLineConfiguration);
samples.front().type = SupportIslandPoint::Type::center_line_end2;
return samples;
}
// line of zig zag points

View File

@ -135,7 +135,7 @@ public:
/// keep same distances between support points
/// call once align
/// </summary>
/// <param name="samples">In/Out support points to be alligned</param>
/// <param name="samples">In/Out support points to be alligned(min 3 points)</param>
/// <param name="island">Area for sampling, border for position of samples</param>
/// <param name="config"> Sampling configuration
/// Maximal distance between neighbor points +
@ -147,7 +147,7 @@ public:
/// <summary>
/// once align
/// </summary>
/// <param name="samples">In/Out support points to be alligned</param>
/// <param name="samples">In/Out support points to be alligned(min 3 points)</param>
/// <param name="island">Area for sampling, border for position of samples</param>
/// <param name="config"> Sampling configuration
/// Maximal distance between neighbor points +
@ -156,6 +156,15 @@ public:
const ExPolygon & island,
const SampleConfig & config);
/// <summary>
/// Align support point the closest to Wanted point
/// </summary>
/// <param name="support">In/Out support point, contain restriction for move</param>
/// <param name="center">Wanted position point</param>
/// <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);
static void draw(SVG & svg,
const SupportIslandPoints &supportIslandPoints,
double size,

View File

@ -16,9 +16,11 @@ struct SupportIslandPoint
one_center_point,
two_points,
center_line,
center_line_end, // end of branch
center_line_end2, // start of main path(only one per VD)
center_circle,
center_circle_end,
center_circle_end2,
center_circle_end, // circle finish by one point (one end per circle - need allign)
center_circle_end2, // circle finish by multi points (one end per circle - need allign)
undefined
};
@ -52,7 +54,9 @@ struct SupportIslandPoint
static const std::set<Type> cant_move({
Type::one_center_point,
Type::two_points
Type::two_points,
Type::center_line_end,
Type::center_line_end2
});
return cant_move.find(type) == cant_move.end();

View File

@ -0,0 +1,128 @@
#ifndef slic3r_SLA_SuppotstIslands_VectorUtils_hpp_
#define slic3r_SLA_SuppotstIslands_VectorUtils_hpp_
#include <vector>
#include <algorithm>
#include <functional>
namespace Slic3r::sla {
/// <summary>
/// Class which contain collection of static function
/// for work with std vector
/// QUESTION: Is it only for SLA?
/// </summary>
class VectorUtils
{
public:
VectorUtils() = delete;
/// <summary>
/// For sorting a vector by calculated value
/// CACHE for calculated values
/// </summary>
/// <param name="data">vetor to be sorted</param>
/// <param name="calc">function to calculate sorting value</param>
template<typename T1, typename T2>
static void sort_by(std::vector<T1> &data, std::function<T2(const T1 &)> &calc)
{
// initialize original index locations
std::vector<size_t> idx(data.size());
iota(idx.begin(), idx.end(), 0);
// values used for sort
std::vector<T2> v;
v.reserve(data.size());
for (const T1 &d : data) v.emplace_back(calc(d));
// sort indexes based on comparing values in v
// using std::stable_sort instead of std::sort
// to avoid unnecessary index re-orderings
// when v contains elements of equal values
std::stable_sort(idx.begin(), idx.end(), [&v](size_t i1, size_t i2) {
return v[i1] < v[i2];
});
reorder_destructive(idx.begin(), idx.end(), data.begin());
}
/// <summary>
/// shortcut to use std::transform with alocation for result
/// </summary>
/// <param name="data">vetor to be transformed</param>
/// <param name="transform_func">lambda to transform data types</param>
/// <returns>result vector</returns>
template<typename T1, typename T2>
static std::vector<T2> transform(const std::vector<T1> &data, std::function<T2(const T1 &)> &transform_func)
{
std::vector<T2> result;
result.reserve(data.size());
std::transform(data.begin(), data.end(), std::back_inserter(result), transform_func);
return result;
}
/// <summary>
/// Reorder vector by indexes given by iterators
/// </summary>
/// <param name="order_begin">Start index</param>
/// <param name="order_end">Last index</param>
/// <param name="v">data to reorder. e.g. vector::begin()</param>
template<typename order_iterator, typename value_iterator>
static void reorder(order_iterator order_begin,
order_iterator order_end,
value_iterator v)
{
typedef typename std::iterator_traits<value_iterator>::value_type value_t;
typedef typename std::iterator_traits<order_iterator>::value_type index_t;
typedef typename std::iterator_traits<order_iterator>::difference_type diff_t;
diff_t remaining = order_end - 1 - order_begin;
for (index_t s = index_t(), d; remaining > 0; ++s) {
for (d = order_begin[s]; d > s; d = order_begin[d])
;
if (d == s) {
--remaining;
value_t temp = v[s];
while (d = order_begin[d], d != s) {
swap(temp, v[d]);
--remaining;
}
v[s] = temp;
}
}
}
/// <summary>
/// Same as function 'reorder' but destroy order vector for speed
/// </summary>
/// <param name="order_begin">Start index</param>
/// <param name="order_end">Last index</param>
/// <param name="v">data to reorder. e.g. vector::begin()</param>
template<typename order_iterator, typename value_iterator>
static void reorder_destructive(order_iterator order_begin,
order_iterator order_end,
value_iterator v)
{
typedef typename std::iterator_traits<value_iterator>::value_type value_t;
typedef typename std::iterator_traits<order_iterator>::value_type index_t;
typedef typename std::iterator_traits<order_iterator>::difference_type diff_t;
diff_t remaining = order_end - 1 - order_begin;
for (index_t s = index_t(); remaining > 0; ++s) {
index_t d = order_begin[s];
if (d == (diff_t) -1) continue;
--remaining;
value_t temp = v[s];
for (index_t d2; d != s; d = d2) {
std::swap(temp, v[d]);
std::swap(order_begin[d], d2 = (diff_t) -1);
--remaining;
}
v[s] = temp;
}
}
};
} // namespace Slic3r::sla
#endif // slic3r_SLA_SuppotstIslands_VectorUtils_hpp_

View File

@ -1,6 +1,7 @@
#include "VoronoiGraphUtils.hpp"
#include <cmath>
#include <set>
#include <libslic3r/VoronoiOffset.hpp>
#include "IStackFunction.hpp"
#include "EvaluateNeighbor.hpp"
@ -11,7 +12,7 @@
#include <libslic3r/VoronoiVisualUtils.hpp>
#define SLA_CELL_2_POLYGON_DEBUG
//#define SLA_CELL_2_POLYGON_DEBUG
using namespace Slic3r::sla;
@ -31,6 +32,11 @@ Slic3r::Point VoronoiGraphUtils::to_point(const VD::vertex_type *vertex)
return Point(to_coord(vertex->x()), to_coord(vertex->y()));
}
Slic3r::Vec2d VoronoiGraphUtils::to_point_d(const VD::vertex_type *vertex)
{
return Vec2d(to_coord(vertex->x()), to_coord(vertex->y()));
}
bool VoronoiGraphUtils::is_coord_in_limits(const VD::coordinate_type &coord,
const coord_t & source,
double max_distance)
@ -120,27 +126,10 @@ std::optional<Slic3r::Line> VoronoiGraphUtils::to_line(
Point(p1.y() - p2.y(), p2.x() - p1.x());
const VD::vertex_type* edge_vertex = (use_v1) ? v1 : v0;
// koeficient for crop line
double koef = 1.;
if (!use_double_precision) {
// only half edges
Point vertex = to_point(edge_vertex);
/*// faster but less preciss version
double abs_max_dir = (std::max)(fabs(direction.x()),
fabs(direction.y())); return 2 * maximal_distance / abs_max_dir;
//*/
// slower but more precisse version
double dir_size = direction.cast<double>().operatorNorm();
Point middle = (p1 + p2) / 2;
Point to_middle = middle - vertex;
double to_middle_size = to_middle.cast<double>().operatorNorm();
double from_middle_size = sqrt(maximal_distance * maximal_distance -
to_middle_size * to_middle_size);
bool is_opposit = is_oposit_direction(direction, to_middle);
if (is_opposit) to_middle_size *= -1;
koef = (from_middle_size + to_middle_size) / dir_size;
Point line_point = vertex + direction * koef;
return Line(vertex, line_point);
Point ray_point = to_point(edge_vertex);
Line ray(ray_point, ray_point + direction);
return LineUtils::crop_half_ray(ray, p1, maximal_distance);
}
std::optional<Linef> segment;
if (use_both) {
@ -148,7 +137,7 @@ std::optional<Slic3r::Line> VoronoiGraphUtils::to_line(
segment = LineUtils::crop_line(edge_segment, p1, maximal_distance);
} else {
Vec2d ray_point(edge_vertex->x(), edge_vertex->y());
Linef ray = Linef(ray_point, ray_point + direction.cast<double>());
Linef ray(ray_point, ray_point + direction.cast<double>());
segment = LineUtils::crop_half_ray(ray, p1, maximal_distance);
}
if (!segment.has_value()) return {};
@ -196,7 +185,6 @@ Slic3r::Polygon VoronoiGraphUtils::to_polygon(const Lines &lines,
points.push_back(p1);
for (size_t i = 1; i < count_segment; i++) {
double angle = a1 + i*increase_angle;
double x = cos(angle) * maximal_distance + center.x();
assert(x < std::numeric_limits<coord_t>::max());
assert(x > std::numeric_limits<coord_t>::min());
@ -207,7 +195,23 @@ Slic3r::Polygon VoronoiGraphUtils::to_polygon(const Lines &lines,
}
points.push_back(p2);
}
return Polygon(points);
Polygon polygon(points);
assert(polygon.is_valid());
if (!polygon.contains(center)) {
SVG svg("bad_polygon.svg", {polygon.points});
svg.draw(polygon, "orange");
svg.draw(lines, "red");
int counter = 0;
for (auto &line : lines) {
++counter;
svg.draw_text(line.a, ("A"+std::to_string(counter)).c_str(), "lightgreen");
svg.draw_text(line.b, ("B" + std::to_string(counter)).c_str(), "lightblue");
}
svg.draw(center);
}
assert(polygon.contains(center));
assert(PolygonUtils::is_ccw(polygon, center));
return polygon;
}
Slic3r::Polygon VoronoiGraphUtils::to_polygon(const VD::cell_type & cell,
@ -229,9 +233,13 @@ Slic3r::Polygon VoronoiGraphUtils::to_polygon(const VD::cell_type & cell,
edge = edge->next();
continue;
}
Geometry::Orientation o = Geometry::orient(center, line->a, line->b);
assert(o != Geometry::Orientation::ORIENTATION_COLINEAR);
if (o == Geometry::Orientation::ORIENTATION_CW)
Geometry::Orientation orientation = Geometry::orient(center, line->a, line->b);
if (orientation == Geometry::Orientation::ORIENTATION_COLINEAR)
{ // on circle over source point edge
edge = edge->next();
continue;
}
if (orientation == Geometry::Orientation::ORIENTATION_CW)
std::swap(line->a, line->b);
lines.push_back(line.value());
edge = edge->next();
@ -411,7 +419,7 @@ double VoronoiGraphUtils::calculate_max_width(
return 2 * std::max(distance0, distance1);
}
VoronoiGraph VoronoiGraphUtils::getSkeleton(const VD &vd, const Lines &lines)
VoronoiGraph VoronoiGraphUtils::create_skeleton(const VD &vd, const Lines &lines)
{
// vd should be annotated.
// assert(Voronoi::debug::verify_inside_outside_annotations(vd));
@ -781,8 +789,14 @@ const VoronoiGraph::Node *VoronoiGraphUtils::get_twin_node(const VoronoiGraph::N
return nullptr;
}
Slic3r::Point VoronoiGraphUtils::get_edge_point(const VD::edge_type *edge,
double ratio)
Slic3r::Point VoronoiGraphUtils::create_edge_point(
const VoronoiGraph::Position &position)
{
return create_edge_point(position.neighbor->edge, position.ratio);
}
Slic3r::Point VoronoiGraphUtils::create_edge_point(const VD::edge_type *edge,
double ratio)
{
const VD::vertex_type *v0 = edge->vertex0();
const VD::vertex_type *v1 = edge->vertex1();
@ -807,6 +821,87 @@ Slic3r::Point VoronoiGraphUtils::get_edge_point(const VD::edge_type *edge,
return Point(v0->x() + dir.x(), v0->y() + dir.y());
}
VoronoiGraph::Position VoronoiGraphUtils::align(
const VoronoiGraph::Position &position, const Point &to, double max_distance)
{
// for each neighbor in max distance try align edge
struct NodeDistance
{
const VoronoiGraph::Node *node;
double distance; // distance to search for closest point
NodeDistance(const VoronoiGraph::Node *node, double distance)
: node(node), distance(distance)
{}
};
std::queue<NodeDistance> process;
const VoronoiGraph::Node::Neighbor* neighbor = position.neighbor;
double from_distance = neighbor->edge_length * position.ratio;
if (from_distance < max_distance) {
const VoronoiGraph::Node *from_node = VoronoiGraphUtils::get_twin_node(neighbor);
process.emplace(from_node, from_distance);
}
double to_distance = neighbor->edge_length * (1 - position.ratio);
if (to_distance < max_distance) {
const VoronoiGraph::Node *to_node = neighbor->node;
process.emplace(to_node, to_distance);
}
if (process.empty()) {
const VoronoiGraph::Node *node = (position.ratio < 0.5) ?
VoronoiGraphUtils::get_twin_node(neighbor) : neighbor->node;
process.emplace(node, max_distance);
}
double closest_distance = std::numeric_limits<double>::max();
VoronoiGraph::Position closest;
std::set<const VoronoiGraph::Node *> done;
while (!process.empty()) {
NodeDistance nd = process.front(); // copy
process.pop();
if (done.find(nd.node) != done.end()) continue;
done.insert(nd.node);
for (const auto &neighbor : nd.node->neighbors) {
if (done.find(neighbor.node) != done.end()) continue;
double ratio;
double distance = get_distance(*neighbor.edge, to, ratio);
if (closest_distance > distance) {
closest_distance = distance;
closest = VoronoiGraph::Position(&neighbor, ratio);
}
double from_start = nd.distance + neighbor.edge_length;
if (from_start < max_distance)
process.emplace(neighbor.node, from_start);
}
}
return closest;
}
double VoronoiGraphUtils::get_distance(const VD::edge_type &edge,
const Point & point,
double & edge_ratio)
{
// TODO: find closest point on curve edge
//if (edge.is_linear()) {
// get line foot point, inspired Geometry::foot_pt
Vec2d v0 = to_point_d(edge.vertex0());
Vec2d v = point.cast<double>() - v0;
Vec2d v1 = to_point_d(edge.vertex1());
Vec2d edge_dir = v1 - v0;
double l2 = edge_dir.squaredNorm();
edge_ratio = v.dot(edge_dir) / l2;
// IMPROVE: not neccesary to calculate point if (edge_ratio > 1 || edge_ratio < 0)
Point edge_point;
if (edge_ratio > 1.) edge_point = v1.cast<coord_t>();
else if (edge_ratio < 0.) edge_point = v0.cast<coord_t>();
else { // foot point
edge_point = (v0 + edge_dir * edge_ratio).cast<coord_t>();
}
double distance = (point - edge_point).cast<double>().norm();
return distance;
}
const VoronoiGraph::Node *VoronoiGraphUtils::getFirstContourNode(
const VoronoiGraph &graph)
{

View File

@ -34,12 +34,19 @@ public:
static coord_t to_coord(const VD::coordinate_type &coord);
/// <summary>
/// Convert Point type to slicer point
/// Convert Vodonoi diagram vertex type to Slicer Point
/// </summary>
/// <param name="vertex">Input point pointer</param>
/// <returns>When it is possible to convert than convert otherwise empty optional</returns>
/// <param name="vertex">Input point pointer(double precission)</param>
/// <returns>Convertedf point(int preccission)</returns>
static Slic3r::Point to_point(const VD::vertex_type *vertex);
/// <summary>
/// Convert point type between voronoi and slicer format
/// </summary>
/// <param name="vertex">Input vertex</param>
/// <returns>created vector</returns>
static Slic3r::Vec2d to_point_d(const VD::vertex_type* vertex);
/// <summary>
/// check if coord is in limits for coord_t
/// </summary>
@ -95,7 +102,7 @@ public:
/// <param name="maximal_distance">Radius around center point</param>
/// <param name="minimal_distance">Merge points closer than minimal_distance</param>
/// <param name="count_points">Count checking points, create help points for result polygon</param>
/// <returns>CCW polygon with center inside of polygon</returns>
/// <returns>Valid CCW polygon with center inside of polygon</returns>
static Slic3r::Polygon to_polygon(const Lines &lines,
const Point &center,
double maximal_distance,
@ -179,16 +186,7 @@ public:
/// (use function Slic3r::Voronoi::annotate_inside_outside)</param>
/// <param name="lines">Source lines for voronoi diagram</param>
/// <returns>Extended voronoi graph by distances and length</returns>
static VoronoiGraph getSkeleton(const VD &vd, const Lines &lines);
/// <summary>
/// For generating support point in distance from node
/// </summary>
/// <param name="node">Node lay on outline with only one neighbor</param>
/// <param name="padding">Distance from outline</param>
/// <returns></returns>
static Slic3r::Point get_offseted_point(const VoronoiGraph::Node &node,
double padding);
static VoronoiGraph create_skeleton(const VD &vd, const Lines &lines);
/// <summary>
/// find neighbor and return distance between nodes
@ -299,7 +297,35 @@ public:
/// Create point on edge defined by neighbor
/// in distance defined by edge length ratio
/// </summary>
static Point get_edge_point(const VD::edge_type *edge, double ratio);
/// <param name="position">Containe neighbor and position ratio on neighbor</param>
/// <returns>Point laying on neighbor edge</returns>
static Point create_edge_point(const VoronoiGraph::Position& position);
static Point create_edge_point(const VD::edge_type *edge, double ratio);
/// <summary>
/// align "position" close to point "to"
/// </summary>
/// <param name="position">input position on VD</param>
/// <param name="to">point to align</param>
/// <param name="max_distance">maximal distance on VD for search point</param>
/// <returns>Position on VD</returns>
static VoronoiGraph::Position align(const VoronoiGraph::Position &position,
const Point & to,
double max_distance);
/// <summary>
/// Calc position by ratio to closest point laying on edge
/// </summary>
/// <param name="edge">edge to align</param>
/// <param name="point">point to align</param>
/// <param name="edge_ratio">output: ratio between vertex0 and vertex1 closest to point,
/// when less than zero vertex0 is closest point on edge
/// when grater than one vertex1 is closest point on edge</param>
/// <returns>distance edge to "to" point
/// only when result ratio is in range from 0 to 1 </returns>
static double get_distance(const VD::edge_type &edge,
const Point & point,
double & edge_ratio);
static const VoronoiGraph::Node *getFirstContourNode(
const VoronoiGraph &graph);

View File

@ -321,8 +321,8 @@ SupportIslandPoints test_island_sampling(const ExPolygon & island,
const SampleConfig &config)
{
auto points = SupportPointGenerator::uniform_cover_island(island, config);
Points chck_points = rasterize(island, config.head_radius); // TODO: Use resolution of printer
Points chck_points = rasterize(island, config.head_radius); // TODO: Use resolution of printer
bool is_ok = true;
double max_distance = config.max_distance;
std::vector<double> point_distances(chck_points.size(),
@ -353,7 +353,7 @@ SupportIslandPoints test_island_sampling(const ExPolygon & island,
for (const Point &pt : island.contour.points) bb.merge(pt);
SVG svg("Error" + std::to_string(++counter) + ".svg", bb);
svg.draw(island, "blue", 0.5f);
for (auto p : points)
for (auto& p : points)
svg.draw(p.point, "lightgreen", config.head_radius);
for (size_t index = 0; index < chck_points.size(); ++index) {
const Point &chck_point = chck_points[index];
@ -380,6 +380,10 @@ SampleConfig create_sample_config(double size) {
cfg.max_length_for_two_support_points = 4*size;
cfg.max_width_for_center_supportr_line = size;
cfg.max_width_for_zig_zag_supportr_line = 2*size;
cfg.minimal_move = std::max(1000., size/1000);
cfg.count_iteration = 100;
cfg.max_align_distance = 0;
return cfg;
}
@ -403,17 +407,41 @@ TEST_CASE("Sampling speed test on FrogLegs", "[VoronoiSkeleton]")
for (int i = 0; i < 100; ++i) {
VoronoiGraph::ExPath longest_path;
VoronoiGraph skeleton = VoronoiGraphUtils::getSkeleton(vd, lines);
VoronoiGraph skeleton = VoronoiGraphUtils::create_skeleton(vd, lines);
auto samples = SampleIslandUtils::sample_voronoi_graph(skeleton, cfg, longest_path);
}
}
TEST_CASE("Speed align", "[VoronoiSkeleton]")
{
SampleConfig cfg = create_sample_config(3e7);
cfg.max_align_distance = 1000;
cfg.count_iteration = 1000;
cfg.max_align_distance = 3e7;
double size = 3e7;
auto island = create_square_with_4holes(5 * size, 5 * size / 2 - size / 3);
using VD = Slic3r::Geometry::VoronoiDiagram;
VD vd;
Lines lines = to_lines(island);
construct_voronoi(lines.begin(), lines.end(), &vd);
Slic3r::Voronoi::annotate_inside_outside(vd, lines);
VoronoiGraph::ExPath longest_path;
VoronoiGraph skeleton = VoronoiGraphUtils::create_skeleton(vd, lines);
auto samples = SampleIslandUtils::sample_voronoi_graph(skeleton, cfg, longest_path);
for (int i = 0; i < 100; ++i) { auto sample_copy = samples; // copy
SampleIslandUtils::align_samples(sample_copy, island, cfg);
}
}
TEST_CASE("Small islands should be supported in center", "[SupGen][VoronoiSkeleton]")
{
double size = 3e7;
SampleConfig cfg = create_sample_config(size);
ExPolygons islands = createTestIslands(size);
for (auto &island : islands) {
for (ExPolygon &island : islands) {
size_t debug_index = &island - &islands.front();
auto points = test_island_sampling(island, cfg);
//cgal_test(points, island);
double angle = 3.14 / 3; // cca 60 degree

View File

@ -47,6 +47,7 @@ void check(Slic3r::Points points, double max_distance) {
TEST_CASE("Polygon from cell", "[Voronoi]")
{
// for debug #define SLA_CELL_2_POLYGON_DEBUG in VoronoiGraphUtils
double max_distance = 1e7;
coord_t size = (int) (4e6);
coord_t half_size = size/2;