2014-01-06 18:29:10 +01:00
#ifndef slic3r_Model_hpp_
#define slic3r_Model_hpp_
2015-12-08 00:39:54 +01:00
#include "libslic3r.h"
2021-06-27 17:36:25 +02:00
#include "enum_bitmask.hpp"
2019-06-27 11:02:45 +02:00
#include "Geometry.hpp"
#include "ObjectID.hpp"
2014-01-06 18:29:10 +01:00
#include "Point.hpp"
2019-06-27 11:02:45 +02:00
#include "PrintConfig.hpp"
2016-12-08 19:02:16 +01:00
#include "Slicing.hpp"
2019-11-11 11:41:14 +01:00
#include "SLA/SupportPoint.hpp"
#include "SLA/Hollowing.hpp"
2019-06-27 11:02:45 +02:00
#include "TriangleMesh.hpp"
2019-07-01 18:22:07 +02:00
#include "Arrange.hpp"
2020-01-23 12:49:39 +01:00
#include "CustomGCode.hpp"
2021-06-27 16:04:23 +02:00
#include "enum_bitmask.hpp"
2019-06-11 17:08:47 +02:00
2014-01-06 18:29:10 +01:00
#include <map>
2019-06-11 17:08:47 +02:00
#include <memory>
2014-01-06 18:29:10 +01:00
#include <string>
#include <utility>
#include <vector>
2019-07-18 12:07:50 +02:00
namespace cereal {
class BinaryInputArchive ;
class BinaryOutputArchive ;
template < class T > void load_optional ( BinaryInputArchive & ar , std :: shared_ptr < const T > & ptr );
template < class T > void save_optional ( BinaryOutputArchive & ar , const std :: shared_ptr < const T > & ptr );
2019-07-19 15:29:04 +02:00
template < class T > void load_by_value ( BinaryInputArchive & ar , T & obj );
template < class T > void save_by_value ( BinaryOutputArchive & ar , const T & obj );
2019-07-18 12:07:50 +02:00
}
2014-01-06 18:29:10 +01:00
namespace Slic3r {
2021-02-10 20:31:17 +01:00
enum class ConversionType ;
2014-01-06 18:29:10 +01:00
2017-06-13 12:09:49 +02:00
class Model ;
2014-01-06 18:29:10 +01:00
class ModelInstance ;
class ModelMaterial ;
class ModelObject ;
class ModelVolume ;
2019-07-19 15:29:04 +02:00
class ModelWipeTower ;
2018-10-17 11:12:38 +02:00
class Print ;
2018-11-21 17:35:35 +01:00
class SLAPrint ;
2020-07-09 16:25:34 +02:00
class TriangleSelector ;
2014-01-06 18:29:10 +01:00
2019-07-02 16:42:23 +02:00
namespace UndoRedo {
class StackImpl ;
}
2020-09-24 15:34:13 +02:00
class ModelConfigObject : public ObjectBase , public ModelConfig
2019-07-03 13:43:54 +02:00
{
private :
friend class cereal :: access ;
friend class UndoRedo :: StackImpl ;
friend class ModelObject ;
friend class ModelVolume ;
friend class ModelMaterial ;
// Constructors to be only called by derived classes.
// Default constructor to assign a unique ID.
2020-10-15 17:29:42 +02:00
explicit ModelConfigObject () = default ;
2019-07-03 13:43:54 +02:00
// Constructor with ignored int parameter to assign an invalid ID, to be replaced
// by an existing ID copied from elsewhere.
2020-09-24 15:34:13 +02:00
explicit ModelConfigObject ( int ) : ObjectBase ( - 1 ) {}
2019-07-03 13:43:54 +02:00
// Copy constructor copies the ID.
2020-10-15 17:29:42 +02:00
explicit ModelConfigObject ( const ModelConfigObject & cfg ) = default ;
2019-07-03 13:43:54 +02:00
// Move constructor copies the ID.
2020-10-15 17:29:42 +02:00
explicit ModelConfigObject ( ModelConfigObject && cfg ) = default ;
2019-07-03 13:43:54 +02:00
2020-09-24 15:34:13 +02:00
Timestamp timestamp () const throw () override { return this -> ModelConfig :: timestamp (); }
bool object_id_and_timestamp_match ( const ModelConfigObject & rhs ) const throw () { return this -> id () == rhs . id () && this -> timestamp () == rhs . timestamp (); }
2019-07-03 13:43:54 +02:00
2020-09-24 15:34:13 +02:00
// called by ModelObject::assign_copy()
ModelConfigObject & operator = ( const ModelConfigObject & rhs ) = default ;
ModelConfigObject & operator = ( ModelConfigObject && rhs ) = default ;
template < class Archive > void serialize ( Archive & ar ) {
ar ( cereal :: base_class < ModelConfig > ( this ));
}
2019-07-03 13:43:54 +02:00
};
2019-07-19 15:29:04 +02:00
namespace Internal {
template < typename T >
class StaticSerializationWrapper
{
public :
StaticSerializationWrapper ( T & wrap ) : wrapped ( wrap ) {}
private :
friend class cereal :: access ;
friend class UndoRedo :: StackImpl ;
template < class Archive > void load ( Archive & ar ) { cereal :: load_by_value ( ar , wrapped ); }
template < class Archive > void save ( Archive & ar ) const { cereal :: save_by_value ( ar , wrapped ); }
T & wrapped ;
};
}
2014-01-06 18:29:10 +01:00
typedef std :: string t_model_material_id ;
typedef std :: string t_model_material_attribute ;
2018-11-02 14:47:13 +01:00
typedef std :: map < t_model_material_attribute , std :: string > t_model_material_attributes ;
2014-01-06 18:29:10 +01:00
2018-11-02 14:47:13 +01:00
typedef std :: map < t_model_material_id , ModelMaterial *> ModelMaterialMap ;
2014-04-30 02:04:49 +03:00
typedef std :: vector < ModelObject *> ModelObjectPtrs ;
typedef std :: vector < ModelVolume *> ModelVolumePtrs ;
typedef std :: vector < ModelInstance *> ModelInstancePtrs ;
2019-06-27 11:02:45 +02:00
#define OBJECTBASE_DERIVED_COPY_MOVE_CLONE(TYPE) \
2018-11-02 14:47:13 +01:00
/* Copy a model, copy the IDs. The Print::apply() will call the TYPE::copy() method */ \
/* to make a private copy for background processing. */ \
2019-07-03 13:43:54 +02:00
static TYPE* new_copy(const TYPE &rhs) { auto *ret = new TYPE(rhs); assert(ret->id() == rhs.id()); return ret; } \
static TYPE* new_copy(TYPE &&rhs) { auto *ret = new TYPE(std::move(rhs)); assert(ret->id() == rhs.id()); return ret; } \
static TYPE make_copy(const TYPE &rhs) { TYPE ret(rhs); assert(ret.id() == rhs.id()); return ret; } \
static TYPE make_copy(TYPE &&rhs) { TYPE ret(std::move(rhs)); assert(ret.id() == rhs.id()); return ret; } \
2018-11-02 14:47:13 +01:00
TYPE& assign_copy(const TYPE &rhs); \
TYPE& assign_copy(TYPE &&rhs); \
/* Copy a TYPE, generate new IDs. The front end will use this call. */ \
2018-11-02 19:49:40 +01:00
static TYPE* new_clone(const TYPE &rhs) { \
2018-11-02 14:47:13 +01:00
/* Default constructor assigning an invalid ID. */ \
auto obj = new TYPE(-1); \
obj->assign_clone(rhs); \
2019-07-03 13:43:54 +02:00
assert(obj->id().valid() && obj->id() != rhs.id()); \
2018-11-02 14:47:13 +01:00
return obj; \
} \
TYPE make_clone(const TYPE &rhs) { \
/* Default constructor assigning an invalid ID. */ \
TYPE obj(-1); \
obj.assign_clone(rhs); \
2019-07-03 13:43:54 +02:00
assert(obj.id().valid() && obj.id() != rhs.id()); \
2018-11-02 14:47:13 +01:00
return obj; \
} \
TYPE& assign_clone(const TYPE &rhs) { \
this->assign_copy(rhs); \
2019-07-03 13:43:54 +02:00
assert(this->id().valid() && this->id() == rhs.id()); \
2018-11-02 14:47:13 +01:00
this->assign_new_unique_ids_recursive(); \
2019-07-03 13:43:54 +02:00
assert(this->id().valid() && this->id() != rhs.id()); \
2018-11-02 14:47:13 +01:00
return *this; \
}
2016-09-13 13:30:00 +02:00
// Material, which may be shared across multiple ModelObjects of a single Model.
2019-07-02 16:42:23 +02:00
class ModelMaterial final : public ObjectBase
2014-01-06 18:29:10 +01:00
{
2016-09-13 13:30:00 +02:00
public :
// Attributes are defined by the AMF file format, but they don't seem to be used by Slic3r for any purpose.
2014-01-06 18:29:10 +01:00
t_model_material_attributes attributes ;
2016-09-13 13:30:00 +02:00
// Dynamic configuration storage for the object specific configuration values, overriding the global configuration.
2020-09-24 15:34:13 +02:00
ModelConfigObject config ;
2014-04-30 02:04:49 +03:00
2017-06-13 12:09:49 +02:00
Model * get_model () const { return m_model ; }
2017-06-13 11:35:24 +02:00
void apply ( const t_model_material_attributes & attributes )
{ this -> attributes . insert ( attributes . begin (), attributes . end ()); }
2016-09-13 13:30:00 +02:00
private :
// Parent, owning this material.
2017-06-13 11:35:24 +02:00
Model * m_model ;
2019-07-03 13:43:54 +02:00
// To be accessed by the Model.
friend class Model ;
// Constructor, which assigns a new unique ID to the material and to its config.
ModelMaterial ( Model * model ) : m_model ( model ) { assert ( this -> id (). valid ()); }
// Copy constructor copies the IDs of the ModelMaterial and its config, and m_model!
ModelMaterial ( const ModelMaterial & rhs ) = default ;
void set_model ( Model * model ) { m_model = model ; }
void set_new_unique_id () { ObjectBase :: set_new_unique_id (); this -> config . set_new_unique_id (); }
// To be accessed by the serialization and Undo/Redo code.
friend class cereal :: access ;
friend class UndoRedo :: StackImpl ;
// Create an object for deserialization, don't allocate IDs for ModelMaterial and its config.
ModelMaterial () : ObjectBase ( - 1 ), config ( - 1 ), m_model ( nullptr ) { assert ( this -> id (). invalid ()); assert ( this -> config . id (). invalid ()); }
template < class Archive > void serialize ( Archive & ar ) {
assert ( this -> id (). invalid ()); assert ( this -> config . id (). invalid ());
2020-09-24 15:34:13 +02:00
Internal :: StaticSerializationWrapper < ModelConfigObject > config_wrapper ( config );
2019-07-19 15:29:04 +02:00
ar ( attributes , config_wrapper );
2019-07-03 13:43:54 +02:00
// assert(this->id().valid()); assert(this->config.id().valid());
}
// Disabled methods.
2018-11-02 19:49:40 +01:00
ModelMaterial ( ModelMaterial && rhs ) = delete ;
ModelMaterial & operator = ( const ModelMaterial & rhs ) = delete ;
ModelMaterial & operator = ( ModelMaterial && rhs ) = delete ;
2014-01-06 18:29:10 +01:00
};
2020-09-24 15:34:13 +02:00
class LayerHeightProfile final : public ObjectWithTimestamp {
public :
2020-10-15 17:29:42 +02:00
// Assign the content if the timestamp differs, don't assign an ObjectID.
2021-05-06 14:43:36 +02:00
void assign ( const LayerHeightProfile & rhs ) { if ( ! this -> timestamp_matches ( rhs )) { m_data = rhs . m_data ; this -> copy_timestamp ( rhs ); } }
void assign ( LayerHeightProfile && rhs ) { if ( ! this -> timestamp_matches ( rhs )) { m_data = std :: move ( rhs . m_data ); this -> copy_timestamp ( rhs ); } }
2020-10-15 17:29:42 +02:00
2020-09-24 15:34:13 +02:00
std :: vector < coordf_t > get () const throw () { return m_data ; }
bool empty () const throw () { return m_data . empty (); }
void set ( const std :: vector < coordf_t > & data ) { if ( m_data != data ) { m_data = data ; this -> touch (); } }
void set ( std :: vector < coordf_t > && data ) { if ( m_data != data ) { m_data = std :: move ( data ); this -> touch (); } }
void clear () { m_data . clear (); this -> touch (); }
template < class Archive > void serialize ( Archive & ar )
{
ar ( cereal :: base_class < ObjectWithTimestamp > ( this ), m_data );
}
private :
2020-10-15 17:29:42 +02:00
// Constructors to be only called by derived classes.
// Default constructor to assign a unique ID.
explicit LayerHeightProfile () = default ;
// Constructor with ignored int parameter to assign an invalid ID, to be replaced
// by an existing ID copied from elsewhere.
explicit LayerHeightProfile ( int ) : ObjectWithTimestamp ( - 1 ) {}
// Copy constructor copies the ID.
explicit LayerHeightProfile ( const LayerHeightProfile & rhs ) = default ;
// Move constructor copies the ID.
explicit LayerHeightProfile ( LayerHeightProfile && rhs ) = default ;
// called by ModelObject::assign_copy()
LayerHeightProfile & operator = ( const LayerHeightProfile & rhs ) = default ;
LayerHeightProfile & operator = ( LayerHeightProfile && rhs ) = default ;
2020-09-24 15:34:13 +02:00
std :: vector < coordf_t > m_data ;
2020-10-09 12:25:57 +02:00
// to access set_new_unique_id() when copy / pasting an object
friend class ModelObject ;
2020-09-24 15:34:13 +02:00
};
2021-05-26 15:36:02 +02:00
// Declared outside of ModelVolume, so it could be forward declared.
enum class ModelVolumeType : int {
INVALID = - 1 ,
MODEL_PART = 0 ,
NEGATIVE_VOLUME ,
PARAMETER_MODIFIER ,
SUPPORT_BLOCKER ,
SUPPORT_ENFORCER ,
};
2021-06-27 17:36:25 +02:00
enum class ModelObjectCutAttribute : int { KeepUpper , KeepLower , FlipLower };
using ModelObjectCutAttributes = enum_bitmask < ModelObjectCutAttribute > ;
ENABLE_ENUM_BITMASK_OPERATORS ( ModelObjectCutAttribute );
2016-09-13 13:30:00 +02:00
// A printable object, possibly having multiple print volumes (each with its own set of parameters and materials),
// and possibly having multiple modifier volumes, each modifier volume with its set of parameters and materials.
// Each ModelObject may be instantiated mutliple times, each instance having different placement on the print bed,
// different rotation and different uniform scaling.
2019-07-02 16:42:23 +02:00
class ModelObject final : public ObjectBase
2014-01-06 18:29:10 +01:00
{
2016-09-13 13:30:00 +02:00
public :
2017-06-13 11:35:24 +02:00
std :: string name ;
2018-09-17 12:15:11 +02:00
std :: string input_file ; // XXX: consider fs::path
2016-09-13 13:30:00 +02:00
// 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.
2017-06-13 11:35:24 +02:00
ModelInstancePtrs instances ;
2016-09-13 13:30:00 +02:00
// Printable and modifier volumes, each with its material ID and a set of override parameters.
// ModelVolumes are owned by this ModelObject.
2017-06-13 11:35:24 +02:00
ModelVolumePtrs volumes ;
2016-09-13 13:30:00 +02:00
// Configuration parameters specific to a single ModelObject, overriding the global Slic3r settings.
2020-09-24 15:34:13 +02:00
ModelConfigObject config ;
2019-06-20 16:15:09 +02:00
// Variation of a layer thickness for spans of Z coordinates + optional parameter overrides.
t_layer_config_ranges layer_config_ranges ;
2017-02-07 18:17:12 +01:00
// Profile of increasing z to a layer height, to be linearly interpolated when calculating the layers.
2019-01-21 10:06:51 +01:00
// The pairs of <z, layer_height> are packed into a 1D array.
2020-09-24 15:34:13 +02:00
LayerHeightProfile layer_height_profile ;
2019-07-31 08:36:08 +02:00
// Whether or not this object is printable
bool printable ;
2018-09-19 14:59:57 +02:00
// This vector holds position of selected support points for SLA. The data are
// saved in mesh coordinates to allow using them for several instances.
2019-01-30 08:26:23 +01:00
// The format is (x, y, z, point_size, supports_island)
2019-11-13 15:55:37 +01:00
sla :: SupportPoints sla_support_points ;
2019-02-27 16:23:10 +01:00
// To keep track of where the points came from (used for synchronization between
// the SLA gizmo and the backend).
2019-11-13 15:55:37 +01:00
sla :: PointsStatus sla_points_status = sla :: PointsStatus :: NoPoints ;
2016-09-13 13:30:00 +02:00
2019-11-08 14:05:56 +01:00
// Holes to be drilled into the object so resin can flow out
2019-11-13 15:55:37 +01:00
sla :: DrainHoles sla_drain_holes ;
2019-11-08 14:05:56 +01:00
2014-10-25 11:10:44 +02:00
/* This vector accumulates the total translation applied to the object by the
center_around_origin() method. Callers might want to apply the same translation
2015-01-09 00:47:40 +01:00
to new volumes before adding them to this object in order to preserve alignment
2014-10-25 11:10:44 +02:00
when user expects that. */
2018-08-21 17:43:05 +02:00
Vec3d origin_translation ;
2014-04-30 02:04:49 +03:00
2020-04-22 11:16:28 +02:00
Model * get_model () { return m_model ; }
const Model * get_model () const { return m_model ; }
2018-11-08 14:23:17 +01:00
2018-10-17 11:12:38 +02:00
ModelVolume * add_volume ( const TriangleMesh & mesh );
2021-05-26 15:36:02 +02:00
ModelVolume * add_volume ( TriangleMesh && mesh , ModelVolumeType type = ModelVolumeType :: MODEL_PART );
2021-05-28 13:02:18 +02:00
ModelVolume * add_volume ( const ModelVolume & volume , ModelVolumeType type = ModelVolumeType :: INVALID );
2018-11-02 14:47:13 +01:00
ModelVolume * add_volume ( const ModelVolume & volume , TriangleMesh && mesh );
2018-10-17 11:12:38 +02:00
void delete_volume ( size_t idx );
void clear_volumes ();
2021-06-02 12:52:47 +02:00
void sort_volumes ( bool full_sort );
2018-10-23 11:26:15 +02:00
bool is_multiparts () const { return volumes . size () > 1 ; }
2018-10-17 11:12:38 +02:00
ModelInstance * add_instance ();
ModelInstance * add_instance ( const ModelInstance & instance );
2019-01-03 15:04:29 +01:00
ModelInstance * add_instance ( const Vec3d & offset , const Vec3d & scaling_factor , const Vec3d & rotation , const Vec3d & mirror );
2018-10-17 11:12:38 +02:00
void delete_instance ( size_t idx );
void delete_last_instance ();
void clear_instances ();
2014-04-30 02:04:49 +03:00
2017-06-13 11:35:24 +02:00
// Returns the bounding box of the transformed instances.
// This bounding box is approximate and not snug.
2018-03-14 16:11:57 +01:00
// This bounding box is being cached.
2018-05-25 15:56:14 +02:00
const BoundingBoxf3 & bounding_box () const ;
2019-04-13 14:15:54 +02:00
void invalidate_bounding_box () { m_bounding_box_valid = false ; m_raw_bounding_box_valid = false ; m_raw_mesh_bounding_box_valid = false ; }
2014-04-30 02:04:49 +03:00
2017-06-13 11:35:24 +02:00
// A mesh containing all transformed instances of this object.
2015-01-19 18:53:04 +01:00
TriangleMesh mesh () const ;
2017-06-13 11:35:24 +02:00
// Non-transformed (non-rotated, non-scaled, non-translated) sum of non-modifier object volumes.
2019-12-02 22:48:01 -05:00
// Currently used by ModelObject::mesh() and to calculate the 2D envelope for 2D plater.
2015-01-19 18:53:04 +01:00
TriangleMesh raw_mesh () const ;
2020-09-17 18:39:28 +02:00
// The same as above, but producing a lightweight indexed_triangle_set.
indexed_triangle_set raw_indexed_triangle_set () const ;
2017-06-13 11:35:24 +02:00
// 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.
2019-04-13 14:15:54 +02:00
const BoundingBoxf3 & raw_bounding_box () const ;
2017-06-13 11:35:24 +02:00
// A snug bounding box around the transformed non-modifier object volumes.
BoundingBoxf3 instance_bounding_box ( size_t instance_idx , bool dont_translate = false ) const ;
2019-01-26 18:51:34 +01:00
// A snug bounding box of non-transformed (non-rotated, non-scaled, non-translated) sum of non-modifier object volumes.
2019-04-13 14:15:54 +02:00
const BoundingBoxf3 & raw_mesh_bounding_box () const ;
2019-01-26 18:51:34 +01:00
// A snug bounding box of non-transformed (non-rotated, non-scaled, non-translated) sum of all object volumes.
2019-01-18 12:52:09 +01:00
BoundingBoxf3 full_raw_mesh_bounding_box () const ;
2019-01-28 10:10:23 +01:00
// Calculate 2D convex hull of of a projection of the transformed printable volumes into the XY plane.
// This method is cheap in that it does not make any unnecessary copy of the volume meshes.
// This method is used by the auto arrange function.
2019-04-18 12:45:43 +02:00
Polygon convex_hull_2d ( const Transform3d & trafo_instance ) const ;
2019-01-28 10:10:23 +01:00
2019-03-22 09:47:40 +01:00
void center_around_origin ( bool include_modifiers = true );
2019-05-21 09:42:59 +02:00
2021-04-28 11:07:15 +02:00
#if ENABLE_ALLOW_NEGATIVE_Z
void ensure_on_bed ( bool allow_negative_z = false );
#else
2018-10-30 16:03:03 +01:00
void ensure_on_bed ();
2021-04-28 11:07:15 +02:00
#endif // ENABLE_ALLOW_NEGATIVE_Z
2018-10-30 16:03:03 +01:00
void translate_instances ( const Vec3d & vector );
void translate_instance ( size_t instance_idx , const Vec3d & vector );
2018-08-21 17:43:05 +02:00
void translate ( const Vec3d & vector ) { this -> translate ( vector ( 0 ), vector ( 1 ), vector ( 2 )); }
2018-11-01 14:25:10 +01:00
void translate ( double x , double y , double z );
2018-08-21 17:43:05 +02:00
void scale ( const Vec3d & versor );
2018-09-20 16:48:13 +02:00
void scale ( const double s ) { this -> scale ( Vec3d ( s , s , s )); }
2018-11-02 14:41:08 +01:00
void scale ( double x , double y , double z ) { this -> scale ( Vec3d ( x , y , z )); }
2019-03-13 15:44:50 +01:00
/// Scale the current ModelObject to fit by altering the scaling factor of ModelInstances.
/// It operates on the total size by duplicating the object according to all the instances.
/// \param size Sizef3 the size vector
void scale_to_fit ( const Vec3d & size );
2018-11-05 08:31:54 +01:00
void rotate ( double angle , Axis axis );
void rotate ( double angle , const Vec3d & axis );
2018-11-05 08:51:00 +01:00
void mirror ( Axis axis );
2018-12-19 09:54:15 +01:00
2019-06-11 17:08:47 +02:00
// This method could only be called before the meshes of this ModelVolumes are not shared!
2019-07-02 16:42:23 +02:00
void scale_mesh_after_creation ( const Vec3d & versor );
2021-02-10 20:31:17 +01:00
void convert_units ( ModelObjectPtrs & new_objects , ConversionType conv_type , std :: vector < int > volume_idxs );
2018-12-19 09:54:15 +01:00
2014-09-21 10:51:36 +02:00
size_t materials_count () const ;
2014-08-08 21:48:59 +02:00
size_t facets_count () const ;
bool needed_repair () const ;
2021-06-27 17:36:25 +02:00
ModelObjectPtrs cut ( size_t instance , coordf_t z , ModelObjectCutAttributes attributes );
2014-11-12 23:50:09 +01:00
void split ( ModelObjectPtrs * new_objects );
2020-05-27 10:55:48 +02:00
void merge ();
2019-04-26 17:28:31 +02:00
// Support for non-uniform scaling of instances. If an instance is rotated by angles, which are not multiples of ninety degrees,
// then the scaling in world coordinate system is not representable by the Geometry::Transformation structure.
// This situation is solved by baking in the instance transformation into the mesh vertices.
// Rotation and mirroring is being baked in. In case the instance scaling was non-uniform, it is baked in as well.
void bake_xy_rotation_into_meshes ( size_t instance_idx );
2018-07-18 14:26:42 +02:00
2018-10-30 16:03:03 +01:00
double get_min_z () const ;
double get_instance_min_z ( size_t instance_idx ) const ;
2018-09-14 09:28:00 +02:00
// Called by Print::validate() from the UI thread.
2018-10-23 15:27:31 +02:00
unsigned int check_instances_print_volume_state ( const BoundingBoxf3 & print_volume );
2017-08-02 16:05:18 +02:00
// Print object statistics to console.
void print_info () const ;
2018-10-17 11:12:38 +02:00
2019-04-04 14:00:31 +02:00
std :: string get_export_filename () const ;
2019-07-03 13:43:54 +02:00
// Get full stl statistics for all object's meshes
2019-04-24 16:04:47 +02:00
stl_stats get_object_stl_stats () const ;
2019-07-03 13:43:54 +02:00
// Get count of errors in the mesh( or all object's meshes, if volume index isn't defined)
2019-04-24 16:04:47 +02:00
int get_mesh_errors_count ( const int vol_idx = - 1 ) const ;
2018-10-17 11:12:38 +02:00
private :
2019-07-03 13:43:54 +02:00
friend class Model ;
// This constructor assigns new ID to this ModelObject and its config.
2019-07-31 08:36:08 +02:00
explicit ModelObject ( Model * model ) : m_model ( model ), printable ( true ), origin_translation ( Vec3d :: Zero ()),
2019-07-03 13:43:54 +02:00
m_bounding_box_valid ( false ), m_raw_bounding_box_valid ( false ), m_raw_mesh_bounding_box_valid ( false )
2020-10-15 17:29:42 +02:00
{
assert ( this -> id (). valid ());
assert ( this -> config . id (). valid ());
assert ( this -> layer_height_profile . id (). valid ());
}
explicit ModelObject ( int ) : ObjectBase ( - 1 ), config ( - 1 ), layer_height_profile ( - 1 ), m_model ( nullptr ), printable ( true ), origin_translation ( Vec3d :: Zero ()), m_bounding_box_valid ( false ), m_raw_bounding_box_valid ( false ), m_raw_mesh_bounding_box_valid ( false )
{
assert ( this -> id (). invalid ());
assert ( this -> config . id (). invalid ());
assert ( this -> layer_height_profile . id (). invalid ());
}
2019-07-03 13:43:54 +02:00
~ ModelObject ();
2019-07-05 19:06:19 +02:00
void assign_new_unique_ids_recursive () override ;
2017-06-13 11:35:24 +02:00
2019-07-03 13:43:54 +02:00
// To be able to return an object from own copy / clone methods. Hopefully the compiler will do the "Copy elision"
// (Omits copy and move(since C++11) constructors, resulting in zero - copy pass - by - value semantics).
2020-10-15 17:29:42 +02:00
ModelObject ( const ModelObject & rhs ) : ObjectBase ( - 1 ), config ( - 1 ), layer_height_profile ( - 1 ), m_model ( rhs . m_model ) {
assert ( this -> id (). invalid ());
assert ( this -> config . id (). invalid ());
assert ( this -> layer_height_profile . id (). invalid ());
assert ( rhs . id () != rhs . config . id ());
assert ( rhs . id () != rhs . layer_height_profile . id ());
2019-07-03 13:43:54 +02:00
this -> assign_copy ( rhs );
2020-10-15 17:29:42 +02:00
assert ( this -> id (). valid ());
assert ( this -> config . id (). valid ());
assert ( this -> layer_height_profile . id (). valid ());
assert ( this -> id () != this -> config . id ());
assert ( this -> id () != this -> layer_height_profile . id ());
assert ( this -> id () == rhs . id ());
assert ( this -> config . id () == rhs . config . id ());
assert ( this -> layer_height_profile . id () == rhs . layer_height_profile . id ());
2019-07-03 13:43:54 +02:00
}
2020-10-15 17:29:42 +02:00
explicit ModelObject ( ModelObject && rhs ) : ObjectBase ( - 1 ), config ( - 1 ), layer_height_profile ( - 1 ) {
assert ( this -> id (). invalid ());
assert ( this -> config . id (). invalid ());
assert ( this -> layer_height_profile . id (). invalid ());
assert ( rhs . id () != rhs . config . id ());
assert ( rhs . id () != rhs . layer_height_profile . id ());
2019-07-03 13:43:54 +02:00
this -> assign_copy ( std :: move ( rhs ));
2020-10-15 17:29:42 +02:00
assert ( this -> id (). valid ());
assert ( this -> config . id (). valid ());
assert ( this -> layer_height_profile . id (). valid ());
assert ( this -> id () != this -> config . id ());
assert ( this -> id () != this -> layer_height_profile . id ());
assert ( this -> id () == rhs . id ());
assert ( this -> config . id () == rhs . config . id ());
assert ( this -> layer_height_profile . id () == rhs . layer_height_profile . id ());
2019-07-03 13:43:54 +02:00
}
2020-10-15 17:29:42 +02:00
ModelObject & operator = ( const ModelObject & rhs ) {
2019-07-03 13:43:54 +02:00
this -> assign_copy ( rhs );
m_model = rhs . m_model ;
2020-10-15 17:29:42 +02:00
assert ( this -> id (). valid ());
assert ( this -> config . id (). valid ());
assert ( this -> layer_height_profile . id (). valid ());
assert ( this -> id () != this -> config . id ());
assert ( this -> id () != this -> layer_height_profile . id ());
assert ( this -> id () == rhs . id ());
assert ( this -> config . id () == rhs . config . id ());
assert ( this -> layer_height_profile . id () == rhs . layer_height_profile . id ());
2019-07-03 13:43:54 +02:00
return * this ;
}
2020-10-15 17:29:42 +02:00
ModelObject & operator = ( ModelObject && rhs ) {
2019-07-03 13:43:54 +02:00
this -> assign_copy ( std :: move ( rhs ));
m_model = rhs . m_model ;
2020-10-15 17:29:42 +02:00
assert ( this -> id (). valid ());
assert ( this -> config . id (). valid ());
assert ( this -> layer_height_profile . id (). valid ());
assert ( this -> id () != this -> config . id ());
assert ( this -> id () != this -> layer_height_profile . id ());
assert ( this -> id () == rhs . id ());
assert ( this -> config . id () == rhs . config . id ());
assert ( this -> layer_height_profile . id () == rhs . layer_height_profile . id ());
2019-07-03 13:43:54 +02:00
return * this ;
}
2020-10-15 17:29:42 +02:00
void set_new_unique_id () {
ObjectBase :: set_new_unique_id ();
this -> config . set_new_unique_id ();
this -> layer_height_profile . set_new_unique_id ();
}
2018-11-02 19:49:40 +01:00
2019-06-27 11:02:45 +02:00
OBJECTBASE_DERIVED_COPY_MOVE_CLONE ( ModelObject )
2017-06-13 11:35:24 +02:00
2018-11-02 19:49:40 +01:00
// Parent object, owning this ModelObject. Set to nullptr here, so the macros above will have it initialized.
Model * m_model = nullptr ;
2018-06-21 08:37:04 +02:00
2017-06-13 11:35:24 +02:00
// Bounding box, cached.
2018-05-25 15:56:14 +02:00
mutable BoundingBoxf3 m_bounding_box ;
mutable bool m_bounding_box_valid ;
2019-04-13 14:15:54 +02:00
mutable BoundingBoxf3 m_raw_bounding_box ;
mutable bool m_raw_bounding_box_valid ;
2019-01-26 18:51:34 +01:00
mutable BoundingBoxf3 m_raw_mesh_bounding_box ;
2019-06-26 16:29:12 +02:00
mutable bool m_raw_mesh_bounding_box_valid ;
2019-07-02 16:42:23 +02:00
// Called by Print::apply() to set the model pointer after making a copy.
friend class Print ;
friend class SLAPrint ;
void set_model ( Model * model ) { m_model = model ; }
// Undo / Redo through the cereal serialization library
2019-06-26 16:29:12 +02:00
friend class cereal :: access ;
2019-07-02 16:42:23 +02:00
friend class UndoRedo :: StackImpl ;
2019-07-03 13:43:54 +02:00
// Used for deserialization -> Don't allocate any IDs for the ModelObject or its config.
2020-10-15 17:29:42 +02:00
ModelObject () :
ObjectBase ( - 1 ), config ( - 1 ), layer_height_profile ( - 1 ),
m_model ( nullptr ), m_bounding_box_valid ( false ), m_raw_bounding_box_valid ( false ), m_raw_mesh_bounding_box_valid ( false ) {
assert ( this -> id (). invalid ());
assert ( this -> config . id (). invalid ());
assert ( this -> layer_height_profile . id (). invalid ());
2019-07-03 13:43:54 +02:00
}
template < class Archive > void serialize ( Archive & ar ) {
2019-06-27 11:02:45 +02:00
ar ( cereal :: base_class < ObjectBase > ( this ));
2020-09-24 15:34:13 +02:00
Internal :: StaticSerializationWrapper < ModelConfigObject > config_wrapper ( config );
Internal :: StaticSerializationWrapper < LayerHeightProfile > layer_heigth_profile_wrapper ( layer_height_profile );
ar ( name , input_file , instances , volumes , config_wrapper , layer_config_ranges , layer_heigth_profile_wrapper ,
sla_support_points , sla_points_status , sla_drain_holes , printable , origin_translation ,
2019-07-31 08:36:08 +02:00
m_bounding_box , m_bounding_box_valid , m_raw_bounding_box , m_raw_bounding_box_valid , m_raw_mesh_bounding_box , m_raw_mesh_bounding_box_valid );
2019-06-26 16:29:12 +02:00
}
2014-01-06 18:29:10 +01:00
};
2020-08-05 14:03:22 +02:00
enum class EnforcerBlockerType : int8_t {
2020-06-11 13:09:34 +02:00
// Maximum is 3. The value is serialized in TriangleSelector into 2 bits!
2020-04-16 14:42:42 +02:00
NONE = 0 ,
ENFORCER = 1 ,
BLOCKER = 2
};
2021-02-10 20:31:17 +01:00
enum class ConversionType : int {
CONV_TO_INCH ,
CONV_FROM_INCH ,
CONV_TO_METER ,
CONV_FROM_METER ,
};
2020-09-24 15:34:13 +02:00
class FacetsAnnotation final : public ObjectWithTimestamp {
2020-04-16 14:42:42 +02:00
public :
2020-10-15 17:29:42 +02:00
// Assign the content if the timestamp differs, don't assign an ObjectID.
2021-05-06 14:43:36 +02:00
void assign ( const FacetsAnnotation & rhs ) { if ( ! this -> timestamp_matches ( rhs )) { m_data = rhs . m_data ; this -> copy_timestamp ( rhs ); } }
void assign ( FacetsAnnotation && rhs ) { if ( ! this -> timestamp_matches ( rhs )) { m_data = std :: move ( rhs . m_data ); this -> copy_timestamp ( rhs ); } }
2021-06-10 09:26:01 +02:00
const std :: pair < std :: vector < std :: pair < int , int >> , std :: vector < bool >>& get_data () const throw () { return m_data ; }
2020-07-15 12:28:52 +02:00
bool set ( const TriangleSelector & selector );
2020-08-05 14:03:22 +02:00
indexed_triangle_set get_facets ( const ModelVolume & mv , EnforcerBlockerType type ) const ;
2021-06-10 09:26:01 +02:00
bool empty () const { return m_data . first . empty (); }
2020-04-16 14:42:42 +02:00
void clear ();
2021-06-10 09:26:01 +02:00
// Serialize triangle into string, for serialization into 3MF/AMF.
2020-07-24 16:53:05 +02:00
std :: string get_triangle_as_string ( int i ) const ;
2021-06-10 09:26:01 +02:00
// Before deserialization, reserve space for n_triangles.
void reserve ( int n_triangles ) { m_data . first . reserve ( n_triangles ); }
// Deserialize triangles one by one, with strictly increasing triangle_id.
2020-07-24 16:53:05 +02:00
void set_triangle_from_string ( int triangle_id , const std :: string & str );
2021-06-10 09:26:01 +02:00
// After deserializing the last triangle, shrink data to fit.
void shrink_to_fit () { m_data . first . shrink_to_fit (); m_data . second . shrink_to_fit (); }
2020-04-16 14:42:42 +02:00
2020-09-24 15:34:13 +02:00
private :
2020-10-15 17:29:42 +02:00
// Constructors to be only called by derived classes.
// Default constructor to assign a unique ID.
explicit FacetsAnnotation () = default ;
// Constructor with ignored int parameter to assign an invalid ID, to be replaced
// by an existing ID copied from elsewhere.
explicit FacetsAnnotation ( int ) : ObjectWithTimestamp ( - 1 ) {}
// Copy constructor copies the ID.
explicit FacetsAnnotation ( const FacetsAnnotation & rhs ) = default ;
// Move constructor copies the ID.
explicit FacetsAnnotation ( FacetsAnnotation && rhs ) = default ;
// called by ModelVolume::assign_copy()
FacetsAnnotation & operator = ( const FacetsAnnotation & rhs ) = default ;
FacetsAnnotation & operator = ( FacetsAnnotation && rhs ) = default ;
2020-09-24 15:34:13 +02:00
friend class cereal :: access ;
friend class UndoRedo :: StackImpl ;
2020-04-16 14:42:42 +02:00
2020-05-05 13:45:04 +02:00
template < class Archive > void serialize ( Archive & ar )
{
2020-09-24 15:34:13 +02:00
ar ( cereal :: base_class < ObjectWithTimestamp > ( this ), m_data );
2020-05-05 13:45:04 +02:00
}
2021-06-10 09:26:01 +02:00
std :: pair < std :: vector < std :: pair < int , int >> , std :: vector < bool >> m_data ;
2020-10-09 12:25:57 +02:00
// To access set_new_unique_id() when copy / pasting a ModelVolume.
friend class ModelVolume ;
2020-04-16 14:42:42 +02:00
};
2016-09-13 13:30:00 +02:00
// An object STL, or a modifier volume, over which a different set of parameters shall be applied.
// ModelVolume instances are owned by a ModelObject.
2019-07-02 16:42:23 +02:00
class ModelVolume final : public ObjectBase
2014-01-06 18:29:10 +01:00
{
2016-09-13 13:30:00 +02:00
public :
2018-10-17 11:12:38 +02:00
std :: string name ;
2019-09-19 09:09:11 +02:00
// struct used by reload from disk command to recover data from disk
struct Source
{
std :: string input_file ;
int object_idx { - 1 };
int volume_idx { - 1 };
Vec3d mesh_offset { Vec3d :: Zero () };
2019-12-20 12:11:58 +01:00
Geometry :: Transformation transform ;
2020-12-11 13:57:38 +01:00
bool is_converted_from_inches = false ;
2021-02-10 20:31:17 +01:00
bool is_converted_from_meters = false ;
2019-09-19 09:09:11 +02:00
2020-09-23 12:59:15 +02:00
template < class Archive > void serialize ( Archive & ar ) {
//FIXME Vojtech: Serialize / deserialize only if the Source is set.
// likely testing input_file or object_idx would be sufficient.
2021-02-10 20:31:17 +01:00
ar ( input_file , object_idx , volume_idx , mesh_offset , transform , is_converted_from_inches , is_converted_from_meters );
2020-09-23 12:59:15 +02:00
}
2019-09-19 09:09:11 +02:00
};
Source source ;
2019-09-23 15:35:49 +02:00
2016-09-13 13:30:00 +02:00
// The triangular model.
2019-06-11 17:08:47 +02:00
const TriangleMesh & mesh () const { return * m_mesh . get (); }
2019-07-02 16:42:23 +02:00
void set_mesh ( const TriangleMesh & mesh ) { m_mesh = std :: make_shared < const TriangleMesh > ( mesh ); }
void set_mesh ( TriangleMesh && mesh ) { m_mesh = std :: make_shared < const TriangleMesh > ( std :: move ( mesh )); }
void set_mesh ( std :: shared_ptr < const TriangleMesh > & mesh ) { m_mesh = mesh ; }
void set_mesh ( std :: unique_ptr < const TriangleMesh > && mesh ) { m_mesh = std :: move ( mesh ); }
void reset_mesh () { m_mesh = std :: make_shared < const TriangleMesh > (); }
2016-09-13 13:30:00 +02:00
// Configuration parameters specific to an object model geometry or a modifier volume,
// overriding the global Slic3r settings and the ModelObject settings.
2020-09-24 15:34:13 +02:00
ModelConfigObject config ;
2018-09-06 14:19:20 +02:00
2020-04-16 14:42:42 +02:00
// List of mesh facets to be supported/unsupported.
2020-10-09 13:09:03 +02:00
FacetsAnnotation supported_facets ;
2020-04-16 14:42:42 +02:00
2020-08-31 07:25:43 +02:00
// List of seam enforcers/blockers.
2020-10-09 13:09:03 +02:00
FacetsAnnotation seam_facets ;
2020-08-31 07:25:43 +02:00
2021-04-19 07:01:11 +02:00
// List of mesh facets painted for MMU segmentation.
FacetsAnnotation mmu_segmentation_facets ;
2016-09-13 13:30:00 +02:00
// A parent object owning this modifier volume.
2020-04-22 11:16:28 +02:00
ModelObject * get_object () const { return this -> object ; }
2019-02-22 12:12:10 +01:00
ModelVolumeType type () const { return m_type ; }
void set_type ( const ModelVolumeType t ) { m_type = t ; }
bool is_model_part () const { return m_type == ModelVolumeType :: MODEL_PART ; }
2021-05-19 09:38:51 +02:00
bool is_negative_volume () const { return m_type == ModelVolumeType :: NEGATIVE_VOLUME ; }
2019-02-22 12:12:10 +01:00
bool is_modifier () const { return m_type == ModelVolumeType :: PARAMETER_MODIFIER ; }
bool is_support_enforcer () const { return m_type == ModelVolumeType :: SUPPORT_ENFORCER ; }
bool is_support_blocker () const { return m_type == ModelVolumeType :: SUPPORT_BLOCKER ; }
bool is_support_modifier () const { return m_type == ModelVolumeType :: SUPPORT_BLOCKER || m_type == ModelVolumeType :: SUPPORT_ENFORCER ; }
2018-10-17 11:12:38 +02:00
t_model_material_id material_id () const { return m_material_id ; }
void set_material_id ( t_model_material_id material_id );
2018-09-06 14:19:20 +02:00
ModelMaterial * material () const ;
void set_material ( t_model_material_id material_id , const ModelMaterial & material );
2018-11-22 13:20:13 +01:00
// Extract the current extruder ID based on this ModelVolume's config and the parent ModelObject's config.
// Extruder ID is only valid for FFF. Returns -1 for SLA or if the extruder ID is not applicable (support volumes).
int extruder_id () const ;
2019-03-13 14:04:59 +01:00
bool is_splittable () const ;
2019-01-21 15:42:33 +01:00
2017-06-15 15:38:15 +02:00
// Split this volume, append the result to the object owning this volume.
// Return the number of volumes created from this one.
// This is useful to assign different materials to different volumes of an object.
2018-09-20 16:48:13 +02:00
size_t split ( unsigned int max_extruders );
2018-11-02 14:41:08 +01:00
void translate ( double x , double y , double z ) { translate ( Vec3d ( x , y , z )); }
2018-11-01 14:25:10 +01:00
void translate ( const Vec3d & displacement );
2018-11-02 14:41:08 +01:00
void scale ( const Vec3d & scaling_factors );
void scale ( double x , double y , double z ) { scale ( Vec3d ( x , y , z )); }
void scale ( double s ) { scale ( Vec3d ( s , s , s )); }
2018-11-05 08:31:54 +01:00
void rotate ( double angle , Axis axis );
void rotate ( double angle , const Vec3d & axis );
2018-11-05 08:51:00 +01:00
void mirror ( Axis axis );
2018-05-07 16:13:58 +02:00
2019-06-11 17:08:47 +02:00
// This method could only be called before the meshes of this ModelVolumes are not shared!
2019-07-02 16:42:23 +02:00
void scale_geometry_after_creation ( const Vec3d & versor );
2018-12-19 09:54:15 +01:00
2019-06-11 17:08:47 +02:00
// Translates the mesh and the convex hull so that the origin of their vertices is in the center of this volume's bounding box.
// Attention! This method may only be called just after ModelVolume creation! It must not be called once the TriangleMesh of this ModelVolume is shared!
2019-09-19 12:39:59 +02:00
void center_geometry_after_creation ( bool update_source_offset = true );
2018-11-06 15:51:33 +01:00
2018-09-20 16:48:13 +02:00
void calculate_convex_hull ();
2018-08-15 12:50:06 +02:00
const TriangleMesh & get_convex_hull () const ;
2019-06-11 17:08:47 +02:00
std :: shared_ptr < const TriangleMesh > get_convex_hull_shared_ptr () const { return m_convex_hull ; }
2019-04-29 15:27:59 +02:00
// Get count of errors in the mesh
int get_mesh_errors_count () const ;
2018-08-15 12:50:06 +02:00
2018-09-06 14:19:20 +02:00
// Helpers for loading / storing into AMF / 3MF files.
2019-02-22 12:12:10 +01:00
static ModelVolumeType type_from_string ( const std :: string & s );
static std :: string type_to_string ( const ModelVolumeType t );
2018-09-06 14:19:20 +02:00
2018-11-01 14:25:10 +01:00
const Geometry :: Transformation & get_transformation () const { return m_transformation ; }
void set_transformation ( const Geometry :: Transformation & transformation ) { m_transformation = transformation ; }
2019-12-19 10:22:46 +01:00
void set_transformation ( const Transform3d & trafo ) { m_transformation . set_from_transform ( trafo ); }
2018-11-01 14:25:10 +01:00
2018-10-31 14:56:51 +01:00
const Vec3d & get_offset () const { return m_transformation . get_offset (); }
double get_offset ( Axis axis ) const { return m_transformation . get_offset ( axis ); }
void set_offset ( const Vec3d & offset ) { m_transformation . set_offset ( offset ); }
void set_offset ( Axis axis , double offset ) { m_transformation . set_offset ( axis , offset ); }
const Vec3d & get_rotation () const { return m_transformation . get_rotation (); }
double get_rotation ( Axis axis ) const { return m_transformation . get_rotation ( axis ); }
void set_rotation ( const Vec3d & rotation ) { m_transformation . set_rotation ( rotation ); }
void set_rotation ( Axis axis , double rotation ) { m_transformation . set_rotation ( axis , rotation ); }
Vec3d get_scaling_factor () const { return m_transformation . get_scaling_factor (); }
double get_scaling_factor ( Axis axis ) const { return m_transformation . get_scaling_factor ( axis ); }
void set_scaling_factor ( const Vec3d & scaling_factor ) { m_transformation . set_scaling_factor ( scaling_factor ); }
void set_scaling_factor ( Axis axis , double scaling_factor ) { m_transformation . set_scaling_factor ( axis , scaling_factor ); }
const Vec3d & get_mirror () const { return m_transformation . get_mirror (); }
double get_mirror ( Axis axis ) const { return m_transformation . get_mirror ( axis ); }
2019-04-02 13:47:49 +02:00
bool is_left_handed () const { return m_transformation . is_left_handed (); }
2018-10-31 14:56:51 +01:00
void set_mirror ( const Vec3d & mirror ) { m_transformation . set_mirror ( mirror ); }
void set_mirror ( Axis axis , double mirror ) { m_transformation . set_mirror ( axis , mirror ); }
2020-12-11 13:57:38 +01:00
void convert_from_imperial_units ();
2021-02-10 20:31:17 +01:00
void convert_from_meters ();
2018-11-01 14:25:10 +01:00
const Transform3d & get_matrix ( bool dont_translate = false , bool dont_rotate = false , bool dont_scale = false , bool dont_mirror = false ) const { return m_transformation . get_matrix ( dont_translate , dont_rotate , dont_scale , dont_mirror ); }
2018-10-31 14:56:51 +01:00
2020-10-15 17:29:42 +02:00
void set_new_unique_id () {
ObjectBase :: set_new_unique_id ();
this -> config . set_new_unique_id ();
this -> supported_facets . set_new_unique_id ();
this -> seam_facets . set_new_unique_id ();
2021-04-19 07:01:11 +02:00
this -> mmu_segmentation_facets . set_new_unique_id ();
2020-10-15 17:29:42 +02:00
}
2019-02-03 22:14:34 +01:00
2018-11-02 19:49:40 +01:00
protected :
2018-11-02 20:41:49 +01:00
friend class Print ;
2018-11-21 17:35:35 +01:00
friend class SLAPrint ;
2019-07-04 10:45:41 +02:00
friend class Model ;
2018-11-02 20:41:49 +01:00
friend class ModelObject ;
2021-05-05 14:32:19 +02:00
friend void model_volume_list_update_supports ( ModelObject & model_object_dst , const ModelObject & model_object_new );
2018-11-02 20:41:49 +01:00
2019-07-03 13:43:54 +02:00
// Copies IDs of both the ModelVolume and its config.
2018-11-12 16:28:27 +01:00
explicit ModelVolume ( const ModelVolume & rhs ) = default ;
2018-11-02 19:49:40 +01:00
void set_model_object ( ModelObject * model_object ) { object = model_object ; }
2020-10-09 12:25:57 +02:00
void assign_new_unique_ids_recursive () override ;
2019-06-11 17:08:47 +02:00
void transform_this_mesh ( const Transform3d & t , bool fix_left_handed );
void transform_this_mesh ( const Matrix3d & m , bool fix_left_handed );
2018-11-02 19:49:40 +01:00
2016-09-13 13:30:00 +02:00
private :
// Parent object owning this ModelVolume.
2019-07-02 16:42:23 +02:00
ModelObject * object ;
2019-06-11 17:08:47 +02:00
// The triangular model.
2019-07-02 16:42:23 +02:00
std :: shared_ptr < const TriangleMesh > m_mesh ;
2018-09-06 14:19:20 +02:00
// Is it an object to be printed, or a modifier volume?
2019-07-02 16:42:23 +02:00
ModelVolumeType m_type ;
t_model_material_id m_material_id ;
2018-11-01 14:25:10 +01:00
// The convex hull of this model's mesh.
2019-07-02 16:42:23 +02:00
std :: shared_ptr < const TriangleMesh > m_convex_hull ;
Geometry :: Transformation m_transformation ;
2018-11-01 14:25:10 +01:00
2019-04-01 12:27:45 +02:00
// flag to optimize the checking if the volume is splittable
// -1 -> is unknown value (before first cheking)
// 0 -> is not splittable
// 1 -> is splittable
2019-06-26 16:29:12 +02:00
mutable int m_is_splittable { - 1 };
2019-04-01 12:27:45 +02:00
2021-05-26 15:36:02 +02:00
ModelVolume ( ModelObject * object , const TriangleMesh & mesh , ModelVolumeType type = ModelVolumeType :: MODEL_PART ) : m_mesh ( new TriangleMesh ( mesh )), m_type ( type ), object ( object )
2018-08-15 12:50:06 +02:00
{
2020-10-15 17:29:42 +02:00
assert ( this -> id (). valid ());
assert ( this -> config . id (). valid ());
assert ( this -> supported_facets . id (). valid ());
2021-04-19 07:01:11 +02:00
assert ( this -> seam_facets . id (). valid ());
assert ( this -> mmu_segmentation_facets . id (). valid ());
2020-10-15 17:29:42 +02:00
assert ( this -> id () != this -> config . id ());
assert ( this -> id () != this -> supported_facets . id ());
assert ( this -> id () != this -> seam_facets . id ());
2021-04-19 07:01:11 +02:00
assert ( this -> id () != this -> mmu_segmentation_facets . id ());
2018-08-15 12:50:06 +02:00
if ( mesh . stl . stats . number_of_facets > 1 )
calculate_convex_hull ();
}
2021-05-26 15:36:02 +02:00
ModelVolume ( ModelObject * object , TriangleMesh && mesh , TriangleMesh && convex_hull , ModelVolumeType type = ModelVolumeType :: MODEL_PART ) :
m_mesh ( new TriangleMesh ( std :: move ( mesh ))), m_convex_hull ( new TriangleMesh ( std :: move ( convex_hull ))), m_type ( type ), object ( object ) {
2020-10-15 17:29:42 +02:00
assert ( this -> id (). valid ());
2021-04-19 07:01:11 +02:00
assert ( this -> config . id (). valid ());
assert ( this -> supported_facets . id (). valid ());
assert ( this -> seam_facets . id (). valid ());
assert ( this -> mmu_segmentation_facets . id (). valid ());
2020-10-15 17:29:42 +02:00
assert ( this -> id () != this -> config . id ());
assert ( this -> id () != this -> supported_facets . id ());
assert ( this -> id () != this -> seam_facets . id ());
2021-04-19 07:01:11 +02:00
assert ( this -> id () != this -> mmu_segmentation_facets . id ());
2019-07-03 13:43:54 +02:00
}
2018-11-02 12:11:28 +01:00
2018-11-05 17:52:55 +01:00
// Copying an existing volume, therefore this volume will get a copy of the ID assigned.
2018-11-02 12:11:28 +01:00
ModelVolume ( ModelObject * object , const ModelVolume & other ) :
2019-07-03 13:43:54 +02:00
ObjectBase ( other ),
2020-04-16 14:42:42 +02:00
name ( other . name ), source ( other . source ), m_mesh ( other . m_mesh ), m_convex_hull ( other . m_convex_hull ),
config ( other . config ), m_type ( other . m_type ), object ( object ), m_transformation ( other . m_transformation ),
2021-05-26 15:23:35 +02:00
supported_facets ( other . supported_facets ), seam_facets ( other . seam_facets ), mmu_segmentation_facets ( other . mmu_segmentation_facets )
2018-11-02 12:11:28 +01:00
{
2020-10-15 17:29:42 +02:00
assert ( this -> id (). valid ());
assert ( this -> config . id (). valid ());
assert ( this -> supported_facets . id (). valid ());
assert ( this -> seam_facets . id (). valid ());
2021-04-19 07:01:11 +02:00
assert ( this -> mmu_segmentation_facets . id (). valid ());
2020-10-15 17:29:42 +02:00
assert ( this -> id () != this -> config . id ());
assert ( this -> id () != this -> supported_facets . id ());
assert ( this -> id () != this -> seam_facets . id ());
2021-04-19 07:01:11 +02:00
assert ( this -> id () != this -> mmu_segmentation_facets . id ());
2020-10-15 17:29:42 +02:00
assert ( this -> id () == other . id ());
assert ( this -> config . id () == other . config . id ());
assert ( this -> supported_facets . id () == other . supported_facets . id ());
assert ( this -> seam_facets . id () == other . seam_facets . id ());
2021-04-19 07:01:11 +02:00
assert ( this -> mmu_segmentation_facets . id () == other . mmu_segmentation_facets . id ());
2018-11-02 12:11:28 +01:00
this -> set_material_id ( other . material_id ());
}
2018-11-05 17:52:55 +01:00
// Providing a new mesh, therefore this volume will get a new unique ID assigned.
2018-11-02 12:11:28 +01:00
ModelVolume ( ModelObject * object , const ModelVolume & other , const TriangleMesh && mesh ) :
2019-09-19 09:09:11 +02:00
name ( other . name ), source ( other . source ), m_mesh ( new TriangleMesh ( std :: move ( mesh ))), config ( other . config ), m_type ( other . m_type ), object ( object ), m_transformation ( other . m_transformation )
2018-11-02 12:11:28 +01:00
{
2020-10-15 17:29:42 +02:00
assert ( this -> id (). valid ());
assert ( this -> config . id (). valid ());
assert ( this -> supported_facets . id (). valid ());
assert ( this -> seam_facets . id (). valid ());
2021-04-19 07:01:11 +02:00
assert ( this -> mmu_segmentation_facets . id (). valid ());
2020-10-15 17:29:42 +02:00
assert ( this -> id () != this -> config . id ());
assert ( this -> id () != this -> supported_facets . id ());
assert ( this -> id () != this -> seam_facets . id ());
2021-04-19 07:01:11 +02:00
assert ( this -> id () != this -> mmu_segmentation_facets . id ());
2020-10-15 17:29:42 +02:00
assert ( this -> id () != other . id ());
assert ( this -> config . id () == other . config . id ());
2018-11-02 12:11:28 +01:00
this -> set_material_id ( other . material_id ());
2019-07-03 13:43:54 +02:00
this -> config . set_new_unique_id ();
2018-11-02 12:11:28 +01:00
if ( mesh . stl . stats . number_of_facets > 1 )
calculate_convex_hull ();
2020-10-15 17:29:42 +02:00
assert ( this -> config . id (). valid ());
assert ( this -> config . id () != other . config . id ());
assert ( this -> supported_facets . id () != other . supported_facets . id ());
assert ( this -> seam_facets . id () != other . seam_facets . id ());
2021-04-19 07:01:11 +02:00
assert ( this -> mmu_segmentation_facets . id () != other . mmu_segmentation_facets . id ());
2020-10-15 17:29:42 +02:00
assert ( this -> id () != this -> config . id ());
assert ( this -> supported_facets . empty ());
assert ( this -> seam_facets . empty ());
2021-04-19 07:01:11 +02:00
assert ( this -> mmu_segmentation_facets . empty ());
2018-11-02 12:11:28 +01:00
}
2018-10-30 15:24:36 +01:00
ModelVolume & operator = ( ModelVolume & rhs ) = delete ;
2019-06-26 16:29:12 +02:00
friend class cereal :: access ;
2019-07-02 16:42:23 +02:00
friend class UndoRedo :: StackImpl ;
2019-07-03 13:43:54 +02:00
// Used for deserialization, therefore no IDs are allocated.
2021-04-19 07:01:11 +02:00
ModelVolume () : ObjectBase ( - 1 ), config ( - 1 ), supported_facets ( - 1 ), seam_facets ( - 1 ), mmu_segmentation_facets ( - 1 ), object ( nullptr ) {
2020-10-15 17:29:42 +02:00
assert ( this -> id (). invalid ());
assert ( this -> config . id (). invalid ());
assert ( this -> supported_facets . id (). invalid ());
assert ( this -> seam_facets . id (). invalid ());
2021-04-19 07:01:11 +02:00
assert ( this -> mmu_segmentation_facets . id (). invalid ());
2019-07-03 13:43:54 +02:00
}
2019-07-18 11:51:06 +02:00
template < class Archive > void load ( Archive & ar ) {
bool has_convex_hull ;
2020-09-24 15:34:13 +02:00
ar ( name , source , m_mesh , m_type , m_material_id , m_transformation , m_is_splittable , has_convex_hull );
2020-10-09 13:09:03 +02:00
cereal :: load_by_value ( ar , supported_facets );
cereal :: load_by_value ( ar , seam_facets );
2021-04-19 07:01:11 +02:00
cereal :: load_by_value ( ar , mmu_segmentation_facets );
2019-09-19 09:09:11 +02:00
cereal :: load_by_value ( ar , config );
2019-07-18 11:51:06 +02:00
assert ( m_mesh );
if ( has_convex_hull ) {
cereal :: load_optional ( ar , m_convex_hull );
if ( ! m_convex_hull && ! m_mesh -> empty ())
// The convex hull was released from the Undo / Redo stack to conserve memory. Recalculate it.
this -> calculate_convex_hull ();
} else
m_convex_hull . reset ();
}
template < class Archive > void save ( Archive & ar ) const {
bool has_convex_hull = m_convex_hull . get () != nullptr ;
2020-09-24 15:34:13 +02:00
ar ( name , source , m_mesh , m_type , m_material_id , m_transformation , m_is_splittable , has_convex_hull );
2020-10-09 13:09:03 +02:00
cereal :: save_by_value ( ar , supported_facets );
cereal :: save_by_value ( ar , seam_facets );
2021-04-19 07:01:11 +02:00
cereal :: save_by_value ( ar , mmu_segmentation_facets );
2019-09-19 09:09:11 +02:00
cereal :: save_by_value ( ar , config );
2019-07-18 11:51:06 +02:00
if ( has_convex_hull )
cereal :: save_optional ( ar , m_convex_hull );
2019-06-26 16:29:12 +02:00
}
2014-01-06 18:29:10 +01:00
};
2021-05-19 09:38:51 +02:00
inline void model_volumes_sort_by_id ( ModelVolumePtrs & model_volumes )
{
std :: sort ( model_volumes . begin (), model_volumes . end (), []( const ModelVolume * l , const ModelVolume * r ) { return l -> id () < r -> id (); });
}
inline const ModelVolume * model_volume_find_by_id ( const ModelVolumePtrs & model_volumes , const ObjectID id )
{
auto it = lower_bound_by_predicate ( model_volumes . begin (), model_volumes . end (), [ id ]( const ModelVolume * mv ) { return mv -> id () < id ; });
2021-05-21 17:57:37 +02:00
return it != model_volumes . end () && ( * it ) -> id () == id ? * it : nullptr ;
2021-05-19 09:38:51 +02:00
}
2020-05-24 00:01:34 +02:00
enum ModelInstanceEPrintVolumeState : unsigned char
{
ModelInstancePVS_Inside ,
ModelInstancePVS_Partly_Outside ,
ModelInstancePVS_Fully_Outside ,
ModelInstanceNum_BedStates
};
2016-09-13 13:30:00 +02:00
// A single instance of a ModelObject.
// Knows the affine transformation of an object.
2019-07-02 16:42:23 +02:00
class ModelInstance final : public ObjectBase
2014-01-06 18:29:10 +01:00
{
2018-09-13 15:15:00 +02:00
private :
2018-10-31 14:56:51 +01:00
Geometry :: Transformation m_transformation ;
2018-09-13 15:15:00 +02:00
public :
2018-07-18 14:26:42 +02:00
// flag showing the position of this instance with respect to the print volume (set by Print::validate() using ModelObject::check_instances_print_volume_state())
2020-05-24 00:01:34 +02:00
ModelInstanceEPrintVolumeState print_volume_state ;
2019-07-31 08:36:08 +02:00
// Whether or not this instance is printable
bool printable ;
2018-07-18 09:37:25 +02:00
2018-06-28 16:14:17 +02:00
ModelObject * get_object () const { return this -> object ; }
2016-09-13 13:30:00 +02:00
2018-10-31 14:56:51 +01:00
const Geometry :: Transformation & get_transformation () const { return m_transformation ; }
2019-07-18 12:58:28 +02:00
void set_transformation ( const Geometry :: Transformation & transformation ) { m_transformation = transformation ; }
2018-10-31 14:56:51 +01:00
const Vec3d & get_offset () const { return m_transformation . get_offset (); }
double get_offset ( Axis axis ) const { return m_transformation . get_offset ( axis ); }
2019-07-17 13:32:31 +02:00
2018-10-31 14:56:51 +01:00
void set_offset ( const Vec3d & offset ) { m_transformation . set_offset ( offset ); }
void set_offset ( Axis axis , double offset ) { m_transformation . set_offset ( axis , offset ); }
const Vec3d & get_rotation () const { return m_transformation . get_rotation (); }
double get_rotation ( Axis axis ) const { return m_transformation . get_rotation ( axis ); }
2019-07-18 12:58:28 +02:00
void set_rotation ( const Vec3d & rotation ) { m_transformation . set_rotation ( rotation ); }
void set_rotation ( Axis axis , double rotation ) { m_transformation . set_rotation ( axis , rotation ); }
2018-10-31 14:56:51 +01:00
2019-01-28 08:52:22 +01:00
const Vec3d & get_scaling_factor () const { return m_transformation . get_scaling_factor (); }
2018-10-31 14:56:51 +01:00
double get_scaling_factor ( Axis axis ) const { return m_transformation . get_scaling_factor ( axis ); }
2019-07-18 12:58:28 +02:00
void set_scaling_factor ( const Vec3d & scaling_factor ) { m_transformation . set_scaling_factor ( scaling_factor ); }
void set_scaling_factor ( Axis axis , double scaling_factor ) { m_transformation . set_scaling_factor ( axis , scaling_factor ); }
2018-10-31 14:56:51 +01:00
const Vec3d & get_mirror () const { return m_transformation . get_mirror (); }
double get_mirror ( Axis axis ) const { return m_transformation . get_mirror ( axis ); }
2019-04-02 13:54:23 +02:00
bool is_left_handed () const { return m_transformation . is_left_handed (); }
2019-07-15 17:30:44 +02:00
2019-07-18 12:58:28 +02:00
void set_mirror ( const Vec3d & mirror ) { m_transformation . set_mirror ( mirror ); }
void set_mirror ( Axis axis , double mirror ) { m_transformation . set_mirror ( axis , mirror ); }
2018-09-20 15:00:40 +02:00
2016-09-13 13:30:00 +02:00
// To be called on an external mesh
2014-08-03 20:33:16 +02:00
void transform_mesh ( TriangleMesh * mesh , bool dont_translate = false ) const ;
2016-11-16 11:53:29 +01:00
// Calculate a bounding box of a transformed mesh. To be called on an external mesh.
2018-11-09 10:31:58 +01:00
BoundingBoxf3 transform_mesh_bounding_box ( const TriangleMesh & mesh , bool dont_translate = false ) const ;
2016-11-16 11:53:29 +01:00
// Transform an external bounding box.
BoundingBoxf3 transform_bounding_box ( const BoundingBoxf3 & bbox , bool dont_translate = false ) const ;
2018-09-06 09:16:32 +02:00
// Transform an external vector.
Vec3d transform_vector ( const Vec3d & v , bool dont_translate = false ) const ;
2016-09-13 13:30:00 +02:00
// To be called on an external polygon. It does not translate the polygon, only rotates and scales.
2014-01-06 18:29:10 +01:00
void transform_polygon ( Polygon * polygon ) const ;
2018-07-18 14:26:42 +02:00
2018-11-01 14:25:10 +01:00
const Transform3d & get_matrix ( bool dont_translate = false , bool dont_rotate = false , bool dont_scale = false , bool dont_mirror = false ) const { return m_transformation . get_matrix ( dont_translate , dont_rotate , dont_scale , dont_mirror ); }
2018-09-04 14:42:14 +02:00
2020-05-24 00:01:34 +02:00
bool is_printable () const { return object -> printable && printable && ( print_volume_state == ModelInstancePVS_Inside ); }
2019-07-31 08:36:08 +02:00
2019-06-28 17:03:50 +02:00
// Getting the input polygon for arrange
2019-07-12 21:03:49 +02:00
arrangement :: ArrangePolygon get_arrange_polygon () const ;
2019-06-28 17:03:50 +02:00
// Apply the arrange result on the ModelInstance
2020-03-30 13:26:24 +02:00
void apply_arrange_result ( const Vec2d & offs , double rotation )
2019-06-27 21:13:44 +02:00
{
// write the transformation data into the model instance
2019-07-17 13:32:31 +02:00
set_rotation ( Z , rotation );
set_offset ( X , unscale < double > ( offs ( X )));
set_offset ( Y , unscale < double > ( offs ( Y )));
2020-01-28 11:11:45 +01:00
this -> object -> invalidate_bounding_box ();
2019-06-27 21:13:44 +02:00
}
2018-07-18 14:26:42 +02:00
2018-11-02 19:49:40 +01:00
protected :
friend class Print ;
2018-11-21 17:35:35 +01:00
friend class SLAPrint ;
2019-07-04 10:45:41 +02:00
friend class Model ;
2018-11-02 19:49:40 +01:00
friend class ModelObject ;
explicit ModelInstance ( const ModelInstance & rhs ) = default ;
void set_model_object ( ModelObject * model_object ) { object = model_object ; }
2016-09-13 13:30:00 +02:00
private :
// Parent object, owning this instance.
2014-05-09 14:24:35 +02:00
ModelObject * object ;
2017-06-13 11:35:24 +02:00
2018-11-02 19:49:40 +01:00
// Constructor, which assigns a new unique ID.
2020-05-24 00:01:34 +02:00
explicit ModelInstance ( ModelObject * object ) : print_volume_state ( ModelInstancePVS_Inside ), printable ( true ), object ( object ) { assert ( this -> id (). valid ()); }
2018-11-02 19:49:40 +01:00
// Constructor, which assigns a new unique ID.
2018-11-02 20:41:49 +01:00
explicit ModelInstance ( ModelObject * object , const ModelInstance & other ) :
2020-05-24 00:01:34 +02:00
m_transformation ( other . m_transformation ), print_volume_state ( ModelInstancePVS_Inside ), printable ( other . printable ), object ( object ) { assert ( this -> id (). valid () && this -> id () != other . id ()); }
2017-06-13 11:35:24 +02:00
2018-11-02 19:49:40 +01:00
explicit ModelInstance ( ModelInstance && rhs ) = delete ;
ModelInstance & operator = ( const ModelInstance & rhs ) = delete ;
ModelInstance & operator = ( ModelInstance && rhs ) = delete ;
2019-06-26 16:29:12 +02:00
friend class cereal :: access ;
2019-07-02 16:42:23 +02:00
friend class UndoRedo :: StackImpl ;
2019-07-03 13:43:54 +02:00
// Used for deserialization, therefore no IDs are allocated.
ModelInstance () : ObjectBase ( - 1 ), object ( nullptr ) { assert ( this -> id (). invalid ()); }
2019-06-26 16:29:12 +02:00
template < class Archive > void serialize ( Archive & ar ) {
2019-07-31 08:36:08 +02:00
ar ( m_transformation , print_volume_state , printable );
}
2018-10-30 15:24:36 +01:00
};
2017-06-13 11:35:24 +02:00
2020-05-24 00:01:34 +02:00
2019-07-19 15:29:04 +02:00
class ModelWipeTower final : public ObjectBase
{
public :
Vec2d position ;
double rotation ;
private :
friend class cereal :: access ;
friend class UndoRedo :: StackImpl ;
friend class Model ;
// Constructors to be only called by derived classes.
// Default constructor to assign a unique ID.
explicit ModelWipeTower () {}
// Constructor with ignored int parameter to assign an invalid ID, to be replaced
// by an existing ID copied from elsewhere.
explicit ModelWipeTower ( int ) : ObjectBase ( - 1 ) {}
// Copy constructor copies the ID.
explicit ModelWipeTower ( const ModelWipeTower & cfg ) = default ;
// Disabled methods.
ModelWipeTower ( ModelWipeTower && rhs ) = delete ;
ModelWipeTower & operator = ( const ModelWipeTower & rhs ) = delete ;
ModelWipeTower & operator = ( ModelWipeTower && rhs ) = delete ;
// For serialization / deserialization of ModelWipeTower composed into another class into the Undo / Redo stack as a separate object.
template < typename Archive > void serialize ( Archive & ar ) { ar ( position , rotation ); }
};
2017-06-13 11:35:24 +02:00
// 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.
2019-07-02 16:42:23 +02:00
class Model final : public ObjectBase
2017-06-13 11:35:24 +02:00
{
public :
// Materials are owned by a model and referenced by objects through t_model_material_id.
// Single material may be shared by multiple models.
2018-11-02 14:47:13 +01:00
ModelMaterialMap materials ;
2017-06-13 11:35:24 +02:00
// Objects are owned by a model. Each model may have multiple instances, each instance having its own transformation (shift, scale, rotation).
2018-11-02 14:47:13 +01:00
ModelObjectPtrs objects ;
2019-07-19 15:29:04 +02:00
// Wipe tower object.
ModelWipeTower wipe_tower ;
2019-10-10 16:03:58 +02:00
2019-10-11 10:39:54 +02:00
// Extensions for color print
2020-01-23 12:49:39 +01:00
CustomGCode :: Info custom_gcode_per_print_z ;
2014-05-09 14:24:35 +02:00
2018-11-02 14:47:13 +01:00
// Default constructor assigns a new ID to the model.
2019-07-03 13:43:54 +02:00
Model () { assert ( this -> id (). valid ()); }
2017-08-02 16:05:18 +02:00
~ Model () { this -> clear_objects (); this -> clear_materials (); }
2018-11-02 19:49:40 +01:00
/* To be able to return an object from own copy / clone methods. Hopefully the compiler will do the "Copy elision" */
/* (Omits copy and move(since C++11) constructors, resulting in zero - copy pass - by - value semantics). */
2019-07-03 13:43:54 +02:00
Model ( const Model & rhs ) : ObjectBase ( - 1 ) { assert ( this -> id (). invalid ()); this -> assign_copy ( rhs ); assert ( this -> id (). valid ()); assert ( this -> id () == rhs . id ()); }
explicit Model ( Model && rhs ) : ObjectBase ( - 1 ) { assert ( this -> id (). invalid ()); this -> assign_copy ( std :: move ( rhs )); assert ( this -> id (). valid ()); assert ( this -> id () == rhs . id ()); }
Model & operator = ( const Model & rhs ) { this -> assign_copy ( rhs ); assert ( this -> id (). valid ()); assert ( this -> id () == rhs . id ()); return * this ; }
Model & operator = ( Model && rhs ) { this -> assign_copy ( std :: move ( rhs )); assert ( this -> id (). valid ()); assert ( this -> id () == rhs . id ()); return * this ; }
2018-11-02 19:49:40 +01:00
2019-06-27 11:02:45 +02:00
OBJECTBASE_DERIVED_COPY_MOVE_CLONE ( Model )
2018-11-02 14:47:13 +01:00
2021-06-27 16:04:23 +02:00
enum class LoadAttribute : int {
AddDefaultInstances ,
CheckVersion
};
using LoadAttributes = enum_bitmask < LoadAttribute > ;
static Model read_from_file (
const std :: string & input_file ,
DynamicPrintConfig * config = nullptr , ConfigSubstitutionContext * config_substitutions = nullptr ,
LoadAttributes options = LoadAttribute :: AddDefaultInstances );
static Model read_from_archive (
const std :: string & input_file ,
DynamicPrintConfig * config , ConfigSubstitutionContext * config_substitutions ,
LoadAttributes options = LoadAttribute :: AddDefaultInstances );
2017-08-02 16:05:18 +02:00
2018-11-02 14:47:13 +01:00
// Add a new ModelObject to this Model, generate a new ID for this ModelObject.
2017-06-13 11:35:24 +02:00
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 );
2018-11-02 14:47:13 +01:00
ModelObject * add_object ( const ModelObject & other );
void delete_object ( size_t idx );
2019-06-27 11:02:45 +02:00
bool delete_object ( ObjectID id );
2018-11-02 19:49:40 +01:00
bool delete_object ( ModelObject * object );
2018-11-02 14:47:13 +01:00
void clear_objects ();
2018-10-18 15:13:38 +02:00
2017-06-13 11:35:24 +02:00
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 ;
}
2018-11-02 19:49:40 +01:00
void delete_material ( t_model_material_id material_id );
void clear_materials ();
bool add_default_instances ();
2018-03-09 10:40:42 +01:00
// Returns approximate axis aligned bounding box of this model
BoundingBoxf3 bounding_box () const ;
2018-10-23 15:27:31 +02:00
// Set the print_volume_state of PrintObject::instances,
// return total number of printable objects.
2019-06-26 16:29:12 +02:00
unsigned int update_print_volume_state ( const BoundingBoxf3 & print_volume );
2018-11-08 20:18:40 +01:00
// Returns true if any ModelObject was modified.
2019-06-26 16:29:12 +02:00
bool center_instances_around_point ( const Vec2d & 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 ;
2020-04-23 18:19:03 +02:00
2017-06-13 11:35:24 +02:00
// Croaks if the duplicated objects do not fit the print bed.
2020-04-23 18:19:03 +02:00
void duplicate_objects_grid ( size_t x , size_t y , coordf_t dist );
2017-08-02 16:05:18 +02:00
2019-06-26 16:29:12 +02:00
bool looks_like_multipart_object () const ;
void convert_multipart_object ( unsigned int max_extruders );
2020-04-29 19:10:13 +02:00
bool looks_like_imperial_units () const ;
2020-12-12 18:54:34 +01:00
void convert_from_imperial_units ( bool only_small_volumes );
2021-02-09 17:04:32 +01:00
bool looks_like_saved_in_meters () const ;
void convert_from_meters ( bool only_small_volumes );
2017-08-02 16:05:18 +02:00
2018-03-06 10:26:39 +01:00
// Ensures that the min z of the model is not negative
2019-06-26 16:29:12 +02:00
void adjust_min_z ();
2018-03-06 10:26:39 +01:00
2019-06-26 16:29:12 +02:00
void print_info () const { for ( const ModelObject * o : this -> objects ) o -> print_info (); }
2018-04-10 12:17:55 +02:00
2019-02-03 10:41:14 +01:00
// Propose an output file name & path based on the first printable object's name and source input file's path.
2019-08-05 17:49:21 +02:00
std :: string propose_export_file_name_and_path () const ;
2019-03-13 15:44:50 +01:00
// Propose an output path, replace extension. The new_extension shall contain the initial dot.
2019-08-05 17:49:21 +02:00
std :: string propose_export_file_name_and_path ( const std :: string & new_extension ) const ;
2018-12-03 13:14:28 +01:00
2018-11-02 14:47:13 +01:00
private :
2020-04-22 11:16:28 +02:00
explicit Model ( int ) : ObjectBase ( - 1 ) { assert ( this -> id (). invalid ()); }
2019-07-03 13:43:54 +02:00
void assign_new_unique_ids_recursive ();
2019-07-04 10:45:41 +02:00
void update_links_bottom_up_recursive ();
2019-06-26 16:29:12 +02:00
friend class cereal :: access ;
2019-07-02 16:42:23 +02:00
friend class UndoRedo :: StackImpl ;
2019-06-26 16:29:12 +02:00
template < class Archive > void serialize ( Archive & ar ) {
2019-07-19 15:29:04 +02:00
Internal :: StaticSerializationWrapper < ModelWipeTower > wipe_tower_wrapper ( wipe_tower );
ar ( materials , objects , wipe_tower_wrapper );
2020-04-23 18:19:03 +02:00
}
2014-01-06 18:29:10 +01:00
};
2021-06-27 16:04:23 +02:00
ENABLE_ENUM_BITMASK_OPERATORS ( Model :: LoadAttribute )
2019-06-27 11:02:45 +02:00
#undef OBJECTBASE_DERIVED_COPY_MOVE_CLONE
#undef OBJECTBASE_DERIVED_PRIVATE_COPY_MOVE
2018-11-02 14:47:13 +01:00
2018-11-21 17:35:35 +01:00
// Test whether the two models contain the same number of ModelObjects with the same set of IDs
// ordered in the same order. In that case it is not necessary to kill the background processing.
2021-05-26 12:41:06 +02:00
bool model_object_list_equal ( const Model & model_old , const Model & model_new );
2018-11-21 17:35:35 +01:00
// Test whether the new model is just an extension of the old model (new objects were added
// to the end of the original list. In that case it is not necessary to kill the background processing.
2021-05-26 12:41:06 +02:00
bool model_object_list_extended ( const Model & model_old , const Model & model_new );
2018-11-21 17:35:35 +01:00
// Test whether the new ModelObject contains a different set of volumes (or sorted in a different order)
// than the old ModelObject.
2021-05-26 12:41:06 +02:00
bool model_volume_list_changed ( const ModelObject & model_object_old , const ModelObject & model_object_new , const ModelVolumeType type );
bool model_volume_list_changed ( const ModelObject & model_object_old , const ModelObject & model_object_new , const std :: initializer_list < ModelVolumeType > & types );
2018-11-21 17:35:35 +01:00
2020-04-22 11:16:28 +02:00
// Test whether the now ModelObject has newer custom supports data than the old one.
// The function assumes that volumes list is synchronized.
2021-05-26 12:41:06 +02:00
bool model_custom_supports_data_changed ( const ModelObject & mo , const ModelObject & mo_new );
2020-08-31 07:25:43 +02:00
// Test whether the now ModelObject has newer custom seam data than the old one.
// The function assumes that volumes list is synchronized.
2021-05-26 12:41:06 +02:00
bool model_custom_seam_data_changed ( const ModelObject & mo , const ModelObject & mo_new );
2020-04-22 11:16:28 +02:00
2021-04-19 07:01:11 +02:00
// Test whether the now ModelObject has newer MMU segmentation data than the old one.
// The function assumes that volumes list is synchronized.
extern bool model_mmu_segmentation_data_changed ( const ModelObject & mo , const ModelObject & mo_new );
2020-04-22 11:16:28 +02:00
2019-07-18 17:41:47 +02:00
// If the model has multi-part objects, then it is currently not supported by the SLA mode.
// Either the model cannot be loaded, or a SLA printer has to be activated.
2021-05-26 12:41:06 +02:00
bool model_has_multi_part_objects ( const Model & model );
2019-07-18 17:41:47 +02:00
// If the model has advanced features, then it cannot be processed in simple mode.
2021-05-26 12:41:06 +02:00
bool model_has_advanced_features ( const Model & model );
2019-07-18 17:41:47 +02:00
2019-01-31 08:47:23 +01:00
#ifndef NDEBUG
2018-11-16 18:28:50 +01:00
// Verify whether the IDs of Model / ModelObject / ModelVolume / ModelInstance / ModelMaterial are valid and unique.
void check_model_ids_validity ( const Model & model );
void check_model_ids_equal ( const Model & model1 , const Model & model2 );
2019-01-31 08:47:23 +01:00
#endif /* NDEBUG */
2018-11-16 18:28:50 +01:00
2021-06-08 10:07:47 +02:00
#if ENABLE_ALLOW_NEGATIVE_Z
static const float SINKING_Z_THRESHOLD = - 0.001f ;
#endif // ENABLE_ALLOW_NEGATIVE_Z
2019-06-27 11:02:45 +02:00
} // namespace Slic3r
2014-01-06 18:29:10 +01:00
2019-07-18 11:51:06 +02:00
namespace cereal
{
template < class Archive > struct specialize < Archive , Slic3r :: ModelVolume , cereal :: specialization :: member_load_save > {};
2020-09-24 15:34:13 +02:00
template < class Archive > struct specialize < Archive , Slic3r :: ModelConfigObject , cereal :: specialization :: member_serialize > {};
2019-07-18 11:51:06 +02:00
}
2019-06-27 11:02:45 +02:00
#endif /* slic3r_Model_hpp_ */