diff --git a/lib/Slic3r/GUI/3DScene.pm b/lib/Slic3r/GUI/3DScene.pm index 5f0c4298a..ca2f11c34 100644 --- a/lib/Slic3r/GUI/3DScene.pm +++ b/lib/Slic3r/GUI/3DScene.pm @@ -547,7 +547,8 @@ sub mouse_wheel_event { $zoom /= 10; $zoom = $self->_zoom / (1-$zoom); # Don't allow to zoom too far outside the scene. - my $zoom_min = $self->get_zoom_to_bounding_box_factor($self->max_bounding_box) * 0.4; + my $zoom_min = $self->get_zoom_to_bounding_box_factor($self->max_bounding_box); + $zoom_min *= 0.4 if defined $zoom_min; $zoom = $zoom_min if defined $zoom_min && $zoom < $zoom_min; $self->_zoom($zoom); diff --git a/lib/Slic3r/GUI/BedShapeDialog.pm b/lib/Slic3r/GUI/BedShapeDialog.pm index 5e7a7008c..12689147a 100644 --- a/lib/Slic3r/GUI/BedShapeDialog.pm +++ b/lib/Slic3r/GUI/BedShapeDialog.pm @@ -290,7 +290,7 @@ sub _load_stl { $dialog->Destroy; my $model = Slic3r::Model->read_from_file($input_file); - my $mesh = $model->raw_mesh; + my $mesh = $model->mesh; my $expolygons = $mesh->horizontal_projection; if (@$expolygons == 0) { diff --git a/lib/Slic3r/GUI/Plater.pm b/lib/Slic3r/GUI/Plater.pm index e4ac29638..20b4fa172 100644 --- a/lib/Slic3r/GUI/Plater.pm +++ b/lib/Slic3r/GUI/Plater.pm @@ -707,7 +707,7 @@ sub load_file { local $SIG{__WARN__} = Slic3r::GUI::warning_catcher($self); - my $model = eval { Slic3r::Model->read_from_file($input_file) }; + my $model = eval { Slic3r::Model->read_from_file($input_file, 0) }; Slic3r::GUI::show_error($self, $@) if $@; my @obj_idx = (); @@ -1007,7 +1007,6 @@ sub rotate { $self->reset_thumbnail($obj_idx); } - $model_object->update_bounding_box; # update print and start background processing $self->{print}->add_model_object($model_object, $obj_idx); @@ -1032,7 +1031,6 @@ sub mirror { } $model_object->mirror($axis); - $model_object->update_bounding_box; # realign object to Z = 0 $model_object->center_around_origin; @@ -1112,7 +1110,6 @@ sub changescale { $_->set_scaling_factor($scale) for @{ $model_object->instances }; $object->transform_thumbnail($self->{model}, $obj_idx); } - $model_object->update_bounding_box; # update print and start background processing $self->stop_background_process; @@ -1133,6 +1130,7 @@ sub arrange { # ignore arrange failures on purpose: user has visual feedback and we don't need to warn him # when parts don't fit in print bed + # Force auto center of the aligned grid of of objects on the print bed. $self->update(1); } @@ -2198,6 +2196,7 @@ sub make_thumbnail { # make method idempotent $self->thumbnail->clear; + # raw_mesh is the non-transformed (non-rotated, non-scaled, non-translated) sum of non-modifier object volumes. my $mesh = $model->objects->[$obj_idx]->raw_mesh; #FIXME The "correct" variant could be extremely slow. # if ($mesh->facets_count <= 5000) { diff --git a/lib/Slic3r/GUI/Plater/2D.pm b/lib/Slic3r/GUI/Plater/2D.pm index 8d7b35ac7..089b25947 100644 --- a/lib/Slic3r/GUI/Plater/2D.pm +++ b/lib/Slic3r/GUI/Plater/2D.pm @@ -246,7 +246,6 @@ sub mouse_event { unscale($point->[X] - $self->{drag_start_pos}[X]), unscale($point->[Y] - $self->{drag_start_pos}[Y]), )); - $model_object->update_bounding_box; $self->Refresh; } elsif ($event->Moving) { my $cursor = wxSTANDARD_CURSOR; diff --git a/lib/Slic3r/Model.pm b/lib/Slic3r/Model.pm index 280688f84..7c0a035b8 100644 --- a/lib/Slic3r/Model.pm +++ b/lib/Slic3r/Model.pm @@ -6,8 +6,8 @@ use List::Util qw(first max any); use Slic3r::Geometry qw(X Y Z move_points); sub read_from_file { - my $class = shift; - my ($input_file) = @_; + my ($class, $input_file, $add_default_instances) = @_; + $add_default_instances //= 1; my $model = $input_file =~ /\.stl$/i ? Slic3r::Model->load_stl(Slic3r::encode_path($input_file), basename($input_file)) : $input_file =~ /\.obj$/i ? Slic3r::Model->load_obj(Slic3r::encode_path($input_file), basename($input_file)) @@ -19,6 +19,7 @@ sub read_from_file { if $model->objects_count == 0; $_->set_input_file($input_file) for @{$model->objects}; + $model->add_default_instances if $add_default_instances; return $model; } diff --git a/slic3r.pl b/slic3r.pl index 0cd814ce5..47963d00d 100755 --- a/slic3r.pl +++ b/slic3r.pl @@ -144,7 +144,6 @@ if (@ARGV) { # slicing from command line foreach my $file (@ARGV) { $file = Slic3r::decode_path($file); my $model = Slic3r::Model->read_from_file($file); - $model->add_default_instances; my $mesh = $model->mesh; $mesh->translate(0, 0, -$mesh->bounding_box->z_min); my $upper = Slic3r::TriangleMesh->new; @@ -164,7 +163,6 @@ if (@ARGV) { # slicing from command line foreach my $file (@ARGV) { $file = Slic3r::decode_path($file); my $model = Slic3r::Model->read_from_file($file); - $model->add_default_instances; my $mesh = $model->mesh; $mesh->repair; diff --git a/utils/view-mesh.pl b/utils/view-mesh.pl index 687a56224..66f1f3ead 100644 --- a/utils/view-mesh.pl +++ b/utils/view-mesh.pl @@ -28,9 +28,6 @@ my %opt = (); { my $model = Slic3r::Model->read_from_file($ARGV[0]); - - # make sure all objects have at least one defined instance - $model->add_default_instances; $_->center_around_origin for @{$model->objects}; # and align to Z = 0 my $app = Slic3r::ViewMesh->new; diff --git a/utils/wireframe.pl b/utils/wireframe.pl index 053581dec..53ac69a8a 100644 --- a/utils/wireframe.pl +++ b/utils/wireframe.pl @@ -38,7 +38,6 @@ my %opt = ( { # load model my $model = Slic3r::Model->read_from_file($ARGV[0]); - $model->add_default_instances; $model->center_instances_around_point(Slic3r::Pointf->new(100,100)); my $mesh = $model->mesh; $mesh->translate(0, 0, -$mesh->bounding_box->z_min); diff --git a/xs/src/libslic3r/Model.cpp b/xs/src/libslic3r/Model.cpp index 2fe6540e7..7b4e88c52 100644 --- a/xs/src/libslic3r/Model.cpp +++ b/xs/src/libslic3r/Model.cpp @@ -3,28 +3,24 @@ namespace Slic3r { -Model::Model() {} - Model::Model(const Model &other) { // copy materials - for (ModelMaterialMap::const_iterator i = other.materials.begin(); i != other.materials.end(); ++i) - this->add_material(i->first, *i->second); - + for (const auto &m : other.materials) + this->add_material(m.first, *m.second); // copy objects this->objects.reserve(other.objects.size()); - for (ModelObjectPtrs::const_iterator i = other.objects.begin(); i != other.objects.end(); ++i) - this->add_object(**i, true); + for (const ModelObject *o : other.objects) + this->add_object(*o, true); } -Model& Model::operator= (Model other) +Model& Model::operator=(Model other) { this->swap(other); return *this; } -void -Model::swap(Model &other) +void Model::swap(Model &other) { std::swap(this->materials, other.materials); std::swap(this->objects, other.objects); @@ -36,16 +32,13 @@ Model::~Model() this->clear_materials(); } -ModelObject* -Model::add_object() +ModelObject* Model::add_object() { - ModelObject* new_object = new ModelObject(this); - this->objects.push_back(new_object); - return new_object; + this->objects.emplace_back(new ModelObject(this)); + return this->objects.back(); } -ModelObject* -Model::add_object(const char *name, const char *path, const TriangleMesh &mesh) +ModelObject* Model::add_object(const char *name, const char *path, const TriangleMesh &mesh) { ModelObject* new_object = new ModelObject(this); this->objects.push_back(new_object); @@ -57,8 +50,7 @@ Model::add_object(const char *name, const char *path, const TriangleMesh &mesh) return new_object; } -ModelObject* -Model::add_object(const char *name, const char *path, TriangleMesh &&mesh) +ModelObject* Model::add_object(const char *name, const char *path, TriangleMesh &&mesh) { ModelObject* new_object = new ModelObject(this); this->objects.push_back(new_object); @@ -70,32 +62,28 @@ Model::add_object(const char *name, const char *path, TriangleMesh &&mesh) return new_object; } -ModelObject* -Model::add_object(const ModelObject &other, bool copy_volumes) +ModelObject* Model::add_object(const ModelObject &other, bool copy_volumes) { ModelObject* new_object = new ModelObject(this, other, copy_volumes); this->objects.push_back(new_object); return new_object; } -void -Model::delete_object(size_t idx) +void Model::delete_object(size_t idx) { ModelObjectPtrs::iterator i = this->objects.begin() + idx; delete *i; this->objects.erase(i); } -void -Model::clear_objects() +void Model::clear_objects() { - // int instead of size_t because it can be -1 when vector is empty - for (int i = this->objects.size()-1; i >= 0; --i) - this->delete_object(i); + for (ModelObject *o : this->objects) + delete o; + this->objects.clear(); } -void -Model::delete_material(t_model_material_id material_id) +void Model::delete_material(t_model_material_id material_id) { ModelMaterialMap::iterator i = this->materials.find(material_id); if (i != this->materials.end()) { @@ -104,145 +92,79 @@ Model::delete_material(t_model_material_id material_id) } } -void -Model::clear_materials() +void Model::clear_materials() { - while (!this->materials.empty()) - this->delete_material( this->materials.begin()->first ); + for (auto &m : this->materials) + delete m.second; + this->materials.clear(); } -ModelMaterial* -Model::add_material(t_model_material_id material_id) +ModelMaterial* Model::add_material(t_model_material_id material_id) { ModelMaterial* material = this->get_material(material_id); - if (material == NULL) { + if (material == nullptr) material = this->materials[material_id] = new ModelMaterial(this); - } return material; } -ModelMaterial* -Model::add_material(t_model_material_id material_id, const ModelMaterial &other) +ModelMaterial* Model::add_material(t_model_material_id material_id, const ModelMaterial &other) { // delete existing material if any ModelMaterial* material = this->get_material(material_id); - if (material != NULL) { - delete material; - } - + delete material; // set new material material = new ModelMaterial(this, other); this->materials[material_id] = material; return material; } -ModelMaterial* -Model::get_material(t_model_material_id material_id) -{ - ModelMaterialMap::iterator i = this->materials.find(material_id); - if (i == this->materials.end()) { - return NULL; - } else { - return i->second; - } -} - -bool -Model::has_objects_with_no_instances() const -{ - for (ModelObjectPtrs::const_iterator i = this->objects.begin(); - i != this->objects.end(); ++i) - { - if ((*i)->instances.empty()) { - return true; - } - } - - return false; -} - // makes sure all objects have at least one instance -bool -Model::add_default_instances() +bool Model::add_default_instances() { // apply a default position to all objects not having one - for (ModelObjectPtrs::const_iterator o = this->objects.begin(); o != this->objects.end(); ++o) { - if ((*o)->instances.empty()) { - (*o)->add_instance(); - } - } + for (ModelObject *o : this->objects) + if (o->instances.empty()) + o->add_instance(); return true; } // this returns the bounding box of the *transformed* instances -BoundingBoxf3 -Model::bounding_box() const +BoundingBoxf3 Model::bounding_box() { BoundingBoxf3 bb; - for (ModelObjectPtrs::const_iterator o = this->objects.begin(); o != this->objects.end(); ++o) { - bb.merge((*o)->bounding_box()); - } + for (ModelObject *o : this->objects) + bb.merge(o->bounding_box()); return bb; } -void -Model::center_instances_around_point(const Pointf &point) +void Model::center_instances_around_point(const Pointf &point) { - BoundingBoxf3 bb = this->bounding_box(); - +// BoundingBoxf3 bb = this->bounding_box(); + BoundingBoxf3 bb; + for (ModelObject *o : this->objects) + for (size_t i = 0; i < o->instances.size(); ++ i) + bb.merge(o->instance_bounding_box(i, false)); + Sizef3 size = bb.size(); coordf_t shift_x = -bb.min.x + point.x - size.x/2; coordf_t shift_y = -bb.min.y + point.y - size.y/2; - for (ModelObjectPtrs::const_iterator o = this->objects.begin(); o != this->objects.end(); ++o) { - for (ModelInstancePtrs::const_iterator i = (*o)->instances.begin(); i != (*o)->instances.end(); ++i) { - (*i)->offset.translate(shift_x, shift_y); - } - (*o)->invalidate_bounding_box(); - } -} - -void -Model::align_instances_to_origin() -{ - BoundingBoxf3 bb = this->bounding_box(); - - Pointf new_center = (Pointf)bb.size(); - new_center.translate(-new_center.x/2, -new_center.y/2); - this->center_instances_around_point(new_center); -} - -void -Model::translate(coordf_t x, coordf_t y, coordf_t z) -{ - for (ModelObjectPtrs::const_iterator o = this->objects.begin(); o != this->objects.end(); ++o) { - (*o)->translate(x, y, z); + for (ModelObject *o : this->objects) { + for (ModelInstance *i : o->instances) + i->offset.translate(shift_x, shift_y); + o->invalidate_bounding_box(); } } // flattens everything to a single mesh -TriangleMesh -Model::mesh() const +TriangleMesh Model::mesh() const { TriangleMesh mesh; - for (ModelObjectPtrs::const_iterator o = this->objects.begin(); o != this->objects.end(); ++o) { - mesh.merge((*o)->mesh()); - } + for (const ModelObject *o : this->objects) + mesh.merge(o->mesh()); return mesh; } -// flattens everything to a single mesh -TriangleMesh -Model::raw_mesh() const -{ - TriangleMesh mesh; - for (ModelObjectPtrs::const_iterator o = this->objects.begin(); o != this->objects.end(); ++o) { - mesh.merge((*o)->raw_mesh()); - } - return mesh; -} - -bool -Model::_arrange(const Pointfs &sizes, coordf_t dist, const BoundingBoxf* bb, Pointfs &out) const +static bool _arrange(const Pointfs &sizes, coordf_t dist, const BoundingBoxf* bb, Pointfs &out) { // we supply unscaled data to arrange() return Slic3r::Geometry::arrange( @@ -256,75 +178,74 @@ Model::_arrange(const Pointfs &sizes, coordf_t dist, const BoundingBoxf* bb, Poi /* arrange objects preserving their instance count but altering their instance positions */ -bool -Model::arrange_objects(coordf_t dist, const BoundingBoxf* bb) +bool Model::arrange_objects(coordf_t dist, const BoundingBoxf* bb) { // get the (transformed) size of each instance so that we take // into account their different transformations when packing Pointfs instance_sizes; - for (ModelObjectPtrs::const_iterator o = this->objects.begin(); o != this->objects.end(); ++o) { - for (size_t i = 0; i < (*o)->instances.size(); ++i) { - instance_sizes.push_back((*o)->instance_bounding_box(i).size()); + Pointfs instance_centers; + for (const ModelObject *o : this->objects) + for (size_t i = 0; i < o->instances.size(); ++ i) { + // an accurate snug bounding box around the transformed mesh. + BoundingBoxf3 bbox(o->instance_bounding_box(i, true)); + instance_sizes.push_back(bbox.size()); + instance_centers.push_back(bbox.center()); } - } - + Pointfs positions; - if (! this->_arrange(instance_sizes, dist, bb, positions)) + if (! _arrange(instance_sizes, dist, bb, positions)) return false; - for (ModelObjectPtrs::const_iterator o = this->objects.begin(); o != this->objects.end(); ++o) { - for (ModelInstancePtrs::const_iterator i = (*o)->instances.begin(); i != (*o)->instances.end(); ++i) { - (*i)->offset = positions.back(); - positions.pop_back(); + size_t idx = 0; + for (ModelObject *o : this->objects) { + for (ModelInstance *i : o->instances) { + i->offset = positions[idx] - instance_centers[idx]; + ++ idx; } - (*o)->invalidate_bounding_box(); + o->invalidate_bounding_box(); } return true; } -/* duplicate the entire model preserving instance relative positions */ -void -Model::duplicate(size_t copies_num, coordf_t dist, const BoundingBoxf* bb) +// Duplicate the entire model preserving instance relative positions. +void Model::duplicate(size_t copies_num, coordf_t dist, const BoundingBoxf* bb) { Pointfs model_sizes(copies_num-1, this->bounding_box().size()); Pointfs positions; - if (! this->_arrange(model_sizes, dist, bb, positions)) + if (! _arrange(model_sizes, dist, bb, positions)) CONFESS("Cannot duplicate part as the resulting objects would not fit on the print bed.\n"); // note that this will leave the object count unaltered - for (ModelObjectPtrs::const_iterator o = this->objects.begin(); o != this->objects.end(); ++o) { + for (ModelObject *o : this->objects) { // make a copy of the pointers in order to avoid recursion when appending their copies - ModelInstancePtrs instances = (*o)->instances; - for (ModelInstancePtrs::const_iterator i = instances.begin(); i != instances.end(); ++i) { - for (Pointfs::const_iterator pos = positions.begin(); pos != positions.end(); ++pos) { - ModelInstance* instance = (*o)->add_instance(**i); - instance->offset.translate(*pos); + ModelInstancePtrs instances = o->instances; + for (const ModelInstance *i : instances) { + for (const Pointf &pos : positions) { + ModelInstance *instance = o->add_instance(*i); + instance->offset.translate(pos); } } - (*o)->invalidate_bounding_box(); + o->invalidate_bounding_box(); } } /* this will append more instances to each object and then automatically rearrange everything */ -void -Model::duplicate_objects(size_t copies_num, coordf_t dist, const BoundingBoxf* bb) +void Model::duplicate_objects(size_t copies_num, coordf_t dist, const BoundingBoxf* bb) { - for (ModelObjectPtrs::const_iterator o = this->objects.begin(); o != this->objects.end(); ++o) { + for (ModelObject *o : this->objects) { // make a copy of the pointers in order to avoid recursion when appending their copies - ModelInstancePtrs instances = (*o)->instances; - for (ModelInstancePtrs::const_iterator i = instances.begin(); i != instances.end(); ++i) { - for (size_t k = 2; k <= copies_num; ++k) - (*o)->add_instance(**i); - } + ModelInstancePtrs instances = o->instances; + for (const ModelInstance *i : instances) + for (size_t k = 2; k <= copies_num; ++ k) + o->add_instance(*i); } this->arrange_objects(dist, bb); } -void -Model::duplicate_objects_grid(size_t x, size_t y, coordf_t dist) +void Model::duplicate_objects_grid(size_t x, size_t y, coordf_t dist) { if (this->objects.size() > 1) throw "Grid duplication is not supported with multiple objects"; if (this->objects.empty()) throw "No objects!"; @@ -343,26 +264,8 @@ Model::duplicate_objects_grid(size_t x, size_t y, coordf_t dist) } } -ModelMaterial::ModelMaterial(Model *model) : model(model) {} -ModelMaterial::ModelMaterial(Model *model, const ModelMaterial &other) - : attributes(other.attributes), config(other.config), model(model) -{} - -void -ModelMaterial::apply(const t_model_material_attributes &attributes) -{ - this->attributes.insert(attributes.begin(), attributes.end()); -} - - -ModelObject::ModelObject(Model *model) : - model(model), - _bounding_box_valid(false), - layer_height_profile_valid(false) -{} - -ModelObject::ModelObject(Model *model, const ModelObject &other, bool copy_volumes) -: name(other.name), +ModelObject::ModelObject(Model *model, const ModelObject &other, bool copy_volumes) : + name(other.name), input_file(other.input_file), instances(), volumes(), @@ -371,9 +274,9 @@ ModelObject::ModelObject(Model *model, const ModelObject &other, bool copy_volum layer_height_profile(other.layer_height_profile), layer_height_profile_valid(other.layer_height_profile_valid), origin_translation(other.origin_translation), - _bounding_box(other._bounding_box), - _bounding_box_valid(other._bounding_box_valid), - model(model) + m_bounding_box(other.m_bounding_box), + m_bounding_box_valid(other.m_bounding_box_valid), + m_model(model) { if (copy_volumes) { this->volumes.reserve(other.volumes.size()); @@ -392,8 +295,7 @@ ModelObject& ModelObject::operator=(ModelObject other) return *this; } -void -ModelObject::swap(ModelObject &other) +void ModelObject::swap(ModelObject &other) { std::swap(this->input_file, other.input_file); std::swap(this->instances, other.instances); @@ -403,8 +305,8 @@ ModelObject::swap(ModelObject &other) std::swap(this->layer_height_profile, other.layer_height_profile); std::swap(this->layer_height_profile_valid, other.layer_height_profile_valid); std::swap(this->origin_translation, other.origin_translation); - std::swap(this->_bounding_box, other._bounding_box); - std::swap(this->_bounding_box_valid, other._bounding_box_valid); + std::swap(m_bounding_box, other.m_bounding_box); + std::swap(m_bounding_box_valid, other.m_bounding_box_valid); } ModelObject::~ModelObject() @@ -413,8 +315,7 @@ ModelObject::~ModelObject() this->clear_instances(); } -ModelVolume* -ModelObject::add_volume(const TriangleMesh &mesh) +ModelVolume* ModelObject::add_volume(const TriangleMesh &mesh) { ModelVolume* v = new ModelVolume(this, mesh); this->volumes.push_back(v); @@ -422,8 +323,7 @@ ModelObject::add_volume(const TriangleMesh &mesh) return v; } -ModelVolume* -ModelObject::add_volume(TriangleMesh &&mesh) +ModelVolume* ModelObject::add_volume(TriangleMesh &&mesh) { ModelVolume* v = new ModelVolume(this, std::move(mesh)); this->volumes.push_back(v); @@ -431,8 +331,7 @@ ModelObject::add_volume(TriangleMesh &&mesh) return v; } -ModelVolume* -ModelObject::add_volume(const ModelVolume &other) +ModelVolume* ModelObject::add_volume(const ModelVolume &other) { ModelVolume* v = new ModelVolume(this, other); this->volumes.push_back(v); @@ -440,8 +339,7 @@ ModelObject::add_volume(const ModelVolume &other) return v; } -void -ModelObject::delete_volume(size_t idx) +void ModelObject::delete_volume(size_t idx) { ModelVolumePtrs::iterator i = this->volumes.begin() + idx; delete *i; @@ -449,16 +347,15 @@ ModelObject::delete_volume(size_t idx) this->invalidate_bounding_box(); } -void -ModelObject::clear_volumes() +void ModelObject::clear_volumes() { - // int instead of size_t because it can be -1 when vector is empty - for (int i = this->volumes.size()-1; i >= 0; --i) - this->delete_volume(i); + for (ModelVolume *v : this->volumes) + delete v; + this->volumes.clear(); + this->invalidate_bounding_box(); } -ModelInstance* -ModelObject::add_instance() +ModelInstance* ModelObject::add_instance() { ModelInstance* i = new ModelInstance(this); this->instances.push_back(i); @@ -466,8 +363,7 @@ ModelObject::add_instance() return i; } -ModelInstance* -ModelObject::add_instance(const ModelInstance &other) +ModelInstance* ModelObject::add_instance(const ModelInstance &other) { ModelInstance* i = new ModelInstance(this, other); this->instances.push_back(i); @@ -475,8 +371,7 @@ ModelObject::add_instance(const ModelInstance &other) return i; } -void -ModelObject::delete_instance(size_t idx) +void ModelObject::delete_instance(size_t idx) { ModelInstancePtrs::iterator i = this->instances.begin() + idx; delete *i; @@ -484,108 +379,93 @@ ModelObject::delete_instance(size_t idx) this->invalidate_bounding_box(); } -void -ModelObject::delete_last_instance() +void ModelObject::delete_last_instance() { this->delete_instance(this->instances.size() - 1); } -void -ModelObject::clear_instances() +void ModelObject::clear_instances() { - for (size_t i = 0; i < this->instances.size(); ++i) - this->delete_instance(i); + for (ModelInstance *i : this->instances) + delete i; + this->instances.clear(); + this->invalidate_bounding_box(); } -// this returns the bounding box of the *transformed* instances -BoundingBoxf3 -ModelObject::bounding_box() +// Returns the bounding box of the transformed instances. +// This bounding box is approximate and not snug. +BoundingBoxf3 ModelObject::bounding_box() { - if (!this->_bounding_box_valid) this->update_bounding_box(); - return this->_bounding_box; -} - -void -ModelObject::invalidate_bounding_box() -{ - this->_bounding_box_valid = false; -} - -void -ModelObject::update_bounding_box() -{ -// this->_bounding_box = this->mesh().bounding_box(); - BoundingBoxf3 raw_bbox; - for (ModelVolumePtrs::const_iterator v = this->volumes.begin(); v != this->volumes.end(); ++v) { - if ((*v)->modifier) continue; - raw_bbox.merge((*v)->mesh.bounding_box()); + if (! m_bounding_box_valid) { + BoundingBoxf3 raw_bbox; + for (const ModelVolume *v : this->volumes) + if (! v->modifier) + raw_bbox.merge(v->mesh.bounding_box()); + BoundingBoxf3 bb; + for (const ModelInstance *i : this->instances) + bb.merge(i->transform_bounding_box(raw_bbox)); + m_bounding_box = bb; + m_bounding_box_valid = true; } - BoundingBoxf3 bb; - for (ModelInstancePtrs::const_iterator i = this->instances.begin(); i != this->instances.end(); ++i) - bb.merge((*i)->transform_bounding_box(raw_bbox)); - this->_bounding_box = bb; - this->_bounding_box_valid = true; + return m_bounding_box; } -// flattens all volumes and instances into a single mesh -TriangleMesh -ModelObject::mesh() const +// A mesh containing all transformed instances of this object. +TriangleMesh ModelObject::mesh() const { TriangleMesh mesh; TriangleMesh raw_mesh = this->raw_mesh(); - - for (ModelInstancePtrs::const_iterator i = this->instances.begin(); i != this->instances.end(); ++i) { + for (const ModelInstance *i : this->instances) { TriangleMesh m = raw_mesh; - (*i)->transform_mesh(&m); + i->transform_mesh(&m); mesh.merge(m); } return mesh; } -TriangleMesh -ModelObject::raw_mesh() const +// Non-transformed (non-rotated, non-scaled, non-translated) sum of non-modifier object volumes. +// Currently used by ModelObject::mesh(), to calculate the 2D envelope for 2D platter +// and to display the object statistics at ModelObject::print_info(). +TriangleMesh ModelObject::raw_mesh() const { TriangleMesh mesh; - for (ModelVolumePtrs::const_iterator v = this->volumes.begin(); v != this->volumes.end(); ++v) { - if ((*v)->modifier) continue; - mesh.merge((*v)->mesh); - } + for (const ModelVolume *v : this->volumes) + if (! v->modifier) + mesh.merge(v->mesh); return mesh; } -BoundingBoxf3 -ModelObject::raw_bounding_box() const +// A transformed snug bounding box around the non-modifier object volumes, without the translation applied. +// This bounding box is only used for the actual slicing. +BoundingBoxf3 ModelObject::raw_bounding_box() const { BoundingBoxf3 bb; - for (ModelVolumePtrs::const_iterator v = this->volumes.begin(); v != this->volumes.end(); ++v) { - if ((*v)->modifier) continue; - if (this->instances.empty()) CONFESS("Can't call raw_bounding_box() with no instances"); - bb.merge(this->instances.front()->transform_mesh_bounding_box(&(*v)->mesh, true)); - } + for (const ModelVolume *v : this->volumes) + if (! v->modifier) { + if (this->instances.empty()) CONFESS("Can't call raw_bounding_box() with no instances"); + bb.merge(this->instances.front()->transform_mesh_bounding_box(&v->mesh, true)); + } return bb; } -// this returns the bounding box of the *transformed* given instance -BoundingBoxf3 -ModelObject::instance_bounding_box(size_t instance_idx) const +// This returns an accurate snug bounding box of the transformed object instance, without the translation applied. +BoundingBoxf3 ModelObject::instance_bounding_box(size_t instance_idx, bool dont_translate) const { BoundingBoxf3 bb; - for (ModelVolumePtrs::const_iterator v = this->volumes.begin(); v != this->volumes.end(); ++v) { - if ((*v)->modifier) continue; - bb.merge(this->instances[instance_idx]->transform_mesh_bounding_box(&(*v)->mesh, true)); - } + for (ModelVolume *v : this->volumes) + if (! v->modifier) + bb.merge(this->instances[instance_idx]->transform_mesh_bounding_box(&v->mesh, dont_translate)); return bb; } -void -ModelObject::center_around_origin() +void ModelObject::center_around_origin() { // calculate the displacements needed to // center this object around the origin BoundingBoxf3 bb; - for (ModelVolumePtrs::const_iterator v = this->volumes.begin(); v != this->volumes.end(); ++v) - if (! (*v)->modifier) - bb.merge((*v)->mesh.bounding_box()); + for (ModelVolume *v : this->volumes) + if (! v->modifier) + bb.merge(v->mesh.bounding_box()); // first align to origin on XYZ Vectorf3 vector(-bb.min.x, -bb.min.y, -bb.min.z); @@ -599,98 +479,77 @@ ModelObject::center_around_origin() this->origin_translation.translate(vector); if (!this->instances.empty()) { - for (ModelInstancePtrs::const_iterator i = this->instances.begin(); i != this->instances.end(); ++i) { + for (ModelInstance *i : this->instances) { // apply rotation and scaling to vector as well before translating instance, // in order to leave final position unaltered Vectorf3 v = vector.negative(); - v.rotate((*i)->rotation, (*i)->offset); - v.scale((*i)->scaling_factor); - (*i)->offset.translate(v.x, v.y); + v.rotate(i->rotation, i->offset); + v.scale(i->scaling_factor); + i->offset.translate(v.x, v.y); } this->invalidate_bounding_box(); } } -void -ModelObject::translate(const Vectorf3 &vector) +void ModelObject::translate(coordf_t x, coordf_t y, coordf_t z) { - this->translate(vector.x, vector.y, vector.z); + for (ModelVolume *v : this->volumes) + v->mesh.translate(float(x), float(y), float(z)); + if (m_bounding_box_valid) + m_bounding_box.translate(x, y, z); } -void -ModelObject::translate(coordf_t x, coordf_t y, coordf_t z) +void ModelObject::scale(const Pointf3 &versor) { - for (ModelVolumePtrs::const_iterator v = this->volumes.begin(); v != this->volumes.end(); ++v) { - (*v)->mesh.translate(x, y, z); - } - if (this->_bounding_box_valid) this->_bounding_box.translate(x, y, z); -} - -void -ModelObject::scale(const Pointf3 &versor) -{ - for (ModelVolumePtrs::const_iterator v = this->volumes.begin(); v != this->volumes.end(); ++v) { - (*v)->mesh.scale(versor); - } - + for (ModelVolume *v : this->volumes) + v->mesh.scale(versor); // reset origin translation since it doesn't make sense anymore this->origin_translation = Pointf3(0,0,0); this->invalidate_bounding_box(); } -void -ModelObject::rotate(float angle, const Axis &axis) +void ModelObject::rotate(float angle, const Axis &axis) { - for (ModelVolumePtrs::const_iterator v = this->volumes.begin(); v != this->volumes.end(); ++v) { - (*v)->mesh.rotate(angle, axis); - } + for (ModelVolume *v : this->volumes) + v->mesh.rotate(angle, axis); this->origin_translation = Pointf3(0,0,0); this->invalidate_bounding_box(); } -void -ModelObject::mirror(const Axis &axis) +void ModelObject::mirror(const Axis &axis) { - for (ModelVolumePtrs::const_iterator v = this->volumes.begin(); v != this->volumes.end(); ++v) { - (*v)->mesh.mirror(axis); - } + for (ModelVolume *v : this->volumes) + v->mesh.mirror(axis); this->origin_translation = Pointf3(0,0,0); this->invalidate_bounding_box(); } -size_t -ModelObject::materials_count() const +size_t ModelObject::materials_count() const { std::set material_ids; - for (ModelVolumePtrs::const_iterator v = this->volumes.begin(); v != this->volumes.end(); ++v) { - material_ids.insert((*v)->material_id()); - } + for (const ModelVolume *v : this->volumes) + material_ids.insert(v->material_id()); return material_ids.size(); } -size_t -ModelObject::facets_count() const +size_t ModelObject::facets_count() const { size_t num = 0; - for (ModelVolumePtrs::const_iterator v = this->volumes.begin(); v != this->volumes.end(); ++v) { - if ((*v)->modifier) continue; - num += (*v)->mesh.stl.stats.number_of_facets; - } + for (const ModelVolume *v : this->volumes) + if (! v->modifier) + num += v->mesh.stl.stats.number_of_facets; return num; } -bool -ModelObject::needed_repair() const +bool ModelObject::needed_repair() const { - for (ModelVolumePtrs::const_iterator v = this->volumes.begin(); v != this->volumes.end(); ++v) { - if ((*v)->modifier) continue; - if ((*v)->mesh.needed_repair()) return true; - } + for (const ModelVolume *v : this->volumes) + if (! v->modifier && v->mesh.needed_repair()) + return true; return false; } -void -ModelObject::cut(coordf_t z, Model* model) const +void ModelObject::cut(coordf_t z, Model* model) const { // clone this one to duplicate instances, materials etc. ModelObject* upper = model->add_object(*this); @@ -700,8 +559,7 @@ ModelObject::cut(coordf_t z, Model* model) const upper->input_file = ""; lower->input_file = ""; - for (ModelVolumePtrs::const_iterator v = this->volumes.begin(); v != this->volumes.end(); ++v) { - ModelVolume* volume = *v; + for (ModelVolume *volume : this->volumes) { if (volume->modifier) { // don't cut modifiers upper->add_volume(*volume); @@ -757,8 +615,7 @@ ModelObject::cut(coordf_t z, Model* model) const } } -void -ModelObject::split(ModelObjectPtrs* new_objects) +void ModelObject::split(ModelObjectPtrs* new_objects) { if (this->volumes.size() > 1) { // We can't split meshes if there's more than one volume, because @@ -772,7 +629,7 @@ ModelObject::split(ModelObjectPtrs* new_objects) for (TriangleMeshPtrs::iterator mesh = meshptrs.begin(); mesh != meshptrs.end(); ++mesh) { (*mesh)->repair(); - ModelObject* new_object = this->model->add_object(*this, false); + ModelObject* new_object = m_model->add_object(*this, false); new_object->input_file = ""; ModelVolume* new_volume = new_object->add_volume(**mesh); new_volume->name = volume->name; @@ -787,30 +644,7 @@ ModelObject::split(ModelObjectPtrs* new_objects) return; } - -ModelVolume::ModelVolume(ModelObject* object, const TriangleMesh &mesh) -: mesh(mesh), modifier(false), object(object) -{} - -ModelVolume::ModelVolume(ModelObject* object, TriangleMesh &&mesh) -: mesh(std::move(mesh)), modifier(false), object(object) -{} - -ModelVolume::ModelVolume(ModelObject* object, const ModelVolume &other) -: name(other.name), mesh(other.mesh), config(other.config), - modifier(other.modifier), object(object) -{ - this->material_id(other.material_id()); -} - -t_model_material_id -ModelVolume::material_id() const -{ - return this->_material_id; -} - -void -ModelVolume::material_id(t_model_material_id material_id) +void ModelVolume::material_id(t_model_material_id material_id) { this->_material_id = material_id; @@ -818,21 +652,18 @@ ModelVolume::material_id(t_model_material_id material_id) (void)this->object->get_model()->add_material(material_id); } -ModelMaterial* -ModelVolume::material() const -{ +ModelMaterial* ModelVolume::material() const +{ return this->object->get_model()->get_material(this->_material_id); } -void -ModelVolume::set_material(t_model_material_id material_id, const ModelMaterial &material) +void ModelVolume::set_material(t_model_material_id material_id, const ModelMaterial &material) { this->_material_id = material_id; (void)this->object->get_model()->add_material(material_id, material); } -ModelMaterial* -ModelVolume::assign_unique_material() +ModelMaterial* ModelVolume::assign_unique_material() { Model* model = this->get_object()->get_model(); @@ -841,17 +672,7 @@ ModelVolume::assign_unique_material() return model->add_material(this->_material_id); } - -ModelInstance::ModelInstance(ModelObject *object) -: rotation(0), scaling_factor(1), object(object) -{} - -ModelInstance::ModelInstance(ModelObject *object, const ModelInstance &other) -: rotation(other.rotation), scaling_factor(other.scaling_factor), offset(other.offset), object(object) -{} - -void -ModelInstance::transform_mesh(TriangleMesh* mesh, bool dont_translate) const +void ModelInstance::transform_mesh(TriangleMesh* mesh, bool dont_translate) const { mesh->rotate_z(this->rotation); // rotate around mesh origin mesh->scale(this->scaling_factor); // scale around mesh origin @@ -861,7 +682,7 @@ ModelInstance::transform_mesh(TriangleMesh* mesh, bool dont_translate) const BoundingBoxf3 ModelInstance::transform_mesh_bounding_box(const TriangleMesh* mesh, bool dont_translate) const { - // rotate around mesh origin + // Rotate around mesh origin. double c = cos(this->rotation); double s = sin(this->rotation); BoundingBoxf3 bbox; @@ -873,16 +694,27 @@ BoundingBoxf3 ModelInstance::transform_mesh_bounding_box(const TriangleMesh* mes double yold = v.y; v.x = float(c * xold - s * yold); v.y = float(s * xold + c * yold); - v.x *= float(this->scaling_factor); - v.y *= float(this->scaling_factor); - v.z *= float(this->scaling_factor); - if (!dont_translate) { - v.x += this->offset.x; - v.y += this->offset.y; - } bbox.merge(Pointf3(v.x, v.y, v.z)); } } + if (! empty(bbox)) { + // Scale the bounding box uniformly. + if (std::abs(this->scaling_factor - 1.) > EPSILON) { + bbox.min.x *= float(this->scaling_factor); + bbox.min.y *= float(this->scaling_factor); + bbox.min.z *= float(this->scaling_factor); + bbox.max.x *= float(this->scaling_factor); + bbox.max.y *= float(this->scaling_factor); + bbox.max.z *= float(this->scaling_factor); + } + // Translate the bounding box. + if (! dont_translate) { + bbox.min.x += float(this->offset.x); + bbox.min.y += float(this->offset.y); + bbox.max.x += float(this->offset.x); + bbox.max.y += float(this->offset.y); + } + } return bbox; } @@ -907,7 +739,7 @@ BoundingBoxf3 ModelInstance::transform_bounding_box(const BoundingBoxf3 &bbox, b v.x *= this->scaling_factor; v.y *= this->scaling_factor; v.z *= this->scaling_factor; - if (!dont_translate) { + if (! dont_translate) { v.x += this->offset.x; v.y += this->offset.y; } @@ -916,8 +748,7 @@ BoundingBoxf3 ModelInstance::transform_bounding_box(const BoundingBoxf3 &bbox, b return out; } -void -ModelInstance::transform_polygon(Polygon* polygon) const +void ModelInstance::transform_polygon(Polygon* polygon) const { polygon->rotate(this->rotation); // rotate around polygon origin polygon->scale(this->scaling_factor); // scale around polygon origin diff --git a/xs/src/libslic3r/Model.hpp b/xs/src/libslic3r/Model.hpp index 9334fc8f2..047f23017 100644 --- a/xs/src/libslic3r/Model.hpp +++ b/xs/src/libslic3r/Model.hpp @@ -28,53 +28,6 @@ typedef std::vector ModelObjectPtrs; typedef std::vector ModelVolumePtrs; typedef std::vector ModelInstancePtrs; -// The print bed content. -// Description of a triangular model with multiple materials, multiple instances with various affine transformations -// and with multiple modifier meshes. -// A model groups multiple objects, each object having possibly multiple instances, -// all objects may share mutliple materials. -class Model -{ -public: - // Materials are owned by a model and referenced by objects through t_model_material_id. - // Single material may be shared by multiple models. - ModelMaterialMap materials; - // Objects are owned by a model. Each model may have multiple instances, each instance having its own transformation (shift, scale, rotation). - ModelObjectPtrs objects; - - Model(); - Model(const Model &other); - Model& operator= (Model other); - void swap(Model &other); - ~Model(); - ModelObject* add_object(); - ModelObject* add_object(const char *name, const char *path, const TriangleMesh &mesh); - ModelObject* add_object(const char *name, const char *path, TriangleMesh &&mesh); - ModelObject* add_object(const ModelObject &other, bool copy_volumes = true); - void delete_object(size_t idx); - void clear_objects(); - - ModelMaterial* add_material(t_model_material_id material_id); - ModelMaterial* add_material(t_model_material_id material_id, const ModelMaterial &other); - ModelMaterial* get_material(t_model_material_id material_id); - void delete_material(t_model_material_id material_id); - void clear_materials(); - bool has_objects_with_no_instances() const; - bool add_default_instances(); - BoundingBoxf3 bounding_box() const; - void center_instances_around_point(const Pointf &point); - void align_instances_to_origin(); - void translate(coordf_t x, coordf_t y, coordf_t z); - TriangleMesh mesh() const; - TriangleMesh raw_mesh() const; - bool _arrange(const Pointfs &sizes, coordf_t dist, const BoundingBoxf* bb, Pointfs &out) const; - bool arrange_objects(coordf_t dist, const BoundingBoxf* bb = NULL); - // Croaks if the duplicated objects do not fit the print bed. - void duplicate(size_t copies_num, coordf_t dist, const BoundingBoxf* bb = NULL); - void duplicate_objects(size_t copies_num, coordf_t dist, const BoundingBoxf* bb = NULL); - void duplicate_objects_grid(size_t x, size_t y, coordf_t dist); -}; - // Material, which may be shared across multiple ModelObjects of a single Model. class ModelMaterial { @@ -85,15 +38,16 @@ public: // Dynamic configuration storage for the object specific configuration values, overriding the global configuration. DynamicPrintConfig config; - Model* get_model() const { return this->model; }; - void apply(const t_model_material_attributes &attributes); - + Model* get_model() const { return m_model; }; + void apply(const t_model_material_attributes &attributes) + { this->attributes.insert(attributes.begin(), attributes.end()); } + private: // Parent, owning this material. - Model* model; + Model *m_model; - ModelMaterial(Model *model); - ModelMaterial(Model *model, const ModelMaterial &other); + ModelMaterial(Model *model) : m_model(model) {} + ModelMaterial(Model *model, const ModelMaterial &other) : attributes(other.attributes), config(other.config), m_model(model) {} }; // A printable object, possibly having multiple print volumes (each with its own set of parameters and materials), @@ -104,37 +58,33 @@ class ModelObject { friend class Model; public: - std::string name; - std::string input_file; + std::string name; + std::string input_file; // Instances of this ModelObject. Each instance defines a shift on the print bed, rotation around the Z axis and a uniform scaling. // Instances are owned by this ModelObject. - ModelInstancePtrs instances; + ModelInstancePtrs instances; // Printable and modifier volumes, each with its material ID and a set of override parameters. // ModelVolumes are owned by this ModelObject. - ModelVolumePtrs volumes; + ModelVolumePtrs volumes; // Configuration parameters specific to a single ModelObject, overriding the global Slic3r settings. - DynamicPrintConfig config; + DynamicPrintConfig config; // Variation of a layer thickness for spans of Z coordinates. - t_layer_height_ranges layer_height_ranges; + t_layer_height_ranges layer_height_ranges; // Profile of increasing z to a layer height, to be linearly interpolated when calculating the layers. // The pairs of are packed into a 1D array to simplify handling by the Perl XS. - std::vector layer_height_profile; + std::vector layer_height_profile; // layer_height_profile is initialized when the layer editing mode is entered. // Only if the user really modified the layer height, layer_height_profile_valid is set // and used subsequently by the PrintObject. - bool layer_height_profile_valid; + bool layer_height_profile_valid; /* This vector accumulates the total translation applied to the object by the center_around_origin() method. Callers might want to apply the same translation to new volumes before adding them to this object in order to preserve alignment when user expects that. */ - Pointf3 origin_translation; + Pointf3 origin_translation; - // these should be private but we need to expose them via XS until all methods are ported - BoundingBoxf3 _bounding_box; - bool _bounding_box_valid; - - Model* get_model() const { return this->model; }; + Model* get_model() const { return m_model; }; ModelVolume* add_volume(const TriangleMesh &mesh); ModelVolume* add_volume(TriangleMesh &&mesh); @@ -148,15 +98,23 @@ public: void delete_last_instance(); void clear_instances(); + // Returns the bounding box of the transformed instances. + // This bounding box is approximate and not snug. BoundingBoxf3 bounding_box(); - void invalidate_bounding_box(); + void invalidate_bounding_box() { m_bounding_box_valid = false; } + // A mesh containing all transformed instances of this object. TriangleMesh mesh() const; + // Non-transformed (non-rotated, non-scaled, non-translated) sum of non-modifier object volumes. + // Currently used by ModelObject::mesh() and to calculate the 2D envelope for 2D platter. TriangleMesh raw_mesh() const; + // A transformed snug bounding box around the non-modifier object volumes, without the translation applied. + // This bounding box is only used for the actual slicing. BoundingBoxf3 raw_bounding_box() const; - BoundingBoxf3 instance_bounding_box(size_t instance_idx) const; + // A snug bounding box around the transformed non-modifier object volumes. + BoundingBoxf3 instance_bounding_box(size_t instance_idx, bool dont_translate = false) const; void center_around_origin(); - void translate(const Vectorf3 &vector); + void translate(const Vectorf3 &vector) { this->translate(vector.x, vector.y, vector.z); } void translate(coordf_t x, coordf_t y, coordf_t z); void scale(const Pointf3 &versor); void rotate(float angle, const Axis &axis); @@ -166,17 +124,19 @@ public: bool needed_repair() const; void cut(coordf_t z, Model* model) const; void split(ModelObjectPtrs* new_objects); - void update_bounding_box(); // this is a private method but we expose it until we need to expose it via XS -private: - // Parent object, owning this ModelObject. - Model* model; - - ModelObject(Model *model); +private: + ModelObject(Model *model) : m_model(model), m_bounding_box_valid(false), layer_height_profile_valid(false) {} ModelObject(Model *model, const ModelObject &other, bool copy_volumes = true); ModelObject& operator= (ModelObject other); void swap(ModelObject &other); ~ModelObject(); + + // Parent object, owning this ModelObject. + Model *m_model; + // Bounding box, cached. + BoundingBoxf3 m_bounding_box; + bool m_bounding_box_valid; }; // An object STL, or a modifier volume, over which a different set of parameters shall be applied. @@ -196,7 +156,7 @@ public: // A parent object owning this modifier volume. ModelObject* get_object() const { return this->object; }; - t_model_material_id material_id() const; + t_model_material_id material_id() const { return this->_material_id; } void material_id(t_model_material_id material_id); ModelMaterial* material() const; void set_material(t_model_material_id material_id, const ModelMaterial &material); @@ -208,9 +168,11 @@ private: ModelObject* object; t_model_material_id _material_id; - ModelVolume(ModelObject *object, const TriangleMesh &mesh); - ModelVolume(ModelObject *object, TriangleMesh &&mesh); - ModelVolume(ModelObject *object, const ModelVolume &other); + ModelVolume(ModelObject *object, const TriangleMesh &mesh) : mesh(mesh), modifier(false), object(object) {} + ModelVolume(ModelObject *object, TriangleMesh &&mesh) : mesh(std::move(mesh)), modifier(false), object(object) {} + ModelVolume(ModelObject *object, const ModelVolume &other) : + name(other.name), mesh(other.mesh), config(other.config), modifier(other.modifier), object(object) + { this->material_id(other.material_id()); } }; // A single instance of a ModelObject. @@ -237,9 +199,58 @@ public: private: // Parent object, owning this instance. ModelObject* object; + + ModelInstance(ModelObject *object) : rotation(0), scaling_factor(1), object(object) {} + ModelInstance(ModelObject *object, const ModelInstance &other) : + rotation(other.rotation), scaling_factor(other.scaling_factor), offset(other.offset), object(object) {} +}; + + +// The print bed content. +// Description of a triangular model with multiple materials, multiple instances with various affine transformations +// and with multiple modifier meshes. +// A model groups multiple objects, each object having possibly multiple instances, +// all objects may share mutliple materials. +class Model +{ +public: + // Materials are owned by a model and referenced by objects through t_model_material_id. + // Single material may be shared by multiple models. + ModelMaterialMap materials; + // Objects are owned by a model. Each model may have multiple instances, each instance having its own transformation (shift, scale, rotation). + ModelObjectPtrs objects; - ModelInstance(ModelObject *object); - ModelInstance(ModelObject *object, const ModelInstance &other); + Model() {} + Model(const Model &other); + Model& operator= (Model other); + void swap(Model &other); + ~Model(); + ModelObject* add_object(); + ModelObject* add_object(const char *name, const char *path, const TriangleMesh &mesh); + ModelObject* add_object(const char *name, const char *path, TriangleMesh &&mesh); + ModelObject* add_object(const ModelObject &other, bool copy_volumes = true); + void delete_object(size_t idx); + void clear_objects(); + + ModelMaterial* add_material(t_model_material_id material_id); + ModelMaterial* add_material(t_model_material_id material_id, const ModelMaterial &other); + ModelMaterial* get_material(t_model_material_id material_id) { + ModelMaterialMap::iterator i = this->materials.find(material_id); + return (i == this->materials.end()) ? nullptr : i->second; + } + + void delete_material(t_model_material_id material_id); + void clear_materials(); + bool add_default_instances(); + BoundingBoxf3 bounding_box(); + void center_instances_around_point(const Pointf &point); + void translate(coordf_t x, coordf_t y, coordf_t z) { for (ModelObject *o : this->objects) o->translate(x, y, z); } + TriangleMesh mesh() const; + bool arrange_objects(coordf_t dist, const BoundingBoxf* bb = NULL); + // Croaks if the duplicated objects do not fit the print bed. + void duplicate(size_t copies_num, coordf_t dist, const BoundingBoxf* bb = NULL); + void duplicate_objects(size_t copies_num, coordf_t dist, const BoundingBoxf* bb = NULL); + void duplicate_objects_grid(size_t x, size_t y, coordf_t dist); }; } diff --git a/xs/src/libslic3r/Print.cpp b/xs/src/libslic3r/Print.cpp index 14c876809..b08e62066 100644 --- a/xs/src/libslic3r/Print.cpp +++ b/xs/src/libslic3r/Print.cpp @@ -509,9 +509,7 @@ std::string Print::validate() const { Polygons convex_hulls_other; for (PrintObject *object : this->objects) { - // Get convex hull of all meshes assigned to this print object - // (this is the same as model_object()->raw_mesh.convex_hull() - // but probably more efficient. + // Get convex hull of all meshes assigned to this print object. Polygon convex_hull; { Polygons mesh_convex_hulls; diff --git a/xs/xsp/Model.xsp b/xs/xsp/Model.xsp index e8585a3da..c38b45ed8 100644 --- a/xs/xsp/Model.xsp +++ b/xs/xsp/Model.xsp @@ -58,15 +58,12 @@ size_t material_count() const %code%{ RETVAL = THIS->materials.size(); %}; - bool has_objects_with_no_instances(); bool add_default_instances(); Clone bounding_box(); void center_instances_around_point(Pointf* point) %code%{ THIS->center_instances_around_point(*point); %}; - void align_instances_to_origin(); void translate(double x, double y, double z); Clone mesh(); - Clone raw_mesh(); ModelObjectPtrs* objects() %code%{ RETVAL = &THIS->objects; %}; @@ -183,25 +180,10 @@ ModelMaterial::attributes() %code%{ RETVAL = &THIS->instances; %}; void invalidate_bounding_box(); - void update_bounding_box(); Clone mesh(); Clone raw_mesh(); - Clone raw_bounding_box(); - Clone instance_bounding_box(int idx); - - Ref _bounding_box(BoundingBoxf3* new_bbox = NULL) - %code{% - if (NULL != new_bbox) { - THIS->_bounding_box = *new_bbox; - THIS->_bounding_box_valid = true; - } - - if (!THIS->_bounding_box_valid) { - XSRETURN_UNDEF; - } - - RETVAL = &THIS->_bounding_box; - %}; + Clone instance_bounding_box(int idx) + %code%{ RETVAL = THIS->instance_bounding_box(idx, true); %}; Clone bounding_box(); %name{_add_volume} Ref add_volume(TriangleMesh* mesh) diff --git a/xs/xsp/Print.xsp b/xs/xsp/Print.xsp index 00877730a..b29b82ba4 100644 --- a/xs/xsp/Print.xsp +++ b/xs/xsp/Print.xsp @@ -64,8 +64,6 @@ _constant() Ref size() %code%{ RETVAL = &THIS->size; %}; Clone bounding_box(); - Ref _copies_shift() - %code%{ RETVAL = &THIS->_copies_shift; %}; bool typed_slices() %code%{ RETVAL = THIS->typed_slices; %};