add the logic to reduce slicing time between shared-mesh objects

also reduce the storage size

Change-Id: I61d6e0997979ec0ce701cc580fa6640a21b6260f
This commit is contained in:
lane.wei 2022-08-18 15:29:33 +08:00 committed by Lane.Wei
parent 9245b4f36a
commit fdd9582e3e
12 changed files with 446 additions and 125 deletions

View file

@ -270,7 +270,7 @@ static ExPolygons top_level_outer_brim_area(const Print &print
return diff_ex(brim_area, no_brim_area); return diff_ex(brim_area, no_brim_area);
} }
// BBS: the brims of different objs will not overlapped with each other, and are stored by objs and by extruders // BBS: the brims of different objs will not overlapped with each other, and are stored by objs and by extruders
static ExPolygons top_level_outer_brim_area(const Print& print, const ConstPrintObjectPtrs& top_level_objects_with_brim, static ExPolygons top_level_outer_brim_area(const Print& print, const ConstPrintObjectPtrs& top_level_objects_with_brim,
const float no_brim_offset, double& brim_width_max, std::map<ObjectID, double>& brim_width_map, const float no_brim_offset, double& brim_width_max, std::map<ObjectID, double>& brim_width_map,
std::map<ObjectID, ExPolygons>& brimAreaMap, std::map<ObjectID, ExPolygons>& brimAreaMap,
@ -453,7 +453,7 @@ static ExPolygons inner_brim_area(const Print &print,
return diff_ex(intersection_ex(to_polygons(std::move(brim_area)), holes), no_brim_area); return diff_ex(intersection_ex(to_polygons(std::move(brim_area)), holes), no_brim_area);
} }
// BBS: the brims of different objs will not overlapped with each other, and are stored by objs and by extruders // BBS: the brims of different objs will not overlapped with each other, and are stored by objs and by extruders
static ExPolygons inner_brim_area(const Print& print, const ConstPrintObjectPtrs& top_level_objects_with_brim, static ExPolygons inner_brim_area(const Print& print, const ConstPrintObjectPtrs& top_level_objects_with_brim,
const float no_brim_offset, std::map<ObjectID, ExPolygons>& brimAreaMap, const float no_brim_offset, std::map<ObjectID, ExPolygons>& brimAreaMap,
std::map<ObjectID, ExPolygons>& supportBrimAreaMap, std::map<ObjectID, ExPolygons>& supportBrimAreaMap,
@ -906,7 +906,11 @@ static ExPolygons outer_inner_brim_area(const Print& print,
std::vector<ModelVolume*> groupVolumePtrs; std::vector<ModelVolume*> groupVolumePtrs;
for (auto& volumeID : volumeGroup.volume_ids) { for (auto& volumeID : volumeGroup.volume_ids) {
ModelVolume* currentModelVolumePtr = nullptr; ModelVolume* currentModelVolumePtr = nullptr;
for (auto volumePtr : object->model_object()->volumes) { //BBS: support shared object logic
const PrintObject* shared_object = object->get_shared_object();
if (!shared_object)
shared_object = object;
for (auto volumePtr : shared_object->model_object()->volumes) {
if (volumePtr->id() == volumeID) { if (volumePtr->id() == volumeID) {
currentModelVolumePtr = volumePtr; currentModelVolumePtr = volumePtr;
break; break;
@ -1066,7 +1070,7 @@ static void optimize_polylines_by_reversing(Polylines *polylines)
double dist_to_start = (next.first_point() - prev.last_point()).cast<double>().norm(); double dist_to_start = (next.first_point() - prev.last_point()).cast<double>().norm();
double dist_to_end = (next.last_point() - prev.last_point()).cast<double>().norm(); double dist_to_end = (next.last_point() - prev.last_point()).cast<double>().norm();
if (dist_to_end < dist_to_start) if (dist_to_end < dist_to_start)
next.reverse(); next.reverse();
} }
} }

View file

@ -258,6 +258,8 @@ static constexpr const char* SOURCE_OFFSET_Z_KEY = "source_offset_z";
static constexpr const char* SOURCE_IN_INCHES = "source_in_inches"; static constexpr const char* SOURCE_IN_INCHES = "source_in_inches";
static constexpr const char* SOURCE_IN_METERS = "source_in_meters"; static constexpr const char* SOURCE_IN_METERS = "source_in_meters";
static constexpr const char* MESH_SHARED_KEY = "mesh_shared";
static constexpr const char* MESH_STAT_EDGES_FIXED = "edges_fixed"; static constexpr const char* MESH_STAT_EDGES_FIXED = "edges_fixed";
static constexpr const char* MESH_STAT_DEGENERATED_FACETS = "degenerate_facets"; static constexpr const char* MESH_STAT_DEGENERATED_FACETS = "degenerate_facets";
static constexpr const char* MESH_STAT_FACETS_REMOVED = "facets_removed"; static constexpr const char* MESH_STAT_FACETS_REMOVED = "facets_removed";
@ -702,6 +704,8 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
std::string m_thumbnail_path; std::string m_thumbnail_path;
std::vector<std::string> m_sub_model_paths; std::vector<std::string> m_sub_model_paths;
std::map<int, ModelVolume*> m_shared_meshes;
//BBS: plater related structures //BBS: plater related structures
bool m_is_bbl_3mf { false }; bool m_is_bbl_3mf { false };
bool m_parsing_slice_info { false }; bool m_parsing_slice_info { false };
@ -847,8 +851,8 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
bool _handle_start_relationship(const char** attributes, unsigned int num_attributes); bool _handle_start_relationship(const char** attributes, unsigned int num_attributes);
void _generate_current_object_list(std::vector<Id> &sub_objects, Id object_id, IdToCurrentObjectMap current_objects); void _generate_current_object_list(std::vector<Component> &sub_objects, Id object_id, IdToCurrentObjectMap current_objects);
bool _generate_volumes_new(ModelObject& object, const std::vector<Id> &sub_objects, const ObjectMetadata::VolumeMetadataList& volumes, ConfigSubstitutionContext& config_substitutions); bool _generate_volumes_new(ModelObject& object, const std::vector<Component> &sub_objects, const ObjectMetadata::VolumeMetadataList& volumes, ConfigSubstitutionContext& config_substitutions);
bool _generate_volumes(ModelObject& object, const Geometry& geometry, const ObjectMetadata::VolumeMetadataList& volumes, ConfigSubstitutionContext& config_substitutions); bool _generate_volumes(ModelObject& object, const Geometry& geometry, const ObjectMetadata::VolumeMetadataList& volumes, ConfigSubstitutionContext& config_substitutions);
// callbacks to parse the .model file // callbacks to parse the .model file
@ -1281,7 +1285,7 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
add_error("3rd 3mf, can not find object, id " + std::to_string(object.first.second)); add_error("3rd 3mf, can not find object, id " + std::to_string(object.first.second));
return false; return false;
} }
std::vector<Id> object_id_list; std::vector<Component> object_id_list;
_generate_current_object_list(object_id_list, object.first, m_current_objects); _generate_current_object_list(object_id_list, object.first, m_current_objects);
ObjectMetadata::VolumeMetadataList volumes; ObjectMetadata::VolumeMetadataList volumes;
@ -1289,7 +1293,7 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
for (int k = 0; k < object_id_list.size(); k++) for (int k = 0; k < object_id_list.size(); k++)
{ {
Id object_id = object_id_list[k]; Id object_id = object_id_list[k].object_id;
volumes.emplace_back(object_id.second); volumes.emplace_back(object_id.second);
} }
@ -1344,7 +1348,7 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
model_object->sla_drain_holes = std::move(obj_drain_holes->second); model_object->sla_drain_holes = std::move(obj_drain_holes->second);
}*/ }*/
std::vector<Id> object_id_list; std::vector<Component> object_id_list;
_generate_current_object_list(object_id_list, object.first, m_current_objects); _generate_current_object_list(object_id_list, object.first, m_current_objects);
ObjectMetadata::VolumeMetadataList volumes; ObjectMetadata::VolumeMetadataList volumes;
@ -1375,7 +1379,7 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
//volumes.emplace_back(0, (int)obj_geometry->second.triangles.size() - 1); //volumes.emplace_back(0, (int)obj_geometry->second.triangles.size() - 1);
for (int k = 0; k < object_id_list.size(); k++) for (int k = 0; k < object_id_list.size(); k++)
{ {
Id object_id = object_id_list[k]; Id object_id = object_id_list[k].object_id;
volumes.emplace_back(object_id.second); volumes.emplace_back(object_id.second);
} }
@ -3279,34 +3283,34 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
return true; return true;
} }
void _BBS_3MF_Importer::_generate_current_object_list(std::vector<Id> &sub_objects, Id object_id, IdToCurrentObjectMap current_objects) void _BBS_3MF_Importer::_generate_current_object_list(std::vector<Component> &sub_objects, Id object_id, IdToCurrentObjectMap current_objects)
{ {
std::list<Id> id_list; std::list<Component> id_list;
id_list.push_back(object_id); id_list.push_back({ object_id, Transform3d::Identity() });
while (!id_list.empty()) while (!id_list.empty())
{ {
Id current_id = id_list.front(); Component current_id = id_list.front();
id_list.pop_front(); id_list.pop_front();
IdToCurrentObjectMap::iterator current_object = current_objects.find(current_id); IdToCurrentObjectMap::iterator current_object = current_objects.find(current_id.object_id);
if (current_object != current_objects.end()) { if (current_object != current_objects.end()) {
//found one //found one
if (!current_object->second.components.empty()) { if (!current_object->second.components.empty()) {
for (const Component& comp: current_object->second.components) for (const Component& comp: current_object->second.components)
{ {
id_list.push_back(comp.object_id); id_list.push_back(comp);
} }
} }
else if (!(current_object->second.geometry.empty())) { else if (!(current_object->second.geometry.empty())) {
//CurrentObject* ptr = &(current_objects[current_id]); //CurrentObject* ptr = &(current_objects[current_id]);
//CurrentObject* ptr2 = &(current_object->second); //CurrentObject* ptr2 = &(current_object->second);
sub_objects.push_back(current_object->first); sub_objects.push_back({ current_object->first, current_id.transform });
} }
} }
} }
} }
bool _BBS_3MF_Importer::_generate_volumes_new(ModelObject& object, const std::vector<Id> &sub_objects, const ObjectMetadata::VolumeMetadataList& volumes, ConfigSubstitutionContext& config_substitutions) bool _BBS_3MF_Importer::_generate_volumes_new(ModelObject& object, const std::vector<Component> &sub_objects, const ObjectMetadata::VolumeMetadataList& volumes, ConfigSubstitutionContext& config_substitutions)
{ {
if (!object.volumes.empty()) { if (!object.volumes.empty()) {
add_error("object already built with parts"); add_error("object already built with parts");
@ -3319,7 +3323,8 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
for (unsigned int index = 0; index < sub_objects.size(); index++) for (unsigned int index = 0; index < sub_objects.size(); index++)
{ {
//find the volume metadata firstly //find the volume metadata firstly
Id object_id = sub_objects[index]; Component sub_comp = sub_objects[index];
Id object_id = sub_comp.object_id;
IdToCurrentObjectMap::iterator current_object = m_current_objects.find(object_id); IdToCurrentObjectMap::iterator current_object = m_current_objects.find(object_id);
if (current_object == m_current_objects.end()) { if (current_object == m_current_objects.end()) {
add_error("sub_objects can not be found, id=" + std::to_string(object_id.second)); add_error("sub_objects can not be found, id=" + std::to_string(object_id.second));
@ -3338,68 +3343,112 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
Transform3d volume_matrix_to_object = Transform3d::Identity(); Transform3d volume_matrix_to_object = Transform3d::Identity();
bool has_transform = false; bool has_transform = false;
int shared_mesh_id = -1;
if (volume_data) if (volume_data)
{ {
int found_count = 0;
// extract the volume transformation from the volume's metadata, if present // extract the volume transformation from the volume's metadata, if present
for (const Metadata& metadata : volume_data->metadata) { for (const Metadata& metadata : volume_data->metadata) {
if (metadata.key == MATRIX_KEY) { if (metadata.key == MATRIX_KEY) {
volume_matrix_to_object = Slic3r::Geometry::transform3d_from_string(metadata.value); volume_matrix_to_object = Slic3r::Geometry::transform3d_from_string(metadata.value);
has_transform = ! volume_matrix_to_object.isApprox(Transform3d::Identity(), 1e-10); has_transform = ! volume_matrix_to_object.isApprox(Transform3d::Identity(), 1e-10);
break; found_count++;
} }
else if (metadata.key == MESH_SHARED_KEY){
//add the shared mesh logic
shared_mesh_id = ::atoi(metadata.value.c_str());
found_count++;
}
if (found_count >= 2)
break;
} }
} }
else { else {
//create a volume_data //create a volume_data
volume_data = &default_volume_data; volume_data = &default_volume_data;
} }
// splits volume out of imported geometry
indexed_triangle_set its; ModelVolume* volume = nullptr;
its.indices.assign(sub_object->geometry.triangles.begin(), sub_object->geometry.triangles.end()); ModelVolume *shared_volume = nullptr;
const size_t triangles_count = its.indices.size(); if (shared_mesh_id != -1) {
std::map<int, ModelVolume*>::iterator iter = m_shared_meshes.find(shared_mesh_id);
if (iter != m_shared_meshes.end()) {
shared_volume = iter->second;
}
}
const size_t triangles_count = sub_object->geometry.triangles.size();
if (triangles_count == 0) { if (triangles_count == 0) {
add_error("found no trianges in the object " + std::to_string(sub_object->id)); add_error("found no trianges in the object " + std::to_string(sub_object->id));
return false; return false;
} }
for (const Vec3i& face : its.indices) { if (!shared_volume){
for (const int tri_id : face) { // splits volume out of imported geometry
if (tri_id < 0 || tri_id >= int(sub_object->geometry.vertices.size())) { indexed_triangle_set its;
add_error("invalid vertex id in object " + std::to_string(sub_object->id)); its.indices.assign(sub_object->geometry.triangles.begin(), sub_object->geometry.triangles.end());
return false; //const size_t triangles_count = its.indices.size();
//if (triangles_count == 0) {
// add_error("found no trianges in the object " + std::to_string(sub_object->id));
// return false;
//}
for (const Vec3i& face : its.indices) {
for (const int tri_id : face) {
if (tri_id < 0 || tri_id >= int(sub_object->geometry.vertices.size())) {
add_error("invalid vertex id in object " + std::to_string(sub_object->id));
return false;
}
} }
} }
}
its.vertices.assign(sub_object->geometry.vertices.begin(), sub_object->geometry.vertices.end()); its.vertices.assign(sub_object->geometry.vertices.begin(), sub_object->geometry.vertices.end());
// BBS // BBS
for (const std::string prop_str : sub_object->geometry.face_properties) { for (const std::string prop_str : sub_object->geometry.face_properties) {
FaceProperty face_prop; FaceProperty face_prop;
face_prop.from_string(prop_str); face_prop.from_string(prop_str);
its.properties.push_back(face_prop); its.properties.push_back(face_prop);
}
TriangleMesh triangle_mesh(std::move(its), volume_data->mesh_stats);
if (m_version == 0) {
// if the 3mf was not produced by BambuStudio and there is only one instance,
// bake the transformation into the geometry to allow the reload from disk command
// to work properly
if (object.instances.size() == 1) {
triangle_mesh.transform(object.instances.front()->get_transformation().get_matrix(), false);
object.instances.front()->set_transformation(Slic3r::Geometry::Transformation());
//FIXME do the mesh fixing?
} }
}
if (triangle_mesh.volume() < 0)
triangle_mesh.flip_triangles();
ModelVolume* volume = object.add_volume(std::move(triangle_mesh)); TriangleMesh triangle_mesh(std::move(its), volume_data->mesh_stats);
if (m_version == 0) {
// if the 3mf was not produced by BambuStudio and there is only one instance,
// bake the transformation into the geometry to allow the reload from disk command
// to work properly
if (object.instances.size() == 1) {
triangle_mesh.transform(object.instances.front()->get_transformation().get_matrix(), false);
object.instances.front()->set_transformation(Slic3r::Geometry::Transformation());
//FIXME do the mesh fixing?
}
}
if (triangle_mesh.volume() < 0)
triangle_mesh.flip_triangles();
volume = object.add_volume(std::move(triangle_mesh));
m_shared_meshes[sub_object->id] = volume;
}
else {
//create volume to use shared mesh
volume = object.add_volume_with_shared_mesh(*shared_volume);
}
// stores the volume matrix taken from the metadata, if present // stores the volume matrix taken from the metadata, if present
if (has_transform) if (has_transform)
volume->source.transform = Slic3r::Geometry::Transformation(volume_matrix_to_object); volume->source.transform = Slic3r::Geometry::Transformation(volume_matrix_to_object);
volume->calculate_convex_hull(); volume->calculate_convex_hull();
//set transform from 3mf
Slic3r::Geometry::Transformation comp_transformatino(sub_comp.transform);
volume->set_transformation(volume->get_transformation() * comp_transformatino);
if (shared_volume) {
const TriangleMesh& trangle_mesh = volume->mesh();
Vec3d shift = trangle_mesh.get_init_shift();
if (!shift.isApprox(Vec3d::Zero()))
volume->translate(shift);
}
// recreate custom supports, seam and mmu segmentation from previously loaded attribute // recreate custom supports, seam and mmu segmentation from previously loaded attribute
if (m_load_config) { if (m_load_config) {
volume->supported_facets.reserve(triangles_count); volume->supported_facets.reserve(triangles_count);
@ -3448,7 +3497,7 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
volume->source.is_converted_from_inches = metadata.value == "1"; volume->source.is_converted_from_inches = metadata.value == "1";
else if (metadata.key == SOURCE_IN_METERS) else if (metadata.key == SOURCE_IN_METERS)
volume->source.is_converted_from_meters = metadata.value == "1"; volume->source.is_converted_from_meters = metadata.value == "1";
else if (metadata.key == MATRIX_KEY) else if ((metadata.key == MATRIX_KEY) || (metadata.key == MESH_SHARED_KEY))
continue; continue;
else else
volume->config.set_deserialize(metadata.key, metadata.value, config_substitutions); volume->config.set_deserialize(metadata.key, metadata.value, config_substitutions);
@ -4648,12 +4697,37 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
if (m_from_backup_save) { if (m_from_backup_save) {
for (unsigned int index = 1; index <= object.volumes.size(); index ++) { for (unsigned int index = 1; index <= object.volumes.size(); index ++) {
unsigned int ref_id = object_id | (index << 16); unsigned int ref_id = object_id | (index << 16);
stream << " <" << COMPONENT_TAG << " objectid=\"" << ref_id << "\"/>\n"; stream << " <" << COMPONENT_TAG << " objectid=\"" << ref_id; // << "\"/>\n";
//add the transform of the volume
ModelVolume* volume = object.volumes[index - 1];
const Transform3d& transf = volume->get_matrix();
stream << "\" " << TRANSFORM_ATTR << "=\"";
for (unsigned c = 0; c < 4; ++c) {
for (unsigned r = 0; r < 3; ++r) {
stream << transf(r, c);
if (r != 2 || c != 3)
stream << " ";
}
}
stream << "\"/>\n";
} }
} }
else { else {
for (unsigned int index = object_id; index < volume_start_id; index ++) for (unsigned int index = object_id; index < volume_start_id; index ++) {
stream << " <" << COMPONENT_TAG << " objectid=\"" << index << "\"/>\n"; stream << " <" << COMPONENT_TAG << " objectid=\"" << index; // << "\"/>\n";
//add the transform of the volume
ModelVolume* volume = object.volumes[index - object_id];
const Transform3d& transf = volume->get_matrix();
stream << "\" " << TRANSFORM_ATTR << "=\"";
for (unsigned c = 0; c < 4; ++c) {
for (unsigned r = 0; r < 3; ++r) {
stream << transf(r, c);
if (r != 2 || c != 3)
stream << " ";
}
}
stream << "\"/>\n";
}
} }
} }
else { else {
@ -4803,7 +4877,10 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
const Transform3d& matrix = volume->get_matrix(); const Transform3d& matrix = volume->get_matrix();
for (size_t i = 0; i < its.vertices.size(); ++i) { for (size_t i = 0; i < its.vertices.size(); ++i) {
Vec3f v = (matrix * its.vertices[i].cast<double>()).cast<float>(); //don't save the volume's matrix into vertex data
//add the shared mesh logic
//Vec3f v = (matrix * its.vertices[i].cast<double>()).cast<float>();
Vec3f v = its.vertices[i];
char* ptr = buf; char* ptr = buf;
boost::spirit::karma::generate(ptr, boost::spirit::lit(" <") << VERTEX_TAG << " x=\""); boost::spirit::karma::generate(ptr, boost::spirit::lit(" <") << VERTEX_TAG << " x=\"");
ptr = format_coordinate(v.x(), ptr); ptr = format_coordinate(v.x(), ptr);
@ -5205,6 +5282,7 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
bool _BBS_3MF_Exporter::_add_model_config_file_to_archive(mz_zip_archive& archive, const Model& model, PlateDataPtrs& plate_data_list, const IdToObjectDataMap &objects_data, int export_plate_idx, bool save_gcode) bool _BBS_3MF_Exporter::_add_model_config_file_to_archive(mz_zip_archive& archive, const Model& model, PlateDataPtrs& plate_data_list, const IdToObjectDataMap &objects_data, int export_plate_idx, bool save_gcode)
{ {
std::stringstream stream; std::stringstream stream;
std::map<const TriangleMesh*, int> shared_meshes;
// Store mesh transformation in full precision, as the volumes are stored transformed and they need to be transformed back // Store mesh transformation in full precision, as the volumes are stored transformed and they need to be transformed back
// when loaded as accurately as possible. // when loaded as accurately as possible.
stream << std::setprecision(std::numeric_limits<double>::max_digits10); stream << std::setprecision(std::numeric_limits<double>::max_digits10);
@ -5297,6 +5375,17 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
stream << " <" << METADATA_TAG << " "<< KEY_ATTR << "=\"" << key << "\" " << VALUE_ATTR << "=\"" << volume->config.opt_serialize(key) << "\"/>\n"; stream << " <" << METADATA_TAG << " "<< KEY_ATTR << "=\"" << key << "\" " << VALUE_ATTR << "=\"" << volume->config.opt_serialize(key) << "\"/>\n";
} }
//add the shared mesh logic
const TriangleMesh* current_mesh = volume->mesh_ptr();
std::map<const TriangleMesh*,int>::iterator mesh_iter;
mesh_iter = shared_meshes.find(current_mesh);
if (mesh_iter != shared_meshes.end()) {
stream << " <" << METADATA_TAG << " "<< KEY_ATTR << "=\"" << MESH_SHARED_KEY << "\" " << VALUE_ATTR << "=\"" << mesh_iter->second << "\"/>\n";
}
else {
shared_meshes[current_mesh] = it->second;
}
// stores mesh's statistics // stores mesh's statistics
const RepairedMeshErrors& stats = volume->mesh().stats().repaired_errors; const RepairedMeshErrors& stats = volume->mesh().stats().repaired_errors;
stream << " <" << MESH_STAT_TAG << " "; stream << " <" << MESH_STAT_TAG << " ";

View file

@ -667,6 +667,7 @@ std::vector<GCode::LayerToPrint> GCode::collect_layers_to_print(const PrintObjec
--idx_tree_support_layer; --idx_tree_support_layer;
} }
layer_to_print.original_object = &object;
layers_to_print.push_back(layer_to_print); layers_to_print.push_back(layer_to_print);
bool has_extrusions = (layer_to_print.object_layer && layer_to_print.object_layer->has_extrusions()) bool has_extrusions = (layer_to_print.object_layer && layer_to_print.object_layer->has_extrusions())
@ -2151,7 +2152,9 @@ std::vector<GCode::InstanceToPrint> GCode::sort_print_object_instances(
// Sequential print, single object is being printed. // Sequential print, single object is being printed.
for (ObjectByExtruder &object_by_extruder : objects_by_extruder) { for (ObjectByExtruder &object_by_extruder : objects_by_extruder) {
const size_t layer_id = &object_by_extruder - objects_by_extruder.data(); const size_t layer_id = &object_by_extruder - objects_by_extruder.data();
const PrintObject *print_object = layers[layer_id].object(); //BBS:add the support of shared print object
const PrintObject *print_object = layers[layer_id].original_object;
//const PrintObject *print_object = layers[layer_id].object();
if (print_object) if (print_object)
out.emplace_back(object_by_extruder, layer_id, *print_object, single_object_instance_idx); out.emplace_back(object_by_extruder, layer_id, *print_object, single_object_instance_idx);
} }
@ -2161,7 +2164,9 @@ std::vector<GCode::InstanceToPrint> GCode::sort_print_object_instances(
sorted.reserve(objects_by_extruder.size()); sorted.reserve(objects_by_extruder.size());
for (ObjectByExtruder &object_by_extruder : objects_by_extruder) { for (ObjectByExtruder &object_by_extruder : objects_by_extruder) {
const size_t layer_id = &object_by_extruder - objects_by_extruder.data(); const size_t layer_id = &object_by_extruder - objects_by_extruder.data();
const PrintObject *print_object = layers[layer_id].object(); //BBS:add the support of shared print object
const PrintObject *print_object = layers[layer_id].original_object;
//const PrintObject *print_object = layers[layer_id].object();
if (print_object) if (print_object)
sorted.emplace_back(print_object, &object_by_extruder); sorted.emplace_back(print_object, &object_by_extruder);
} }
@ -2171,6 +2176,10 @@ std::vector<GCode::InstanceToPrint> GCode::sort_print_object_instances(
out.reserve(sorted.size()); out.reserve(sorted.size());
for (const PrintInstance *instance : *ordering) { for (const PrintInstance *instance : *ordering) {
const PrintObject &print_object = *instance->print_object; const PrintObject &print_object = *instance->print_object;
//BBS:add the support of shared print object
//const PrintObject* print_obj_ptr = &print_object;
//if (print_object.get_shared_object())
// print_obj_ptr = print_object.get_shared_object();
std::pair<const PrintObject*, ObjectByExtruder*> key(&print_object, nullptr); std::pair<const PrintObject*, ObjectByExtruder*> key(&print_object, nullptr);
auto it = std::lower_bound(sorted.begin(), sorted.end(), key); auto it = std::lower_bound(sorted.begin(), sorted.end(), key);
if (it != sorted.end() && it->first == &print_object) if (it != sorted.end() && it->first == &print_object)

View file

@ -41,11 +41,11 @@ class OozePrevention {
public: public:
bool enable; bool enable;
Points standby_points; Points standby_points;
OozePrevention() : enable(false) {} OozePrevention() : enable(false) {}
std::string pre_toolchange(GCode &gcodegen); std::string pre_toolchange(GCode &gcodegen);
std::string post_toolchange(GCode &gcodegen); std::string post_toolchange(GCode &gcodegen);
private: private:
int _get_temp(GCode &gcodegen); int _get_temp(GCode &gcodegen);
}; };
@ -54,7 +54,7 @@ class Wipe {
public: public:
bool enable; bool enable;
Polyline path; Polyline path;
Wipe() : enable(false) {} Wipe() : enable(false) {}
bool has_path() const { return !this->path.points.empty(); } bool has_path() const { return !this->path.points.empty(); }
void reset_path() { this->path = Polyline(); } void reset_path() { this->path = Polyline(); }
@ -136,15 +136,15 @@ public:
}; };
class GCode { class GCode {
public: public:
GCode() : GCode() :
m_origin(Vec2d::Zero()), m_origin(Vec2d::Zero()),
m_enable_loop_clipping(true), m_enable_loop_clipping(true),
m_enable_cooling_markers(false), m_enable_cooling_markers(false),
m_enable_extrusion_role_markers(false), m_enable_extrusion_role_markers(false),
m_last_processor_extrusion_role(erNone), m_last_processor_extrusion_role(erNone),
m_layer_count(0), m_layer_count(0),
m_layer_index(-1), m_layer_index(-1),
m_layer(nullptr), m_layer(nullptr),
m_object_layer_over_raft(false), m_object_layer_over_raft(false),
//m_volumetric_speed(0), //m_volumetric_speed(0),
@ -201,10 +201,11 @@ public:
// public, so that it could be accessed by free helper functions from GCode.cpp // public, so that it could be accessed by free helper functions from GCode.cpp
struct LayerToPrint struct LayerToPrint
{ {
LayerToPrint() : object_layer(nullptr), support_layer(nullptr), tree_support_layer(nullptr) {} LayerToPrint() : object_layer(nullptr), support_layer(nullptr), tree_support_layer(nullptr), original_object(nullptr) {}
const Layer* object_layer; const Layer* object_layer;
const SupportLayer* support_layer; const SupportLayer* support_layer;
const TreeSupportLayer* tree_support_layer; const TreeSupportLayer* tree_support_layer;
const PrintObject* original_object; //BBS: used for shared object logic
const Layer* layer() const const Layer* layer() const
{ {
if (object_layer != nullptr) if (object_layer != nullptr)
@ -218,7 +219,11 @@ public:
return nullptr; return nullptr;
} }
const PrintObject* object() const { return (this->layer() != nullptr) ? this->layer()->object() : nullptr; }
const PrintObject* object() const
{
return (this->layer() != nullptr) ? this->layer()->object() : nullptr;
}
coordf_t print_z() const coordf_t print_z() const
{ {
coordf_t sum_z = 0.; coordf_t sum_z = 0.;
@ -249,7 +254,7 @@ private:
bool is_open() const { return f; } bool is_open() const { return f; }
bool is_error() const; bool is_error() const;
void flush(); void flush();
void close(); void close();
@ -257,12 +262,12 @@ private:
void write(const std::string& what) { this->write(what.c_str()); } void write(const std::string& what) { this->write(what.c_str()); }
void write(const char* what); void write(const char* what);
// Write a string into a file. // Write a string into a file.
// Add a newline, if the string does not end with a newline already. // Add a newline, if the string does not end with a newline already.
// Used to export a custom G-code section processed by the PlaceholderParser. // Used to export a custom G-code section processed by the PlaceholderParser.
void writeln(const std::string& what); void writeln(const std::string& what);
// Formats and write into a file the given data. // Formats and write into a file the given data.
void write_format(const char* format, ...); void write_format(const char* format, ...);
private: private:
@ -375,7 +380,7 @@ private:
InstanceToPrint(ObjectByExtruder &object_by_extruder, size_t layer_id, const PrintObject &print_object, size_t instance_id) : InstanceToPrint(ObjectByExtruder &object_by_extruder, size_t layer_id, const PrintObject &print_object, size_t instance_id) :
object_by_extruder(object_by_extruder), layer_id(layer_id), print_object(print_object), instance_id(instance_id) {} object_by_extruder(object_by_extruder), layer_id(layer_id), print_object(print_object), instance_id(instance_id) {}
// Repository // Repository
ObjectByExtruder &object_by_extruder; ObjectByExtruder &object_by_extruder;
// Index into std::vector<LayerToPrint>, which contains Object and Support layers for the current print_z, collected for a single object, or for possibly multiple objects with multiple instances. // Index into std::vector<LayerToPrint>, which contains Object and Support layers for the current print_z, collected for a single object, or for possibly multiple objects with multiple instances.
const size_t layer_id; const size_t layer_id;
@ -500,14 +505,14 @@ private:
bool object_layer_over_raft() const { return m_object_layer_over_raft; } bool object_layer_over_raft() const { return m_object_layer_over_raft; }
friend ObjectByExtruder& object_by_extruder( friend ObjectByExtruder& object_by_extruder(
std::map<unsigned int, std::vector<ObjectByExtruder>> &by_extruder, std::map<unsigned int, std::vector<ObjectByExtruder>> &by_extruder,
unsigned int extruder_id, unsigned int extruder_id,
size_t object_idx, size_t object_idx,
size_t num_objects); size_t num_objects);
friend std::vector<ObjectByExtruder::Island>& object_islands_by_extruder( friend std::vector<ObjectByExtruder::Island>& object_islands_by_extruder(
std::map<unsigned int, std::vector<ObjectByExtruder>> &by_extruder, std::map<unsigned int, std::vector<ObjectByExtruder>> &by_extruder,
unsigned int extruder_id, unsigned int extruder_id,
size_t object_idx, size_t object_idx,
size_t num_objects, size_t num_objects,
size_t num_islands); size_t num_islands);

View file

@ -185,10 +185,10 @@ Model Model::read_from_file(const std::string& input_file, DynamicPrintConfig* c
if (model.objects.empty()) if (model.objects.empty())
throw Slic3r::RuntimeError("The supplied file couldn't be read because it's empty"); throw Slic3r::RuntimeError("The supplied file couldn't be read because it's empty");
for (ModelObject *o : model.objects) for (ModelObject *o : model.objects)
o->input_file = input_file; o->input_file = input_file;
if (options & LoadStrategy::AddDefaultInstances) if (options & LoadStrategy::AddDefaultInstances)
model.add_default_instances(); model.add_default_instances();
@ -259,14 +259,14 @@ Model Model::read_from_archive(const std::string& input_file, DynamicPrintConfig
//BBS //BBS
//CustomGCode::update_custom_gcode_per_print_z_from_config(model.custom_gcode_per_print_z, config); //CustomGCode::update_custom_gcode_per_print_z_from_config(model.custom_gcode_per_print_z, config);
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ":" << __LINE__ << boost::format("import 3mf IMPORT_STAGE_UPDATE_GCODE\n"); BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ":" << __LINE__ << boost::format("import 3mf IMPORT_STAGE_UPDATE_GCODE\n");
if (proFn) { if (proFn) {
proFn(IMPORT_STAGE_UPDATE_GCODE, 0, 1, cb_cancel); proFn(IMPORT_STAGE_UPDATE_GCODE, 0, 1, cb_cancel);
if (cb_cancel) if (cb_cancel)
throw Slic3r::RuntimeError("Canceled"); throw Slic3r::RuntimeError("Canceled");
} }
CustomGCode::check_mode_for_custom_gcode_per_print_z(model.custom_gcode_per_print_z); CustomGCode::check_mode_for_custom_gcode_per_print_z(model.custom_gcode_per_print_z);
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ":" << __LINE__ << boost::format("import 3mf IMPORT_STAGE_CHECK_MODE_GCODE\n"); BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ":" << __LINE__ << boost::format("import 3mf IMPORT_STAGE_CHECK_MODE_GCODE\n");
@ -416,7 +416,7 @@ void Model::collect_reusable_objects(std::vector<ObjectBase*>& objects)
std::mem_fn(&ObjectBase::id)); std::mem_fn(&ObjectBase::id));
model_object->volumes.clear(); model_object->volumes.clear();
} }
// we never own these objects // we never own these objects
this->objects.clear(); this->objects.clear();
} }
@ -591,7 +591,7 @@ void Model::convert_multipart_object(unsigned int max_extruders)
assert(this->objects.size() >= 2); assert(this->objects.size() >= 2);
if (this->objects.size() < 2) if (this->objects.size() < 2)
return; return;
ModelObject* object = new ModelObject(this); ModelObject* object = new ModelObject(this);
object->input_file = this->objects.front()->input_file; object->input_file = this->objects.front()->input_file;
object->name = boost::filesystem::path(this->objects.front()->input_file).stem().string(); object->name = boost::filesystem::path(this->objects.front()->input_file).stem().string();
@ -601,7 +601,7 @@ void Model::convert_multipart_object(unsigned int max_extruders)
for (const ModelObject* o : this->objects) for (const ModelObject* o : this->objects)
for (const ModelVolume* v : o->volumes) { for (const ModelVolume* v : o->volumes) {
// If there are more than one object, put all volumes together // If there are more than one object, put all volumes together
// Each object may contain any number of volumes and instances // Each object may contain any number of volumes and instances
// The volumes transformations are relative to the object containing them... // The volumes transformations are relative to the object containing them...
Geometry::Transformation trafo_volume = v->get_transformation(); Geometry::Transformation trafo_volume = v->get_transformation();
@ -620,7 +620,7 @@ void Model::convert_multipart_object(unsigned int max_extruders)
} else { } else {
for (const ModelInstance* i : o->instances) for (const ModelInstance* i : o->instances)
// ...so, transform everything to a common reference system (world) // ...so, transform everything to a common reference system (world)
copy_volume(object->add_volume(*v))->set_transformation(i->get_transformation() * trafo_volume); copy_volume(object->add_volume(*v))->set_transformation(i->get_transformation() * trafo_volume);
} }
} }
@ -1010,6 +1010,20 @@ ModelVolume* ModelObject::add_volume(const ModelVolume &other, TriangleMesh &&me
return v; return v;
} }
ModelVolume* ModelObject::add_volume_with_shared_mesh(const ModelVolume &other, ModelVolumeType type /*= ModelVolumeType::INVALID*/)
{
ModelVolume* v = new ModelVolume(this, other.m_mesh);
if (type != ModelVolumeType::INVALID && v->type() != type)
v->set_type(type);
this->volumes.push_back(v);
// The volume should already be centered at this point of time when copying shared pointers of the triangle mesh and convex hull.
// v->center_geometry_after_creation();
// this->invalidate_bounding_box();
// BBS: backup
Slic3r::save_object_mesh(*this);
return v;
}
void ModelObject::delete_volume(size_t idx) void ModelObject::delete_volume(size_t idx)
{ {
ModelVolumePtrs::iterator i = this->volumes.begin() + idx; ModelVolumePtrs::iterator i = this->volumes.begin() + idx;
@ -1324,7 +1338,7 @@ Polygon ModelObject::convex_hull_2d(const Transform3d& trafo_instance) const
void ModelObject::center_around_origin(bool include_modifiers) void ModelObject::center_around_origin(bool include_modifiers)
{ {
// calculate the displacements needed to // calculate the displacements needed to
// center this object around the origin // center this object around the origin
const BoundingBoxf3 bb = include_modifiers ? full_raw_mesh_bounding_box() : raw_mesh_bounding_box(); const BoundingBoxf3 bb = include_modifiers ? full_raw_mesh_bounding_box() : raw_mesh_bounding_box();
@ -1476,8 +1490,8 @@ void ModelObject::convert_units(ModelObjectPtrs& new_objects, ConversionType con
// Perform conversion only if the target "imperial" state is different from the current one. // Perform conversion only if the target "imperial" state is different from the current one.
// This check supports conversion of "mixed" set of volumes, each with different "imperial" state. // This check supports conversion of "mixed" set of volumes, each with different "imperial" state.
if (//vol->source.is_converted_from_inches != from_imperial && if (//vol->source.is_converted_from_inches != from_imperial &&
(volume_idxs.empty() || (volume_idxs.empty() ||
std::find(volume_idxs.begin(), volume_idxs.end(), vol_idx) != volume_idxs.end())) { std::find(volume_idxs.begin(), volume_idxs.end(), vol_idx) != volume_idxs.end())) {
vol->scale_geometry_after_creation(koef); vol->scale_geometry_after_creation(koef);
vol->set_offset(Vec3d(koef, koef, koef).cwiseProduct(volume->get_offset())); vol->set_offset(Vec3d(koef, koef, koef).cwiseProduct(volume->get_offset()));
@ -1598,7 +1612,7 @@ ModelObjectPtrs ModelObject::cut(size_t instance, std::array<Vec3d, 4> plane_poi
if (attributes.has(ModelObjectCutAttribute::KeepLower)) if (attributes.has(ModelObjectCutAttribute::KeepLower))
lower->add_volume(*volume); lower->add_volume(*volume);
} }
else if (! volume->mesh().empty()) { else if (! volume->mesh().empty()) {
// Transform the mesh by the combined transformation matrix. // Transform the mesh by the combined transformation matrix.
// Flip the triangles in case the composite transformation is left handed. // Flip the triangles in case the composite transformation is left handed.
TriangleMesh mesh(volume->mesh()); TriangleMesh mesh(volume->mesh());
@ -1744,7 +1758,7 @@ ModelObjectPtrs ModelObject::segment(size_t instance, unsigned int max_extruders
// Modifiers are not cut, but we still need to add the instance transformation // Modifiers are not cut, but we still need to add the instance transformation
// to the modifier volume transformation to preserve their shape properly. // to the modifier volume transformation to preserve their shape properly.
volume->set_transformation(Geometry::Transformation(instance_matrix * volume_matrix)); volume->set_transformation(Geometry::Transformation(instance_matrix * volume_matrix));
upper->add_volume(*volume); upper->add_volume(*volume);
} }
else if (!volume->mesh().empty()) { else if (!volume->mesh().empty()) {
// Transform the mesh by the combined transformation matrix. // Transform the mesh by the combined transformation matrix.
@ -2185,7 +2199,7 @@ void ModelObject::print_info() const
using namespace std; using namespace std;
cout << fixed; cout << fixed;
boost::nowide::cout << "[" << boost::filesystem::path(this->input_file).filename().string() << "]" << endl; boost::nowide::cout << "[" << boost::filesystem::path(this->input_file).filename().string() << "]" << endl;
TriangleMesh mesh = this->raw_mesh(); TriangleMesh mesh = this->raw_mesh();
BoundingBoxf3 bb = mesh.bounding_box(); BoundingBoxf3 bb = mesh.bounding_box();
Vec3d size = bb.size(); Vec3d size = bb.size();
@ -2203,7 +2217,7 @@ void ModelObject::print_info() const
cout << "manifold = " << (mesh.stats().manifold() ? "yes" : "no") << endl; cout << "manifold = " << (mesh.stats().manifold() ? "yes" : "no") << endl;
if (! mesh.stats().manifold()) if (! mesh.stats().manifold())
cout << "open_edges = " << mesh.stats().open_edges << endl; cout << "open_edges = " << mesh.stats().open_edges << endl;
if (mesh.stats().repaired()) { if (mesh.stats().repaired()) {
const RepairedMeshErrors& stats = mesh.stats().repaired_errors; const RepairedMeshErrors& stats = mesh.stats().repaired_errors;
if (stats.degenerate_facets > 0) if (stats.degenerate_facets > 0)
@ -2286,7 +2300,7 @@ void ModelVolume::set_material_id(t_model_material_id material_id)
} }
ModelMaterial* ModelVolume::material() const ModelMaterial* ModelVolume::material() const
{ {
return this->object->get_model()->get_material(m_material_id); return this->object->get_model()->get_material(m_material_id);
} }
@ -2362,8 +2376,10 @@ void ModelVolume::center_geometry_after_creation(bool update_source_offset)
Vec3d shift = this->mesh().bounding_box().center(); Vec3d shift = this->mesh().bounding_box().center();
if (!shift.isApprox(Vec3d::Zero())) if (!shift.isApprox(Vec3d::Zero()))
{ {
if (m_mesh) if (m_mesh) {
const_cast<TriangleMesh*>(m_mesh.get())->translate(-(float)shift(0), -(float)shift(1), -(float)shift(2)); const_cast<TriangleMesh*>(m_mesh.get())->translate(-(float)shift(0), -(float)shift(1), -(float)shift(2));
const_cast<TriangleMesh*>(m_mesh.get())->set_init_shift(shift);
}
if (m_convex_hull) if (m_convex_hull)
const_cast<TriangleMesh*>(m_convex_hull.get())->translate(-(float)shift(0), -(float)shift(1), -(float)shift(2)); const_cast<TriangleMesh*>(m_convex_hull.get())->translate(-(float)shift(0), -(float)shift(1), -(float)shift(2));
translate(shift); translate(shift);
@ -2803,7 +2819,7 @@ double Model::getThermalLength(const std::vector<ModelVolume*> modelVolumePtrs)
} }
return thermalLength; return thermalLength;
} }
// max printing speed, difference in bed temperature and envirument temperature and bed adhension coefficients are considered // max printing speed, difference in bed temperature and envirument temperature and bed adhension coefficients are considered
double ModelInstance::get_auto_brim_width(double deltaT, double adhension) const double ModelInstance::get_auto_brim_width(double deltaT, double adhension) const
{ {
BoundingBoxf3 raw_bbox = object->raw_mesh_bounding_box(); BoundingBoxf3 raw_bbox = object->raw_mesh_bounding_box();
@ -2896,7 +2912,7 @@ double ModelInstance::get_auto_brim_width() const
void ModelInstance::get_arrange_polygon(void* ap) const void ModelInstance::get_arrange_polygon(void* ap) const
{ {
// static const double SIMPLIFY_TOLERANCE_MM = 0.1; // static const double SIMPLIFY_TOLERANCE_MM = 0.1;
Vec3d rotation = get_rotation(); Vec3d rotation = get_rotation();
rotation.z() = 0.; rotation.z() = 0.;
Transform3d trafo_instance = Transform3d trafo_instance =
@ -2909,7 +2925,7 @@ void ModelInstance::get_arrange_polygon(void* ap) const
// pp = p.simplify(scaled<double>(SIMPLIFY_TOLERANCE_MM)); // pp = p.simplify(scaled<double>(SIMPLIFY_TOLERANCE_MM));
// if (!pp.empty()) p = pp.front(); // if (!pp.empty()) p = pp.front();
// } // }
arrangement::ArrangePolygon& ret = *(arrangement::ArrangePolygon*)ap; arrangement::ArrangePolygon& ret = *(arrangement::ArrangePolygon*)ap;
ret.poly.contour = std::move(p); ret.poly.contour = std::move(p);
ret.translation = Vec2crd{scaled(get_offset(X)), scaled(get_offset(Y))}; ret.translation = Vec2crd{scaled(get_offset(X)), scaled(get_offset(Y))};
@ -3039,6 +3055,12 @@ void FacetsAnnotation::set_triangle_from_string(int triangle_id, const std::stri
} }
} }
bool FacetsAnnotation::equals(const FacetsAnnotation &other) const
{
const std::pair<std::vector<std::pair<int, int>>, std::vector<bool>>& data = other.get_data();
return (m_data == data);
}
// Test whether the two models contain the same number of ModelObjects with the same set of IDs // 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. // ordered in the same order. In that case it is not necessary to kill the background processing.
bool model_object_list_equal(const Model &model_old, const Model &model_new) bool model_object_list_equal(const Model &model_old, const Model &model_new)
@ -3140,22 +3162,22 @@ bool model_property_changed(const ModelObject &model_object_old, const ModelObje
bool model_custom_supports_data_changed(const ModelObject& mo, const ModelObject& mo_new) bool model_custom_supports_data_changed(const ModelObject& mo, const ModelObject& mo_new)
{ {
return model_property_changed(mo, mo_new, return model_property_changed(mo, mo_new,
[](const ModelVolumeType t) { return t == ModelVolumeType::MODEL_PART; }, [](const ModelVolumeType t) { return t == ModelVolumeType::MODEL_PART; },
[](const ModelVolume &mv_old, const ModelVolume &mv_new){ return mv_old.supported_facets.timestamp_matches(mv_new.supported_facets); }); [](const ModelVolume &mv_old, const ModelVolume &mv_new){ return mv_old.supported_facets.timestamp_matches(mv_new.supported_facets); });
} }
bool model_custom_seam_data_changed(const ModelObject& mo, const ModelObject& mo_new) bool model_custom_seam_data_changed(const ModelObject& mo, const ModelObject& mo_new)
{ {
return model_property_changed(mo, mo_new, return model_property_changed(mo, mo_new,
[](const ModelVolumeType t) { return t == ModelVolumeType::MODEL_PART; }, [](const ModelVolumeType t) { return t == ModelVolumeType::MODEL_PART; },
[](const ModelVolume &mv_old, const ModelVolume &mv_new){ return mv_old.seam_facets.timestamp_matches(mv_new.seam_facets); }); [](const ModelVolume &mv_old, const ModelVolume &mv_new){ return mv_old.seam_facets.timestamp_matches(mv_new.seam_facets); });
} }
bool model_mmu_segmentation_data_changed(const ModelObject& mo, const ModelObject& mo_new) bool model_mmu_segmentation_data_changed(const ModelObject& mo, const ModelObject& mo_new)
{ {
return model_property_changed(mo, mo_new, return model_property_changed(mo, mo_new,
[](const ModelVolumeType t) { return t == ModelVolumeType::MODEL_PART; }, [](const ModelVolumeType t) { return t == ModelVolumeType::MODEL_PART; },
[](const ModelVolume &mv_old, const ModelVolume &mv_new){ return mv_old.mmu_segmentation_facets.timestamp_matches(mv_new.mmu_segmentation_facets); }); [](const ModelVolume &mv_old, const ModelVolume &mv_new){ return mv_old.mmu_segmentation_facets.timestamp_matches(mv_new.mmu_segmentation_facets); });
} }
@ -3189,7 +3211,7 @@ bool model_has_advanced_features(const Model &model)
void check_model_ids_validity(const Model &model) void check_model_ids_validity(const Model &model)
{ {
std::set<ObjectID> ids; std::set<ObjectID> ids;
auto check = [&ids](ObjectID id) { auto check = [&ids](ObjectID id) {
assert(id.valid()); assert(id.valid());
assert(ids.find(id) == ids.end()); assert(ids.find(id) == ids.end());
ids.insert(id); ids.insert(id);

View file

@ -308,6 +308,7 @@ public:
ModelVolume* add_volume(TriangleMesh &&mesh, ModelVolumeType type = ModelVolumeType::MODEL_PART); ModelVolume* add_volume(TriangleMesh &&mesh, ModelVolumeType type = ModelVolumeType::MODEL_PART);
ModelVolume* add_volume(const ModelVolume &volume, ModelVolumeType type = ModelVolumeType::INVALID); ModelVolume* add_volume(const ModelVolume &volume, ModelVolumeType type = ModelVolumeType::INVALID);
ModelVolume* add_volume(const ModelVolume &volume, TriangleMesh &&mesh); ModelVolume* add_volume(const ModelVolume &volume, TriangleMesh &&mesh);
ModelVolume* add_volume_with_shared_mesh(const ModelVolume &other, ModelVolumeType type = ModelVolumeType::MODEL_PART);
void delete_volume(size_t idx); void delete_volume(size_t idx);
void clear_volumes(); void clear_volumes();
void sort_volumes(bool full_sort); void sort_volumes(bool full_sort);
@ -617,6 +618,7 @@ public:
void set_triangle_from_string(int triangle_id, const std::string& str); void set_triangle_from_string(int triangle_id, const std::string& str);
// After deserializing the last triangle, shrink data to fit. // 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(); } void shrink_to_fit() { m_data.first.shrink_to_fit(); m_data.second.shrink_to_fit(); }
bool equals(const FacetsAnnotation &other) const;
private: private:
// Constructors to be only called by derived classes. // Constructors to be only called by derived classes.
@ -676,6 +678,7 @@ public:
// The triangular model. // The triangular model.
const TriangleMesh& mesh() const { return *m_mesh.get(); } const TriangleMesh& mesh() const { return *m_mesh.get(); }
const TriangleMesh* mesh_ptr() const { return m_mesh.get(); }
void set_mesh(const TriangleMesh &mesh) { m_mesh = std::make_shared<const TriangleMesh>(mesh); } 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(TriangleMesh &&mesh) { m_mesh = std::make_shared<const TriangleMesh>(std::move(mesh)); }
void set_mesh(const indexed_triangle_set &mesh) { m_mesh = std::make_shared<const TriangleMesh>(mesh); } void set_mesh(const indexed_triangle_set &mesh) { m_mesh = std::make_shared<const TriangleMesh>(mesh); }
@ -859,6 +862,18 @@ private:
if (mesh.facets_count() > 1) if (mesh.facets_count() > 1)
calculate_convex_hull(); calculate_convex_hull();
} }
ModelVolume(ModelObject *object, const std::shared_ptr<const TriangleMesh> &mesh, ModelVolumeType type = ModelVolumeType::MODEL_PART) : m_mesh(mesh), m_type(type), object(object)
{
assert(this->id().valid());
assert(this->config.id().valid());
assert(this->supported_facets.id().valid());
assert(this->seam_facets.id().valid());
assert(this->mmu_segmentation_facets.id().valid());
assert(this->id() != this->config.id());
assert(this->id() != this->supported_facets.id());
assert(this->id() != this->seam_facets.id());
assert(this->id() != this->mmu_segmentation_facets.id());
}
ModelVolume(ModelObject *object, TriangleMesh &&mesh, TriangleMesh &&convex_hull, ModelVolumeType type = ModelVolumeType::MODEL_PART) : 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) { m_mesh(new TriangleMesh(std::move(mesh))), m_convex_hull(new TriangleMesh(std::move(convex_hull))), m_type(type), object(object) {
assert(this->id().valid()); assert(this->id().valid());

View file

@ -1130,6 +1130,46 @@ void Print::auto_assign_extruders(ModelObject* model_object) const
} }
} }
void PrintObject::set_shared_object(PrintObject *object)
{
m_shared_object = object;
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(": this=%1%, found shared object from %2%")%this%m_shared_object;
}
void PrintObject::clear_shared_object()
{
if (m_shared_object) {
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(": this=%1%, clear previous shared object data %2%")%this %m_shared_object;
m_layers.clear();
m_support_layers.clear();
m_tree_support_layers.clear();
m_shared_object = nullptr;
invalidate_all_steps_without_cancel();
}
}
void PrintObject::copy_layers_from_shared_object()
{
if (m_shared_object) {
m_layers.clear();
m_support_layers.clear();
m_tree_support_layers.clear();
firstLayerObjSliceByVolume.clear();
firstLayerObjSliceByGroups.clear();
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(": this=%1%, copied layers from object %2%")%this%m_shared_object;
m_layers = m_shared_object->layers();
m_support_layers = m_shared_object->support_layers();
m_tree_support_layers = m_shared_object->tree_support_layers();
firstLayerObjSliceByVolume = m_shared_object->firstLayerObjSlice();
firstLayerObjSliceByGroups = m_shared_object->firstLayerObjGroups();
}
}
// BBS // BBS
BoundingBox PrintObject::get_first_layer_bbox(float& a, float& layer_height, std::string& name) BoundingBox PrintObject::get_first_layer_bbox(float& a, float& layer_height, std::string& name)
{ {
@ -1179,15 +1219,115 @@ void Print::process()
{ {
name_tbb_thread_pool_threads_set_locale(); name_tbb_thread_pool_threads_set_locale();
//compute the PrintObject with the same geometries
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(": this=%1%, enter")%this;
for (PrintObject *obj : m_objects)
obj->clear_shared_object();
//add the print_object share check logic
auto is_print_object_the_same = [this](const PrintObject* object1, const PrintObject* object2) -> bool{
if (object1->trafo().matrix() != object2->trafo().matrix())
return false;
const ModelObject* model_obj1 = object1->model_object();
const ModelObject* model_obj2 = object2->model_object();
if (model_obj1->volumes.size() != model_obj2->volumes.size())
return false;
bool has_extruder1 = model_obj1->config.has("extruder");
bool has_extruder2 = model_obj2->config.has("extruder");
if ((has_extruder1 != has_extruder2)
|| (has_extruder1 && model_obj1->config.extruder() != model_obj2->config.extruder()))
return false;
for (int index = 0; index < model_obj1->volumes.size(); index++) {
const ModelVolume &model_volume1 = *model_obj1->volumes[index];
const ModelVolume &model_volume2 = *model_obj2->volumes[index];
if (model_volume1.type() != model_volume2.type())
return false;
if (model_volume1.mesh_ptr() != model_volume2.mesh_ptr())
return false;
has_extruder1 = model_volume1.config.has("extruder");
has_extruder2 = model_volume2.config.has("extruder");
if ((has_extruder1 != has_extruder2)
|| (has_extruder1 && model_volume1.config.extruder() != model_volume2.config.extruder()))
return false;
if (!model_volume1.supported_facets.equals(model_volume2.supported_facets))
return false;
if (!model_volume1.seam_facets.equals(model_volume2.seam_facets))
return false;
if (!model_volume1.mmu_segmentation_facets.equals(model_volume2.mmu_segmentation_facets))
return false;
if (model_volume1.config.get() != model_volume2.config.get())
return false;
}
//if (!object1->config().equals(object2->config()))
// return false;
if (model_obj1->config.get() != model_obj2->config.get())
return false;
return true;
};
int object_count = m_objects.size();
std::set<PrintObject*> need_slicing_objects;
for (int index = 0; index < object_count; index++)
{
PrintObject *obj = m_objects[index];
for (PrintObject *slicing_obj : need_slicing_objects)
{
if (is_print_object_the_same(obj, slicing_obj)) {
obj->set_shared_object(slicing_obj);
break;
}
}
if (!obj->get_shared_object())
need_slicing_objects.insert(obj);
}
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(": total object counts %1% in current print, need to slice %2%")%m_objects.size()%need_slicing_objects.size();
BOOST_LOG_TRIVIAL(info) << "Starting the slicing process." << log_memory_info(); BOOST_LOG_TRIVIAL(info) << "Starting the slicing process." << log_memory_info();
for (PrintObject *obj : m_objects) {
if (need_slicing_objects.count(obj) != 0) {
obj->make_perimeters();
}
else {
if (obj->set_started(posSlice))
obj->set_done(posSlice);
if (obj->set_started(posPerimeters))
obj->set_done(posPerimeters);
}
}
for (PrintObject *obj : m_objects) {
if (need_slicing_objects.count(obj) != 0) {
obj->infill();
}
else {
if (obj->set_started(posPrepareInfill))
obj->set_done(posPrepareInfill);
if (obj->set_started(posInfill))
obj->set_done(posInfill);
}
}
for (PrintObject *obj : m_objects) {
if (need_slicing_objects.count(obj) != 0) {
obj->ironing();
}
else {
if (obj->set_started(posIroning))
obj->set_done(posIroning);
}
}
for (PrintObject *obj : m_objects) {
if (need_slicing_objects.count(obj) != 0) {
obj->generate_support_material();
}
else {
if (obj->set_started(posSupportMaterial))
obj->set_done(posSupportMaterial);
}
}
for (PrintObject *obj : m_objects) for (PrintObject *obj : m_objects)
obj->make_perimeters(); {
for (PrintObject *obj : m_objects) if (need_slicing_objects.count(obj) == 0)
obj->infill(); obj->copy_layers_from_shared_object();
for (PrintObject *obj : m_objects) }
obj->ironing();
for (PrintObject *obj : m_objects)
obj->generate_support_material();
if (this->set_started(psWipeTower)) { if (this->set_started(psWipeTower)) {
m_wipe_tower_data.clear(); m_wipe_tower_data.clear();
m_tool_ordering.clear(); m_tool_ordering.clear();
@ -1290,8 +1430,17 @@ void Print::process()
this->set_done(psSkirtBrim); this->set_done(psSkirtBrim);
} }
//BBS //BBS
for (PrintObject *obj : m_objects) for (PrintObject *obj : m_objects) {
obj->simplify_extrusion_path(); if (need_slicing_objects.count(obj) != 0) {
obj->simplify_extrusion_path();
}
else {
if (obj->set_started(posSimplifyPath))
obj->set_done(posSimplifyPath);
if (obj->set_started(posSimplifySupportPath))
obj->set_done(posSimplifySupportPath);
}
}
BOOST_LOG_TRIVIAL(info) << "Slicing process finished." << log_memory_info(); BOOST_LOG_TRIVIAL(info) << "Slicing process finished." << log_memory_info();
} }
@ -1632,7 +1781,7 @@ void Print::_make_wipe_tower()
for (LayerTools& layer_tools : layer_tools_array) { for (LayerTools& layer_tools : layer_tools_array) {
layer_tools.has_wipe_tower = true; layer_tools.has_wipe_tower = true;
if (layer_tools.wipe_tower_partitions == 0) { if (layer_tools.wipe_tower_partitions == 0) {
layer_tools.wipe_tower_partitions = 1; layer_tools.wipe_tower_partitions = 1;
} }
} }
} }

View file

@ -415,6 +415,11 @@ public:
//BBS //BBS
BoundingBox get_first_layer_bbox(float& area, float& layer_height, std::string& name); BoundingBox get_first_layer_bbox(float& area, float& layer_height, std::string& name);
PrintObject* get_shared_object() const { return m_shared_object; }
void set_shared_object(PrintObject *object);
void clear_shared_object();
void copy_layers_from_shared_object();
// BBS: Boundingbox of the first layer // BBS: Boundingbox of the first layer
BoundingBox firstLayerObjectBrimBoundingBox; BoundingBox firstLayerObjectBrimBoundingBox;
private: private:
@ -495,6 +500,8 @@ private:
// BBS: per object skirt // BBS: per object skirt
ExtrusionEntityCollection m_skirt; ExtrusionEntityCollection m_skirt;
PrintObject* m_shared_object{ nullptr };
public: public:
//BBS: When printing multi-material objects, this settings will make slicer to clip the overlapping object parts one by the other. //BBS: When printing multi-material objects, this settings will make slicer to clip the overlapping object parts one by the other.
//(2nd part will be clipped by the 1st, 3rd part will be clipped by the 1st and 2nd etc). //(2nd part will be clipped by the 1st, 3rd part will be clipped by the 1st and 2nd etc).

View file

@ -629,6 +629,8 @@ protected:
{ return m_state.invalidate_multiple(il.begin(), il.end(), PrintObjectBase::cancel_callback(m_print)); } { return m_state.invalidate_multiple(il.begin(), il.end(), PrintObjectBase::cancel_callback(m_print)); }
bool invalidate_all_steps() bool invalidate_all_steps()
{ return m_state.invalidate_all(PrintObjectBase::cancel_callback(m_print)); } { return m_state.invalidate_all(PrintObjectBase::cancel_callback(m_print)); }
bool invalidate_all_steps_without_cancel()
{ return m_state.invalidate_all([](){}); }
bool is_step_started_unguarded(PrintObjectStepEnum step) const { return m_state.is_started_unguarded(step); } bool is_step_started_unguarded(PrintObjectStepEnum step) const { return m_state.is_started_unguarded(step); }
bool is_step_done_unguarded(PrintObjectStepEnum step) const { return m_state.is_done_unguarded(step); } bool is_step_done_unguarded(PrintObjectStepEnum step) const { return m_state.is_done_unguarded(step); }

View file

@ -86,6 +86,7 @@ PrintObject::PrintObject(Print* print, ModelObject* model_object, const Transfor
PrintObject::~PrintObject() PrintObject::~PrintObject()
{ {
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(": this=%1%, m_shared_object %2%")%this%m_shared_object;
if (m_shared_regions && -- m_shared_regions->m_ref_cnt == 0) delete m_shared_regions; if (m_shared_regions && -- m_shared_regions->m_ref_cnt == 0) delete m_shared_regions;
clear_layers(); clear_layers();
clear_support_layers(); clear_support_layers();
@ -535,9 +536,11 @@ std::pair<FillAdaptive::OctreePtr, FillAdaptive::OctreePtr> PrintObject::prepare
void PrintObject::clear_layers() void PrintObject::clear_layers()
{ {
for (Layer *l : m_layers) if (!m_shared_object) {
delete l; for (Layer *l : m_layers)
m_layers.clear(); delete l;
m_layers.clear();
}
} }
Layer* PrintObject::add_layer(int id, coordf_t height, coordf_t print_z, coordf_t slice_z) Layer* PrintObject::add_layer(int id, coordf_t height, coordf_t print_z, coordf_t slice_z)
@ -573,9 +576,11 @@ SupportLayer* PrintObject::get_support_layer_at_printz(coordf_t print_z, coordf_
void PrintObject::clear_tree_support_layers() void PrintObject::clear_tree_support_layers()
{ {
for (TreeSupportLayer* l : m_tree_support_layers) if (!m_shared_object) {
delete l; for (TreeSupportLayer* l : m_tree_support_layers)
m_tree_support_layers.clear(); delete l;
m_tree_support_layers.clear();
}
} }
std::shared_ptr<TreeSupportData> PrintObject::alloc_tree_support_preview_cache() std::shared_ptr<TreeSupportData> PrintObject::alloc_tree_support_preview_cache()
@ -602,9 +607,11 @@ TreeSupportLayer* PrintObject::add_tree_support_layer(int id, coordf_t height, c
void PrintObject::clear_support_layers() void PrintObject::clear_support_layers()
{ {
for (Layer *l : m_support_layers) if (!m_shared_object) {
delete l; for (Layer *l : m_support_layers)
m_support_layers.clear(); delete l;
m_support_layers.clear();
}
} }
SupportLayer* PrintObject::add_support_layer(int id, int interface_id, coordf_t height, coordf_t print_z) SupportLayer* PrintObject::add_support_layer(int id, int interface_id, coordf_t height, coordf_t print_z)

View file

@ -152,10 +152,14 @@ public:
const TriangleMeshStats& stats() const { return m_stats; } const TriangleMeshStats& stats() const { return m_stats; }
void set_init_shift(const Vec3d &offset) { m_init_shift = offset; }
Vec3d get_init_shift() const { return m_init_shift; }
indexed_triangle_set its; indexed_triangle_set its;
private: private:
TriangleMeshStats m_stats; TriangleMeshStats m_stats;
Vec3d m_init_shift {0.0, 0.0, 0.0};
}; };
// Index of face indices incident with a vertex index. // Index of face indices incident with a vertex index.

View file

@ -2740,6 +2740,14 @@ std::vector<size_t> Plater::priv::load_files(const std::vector<fs::path>& input_
context += append; context += append;
show_info(q, context, _L("Newer 3mf version")); show_info(q, context, _L("Newer 3mf version"));
} }
else {
//if the minor version is not matched
if (file_version.min() != app_version.min()) {
wxString text = wxString::Format(_L("The 3mf's version %s is newer than %s's version %s, Suggest to upgrade your software.\n"),
file_version.to_string(), std::string(SLIC3R_APP_FULL_NAME), app_version.to_string());
show_info(q, text, _L("Newer 3mf version"));
}
}
} else if (!load_config) { } else if (!load_config) {
for (ModelObject *model_object : model.objects) { for (ModelObject *model_object : model.objects) {
model_object->config.reset(); model_object->config.reset();