Browse Source

Ported some methods including add_model_object() and apply_config() to XS

Alessandro Ranellucci 10 years ago
parent
commit
3e4c572164

+ 0 - 30
lib/Slic3r/Config.pm

@@ -174,19 +174,6 @@ sub _handle_legacy {
     return ($opt_key, $value);
 }
 
-sub set_ifndef {
-    my $self = shift;
-    my ($opt_key, $value, $deserialize) = @_;
-    
-    if (!$self->has($opt_key)) {
-        if ($deserialize) {
-            $self->set_deserialize($opt_key, $value);
-        } else {
-            $self->set($opt_key, $value);
-        }
-    }
-}
-
 sub as_ini {
     my ($self) = @_;
     
@@ -213,23 +200,6 @@ sub setenv {
     }
 }
 
-sub equals {
-    my ($self, $other) = @_;
-    return @{ $self->diff($other) } == 0;
-}
-
-# this will *ignore* options not present in both configs
-sub diff {
-    my ($self, $other) = @_;
-    
-    my @diff = ();
-    foreach my $opt_key (sort @{$self->get_keys}) {
-        push @diff, $opt_key
-            if $other->has($opt_key) && $other->serialize($opt_key) ne $self->serialize($opt_key);
-    }
-    return [@diff];
-}
-
 # this method is idempotent by design and only applies to ::DynamicConfig or ::Full
 # objects because it performs cross checks
 sub validate {

+ 0 - 183
lib/Slic3r/Print.pm

@@ -34,189 +34,6 @@ sub status_cb {
     return $status_cb // sub {};
 }
 
-sub apply_config {
-    my ($self, $config) = @_;
-    
-    $config = $config->clone;
-    $config->normalize;
-    
-    # apply variables to placeholder parser
-    $self->placeholder_parser->apply_config($config);
-    
-    my $invalidated = 0;
-    
-    # handle changes to print config
-    my $print_diff = $self->config->diff($config);
-    if (@$print_diff) {
-        $self->config->apply_dynamic($config);
-        
-        $invalidated = 1
-            if $self->invalidate_state_by_config_options($print_diff);
-    }
-    
-    # handle changes to object config defaults
-    $self->default_object_config->apply_dynamic($config);
-    foreach my $object (@{$self->objects}) {
-        # we don't assume that $config contains a full ObjectConfig,
-        # so we base it on the current print-wise default
-        my $new = $self->default_object_config->clone;
-        $new->apply_dynamic($config);
-        
-        # we override the new config with object-specific options
-        my $model_object_config = $object->model_object->config->clone;
-        $model_object_config->normalize;
-        $new->apply_dynamic($model_object_config);
-        
-        # check whether the new config is different from the current one
-        my $diff = $object->config->diff($new);
-        if (@$diff) {
-            $object->config->apply($new);
-            
-            $invalidated = 1
-                if $object->invalidate_state_by_config_options($diff);
-        }
-    }
-    
-    # handle changes to regions config defaults
-    $self->default_region_config->apply_dynamic($config);
-    
-    # All regions now have distinct settings.
-    # Check whether applying the new region config defaults we'd get different regions.
-    my $rearrange_regions = 0;
-    my @other_region_configs = ();
-    REGION: foreach my $region_id (0..($self->region_count - 1)) {
-        my $region = $self->regions->[$region_id];
-        my @this_region_configs = ();
-        foreach my $object (@{$self->objects}) {
-            foreach my $volume_id (@{ $object->get_region_volumes($region_id) }) {
-                my $volume = $object->model_object->volumes->[$volume_id];
-                
-                my $new = $self->default_region_config->clone;
-                foreach my $other_config ($object->model_object->config, $volume->config) {
-                    my $other_config = $other_config->clone;
-                    $other_config->normalize;
-                    $new->apply_dynamic($other_config);
-                }
-                if ($volume->material_id ne '') {
-                    my $material_config = $object->model_object->model->get_material($volume->material_id)->config->clone;
-                    $material_config->normalize;
-                    $new->apply_dynamic($material_config);
-                }
-                if (defined first { !$_->equals($new) } @this_region_configs) {
-                    # if the new config for this volume differs from the other
-                    # volume configs currently associated to this region, it means
-                    # the region subdivision does not make sense anymore
-                    $rearrange_regions = 1;
-                    last REGION;
-                }
-                push @this_region_configs, $new;
-                
-                if (defined first { $_->equals($new) } @other_region_configs) {
-                    # if the new config for this volume equals any of the other
-                    # volume configs that are not currently associated to this
-                    # region, it means the region subdivision does not make
-                    # sense anymore
-                    $rearrange_regions = 1;
-                    last REGION;
-                }
-                
-                # if we're here and the new region config is different from the old
-                # one, we need to apply the new config and invalidate all objects
-                # (possible optimization: only invalidate objects using this region)
-                my $region_config_diff = $region->config->diff($new);
-                if (@$region_config_diff) {
-                    $region->config->apply($new);
-                    foreach my $o (@{$self->objects}) {
-                        $invalidated = 1
-                            if $o->invalidate_state_by_config_options($region_config_diff);
-                    }
-                }
-            }
-        }
-        push @other_region_configs, @this_region_configs;
-    }
-    
-    if ($rearrange_regions) {
-        # the current subdivision of regions does not make sense anymore.
-        # we need to remove all objects and re-add them
-        my @model_objects = map $_->model_object, @{$self->objects};
-        $self->clear_objects;
-        $self->add_model_object($_) for @model_objects;
-        $invalidated = 1;
-    }
-    
-    return $invalidated;
-}
-
-# caller is responsible for supplying models whose objects don't collide
-# and have explicit instance positions
-sub add_model_object {
-    my $self = shift;
-    my ($object, $obj_idx) = @_;
-    
-    my $object_config = $object->config->clone;
-    $object_config->normalize;
-
-    # initialize print object and store it at the given position
-    my $o;
-    if (defined $obj_idx) {
-        $o = $self->set_new_object($obj_idx, $object, $object->raw_bounding_box);
-    } else {
-        $o = $self->add_object($object, $object->raw_bounding_box);
-    }
-    
-    $o->set_copies([ map Slic3r::Point->new_scale(@{ $_->offset }), @{ $object->instances } ]);
-    $o->set_layer_height_ranges($object->layer_height_ranges);
-
-    # TODO: translate _trigger_copies to C++, then this can be done by
-        # PrintObject constructor
-    $o->_trigger_copies;
-
-    foreach my $volume_id (0..$#{$object->volumes}) {
-        my $volume = $object->volumes->[$volume_id];
-        
-        # get the config applied to this volume: start from our global defaults
-        my $config = Slic3r::Config::PrintRegion->new;
-        $config->apply($self->default_region_config);
-        
-        # override the defaults with per-object config and then with per-volume and per-material configs
-        foreach my $other_config ($object_config, $volume->config) {
-            my $other_config = $other_config->clone;
-            $other_config->normalize;
-            $config->apply_dynamic($other_config);
-        }
-        if ($volume->material_id ne '') {
-            my $material_config = $volume->material->config->clone;
-            $material_config->normalize;
-            $config->apply_dynamic($material_config);
-        }
-        
-        # find an existing print region with the same config
-        my $region_id;
-        foreach my $i (0..($self->region_count - 1)) {
-            my $region = $self->regions->[$i];
-            if ($config->equals($region->config)) {
-                $region_id = $i;
-                last;
-            }
-        }
-        
-        # if no region exists with the same config, create a new one
-        if (!defined $region_id) {
-            my $r = $self->add_region();
-            $r->config->apply($config);
-            $region_id = $self->region_count - 1;
-        }
-        
-        # assign volume to region
-        $o->add_region_volume($region_id, $volume_id);
-    }
-
-    # apply config to print object
-    $o->config->apply($self->default_object_config);
-    $o->config->apply_dynamic($object_config);
-}
-
 sub reload_object {
     my ($self, $obj_idx) = @_;
     

+ 0 - 24
lib/Slic3r/Print/Object.pm

@@ -32,34 +32,12 @@ sub support_layers {
     return [ map $self->get_support_layer($_), 0..($self->support_layer_count - 1) ];
 }
 
-# TODO: translate to C++, then call it from constructor (see also
-    # Print->add_model_object)
-sub _trigger_copies {
-    my $self = shift;
-    
-    # TODO: should this mean point is 0,0?
-    return if !defined $self->_copies_shift;
-    
-    # order copies with a nearest neighbor search and translate them by _copies_shift
-    $self->set_shifted_copies([
-        map {
-            my $c = $_->clone;
-            $c->translate(@{ $self->_copies_shift });
-            $c;
-        } @{$self->copies}[@{chained_path($self->copies)}]
-    ]);
-    
-    $self->print->invalidate_step(STEP_SKIRT);
-    $self->print->invalidate_step(STEP_BRIM);
-}
-
 # in unscaled coordinates
 sub add_copy {
     my ($self, $x, $y) = @_;
     my @copies = @{$self->copies};
     push @copies, Slic3r::Point->new_scale($x, $y);
     $self->set_copies(\@copies);
-    $self->_trigger_copies;
 }
 
 sub delete_last_copy {
@@ -67,13 +45,11 @@ sub delete_last_copy {
     my @copies = $self->copies;
     pop @copies;
     $self->set_copies(\@copies);
-    $self->_trigger_copies;
 }
 
 sub delete_all_copies {
     my ($self) = @_;
     $self->set_copies([]);
-    $self->_trigger_copies;
 }
 
 # this is the *total* layer count (including support layers)

+ 33 - 0
xs/src/libslic3r/Config.cpp

@@ -27,6 +27,27 @@ ConfigBase::apply(const ConfigBase &other, bool ignore_nonexistent) {
     }
 }
 
+bool
+ConfigBase::equals(ConfigBase &other) {
+    return this->diff(other).empty();
+}
+
+// this will *ignore* options not present in both configs
+t_config_option_keys
+ConfigBase::diff(ConfigBase &other) {
+    t_config_option_keys diff;
+    
+    t_config_option_keys my_keys;
+    this->keys(&my_keys);
+    for (t_config_option_keys::const_iterator opt_key = my_keys.begin(); opt_key != my_keys.end(); ++opt_key) {
+        if (other.has(*opt_key) && other.serialize(*opt_key) != this->serialize(*opt_key)) {
+            diff.push_back(*opt_key);
+        }
+    }
+    
+    return diff;
+}
+
 std::string
 ConfigBase::serialize(const t_config_option_key opt_key) {
     ConfigOption* opt = this->option(opt_key);
@@ -248,6 +269,18 @@ ConfigBase::set_deserialize(const t_config_option_key opt_key, SV* str) {
     
     return this->set_deserialize(opt_key, value);
 }
+
+void
+ConfigBase::set_ifndef(t_config_option_key opt_key, SV* value, bool deserialize)
+{
+    if (!this->has(opt_key)) {
+        if (deserialize) {
+            this->set_deserialize(opt_key, value);
+        } else {
+            this->set(opt_key, value);
+        }
+    }
+}
 #endif
 
 DynamicConfig& DynamicConfig::operator= (DynamicConfig other)

+ 3 - 0
xs/src/libslic3r/Config.hpp

@@ -464,8 +464,11 @@ class ConfigBase
     virtual const ConfigOption* option(const t_config_option_key opt_key) const = 0;
     virtual void keys(t_config_option_keys *keys) const = 0;
     void apply(const ConfigBase &other, bool ignore_nonexistent = false);
+    bool equals(ConfigBase &other);
+    t_config_option_keys diff(ConfigBase &other);
     std::string serialize(const t_config_option_key opt_key);
     bool set_deserialize(const t_config_option_key opt_key, std::string str);
+    void set_ifndef(t_config_option_key opt_key, SV* value, bool deserialize = false);
     double get_abs_value(const t_config_option_key opt_key);
     double get_abs_value(const t_config_option_key opt_key, double ratio_over);
     

+ 6 - 6
xs/src/libslic3r/Geometry.cpp

@@ -25,7 +25,7 @@ sort_points (Point a, Point b)
 
 /* This implementation is based on Andrew's monotone chain 2D convex hull algorithm */
 void
-convex_hull(Points &points, Polygon* hull)
+convex_hull(Points points, Polygon* hull)
 {
     assert(points.size() >= 3);
     // sort input points
@@ -55,12 +55,12 @@ convex_hull(Points &points, Polygon* hull)
 /* accepts an arrayref of points and returns a list of indices
    according to a nearest-neighbor walk */
 void
-chained_path(Points &points, std::vector<Points::size_type> &retval, Point start_near)
+chained_path(const Points &points, std::vector<Points::size_type> &retval, Point start_near)
 {
-    PointPtrs my_points;
-    std::map<Point*,Points::size_type> indices;
+    PointConstPtrs my_points;
+    std::map<const Point*,Points::size_type> indices;
     my_points.reserve(points.size());
-    for (Points::iterator it = points.begin(); it != points.end(); ++it) {
+    for (Points::const_iterator it = points.begin(); it != points.end(); ++it) {
         my_points.push_back(&*it);
         indices[&*it] = it - points.begin();
     }
@@ -75,7 +75,7 @@ chained_path(Points &points, std::vector<Points::size_type> &retval, Point start
 }
 
 void
-chained_path(Points &points, std::vector<Points::size_type> &retval)
+chained_path(const Points &points, std::vector<Points::size_type> &retval)
 {
     if (points.empty()) return;  // can't call front() on empty vector
     chained_path(points, retval, points.front());

+ 3 - 3
xs/src/libslic3r/Geometry.hpp

@@ -11,9 +11,9 @@ using boost::polygon::voronoi_diagram;
 
 namespace Slic3r { namespace Geometry {
 
-void convex_hull(Points &points, Polygon* hull);
-void chained_path(Points &points, std::vector<Points::size_type> &retval, Point start_near);
-void chained_path(Points &points, std::vector<Points::size_type> &retval);
+void convex_hull(Points points, 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);
 bool directions_parallel(double angle1, double angle2, double max_diff = 0);
 

+ 6 - 0
xs/src/libslic3r/Point.cpp

@@ -40,6 +40,12 @@ Point::translate(double x, double y)
     this->y += y;
 }
 
+void
+Point::translate(const Point &vector)
+{
+    this->translate(vector.x, vector.y);
+}
+
 void
 Point::rotate(double angle, const Point &center)
 {

+ 4 - 0
xs/src/libslic3r/Point.hpp

@@ -27,10 +27,14 @@ class Point
     Point(int _x, int _y): x(_x), y(_y) {};
     Point(long long _x, long long _y): x(_x), y(_y) {};  // for Clipper
     Point(double x, double y);
+    static Point new_scale(coordf_t x, coordf_t y) {
+        return Point(scale_(x), scale_(y));
+    };
     bool operator==(const Point& rhs) const;
     std::string wkt() const;
     void scale(double factor);
     void translate(double x, double y);
+    void translate(const Point &vector);
     void rotate(double angle, const Point &center);
     bool coincides_with(const Point &point) const;
     bool coincides_with_epsilon(const Point &point) const;

+ 205 - 0
xs/src/libslic3r/Print.cpp

@@ -308,6 +308,189 @@ Print::max_allowed_layer_height() const
     return *std::max_element(nozzle_diameter.begin(), nozzle_diameter.end());
 }
 
+/*  Caller is responsible for supplying models whose objects don't collide
+    and have explicit instance positions */
+void
+Print::add_model_object(ModelObject* model_object, int idx)
+{
+    DynamicPrintConfig object_config = model_object->config;  // clone
+    object_config.normalize();
+
+    // initialize print object and store it at the given position
+    PrintObject* o;
+    {
+        BoundingBoxf3 bb;
+        model_object->raw_bounding_box(&bb);
+        o = (idx != -1)
+            ? this->set_new_object(idx, model_object, bb)
+            : this->add_object(model_object, bb);
+    }
+    
+    {
+        Points copies;
+        for (ModelInstancePtrs::const_iterator i = model_object->instances.begin(); i != model_object->instances.end(); ++i) {
+            copies.push_back(Point::new_scale((*i)->offset.x, (*i)->offset.y));
+        }
+        o->set_copies(copies);
+    }
+    o->layer_height_ranges = model_object->layer_height_ranges;
+
+    for (ModelVolumePtrs::const_iterator v_i = model_object->volumes.begin(); v_i != model_object->volumes.end(); ++v_i) {
+        size_t volume_id = v_i - model_object->volumes.begin();
+        ModelVolume* volume = *v_i;
+        
+        // get the config applied to this volume
+        PrintRegionConfig config = this->_region_config_from_model_volume(*volume);
+        
+        // find an existing print region with the same config
+        int region_id = -1;
+        for (PrintRegionPtrs::const_iterator region = this->regions.begin(); region != this->regions.end(); ++region) {
+            if (config.equals((*region)->config)) {
+                region_id = region - this->regions.begin();
+                break;
+            }
+        }
+        
+        // if no region exists with the same config, create a new one
+        if (region_id == -1) {
+            PrintRegion* r = this->add_region();
+            r->config.apply(config);
+            region_id = this->regions.size() - 1;
+        }
+        
+        // assign volume to region
+        o->add_region_volume(region_id, volume_id);
+    }
+
+    // apply config to print object
+    o->config.apply(this->default_object_config);
+    o->config.apply(object_config, true);
+}
+
+bool
+Print::apply_config(DynamicPrintConfig config)
+{
+    // we get a copy of the config object so we can modify it safely
+    config.normalize();
+    
+    // apply variables to placeholder parser
+    this->placeholder_parser.apply_config(config);
+    
+    bool invalidated = false;
+    
+    // handle changes to print config
+    t_config_option_keys print_diff = this->config.diff(config);
+    if (!print_diff.empty()) {
+        this->config.apply(config, true);
+        
+        if (this->invalidate_state_by_config_options(print_diff))
+            invalidated = true;
+    }
+    
+    // handle changes to object config defaults
+    this->default_object_config.apply(config, true);
+    FOREACH_OBJECT(this, obj_ptr) {
+        // we don't assume that config contains a full ObjectConfig,
+        // so we base it on the current print-wise default
+        PrintObjectConfig new_config = this->default_object_config;
+        new_config.apply(config, true);
+        
+        // we override the new config with object-specific options
+        {
+            DynamicPrintConfig model_object_config = (*obj_ptr)->model_object()->config;
+            model_object_config.normalize();
+            new_config.apply(model_object_config, true);
+        }
+        
+        // check whether the new config is different from the current one
+        t_config_option_keys diff = (*obj_ptr)->config.diff(new_config);
+        if (!diff.empty()) {
+            (*obj_ptr)->config.apply(new_config, true);
+            
+            if ((*obj_ptr)->invalidate_state_by_config_options(diff))
+                invalidated = true;
+        }
+    }
+    
+    // handle changes to regions config defaults
+    this->default_region_config.apply(config, true);
+    
+    // All regions now have distinct settings.
+    // Check whether applying the new region config defaults we'd get different regions.
+    bool rearrange_regions = false;
+    std::vector<PrintRegionConfig> other_region_configs;
+    FOREACH_REGION(this, it_r) {
+        size_t region_id = it_r - this->regions.begin();
+        PrintRegion* region = *it_r;
+        
+        std::vector<PrintRegionConfig> this_region_configs;
+        FOREACH_OBJECT(this, it_o) {
+            PrintObject* object = *it_o;
+            
+            std::vector<int> &region_volumes = object->region_volumes[region_id];
+            for (std::vector<int>::const_iterator volume_id = region_volumes.begin(); volume_id != region_volumes.end(); ++volume_id) {
+                ModelVolume* volume = object->model_object()->volumes[*volume_id];
+                
+                PrintRegionConfig new_config = this->_region_config_from_model_volume(*volume);
+                
+                for (std::vector<PrintRegionConfig>::iterator it = this_region_configs.begin(); it != this_region_configs.end(); ++it) {
+                    // if the new config for this volume differs from the other
+                    // volume configs currently associated to this region, it means
+                    // the region subdivision does not make sense anymore
+                    if (!it->equals(new_config)) {
+                        rearrange_regions = true;
+                        goto NEXT_REGION;
+                    }
+                }
+                this_region_configs.push_back(new_config);
+                
+                for (std::vector<PrintRegionConfig>::iterator it = other_region_configs.begin(); it != other_region_configs.end(); ++it) {
+                    // if the new config for this volume equals any of the other
+                    // volume configs that are not currently associated to this
+                    // region, it means the region subdivision does not make
+                    // sense anymore
+                    if (it->equals(new_config)) {
+                        rearrange_regions = true;
+                        goto NEXT_REGION;
+                    }
+                }
+                
+                // if we're here and the new region config is different from the old
+                // one, we need to apply the new config and invalidate all objects
+                // (possible optimization: only invalidate objects using this region)
+                t_config_option_keys region_config_diff = region->config.diff(new_config);
+                if (!region_config_diff.empty()) {
+                    region->config.apply(new_config);
+                    FOREACH_OBJECT(this, o) {
+                        if ((*o)->invalidate_state_by_config_options(region_config_diff))
+                            invalidated = true;
+                    }
+                }
+            }
+        }
+        other_region_configs.insert(other_region_configs.end(), this_region_configs.begin(), this_region_configs.end());
+        
+        NEXT_REGION:
+            continue;
+    }
+    
+    if (rearrange_regions) {
+        // the current subdivision of regions does not make sense anymore.
+        // we need to remove all objects and re-add them
+        ModelObjectPtrs model_objects;
+        FOREACH_OBJECT(this, o) {
+            model_objects.push_back((*o)->model_object());
+        }
+        this->clear_objects();
+        for (ModelObjectPtrs::iterator it = model_objects.begin(); it != model_objects.end(); ++it) {
+            this->add_model_object(*it);
+        }
+        invalidated = true;
+    }
+    
+    return invalidated;
+}
+
 void
 Print::init_extruders()
 {
@@ -324,6 +507,28 @@ Print::init_extruders()
     this->state.set_done(psInitExtruders);
 }
 
+PrintRegionConfig
+Print::_region_config_from_model_volume(const ModelVolume &volume)
+{
+    PrintRegionConfig config = this->default_region_config;
+    {
+        DynamicPrintConfig other_config = volume.get_object()->config;
+        other_config.normalize();
+        config.apply(other_config, true);
+    }
+    {
+        DynamicPrintConfig other_config = volume.config;
+        other_config.normalize();
+        config.apply(other_config, true);
+    }
+    if (!volume.material_id().empty()) {
+        DynamicPrintConfig material_config = volume.material()->config;
+        material_config.normalize();
+        config.apply(material_config, true);
+    }
+    return config;
+}
+
 bool
 Print::has_support_material() const
 {

Some files were not shown because too many files changed in this diff