convert Voronoi cell to polygon

This commit is contained in:
Filip Sykala 2021-03-16 09:35:05 +01:00 committed by Lukas Matena
parent 51dfdd8f38
commit 81f0ad8f63
15 changed files with 498 additions and 70 deletions

View File

@ -0,0 +1,20 @@
#include "LineUtils.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();
}
});
}

View File

@ -0,0 +1,27 @@
#ifndef slic3r_SLA_SuppotstIslands_LineUtils_hpp_
#define slic3r_SLA_SuppotstIslands_LineUtils_hpp_
#include <libslic3r/Line.hpp>
namespace Slic3r::sla {
/// <summary>
/// Class which contain collection of static function
/// for work with Line and Lines.
/// QUESTION: Is it only for SLA?
/// </summary>
class LineUtils
{
public:
LineUtils() = delete;
/// <summary>
/// Sort lines to be in counter clock wise order
/// </summary>
/// <param name="lines">Lines to sort</param>
/// <param name="center">Center for order</param>
static void sort_CCW(Lines &lines, const Point &center);
};
} // namespace Slic3r::sla
#endif // slic3r_SLA_SuppotstIslands_LineUtils_hpp_

View File

@ -21,5 +21,23 @@ struct Parabola
{}
};
/// <summary>
/// DTO store segment of parabola
/// Parabola with start(from) and end(to) point lay on parabola
/// </summary>
struct ParabolaSegment: public Parabola
{
Point from;
Point to;
ParabolaSegment(Parabola parabola, Point from, Point to) :
Parabola(std::move(parabola)), from(from), to(to)
{}
ParabolaSegment(Line directrix, Point focus, Point from, Point to)
: Parabola(directrix, focus), from(from), to(to)
{}
};
} // namespace Slic3r::sla
#endif // slic3r_SLA_SuppotstIslands_Parabola_hpp_

View File

@ -2,16 +2,15 @@
using namespace Slic3r::sla;
double ParabolaUtils::calculate_length_of_parabola(
const Parabola &parabola, const Point &from, const Point &to)
double ParabolaUtils::length(const ParabolaSegment &parabola)
{
const Point &point = parabola.focus;
const Line & line = parabola.directrix;
Line norm_line(point, point + line.normal());
// sign of distance is resolved by dot product in function is_over_zero()
double scaled_x1 = norm_line.perp_distance_to(from);
double scaled_x2 = norm_line.perp_distance_to(to);
double scaled_x1 = norm_line.perp_distance_to(parabola.from);
double scaled_x2 = norm_line.perp_distance_to(parabola.to);
double parabola_scale = 1. / (4. * focal_length(parabola));
@ -21,23 +20,21 @@ double ParabolaUtils::calculate_length_of_parabola(
double length_x1 = parabola_arc_length(x1) / parabola_scale;
double length_x2 = parabola_arc_length(x2) / parabola_scale;
return (is_over_zero(parabola, from, to)) ?
return (is_over_zero(parabola)) ?
(length_x1 + length_x2) : // interval is over zero
fabs(length_x1 - length_x2); // interval is on same side of parabola
}
#include <Libslic3r/Geometry.hpp>
#include <Libslic3r/VoronoiOffset.hpp>
#include <Libslic3r/VoronoiVisualUtils.hpp>
double ParabolaUtils::calculate_length_of_parabola_by_sampling(
const Parabola &parabola,
const Point & from,
const Point & to,
double ParabolaUtils::length_by_sampling(
const ParabolaSegment &parabola,
double discretization_step)
{
using VD = Slic3r::Geometry::VoronoiDiagram;
std::vector<Voronoi::Internal::point_type> parabola_samples({from, to});
std::vector<Voronoi::Internal::point_type> parabola_samples(
{parabola.from, parabola.to});
VD::point_type source_point = parabola.focus;
VD::segment_type source_segment(parabola.directrix.a, parabola.directrix.b);
@ -65,12 +62,19 @@ double ParabolaUtils::focal_length(const Parabola &parabola)
return f;
}
bool ParabolaUtils::is_over_zero(const Parabola &parabola,
const Point & from,
const Point & to)
bool ParabolaUtils::is_over_zero(const ParabolaSegment &parabola)
{
Point line_direction = parabola.directrix.b - parabola.directrix.a;
bool is_positive_x1 = line_direction.dot(parabola.focus - from) > 0.;
bool is_positive_x2 = line_direction.dot(parabola.focus - to) > 0.;
Point focus_from = parabola.focus - parabola.from;
Point focus_to = parabola.focus - parabola.to;
bool is_positive_x1 = line_direction.dot(focus_from) > 0.;
bool is_positive_x2 = line_direction.dot(focus_to) > 0.;
return is_positive_x1 != is_positive_x2;
}
// PRIVATE
double ParabolaUtils::parabola_arc_length(double x)
{
double sqrtRes = sqrt(1 + 4 * x * x);
return 1 / 4. * log(2 * x + sqrtRes) + 1 / 2. * x * sqrtRes;
};

View File

@ -17,27 +17,18 @@ public:
/// <summary>
/// Integrate length over interval defined by points from and to
/// </summary>
/// <param name="parabola">Input parabola</param>
/// <param name="from">Input point lay on parabola</param>
/// <param name="to">Input point lay on parabola</param>
/// <param name="parabola">Input segment of parabola</param>
/// <returns>Length of parabola arc</returns>
static double calculate_length_of_parabola(const Parabola &parabola,
const Point & from,
const Point & to);
static double length(const ParabolaSegment &parabola);
/// <summary>
/// Sample parabola between points from and to by step.
/// </summary>
/// <param name="parabola">Input parabola</param>
/// <param name="from">Input point lay on parabola</param>
/// <param name="to">Input point lay on parabola</param>
/// <param name="parabola">Input segment of parabola</param>
/// <param name="discretization_step">Define sampling</param>
/// <returns>Length of parabola arc</returns>
static double calculate_length_of_parabola_by_sampling(
const Parabola &parabola,
const Point & from,
const Point & to,
double discretization_step = 0.0002 * 1e6);
static double length_by_sampling(const ParabolaSegment &parabola,
double discretization_step = 200);
/// <summary>
/// calculate focal length of parabola
@ -49,13 +40,9 @@ public:
/// <summary>
/// Check if parabola interval (from, to) contains top of parabola
/// </summary>
/// <param name="parabola">input parabola</param>
/// <param name="from">Start of interval, point lay on parabola</param>
/// <param name="to">End of interval, point lay on parabola</param>
/// <param name="parabola">Input segment of parabola</param>
/// <returns>True when interval contain top of parabola otherwise False</returns>
static bool is_over_zero(const Parabola &parabola,
const Point & from,
const Point & to);
static bool is_over_zero(const ParabolaSegment &parabola);
private:
/// <summary>
@ -64,10 +51,7 @@ private:
/// </summary>
/// <param name="x">x coordinate of parabola, Positive number</param>
/// <returns>Length of parabola from zero to x</returns>
static double parabola_arc_length(double x) {
double sqrtRes = sqrt(1 + 4 * x * x);
return 1 / 4. * log(2 * x + sqrtRes) + 1 / 2. * x * sqrtRes;
};
static double parabola_arc_length(double x);
};
} // namespace Slic3r::sla

View File

@ -0,0 +1,13 @@
#include "PointUtils.hpp"
using namespace Slic3r::sla;
bool PointUtils::is_ccw(const Point &p1, const Point &p2, const Point &center)
{
Slic3r::Point v1 = p1 - center;
Slic3r::Point v2 = p2 - center;
double cross_product = v1.x() * (double) v2.y() -
v2.x() * (double) v1.y();
return cross_product > 0;
}

View File

@ -0,0 +1,23 @@
#ifndef slic3r_SLA_SuppotstIslands_PointUtils_hpp_
#define slic3r_SLA_SuppotstIslands_PointUtils_hpp_
#include <libslic3r/Point.hpp>
namespace Slic3r::sla {
/// <summary>
/// Class which contain collection of static function
/// for work with Point and Points.
/// QUESTION: Is it only for SLA?
/// </summary>
class PointUtils
{
public:
PointUtils() = delete;
// is point p1 to p2 in counter clock wise order against center?
static bool is_ccw(const Point &p1, const Point &p2, const Point &center);
};
} // namespace Slic3r::sla
#endif // slic3r_SLA_SuppotstIslands_PointUtils_hpp_

View File

@ -49,7 +49,9 @@ SupportIslandPoint SampleIslandUtils::create_point_on_path(
// distance must be inside path
// this means bad input params
assert(false);
return Point(0, 0);
return SupportIslandPoint(Point(0, 0),
SupportIslandPoint::Type::undefined,
VoronoiGraph::Position(nullptr,0.));
}
SupportIslandPoint SampleIslandUtils::create_middle_path_point(
@ -174,6 +176,31 @@ std::vector<std::set<const VoronoiGraph::Node *>> create_circles_sets(
return result;
}
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;
}
void SampleIslandUtils::align_samples(SupportIslandPoints &samples, double max_distance)
{
using VD = Slic3r::Geometry::VoronoiDiagram;
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
}
SupportIslandPoints SampleIslandUtils::sample_center_line(
const VoronoiGraph::ExPath &path, const CenterLineConfiguration &cfg)
{
@ -187,6 +214,8 @@ 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;
}

View File

@ -129,6 +129,15 @@ public:
const SampleConfig & config,
VoronoiGraph::ExPath &longest_path);
static Slic3r::Points to_points(const SupportIslandPoints &support_points);
/// <summary>
/// keep same distances between support points
/// </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);
static void draw(SVG & svg,
const SupportIslandPoints &supportIslandPoints,
double size,

View File

@ -30,14 +30,10 @@ struct SupportIslandPoint
Type type;
SupportIslandPoint(Slic3r::Point point,
Type type = Type::undefined,
VoronoiGraph::Position position = {})
Type type,
VoronoiGraph::Position position)
: point(std::move(point)), type(type), position(position)
{
if (position.neighbor == nullptr) {
int i = 5;
}
}
{}
};
using SupportIslandPoints = std::vector<SupportIslandPoint>;

View File

@ -5,11 +5,193 @@
#include "IStackFunction.hpp"
#include "EvaluateNeighbor.hpp"
#include "ParabolaUtils.hpp"
#include "LineUtils.hpp"
#include "PointUtils.hpp"
#include <libslic3r/VoronoiVisualUtils.hpp>
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()));
}
// 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)
{
Point middle = (point1 + point2) / 2;
Point diff = point1 - point2;
double distance_2 = diff.x() * static_cast<double>(diff.x()) +
diff.y() * static_cast<double>(diff.y());
double half_distance = sqrt(distance_2) / 2.;
double half_distance_2 = distance_2 / 4;
double size = sqrt(maximal_distance * maximal_distance - half_distance_2);
// normalized direction to side multiplied by size/2
double scale = size / half_distance / 2;
Point side_dir(-diff.y() * scale, diff.x() * scale);
return Line(middle - side_dir, middle + side_dir);
}
bool is_oposit_direction(const Slic3r::Point &p1, const Slic3r::Point &p2) {
if (abs(p1.x()) > abs(p1.y())) {
return (p1.x() > 0) != (p2.x() > 0);
}
return (p1.y() > 0) != (p2.y() > 0);
}
Slic3r::Line VoronoiGraphUtils::to_line(const VD::edge_type & edge,
const Points &points,
double maximal_distance)
{
assert(edge.is_linear());
assert(edge.is_primary());
if (edge.is_finite()) return to_line(edge);
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
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 - v;
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);
}
}
Slic3r::Polygon VoronoiGraphUtils::to_polygon(const Lines &lines,
const Point &center,
double maximal_distance,
double minimal_distance,
size_t count_points)
{
assert(lines.size() >= 1);
assert(minimal_distance > 0.);
assert(maximal_distance > minimal_distance);
assert(count_points >= 3);
Points points;
points.reserve(lines.size());
const Line *prev_line = &lines.back();
double max_angle = 2 * M_PI / count_points;
for (const Line &line : lines) {
const Point &p1 = prev_line->b;
const Point &p2 = line.a;
prev_line = &line;
Point diff = p1-p2;
if (abs(diff.x()) < minimal_distance &&
abs(diff.y()) < minimal_distance) {
Point avg = (p1 + p2) / 2;
points.push_back(avg);
continue;
}
Point v1 = p1 - center;
Point v2 = p2 - center;
double a1 = std::atan2(v1.y(), v1.x());
double a2 = std::atan2(v2.y(), v2.x());
double diff_angle = a2 - a1;
if(diff_angle < 0.) diff_angle += 2 * M_PI;
if(diff_angle > 2 * M_PI) diff_angle -= 2 * M_PI;
size_t count_segment = std::floor(fabs(diff_angle) / max_angle) + 1;
double increase_angle = diff_angle / count_segment;
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);
}
points.push_back(p2);
}
return Polygon(points);
}
Slic3r::Polygon VoronoiGraphUtils::to_polygon(const VD::cell_type & cell,
const Slic3r::Points &points,
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);
}
edge = edge->next();
} while (edge != cell.incident_edge());
LineUtils::sort_CCW(lines, center);
// preccission to decide when not connect neighbor points
double min_distance = maximal_distance / 1000.;
size_t count_point = 6; // count added points
Slic3r::Polygon polygon = to_polygon(lines, center, maximal_distance, min_distance, count_point);
#ifdef SLA_SUPPORTPOINTGEN_DEBUG
{
std::cout << "cell " << cell.source_index() << " has " << lines.size() << "edges" << std::endl;
BoundingBox bbox(center - Point(maximal_distance, maximal_distance),
center + Point(maximal_distance, maximal_distance));
static int counter = 0;
std::string filename = "polygon" + std::to_string(counter++) + ".svg";
SVG svg(filename.c_str(), bbox);
svg.draw(center, "lightgreen", maximal_distance);
svg.draw(polygon, "lightblue");
int index = 0;
for (auto &line : lines) {
svg.draw(line);
svg.draw_text(line.a, ("A"+std::to_string(++index)).c_str(), "green");
svg.draw_text(line.b, ("B" + std::to_string(index)).c_str(), "blue");
}
svg.draw(center, "red", maximal_distance / 100);
}
#endif /* SLA_SUPPORTPOINTGEN_DEBUG */
return polygon;
}
VoronoiGraph::Node *VoronoiGraphUtils::getNode(VoronoiGraph & graph,
const VD::vertex_type *vertex,
const VD::edge_type * edge,
@ -39,16 +221,21 @@ VoronoiGraph::Node *VoronoiGraphUtils::getNode(VoronoiGraph & graph,
Slic3r::Point VoronoiGraphUtils::retrieve_point(const Lines & lines,
const VD::cell_type &cell)
{
assert(cell.source_category() ==
boost::polygon::SOURCE_CATEGORY_SEGMENT_START_POINT ||
cell.source_category() ==
boost::polygon::SOURCE_CATEGORY_SEGMENT_END_POINT);
return (cell.source_category() ==
boost::polygon::SOURCE_CATEGORY_SEGMENT_START_POINT) ?
using namespace boost::polygon;
assert(cell.source_category() == SOURCE_CATEGORY_SEGMENT_START_POINT ||
cell.source_category() == SOURCE_CATEGORY_SEGMENT_END_POINT);
return (cell.source_category() == SOURCE_CATEGORY_SEGMENT_START_POINT) ?
lines[cell.source_index()].a :
lines[cell.source_index()].b;
}
Slic3r::Point VoronoiGraphUtils::retrieve_point(const Points & points,
const VD::cell_type &cell)
{
assert(cell.source_category() == boost::polygon::SOURCE_CATEGORY_SINGLE_POINT);
return points[cell.source_index()];
}
Slic3r::Point VoronoiGraphUtils::get_parabola_point(
const VD::edge_type &parabola, const Slic3r::Lines &lines)
{
@ -88,8 +275,8 @@ double VoronoiGraphUtils::calculate_length_of_parabola(
{
Point v0{edge.vertex0()->x(), edge.vertex0()->y()};
Point v1{edge.vertex1()->x(), edge.vertex1()->y()};
Parabola parabola = get_parabola(edge, lines);
return ParabolaUtils::calculate_length_of_parabola(parabola, v0, v1);
ParabolaSegment parabola(get_parabola(edge, lines), v0, v1);
return ParabolaUtils::length(parabola);
}
double VoronoiGraphUtils::calculate_length(

View File

@ -26,6 +26,67 @@ class VoronoiGraphUtils
public:
VoronoiGraphUtils() = delete;
/// <summary>
/// Convert line edge segment to slicer line
/// only for line edge
/// only for finite line
/// </summary>
/// <param name="edge">line edge</param>
/// <returns>line</returns>
static Slic3r::Line to_line(const VD::edge_type &edge);
/// <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="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);
/// <summary>
/// Convert edge to line
/// only for line edge
/// crop infinite edge by maximal distance from source point
/// inspiration in VoronoiVisualUtils::clip_infinite_edge
/// </summary>
/// <param name="edge"></param>
/// <param name="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);
/// <summary>
/// close polygon defined by lines
/// close points will convert to their center
/// Mainly for convert to polygon
/// </summary>
/// <param name="lines">Border of polygon, sorted lines CCW</param>
/// <param name="center">Center point of polygon</param>
/// <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>
static Slic3r::Polygon to_polygon(const Lines &lines,
const Point &center,
double maximal_distance,
double minimal_distance,
size_t count_points);
/// <summary>
/// Convert cell to polygon
/// Source for VD must be only point to create VD with only line segments
/// infinite cell are croped by maximal distance from source point
/// </summary>
/// <param name="cell">cell from VD created only by points</param>
/// <param name="points">source points for VD</param>
/// <param name="maximal_distance">maximal distance from source point - only for infinite edges(cells)</param>
/// <returns>polygon created by cell</returns>
static Slic3r::Polygon to_polygon(const VD::cell_type & cell,
const Slic3r::Points &points,
double maximal_distance);
// return node from graph by vertex, when no exists create one
static VoronoiGraph::Node *getNode(VoronoiGraph & graph,
const VD::vertex_type *vertex,
@ -33,12 +94,26 @@ public:
const Lines & lines);
/// <summary>
/// extract parabola focus point from lines belongs to cell
/// Extract point from lines, belongs to cell
/// ! Source for VD must be only lines
/// Main purpose parabola focus point from lines belongs to cell
/// inspiration in VoronoiVisualUtils::retrieve_point
/// </summary>
/// <param name="lines">source of Voronoi diagram</param>
/// <param name="cell">cell inside of Voronoi diagram</param>
/// <returns>Point from lines which create parabola.</returns>
/// <param name="lines">Source of Voronoi diagram</param>
/// <param name="cell">Cell inside of Voronoi diagram</param>
/// <returns>Point from source lines.</returns>
static Point retrieve_point(const Lines &lines, const VD::cell_type &cell);
/// <summary>
/// Extract point from lines
/// ! Source for VD must be only points
/// inspiration in VoronoiVisualUtils::retrieve_point
/// </summary>
/// <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 Slic3r::Point get_parabola_point(const VD::edge_type &parabola, const Slic3r::Lines &lines);
static Slic3r::Line get_parabola_line(const VD::edge_type &parabola, const Lines &lines);
static Parabola get_parabola(const VD::edge_type &edge, const Lines &lines);

View File

@ -5,6 +5,7 @@ add_executable(${_TEST_NAME}_tests ${_TEST_NAME}_tests_main.cpp
sla_supptgen_tests.cpp
sla_raycast_tests.cpp
sla_parabola_tests.cpp
sla_voronoi_graph_tests.cpp
sla_supptreeutils_tests.cpp
sla_archive_readwrite_tests.cpp
sla_zcorrection_tests.cpp)

View File

@ -5,19 +5,14 @@
using namespace Slic3r;
using namespace Slic3r::sla;
void parabola_check(const Parabola &parabola,
const Point & from,
const Point & to)
void parabola_check_length(const ParabolaSegment &parabola)
{
auto diffPoint = to - from;
auto diffPoint = parabola.to - parabola.from;
double min = sqrt(diffPoint.x() * diffPoint.x() +
diffPoint.y() * diffPoint.y());
double max = static_cast<double>(diffPoint.x()) + diffPoint.y();
double len = ParabolaUtils::calculate_length_of_parabola(parabola, from, to);
double len2 = ParabolaUtils::calculate_length_of_parabola_by_sampling(
parabola, from, to, 1.);
double len = ParabolaUtils::length(parabola);
double len2 = ParabolaUtils::length_by_sampling(parabola, 1.);
CHECK(fabs(len2 - len) < 1.);
CHECK(len >= min);
CHECK(len <= max);
@ -48,7 +43,8 @@ TEST_CASE("Parabola length", "[SupGen][Voronoi][Parabola]")
double to_x = 3 * scale;
Point from(from_x, getParabolaY(parabola_x2, from_x));
Point to(to_x, getParabolaY(parabola_x2, to_x));
parabola_check(parabola_x2, from, to);
ParabolaSegment parabola_segment(parabola_x2, from, to);
parabola_check_length(parabola_segment);
}

View File

@ -0,0 +1,46 @@
#include "sla_test_utils.hpp"
#include <libslic3r/SLA/SupportIslands/VoronoiGraphUtils.hpp>
using namespace Slic3r;
using namespace Slic3r::sla;
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
for (const VD::cell_type &cell : vd.cells()) {
Slic3r::Polygon polygon = VoronoiGraphUtils::to_polygon(cell, points, max_distance);
CHECK(polygon.area() < max_area);
}
}
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);
Slic3r::Points two_rows({Point(0, 0), Point(0, size)});
check(two_rows, max_distance);
Slic3r::Points two_diag({Point(0, 0), Point(size, size)});
check(two_diag, max_distance);
Slic3r::Points three({Point(0, 0), Point(size, 0), Point(half_size, size)});
check(three, max_distance);
Slic3r::Points middle_point({Point(0, 0), Point(size, half_size),
Point(-size, half_size), Point(0, -size)});
check(middle_point, max_distance);
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);
}