mirror of
https://git.mirrors.martin98.com/https://github.com/prusa3d/PrusaSlicer.git
synced 2025-08-14 23:55:59 +08:00
Complete arrangement prevention of integer coordinate overflows
This commit is contained in:
parent
be9bbb7552
commit
cb3596e90b
@ -83,11 +83,19 @@ void Arranger<ArrItem>::arrange(std::vector<ArrItem> &items,
|
|||||||
arrange(items, fixed, bed, DefaultArrangerCtl<ArrItem>{ctl});
|
arrange(items, fixed, bed, DefaultArrangerCtl<ArrItem>{ctl});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class EmptyItemOutlineError: public std::exception {
|
||||||
|
static constexpr const char *Msg = "No outline can be derived for object";
|
||||||
|
|
||||||
|
public:
|
||||||
|
const char* what() const noexcept override { return Msg; }
|
||||||
|
};
|
||||||
|
|
||||||
template<class ArrItem> class ArrangeableToItemConverter
|
template<class ArrItem> class ArrangeableToItemConverter
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual ~ArrangeableToItemConverter() = default;
|
virtual ~ArrangeableToItemConverter() = default;
|
||||||
|
|
||||||
|
// May throw EmptyItemOutlineError
|
||||||
virtual ArrItem convert(const Arrangeable &arrbl, coord_t offs = 0) const = 0;
|
virtual ArrItem convert(const Arrangeable &arrbl, coord_t offs = 0) const = 0;
|
||||||
|
|
||||||
// Returns the extent of simplification that the converter utilizes when
|
// Returns the extent of simplification that the converter utilizes when
|
||||||
|
@ -370,6 +370,10 @@ ArrItem ConvexItemConverter<ArrItem>::convert(const Arrangeable &arrbl,
|
|||||||
{
|
{
|
||||||
auto bed_index = arrbl.get_bed_index();
|
auto bed_index = arrbl.get_bed_index();
|
||||||
Polygon outline = arrbl.convex_outline();
|
Polygon outline = arrbl.convex_outline();
|
||||||
|
|
||||||
|
if (outline.empty())
|
||||||
|
throw EmptyItemOutlineError{};
|
||||||
|
|
||||||
Polygon envelope = arrbl.convex_envelope();
|
Polygon envelope = arrbl.convex_envelope();
|
||||||
|
|
||||||
coord_t infl = offs + coord_t(std::ceil(this->safety_dist() / 2.));
|
coord_t infl = offs + coord_t(std::ceil(this->safety_dist() / 2.));
|
||||||
@ -418,6 +422,10 @@ ArrItem AdvancedItemConverter<ArrItem>::get_arritem(const Arrangeable &arrbl,
|
|||||||
coord_t infl = offs + coord_t(std::ceil(this->safety_dist() / 2.));
|
coord_t infl = offs + coord_t(std::ceil(this->safety_dist() / 2.));
|
||||||
|
|
||||||
auto outline = arrbl.full_outline();
|
auto outline = arrbl.full_outline();
|
||||||
|
|
||||||
|
if (outline.empty())
|
||||||
|
throw EmptyItemOutlineError{};
|
||||||
|
|
||||||
auto envelope = arrbl.full_envelope();
|
auto envelope = arrbl.full_envelope();
|
||||||
|
|
||||||
if (infl != 0) {
|
if (infl != 0) {
|
||||||
|
@ -64,7 +64,9 @@ void transform_instance(ModelInstance &mi,
|
|||||||
mi.invalidate_object_bounding_box();
|
mi.invalidate_object_bounding_box();
|
||||||
}
|
}
|
||||||
|
|
||||||
BoundingBoxf3 instance_bounding_box(const ModelInstance &mi, bool dont_translate)
|
BoundingBoxf3 instance_bounding_box(const ModelInstance &mi,
|
||||||
|
const Transform3d &tr,
|
||||||
|
bool dont_translate)
|
||||||
{
|
{
|
||||||
BoundingBoxf3 bb;
|
BoundingBoxf3 bb;
|
||||||
const Transform3d inst_matrix
|
const Transform3d inst_matrix
|
||||||
@ -73,7 +75,7 @@ BoundingBoxf3 instance_bounding_box(const ModelInstance &mi, bool dont_translate
|
|||||||
|
|
||||||
for (ModelVolume *v : mi.get_object()->volumes) {
|
for (ModelVolume *v : mi.get_object()->volumes) {
|
||||||
if (v->is_model_part()) {
|
if (v->is_model_part()) {
|
||||||
bb.merge(v->mesh().transformed_bounding_box(inst_matrix
|
bb.merge(v->mesh().transformed_bounding_box(tr * inst_matrix
|
||||||
* v->get_matrix()));
|
* v->get_matrix()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -81,11 +83,32 @@ BoundingBoxf3 instance_bounding_box(const ModelInstance &mi, bool dont_translate
|
|||||||
return bb;
|
return bb;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BoundingBoxf3 instance_bounding_box(const ModelInstance &mi, bool dont_translate)
|
||||||
|
{
|
||||||
|
return instance_bounding_box(mi, Transform3d::Identity(), dont_translate);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool check_coord_bounds(const BoundingBoxf &bb)
|
||||||
|
{
|
||||||
|
constexpr double hi = 1000.;
|
||||||
|
|
||||||
|
return std::abs(bb.min.x()) < hi &&
|
||||||
|
std::abs(bb.min.y()) < hi &&
|
||||||
|
std::abs(bb.max.x()) < hi &&
|
||||||
|
std::abs(bb.max.y()) < hi;
|
||||||
|
}
|
||||||
|
|
||||||
ExPolygons extract_full_outline(const ModelInstance &inst, const Transform3d &tr)
|
ExPolygons extract_full_outline(const ModelInstance &inst, const Transform3d &tr)
|
||||||
{
|
{
|
||||||
ExPolygons outline;
|
ExPolygons outline;
|
||||||
for (const ModelVolume *v : inst.get_object()->volumes) {
|
for (const ModelVolume *v : inst.get_object()->volumes) {
|
||||||
Polygons vol_outline;
|
Polygons vol_outline;
|
||||||
|
|
||||||
|
if (!check_coord_bounds(to_2d(v->mesh().transformed_bounding_box(tr)))) {
|
||||||
|
outline.clear();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
vol_outline = project_mesh(v->mesh().its,
|
vol_outline = project_mesh(v->mesh().its,
|
||||||
tr * inst.get_matrix() * v->get_matrix(),
|
tr * inst.get_matrix() * v->get_matrix(),
|
||||||
[] {});
|
[] {});
|
||||||
@ -105,7 +128,14 @@ ExPolygons extract_full_outline(const ModelInstance &inst, const Transform3d &tr
|
|||||||
|
|
||||||
Polygon extract_convex_outline(const ModelInstance &inst, const Transform3d &tr)
|
Polygon extract_convex_outline(const ModelInstance &inst, const Transform3d &tr)
|
||||||
{
|
{
|
||||||
return inst.get_object()->convex_hull_2d(tr * inst.get_matrix());
|
auto bb = to_2d(instance_bounding_box(inst, tr));
|
||||||
|
Polygon ret;
|
||||||
|
|
||||||
|
if (check_coord_bounds(bb)) {
|
||||||
|
ret = inst.get_object()->convex_hull_2d(tr * inst.get_matrix());
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline static bool is_infinite_bed(const ExtendedBed &ebed) noexcept
|
inline static bool is_infinite_bed(const ExtendedBed &ebed) noexcept
|
||||||
@ -190,7 +220,14 @@ int XStriderVBedHandler::get_bed_index(const VBedPlaceable &obj) const
|
|||||||
auto reference_pos_x = (instance_bb.min.x() - bedx);
|
auto reference_pos_x = (instance_bb.min.x() - bedx);
|
||||||
auto stride = unscaled(stride_s);
|
auto stride = unscaled(stride_s);
|
||||||
|
|
||||||
bedidx = static_cast<int>(std::floor(reference_pos_x / stride));
|
auto bedidx_d = std::floor(reference_pos_x / stride);
|
||||||
|
|
||||||
|
if (bedidx_d < std::numeric_limits<int>::min())
|
||||||
|
bedidx = std::numeric_limits<int>::min();
|
||||||
|
else if (bedidx_d > std::numeric_limits<int>::max())
|
||||||
|
bedidx = std::numeric_limits<int>::max();
|
||||||
|
else
|
||||||
|
bedidx = static_cast<int>(bedidx_d);
|
||||||
}
|
}
|
||||||
|
|
||||||
return bedidx;
|
return bedidx;
|
||||||
@ -231,7 +268,14 @@ int YStriderVBedHandler::get_bed_index(const VBedPlaceable &obj) const
|
|||||||
auto reference_pos_y = (instance_bb.min.y() - ystart);
|
auto reference_pos_y = (instance_bb.min.y() - ystart);
|
||||||
auto stride = unscaled(stride_s);
|
auto stride = unscaled(stride_s);
|
||||||
|
|
||||||
bedidx = static_cast<int>(std::floor(reference_pos_y / stride));
|
auto bedidx_d = std::floor(reference_pos_y / stride);
|
||||||
|
|
||||||
|
if (bedidx_d < std::numeric_limits<int>::min())
|
||||||
|
bedidx = std::numeric_limits<int>::min();
|
||||||
|
else if (bedidx_d > std::numeric_limits<int>::max())
|
||||||
|
bedidx = std::numeric_limits<int>::max();
|
||||||
|
else
|
||||||
|
bedidx = static_cast<int>(bedidx_d);
|
||||||
}
|
}
|
||||||
|
|
||||||
return bedidx;
|
return bedidx;
|
||||||
@ -274,7 +318,8 @@ Vec2i GridStriderVBedHandler::raw2grid(int bed_idx) const
|
|||||||
|
|
||||||
int GridStriderVBedHandler::grid2raw(const Vec2i &crd) const
|
int GridStriderVBedHandler::grid2raw(const Vec2i &crd) const
|
||||||
{
|
{
|
||||||
assert(crd.x() < ColsOutside - 1 && crd.y() < ColsOutside - 1);
|
assert(std::abs(crd.x()) < ColsOutside - 1 &&
|
||||||
|
std::abs(crd.y()) < ColsOutside - 1);
|
||||||
|
|
||||||
return crd.y() * ColsOutside + crd.x();
|
return crd.y() * ColsOutside + crd.x();
|
||||||
}
|
}
|
||||||
|
@ -377,6 +377,9 @@ void transform_instance(ModelInstance &mi,
|
|||||||
BoundingBoxf3 instance_bounding_box(const ModelInstance &mi,
|
BoundingBoxf3 instance_bounding_box(const ModelInstance &mi,
|
||||||
bool dont_translate = false);
|
bool dont_translate = false);
|
||||||
|
|
||||||
|
BoundingBoxf3 instance_bounding_box(const ModelInstance &mi,
|
||||||
|
const Transform3d &tr,
|
||||||
|
bool dont_translate = false);
|
||||||
|
|
||||||
ExPolygons extract_full_outline(const ModelInstance &inst,
|
ExPolygons extract_full_outline(const ModelInstance &inst,
|
||||||
const Transform3d &tr = Transform3d::Identity());
|
const Transform3d &tr = Transform3d::Identity());
|
||||||
|
@ -3,6 +3,8 @@
|
|||||||
|
|
||||||
#include <random>
|
#include <random>
|
||||||
|
|
||||||
|
#include <boost/log/trivial.hpp>
|
||||||
|
|
||||||
#include "ArrangeTask.hpp"
|
#include "ArrangeTask.hpp"
|
||||||
|
|
||||||
namespace Slic3r { namespace arr2 {
|
namespace Slic3r { namespace arr2 {
|
||||||
@ -20,6 +22,7 @@ void extract_selected(ArrangeTask<ArrItem> &task,
|
|||||||
bool selected = arrbl.is_selected();
|
bool selected = arrbl.is_selected();
|
||||||
bool printable = arrbl.is_printable();
|
bool printable = arrbl.is_printable();
|
||||||
|
|
||||||
|
try {
|
||||||
auto itm = itm_conv.convert(arrbl, selected ? 0 : -SCALED_EPSILON);
|
auto itm = itm_conv.convert(arrbl, selected ? 0 : -SCALED_EPSILON);
|
||||||
|
|
||||||
auto &container_parent = printable ? task.printable :
|
auto &container_parent = printable ? task.printable :
|
||||||
@ -30,6 +33,10 @@ void extract_selected(ArrangeTask<ArrItem> &task,
|
|||||||
container_parent.unselected;
|
container_parent.unselected;
|
||||||
|
|
||||||
container.emplace_back(std::move(itm));
|
container.emplace_back(std::move(itm));
|
||||||
|
} catch (const EmptyItemOutlineError &ex) {
|
||||||
|
BOOST_LOG_TRIVIAL(error)
|
||||||
|
<< "ObjectID " << std::to_string(arrbl.id().id) << ": " << ex.what();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// If the selection was empty arrange everything
|
// If the selection was empty arrange everything
|
||||||
|
@ -5,6 +5,8 @@
|
|||||||
|
|
||||||
#include "Arrange/Core/NFP/NFPArrangeItemTraits.hpp"
|
#include "Arrange/Core/NFP/NFPArrangeItemTraits.hpp"
|
||||||
|
|
||||||
|
#include <boost/log/trivial.hpp>
|
||||||
|
|
||||||
namespace Slic3r { namespace arr2 {
|
namespace Slic3r { namespace arr2 {
|
||||||
|
|
||||||
template<class ArrItem>
|
template<class ArrItem>
|
||||||
@ -81,6 +83,7 @@ void extract(FillBedTask<ArrItem> &task,
|
|||||||
|
|
||||||
auto collect_task_items = [&prototype_geometry_id, &task,
|
auto collect_task_items = [&prototype_geometry_id, &task,
|
||||||
&itm_conv](const Arrangeable &arrbl) {
|
&itm_conv](const Arrangeable &arrbl) {
|
||||||
|
try {
|
||||||
if (arrbl.geometry_id() == prototype_geometry_id) {
|
if (arrbl.geometry_id() == prototype_geometry_id) {
|
||||||
if (arrbl.is_printable()) {
|
if (arrbl.is_printable()) {
|
||||||
auto itm = itm_conv.convert(arrbl);
|
auto itm = itm_conv.convert(arrbl);
|
||||||
@ -91,6 +94,10 @@ void extract(FillBedTask<ArrItem> &task,
|
|||||||
auto itm = itm_conv.convert(arrbl, -SCALED_EPSILON);
|
auto itm = itm_conv.convert(arrbl, -SCALED_EPSILON);
|
||||||
task.unselected.emplace_back(std::move(itm));
|
task.unselected.emplace_back(std::move(itm));
|
||||||
}
|
}
|
||||||
|
} catch (const EmptyItemOutlineError &ex) {
|
||||||
|
BOOST_LOG_TRIVIAL(error)
|
||||||
|
<< "ObjectID " << std::to_string(arrbl.id().id) << ": " << ex.what();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Set the lowest priority to the shrinked prototype (hole filler) item
|
// Set the lowest priority to the shrinked prototype (hole filler) item
|
||||||
|
@ -3,6 +3,8 @@
|
|||||||
|
|
||||||
#include "MultiplySelectionTask.hpp"
|
#include "MultiplySelectionTask.hpp"
|
||||||
|
|
||||||
|
#include <boost/log/trivial.hpp>
|
||||||
|
|
||||||
namespace Slic3r { namespace arr2 {
|
namespace Slic3r { namespace arr2 {
|
||||||
|
|
||||||
template<class ArrItem>
|
template<class ArrItem>
|
||||||
@ -45,6 +47,7 @@ std::unique_ptr<MultiplySelectionTask<ArrItem>> MultiplySelectionTask<ArrItem>::
|
|||||||
|
|
||||||
auto collect_task_items = [&prototype_geometry_id, &task,
|
auto collect_task_items = [&prototype_geometry_id, &task,
|
||||||
&itm_conv](const Arrangeable &arrbl) {
|
&itm_conv](const Arrangeable &arrbl) {
|
||||||
|
try {
|
||||||
if (arrbl.geometry_id() == prototype_geometry_id) {
|
if (arrbl.geometry_id() == prototype_geometry_id) {
|
||||||
if (arrbl.is_printable()) {
|
if (arrbl.is_printable()) {
|
||||||
auto itm = itm_conv.convert(arrbl);
|
auto itm = itm_conv.convert(arrbl);
|
||||||
@ -55,6 +58,10 @@ std::unique_ptr<MultiplySelectionTask<ArrItem>> MultiplySelectionTask<ArrItem>::
|
|||||||
auto itm = itm_conv.convert(arrbl, -SCALED_EPSILON);
|
auto itm = itm_conv.convert(arrbl, -SCALED_EPSILON);
|
||||||
task.unselected.emplace_back(std::move(itm));
|
task.unselected.emplace_back(std::move(itm));
|
||||||
}
|
}
|
||||||
|
} catch (const EmptyItemOutlineError &ex) {
|
||||||
|
BOOST_LOG_TRIVIAL(error)
|
||||||
|
<< "ObjectID " << std::to_string(arrbl.id().id) << ": " << ex.what();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
scene.model().for_each_arrangeable(collect_task_items);
|
scene.model().for_each_arrangeable(collect_task_items);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user