mirror of
https://git.mirrors.martin98.com/https://github.com/prusa3d/PrusaSlicer.git
synced 2025-08-16 02:55:58 +08:00
Cell from over limit points
This commit is contained in:
parent
81f0ad8f63
commit
9c9880aba8
@ -1,9 +1,9 @@
|
||||
///|/ Copyright (c) Prusa Research 2016 - 2023 Vojtěch Bubník @bubnikv, Enrico Turri @enricoturri1966, Tomáš Mészáros @tamasmeszaros, Lukáš Matěna @lukasmatena, Filip Sykala @Jony01, Lukáš Hejl @hejllukas
|
||||
///|/ Copyright (c) Prusa Research 2016 - 2023 Vojt<EFBFBD>ch Bubn<62>k @bubnikv, Enrico Turri @enricoturri1966, Tom<6F> M<>sz<73>ros @tamasmeszaros, Luk<75> Mat<61>na @lukasmatena, Filip Sykala @Jony01, Luk<75> Hejl @hejllukas
|
||||
///|/ Copyright (c) 2017 Eyal Soha @eyal0
|
||||
///|/ Copyright (c) Slic3r 2013 - 2016 Alessandro Ranellucci @alranel
|
||||
///|/
|
||||
///|/ ported from lib/Slic3r/Geometry.pm:
|
||||
///|/ Copyright (c) Prusa Research 2017 - 2022 Vojtěch Bubník @bubnikv
|
||||
///|/ Copyright (c) Prusa Research 2017 - 2022 Vojt<EFBFBD>ch Bubn<62>k @bubnikv
|
||||
///|/ Copyright (c) Slic3r 2011 - 2015 Alessandro Ranellucci @alranel
|
||||
///|/ Copyright (c) 2013 Jose Luis Perez Diez
|
||||
///|/ Copyright (c) 2013 Anders Sundman
|
||||
@ -309,6 +309,39 @@ bool liang_barsky_line_clipping(
|
||||
return liang_barsky_line_clipping(x0clip, x1clip, bbox);
|
||||
}
|
||||
|
||||
// Ugly named variant, that accepts the squared line
|
||||
// Don't call me with a nearly zero length vector!
|
||||
template<typename T>
|
||||
int ray_circle_intersections_r2_lv2_c(T r2, T a, T b, T lv2, T c, std::pair<Eigen::Matrix<T, 2, 1, Eigen::DontAlign>, Eigen::Matrix<T, 2, 1, Eigen::DontAlign>> &out)
|
||||
{
|
||||
T x0 = - a * c / lv2;
|
||||
T y0 = - b * c / lv2;
|
||||
T d = r2 - c * c / lv2;
|
||||
if (d < T(0))
|
||||
return 0;
|
||||
T mult = sqrt(d / lv2);
|
||||
out.first.x() = x0 + b * mult;
|
||||
out.first.y() = y0 - a * mult;
|
||||
out.second.x() = x0 - b * mult;
|
||||
out.second.y() = y0 + a * mult;
|
||||
return mult == T(0) ? 1 : 2;
|
||||
}
|
||||
template<typename T>
|
||||
int ray_circle_intersections(T r, T a, T b, T c, std::pair<Eigen::Matrix<T, 2, 1, Eigen::DontAlign>, Eigen::Matrix<T, 2, 1, Eigen::DontAlign>> &out)
|
||||
{
|
||||
T lv2 = a * a + b * b;
|
||||
if (lv2 < T(SCALED_EPSILON * SCALED_EPSILON)) {
|
||||
//FIXME what is the correct epsilon?
|
||||
// What if the line touches the circle?
|
||||
return false;
|
||||
}
|
||||
return ray_circle_intersections_r2_lv2_c(r * r, a, b, a * a + b * b, c, out);
|
||||
}
|
||||
|
||||
Pointf3s convex_hull(Pointf3s points);
|
||||
Polygon convex_hull(Points points);
|
||||
Polygon convex_hull(const Polygons &polygons);
|
||||
|
||||
bool directions_parallel(double angle1, double angle2, double max_diff = 0);
|
||||
bool directions_perpendicular(double angle1, double angle2, double max_diff = 0);
|
||||
template<class T> bool contains(const std::vector<T> &vector, const Point &point);
|
||||
|
@ -1,4 +1,6 @@
|
||||
#include "LineUtils.hpp"
|
||||
#include <libslic3r/Geometry.hpp>
|
||||
#include <functional>
|
||||
|
||||
using namespace Slic3r::sla;
|
||||
|
||||
@ -18,3 +20,212 @@ void LineUtils::sort_CCW(Lines &lines, const Point& center)
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
bool LineUtils::is_parallel_y(const Line &line) {
|
||||
coord_t x_change = line.a.x() - line.b.x();
|
||||
return (x_change == 0);
|
||||
}
|
||||
bool LineUtils::is_parallel_y(const Linef &line)
|
||||
{
|
||||
double x_change = line.a.x() - line.b.x();
|
||||
return (fabs(x_change) < std::numeric_limits<double>::epsilon());
|
||||
}
|
||||
|
||||
std::optional<Slic3r::Line> LineUtils::crop_ray(const Line & ray,
|
||||
const Point ¢er,
|
||||
double radius)
|
||||
{
|
||||
if (is_parallel_y(ray)) {
|
||||
coord_t x = ray.a.x();
|
||||
coord_t diff = x - center.x();
|
||||
coord_t abs_diff = abs(diff);
|
||||
if (abs_diff > radius) return {};
|
||||
// create cross points
|
||||
double move_y = sqrt(radius * radius - (double) x * x);
|
||||
coord_t y = std::round(move_y);
|
||||
Point first(x, y);
|
||||
Point second(x,-y);
|
||||
return Line(first + center, second + center);
|
||||
} else {
|
||||
Line moved_line(ray.a - center, ray.b - center);
|
||||
double a, b, c;
|
||||
std::tie(a, b, c) = get_param(moved_line);
|
||||
std::pair<Vec2d, Vec2d> points;
|
||||
int count = Slic3r::Geometry::ray_circle_intersections(
|
||||
radius, a, b, c, points);
|
||||
if (count != 2) return {};
|
||||
return Line(points.first.cast<coord_t>() + center,
|
||||
points.second.cast<coord_t>() + center);
|
||||
}
|
||||
}
|
||||
std::optional<Slic3r::Linef> LineUtils::crop_ray(const Linef &ray,
|
||||
const Point ¢er,
|
||||
double radius)
|
||||
{
|
||||
Vec2d center_d = center.cast<double>();
|
||||
if (is_parallel_y(ray)) {
|
||||
double x = ray.a.x();
|
||||
double diff = x - center.x();
|
||||
double abs_diff = fabs(diff);
|
||||
if (abs_diff > radius) return {};
|
||||
// create cross points
|
||||
double y = sqrt(radius * radius - x * x);
|
||||
Vec2d first(x, y);
|
||||
Vec2d second(x, -y);
|
||||
return Linef(first + center_d,
|
||||
second + center_d);
|
||||
} else {
|
||||
Linef moved_line(ray.a - center_d, ray.b - center_d);
|
||||
double a, b, c;
|
||||
std::tie(a, b, c) = get_param(moved_line);
|
||||
std::pair<Vec2d, Vec2d> points;
|
||||
int count = Slic3r::Geometry::ray_circle_intersections(radius, a, b,
|
||||
c, points);
|
||||
if (count != 2) return {};
|
||||
return Linef(points.first + center_d, points.second + center_d);
|
||||
}
|
||||
}
|
||||
|
||||
std::optional<Slic3r::Line> LineUtils::crop_half_ray(const Line & half_ray,
|
||||
const Point ¢er,
|
||||
double radius)
|
||||
{
|
||||
auto segment = crop_ray(half_ray, center, radius);
|
||||
if (!segment.has_value()) return {};
|
||||
Point dir = half_ray.b - half_ray.a;
|
||||
using fnc = std::function<bool(const Point &)>;
|
||||
fnc use_point_x = [&half_ray, &dir](const Point &p) -> bool {
|
||||
return (p.x() > half_ray.a.x()) == (dir.x() > 0);
|
||||
};
|
||||
fnc use_point_y = [&half_ray, &dir](const Point &p) -> bool {
|
||||
return (p.y() > half_ray.a.y()) == (dir.y() > 0);
|
||||
};
|
||||
bool use_x = abs(dir.x()) > abs(dir.y());
|
||||
fnc use_point = (use_x) ? use_point_x : use_point_y;
|
||||
bool use_a = use_point(segment->a);
|
||||
bool use_b = use_point(segment->b);
|
||||
if (!use_a && !use_b) return {};
|
||||
if (use_a && use_b) return segment;
|
||||
return Line(half_ray.a, (use_a)?segment->a : segment->b);
|
||||
}
|
||||
|
||||
std::optional<Slic3r::Linef> LineUtils::crop_half_ray(const Linef & half_ray,
|
||||
const Point ¢er,
|
||||
double radius)
|
||||
{
|
||||
auto segment = crop_ray(half_ray, center, radius);
|
||||
if (!segment.has_value()) return {};
|
||||
Vec2d dir = half_ray.b - half_ray.a;
|
||||
using fnc = std::function<bool(const Vec2d &)>;
|
||||
fnc use_point_x = [&half_ray, &dir](const Vec2d &p) -> bool {
|
||||
return (p.x() > half_ray.a.x()) == (dir.x() > 0);
|
||||
};
|
||||
fnc use_point_y = [&half_ray, &dir](const Vec2d &p) -> bool {
|
||||
return (p.y() > half_ray.a.y()) == (dir.y() > 0);
|
||||
};
|
||||
bool use_x = fabs(dir.x()) > fabs(dir.y());
|
||||
fnc use_point = (use_x) ? use_point_x : use_point_y;
|
||||
bool use_a = use_point(segment->a);
|
||||
bool use_b = use_point(segment->b);
|
||||
if (!use_a && !use_b) return {};
|
||||
if (use_a && use_b) return segment;
|
||||
return Linef(half_ray.a, (use_a) ? segment->a : segment->b);
|
||||
}
|
||||
|
||||
std::optional<Slic3r::Line> LineUtils::crop_line(const Line & line,
|
||||
const Point ¢er,
|
||||
double radius)
|
||||
{
|
||||
auto segment = crop_ray(line, center, radius);
|
||||
if (!segment.has_value()) return {};
|
||||
|
||||
Point dir = line.b - line.a;
|
||||
using fnc = std::function<bool(const Point &)>;
|
||||
fnc use_point_x = [&line, &dir](const Point &p) -> bool {
|
||||
return (dir.x() > 0) ? (p.x() > line.a.x()) && (p.x() < line.b.x()) :
|
||||
(p.x() < line.a.x()) && (p.x() > line.b.x());
|
||||
};
|
||||
fnc use_point_y = [&line, &dir](const Point &p) -> bool {
|
||||
return (dir.y() > 0) ? (p.y() > line.a.y()) && (p.y() < line.b.y()) :
|
||||
(p.y() < line.a.y()) && (p.y() > line.b.y());
|
||||
};
|
||||
bool use_x = abs(dir.x()) > abs(dir.y());
|
||||
fnc use_point = (use_x) ? use_point_x : use_point_y;
|
||||
bool use_a = use_point(segment->a);
|
||||
bool use_b = use_point(segment->b);
|
||||
if (!use_a && !use_b) return {};
|
||||
if (use_a && use_b) return segment;
|
||||
bool same_dir = (use_x) ?
|
||||
((dir.x() > 0) == (segment->b.x() - segment->a.x()) > 0) :
|
||||
((dir.y() > 0) == (segment->b.y() - segment->a.y()) > 0) ;
|
||||
if (use_a) {
|
||||
if (same_dir)
|
||||
return Line(segment->a, line.b);
|
||||
else
|
||||
return Line(line.a, segment->a);
|
||||
} else { // use b
|
||||
if (same_dir)
|
||||
return Line(line.a, segment->b);
|
||||
else
|
||||
return Line(segment->b, line.b);
|
||||
}
|
||||
}
|
||||
|
||||
std::optional<Slic3r::Linef> LineUtils::crop_line(const Linef & line,
|
||||
const Point ¢er,
|
||||
double radius)
|
||||
{
|
||||
auto segment = crop_ray(line, center, radius);
|
||||
if (!segment.has_value()) return {};
|
||||
|
||||
Vec2d dir = line.b - line.a;
|
||||
using fnc = std::function<bool(const Vec2d &)>;
|
||||
fnc use_point_x = [&line, &dir](const Vec2d &p) -> bool {
|
||||
return (dir.x() > 0) ? (p.x() > line.a.x()) && (p.x() < line.b.x()) :
|
||||
(p.x() < line.a.x()) && (p.x() > line.b.x());
|
||||
};
|
||||
fnc use_point_y = [&line, &dir](const Vec2d &p) -> bool {
|
||||
return (dir.y() > 0) ? (p.y() > line.a.y()) && (p.y() < line.b.y()) :
|
||||
(p.y() < line.a.y()) && (p.y() > line.b.y());
|
||||
};
|
||||
bool use_x = abs(dir.x()) > abs(dir.y());
|
||||
fnc use_point = (use_x) ? use_point_x : use_point_y;
|
||||
bool use_a = use_point(segment->a);
|
||||
bool use_b = use_point(segment->b);
|
||||
if (!use_a && !use_b) return {};
|
||||
if (use_a && use_b) return segment;
|
||||
bool same_dir = (use_x) ? ((dir.x() > 0) ==
|
||||
(segment->b.x() - segment->a.x()) > 0) :
|
||||
((dir.y() > 0) ==
|
||||
(segment->b.y() - segment->a.y()) > 0);
|
||||
if (use_a) {
|
||||
if (same_dir)
|
||||
return Linef(segment->a, line.b);
|
||||
else
|
||||
return Linef(line.a, segment->a);
|
||||
} else { // use b
|
||||
if (same_dir)
|
||||
return Linef(line.a, segment->b);
|
||||
else
|
||||
return Linef(segment->b, line.b);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
std::tuple<double, double, double> LineUtils::get_param(const Line &line) {
|
||||
Vector normal = line.normal();
|
||||
double a = normal.x();
|
||||
double b = normal.y();
|
||||
double c = -a * line.a.x() - b * line.a.y();
|
||||
return {a, b, c};
|
||||
}
|
||||
|
||||
std::tuple<double, double, double> LineUtils::get_param(const Linef &line)
|
||||
{
|
||||
Vec2d direction = line.b - line.a;
|
||||
Vec2d normal(-direction.y(), direction.x());
|
||||
double a = normal.x();
|
||||
double b = normal.y();
|
||||
double c = -a * line.a.x() - b * line.a.y();
|
||||
return {a, b, c};
|
||||
}
|
@ -1,6 +1,8 @@
|
||||
#ifndef slic3r_SLA_SuppotstIslands_LineUtils_hpp_
|
||||
#define slic3r_SLA_SuppotstIslands_LineUtils_hpp_
|
||||
|
||||
#include <optional>
|
||||
#include <tuple>
|
||||
#include <libslic3r/Line.hpp>
|
||||
|
||||
namespace Slic3r::sla {
|
||||
@ -21,6 +23,64 @@ public:
|
||||
/// <param name="lines">Lines to sort</param>
|
||||
/// <param name="center">Center for order</param>
|
||||
static void sort_CCW(Lines &lines, const Point ¢er);
|
||||
|
||||
/// <summary>
|
||||
/// Create line segment intersection of line and circle
|
||||
/// </summary>
|
||||
/// <param name="line">Input line.</param>
|
||||
/// <param name="center">Circle center.</param>
|
||||
/// <param name="radius">Circle radius.</param>
|
||||
/// <returns>Chord -> line segment inside circle</returns>
|
||||
static std::optional<Slic3r::Line> crop_line(const Line & line,
|
||||
const Point ¢er,
|
||||
double radius);
|
||||
static std::optional<Slic3r::Linef> crop_line(const Linef & line,
|
||||
const Point ¢er,
|
||||
double radius);
|
||||
/// <summary>
|
||||
/// Create line segment intersection of ray and circle, when exist
|
||||
/// </summary>
|
||||
/// <param name="ray">Input ray.</param>
|
||||
/// <param name="center">Circle center.</param>
|
||||
/// <param name="radius">Circle radius.</param>
|
||||
/// <returns>Chord -> line segment inside circle</returns>
|
||||
static std::optional<Slic3r::Line> crop_ray(const Line & ray,
|
||||
const Point ¢er,
|
||||
double radius);
|
||||
static std::optional<Slic3r::Linef> crop_ray(const Linef & ray,
|
||||
const Point ¢er,
|
||||
double radius);
|
||||
/// <summary>
|
||||
/// Create line segment intersection of half ray(start point and direction) and circle, when exist
|
||||
/// </summary>
|
||||
/// <param name="half_ray">Use Line::a as start point and Line::b as direction but no limit</param>
|
||||
/// <param name="center">Circle center.</param>
|
||||
/// <param name="radius">Circle radius.</param>
|
||||
/// <returns>Chord -> line segment inside circle</returns>
|
||||
static std::optional<Slic3r::Line> crop_half_ray(const Line & half_ray,
|
||||
const Point ¢er,
|
||||
double radius);
|
||||
static std::optional<Slic3r::Linef> crop_half_ray(const Linef & half_ray,
|
||||
const Point ¢er,
|
||||
double radius);
|
||||
|
||||
/// <summary>
|
||||
/// check if line is parallel to Y
|
||||
/// </summary>
|
||||
/// <param name="line">Input line</param>
|
||||
/// <returns>True when parallel otherwise FALSE</returns>
|
||||
static bool is_parallel_y(const Line &line);
|
||||
static bool is_parallel_y(const Linef &line);
|
||||
|
||||
/// <summary>
|
||||
/// Create parametric coeficient
|
||||
/// ax + by + c = 0
|
||||
/// Can't be parallel to Y axis - check by function is_parallel_y
|
||||
/// </summary>
|
||||
/// <param name="line">Input line - cant be parallel with y axis</param>
|
||||
/// <returns>a, b, c</returns>
|
||||
static std::tuple<double, double, double> get_param(const Line &line);
|
||||
static std::tuple<double, double, double> get_param(const Linef &line);
|
||||
};
|
||||
|
||||
} // namespace Slic3r::sla
|
||||
|
55
src/libslic3r/SLA/SupportIslands/PolygonUtils.cpp
Normal file
55
src/libslic3r/SLA/SupportIslands/PolygonUtils.cpp
Normal file
@ -0,0 +1,55 @@
|
||||
#include "PolygonUtils.hpp"
|
||||
|
||||
using namespace Slic3r::sla;
|
||||
|
||||
Slic3r::Polygon PolygonUtils::create_regular(size_t count_points,
|
||||
double radius,
|
||||
const Point ¢er)
|
||||
{
|
||||
assert(radius >= 1.);
|
||||
assert(count_points >= 3);
|
||||
auto is_in_limits = [](double value) {
|
||||
return (value < std::numeric_limits<coord_t>::max()) &&
|
||||
(value > std::numeric_limits<coord_t>::min());
|
||||
};
|
||||
Points points;
|
||||
points.reserve(count_points);
|
||||
double increase_angle = 2 * M_PI / count_points;
|
||||
for (int i = 0; i < count_points; ++i) {
|
||||
double angle = i * increase_angle;
|
||||
double x = cos(angle) * radius + center.x();
|
||||
assert(is_in_limits(x));
|
||||
double y = sin(angle) * radius + center.y();
|
||||
assert(is_in_limits(y));
|
||||
points.emplace_back(x, y);
|
||||
}
|
||||
return Polygon(points);
|
||||
}
|
||||
|
||||
Slic3r::Polygon PolygonUtils::create_equilateral_triangle(double edge_size)
|
||||
{
|
||||
return {{.0, .0},
|
||||
{edge_size, .0},
|
||||
{edge_size / 2., sqrt(edge_size * edge_size - edge_size * edge_size / 4)}};
|
||||
}
|
||||
|
||||
Slic3r::Polygon PolygonUtils::create_isosceles_triangle(double side, double height)
|
||||
{
|
||||
return {{-side / 2, 0.}, {side / 2, 0.}, {.0, height}};
|
||||
}
|
||||
|
||||
Slic3r::Polygon PolygonUtils::create_square(double size)
|
||||
{
|
||||
double size_2 = size / 2;
|
||||
return {{-size_2, size_2},
|
||||
{-size_2, -size_2},
|
||||
{size_2, -size_2},
|
||||
{size_2, size_2}};
|
||||
}
|
||||
|
||||
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}};
|
||||
}
|
68
src/libslic3r/SLA/SupportIslands/PolygonUtils.hpp
Normal file
68
src/libslic3r/SLA/SupportIslands/PolygonUtils.hpp
Normal file
@ -0,0 +1,68 @@
|
||||
#ifndef slic3r_SLA_SuppotstIslands_PolygonUtils_hpp_
|
||||
#define slic3r_SLA_SuppotstIslands_PolygonUtils_hpp_
|
||||
|
||||
#include <libslic3r/Polygon.hpp>
|
||||
|
||||
namespace Slic3r::sla {
|
||||
/// <summary>
|
||||
/// Class which contain collection of static function
|
||||
/// for work with Polygon.
|
||||
/// </summary>
|
||||
class PolygonUtils
|
||||
{
|
||||
public:
|
||||
PolygonUtils() = delete;
|
||||
|
||||
/// <summary>
|
||||
/// Create regular polygon with N points
|
||||
/// </summary>
|
||||
/// <param name="count_points">Count points of regular polygon</param>
|
||||
/// <param name="radius">Radius around center</param>
|
||||
/// <param name="center">Center point</param>
|
||||
/// <returns>Regular Polygon with CCW points</returns>
|
||||
static Polygon create_regular(size_t count_points, double radius = 10., const Point& center = Point(0,0));
|
||||
|
||||
/// <summary>
|
||||
/// Create circle with N points
|
||||
/// alias for create regular
|
||||
/// </summary>
|
||||
/// <param name="radius">Radius of circle</param>
|
||||
/// <param name="count_points">Count points of circle</param>
|
||||
/// <param name="center">Center point</param>
|
||||
/// <returns>Regular Polygon with CCW points</returns>
|
||||
static Polygon create_circle(double radius, size_t count_points = 10, const Point& center = Point(0,0)){
|
||||
return create_regular(count_points, radius, center);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create triangle with same length for all sides
|
||||
/// </summary>
|
||||
/// <param name="edge_size">triangel edge size</param>
|
||||
/// <returns>Equilateral triangle</returns>
|
||||
static Polygon create_equilateral_triangle(double edge_size);
|
||||
|
||||
/// <summary>
|
||||
/// Create triangle with two side with same size
|
||||
/// </summary>
|
||||
/// <param name="side">Size of unique side</param>
|
||||
/// <param name="height">triangle height</param>
|
||||
/// <returns>Isosceles Triangle </returns>
|
||||
static Polygon create_isosceles_triangle(double side, double height);
|
||||
|
||||
/// <summary>
|
||||
/// Create squar with center in [0,0]
|
||||
/// </summary>
|
||||
/// <param name="size"></param>
|
||||
/// <returns>Square</returns>
|
||||
static Polygon create_square(double size);
|
||||
|
||||
/// <summary>
|
||||
/// Create rect with center in [0,0]
|
||||
/// </summary>
|
||||
/// <param name="width">width</param>
|
||||
/// <param name="height">height</param>
|
||||
/// <returns>Rectangle</returns>
|
||||
static Polygon create_rect(double width, double height);
|
||||
};
|
||||
} // namespace Slic3r::sla
|
||||
#endif // slic3r_SLA_SuppotstIslands_PolygonUtils_hpp_
|
@ -33,6 +33,11 @@ struct SampleConfig
|
||||
// Maximal width of line island supported by zig zag
|
||||
double max_width_for_zig_zag_supportr_line = 1.;
|
||||
|
||||
// Term criteria for end of alignment
|
||||
// Minimal change in manhatn move of support position before termination
|
||||
coord_t minimal_move = 1;
|
||||
// Maximal count of align iteration
|
||||
size_t count_iteration = 100;
|
||||
};
|
||||
} // namespace Slic3r::sla
|
||||
#endif // slic3r_SLA_SuppotstIslands_SampleConfig_hpp_
|
||||
|
@ -10,6 +10,8 @@
|
||||
#include <magic_enum/magic_enum.hpp>
|
||||
#include <libslic3r/VoronoiVisualUtils.hpp>
|
||||
|
||||
#include <libslic3r/ClipperUtils.hpp> // allign
|
||||
|
||||
using namespace Slic3r::sla;
|
||||
|
||||
SupportIslandPoint SampleIslandUtils::create_point(
|
||||
@ -187,18 +189,48 @@ Slic3r::Points SampleIslandUtils::to_points(const SupportIslandPoints &support_p
|
||||
return points;
|
||||
}
|
||||
|
||||
void SampleIslandUtils::align_samples(SupportIslandPoints &samples, double max_distance)
|
||||
void SampleIslandUtils::align_samples(SupportIslandPoints &samples,
|
||||
const ExPolygon & island,
|
||||
const SampleConfig & config)
|
||||
{
|
||||
size_t count_iteration = config.count_iteration; // copy
|
||||
while (--count_iteration > 1) {
|
||||
coord_t max_move = align_once(samples, island, config);
|
||||
if (max_move < config.minimal_move) break;
|
||||
}
|
||||
}
|
||||
|
||||
coord_t SampleIslandUtils::align_once(SupportIslandPoints &samples,
|
||||
const ExPolygon & island,
|
||||
const SampleConfig & config)
|
||||
{
|
||||
using VD = Slic3r::Geometry::VoronoiDiagram;
|
||||
VD vd;
|
||||
VD vd;
|
||||
Slic3r::Points points = SampleIslandUtils::to_points(samples);
|
||||
construct_voronoi(points.begin(), points.end(), &vd);
|
||||
for (const VD::cell_type &cell : vd.cells()) {
|
||||
SupportIslandPoint& sample = samples[cell.source_index()];
|
||||
Polygon polygon = VoronoiGraphUtils::to_polygon(cell, points, max_distance);
|
||||
|
||||
}
|
||||
// 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()) {
|
||||
SupportIslandPoint &sample = samples[cell.source_index()];
|
||||
if (!sample.can_move()) continue;
|
||||
Polygon polygon = VoronoiGraphUtils::to_polygon(cell, points, config.max_distance);
|
||||
Polygons intersections = Slic3r::intersection(island, ExPolygon(polygon));
|
||||
const Polygon *island_cell = nullptr;
|
||||
for (const Polygon &intersection : intersections) {
|
||||
if (intersection.contains(sample.point)) {
|
||||
island_cell = &intersection;
|
||||
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
|
||||
if (max_move < act_move) max_move = act_move;
|
||||
}
|
||||
return max_move;
|
||||
}
|
||||
|
||||
SupportIslandPoints SampleIslandUtils::sample_center_line(
|
||||
@ -214,8 +246,6 @@ SupportIslandPoints SampleIslandUtils::sample_center_line(
|
||||
|
||||
if (path.circles.empty()) return result;
|
||||
sample_center_circles(path, cfg, result);
|
||||
|
||||
align_samples(result, cfg.max_sample_distance);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
@ -133,10 +133,28 @@ public:
|
||||
|
||||
/// <summary>
|
||||
/// keep same distances between support points
|
||||
/// call once align
|
||||
/// </summary>
|
||||
/// <param name="result">In/Out vector of support points</param>
|
||||
/// <param name="max_distance">Maximal distance between neighbor points</param>
|
||||
static void align_samples(SupportIslandPoints &samples, double max_distance);
|
||||
/// <param name="samples">In/Out support points to be alligned</param>
|
||||
/// <param name="island">Area for sampling, border for position of samples</param>
|
||||
/// <param name="config"> Sampling configuration
|
||||
/// Maximal distance between neighbor points +
|
||||
/// Term criteria for align: Minimal sample move and Maximal count of iteration</param>
|
||||
static void align_samples(SupportIslandPoints &samples,
|
||||
const ExPolygon & island,
|
||||
const SampleConfig &config);
|
||||
|
||||
/// <summary>
|
||||
/// once align
|
||||
/// </summary>
|
||||
/// <param name="samples">In/Out support points to be alligned</param>
|
||||
/// <param name="island">Area for sampling, border for position of samples</param>
|
||||
/// <param name="config"> Sampling configuration
|
||||
/// Maximal distance between neighbor points +
|
||||
/// Term criteria for align: Minimal sample move and Maximal count of iteration</param>
|
||||
static coord_t align_once(SupportIslandPoints &samples,
|
||||
const ExPolygon & island,
|
||||
const SampleConfig & config);
|
||||
|
||||
static void draw(SVG & svg,
|
||||
const SupportIslandPoints &supportIslandPoints,
|
||||
|
@ -1,6 +1,7 @@
|
||||
#ifndef slic3r_SLA_SuppotstIslands_SupportIslandPoint_hpp_
|
||||
#define slic3r_SLA_SuppotstIslands_SupportIslandPoint_hpp_
|
||||
|
||||
#include <set>
|
||||
#include <libslic3r/Point.hpp>
|
||||
#include "VoronoiGraph.hpp"
|
||||
|
||||
@ -34,6 +35,29 @@ struct SupportIslandPoint
|
||||
VoronoiGraph::Position position)
|
||||
: point(std::move(point)), type(type), position(position)
|
||||
{}
|
||||
|
||||
bool can_move() const{
|
||||
// use shorter list
|
||||
/*
|
||||
|
||||
static const std::set<Type> can_move({
|
||||
Type::center_line,
|
||||
Type::center_circle,
|
||||
Type::center_circle_end,
|
||||
Type::center_circle_end2
|
||||
});
|
||||
return can_move.find(type) != can_move.end();
|
||||
|
||||
/*/
|
||||
|
||||
static const std::set<Type> cant_move({
|
||||
Type::one_center_point,
|
||||
Type::two_points
|
||||
});
|
||||
return cant_move.find(type) == cant_move.end();
|
||||
|
||||
//*/
|
||||
}
|
||||
};
|
||||
|
||||
using SupportIslandPoints = std::vector<SupportIslandPoint>;
|
||||
|
@ -7,22 +7,53 @@
|
||||
#include "ParabolaUtils.hpp"
|
||||
#include "LineUtils.hpp"
|
||||
#include "PointUtils.hpp"
|
||||
#include "PolygonUtils.hpp"
|
||||
|
||||
#include <libslic3r/VoronoiVisualUtils.hpp>
|
||||
|
||||
#define SLA_CELL_2_POLYGON_DEBUG
|
||||
|
||||
using namespace Slic3r::sla;
|
||||
|
||||
Slic3r::Line VoronoiGraphUtils::to_line(const VD::edge_type &edge) {
|
||||
assert(edge.is_linear());
|
||||
assert(edge.is_finite());
|
||||
return Line(Point(edge.vertex0()->x(), edge.vertex0()->y()),
|
||||
Point(edge.vertex1()->x(), edge.vertex1()->y()));
|
||||
coord_t VoronoiGraphUtils::to_coord(const VD::coordinate_type &coord)
|
||||
{
|
||||
static const VD::coordinate_type min_val =
|
||||
static_cast<VD::coordinate_type>(std::numeric_limits<coord_t>::min());
|
||||
static const VD::coordinate_type max_val =
|
||||
static_cast<VD::coordinate_type>(std::numeric_limits<coord_t>::max());
|
||||
if (coord > max_val) return std::numeric_limits<coord_t>::max();
|
||||
if (coord < min_val) return std::numeric_limits<coord_t>::min();
|
||||
return static_cast<coord_t>(std::round(coord));
|
||||
}
|
||||
|
||||
Slic3r::Point VoronoiGraphUtils::to_point(const VD::vertex_type *vertex)
|
||||
{
|
||||
return Point(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)
|
||||
{
|
||||
VD::coordinate_type min_val = source - max_distance;
|
||||
VD::coordinate_type max_val = source + max_distance;
|
||||
if (coord > max_val) return false;
|
||||
if (coord < min_val) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool VoronoiGraphUtils::is_point_in_limits(const VD::vertex_type *vertex,
|
||||
const Point & source,
|
||||
double max_distance)
|
||||
{
|
||||
if (vertex == nullptr) return false;
|
||||
return is_coord_in_limits(vertex->x(), source.x(), max_distance) &&
|
||||
is_coord_in_limits(vertex->y(), source.y(), max_distance);
|
||||
}
|
||||
|
||||
// create line segment between (in the middle) points. With size depend on their distance
|
||||
Slic3r::Line VoronoiGraphUtils::to_line(Point point1,
|
||||
Point point2,
|
||||
double maximal_distance)
|
||||
Slic3r::Line VoronoiGraphUtils::create_line_between_source_points(
|
||||
const Point &point1, const Point &point2, double maximal_distance)
|
||||
{
|
||||
Point middle = (point1 + point2) / 2;
|
||||
Point diff = point1 - point2;
|
||||
@ -44,57 +75,84 @@ bool is_oposit_direction(const Slic3r::Point &p1, const Slic3r::Point &p2) {
|
||||
return (p1.y() > 0) != (p2.y() > 0);
|
||||
}
|
||||
|
||||
Slic3r::Line VoronoiGraphUtils::to_line(const VD::edge_type & edge,
|
||||
const Points &points,
|
||||
double maximal_distance)
|
||||
std::optional<Slic3r::Line> VoronoiGraphUtils::to_line(
|
||||
const VD::edge_type &edge, const Points &points, double maximal_distance)
|
||||
{
|
||||
assert(edge.is_linear());
|
||||
assert(edge.is_primary());
|
||||
const Point &p1 = retrieve_point(points, *edge.cell());
|
||||
const Point &p2 = retrieve_point(points, *edge.twin()->cell());
|
||||
const VD::vertex_type *v0 = edge.vertex0();
|
||||
const VD::vertex_type *v1 = edge.vertex1();
|
||||
|
||||
if (edge.is_finite()) return to_line(edge);
|
||||
bool use_v1 = false; // v0 == nullptr or out of limits
|
||||
bool use_double_precision = false;
|
||||
bool use_both = false;
|
||||
if (edge.is_finite()) {
|
||||
bool is_v0_in_limit = is_point_in_limits(v0, p1, maximal_distance);
|
||||
bool is_v1_in_limit = is_point_in_limits(v1, p1, maximal_distance);
|
||||
if (!is_v0_in_limit) {
|
||||
use_v1 = true;
|
||||
if (!is_v1_in_limit) {
|
||||
use_double_precision = true;
|
||||
use_both = true;
|
||||
}
|
||||
} else if (is_v1_in_limit) {
|
||||
// normal full edge line segment
|
||||
return Line(to_point(v0), to_point(v1));
|
||||
}
|
||||
} else if (v0 == nullptr) {
|
||||
if (v1 == nullptr)
|
||||
{// both vertex are nullptr, create edge between points
|
||||
return create_line_between_source_points(p1, p2, maximal_distance);
|
||||
}
|
||||
if (!is_point_in_limits(v1, p1, maximal_distance))
|
||||
use_double_precision = true;
|
||||
use_v1 = true;
|
||||
} else if (!is_point_in_limits(v0, p1, maximal_distance)) {
|
||||
use_double_precision = true;
|
||||
if (v1 != nullptr)
|
||||
use_v1 = true; // v1 is in
|
||||
}
|
||||
|
||||
const VD::cell_type &cell1 = *edge.cell();
|
||||
const VD::cell_type &cell2 = *edge.twin()->cell();
|
||||
assert(cell1.contains_point());
|
||||
assert(cell2.contains_point());
|
||||
Point p1 = retrieve_point(points, cell1);
|
||||
Point p2 = retrieve_point(points, cell2);
|
||||
if (edge.vertex0() == nullptr && edge.vertex1() == nullptr)
|
||||
return to_line(p1, p2, maximal_distance);
|
||||
|
||||
bool is_v0_null = edge.vertex0() == nullptr;
|
||||
if (is_v0_null) std::swap(p1, p2);
|
||||
Point direction(p1.y() - p2.y(), p2.x() - p1.x());
|
||||
|
||||
auto get_koef = [&](const Point &v)->double {
|
||||
/*/
|
||||
// faster but less preciss version
|
||||
Point direction = (use_v1) ?
|
||||
Point(p2.y() - p1.y(), p1.x() - p2.x()) :
|
||||
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;
|
||||
|
||||
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 - v;
|
||||
double to_middle_size = to_middle.cast<double>().operatorNorm();
|
||||
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);
|
||||
if (is_oposit_direction(direction, to_middle)) to_middle_size *= -1;
|
||||
return (from_middle_size + to_middle_size)/dir_size;
|
||||
};
|
||||
|
||||
if (is_v0_null) {
|
||||
Point v1(edge.vertex1()->x(), edge.vertex1()->y());
|
||||
Point a = v1 + direction * get_koef(v1);
|
||||
return Line(a, v1);
|
||||
} else {
|
||||
Point v0(edge.vertex0()->x(), edge.vertex0()->y());
|
||||
Point b = v0 + direction * get_koef(v0);
|
||||
return Line(v0, b);
|
||||
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);
|
||||
}
|
||||
std::optional<Linef> segment;
|
||||
if (use_both) {
|
||||
Linef edge_segment(Vec2d(v0->x(), v0->y()), Vec2d(v1->x(), v1->y()));
|
||||
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>());
|
||||
segment = LineUtils::crop_half_ray(ray, p1, maximal_distance);
|
||||
}
|
||||
if (!segment.has_value()) return {};
|
||||
return Line(segment->a.cast<coord_t>(), segment->b.cast<coord_t>());
|
||||
}
|
||||
|
||||
Slic3r::Polygon VoronoiGraphUtils::to_polygon(const Lines &lines,
|
||||
@ -103,12 +161,14 @@ Slic3r::Polygon VoronoiGraphUtils::to_polygon(const Lines &lines,
|
||||
double minimal_distance,
|
||||
size_t count_points)
|
||||
{
|
||||
assert(lines.size() >= 1);
|
||||
assert(minimal_distance > 0.);
|
||||
assert(maximal_distance > minimal_distance);
|
||||
assert(count_points >= 3);
|
||||
if (lines.empty())
|
||||
return PolygonUtils::create_regular(count_points, maximal_distance, center);
|
||||
|
||||
Points points;
|
||||
points.reserve(lines.size());
|
||||
points.reserve(std::max(lines.size(), count_points));
|
||||
const Line *prev_line = &lines.back();
|
||||
double max_angle = 2 * M_PI / count_points;
|
||||
for (const Line &line : lines) {
|
||||
@ -136,13 +196,16 @@ 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;
|
||||
Point direction(
|
||||
static_cast<coord_t>(cos(angle) * maximal_distance),
|
||||
static_cast<coord_t>(sin(angle) * maximal_distance));
|
||||
points.push_back(center + direction);
|
||||
|
||||
double x = cos(angle) * maximal_distance + center.x();
|
||||
assert(x < std::numeric_limits<coord_t>::max());
|
||||
assert(x > std::numeric_limits<coord_t>::min());
|
||||
double y = sin(angle) * maximal_distance + center.y();
|
||||
assert(y < std::numeric_limits<coord_t>::max());
|
||||
assert(y > std::numeric_limits<coord_t>::min());
|
||||
points.emplace_back(x,y);
|
||||
}
|
||||
points.push_back(p2);
|
||||
|
||||
}
|
||||
return Polygon(points);
|
||||
}
|
||||
@ -152,16 +215,18 @@ Slic3r::Polygon VoronoiGraphUtils::to_polygon(const VD::cell_type & cell,
|
||||
double maximal_distance)
|
||||
{
|
||||
const VD::edge_type *edge = cell.incident_edge();
|
||||
|
||||
Lines lines;
|
||||
Point center = points[cell.source_index()];
|
||||
// Convenient way to iterate edges around Voronoi cell.
|
||||
do {
|
||||
assert(edge->is_linear());
|
||||
if (edge->is_primary()) {
|
||||
Line line = to_line(*edge, points, maximal_distance);
|
||||
if (!PointUtils::is_ccw(line.a, line.b, center)) std::swap(line.a, line.b);
|
||||
lines.push_back(line);
|
||||
std::optional<Line> line = to_line(*edge, points, maximal_distance);
|
||||
if (line.has_value()) {
|
||||
if (!PointUtils::is_ccw(line->a, line->b, center))
|
||||
std::swap(line->a, line->b);
|
||||
lines.push_back(line.value());
|
||||
}
|
||||
}
|
||||
edge = edge->next();
|
||||
} while (edge != cell.incident_edge());
|
||||
@ -170,7 +235,7 @@ Slic3r::Polygon VoronoiGraphUtils::to_polygon(const VD::cell_type & cell,
|
||||
double min_distance = maximal_distance / 1000.;
|
||||
size_t count_point = 6; // count added points
|
||||
Slic3r::Polygon polygon = to_polygon(lines, center, maximal_distance, min_distance, count_point);
|
||||
#ifdef SLA_SUPPORTPOINTGEN_DEBUG
|
||||
#ifdef SLA_CELL_2_POLYGON_DEBUG
|
||||
{
|
||||
std::cout << "cell " << cell.source_index() << " has " << lines.size() << "edges" << std::endl;
|
||||
BoundingBox bbox(center - Point(maximal_distance, maximal_distance),
|
||||
@ -188,7 +253,7 @@ Slic3r::Polygon VoronoiGraphUtils::to_polygon(const VD::cell_type & cell,
|
||||
}
|
||||
svg.draw(center, "red", maximal_distance / 100);
|
||||
}
|
||||
#endif /* SLA_SUPPORTPOINTGEN_DEBUG */
|
||||
#endif /* SLA_CELL_2_POLYGON_DEBUG */
|
||||
return polygon;
|
||||
}
|
||||
|
||||
@ -208,7 +273,7 @@ VoronoiGraph::Node *VoronoiGraphUtils::getNode(VoronoiGraph & graph,
|
||||
// const VD::cell_type * cell2 = edge.twin()->cell();
|
||||
const Line &line = lines[cell->source_index()];
|
||||
// const Line & line1 = lines[cell2->source_index()];
|
||||
Point point(vertex->x(), vertex->y());
|
||||
Point point = to_point(vertex);
|
||||
double distance = line.distance_to(point);
|
||||
|
||||
auto &[iterator,
|
||||
@ -229,9 +294,10 @@ Slic3r::Point VoronoiGraphUtils::retrieve_point(const Lines & lines,
|
||||
lines[cell.source_index()].b;
|
||||
}
|
||||
|
||||
Slic3r::Point VoronoiGraphUtils::retrieve_point(const Points & points,
|
||||
const VD::cell_type &cell)
|
||||
const Slic3r::Point &VoronoiGraphUtils::retrieve_point(
|
||||
const Points &points, const VD::cell_type &cell)
|
||||
{
|
||||
assert(cell.contains_point());
|
||||
assert(cell.source_category() == boost::polygon::SOURCE_CATEGORY_SINGLE_POINT);
|
||||
return points[cell.source_index()];
|
||||
}
|
||||
@ -273,8 +339,8 @@ double VoronoiGraphUtils::calculate_length_of_parabola(
|
||||
const VD::edge_type & edge,
|
||||
const Lines & lines)
|
||||
{
|
||||
Point v0{edge.vertex0()->x(), edge.vertex0()->y()};
|
||||
Point v1{edge.vertex1()->x(), edge.vertex1()->y()};
|
||||
Point v0 = to_point(edge.vertex0());
|
||||
Point v1 = to_point(edge.vertex1());
|
||||
ParabolaSegment parabola(get_parabola(edge, lines), v0, v1);
|
||||
return ParabolaUtils::length(parabola);
|
||||
}
|
||||
@ -296,8 +362,8 @@ double VoronoiGraphUtils::calculate_length(
|
||||
double VoronoiGraphUtils::calculate_max_width(
|
||||
const VD::edge_type &edge, const Lines &lines)
|
||||
{
|
||||
Point v0{edge.vertex0()->x(), edge.vertex0()->y()};
|
||||
Point v1{edge.vertex1()->x(), edge.vertex1()->y()};
|
||||
Point v0 = to_point(edge.vertex0());
|
||||
Point v1 = to_point(edge.vertex1());
|
||||
|
||||
if (edge.is_linear()) {
|
||||
// edge line could be initialized by 2 points
|
||||
@ -822,10 +888,8 @@ void VoronoiGraphUtils::draw(SVG & svg,
|
||||
svg.draw(Point(key->x(), key->y()), "lightgray", width);
|
||||
for (const auto &n : value.neighbors) {
|
||||
if (n.edge->vertex0() > n.edge->vertex1()) continue;
|
||||
auto v0 = *n.edge->vertex0();
|
||||
Point from(v0.x(), v0.y());
|
||||
auto v1 = *n.edge->vertex1();
|
||||
Point to(v1.x(), v1.y());
|
||||
Point from = to_point(n.edge->vertex0());
|
||||
Point to = to_point(n.edge->vertex1());
|
||||
svg.draw(Line(from, to), "gray", width);
|
||||
|
||||
Point center = from + to;
|
||||
@ -850,8 +914,9 @@ void VoronoiGraphUtils::draw(SVG & svg,
|
||||
prev_node = node;
|
||||
continue;
|
||||
}
|
||||
Point from(prev_node->vertex->x(), prev_node->vertex->y());
|
||||
Point to(node->vertex->x(), node->vertex->y());
|
||||
|
||||
Point from = to_point(prev_node->vertex);
|
||||
Point to = to_point(node->vertex);
|
||||
svg.draw(Line(from, to), color, width);
|
||||
|
||||
svg.draw_text(from, std::to_string(index - 1).c_str(), color);
|
||||
@ -872,8 +937,7 @@ void VoronoiGraphUtils::draw(SVG & svg,
|
||||
draw(svg, circle.nodes, width, circlePathColor, true);
|
||||
Point center(0, 0);
|
||||
for (auto p : circle.nodes) {
|
||||
center.x() += p->vertex->x();
|
||||
center.y() += p->vertex->y();
|
||||
center += to_point(p->vertex);
|
||||
}
|
||||
center.x() /= circle.nodes.size();
|
||||
center.y() /= circle.nodes.size();
|
||||
|
@ -27,24 +27,51 @@ public:
|
||||
VoronoiGraphUtils() = delete;
|
||||
|
||||
/// <summary>
|
||||
/// Convert line edge segment to slicer line
|
||||
/// only for line edge
|
||||
/// only for finite line
|
||||
/// Convert coordinate type between voronoi and slicer format
|
||||
/// </summary>
|
||||
/// <param name="edge">line edge</param>
|
||||
/// <returns>line</returns>
|
||||
static Slic3r::Line to_line(const VD::edge_type &edge);
|
||||
/// <param name="coor">Coordinate</param>
|
||||
/// <returns>When it is possible than cast it otherwise empty optional</returns>
|
||||
static coord_t to_coord(const VD::coordinate_type &coord);
|
||||
|
||||
/// <summary>
|
||||
/// Convert Point 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>
|
||||
static Slic3r::Point to_point(const VD::vertex_type *vertex);
|
||||
|
||||
/// <summary>
|
||||
/// check if coord is in limits for coord_t
|
||||
/// </summary>
|
||||
/// <param name="coord">input value</param>
|
||||
/// <param name="source">VD source point coordinate</param>
|
||||
/// <param name="max_distance">Maximal distance from source</param>
|
||||
/// <returns>True when coord is in +- max_distance from source otherwise FALSE.</returns>
|
||||
static bool is_coord_in_limits(const VD::coordinate_type &coord,
|
||||
const coord_t & source,
|
||||
double max_distance);
|
||||
|
||||
/// <summary>
|
||||
/// Check x and y values of vertex
|
||||
/// </summary>
|
||||
/// <param name="vertex">input vertex</param>
|
||||
/// <param name="source">VD source point</param>
|
||||
/// <param name="max_distance">Maximal distance from source</param>
|
||||
/// <returns>True when both coord are in limits given by source and max distance otherwise FALSE</returns>
|
||||
static bool is_point_in_limits(const VD::vertex_type *vertex,
|
||||
const Point & source,
|
||||
double max_distance);
|
||||
|
||||
/// <summary>
|
||||
/// Private function to help convert edge without vertex to line
|
||||
/// </summary>
|
||||
/// <param name="point1">VD Source point</param>
|
||||
/// <param name="point2">VD Source point</param>
|
||||
/// <param name="point1">VD source point</param>
|
||||
/// <param name="point2">VD source point</param>
|
||||
/// <param name="maximal_distance">Maximal distance from source point</param>
|
||||
/// <returns>Line segment between lines</returns>
|
||||
static Slic3r::Line to_line(Point point1,
|
||||
Point point2,
|
||||
double maximal_distance);
|
||||
static Slic3r::Line create_line_between_source_points(
|
||||
const Point &point1, const Point &point2, double maximal_distance);
|
||||
|
||||
/// <summary>
|
||||
/// Convert edge to line
|
||||
/// only for line edge
|
||||
@ -54,10 +81,10 @@ public:
|
||||
/// <param name="edge"></param>
|
||||
/// <param name="points">Source point for voronoi diagram</param>
|
||||
/// <param name="maximal_distance">Maximal distance from source point</param>
|
||||
/// <returns>Croped line</returns>
|
||||
static Slic3r::Line to_line(const VD::edge_type & edge,
|
||||
const Points &points,
|
||||
double maximal_distance);
|
||||
/// <returns>Croped line, when all line segment is out of max distance return empty optional</returns>
|
||||
static std::optional<Slic3r::Line> to_line(const VD::edge_type &edge,
|
||||
const Points & points,
|
||||
double maximal_distance);
|
||||
/// <summary>
|
||||
/// close polygon defined by lines
|
||||
/// close points will convert to their center
|
||||
@ -112,7 +139,7 @@ public:
|
||||
/// <param name="points">Source of Voronoi diagram</param>
|
||||
/// <param name="cell">Cell inside of Voronoi diagram</param>
|
||||
/// <returns>Point from source points.</returns>
|
||||
static Point retrieve_point(const Points &points, const VD::cell_type &cell);
|
||||
static const Point& retrieve_point(const Points &points, const VD::cell_type &cell);
|
||||
|
||||
static Slic3r::Point get_parabola_point(const VD::edge_type ¶bola, const Slic3r::Lines &lines);
|
||||
static Slic3r::Line get_parabola_line(const VD::edge_type ¶bola, const Lines &lines);
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include <libslic3r/SLA/SupportIslands/SampleConfig.hpp>
|
||||
#include <libslic3r/SLA/SupportIslands/VoronoiGraphUtils.hpp>
|
||||
#include <libslic3r/SLA/SupportIslands/SampleIslandUtils.hpp>
|
||||
#include <libslic3r/SLA/SupportIslands/PolygonUtils.hpp>
|
||||
|
||||
#include "sla_test_utils.hpp"
|
||||
|
||||
@ -138,59 +139,18 @@ TEST_CASE("Two parallel plates should be supported", "[SupGen][Hollowed]")
|
||||
REQUIRE(!pts.empty());
|
||||
}
|
||||
|
||||
// all triangle side are same length
|
||||
Slic3r::Polygon equilateral_triangle(double size)
|
||||
{
|
||||
return {{.0, .0},
|
||||
{size, .0},
|
||||
{size / 2., sqrt(size * size - size * size / 4)}};
|
||||
}
|
||||
|
||||
// two side of triangle are same size
|
||||
Slic3r::Polygon isosceles_triangle(double side, double height)
|
||||
{
|
||||
return {{-side / 2, 0.}, {side / 2, 0.}, {.0, height}};
|
||||
}
|
||||
|
||||
Slic3r::Polygon square(double size)
|
||||
{
|
||||
double size_2 = size / 2;
|
||||
return {{-size_2, size_2},
|
||||
{-size_2, -size_2},
|
||||
{size_2, -size_2},
|
||||
{size_2, size_2}};
|
||||
}
|
||||
|
||||
Slic3r::Polygon rect(double x, double y){
|
||||
double x_2 = x / 2;
|
||||
double y_2 = y / 2;
|
||||
return {{-x_2, y_2}, {-x_2, -y_2}, {x_2, -y_2}, {x_2, y_2}};
|
||||
}
|
||||
|
||||
Slic3r::Polygon circle(double radius, size_t count_line_segments) {
|
||||
// CCW: couter clock wise, CW: clock wise
|
||||
Points circle;
|
||||
circle.reserve(count_line_segments);
|
||||
for (size_t i = 0; i < count_line_segments; ++i) {
|
||||
double alpha = (2 * M_PI * i) / count_line_segments;
|
||||
double sina = sin(alpha);
|
||||
double cosa = cos(alpha);
|
||||
circle.emplace_back(-radius * sina, radius * cosa);
|
||||
}
|
||||
return Slic3r::Polygon(circle);
|
||||
}
|
||||
|
||||
Slic3r::Polygon create_cross_roads(double size, double width)
|
||||
{
|
||||
auto r1 = rect( 5.3 * size, width);
|
||||
auto r1 = PolygonUtils::create_rect(5.3 * size, width);
|
||||
r1.rotate(3.14/4);
|
||||
r1.translate(2 * size, width / 2);
|
||||
auto r2 = rect(6.1*size, 3/4.*width);
|
||||
auto r2 = PolygonUtils::create_rect(6.1 * size, 3 / 4. * width);
|
||||
r2.rotate(-3.14 / 5);
|
||||
r2.translate(3 * size, width / 2);
|
||||
auto r3 = rect(7.9*size, 4/5.*width);
|
||||
auto r3 = PolygonUtils::create_rect(7.9 * size, 4 / 5. * width);
|
||||
r3.translate(2*size, width/2);
|
||||
auto r4 = rect(5 / 6. * width, 5.7 * size);
|
||||
auto r4 = PolygonUtils::create_rect(5 / 6. * width, 5.7 * size);
|
||||
r4.translate(-size,3*size);
|
||||
Polygons rr = union_(Polygons({r1, r2, r3, r4}));
|
||||
return rr.front();
|
||||
@ -198,7 +158,8 @@ Slic3r::Polygon create_cross_roads(double size, double width)
|
||||
|
||||
ExPolygon create_trinagle_with_hole(double size)
|
||||
{
|
||||
return ExPolygon(equilateral_triangle(size), {{size / 4, size / 4},
|
||||
return ExPolygon(PolygonUtils::create_equilateral_triangle(size),
|
||||
{{size / 4, size / 4},
|
||||
{size / 2, size / 2},
|
||||
{size / 2, size / 4}});
|
||||
}
|
||||
@ -206,14 +167,14 @@ ExPolygon create_trinagle_with_hole(double size)
|
||||
ExPolygon create_square_with_hole(double size, double hole_size)
|
||||
{
|
||||
assert(sqrt(hole_size *hole_size / 2) < size);
|
||||
auto hole = square(hole_size);
|
||||
auto hole = PolygonUtils::create_square(hole_size);
|
||||
hole.rotate(M_PI / 4.); // 45
|
||||
hole.reverse();
|
||||
return ExPolygon(square(size), hole);
|
||||
return ExPolygon(PolygonUtils::create_square(size), hole);
|
||||
}
|
||||
|
||||
ExPolygon create_square_with_4holes(double size, double hole_size) {
|
||||
auto hole = square(hole_size);
|
||||
auto hole = PolygonUtils::create_square(hole_size);
|
||||
hole.reverse();
|
||||
double size_4 = size / 4;
|
||||
auto h1 = hole;
|
||||
@ -224,7 +185,7 @@ ExPolygon create_square_with_4holes(double size, double hole_size) {
|
||||
h3.translate(size_4, -size_4);
|
||||
auto h4 = hole;
|
||||
h4.translate(-size_4, -size_4);
|
||||
ExPolygon result(square(size));
|
||||
ExPolygon result(PolygonUtils::create_square(size));
|
||||
result.holes = Polygons({h1, h2, h3, h4});
|
||||
return result;
|
||||
}
|
||||
@ -233,14 +194,17 @@ ExPolygon create_square_with_4holes(double size, double hole_size) {
|
||||
ExPolygon create_disc(double radius, double width, size_t count_line_segments)
|
||||
{
|
||||
double width_2 = width / 2;
|
||||
auto hole = circle(radius-width_2, count_line_segments);
|
||||
auto hole = PolygonUtils::create_circle(radius - width_2,
|
||||
count_line_segments);
|
||||
hole.reverse();
|
||||
return ExPolygon(circle(radius + width_2, count_line_segments), hole);
|
||||
return ExPolygon(PolygonUtils::create_circle(radius + width_2,
|
||||
count_line_segments),
|
||||
hole);
|
||||
}
|
||||
|
||||
Slic3r::Polygon create_V_shape(double height, double line_width, double angle = M_PI/4) {
|
||||
double angle_2 = angle / 2;
|
||||
auto left_side = rect(line_width, height);
|
||||
auto left_side = PolygonUtils::create_rect(line_width, height);
|
||||
auto right_side = left_side;
|
||||
right_side.rotate(-angle_2);
|
||||
double small_move = cos(angle_2) * line_width / 2;
|
||||
@ -248,7 +212,7 @@ Slic3r::Polygon create_V_shape(double height, double line_width, double angle =
|
||||
right_side.translate(side_move,0);
|
||||
left_side.rotate(angle_2);
|
||||
left_side.translate(-side_move, 0);
|
||||
auto bottom = rect(4 * small_move, line_width);
|
||||
auto bottom = PolygonUtils::create_rect(4 * small_move, line_width);
|
||||
bottom.translate(0., -cos(angle_2) * height / 2 + line_width/2);
|
||||
Polygons polygons = union_(Polygons({left_side, right_side, bottom}));
|
||||
return polygons.front();
|
||||
@ -267,22 +231,22 @@ ExPolygons createTestIslands(double size)
|
||||
{size / 7, size}});
|
||||
ExPolygons result = {
|
||||
// one support point
|
||||
ExPolygon(equilateral_triangle(size)),
|
||||
ExPolygon(square(size)),
|
||||
ExPolygon(rect(size / 2, size)),
|
||||
ExPolygon(isosceles_triangle(size / 2, 3 * size / 2)), // small sharp triangle
|
||||
ExPolygon(circle(size/2, 10)),
|
||||
ExPolygon(PolygonUtils::create_equilateral_triangle(size)),
|
||||
ExPolygon(PolygonUtils::create_square(size)),
|
||||
ExPolygon(PolygonUtils::create_rect(size / 2, size)),
|
||||
ExPolygon(PolygonUtils::create_isosceles_triangle(size / 2, 3 * size / 2)), // small sharp triangle
|
||||
ExPolygon(PolygonUtils::create_circle(size / 2, 10)),
|
||||
create_square_with_4holes(size, size / 4),
|
||||
create_disc(size/4, size / 4, 10),
|
||||
ExPolygon(create_V_shape(2*size/3, size / 4)),
|
||||
|
||||
// two support points
|
||||
ExPolygon(isosceles_triangle(size / 2, 3 * size)), // small sharp triangle
|
||||
ExPolygon(rect(size / 2, 3 * size)),
|
||||
ExPolygon(PolygonUtils::create_isosceles_triangle(size / 2, 3 * size)), // small sharp triangle
|
||||
ExPolygon(PolygonUtils::create_rect(size / 2, 3 * size)),
|
||||
ExPolygon(create_V_shape(1.5*size, size/3)),
|
||||
|
||||
// tiny line support points
|
||||
ExPolygon(rect(size / 2, 10 * size)), // long line
|
||||
ExPolygon(PolygonUtils::create_rect(size / 2, 10 * size)), // long line
|
||||
ExPolygon(create_V_shape(size*4, size / 3)),
|
||||
ExPolygon(create_cross_roads(size, size / 3)),
|
||||
create_disc(3*size, size / 4, 30),
|
||||
@ -290,8 +254,8 @@ ExPolygons createTestIslands(double size)
|
||||
|
||||
// still problem
|
||||
// three support points
|
||||
ExPolygon(equilateral_triangle(3 * size)),
|
||||
ExPolygon(circle(size, 20)),
|
||||
ExPolygon(PolygonUtils::create_equilateral_triangle(3 * size)),
|
||||
ExPolygon(PolygonUtils::create_circle(size, 20)),
|
||||
|
||||
mountains,
|
||||
create_trinagle_with_hole(size),
|
||||
@ -444,23 +408,6 @@ TEST_CASE("Sampling speed test on FrogLegs", "[VoronoiSkeleton]")
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
|
||||
#include <CGAL/Delaunay_triangulation_2.h>
|
||||
void cgal_test(const SupportIslandPoints &points, const ExPolygon &island) {
|
||||
using Kernel = CGAL::Exact_predicates_inexact_constructions_kernel;
|
||||
using Delaunay = CGAL::Delaunay_triangulation_2<Kernel>;
|
||||
std::vector<Kernel::Point_2> k_points;
|
||||
k_points.reserve(points.size());
|
||||
std::transform(points.begin(), points.end(), std::back_inserter(k_points),
|
||||
[](const SupportIslandPoint &p) {
|
||||
return Kernel::Point_2(p.point.x(), p.point.y());
|
||||
});
|
||||
Delaunay dt;
|
||||
dt.insert(k_points.begin(), k_points.end());
|
||||
std::cout << dt.number_of_vertices() << std::endl;
|
||||
}*/
|
||||
|
||||
TEST_CASE("Small islands should be supported in center", "[SupGen][VoronoiSkeleton]")
|
||||
{
|
||||
double size = 3e7;
|
||||
|
@ -1,18 +1,47 @@
|
||||
#include "sla_test_utils.hpp"
|
||||
|
||||
#include <libslic3r/SLA/SupportIslands/VoronoiGraphUtils.hpp>
|
||||
#include <libslic3r/VoronoiVisualUtils.hpp>
|
||||
|
||||
using namespace Slic3r;
|
||||
using namespace Slic3r::sla;
|
||||
|
||||
TEST_CASE("Convert coordinate datatype", "[Voronoi]")
|
||||
{
|
||||
using VD = Slic3r::Geometry::VoronoiDiagram;
|
||||
VD::coordinate_type coord = 101197493902.64694;
|
||||
coord_t coord2 = VoronoiGraphUtils::to_coord(coord);
|
||||
CHECK(coord2 > 100);
|
||||
|
||||
coord = -101197493902.64694;
|
||||
coord2 = VoronoiGraphUtils::to_coord(coord);
|
||||
CHECK(coord2 < -100);
|
||||
|
||||
coord = 12345.1;
|
||||
coord2 = VoronoiGraphUtils::to_coord(coord);
|
||||
CHECK(coord2 == 12345);
|
||||
|
||||
coord = -12345.1;
|
||||
coord2 = VoronoiGraphUtils::to_coord(coord);
|
||||
CHECK(coord2 == -12345);
|
||||
|
||||
coord = 12345.9;
|
||||
coord2 = VoronoiGraphUtils::to_coord(coord);
|
||||
CHECK(coord2 == 12346);
|
||||
|
||||
coord = -12345.9;
|
||||
coord2 = VoronoiGraphUtils::to_coord(coord);
|
||||
CHECK(coord2 == -12346);
|
||||
}
|
||||
|
||||
void check(Slic3r::Points points, double max_distance) {
|
||||
using VD = Slic3r::Geometry::VoronoiDiagram;
|
||||
VD vd;
|
||||
construct_voronoi(points.begin(), points.end(), &vd);
|
||||
double max_area = 3.15 * 4 * max_distance*max_distance; // circle
|
||||
construct_voronoi(points.begin(), points.end(), &vd);
|
||||
double max_area = M_PI * max_distance*max_distance; // circle = Pi * r^2
|
||||
for (const VD::cell_type &cell : vd.cells()) {
|
||||
Slic3r::Polygon polygon = VoronoiGraphUtils::to_polygon(cell, points, max_distance);
|
||||
CHECK(polygon.area() < max_area);
|
||||
CHECK(polygon.contains(points[cell.source_index()]));
|
||||
}
|
||||
}
|
||||
|
||||
@ -21,7 +50,7 @@ TEST_CASE("Polygon from cell", "[Voronoi]")
|
||||
double max_distance = 1e7;
|
||||
coord_t size = (int) (4e6);
|
||||
coord_t half_size = size/2;
|
||||
|
||||
|
||||
Slic3r::Points two_cols({Point(0, 0), Point(size, 0)});
|
||||
check(two_cols, max_distance);
|
||||
|
||||
@ -40,7 +69,22 @@ TEST_CASE("Polygon from cell", "[Voronoi]")
|
||||
|
||||
Slic3r::Points middle_point2({Point(half_size, half_size), Point(-size, -size), Point(-size, size),
|
||||
Point(size, -size), Point(size, size)});
|
||||
check(middle_point2, max_distance);
|
||||
check(middle_point2, max_distance);
|
||||
|
||||
Slic3r::Points diagonal_points({{-123473762, 71287970},
|
||||
{-61731535, 35684428},
|
||||
{0, 0},
|
||||
{61731535, -35684428},
|
||||
{123473762, -71287970}});
|
||||
double diagonal_max_distance = 5e7;
|
||||
check(diagonal_points, diagonal_max_distance);
|
||||
|
||||
int scale = 10;
|
||||
Slic3r::Points diagonal_points2;
|
||||
std::transform(diagonal_points.begin(), diagonal_points.end(),
|
||||
std::back_inserter(diagonal_points2),
|
||||
[&](const Slic3r::Point &p) { return p/scale; });
|
||||
check(diagonal_points2, diagonal_max_distance / scale);
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user