2014-01-06 17:29:10 +00:00
# ifndef slic3r_Model_hpp_
# define slic3r_Model_hpp_
2015-12-07 23:39:54 +00:00
# include "libslic3r.h"
2021-06-27 15:36:25 +00:00
# include "enum_bitmask.hpp"
2019-06-27 09:02:45 +00:00
# include "Geometry.hpp"
# include "ObjectID.hpp"
2014-01-06 17:29:10 +00:00
# include "Point.hpp"
2019-06-27 09:02:45 +00:00
# include "PrintConfig.hpp"
2016-12-08 18:02:16 +00:00
# include "Slicing.hpp"
2019-11-11 10:41:14 +00:00
# include "SLA/SupportPoint.hpp"
# include "SLA/Hollowing.hpp"
2019-06-27 09:02:45 +00:00
# include "TriangleMesh.hpp"
2019-07-01 16:22:07 +00:00
# include "Arrange.hpp"
2020-01-23 11:49:39 +00:00
# include "CustomGCode.hpp"
Support for forward compatibility of configurations, user and system
config bundles, project files (3MFs, AMFs). When loading these files,
the caller may decide whether to substitute some of the configuration
values the current PrusaSlicer version does not understand with
some reasonable default value, and whether to report it. If substitution
is disabled, an exception is being thrown as before this commit.
If substitution is enabled, list of substitutions is returned by the
API to be presented to the user. This allows us to introduce for example
new firmware flavor key in PrusaSlicer 2.4 while letting PrusaSlicer
2.3.2 to fall back to some default and to report it to the user.
When slicing from command line, substutions are performed by default
and reported into the console, however substitutions may be either
disabled or made silent with the new "config-compatibility" command
line option.
Substitute enums and bools only. Allow booleans to be parsed as
true: "1", "enabled", "on" case insensitive
false: "0", "disabled", "off" case insensitive
This will allow us in the future for example to switch the draft_shield
boolean to an enum with the following values: "disabled" / "enabled" / "limited".
Added "enum_bitmask.hpp" - support for type safe sets of options.
See for example PresetBundle::load_configbundle(...
LoadConfigBundleAttributes flags) for an example of intended usage.
WIP: GUI for reporting the list of config substitutions needs to be
implemented by @YuSanka.
2021-06-27 14:04:23 +00:00
# include "enum_bitmask.hpp"
2019-06-11 15:08:47 +00:00
2014-01-06 17:29:10 +00:00
# include <map>
2019-06-11 15:08:47 +00:00
# include <memory>
2014-01-06 17:29:10 +00:00
# include <string>
# include <utility>
# include <vector>
2019-07-18 10:07:50 +00: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 13:29:04 +00: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 10:07:50 +00:00
}
2014-01-06 17:29:10 +00:00
namespace Slic3r {
2021-02-10 19:31:17 +00:00
enum class ConversionType ;
2014-01-06 17:29:10 +00:00
2017-06-13 10:09:49 +00:00
class Model ;
2014-01-06 17:29:10 +00:00
class ModelInstance ;
class ModelMaterial ;
class ModelObject ;
class ModelVolume ;
2019-07-19 13:29:04 +00:00
class ModelWipeTower ;
2018-10-17 09:12:38 +00:00
class Print ;
2018-11-21 16:35:35 +00:00
class SLAPrint ;
2020-07-09 14:25:34 +00:00
class TriangleSelector ;
2014-01-06 17:29:10 +00:00
2019-07-02 14:42:23 +00:00
namespace UndoRedo {
class StackImpl ;
}
2019-04-26 15:28:31 +00:00
2020-09-24 13:34:13 +00:00
class ModelConfigObject : public ObjectBase , public ModelConfig
2018-10-17 09:12:38 +00:00
{
2019-07-03 11:43:54 +00:00
private :
friend class cereal : : access ;
friend class UndoRedo : : StackImpl ;
friend class ModelObject ;
friend class ModelVolume ;
friend class ModelMaterial ;
2018-10-17 09:12:38 +00:00
2018-11-02 13:47:13 +00:00
// Constructors to be only called by derived classes.
// Default constructor to assign a unique ID.
2020-10-15 15:29:42 +00:00
explicit ModelConfigObject ( ) = default ;
2018-11-02 13:47:13 +00:00
// Constructor with ignored int parameter to assign an invalid ID, to be replaced
// by an existing ID copied from elsewhere.
2020-09-24 13:34:13 +00:00
explicit ModelConfigObject ( int ) : ObjectBase ( - 1 ) { }
2019-07-03 11:43:54 +00:00
// Copy constructor copies the ID.
2020-10-15 15:29:42 +00:00
explicit ModelConfigObject ( const ModelConfigObject & cfg ) = default ;
2019-07-03 11:43:54 +00:00
// Move constructor copies the ID.
2020-10-15 15:29:42 +00:00
explicit ModelConfigObject ( ModelConfigObject & & cfg ) = default ;
2019-07-03 11:43:54 +00:00
2020-09-24 13:34:13 +00: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 11:43:54 +00:00
2020-09-24 13:34:13 +00: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 11:43:54 +00:00
} ;
2018-10-17 09:12:38 +00:00
2019-07-19 13:29:04 +00: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 17:29:10 +00:00
typedef std : : string t_model_material_id ;
typedef std : : string t_model_material_attribute ;
2018-11-02 13:47:13 +00:00
typedef std : : map < t_model_material_attribute , std : : string > t_model_material_attributes ;
typedef std : : map < t_model_material_id , ModelMaterial * > ModelMaterialMap ;
2014-04-29 23:04:49 +00:00
typedef std : : vector < ModelObject * > ModelObjectPtrs ;
typedef std : : vector < ModelVolume * > ModelVolumePtrs ;
typedef std : : vector < ModelInstance * > ModelInstancePtrs ;
2018-10-17 09:12:38 +00:00
2019-06-27 09:02:45 +00:00
# define OBJECTBASE_DERIVED_COPY_MOVE_CLONE(TYPE) \
2018-11-02 13:47:13 +00: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 11:43:54 +00: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 13:47:13 +00: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 18:49:40 +00:00
static TYPE * new_clone ( const TYPE & rhs ) { \
2018-11-02 13:47:13 +00:00
/* Default constructor assigning an invalid ID. */ \
auto obj = new TYPE ( - 1 ) ; \
obj - > assign_clone ( rhs ) ; \
2019-07-03 11:43:54 +00:00
assert ( obj - > id ( ) . valid ( ) & & obj - > id ( ) ! = rhs . id ( ) ) ; \
2018-11-02 13:47:13 +00: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 11:43:54 +00:00
assert ( obj . id ( ) . valid ( ) & & obj . id ( ) ! = rhs . id ( ) ) ; \
2018-11-02 13:47:13 +00:00
return obj ; \
} \
TYPE & assign_clone ( const TYPE & rhs ) { \
this - > assign_copy ( rhs ) ; \
2019-07-03 11:43:54 +00:00
assert ( this - > id ( ) . valid ( ) & & this - > id ( ) = = rhs . id ( ) ) ; \
2018-11-02 13:47:13 +00:00
this - > assign_new_unique_ids_recursive ( ) ; \
2019-07-03 11:43:54 +00:00
assert ( this - > id ( ) . valid ( ) & & this - > id ( ) ! = rhs . id ( ) ) ; \
2018-11-02 13:47:13 +00:00
return * this ; \
}
2016-09-13 11:30:00 +00:00
// Material, which may be shared across multiple ModelObjects of a single Model.
2019-07-02 14:42:23 +00:00
class ModelMaterial final : public ObjectBase
2014-01-06 17:29:10 +00:00
{
2016-09-13 11:30:00 +00: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 17:29:10 +00:00
t_model_material_attributes attributes ;
2016-09-13 11:30:00 +00:00
// Dynamic configuration storage for the object specific configuration values, overriding the global configuration.
2020-09-24 13:34:13 +00:00
ModelConfigObject config ;
2014-04-29 23:04:49 +00:00
2017-06-13 10:09:49 +00:00
Model * get_model ( ) const { return m_model ; }
2017-06-13 09:35:24 +00:00
void apply ( const t_model_material_attributes & attributes )
{ this - > attributes . insert ( attributes . begin ( ) , attributes . end ( ) ) ; }
2016-09-13 11:30:00 +00:00
private :
// Parent, owning this material.
2017-06-13 09:35:24 +00:00
Model * m_model ;
2019-07-03 11:43:54 +00:00
// To be accessed by the Model.
2018-11-02 18:49:40 +00:00
friend class Model ;
2019-07-03 11:43:54 +00:00
// 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!
2018-11-02 18:49:40 +00:00
ModelMaterial ( const ModelMaterial & rhs ) = default ;
void set_model ( Model * model ) { m_model = model ; }
2019-07-03 11:43:54 +00:00
void set_new_unique_id ( ) { ObjectBase : : set_new_unique_id ( ) ; this - > config . set_new_unique_id ( ) ; }
2018-11-02 18:49:40 +00:00
2019-07-03 11:43:54 +00:00
// 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 13:34:13 +00:00
Internal : : StaticSerializationWrapper < ModelConfigObject > config_wrapper ( config ) ;
2019-07-19 13:29:04 +00:00
ar ( attributes , config_wrapper ) ;
2019-07-03 11:43:54 +00:00
// assert(this->id().valid()); assert(this->config.id().valid());
}
// Disabled methods.
2018-11-02 18:49:40 +00:00
ModelMaterial ( ModelMaterial & & rhs ) = delete ;
ModelMaterial & operator = ( const ModelMaterial & rhs ) = delete ;
ModelMaterial & operator = ( ModelMaterial & & rhs ) = delete ;
2014-01-06 17:29:10 +00:00
} ;
2020-09-24 13:34:13 +00:00
class LayerHeightProfile final : public ObjectWithTimestamp {
public :
2020-10-15 15:29:42 +00:00
// Assign the content if the timestamp differs, don't assign an ObjectID.
2021-05-06 12:43:36 +00: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 15:29:42 +00:00
2020-09-24 13:34:13 +00: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 15:29:42 +00: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 13:34:13 +00:00
std : : vector < coordf_t > m_data ;
2020-10-09 10:25:57 +00:00
// to access set_new_unique_id() when copy / pasting an object
friend class ModelObject ;
2020-09-24 13:34:13 +00:00
} ;
2021-05-26 13:36:02 +00: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 15:36:25 +00:00
enum class ModelObjectCutAttribute : int { KeepUpper , KeepLower , FlipLower } ;
using ModelObjectCutAttributes = enum_bitmask < ModelObjectCutAttribute > ;
ENABLE_ENUM_BITMASK_OPERATORS ( ModelObjectCutAttribute ) ;
2016-09-13 11:30:00 +00: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 14:42:23 +00:00
class ModelObject final : public ObjectBase
2014-01-06 17:29:10 +00:00
{
2016-09-13 11:30:00 +00:00
public :
2017-06-13 09:35:24 +00:00
std : : string name ;
2018-09-17 10:15:11 +00:00
std : : string input_file ; // XXX: consider fs::path
2016-09-13 11:30:00 +00: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 09:35:24 +00:00
ModelInstancePtrs instances ;
2016-09-13 11:30:00 +00: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 09:35:24 +00:00
ModelVolumePtrs volumes ;
2016-09-13 11:30:00 +00:00
// Configuration parameters specific to a single ModelObject, overriding the global Slic3r settings.
2020-09-24 13:34:13 +00:00
ModelConfigObject config ;
2019-06-20 14:15:09 +00:00
// Variation of a layer thickness for spans of Z coordinates + optional parameter overrides.
t_layer_config_ranges layer_config_ranges ;
2017-02-07 17:17:12 +00:00
// Profile of increasing z to a layer height, to be linearly interpolated when calculating the layers.
2019-01-21 09:06:51 +00:00
// The pairs of <z, layer_height> are packed into a 1D array.
2020-09-24 13:34:13 +00:00
LayerHeightProfile layer_height_profile ;
2019-07-31 06:36:08 +00:00
// Whether or not this object is printable
bool printable ;
2018-09-19 12:59:57 +00: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 07:26:23 +00:00
// The format is (x, y, z, point_size, supports_island)
2019-11-13 14:55:37 +00:00
sla : : SupportPoints sla_support_points ;
2019-02-27 15:23:10 +00:00
// To keep track of where the points came from (used for synchronization between
// the SLA gizmo and the backend).
2019-11-13 14:55:37 +00:00
sla : : PointsStatus sla_points_status = sla : : PointsStatus : : NoPoints ;
2016-09-13 11:30:00 +00:00
2019-11-08 13:05:56 +00:00
// Holes to be drilled into the object so resin can flow out
2019-11-13 14:55:37 +00:00
sla : : DrainHoles sla_drain_holes ;
2019-11-08 13:05:56 +00:00
2014-10-25 09:10:44 +00: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-08 23:47:40 +00:00
to new volumes before adding them to this object in order to preserve alignment
2014-10-25 09:10:44 +00:00
when user expects that . */
2018-08-21 15:43:05 +00:00
Vec3d origin_translation ;
2018-10-17 09:12:38 +00:00
2020-04-22 09:16:28 +00:00
Model * get_model ( ) { return m_model ; }
const Model * get_model ( ) const { return m_model ; }
2018-11-08 13:23:17 +00:00
2018-10-17 09:12:38 +00:00
ModelVolume * add_volume ( const TriangleMesh & mesh ) ;
2021-05-26 13:36:02 +00:00
ModelVolume * add_volume ( TriangleMesh & & mesh , ModelVolumeType type = ModelVolumeType : : MODEL_PART ) ;
2021-05-28 11:02:18 +00:00
ModelVolume * add_volume ( const ModelVolume & volume , ModelVolumeType type = ModelVolumeType : : INVALID ) ;
2018-11-02 13:47:13 +00:00
ModelVolume * add_volume ( const ModelVolume & volume , TriangleMesh & & mesh ) ;
2018-10-17 09:12:38 +00:00
void delete_volume ( size_t idx ) ;
void clear_volumes ( ) ;
2021-06-02 10:52:47 +00:00
void sort_volumes ( bool full_sort ) ;
2018-10-23 09:26:15 +00:00
bool is_multiparts ( ) const { return volumes . size ( ) > 1 ; }
2018-10-17 09:12:38 +00:00
ModelInstance * add_instance ( ) ;
ModelInstance * add_instance ( const ModelInstance & instance ) ;
2019-01-03 14:04:29 +00:00
ModelInstance * add_instance ( const Vec3d & offset , const Vec3d & scaling_factor , const Vec3d & rotation , const Vec3d & mirror ) ;
2018-10-17 09:12:38 +00:00
void delete_instance ( size_t idx ) ;
void delete_last_instance ( ) ;
void clear_instances ( ) ;
2014-04-29 23:04:49 +00:00
2017-06-13 09:35:24 +00:00
// Returns the bounding box of the transformed instances.
// This bounding box is approximate and not snug.
2018-03-14 15:11:57 +00:00
// This bounding box is being cached.
2018-05-25 13:56:14 +00:00
const BoundingBoxf3 & bounding_box ( ) const ;
2019-04-13 12:15:54 +00: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-29 23:04:49 +00:00
2017-06-13 09:35:24 +00:00
// A mesh containing all transformed instances of this object.
2015-01-19 17:53:04 +00:00
TriangleMesh mesh ( ) const ;
2017-06-13 09:35:24 +00:00
// Non-transformed (non-rotated, non-scaled, non-translated) sum of non-modifier object volumes.
2019-12-03 03:48:01 +00:00
// Currently used by ModelObject::mesh() and to calculate the 2D envelope for 2D plater.
2015-01-19 17:53:04 +00:00
TriangleMesh raw_mesh ( ) const ;
2020-09-17 16:39:28 +00:00
// The same as above, but producing a lightweight indexed_triangle_set.
indexed_triangle_set raw_indexed_triangle_set ( ) const ;
2017-06-13 09:35:24 +00: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 12:15:54 +00:00
const BoundingBoxf3 & raw_bounding_box ( ) const ;
2017-06-13 09:35:24 +00: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 17:51:34 +00:00
// A snug bounding box of non-transformed (non-rotated, non-scaled, non-translated) sum of non-modifier object volumes.
2019-04-13 12:15:54 +00:00
const BoundingBoxf3 & raw_mesh_bounding_box ( ) const ;
2019-01-26 17:51:34 +00:00
// A snug bounding box of non-transformed (non-rotated, non-scaled, non-translated) sum of all object volumes.
2019-01-18 11:52:09 +00:00
BoundingBoxf3 full_raw_mesh_bounding_box ( ) const ;
2019-01-28 09:10:23 +00: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 10:45:43 +00:00
Polygon convex_hull_2d ( const Transform3d & trafo_instance ) const ;
2019-01-28 09:10:23 +00:00
2019-03-22 08:47:40 +00:00
void center_around_origin ( bool include_modifiers = true ) ;
2019-05-21 07:42:59 +00:00
2021-04-28 09:07:15 +00:00
# if ENABLE_ALLOW_NEGATIVE_Z
void ensure_on_bed ( bool allow_negative_z = false ) ;
# else
2018-10-30 15:03:03 +00:00
void ensure_on_bed ( ) ;
2021-04-28 09:07:15 +00:00
# endif // ENABLE_ALLOW_NEGATIVE_Z
2018-10-30 15:03:03 +00:00
void translate_instances ( const Vec3d & vector ) ;
void translate_instance ( size_t instance_idx , const Vec3d & vector ) ;
2018-08-21 15:43:05 +00:00
void translate ( const Vec3d & vector ) { this - > translate ( vector ( 0 ) , vector ( 1 ) , vector ( 2 ) ) ; }
2018-11-01 13:25:10 +00:00
void translate ( double x , double y , double z ) ;
2018-08-21 15:43:05 +00:00
void scale ( const Vec3d & versor ) ;
2018-09-20 14:48:13 +00:00
void scale ( const double s ) { this - > scale ( Vec3d ( s , s , s ) ) ; }
2018-11-02 13:41:08 +00:00
void scale ( double x , double y , double z ) { this - > scale ( Vec3d ( x , y , z ) ) ; }
2019-03-13 14:44:50 +00: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 07:31:54 +00:00
void rotate ( double angle , Axis axis ) ;
void rotate ( double angle , const Vec3d & axis ) ;
2018-11-05 07:51:00 +00:00
void mirror ( Axis axis ) ;
2018-12-19 08:54:15 +00:00
2019-06-11 15:08:47 +00:00
// This method could only be called before the meshes of this ModelVolumes are not shared!
2019-07-02 14:42:23 +00:00
void scale_mesh_after_creation ( const Vec3d & versor ) ;
2021-02-10 19:31:17 +00:00
void convert_units ( ModelObjectPtrs & new_objects , ConversionType conv_type , std : : vector < int > volume_idxs ) ;
2018-12-19 08:54:15 +00:00
2014-09-21 08:51:36 +00:00
size_t materials_count ( ) const ;
2014-08-08 19:48:59 +00:00
size_t facets_count ( ) const ;
bool needed_repair ( ) const ;
2021-06-27 15:36:25 +00:00
ModelObjectPtrs cut ( size_t instance , coordf_t z , ModelObjectCutAttributes attributes ) ;
2014-11-12 22:50:09 +00:00
void split ( ModelObjectPtrs * new_objects ) ;
2020-05-27 08:55:48 +00:00
void merge ( ) ;
2019-04-26 15:28:31 +00: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 12:26:42 +00:00
2018-10-30 15:03:03 +00:00
double get_min_z ( ) const ;
double get_instance_min_z ( size_t instance_idx ) const ;
2018-09-14 07:28:00 +00:00
// Called by Print::validate() from the UI thread.
2018-10-23 13:27:31 +00:00
unsigned int check_instances_print_volume_state ( const BoundingBoxf3 & print_volume ) ;
2017-08-02 14:05:18 +00:00
// Print object statistics to console.
void print_info ( ) const ;
2018-10-17 09:12:38 +00:00
2019-04-04 12:00:31 +00:00
std : : string get_export_filename ( ) const ;
2019-07-03 11:43:54 +00:00
// Get full stl statistics for all object's meshes
2019-04-24 14:04:47 +00:00
stl_stats get_object_stl_stats ( ) const ;
2019-07-03 11:43:54 +00:00
// Get count of errors in the mesh( or all object's meshes, if volume index isn't defined)
2019-04-24 14:04:47 +00:00
int get_mesh_errors_count ( const int vol_idx = - 1 ) const ;
2018-10-17 09:12:38 +00:00
private :
2019-07-03 11:43:54 +00:00
friend class Model ;
// This constructor assigns new ID to this ModelObject and its config.
2019-07-31 06:36:08 +00:00
explicit ModelObject ( Model * model ) : m_model ( model ) , printable ( true ) , origin_translation ( Vec3d : : Zero ( ) ) ,
2019-07-03 11:43:54 +00:00
m_bounding_box_valid ( false ) , m_raw_bounding_box_valid ( false ) , m_raw_mesh_bounding_box_valid ( false )
2020-10-15 15:29:42 +00: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 11:43:54 +00:00
~ ModelObject ( ) ;
2019-07-05 17:06:19 +00:00
void assign_new_unique_ids_recursive ( ) override ;
2019-07-03 11:43:54 +00: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 15:29:42 +00: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 11:43:54 +00:00
this - > assign_copy ( rhs ) ;
2020-10-15 15:29:42 +00: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 11:43:54 +00:00
}
2020-10-15 15:29:42 +00: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 11:43:54 +00:00
this - > assign_copy ( std : : move ( rhs ) ) ;
2020-10-15 15:29:42 +00: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 11:43:54 +00:00
}
2020-10-15 15:29:42 +00:00
ModelObject & operator = ( const ModelObject & rhs ) {
2019-07-03 11:43:54 +00:00
this - > assign_copy ( rhs ) ;
m_model = rhs . m_model ;
2020-10-15 15:29:42 +00: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 11:43:54 +00:00
return * this ;
}
2020-10-15 15:29:42 +00:00
ModelObject & operator = ( ModelObject & & rhs ) {
2019-07-03 11:43:54 +00:00
this - > assign_copy ( std : : move ( rhs ) ) ;
m_model = rhs . m_model ;
2020-10-15 15:29:42 +00: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 11:43:54 +00:00
return * this ;
}
2020-10-15 15:29:42 +00: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 18:49:40 +00:00
2019-06-27 09:02:45 +00:00
OBJECTBASE_DERIVED_COPY_MOVE_CLONE ( ModelObject )
2017-06-13 09:35:24 +00:00
2018-11-02 18:49:40 +00: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 06:37:04 +00:00
2018-11-02 18:49:40 +00:00
// Bounding box, cached.
2018-05-25 13:56:14 +00:00
mutable BoundingBoxf3 m_bounding_box ;
mutable bool m_bounding_box_valid ;
2019-04-13 12:15:54 +00:00
mutable BoundingBoxf3 m_raw_bounding_box ;
mutable bool m_raw_bounding_box_valid ;
2019-01-26 17:51:34 +00:00
mutable BoundingBoxf3 m_raw_mesh_bounding_box ;
2019-06-26 14:29:12 +00:00
mutable bool m_raw_mesh_bounding_box_valid ;
2019-07-02 14:42:23 +00: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 14:29:12 +00:00
friend class cereal : : access ;
2019-07-02 14:42:23 +00:00
friend class UndoRedo : : StackImpl ;
2019-07-03 11:43:54 +00:00
// Used for deserialization -> Don't allocate any IDs for the ModelObject or its config.
2020-10-15 15:29:42 +00: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 11:43:54 +00:00
}
template < class Archive > void serialize ( Archive & ar ) {
2019-06-27 09:02:45 +00:00
ar ( cereal : : base_class < ObjectBase > ( this ) ) ;
2020-09-24 13:34:13 +00: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 06:36:08 +00: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 14:29:12 +00:00
}
2014-01-06 17:29:10 +00:00
} ;
2020-08-05 12:03:22 +00:00
enum class EnforcerBlockerType : int8_t {
2021-06-20 13:21:12 +00:00
// Maximum is 3. The value is serialized in TriangleSelector into 2 bits.
2020-04-16 12:42:42 +00:00
NONE = 0 ,
ENFORCER = 1 ,
2021-06-20 13:21:12 +00:00
BLOCKER = 2 ,
// Maximum is 15. The value is serialized in TriangleSelector into 6 bits using a 2 bit prefix code.
Extruder1 = ENFORCER ,
Extruder2 = BLOCKER ,
Extruder3 ,
Extruder4 ,
Extruder5 ,
Extruder6 ,
Extruder7 ,
Extruder8 ,
Extruder9 ,
Extruder10 ,
Extruder11 ,
Extruder12 ,
Extruder13 ,
Extruder14 ,
Extruder15 ,
2020-04-16 12:42:42 +00:00
} ;
2021-02-10 19:31:17 +00:00
enum class ConversionType : int {
CONV_TO_INCH ,
CONV_FROM_INCH ,
CONV_TO_METER ,
CONV_FROM_METER ,
} ;
2020-09-24 13:34:13 +00:00
class FacetsAnnotation final : public ObjectWithTimestamp {
2020-04-16 12:42:42 +00:00
public :
2020-10-15 15:29:42 +00:00
// Assign the content if the timestamp differs, don't assign an ObjectID.
2021-05-06 12:43:36 +00: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 07:26:01 +00:00
const std : : pair < std : : vector < std : : pair < int , int > > , std : : vector < bool > > & get_data ( ) const throw ( ) { return m_data ; }
2020-07-15 10:28:52 +00:00
bool set ( const TriangleSelector & selector ) ;
2020-08-05 12:03:22 +00:00
indexed_triangle_set get_facets ( const ModelVolume & mv , EnforcerBlockerType type ) const ;
2021-06-20 13:21:12 +00:00
indexed_triangle_set get_facets_strict ( const ModelVolume & mv , EnforcerBlockerType type ) const ;
bool has_facets ( const ModelVolume & mv , EnforcerBlockerType type ) const ;
2021-06-10 07:26:01 +00:00
bool empty ( ) const { return m_data . first . empty ( ) ; }
2020-04-16 12:42:42 +00:00
void clear ( ) ;
2021-06-10 07:26:01 +00:00
// Serialize triangle into string, for serialization into 3MF/AMF.
2020-07-24 14:53:05 +00:00
std : : string get_triangle_as_string ( int i ) const ;
2021-06-10 07:26:01 +00: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 14:53:05 +00:00
void set_triangle_from_string ( int triangle_id , const std : : string & str ) ;
2021-06-10 07:26:01 +00: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 12:42:42 +00:00
2020-09-24 13:34:13 +00:00
private :
2020-10-15 15:29:42 +00: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 13:34:13 +00:00
friend class cereal : : access ;
friend class UndoRedo : : StackImpl ;
2020-04-16 12:42:42 +00:00
2020-05-05 11:45:04 +00:00
template < class Archive > void serialize ( Archive & ar )
{
2020-09-24 13:34:13 +00:00
ar ( cereal : : base_class < ObjectWithTimestamp > ( this ) , m_data ) ;
2020-05-05 11:45:04 +00:00
}
2021-06-10 07:26:01 +00:00
std : : pair < std : : vector < std : : pair < int , int > > , std : : vector < bool > > m_data ;
2020-10-09 10:25:57 +00:00
// To access set_new_unique_id() when copy / pasting a ModelVolume.
friend class ModelVolume ;
2020-04-16 12:42:42 +00:00
} ;
2016-09-13 11:30:00 +00: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 14:42:23 +00:00
class ModelVolume final : public ObjectBase
2014-01-06 17:29:10 +00:00
{
2016-09-13 11:30:00 +00:00
public :
2018-10-17 09:12:38 +00:00
std : : string name ;
2019-09-19 07:09:11 +00: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 11:11:58 +00:00
Geometry : : Transformation transform ;
2021-07-16 10:30:47 +00:00
bool is_converted_from_inches { false } ;
bool is_converted_from_meters { false } ;
bool is_from_builtin_objects { false } ;
2019-09-19 07:09:11 +00:00
2020-09-23 10:59:15 +00: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-07-16 10:30:47 +00:00
ar ( input_file , object_idx , volume_idx , mesh_offset , transform , is_converted_from_inches , is_converted_from_meters , is_from_builtin_objects ) ;
2020-09-23 10:59:15 +00:00
}
2019-09-19 07:09:11 +00:00
} ;
Source source ;
2019-09-23 13:35:49 +00:00
2016-09-13 11:30:00 +00:00
// The triangular model.
2019-06-11 15:08:47 +00:00
const TriangleMesh & mesh ( ) const { return * m_mesh . get ( ) ; }
2019-07-02 14:42:23 +00: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 11:30:00 +00: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 13:34:13 +00:00
ModelConfigObject config ;
2018-09-06 12:19:20 +00:00
2020-04-16 12:42:42 +00:00
// List of mesh facets to be supported/unsupported.
2020-10-09 11:09:03 +00:00
FacetsAnnotation supported_facets ;
2020-04-16 12:42:42 +00:00
2020-08-31 05:25:43 +00:00
// List of seam enforcers/blockers.
2020-10-09 11:09:03 +00:00
FacetsAnnotation seam_facets ;
2020-08-31 05:25:43 +00:00
2021-04-19 05:01:11 +00:00
// List of mesh facets painted for MMU segmentation.
FacetsAnnotation mmu_segmentation_facets ;
2016-09-13 11:30:00 +00:00
// A parent object owning this modifier volume.
2020-04-22 09:16:28 +00:00
ModelObject * get_object ( ) const { return this - > object ; }
2019-02-22 11:12:10 +00: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 07:38:51 +00:00
bool is_negative_volume ( ) const { return m_type = = ModelVolumeType : : NEGATIVE_VOLUME ; }
2019-02-22 11:12:10 +00: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 09:12:38 +00: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 12:19:20 +00:00
ModelMaterial * material ( ) const ;
void set_material ( t_model_material_id material_id , const ModelMaterial & material ) ;
2018-11-22 12:20:13 +00: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 13:04:59 +00:00
bool is_splittable ( ) const ;
2019-01-21 14:42:33 +00:00
2017-06-15 13:38:15 +00: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 14:48:13 +00:00
size_t split ( unsigned int max_extruders ) ;
2018-11-02 13:41:08 +00:00
void translate ( double x , double y , double z ) { translate ( Vec3d ( x , y , z ) ) ; }
2018-11-01 13:25:10 +00:00
void translate ( const Vec3d & displacement ) ;
2018-11-02 13:41:08 +00: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 07:31:54 +00:00
void rotate ( double angle , Axis axis ) ;
void rotate ( double angle , const Vec3d & axis ) ;
2018-11-05 07:51:00 +00:00
void mirror ( Axis axis ) ;
2018-05-07 14:13:58 +00:00
2019-06-11 15:08:47 +00:00
// This method could only be called before the meshes of this ModelVolumes are not shared!
2019-07-02 14:42:23 +00:00
void scale_geometry_after_creation ( const Vec3d & versor ) ;
2018-12-19 08:54:15 +00:00
2019-06-11 15:08:47 +00: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 10:39:59 +00:00
void center_geometry_after_creation ( bool update_source_offset = true ) ;
2018-11-06 14:51:33 +00:00
2018-09-20 14:48:13 +00:00
void calculate_convex_hull ( ) ;
2018-08-15 10:50:06 +00:00
const TriangleMesh & get_convex_hull ( ) const ;
2019-06-11 15:08:47 +00:00
std : : shared_ptr < const TriangleMesh > get_convex_hull_shared_ptr ( ) const { return m_convex_hull ; }
2019-04-29 13:27:59 +00:00
// Get count of errors in the mesh
int get_mesh_errors_count ( ) const ;
2018-08-15 10:50:06 +00:00
2018-09-06 12:19:20 +00:00
// Helpers for loading / storing into AMF / 3MF files.
2019-02-22 11:12:10 +00:00
static ModelVolumeType type_from_string ( const std : : string & s ) ;
static std : : string type_to_string ( const ModelVolumeType t ) ;
2018-09-06 12:19:20 +00:00
2018-11-01 13:25:10 +00:00
const Geometry : : Transformation & get_transformation ( ) const { return m_transformation ; }
void set_transformation ( const Geometry : : Transformation & transformation ) { m_transformation = transformation ; }
2019-12-19 09:22:46 +00:00
void set_transformation ( const Transform3d & trafo ) { m_transformation . set_from_transform ( trafo ) ; }
2018-11-01 13:25:10 +00:00
2018-10-31 13:56:51 +00: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 11:47:49 +00:00
bool is_left_handed ( ) const { return m_transformation . is_left_handed ( ) ; }
2018-10-31 13:56:51 +00: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 12:57:38 +00:00
void convert_from_imperial_units ( ) ;
2021-02-10 19:31:17 +00:00
void convert_from_meters ( ) ;
2018-11-01 13:25:10 +00: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 13:56:51 +00:00
2020-10-15 15:29:42 +00: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 05:01:11 +00:00
this - > mmu_segmentation_facets . set_new_unique_id ( ) ;
2020-10-15 15:29:42 +00:00
}
2019-02-03 21:14:34 +00:00
2018-11-02 18:49:40 +00:00
protected :
2018-11-02 19:41:49 +00:00
friend class Print ;
2018-11-21 16:35:35 +00:00
friend class SLAPrint ;
2019-07-04 08:45:41 +00:00
friend class Model ;
2018-11-02 19:41:49 +00:00
friend class ModelObject ;
2021-05-05 12:32:19 +00:00
friend void model_volume_list_update_supports ( ModelObject & model_object_dst , const ModelObject & model_object_new ) ;
2018-11-02 19:41:49 +00:00
2019-07-03 11:43:54 +00:00
// Copies IDs of both the ModelVolume and its config.
2018-11-12 15:28:27 +00:00
explicit ModelVolume ( const ModelVolume & rhs ) = default ;
2018-11-02 18:49:40 +00:00
void set_model_object ( ModelObject * model_object ) { object = model_object ; }
2020-10-09 10:25:57 +00:00
void assign_new_unique_ids_recursive ( ) override ;
2019-06-11 15:08:47 +00: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 18:49:40 +00:00
2016-09-13 11:30:00 +00:00
private :
// Parent object owning this ModelVolume.
2019-07-02 14:42:23 +00:00
ModelObject * object ;
2019-06-11 15:08:47 +00:00
// The triangular model.
2019-07-02 14:42:23 +00:00
std : : shared_ptr < const TriangleMesh > m_mesh ;
2018-09-06 12:19:20 +00:00
// Is it an object to be printed, or a modifier volume?
2019-07-02 14:42:23 +00:00
ModelVolumeType m_type ;
t_model_material_id m_material_id ;
2018-11-01 13:25:10 +00:00
// The convex hull of this model's mesh.
2019-07-02 14:42:23 +00:00
std : : shared_ptr < const TriangleMesh > m_convex_hull ;
Geometry : : Transformation m_transformation ;
2018-11-01 13:25:10 +00:00
2019-04-01 10:27:45 +00: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 14:29:12 +00:00
mutable int m_is_splittable { - 1 } ;
2019-04-01 10:27:45 +00:00
2021-05-26 13:36:02 +00: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 10:50:06 +00:00
{
2020-10-15 15:29:42 +00:00
assert ( this - > id ( ) . valid ( ) ) ;
assert ( this - > config . id ( ) . valid ( ) ) ;
assert ( this - > supported_facets . id ( ) . valid ( ) ) ;
2021-04-19 05:01:11 +00:00
assert ( this - > seam_facets . id ( ) . valid ( ) ) ;
assert ( this - > mmu_segmentation_facets . id ( ) . valid ( ) ) ;
2020-10-15 15:29:42 +00:00
assert ( this - > id ( ) ! = this - > config . id ( ) ) ;
assert ( this - > id ( ) ! = this - > supported_facets . id ( ) ) ;
assert ( this - > id ( ) ! = this - > seam_facets . id ( ) ) ;
2021-04-19 05:01:11 +00:00
assert ( this - > id ( ) ! = this - > mmu_segmentation_facets . id ( ) ) ;
2018-08-15 10:50:06 +00:00
if ( mesh . stl . stats . number_of_facets > 1 )
calculate_convex_hull ( ) ;
}
2021-05-26 13:36:02 +00: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 15:29:42 +00:00
assert ( this - > id ( ) . valid ( ) ) ;
2021-04-19 05:01:11 +00: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 15:29:42 +00:00
assert ( this - > id ( ) ! = this - > config . id ( ) ) ;
assert ( this - > id ( ) ! = this - > supported_facets . id ( ) ) ;
assert ( this - > id ( ) ! = this - > seam_facets . id ( ) ) ;
2021-04-19 05:01:11 +00:00
assert ( this - > id ( ) ! = this - > mmu_segmentation_facets . id ( ) ) ;
2019-07-03 11:43:54 +00:00
}
2018-11-02 11:11:28 +00:00
2018-11-05 16:52:55 +00:00
// Copying an existing volume, therefore this volume will get a copy of the ID assigned.
2018-11-02 11:11:28 +00:00
ModelVolume ( ModelObject * object , const ModelVolume & other ) :
2019-07-03 11:43:54 +00:00
ObjectBase ( other ) ,
2020-04-16 12:42:42 +00: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 13:23:35 +00:00
supported_facets ( other . supported_facets ) , seam_facets ( other . seam_facets ) , mmu_segmentation_facets ( other . mmu_segmentation_facets )
2018-11-02 11:11:28 +00:00
{
2020-10-15 15:29:42 +00: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 05:01:11 +00:00
assert ( this - > mmu_segmentation_facets . id ( ) . valid ( ) ) ;
2020-10-15 15:29:42 +00:00
assert ( this - > id ( ) ! = this - > config . id ( ) ) ;
assert ( this - > id ( ) ! = this - > supported_facets . id ( ) ) ;
assert ( this - > id ( ) ! = this - > seam_facets . id ( ) ) ;
2021-04-19 05:01:11 +00:00
assert ( this - > id ( ) ! = this - > mmu_segmentation_facets . id ( ) ) ;
2020-10-15 15:29:42 +00: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 05:01:11 +00:00
assert ( this - > mmu_segmentation_facets . id ( ) = = other . mmu_segmentation_facets . id ( ) ) ;
2018-11-02 11:11:28 +00:00
this - > set_material_id ( other . material_id ( ) ) ;
}
2018-11-05 16:52:55 +00:00
// Providing a new mesh, therefore this volume will get a new unique ID assigned.
2018-11-02 11:11:28 +00:00
ModelVolume ( ModelObject * object , const ModelVolume & other , const TriangleMesh & & mesh ) :
2019-09-19 07:09:11 +00: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 11:11:28 +00:00
{
2020-10-15 15:29:42 +00: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 05:01:11 +00:00
assert ( this - > mmu_segmentation_facets . id ( ) . valid ( ) ) ;
2020-10-15 15:29:42 +00:00
assert ( this - > id ( ) ! = this - > config . id ( ) ) ;
assert ( this - > id ( ) ! = this - > supported_facets . id ( ) ) ;
assert ( this - > id ( ) ! = this - > seam_facets . id ( ) ) ;
2021-04-19 05:01:11 +00:00
assert ( this - > id ( ) ! = this - > mmu_segmentation_facets . id ( ) ) ;
2020-10-15 15:29:42 +00:00
assert ( this - > id ( ) ! = other . id ( ) ) ;
assert ( this - > config . id ( ) = = other . config . id ( ) ) ;
2018-11-02 11:11:28 +00:00
this - > set_material_id ( other . material_id ( ) ) ;
2019-07-03 11:43:54 +00:00
this - > config . set_new_unique_id ( ) ;
2018-11-02 11:11:28 +00:00
if ( mesh . stl . stats . number_of_facets > 1 )
calculate_convex_hull ( ) ;
2020-10-15 15:29:42 +00: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 05:01:11 +00:00
assert ( this - > mmu_segmentation_facets . id ( ) ! = other . mmu_segmentation_facets . id ( ) ) ;
2020-10-15 15:29:42 +00:00
assert ( this - > id ( ) ! = this - > config . id ( ) ) ;
assert ( this - > supported_facets . empty ( ) ) ;
assert ( this - > seam_facets . empty ( ) ) ;
2021-04-19 05:01:11 +00:00
assert ( this - > mmu_segmentation_facets . empty ( ) ) ;
2018-11-02 11:11:28 +00:00
}
2018-10-30 14:24:36 +00:00
ModelVolume & operator = ( ModelVolume & rhs ) = delete ;
2019-06-26 14:29:12 +00:00
friend class cereal : : access ;
2019-07-02 14:42:23 +00:00
friend class UndoRedo : : StackImpl ;
2019-07-03 11:43:54 +00:00
// Used for deserialization, therefore no IDs are allocated.
2021-04-19 05:01:11 +00:00
ModelVolume ( ) : ObjectBase ( - 1 ) , config ( - 1 ) , supported_facets ( - 1 ) , seam_facets ( - 1 ) , mmu_segmentation_facets ( - 1 ) , object ( nullptr ) {
2020-10-15 15:29:42 +00: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 05:01:11 +00:00
assert ( this - > mmu_segmentation_facets . id ( ) . invalid ( ) ) ;
2019-07-03 11:43:54 +00:00
}
2019-07-18 09:51:06 +00:00
template < class Archive > void load ( Archive & ar ) {
bool has_convex_hull ;
2020-09-24 13:34:13 +00:00
ar ( name , source , m_mesh , m_type , m_material_id , m_transformation , m_is_splittable , has_convex_hull ) ;
2020-10-09 11:09:03 +00:00
cereal : : load_by_value ( ar , supported_facets ) ;
cereal : : load_by_value ( ar , seam_facets ) ;
2021-04-19 05:01:11 +00:00
cereal : : load_by_value ( ar , mmu_segmentation_facets ) ;
2019-09-19 07:09:11 +00:00
cereal : : load_by_value ( ar , config ) ;
2019-07-18 09:51:06 +00: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 13:34:13 +00:00
ar ( name , source , m_mesh , m_type , m_material_id , m_transformation , m_is_splittable , has_convex_hull ) ;
2020-10-09 11:09:03 +00:00
cereal : : save_by_value ( ar , supported_facets ) ;
cereal : : save_by_value ( ar , seam_facets ) ;
2021-04-19 05:01:11 +00:00
cereal : : save_by_value ( ar , mmu_segmentation_facets ) ;
2019-09-19 07:09:11 +00:00
cereal : : save_by_value ( ar , config ) ;
2019-07-18 09:51:06 +00:00
if ( has_convex_hull )
cereal : : save_optional ( ar , m_convex_hull ) ;
2019-06-26 14:29:12 +00:00
}
2014-01-06 17:29:10 +00:00
} ;
2021-05-19 07:38:51 +00: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 15:57:37 +00:00
return it ! = model_volumes . end ( ) & & ( * it ) - > id ( ) = = id ? * it : nullptr ;
2021-05-19 07:38:51 +00:00
}
2020-05-23 22:01:34 +00:00
enum ModelInstanceEPrintVolumeState : unsigned char
{
ModelInstancePVS_Inside ,
ModelInstancePVS_Partly_Outside ,
ModelInstancePVS_Fully_Outside ,
ModelInstanceNum_BedStates
} ;
2016-09-13 11:30:00 +00:00
// A single instance of a ModelObject.
// Knows the affine transformation of an object.
2019-07-02 14:42:23 +00:00
class ModelInstance final : public ObjectBase
2014-01-06 17:29:10 +00:00
{
2018-09-13 13:15:00 +00:00
private :
2018-10-31 13:56:51 +00:00
Geometry : : Transformation m_transformation ;
2018-09-13 13:15:00 +00:00
public :
2018-07-18 12:26:42 +00: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-23 22:01:34 +00:00
ModelInstanceEPrintVolumeState print_volume_state ;
2019-07-31 06:36:08 +00:00
// Whether or not this instance is printable
bool printable ;
2018-07-18 07:37:25 +00:00
2018-06-28 14:14:17 +00:00
ModelObject * get_object ( ) const { return this - > object ; }
2016-09-13 11:30:00 +00:00
2018-10-31 13:56:51 +00:00
const Geometry : : Transformation & get_transformation ( ) const { return m_transformation ; }
2019-07-18 10:58:28 +00:00
void set_transformation ( const Geometry : : Transformation & transformation ) { m_transformation = transformation ; }
2018-10-31 13:56:51 +00: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 11:32:31 +00:00
2018-10-31 13:56:51 +00: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 10:58:28 +00: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 13:56:51 +00:00
2019-01-28 07:52:22 +00:00
const Vec3d & get_scaling_factor ( ) const { return m_transformation . get_scaling_factor ( ) ; }
2018-10-31 13:56:51 +00:00
double get_scaling_factor ( Axis axis ) const { return m_transformation . get_scaling_factor ( axis ) ; }
2019-07-18 10:58:28 +00: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 13:56:51 +00: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 11:54:23 +00:00
bool is_left_handed ( ) const { return m_transformation . is_left_handed ( ) ; }
2019-07-15 15:30:44 +00:00
2019-07-18 10:58:28 +00: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 13:00:40 +00:00
2016-09-13 11:30:00 +00:00
// To be called on an external mesh
2014-08-03 18:33:16 +00:00
void transform_mesh ( TriangleMesh * mesh , bool dont_translate = false ) const ;
2016-11-16 10:53:29 +00:00
// Calculate a bounding box of a transformed mesh. To be called on an external mesh.
2018-11-09 09:31:58 +00:00
BoundingBoxf3 transform_mesh_bounding_box ( const TriangleMesh & mesh , bool dont_translate = false ) const ;
2016-11-16 10:53:29 +00:00
// Transform an external bounding box.
BoundingBoxf3 transform_bounding_box ( const BoundingBoxf3 & bbox , bool dont_translate = false ) const ;
2018-09-06 07:16:32 +00:00
// Transform an external vector.
Vec3d transform_vector ( const Vec3d & v , bool dont_translate = false ) const ;
2016-09-13 11:30:00 +00:00
// To be called on an external polygon. It does not translate the polygon, only rotates and scales.
2014-01-06 17:29:10 +00:00
void transform_polygon ( Polygon * polygon ) const ;
2018-07-18 12:26:42 +00:00
2018-11-01 13:25:10 +00: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 12:42:14 +00:00
2020-05-23 22:01:34 +00:00
bool is_printable ( ) const { return object - > printable & & printable & & ( print_volume_state = = ModelInstancePVS_Inside ) ; }
2019-07-31 06:36:08 +00:00
2019-06-28 15:03:50 +00:00
// Getting the input polygon for arrange
2019-07-12 19:03:49 +00:00
arrangement : : ArrangePolygon get_arrange_polygon ( ) const ;
2019-06-28 15:03:50 +00:00
// Apply the arrange result on the ModelInstance
2020-03-30 11:26:24 +00:00
void apply_arrange_result ( const Vec2d & offs , double rotation )
2019-06-27 19:13:44 +00:00
{
// write the transformation data into the model instance
2019-07-17 11:32:31 +00:00
set_rotation ( Z , rotation ) ;
set_offset ( X , unscale < double > ( offs ( X ) ) ) ;
set_offset ( Y , unscale < double > ( offs ( Y ) ) ) ;
2020-01-28 10:11:45 +00:00
this - > object - > invalidate_bounding_box ( ) ;
2019-06-27 19:13:44 +00:00
}
2018-07-18 12:26:42 +00:00
2018-11-02 18:49:40 +00:00
protected :
friend class Print ;
2018-11-21 16:35:35 +00:00
friend class SLAPrint ;
2019-07-04 08:45:41 +00:00
friend class Model ;
2018-11-02 18:49:40 +00:00
friend class ModelObject ;
explicit ModelInstance ( const ModelInstance & rhs ) = default ;
void set_model_object ( ModelObject * model_object ) { object = model_object ; }
2016-09-13 11:30:00 +00:00
private :
// Parent object, owning this instance.
2014-05-09 12:24:35 +00:00
ModelObject * object ;
2017-06-13 09:35:24 +00:00
2018-11-02 18:49:40 +00:00
// Constructor, which assigns a new unique ID.
2020-05-23 22:01:34 +00:00
explicit ModelInstance ( ModelObject * object ) : print_volume_state ( ModelInstancePVS_Inside ) , printable ( true ) , object ( object ) { assert ( this - > id ( ) . valid ( ) ) ; }
2018-11-02 18:49:40 +00:00
// Constructor, which assigns a new unique ID.
2018-11-02 19:41:49 +00:00
explicit ModelInstance ( ModelObject * object , const ModelInstance & other ) :
2020-05-23 22:01:34 +00: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 09:35:24 +00:00
2018-11-02 18:49:40 +00:00
explicit ModelInstance ( ModelInstance & & rhs ) = delete ;
ModelInstance & operator = ( const ModelInstance & rhs ) = delete ;
ModelInstance & operator = ( ModelInstance & & rhs ) = delete ;
2019-06-26 14:29:12 +00:00
friend class cereal : : access ;
2019-07-02 14:42:23 +00:00
friend class UndoRedo : : StackImpl ;
2019-07-03 11:43:54 +00:00
// Used for deserialization, therefore no IDs are allocated.
ModelInstance ( ) : ObjectBase ( - 1 ) , object ( nullptr ) { assert ( this - > id ( ) . invalid ( ) ) ; }
2019-06-26 14:29:12 +00:00
template < class Archive > void serialize ( Archive & ar ) {
2019-07-31 06:36:08 +00:00
ar ( m_transformation , print_volume_state , printable ) ;
}
2018-10-30 14:24:36 +00:00
} ;
2017-06-13 09:35:24 +00:00
2020-05-23 22:01:34 +00:00
2019-07-19 13:29:04 +00: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 09:35:24 +00: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 14:42:23 +00:00
class Model final : public ObjectBase
2017-06-13 09:35:24 +00: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 13:47:13 +00:00
ModelMaterialMap materials ;
2017-06-13 09:35:24 +00: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 13:47:13 +00:00
ModelObjectPtrs objects ;
2019-07-19 13:29:04 +00:00
// Wipe tower object.
ModelWipeTower wipe_tower ;
2019-10-10 14:03:58 +00:00
2019-10-11 08:39:54 +00:00
// Extensions for color print
2020-01-23 11:49:39 +00:00
CustomGCode : : Info custom_gcode_per_print_z ;
2017-06-13 09:35:24 +00:00
2018-11-02 13:47:13 +00:00
// Default constructor assigns a new ID to the model.
2019-07-03 11:43:54 +00:00
Model ( ) { assert ( this - > id ( ) . valid ( ) ) ; }
2017-08-02 14:05:18 +00:00
~ Model ( ) { this - > clear_objects ( ) ; this - > clear_materials ( ) ; }
2018-11-02 18:49:40 +00: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 11:43:54 +00: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 18:49:40 +00:00
2019-06-27 09:02:45 +00:00
OBJECTBASE_DERIVED_COPY_MOVE_CLONE ( Model )
2018-11-02 13:47:13 +00:00
Support for forward compatibility of configurations, user and system
config bundles, project files (3MFs, AMFs). When loading these files,
the caller may decide whether to substitute some of the configuration
values the current PrusaSlicer version does not understand with
some reasonable default value, and whether to report it. If substitution
is disabled, an exception is being thrown as before this commit.
If substitution is enabled, list of substitutions is returned by the
API to be presented to the user. This allows us to introduce for example
new firmware flavor key in PrusaSlicer 2.4 while letting PrusaSlicer
2.3.2 to fall back to some default and to report it to the user.
When slicing from command line, substutions are performed by default
and reported into the console, however substitutions may be either
disabled or made silent with the new "config-compatibility" command
line option.
Substitute enums and bools only. Allow booleans to be parsed as
true: "1", "enabled", "on" case insensitive
false: "0", "disabled", "off" case insensitive
This will allow us in the future for example to switch the draft_shield
boolean to an enum with the following values: "disabled" / "enabled" / "limited".
Added "enum_bitmask.hpp" - support for type safe sets of options.
See for example PresetBundle::load_configbundle(...
LoadConfigBundleAttributes flags) for an example of intended usage.
WIP: GUI for reporting the list of config substitutions needs to be
implemented by @YuSanka.
2021-06-27 14:04:23 +00: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 14:05:18 +00:00
2018-11-02 13:47:13 +00:00
// Add a new ModelObject to this Model, generate a new ID for this ModelObject.
2017-06-13 09:35:24 +00: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 13:47:13 +00:00
ModelObject * add_object ( const ModelObject & other ) ;
void delete_object ( size_t idx ) ;
2019-06-27 09:02:45 +00:00
bool delete_object ( ObjectID id ) ;
2018-11-02 18:49:40 +00:00
bool delete_object ( ModelObject * object ) ;
2018-11-02 13:47:13 +00:00
void clear_objects ( ) ;
2018-10-18 13:13:38 +00:00
2017-06-13 09:35:24 +00: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 18:49:40 +00:00
void delete_material ( t_model_material_id material_id ) ;
void clear_materials ( ) ;
bool add_default_instances ( ) ;
2018-03-09 09:40:42 +00:00
// Returns approximate axis aligned bounding box of this model
BoundingBoxf3 bounding_box ( ) const ;
2018-10-23 13:27:31 +00:00
// Set the print_volume_state of PrintObject::instances,
// return total number of printable objects.
2019-06-26 14:29:12 +00:00
unsigned int update_print_volume_state ( const BoundingBoxf3 & print_volume ) ;
2018-11-08 19:18:40 +00:00
// Returns true if any ModelObject was modified.
2019-06-26 14:29:12 +00: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 16:19:03 +00:00
2017-06-13 09:35:24 +00:00
// Croaks if the duplicated objects do not fit the print bed.
2020-04-23 16:19:03 +00:00
void duplicate_objects_grid ( size_t x , size_t y , coordf_t dist ) ;
2017-08-02 14:05:18 +00:00
2019-06-26 14:29:12 +00:00
bool looks_like_multipart_object ( ) const ;
void convert_multipart_object ( unsigned int max_extruders ) ;
2020-04-29 17:10:13 +00:00
bool looks_like_imperial_units ( ) const ;
2020-12-12 17:54:34 +00:00
void convert_from_imperial_units ( bool only_small_volumes ) ;
2021-02-09 16:04:32 +00:00
bool looks_like_saved_in_meters ( ) const ;
void convert_from_meters ( bool only_small_volumes ) ;
2017-08-02 14:05:18 +00:00
2018-03-06 09:26:39 +00:00
// Ensures that the min z of the model is not negative
2019-06-26 14:29:12 +00:00
void adjust_min_z ( ) ;
2018-03-06 09:26:39 +00:00
2019-06-26 14:29:12 +00:00
void print_info ( ) const { for ( const ModelObject * o : this - > objects ) o - > print_info ( ) ; }
2018-04-10 10:17:55 +00:00
2019-02-03 09:41:14 +00:00
// Propose an output file name & path based on the first printable object's name and source input file's path.
2019-08-05 15:49:21 +00:00
std : : string propose_export_file_name_and_path ( ) const ;
2019-03-13 14:44:50 +00:00
// Propose an output path, replace extension. The new_extension shall contain the initial dot.
2019-08-05 15:49:21 +00:00
std : : string propose_export_file_name_and_path ( const std : : string & new_extension ) const ;
2018-12-03 12:14:28 +00:00
2018-11-02 13:47:13 +00:00
private :
2020-04-22 09:16:28 +00:00
explicit Model ( int ) : ObjectBase ( - 1 ) { assert ( this - > id ( ) . invalid ( ) ) ; }
2019-07-03 11:43:54 +00:00
void assign_new_unique_ids_recursive ( ) ;
2019-07-04 08:45:41 +00:00
void update_links_bottom_up_recursive ( ) ;
2019-06-26 14:29:12 +00:00
friend class cereal : : access ;
2019-07-02 14:42:23 +00:00
friend class UndoRedo : : StackImpl ;
2019-06-26 14:29:12 +00:00
template < class Archive > void serialize ( Archive & ar ) {
2019-07-19 13:29:04 +00:00
Internal : : StaticSerializationWrapper < ModelWipeTower > wipe_tower_wrapper ( wipe_tower ) ;
ar ( materials , objects , wipe_tower_wrapper ) ;
2020-04-23 16:19:03 +00:00
}
2014-01-06 17:29:10 +00:00
} ;
Support for forward compatibility of configurations, user and system
config bundles, project files (3MFs, AMFs). When loading these files,
the caller may decide whether to substitute some of the configuration
values the current PrusaSlicer version does not understand with
some reasonable default value, and whether to report it. If substitution
is disabled, an exception is being thrown as before this commit.
If substitution is enabled, list of substitutions is returned by the
API to be presented to the user. This allows us to introduce for example
new firmware flavor key in PrusaSlicer 2.4 while letting PrusaSlicer
2.3.2 to fall back to some default and to report it to the user.
When slicing from command line, substutions are performed by default
and reported into the console, however substitutions may be either
disabled or made silent with the new "config-compatibility" command
line option.
Substitute enums and bools only. Allow booleans to be parsed as
true: "1", "enabled", "on" case insensitive
false: "0", "disabled", "off" case insensitive
This will allow us in the future for example to switch the draft_shield
boolean to an enum with the following values: "disabled" / "enabled" / "limited".
Added "enum_bitmask.hpp" - support for type safe sets of options.
See for example PresetBundle::load_configbundle(...
LoadConfigBundleAttributes flags) for an example of intended usage.
WIP: GUI for reporting the list of config substitutions needs to be
implemented by @YuSanka.
2021-06-27 14:04:23 +00:00
ENABLE_ENUM_BITMASK_OPERATORS ( Model : : LoadAttribute )
2019-06-27 09:02:45 +00:00
# undef OBJECTBASE_DERIVED_COPY_MOVE_CLONE
# undef OBJECTBASE_DERIVED_PRIVATE_COPY_MOVE
2018-11-02 13:47:13 +00:00
2018-11-21 16:35:35 +00: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 10:41:06 +00:00
bool model_object_list_equal ( const Model & model_old , const Model & model_new ) ;
2018-11-21 16:35:35 +00: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 10:41:06 +00:00
bool model_object_list_extended ( const Model & model_old , const Model & model_new ) ;
2018-11-21 16:35:35 +00: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 10:41:06 +00: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 16:35:35 +00:00
2020-04-22 09:16:28 +00: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 10:41:06 +00:00
bool model_custom_supports_data_changed ( const ModelObject & mo , const ModelObject & mo_new ) ;
2020-08-31 05:25:43 +00: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 10:41:06 +00:00
bool model_custom_seam_data_changed ( const ModelObject & mo , const ModelObject & mo_new ) ;
2020-04-22 09:16:28 +00:00
2021-04-19 05:01:11 +00: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 09:16:28 +00:00
2019-07-18 15:41:47 +00: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 10:41:06 +00:00
bool model_has_multi_part_objects ( const Model & model ) ;
2019-07-18 15:41:47 +00:00
// If the model has advanced features, then it cannot be processed in simple mode.
2021-05-26 10:41:06 +00:00
bool model_has_advanced_features ( const Model & model ) ;
2019-07-18 15:41:47 +00:00
2019-01-31 07:47:23 +00:00
# ifndef NDEBUG
2018-11-16 17:28:50 +00: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 07:47:23 +00:00
# endif /* NDEBUG */
2018-11-16 17:28:50 +00:00
2021-06-08 08:07:47 +00:00
# if ENABLE_ALLOW_NEGATIVE_Z
static const float SINKING_Z_THRESHOLD = - 0.001f ;
# endif // ENABLE_ALLOW_NEGATIVE_Z
2019-06-27 09:02:45 +00:00
} // namespace Slic3r
2014-01-06 17:29:10 +00:00
2019-07-18 09:51:06 +00:00
namespace cereal
{
template < class Archive > struct specialize < Archive , Slic3r : : ModelVolume , cereal : : specialization : : member_load_save > { } ;
2020-09-24 13:34:13 +00:00
template < class Archive > struct specialize < Archive , Slic3r : : ModelConfigObject , cereal : : specialization : : member_serialize > { } ;
2019-07-18 09:51:06 +00:00
}
2019-06-27 09:02:45 +00:00
# endif /* slic3r_Model_hpp_ */