Ported Print::validate() to XS
This commit is contained in:
parent
3e4c572164
commit
bad0bd8520
@ -48,81 +48,6 @@ sub reload_object {
|
|||||||
$self->add_model_object($_) for @models_objects;
|
$self->add_model_object($_) for @models_objects;
|
||||||
}
|
}
|
||||||
|
|
||||||
sub validate {
|
|
||||||
my $self = shift;
|
|
||||||
|
|
||||||
if ($self->config->complete_objects) {
|
|
||||||
# check horizontal clearance
|
|
||||||
{
|
|
||||||
my @a = ();
|
|
||||||
foreach my $object (@{$self->objects}) {
|
|
||||||
# get convex hulls of all meshes assigned to this print object
|
|
||||||
my @mesh_convex_hulls = map $object->model_object->volumes->[$_]->mesh->convex_hull,
|
|
||||||
map @$_,
|
|
||||||
grep defined $_,
|
|
||||||
@{$object->region_volumes};
|
|
||||||
|
|
||||||
# make a single convex hull for all of them
|
|
||||||
my $convex_hull = convex_hull([ map @$_, @mesh_convex_hulls ]);
|
|
||||||
|
|
||||||
# apply the same transformations we apply to the actual meshes when slicing them
|
|
||||||
$object->model_object->instances->[0]->transform_polygon($convex_hull);
|
|
||||||
|
|
||||||
# align object to Z = 0 and apply XY shift
|
|
||||||
$convex_hull->translate(@{$object->_copies_shift});
|
|
||||||
|
|
||||||
# grow convex hull with the clearance margin
|
|
||||||
($convex_hull) = @{offset([$convex_hull], scale $self->config->extruder_clearance_radius / 2, 1, JT_ROUND, scale(0.1))};
|
|
||||||
|
|
||||||
# now we need that no instance of $convex_hull does not intersect any of the previously checked object instances
|
|
||||||
for my $copy (@{$object->_shifted_copies}) {
|
|
||||||
my $p = $convex_hull->clone;
|
|
||||||
|
|
||||||
$p->translate(@$copy);
|
|
||||||
if (@{ intersection(\@a, [$p]) }) {
|
|
||||||
die "Some objects are too close; your extruder will collide with them.\n";
|
|
||||||
}
|
|
||||||
@a = @{union([@a, $p])};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
# check vertical clearance
|
|
||||||
{
|
|
||||||
my @object_height = ();
|
|
||||||
foreach my $object (@{$self->objects}) {
|
|
||||||
my $height = $object->size->z;
|
|
||||||
push @object_height, $height for @{$object->copies};
|
|
||||||
}
|
|
||||||
@object_height = sort { $a <=> $b } @object_height;
|
|
||||||
# ignore the tallest *copy* (this is why we repeat height for all of them):
|
|
||||||
# it will be printed as last one so its height doesn't matter
|
|
||||||
pop @object_height;
|
|
||||||
if (@object_height && max(@object_height) > scale $self->config->extruder_clearance_height) {
|
|
||||||
die "Some objects are too tall and cannot be printed without extruder collisions.\n";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($self->config->spiral_vase) {
|
|
||||||
if ((map @{$_->copies}, @{$self->objects}) > 1) {
|
|
||||||
die "The Spiral Vase option can only be used when printing a single object.\n";
|
|
||||||
}
|
|
||||||
if (@{$self->regions} > 1) {
|
|
||||||
die "The Spiral Vase option can only be used when printing single material objects.\n";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
my $max_layer_height = max(
|
|
||||||
map { $_->config->layer_height, $_->config->get_value('first_layer_height') } @{$self->objects},
|
|
||||||
);
|
|
||||||
my $extruders = $self->extruders;
|
|
||||||
die "Layer height can't be greater than nozzle diameter\n"
|
|
||||||
if grep { $max_layer_height > $self->config->get_at('nozzle_diameter', $_) } @$extruders;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
# this value is not supposed to be compared with $layer->id
|
# this value is not supposed to be compared with $layer->id
|
||||||
# since they have different semantics
|
# since they have different semantics
|
||||||
sub total_layer_count {
|
sub total_layer_count {
|
||||||
|
@ -417,6 +417,16 @@ template void intersection<Slic3r::Polygons, Slic3r::Polygons>(const Slic3r::Pol
|
|||||||
template void intersection<Slic3r::Polygons, Slic3r::Polylines>(const Slic3r::Polygons &subject, const Slic3r::Polygons &clip, Slic3r::Polylines &retval, bool safety_offset_);
|
template void intersection<Slic3r::Polygons, Slic3r::Polylines>(const Slic3r::Polygons &subject, const Slic3r::Polygons &clip, Slic3r::Polylines &retval, bool safety_offset_);
|
||||||
template void intersection<Slic3r::Polylines, Slic3r::Polylines>(const Slic3r::Polylines &subject, const Slic3r::Polygons &clip, Slic3r::Polylines &retval, bool safety_offset_);
|
template void intersection<Slic3r::Polylines, Slic3r::Polylines>(const Slic3r::Polylines &subject, const Slic3r::Polygons &clip, Slic3r::Polylines &retval, bool safety_offset_);
|
||||||
|
|
||||||
|
template <class SubjectType>
|
||||||
|
bool intersects(const SubjectType &subject, const Slic3r::Polygons &clip, bool safety_offset_)
|
||||||
|
{
|
||||||
|
SubjectType retval;
|
||||||
|
intersection(subject, clip, retval, safety_offset_);
|
||||||
|
return !retval.empty();
|
||||||
|
}
|
||||||
|
template bool intersects<Slic3r::Polygons>(const Slic3r::Polygons &subject, const Slic3r::Polygons &clip, bool safety_offset_);
|
||||||
|
template bool intersects<Slic3r::Polylines>(const Slic3r::Polylines &subject, const Slic3r::Polygons &clip, bool safety_offset_);
|
||||||
|
|
||||||
void xor_ex(const Slic3r::Polygons &subject, const Slic3r::Polygons &clip, Slic3r::ExPolygons &retval,
|
void xor_ex(const Slic3r::Polygons &subject, const Slic3r::Polygons &clip, Slic3r::ExPolygons &retval,
|
||||||
bool safety_offset_)
|
bool safety_offset_)
|
||||||
{
|
{
|
||||||
@ -432,6 +442,13 @@ void union_(const Slic3r::Polygons &subject, T &retval, bool safety_offset_)
|
|||||||
template void union_<Slic3r::ExPolygons>(const Slic3r::Polygons &subject, Slic3r::ExPolygons &retval, bool safety_offset_);
|
template void union_<Slic3r::ExPolygons>(const Slic3r::Polygons &subject, Slic3r::ExPolygons &retval, bool safety_offset_);
|
||||||
template void union_<Slic3r::Polygons>(const Slic3r::Polygons &subject, Slic3r::Polygons &retval, bool safety_offset_);
|
template void union_<Slic3r::Polygons>(const Slic3r::Polygons &subject, Slic3r::Polygons &retval, bool safety_offset_);
|
||||||
|
|
||||||
|
void union_(const Slic3r::Polygons &subject1, const Slic3r::Polygons &subject2, Slic3r::Polygons &retval, bool safety_offset)
|
||||||
|
{
|
||||||
|
Polygons pp = subject1;
|
||||||
|
pp.insert(pp.end(), subject2.begin(), subject2.end());
|
||||||
|
union_(pp, retval, safety_offset);
|
||||||
|
}
|
||||||
|
|
||||||
void union_pt(const Slic3r::Polygons &subject, ClipperLib::PolyTree &retval, bool safety_offset_)
|
void union_pt(const Slic3r::Polygons &subject, ClipperLib::PolyTree &retval, bool safety_offset_)
|
||||||
{
|
{
|
||||||
Slic3r::Polygons clip;
|
Slic3r::Polygons clip;
|
||||||
|
@ -84,12 +84,17 @@ void diff(const SubjectType &subject, const Slic3r::Polygons &clip, ResultType &
|
|||||||
template <class SubjectType, class ResultType>
|
template <class SubjectType, class ResultType>
|
||||||
void intersection(const SubjectType &subject, const Slic3r::Polygons &clip, ResultType &retval, bool safety_offset_ = false);
|
void intersection(const SubjectType &subject, const Slic3r::Polygons &clip, ResultType &retval, bool safety_offset_ = false);
|
||||||
|
|
||||||
|
template <class SubjectType>
|
||||||
|
bool intersects(const SubjectType &subject, const Slic3r::Polygons &clip, bool safety_offset_ = false);
|
||||||
|
|
||||||
void xor_ex(const Slic3r::Polygons &subject, const Slic3r::Polygons &clip, Slic3r::ExPolygons &retval,
|
void xor_ex(const Slic3r::Polygons &subject, const Slic3r::Polygons &clip, Slic3r::ExPolygons &retval,
|
||||||
bool safety_offset_ = false);
|
bool safety_offset_ = false);
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
void union_(const Slic3r::Polygons &subject, T &retval, bool safety_offset_ = false);
|
void union_(const Slic3r::Polygons &subject, T &retval, bool safety_offset_ = false);
|
||||||
|
|
||||||
|
void union_(const Slic3r::Polygons &subject1, const Slic3r::Polygons &subject2, Slic3r::Polygons &retval, bool safety_offset = false);
|
||||||
|
|
||||||
void union_pt(const Slic3r::Polygons &subject, ClipperLib::PolyTree &retval, bool safety_offset_ = false);
|
void union_pt(const Slic3r::Polygons &subject, ClipperLib::PolyTree &retval, bool safety_offset_ = false);
|
||||||
void union_pt_chained(const Slic3r::Polygons &subject, Slic3r::Polygons &retval, bool safety_offset_ = false);
|
void union_pt_chained(const Slic3r::Polygons &subject, Slic3r::Polygons &retval, bool safety_offset_ = false);
|
||||||
static void traverse_pt(ClipperLib::PolyNodes &nodes, Slic3r::Polygons &retval);
|
static void traverse_pt(ClipperLib::PolyNodes &nodes, Slic3r::Polygons &retval);
|
||||||
|
@ -52,6 +52,16 @@ convex_hull(Points points, Polygon* hull)
|
|||||||
hull->points.pop_back();
|
hull->points.pop_back();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
convex_hull(const Polygons &polygons, Polygon* hull)
|
||||||
|
{
|
||||||
|
Points pp;
|
||||||
|
for (Polygons::const_iterator p = polygons.begin(); p != polygons.end(); ++p) {
|
||||||
|
pp.insert(pp.end(), p->points.begin(), p->points.end());
|
||||||
|
}
|
||||||
|
convex_hull(pp, hull);
|
||||||
|
}
|
||||||
|
|
||||||
/* accepts an arrayref of points and returns a list of indices
|
/* accepts an arrayref of points and returns a list of indices
|
||||||
according to a nearest-neighbor walk */
|
according to a nearest-neighbor walk */
|
||||||
void
|
void
|
||||||
|
@ -12,6 +12,7 @@ using boost::polygon::voronoi_diagram;
|
|||||||
namespace Slic3r { namespace Geometry {
|
namespace Slic3r { namespace Geometry {
|
||||||
|
|
||||||
void convex_hull(Points points, Polygon* hull);
|
void convex_hull(Points points, Polygon* hull);
|
||||||
|
void convex_hull(const Polygons &polygons, Polygon* hull);
|
||||||
void chained_path(const Points &points, std::vector<Points::size_type> &retval, Point start_near);
|
void chained_path(const Points &points, std::vector<Points::size_type> &retval, Point start_near);
|
||||||
void chained_path(const Points &points, std::vector<Points::size_type> &retval);
|
void chained_path(const Points &points, std::vector<Points::size_type> &retval);
|
||||||
template<class T> void chained_path_items(Points &points, T &items, T &retval);
|
template<class T> void chained_path_items(Points &points, T &items, T &retval);
|
||||||
|
@ -24,6 +24,12 @@ MultiPoint::translate(double x, double y)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MultiPoint::translate(const Point &vector)
|
||||||
|
{
|
||||||
|
this->translate(vector.x, vector.y);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
MultiPoint::rotate(double angle, const Point ¢er)
|
MultiPoint::rotate(double angle, const Point ¢er)
|
||||||
{
|
{
|
||||||
|
@ -19,6 +19,7 @@ class MultiPoint
|
|||||||
operator Points() const;
|
operator Points() const;
|
||||||
void scale(double factor);
|
void scale(double factor);
|
||||||
void translate(double x, double y);
|
void translate(double x, double y);
|
||||||
|
void translate(const Point &vector);
|
||||||
void rotate(double angle, const Point ¢er);
|
void rotate(double angle, const Point ¢er);
|
||||||
void reverse();
|
void reverse();
|
||||||
Point first_point() const;
|
Point first_point() const;
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
#include "Print.hpp"
|
#include "Print.hpp"
|
||||||
#include "BoundingBox.hpp"
|
#include "BoundingBox.hpp"
|
||||||
|
#include "ClipperUtils.hpp"
|
||||||
|
#include "Geometry.hpp";
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
namespace Slic3r {
|
namespace Slic3r {
|
||||||
@ -507,6 +509,97 @@ Print::init_extruders()
|
|||||||
this->state.set_done(psInitExtruders);
|
this->state.set_done(psInitExtruders);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Print::validate() const
|
||||||
|
{
|
||||||
|
if (this->config.complete_objects) {
|
||||||
|
// check horizontal clearance
|
||||||
|
{
|
||||||
|
Polygons a;
|
||||||
|
FOREACH_OBJECT(this, i_object) {
|
||||||
|
PrintObject* object = *i_object;
|
||||||
|
|
||||||
|
// get convex hulls of all meshes assigned to this print object
|
||||||
|
Polygons mesh_convex_hulls;
|
||||||
|
for (size_t i = 0; i < this->regions.size(); ++i) {
|
||||||
|
for (std::vector<int>::const_iterator it = object->region_volumes[i].begin(); it != object->region_volumes[i].end(); ++it) {
|
||||||
|
Polygon hull;
|
||||||
|
object->model_object()->volumes[*it]->mesh.convex_hull(&hull);
|
||||||
|
mesh_convex_hulls.push_back(hull);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// make a single convex hull for all of them
|
||||||
|
Polygon convex_hull;
|
||||||
|
Slic3r::Geometry::convex_hull(mesh_convex_hulls, &convex_hull);
|
||||||
|
|
||||||
|
// apply the same transformations we apply to the actual meshes when slicing them
|
||||||
|
object->model_object()->instances.front()->transform_polygon(&convex_hull);
|
||||||
|
|
||||||
|
// align object to Z = 0 and apply XY shift
|
||||||
|
convex_hull.translate(object->_copies_shift);
|
||||||
|
|
||||||
|
// grow convex hull with the clearance margin
|
||||||
|
{
|
||||||
|
Polygons grown_hull;
|
||||||
|
offset(convex_hull, grown_hull, scale_(this->config.extruder_clearance_radius.value)/2, 1, jtRound, scale_(0.1));
|
||||||
|
convex_hull = grown_hull.front();
|
||||||
|
}
|
||||||
|
|
||||||
|
// now we check that no instance of convex_hull intersects any of the previously checked object instances
|
||||||
|
for (Points::const_iterator copy = object->_shifted_copies.begin(); copy != object->_shifted_copies.end(); ++copy) {
|
||||||
|
Polygon p = convex_hull;
|
||||||
|
p.translate(*copy);
|
||||||
|
if (intersects(a, p))
|
||||||
|
throw PrintValidationException("Some objects are too close; your extruder will collide with them.");
|
||||||
|
|
||||||
|
union_(a, p, a);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// check vertical clearance
|
||||||
|
{
|
||||||
|
std::vector<coord_t> object_height;
|
||||||
|
FOREACH_OBJECT(this, i_object) {
|
||||||
|
PrintObject* object = *i_object;
|
||||||
|
object_height.insert(object_height.end(), object->copies().size(), object->size.z);
|
||||||
|
}
|
||||||
|
std::sort(object_height.begin(), object_height.end());
|
||||||
|
// ignore the tallest *copy* (this is why we repeat height for all of them):
|
||||||
|
// it will be printed as last one so its height doesn't matter
|
||||||
|
object_height.pop_back();
|
||||||
|
if (!object_height.empty() && object_height.back() > scale_(this->config.extruder_clearance_height.value))
|
||||||
|
throw PrintValidationException("Some objects are too tall and cannot be printed without extruder collisions.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this->config.spiral_vase) {
|
||||||
|
size_t total_copies_count = 0;
|
||||||
|
FOREACH_OBJECT(this, i_object) total_copies_count += (*i_object)->copies().size();
|
||||||
|
if (total_copies_count > 1)
|
||||||
|
throw PrintValidationException("The Spiral Vase option can only be used when printing a single object.");
|
||||||
|
if (this->regions.size() > 1)
|
||||||
|
throw PrintValidationException("The Spiral Vase option can only be used when printing single material objects.");
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
std::vector<double> layer_heights;
|
||||||
|
FOREACH_OBJECT(this, i_object) {
|
||||||
|
PrintObject* object = *i_object;
|
||||||
|
layer_heights.push_back(object->config.layer_height);
|
||||||
|
layer_heights.push_back(object->config.get_abs_value("first_layer_height"));
|
||||||
|
}
|
||||||
|
double max_layer_height = *std::max_element(layer_heights.begin(), layer_heights.end());
|
||||||
|
|
||||||
|
std::set<size_t> extruders = this->extruders();
|
||||||
|
for (std::set<size_t>::iterator it = extruders.begin(); it != extruders.end(); ++it) {
|
||||||
|
if (max_layer_height > this->config.nozzle_diameter.get_at(*it))
|
||||||
|
throw PrintValidationException("Layer height can't be greater than nozzle diameter");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
PrintRegionConfig
|
PrintRegionConfig
|
||||||
Print::_region_config_from_model_volume(const ModelVolume &volume)
|
Print::_region_config_from_model_volume(const ModelVolume &volume)
|
||||||
{
|
{
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
#include <myinit.h>
|
#include <myinit.h>
|
||||||
#include <set>
|
#include <set>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <stdexcept>
|
||||||
#include "Flow.hpp"
|
#include "Flow.hpp"
|
||||||
#include "PrintConfig.hpp"
|
#include "PrintConfig.hpp"
|
||||||
#include "Point.hpp"
|
#include "Point.hpp"
|
||||||
@ -27,6 +28,11 @@ enum PrintObjectStep {
|
|||||||
posInfill, posSupportMaterial,
|
posInfill, posSupportMaterial,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class PrintValidationException : public std::runtime_error {
|
||||||
|
public:
|
||||||
|
PrintValidationException(const std::string &error) : std::runtime_error(error) {};
|
||||||
|
};
|
||||||
|
|
||||||
template <class StepType>
|
template <class StepType>
|
||||||
class PrintState
|
class PrintState
|
||||||
{
|
{
|
||||||
@ -171,6 +177,7 @@ class Print
|
|||||||
void add_model_object(ModelObject* model_object, int idx = -1);
|
void add_model_object(ModelObject* model_object, int idx = -1);
|
||||||
bool apply_config(DynamicPrintConfig config);
|
bool apply_config(DynamicPrintConfig config);
|
||||||
void init_extruders();
|
void init_extruders();
|
||||||
|
void validate() const;
|
||||||
|
|
||||||
std::set<size_t> extruders() const;
|
std::set<size_t> extruders() const;
|
||||||
void _simplify_slices(double distance);
|
void _simplify_slices(double distance);
|
||||||
|
@ -171,6 +171,14 @@ _constant()
|
|||||||
bool apply_config(DynamicPrintConfig* config)
|
bool apply_config(DynamicPrintConfig* config)
|
||||||
%code%{ RETVAL = THIS->apply_config(*config); %};
|
%code%{ RETVAL = THIS->apply_config(*config); %};
|
||||||
void init_extruders();
|
void init_extruders();
|
||||||
|
void validate()
|
||||||
|
%code%{
|
||||||
|
try {
|
||||||
|
THIS->validate();
|
||||||
|
} catch (PrintValidationException &e) {
|
||||||
|
croak(e.what());
|
||||||
|
}
|
||||||
|
%};
|
||||||
%{
|
%{
|
||||||
|
|
||||||
double
|
double
|
||||||
|
Loading…
Reference in New Issue
Block a user