mirror of
https://github.com/SoftFever/OrcaSlicer.git
synced 2025-10-29 03:31:17 -06:00
Merge branch 'master' of https://github.com/prusa3d/PrusaSlicer into et_perspective_camera
This commit is contained in:
commit
5dcc6c7f36
25 changed files with 1333 additions and 899 deletions
|
|
@ -160,6 +160,8 @@ add_library(libslic3r STATIC
|
|||
MTUtils.hpp
|
||||
Zipper.hpp
|
||||
Zipper.cpp
|
||||
MinAreaBoundingBox.hpp
|
||||
MinAreaBoundingBox.cpp
|
||||
miniz_extension.hpp
|
||||
miniz_extension.cpp
|
||||
SLA/SLABoilerPlate.hpp
|
||||
|
|
|
|||
|
|
@ -37,6 +37,8 @@
|
|||
* *
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef SLIC3R_INT128_HPP
|
||||
#define SLIC3R_INT128_HPP
|
||||
// #define SLIC3R_DEBUG
|
||||
|
||||
// Make assert active if SLIC3R_DEBUG
|
||||
|
|
@ -48,6 +50,8 @@
|
|||
#endif
|
||||
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
#include <cmath>
|
||||
|
||||
#if ! defined(_MSC_VER) && defined(__SIZEOF_INT128__)
|
||||
#define HAS_INTRINSIC_128_TYPE
|
||||
|
|
@ -293,3 +297,5 @@ public:
|
|||
return sign_determinant_2x2(p1, q1, p2, q2) * invert;
|
||||
}
|
||||
};
|
||||
|
||||
#endif // SLIC3R_INT128_HPP
|
||||
|
|
|
|||
142
src/libslic3r/MinAreaBoundingBox.cpp
Normal file
142
src/libslic3r/MinAreaBoundingBox.cpp
Normal file
|
|
@ -0,0 +1,142 @@
|
|||
#include "MinAreaBoundingBox.hpp"
|
||||
|
||||
#include <libslic3r/ExPolygon.hpp>
|
||||
#include <boost/rational.hpp>
|
||||
|
||||
#include <libslic3r/Int128.hpp>
|
||||
|
||||
#if !defined(HAS_INTRINSIC_128_TYPE) || defined(__APPLE__)
|
||||
#include <boost/multiprecision/integer.hpp>
|
||||
#endif
|
||||
|
||||
#include <libnest2d/geometry_traits.hpp>
|
||||
#include <libnest2d/utils/rotcalipers.hpp>
|
||||
|
||||
namespace libnest2d {
|
||||
|
||||
template<> struct PointType<Slic3r::Points> { using Type = Slic3r::Point; };
|
||||
template<> struct CoordType<Slic3r::Point> { using Type = coord_t; };
|
||||
template<> struct ShapeTag<Slic3r::ExPolygon> { using Type = PolygonTag; };
|
||||
template<> struct ShapeTag<Slic3r::Polygon> { using Type = PolygonTag; };
|
||||
template<> struct ShapeTag<Slic3r::Points> { using Type = PathTag; };
|
||||
template<> struct ShapeTag<Slic3r::Point> { using Type = PointTag; };
|
||||
template<> struct ContourType<Slic3r::ExPolygon> { using Type = Slic3r::Points; };
|
||||
template<> struct ContourType<Slic3r::Polygon> { using Type = Slic3r::Points; };
|
||||
|
||||
namespace pointlike {
|
||||
|
||||
template<> inline coord_t x(const Slic3r::Point& p) { return p.x(); }
|
||||
template<> inline coord_t y(const Slic3r::Point& p) { return p.y(); }
|
||||
template<> inline coord_t& x(Slic3r::Point& p) { return p.x(); }
|
||||
template<> inline coord_t& y(Slic3r::Point& p) { return p.y(); }
|
||||
|
||||
} // pointlike
|
||||
|
||||
namespace shapelike {
|
||||
template<> inline Slic3r::Points& contour(Slic3r::ExPolygon& sh) { return sh.contour.points; }
|
||||
template<> inline const Slic3r::Points& contour(const Slic3r::ExPolygon& sh) { return sh.contour.points; }
|
||||
template<> inline Slic3r::Points& contour(Slic3r::Polygon& sh) { return sh.points; }
|
||||
template<> inline const Slic3r::Points& contour(const Slic3r::Polygon& sh) { return sh.points; }
|
||||
|
||||
template<> Slic3r::Points::iterator begin(Slic3r::Points& pts, const PathTag&) { return pts.begin();}
|
||||
template<> Slic3r::Points::const_iterator cbegin(const Slic3r::Points& pts, const PathTag&) { return pts.begin(); }
|
||||
template<> Slic3r::Points::iterator end(Slic3r::Points& pts, const PathTag&) { return pts.end();}
|
||||
template<> Slic3r::Points::const_iterator cend(const Slic3r::Points& pts, const PathTag&) { return pts.cend(); }
|
||||
|
||||
template<> inline Slic3r::ExPolygon create<Slic3r::ExPolygon>(Slic3r::Points&& contour)
|
||||
{
|
||||
Slic3r::ExPolygon expoly; expoly.contour.points.swap(contour);
|
||||
return expoly;
|
||||
}
|
||||
|
||||
template<> inline Slic3r::Polygon create<Slic3r::Polygon>(Slic3r::Points&& contour)
|
||||
{
|
||||
Slic3r::Polygon poly; poly.points.swap(contour);
|
||||
return poly;
|
||||
}
|
||||
|
||||
} // shapelike
|
||||
} // libnest2d
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
// Used as compute type.
|
||||
using Unit = int64_t;
|
||||
|
||||
#if !defined(HAS_INTRINSIC_128_TYPE) || defined(__APPLE__)
|
||||
using Rational = boost::rational<boost::multiprecision::int128_t>;
|
||||
#else
|
||||
using Rational = boost::rational<__int128>;
|
||||
#endif
|
||||
|
||||
MinAreaBoundigBox::MinAreaBoundigBox(const Polygon &p, PolygonLevel pc)
|
||||
{
|
||||
const Polygon& chull = pc == pcConvex ? p : libnest2d::sl::convexHull(p);
|
||||
|
||||
libnest2d::RotatedBox<Point, Unit> box =
|
||||
libnest2d::minAreaBoundingBox<Polygon, Unit, Rational>(chull);
|
||||
|
||||
m_right = box.right_extent();
|
||||
m_bottom = box.bottom_extent();
|
||||
m_axis = box.axis();
|
||||
}
|
||||
|
||||
MinAreaBoundigBox::MinAreaBoundigBox(const ExPolygon &p, PolygonLevel pc)
|
||||
{
|
||||
const ExPolygon& chull = pc == pcConvex ? p : libnest2d::sl::convexHull(p);
|
||||
|
||||
libnest2d::RotatedBox<Point, Unit> box =
|
||||
libnest2d::minAreaBoundingBox<ExPolygon, Unit, Rational>(chull);
|
||||
|
||||
m_right = box.right_extent();
|
||||
m_bottom = box.bottom_extent();
|
||||
m_axis = box.axis();
|
||||
}
|
||||
|
||||
MinAreaBoundigBox::MinAreaBoundigBox(const Points &pts, PolygonLevel pc)
|
||||
{
|
||||
const Points& chull = pc == pcConvex ? pts : libnest2d::sl::convexHull(pts);
|
||||
|
||||
libnest2d::RotatedBox<Point, Unit> box =
|
||||
libnest2d::minAreaBoundingBox<Points, Unit, Rational>(chull);
|
||||
|
||||
m_right = box.right_extent();
|
||||
m_bottom = box.bottom_extent();
|
||||
m_axis = box.axis();
|
||||
}
|
||||
|
||||
double MinAreaBoundigBox::angle_to_X() const
|
||||
{
|
||||
double ret = std::atan2(m_axis.y(), m_axis.x());
|
||||
auto s = std::signbit(ret);
|
||||
if(s) ret += 2 * PI;
|
||||
return -ret;
|
||||
}
|
||||
|
||||
long double MinAreaBoundigBox::width() const
|
||||
{
|
||||
return std::abs(m_bottom) / std::sqrt(libnest2d::pl::magnsq<Point, long double>(m_axis));
|
||||
}
|
||||
|
||||
long double MinAreaBoundigBox::height() const
|
||||
{
|
||||
return std::abs(m_right) / std::sqrt(libnest2d::pl::magnsq<Point, long double>(m_axis));
|
||||
}
|
||||
|
||||
long double MinAreaBoundigBox::area() const
|
||||
{
|
||||
long double asq = libnest2d::pl::magnsq<Point, long double>(m_axis);
|
||||
return m_bottom * m_right / asq;
|
||||
}
|
||||
|
||||
void remove_collinear_points(Polygon &p)
|
||||
{
|
||||
p = libnest2d::removeCollinearPoints<Polygon>(p, Unit(0));
|
||||
}
|
||||
|
||||
void remove_collinear_points(ExPolygon &p)
|
||||
{
|
||||
p = libnest2d::removeCollinearPoints<ExPolygon>(p, Unit(0));
|
||||
}
|
||||
|
||||
}
|
||||
59
src/libslic3r/MinAreaBoundingBox.hpp
Normal file
59
src/libslic3r/MinAreaBoundingBox.hpp
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
#ifndef MINAREABOUNDINGBOX_HPP
|
||||
#define MINAREABOUNDINGBOX_HPP
|
||||
|
||||
#include "libslic3r/Point.hpp"
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
class Polygon;
|
||||
class ExPolygon;
|
||||
|
||||
void remove_collinear_points(Polygon& p);
|
||||
void remove_collinear_points(ExPolygon& p);
|
||||
|
||||
/// A class that holds a rotated bounding box. If instantiated with a polygon
|
||||
/// type it will hold the minimum area bounding box for the given polygon.
|
||||
/// If the input polygon is convex, the complexity is linear to the number of
|
||||
/// points. Otherwise a convex hull of O(n*log(n)) has to be performed.
|
||||
class MinAreaBoundigBox {
|
||||
Point m_axis;
|
||||
long double m_bottom = 0.0l, m_right = 0.0l;
|
||||
public:
|
||||
|
||||
// Polygons can be convex or simple (convex or concave with possible holes)
|
||||
enum PolygonLevel {
|
||||
pcConvex, pcSimple
|
||||
};
|
||||
|
||||
// Constructors with various types of geometry data used in Slic3r.
|
||||
// If the convexity is known apriory, pcConvex can be used to skip
|
||||
// convex hull calculation. It is very important that the input polygons
|
||||
// do NOT have any collinear points (except for the first and the last
|
||||
// vertex being the same -- meaning a closed polygon for boost)
|
||||
// To make sure this constraint is satisfied, you can call
|
||||
// remove_collinear_points on the input polygon before handing over here)
|
||||
explicit MinAreaBoundigBox(const Polygon&, PolygonLevel = pcSimple);
|
||||
explicit MinAreaBoundigBox(const ExPolygon&, PolygonLevel = pcSimple);
|
||||
explicit MinAreaBoundigBox(const Points&, PolygonLevel = pcSimple);
|
||||
|
||||
// Returns the angle in radians needed for the box to be aligned with the
|
||||
// X axis. Rotate the polygon by this angle and it will be aligned.
|
||||
double angle_to_X() const;
|
||||
|
||||
// The box width
|
||||
long double width() const;
|
||||
|
||||
// The box height
|
||||
long double height() const;
|
||||
|
||||
// The box area
|
||||
long double area() const;
|
||||
|
||||
// The axis of the rotated box. If the angle_to_X is not sufficiently
|
||||
// precise, use this unnormalized direction vector.
|
||||
const Point& axis() const { return m_axis; }
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // MINAREABOUNDINGBOX_HPP
|
||||
|
|
@ -9,6 +9,31 @@
|
|||
#include <ClipperUtils.hpp>
|
||||
|
||||
#include <boost/geometry/index/rtree.hpp>
|
||||
#include <boost/multiprecision/integer.hpp>
|
||||
#include <boost/rational.hpp>
|
||||
|
||||
namespace libnest2d {
|
||||
#if !defined(_MSC_VER) && defined(__SIZEOF_INT128__) && !defined(__APPLE__)
|
||||
using LargeInt = __int128;
|
||||
#else
|
||||
using LargeInt = boost::multiprecision::int128_t;
|
||||
template<> struct _NumTag<LargeInt> { using Type = ScalarTag; };
|
||||
#endif
|
||||
template<class T> struct _NumTag<boost::rational<T>> { using Type = RationalTag; };
|
||||
|
||||
namespace nfp {
|
||||
|
||||
template<class S>
|
||||
struct NfpImpl<S, NfpLevel::CONVEX_ONLY>
|
||||
{
|
||||
NfpResult<S> operator()(const S &sh, const S &other)
|
||||
{
|
||||
return nfpConvexOnly<S, boost::rational<LargeInt>>(sh, other);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
|
|
@ -130,7 +155,7 @@ Box boundingBox(const Box& pilebb, const Box& ibb ) {
|
|||
// at the same time, it has to provide reasonable results.
|
||||
std::tuple<double /*score*/, Box /*farthest point from bin center*/>
|
||||
objfunc(const PointImpl& bincenter,
|
||||
const shapelike::Shapes<PolygonImpl>& merged_pile,
|
||||
const TMultiShape<PolygonImpl>& merged_pile,
|
||||
const Box& pilebb,
|
||||
const ItemGroup& items,
|
||||
const Item &item,
|
||||
|
|
@ -293,7 +318,7 @@ class AutoArranger {};
|
|||
// management and spatial index structures for acceleration.
|
||||
template<class TBin>
|
||||
class _ArrBase {
|
||||
protected:
|
||||
public:
|
||||
|
||||
// Useful type shortcuts...
|
||||
using Placer = TPacker<TBin>;
|
||||
|
|
@ -301,7 +326,9 @@ protected:
|
|||
using Packer = Nester<Placer, Selector>;
|
||||
using PConfig = typename Packer::PlacementConfig;
|
||||
using Distance = TCoord<PointImpl>;
|
||||
using Pile = sl::Shapes<PolygonImpl>;
|
||||
using Pile = TMultiShape<PolygonImpl>;
|
||||
|
||||
protected:
|
||||
|
||||
Packer m_pck;
|
||||
PConfig m_pconf; // Placement configuration
|
||||
|
|
@ -539,7 +566,10 @@ public:
|
|||
// 2D shape from top view.
|
||||
using ShapeData2D = std::vector<std::pair<Slic3r::ModelInstance*, Item>>;
|
||||
|
||||
ShapeData2D projectModelFromTop(const Slic3r::Model &model, const WipeTowerInfo& wti) {
|
||||
ShapeData2D projectModelFromTop(const Slic3r::Model &model,
|
||||
const WipeTowerInfo &wti,
|
||||
double tolerance)
|
||||
{
|
||||
ShapeData2D ret;
|
||||
|
||||
// Count all the items on the bin (all the object's instances)
|
||||
|
|
@ -561,21 +591,32 @@ ShapeData2D projectModelFromTop(const Slic3r::Model &model, const WipeTowerInfo&
|
|||
// Object instances should carry the same scaling and
|
||||
// x, y rotation that is why we use the first instance.
|
||||
{
|
||||
ModelInstance *finst = objptr->instances.front();
|
||||
Vec3d rotation = finst->get_rotation();
|
||||
rotation.z() = 0.;
|
||||
Transform3d trafo_instance = Geometry::assemble_transform(Vec3d::Zero(), rotation, finst->get_scaling_factor(), finst->get_mirror());
|
||||
ModelInstance *finst = objptr->instances.front();
|
||||
Vec3d rotation = finst->get_rotation();
|
||||
rotation.z() = 0.;
|
||||
Transform3d trafo_instance = Geometry::assemble_transform(
|
||||
Vec3d::Zero(),
|
||||
rotation,
|
||||
finst->get_scaling_factor(),
|
||||
finst->get_mirror());
|
||||
Polygon p = objptr->convex_hull_2d(trafo_instance);
|
||||
assert(! p.points.empty());
|
||||
|
||||
// this may happen for malformed models, see: https://github.com/prusa3d/PrusaSlicer/issues/2209
|
||||
if (p.points.empty())
|
||||
continue;
|
||||
|
||||
assert(!p.points.empty());
|
||||
|
||||
// this may happen for malformed models, see:
|
||||
// https://github.com/prusa3d/PrusaSlicer/issues/2209
|
||||
if (p.points.empty()) continue;
|
||||
|
||||
if(tolerance > EPSILON) {
|
||||
Polygons pp { p };
|
||||
pp = p.simplify(double(scaled(tolerance)));
|
||||
if (!pp.empty()) p = pp.front();
|
||||
}
|
||||
|
||||
p.reverse();
|
||||
assert(!p.is_counter_clockwise());
|
||||
p.append(p.first_point());
|
||||
clpath = Slic3rMultiPoint_to_ClipperPath(p);
|
||||
auto firstp = clpath.front(); clpath.emplace_back(firstp);
|
||||
}
|
||||
|
||||
Vec3d rotation0 = objptr->instances.front()->get_rotation();
|
||||
|
|
@ -589,7 +630,7 @@ ShapeData2D projectModelFromTop(const Slic3r::Model &model, const WipeTowerInfo&
|
|||
|
||||
// Invalid geometries would throw exceptions when arranging
|
||||
if(item.vertexCount() > 3) {
|
||||
item.rotation(float(Geometry::rotation_diff_z(rotation0, objinst->get_rotation()))),
|
||||
item.rotation(Geometry::rotation_diff_z(rotation0, objinst->get_rotation()));
|
||||
item.translation({
|
||||
ClipperLib::cInt(objinst->get_offset(X)/SCALING_FACTOR),
|
||||
ClipperLib::cInt(objinst->get_offset(Y)/SCALING_FACTOR)
|
||||
|
|
@ -741,6 +782,8 @@ BedShapeHint bedShape(const Polyline &bed) {
|
|||
return ret;
|
||||
}
|
||||
|
||||
static const SLIC3R_CONSTEXPR double SIMPLIFY_TOLERANCE_MM = 0.1;
|
||||
|
||||
// The final client function to arrange the Model. A progress indicator and
|
||||
// a stop predicate can be also be passed to control the process.
|
||||
bool arrange(Model &model, // The model with the geometries
|
||||
|
|
@ -755,9 +798,9 @@ bool arrange(Model &model, // The model with the geometries
|
|||
std::function<bool ()> stopcondition)
|
||||
{
|
||||
bool ret = true;
|
||||
|
||||
|
||||
// Get the 2D projected shapes with their 3D model instance pointers
|
||||
auto shapemap = arr::projectModelFromTop(model, wti);
|
||||
auto shapemap = arr::projectModelFromTop(model, wti, SIMPLIFY_TOLERANCE_MM);
|
||||
|
||||
// Copy the references for the shapes only as the arranger expects a
|
||||
// sequence of objects convertible to Item or ClipperPolygon
|
||||
|
|
@ -782,7 +825,7 @@ bool arrange(Model &model, // The model with the geometries
|
|||
static_cast<libnest2d::Coord>(bbb.min(0)),
|
||||
static_cast<libnest2d::Coord>(bbb.min(1))
|
||||
},
|
||||
{
|
||||
{
|
||||
static_cast<libnest2d::Coord>(bbb.max(0)),
|
||||
static_cast<libnest2d::Coord>(bbb.max(1))
|
||||
});
|
||||
|
|
@ -856,9 +899,9 @@ void find_new_position(const Model &model,
|
|||
coord_t min_obj_distance,
|
||||
const Polyline &bed,
|
||||
WipeTowerInfo& wti)
|
||||
{
|
||||
{
|
||||
// Get the 2D projected shapes with their 3D model instance pointers
|
||||
auto shapemap = arr::projectModelFromTop(model, wti);
|
||||
auto shapemap = arr::projectModelFromTop(model, wti, SIMPLIFY_TOLERANCE_MM);
|
||||
|
||||
// Copy the references for the shapes only as the arranger expects a
|
||||
// sequence of objects convertible to Item or ClipperPolygon
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue