mirror of
https://git.mirrors.martin98.com/https://github.com/prusa3d/PrusaSlicer.git
synced 2025-08-14 19:15:56 +08:00
Prepare ground for IGL experiments
Test with raycasting/Marching cubes
This commit is contained in:
parent
f5ec76c230
commit
ab80ef4dd9
@ -700,6 +700,16 @@ wxMenuItem* MenuFactory::append_menu_item_fix_through_netfabb(wxMenu* menu)
|
||||
return menu_item;
|
||||
}
|
||||
|
||||
|
||||
wxMenuItem* MenuFactory::append_menu_item_fix_model_mesh(wxMenu* menu)
|
||||
{
|
||||
wxMenuItem* menu_item = append_menu_item(menu, wxID_ANY, _L("Fix model mesh"), "",
|
||||
[](wxCommandEvent&) { obj_list()->fix_model_mesh(); }, "", menu,
|
||||
[]() {return plater()->can_fix_model_mesh(); }, m_parent);
|
||||
|
||||
return menu_item;
|
||||
}
|
||||
|
||||
wxMenuItem* MenuFactory::append_menu_item_simplify(wxMenu* menu)
|
||||
{
|
||||
wxMenuItem* menu_item = append_menu_item(menu, wxID_ANY, _L("Simplify model"), "",
|
||||
@ -923,6 +933,7 @@ void MenuFactory::create_common_object_menu(wxMenu* menu)
|
||||
append_menu_item_scale_selection_to_fit_print_volume(menu);
|
||||
|
||||
append_menu_item_fix_through_netfabb(menu);
|
||||
append_menu_item_fix_model_mesh(menu);
|
||||
append_menu_item_simplify(menu);
|
||||
append_menu_items_mirror(menu);
|
||||
}
|
||||
|
@ -92,6 +92,7 @@ private:
|
||||
wxMenuItem* append_menu_item_printable(wxMenu* menu);
|
||||
void append_menu_items_osx(wxMenu* menu);
|
||||
wxMenuItem* append_menu_item_fix_through_netfabb(wxMenu* menu);
|
||||
wxMenuItem* append_menu_item_fix_model_mesh(wxMenu* menu);
|
||||
wxMenuItem* append_menu_item_simplify(wxMenu* menu);
|
||||
void append_menu_item_export_stl(wxMenu* menu);
|
||||
void append_menu_item_reload_from_disk(wxMenu* menu);
|
||||
|
@ -28,6 +28,7 @@
|
||||
#include <wx/numformatter.h>
|
||||
|
||||
#include "slic3r/Utils/FixModelByWin10.hpp"
|
||||
#include "slic3r/Utils/FixModelMesh.hpp"
|
||||
|
||||
#ifdef __WXMSW__
|
||||
#include "wx/uiaction.h"
|
||||
@ -4164,6 +4165,117 @@ void ObjectList::fix_through_netfabb()
|
||||
plater->get_notification_manager()->push_notification(NotificationType::NetfabbFinished, NotificationManager::NotificationLevel::PrintInfoShortNotificationLevel, boost::nowide::narrow(msg));
|
||||
}
|
||||
|
||||
|
||||
void ObjectList::fix_model_mesh()
|
||||
{
|
||||
// Do not fix anything when a gizmo is open. There might be issues with updates
|
||||
// and what is worse, the snapshot time would refer to the internal stack.
|
||||
if (!wxGetApp().plater()->canvas3D()->get_gizmos_manager().check_gizmos_closed_except(GLGizmosManager::Undefined))
|
||||
return;
|
||||
|
||||
// model_name
|
||||
std::vector<std::string> succes_models;
|
||||
// model_name failing reason
|
||||
std::vector<std::pair<std::string, std::string>> failed_models;
|
||||
|
||||
std::vector<int> obj_idxs, vol_idxs;
|
||||
get_selection_indexes(obj_idxs, vol_idxs);
|
||||
|
||||
std::vector<std::string> model_names;
|
||||
|
||||
// fill names of models to repairing
|
||||
if (vol_idxs.empty()) {
|
||||
for (int obj_idx : obj_idxs)
|
||||
model_names.push_back(object(obj_idx)->name);
|
||||
}
|
||||
else {
|
||||
ModelObject* obj = object(obj_idxs.front());
|
||||
for (int vol_idx : vol_idxs)
|
||||
model_names.push_back(obj->volumes[vol_idx]->name);
|
||||
}
|
||||
|
||||
auto plater = wxGetApp().plater();
|
||||
|
||||
auto fix_and_update_progress = [this, plater, model_names](const int obj_idx, const int vol_idx,
|
||||
int model_idx,
|
||||
wxProgressDialog& progress_dlg,
|
||||
std::vector<std::string>& succes_models,
|
||||
std::vector<std::pair<std::string, std::string>>& failed_models)
|
||||
{
|
||||
const std::string& model_name = model_names[model_idx];
|
||||
wxString msg = _L("Repairing model");
|
||||
if (model_names.size() == 1)
|
||||
msg += ": " + from_u8(model_name) + "\n";
|
||||
else {
|
||||
msg += ":\n";
|
||||
for (int i = 0; i < int(model_names.size()); ++i)
|
||||
msg += (i == model_idx ? " > " : " ") + from_u8(model_names[i]) + "\n";
|
||||
msg += "\n";
|
||||
}
|
||||
|
||||
plater->clear_before_change_mesh(obj_idx);
|
||||
std::string res;
|
||||
if (!fix_by_raycasting(*(object(obj_idx)), vol_idx, progress_dlg, msg, res))
|
||||
return false;
|
||||
wxGetApp().plater()->changed_mesh(obj_idx);
|
||||
|
||||
plater->changed_mesh(obj_idx);
|
||||
|
||||
if (res.empty())
|
||||
succes_models.push_back(model_name);
|
||||
else
|
||||
failed_models.push_back({ model_name, res });
|
||||
|
||||
update_item_error_icon(obj_idx, vol_idx);
|
||||
update_info_items(obj_idx);
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
Plater::TakeSnapshot snapshot(plater, _L("Fix model mesh"));
|
||||
|
||||
// Open a progress dialog.
|
||||
wxProgressDialog progress_dlg(_L("Fixing model mesh"), "", 100, find_toplevel_parent(plater),
|
||||
wxPD_AUTO_HIDE | wxPD_APP_MODAL | wxPD_CAN_ABORT);
|
||||
int model_idx{ 0 };
|
||||
if (vol_idxs.empty()) {
|
||||
int vol_idx{ -1 };
|
||||
for (int obj_idx : obj_idxs) {
|
||||
if (!fix_and_update_progress(obj_idx, vol_idx, model_idx, progress_dlg, succes_models, failed_models))
|
||||
break;
|
||||
model_idx++;
|
||||
}
|
||||
}
|
||||
else {
|
||||
int obj_idx{ obj_idxs.front() };
|
||||
for (int vol_idx : vol_idxs) {
|
||||
if (!fix_and_update_progress(obj_idx, vol_idx, model_idx, progress_dlg, succes_models, failed_models))
|
||||
break;
|
||||
model_idx++;
|
||||
}
|
||||
}
|
||||
// Close the progress dialog
|
||||
progress_dlg.Update(100, "");
|
||||
|
||||
// Show info notification
|
||||
wxString msg;
|
||||
wxString bullet_suf = "\n - ";
|
||||
if (!succes_models.empty()) {
|
||||
msg = _L_PLURAL("The following model was repaired successfully", "The following models were repaired successfully", succes_models.size()) + ":";
|
||||
for (auto& model : succes_models)
|
||||
msg += bullet_suf + from_u8(model);
|
||||
msg += "\n\n";
|
||||
}
|
||||
if (!failed_models.empty()) {
|
||||
msg += _L_PLURAL("Folowing model repair failed", "Folowing models repair failed", failed_models.size()) + ":\n";
|
||||
for (auto& model : failed_models)
|
||||
msg += bullet_suf + from_u8(model.first) + ": " + _(model.second);
|
||||
}
|
||||
if (msg.IsEmpty())
|
||||
msg = _L("Repairing was canceled");
|
||||
plater->get_notification_manager()->push_notification(NotificationType::NetfabbFinished, NotificationManager::NotificationLevel::PrintInfoShortNotificationLevel, boost::nowide::narrow(msg));
|
||||
}
|
||||
|
||||
void ObjectList::simplify()
|
||||
{
|
||||
auto plater = wxGetApp().plater();
|
||||
|
@ -368,6 +368,7 @@ public:
|
||||
void split_instances();
|
||||
void rename_item();
|
||||
void fix_through_netfabb();
|
||||
void fix_model_mesh();
|
||||
void simplify();
|
||||
void update_item_error_icon(const int obj_idx, int vol_idx) const ;
|
||||
|
||||
|
@ -1910,6 +1910,7 @@ struct Plater::priv
|
||||
bool can_arrange() const;
|
||||
bool can_layers_editing() const;
|
||||
bool can_fix_through_netfabb() const;
|
||||
bool can_fix_model_mesh() const;
|
||||
bool can_simplify() const;
|
||||
bool can_set_instance_to_object() const;
|
||||
bool can_mirror() const;
|
||||
@ -4857,6 +4858,13 @@ bool Plater::priv::can_fix_through_netfabb() const
|
||||
#endif // FIX_THROUGH_NETFABB_ALWAYS
|
||||
}
|
||||
|
||||
bool Plater::priv::can_fix_model_mesh() const
|
||||
{
|
||||
std::vector<int> obj_idxs, vol_idxs;
|
||||
sidebar->obj_list()->get_selection_indexes(obj_idxs, vol_idxs);
|
||||
return ! obj_idxs.empty() || ! vol_idxs.empty();
|
||||
}
|
||||
|
||||
bool Plater::priv::can_simplify() const
|
||||
{
|
||||
// is object for simplification selected
|
||||
@ -7075,6 +7083,7 @@ bool Plater::can_increase_instances() const { return p->can_increase_instances()
|
||||
bool Plater::can_decrease_instances() const { return p->can_decrease_instances(); }
|
||||
bool Plater::can_set_instance_to_object() const { return p->can_set_instance_to_object(); }
|
||||
bool Plater::can_fix_through_netfabb() const { return p->can_fix_through_netfabb(); }
|
||||
bool Plater::can_fix_model_mesh() const { return p->can_fix_model_mesh(); }
|
||||
bool Plater::can_simplify() const { return p->can_simplify(); }
|
||||
bool Plater::can_split_to_objects() const { return p->can_split_to_objects(); }
|
||||
bool Plater::can_split_to_volumes() const { return p->can_split_to_volumes(); }
|
||||
|
@ -351,6 +351,7 @@ public:
|
||||
bool can_decrease_instances() const;
|
||||
bool can_set_instance_to_object() const;
|
||||
bool can_fix_through_netfabb() const;
|
||||
bool can_fix_model_mesh() const;
|
||||
bool can_simplify() const;
|
||||
bool can_split_to_objects() const;
|
||||
bool can_split_to_volumes() const;
|
||||
|
154
src/slic3r/Utils/FixModelMesh.hpp
Normal file
154
src/slic3r/Utils/FixModelMesh.hpp
Normal file
@ -0,0 +1,154 @@
|
||||
#ifndef SRC_SLIC3R_UTILS_FIXMODELMESH_HPP_
|
||||
#define SRC_SLIC3R_UTILS_FIXMODELMESH_HPP_
|
||||
|
||||
#include <string>
|
||||
#include "libslic3r/AABBTreeIndirect.hpp"
|
||||
#include "tbb/parallel_for.h"
|
||||
#include "tbb/blocked_range.h"
|
||||
#include "libigl/igl/copyleft/marching_cubes.h"
|
||||
#include "libigl/igl/voxel_grid.h"
|
||||
|
||||
class wxProgressDialog;
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
namespace detail {
|
||||
|
||||
Vec3f sample_sphere_uniform(const Vec2f &samples) {
|
||||
float term1 = 2.0f * float(PI) * samples.x();
|
||||
float term2 = 2.0f * sqrt(samples.y() - samples.y() * samples.y());
|
||||
return {cos(term1) * term2, sin(term1) * term2,
|
||||
1.0f - 2.0f * samples.y()};
|
||||
}
|
||||
|
||||
indexed_triangle_set fix_model_volume_mesh(const TriangleMesh &mesh) {
|
||||
float thickness = 2.0f;
|
||||
float resolution = 0.2f;
|
||||
|
||||
//prepare uniform samples of a sphere
|
||||
size_t sqrt_sample_count = 8;
|
||||
float step_size = 1.0f / sqrt_sample_count;
|
||||
std::vector<Vec3f> precomputed_sample_directions(
|
||||
sqrt_sample_count * sqrt_sample_count);
|
||||
for (size_t x_idx = 0; x_idx < sqrt_sample_count; ++x_idx) {
|
||||
float sample_x = x_idx * step_size + step_size / 2.0;
|
||||
for (size_t y_idx = 0; y_idx < sqrt_sample_count; ++y_idx) {
|
||||
size_t dir_index = x_idx * sqrt_sample_count + y_idx;
|
||||
float sample_y = y_idx * step_size + step_size / 2.0;
|
||||
precomputed_sample_directions[dir_index] = sample_sphere_uniform( { sample_x, sample_y });
|
||||
}
|
||||
}
|
||||
|
||||
indexed_triangle_set its = mesh.its;
|
||||
float max_size = mesh.bounding_box().size().maxCoeff();
|
||||
int samples = max_size / resolution;
|
||||
// create grid
|
||||
Eigen::MatrixXf grid_points;
|
||||
Eigen::RowVector3i res;
|
||||
|
||||
const BoundingBoxf3 &slicer_bbox = mesh.bounding_box();
|
||||
Eigen::AlignedBox<float, 3> eigen_box(slicer_bbox.min.cast<float>(), slicer_bbox.max.cast<float>());
|
||||
|
||||
std::cout << "building voxel grid " << std::endl;
|
||||
igl::voxel_grid(eigen_box, samples, 1, grid_points, res);
|
||||
|
||||
auto tree = AABBTreeIndirect::build_aabb_tree_over_indexed_triangle_set(its.vertices, its.indices);
|
||||
Eigen::VectorXf grid_values;
|
||||
grid_values.resize(grid_points.size());
|
||||
|
||||
std::cout << "g info: " << grid_points.size() << std::endl;
|
||||
std::cout << "g info: " << grid_points.rows() << std::endl;
|
||||
std::cout << "g info: " << grid_points.cols() << std::endl;
|
||||
|
||||
std::cout << "raycasting " << std::endl;
|
||||
|
||||
tbb::parallel_for(
|
||||
tbb::blocked_range<size_t>(0, grid_points.rows()), [&](tbb::blocked_range<size_t> r) {
|
||||
for (size_t index = r.begin(); index < r.end(); ++index) {
|
||||
Vec3f origin = grid_points.row(index);
|
||||
float &value = grid_values(index);
|
||||
|
||||
size_t hit_idx;
|
||||
Vec3f hit_point;
|
||||
bool apply_bonus = false;
|
||||
float distance = sqrt(AABBTreeIndirect::squared_distance_to_indexed_triangle_set(its.vertices, its.indices, tree, origin, hit_idx, hit_point));
|
||||
Vec3f face_normal = its_face_normal(its, hit_idx);
|
||||
if ((hit_point - origin).dot(face_normal) > 0 && distance < thickness) {
|
||||
apply_bonus = true;
|
||||
}
|
||||
|
||||
igl::Hit hit;
|
||||
size_t inside_hits = 0;
|
||||
for (const Vec3f &dir : precomputed_sample_directions) {
|
||||
if (AABBTreeIndirect::intersect_ray_first_hit(its.vertices, its.indices, tree,
|
||||
Vec3d(origin.cast<double>()),
|
||||
Vec3d(dir.cast<double>()), hit)) {
|
||||
Vec3f face_normal = its_face_normal(its, hit.id);
|
||||
if (dir.dot(face_normal) > 0) {
|
||||
inside_hits += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (inside_hits > precomputed_sample_directions.size() / 2) {
|
||||
value = -distance;
|
||||
if (apply_bonus) {
|
||||
value = -2.0f * distance;
|
||||
}
|
||||
} else {
|
||||
value = distance;
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
std::cout << "marching cubes " << std::endl;
|
||||
Eigen::MatrixXf vertices;
|
||||
Eigen::MatrixXi faces;
|
||||
igl::copyleft::marching_cubes(grid_values, grid_points, res.x(), res.y(), res.z(), vertices, faces);
|
||||
|
||||
std::cout << "vertices info: " << vertices.size() << std::endl;
|
||||
std::cout << "vertices info: " << vertices.rows() << std::endl;
|
||||
std::cout << "vertices info: " << vertices.cols() << std::endl;
|
||||
|
||||
indexed_triangle_set fixed_mesh;
|
||||
fixed_mesh.vertices.resize(vertices.rows());
|
||||
fixed_mesh.indices.resize(faces.rows());
|
||||
|
||||
for (int v = 0; v < vertices.rows(); ++v) {
|
||||
fixed_mesh.vertices[v] = vertices.row(v);
|
||||
}
|
||||
|
||||
for (int f = 0; f < faces.rows(); ++f) {
|
||||
fixed_mesh.indices[f] = faces.row(f);
|
||||
}
|
||||
|
||||
return fixed_mesh;
|
||||
}
|
||||
}
|
||||
|
||||
bool fix_by_raycasting(ModelObject &model_object, int volume_idx, wxProgressDialog &progress_dlg,
|
||||
const wxString &msg_header, std::string &fix_result) {
|
||||
|
||||
std::vector<ModelVolume*> volumes;
|
||||
if (volume_idx == -1) {
|
||||
volumes = model_object.volumes;
|
||||
} else {
|
||||
volumes.emplace_back(model_object.volumes[volume_idx]);
|
||||
}
|
||||
|
||||
for (ModelVolume *mv : volumes) {
|
||||
auto mesh = mv->mesh();
|
||||
mv->set_mesh(detail::fix_model_volume_mesh(mesh));
|
||||
std::cout << "update mv " << std::endl;
|
||||
mv->calculate_convex_hull();
|
||||
mv->set_new_unique_id();
|
||||
}
|
||||
model_object.invalidate_bounding_box();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif /* SRC_SLIC3R_UTILS_FIXMODELMESH_HPP_ */
|
Loading…
x
Reference in New Issue
Block a user