mirror of
https://github.com/SoftFever/OrcaSlicer.git
synced 2025-07-25 07:34:03 -06:00
Eradicated admesh from TriangleMesh:
TriangleMesh newly only holds indexed_triangle_set and TriangleMeshStats. TriangleMeshStats contains an excerpt of stl_stats. TriangleMeshStats are updated when initializing with indexed_triangle_set. Admesh triangle mesh fixing is newly only used when loading an STL. AMF / 3MF / OBJ file formats are already indexed triangle sets, thus they are no more converted to admesh stl_file format, nor fixed through admesh repair machinery. When importing AMF / 3MF / OBJ files, volume is calculated and if negative, all faces are flipped. Also a bounding box and number of open edges is calculated. Implemented its_number_of_patches(), its_num_open_edges() Optimized its_split(), its_is_splittable() using a visitor pattern. Reworked QHull integration into TriangleMesh: 1) Face normals were not right. 2) Indexed triangle set is newly emitted instead of duplicating vertices for each face. Fixed cut_mesh(): Orient the triangulated faces correctly.
This commit is contained in:
parent
f484953a5a
commit
8a2a9dba2f
59 changed files with 1056 additions and 1758 deletions
|
@ -313,7 +313,6 @@ void GLVolume::SinkingContours::update()
|
|||
m_shift = Vec3d::Zero();
|
||||
|
||||
const TriangleMesh& mesh = model.objects[object_idx]->volumes[m_parent.volume_idx()]->mesh();
|
||||
assert(mesh.has_shared_vertices());
|
||||
|
||||
m_model.reset();
|
||||
GUI::GLModel::InitializationData init_data;
|
||||
|
@ -519,7 +518,7 @@ const BoundingBoxf3& GLVolume::transformed_convex_hull_bounding_box() const
|
|||
|
||||
BoundingBoxf3 GLVolume::transformed_convex_hull_bounding_box(const Transform3d &trafo) const
|
||||
{
|
||||
return (m_convex_hull && m_convex_hull->facets_count() > 0) ?
|
||||
return (m_convex_hull && ! m_convex_hull->empty()) ?
|
||||
m_convex_hull->transformed_bounding_box(trafo) :
|
||||
bounding_box().transformed(trafo);
|
||||
}
|
||||
|
@ -719,21 +718,20 @@ int GLVolumeCollection::load_wipe_tower_preview(
|
|||
float min_width = 30.f;
|
||||
// We'll now create the box with jagged edge. y-coordinates of the pre-generated model
|
||||
// are shifted so that the front edge has y=0 and centerline of the back edge has y=depth:
|
||||
Pointf3s points;
|
||||
std::vector<Vec3i> facets;
|
||||
float out_points_idx[][3] = { { 0, -depth, 0 }, { 0, 0, 0 }, { 38.453f, 0, 0 }, { 61.547f, 0, 0 }, { 100.0f, 0, 0 }, { 100.0f, -depth, 0 }, { 55.7735f, -10.0f, 0 }, { 44.2265f, 10.0f, 0 },
|
||||
{ 38.453f, 0, 1 }, { 0, 0, 1 }, { 0, -depth, 1 }, { 100.0f, -depth, 1 }, { 100.0f, 0, 1 }, { 61.547f, 0, 1 }, { 55.7735f, -10.0f, 1 }, { 44.2265f, 10.0f, 1 } };
|
||||
int out_facets_idx[][3] = { { 0, 1, 2 }, { 3, 4, 5 }, { 6, 5, 0 }, { 3, 5, 6 }, { 6, 2, 7 }, { 6, 0, 2 }, { 8, 9, 10 }, { 11, 12, 13 }, { 10, 11, 14 }, { 14, 11, 13 }, { 15, 8, 14 },
|
||||
{8, 10, 14}, {3, 12, 4}, {3, 13, 12}, {6, 13, 3}, {6, 14, 13}, {7, 14, 6}, {7, 15, 14}, {2, 15, 7}, {2, 8, 15}, {1, 8, 2}, {1, 9, 8},
|
||||
{0, 9, 1}, {0, 10, 9}, {5, 10, 0}, {5, 11, 10}, {4, 11, 5}, {4, 12, 11} };
|
||||
static constexpr const int out_facets_idx[][3] = {
|
||||
{ 0, 1, 2 }, { 3, 4, 5 }, { 6, 5, 0 }, { 3, 5, 6 }, { 6, 2, 7 }, { 6, 0, 2 }, { 8, 9, 10 }, { 11, 12, 13 }, { 10, 11, 14 }, { 14, 11, 13 }, { 15, 8, 14 },
|
||||
{ 8, 10, 14 }, { 3, 12, 4 }, { 3, 13, 12 }, { 6, 13, 3 }, { 6, 14, 13 }, { 7, 14, 6 }, { 7, 15, 14 }, { 2, 15, 7 }, { 2, 8, 15 }, { 1, 8, 2 }, { 1, 9, 8 },
|
||||
{ 0, 9, 1 }, { 0, 10, 9 }, { 5, 10, 0 }, { 5, 11, 10 }, { 4, 11, 5 }, { 4, 12, 11 } };
|
||||
indexed_triangle_set its;
|
||||
for (int i = 0; i < 16; ++i)
|
||||
points.emplace_back(out_points_idx[i][0] / (100.f / min_width),
|
||||
out_points_idx[i][1] + depth, out_points_idx[i][2]);
|
||||
for (int i = 0; i < 28; ++i)
|
||||
facets.emplace_back(out_facets_idx[i][0],
|
||||
out_facets_idx[i][1],
|
||||
out_facets_idx[i][2]);
|
||||
TriangleMesh tooth_mesh(points, facets);
|
||||
its.vertices.emplace_back(out_points_idx[i][0] / (100.f / min_width),
|
||||
out_points_idx[i][1] + depth, out_points_idx[i][2]);
|
||||
its.indices.reserve(28);
|
||||
for (const int *face : out_facets_idx)
|
||||
its.indices.emplace_back(face);
|
||||
TriangleMesh tooth_mesh(std::move(its));
|
||||
|
||||
// We have the mesh ready. It has one tooth and width of min_width. We will now
|
||||
// append several of these together until we are close to the required width
|
||||
|
@ -744,7 +742,7 @@ int GLVolumeCollection::load_wipe_tower_preview(
|
|||
tooth_mesh.translate(min_width, 0.f, 0.f);
|
||||
}
|
||||
|
||||
mesh.scale(Vec3d(width / (n * min_width), 1.f, height)); // Scaling to proper width
|
||||
mesh.scale(Vec3f(width / (n * min_width), 1.f, height)); // Scaling to proper width
|
||||
}
|
||||
else
|
||||
mesh = make_cube(width, depth, height);
|
||||
|
@ -753,7 +751,6 @@ int GLVolumeCollection::load_wipe_tower_preview(
|
|||
TriangleMesh brim_mesh = make_cube(width + 2.f * brim_width, depth + 2.f * brim_width, 0.2f);
|
||||
brim_mesh.translate(-brim_width, -brim_width, 0.f);
|
||||
mesh.merge(brim_mesh);
|
||||
mesh.repair();
|
||||
|
||||
volumes.emplace_back(new GLVolume(color));
|
||||
GLVolume& v = *volumes.back();
|
||||
|
|
|
@ -160,7 +160,6 @@ bool GLModel::init_from_file(const std::string& filename)
|
|||
}
|
||||
|
||||
TriangleMesh mesh = model.mesh();
|
||||
mesh.require_shared_vertices();
|
||||
init_from(mesh.its, mesh.bounding_box());
|
||||
|
||||
m_filename = filename;
|
||||
|
|
|
@ -392,9 +392,9 @@ wxString ObjectList::get_mesh_errors_list(const int obj_idx, const int vol_idx /
|
|||
// Create tooltip string, if there are errors
|
||||
wxString tooltip = format_wxstr(_L_PLURAL("Auto-repaired %1$d error", "Auto-repaired %1$d errors", errors), errors) + ":\n";
|
||||
|
||||
const stl_stats& stats = vol_idx == -1 ?
|
||||
(*m_objects)[obj_idx]->get_object_stl_stats() :
|
||||
(*m_objects)[obj_idx]->volumes[vol_idx]->mesh().stats();
|
||||
const TriangleMeshStats& stats = vol_idx == -1 ?
|
||||
(*m_objects)[obj_idx]->get_object_stl_stats() :
|
||||
(*m_objects)[obj_idx]->volumes[vol_idx]->mesh().stats();
|
||||
|
||||
if (stats.degenerate_facets > 0)
|
||||
tooltip += "\t" + format_wxstr(_L_PLURAL("%1$d degenerate facet", "%1$d degenerate facets", stats.degenerate_facets), stats.degenerate_facets) + "\n";
|
||||
|
@ -402,8 +402,6 @@ wxString ObjectList::get_mesh_errors_list(const int obj_idx, const int vol_idx /
|
|||
tooltip += "\t" + format_wxstr(_L_PLURAL("%1$d edge fixed", "%1$d edges fixed", stats.edges_fixed), stats.edges_fixed) + "\n";
|
||||
if (stats.facets_removed > 0)
|
||||
tooltip += "\t" + format_wxstr(_L_PLURAL("%1$d facet removed", "%1$d facets removed", stats.facets_removed), stats.facets_removed) + "\n";
|
||||
if (stats.facets_added > 0)
|
||||
tooltip += "\t" + format_wxstr(_L_PLURAL("%1$d facet added", "%1$d facets added", stats.facets_added), stats.facets_added) + "\n";
|
||||
if (stats.facets_reversed > 0)
|
||||
tooltip += "\t" + format_wxstr(_L_PLURAL("%1$d facet reversed", "%1$d facets reversed", stats.facets_reversed), stats.facets_reversed) + "\n";
|
||||
if (stats.backwards_edges > 0)
|
||||
|
@ -1535,7 +1533,6 @@ void ObjectList::load_modifier(ModelObject& model_object, std::vector<ModelVolum
|
|||
}
|
||||
|
||||
TriangleMesh mesh = model.mesh();
|
||||
mesh.repair();
|
||||
// Mesh will be centered when loading.
|
||||
ModelVolume* new_volume = model_object.add_volume(std::move(mesh), type);
|
||||
new_volume->name = boost::filesystem::path(input_file).filename().string();
|
||||
|
@ -1558,27 +1555,24 @@ void ObjectList::load_modifier(ModelObject& model_object, std::vector<ModelVolum
|
|||
|
||||
static TriangleMesh create_mesh(const std::string& type_name, const BoundingBoxf3& bb)
|
||||
{
|
||||
TriangleMesh mesh;
|
||||
|
||||
const double side = wxGetApp().plater()->canvas3D()->get_size_proportional_to_max_bed_size(0.1);
|
||||
|
||||
indexed_triangle_set mesh;
|
||||
if (type_name == "Box")
|
||||
// Sitting on the print bed, left front front corner at (0, 0).
|
||||
mesh = make_cube(side, side, side);
|
||||
mesh = its_make_cube(side, side, side);
|
||||
else if (type_name == "Cylinder")
|
||||
// Centered around 0, sitting on the print bed.
|
||||
// The cylinder has the same volume as the box above.
|
||||
mesh = make_cylinder(0.564 * side, side);
|
||||
mesh = its_make_cylinder(0.564 * side, side);
|
||||
else if (type_name == "Sphere")
|
||||
// Centered around 0, half the sphere below the print bed, half above.
|
||||
// The sphere has the same volume as the box above.
|
||||
mesh = make_sphere(0.62 * side, PI / 18);
|
||||
mesh = its_make_sphere(0.62 * side, PI / 18);
|
||||
else if (type_name == "Slab")
|
||||
// Sitting on the print bed, left front front corner at (0, 0).
|
||||
mesh = make_cube(bb.size().x() * 1.5, bb.size().y() * 1.5, bb.size().z() * 0.5);
|
||||
mesh.repair();
|
||||
|
||||
return mesh;
|
||||
mesh = its_make_cube(bb.size().x() * 1.5, bb.size().y() * 1.5, bb.size().z() * 0.5);
|
||||
return TriangleMesh(mesh);
|
||||
}
|
||||
|
||||
void ObjectList::load_generic_subobject(const std::string& type_name, const ModelVolumeType type)
|
||||
|
|
|
@ -282,10 +282,8 @@ void GLGizmoCut::update_contours()
|
|||
if (m_cut_contours.cut_z != m_cut_z || m_cut_contours.object_id != model_object->id() || m_cut_contours.instance_idx != instance_idx) {
|
||||
m_cut_contours.cut_z = m_cut_z;
|
||||
|
||||
if (m_cut_contours.object_id != model_object->id()) {
|
||||
if (m_cut_contours.object_id != model_object->id())
|
||||
m_cut_contours.mesh = model_object->raw_mesh();
|
||||
m_cut_contours.mesh.repair();
|
||||
}
|
||||
|
||||
m_cut_contours.position = box.center();
|
||||
m_cut_contours.shift = Vec3d::Zero();
|
||||
|
|
|
@ -313,9 +313,8 @@ void GLGizmoSimplify::process()
|
|||
}
|
||||
|
||||
void GLGizmoSimplify::set_its(indexed_triangle_set &its) {
|
||||
auto tm = std::make_unique<TriangleMesh>(its);
|
||||
tm->repair();
|
||||
m_volume->set_mesh(std::move(tm));
|
||||
m_volume->set_mesh(its);
|
||||
m_volume->calculate_convex_hull();
|
||||
m_volume->set_new_unique_id();
|
||||
m_volume->get_object()->invalidate_bounding_box();
|
||||
m_need_reload = true;
|
||||
|
|
|
@ -270,11 +270,10 @@ void HollowedMesh::on_update()
|
|||
m_drainholes = print_object->model_object()->sla_drain_holes;
|
||||
m_old_hollowing_timestamp = timestamp;
|
||||
|
||||
const indexed_triangle_set &interior = print_object->hollowed_interior_mesh();
|
||||
indexed_triangle_set interior = print_object->hollowed_interior_mesh();
|
||||
if (!interior.empty()) {
|
||||
m_hollowed_interior_transformed = std::make_unique<TriangleMesh>(interior);
|
||||
m_hollowed_interior_transformed->repaired = false;
|
||||
m_hollowed_interior_transformed->repair(true);
|
||||
its_flip_triangles(interior);
|
||||
m_hollowed_interior_transformed = std::make_unique<TriangleMesh>(std::move(interior));
|
||||
m_hollowed_interior_transformed->transform(trafo_inv);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1740,7 +1740,6 @@ void MainFrame::repair_stl()
|
|||
|
||||
Slic3r::TriangleMesh tmesh;
|
||||
tmesh.ReadSTLFile(input_file.ToUTF8().data());
|
||||
tmesh.repair();
|
||||
tmesh.WriteOBJFile(output_file.ToUTF8().data());
|
||||
Slic3r::GUI::show_info(this, L("Your file was repaired."), L("Repair"));
|
||||
}
|
||||
|
|
|
@ -91,11 +91,9 @@ void MeshClipper::recalculate_triangles()
|
|||
MeshSlicingParams slicing_params;
|
||||
slicing_params.trafo.rotate(Eigen::Quaternion<double, Eigen::DontAlign>::FromTwoVectors(up, Vec3d::UnitZ()));
|
||||
|
||||
assert(m_mesh->has_shared_vertices());
|
||||
ExPolygons expolys = union_ex(slice_mesh(m_mesh->its, height_mesh, slicing_params));
|
||||
|
||||
if (m_negative_mesh && !m_negative_mesh->empty()) {
|
||||
assert(m_negative_mesh->has_shared_vertices());
|
||||
ExPolygons neg_expolys = union_ex(slice_mesh(m_negative_mesh->its, height_mesh, slicing_params));
|
||||
expolys = diff_ex(expolys, neg_expolys);
|
||||
}
|
||||
|
|
|
@ -1135,7 +1135,7 @@ void Sidebar::show_info_sizer()
|
|||
static_cast<int>(model_object->facets_count()), stats.number_of_parts));
|
||||
|
||||
int errors = stats.degenerate_facets + stats.edges_fixed + stats.facets_removed +
|
||||
stats.facets_added + stats.facets_reversed + stats.backwards_edges;
|
||||
stats.facets_reversed + stats.backwards_edges;
|
||||
if (errors > 0) {
|
||||
wxString tooltip = format_wxstr(_L_PLURAL("Auto-repaired %1$d error", "Auto-repaired %1$d errors", errors), errors);
|
||||
p->object_info->info_manifold->SetLabel(tooltip);
|
||||
|
@ -1147,8 +1147,6 @@ void Sidebar::show_info_sizer()
|
|||
tooltip += format_wxstr(_L_PLURAL("%1$d edge fixed", "%1$d edges fixed", stats.edges_fixed), stats.edges_fixed) + ", ";
|
||||
if (stats.facets_removed > 0)
|
||||
tooltip += format_wxstr(_L_PLURAL("%1$d facet removed", "%1$d facets removed", stats.facets_removed), stats.facets_removed) + ", ";
|
||||
if (stats.facets_added > 0)
|
||||
tooltip += format_wxstr(_L_PLURAL("%1$d facet added", "%1$d facets added", stats.facets_added), stats.facets_added) + ", ";
|
||||
if (stats.facets_reversed > 0)
|
||||
tooltip += format_wxstr(_L_PLURAL("%1$d facet reversed", "%1$d facets reversed", stats.facets_reversed), stats.facets_reversed) + ", ";
|
||||
if (stats.backwards_edges > 0)
|
||||
|
@ -2544,16 +2542,14 @@ std::vector<size_t> Plater::priv::load_model_objects(const ModelObjectPtrs& mode
|
|||
if (max_ratio > 10000) {
|
||||
// the size of the object is too big -> this could lead to overflow when moving to clipper coordinates,
|
||||
// so scale down the mesh
|
||||
double inv = 1. / max_ratio;
|
||||
object->scale_mesh_after_creation(inv * Vec3d::Ones());
|
||||
object->scale_mesh_after_creation(1. / max_ratio);
|
||||
object->origin_translation = Vec3d::Zero();
|
||||
object->center_around_origin();
|
||||
scaled_down = true;
|
||||
break;
|
||||
}
|
||||
else if (max_ratio > 5) {
|
||||
const Vec3d inverse = 1.0 / max_ratio * Vec3d::Ones();
|
||||
instance->set_scaling_factor(inverse.cwiseProduct(instance->get_scaling_factor()));
|
||||
instance->set_scaling_factor(instance->get_scaling_factor() / max_ratio);
|
||||
scaled_down = true;
|
||||
}
|
||||
}
|
||||
|
@ -5587,11 +5583,9 @@ void Plater::export_stl(bool extended, bool selection_only)
|
|||
for (const ModelVolume *v : mo->volumes)
|
||||
if (v->is_model_part()) {
|
||||
TriangleMesh vol_mesh(v->mesh());
|
||||
vol_mesh.repair();
|
||||
vol_mesh.transform(v->get_matrix(), true);
|
||||
mesh.merge(vol_mesh);
|
||||
}
|
||||
mesh.repair();
|
||||
if (instances) {
|
||||
TriangleMesh vols_mesh(mesh);
|
||||
mesh = TriangleMesh();
|
||||
|
@ -5601,7 +5595,6 @@ void Plater::export_stl(bool extended, bool selection_only)
|
|||
mesh.merge(m);
|
||||
}
|
||||
}
|
||||
mesh.repair();
|
||||
return mesh;
|
||||
};
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue