Ported Print::validate() to XS

This commit is contained in:
Alessandro Ranellucci 2014-11-09 15:27:34 +01:00
parent 3e4c572164
commit bad0bd8520
10 changed files with 148 additions and 75 deletions

View File

@ -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 {

View File

@ -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;

View File

@ -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);

View File

@ -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

View File

@ -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);

View File

@ -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 &center)
{

View File

@ -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 &center);
void reverse();
Point first_point() const;

View File

@ -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)
{

View File

@ -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);

View File

@ -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