mirror of
https://git.mirrors.martin98.com/https://github.com/prusa3d/PrusaSlicer.git
synced 2025-08-14 06:45:56 +08:00
Align of SP
This commit is contained in:
parent
e27734266f
commit
60a0ac46c2
@ -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 = [¢er](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) {
|
||||
|
@ -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 ¢er);
|
||||
|
||||
/// <summary>
|
||||
|
@ -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 ¢er) {
|
||||
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;
|
||||
}
|
@ -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 ¢er);
|
||||
};
|
||||
} // namespace Slic3r::sla
|
||||
#endif // slic3r_SLA_SuppotstIslands_PolygonUtils_hpp_
|
||||
|
@ -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_
|
||||
|
@ -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;
|
||||
}
|
||||
};
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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();
|
||||
|
||||
|
128
src/libslic3r/SLA/SupportIslands/VectorUtils.hpp
Normal file
128
src/libslic3r/SLA/SupportIslands/VectorUtils.hpp
Normal 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_
|
@ -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)
|
||||
{
|
||||
|
@ -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 ¢er,
|
||||
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);
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
Loading…
x
Reference in New Issue
Block a user