Merge branch 'master' of https://github.com/prusa3d/PrusaSlicer into et_preview_layout
Before Width: | Height: | Size: 600 B |
Before Width: | Height: | Size: 695 B |
Before Width: | Height: | Size: 589 B |
Before Width: | Height: | Size: 628 B |
Before Width: | Height: | Size: 631 B |
Before Width: | Height: | Size: 651 B |
Before Width: | Height: | Size: 93 B |
4
resources/icons/mirroring_transparent.svg
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<svg width="19" height="19" version="1.1" viewBox="0 0 19 19" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path id="rectangle_transparent" d="m0 0h19v19h-19z" fill-opacity="0"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 217 B |
Before Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 158 B |
Before Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 164 B |
Before Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 158 B |
Before Width: | Height: | Size: 1,001 B |
Before Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 997 B |
Before Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 5.7 KiB |
Before Width: | Height: | Size: 654 B |
Before Width: | Height: | Size: 1.9 KiB |
Before Width: | Height: | Size: 803 B |
Before Width: | Height: | Size: 465 B |
Before Width: | Height: | Size: 650 B |
Before Width: | Height: | Size: 1 KiB |
Before Width: | Height: | Size: 9.8 KiB |
|
@ -513,6 +513,22 @@ void Model::convert_from_meters(bool only_small_volumes)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static constexpr const double zero_volume = 0.0000000001;
|
||||||
|
|
||||||
|
int Model::removed_objects_with_zero_volume()
|
||||||
|
{
|
||||||
|
if (objects.size() == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
int removed = 0;
|
||||||
|
for (int i = int(objects.size()) - 1; i >= 0; i--)
|
||||||
|
if (objects[i]->get_object_stl_stats().volume < zero_volume) {
|
||||||
|
delete_object(size_t(i));
|
||||||
|
removed++;
|
||||||
|
}
|
||||||
|
return removed;
|
||||||
|
}
|
||||||
|
|
||||||
void Model::adjust_min_z()
|
void Model::adjust_min_z()
|
||||||
{
|
{
|
||||||
if (objects.empty())
|
if (objects.empty())
|
||||||
|
@ -1629,10 +1645,10 @@ TriangleMeshStats ModelObject::get_object_stl_stats() const
|
||||||
return full_stats;
|
return full_stats;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ModelObject::get_mesh_errors_count(const int vol_idx /*= -1*/) const
|
int ModelObject::get_repaired_errors_count(const int vol_idx /*= -1*/) const
|
||||||
{
|
{
|
||||||
if (vol_idx >= 0)
|
if (vol_idx >= 0)
|
||||||
return this->volumes[vol_idx]->get_mesh_errors_count();
|
return this->volumes[vol_idx]->get_repaired_errors_count();
|
||||||
|
|
||||||
const RepairedMeshErrors& stats = get_object_stl_stats().repaired_errors;
|
const RepairedMeshErrors& stats = get_object_stl_stats().repaired_errors;
|
||||||
|
|
||||||
|
@ -1704,7 +1720,7 @@ void ModelVolume::calculate_convex_hull()
|
||||||
assert(m_convex_hull.get());
|
assert(m_convex_hull.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
int ModelVolume::get_mesh_errors_count() const
|
int ModelVolume::get_repaired_errors_count() const
|
||||||
{
|
{
|
||||||
const RepairedMeshErrors &stats = this->mesh().stats().repaired_errors;
|
const RepairedMeshErrors &stats = this->mesh().stats().repaired_errors;
|
||||||
|
|
||||||
|
|
|
@ -377,7 +377,7 @@ public:
|
||||||
// Get full stl statistics for all object's meshes
|
// Get full stl statistics for all object's meshes
|
||||||
TriangleMeshStats get_object_stl_stats() const;
|
TriangleMeshStats get_object_stl_stats() const;
|
||||||
// Get count of errors in the mesh( or all object's meshes, if volume index isn't defined)
|
// Get count of errors in the mesh( or all object's meshes, if volume index isn't defined)
|
||||||
int get_mesh_errors_count(const int vol_idx = -1) const;
|
int get_repaired_errors_count(const int vol_idx = -1) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend class Model;
|
friend class Model;
|
||||||
|
@ -682,7 +682,7 @@ public:
|
||||||
const TriangleMesh& get_convex_hull() const;
|
const TriangleMesh& get_convex_hull() const;
|
||||||
std::shared_ptr<const TriangleMesh> get_convex_hull_shared_ptr() const { return m_convex_hull; }
|
std::shared_ptr<const TriangleMesh> get_convex_hull_shared_ptr() const { return m_convex_hull; }
|
||||||
// Get count of errors in the mesh
|
// Get count of errors in the mesh
|
||||||
int get_mesh_errors_count() const;
|
int get_repaired_errors_count() const;
|
||||||
|
|
||||||
// Helpers for loading / storing into AMF / 3MF files.
|
// Helpers for loading / storing into AMF / 3MF files.
|
||||||
static ModelVolumeType type_from_string(const std::string &s);
|
static ModelVolumeType type_from_string(const std::string &s);
|
||||||
|
@ -1124,6 +1124,7 @@ public:
|
||||||
void convert_from_imperial_units(bool only_small_volumes);
|
void convert_from_imperial_units(bool only_small_volumes);
|
||||||
bool looks_like_saved_in_meters() const;
|
bool looks_like_saved_in_meters() const;
|
||||||
void convert_from_meters(bool only_small_volumes);
|
void convert_from_meters(bool only_small_volumes);
|
||||||
|
int removed_objects_with_zero_volume();
|
||||||
|
|
||||||
// Ensures that the min z of the model is not negative
|
// Ensures that the min z of the model is not negative
|
||||||
void adjust_min_z();
|
void adjust_min_z();
|
||||||
|
|
|
@ -68,8 +68,7 @@ TriangleMesh::TriangleMesh(const indexed_triangle_set &its) : its(its)
|
||||||
|
|
||||||
TriangleMesh::TriangleMesh(indexed_triangle_set &&its, const RepairedMeshErrors& errors/* = RepairedMeshErrors()*/) : its(std::move(its))
|
TriangleMesh::TriangleMesh(indexed_triangle_set &&its, const RepairedMeshErrors& errors/* = RepairedMeshErrors()*/) : its(std::move(its))
|
||||||
{
|
{
|
||||||
if (errors.repaired())
|
m_stats.repaired_errors = errors;
|
||||||
m_stats.repaired_errors = errors;
|
|
||||||
fill_initial_stats(this->its, m_stats);
|
fill_initial_stats(this->its, m_stats);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -33,14 +33,12 @@ struct RepairedMeshErrors {
|
||||||
|
|
||||||
void clear() { *this = RepairedMeshErrors(); }
|
void clear() { *this = RepairedMeshErrors(); }
|
||||||
|
|
||||||
RepairedMeshErrors merge(const RepairedMeshErrors& rhs) const {
|
void merge(const RepairedMeshErrors& rhs) {
|
||||||
RepairedMeshErrors out;
|
this->edges_fixed += rhs.edges_fixed;
|
||||||
out.edges_fixed = this->edges_fixed + rhs.edges_fixed;
|
this->degenerate_facets += rhs.degenerate_facets;
|
||||||
out.degenerate_facets = this->degenerate_facets + rhs.degenerate_facets;
|
this->facets_removed += rhs.facets_removed;
|
||||||
out.facets_removed = this->facets_removed + rhs.facets_removed;
|
this->facets_reversed += rhs.facets_reversed;
|
||||||
out.facets_reversed = this->facets_reversed + rhs.facets_reversed;
|
this->backwards_edges += rhs.backwards_edges;
|
||||||
out.backwards_edges = this->backwards_edges + rhs.backwards_edges;
|
|
||||||
return out;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool repaired() const { return degenerate_facets > 0 || edges_fixed > 0 || facets_removed > 0 || facets_reversed > 0 || backwards_edges > 0; }
|
bool repaired() const { return degenerate_facets > 0 || edges_fixed > 0 || facets_removed > 0 || facets_reversed > 0 || backwards_edges > 0; }
|
||||||
|
|
|
@ -375,9 +375,9 @@ void ObjectList::get_selection_indexes(std::vector<int>& obj_idxs, std::vector<i
|
||||||
obj_idxs.erase(std::unique(obj_idxs.begin(), obj_idxs.end()), obj_idxs.end());
|
obj_idxs.erase(std::unique(obj_idxs.begin(), obj_idxs.end()), obj_idxs.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
int ObjectList::get_mesh_errors_count(const int obj_idx, const int vol_idx /*= -1*/) const
|
int ObjectList::get_repaired_errors_count(const int obj_idx, const int vol_idx /*= -1*/) const
|
||||||
{
|
{
|
||||||
return obj_idx >= 0 ? (*m_objects)[obj_idx]->get_mesh_errors_count(vol_idx) : 0;
|
return obj_idx >= 0 ? (*m_objects)[obj_idx]->get_repaired_errors_count(vol_idx) : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::string get_warning_icon_name(const TriangleMeshStats& stats)
|
static std::string get_warning_icon_name(const TriangleMeshStats& stats)
|
||||||
|
@ -385,8 +385,11 @@ static std::string get_warning_icon_name(const TriangleMeshStats& stats)
|
||||||
return stats.manifold() ? (stats.repaired() ? "exclamation_manifold" : "") : "exclamation";
|
return stats.manifold() ? (stats.repaired() ? "exclamation_manifold" : "") : "exclamation";
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<wxString, std::string> ObjectList::get_mesh_errors(const int obj_idx, const int vol_idx /*= -1*/, wxString* sidebar_info /*= nullptr*/) const
|
MeshErrorsInfo ObjectList::get_mesh_errors_info(const int obj_idx, const int vol_idx /*= -1*/, wxString* sidebar_info /*= nullptr*/) const
|
||||||
{
|
{
|
||||||
|
if (obj_idx < 0)
|
||||||
|
return { {}, {} }; // hide tooltip
|
||||||
|
|
||||||
const TriangleMeshStats& stats = vol_idx == -1 ?
|
const TriangleMeshStats& stats = vol_idx == -1 ?
|
||||||
(*m_objects)[obj_idx]->get_object_stl_stats() :
|
(*m_objects)[obj_idx]->get_object_stl_stats() :
|
||||||
(*m_objects)[obj_idx]->volumes[vol_idx]->mesh().stats();
|
(*m_objects)[obj_idx]->volumes[vol_idx]->mesh().stats();
|
||||||
|
@ -401,7 +404,7 @@ std::pair<wxString, std::string> ObjectList::get_mesh_errors(const int obj_idx,
|
||||||
|
|
||||||
// Create tooltip string, if there are errors
|
// Create tooltip string, if there are errors
|
||||||
if (stats.repaired()) {
|
if (stats.repaired()) {
|
||||||
const int errors = get_mesh_errors_count(obj_idx, vol_idx);
|
const int errors = get_repaired_errors_count(obj_idx, vol_idx);
|
||||||
auto_repaired_info = format_wxstr(_L_PLURAL("Auto-repaired %1$d error", "Auto-repaired %1$d errors", errors), errors);
|
auto_repaired_info = format_wxstr(_L_PLURAL("Auto-repaired %1$d error", "Auto-repaired %1$d errors", errors), errors);
|
||||||
tooltip += auto_repaired_info +":\n";
|
tooltip += auto_repaired_info +":\n";
|
||||||
|
|
||||||
|
@ -434,15 +437,24 @@ std::pair<wxString, std::string> ObjectList::get_mesh_errors(const int obj_idx,
|
||||||
return { tooltip, get_warning_icon_name(stats) };
|
return { tooltip, get_warning_icon_name(stats) };
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<wxString, std::string> ObjectList::get_mesh_errors(wxString* sidebar_info /*= nullptr*/)
|
MeshErrorsInfo ObjectList::get_mesh_errors_info(wxString* sidebar_info /*= nullptr*/)
|
||||||
{
|
{
|
||||||
if (!GetSelection())
|
wxDataViewItem item = GetSelection();
|
||||||
|
if (!item)
|
||||||
return { "", "" };
|
return { "", "" };
|
||||||
|
|
||||||
int obj_idx, vol_idx;
|
int obj_idx, vol_idx;
|
||||||
get_selected_item_indexes(obj_idx, vol_idx);
|
get_selected_item_indexes(obj_idx, vol_idx);
|
||||||
|
|
||||||
return get_mesh_errors(obj_idx, vol_idx, sidebar_info);
|
if (obj_idx < 0) { // child of ObjectItem is selected
|
||||||
|
if (sidebar_info)
|
||||||
|
obj_idx = m_objects_model->GetObjectIdByItem(item);
|
||||||
|
else
|
||||||
|
return { "", "" };
|
||||||
|
}
|
||||||
|
assert(obj_idx >= 0);
|
||||||
|
|
||||||
|
return get_mesh_errors_info(obj_idx, vol_idx, sidebar_info);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ObjectList::set_tooltip_for_item(const wxPoint& pt)
|
void ObjectList::set_tooltip_for_item(const wxPoint& pt)
|
||||||
|
@ -478,9 +490,12 @@ void ObjectList::set_tooltip_for_item(const wxPoint& pt)
|
||||||
#endif //__WXMSW__
|
#endif //__WXMSW__
|
||||||
else if (col->GetTitle() == _("Name") && (pt.x >= 2 * wxGetApp().em_unit() && pt.x <= 4 * wxGetApp().em_unit()))
|
else if (col->GetTitle() == _("Name") && (pt.x >= 2 * wxGetApp().em_unit() && pt.x <= 4 * wxGetApp().em_unit()))
|
||||||
{
|
{
|
||||||
int obj_idx, vol_idx;
|
if (const ItemType type = m_objects_model->GetItemType(item);
|
||||||
get_selected_item_indexes(obj_idx, vol_idx, item);
|
type & (itObject | itVolume)) {
|
||||||
tooltip = get_mesh_errors(obj_idx, vol_idx).first;
|
int obj_idx = m_objects_model->GetObjectIdByItem(item);
|
||||||
|
int vol_idx = type & itVolume ? m_objects_model->GetVolumeIdByItem(item) : -1;
|
||||||
|
tooltip = get_mesh_errors_info(obj_idx, vol_idx).tooltip;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
GetMainWindow()->SetToolTip(tooltip);
|
GetMainWindow()->SetToolTip(tooltip);
|
||||||
|
@ -1797,10 +1812,8 @@ void ObjectList::del_subobject_item(wxDataViewItem& item)
|
||||||
|
|
||||||
// If last volume item with warning was deleted, unmark object item
|
// If last volume item with warning was deleted, unmark object item
|
||||||
if (type & itVolume) {
|
if (type & itVolume) {
|
||||||
if (auto obj = object(obj_idx); obj->get_mesh_errors_count() == 0)
|
const std::string& icon_name = get_warning_icon_name(object(obj_idx)->get_object_stl_stats());
|
||||||
m_objects_model->DeleteWarningIcon(parent);
|
m_objects_model->UpdateWarningIcon(parent, icon_name);
|
||||||
else
|
|
||||||
m_objects_model->AddWarningIcon(parent, get_warning_icon_name(obj->mesh().stats()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
m_objects_model->Delete(item);
|
m_objects_model->Delete(item);
|
||||||
|
@ -2509,7 +2522,7 @@ void ObjectList::part_selection_changed()
|
||||||
if (item) {
|
if (item) {
|
||||||
// wxGetApp().obj_manipul()->get_og()->set_value("object_name", m_objects_model->GetName(item));
|
// wxGetApp().obj_manipul()->get_og()->set_value("object_name", m_objects_model->GetName(item));
|
||||||
wxGetApp().obj_manipul()->update_item_name(m_objects_model->GetName(item));
|
wxGetApp().obj_manipul()->update_item_name(m_objects_model->GetName(item));
|
||||||
wxGetApp().obj_manipul()->update_warning_icon_state(get_mesh_errors(obj_idx, volume_id));
|
wxGetApp().obj_manipul()->update_warning_icon_state(get_mesh_errors_info(obj_idx, volume_id));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2769,10 +2782,7 @@ void ObjectList::delete_from_model_and_list(const std::vector<ItemForDelete>& it
|
||||||
m_objects_model->SetExtruder(extruder, parent);
|
m_objects_model->SetExtruder(extruder, parent);
|
||||||
}
|
}
|
||||||
// If last volume item with warning was deleted, unmark object item
|
// If last volume item with warning was deleted, unmark object item
|
||||||
if (obj->get_mesh_errors_count() == 0)
|
m_objects_model->UpdateWarningIcon(parent, get_warning_icon_name(obj->get_object_stl_stats()));
|
||||||
m_objects_model->DeleteWarningIcon(parent);
|
|
||||||
else
|
|
||||||
m_objects_model->AddWarningIcon(parent, get_warning_icon_name(obj->mesh().stats()));
|
|
||||||
}
|
}
|
||||||
wxGetApp().plater()->canvas3D()->ensure_on_bed(item->obj_idx, printer_technology() != ptSLA);
|
wxGetApp().plater()->canvas3D()->ensure_on_bed(item->obj_idx, printer_technology() != ptSLA);
|
||||||
}
|
}
|
||||||
|
@ -4055,7 +4065,7 @@ void ObjectList::fix_through_netfabb()
|
||||||
if (vol_idxs.empty()) {
|
if (vol_idxs.empty()) {
|
||||||
#if !FIX_THROUGH_NETFABB_ALWAYS
|
#if !FIX_THROUGH_NETFABB_ALWAYS
|
||||||
for (int i = int(obj_idxs.size())-1; i >= 0; --i)
|
for (int i = int(obj_idxs.size())-1; i >= 0; --i)
|
||||||
if (object(obj_idxs[i])->get_mesh_errors_count() == 0)
|
if (object(obj_idxs[i])->get_repaired_errors_count() == 0)
|
||||||
obj_idxs.erase(obj_idxs.begin()+i);
|
obj_idxs.erase(obj_idxs.begin()+i);
|
||||||
#endif // FIX_THROUGH_NETFABB_ALWAYS
|
#endif // FIX_THROUGH_NETFABB_ALWAYS
|
||||||
for (int obj_idx : obj_idxs)
|
for (int obj_idx : obj_idxs)
|
||||||
|
@ -4065,7 +4075,7 @@ void ObjectList::fix_through_netfabb()
|
||||||
ModelObject* obj = object(obj_idxs.front());
|
ModelObject* obj = object(obj_idxs.front());
|
||||||
#if !FIX_THROUGH_NETFABB_ALWAYS
|
#if !FIX_THROUGH_NETFABB_ALWAYS
|
||||||
for (int i = int(vol_idxs.size()) - 1; i >= 0; --i)
|
for (int i = int(vol_idxs.size()) - 1; i >= 0; --i)
|
||||||
if (obj->get_mesh_errors_count(vol_idxs[i]) == 0)
|
if (obj->get_repaired_errors_count(vol_idxs[i]) == 0)
|
||||||
vol_idxs.erase(vol_idxs.begin() + i);
|
vol_idxs.erase(vol_idxs.begin() + i);
|
||||||
#endif // FIX_THROUGH_NETFABB_ALWAYS
|
#endif // FIX_THROUGH_NETFABB_ALWAYS
|
||||||
for (int vol_idx : vol_idxs)
|
for (int vol_idx : vol_idxs)
|
||||||
|
@ -4121,7 +4131,7 @@ void ObjectList::fix_through_netfabb()
|
||||||
int vol_idx{ -1 };
|
int vol_idx{ -1 };
|
||||||
for (int obj_idx : obj_idxs) {
|
for (int obj_idx : obj_idxs) {
|
||||||
#if !FIX_THROUGH_NETFABB_ALWAYS
|
#if !FIX_THROUGH_NETFABB_ALWAYS
|
||||||
if (object(obj_idx)->get_mesh_errors_count(vol_idx) == 0)
|
if (object(obj_idx)->get_repaired_errors_count(vol_idx) == 0)
|
||||||
continue;
|
continue;
|
||||||
#endif // FIX_THROUGH_NETFABB_ALWAYS
|
#endif // FIX_THROUGH_NETFABB_ALWAYS
|
||||||
if (!fix_and_update_progress(obj_idx, vol_idx, model_idx, progress_dlg, succes_models, failed_models))
|
if (!fix_and_update_progress(obj_idx, vol_idx, model_idx, progress_dlg, succes_models, failed_models))
|
||||||
|
@ -4178,24 +4188,18 @@ void ObjectList::simplify()
|
||||||
|
|
||||||
void ObjectList::update_item_error_icon(const int obj_idx, const int vol_idx) const
|
void ObjectList::update_item_error_icon(const int obj_idx, const int vol_idx) const
|
||||||
{
|
{
|
||||||
const wxDataViewItem item = vol_idx <0 ? m_objects_model->GetItemById(obj_idx) :
|
auto obj = object(obj_idx);
|
||||||
m_objects_model->GetItemByVolumeId(obj_idx, vol_idx);
|
if (wxDataViewItem obj_item = m_objects_model->GetItemById(obj_idx)) {
|
||||||
if (!item)
|
const std::string& icon_name = get_warning_icon_name(obj->get_object_stl_stats());
|
||||||
|
m_objects_model->UpdateWarningIcon(obj_item, icon_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (vol_idx < 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (get_mesh_errors_count(obj_idx, vol_idx) == 0)
|
if (wxDataViewItem vol_item = m_objects_model->GetItemByVolumeId(obj_idx, vol_idx)) {
|
||||||
{
|
const std::string& icon_name = get_warning_icon_name(obj->volumes[vol_idx]->mesh().stats());
|
||||||
// if whole object has no errors more,
|
m_objects_model->UpdateWarningIcon(vol_item, icon_name);
|
||||||
if (get_mesh_errors_count(obj_idx) == 0)
|
|
||||||
// unmark all items in the object
|
|
||||||
m_objects_model->DeleteWarningIcon(vol_idx >= 0 ? m_objects_model->GetParent(item) : item, true);
|
|
||||||
else
|
|
||||||
// unmark fixed item only
|
|
||||||
m_objects_model->DeleteWarningIcon(item);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
auto obj = object(obj_idx);
|
|
||||||
m_objects_model->AddWarningIcon(item, get_warning_icon_name(vol_idx < 0 ? obj->mesh().stats() : obj->volumes[vol_idx]->mesh().stats()));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -67,6 +67,12 @@ struct ItemForDelete
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct MeshErrorsInfo
|
||||||
|
{
|
||||||
|
wxString tooltip;
|
||||||
|
std::string warning_icon_name;
|
||||||
|
};
|
||||||
|
|
||||||
class ObjectList : public wxDataViewCtrl
|
class ObjectList : public wxDataViewCtrl
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -212,13 +218,13 @@ public:
|
||||||
void get_selected_item_indexes(int& obj_idx, int& vol_idx, const wxDataViewItem& item = wxDataViewItem(0));
|
void get_selected_item_indexes(int& obj_idx, int& vol_idx, const wxDataViewItem& item = wxDataViewItem(0));
|
||||||
void get_selection_indexes(std::vector<int>& obj_idxs, std::vector<int>& vol_idxs);
|
void get_selection_indexes(std::vector<int>& obj_idxs, std::vector<int>& vol_idxs);
|
||||||
// Get count of errors in the mesh
|
// Get count of errors in the mesh
|
||||||
int get_mesh_errors_count(const int obj_idx, const int vol_idx = -1) const;
|
int get_repaired_errors_count(const int obj_idx, const int vol_idx = -1) const;
|
||||||
// Get list of errors in the mesh and name of the warning icon
|
// Get list of errors in the mesh and name of the warning icon
|
||||||
// Return value is a pair <Tooltip, warning_icon_name>, used for the tooltip and related warning icon
|
// Return value is a pair <Tooltip, warning_icon_name>, used for the tooltip and related warning icon
|
||||||
// Function without parameters is for a call from Manipulation panel,
|
// Function without parameters is for a call from Manipulation panel,
|
||||||
// when we don't know parameters of selected item
|
// when we don't know parameters of selected item
|
||||||
std::pair<wxString, std::string> get_mesh_errors(const int obj_idx, const int vol_idx = -1, wxString* sidebar_info = nullptr) const;
|
MeshErrorsInfo get_mesh_errors_info(const int obj_idx, const int vol_idx = -1, wxString* sidebar_info = nullptr) const;
|
||||||
std::pair<wxString, std::string> get_mesh_errors(wxString* sidebar_info = nullptr);
|
MeshErrorsInfo get_mesh_errors_info(wxString* sidebar_info = nullptr);
|
||||||
void set_tooltip_for_item(const wxPoint& pt);
|
void set_tooltip_for_item(const wxPoint& pt);
|
||||||
|
|
||||||
void selection_changed();
|
void selection_changed();
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
#include "GUI_ObjectManipulation.hpp"
|
#include "GUI_ObjectManipulation.hpp"
|
||||||
#include "GUI_ObjectList.hpp"
|
|
||||||
#include "I18N.hpp"
|
#include "I18N.hpp"
|
||||||
#include "BitmapComboBox.hpp"
|
#include "BitmapComboBox.hpp"
|
||||||
|
|
||||||
|
@ -132,7 +131,7 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) :
|
||||||
return;
|
return;
|
||||||
|
|
||||||
wxGetApp().obj_list()->fix_through_netfabb();
|
wxGetApp().obj_list()->fix_through_netfabb();
|
||||||
update_warning_icon_state(wxGetApp().obj_list()->get_mesh_errors());
|
update_warning_icon_state(wxGetApp().obj_list()->get_mesh_errors_info());
|
||||||
});
|
});
|
||||||
|
|
||||||
sizer->Add(m_fix_throught_netfab_bitmap);
|
sizer->Add(m_fix_throught_netfab_bitmap);
|
||||||
|
@ -548,8 +547,8 @@ void ObjectManipulation::update_settings_value(const Selection& selection)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
m_new_rotation = volume->get_instance_rotation() * (180. / M_PI);
|
m_new_rotation = volume->get_instance_rotation() * (180. / M_PI);
|
||||||
m_new_size = volume->get_instance_transformation().get_scaling_factor().cwiseProduct(wxGetApp().model().objects[volume->object_idx()]->raw_mesh_bounding_box().size());
|
m_new_size = volume->get_instance_scaling_factor().cwiseProduct(wxGetApp().model().objects[volume->object_idx()]->raw_mesh_bounding_box().size());
|
||||||
m_new_scale = volume->get_instance_scaling_factor() * 100.;
|
m_new_scale = volume->get_instance_scaling_factor() * 100.;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_new_enabled = true;
|
m_new_enabled = true;
|
||||||
|
@ -570,7 +569,7 @@ void ObjectManipulation::update_settings_value(const Selection& selection)
|
||||||
m_new_position = volume->get_volume_offset();
|
m_new_position = volume->get_volume_offset();
|
||||||
m_new_rotation = volume->get_volume_rotation() * (180. / M_PI);
|
m_new_rotation = volume->get_volume_rotation() * (180. / M_PI);
|
||||||
m_new_scale = volume->get_volume_scaling_factor() * 100.;
|
m_new_scale = volume->get_volume_scaling_factor() * 100.;
|
||||||
m_new_size = volume->get_instance_transformation().get_scaling_factor().cwiseProduct(volume->get_volume_transformation().get_scaling_factor().cwiseProduct(volume->bounding_box().size()));
|
m_new_size = volume->get_instance_scaling_factor().cwiseProduct(volume->get_volume_scaling_factor().cwiseProduct(volume->bounding_box().size()));
|
||||||
m_new_enabled = true;
|
m_new_enabled = true;
|
||||||
}
|
}
|
||||||
else if (obj_list->multiple_selection() || obj_list->is_selected(itInstanceRoot)) {
|
else if (obj_list->multiple_selection() || obj_list->is_selected(itInstanceRoot)) {
|
||||||
|
@ -781,12 +780,12 @@ void ObjectManipulation::update_item_name(const wxString& item_name)
|
||||||
m_item_name->SetLabel(item_name);
|
m_item_name->SetLabel(item_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ObjectManipulation::update_warning_icon_state(const std::pair<wxString, std::string>& warning)
|
void ObjectManipulation::update_warning_icon_state(const MeshErrorsInfo& warning)
|
||||||
{
|
{
|
||||||
if (const std::string& warning_icon_name = warning.second;
|
if (const std::string& warning_icon_name = warning.warning_icon_name;
|
||||||
!warning_icon_name.empty())
|
!warning_icon_name.empty())
|
||||||
m_manifold_warning_bmp = ScalableBitmap(m_parent, warning_icon_name);
|
m_manifold_warning_bmp = ScalableBitmap(m_parent, warning_icon_name);
|
||||||
const wxString& tooltip = warning.first;
|
const wxString& tooltip = warning.tooltip;
|
||||||
m_fix_throught_netfab_bitmap->SetBitmap(tooltip.IsEmpty() ? wxNullBitmap : m_manifold_warning_bmp.bmp());
|
m_fix_throught_netfab_bitmap->SetBitmap(tooltip.IsEmpty() ? wxNullBitmap : m_manifold_warning_bmp.bmp());
|
||||||
m_fix_throught_netfab_bitmap->SetMinSize(tooltip.IsEmpty() ? wxSize(0,0) : m_manifold_warning_bmp.bmp().GetSize());
|
m_fix_throught_netfab_bitmap->SetMinSize(tooltip.IsEmpty() ? wxSize(0,0) : m_manifold_warning_bmp.bmp().GetSize());
|
||||||
m_fix_throught_netfab_bitmap->SetToolTip(tooltip);
|
m_fix_throught_netfab_bitmap->SetToolTip(tooltip);
|
||||||
|
@ -862,7 +861,7 @@ void ObjectManipulation::change_scale_value(int axis, double value)
|
||||||
Vec3d scale = m_cache.scale;
|
Vec3d scale = m_cache.scale;
|
||||||
scale(axis) = value;
|
scale(axis) = value;
|
||||||
|
|
||||||
this->do_scale(axis, scale);
|
this->do_scale(axis, 0.01 * scale);
|
||||||
|
|
||||||
m_cache.scale = scale;
|
m_cache.scale = scale;
|
||||||
m_cache.scale_rounded(axis) = DBL_MAX;
|
m_cache.scale_rounded(axis) = DBL_MAX;
|
||||||
|
@ -881,14 +880,21 @@ void ObjectManipulation::change_size_value(int axis, double value)
|
||||||
const Selection& selection = wxGetApp().plater()->canvas3D()->get_selection();
|
const Selection& selection = wxGetApp().plater()->canvas3D()->get_selection();
|
||||||
|
|
||||||
Vec3d ref_size = m_cache.size;
|
Vec3d ref_size = m_cache.size;
|
||||||
if (selection.is_single_volume() || selection.is_single_modifier())
|
if (selection.is_single_volume() || selection.is_single_modifier()) {
|
||||||
ref_size = selection.get_volume(*selection.get_volume_idxs().begin())->bounding_box().size();
|
const GLVolume* v = selection.get_volume(*selection.get_volume_idxs().begin());
|
||||||
|
const Vec3d local_size = size.cwiseQuotient(v->get_instance_scaling_factor());
|
||||||
|
const Vec3d local_ref_size = v->bounding_box().size().cwiseProduct(v->get_volume_scaling_factor());
|
||||||
|
const Vec3d local_change = local_size.cwiseQuotient(local_ref_size);
|
||||||
|
|
||||||
|
size = local_change.cwiseProduct(v->get_volume_scaling_factor());
|
||||||
|
ref_size = Vec3d::Ones();
|
||||||
|
}
|
||||||
else if (selection.is_single_full_instance())
|
else if (selection.is_single_full_instance())
|
||||||
ref_size = m_world_coordinates ?
|
ref_size = m_world_coordinates ?
|
||||||
selection.get_unscaled_instance_bounding_box().size() :
|
selection.get_unscaled_instance_bounding_box().size() :
|
||||||
wxGetApp().model().objects[selection.get_volume(*selection.get_volume_idxs().begin())->object_idx()]->raw_mesh_bounding_box().size();
|
wxGetApp().model().objects[selection.get_volume(*selection.get_volume_idxs().begin())->object_idx()]->raw_mesh_bounding_box().size();
|
||||||
|
|
||||||
this->do_scale(axis, 100. * Vec3d(size(0) / ref_size(0), size(1) / ref_size(1), size(2) / ref_size(2)));
|
this->do_scale(axis, size.cwiseQuotient(ref_size));
|
||||||
|
|
||||||
m_cache.size = size;
|
m_cache.size = size;
|
||||||
m_cache.size_rounded(axis) = DBL_MAX;
|
m_cache.size_rounded(axis) = DBL_MAX;
|
||||||
|
@ -911,7 +917,7 @@ void ObjectManipulation::do_scale(int axis, const Vec3d &scale) const
|
||||||
scaling_factor = scale(axis) * Vec3d::Ones();
|
scaling_factor = scale(axis) * Vec3d::Ones();
|
||||||
|
|
||||||
selection.start_dragging();
|
selection.start_dragging();
|
||||||
selection.scale(scaling_factor * 0.01, transformation_type);
|
selection.scale(scaling_factor, transformation_type);
|
||||||
wxGetApp().plater()->canvas3D()->do_scale(L("Set Scale"));
|
wxGetApp().plater()->canvas3D()->do_scale(L("Set Scale"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
#include "GUI_ObjectSettings.hpp"
|
#include "GUI_ObjectSettings.hpp"
|
||||||
|
#include "GUI_ObjectList.hpp"
|
||||||
#include "libslic3r/Point.hpp"
|
#include "libslic3r/Point.hpp"
|
||||||
#include <float.h>
|
#include <float.h>
|
||||||
|
|
||||||
|
@ -194,7 +195,7 @@ public:
|
||||||
#endif // __APPLE__
|
#endif // __APPLE__
|
||||||
|
|
||||||
void update_item_name(const wxString &item_name);
|
void update_item_name(const wxString &item_name);
|
||||||
void update_warning_icon_state(const std::pair<wxString, std::string>& warning);
|
void update_warning_icon_state(const MeshErrorsInfo& warning);
|
||||||
void msw_rescale();
|
void msw_rescale();
|
||||||
void sys_color_changed();
|
void sys_color_changed();
|
||||||
void on_change(const std::string& opt_key, int axis, double new_value);
|
void on_change(const std::string& opt_key, int axis, double new_value);
|
||||||
|
|
|
@ -1786,6 +1786,14 @@ bool ObjectDataViewModel::HasWarningIcon(const wxDataViewItem& item) const
|
||||||
return node->has_warning_icon();
|
return node->has_warning_icon();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ObjectDataViewModel::UpdateWarningIcon(const wxDataViewItem& item, const std::string& warning_icon_name)
|
||||||
|
{
|
||||||
|
if (warning_icon_name.empty())
|
||||||
|
DeleteWarningIcon(item, true);
|
||||||
|
else
|
||||||
|
AddWarningIcon(item, warning_icon_name);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace GUI
|
} // namespace GUI
|
||||||
} // namespace Slic3r
|
} // namespace Slic3r
|
||||||
|
|
||||||
|
|
|
@ -389,6 +389,7 @@ public:
|
||||||
const std::string& warning_icon_name = std::string());
|
const std::string& warning_icon_name = std::string());
|
||||||
void AddWarningIcon(const wxDataViewItem& item, const std::string& warning_name);
|
void AddWarningIcon(const wxDataViewItem& item, const std::string& warning_name);
|
||||||
void DeleteWarningIcon(const wxDataViewItem& item, const bool unmark_object = false);
|
void DeleteWarningIcon(const wxDataViewItem& item, const bool unmark_object = false);
|
||||||
|
void UpdateWarningIcon(const wxDataViewItem& item, const std::string& warning_name);
|
||||||
bool HasWarningIcon(const wxDataViewItem& item) const;
|
bool HasWarningIcon(const wxDataViewItem& item) const;
|
||||||
t_layer_height_range GetLayerRangeByItem(const wxDataViewItem& item) const;
|
t_layer_height_range GetLayerRangeByItem(const wxDataViewItem& item) const;
|
||||||
|
|
||||||
|
|
|
@ -1204,9 +1204,9 @@ void Sidebar::show_info_sizer()
|
||||||
static_cast<int>(model_object->facets_count()), stats.number_of_parts));
|
static_cast<int>(model_object->facets_count()), stats.number_of_parts));
|
||||||
|
|
||||||
wxString info_manifold_label;
|
wxString info_manifold_label;
|
||||||
auto mesh_errors = obj_list()->get_mesh_errors(&info_manifold_label);
|
auto mesh_errors = obj_list()->get_mesh_errors_info(&info_manifold_label);
|
||||||
wxString tooltip = mesh_errors.first;
|
wxString tooltip = mesh_errors.tooltip;
|
||||||
p->object_info->update_warning_icon(mesh_errors.second);
|
p->object_info->update_warning_icon(mesh_errors.warning_icon_name);
|
||||||
p->object_info->info_manifold->SetLabel(info_manifold_label);
|
p->object_info->info_manifold->SetLabel(info_manifold_label);
|
||||||
p->object_info->info_manifold->SetToolTip(tooltip);
|
p->object_info->info_manifold->SetToolTip(tooltip);
|
||||||
p->object_info->manifold_warning_icon->SetToolTip(tooltip);
|
p->object_info->manifold_warning_icon->SetToolTip(tooltip);
|
||||||
|
@ -2440,6 +2440,14 @@ std::vector<size_t> Plater::priv::load_files(const std::vector<fs::path>& input_
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!is_project_file) {
|
if (!is_project_file) {
|
||||||
|
if (int deleted_objects = model.removed_objects_with_zero_volume(); deleted_objects > 0) {
|
||||||
|
MessageDialog(q, format_wxstr(_L_PLURAL(
|
||||||
|
"Object size from file %s appears to be zero.\n"
|
||||||
|
"This object has been removed from the model",
|
||||||
|
"Objects size from file %s appear to be zero.\n"
|
||||||
|
"These objects have been removed from the model", deleted_objects), from_path(filename)) + "\n",
|
||||||
|
_L("Object size is zero"), wxICON_INFORMATION | wxOK).ShowModal();
|
||||||
|
}
|
||||||
if (imperial_units)
|
if (imperial_units)
|
||||||
// Convert even if the object is big.
|
// Convert even if the object is big.
|
||||||
convert_from_imperial_units(model, false);
|
convert_from_imperial_units(model, false);
|
||||||
|
@ -4597,14 +4605,14 @@ bool Plater::priv::can_fix_through_netfabb() const
|
||||||
// Fixing only if the model is not manifold.
|
// Fixing only if the model is not manifold.
|
||||||
if (vol_idxs.empty()) {
|
if (vol_idxs.empty()) {
|
||||||
for (auto obj_idx : obj_idxs)
|
for (auto obj_idx : obj_idxs)
|
||||||
if (model.objects[obj_idx]->get_mesh_errors_count() > 0)
|
if (model.objects[obj_idx]->get_repaired_errors_count() > 0)
|
||||||
return true;
|
return true;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
int obj_idx = obj_idxs.front();
|
int obj_idx = obj_idxs.front();
|
||||||
for (auto vol_idx : vol_idxs)
|
for (auto vol_idx : vol_idxs)
|
||||||
if (model.objects[obj_idx]->get_mesh_errors_count(vol_idx) > 0)
|
if (model.objects[obj_idx]->get_repaired_errors_count(vol_idx) > 0)
|
||||||
return true;
|
return true;
|
||||||
return false;
|
return false;
|
||||||
#endif // FIX_THROUGH_NETFABB_ALWAYS
|
#endif // FIX_THROUGH_NETFABB_ALWAYS
|
||||||
|
|