Custom seam: Model integration, backend invalidation, 3MF loading/saving
This commit is contained in:
parent
01b59ff57b
commit
9c59b4f930
@ -87,6 +87,7 @@ const char* TRANSFORM_ATTR = "transform";
|
|||||||
const char* PRINTABLE_ATTR = "printable";
|
const char* PRINTABLE_ATTR = "printable";
|
||||||
const char* INSTANCESCOUNT_ATTR = "instances_count";
|
const char* INSTANCESCOUNT_ATTR = "instances_count";
|
||||||
const char* CUSTOM_SUPPORTS_ATTR = "slic3rpe:custom_supports";
|
const char* CUSTOM_SUPPORTS_ATTR = "slic3rpe:custom_supports";
|
||||||
|
const char* CUSTOM_SEAM_ATTR = "slic3rpe:custom_seam";
|
||||||
|
|
||||||
const char* KEY_ATTR = "key";
|
const char* KEY_ATTR = "key";
|
||||||
const char* VALUE_ATTR = "value";
|
const char* VALUE_ATTR = "value";
|
||||||
@ -285,6 +286,7 @@ namespace Slic3r {
|
|||||||
std::vector<float> vertices;
|
std::vector<float> vertices;
|
||||||
std::vector<unsigned int> triangles;
|
std::vector<unsigned int> triangles;
|
||||||
std::vector<std::string> custom_supports;
|
std::vector<std::string> custom_supports;
|
||||||
|
std::vector<std::string> custom_seam;
|
||||||
|
|
||||||
bool empty()
|
bool empty()
|
||||||
{
|
{
|
||||||
@ -296,6 +298,7 @@ namespace Slic3r {
|
|||||||
vertices.clear();
|
vertices.clear();
|
||||||
triangles.clear();
|
triangles.clear();
|
||||||
custom_supports.clear();
|
custom_supports.clear();
|
||||||
|
custom_seam.clear();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1544,6 +1547,7 @@ namespace Slic3r {
|
|||||||
m_curr_object.geometry.triangles.push_back((unsigned int)get_attribute_value_int(attributes, num_attributes, V3_ATTR));
|
m_curr_object.geometry.triangles.push_back((unsigned int)get_attribute_value_int(attributes, num_attributes, V3_ATTR));
|
||||||
|
|
||||||
m_curr_object.geometry.custom_supports.push_back(get_attribute_value_string(attributes, num_attributes, CUSTOM_SUPPORTS_ATTR));
|
m_curr_object.geometry.custom_supports.push_back(get_attribute_value_string(attributes, num_attributes, CUSTOM_SUPPORTS_ATTR));
|
||||||
|
m_curr_object.geometry.custom_seam.push_back(get_attribute_value_string(attributes, num_attributes, CUSTOM_SEAM_ATTR));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1877,14 +1881,18 @@ namespace Slic3r {
|
|||||||
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();
|
||||||
|
|
||||||
// recreate custom supports from previously loaded attribute
|
// recreate custom supports and seam from previously loaded attribute
|
||||||
for (unsigned i=0; i<triangles_count; ++i) {
|
for (unsigned i=0; i<triangles_count; ++i) {
|
||||||
size_t index = src_start_id/3 + i;
|
size_t index = src_start_id/3 + i;
|
||||||
assert(index < geometry.custom_supports.size());
|
assert(index < geometry.custom_supports.size());
|
||||||
|
assert(index < geometry.custom_seam.size());
|
||||||
if (! geometry.custom_supports[index].empty())
|
if (! geometry.custom_supports[index].empty())
|
||||||
volume->m_supported_facets.set_triangle_from_string(i, geometry.custom_supports[index]);
|
volume->m_supported_facets.set_triangle_from_string(i, geometry.custom_supports[index]);
|
||||||
|
if (! geometry.custom_seam[index].empty())
|
||||||
|
volume->m_seam_facets.set_triangle_from_string(i, geometry.custom_seam[index]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// apply the remaining volume's metadata
|
// apply the remaining volume's metadata
|
||||||
for (const Metadata& metadata : volume_data.metadata)
|
for (const Metadata& metadata : volume_data.metadata)
|
||||||
{
|
{
|
||||||
@ -2401,6 +2409,10 @@ namespace Slic3r {
|
|||||||
if (! custom_supports_data_string.empty())
|
if (! custom_supports_data_string.empty())
|
||||||
stream << CUSTOM_SUPPORTS_ATTR << "=\"" << custom_supports_data_string << "\" ";
|
stream << CUSTOM_SUPPORTS_ATTR << "=\"" << custom_supports_data_string << "\" ";
|
||||||
|
|
||||||
|
std::string custom_seam_data_string = volume->m_seam_facets.get_triangle_as_string(i);
|
||||||
|
if (! custom_seam_data_string.empty())
|
||||||
|
stream << CUSTOM_SEAM_ATTR << "=\"" << custom_seam_data_string << "\" ";
|
||||||
|
|
||||||
stream << "/>\n";
|
stream << "/>\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1007,6 +1007,7 @@ void ModelObject::convert_units(ModelObjectPtrs& new_objects, bool from_imperial
|
|||||||
for (ModelVolume* volume : volumes)
|
for (ModelVolume* volume : volumes)
|
||||||
{
|
{
|
||||||
volume->m_supported_facets.clear();
|
volume->m_supported_facets.clear();
|
||||||
|
volume->m_seam_facets.clear();
|
||||||
if (!volume->mesh().empty()) {
|
if (!volume->mesh().empty()) {
|
||||||
TriangleMesh mesh(volume->mesh());
|
TriangleMesh mesh(volume->mesh());
|
||||||
mesh.require_shared_vertices();
|
mesh.require_shared_vertices();
|
||||||
@ -1112,6 +1113,7 @@ ModelObjectPtrs ModelObject::cut(size_t instance, coordf_t z, bool keep_upper, b
|
|||||||
const auto volume_matrix = volume->get_matrix();
|
const auto volume_matrix = volume->get_matrix();
|
||||||
|
|
||||||
volume->m_supported_facets.clear();
|
volume->m_supported_facets.clear();
|
||||||
|
volume->m_seam_facets.clear();
|
||||||
|
|
||||||
if (! volume->is_model_part()) {
|
if (! volume->is_model_part()) {
|
||||||
// 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
|
||||||
@ -1993,6 +1995,16 @@ bool model_custom_supports_data_changed(const ModelObject& mo, const ModelObject
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool model_custom_seam_data_changed(const ModelObject& mo, const ModelObject& mo_new) {
|
||||||
|
assert(! model_volume_list_changed(mo, mo_new, ModelVolumeType::MODEL_PART));
|
||||||
|
assert(mo.volumes.size() == mo_new.volumes.size());
|
||||||
|
for (size_t i=0; i<mo.volumes.size(); ++i) {
|
||||||
|
if (! mo_new.volumes[i]->m_seam_facets.is_same_as(mo.volumes[i]->m_seam_facets))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
extern bool model_has_multi_part_objects(const Model &model)
|
extern bool model_has_multi_part_objects(const Model &model)
|
||||||
{
|
{
|
||||||
for (const ModelObject *model_object : model.objects)
|
for (const ModelObject *model_object : model.objects)
|
||||||
|
@ -464,6 +464,9 @@ public:
|
|||||||
// List of mesh facets to be supported/unsupported.
|
// List of mesh facets to be supported/unsupported.
|
||||||
FacetsAnnotation m_supported_facets;
|
FacetsAnnotation m_supported_facets;
|
||||||
|
|
||||||
|
// List of seam enforcers/blockers.
|
||||||
|
FacetsAnnotation m_seam_facets;
|
||||||
|
|
||||||
// A parent object owning this modifier volume.
|
// A parent object owning this modifier volume.
|
||||||
ModelObject* get_object() const { return this->object; }
|
ModelObject* get_object() const { return this->object; }
|
||||||
ModelVolumeType type() const { return m_type; }
|
ModelVolumeType type() const { return m_type; }
|
||||||
@ -593,7 +596,7 @@ private:
|
|||||||
ObjectBase(other),
|
ObjectBase(other),
|
||||||
name(other.name), source(other.source), m_mesh(other.m_mesh), m_convex_hull(other.m_convex_hull),
|
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),
|
config(other.config), m_type(other.m_type), object(object), m_transformation(other.m_transformation),
|
||||||
m_supported_facets(other.m_supported_facets)
|
m_supported_facets(other.m_supported_facets), m_seam_facets(other.m_seam_facets)
|
||||||
{
|
{
|
||||||
assert(this->id().valid()); assert(this->config.id().valid()); assert(this->id() != this->config.id());
|
assert(this->id().valid()); assert(this->config.id().valid()); assert(this->id() != this->config.id());
|
||||||
assert(this->id() == other.id() && this->config.id() == other.config.id());
|
assert(this->id() == other.id() && this->config.id() == other.config.id());
|
||||||
@ -612,6 +615,7 @@ private:
|
|||||||
assert(this->config.id().valid()); assert(this->config.id() != other.config.id()); assert(this->id() != this->config.id());
|
assert(this->config.id().valid()); assert(this->config.id() != other.config.id()); assert(this->id() != this->config.id());
|
||||||
|
|
||||||
m_supported_facets.clear();
|
m_supported_facets.clear();
|
||||||
|
m_seam_facets.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
ModelVolume& operator=(ModelVolume &rhs) = delete;
|
ModelVolume& operator=(ModelVolume &rhs) = delete;
|
||||||
@ -625,7 +629,7 @@ private:
|
|||||||
template<class Archive> void load(Archive &ar) {
|
template<class Archive> void load(Archive &ar) {
|
||||||
bool has_convex_hull;
|
bool has_convex_hull;
|
||||||
ar(name, source, m_mesh, m_type, m_material_id, m_transformation,
|
ar(name, source, m_mesh, m_type, m_material_id, m_transformation,
|
||||||
m_is_splittable, has_convex_hull, m_supported_facets);
|
m_is_splittable, has_convex_hull, m_supported_facets, m_seam_facets);
|
||||||
cereal::load_by_value(ar, config);
|
cereal::load_by_value(ar, config);
|
||||||
assert(m_mesh);
|
assert(m_mesh);
|
||||||
if (has_convex_hull) {
|
if (has_convex_hull) {
|
||||||
@ -639,7 +643,7 @@ private:
|
|||||||
template<class Archive> void save(Archive &ar) const {
|
template<class Archive> void save(Archive &ar) const {
|
||||||
bool has_convex_hull = m_convex_hull.get() != nullptr;
|
bool has_convex_hull = m_convex_hull.get() != nullptr;
|
||||||
ar(name, source, m_mesh, m_type, m_material_id, m_transformation,
|
ar(name, source, m_mesh, m_type, m_material_id, m_transformation,
|
||||||
m_is_splittable, has_convex_hull, m_supported_facets);
|
m_is_splittable, has_convex_hull, m_supported_facets, m_seam_facets);
|
||||||
cereal::save_by_value(ar, config);
|
cereal::save_by_value(ar, config);
|
||||||
if (has_convex_hull)
|
if (has_convex_hull)
|
||||||
cereal::save_optional(ar, m_convex_hull);
|
cereal::save_optional(ar, m_convex_hull);
|
||||||
@ -904,6 +908,10 @@ extern bool model_volume_list_changed(const ModelObject &model_object_old, const
|
|||||||
// The function assumes that volumes list is synchronized.
|
// The function assumes that volumes list is synchronized.
|
||||||
extern bool model_custom_supports_data_changed(const ModelObject& mo, const ModelObject& mo_new);
|
extern bool model_custom_supports_data_changed(const ModelObject& mo, const ModelObject& mo_new);
|
||||||
|
|
||||||
|
// Test whether the now ModelObject has newer custom seam data than the old one.
|
||||||
|
// The function assumes that volumes list is synchronized.
|
||||||
|
extern bool model_custom_seam_data_changed(const ModelObject& mo, const ModelObject& mo_new);
|
||||||
|
|
||||||
// If the model has multi-part objects, then it is currently not supported by the SLA mode.
|
// 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.
|
// Either the model cannot be loaded, or a SLA printer has to be activated.
|
||||||
extern bool model_has_multi_part_objects(const Model &model);
|
extern bool model_has_multi_part_objects(const Model &model);
|
||||||
|
@ -404,6 +404,7 @@ static inline void model_volume_list_copy_configs(ModelObject &model_object_dst,
|
|||||||
mv_dst.name = mv_src.name;
|
mv_dst.name = mv_src.name;
|
||||||
static_cast<DynamicPrintConfig&>(mv_dst.config) = static_cast<const DynamicPrintConfig&>(mv_src.config);
|
static_cast<DynamicPrintConfig&>(mv_dst.config) = static_cast<const DynamicPrintConfig&>(mv_src.config);
|
||||||
mv_dst.m_supported_facets = mv_src.m_supported_facets;
|
mv_dst.m_supported_facets = mv_src.m_supported_facets;
|
||||||
|
mv_dst.m_seam_facets = mv_src.m_seam_facets;
|
||||||
//FIXME what to do with the materials?
|
//FIXME what to do with the materials?
|
||||||
// mv_dst.m_material_id = mv_src.m_material_id;
|
// mv_dst.m_material_id = mv_src.m_material_id;
|
||||||
++ i_src;
|
++ i_src;
|
||||||
@ -867,6 +868,9 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_
|
|||||||
model_volume_list_update_supports(model_object, model_object_new);
|
model_volume_list_update_supports(model_object, model_object_new);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (model_custom_seam_data_changed(model_object, model_object_new)) {
|
||||||
|
update_apply_status(this->invalidate_step(psGCodeExport));
|
||||||
|
}
|
||||||
if (! model_parts_differ && ! modifiers_differ) {
|
if (! model_parts_differ && ! modifiers_differ) {
|
||||||
// Synchronize Object's config.
|
// Synchronize Object's config.
|
||||||
bool object_config_changed = model_object.config != model_object_new.config;
|
bool object_config_changed = model_object.config != model_object_new.config;
|
||||||
|
@ -186,10 +186,8 @@ public:
|
|||||||
std::vector<ExPolygons> slice_support_blockers() const { return this->slice_support_volumes(ModelVolumeType::SUPPORT_BLOCKER); }
|
std::vector<ExPolygons> slice_support_blockers() const { return this->slice_support_volumes(ModelVolumeType::SUPPORT_BLOCKER); }
|
||||||
std::vector<ExPolygons> slice_support_enforcers() const { return this->slice_support_volumes(ModelVolumeType::SUPPORT_ENFORCER); }
|
std::vector<ExPolygons> slice_support_enforcers() const { return this->slice_support_volumes(ModelVolumeType::SUPPORT_ENFORCER); }
|
||||||
|
|
||||||
// Helpers to project custom supports on slices
|
// Helpers to project custom facets on slices
|
||||||
void project_and_append_custom_supports(EnforcerBlockerType type, std::vector<ExPolygons>& expolys) const;
|
void project_and_append_custom_facets(bool seam, EnforcerBlockerType type, std::vector<ExPolygons>& expolys) const;
|
||||||
void project_and_append_custom_enforcers(std::vector<ExPolygons>& enforcers) const { project_and_append_custom_supports(EnforcerBlockerType::ENFORCER, enforcers); }
|
|
||||||
void project_and_append_custom_blockers(std::vector<ExPolygons>& blockers) const { project_and_append_custom_supports(EnforcerBlockerType::BLOCKER, blockers); }
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// to be called from Print only.
|
// to be called from Print only.
|
||||||
|
@ -2669,12 +2669,14 @@ void PrintObject::_generate_support_material()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void PrintObject::project_and_append_custom_supports(
|
void PrintObject::project_and_append_custom_facets(
|
||||||
EnforcerBlockerType type, std::vector<ExPolygons>& expolys) const
|
bool seam, EnforcerBlockerType type, std::vector<ExPolygons>& expolys) const
|
||||||
{
|
{
|
||||||
for (const ModelVolume* mv : this->model_object()->volumes) {
|
for (const ModelVolume* mv : this->model_object()->volumes) {
|
||||||
const indexed_triangle_set custom_facets = mv->m_supported_facets.get_facets(*mv, type);
|
const indexed_triangle_set custom_facets = seam
|
||||||
if (custom_facets.indices.empty())
|
? mv->m_seam_facets.get_facets(*mv, type)
|
||||||
|
: mv->m_supported_facets.get_facets(*mv, type);
|
||||||
|
if (! mv->is_model_part() || custom_facets.indices.empty())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
const Transform3f& tr1 = mv->get_matrix().cast<float>();
|
const Transform3f& tr1 = mv->get_matrix().cast<float>();
|
||||||
@ -2721,7 +2723,7 @@ void PrintObject::project_and_append_custom_supports(
|
|||||||
|
|
||||||
// Ignore triangles with upward-pointing normal. Don't forget about mirroring.
|
// Ignore triangles with upward-pointing normal. Don't forget about mirroring.
|
||||||
float z_comp = (facet[1]-facet[0]).cross(facet[2]-facet[0]).z();
|
float z_comp = (facet[1]-facet[0]).cross(facet[2]-facet[0]).z();
|
||||||
if (tr_det_sign * z_comp > 0.)
|
if (! seam && tr_det_sign * z_comp > 0.)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// Sort the three vertices according to z-coordinate.
|
// Sort the three vertices according to z-coordinate.
|
||||||
|
@ -972,8 +972,8 @@ PrintObjectSupportMaterial::MyLayersPtr PrintObjectSupportMaterial::top_contact_
|
|||||||
std::vector<ExPolygons> blockers = object.slice_support_blockers();
|
std::vector<ExPolygons> blockers = object.slice_support_blockers();
|
||||||
|
|
||||||
// Append custom supports.
|
// Append custom supports.
|
||||||
object.project_and_append_custom_enforcers(enforcers);
|
object.project_and_append_custom_facets(false, EnforcerBlockerType::ENFORCER, enforcers);
|
||||||
object.project_and_append_custom_blockers(blockers);
|
object.project_and_append_custom_facets(false, EnforcerBlockerType::BLOCKER, blockers);
|
||||||
|
|
||||||
// Output layers, sorted by top Z.
|
// Output layers, sorted by top Z.
|
||||||
MyLayersPtr contact_out;
|
MyLayersPtr contact_out;
|
||||||
|
@ -172,7 +172,7 @@ void GLGizmoSeam::update_model_object() const
|
|||||||
if (! mv->is_model_part())
|
if (! mv->is_model_part())
|
||||||
continue;
|
continue;
|
||||||
++idx;
|
++idx;
|
||||||
updated |= mv->m_supported_facets.set(*m_triangle_selectors[idx].get());
|
updated |= mv->m_seam_facets.set(*m_triangle_selectors[idx].get());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (updated)
|
if (updated)
|
||||||
@ -199,7 +199,7 @@ void GLGizmoSeam::update_from_model_object()
|
|||||||
const TriangleMesh* mesh = &mv->mesh();
|
const TriangleMesh* mesh = &mv->mesh();
|
||||||
|
|
||||||
m_triangle_selectors.emplace_back(std::make_unique<TriangleSelectorGUI>(*mesh));
|
m_triangle_selectors.emplace_back(std::make_unique<TriangleSelectorGUI>(*mesh));
|
||||||
m_triangle_selectors.back()->deserialize(mv->m_supported_facets.get_data());
|
m_triangle_selectors.back()->deserialize(mv->m_seam_facets.get_data());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user