mirror of
https://github.com/SoftFever/OrcaSlicer.git
synced 2025-07-25 07:34:03 -06:00
Merge branch 'vb_admesh_fix'
This commit is contained in:
commit
c95a324c3f
36 changed files with 2313 additions and 2894 deletions
|
@ -15,7 +15,7 @@
|
|||
|
||||
#include "FillRectilinear3.hpp"
|
||||
|
||||
#define SLIC3R_DEBUG
|
||||
// #define SLIC3R_DEBUG
|
||||
|
||||
// Make assert active if SLIC3R_DEBUG
|
||||
#ifdef SLIC3R_DEBUG
|
||||
|
|
|
@ -1489,10 +1489,10 @@ namespace Slic3r {
|
|||
}
|
||||
|
||||
// splits volume out of imported geometry
|
||||
unsigned int triangles_count = volume_data.last_triangle_id - volume_data.first_triangle_id + 1;
|
||||
ModelVolume* volume = object.add_volume(TriangleMesh());
|
||||
stl_file& stl = volume->mesh.stl;
|
||||
stl.stats.type = inmemory;
|
||||
TriangleMesh triangle_mesh;
|
||||
stl_file &stl = triangle_mesh.stl;
|
||||
unsigned int triangles_count = volume_data.last_triangle_id - volume_data.first_triangle_id + 1;
|
||||
stl.stats.type = inmemory;
|
||||
stl.stats.number_of_facets = (uint32_t)triangles_count;
|
||||
stl.stats.original_num_facets = (int)stl.stats.number_of_facets;
|
||||
stl_allocate(&stl);
|
||||
|
@ -1509,9 +1509,11 @@ namespace Slic3r {
|
|||
}
|
||||
}
|
||||
|
||||
stl_get_size(&stl);
|
||||
volume->mesh.repair();
|
||||
volume->center_geometry();
|
||||
stl_get_size(&stl);
|
||||
triangle_mesh.repair();
|
||||
|
||||
ModelVolume* volume = object.add_volume(std::move(triangle_mesh));
|
||||
volume->center_geometry_after_creation();
|
||||
volume->calculate_convex_hull();
|
||||
|
||||
// apply volume's name and config data
|
||||
|
@ -1879,29 +1881,28 @@ namespace Slic3r {
|
|||
if (volume == nullptr)
|
||||
continue;
|
||||
|
||||
if (!volume->mesh().repaired)
|
||||
throw std::runtime_error("store_3mf() requires repair()");
|
||||
if (!volume->mesh().has_shared_vertices())
|
||||
throw std::runtime_error("store_3mf() requires shared vertices");
|
||||
|
||||
volumes_offsets.insert(VolumeToOffsetsMap::value_type(volume, Offsets(vertices_count))).first;
|
||||
|
||||
if (!volume->mesh.repaired)
|
||||
volume->mesh.repair();
|
||||
|
||||
stl_file& stl = volume->mesh.stl;
|
||||
if (stl.v_shared == nullptr)
|
||||
stl_generate_shared_vertices(&stl);
|
||||
|
||||
if (stl.stats.shared_vertices == 0)
|
||||
const indexed_triangle_set &its = volume->mesh().its;
|
||||
if (its.vertices.empty())
|
||||
{
|
||||
add_error("Found invalid mesh");
|
||||
return false;
|
||||
}
|
||||
|
||||
vertices_count += stl.stats.shared_vertices;
|
||||
vertices_count += its.vertices.size();
|
||||
|
||||
const Transform3d& matrix = volume->get_matrix();
|
||||
|
||||
for (int i = 0; i < stl.stats.shared_vertices; ++i)
|
||||
for (size_t i = 0; i < its.vertices.size(); ++i)
|
||||
{
|
||||
stream << " <" << VERTEX_TAG << " ";
|
||||
Vec3f v = (matrix * stl.v_shared[i].cast<double>()).cast<float>();
|
||||
Vec3f v = (matrix * its.vertices[i].cast<double>()).cast<float>();
|
||||
stream << "x=\"" << v(0) << "\" ";
|
||||
stream << "y=\"" << v(1) << "\" ";
|
||||
stream << "z=\"" << v(2) << "\" />\n";
|
||||
|
@ -1920,19 +1921,19 @@ namespace Slic3r {
|
|||
VolumeToOffsetsMap::iterator volume_it = volumes_offsets.find(volume);
|
||||
assert(volume_it != volumes_offsets.end());
|
||||
|
||||
stl_file& stl = volume->mesh.stl;
|
||||
const indexed_triangle_set &its = volume->mesh().its;
|
||||
|
||||
// updates triangle offsets
|
||||
volume_it->second.first_triangle_id = triangles_count;
|
||||
triangles_count += stl.stats.number_of_facets;
|
||||
triangles_count += its.indices.size();
|
||||
volume_it->second.last_triangle_id = triangles_count - 1;
|
||||
|
||||
for (uint32_t i = 0; i < stl.stats.number_of_facets; ++i)
|
||||
for (size_t i = 0; i < its.indices.size(); ++ i)
|
||||
{
|
||||
stream << " <" << TRIANGLE_TAG << " ";
|
||||
for (int j = 0; j < 3; ++j)
|
||||
{
|
||||
stream << "v" << j + 1 << "=\"" << stl.v_indices[i].vertex[j] + volume_it->second.first_vertex_id << "\" ";
|
||||
stream << "v" << j + 1 << "=\"" << its.indices[i][j] + volume_it->second.first_vertex_id << "\" ";
|
||||
}
|
||||
stream << "/>\n";
|
||||
}
|
||||
|
|
|
@ -522,7 +522,8 @@ void AMFParserContext::endElement(const char * /* name */)
|
|||
case NODE_TYPE_VOLUME:
|
||||
{
|
||||
assert(m_object && m_volume);
|
||||
stl_file &stl = m_volume->mesh.stl;
|
||||
TriangleMesh mesh;
|
||||
stl_file &stl = mesh.stl;
|
||||
stl.stats.type = inmemory;
|
||||
stl.stats.number_of_facets = int(m_volume_facets.size() / 3);
|
||||
stl.stats.original_num_facets = stl.stats.number_of_facets;
|
||||
|
@ -533,8 +534,9 @@ void AMFParserContext::endElement(const char * /* name */)
|
|||
memcpy(facet.vertex[v].data(), &m_object_vertices[m_volume_facets[i ++] * 3], 3 * sizeof(float));
|
||||
}
|
||||
stl_get_size(&stl);
|
||||
m_volume->mesh.repair();
|
||||
m_volume->center_geometry();
|
||||
mesh.repair();
|
||||
m_volume->set_mesh(std::move(mesh));
|
||||
m_volume->center_geometry_after_creation();
|
||||
m_volume->calculate_convex_hull();
|
||||
m_volume_facets.clear();
|
||||
m_volume = nullptr;
|
||||
|
@ -923,23 +925,23 @@ bool store_amf(const char *path, Model *model, const DynamicPrintConfig *config)
|
|||
int num_vertices = 0;
|
||||
for (ModelVolume *volume : object->volumes) {
|
||||
vertices_offsets.push_back(num_vertices);
|
||||
if (! volume->mesh.repaired)
|
||||
if (! volume->mesh().repaired)
|
||||
throw std::runtime_error("store_amf() requires repair()");
|
||||
auto &stl = volume->mesh.stl;
|
||||
if (stl.v_shared == nullptr)
|
||||
stl_generate_shared_vertices(&stl);
|
||||
if (! volume->mesh().has_shared_vertices())
|
||||
throw std::runtime_error("store_amf() requires shared vertices");
|
||||
const indexed_triangle_set &its = volume->mesh().its;
|
||||
const Transform3d& matrix = volume->get_matrix();
|
||||
for (size_t i = 0; i < stl.stats.shared_vertices; ++i) {
|
||||
for (size_t i = 0; i < its.vertices.size(); ++i) {
|
||||
stream << " <vertex>\n";
|
||||
stream << " <coordinates>\n";
|
||||
Vec3f v = (matrix * stl.v_shared[i].cast<double>()).cast<float>();
|
||||
Vec3f v = (matrix * its.vertices[i].cast<double>()).cast<float>();
|
||||
stream << " <x>" << v(0) << "</x>\n";
|
||||
stream << " <y>" << v(1) << "</y>\n";
|
||||
stream << " <z>" << v(2) << "</z>\n";
|
||||
stream << " </coordinates>\n";
|
||||
stream << " </vertex>\n";
|
||||
}
|
||||
num_vertices += stl.stats.shared_vertices;
|
||||
num_vertices += its.vertices.size();
|
||||
}
|
||||
stream << " </vertices>\n";
|
||||
for (size_t i_volume = 0; i_volume < object->volumes.size(); ++i_volume) {
|
||||
|
@ -956,10 +958,11 @@ bool store_amf(const char *path, Model *model, const DynamicPrintConfig *config)
|
|||
if (volume->is_modifier())
|
||||
stream << " <metadata type=\"slic3r.modifier\">1</metadata>\n";
|
||||
stream << " <metadata type=\"slic3r.volume_type\">" << ModelVolume::type_to_string(volume->type()) << "</metadata>\n";
|
||||
for (int i = 0; i < (int)volume->mesh.stl.stats.number_of_facets; ++i) {
|
||||
const indexed_triangle_set &its = volume->mesh().its;
|
||||
for (size_t i = 0; i < (int)its.indices.size(); ++i) {
|
||||
stream << " <triangle>\n";
|
||||
for (int j = 0; j < 3; ++j)
|
||||
stream << " <v" << j + 1 << ">" << volume->mesh.stl.v_indices[i].vertex[j] + vertices_offset << "</v" << j + 1 << ">\n";
|
||||
stream << " <v" << j + 1 << ">" << its.indices[i][j] + vertices_offset << "</v" << j + 1 << ">\n";
|
||||
stream << " </triangle>\n";
|
||||
}
|
||||
stream << " </volume>\n";
|
||||
|
|
|
@ -161,16 +161,15 @@ static void extract_model_from_archive(
|
|||
else {
|
||||
// Header has been extracted. Now read the faces.
|
||||
stl_file &stl = mesh.stl;
|
||||
stl.error = 0;
|
||||
stl.stats.type = inmemory;
|
||||
stl.stats.number_of_facets = header.nTriangles;
|
||||
stl.stats.original_num_facets = header.nTriangles;
|
||||
stl_allocate(&stl);
|
||||
if (header.nTriangles > 0 && data.size() == 50 * header.nTriangles + sizeof(StlHeader)) {
|
||||
memcpy((char*)stl.facet_start, data.data() + sizeof(StlHeader), 50 * header.nTriangles);
|
||||
memcpy((char*)stl.facet_start.data(), data.data() + sizeof(StlHeader), 50 * header.nTriangles);
|
||||
if (sizeof(stl_facet) > SIZEOF_STL_FACET) {
|
||||
// The stl.facet_start is not packed tightly. Unpack the array of stl_facets.
|
||||
unsigned char *data = (unsigned char*)stl.facet_start;
|
||||
unsigned char *data = (unsigned char*)stl.facet_start.data();
|
||||
for (size_t i = header.nTriangles - 1; i > 0; -- i)
|
||||
memmove(data + i * sizeof(stl_facet), data + i * SIZEOF_STL_FACET, SIZEOF_STL_FACET);
|
||||
}
|
||||
|
@ -257,7 +256,7 @@ static void extract_model_from_archive(
|
|||
stl.stats.number_of_facets = (uint32_t)facets.size();
|
||||
stl.stats.original_num_facets = (int)facets.size();
|
||||
stl_allocate(&stl);
|
||||
memcpy((void*)stl.facet_start, facets.data(), facets.size() * 50);
|
||||
memcpy((void*)stl.facet_start.data(), facets.data(), facets.size() * 50);
|
||||
stl_get_size(&stl);
|
||||
mesh.repair();
|
||||
// Add a mesh to a model.
|
||||
|
|
|
@ -17,8 +17,7 @@ namespace Slic3r {
|
|||
bool load_stl(const char *path, Model *model, const char *object_name_in)
|
||||
{
|
||||
TriangleMesh mesh;
|
||||
mesh.ReadSTLFile(path);
|
||||
if (mesh.stl.error) {
|
||||
if (! mesh.ReadSTLFile(path)) {
|
||||
// die "Failed to open $file\n" if !-e $path;
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -160,12 +160,6 @@ Model Model::read_from_archive(const std::string &input_file, DynamicPrintConfig
|
|||
return model;
|
||||
}
|
||||
|
||||
void Model::repair()
|
||||
{
|
||||
for (ModelObject *o : this->objects)
|
||||
o->repair();
|
||||
}
|
||||
|
||||
ModelObject* Model::add_object()
|
||||
{
|
||||
this->objects.emplace_back(new ModelObject(this));
|
||||
|
@ -472,7 +466,7 @@ bool Model::looks_like_multipart_object() const
|
|||
if (obj->volumes.size() > 1 || obj->config.keys().size() > 1)
|
||||
return false;
|
||||
for (const ModelVolume *vol : obj->volumes) {
|
||||
double zmin_this = vol->mesh.bounding_box().min(2);
|
||||
double zmin_this = vol->mesh().bounding_box().min(2);
|
||||
if (zmin == std::numeric_limits<double>::max())
|
||||
zmin = zmin_this;
|
||||
else if (std::abs(zmin - zmin_this) > EPSILON)
|
||||
|
@ -679,7 +673,7 @@ ModelVolume* ModelObject::add_volume(const TriangleMesh &mesh)
|
|||
{
|
||||
ModelVolume* v = new ModelVolume(this, mesh);
|
||||
this->volumes.push_back(v);
|
||||
v->center_geometry();
|
||||
v->center_geometry_after_creation();
|
||||
this->invalidate_bounding_box();
|
||||
return v;
|
||||
}
|
||||
|
@ -688,7 +682,7 @@ ModelVolume* ModelObject::add_volume(TriangleMesh &&mesh)
|
|||
{
|
||||
ModelVolume* v = new ModelVolume(this, std::move(mesh));
|
||||
this->volumes.push_back(v);
|
||||
v->center_geometry();
|
||||
v->center_geometry_after_creation();
|
||||
this->invalidate_bounding_box();
|
||||
return v;
|
||||
}
|
||||
|
@ -697,8 +691,9 @@ ModelVolume* ModelObject::add_volume(const ModelVolume &other)
|
|||
{
|
||||
ModelVolume* v = new ModelVolume(this, other);
|
||||
this->volumes.push_back(v);
|
||||
v->center_geometry();
|
||||
this->invalidate_bounding_box();
|
||||
// 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();
|
||||
return v;
|
||||
}
|
||||
|
||||
|
@ -706,7 +701,7 @@ ModelVolume* ModelObject::add_volume(const ModelVolume &other, TriangleMesh &&me
|
|||
{
|
||||
ModelVolume* v = new ModelVolume(this, other, std::move(mesh));
|
||||
this->volumes.push_back(v);
|
||||
v->center_geometry();
|
||||
v->center_geometry_after_creation();
|
||||
this->invalidate_bounding_box();
|
||||
return v;
|
||||
}
|
||||
|
@ -827,7 +822,7 @@ TriangleMesh ModelObject::raw_mesh() const
|
|||
for (const ModelVolume *v : this->volumes)
|
||||
if (v->is_model_part())
|
||||
{
|
||||
TriangleMesh vol_mesh(v->mesh);
|
||||
TriangleMesh vol_mesh(v->mesh());
|
||||
vol_mesh.transform(v->get_matrix());
|
||||
mesh.merge(vol_mesh);
|
||||
}
|
||||
|
@ -840,7 +835,7 @@ TriangleMesh ModelObject::full_raw_mesh() const
|
|||
TriangleMesh mesh;
|
||||
for (const ModelVolume *v : this->volumes)
|
||||
{
|
||||
TriangleMesh vol_mesh(v->mesh);
|
||||
TriangleMesh vol_mesh(v->mesh());
|
||||
vol_mesh.transform(v->get_matrix());
|
||||
mesh.merge(vol_mesh);
|
||||
}
|
||||
|
@ -854,7 +849,7 @@ const BoundingBoxf3& ModelObject::raw_mesh_bounding_box() const
|
|||
m_raw_mesh_bounding_box.reset();
|
||||
for (const ModelVolume *v : this->volumes)
|
||||
if (v->is_model_part())
|
||||
m_raw_mesh_bounding_box.merge(v->mesh.transformed_bounding_box(v->get_matrix()));
|
||||
m_raw_mesh_bounding_box.merge(v->mesh().transformed_bounding_box(v->get_matrix()));
|
||||
}
|
||||
return m_raw_mesh_bounding_box;
|
||||
}
|
||||
|
@ -863,7 +858,7 @@ BoundingBoxf3 ModelObject::full_raw_mesh_bounding_box() const
|
|||
{
|
||||
BoundingBoxf3 bb;
|
||||
for (const ModelVolume *v : this->volumes)
|
||||
bb.merge(v->mesh.transformed_bounding_box(v->get_matrix()));
|
||||
bb.merge(v->mesh().transformed_bounding_box(v->get_matrix()));
|
||||
return bb;
|
||||
}
|
||||
|
||||
|
@ -881,7 +876,7 @@ const BoundingBoxf3& ModelObject::raw_bounding_box() const
|
|||
for (const ModelVolume *v : this->volumes)
|
||||
{
|
||||
if (v->is_model_part())
|
||||
m_raw_bounding_box.merge(v->mesh.transformed_bounding_box(inst_matrix * v->get_matrix()));
|
||||
m_raw_bounding_box.merge(v->mesh().transformed_bounding_box(inst_matrix * v->get_matrix()));
|
||||
}
|
||||
}
|
||||
return m_raw_bounding_box;
|
||||
|
@ -895,7 +890,7 @@ BoundingBoxf3 ModelObject::instance_bounding_box(size_t instance_idx, bool dont_
|
|||
for (ModelVolume *v : this->volumes)
|
||||
{
|
||||
if (v->is_model_part())
|
||||
bb.merge(v->mesh.transformed_bounding_box(inst_matrix * v->get_matrix()));
|
||||
bb.merge(v->mesh().transformed_bounding_box(inst_matrix * v->get_matrix()));
|
||||
}
|
||||
return bb;
|
||||
}
|
||||
|
@ -908,21 +903,20 @@ Polygon ModelObject::convex_hull_2d(const Transform3d &trafo_instance) const
|
|||
Points pts;
|
||||
for (const ModelVolume *v : this->volumes)
|
||||
if (v->is_model_part()) {
|
||||
const stl_file &stl = v->mesh.stl;
|
||||
Transform3d trafo = trafo_instance * v->get_matrix();
|
||||
if (stl.v_shared == nullptr) {
|
||||
const indexed_triangle_set &its = v->mesh().its;
|
||||
if (its.vertices.empty()) {
|
||||
// Using the STL faces.
|
||||
for (unsigned int i = 0; i < stl.stats.number_of_facets; ++ i) {
|
||||
const stl_facet &facet = stl.facet_start[i];
|
||||
const stl_file& stl = v->mesh().stl;
|
||||
for (const stl_facet &facet : stl.facet_start)
|
||||
for (size_t j = 0; j < 3; ++ j) {
|
||||
Vec3d p = trafo * facet.vertex[j].cast<double>();
|
||||
pts.emplace_back(coord_t(scale_(p.x())), coord_t(scale_(p.y())));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Using the shared vertices should be a bit quicker than using the STL faces.
|
||||
for (int i = 0; i < stl.stats.shared_vertices; ++ i) {
|
||||
Vec3d p = trafo * stl.v_shared[i].cast<double>();
|
||||
for (size_t i = 0; i < its.vertices.size(); ++ i) {
|
||||
Vec3d p = trafo * its.vertices[i].cast<double>();
|
||||
pts.emplace_back(coord_t(scale_(p.x())), coord_t(scale_(p.y())));
|
||||
}
|
||||
}
|
||||
|
@ -1039,6 +1033,7 @@ void ModelObject::mirror(Axis axis)
|
|||
this->invalidate_bounding_box();
|
||||
}
|
||||
|
||||
// This method could only be called before the meshes of this ModelVolumes are not shared!
|
||||
void ModelObject::scale_mesh(const Vec3d &versor)
|
||||
{
|
||||
for (ModelVolume *v : this->volumes)
|
||||
|
@ -1062,14 +1057,14 @@ size_t ModelObject::facets_count() const
|
|||
size_t num = 0;
|
||||
for (const ModelVolume *v : this->volumes)
|
||||
if (v->is_model_part())
|
||||
num += v->mesh.stl.stats.number_of_facets;
|
||||
num += v->mesh().stl.stats.number_of_facets;
|
||||
return num;
|
||||
}
|
||||
|
||||
bool ModelObject::needed_repair() const
|
||||
{
|
||||
for (const ModelVolume *v : this->volumes)
|
||||
if (v->is_model_part() && v->mesh.needed_repair())
|
||||
if (v->is_model_part() && v->mesh().needed_repair())
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
@ -1135,11 +1130,12 @@ ModelObjectPtrs ModelObject::cut(size_t instance, coordf_t z, bool keep_upper, b
|
|||
|
||||
// Transform the mesh by the combined transformation matrix.
|
||||
// Flip the triangles in case the composite transformation is left handed.
|
||||
volume->mesh.transform(instance_matrix * volume_matrix, true);
|
||||
TriangleMesh mesh(volume->mesh());
|
||||
mesh.transform(instance_matrix * volume_matrix, true);
|
||||
volume->reset_mesh();
|
||||
|
||||
// Perform cut
|
||||
volume->mesh.require_shared_vertices(); // TriangleMeshSlicer needs this
|
||||
TriangleMeshSlicer tms(&volume->mesh);
|
||||
TriangleMeshSlicer tms(&mesh);
|
||||
tms.cut(float(z), &upper_mesh, &lower_mesh);
|
||||
|
||||
// Reset volume transformation except for offset
|
||||
|
@ -1158,14 +1154,14 @@ ModelObjectPtrs ModelObject::cut(size_t instance, coordf_t z, bool keep_upper, b
|
|||
|
||||
if (keep_upper && upper_mesh.facets_count() > 0) {
|
||||
ModelVolume* vol = upper->add_volume(upper_mesh);
|
||||
vol->name = volume->name;
|
||||
vol->config = volume->config;
|
||||
vol->name = volume->name;
|
||||
vol->config = volume->config;
|
||||
vol->set_material(volume->material_id(), *volume->material());
|
||||
}
|
||||
if (keep_lower && lower_mesh.facets_count() > 0) {
|
||||
ModelVolume* vol = lower->add_volume(lower_mesh);
|
||||
vol->name = volume->name;
|
||||
vol->config = volume->config;
|
||||
vol->name = volume->name;
|
||||
vol->config = volume->config;
|
||||
vol->set_material(volume->material_id(), *volume->material());
|
||||
|
||||
// Compute the lower part instances' bounding boxes to figure out where to place
|
||||
|
@ -1233,7 +1229,7 @@ void ModelObject::split(ModelObjectPtrs* new_objects)
|
|||
}
|
||||
|
||||
ModelVolume* volume = this->volumes.front();
|
||||
TriangleMeshPtrs meshptrs = volume->mesh.split();
|
||||
TriangleMeshPtrs meshptrs = volume->mesh().split();
|
||||
for (TriangleMesh *mesh : meshptrs) {
|
||||
mesh->repair();
|
||||
|
||||
|
@ -1260,12 +1256,6 @@ void ModelObject::split(ModelObjectPtrs* new_objects)
|
|||
return;
|
||||
}
|
||||
|
||||
void ModelObject::repair()
|
||||
{
|
||||
for (ModelVolume *v : this->volumes)
|
||||
v->mesh.repair();
|
||||
}
|
||||
|
||||
// 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.
|
||||
|
@ -1295,8 +1285,8 @@ void ModelObject::bake_xy_rotation_into_meshes(size_t instance_idx)
|
|||
|
||||
// Adjust the meshes.
|
||||
// Transformation to be applied to the meshes.
|
||||
Eigen::Matrix3d mesh_trafo_3x3 = reference_trafo.get_matrix(true, false, uniform_scaling, ! has_mirrorring).matrix().block<3, 3>(0, 0);
|
||||
Transform3d volume_offset_correction = this->instances[instance_idx]->get_transformation().get_matrix().inverse() * reference_trafo.get_matrix();
|
||||
Eigen::Matrix3d mesh_trafo_3x3 = reference_trafo.get_matrix(true, false, uniform_scaling, ! has_mirrorring).matrix().block<3, 3>(0, 0);
|
||||
Transform3d volume_offset_correction = this->instances[instance_idx]->get_transformation().get_matrix().inverse() * reference_trafo.get_matrix();
|
||||
for (ModelVolume *model_volume : this->volumes) {
|
||||
const Geometry::Transformation volume_trafo = model_volume->get_transformation();
|
||||
bool volume_left_handed = volume_trafo.is_left_handed();
|
||||
|
@ -1306,7 +1296,8 @@ void ModelObject::bake_xy_rotation_into_meshes(size_t instance_idx)
|
|||
double volume_new_scaling_factor = volume_uniform_scaling ? volume_trafo.get_scaling_factor().x() : 1.;
|
||||
// Transform the mesh.
|
||||
Matrix3d volume_trafo_3x3 = volume_trafo.get_matrix(true, false, volume_uniform_scaling, !volume_has_mirrorring).matrix().block<3, 3>(0, 0);
|
||||
model_volume->transform_mesh(mesh_trafo_3x3 * volume_trafo_3x3, left_handed != volume_left_handed);
|
||||
// Following method creates a new shared_ptr<TriangleMesh>
|
||||
model_volume->transform_this_mesh(mesh_trafo_3x3 * volume_trafo_3x3, left_handed != volume_left_handed);
|
||||
// Reset the rotation, scaling and mirroring.
|
||||
model_volume->set_rotation(Vec3d(0., 0., 0.));
|
||||
model_volume->set_scaling_factor(Vec3d(volume_new_scaling_factor, volume_new_scaling_factor, volume_new_scaling_factor));
|
||||
|
@ -1347,13 +1338,9 @@ double ModelObject::get_instance_min_z(size_t instance_idx) const
|
|||
|
||||
Transform3d mv = mi * v->get_matrix();
|
||||
const TriangleMesh& hull = v->get_convex_hull();
|
||||
for (uint32_t f = 0; f < hull.stl.stats.number_of_facets; ++f)
|
||||
{
|
||||
const stl_facet* facet = hull.stl.facet_start + f;
|
||||
min_z = std::min(min_z, Vec3d::UnitZ().dot(mv * facet->vertex[0].cast<double>()));
|
||||
min_z = std::min(min_z, Vec3d::UnitZ().dot(mv * facet->vertex[1].cast<double>()));
|
||||
min_z = std::min(min_z, Vec3d::UnitZ().dot(mv * facet->vertex[2].cast<double>()));
|
||||
}
|
||||
for (const stl_facet &facet : hull.stl.facet_start)
|
||||
for (int i = 0; i < 3; ++ i)
|
||||
min_z = std::min(min_z, (mv * facet.vertex[i].cast<double>()).z());
|
||||
}
|
||||
|
||||
return min_z + inst->get_offset(Z);
|
||||
|
@ -1452,7 +1439,7 @@ std::string ModelObject::get_export_filename() const
|
|||
stl_stats ModelObject::get_object_stl_stats() const
|
||||
{
|
||||
if (this->volumes.size() == 1)
|
||||
return this->volumes[0]->mesh.stl.stats;
|
||||
return this->volumes[0]->mesh().stl.stats;
|
||||
|
||||
stl_stats full_stats;
|
||||
memset(&full_stats, 0, sizeof(stl_stats));
|
||||
|
@ -1463,7 +1450,7 @@ stl_stats ModelObject::get_object_stl_stats() const
|
|||
if (volume->id() == this->volumes[0]->id())
|
||||
continue;
|
||||
|
||||
const stl_stats& stats = volume->mesh.stl.stats;
|
||||
const stl_stats& stats = volume->mesh().stl.stats;
|
||||
|
||||
// initialize full_stats (for repaired errors)
|
||||
full_stats.degenerate_facets += stats.degenerate_facets;
|
||||
|
@ -1531,30 +1518,30 @@ bool ModelVolume::is_splittable() const
|
|||
{
|
||||
// the call mesh.is_splittable() is expensive, so cache the value to calculate it only once
|
||||
if (m_is_splittable == -1)
|
||||
m_is_splittable = (int)mesh.is_splittable();
|
||||
m_is_splittable = (int)this->mesh().is_splittable();
|
||||
|
||||
return m_is_splittable == 1;
|
||||
}
|
||||
|
||||
void ModelVolume::center_geometry()
|
||||
void ModelVolume::center_geometry_after_creation()
|
||||
{
|
||||
Vec3d shift = mesh.bounding_box().center();
|
||||
Vec3d shift = this->mesh().bounding_box().center();
|
||||
if (!shift.isApprox(Vec3d::Zero()))
|
||||
{
|
||||
mesh.translate(-(float)shift(0), -(float)shift(1), -(float)shift(2));
|
||||
m_convex_hull.translate(-(float)shift(0), -(float)shift(1), -(float)shift(2));
|
||||
m_mesh->translate(-(float)shift(0), -(float)shift(1), -(float)shift(2));
|
||||
m_convex_hull->translate(-(float)shift(0), -(float)shift(1), -(float)shift(2));
|
||||
translate(shift);
|
||||
}
|
||||
}
|
||||
|
||||
void ModelVolume::calculate_convex_hull()
|
||||
{
|
||||
m_convex_hull = mesh.convex_hull_3d();
|
||||
m_convex_hull = std::make_shared<TriangleMesh>(this->mesh().convex_hull_3d());
|
||||
}
|
||||
|
||||
int ModelVolume::get_mesh_errors_count() const
|
||||
{
|
||||
const stl_stats& stats = this->mesh.stl.stats;
|
||||
const stl_stats& stats = this->mesh().stl.stats;
|
||||
|
||||
return stats.degenerate_facets + stats.edges_fixed + stats.facets_removed +
|
||||
stats.facets_added + stats.facets_reversed + stats.backwards_edges;
|
||||
|
@ -1562,7 +1549,7 @@ int ModelVolume::get_mesh_errors_count() const
|
|||
|
||||
const TriangleMesh& ModelVolume::get_convex_hull() const
|
||||
{
|
||||
return m_convex_hull;
|
||||
return *m_convex_hull.get();
|
||||
}
|
||||
|
||||
ModelVolumeType ModelVolume::type_from_string(const std::string &s)
|
||||
|
@ -1602,7 +1589,7 @@ std::string ModelVolume::type_to_string(const ModelVolumeType t)
|
|||
// This is useful to assign different materials to different volumes of an object.
|
||||
size_t ModelVolume::split(unsigned int max_extruders)
|
||||
{
|
||||
TriangleMeshPtrs meshptrs = this->mesh.split();
|
||||
TriangleMeshPtrs meshptrs = this->mesh().split();
|
||||
if (meshptrs.size() <= 1) {
|
||||
delete meshptrs.front();
|
||||
return 1;
|
||||
|
@ -1619,7 +1606,7 @@ size_t ModelVolume::split(unsigned int max_extruders)
|
|||
mesh->repair();
|
||||
if (idx == 0)
|
||||
{
|
||||
this->mesh = std::move(*mesh);
|
||||
this->set_mesh(std::move(*mesh));
|
||||
this->calculate_convex_hull();
|
||||
// Assign a new unique ID, so that a new GLVolume will be generated.
|
||||
this->set_new_unique_id();
|
||||
|
@ -1628,7 +1615,7 @@ size_t ModelVolume::split(unsigned int max_extruders)
|
|||
this->object->volumes.insert(this->object->volumes.begin() + (++ivolume), new ModelVolume(object, *this, std::move(*mesh)));
|
||||
|
||||
this->object->volumes[ivolume]->set_offset(Vec3d::Zero());
|
||||
this->object->volumes[ivolume]->center_geometry();
|
||||
this->object->volumes[ivolume]->center_geometry_after_creation();
|
||||
this->object->volumes[ivolume]->translate(offset);
|
||||
this->object->volumes[ivolume]->name = name + "_" + std::to_string(idx + 1);
|
||||
this->object->volumes[ivolume]->config.set_deserialize("extruder", Model::get_auto_extruder_id_as_string(max_extruders));
|
||||
|
@ -1694,24 +1681,33 @@ void ModelVolume::mirror(Axis axis)
|
|||
set_mirror(mirror);
|
||||
}
|
||||
|
||||
// This method could only be called before the meshes of this ModelVolumes are not shared!
|
||||
void ModelVolume::scale_geometry(const Vec3d& versor)
|
||||
{
|
||||
mesh.scale(versor);
|
||||
m_convex_hull.scale(versor);
|
||||
m_mesh->scale(versor);
|
||||
m_convex_hull->scale(versor);
|
||||
}
|
||||
|
||||
void ModelVolume::transform_mesh(const Transform3d &mesh_trafo, bool fix_left_handed)
|
||||
void ModelVolume::transform_this_mesh(const Transform3d &mesh_trafo, bool fix_left_handed)
|
||||
{
|
||||
this->mesh.transform(mesh_trafo, fix_left_handed);
|
||||
this->m_convex_hull.transform(mesh_trafo, fix_left_handed);
|
||||
TriangleMesh mesh = this->mesh();
|
||||
mesh.transform(mesh_trafo, fix_left_handed);
|
||||
this->set_mesh(std::move(mesh));
|
||||
TriangleMesh convex_hull = this->get_convex_hull();
|
||||
convex_hull.transform(mesh_trafo, fix_left_handed);
|
||||
this->m_convex_hull = std::make_shared<TriangleMesh>(std::move(convex_hull));
|
||||
// Let the rest of the application know that the geometry changed, so the meshes have to be reloaded.
|
||||
this->set_new_unique_id();
|
||||
}
|
||||
|
||||
void ModelVolume::transform_mesh(const Matrix3d &matrix, bool fix_left_handed)
|
||||
void ModelVolume::transform_this_mesh(const Matrix3d &matrix, bool fix_left_handed)
|
||||
{
|
||||
this->mesh.transform(matrix, fix_left_handed);
|
||||
this->m_convex_hull.transform(matrix, fix_left_handed);
|
||||
TriangleMesh mesh = this->mesh();
|
||||
mesh.transform(matrix, fix_left_handed);
|
||||
this->set_mesh(std::move(mesh));
|
||||
TriangleMesh convex_hull = this->get_convex_hull();
|
||||
convex_hull.transform(matrix, fix_left_handed);
|
||||
this->m_convex_hull = std::make_shared<TriangleMesh>(std::move(convex_hull));
|
||||
// Let the rest of the application know that the geometry changed, so the meshes have to be reloaded.
|
||||
this->set_new_unique_id();
|
||||
}
|
||||
|
|
|
@ -7,7 +7,9 @@
|
|||
#include "Point.hpp"
|
||||
#include "TriangleMesh.hpp"
|
||||
#include "Slicing.hpp"
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
@ -261,6 +263,7 @@ public:
|
|||
void rotate(double angle, const Vec3d& axis);
|
||||
void mirror(Axis axis);
|
||||
|
||||
// This method could only be called before the meshes of this ModelVolumes are not shared!
|
||||
void scale_mesh(const Vec3d& versor);
|
||||
|
||||
size_t materials_count() const;
|
||||
|
@ -268,7 +271,6 @@ public:
|
|||
bool needed_repair() const;
|
||||
ModelObjectPtrs cut(size_t instance, coordf_t z, bool keep_upper = true, bool keep_lower = true, bool rotate_lower = false); // Note: z is in world coordinates
|
||||
void split(ModelObjectPtrs* new_objects);
|
||||
void repair();
|
||||
// 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.
|
||||
|
@ -340,7 +342,12 @@ class ModelVolume : public ModelBase
|
|||
public:
|
||||
std::string name;
|
||||
// The triangular model.
|
||||
TriangleMesh mesh;
|
||||
const TriangleMesh& mesh() const { return *m_mesh.get(); }
|
||||
void set_mesh(const TriangleMesh &mesh) { m_mesh = std::make_shared<TriangleMesh>(mesh); }
|
||||
void set_mesh(TriangleMesh &&mesh) { m_mesh = std::make_shared<TriangleMesh>(std::move(mesh)); }
|
||||
void set_mesh(std::shared_ptr<TriangleMesh> &mesh) { m_mesh = mesh; }
|
||||
void set_mesh(std::unique_ptr<TriangleMesh> &&mesh) { m_mesh = std::move(mesh); }
|
||||
void reset_mesh() { m_mesh = std::make_shared<TriangleMesh>(); }
|
||||
// Configuration parameters specific to an object model geometry or a modifier volume,
|
||||
// overriding the global Slic3r settings and the ModelObject settings.
|
||||
DynamicPrintConfig config;
|
||||
|
@ -377,13 +384,16 @@ public:
|
|||
void rotate(double angle, const Vec3d& axis);
|
||||
void mirror(Axis axis);
|
||||
|
||||
// This method could only be called before the meshes of this ModelVolumes are not shared!
|
||||
void scale_geometry(const Vec3d& versor);
|
||||
|
||||
// translates the mesh and the convex hull so that the origin of their vertices is in the center of this volume's bounding box
|
||||
void center_geometry();
|
||||
// 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!
|
||||
void center_geometry_after_creation();
|
||||
|
||||
void calculate_convex_hull();
|
||||
const TriangleMesh& get_convex_hull() const;
|
||||
std::shared_ptr<const TriangleMesh> get_convex_hull_shared_ptr() const { return m_convex_hull; }
|
||||
// Get count of errors in the mesh
|
||||
int get_mesh_errors_count() const;
|
||||
|
||||
|
@ -430,18 +440,20 @@ protected:
|
|||
|
||||
explicit ModelVolume(const ModelVolume &rhs) = default;
|
||||
void set_model_object(ModelObject *model_object) { object = model_object; }
|
||||
void transform_mesh(const Transform3d& t, bool fix_left_handed);
|
||||
void transform_mesh(const Matrix3d& m, bool fix_left_handed);
|
||||
void transform_this_mesh(const Transform3d& t, bool fix_left_handed);
|
||||
void transform_this_mesh(const Matrix3d& m, bool fix_left_handed);
|
||||
|
||||
private:
|
||||
// Parent object owning this ModelVolume.
|
||||
ModelObject* object;
|
||||
ModelObject* object;
|
||||
// The triangular model.
|
||||
std::shared_ptr<TriangleMesh> m_mesh;
|
||||
// Is it an object to be printed, or a modifier volume?
|
||||
ModelVolumeType m_type;
|
||||
t_model_material_id m_material_id;
|
||||
ModelVolumeType m_type;
|
||||
t_model_material_id m_material_id;
|
||||
// The convex hull of this model's mesh.
|
||||
TriangleMesh m_convex_hull;
|
||||
Geometry::Transformation m_transformation;
|
||||
std::shared_ptr<TriangleMesh> m_convex_hull;
|
||||
Geometry::Transformation m_transformation;
|
||||
|
||||
// flag to optimize the checking if the volume is splittable
|
||||
// -1 -> is unknown value (before first cheking)
|
||||
|
@ -449,24 +461,24 @@ private:
|
|||
// 1 -> is splittable
|
||||
mutable int m_is_splittable{ -1 };
|
||||
|
||||
ModelVolume(ModelObject *object, const TriangleMesh &mesh) : mesh(mesh), m_type(ModelVolumeType::MODEL_PART), object(object)
|
||||
ModelVolume(ModelObject *object, const TriangleMesh &mesh) : m_mesh(new TriangleMesh(mesh)), m_type(ModelVolumeType::MODEL_PART), object(object)
|
||||
{
|
||||
if (mesh.stl.stats.number_of_facets > 1)
|
||||
calculate_convex_hull();
|
||||
}
|
||||
ModelVolume(ModelObject *object, TriangleMesh &&mesh, TriangleMesh &&convex_hull) :
|
||||
mesh(std::move(mesh)), m_convex_hull(std::move(convex_hull)), m_type(ModelVolumeType::MODEL_PART), object(object) {}
|
||||
m_mesh(new TriangleMesh(std::move(mesh))), m_convex_hull(new TriangleMesh(std::move(convex_hull))), m_type(ModelVolumeType::MODEL_PART), object(object) {}
|
||||
|
||||
// Copying an existing volume, therefore this volume will get a copy of the ID assigned.
|
||||
ModelVolume(ModelObject *object, const ModelVolume &other) :
|
||||
ModelBase(other), // copy the ID
|
||||
name(other.name), mesh(other.mesh), m_convex_hull(other.m_convex_hull), config(other.config), m_type(other.m_type), object(object), m_transformation(other.m_transformation)
|
||||
name(other.name), 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)
|
||||
{
|
||||
this->set_material_id(other.material_id());
|
||||
}
|
||||
// Providing a new mesh, therefore this volume will get a new unique ID assigned.
|
||||
ModelVolume(ModelObject *object, const ModelVolume &other, const TriangleMesh &&mesh) :
|
||||
name(other.name), mesh(std::move(mesh)), config(other.config), m_type(other.m_type), object(object), m_transformation(other.m_transformation)
|
||||
name(other.name), m_mesh(new TriangleMesh(std::move(mesh))), config(other.config), m_type(other.m_type), object(object), m_transformation(other.m_transformation)
|
||||
{
|
||||
this->set_material_id(other.material_id());
|
||||
if (mesh.stl.stats.number_of_facets > 1)
|
||||
|
@ -597,10 +609,6 @@ public:
|
|||
static Model read_from_file(const std::string &input_file, DynamicPrintConfig *config = nullptr, bool add_default_instances = true);
|
||||
static Model read_from_archive(const std::string &input_file, DynamicPrintConfig *config, bool add_default_instances = true);
|
||||
|
||||
/// Repair the ModelObjects of the current Model.
|
||||
/// This function calls repair function on each TriangleMesh of each model object volume
|
||||
void repair();
|
||||
|
||||
// Add a new ModelObject to this Model, generate a new ID for this ModelObject.
|
||||
ModelObject* add_object();
|
||||
ModelObject* add_object(const char *name, const char *path, const TriangleMesh &mesh);
|
||||
|
|
|
@ -1797,7 +1797,7 @@ std::vector<ExPolygons> PrintObject::_slice_volumes(const std::vector<float> &z,
|
|||
if (! volumes.empty()) {
|
||||
// Compose mesh.
|
||||
//FIXME better to perform slicing over each volume separately and then to use a Boolean operation to merge them.
|
||||
TriangleMesh mesh(volumes.front()->mesh);
|
||||
TriangleMesh mesh(volumes.front()->mesh());
|
||||
mesh.transform(volumes.front()->get_matrix(), true);
|
||||
assert(mesh.repaired);
|
||||
if (volumes.size() == 1 && mesh.repaired) {
|
||||
|
@ -1806,7 +1806,7 @@ std::vector<ExPolygons> PrintObject::_slice_volumes(const std::vector<float> &z,
|
|||
}
|
||||
for (size_t idx_volume = 1; idx_volume < volumes.size(); ++ idx_volume) {
|
||||
const ModelVolume &model_volume = *volumes[idx_volume];
|
||||
TriangleMesh vol_mesh(model_volume.mesh);
|
||||
TriangleMesh vol_mesh(model_volume.mesh());
|
||||
vol_mesh.transform(model_volume.get_matrix(), true);
|
||||
mesh.merge(vol_mesh);
|
||||
}
|
||||
|
@ -1815,10 +1815,11 @@ std::vector<ExPolygons> PrintObject::_slice_volumes(const std::vector<float> &z,
|
|||
// apply XY shift
|
||||
mesh.translate(- unscale<float>(m_copies_shift(0)), - unscale<float>(m_copies_shift(1)), 0);
|
||||
// perform actual slicing
|
||||
TriangleMeshSlicer mslicer;
|
||||
const Print *print = this->print();
|
||||
auto callback = TriangleMeshSlicer::throw_on_cancel_callback_type([print](){print->throw_if_canceled();});
|
||||
mesh.require_shared_vertices(); // TriangleMeshSlicer needs this
|
||||
// TriangleMeshSlicer needs shared vertices, also this calls the repair() function.
|
||||
mesh.require_shared_vertices();
|
||||
TriangleMeshSlicer mslicer;
|
||||
mslicer.init(&mesh, callback);
|
||||
mslicer.slice(z, float(m_config.slice_closing_radius.value), &layers, callback);
|
||||
m_print->throw_if_canceled();
|
||||
|
@ -1832,7 +1833,7 @@ std::vector<ExPolygons> PrintObject::_slice_volume(const std::vector<float> &z,
|
|||
std::vector<ExPolygons> layers;
|
||||
// Compose mesh.
|
||||
//FIXME better to perform slicing over each volume separately and then to use a Boolean operation to merge them.
|
||||
TriangleMesh mesh(volume.mesh);
|
||||
TriangleMesh mesh(volume.mesh());
|
||||
mesh.transform(volume.get_matrix(), true);
|
||||
if (mesh.repaired) {
|
||||
//FIXME The admesh repair function may break the face connectivity, rather refresh it here as the slicing code relies on it.
|
||||
|
@ -1846,7 +1847,8 @@ std::vector<ExPolygons> PrintObject::_slice_volume(const std::vector<float> &z,
|
|||
TriangleMeshSlicer mslicer;
|
||||
const Print *print = this->print();
|
||||
auto callback = TriangleMeshSlicer::throw_on_cancel_callback_type([print](){print->throw_if_canceled();});
|
||||
mesh.require_shared_vertices(); // TriangleMeshSlicer needs this
|
||||
// TriangleMeshSlicer needs the shared vertices.
|
||||
mesh.require_shared_vertices();
|
||||
mslicer.init(&mesh, callback);
|
||||
mslicer.slice(z, float(m_config.slice_closing_radius.value), &layers, callback);
|
||||
m_print->throw_if_canceled();
|
||||
|
|
|
@ -121,19 +121,10 @@ EigenMesh3D::EigenMesh3D(const TriangleMesh& tmesh): m_aabb(new AABBImpl()) {
|
|||
V.resize(3*stl.stats.number_of_facets, 3);
|
||||
F.resize(stl.stats.number_of_facets, 3);
|
||||
for (unsigned int i = 0; i < stl.stats.number_of_facets; ++i) {
|
||||
const stl_facet* facet = stl.facet_start+i;
|
||||
V(3*i+0, 0) = double(facet->vertex[0](0));
|
||||
V(3*i+0, 1) = double(facet->vertex[0](1));
|
||||
V(3*i+0, 2) = double(facet->vertex[0](2));
|
||||
|
||||
V(3*i+1, 0) = double(facet->vertex[1](0));
|
||||
V(3*i+1, 1) = double(facet->vertex[1](1));
|
||||
V(3*i+1, 2) = double(facet->vertex[1](2));
|
||||
|
||||
V(3*i+2, 0) = double(facet->vertex[2](0));
|
||||
V(3*i+2, 1) = double(facet->vertex[2](1));
|
||||
V(3*i+2, 2) = double(facet->vertex[2](2));
|
||||
|
||||
const stl_facet &facet = stl.facet_start[i];
|
||||
V.block<1, 3>(3 * i + 0, 0) = facet.vertex[0].cast<double>();
|
||||
V.block<1, 3>(3 * i + 1, 0) = facet.vertex[1].cast<double>();
|
||||
V.block<1, 3>(3 * i + 2, 0) = facet.vertex[2].cast<double>();
|
||||
F(i, 0) = int(3*i+0);
|
||||
F(i, 1) = int(3*i+1);
|
||||
F(i, 2) = int(3*i+2);
|
||||
|
|
|
@ -227,7 +227,7 @@ std::vector<coordf_t> layer_height_profile_adaptive(
|
|||
as.set_slicing_parameters(slicing_params);
|
||||
for (const ModelVolume *volume : volumes)
|
||||
if (volume->is_model_part())
|
||||
as.add_mesh(&volume->mesh);
|
||||
as.add_mesh(&volume->mesh());
|
||||
as.prepare();
|
||||
|
||||
// 2) Generate layers using the algorithm of @platsch
|
||||
|
|
|
@ -27,8 +27,8 @@ void SlicingAdaptive::prepare()
|
|||
nfaces_total += (*it_mesh)->stl.stats.number_of_facets;
|
||||
m_faces.reserve(nfaces_total);
|
||||
for (std::vector<const TriangleMesh*>::const_iterator it_mesh = m_meshes.begin(); it_mesh != m_meshes.end(); ++ it_mesh)
|
||||
for (int i = 0; i < (*it_mesh)->stl.stats.number_of_facets; ++ i)
|
||||
m_faces.push_back((*it_mesh)->stl.facet_start + i);
|
||||
for (const stl_facet &face : (*it_mesh)->stl.facet_start)
|
||||
m_faces.emplace_back(&face);
|
||||
|
||||
// 2) Sort faces lexicographically by their Z span.
|
||||
std::sort(m_faces.begin(), m_faces.end(), [](const stl_facet *f1, const stl_facet *f2) {
|
||||
|
|
|
@ -42,20 +42,17 @@
|
|||
|
||||
namespace Slic3r {
|
||||
|
||||
TriangleMesh::TriangleMesh(const Pointf3s &points, const std::vector<Vec3crd>& facets)
|
||||
: repaired(false)
|
||||
TriangleMesh::TriangleMesh(const Pointf3s &points, const std::vector<Vec3crd>& facets) : repaired(false)
|
||||
{
|
||||
stl_initialize(&this->stl);
|
||||
stl_file &stl = this->stl;
|
||||
stl.error = 0;
|
||||
stl.stats.type = inmemory;
|
||||
|
||||
// count facets and allocate memory
|
||||
stl.stats.number_of_facets = facets.size();
|
||||
stl.stats.number_of_facets = (uint32_t)facets.size();
|
||||
stl.stats.original_num_facets = stl.stats.number_of_facets;
|
||||
stl_allocate(&stl);
|
||||
|
||||
for (uint32_t i = 0; i < stl.stats.number_of_facets; i++) {
|
||||
for (uint32_t i = 0; i < stl.stats.number_of_facets; ++ i) {
|
||||
stl_facet facet;
|
||||
facet.vertex[0] = points[facets[i](0)].cast<float>();
|
||||
facet.vertex[1] = points[facets[i](1)].cast<float>();
|
||||
|
@ -73,57 +70,37 @@ TriangleMesh::TriangleMesh(const Pointf3s &points, const std::vector<Vec3crd>& f
|
|||
stl_get_size(&stl);
|
||||
}
|
||||
|
||||
TriangleMesh& TriangleMesh::operator=(const TriangleMesh &other)
|
||||
{
|
||||
stl_close(&this->stl);
|
||||
this->stl = other.stl;
|
||||
this->repaired = other.repaired;
|
||||
this->stl.heads = nullptr;
|
||||
this->stl.tail = nullptr;
|
||||
this->stl.error = other.stl.error;
|
||||
if (other.stl.facet_start != nullptr) {
|
||||
this->stl.facet_start = (stl_facet*)calloc(other.stl.stats.number_of_facets, sizeof(stl_facet));
|
||||
std::copy(other.stl.facet_start, other.stl.facet_start + other.stl.stats.number_of_facets, this->stl.facet_start);
|
||||
}
|
||||
if (other.stl.neighbors_start != nullptr) {
|
||||
this->stl.neighbors_start = (stl_neighbors*)calloc(other.stl.stats.number_of_facets, sizeof(stl_neighbors));
|
||||
std::copy(other.stl.neighbors_start, other.stl.neighbors_start + other.stl.stats.number_of_facets, this->stl.neighbors_start);
|
||||
}
|
||||
if (other.stl.v_indices != nullptr) {
|
||||
this->stl.v_indices = (v_indices_struct*)calloc(other.stl.stats.number_of_facets, sizeof(v_indices_struct));
|
||||
std::copy(other.stl.v_indices, other.stl.v_indices + other.stl.stats.number_of_facets, this->stl.v_indices);
|
||||
}
|
||||
if (other.stl.v_shared != nullptr) {
|
||||
this->stl.v_shared = (stl_vertex*)calloc(other.stl.stats.shared_vertices, sizeof(stl_vertex));
|
||||
std::copy(other.stl.v_shared, other.stl.v_shared + other.stl.stats.shared_vertices, this->stl.v_shared);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
// #define SLIC3R_TRACE_REPAIR
|
||||
|
||||
void TriangleMesh::repair()
|
||||
void TriangleMesh::repair(bool update_shared_vertices)
|
||||
{
|
||||
if (this->repaired) return;
|
||||
|
||||
if (this->repaired) {
|
||||
if (update_shared_vertices)
|
||||
this->require_shared_vertices();
|
||||
return;
|
||||
}
|
||||
|
||||
// admesh fails when repairing empty meshes
|
||||
if (this->stl.stats.number_of_facets == 0) return;
|
||||
if (this->stl.stats.number_of_facets == 0)
|
||||
return;
|
||||
|
||||
BOOST_LOG_TRIVIAL(debug) << "TriangleMesh::repair() started";
|
||||
|
||||
|
||||
// checking exact
|
||||
#ifdef SLIC3R_TRACE_REPAIR
|
||||
BOOST_LOG_TRIVIAL(trace) << "\tstl_check_faces_exact";
|
||||
#endif /* SLIC3R_TRACE_REPAIR */
|
||||
assert(stl_validate(&this->stl));
|
||||
stl_check_facets_exact(&stl);
|
||||
assert(stl_validate(&this->stl));
|
||||
stl.stats.facets_w_1_bad_edge = (stl.stats.connected_facets_2_edge - stl.stats.connected_facets_3_edge);
|
||||
stl.stats.facets_w_2_bad_edge = (stl.stats.connected_facets_1_edge - stl.stats.connected_facets_2_edge);
|
||||
stl.stats.facets_w_3_bad_edge = (stl.stats.number_of_facets - stl.stats.connected_facets_1_edge);
|
||||
|
||||
// checking nearby
|
||||
//int last_edges_fixed = 0;
|
||||
float tolerance = stl.stats.shortest_edge;
|
||||
float increment = stl.stats.bounding_diameter / 10000.0;
|
||||
float tolerance = (float)stl.stats.shortest_edge;
|
||||
float increment = (float)stl.stats.bounding_diameter / 10000.0f;
|
||||
int iterations = 2;
|
||||
if (stl.stats.connected_facets_3_edge < (int)stl.stats.number_of_facets) {
|
||||
for (int i = 0; i < iterations; i++) {
|
||||
|
@ -141,6 +118,7 @@ void TriangleMesh::repair()
|
|||
}
|
||||
}
|
||||
}
|
||||
assert(stl_validate(&this->stl));
|
||||
|
||||
// remove_unconnected
|
||||
if (stl.stats.connected_facets_3_edge < (int)stl.stats.number_of_facets) {
|
||||
|
@ -148,6 +126,7 @@ void TriangleMesh::repair()
|
|||
BOOST_LOG_TRIVIAL(trace) << "\tstl_remove_unconnected_facets";
|
||||
#endif /* SLIC3R_TRACE_REPAIR */
|
||||
stl_remove_unconnected_facets(&stl);
|
||||
assert(stl_validate(&this->stl));
|
||||
}
|
||||
|
||||
// fill_holes
|
||||
|
@ -168,28 +147,38 @@ void TriangleMesh::repair()
|
|||
BOOST_LOG_TRIVIAL(trace) << "\tstl_fix_normal_directions";
|
||||
#endif /* SLIC3R_TRACE_REPAIR */
|
||||
stl_fix_normal_directions(&stl);
|
||||
assert(stl_validate(&this->stl));
|
||||
|
||||
// normal_values
|
||||
#ifdef SLIC3R_TRACE_REPAIR
|
||||
BOOST_LOG_TRIVIAL(trace) << "\tstl_fix_normal_values";
|
||||
#endif /* SLIC3R_TRACE_REPAIR */
|
||||
stl_fix_normal_values(&stl);
|
||||
assert(stl_validate(&this->stl));
|
||||
|
||||
// always calculate the volume and reverse all normals if volume is negative
|
||||
#ifdef SLIC3R_TRACE_REPAIR
|
||||
BOOST_LOG_TRIVIAL(trace) << "\tstl_calculate_volume";
|
||||
#endif /* SLIC3R_TRACE_REPAIR */
|
||||
stl_calculate_volume(&stl);
|
||||
assert(stl_validate(&this->stl));
|
||||
|
||||
// neighbors
|
||||
#ifdef SLIC3R_TRACE_REPAIR
|
||||
BOOST_LOG_TRIVIAL(trace) << "\tstl_verify_neighbors";
|
||||
#endif /* SLIC3R_TRACE_REPAIR */
|
||||
stl_verify_neighbors(&stl);
|
||||
assert(stl_validate(&this->stl));
|
||||
|
||||
this->repaired = true;
|
||||
|
||||
BOOST_LOG_TRIVIAL(debug) << "TriangleMesh::repair() finished";
|
||||
|
||||
// This call should be quite cheap, a lot of code requires the indexed_triangle_set data structure,
|
||||
// and it is risky to generate such a structure once the meshes are shared. Do it now.
|
||||
this->its.clear();
|
||||
if (update_shared_vertices)
|
||||
this->require_shared_vertices();
|
||||
}
|
||||
|
||||
float TriangleMesh::volume()
|
||||
|
@ -249,20 +238,24 @@ bool TriangleMesh::needed_repair() const
|
|||
|
||||
void TriangleMesh::WriteOBJFile(const char* output_file)
|
||||
{
|
||||
stl_generate_shared_vertices(&stl);
|
||||
stl_write_obj(&stl, output_file);
|
||||
its_write_obj(this->its, output_file);
|
||||
}
|
||||
|
||||
void TriangleMesh::scale(float factor)
|
||||
{
|
||||
stl_scale(&(this->stl), factor);
|
||||
stl_invalidate_shared_vertices(&this->stl);
|
||||
for (stl_vertex& v : this->its.vertices)
|
||||
v *= factor;
|
||||
}
|
||||
|
||||
void TriangleMesh::scale(const Vec3d &versor)
|
||||
{
|
||||
stl_scale_versor(&this->stl, versor.cast<float>());
|
||||
stl_invalidate_shared_vertices(&this->stl);
|
||||
for (stl_vertex& v : this->its.vertices) {
|
||||
v.x() *= versor.x();
|
||||
v.y() *= versor.y();
|
||||
v.z() *= versor.z();
|
||||
}
|
||||
}
|
||||
|
||||
void TriangleMesh::translate(float x, float y, float z)
|
||||
|
@ -270,7 +263,9 @@ void TriangleMesh::translate(float x, float y, float z)
|
|||
if (x == 0.f && y == 0.f && z == 0.f)
|
||||
return;
|
||||
stl_translate_relative(&(this->stl), x, y, z);
|
||||
stl_invalidate_shared_vertices(&this->stl);
|
||||
stl_vertex shift(x, y, z);
|
||||
for (stl_vertex& v : this->its.vertices)
|
||||
v += shift;
|
||||
}
|
||||
|
||||
void TriangleMesh::translate(const Vec3f &displacement)
|
||||
|
@ -287,13 +282,15 @@ void TriangleMesh::rotate(float angle, const Axis &axis)
|
|||
angle = Slic3r::Geometry::rad2deg(angle);
|
||||
|
||||
if (axis == X) {
|
||||
stl_rotate_x(&(this->stl), angle);
|
||||
stl_rotate_x(&this->stl, angle);
|
||||
its_rotate_x(this->its, angle);
|
||||
} else if (axis == Y) {
|
||||
stl_rotate_y(&(this->stl), angle);
|
||||
stl_rotate_y(&this->stl, angle);
|
||||
its_rotate_y(this->its, angle);
|
||||
} else if (axis == Z) {
|
||||
stl_rotate_z(&(this->stl), angle);
|
||||
stl_rotate_z(&this->stl, angle);
|
||||
its_rotate_z(this->its, angle);
|
||||
}
|
||||
stl_invalidate_shared_vertices(&this->stl);
|
||||
}
|
||||
|
||||
void TriangleMesh::rotate(float angle, const Vec3d& axis)
|
||||
|
@ -305,39 +302,49 @@ void TriangleMesh::rotate(float angle, const Vec3d& axis)
|
|||
Transform3d m = Transform3d::Identity();
|
||||
m.rotate(Eigen::AngleAxisd(angle, axis_norm));
|
||||
stl_transform(&stl, m);
|
||||
its_transform(its, m);
|
||||
}
|
||||
|
||||
void TriangleMesh::mirror(const Axis &axis)
|
||||
{
|
||||
if (axis == X) {
|
||||
stl_mirror_yz(&this->stl);
|
||||
for (stl_vertex &v : this->its.vertices)
|
||||
v(0) *= -1.0;
|
||||
} else if (axis == Y) {
|
||||
stl_mirror_xz(&this->stl);
|
||||
for (stl_vertex &v : this->its.vertices)
|
||||
v(1) *= -1.0;
|
||||
} else if (axis == Z) {
|
||||
stl_mirror_xy(&this->stl);
|
||||
for (stl_vertex &v : this->its.vertices)
|
||||
v(2) *= -1.0;
|
||||
}
|
||||
stl_invalidate_shared_vertices(&this->stl);
|
||||
}
|
||||
|
||||
void TriangleMesh::transform(const Transform3d& t, bool fix_left_handed)
|
||||
{
|
||||
stl_transform(&stl, t);
|
||||
stl_invalidate_shared_vertices(&stl);
|
||||
its_transform(its, t);
|
||||
if (fix_left_handed && t.matrix().block(0, 0, 3, 3).determinant() < 0.) {
|
||||
// Left handed transformation is being applied. It is a good idea to flip the faces and their normals.
|
||||
this->repair();
|
||||
this->repair(false);
|
||||
stl_reverse_all_facets(&stl);
|
||||
this->its.clear();
|
||||
this->require_shared_vertices();
|
||||
}
|
||||
}
|
||||
|
||||
void TriangleMesh::transform(const Matrix3d& m, bool fix_left_handed)
|
||||
{
|
||||
stl_transform(&stl, m);
|
||||
stl_invalidate_shared_vertices(&stl);
|
||||
its_transform(its, m);
|
||||
if (fix_left_handed && m.determinant() < 0.) {
|
||||
// Left handed transformation is being applied. It is a good idea to flip the faces and their normals.
|
||||
this->repair();
|
||||
this->repair(false);
|
||||
stl_reverse_all_facets(&stl);
|
||||
this->its.clear();
|
||||
this->require_shared_vertices();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -355,7 +362,8 @@ void TriangleMesh::rotate(double angle, Point* center)
|
|||
return;
|
||||
Vec2f c = center->cast<float>();
|
||||
this->translate(-c(0), -c(1), 0);
|
||||
stl_rotate_z(&(this->stl), (float)angle);
|
||||
stl_rotate_z(&this->stl, (float)angle);
|
||||
its_rotate_z(this->its, (float)angle);
|
||||
this->translate(c(0), c(1), 0);
|
||||
}
|
||||
|
||||
|
@ -435,9 +443,8 @@ TriangleMeshPtrs TriangleMesh::split() const
|
|||
TriangleMesh* mesh = new TriangleMesh;
|
||||
meshes.emplace_back(mesh);
|
||||
mesh->stl.stats.type = inmemory;
|
||||
mesh->stl.stats.number_of_facets = facets.size();
|
||||
mesh->stl.stats.number_of_facets = (uint32_t)facets.size();
|
||||
mesh->stl.stats.original_num_facets = mesh->stl.stats.number_of_facets;
|
||||
stl_clear_error(&mesh->stl);
|
||||
stl_allocate(&mesh->stl);
|
||||
|
||||
// Assign the facets to the new mesh.
|
||||
|
@ -455,7 +462,7 @@ void TriangleMesh::merge(const TriangleMesh &mesh)
|
|||
{
|
||||
// reset stats and metadata
|
||||
int number_of_facets = this->stl.stats.number_of_facets;
|
||||
stl_invalidate_shared_vertices(&this->stl);
|
||||
this->its.clear();
|
||||
this->repaired = false;
|
||||
|
||||
// update facet count and allocate more memory
|
||||
|
@ -477,13 +484,12 @@ ExPolygons TriangleMesh::horizontal_projection() const
|
|||
{
|
||||
Polygons pp;
|
||||
pp.reserve(this->stl.stats.number_of_facets);
|
||||
for (uint32_t i = 0; i < this->stl.stats.number_of_facets; ++ i) {
|
||||
stl_facet* facet = &this->stl.facet_start[i];
|
||||
for (const stl_facet &facet : this->stl.facet_start) {
|
||||
Polygon p;
|
||||
p.points.resize(3);
|
||||
p.points[0] = Point::new_scale(facet->vertex[0](0), facet->vertex[0](1));
|
||||
p.points[1] = Point::new_scale(facet->vertex[1](0), facet->vertex[1](1));
|
||||
p.points[2] = Point::new_scale(facet->vertex[2](0), facet->vertex[2](1));
|
||||
p.points[0] = Point::new_scale(facet.vertex[0](0), facet.vertex[0](1));
|
||||
p.points[1] = Point::new_scale(facet.vertex[1](0), facet.vertex[1](1));
|
||||
p.points[2] = Point::new_scale(facet.vertex[2](0), facet.vertex[2](1));
|
||||
p.make_counter_clockwise(); // do this after scaling, as winding order might change while doing that
|
||||
pp.emplace_back(p);
|
||||
}
|
||||
|
@ -495,11 +501,10 @@ ExPolygons TriangleMesh::horizontal_projection() const
|
|||
// 2D convex hull of a 3D mesh projected into the Z=0 plane.
|
||||
Polygon TriangleMesh::convex_hull()
|
||||
{
|
||||
this->require_shared_vertices();
|
||||
Points pp;
|
||||
pp.reserve(this->stl.stats.shared_vertices);
|
||||
for (int i = 0; i < this->stl.stats.shared_vertices; ++ i) {
|
||||
const stl_vertex &v = this->stl.v_shared[i];
|
||||
pp.reserve(this->its.vertices.size());
|
||||
for (size_t i = 0; i < this->its.vertices.size(); ++ i) {
|
||||
const stl_vertex &v = this->its.vertices[i];
|
||||
pp.emplace_back(Point::new_scale(v(0), v(1)));
|
||||
}
|
||||
return Slic3r::Geometry::convex_hull(pp);
|
||||
|
@ -517,49 +522,47 @@ BoundingBoxf3 TriangleMesh::bounding_box() const
|
|||
BoundingBoxf3 TriangleMesh::transformed_bounding_box(const Transform3d &trafo) const
|
||||
{
|
||||
BoundingBoxf3 bbox;
|
||||
if (stl.v_shared == nullptr) {
|
||||
if (this->its.vertices.empty()) {
|
||||
// Using the STL faces.
|
||||
for (size_t i = 0; i < this->facets_count(); ++ i) {
|
||||
const stl_facet &facet = this->stl.facet_start[i];
|
||||
for (const stl_facet &facet : this->stl.facet_start)
|
||||
for (size_t j = 0; j < 3; ++ j)
|
||||
bbox.merge(trafo * facet.vertex[j].cast<double>());
|
||||
}
|
||||
} else {
|
||||
// Using the shared vertices should be a bit quicker than using the STL faces.
|
||||
for (int i = 0; i < stl.stats.shared_vertices; ++ i)
|
||||
bbox.merge(trafo * this->stl.v_shared[i].cast<double>());
|
||||
for (const stl_vertex &v : this->its.vertices)
|
||||
bbox.merge(trafo * v.cast<double>());
|
||||
}
|
||||
return bbox;
|
||||
}
|
||||
|
||||
TriangleMesh TriangleMesh::convex_hull_3d() const
|
||||
{
|
||||
// Helper struct for qhull:
|
||||
struct PointForQHull{
|
||||
PointForQHull(float x_p, float y_p, float z_p) : x((realT)x_p), y((realT)y_p), z((realT)z_p) {}
|
||||
realT x, y, z;
|
||||
};
|
||||
std::vector<PointForQHull> src_vertices;
|
||||
|
||||
// We will now fill the vector with input points for computation:
|
||||
stl_facet* facet_ptr = stl.facet_start;
|
||||
while (facet_ptr < stl.facet_start + stl.stats.number_of_facets)
|
||||
{
|
||||
for (int i = 0; i < 3; ++i)
|
||||
{
|
||||
const stl_vertex& v = facet_ptr->vertex[i];
|
||||
src_vertices.emplace_back(v(0), v(1), v(2));
|
||||
}
|
||||
|
||||
facet_ptr += 1;
|
||||
}
|
||||
|
||||
// The qhull call:
|
||||
orgQhull::Qhull qhull;
|
||||
qhull.disableOutputStream(); // we want qhull to be quiet
|
||||
try
|
||||
std::vector<realT> src_vertices;
|
||||
try
|
||||
{
|
||||
qhull.runQhull("", 3, (int)src_vertices.size(), (const realT*)(src_vertices.data()), "Qt");
|
||||
if (this->has_shared_vertices()) {
|
||||
#if REALfloat
|
||||
qhull.runQhull("", 3, (int)this->its.vertices.size(), (const realT*)(this->its.vertices.front().data()), "Qt");
|
||||
#else
|
||||
src_vertices.reserve(this->its.vertices() * 3);
|
||||
// We will now fill the vector with input points for computation:
|
||||
for (const stl_vertex &v : ths->its.vertices.size())
|
||||
for (int i = 0; i < 3; ++ i)
|
||||
src_vertices.emplace_back(v(i));
|
||||
qhull.runQhull("", 3, (int)src_vertices.size() / 3, src_vertices.data(), "Qt");
|
||||
#endif
|
||||
} else {
|
||||
src_vertices.reserve(this->stl.facet_start.size() * 9);
|
||||
// We will now fill the vector with input points for computation:
|
||||
for (const stl_facet &f : this->stl.facet_start)
|
||||
for (int i = 0; i < 3; ++ i)
|
||||
for (int j = 0; j < 3; ++ j)
|
||||
src_vertices.emplace_back(f.vertex[i](j));
|
||||
qhull.runQhull("", 3, (int)src_vertices.size() / 3, src_vertices.data(), "Qt");
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
|
@ -587,34 +590,20 @@ TriangleMesh TriangleMesh::convex_hull_3d() const
|
|||
|
||||
TriangleMesh output_mesh(dst_vertices, facets);
|
||||
output_mesh.repair();
|
||||
output_mesh.require_shared_vertices();
|
||||
return output_mesh;
|
||||
}
|
||||
|
||||
void TriangleMesh::require_shared_vertices()
|
||||
{
|
||||
BOOST_LOG_TRIVIAL(trace) << "TriangleMeshSlicer::require_shared_vertices - start";
|
||||
if (!this->repaired)
|
||||
assert(stl_validate(&this->stl));
|
||||
if (! this->repaired)
|
||||
this->repair();
|
||||
if (this->stl.v_shared == NULL) {
|
||||
if (this->its.vertices.empty()) {
|
||||
BOOST_LOG_TRIVIAL(trace) << "TriangleMeshSlicer::require_shared_vertices - stl_generate_shared_vertices";
|
||||
stl_generate_shared_vertices(&(this->stl));
|
||||
stl_generate_shared_vertices(&this->stl, this->its);
|
||||
}
|
||||
#ifdef _DEBUG
|
||||
// Verify validity of neighborship data.
|
||||
for (int facet_idx = 0; facet_idx < stl.stats.number_of_facets; ++facet_idx) {
|
||||
const stl_neighbors &nbr = stl.neighbors_start[facet_idx];
|
||||
const int *vertices = stl.v_indices[facet_idx].vertex;
|
||||
for (int nbr_idx = 0; nbr_idx < 3; ++nbr_idx) {
|
||||
int nbr_face = this->stl.neighbors_start[facet_idx].neighbor[nbr_idx];
|
||||
if (nbr_face != -1) {
|
||||
assert(
|
||||
(stl.v_indices[nbr_face].vertex[(nbr.which_vertex_not[nbr_idx] + 1) % 3] == vertices[(nbr_idx + 1) % 3] && stl.v_indices[nbr_face].vertex[(nbr.which_vertex_not[nbr_idx] + 2) % 3] == vertices[nbr_idx]) ||
|
||||
(stl.v_indices[nbr_face].vertex[(nbr.which_vertex_not[nbr_idx] + 2) % 3] == vertices[(nbr_idx + 1) % 3] && stl.v_indices[nbr_face].vertex[(nbr.which_vertex_not[nbr_idx] + 1) % 3] == vertices[nbr_idx]));
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif /* _DEBUG */
|
||||
assert(stl_validate(&this->stl, this->its));
|
||||
BOOST_LOG_TRIVIAL(trace) << "TriangleMeshSlicer::require_shared_vertices - end";
|
||||
}
|
||||
|
||||
|
@ -626,10 +615,9 @@ void TriangleMeshSlicer::init(const TriangleMesh *_mesh, throw_on_cancel_callbac
|
|||
|
||||
throw_on_cancel();
|
||||
facets_edges.assign(_mesh->stl.stats.number_of_facets * 3, -1);
|
||||
v_scaled_shared.assign(_mesh->stl.v_shared, _mesh->stl.v_shared + _mesh->stl.stats.shared_vertices);
|
||||
// Scale the copied vertices.
|
||||
for (int i = 0; i < this->mesh->stl.stats.shared_vertices; ++ i)
|
||||
this->v_scaled_shared[i] *= float(1. / SCALING_FACTOR);
|
||||
v_scaled_shared.assign(_mesh->its.vertices.size(), stl_vertex());
|
||||
for (size_t i = 0; i < v_scaled_shared.size(); ++ i)
|
||||
this->v_scaled_shared[i] = _mesh->its.vertices[i] / float(SCALING_FACTOR);
|
||||
|
||||
// Create a mapping from triangle edge into face.
|
||||
struct EdgeToFace {
|
||||
|
@ -649,8 +637,8 @@ void TriangleMeshSlicer::init(const TriangleMesh *_mesh, throw_on_cancel_callbac
|
|||
for (uint32_t facet_idx = 0; facet_idx < this->mesh->stl.stats.number_of_facets; ++ facet_idx)
|
||||
for (int i = 0; i < 3; ++ i) {
|
||||
EdgeToFace &e2f = edges_map[facet_idx*3+i];
|
||||
e2f.vertex_low = this->mesh->stl.v_indices[facet_idx].vertex[i];
|
||||
e2f.vertex_high = this->mesh->stl.v_indices[facet_idx].vertex[(i + 1) % 3];
|
||||
e2f.vertex_low = this->mesh->its.indices[facet_idx][i];
|
||||
e2f.vertex_high = this->mesh->its.indices[facet_idx][(i + 1) % 3];
|
||||
e2f.face = facet_idx;
|
||||
// 1 based indexing, to be always strictly positive.
|
||||
e2f.face_edge = i + 1;
|
||||
|
@ -818,7 +806,7 @@ void TriangleMeshSlicer::slice(const std::vector<float> &z, std::vector<Polygons
|
|||
void TriangleMeshSlicer::_slice_do(size_t facet_idx, std::vector<IntersectionLines>* lines, boost::mutex* lines_mutex,
|
||||
const std::vector<float> &z) const
|
||||
{
|
||||
const stl_facet &facet = m_use_quaternion ? this->mesh->stl.facet_start[facet_idx].rotated(m_quaternion) : this->mesh->stl.facet_start[facet_idx];
|
||||
const stl_facet &facet = m_use_quaternion ? (this->mesh->stl.facet_start.data() + facet_idx)->rotated(m_quaternion) : *(this->mesh->stl.facet_start.data() + facet_idx);
|
||||
|
||||
// find facet extents
|
||||
const float min_z = fminf(facet.vertex[0](2), fminf(facet.vertex[1](2), facet.vertex[2](2)));
|
||||
|
@ -887,7 +875,7 @@ TriangleMeshSlicer::FacetSliceType TriangleMeshSlicer::slice_facet(
|
|||
// Reorder vertices so that the first one is the one with lowest Z.
|
||||
// This is needed to get all intersection lines in a consistent order
|
||||
// (external on the right of the line)
|
||||
const int *vertices = this->mesh->stl.v_indices[facet_idx].vertex;
|
||||
const stl_triangle_vertex_indices &vertices = this->mesh->its.indices[facet_idx];
|
||||
int i = (facet.vertex[1].z() == min_z) ? 1 : ((facet.vertex[2].z() == min_z) ? 2 : 0);
|
||||
|
||||
// These are used only if the cut plane is tilted:
|
||||
|
@ -1714,7 +1702,7 @@ void TriangleMeshSlicer::cut(float z, TriangleMesh* upper, TriangleMesh* lower)
|
|||
BOOST_LOG_TRIVIAL(trace) << "TriangleMeshSlicer::cut - slicing object";
|
||||
float scaled_z = scale_(z);
|
||||
for (uint32_t facet_idx = 0; facet_idx < this->mesh->stl.stats.number_of_facets; ++ facet_idx) {
|
||||
stl_facet* facet = &this->mesh->stl.facet_start[facet_idx];
|
||||
const stl_facet* facet = &this->mesh->stl.facet_start[facet_idx];
|
||||
|
||||
// find facet extents
|
||||
float min_z = std::min(facet->vertex[0](2), std::min(facet->vertex[1](2), facet->vertex[2](2)));
|
||||
|
@ -1736,10 +1724,12 @@ void TriangleMeshSlicer::cut(float z, TriangleMesh* upper, TriangleMesh* lower)
|
|||
|
||||
if (min_z > z || (min_z == z && max_z > z)) {
|
||||
// facet is above the cut plane and does not belong to it
|
||||
if (upper != NULL) stl_add_facet(&upper->stl, facet);
|
||||
if (upper != nullptr)
|
||||
stl_add_facet(&upper->stl, facet);
|
||||
} else if (max_z < z || (max_z == z && min_z < z)) {
|
||||
// facet is below the cut plane and does not belong to it
|
||||
if (lower != NULL) stl_add_facet(&lower->stl, facet);
|
||||
if (lower != nullptr)
|
||||
stl_add_facet(&lower->stl, facet);
|
||||
} else if (min_z < z && max_z > z) {
|
||||
// Facet is cut by the slicing plane.
|
||||
|
||||
|
@ -1786,22 +1776,24 @@ void TriangleMeshSlicer::cut(float z, TriangleMesh* upper, TriangleMesh* lower)
|
|||
quadrilateral[1].vertex[2] = v0v1;
|
||||
|
||||
if (v0(2) > z) {
|
||||
if (upper != NULL) stl_add_facet(&upper->stl, &triangle);
|
||||
if (lower != NULL) {
|
||||
if (upper != nullptr)
|
||||
stl_add_facet(&upper->stl, &triangle);
|
||||
if (lower != nullptr) {
|
||||
stl_add_facet(&lower->stl, &quadrilateral[0]);
|
||||
stl_add_facet(&lower->stl, &quadrilateral[1]);
|
||||
}
|
||||
} else {
|
||||
if (upper != NULL) {
|
||||
if (upper != nullptr) {
|
||||
stl_add_facet(&upper->stl, &quadrilateral[0]);
|
||||
stl_add_facet(&upper->stl, &quadrilateral[1]);
|
||||
}
|
||||
if (lower != NULL) stl_add_facet(&lower->stl, &triangle);
|
||||
if (lower != nullptr)
|
||||
stl_add_facet(&lower->stl, &triangle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (upper != NULL) {
|
||||
if (upper != nullptr) {
|
||||
BOOST_LOG_TRIVIAL(trace) << "TriangleMeshSlicer::cut - triangulating upper part";
|
||||
ExPolygons section;
|
||||
this->make_expolygons_simple(upper_lines, §ion);
|
||||
|
@ -1815,7 +1807,7 @@ void TriangleMeshSlicer::cut(float z, TriangleMesh* upper, TriangleMesh* lower)
|
|||
}
|
||||
}
|
||||
|
||||
if (lower != NULL) {
|
||||
if (lower != nullptr) {
|
||||
BOOST_LOG_TRIVIAL(trace) << "TriangleMeshSlicer::cut - triangulating lower part";
|
||||
ExPolygons section;
|
||||
this->make_expolygons_simple(lower_lines, §ion);
|
||||
|
@ -1905,10 +1897,10 @@ TriangleMesh make_cylinder(double r, double h, double fa)
|
|||
//FIXME better to discretize an Icosahedron recursively http://www.songho.ca/opengl/gl_sphere.html
|
||||
TriangleMesh make_sphere(double radius, double fa)
|
||||
{
|
||||
int sectorCount = ceil(2. * M_PI / fa);
|
||||
int stackCount = ceil(M_PI / fa);
|
||||
float sectorStep = 2. * M_PI / sectorCount;
|
||||
float stackStep = M_PI / stackCount;
|
||||
int sectorCount = int(ceil(2. * M_PI / fa));
|
||||
int stackCount = int(ceil(M_PI / fa));
|
||||
float sectorStep = float(2. * M_PI / sectorCount);
|
||||
float stackStep = float(M_PI / stackCount);
|
||||
|
||||
Pointf3s vertices;
|
||||
vertices.reserve((stackCount - 1) * sectorCount + 2);
|
||||
|
|
|
@ -21,19 +21,13 @@ typedef std::vector<TriangleMesh*> TriangleMeshPtrs;
|
|||
class TriangleMesh
|
||||
{
|
||||
public:
|
||||
TriangleMesh() : repaired(false) { stl_initialize(&this->stl); }
|
||||
TriangleMesh() : repaired(false) {}
|
||||
TriangleMesh(const Pointf3s &points, const std::vector<Vec3crd> &facets);
|
||||
TriangleMesh(const TriangleMesh &other) : repaired(false) { stl_initialize(&this->stl); *this = other; }
|
||||
TriangleMesh(TriangleMesh &&other) : repaired(false) { stl_initialize(&this->stl); this->swap(other); }
|
||||
~TriangleMesh() { clear(); }
|
||||
TriangleMesh& operator=(const TriangleMesh &other);
|
||||
TriangleMesh& operator=(TriangleMesh &&other) { this->swap(other); return *this; }
|
||||
void clear() { stl_close(&this->stl); this->repaired = false; }
|
||||
void swap(TriangleMesh &other) { std::swap(this->stl, other.stl); std::swap(this->repaired, other.repaired); }
|
||||
void ReadSTLFile(const char* input_file) { stl_open(&stl, input_file); }
|
||||
void write_ascii(const char* output_file) { stl_write_ascii(&this->stl, output_file, ""); }
|
||||
void write_binary(const char* output_file) { stl_write_binary(&this->stl, output_file, ""); }
|
||||
void repair();
|
||||
void clear() { this->stl.clear(); this->its.clear(); this->repaired = false; }
|
||||
bool ReadSTLFile(const char* input_file) { return stl_open(&stl, input_file); }
|
||||
bool write_ascii(const char* output_file) { return stl_write_ascii(&this->stl, output_file, ""); }
|
||||
bool write_binary(const char* output_file) { return stl_write_binary(&this->stl, output_file, ""); }
|
||||
void repair(bool update_shared_vertices = true);
|
||||
float volume();
|
||||
void check_topology();
|
||||
bool is_manifold() const { return this->stl.stats.connected_facets_3_edge == (int)this->stl.stats.number_of_facets; }
|
||||
|
@ -58,7 +52,7 @@ public:
|
|||
TriangleMeshPtrs split() const;
|
||||
void merge(const TriangleMesh &mesh);
|
||||
ExPolygons horizontal_projection() const;
|
||||
const float* first_vertex() const { return this->stl.facet_start ? &this->stl.facet_start->vertex[0](0) : nullptr; }
|
||||
const float* first_vertex() const { return this->stl.facet_start.empty() ? nullptr : &this->stl.facet_start.front().vertex[0](0); }
|
||||
// 2D convex hull of a 3D mesh projected into the Z=0 plane.
|
||||
Polygon convex_hull();
|
||||
BoundingBoxf3 bounding_box() const;
|
||||
|
@ -69,12 +63,13 @@ public:
|
|||
void reset_repair_stats();
|
||||
bool needed_repair() const;
|
||||
void require_shared_vertices();
|
||||
bool has_shared_vertices() const { return stl.v_shared != NULL; }
|
||||
bool has_shared_vertices() const { return ! this->its.vertices.empty(); }
|
||||
size_t facets_count() const { return this->stl.stats.number_of_facets; }
|
||||
bool empty() const { return this->facets_count() == 0; }
|
||||
bool is_splittable() const;
|
||||
|
||||
stl_file stl;
|
||||
indexed_triangle_set its;
|
||||
bool repaired;
|
||||
|
||||
private:
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue