Complete arrangement prevention of integer coordinate overflows

This commit is contained in:
tamasmeszaros 2023-08-16 17:34:42 +02:00
parent be9bbb7552
commit cb3596e90b
7 changed files with 112 additions and 27 deletions

View File

@ -83,11 +83,19 @@ void Arranger<ArrItem>::arrange(std::vector<ArrItem> &items,
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
{
public:
virtual ~ArrangeableToItemConverter() = default;
// May throw EmptyItemOutlineError
virtual ArrItem convert(const Arrangeable &arrbl, coord_t offs = 0) const = 0;
// Returns the extent of simplification that the converter utilizes when

View File

@ -370,6 +370,10 @@ ArrItem ConvexItemConverter<ArrItem>::convert(const Arrangeable &arrbl,
{
auto bed_index = arrbl.get_bed_index();
Polygon outline = arrbl.convex_outline();
if (outline.empty())
throw EmptyItemOutlineError{};
Polygon envelope = arrbl.convex_envelope();
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.));
auto outline = arrbl.full_outline();
if (outline.empty())
throw EmptyItemOutlineError{};
auto envelope = arrbl.full_envelope();
if (infl != 0) {

View File

@ -64,16 +64,18 @@ void transform_instance(ModelInstance &mi,
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;
const Transform3d inst_matrix
= dont_translate ? mi.get_transformation().get_matrix_no_offset()
: mi.get_transformation().get_matrix();
: mi.get_transformation().get_matrix();
for (ModelVolume *v : mi.get_object()->volumes) {
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()));
}
}
@ -81,11 +83,32 @@ BoundingBoxf3 instance_bounding_box(const ModelInstance &mi, bool dont_translate
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 outline;
for (const ModelVolume *v : inst.get_object()->volumes) {
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,
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)
{
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
@ -190,7 +220,14 @@ int XStriderVBedHandler::get_bed_index(const VBedPlaceable &obj) const
auto reference_pos_x = (instance_bb.min.x() - bedx);
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;
@ -231,7 +268,14 @@ int YStriderVBedHandler::get_bed_index(const VBedPlaceable &obj) const
auto reference_pos_y = (instance_bb.min.y() - ystart);
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;
@ -274,7 +318,8 @@ Vec2i GridStriderVBedHandler::raw2grid(int bed_idx) 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();
}

View File

@ -377,6 +377,9 @@ void transform_instance(ModelInstance &mi,
BoundingBoxf3 instance_bounding_box(const ModelInstance &mi,
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,
const Transform3d &tr = Transform3d::Identity());

View File

@ -3,6 +3,8 @@
#include <random>
#include <boost/log/trivial.hpp>
#include "ArrangeTask.hpp"
namespace Slic3r { namespace arr2 {
@ -20,16 +22,21 @@ void extract_selected(ArrangeTask<ArrItem> &task,
bool selected = arrbl.is_selected();
bool printable = arrbl.is_printable();
auto itm = itm_conv.convert(arrbl, selected ? 0 : -SCALED_EPSILON);
try {
auto itm = itm_conv.convert(arrbl, selected ? 0 : -SCALED_EPSILON);
auto &container_parent = printable ? task.printable :
auto &container_parent = printable ? task.printable :
task.unprintable;
auto &container = selected ?
auto &container = selected ?
container_parent.selected :
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

View File

@ -5,6 +5,8 @@
#include "Arrange/Core/NFP/NFPArrangeItemTraits.hpp"
#include <boost/log/trivial.hpp>
namespace Slic3r { namespace arr2 {
template<class ArrItem>
@ -81,15 +83,20 @@ void extract(FillBedTask<ArrItem> &task,
auto collect_task_items = [&prototype_geometry_id, &task,
&itm_conv](const Arrangeable &arrbl) {
if (arrbl.geometry_id() == prototype_geometry_id) {
if (arrbl.is_printable()) {
auto itm = itm_conv.convert(arrbl);
raise_priority(itm);
task.selected.emplace_back(std::move(itm));
try {
if (arrbl.geometry_id() == prototype_geometry_id) {
if (arrbl.is_printable()) {
auto itm = itm_conv.convert(arrbl);
raise_priority(itm);
task.selected.emplace_back(std::move(itm));
}
} else {
auto itm = itm_conv.convert(arrbl, -SCALED_EPSILON);
task.unselected.emplace_back(std::move(itm));
}
} else {
auto itm = itm_conv.convert(arrbl, -SCALED_EPSILON);
task.unselected.emplace_back(std::move(itm));
} catch (const EmptyItemOutlineError &ex) {
BOOST_LOG_TRIVIAL(error)
<< "ObjectID " << std::to_string(arrbl.id().id) << ": " << ex.what();
}
};

View File

@ -3,6 +3,8 @@
#include "MultiplySelectionTask.hpp"
#include <boost/log/trivial.hpp>
namespace Slic3r { namespace arr2 {
template<class ArrItem>
@ -45,15 +47,20 @@ std::unique_ptr<MultiplySelectionTask<ArrItem>> MultiplySelectionTask<ArrItem>::
auto collect_task_items = [&prototype_geometry_id, &task,
&itm_conv](const Arrangeable &arrbl) {
if (arrbl.geometry_id() == prototype_geometry_id) {
if (arrbl.is_printable()) {
auto itm = itm_conv.convert(arrbl);
raise_priority(itm);
task.selected.emplace_back(std::move(itm));
try {
if (arrbl.geometry_id() == prototype_geometry_id) {
if (arrbl.is_printable()) {
auto itm = itm_conv.convert(arrbl);
raise_priority(itm);
task.selected.emplace_back(std::move(itm));
}
} else {
auto itm = itm_conv.convert(arrbl, -SCALED_EPSILON);
task.unselected.emplace_back(std::move(itm));
}
} else {
auto itm = itm_conv.convert(arrbl, -SCALED_EPSILON);
task.unselected.emplace_back(std::move(itm));
} catch (const EmptyItemOutlineError &ex) {
BOOST_LOG_TRIVIAL(error)
<< "ObjectID " << std::to_string(arrbl.id().id) << ": " << ex.what();
}
};