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;
|
||||
}
|
||||
|
||||
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
|
||||
# since they have different semantics
|
||||
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::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,
|
||||
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::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_)
|
||||
{
|
||||
Slic3r::Polygons clip;
|
||||
|
@ -84,12 +84,17 @@ void diff(const SubjectType &subject, const Slic3r::Polygons &clip, ResultType &
|
||||
template <class SubjectType, class ResultType>
|
||||
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,
|
||||
bool safety_offset_ = false);
|
||||
|
||||
template <class T>
|
||||
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_chained(const Slic3r::Polygons &subject, Slic3r::Polygons &retval, bool safety_offset_ = false);
|
||||
static void traverse_pt(ClipperLib::PolyNodes &nodes, Slic3r::Polygons &retval);
|
||||
|
@ -52,6 +52,16 @@ convex_hull(Points points, Polygon* hull)
|
||||
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
|
||||
according to a nearest-neighbor walk */
|
||||
void
|
||||
|
@ -12,6 +12,7 @@ using boost::polygon::voronoi_diagram;
|
||||
namespace Slic3r { namespace Geometry {
|
||||
|
||||
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);
|
||||
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
|
||||
MultiPoint::rotate(double angle, const Point ¢er)
|
||||
{
|
||||
|
@ -19,6 +19,7 @@ class MultiPoint
|
||||
operator Points() const;
|
||||
void scale(double factor);
|
||||
void translate(double x, double y);
|
||||
void translate(const Point &vector);
|
||||
void rotate(double angle, const Point ¢er);
|
||||
void reverse();
|
||||
Point first_point() const;
|
||||
|
@ -1,5 +1,7 @@
|
||||
#include "Print.hpp"
|
||||
#include "BoundingBox.hpp"
|
||||
#include "ClipperUtils.hpp"
|
||||
#include "Geometry.hpp";
|
||||
#include <algorithm>
|
||||
|
||||
namespace Slic3r {
|
||||
@ -507,6 +509,97 @@ Print::init_extruders()
|
||||
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
|
||||
Print::_region_config_from_model_volume(const ModelVolume &volume)
|
||||
{
|
||||
|
@ -4,6 +4,7 @@
|
||||
#include <myinit.h>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
#include <stdexcept>
|
||||
#include "Flow.hpp"
|
||||
#include "PrintConfig.hpp"
|
||||
#include "Point.hpp"
|
||||
@ -27,6 +28,11 @@ enum PrintObjectStep {
|
||||
posInfill, posSupportMaterial,
|
||||
};
|
||||
|
||||
class PrintValidationException : public std::runtime_error {
|
||||
public:
|
||||
PrintValidationException(const std::string &error) : std::runtime_error(error) {};
|
||||
};
|
||||
|
||||
template <class StepType>
|
||||
class PrintState
|
||||
{
|
||||
@ -171,6 +177,7 @@ class Print
|
||||
void add_model_object(ModelObject* model_object, int idx = -1);
|
||||
bool apply_config(DynamicPrintConfig config);
|
||||
void init_extruders();
|
||||
void validate() const;
|
||||
|
||||
std::set<size_t> extruders() const;
|
||||
void _simplify_slices(double distance);
|
||||
|
@ -171,6 +171,14 @@ _constant()
|
||||
bool apply_config(DynamicPrintConfig* config)
|
||||
%code%{ RETVAL = THIS->apply_config(*config); %};
|
||||
void init_extruders();
|
||||
void validate()
|
||||
%code%{
|
||||
try {
|
||||
THIS->validate();
|
||||
} catch (PrintValidationException &e) {
|
||||
croak(e.what());
|
||||
}
|
||||
%};
|
||||
%{
|
||||
|
||||
double
|
||||
|
Loading…
Reference in New Issue
Block a user