Still WIP
This commit is contained in:
parent
cb3a586deb
commit
253ec07cb2
@ -19,7 +19,7 @@ AlwaysBreakAfterDefinitionReturnType: None
|
|||||||
AlwaysBreakAfterReturnType: None
|
AlwaysBreakAfterReturnType: None
|
||||||
AlwaysBreakBeforeMultilineStrings: false
|
AlwaysBreakBeforeMultilineStrings: false
|
||||||
AlwaysBreakTemplateDeclarations: false
|
AlwaysBreakTemplateDeclarations: false
|
||||||
BinPackArguments: false
|
BinPackArguments: true
|
||||||
BinPackParameters: false
|
BinPackParameters: false
|
||||||
BraceWrapping:
|
BraceWrapping:
|
||||||
AfterClass: true
|
AfterClass: true
|
||||||
|
@ -901,7 +901,7 @@ private:
|
|||||||
selector_.template packItems<PlacementStrategy>(
|
selector_.template packItems<PlacementStrategy>(
|
||||||
from, to, bin_, pconfig_);
|
from, to, bin_, pconfig_);
|
||||||
|
|
||||||
if(min_obj_distance_ > 0) std::for_each(from, to, [this](Item& item) {
|
if(min_obj_distance_ > 0) std::for_each(from, to, [](Item& item) {
|
||||||
item.removeOffset();
|
item.removeOffset();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
#include "ModelArrange.hpp"
|
#include "Arrange.hpp"
|
||||||
#include "Geometry.hpp"
|
#include "Geometry.hpp"
|
||||||
#include "SVG.hpp"
|
#include "SVG.hpp"
|
||||||
#include "MTUtils.hpp"
|
#include "MTUtils.hpp"
|
||||||
@ -46,7 +46,14 @@ template<class S> struct NfpImpl<S, NfpLevel::CONVEX_ONLY>
|
|||||||
|
|
||||||
namespace Slic3r {
|
namespace Slic3r {
|
||||||
|
|
||||||
namespace arr {
|
template<class Tout = double, class = FloatingOnly<Tout>>
|
||||||
|
inline SLIC3R_CONSTEXPR EigenVec<Tout, 2> unscaled(
|
||||||
|
const ClipperLib::IntPoint &v) SLIC3R_NOEXCEPT
|
||||||
|
{
|
||||||
|
return EigenVec<Tout, 2>{unscaled<Tout>(v.X), unscaled<Tout>(v.Y)};
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace arrangement {
|
||||||
|
|
||||||
using namespace libnest2d;
|
using namespace libnest2d;
|
||||||
namespace clppr = ClipperLib;
|
namespace clppr = ClipperLib;
|
||||||
@ -328,7 +335,6 @@ void fillConfig(PConf& pcfg) {
|
|||||||
template<class TBin>
|
template<class TBin>
|
||||||
class AutoArranger {};
|
class AutoArranger {};
|
||||||
|
|
||||||
|
|
||||||
// A class encapsulating the libnest2d Nester class and extending it with other
|
// A class encapsulating the libnest2d Nester class and extending it with other
|
||||||
// management and spatial index structures for acceleration.
|
// management and spatial index structures for acceleration.
|
||||||
template<class TBin>
|
template<class TBin>
|
||||||
@ -360,7 +366,7 @@ public:
|
|||||||
std::function<void(unsigned)> progressind,
|
std::function<void(unsigned)> progressind,
|
||||||
std::function<bool(void)> stopcond):
|
std::function<bool(void)> stopcond):
|
||||||
m_pck(bin, dist), m_bin_area(sl::area(bin)),
|
m_pck(bin, dist), m_bin_area(sl::area(bin)),
|
||||||
m_norm(std::sqrt(sl::area(bin)))
|
m_norm(std::sqrt(m_bin_area))
|
||||||
{
|
{
|
||||||
fillConfig(m_pconf);
|
fillConfig(m_pconf);
|
||||||
|
|
||||||
@ -392,8 +398,8 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
m_pck.progressIndicator(progressind);
|
if (progressind) m_pck.progressIndicator(progressind);
|
||||||
m_pck.stopCondition(stopcond);
|
if (stopcond) m_pck.stopCondition(stopcond);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class...Args> inline PackGroup operator()(Args&&...args) {
|
template<class...Args> inline PackGroup operator()(Args&&...args) {
|
||||||
@ -545,35 +551,6 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Specialization with no bin. In this case the arranger should just arrange
|
|
||||||
// all objects into a minimum sized pile but it is not limited by a bin. A
|
|
||||||
// consequence is that only one pile should be created.
|
|
||||||
template<> class AutoArranger<bool>: public _ArrBase<Box> {
|
|
||||||
public:
|
|
||||||
|
|
||||||
AutoArranger(bool, Distance dist, std::function<void(unsigned)> progressind,
|
|
||||||
std::function<bool(void)> stopcond):
|
|
||||||
_ArrBase<Box>(Box(0, 0), dist, progressind, stopcond)
|
|
||||||
{
|
|
||||||
this->m_pconf.object_function = [this] (const Item &item) {
|
|
||||||
|
|
||||||
auto result = objfunc({0, 0},
|
|
||||||
m_merged_pile,
|
|
||||||
m_pilebb,
|
|
||||||
m_items,
|
|
||||||
item,
|
|
||||||
0,
|
|
||||||
m_norm,
|
|
||||||
m_rtree,
|
|
||||||
m_smallsrtree,
|
|
||||||
m_remaining);
|
|
||||||
return std::get<0>(result);
|
|
||||||
};
|
|
||||||
|
|
||||||
this->m_pck.configure(m_pconf);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Get the type of bed geometry from a simple vector of points.
|
// Get the type of bed geometry from a simple vector of points.
|
||||||
BedShapeHint bedShape(const Polyline &bed) {
|
BedShapeHint bedShape(const Polyline &bed) {
|
||||||
BedShapeHint ret;
|
BedShapeHint ret;
|
||||||
@ -653,19 +630,6 @@ BedShapeHint bedShape(const Polyline &bed) {
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
//static const SLIC3R_CONSTEXPR double SIMPLIFY_TOLERANCE_MM = 0.1;
|
|
||||||
|
|
||||||
//template<class BinT>
|
|
||||||
//PackGroup _arrange(std::vector<Item> & items,
|
|
||||||
// const BinT & bin,
|
|
||||||
// coord_t minobjd,
|
|
||||||
// std::function<void(unsigned)> prind,
|
|
||||||
// std::function<bool()> stopfn)
|
|
||||||
//{
|
|
||||||
// AutoArranger<BinT> arranger{bin, minobjd, prind, stopfn};
|
|
||||||
// return arranger(items.begin(), items.end());
|
|
||||||
//}
|
|
||||||
|
|
||||||
template<class BinT>
|
template<class BinT>
|
||||||
PackGroup _arrange(std::vector<Item> & shapes,
|
PackGroup _arrange(std::vector<Item> & shapes,
|
||||||
const PackGroup & preshapes,
|
const PackGroup & preshapes,
|
||||||
@ -674,44 +638,34 @@ PackGroup _arrange(std::vector<Item> & shapes,
|
|||||||
std::function<void(unsigned)> prind,
|
std::function<void(unsigned)> prind,
|
||||||
std::function<bool()> stopfn)
|
std::function<bool()> stopfn)
|
||||||
{
|
{
|
||||||
|
|
||||||
// auto binbb = sl::boundingBox(bin);
|
|
||||||
|
|
||||||
AutoArranger<BinT> arranger{bin, minobjd, prind, stopfn};
|
AutoArranger<BinT> arranger{bin, minobjd, prind, stopfn};
|
||||||
|
|
||||||
if(!preshapes.front().empty()) { // If there is something on the plate
|
// If there is something on the plate
|
||||||
|
if(!preshapes.empty() && !preshapes.front().empty()) {
|
||||||
arranger.preload(preshapes);
|
arranger.preload(preshapes);
|
||||||
|
auto binbb = sl::boundingBox(bin);
|
||||||
|
|
||||||
// Try to put the first item to the center, as the arranger will not
|
// Try to put the first item to the center, as the arranger will not
|
||||||
// do this for us.
|
// do this for us.
|
||||||
// auto shptrit = minstances.begin();
|
for (auto it = shapes.begin(); it != shapes.end(); ++it) {
|
||||||
// for(auto shit = shapes.begin(); shit != shapes.end(); ++shit, ++shptrit)
|
Item &itm = *it;
|
||||||
// {
|
auto ibb = itm.boundingBox();
|
||||||
// // Try to place items to the center
|
auto d = binbb.center() - ibb.center();
|
||||||
// Item& itm = *shit;
|
itm.translate(d);
|
||||||
// auto ibb = itm.boundingBox();
|
|
||||||
// auto d = binbb.center() - ibb.center();
|
|
||||||
// itm.translate(d);
|
|
||||||
// if(!arranger.is_colliding(itm)) {
|
|
||||||
// arranger.preload({{itm}});
|
|
||||||
|
|
||||||
// auto offset = itm.translation();
|
if (!arranger.is_colliding(itm)) {
|
||||||
// Radians rot = itm.rotation();
|
arranger.preload({{itm}});
|
||||||
// ModelInstance *minst = *shptrit;
|
|
||||||
|
|
||||||
// Vec3d foffset(unscaled(offset.X),
|
// Write the transformation data into the item. The callback
|
||||||
// unscaled(offset.Y),
|
// was set on the instantiation of Item and calls the
|
||||||
// minst->get_offset()(Z));
|
// Arrangeable interface.
|
||||||
|
it->callApplyFunction(0);
|
||||||
|
|
||||||
// // write the transformation data into the model instance
|
// Remove this item, as it is arranged now
|
||||||
// minst->set_rotation(Z, rot);
|
it = shapes.erase(it);
|
||||||
// minst->set_offset(foffset);
|
break;
|
||||||
|
}
|
||||||
// shit = shapes.erase(shit);
|
}
|
||||||
// shptrit = minstances.erase(shptrit);
|
|
||||||
// break;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return arranger(shapes.begin(), shapes.end());
|
return arranger(shapes.begin(), shapes.end());
|
||||||
@ -724,8 +678,8 @@ inline SLIC3R_CONSTEXPR coord_t stride_padding(coord_t w)
|
|||||||
|
|
||||||
//// The final client function to arrange the Model. A progress indicator and
|
//// The final client function to arrange the Model. A progress indicator and
|
||||||
//// a stop predicate can be also be passed to control the process.
|
//// a stop predicate can be also be passed to control the process.
|
||||||
bool arrange(Arrangeables & arrangables,
|
bool arrange(ArrangeablePtrs & arrangables,
|
||||||
const Arrangeables & excludes,
|
const ArrangeablePtrs & excludes,
|
||||||
coord_t min_obj_distance,
|
coord_t min_obj_distance,
|
||||||
const BedShapeHint & bedhint,
|
const BedShapeHint & bedhint,
|
||||||
std::function<void(unsigned)> progressind,
|
std::function<void(unsigned)> progressind,
|
||||||
@ -774,8 +728,7 @@ bool arrange(Arrangeables & arrangables,
|
|||||||
clppr::cInt stride = binidx * stride_padding(binwidth);
|
clppr::cInt stride = binidx * stride_padding(binwidth);
|
||||||
|
|
||||||
clppr::IntPoint offs = itm.translation();
|
clppr::IntPoint offs = itm.translation();
|
||||||
arrangeable->apply_arrange_result({unscaled(offs.X +
|
arrangeable->apply_arrange_result({unscaled(offs.X + stride),
|
||||||
stride),
|
|
||||||
unscaled(offs.Y)},
|
unscaled(offs.Y)},
|
||||||
itm.rotation());
|
itm.rotation());
|
||||||
});
|
});
|
||||||
@ -797,7 +750,6 @@ bool arrange(Arrangeables & arrangables,
|
|||||||
// Create the arranger for the box shaped bed
|
// Create the arranger for the box shaped bed
|
||||||
BoundingBox bbb = bedhint.shape.box;
|
BoundingBox bbb = bedhint.shape.box;
|
||||||
bbb.min -= Point{md, md}, bbb.max += Point{md, md};
|
bbb.min -= Point{md, md}, bbb.max += Point{md, md};
|
||||||
|
|
||||||
Box binbb{{bbb.min(X), bbb.min(Y)}, {bbb.max(X), bbb.max(Y)}};
|
Box binbb{{bbb.min(X), bbb.min(Y)}, {bbb.max(X), bbb.max(Y)}};
|
||||||
binwidth = coord_t(binbb.width());
|
binwidth = coord_t(binbb.width());
|
||||||
|
|
||||||
@ -808,6 +760,7 @@ bool arrange(Arrangeables & arrangables,
|
|||||||
auto c = bedhint.shape.circ;
|
auto c = bedhint.shape.circ;
|
||||||
auto cc = to_lnCircle(c);
|
auto cc = to_lnCircle(c);
|
||||||
binwidth = scaled(c.radius());
|
binwidth = scaled(c.radius());
|
||||||
|
|
||||||
_arrange(items, preshapes, cc, min_obj_distance, progressind, cfn);
|
_arrange(items, preshapes, cc, min_obj_distance, progressind, cfn);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -816,11 +769,21 @@ bool arrange(Arrangeables & arrangables,
|
|||||||
auto irrbed = sl::create<clppr::Polygon>(std::move(ctour));
|
auto irrbed = sl::create<clppr::Polygon>(std::move(ctour));
|
||||||
BoundingBox polybb(bedhint.shape.polygon);
|
BoundingBox polybb(bedhint.shape.polygon);
|
||||||
binwidth = (polybb.max(X) - polybb.min(X));
|
binwidth = (polybb.max(X) - polybb.min(X));
|
||||||
|
|
||||||
_arrange(items, preshapes, irrbed, min_obj_distance, progressind, cfn);
|
_arrange(items, preshapes, irrbed, min_obj_distance, progressind, cfn);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case BedShapeType::WHO_KNOWS: {
|
case BedShapeType::INFINITE: {
|
||||||
_arrange(items, preshapes, false, min_obj_distance, progressind, cfn);
|
// const InfiniteBed& nobin = bedhint.shape.infinite;
|
||||||
|
//Box infbb{{nobin.center.x(), nobin.center.y()}};
|
||||||
|
Box infbb;
|
||||||
|
|
||||||
|
_arrange(items, preshapes, infbb, min_obj_distance, progressind, cfn);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case BedShapeType::UNKNOWN: {
|
||||||
|
// We know nothing about the bed, let it be infinite and zero centered
|
||||||
|
_arrange(items, preshapes, Box{}, min_obj_distance, progressind, cfn);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -831,7 +794,7 @@ bool arrange(Arrangeables & arrangables,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Arrange, without the fixed items (excludes)
|
/// Arrange, without the fixed items (excludes)
|
||||||
bool arrange(Arrangeables & inp,
|
bool arrange(ArrangeablePtrs & inp,
|
||||||
coord_t min_d,
|
coord_t min_d,
|
||||||
const BedShapeHint & bedhint,
|
const BedShapeHint & bedhint,
|
||||||
std::function<void(unsigned)> prfn,
|
std::function<void(unsigned)> prfn,
|
@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
namespace Slic3r {
|
namespace Slic3r {
|
||||||
|
|
||||||
namespace arr {
|
namespace arrangement {
|
||||||
|
|
||||||
/// A geometry abstraction for a circular print bed. Similarly to BoundingBox.
|
/// A geometry abstraction for a circular print bed. Similarly to BoundingBox.
|
||||||
class CircleBed {
|
class CircleBed {
|
||||||
@ -22,21 +22,26 @@ public:
|
|||||||
inline operator bool() { return !std::isnan(radius_); }
|
inline operator bool() { return !std::isnan(radius_); }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// Representing an unbounded bin
|
||||||
|
struct InfiniteBed { Point center; };
|
||||||
|
|
||||||
/// Types of print bed shapes.
|
/// Types of print bed shapes.
|
||||||
enum class BedShapeType {
|
enum class BedShapeType {
|
||||||
BOX,
|
BOX,
|
||||||
CIRCLE,
|
CIRCLE,
|
||||||
IRREGULAR,
|
IRREGULAR,
|
||||||
WHO_KNOWS
|
INFINITE,
|
||||||
|
UNKNOWN
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Info about the print bed for the arrange() function.
|
/// Info about the print bed for the arrange() function.
|
||||||
struct BedShapeHint {
|
struct BedShapeHint {
|
||||||
BedShapeType type = BedShapeType::WHO_KNOWS;
|
BedShapeType type = BedShapeType::INFINITE;
|
||||||
/*union*/ struct { // I know but who cares... TODO: use variant from cpp17?
|
/*union*/ struct { // I know but who cares... TODO: use variant from cpp17?
|
||||||
CircleBed circ;
|
CircleBed circ;
|
||||||
BoundingBox box;
|
BoundingBox box;
|
||||||
Polyline polygon;
|
Polyline polygon;
|
||||||
|
InfiniteBed infinite;
|
||||||
} shape;
|
} shape;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -59,7 +64,7 @@ public:
|
|||||||
virtual std::tuple<Polygon, Vec2crd, double> get_arrange_polygon() const = 0;
|
virtual std::tuple<Polygon, Vec2crd, double> get_arrange_polygon() const = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
using Arrangeables = std::vector<Arrangeable*>;
|
using ArrangeablePtrs = std::vector<Arrangeable*>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Arranges the model objects on the screen.
|
* \brief Arranges the model objects on the screen.
|
||||||
@ -92,20 +97,20 @@ using Arrangeables = std::vector<Arrangeable*>;
|
|||||||
*
|
*
|
||||||
* \param stopcondition A predicate returning true if abort is needed.
|
* \param stopcondition A predicate returning true if abort is needed.
|
||||||
*/
|
*/
|
||||||
bool arrange(Arrangeables &items,
|
bool arrange(ArrangeablePtrs &items,
|
||||||
coord_t min_obj_distance,
|
coord_t min_obj_distance,
|
||||||
const BedShapeHint& bedhint,
|
const BedShapeHint& bedhint,
|
||||||
std::function<void(unsigned)> progressind,
|
std::function<void(unsigned)> progressind = nullptr,
|
||||||
std::function<bool(void)> stopcondition);
|
std::function<bool(void)> stopcondition = nullptr);
|
||||||
|
|
||||||
/// Same as the previous, only that it takes unmovable items as an
|
/// Same as the previous, only that it takes unmovable items as an
|
||||||
/// additional argument.
|
/// additional argument.
|
||||||
bool arrange(Arrangeables &items,
|
bool arrange(ArrangeablePtrs &items,
|
||||||
const Arrangeables &excludes,
|
const ArrangeablePtrs &excludes,
|
||||||
coord_t min_obj_distance,
|
coord_t min_obj_distance,
|
||||||
const BedShapeHint& bedhint,
|
const BedShapeHint& bedhint,
|
||||||
std::function<void(unsigned)> progressind,
|
std::function<void(unsigned)> progressind = nullptr,
|
||||||
std::function<bool(void)> stopcondition);
|
std::function<bool(void)> stopcondition = nullptr);
|
||||||
|
|
||||||
} // arr
|
} // arr
|
||||||
} // Slic3r
|
} // Slic3r
|
@ -107,8 +107,8 @@ add_library(libslic3r STATIC
|
|||||||
Line.hpp
|
Line.hpp
|
||||||
Model.cpp
|
Model.cpp
|
||||||
Model.hpp
|
Model.hpp
|
||||||
ModelArrange.hpp
|
Arrange.hpp
|
||||||
ModelArrange.cpp
|
Arrange.cpp
|
||||||
MotionPlanner.cpp
|
MotionPlanner.cpp
|
||||||
MotionPlanner.hpp
|
MotionPlanner.hpp
|
||||||
MultiPoint.cpp
|
MultiPoint.cpp
|
||||||
|
@ -375,31 +375,46 @@ bool Model::arrange_objects(coordf_t dist, const BoundingBoxf* bb)
|
|||||||
{
|
{
|
||||||
// get the (transformed) size of each instance so that we take
|
// get the (transformed) size of each instance so that we take
|
||||||
// into account their different transformations when packing
|
// into account their different transformations when packing
|
||||||
Pointfs instance_sizes;
|
// Pointfs instance_sizes;
|
||||||
Pointfs instance_centers;
|
// Pointfs instance_centers;
|
||||||
for (const ModelObject *o : this->objects)
|
// for (const ModelObject *o : this->objects)
|
||||||
for (size_t i = 0; i < o->instances.size(); ++ i) {
|
// for (size_t i = 0; i < o->instances.size(); ++ i) {
|
||||||
// an accurate snug bounding box around the transformed mesh.
|
// // an accurate snug bounding box around the transformed mesh.
|
||||||
BoundingBoxf3 bbox(o->instance_bounding_box(i, true));
|
// BoundingBoxf3 bbox(o->instance_bounding_box(i, true));
|
||||||
instance_sizes.emplace_back(to_2d(bbox.size()));
|
// instance_sizes.emplace_back(to_2d(bbox.size()));
|
||||||
instance_centers.emplace_back(to_2d(bbox.center()));
|
// instance_centers.emplace_back(to_2d(bbox.center()));
|
||||||
|
// }
|
||||||
|
|
||||||
|
// Pointfs positions;
|
||||||
|
// if (! _arrange(instance_sizes, dist, bb, positions))
|
||||||
|
// return false;
|
||||||
|
|
||||||
|
// size_t idx = 0;
|
||||||
|
// for (ModelObject *o : this->objects) {
|
||||||
|
// for (ModelInstance *i : o->instances) {
|
||||||
|
// Vec2d offset_xy = positions[idx] - instance_centers[idx];
|
||||||
|
// i->set_offset(Vec3d(offset_xy(0), offset_xy(1), i->get_offset(Z)));
|
||||||
|
// ++idx;
|
||||||
|
// }
|
||||||
|
// o->invalidate_bounding_box();
|
||||||
|
// }
|
||||||
|
size_t count = 0;
|
||||||
|
for (auto obj : objects) count += obj->instances.size();
|
||||||
|
|
||||||
|
arrangement::ArrangeablePtrs input;
|
||||||
|
input.reserve(count);
|
||||||
|
for (ModelObject *mo : objects)
|
||||||
|
for (ModelInstance *minst : mo->instances)
|
||||||
|
input.emplace_back(minst);
|
||||||
|
|
||||||
|
arrangement::BedShapeHint bedhint;
|
||||||
|
|
||||||
|
if (bb) {
|
||||||
|
bedhint.type = arrangement::BedShapeType::BOX;
|
||||||
|
bedhint.shape.box = BoundingBox(scaled(bb->min), scaled(bb->max));
|
||||||
}
|
}
|
||||||
|
|
||||||
Pointfs positions;
|
return arrangement::arrange(input, scaled(dist), bedhint);
|
||||||
if (! _arrange(instance_sizes, dist, bb, positions))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
size_t idx = 0;
|
|
||||||
for (ModelObject *o : this->objects) {
|
|
||||||
for (ModelInstance *i : o->instances) {
|
|
||||||
Vec2d offset_xy = positions[idx] - instance_centers[idx];
|
|
||||||
i->set_offset(Vec3d(offset_xy(0), offset_xy(1), i->get_offset(Z)));
|
|
||||||
++idx;
|
|
||||||
}
|
|
||||||
o->invalidate_bounding_box();
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Duplicate the entire model preserving instance relative positions.
|
// Duplicate the entire model preserving instance relative positions.
|
||||||
@ -1805,15 +1820,11 @@ std::tuple<Polygon, Vec2crd, double> ModelInstance::get_arrange_polygon() const
|
|||||||
{
|
{
|
||||||
static const double SIMPLIFY_TOLERANCE_MM = 0.1;
|
static const double SIMPLIFY_TOLERANCE_MM = 0.1;
|
||||||
|
|
||||||
assert(m_inst);
|
|
||||||
|
|
||||||
Vec3d rotation = get_rotation();
|
Vec3d rotation = get_rotation();
|
||||||
rotation.z() = 0.;
|
rotation.z() = 0.;
|
||||||
Transform3d trafo_instance = Geometry::
|
Transform3d trafo_instance =
|
||||||
assemble_transform(Vec3d::Zero(),
|
Geometry::assemble_transform(Vec3d::Zero(), rotation,
|
||||||
rotation,
|
get_scaling_factor(), get_mirror());
|
||||||
get_scaling_factor(),
|
|
||||||
get_mirror());
|
|
||||||
|
|
||||||
Polygon p = get_object()->convex_hull_2d(trafo_instance);
|
Polygon p = get_object()->convex_hull_2d(trafo_instance);
|
||||||
|
|
||||||
@ -1827,8 +1838,8 @@ std::tuple<Polygon, Vec2crd, double> ModelInstance::get_arrange_polygon() const
|
|||||||
pp = p.simplify(scaled<double>(SIMPLIFY_TOLERANCE_MM));
|
pp = p.simplify(scaled<double>(SIMPLIFY_TOLERANCE_MM));
|
||||||
if (!pp.empty()) p = pp.front();
|
if (!pp.empty()) p = pp.front();
|
||||||
|
|
||||||
return std::make_tuple(p, Vec2crd{scaled(get_offset(X)),
|
return std::make_tuple(p,
|
||||||
scaled(get_offset(Y))},
|
Vec2crd{scaled(get_offset(X)), scaled(get_offset(Y))},
|
||||||
get_rotation(Z));
|
get_rotation(Z));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
#include "Point.hpp"
|
#include "Point.hpp"
|
||||||
#include "TriangleMesh.hpp"
|
#include "TriangleMesh.hpp"
|
||||||
#include "Slicing.hpp"
|
#include "Slicing.hpp"
|
||||||
#include "ModelArrange.hpp"
|
#include "Arrange.hpp"
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
@ -491,7 +491,7 @@ private:
|
|||||||
|
|
||||||
// A single instance of a ModelObject.
|
// A single instance of a ModelObject.
|
||||||
// Knows the affine transformation of an object.
|
// Knows the affine transformation of an object.
|
||||||
class ModelInstance : public ModelBase, public arr::Arrangeable
|
class ModelInstance : public ModelBase, public arrangement::Arrangeable
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
enum EPrintVolumeState : unsigned char
|
enum EPrintVolumeState : unsigned char
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
#include "libslic3r/ModelArrange.hpp"
|
#include "libslic3r/Arrange.hpp"
|
||||||
#include "3DScene.hpp"
|
#include "3DScene.hpp"
|
||||||
#include "GLToolbar.hpp"
|
#include "GLToolbar.hpp"
|
||||||
#include "Event.hpp"
|
#include "Event.hpp"
|
||||||
@ -612,7 +612,7 @@ public:
|
|||||||
int get_move_volume_id() const { return m_mouse.drag.move_volume_idx; }
|
int get_move_volume_id() const { return m_mouse.drag.move_volume_idx; }
|
||||||
int get_first_hover_volume_idx() const { return m_hover_volume_idxs.empty() ? -1 : m_hover_volume_idxs.front(); }
|
int get_first_hover_volume_idx() const { return m_hover_volume_idxs.empty() ? -1 : m_hover_volume_idxs.front(); }
|
||||||
|
|
||||||
class WipeTowerInfo: public arr::Arrangeable {
|
class WipeTowerInfo: public arrangement::Arrangeable {
|
||||||
Vec2d m_pos = {std::nan(""), std::nan("")};
|
Vec2d m_pos = {std::nan(""), std::nan("")};
|
||||||
Vec2d m_bb_size;
|
Vec2d m_bb_size;
|
||||||
double m_rotation;
|
double m_rotation;
|
||||||
|
@ -32,7 +32,6 @@
|
|||||||
#include "libslic3r/Format/3mf.hpp"
|
#include "libslic3r/Format/3mf.hpp"
|
||||||
#include "libslic3r/GCode/PreviewData.hpp"
|
#include "libslic3r/GCode/PreviewData.hpp"
|
||||||
#include "libslic3r/Model.hpp"
|
#include "libslic3r/Model.hpp"
|
||||||
#include "libslic3r/ModelArrange.hpp"
|
|
||||||
#include "libslic3r/Polygon.hpp"
|
#include "libslic3r/Polygon.hpp"
|
||||||
#include "libslic3r/Print.hpp"
|
#include "libslic3r/Print.hpp"
|
||||||
#include "libslic3r/PrintConfig.hpp"
|
#include "libslic3r/PrintConfig.hpp"
|
||||||
@ -1218,6 +1217,28 @@ bool PlaterDropTarget::OnDropFiles(wxCoord x, wxCoord y, const wxArrayString &fi
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
arrangement::ArrangeablePtrs get_arrange_input(Model &model, const Selection &sel) {
|
||||||
|
auto selmap = sel.get_content();
|
||||||
|
|
||||||
|
size_t count = 0;
|
||||||
|
for (auto obj : model.objects) count += obj->instances.size();
|
||||||
|
|
||||||
|
arrangement::ArrangeablePtrs ret; ret.reserve(count);
|
||||||
|
|
||||||
|
if (selmap.empty())
|
||||||
|
for (ModelObject *mo : model.objects)
|
||||||
|
for (ModelInstance *minst : mo->instances)
|
||||||
|
ret.emplace_back(minst);
|
||||||
|
else
|
||||||
|
for (auto &s : selmap)
|
||||||
|
for (auto &instid : s.second)
|
||||||
|
ret.emplace_back(model.objects[s.first]->instances[instid]);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Plater / private
|
// Plater / private
|
||||||
struct Plater::priv
|
struct Plater::priv
|
||||||
{
|
{
|
||||||
@ -1425,50 +1446,91 @@ struct Plater::priv
|
|||||||
|
|
||||||
class ArrangeJob : public Job
|
class ArrangeJob : public Job
|
||||||
{
|
{
|
||||||
int m_count = 0;
|
|
||||||
GLCanvas3D::WipeTowerInfo m_wti;
|
GLCanvas3D::WipeTowerInfo m_wti;
|
||||||
|
arrangement::ArrangeablePtrs m_selected, m_unselected;
|
||||||
|
|
||||||
|
static std::array<arrangement::ArrangeablePtrs, 2> collect(
|
||||||
|
Model &model, const Selection &sel)
|
||||||
|
{
|
||||||
|
auto selmap = sel.get_content();
|
||||||
|
|
||||||
|
size_t count = 0;
|
||||||
|
for (auto obj : model.objects) count += obj->instances.size();
|
||||||
|
|
||||||
|
arrangement::ArrangeablePtrs selected, unselected;
|
||||||
|
selected.reserve(count + 1 /* for optional wti */);
|
||||||
|
unselected.reserve(count + 1 /* for optional wti */);
|
||||||
|
|
||||||
|
for (size_t oidx = 0; oidx < model.objects.size(); ++oidx) {
|
||||||
|
auto oit = selmap.find(int(oidx));
|
||||||
|
|
||||||
|
if (oit != selmap.end()) {
|
||||||
|
auto &iids = oit->second;
|
||||||
|
|
||||||
|
for (size_t iidx = 0;
|
||||||
|
iidx < model.objects[oidx]->instances.size();
|
||||||
|
++iidx)
|
||||||
|
{
|
||||||
|
auto instit = iids.find(iidx);
|
||||||
|
ModelInstance *inst = model.objects[oidx]
|
||||||
|
->instances[iidx];
|
||||||
|
instit == iids.end() ?
|
||||||
|
unselected.emplace_back(inst) :
|
||||||
|
selected.emplace_back(inst);
|
||||||
|
}
|
||||||
|
} else // object not selected, all instances are unselected
|
||||||
|
for (auto inst : model.objects[oidx]->instances)
|
||||||
|
unselected.emplace_back(inst);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (selected.empty()) selected.swap(unselected);
|
||||||
|
|
||||||
|
return {selected, unselected};
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
void prepare() override
|
void prepare() override
|
||||||
{
|
{
|
||||||
m_wti = plater().view3D->get_canvas3d()->get_wipe_tower_info();
|
m_wti = plater().view3D->get_canvas3d()->get_wipe_tower_info();
|
||||||
m_count = bool(m_wti);
|
|
||||||
|
|
||||||
for (auto obj : plater().model.objects)
|
const Selection& sel = plater().get_selection();
|
||||||
m_count += int(obj->instances.size());
|
auto arrinput = collect(plater().model, sel);
|
||||||
|
m_selected.swap(arrinput[0]);
|
||||||
|
m_unselected.swap(arrinput[1]);
|
||||||
|
|
||||||
|
if (m_wti)
|
||||||
|
sel.is_wipe_tower() ?
|
||||||
|
m_selected.emplace_back(&m_wti) :
|
||||||
|
m_unselected.emplace_back(&m_wti);
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
//using Job::Job;
|
using Job::Job;
|
||||||
ArrangeJob(priv * pltr): Job(pltr) {}
|
int status_range() const override
|
||||||
int status_range() const override { return m_count; }
|
{
|
||||||
void set_count(int c) { m_count = c; }
|
return int(m_selected.size());
|
||||||
|
}
|
||||||
void process() override;
|
void process() override;
|
||||||
} arrange_job/*{m_plater}*/;
|
} arrange_job{m_plater};
|
||||||
|
|
||||||
class RotoptimizeJob : public Job
|
class RotoptimizeJob : public Job
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
//using Job::Job;
|
using Job::Job;
|
||||||
RotoptimizeJob(priv * pltr): Job(pltr) {}
|
|
||||||
void process() override;
|
void process() override;
|
||||||
} rotoptimize_job/*{m_plater}*/;
|
} rotoptimize_job{m_plater};
|
||||||
|
|
||||||
// To create a new job, just define a new subclass of Job, implement
|
// To create a new job, just define a new subclass of Job, implement
|
||||||
// the process and the optional prepare() and finalize() methods
|
// the process and the optional prepare() and finalize() methods
|
||||||
// Register the instance of the class in the m_jobs container
|
// Register the instance of the class in the m_jobs container
|
||||||
// if it cannot run concurrently with other jobs in this group
|
// if it cannot run concurrently with other jobs in this group
|
||||||
|
|
||||||
std::vector<std::reference_wrapper<Job>> m_jobs/*{arrange_job,
|
std::vector<std::reference_wrapper<Job>> m_jobs{arrange_job,
|
||||||
rotoptimize_job}*/;
|
rotoptimize_job};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ExclusiveJobGroup(priv *_plater)
|
ExclusiveJobGroup(priv *_plater) : m_plater(_plater) {}
|
||||||
: m_plater(_plater)
|
|
||||||
, arrange_job(m_plater)
|
|
||||||
, rotoptimize_job(m_plater)
|
|
||||||
, m_jobs({arrange_job, rotoptimize_job})
|
|
||||||
{}
|
|
||||||
|
|
||||||
void start(Jobs jid) {
|
void start(Jobs jid) {
|
||||||
m_plater->background_process.stop();
|
m_plater->background_process.stop();
|
||||||
@ -1528,7 +1590,7 @@ struct Plater::priv
|
|||||||
std::string get_config(const std::string &key) const;
|
std::string get_config(const std::string &key) const;
|
||||||
BoundingBoxf bed_shape_bb() const;
|
BoundingBoxf bed_shape_bb() const;
|
||||||
BoundingBox scaled_bed_shape_bb() const;
|
BoundingBox scaled_bed_shape_bb() const;
|
||||||
arr::BedShapeHint get_bed_shape_hint() const;
|
arrangement::BedShapeHint get_bed_shape_hint() const;
|
||||||
std::vector<size_t> load_files(const std::vector<fs::path>& input_files, bool load_model, bool load_config);
|
std::vector<size_t> load_files(const std::vector<fs::path>& input_files, bool load_model, bool load_config);
|
||||||
std::vector<size_t> load_model_objects(const ModelObjectPtrs &model_objects);
|
std::vector<size_t> load_model_objects(const ModelObjectPtrs &model_objects);
|
||||||
wxString get_export_file(GUI::FileType file_type);
|
wxString get_export_file(GUI::FileType file_type);
|
||||||
@ -2404,8 +2466,8 @@ void Plater::priv::sla_optimize_rotation() {
|
|||||||
m_ui_jobs.start(Jobs::Rotoptimize);
|
m_ui_jobs.start(Jobs::Rotoptimize);
|
||||||
}
|
}
|
||||||
|
|
||||||
arr::BedShapeHint Plater::priv::get_bed_shape_hint() const {
|
arrangement::BedShapeHint Plater::priv::get_bed_shape_hint() const {
|
||||||
arr::BedShapeHint bedshape;
|
arrangement::BedShapeHint bedshape;
|
||||||
|
|
||||||
const auto *bed_shape_opt = config->opt<ConfigOptionPoints>("bed_shape");
|
const auto *bed_shape_opt = config->opt<ConfigOptionPoints>("bed_shape");
|
||||||
assert(bed_shape_opt);
|
assert(bed_shape_opt);
|
||||||
@ -2414,7 +2476,7 @@ arr::BedShapeHint Plater::priv::get_bed_shape_hint() const {
|
|||||||
auto &bedpoints = bed_shape_opt->values;
|
auto &bedpoints = bed_shape_opt->values;
|
||||||
Polyline bedpoly; bedpoly.points.reserve(bedpoints.size());
|
Polyline bedpoly; bedpoly.points.reserve(bedpoints.size());
|
||||||
for (auto &v : bedpoints) bedpoly.append(scaled(v));
|
for (auto &v : bedpoints) bedpoly.append(scaled(v));
|
||||||
bedshape = arr::bedShape(bedpoly);
|
bedshape = arrangement::bedShape(bedpoly);
|
||||||
}
|
}
|
||||||
|
|
||||||
return bedshape;
|
return bedshape;
|
||||||
@ -2423,15 +2485,6 @@ arr::BedShapeHint Plater::priv::get_bed_shape_hint() const {
|
|||||||
void Plater::priv::ExclusiveJobGroup::ArrangeJob::process() {
|
void Plater::priv::ExclusiveJobGroup::ArrangeJob::process() {
|
||||||
static const auto arrangestr = _(L("Arranging"));
|
static const auto arrangestr = _(L("Arranging"));
|
||||||
|
|
||||||
// Collect the model instances and place them into the input vector
|
|
||||||
arr::Arrangeables arrangeinput; arrangeinput.reserve(m_count);
|
|
||||||
for(ModelObject *mo : plater().model.objects)
|
|
||||||
for(ModelInstance *minst : mo->instances)
|
|
||||||
arrangeinput.emplace_back(minst);
|
|
||||||
|
|
||||||
// Place back the wipe tower if that's available.
|
|
||||||
if (m_wti) arrangeinput.emplace_back(&m_wti);
|
|
||||||
|
|
||||||
// FIXME: I don't know how to obtain the minimum distance, it depends
|
// FIXME: I don't know how to obtain the minimum distance, it depends
|
||||||
// on printer technology. I guess the following should work but it crashes.
|
// on printer technology. I guess the following should work but it crashes.
|
||||||
double dist = 6; // PrintConfig::min_object_distance(config);
|
double dist = 6; // PrintConfig::min_object_distance(config);
|
||||||
@ -2440,16 +2493,15 @@ void Plater::priv::ExclusiveJobGroup::ArrangeJob::process() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
coord_t min_obj_distance = scaled(dist);
|
coord_t min_obj_distance = scaled(dist);
|
||||||
|
auto count = unsigned(m_selected.size());
|
||||||
arr::BedShapeHint bedshape = plater().get_bed_shape_hint();
|
arrangement::BedShapeHint bedshape = plater().get_bed_shape_hint();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
arr::arrange(arrangeinput,
|
arrangement::arrange(m_selected, m_unselected, min_obj_distance,
|
||||||
min_obj_distance,
|
|
||||||
bedshape,
|
bedshape,
|
||||||
[this](unsigned st) {
|
[this, count](unsigned st) {
|
||||||
if (st > 0)
|
if (st > 0) // will not finalize after last one
|
||||||
update_status(m_count - int(st), arrangestr);
|
update_status(count - st, arrangestr);
|
||||||
},
|
},
|
||||||
[this]() { return was_canceled(); });
|
[this]() { return was_canceled(); });
|
||||||
} catch (std::exception & /*e*/) {
|
} catch (std::exception & /*e*/) {
|
||||||
@ -2458,7 +2510,8 @@ void Plater::priv::ExclusiveJobGroup::ArrangeJob::process() {
|
|||||||
"Some geometries may be invalid.")));
|
"Some geometries may be invalid.")));
|
||||||
}
|
}
|
||||||
|
|
||||||
update_status(m_count,
|
// finalize just here.
|
||||||
|
update_status(int(count),
|
||||||
was_canceled() ? _(L("Arranging canceled."))
|
was_canceled() ? _(L("Arranging canceled."))
|
||||||
: _(L("Arranging done.")));
|
: _(L("Arranging done.")));
|
||||||
}
|
}
|
||||||
@ -2466,7 +2519,7 @@ void Plater::priv::ExclusiveJobGroup::ArrangeJob::process() {
|
|||||||
void find_new_position(const Model & model,
|
void find_new_position(const Model & model,
|
||||||
ModelInstancePtrs instances,
|
ModelInstancePtrs instances,
|
||||||
coord_t min_d,
|
coord_t min_d,
|
||||||
const arr::BedShapeHint &bedhint)
|
const arrangement::BedShapeHint &bedhint)
|
||||||
{
|
{
|
||||||
|
|
||||||
// TODO
|
// TODO
|
||||||
|
Loading…
Reference in New Issue
Block a user