mirror of
https://git.mirrors.martin98.com/https://github.com/prusa3d/PrusaSlicer.git
synced 2025-08-14 00:45:55 +08:00
convert Voronoi cell to polygon
This commit is contained in:
parent
51dfdd8f38
commit
81f0ad8f63
20
src/libslic3r/SLA/SupportIslands/LineUtils.cpp
Normal file
20
src/libslic3r/SLA/SupportIslands/LineUtils.cpp
Normal 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();
|
||||
}
|
||||
});
|
||||
}
|
27
src/libslic3r/SLA/SupportIslands/LineUtils.hpp
Normal file
27
src/libslic3r/SLA/SupportIslands/LineUtils.hpp
Normal 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 ¢er);
|
||||
};
|
||||
|
||||
} // namespace Slic3r::sla
|
||||
#endif // slic3r_SLA_SuppotstIslands_LineUtils_hpp_
|
@ -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_
|
||||
|
@ -2,16 +2,15 @@
|
||||
|
||||
using namespace Slic3r::sla;
|
||||
|
||||
double ParabolaUtils::calculate_length_of_parabola(
|
||||
const Parabola ¶bola, const Point &from, const Point &to)
|
||||
double ParabolaUtils::length(const ParabolaSegment ¶bola)
|
||||
{
|
||||
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 ¶bola,
|
||||
const Point & from,
|
||||
const Point & to,
|
||||
double ParabolaUtils::length_by_sampling(
|
||||
const ParabolaSegment ¶bola,
|
||||
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 ¶bola)
|
||||
return f;
|
||||
}
|
||||
|
||||
bool ParabolaUtils::is_over_zero(const Parabola ¶bola,
|
||||
const Point & from,
|
||||
const Point & to)
|
||||
bool ParabolaUtils::is_over_zero(const ParabolaSegment ¶bola)
|
||||
{
|
||||
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;
|
||||
};
|
||||
|
@ -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 ¶bola,
|
||||
const Point & from,
|
||||
const Point & to);
|
||||
static double length(const ParabolaSegment ¶bola);
|
||||
|
||||
/// <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 ¶bola,
|
||||
const Point & from,
|
||||
const Point & to,
|
||||
double discretization_step = 0.0002 * 1e6);
|
||||
static double length_by_sampling(const ParabolaSegment ¶bola,
|
||||
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 ¶bola,
|
||||
const Point & from,
|
||||
const Point & to);
|
||||
static bool is_over_zero(const ParabolaSegment ¶bola);
|
||||
|
||||
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
|
||||
|
13
src/libslic3r/SLA/SupportIslands/PointUtils.cpp
Normal file
13
src/libslic3r/SLA/SupportIslands/PointUtils.cpp
Normal file
@ -0,0 +1,13 @@
|
||||
#include "PointUtils.hpp"
|
||||
|
||||
using namespace Slic3r::sla;
|
||||
|
||||
bool PointUtils::is_ccw(const Point &p1, const Point &p2, const Point ¢er)
|
||||
{
|
||||
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;
|
||||
}
|
23
src/libslic3r/SLA/SupportIslands/PointUtils.hpp
Normal file
23
src/libslic3r/SLA/SupportIslands/PointUtils.hpp
Normal 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 ¢er);
|
||||
};
|
||||
|
||||
} // namespace Slic3r::sla
|
||||
#endif // slic3r_SLA_SuppotstIslands_PointUtils_hpp_
|
@ -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;
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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>;
|
||||
|
@ -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 ¢er,
|
||||
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 ¶bola, 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(
|
||||
|
@ -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 ¢er,
|
||||
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 ¶bola, const Slic3r::Lines &lines);
|
||||
static Slic3r::Line get_parabola_line(const VD::edge_type ¶bola, const Lines &lines);
|
||||
static Parabola get_parabola(const VD::edge_type &edge, const Lines &lines);
|
||||
|
@ -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)
|
||||
|
@ -5,19 +5,14 @@
|
||||
using namespace Slic3r;
|
||||
using namespace Slic3r::sla;
|
||||
|
||||
void parabola_check(const Parabola ¶bola,
|
||||
const Point & from,
|
||||
const Point & to)
|
||||
void parabola_check_length(const ParabolaSegment ¶bola)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
|
46
tests/sla_print/sla_voronoi_graph_tests.cpp
Normal file
46
tests/sla_print/sla_voronoi_graph_tests.cpp
Normal 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);
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user