mirror of
https://git.mirrors.martin98.com/https://github.com/prusa3d/PrusaSlicer.git
synced 2025-08-13 23:35:59 +08:00
Refactoring of VoronoiUtils::discretizeParabola() to remove PointMatrix.
This commit is contained in:
parent
5f37d422f0
commit
4b6a6379fc
@ -7,6 +7,7 @@
|
||||
|
||||
#include "linearAlg2D.hpp"
|
||||
#include "VoronoiUtils.hpp"
|
||||
#include "libslic3r/Geometry/VoronoiUtils.hpp"
|
||||
|
||||
namespace Slic3r::Arachne
|
||||
{
|
||||
@ -85,164 +86,95 @@ const VoronoiUtils::Segment &VoronoiUtils::getSourceSegment(const vd_t::cell_typ
|
||||
return segments[cell.source_index()];
|
||||
}
|
||||
|
||||
class PointMatrix
|
||||
{
|
||||
public:
|
||||
double matrix[4];
|
||||
|
||||
PointMatrix()
|
||||
{
|
||||
matrix[0] = 1;
|
||||
matrix[1] = 0;
|
||||
matrix[2] = 0;
|
||||
matrix[3] = 1;
|
||||
}
|
||||
|
||||
PointMatrix(double rotation)
|
||||
{
|
||||
rotation = rotation / 180 * M_PI;
|
||||
matrix[0] = cos(rotation);
|
||||
matrix[1] = -sin(rotation);
|
||||
matrix[2] = -matrix[1];
|
||||
matrix[3] = matrix[0];
|
||||
}
|
||||
|
||||
PointMatrix(const Point p)
|
||||
{
|
||||
matrix[0] = p.x();
|
||||
matrix[1] = p.y();
|
||||
double f = sqrt((matrix[0] * matrix[0]) + (matrix[1] * matrix[1]));
|
||||
matrix[0] /= f;
|
||||
matrix[1] /= f;
|
||||
matrix[2] = -matrix[1];
|
||||
matrix[3] = matrix[0];
|
||||
}
|
||||
|
||||
static PointMatrix scale(double s)
|
||||
{
|
||||
PointMatrix ret;
|
||||
ret.matrix[0] = s;
|
||||
ret.matrix[3] = s;
|
||||
return ret;
|
||||
}
|
||||
|
||||
Point apply(const Point p) const
|
||||
{
|
||||
return Point(coord_t(p.x() * matrix[0] + p.y() * matrix[1]), coord_t(p.x() * matrix[2] + p.y() * matrix[3]));
|
||||
}
|
||||
|
||||
Point unapply(const Point p) const
|
||||
{
|
||||
return Point(coord_t(p.x() * matrix[0] + p.y() * matrix[2]), coord_t(p.x() * matrix[1] + p.y() * matrix[3]));
|
||||
}
|
||||
};
|
||||
Points VoronoiUtils::discretizeParabola(const Point& p, const Segment& segment, Point s, Point e, coord_t approximate_step_size, float transitioning_angle)
|
||||
Points VoronoiUtils::discretizeParabola(const Point &source_point, const Segment &source_segment, const Point &start, const Point &end, const coord_t approximate_step_size, float transitioning_angle)
|
||||
{
|
||||
Points discretized;
|
||||
// x is distance of point projected on the segment ab
|
||||
// xx is point projected on the segment ab
|
||||
const Point a = segment.from();
|
||||
const Point b = segment.to();
|
||||
const Point ab = b - a;
|
||||
const Point as = s - a;
|
||||
const Point ae = e - a;
|
||||
const Point a = source_segment.from();
|
||||
const Point b = source_segment.to();
|
||||
const Point ab = b - a;
|
||||
const Point as = start - a;
|
||||
const Point ae = end - a;
|
||||
const coord_t ab_size = ab.cast<int64_t>().norm();
|
||||
const coord_t sx = as.cast<int64_t>().dot(ab.cast<int64_t>()) / ab_size;
|
||||
const coord_t ex = ae.cast<int64_t>().dot(ab.cast<int64_t>()) / ab_size;
|
||||
const coord_t sxex = ex - sx;
|
||||
const coord_t sx = as.cast<int64_t>().dot(ab.cast<int64_t>()) / ab_size;
|
||||
const coord_t ex = ae.cast<int64_t>().dot(ab.cast<int64_t>()) / ab_size;
|
||||
const coord_t sxex = ex - sx;
|
||||
|
||||
assert((as.cast<int64_t>().dot(ab.cast<int64_t>()) / int64_t(ab_size)) <= std::numeric_limits<coord_t>::max());
|
||||
assert((ae.cast<int64_t>().dot(ab.cast<int64_t>()) / int64_t(ab_size)) <= std::numeric_limits<coord_t>::max());
|
||||
|
||||
const Point ap = p - a;
|
||||
const Point ap = source_point - a;
|
||||
const coord_t px = ap.cast<int64_t>().dot(ab.cast<int64_t>()) / ab_size;
|
||||
|
||||
assert((ap.cast<int64_t>().dot(ab.cast<int64_t>()) / int64_t(ab_size)) <= std::numeric_limits<coord_t>::max());
|
||||
|
||||
Point pxx;
|
||||
Line(a, b).distance_to_infinite_squared(p, &pxx);
|
||||
const Point ppxx = pxx - p;
|
||||
const coord_t d = ppxx.cast<int64_t>().norm();
|
||||
const PointMatrix rot = PointMatrix(perp(ppxx));
|
||||
Line(a, b).distance_to_infinite_squared(source_point, &pxx);
|
||||
const Point ppxx = pxx - source_point;
|
||||
const coord_t d = ppxx.cast<int64_t>().norm();
|
||||
|
||||
if (d == 0)
|
||||
{
|
||||
discretized.emplace_back(s);
|
||||
discretized.emplace_back(e);
|
||||
const Vec2d rot = perp(ppxx).cast<double>().normalized();
|
||||
const double rot_cos_theta = rot.x();
|
||||
const double rot_sin_theta = rot.y();
|
||||
|
||||
if (d == 0) {
|
||||
discretized.emplace_back(start);
|
||||
discretized.emplace_back(end);
|
||||
return discretized;
|
||||
}
|
||||
|
||||
const float marking_bound = atan(transitioning_angle * 0.5);
|
||||
int64_t msx = - marking_bound * int64_t(d); // projected marking_start
|
||||
int64_t mex = marking_bound * int64_t(d); // projected marking_end
|
||||
|
||||
assert(msx <= std::numeric_limits<coord_t>::max());
|
||||
assert(double(msx) * double(msx) <= double(std::numeric_limits<int64_t>::max()));
|
||||
assert(mex <= std::numeric_limits<coord_t>::max());
|
||||
assert(double(msx) * double(msx) / double(2 * d) + double(d / 2) <= std::numeric_limits<coord_t>::max());
|
||||
const double marking_bound = atan(transitioning_angle * 0.5);
|
||||
int64_t msx = -marking_bound * int64_t(d); // projected marking_start
|
||||
int64_t mex = marking_bound * int64_t(d); // projected marking_end
|
||||
|
||||
const coord_t marking_start_end_h = msx * msx / (2 * d) + d / 2;
|
||||
Point marking_start = rot.unapply(Point(coord_t(msx), marking_start_end_h)) + pxx;
|
||||
Point marking_end = rot.unapply(Point(coord_t(mex), marking_start_end_h)) + pxx;
|
||||
const int dir = (sx > ex) ? -1 : 1;
|
||||
if (dir < 0)
|
||||
{
|
||||
Point marking_start = Point(coord_t(msx), marking_start_end_h).rotated(rot_cos_theta, rot_sin_theta) + pxx;
|
||||
Point marking_end = Point(coord_t(mex), marking_start_end_h).rotated(rot_cos_theta, rot_sin_theta) + pxx;
|
||||
const int dir = (sx > ex) ? -1 : 1;
|
||||
if (dir < 0) {
|
||||
std::swap(marking_start, marking_end);
|
||||
std::swap(msx, mex);
|
||||
}
|
||||
|
||||
|
||||
bool add_marking_start = msx * int64_t(dir) > int64_t(sx - px) * int64_t(dir) && msx * int64_t(dir) < int64_t(ex - px) * int64_t(dir);
|
||||
bool add_marking_end = mex * int64_t(dir) > int64_t(sx - px) * int64_t(dir) && mex * int64_t(dir) < int64_t(ex - px) * int64_t(dir);
|
||||
bool add_marking_end = mex * int64_t(dir) > int64_t(sx - px) * int64_t(dir) && mex * int64_t(dir) < int64_t(ex - px) * int64_t(dir);
|
||||
|
||||
const Point apex = rot.unapply(Point(0, d / 2)) + pxx;
|
||||
bool add_apex = int64_t(sx - px) * int64_t(dir) < 0 && int64_t(ex - px) * int64_t(dir) > 0;
|
||||
const Point apex = Point(0, d / 2).rotated(rot_cos_theta, rot_sin_theta) + pxx;
|
||||
bool add_apex = int64_t(sx - px) * int64_t(dir) < 0 && int64_t(ex - px) * int64_t(dir) > 0;
|
||||
|
||||
assert(!(add_marking_start && add_marking_end) || add_apex);
|
||||
if(add_marking_start && add_marking_end && !add_apex)
|
||||
{
|
||||
assert(!add_marking_start || !add_marking_end || add_apex);
|
||||
if (add_marking_start && add_marking_end && !add_apex)
|
||||
BOOST_LOG_TRIVIAL(warning) << "Failing to discretize parabola! Must add an apex or one of the endpoints.";
|
||||
}
|
||||
|
||||
const coord_t step_count = static_cast<coord_t>(static_cast<float>(std::abs(ex - sx)) / approximate_step_size + 0.5);
|
||||
|
||||
discretized.emplace_back(s);
|
||||
for (coord_t step = 1; step < step_count; step++)
|
||||
{
|
||||
assert(double(sxex) * double(step) <= double(std::numeric_limits<int64_t>::max()));
|
||||
|
||||
const coord_t step_count = lround(static_cast<double>(std::abs(ex - sx)) / approximate_step_size);
|
||||
discretized.emplace_back(start);
|
||||
for (coord_t step = 1; step < step_count; ++step) {
|
||||
const int64_t x = int64_t(sx) + int64_t(sxex) * int64_t(step) / int64_t(step_count) - int64_t(px);
|
||||
assert(double(x) * double(x) <= double(std::numeric_limits<int64_t>::max()));
|
||||
assert(double(x) * double(x) / double(2 * d) + double(d / 2) <= double(std::numeric_limits<int64_t>::max()));
|
||||
const int64_t y = int64_t(x) * int64_t(x) / int64_t(2 * d) + int64_t(d / 2);
|
||||
|
||||
if (add_marking_start && msx * int64_t(dir) < int64_t(x) * int64_t(dir))
|
||||
{
|
||||
|
||||
if (add_marking_start && msx * int64_t(dir) < int64_t(x) * int64_t(dir)) {
|
||||
discretized.emplace_back(marking_start);
|
||||
add_marking_start = false;
|
||||
}
|
||||
if (add_apex && int64_t(x) * int64_t(dir) > 0)
|
||||
{
|
||||
|
||||
if (add_apex && int64_t(x) * int64_t(dir) > 0) {
|
||||
discretized.emplace_back(apex);
|
||||
add_apex = false; // only add the apex just before the
|
||||
add_apex = false; // only add the apex just before the
|
||||
}
|
||||
if (add_marking_end && mex * int64_t(dir) < int64_t(x) * int64_t(dir))
|
||||
{
|
||||
|
||||
if (add_marking_end && mex * int64_t(dir) < int64_t(x) * int64_t(dir)) {
|
||||
discretized.emplace_back(marking_end);
|
||||
add_marking_end = false;
|
||||
}
|
||||
assert(x <= std::numeric_limits<coord_t>::max() && x >= std::numeric_limits<coord_t>::lowest());
|
||||
assert(y <= std::numeric_limits<coord_t>::max() && y >= std::numeric_limits<coord_t>::lowest());
|
||||
const Point result = rot.unapply(Point(x, y)) + pxx;
|
||||
|
||||
assert(Geometry::VoronoiUtils::is_in_range<coord_t>(x) && Geometry::VoronoiUtils::is_in_range<coord_t>(y));
|
||||
const Point result = Point(x, y).rotated(rot_cos_theta, rot_sin_theta) + pxx;
|
||||
discretized.emplace_back(result);
|
||||
}
|
||||
|
||||
if (add_apex)
|
||||
{
|
||||
discretized.emplace_back(apex);
|
||||
}
|
||||
|
||||
if (add_marking_end)
|
||||
{
|
||||
discretized.emplace_back(marking_end);
|
||||
}
|
||||
discretized.emplace_back(e);
|
||||
|
||||
discretized.emplace_back(end);
|
||||
return discretized;
|
||||
}
|
||||
|
||||
|
@ -34,7 +34,7 @@ public:
|
||||
* Discretize a parabola based on (approximate) step size.
|
||||
* The \p approximate_step_size is measured parallel to the \p source_segment, not along the parabola.
|
||||
*/
|
||||
static Points discretizeParabola(const Point &source_point, const Segment &source_segment, Point start, Point end, coord_t approximate_step_size, float transitioning_angle);
|
||||
static Points discretizeParabola(const Point &source_point, const Segment &source_segment, const Point& start, const Point &end, coord_t approximate_step_size, float transitioning_angle);
|
||||
|
||||
static inline bool is_finite(const VoronoiUtils::vd_t::vertex_type &vertex)
|
||||
{
|
||||
|
@ -214,6 +214,8 @@ set(SLIC3R_SOURCES
|
||||
Geometry/Voronoi.hpp
|
||||
Geometry/VoronoiOffset.cpp
|
||||
Geometry/VoronoiOffset.hpp
|
||||
Geometry/VoronoiUtils.hpp
|
||||
Geometry/VoronoiUtils.cpp
|
||||
Geometry/VoronoiVisualUtils.hpp
|
||||
Int128.hpp
|
||||
JumpPointSearch.cpp
|
||||
@ -464,7 +466,6 @@ set(SLIC3R_SOURCES
|
||||
BranchingTree/BranchingTree.hpp
|
||||
BranchingTree/PointCloud.cpp
|
||||
BranchingTree/PointCloud.hpp
|
||||
|
||||
Arachne/BeadingStrategy/BeadingStrategy.hpp
|
||||
Arachne/BeadingStrategy/BeadingStrategy.cpp
|
||||
Arachne/BeadingStrategy/BeadingStrategyFactory.hpp
|
||||
|
10
src/libslic3r/Geometry/VoronoiUtils.cpp
Normal file
10
src/libslic3r/Geometry/VoronoiUtils.cpp
Normal file
@ -0,0 +1,10 @@
|
||||
#include "VoronoiUtils.hpp"
|
||||
|
||||
namespace Slic3r::Geometry {
|
||||
|
||||
bool VoronoiUtils::is_finite(const VD::vertex_type &vertex)
|
||||
{
|
||||
return std::isfinite(vertex.x()) && std::isfinite(vertex.y());
|
||||
}
|
||||
|
||||
} // namespace Slic3r::Geometry
|
36
src/libslic3r/Geometry/VoronoiUtils.hpp
Normal file
36
src/libslic3r/Geometry/VoronoiUtils.hpp
Normal file
@ -0,0 +1,36 @@
|
||||
#ifndef slic3r_VoronoiUtils_hpp_
|
||||
#define slic3r_VoronoiUtils_hpp_
|
||||
|
||||
#include "libslic3r/Geometry/Voronoi.hpp"
|
||||
|
||||
using VD = Slic3r::Geometry::VoronoiDiagram;
|
||||
|
||||
namespace Slic3r::Geometry {
|
||||
|
||||
class VoronoiUtils
|
||||
{
|
||||
public:
|
||||
static bool is_finite(const VD::vertex_type &vertex);
|
||||
|
||||
template<typename T> static bool is_in_range(double value)
|
||||
{
|
||||
return double(std::numeric_limits<T>::lowest()) <= value && value <= double(std::numeric_limits<T>::max());
|
||||
}
|
||||
|
||||
template<typename T> static bool is_in_range(const VD::vertex_type &vertex)
|
||||
{
|
||||
return VoronoiUtils::is_finite(vertex) && is_in_range<T>(vertex.x()) && is_in_range<T>(vertex.y());
|
||||
}
|
||||
|
||||
template<typename T> static bool is_in_range(const VD::edge_type &edge)
|
||||
{
|
||||
if (edge.vertex0() == nullptr || edge.vertex1() == nullptr)
|
||||
return false;
|
||||
|
||||
return is_in_range<T>(*edge.vertex0()) && is_in_range<T>(*edge.vertex1());
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace Slic3r::Geometry
|
||||
|
||||
#endif // slic3r_VoronoiUtils_hpp_
|
Loading…
x
Reference in New Issue
Block a user