mirror of
				https://github.com/SoftFever/OrcaSlicer.git
				synced 2025-11-02 20:51:23 -07:00 
			
		
		
		
	Ported Print::validate() to XS
This commit is contained in:
		
							parent
							
								
									3e4c572164
								
							
						
					
					
						commit
						bad0bd8520
					
				
					 10 changed files with 148 additions and 75 deletions
				
			
		| 
						 | 
				
			
			@ -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…
	
	Add table
		Add a link
		
	
		Reference in a new issue