Merge branch 'master' of https://github.com/prusa3d/PrusaSlicer into et_perspective_camera

This commit is contained in:
Enrico Turri 2019-06-19 14:33:31 +02:00
commit 5dcc6c7f36
25 changed files with 1333 additions and 899 deletions

View file

@ -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

View file

@ -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

View 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));
}
}

View 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

View file

@ -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