Merge branch 'master' of https://github.com/prusa3d/PrusaSlicer into et_sinking_objects_collision

This commit is contained in:
enricoturri1966 2021-10-07 14:22:06 +02:00
commit 29340c1560
56 changed files with 673 additions and 361 deletions

View File

@ -0,0 +1,73 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 25.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.0" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 1024 1024" enable-background="new 0 0 1024 1024" xml:space="preserve">
<circle fill="#FFFFFF" cx="512" cy="512" r="512"/>
<path fill="#333333" d="M308.97,650.05c0.72,0.89,1.44,1.77,2.17,2.65c0.47,0.57,0.94,1.13,1.42,1.69
c5.82,6.94,11.97,13.7,18.49,20.22l435.89-435.89c-21.69-21.69-45.83-39.46-71.5-53.33c-0.46-0.25-0.93-0.51-1.39-0.75
c-1.31-0.7-2.63-1.39-3.96-2.07c-0.58-0.3-1.16-0.59-1.73-0.88c-1.34-0.68-2.69-1.36-4.04-2.02c0,0,0,0,0,0l0,0
c-23.73-11.59-48.64-19.95-74.07-25.08l0,0c0,0,0,0,0,0c-4.86-0.98-9.74-1.84-14.63-2.59c0,0,0,0-0.01,0
c-2.44-0.37-4.89-0.71-7.34-1.03c0,0-0.01,0-0.01,0c-2.45-0.31-4.91-0.6-7.37-0.85l0,0l0,0c-8.26-0.85-16.54-1.39-24.83-1.58
c-1.96-0.04-3.92-0.06-5.87-0.07c-0.4,0-0.79-0.01-1.19-0.01c-0.3,0-0.61,0.01-0.91,0.01c-1.78,0.01-3.57,0.03-5.35,0.06
c-0.96,0.02-1.92,0.05-2.88,0.08c-1.03,0.03-2.05,0.07-3.08,0.11c-1.84,0.07-3.67,0.16-5.5,0.27c-0.56,0.03-1.12,0.07-1.68,0.1
c-15.09,0.95-30.12,2.99-44.97,6.15l0,0c0,0,0,0,0,0c-2.2,0.47-4.39,0.96-6.58,1.48c-0.14,0.03-0.28,0.06-0.42,0.1
c-2.11,0.5-4.22,1.03-6.33,1.57c-0.2,0.05-0.4,0.1-0.61,0.16c-2.07,0.54-4.14,1.11-6.2,1.7c-0.22,0.06-0.44,0.12-0.67,0.19
c-2.06,0.59-4.12,1.21-6.17,1.84c-0.21,0.06-0.42,0.13-0.63,0.19c-2.07,0.65-4.14,1.31-6.2,2c-0.18,0.06-0.35,0.12-0.53,0.18
c-2.09,0.71-4.18,1.43-6.26,2.18c-0.13,0.05-0.26,0.1-0.4,0.14c-2.12,0.77-4.24,1.56-6.35,2.38c-0.07,0.03-0.14,0.06-0.22,0.08
c-2.17,0.84-4.33,1.71-6.48,2.6c0,0,0,0,0,0l0,0c-33.3,13.84-64.67,33.76-92.4,59.79h0c0,0,0,0,0,0c-0.94,0.88-1.87,1.77-2.8,2.66
c-1.46,1.4-2.91,2.81-4.35,4.24c-1.43,1.43-2.84,2.88-4.23,4.34c-25.08,26.07-44.67,55.46-58.78,86.73v0c0,0,0,0,0,0
c-2.06,4.57-4.01,9.17-5.83,13.82c-0.18,0.45-0.36,0.91-0.53,1.36c-0.54,1.4-1.08,2.8-1.61,4.21c0,0,0,0,0,0l0,0
c-15.88,42.78-21.94,88.37-18.19,133.3c0,0,0,0,0,0l0,0c1.15,13.7,3.19,27.35,6.16,40.83c0.4,1.81,0.82,3.61,1.25,5.42
c0.19,0.79,0.38,1.57,0.57,2.36c0.41,1.64,0.83,3.28,1.26,4.92c0.27,1.03,0.55,2.05,0.84,3.07c0.23,0.82,0.46,1.64,0.7,2.46
c0.56,1.95,1.13,3.89,1.73,5.83c0.12,0.39,0.24,0.78,0.36,1.17c0.79,2.54,1.61,5.07,2.47,7.59c0,0,0,0,0,0l0,0
c10.76,31.64,26.79,61.88,48.12,89.34C306.53,647,307.74,648.53,308.97,650.05z M346.52,261.4l26.16,17.44v51.62l-26.16,17.44
l-26.16,17.44l-26.16-17.44l-9.53-6.35c13.53-31.12,32.34-59.34,56-84.05L346.52,261.4z M549.89,168.46l9.76,6.51v51.62
l-26.16,17.44l-26.16,17.44l-46.15-30.77l-6.17-4.11v-42.45c30.19-10.41,61.74-15.69,93.99-15.69
C549.29,168.44,549.59,168.45,549.89,168.46z M641.98,330.46v-51.62l26.16-17.44l26.16-17.44l23.46,15.64l-72.83,72.83
L641.98,330.46z M509.79,467.58l-2.46,1.64L455,434.34v-51.62l10.98-7.32l41.34-27.56l26.16,17.44l26.16,17.44v35L509.79,467.58z
M330.35,642.09v-51.62l26.16-17.44l26.16-17.44l23.46,15.64l-72.83,72.83L330.35,642.09z M418.84,555.65l-26.16-17.44v-51.62
l26.16-17.44L445,451.71l26.16,17.44l22.23,14.82l-72.83,72.83L418.84,555.65z M621.98,330.46l-26.16,17.44l-26.16,17.44
l-52.32-34.88v-51.62l52.32-34.88l26.16,17.44l26.16,17.44V330.46z M624.65,352.72l-45,45v-15l26.16-17.44L624.65,352.72z
M445,243.96l26.16,17.44l26.16,17.44v51.62l-26.16,17.44L445,365.34l-26.16-17.44l-26.16-17.44v-51.62l26.16-17.44L445,243.96z
M408.84,365.27L435,382.72v51.62l-52.32,34.88l-26.16-17.44l-26.16-17.44v-51.62l26.16-17.44l26.16-17.44L408.84,365.27z
M346.52,469.15l26.16,17.44v51.62l-26.16,17.44l-26.16,17.44l-26.16-17.44l-20.57-13.72c-2.12-6.87-3.99-13.8-5.59-20.79v-34.56
l26.16-17.44l26.16-17.44L346.52,469.15z M310.35,590.47v27.94c-9.53-14.02-17.77-28.84-24.69-44.4L310.35,590.47z M732.19,245.18
l-27.89-18.59v-12.8c11.86,7.6,23.16,16.08,33.87,25.42L732.19,245.18z M657.46,189.55c9.2,3.73,18.15,7.91,26.85,12.53v24.51
l-26.16,17.44l-26.16,17.44l-26.16-17.44l-26.16-17.44v-51.62l6.25-4.17C610.43,173.93,634.38,180.19,657.46,189.55z M435,191.87
v34.72l-26.16,17.44l-26.16,17.44l-26.16-17.44l-1.21-0.81C378.99,221.68,405.73,204.45,435,191.87z M284.19,365.27l26.16,17.44
v51.62l-49.37,32.92c-0.13-3.52-0.21-7.05-0.21-10.59c0-32.99,5.52-65.24,16.41-96.07L284.19,365.27z"/>
<path fill="#ED6B21" d="M759.84,687.31c0.31-0.74,0.63-1.49,0.94-2.23c0.51-1.24,1.01-2.48,1.51-3.72c0.3-0.75,0.59-1.5,0.88-2.26
c15.37-39.59,22.26-81.7,20.67-123.56c-0.02-0.42-0.03-0.85-0.05-1.28c-0.08-1.87-0.18-3.74-0.29-5.61
c-0.01-0.19-0.02-0.38-0.03-0.57c-0.12-1.99-0.27-3.98-0.43-5.96c0,0,0,0,0,0l0,0c-1.24-15.16-3.59-30.24-7.06-45.12l0,0
c0,0,0,0,0,0c-0.58-2.49-1.19-4.98-1.84-7.46c0,0,0,0,0,0c-0.64-2.47-1.31-4.92-2.01-7.38c-0.01-0.02-0.01-0.05-0.02-0.07
c-0.7-2.43-1.43-4.86-2.18-7.28c-0.01-0.04-0.02-0.07-0.03-0.11c-0.77-2.44-1.56-4.87-2.39-7.3c0,0,0,0,0,0l0,0
c-10.8-31.61-26.88-61.81-48.25-89.23c-1.1-1.41-2.22-2.81-3.35-4.21c-0.8-0.99-1.61-1.98-2.43-2.96c-0.44-0.53-0.88-1.05-1.32-1.57
c-5.77-6.88-11.87-13.57-18.34-20.04l-5.16,5.16l0,0l-14.42,14.42l0,0L590.4,452.8l-3.42,3.42l0,0l-60.3,60.3l0,0l-20,20l0,0
l-2.64,2.64l0,0l-30.11,30.11l-96.89,96.89l0,0l-10.84,10.84l-76.42,76.42h0l-13.83,13.83l-18.03,18.03
c18.94,18.94,39.73,34.89,61.78,47.87c1.78,1.05,3.56,2.07,5.36,3.08c0.86,0.48,1.72,0.95,2.58,1.42c1.13,0.62,2.26,1.24,3.4,1.84
c0.89,0.47,1.78,0.95,2.67,1.41c1.25,0.65,2.5,1.28,3.75,1.91c28.95,14.55,59.72,24.25,91.1,29.1c0,0,0,0,0,0
c2.44,0.38,4.88,0.72,7.32,1.04c0,0,0.01,0,0.01,0c2.45,0.32,4.89,0.61,7.34,0.87c0,0,0,0,0,0l0,0c8.87,0.94,17.78,1.5,26.69,1.67
c1.44,0.03,2.87,0.04,4.31,0.05c0.54,0,1.08,0.02,1.62,0.02c0.41,0,0.83-0.01,1.24-0.01c1.49-0.01,2.97-0.02,4.46-0.05
c1.11-0.02,2.23-0.05,3.34-0.08c0.66-0.02,1.31-0.05,1.97-0.07c2.2-0.08,4.4-0.18,6.59-0.3c0.26-0.02,0.52-0.03,0.79-0.05
c15.01-0.89,29.97-2.88,44.75-5.95l0,0c0,0,0,0,0,0c2.3-0.48,4.61-0.99,6.9-1.52c0.04-0.01,0.08-0.02,0.12-0.03
c2.26-0.53,4.52-1.08,6.77-1.66c0.08-0.02,0.15-0.04,0.23-0.06c2.22-0.57,4.43-1.17,6.64-1.79c0.11-0.03,0.21-0.06,0.32-0.09
c2.18-0.62,4.36-1.26,6.54-1.93c0.13-0.04,0.25-0.08,0.38-0.12c2.16-0.67,4.31-1.35,6.46-2.07c0.13-0.04,0.26-0.09,0.39-0.13
c2.15-0.72,4.29-1.46,6.42-2.22c0.12-0.04,0.24-0.09,0.35-0.13c2.15-0.78,4.3-1.57,6.44-2.4c0.08-0.03,0.15-0.06,0.23-0.09
c37.07-14.33,71.92-36.1,102.27-65.29c1.46-1.39,2.91-2.8,4.34-4.23c1.43-1.43,2.84-2.89,4.24-4.35c0.9-0.94,1.8-1.88,2.69-2.83l0,0
l0,0C726.34,750.82,746.03,720.02,759.84,687.31z M739.81,658.73l-26.16-17.44v-51.62l26.16-17.44l24.04-16.03
c0.14,3.71,0.23,7.42,0.23,11.14c0,33.15-5.58,65.56-16.57,96.52L739.81,658.73z M474.09,855.53l-9.75-6.5v-51.62l26.16-17.44
l26.16-17.44l26.16,17.44L569,797.41v42.74c-29.93,10.21-61.19,15.4-93.13,15.4C475.27,855.56,474.68,855.54,474.09,855.53z
M516.69,554.79l26.14,17.43L569,589.66v51.62l-26.16,17.44l-26.16,17.44l-26.16-17.44l-26.16-17.44v-34.15L516.69,554.79z
M579,658.66l26.16,17.44l26.16,17.44v51.62l-26.16,17.44L579,780.04l-26.16-17.44l-26.16-17.44v-51.62l26.16-17.44L579,658.66z
M402.02,693.54l26.16-17.44l26.16-17.44l26.16,17.44l26.16,17.44v51.62l-26.16,17.44l-26.16,17.44l-26.16-17.44l-26.16-17.44
V693.54z M401.91,669.58l42.44-42.44v14.15l-26.16,17.44L401.91,669.58z M589,797.41l26.16-17.44l26.16-17.44l26.16,17.44l1.71,1.14
c-23.82,21.6-50.73,38.83-80.2,51.38V797.41z M615.16,658.73L589,641.28v-51.62l26.16-17.44l26.16-17.44l26.16,17.44l26.16,17.44
v51.62l-26.16,17.44l-26.16,17.44L615.16,658.73z M677.48,554.85l-26.16-17.44v-51.62l26.16-17.44l26.16-17.44l26.16,17.44
l21.65,14.43c1.66,5.43,3.18,10.89,4.51,16.4v38.23l-26.16,17.44l-26.16,17.44L677.48,554.85z M739.55,450.8l-25.9-17.27v-29.18
C723.7,418.98,732.35,434.49,739.55,450.8z M693.65,381.91v51.62l-26.16,17.44l-26.16,17.44l-22.95-15.3l72.83-72.83L693.65,381.91z
M605.16,468.35l26.16,17.44v51.62l-26.16,17.44L579,572.29l-26.16-17.44l-21.72-14.48l72.83-72.83L605.16,468.35z M379.58,691.91
l2.44,1.63v51.62l-26.16,17.44l-26.16,17.44l-22.95-15.3L379.58,691.91z M292.32,779.16l27.38,18.25v12.26
c-11.55-7.46-22.56-15.75-33.01-24.87L292.32,779.16z M339.7,821.46v-24.04l26.16-17.44l26.16-17.44l26.16,17.44l26.16,17.44v51.62
l-6.11,4.07c-24.28-3.16-47.99-9.39-70.84-18.65C357.9,830.6,348.66,826.26,339.7,821.46z M677.48,762.6l-26.16-17.44v-51.62
l26.16-17.44l26.16-17.44l26.16,17.44l10.18,6.79c-13.58,31.09-32.43,59.28-56.14,83.96L677.48,762.6z"/>
</svg>

After

Width:  |  Height:  |  Size: 8.1 KiB

View File

Before

Width:  |  Height:  |  Size: 374 B

After

Width:  |  Height:  |  Size: 374 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 600 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 695 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 589 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 628 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 631 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 651 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 93 B

View 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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 158 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 164 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 158 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1001 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 997 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 654 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 803 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 465 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 650 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.8 KiB

View File

@ -85,9 +85,6 @@ void AppConfig::set_defaults()
if (get("associate_stl").empty()) if (get("associate_stl").empty())
set("associate_stl", "0"); set("associate_stl", "0");
if (get("dark_color_mode").empty())
set("dark_color_mode", "0");
if (get("tabs_as_menu").empty()) if (get("tabs_as_menu").empty())
set("tabs_as_menu", "0"); set("tabs_as_menu", "0");
#endif // _WIN32 #endif // _WIN32
@ -179,6 +176,9 @@ void AppConfig::set_defaults()
#ifdef _WIN32 #ifdef _WIN32
if (get("use_legacy_3DConnexion").empty()) if (get("use_legacy_3DConnexion").empty())
set("use_legacy_3DConnexion", "0"); set("use_legacy_3DConnexion", "0");
if (get("dark_color_mode").empty())
set("dark_color_mode", "0");
#endif // _WIN32 #endif // _WIN32
// Remove legacy window positions/sizes // Remove legacy window positions/sizes

View File

@ -552,6 +552,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())
@ -1701,10 +1717,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;
@ -1776,7 +1792,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;

View File

@ -381,7 +381,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;
@ -686,7 +686,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);
@ -1140,6 +1140,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();

View File

@ -1214,7 +1214,7 @@ static void cut_segmented_layers(const std::vector<ExPolygons>
const std::function<void()> &throw_on_cancel_callback) const std::function<void()> &throw_on_cancel_callback)
{ {
BOOST_LOG_TRIVIAL(debug) << "MMU segmentation - cutting segmented layers in parallel - begin"; BOOST_LOG_TRIVIAL(debug) << "MMU segmentation - cutting segmented layers in parallel - begin";
tbb::parallel_for(tbb::blocked_range<size_t>(0, segmented_regions.size()),[&](const tbb::blocked_range<size_t>& range) { tbb::parallel_for(tbb::blocked_range<size_t>(0, segmented_regions.size()),[&segmented_regions, &input_expolygons, &cut_width, &throw_on_cancel_callback](const tbb::blocked_range<size_t>& range) {
for (size_t layer_idx = range.begin(); layer_idx < range.end(); ++layer_idx) { for (size_t layer_idx = range.begin(); layer_idx < range.end(); ++layer_idx) {
throw_on_cancel_callback(); throw_on_cancel_callback();
std::vector<std::pair<ExPolygon, size_t>> segmented_regions_cuts; std::vector<std::pair<ExPolygon, size_t>> segmented_regions_cuts;
@ -1366,7 +1366,8 @@ static inline std::vector<std::vector<ExPolygons>> mmu_segmentation_top_and_bott
return out; return out;
}; };
tbb::parallel_for(tbb::blocked_range<size_t>(0, num_layers, granularity), [&](const tbb::blocked_range<size_t> &range) { tbb::parallel_for(tbb::blocked_range<size_t>(0, num_layers, granularity), [&granularity, &num_layers, &num_extruders, &layer_color_stat, &top_raw, &triangles_by_color_top,
&throw_on_cancel_callback, &input_expolygons, &bottom_raw, &triangles_by_color_bottom](const tbb::blocked_range<size_t> &range) {
size_t group_idx = range.begin() / granularity; size_t group_idx = range.begin() / granularity;
size_t layer_idx_offset = (group_idx & 1) * num_layers; size_t layer_idx_offset = (group_idx & 1) * num_layers;
for (size_t layer_idx = range.begin(); layer_idx < range.end(); ++ layer_idx) { for (size_t layer_idx = range.begin(); layer_idx < range.end(); ++ layer_idx) {
@ -1417,7 +1418,7 @@ static inline std::vector<std::vector<ExPolygons>> mmu_segmentation_top_and_bott
std::vector<std::vector<ExPolygons>> triangles_by_color_merged(num_extruders); std::vector<std::vector<ExPolygons>> triangles_by_color_merged(num_extruders);
triangles_by_color_merged.assign(num_extruders, std::vector<ExPolygons>(num_layers)); triangles_by_color_merged.assign(num_extruders, std::vector<ExPolygons>(num_layers));
tbb::parallel_for(tbb::blocked_range<size_t>(0, num_layers), [&](const tbb::blocked_range<size_t> &range) { tbb::parallel_for(tbb::blocked_range<size_t>(0, num_layers), [&triangles_by_color_merged, &triangles_by_color_bottom, &triangles_by_color_top, &num_layers, &throw_on_cancel_callback](const tbb::blocked_range<size_t> &range) {
for (size_t layer_idx = range.begin(); layer_idx < range.end(); ++ layer_idx) { for (size_t layer_idx = range.begin(); layer_idx < range.end(); ++ layer_idx) {
throw_on_cancel_callback(); throw_on_cancel_callback();
for (size_t color_idx = 0; color_idx < triangles_by_color_merged.size(); ++color_idx) { for (size_t color_idx = 0; color_idx < triangles_by_color_merged.size(); ++color_idx) {
@ -1446,7 +1447,7 @@ static std::vector<std::vector<std::pair<ExPolygon, size_t>>> merge_segmented_la
std::vector<std::vector<std::pair<ExPolygon, size_t>>> segmented_regions_merged(segmented_regions.size()); std::vector<std::vector<std::pair<ExPolygon, size_t>>> segmented_regions_merged(segmented_regions.size());
BOOST_LOG_TRIVIAL(debug) << "MMU segmentation - merging segmented layers in parallel - begin"; BOOST_LOG_TRIVIAL(debug) << "MMU segmentation - merging segmented layers in parallel - begin";
tbb::parallel_for(tbb::blocked_range<size_t>(0, segmented_regions.size()), [&](const tbb::blocked_range<size_t> &range) { tbb::parallel_for(tbb::blocked_range<size_t>(0, segmented_regions.size()), [&segmented_regions, &top_and_bottom_layers, &segmented_regions_merged, &throw_on_cancel_callback](const tbb::blocked_range<size_t> &range) {
for (size_t layer_idx = range.begin(); layer_idx < range.end(); ++layer_idx) { for (size_t layer_idx = range.begin(); layer_idx < range.end(); ++layer_idx) {
for (const std::pair<ExPolygon, size_t> &colored_expoly : segmented_regions[layer_idx]) { for (const std::pair<ExPolygon, size_t> &colored_expoly : segmented_regions[layer_idx]) {
throw_on_cancel_callback(); throw_on_cancel_callback();
@ -1526,6 +1527,20 @@ void export_processed_input_expolygons_to_svg(const std::string &path, const Lay
} }
#endif // MMU_SEGMENTATION_DEBUG_INPUT #endif // MMU_SEGMENTATION_DEBUG_INPUT
// Check if all ColoredLine representing a single layer uses the same color.
static bool has_layer_only_one_color(const std::vector<std::vector<ColoredLine>> &colored_polygons)
{
assert(!colored_polygons.empty());
assert(!colored_polygons.front().empty());
int first_line_color = colored_polygons.front().front().color;
for (const std::vector<ColoredLine> &colored_polygon : colored_polygons)
for (const ColoredLine &colored_line : colored_polygon)
if (first_line_color != colored_line.color)
return false;
return true;
}
std::vector<std::vector<std::pair<ExPolygon, size_t>>> multi_material_segmentation_by_painting(const PrintObject &print_object, const std::function<void()> &throw_on_cancel_callback) std::vector<std::vector<std::pair<ExPolygon, size_t>>> multi_material_segmentation_by_painting(const PrintObject &print_object, const std::function<void()> &throw_on_cancel_callback)
{ {
std::vector<std::vector<std::pair<ExPolygon, size_t>>> segmented_regions(print_object.layers().size()); std::vector<std::vector<std::pair<ExPolygon, size_t>>> segmented_regions(print_object.layers().size());
@ -1539,7 +1554,7 @@ std::vector<std::vector<std::pair<ExPolygon, size_t>>> multi_material_segmentati
// Merge all regions and remove small holes // Merge all regions and remove small holes
BOOST_LOG_TRIVIAL(debug) << "MMU segmentation - slices preparation in parallel - begin"; BOOST_LOG_TRIVIAL(debug) << "MMU segmentation - slices preparation in parallel - begin";
tbb::parallel_for(tbb::blocked_range<size_t>(0, layers.size()), [&](const tbb::blocked_range<size_t> &range) { tbb::parallel_for(tbb::blocked_range<size_t>(0, layers.size()), [&layers, &input_expolygons, &throw_on_cancel_callback](const tbb::blocked_range<size_t> &range) {
for (size_t layer_idx = range.begin(); layer_idx < range.end(); ++layer_idx) { for (size_t layer_idx = range.begin(); layer_idx < range.end(); ++layer_idx) {
throw_on_cancel_callback(); throw_on_cancel_callback();
ExPolygons ex_polygons; ExPolygons ex_polygons;
@ -1649,16 +1664,16 @@ std::vector<std::vector<std::pair<ExPolygon, size_t>>> multi_material_segmentati
edge_grids[layer_idx].visit_cells_intersecting_line(line_start, line_end, visitor); edge_grids[layer_idx].visit_cells_intersecting_line(line_start, line_end, visitor);
} }
} }
}); }); // end of parallel_for
} }
}); }); // end of parallel_for
} }
BOOST_LOG_TRIVIAL(debug) << "MMU segmentation - projection of painted triangles - end"; BOOST_LOG_TRIVIAL(debug) << "MMU segmentation - projection of painted triangles - end";
BOOST_LOG_TRIVIAL(debug) << "MMU segmentation - painted layers count: " BOOST_LOG_TRIVIAL(debug) << "MMU segmentation - painted layers count: "
<< std::count_if(painted_lines.begin(), painted_lines.end(), [](const std::vector<PaintedLine> &pl) { return !pl.empty(); }); << std::count_if(painted_lines.begin(), painted_lines.end(), [](const std::vector<PaintedLine> &pl) { return !pl.empty(); });
BOOST_LOG_TRIVIAL(debug) << "MMU segmentation - layers segmentation in parallel - begin"; BOOST_LOG_TRIVIAL(debug) << "MMU segmentation - layers segmentation in parallel - begin";
tbb::parallel_for(tbb::blocked_range<size_t>(0, print_object.layers().size()), [&](const tbb::blocked_range<size_t> &range) { tbb::parallel_for(tbb::blocked_range<size_t>(0, print_object.layers().size()), [&edge_grids, &input_expolygons, &painted_lines, &segmented_regions, &throw_on_cancel_callback](const tbb::blocked_range<size_t> &range) {
for (size_t layer_idx = range.begin(); layer_idx < range.end(); ++layer_idx) { for (size_t layer_idx = range.begin(); layer_idx < range.end(); ++layer_idx) {
throw_on_cancel_callback(); throw_on_cancel_callback();
auto comp = [&edge_grids, layer_idx](const PaintedLine &first, const PaintedLine &second) { auto comp = [&edge_grids, layer_idx](const PaintedLine &first, const PaintedLine &second) {
@ -1677,20 +1692,28 @@ std::vector<std::vector<std::pair<ExPolygon, size_t>>> multi_material_segmentati
if (!painted_lines_single.empty()) { if (!painted_lines_single.empty()) {
std::vector<std::vector<ColoredLine>> color_poly = colorize_polygons(edge_grids[layer_idx].contours(), painted_lines_single); std::vector<std::vector<ColoredLine>> color_poly = colorize_polygons(edge_grids[layer_idx].contours(), painted_lines_single);
MMU_Graph graph = build_graph(layer_idx, color_poly); assert(!color_poly.empty());
remove_multiple_edges_in_vertices(graph, color_poly); assert(!color_poly.front().empty());
graph.remove_nodes_with_one_arc(); if (has_layer_only_one_color(color_poly)) {
// If the whole layer is painted using the same color, it is not needed to construct a Voronoi diagram for the segmentation of this layer.
for (const ExPolygon &ex_polygon : input_expolygons[layer_idx])
segmented_regions[layer_idx].emplace_back(ex_polygon, size_t(color_poly.front().front().color));
} else {
MMU_Graph graph = build_graph(layer_idx, color_poly);
remove_multiple_edges_in_vertices(graph, color_poly);
graph.remove_nodes_with_one_arc();
#ifdef MMU_SEGMENTATION_DEBUG_GRAPH #ifdef MMU_SEGMENTATION_DEBUG_GRAPH
{ {
static int iRun = 0; static int iRun = 0;
export_graph_to_svg(debug_out_path("mm-graph-final-%d-%d.svg", layer_idx, iRun++), graph, input_expolygons[layer_idx]); export_graph_to_svg(debug_out_path("mm-graph-final-%d-%d.svg", layer_idx, iRun++), graph, input_expolygons[layer_idx]);
} }
#endif // MMU_SEGMENTATION_DEBUG_GRAPH #endif // MMU_SEGMENTATION_DEBUG_GRAPH
std::vector<std::pair<Polygon, size_t>> segmentation = extract_colored_segments(graph); std::vector<std::pair<Polygon, size_t>> segmentation = extract_colored_segments(graph);
for (std::pair<Polygon, size_t> &region : segmentation) for (std::pair<Polygon, size_t> &region : segmentation)
segmented_regions[layer_idx].emplace_back(std::move(region)); segmented_regions[layer_idx].emplace_back(std::move(region));
}
#ifdef MMU_SEGMENTATION_DEBUG_REGIONS #ifdef MMU_SEGMENTATION_DEBUG_REGIONS
{ {

View File

@ -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);
} }

View File

@ -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; }

View File

@ -220,7 +220,7 @@ AboutDialog::AboutDialog()
main_sizer->Add(hsizer, 0, wxEXPAND | wxALL, 20); main_sizer->Add(hsizer, 0, wxEXPAND | wxALL, 20);
// logo // logo
m_logo_bitmap = ScalableBitmap(this, wxGetApp().is_editor() ? "PrusaSlicer_192px.png" : "PrusaSlicer-gcodeviewer_192px.png", 192); m_logo_bitmap = ScalableBitmap(this, wxGetApp().logo_name(), 192);
m_logo = new wxStaticBitmap(this, wxID_ANY, m_logo_bitmap.bmp()); m_logo = new wxStaticBitmap(this, wxID_ANY, m_logo_bitmap.bmp());
hsizer->Add(m_logo, 1, wxALIGN_CENTER_VERTICAL); hsizer->Add(m_logo, 1, wxALIGN_CENTER_VERTICAL);

View File

@ -193,7 +193,7 @@ public:
// load bitmap for logo // load bitmap for logo
BitmapCache bmp_cache; BitmapCache bmp_cache;
int logo_size = lround(width * 0.25); int logo_size = lround(width * 0.25);
wxBitmap logo_bmp = *bmp_cache.load_svg(wxGetApp().is_editor() ? "prusa_slicer_logo" : "add_gcode", logo_size, logo_size); wxBitmap logo_bmp = *bmp_cache.load_svg(wxGetApp().logo_name(), logo_size, logo_size);
wxCoord margin = int(m_scale * 20); wxCoord margin = int(m_scale * 20);
@ -883,7 +883,7 @@ bool GUI_App::on_init_inner()
} }
// create splash screen with updated bmp // create splash screen with updated bmp
scrn = new SplashScreen(bmp.IsOk() ? bmp : create_scaled_bitmap("prusa_slicer_logo", nullptr, 400), scrn = new SplashScreen(bmp.IsOk() ? bmp : create_scaled_bitmap("PrusaSlicer", nullptr, 400),
wxSPLASH_CENTRE_ON_SCREEN | wxSPLASH_TIMEOUT, 4000, splashscreen_pos); wxSPLASH_CENTRE_ON_SCREEN | wxSPLASH_TIMEOUT, 4000, splashscreen_pos);
#ifndef __linux__ #ifndef __linux__
wxYield(); wxYield();

View File

@ -166,6 +166,7 @@ public:
bool is_editor() const { return m_app_mode == EAppMode::Editor; } bool is_editor() const { return m_app_mode == EAppMode::Editor; }
bool is_gcode_viewer() const { return m_app_mode == EAppMode::GCodeViewer; } bool is_gcode_viewer() const { return m_app_mode == EAppMode::GCodeViewer; }
bool is_recreating_gui() const { return m_is_recreating_gui; } bool is_recreating_gui() const { return m_is_recreating_gui; }
std::string logo_name() const { return is_editor() ? "PrusaSlicer" : "PrusaSlicer-gcodeviewer"; }
// To be called after the GUI is fully built up. // To be called after the GUI is fully built up.
// Process command line parameters cached in this->init_params, // Process command line parameters cached in this->init_params,

View File

@ -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)
@ -4113,15 +4123,14 @@ void ObjectList::fix_through_netfabb()
Plater::TakeSnapshot snapshot(plater, _L("Fix through NetFabb")); Plater::TakeSnapshot snapshot(plater, _L("Fix through NetFabb"));
// Open a progress dialog. // Open a progress dialog.
wxProgressDialog progress_dlg(_L("Fixing through NetFabb"), "", 100, wxProgressDialog progress_dlg(_L("Fixing through NetFabb"), "", 100, plater,
nullptr, // ! parent of the wxProgressDialog should be nullptr to avoid flickering during the model fixing
wxPD_AUTO_HIDE | wxPD_APP_MODAL | wxPD_CAN_ABORT); wxPD_AUTO_HIDE | wxPD_APP_MODAL | wxPD_CAN_ABORT);
int model_idx{ 0 }; int model_idx{ 0 };
if (vol_idxs.empty()) { if (vol_idxs.empty()) {
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 +4187,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()));
} }
} }

View File

@ -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();

View File

@ -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)) {
@ -786,12 +785,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);
@ -867,7 +866,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;
@ -886,14 +885,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;
@ -916,7 +922,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"));
} }

View File

@ -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);

View File

@ -496,13 +496,22 @@ void Preview::on_combochecklist_features(wxCommandEvent& evt)
void Preview::on_combochecklist_options(wxCommandEvent& evt) void Preview::on_combochecklist_options(wxCommandEvent& evt)
{ {
unsigned int curr_flags = m_canvas->get_gcode_options_visibility_flags(); const unsigned int curr_flags = m_canvas->get_gcode_options_visibility_flags();
unsigned int new_flags = Slic3r::GUI::combochecklist_get_flags(m_combochecklist_options); const unsigned int new_flags = Slic3r::GUI::combochecklist_get_flags(m_combochecklist_options);
if (curr_flags == new_flags) if (curr_flags == new_flags)
return; return;
m_canvas->set_gcode_options_visibility_from_flags(new_flags); m_canvas->set_gcode_options_visibility_from_flags(new_flags);
m_canvas->refresh_gcode_preview_render_paths(); if (m_canvas->get_gcode_view_type() == GCodeViewer::EViewType::Feedrate) {
const unsigned int diff_flags = curr_flags ^ new_flags;
if ((diff_flags & (1 << static_cast<unsigned int>(Preview::OptionType::Travel))) != 0)
refresh_print();
else
m_canvas->refresh_gcode_preview_render_paths();
}
else
m_canvas->refresh_gcode_preview_render_paths();
update_moves_slider(); update_moves_slider();
} }

View File

@ -51,10 +51,17 @@ bool GLGizmoFdmSupports::on_init()
m_desc["remove_all"] = _L("Remove all selection"); m_desc["remove_all"] = _L("Remove all selection");
m_desc["circle"] = _L("Circle"); m_desc["circle"] = _L("Circle");
m_desc["sphere"] = _L("Sphere"); m_desc["sphere"] = _L("Sphere");
m_desc["pointer"] = _L("Triangles");
m_desc["highlight_by_angle"] = _L("Highlight by angle"); m_desc["highlight_by_angle"] = _L("Highlight by angle");
m_desc["enforce_button"] = _L("Enforce"); m_desc["enforce_button"] = _L("Enforce");
m_desc["cancel"] = _L("Cancel"); m_desc["cancel"] = _L("Cancel");
m_desc["tool_type"] = _L("Tool type") + ": ";
m_desc["tool_brush"] = _L("Brush");
m_desc["tool_smart_fill"] = _L("Smart fill");
m_desc["smart_fill_angle"] = _L("Smart fill angle");
return true; return true;
} }
@ -82,42 +89,48 @@ void GLGizmoFdmSupports::on_render_input_window(float x, float y, float bottom_l
if (! m_c->selection_info()->model_object()) if (! m_c->selection_info()->model_object())
return; return;
const float approx_height = m_imgui->scaled(17.0f); const float approx_height = m_imgui->scaled(20.5f);
y = std::min(y, bottom_limit - approx_height); y = std::min(y, bottom_limit - approx_height);
m_imgui->set_next_window_pos(x, y, ImGuiCond_Always); m_imgui->set_next_window_pos(x, y, ImGuiCond_Always);
m_imgui->begin(get_name(), ImGuiWindowFlags_NoMove | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoCollapse); m_imgui->begin(get_name(), ImGuiWindowFlags_NoMove | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoCollapse);
// First calculate width of all the texts that are could possibly be shown. We will decide set the dialog width based on that: // First calculate width of all the texts that are could possibly be shown. We will decide set the dialog width based on that:
const float clipping_slider_left = std::max(m_imgui->calc_text_size(m_desc.at("clipping_of_view")).x, const float clipping_slider_left = std::max(m_imgui->calc_text_size(m_desc.at("clipping_of_view")).x,
m_imgui->calc_text_size(m_desc.at("reset_direction")).x) m_imgui->calc_text_size(m_desc.at("reset_direction")).x) + m_imgui->scaled(1.5f);
+ m_imgui->scaled(1.5f); const float cursor_slider_left = m_imgui->calc_text_size(m_desc.at("cursor_size")).x + m_imgui->scaled(1.f);
const float cursor_slider_left = m_imgui->calc_text_size(m_desc.at("cursor_size")).x + m_imgui->scaled(1.f); const float autoset_slider_left = m_imgui->calc_text_size(m_desc.at("highlight_by_angle")).x + m_imgui->scaled(1.f);
const float autoset_slider_left = m_imgui->calc_text_size(m_desc.at("highlight_by_angle")).x + m_imgui->scaled(1.f); const float smart_fill_slider_left = m_imgui->calc_text_size(m_desc.at("smart_fill_angle")).x + m_imgui->scaled(1.f);
const float cursor_type_radio_left = m_imgui->calc_text_size(m_desc.at("cursor_type")).x + m_imgui->scaled(1.f);
const float cursor_type_radio_width1 = m_imgui->calc_text_size(m_desc["circle"]).x const float cursor_type_radio_circle = m_imgui->calc_text_size(m_desc["circle"]).x + m_imgui->scaled(2.5f);
+ m_imgui->scaled(2.5f); const float cursor_type_radio_sphere = m_imgui->calc_text_size(m_desc["sphere"]).x + m_imgui->scaled(2.5f);
const float cursor_type_radio_width2 = m_imgui->calc_text_size(m_desc["sphere"]).x const float cursor_type_radio_pointer = m_imgui->calc_text_size(m_desc["pointer"]).x + m_imgui->scaled(2.5f);
+ m_imgui->scaled(2.5f);
const float button_width = m_imgui->calc_text_size(m_desc.at("remove_all")).x + m_imgui->scaled(1.f); const float button_width = m_imgui->calc_text_size(m_desc.at("remove_all")).x + m_imgui->scaled(1.f);
const float button_enforce_width = m_imgui->calc_text_size(m_desc.at("enforce_button")).x; const float button_enforce_width = m_imgui->calc_text_size(m_desc.at("enforce_button")).x;
const float button_cancel_width = m_imgui->calc_text_size(m_desc.at("cancel")).x; const float button_cancel_width = m_imgui->calc_text_size(m_desc.at("cancel")).x;
const float buttons_width = std::max(button_enforce_width, button_cancel_width) + m_imgui->scaled(0.5f); const float buttons_width = std::max(button_enforce_width, button_cancel_width) + m_imgui->scaled(0.5f);
const float minimal_slider_width = m_imgui->scaled(4.f); const float minimal_slider_width = m_imgui->scaled(4.f);
const float tool_type_radio_left = m_imgui->calc_text_size(m_desc["tool_type"]).x + m_imgui->scaled(1.f);
const float tool_type_radio_brush = m_imgui->calc_text_size(m_desc["tool_brush"]).x + m_imgui->scaled(2.5f);
const float tool_type_radio_smart_fill = m_imgui->calc_text_size(m_desc["tool_smart_fill"]).x + m_imgui->scaled(2.5f);
float caption_max = 0.f; float caption_max = 0.f;
float total_text_max = 0.f; float total_text_max = 0.f;
for (const auto &t : std::array<std::string, 3>{"enforce", "block", "remove"}) { for (const auto &t : std::array<std::string, 3>{"enforce", "block", "remove"}) {
caption_max = std::max(caption_max, m_imgui->calc_text_size(m_desc.at(t + "_caption")).x); caption_max = std::max(caption_max, m_imgui->calc_text_size(m_desc[t + "_caption"]).x);
total_text_max = std::max(total_text_max, caption_max + m_imgui->calc_text_size(m_desc.at(t)).x); total_text_max = std::max(total_text_max, m_imgui->calc_text_size(m_desc[t]).x);
} }
caption_max += m_imgui->scaled(1.f); total_text_max += caption_max + m_imgui->scaled(1.f);
total_text_max += m_imgui->scaled(1.f); caption_max += m_imgui->scaled(1.f);
float window_width = minimal_slider_width + std::max(autoset_slider_left, std::max(cursor_slider_left, clipping_slider_left)); float sliders_width = std::max(std::max(autoset_slider_left, smart_fill_slider_left), std::max(cursor_slider_left, clipping_slider_left));
float window_width = minimal_slider_width + sliders_width;
window_width = std::max(window_width, total_text_max); window_width = std::max(window_width, total_text_max);
window_width = std::max(window_width, button_width); window_width = std::max(window_width, button_width);
window_width = std::max(window_width, cursor_type_radio_left + cursor_type_radio_width1 + cursor_type_radio_width2); window_width = std::max(window_width, cursor_type_radio_circle + cursor_type_radio_sphere + cursor_type_radio_pointer);
window_width = std::max(window_width, tool_type_radio_left + tool_type_radio_brush + tool_type_radio_smart_fill);
window_width = std::max(window_width, 2.f * buttons_width + m_imgui->scaled(1.f)); window_width = std::max(window_width, 2.f * buttons_width + m_imgui->scaled(1.f));
auto draw_text_with_caption = [this, &caption_max](const wxString& caption, const wxString& text) { auto draw_text_with_caption = [this, &caption_max](const wxString& caption, const wxString& text) {
@ -129,7 +142,6 @@ void GLGizmoFdmSupports::on_render_input_window(float x, float y, float bottom_l
for (const auto &t : std::array<std::string, 3>{"enforce", "block", "remove"}) for (const auto &t : std::array<std::string, 3>{"enforce", "block", "remove"})
draw_text_with_caption(m_desc.at(t + "_caption"), m_desc.at(t)); draw_text_with_caption(m_desc.at(t + "_caption"), m_desc.at(t));
m_imgui->text("");
ImGui::Separator(); ImGui::Separator();
ImGui::AlignTextToFramePadding(); ImGui::AlignTextToFramePadding();
@ -138,9 +150,9 @@ void GLGizmoFdmSupports::on_render_input_window(float x, float y, float bottom_l
std::string format_str = std::string("%.f") + I18N::translate_utf8("°", std::string format_str = std::string("%.f") + I18N::translate_utf8("°",
"Degree sign to use in the respective slider in FDM supports gizmo," "Degree sign to use in the respective slider in FDM supports gizmo,"
"placed after the number with no whitespace in between."); "placed after the number with no whitespace in between.");
ImGui::SameLine(autoset_slider_left); ImGui::SameLine(sliders_width);
ImGui::PushItemWidth(window_width - autoset_slider_left); ImGui::PushItemWidth(window_width - sliders_width);
if (m_imgui->slider_float("", &m_angle_threshold_deg, 0.f, 90.f, format_str.data())) { if (m_imgui->slider_float("##angle_threshold_deg", &m_angle_threshold_deg, 0.f, 90.f, format_str.data())) {
m_parent.set_slope_normal_angle(90.f - m_angle_threshold_deg); m_parent.set_slope_normal_angle(90.f - m_angle_threshold_deg);
if (! m_parent.is_using_slope()) { if (! m_parent.is_using_slope()) {
m_parent.use_slope(true); m_parent.use_slope(true);
@ -163,79 +175,136 @@ void GLGizmoFdmSupports::on_render_input_window(float x, float y, float bottom_l
} }
m_imgui->disabled_end(); m_imgui->disabled_end();
ImGui::Separator();
if (m_imgui->button(m_desc.at("remove_all"))) {
Plater::TakeSnapshot snapshot(wxGetApp().plater(), _L("Reset selection"),
UndoRedo::SnapshotType::GizmoAction);
ModelObject* mo = m_c->selection_info()->model_object();
int idx = -1;
for (ModelVolume* mv : mo->volumes) {
if (mv->is_model_part()) {
++idx;
m_triangle_selectors[idx]->reset();
m_triangle_selectors[idx]->request_update_render_data();
}
}
update_model_object();
m_parent.set_as_dirty();
}
const float max_tooltip_width = ImGui::GetFontSize() * 20.0f; const float max_tooltip_width = ImGui::GetFontSize() * 20.0f;
ImGui::AlignTextToFramePadding(); ImGui::Separator();
m_imgui->text(m_desc.at("cursor_size"));
ImGui::SameLine(cursor_slider_left);
ImGui::PushItemWidth(window_width - cursor_slider_left);
m_imgui->slider_float(" ", &m_cursor_radius, CursorRadiusMin, CursorRadiusMax, "%.2f");
if (ImGui::IsItemHovered()) {
ImGui::BeginTooltip();
ImGui::PushTextWrapPos(max_tooltip_width);
ImGui::TextUnformatted(_L("Alt + Mouse wheel").ToUTF8().data());
ImGui::PopTextWrapPos();
ImGui::EndTooltip();
}
ImGui::AlignTextToFramePadding(); ImGui::AlignTextToFramePadding();
m_imgui->text(m_desc.at("cursor_type")); m_imgui->text(m_desc["tool_type"]);
ImGui::SameLine(cursor_type_radio_left + m_imgui->scaled(0.f));
ImGui::PushItemWidth(cursor_type_radio_width1);
bool sphere_sel = m_cursor_type == TriangleSelector::CursorType::SPHERE; float tool_type_offset = tool_type_radio_left + (window_width - tool_type_radio_left - tool_type_radio_brush - tool_type_radio_smart_fill + m_imgui->scaled(0.5f)) / 2.f;
if (m_imgui->radio_button(m_desc["sphere"], sphere_sel)) ImGui::SameLine(tool_type_offset);
sphere_sel = true; ImGui::PushItemWidth(tool_type_radio_brush);
if (m_imgui->radio_button(m_desc["tool_brush"], m_tool_type == ToolType::BRUSH))
m_tool_type = ToolType::BRUSH;
if (ImGui::IsItemHovered()) { if (ImGui::IsItemHovered()) {
ImGui::BeginTooltip(); ImGui::BeginTooltip();
ImGui::PushTextWrapPos(max_tooltip_width); ImGui::PushTextWrapPos(max_tooltip_width);
ImGui::TextUnformatted(_L("Paints all facets inside, regardless of their orientation.").ToUTF8().data()); ImGui::TextUnformatted(_L("Paints facets according to the chosen painting brush.").ToUTF8().data());
ImGui::PopTextWrapPos(); ImGui::PopTextWrapPos();
ImGui::EndTooltip(); ImGui::EndTooltip();
} }
ImGui::SameLine(cursor_type_radio_left + cursor_type_radio_width2 + m_imgui->scaled(0.f)); ImGui::SameLine(tool_type_offset + tool_type_radio_brush);
ImGui::PushItemWidth(cursor_type_radio_width2); ImGui::PushItemWidth(tool_type_radio_smart_fill);
if (m_imgui->radio_button(m_desc["tool_smart_fill"], m_tool_type == ToolType::SMART_FILL))
if (m_imgui->radio_button(m_desc["circle"], ! sphere_sel)) m_tool_type = ToolType::SMART_FILL;
sphere_sel = false;
if (ImGui::IsItemHovered()) { if (ImGui::IsItemHovered()) {
ImGui::BeginTooltip(); ImGui::BeginTooltip();
ImGui::PushTextWrapPos(max_tooltip_width); ImGui::PushTextWrapPos(max_tooltip_width);
ImGui::TextUnformatted(_L("Ignores facets facing away from the camera.").ToUTF8().data()); ImGui::TextUnformatted(_L("Paints neighboring facets whose relative angle is less or equal to set angle.").ToUTF8().data());
ImGui::PopTextWrapPos(); ImGui::PopTextWrapPos();
ImGui::EndTooltip(); ImGui::EndTooltip();
} }
m_cursor_type = sphere_sel ImGui::Separator();
? TriangleSelector::CursorType::SPHERE
: TriangleSelector::CursorType::CIRCLE;
if (m_tool_type == ToolType::BRUSH) {
m_imgui->text(m_desc.at("cursor_type"));
ImGui::NewLine();
float cursor_type_offset = (window_width - cursor_type_radio_sphere - cursor_type_radio_circle - cursor_type_radio_pointer + m_imgui->scaled(1.5f)) / 2.f;
ImGui::SameLine(cursor_type_offset);
ImGui::PushItemWidth(cursor_type_radio_sphere);
if (m_imgui->radio_button(m_desc["sphere"], m_cursor_type == TriangleSelector::CursorType::SPHERE))
m_cursor_type = TriangleSelector::CursorType::SPHERE;
if (ImGui::IsItemHovered()) {
ImGui::BeginTooltip();
ImGui::PushTextWrapPos(max_tooltip_width);
ImGui::TextUnformatted(_L("Paints all facets inside, regardless of their orientation.").ToUTF8().data());
ImGui::PopTextWrapPos();
ImGui::EndTooltip();
}
ImGui::SameLine(cursor_type_offset + cursor_type_radio_sphere);
ImGui::PushItemWidth(cursor_type_radio_circle);
if (m_imgui->radio_button(m_desc["circle"], m_cursor_type == TriangleSelector::CursorType::CIRCLE))
m_cursor_type = TriangleSelector::CursorType::CIRCLE;
if (ImGui::IsItemHovered()) {
ImGui::BeginTooltip();
ImGui::PushTextWrapPos(max_tooltip_width);
ImGui::TextUnformatted(_L("Ignores facets facing away from the camera.").ToUTF8().data());
ImGui::PopTextWrapPos();
ImGui::EndTooltip();
}
ImGui::SameLine(cursor_type_offset + cursor_type_radio_sphere + cursor_type_radio_circle);
ImGui::PushItemWidth(cursor_type_radio_pointer);
if (m_imgui->radio_button(m_desc["pointer"], m_cursor_type == TriangleSelector::CursorType::POINTER))
m_cursor_type = TriangleSelector::CursorType::POINTER;
if (ImGui::IsItemHovered()) {
ImGui::BeginTooltip();
ImGui::PushTextWrapPos(max_tooltip_width);
ImGui::TextUnformatted(_L("Paints only one facet.").ToUTF8().data());
ImGui::PopTextWrapPos();
ImGui::EndTooltip();
}
m_imgui->disabled_begin(m_cursor_type != TriangleSelector::CursorType::SPHERE && m_cursor_type != TriangleSelector::CursorType::CIRCLE);
ImGui::AlignTextToFramePadding();
m_imgui->text(m_desc.at("cursor_size"));
ImGui::SameLine(sliders_width);
ImGui::PushItemWidth(window_width - sliders_width);
m_imgui->slider_float("##cursor_radius", &m_cursor_radius, CursorRadiusMin, CursorRadiusMax, "%.2f");
if (ImGui::IsItemHovered()) {
ImGui::BeginTooltip();
ImGui::PushTextWrapPos(max_tooltip_width);
ImGui::TextUnformatted(_L("Alt + Mouse wheel").ToUTF8().data());
ImGui::PopTextWrapPos();
ImGui::EndTooltip();
}
m_imgui->checkbox(_L("Split triangles"), m_triangle_splitting_enabled);
if (ImGui::IsItemHovered()) {
ImGui::BeginTooltip();
ImGui::PushTextWrapPos(max_tooltip_width);
ImGui::TextUnformatted(_L("Split bigger facets into smaller ones while the object is painted.").ToUTF8().data());
ImGui::PopTextWrapPos();
ImGui::EndTooltip();
}
m_imgui->disabled_end();
} else {
assert(m_tool_type == ToolType::SMART_FILL);
ImGui::AlignTextToFramePadding();
m_imgui->text(m_desc["smart_fill_angle"] + ":");
std::string format_str = std::string("%.f") + I18N::translate_utf8("°", "Degree sign to use in the respective slider in MMU gizmo,"
"placed after the number with no whitespace in between.");
ImGui::SameLine(sliders_width);
ImGui::PushItemWidth(window_width - sliders_width);
if (m_imgui->slider_float("##smart_fill_angle", &m_smart_fill_angle, SmartFillAngleMin, SmartFillAngleMax, format_str.data()))
for (auto &triangle_selector : m_triangle_selectors) {
triangle_selector->seed_fill_unselect_all_triangles();
triangle_selector->request_update_render_data();
}
if (ImGui::IsItemHovered()) {
ImGui::BeginTooltip();
ImGui::PushTextWrapPos(max_tooltip_width);
ImGui::TextUnformatted(_L("Alt + Mouse wheel").ToUTF8().data());
ImGui::PopTextWrapPos();
ImGui::EndTooltip();
}
}
ImGui::Separator(); ImGui::Separator();
if (m_c->object_clipper()->get_position() == 0.f) { if (m_c->object_clipper()->get_position() == 0.f) {
@ -250,10 +319,10 @@ void GLGizmoFdmSupports::on_render_input_window(float x, float y, float bottom_l
} }
} }
ImGui::SameLine(clipping_slider_left); ImGui::SameLine(sliders_width);
ImGui::PushItemWidth(window_width - clipping_slider_left); ImGui::PushItemWidth(window_width - sliders_width);
auto clp_dist = float(m_c->object_clipper()->get_position()); auto clp_dist = float(m_c->object_clipper()->get_position());
if (m_imgui->slider_float(" ", &clp_dist, 0.f, 1.f, "%.2f")) if (m_imgui->slider_float("##clp_dist", &clp_dist, 0.f, 1.f, "%.2f"))
m_c->object_clipper()->set_position(clp_dist, true); m_c->object_clipper()->set_position(clp_dist, true);
if (ImGui::IsItemHovered()) { if (ImGui::IsItemHovered()) {
@ -263,6 +332,23 @@ void GLGizmoFdmSupports::on_render_input_window(float x, float y, float bottom_l
ImGui::PopTextWrapPos(); ImGui::PopTextWrapPos();
ImGui::EndTooltip(); ImGui::EndTooltip();
} }
ImGui::Separator();
if (m_imgui->button(m_desc.at("remove_all"))) {
Plater::TakeSnapshot snapshot(wxGetApp().plater(), _L("Reset selection"), UndoRedo::SnapshotType::GizmoAction);
ModelObject *mo = m_c->selection_info()->model_object();
int idx = -1;
for (ModelVolume *mv : mo->volumes)
if (mv->is_model_part()) {
++idx;
m_triangle_selectors[idx]->reset();
m_triangle_selectors[idx]->request_update_render_data();
}
update_model_object();
m_parent.set_as_dirty();
}
m_imgui->end(); m_imgui->end();
} }
@ -291,7 +377,7 @@ void GLGizmoFdmSupports::select_facets_by_angle(float threshold_deg, bool block)
// Now calculate dot product of vert_direction and facets' normals. // Now calculate dot product of vert_direction and facets' normals.
int idx = 0; int idx = 0;
const indexed_triangle_set &its = mv->mesh().its; const indexed_triangle_set &its = mv->mesh().its;
for (stl_triangle_vertex_indices face : its.indices) { for (const stl_triangle_vertex_indices &face : its.indices) {
if (its_face_normal(its, face).dot(down) > dot_limit) { if (its_face_normal(its, face).dot(down) > dot_limit) {
m_triangle_selectors[mesh_id]->set_facet(idx, block ? EnforcerBlockerType::BLOCKER : EnforcerBlockerType::ENFORCER); m_triangle_selectors[mesh_id]->set_facet(idx, block ? EnforcerBlockerType::BLOCKER : EnforcerBlockerType::ENFORCER);
m_triangle_selectors.back()->request_update_render_data(); m_triangle_selectors.back()->request_update_render_data();

View File

@ -42,7 +42,6 @@ void GLGizmoMmuSegmentation::on_shutdown()
std::string GLGizmoMmuSegmentation::on_get_name() const std::string GLGizmoMmuSegmentation::on_get_name() const
{ {
// FIXME Lukas H.: Discuss and change shortcut
return _u8L("Multimaterial painting"); return _u8L("Multimaterial painting");
} }
@ -107,7 +106,6 @@ void GLGizmoMmuSegmentation::init_extruders_data()
bool GLGizmoMmuSegmentation::on_init() bool GLGizmoMmuSegmentation::on_init()
{ {
// FIXME Lukas H.: Discuss and change shortcut
m_shortcut_key = WXK_CONTROL_N; m_shortcut_key = WXK_CONTROL_N;
m_desc["reset_direction"] = _L("Reset direction"); m_desc["reset_direction"] = _L("Reset direction");
@ -123,7 +121,7 @@ bool GLGizmoMmuSegmentation::on_init()
m_desc["remove_all"] = _L("Remove all painted areas"); m_desc["remove_all"] = _L("Remove all painted areas");
m_desc["circle"] = _L("Circle"); m_desc["circle"] = _L("Circle");
m_desc["sphere"] = _L("Sphere"); m_desc["sphere"] = _L("Sphere");
m_desc["pointer"] = _L("Pointer"); m_desc["pointer"] = _L("Triangles");
m_desc["tool_type"] = _L("Tool type"); m_desc["tool_type"] = _L("Tool type");
m_desc["tool_brush"] = _L("Brush"); m_desc["tool_brush"] = _L("Brush");
@ -236,7 +234,7 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott
if (!m_c->selection_info()->model_object()) if (!m_c->selection_info()->model_object())
return; return;
const float approx_height = m_imgui->scaled(25.0f); const float approx_height = m_imgui->scaled(22.0f);
y = std::min(y, bottom_limit - approx_height); y = std::min(y, bottom_limit - approx_height);
m_imgui->set_next_window_pos(x, y, ImGuiCond_Always); m_imgui->set_next_window_pos(x, y, ImGuiCond_Always);
@ -264,13 +262,13 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott
const float tool_type_radio_smart_fill = m_imgui->calc_text_size(m_desc["tool_smart_fill"]).x + m_imgui->scaled(2.5f); const float tool_type_radio_smart_fill = m_imgui->calc_text_size(m_desc["tool_smart_fill"]).x + m_imgui->scaled(2.5f);
float caption_max = 0.f; float caption_max = 0.f;
float total_text_max = 0.; float total_text_max = 0.f;
for (const auto &t : std::array<std::string, 3>{"first_color", "second_color", "remove"}) { for (const auto &t : std::array<std::string, 3>{"first_color", "second_color", "remove"}) {
caption_max = std::max(caption_max, m_imgui->calc_text_size(m_desc.at(t + "_caption")).x); caption_max = std::max(caption_max, m_imgui->calc_text_size(m_desc[t + "_caption"]).x);
total_text_max = std::max(total_text_max, caption_max + m_imgui->calc_text_size(m_desc.at(t)).x); total_text_max = std::max(total_text_max, m_imgui->calc_text_size(m_desc[t]).x);
} }
caption_max += m_imgui->scaled(1.f); total_text_max += caption_max + m_imgui->scaled(1.f);
total_text_max += m_imgui->scaled(1.f); caption_max += m_imgui->scaled(1.f);
float sliders_width = std::max(smart_fill_slider_left, std::max(cursor_slider_left, clipping_slider_left)); float sliders_width = std::max(smart_fill_slider_left, std::max(cursor_slider_left, clipping_slider_left));
float window_width = minimal_slider_width + sliders_width; float window_width = minimal_slider_width + sliders_width;
@ -289,7 +287,6 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott
for (const auto &t : std::array<std::string, 3>{"first_color", "second_color", "remove"}) for (const auto &t : std::array<std::string, 3>{"first_color", "second_color", "remove"})
draw_text_with_caption(m_desc.at(t + "_caption"), m_desc.at(t)); draw_text_with_caption(m_desc.at(t + "_caption"), m_desc.at(t));
m_imgui->text("");
ImGui::Separator(); ImGui::Separator();
ImGui::AlignTextToFramePadding(); ImGui::AlignTextToFramePadding();
@ -321,15 +318,13 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott
ImGui::Separator(); ImGui::Separator();
m_imgui->text(m_desc.at("tool_type")); m_imgui->text(m_desc.at("tool_type"));
float tool_type_offset = (window_width - tool_type_radio_brush - tool_type_radio_bucket_fill - tool_type_radio_smart_fill + m_imgui->scaled(2.f)) / 2.f;
ImGui::NewLine(); ImGui::NewLine();
ImGui::SameLine(tool_type_offset + m_imgui->scaled(0.f)); float tool_type_offset = (window_width - tool_type_radio_brush - tool_type_radio_bucket_fill - tool_type_radio_smart_fill + m_imgui->scaled(1.5f)) / 2.f;
ImGui::SameLine(tool_type_offset);
ImGui::PushItemWidth(tool_type_radio_brush); ImGui::PushItemWidth(tool_type_radio_brush);
if (m_imgui->radio_button(m_desc["tool_brush"], m_tool_type == GLGizmoMmuSegmentation::ToolType::BRUSH)) { if (m_imgui->radio_button(m_desc["tool_brush"], m_tool_type == ToolType::BRUSH)) {
m_tool_type = GLGizmoMmuSegmentation::ToolType::BRUSH; m_tool_type = ToolType::BRUSH;
for (auto &triangle_selector : m_triangle_selectors) { for (auto &triangle_selector : m_triangle_selectors) {
triangle_selector->seed_fill_unselect_all_triangles(); triangle_selector->seed_fill_unselect_all_triangles();
triangle_selector->request_update_render_data(); triangle_selector->request_update_render_data();
@ -344,10 +339,10 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott
ImGui::EndTooltip(); ImGui::EndTooltip();
} }
ImGui::SameLine(tool_type_offset + tool_type_radio_brush + m_imgui->scaled(0.f)); ImGui::SameLine(tool_type_offset + tool_type_radio_brush);
ImGui::PushItemWidth(tool_type_radio_smart_fill); ImGui::PushItemWidth(tool_type_radio_smart_fill);
if (m_imgui->radio_button(m_desc["tool_smart_fill"], m_tool_type == GLGizmoMmuSegmentation::ToolType::SMART_FILL)) { if (m_imgui->radio_button(m_desc["tool_smart_fill"], m_tool_type == ToolType::SMART_FILL)) {
m_tool_type = GLGizmoMmuSegmentation::ToolType::SMART_FILL; m_tool_type = ToolType::SMART_FILL;
for (auto &triangle_selector : m_triangle_selectors) { for (auto &triangle_selector : m_triangle_selectors) {
triangle_selector->seed_fill_unselect_all_triangles(); triangle_selector->seed_fill_unselect_all_triangles();
triangle_selector->request_update_render_data(); triangle_selector->request_update_render_data();
@ -362,10 +357,10 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott
ImGui::EndTooltip(); ImGui::EndTooltip();
} }
ImGui::SameLine(tool_type_offset + tool_type_radio_brush + tool_type_radio_smart_fill + m_imgui->scaled(0.f)); ImGui::SameLine(tool_type_offset + tool_type_radio_brush + tool_type_radio_smart_fill);
ImGui::PushItemWidth(tool_type_radio_bucket_fill); ImGui::PushItemWidth(tool_type_radio_bucket_fill);
if (m_imgui->radio_button(m_desc["tool_bucket_fill"], m_tool_type == GLGizmoMmuSegmentation::ToolType::BUCKET_FILL)) { if (m_imgui->radio_button(m_desc["tool_bucket_fill"], m_tool_type == ToolType::BUCKET_FILL)) {
m_tool_type = GLGizmoMmuSegmentation::ToolType::BUCKET_FILL; m_tool_type = ToolType::BUCKET_FILL;
for (auto &triangle_selector : m_triangle_selectors) { for (auto &triangle_selector : m_triangle_selectors) {
triangle_selector->seed_fill_unselect_all_triangles(); triangle_selector->seed_fill_unselect_all_triangles();
triangle_selector->request_update_render_data(); triangle_selector->request_update_render_data();
@ -386,8 +381,8 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott
m_imgui->text(m_desc.at("cursor_type")); m_imgui->text(m_desc.at("cursor_type"));
ImGui::NewLine(); ImGui::NewLine();
float cursor_type_offset = (window_width - cursor_type_radio_sphere - cursor_type_radio_circle - cursor_type_radio_pointer + m_imgui->scaled(2.f)) / 2.f; float cursor_type_offset = (window_width - cursor_type_radio_sphere - cursor_type_radio_circle - cursor_type_radio_pointer + m_imgui->scaled(1.5f)) / 2.f;
ImGui::SameLine(cursor_type_offset + m_imgui->scaled(0.f)); ImGui::SameLine(cursor_type_offset);
ImGui::PushItemWidth(cursor_type_radio_sphere); ImGui::PushItemWidth(cursor_type_radio_sphere);
if (m_imgui->radio_button(m_desc["sphere"], m_cursor_type == TriangleSelector::CursorType::SPHERE)) if (m_imgui->radio_button(m_desc["sphere"], m_cursor_type == TriangleSelector::CursorType::SPHERE))
m_cursor_type = TriangleSelector::CursorType::SPHERE; m_cursor_type = TriangleSelector::CursorType::SPHERE;
@ -400,7 +395,7 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott
ImGui::EndTooltip(); ImGui::EndTooltip();
} }
ImGui::SameLine(cursor_type_offset +cursor_type_radio_sphere + m_imgui->scaled(0.f)); ImGui::SameLine(cursor_type_offset + cursor_type_radio_sphere);
ImGui::PushItemWidth(cursor_type_radio_circle); ImGui::PushItemWidth(cursor_type_radio_circle);
if (m_imgui->radio_button(m_desc["circle"], m_cursor_type == TriangleSelector::CursorType::CIRCLE)) if (m_imgui->radio_button(m_desc["circle"], m_cursor_type == TriangleSelector::CursorType::CIRCLE))
@ -414,7 +409,7 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott
ImGui::EndTooltip(); ImGui::EndTooltip();
} }
ImGui::SameLine(cursor_type_offset + cursor_type_radio_sphere + cursor_type_radio_circle + m_imgui->scaled(0.f)); ImGui::SameLine(cursor_type_offset + cursor_type_radio_sphere + cursor_type_radio_circle);
ImGui::PushItemWidth(cursor_type_radio_pointer); ImGui::PushItemWidth(cursor_type_radio_pointer);
if (m_imgui->radio_button(m_desc["pointer"], m_cursor_type == TriangleSelector::CursorType::POINTER)) if (m_imgui->radio_button(m_desc["pointer"], m_cursor_type == TriangleSelector::CursorType::POINTER))
@ -434,7 +429,7 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott
m_imgui->text(m_desc.at("cursor_size")); m_imgui->text(m_desc.at("cursor_size"));
ImGui::SameLine(sliders_width); ImGui::SameLine(sliders_width);
ImGui::PushItemWidth(window_width - sliders_width); ImGui::PushItemWidth(window_width - sliders_width);
m_imgui->slider_float(" ", &m_cursor_radius, CursorRadiusMin, CursorRadiusMax, "%.2f"); m_imgui->slider_float("##cursor_radius", &m_cursor_radius, CursorRadiusMin, CursorRadiusMax, "%.2f");
if (ImGui::IsItemHovered()) { if (ImGui::IsItemHovered()) {
ImGui::BeginTooltip(); ImGui::BeginTooltip();
ImGui::PushTextWrapPos(max_tooltip_width); ImGui::PushTextWrapPos(max_tooltip_width);
@ -492,8 +487,9 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott
ImGui::SameLine(sliders_width); ImGui::SameLine(sliders_width);
ImGui::PushItemWidth(window_width - sliders_width); ImGui::PushItemWidth(window_width - sliders_width);
auto clp_dist = float(m_c->object_clipper()->get_position()); auto clp_dist = float(m_c->object_clipper()->get_position());
if (m_imgui->slider_float(" ", &clp_dist, 0.f, 1.f, "%.2f")) if (m_imgui->slider_float("##clp_dist", &clp_dist, 0.f, 1.f, "%.2f"))
m_c->object_clipper()->set_position(clp_dist, true); m_c->object_clipper()->set_position(clp_dist, true);
if (ImGui::IsItemHovered()) { if (ImGui::IsItemHovered()) {
ImGui::BeginTooltip(); ImGui::BeginTooltip();
ImGui::PushTextWrapPos(max_tooltip_width); ImGui::PushTextWrapPos(max_tooltip_width);
@ -596,11 +592,6 @@ std::array<float, 4> GLGizmoMmuSegmentation::get_cursor_sphere_right_button_colo
return {color[0], color[1], color[2], 0.25f}; return {color[0], color[1], color[2], 0.25f};
} }
static std::array<float, 4> get_seed_fill_color(const std::array<float, 4> &base_color)
{
return {base_color[0] * 0.75f, base_color[1] * 0.75f, base_color[2] * 0.75f, 1.f};
}
void TriangleSelectorMmGui::render(ImGuiWrapper *imgui) void TriangleSelectorMmGui::render(ImGuiWrapper *imgui)
{ {
if (m_update_render_data) if (m_update_render_data)
@ -620,14 +611,14 @@ void TriangleSelectorMmGui::render(ImGuiWrapper *imgui)
for (size_t color_idx = 0; color_idx < m_gizmo_scene.triangle_indices.size(); ++color_idx) for (size_t color_idx = 0; color_idx < m_gizmo_scene.triangle_indices.size(); ++color_idx)
if (m_gizmo_scene.has_VBOs(color_idx)) { if (m_gizmo_scene.has_VBOs(color_idx)) {
if (color_idx > m_colors.size()) // Seed fill VBO if (color_idx > m_colors.size()) // Seed fill VBO
shader->set_uniform("uniform_color", get_seed_fill_color(color_idx == (m_colors.size() + 1) ? m_default_volume_color : m_colors[color_idx - (m_colors.size() + 1) - 1])); shader->set_uniform("uniform_color", TriangleSelectorGUI::get_seed_fill_color(color_idx == (m_colors.size() + 1) ? m_default_volume_color : m_colors[color_idx - (m_colors.size() + 1) - 1]));
else // Normal VBO else // Normal VBO
shader->set_uniform("uniform_color", color_idx == 0 ? m_default_volume_color : m_colors[color_idx - 1]); shader->set_uniform("uniform_color", color_idx == 0 ? m_default_volume_color : m_colors[color_idx - 1]);
m_gizmo_scene.render(color_idx); m_gizmo_scene.render(color_idx);
} }
if (m_gizmo_scene.has_contour_VBO()) { if (m_paint_contour.has_VBO()) {
ScopeGuard guard_gouraud([shader]() { shader->start_using(); }); ScopeGuard guard_gouraud([shader]() { shader->start_using(); });
shader->stop_using(); shader->stop_using();
@ -635,7 +626,7 @@ void TriangleSelectorMmGui::render(ImGuiWrapper *imgui)
contour_shader->start_using(); contour_shader->start_using();
glsafe(::glDepthFunc(GL_LEQUAL)); glsafe(::glDepthFunc(GL_LEQUAL));
m_gizmo_scene.render_contour(); m_paint_contour.render();
glsafe(::glDepthFunc(GL_LESS)); glsafe(::glDepthFunc(GL_LESS));
contour_shader->stop_using(); contour_shader->stop_using();
@ -674,23 +665,24 @@ void TriangleSelectorMmGui::update_render_data()
m_gizmo_scene.finalize_triangle_indices(); m_gizmo_scene.finalize_triangle_indices();
m_paint_contour.release_geometry();
std::vector<Vec2i> contour_edges = this->get_seed_fill_contour(); std::vector<Vec2i> contour_edges = this->get_seed_fill_contour();
m_gizmo_scene.contour_vertices.reserve(contour_edges.size() * 6); m_paint_contour.contour_vertices.reserve(contour_edges.size() * 6);
for (const Vec2i &edge : contour_edges) { for (const Vec2i &edge : contour_edges) {
m_gizmo_scene.contour_vertices.emplace_back(m_vertices[edge(0)].v.x()); m_paint_contour.contour_vertices.emplace_back(m_vertices[edge(0)].v.x());
m_gizmo_scene.contour_vertices.emplace_back(m_vertices[edge(0)].v.y()); m_paint_contour.contour_vertices.emplace_back(m_vertices[edge(0)].v.y());
m_gizmo_scene.contour_vertices.emplace_back(m_vertices[edge(0)].v.z()); m_paint_contour.contour_vertices.emplace_back(m_vertices[edge(0)].v.z());
m_gizmo_scene.contour_vertices.emplace_back(m_vertices[edge(1)].v.x()); m_paint_contour.contour_vertices.emplace_back(m_vertices[edge(1)].v.x());
m_gizmo_scene.contour_vertices.emplace_back(m_vertices[edge(1)].v.y()); m_paint_contour.contour_vertices.emplace_back(m_vertices[edge(1)].v.y());
m_gizmo_scene.contour_vertices.emplace_back(m_vertices[edge(1)].v.z()); m_paint_contour.contour_vertices.emplace_back(m_vertices[edge(1)].v.z());
} }
m_gizmo_scene.contour_indices.assign(m_gizmo_scene.contour_vertices.size() / 3, 0); m_paint_contour.contour_indices.assign(m_paint_contour.contour_vertices.size() / 3, 0);
std::iota(m_gizmo_scene.contour_indices.begin(), m_gizmo_scene.contour_indices.end(), 0); std::iota(m_paint_contour.contour_indices.begin(), m_paint_contour.contour_indices.end(), 0);
m_gizmo_scene.contour_indices_size = m_gizmo_scene.contour_indices.size(); m_paint_contour.contour_indices_size = m_paint_contour.contour_indices.size();
m_gizmo_scene.finalize_contour(); m_paint_contour.finalize_geometry();
} }
wxString GLGizmoMmuSegmentation::handle_snapshot_action_name(bool shift_down, GLGizmoPainterBase::Button button_down) const wxString GLGizmoMmuSegmentation::handle_snapshot_action_name(bool shift_down, GLGizmoPainterBase::Button button_down) const
@ -714,14 +706,6 @@ void GLMmSegmentationGizmo3DScene::release_geometry() {
glsafe(::glDeleteBuffers(1, &triangle_indices_VBO_id)); glsafe(::glDeleteBuffers(1, &triangle_indices_VBO_id));
triangle_indices_VBO_id = 0; triangle_indices_VBO_id = 0;
} }
if (this->contour_vertices_VBO_id) {
glsafe(::glDeleteBuffers(1, &this->contour_vertices_VBO_id));
this->contour_vertices_VBO_id = 0;
}
if (this->contour_indices_VBO_id) {
glsafe(::glDeleteBuffers(1, &this->contour_indices_VBO_id));
this->contour_indices_VBO_id = 0;
}
this->clear(); this->clear();
} }
@ -749,29 +733,6 @@ void GLMmSegmentationGizmo3DScene::render(size_t triangle_indices_idx) const
glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0)); glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0));
} }
void GLMmSegmentationGizmo3DScene::render_contour() const
{
assert(this->contour_vertices_VBO_id != 0);
assert(this->contour_indices_VBO_id != 0);
glsafe(::glLineWidth(4.0f));
glsafe(::glBindBuffer(GL_ARRAY_BUFFER, this->contour_vertices_VBO_id));
glsafe(::glVertexPointer(3, GL_FLOAT, 3 * sizeof(float), nullptr));
glsafe(::glEnableClientState(GL_VERTEX_ARRAY));
if (this->contour_indices_size > 0) {
glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, this->contour_indices_VBO_id));
glsafe(::glDrawElements(GL_LINES, GLsizei(this->contour_indices_size), GL_UNSIGNED_INT, nullptr));
glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0));
}
glsafe(::glDisableClientState(GL_VERTEX_ARRAY));
glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0));
}
void GLMmSegmentationGizmo3DScene::finalize_vertices() void GLMmSegmentationGizmo3DScene::finalize_vertices()
{ {
assert(this->vertices_VBO_id == 0); assert(this->vertices_VBO_id == 0);
@ -799,26 +760,4 @@ void GLMmSegmentationGizmo3DScene::finalize_triangle_indices()
} }
} }
void GLMmSegmentationGizmo3DScene::finalize_contour()
{
assert(this->contour_vertices_VBO_id == 0);
assert(this->contour_indices_VBO_id == 0);
if (!this->contour_vertices.empty()) {
glsafe(::glGenBuffers(1, &this->contour_vertices_VBO_id));
glsafe(::glBindBuffer(GL_ARRAY_BUFFER, this->contour_vertices_VBO_id));
glsafe(::glBufferData(GL_ARRAY_BUFFER, this->contour_vertices.size() * sizeof(float), this->contour_vertices.data(), GL_STATIC_DRAW));
glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0));
this->contour_vertices.clear();
}
if (!this->contour_indices.empty()) {
glsafe(::glGenBuffers(1, &this->contour_indices_VBO_id));
glsafe(::glBindBuffer(GL_ARRAY_BUFFER, this->contour_indices_VBO_id));
glsafe(::glBufferData(GL_ARRAY_BUFFER, this->contour_indices.size() * sizeof(unsigned int), this->contour_indices.data(), GL_STATIC_DRAW));
glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0));
this->contour_indices.clear();
}
}
} // namespace Slic3r } // namespace Slic3r

View File

@ -25,8 +25,6 @@ public:
return this->triangle_indices_VBO_ids[triangle_indices_idx] != 0; return this->triangle_indices_VBO_ids[triangle_indices_idx] != 0;
} }
[[nodiscard]] inline bool has_contour_VBO() const { return this->contour_indices_VBO_id != 0; }
// Release the geometry data, release OpenGL VBOs. // Release the geometry data, release OpenGL VBOs.
void release_geometry(); void release_geometry();
// Finalize the initialization of the geometry, upload the geometry to OpenGL VBO objects // Finalize the initialization of the geometry, upload the geometry to OpenGL VBO objects
@ -35,9 +33,6 @@ public:
// Finalize the initialization of the indices, upload the indices to OpenGL VBO objects // Finalize the initialization of the indices, upload the indices to OpenGL VBO objects
// and possibly releasing it if it has been loaded into the VBOs. // and possibly releasing it if it has been loaded into the VBOs.
void finalize_triangle_indices(); void finalize_triangle_indices();
// Finalize the initialization of the contour geometry and the indices, upload both to OpenGL VBO objects
// and possibly releasing it if it has been loaded into the VBOs.
void finalize_contour();
void clear() void clear()
{ {
@ -47,34 +42,21 @@ public:
for (size_t &triangle_indices_size : this->triangle_indices_sizes) for (size_t &triangle_indices_size : this->triangle_indices_sizes)
triangle_indices_size = 0; triangle_indices_size = 0;
this->contour_vertices.clear();
this->contour_indices.clear();
this->contour_indices_size = 0;
} }
void render(size_t triangle_indices_idx) const; void render(size_t triangle_indices_idx) const;
void render_contour() const;
std::vector<float> vertices; std::vector<float> vertices;
std::vector<std::vector<int>> triangle_indices; std::vector<std::vector<int>> triangle_indices;
std::vector<float> contour_vertices;
std::vector<int> contour_indices;
// When the triangle indices are loaded into the graphics card as Vertex Buffer Objects, // When the triangle indices are loaded into the graphics card as Vertex Buffer Objects,
// the above mentioned std::vectors are cleared and the following variables keep their original length. // the above mentioned std::vectors are cleared and the following variables keep their original length.
std::vector<size_t> triangle_indices_sizes; std::vector<size_t> triangle_indices_sizes;
size_t contour_indices_size{0};
// IDs of the Vertex Array Objects, into which the geometry has been loaded. // IDs of the Vertex Array Objects, into which the geometry has been loaded.
// Zero if the VBOs are not sent to GPU yet. // Zero if the VBOs are not sent to GPU yet.
unsigned int vertices_VBO_id{0}; unsigned int vertices_VBO_id{0};
std::vector<unsigned int> triangle_indices_VBO_ids; std::vector<unsigned int> triangle_indices_VBO_ids;
unsigned int contour_vertices_VBO_id{0};
unsigned int contour_indices_VBO_id{0};
}; };
class TriangleSelectorMmGui : public TriangleSelectorGUI { class TriangleSelectorMmGui : public TriangleSelectorGUI {

View File

@ -553,7 +553,10 @@ void GLGizmoPainterBase::on_load(cereal::BinaryInputArchive&)
m_schedule_update = true; m_schedule_update = true;
} }
std::array<float, 4> TriangleSelectorGUI::get_seed_fill_color(const std::array<float, 4> &base_color)
{
return {base_color[0] * 0.75f, base_color[1] * 0.75f, base_color[2] * 0.75f, 1.f};
}
void TriangleSelectorGUI::render(ImGuiWrapper* imgui) void TriangleSelectorGUI::render(ImGuiWrapper* imgui)
{ {
@ -582,6 +585,29 @@ void TriangleSelectorGUI::render(ImGuiWrapper* imgui)
} }
} }
for (auto &iva : m_iva_seed_fills)
if (iva.has_VBOs()) {
size_t color_idx = &iva - &m_iva_seed_fills.front();
const std::array<float, 4> &color = TriangleSelectorGUI::get_seed_fill_color(color_idx == 1 ? enforcers_color :
color_idx == 2 ? blockers_color :
GLVolume::NEUTRAL_COLOR);
shader->set_uniform("uniform_color", color);
iva.render();
}
if (m_paint_contour.has_VBO()) {
ScopeGuard guard_gouraud([shader]() { shader->start_using(); });
shader->stop_using();
auto *contour_shader = wxGetApp().get_shader("mm_contour");
contour_shader->start_using();
glsafe(::glDepthFunc(GL_GEQUAL));
m_paint_contour.render();
glsafe(::glDepthFunc(GL_LESS));
contour_shader->stop_using();
}
#ifdef PRUSASLICER_TRIANGLE_SELECTOR_DEBUG #ifdef PRUSASLICER_TRIANGLE_SELECTOR_DEBUG
if (imgui) if (imgui)
@ -591,26 +617,33 @@ void TriangleSelectorGUI::render(ImGuiWrapper* imgui)
#endif #endif
} }
void TriangleSelectorGUI::update_render_data() void TriangleSelectorGUI::update_render_data()
{ {
int enf_cnt = 0; int enf_cnt = 0;
int blc_cnt = 0; int blc_cnt = 0;
std::vector<int> seed_fill_cnt(m_iva_seed_fills.size(), 0);
for (auto *iva : {&m_iva_enforcers, &m_iva_blockers}) for (auto *iva : {&m_iva_enforcers, &m_iva_blockers})
iva->release_geometry(); iva->release_geometry();
for (auto &iva : m_iva_seed_fills)
iva.release_geometry();
for (const Triangle &tr : m_triangles) { for (const Triangle &tr : m_triangles) {
if (!tr.valid() || tr.is_split() || tr.get_state() == EnforcerBlockerType::NONE) if (!tr.valid() || tr.is_split() || (tr.get_state() == EnforcerBlockerType::NONE && !tr.is_selected_by_seed_fill()))
continue; continue;
GLIndexedVertexArray &iva = tr.get_state() == EnforcerBlockerType::ENFORCER ? m_iva_enforcers : m_iva_blockers; int tr_state = int(tr.get_state());
int & cnt = tr.get_state() == EnforcerBlockerType::ENFORCER ? enf_cnt : blc_cnt; GLIndexedVertexArray &iva = tr.is_selected_by_seed_fill() ? m_iva_seed_fills[tr_state] :
tr.get_state() == EnforcerBlockerType::ENFORCER ? m_iva_enforcers :
m_iva_blockers;
int &cnt = tr.is_selected_by_seed_fill() ? seed_fill_cnt[tr_state] :
tr.get_state() == EnforcerBlockerType::ENFORCER ? enf_cnt :
blc_cnt;
const Vec3f &v0 = m_vertices[tr.verts_idxs[0]].v; const Vec3f &v0 = m_vertices[tr.verts_idxs[0]].v;
const Vec3f &v1 = m_vertices[tr.verts_idxs[1]].v; const Vec3f &v1 = m_vertices[tr.verts_idxs[1]].v;
const Vec3f &v2 = m_vertices[tr.verts_idxs[2]].v; const Vec3f &v2 = m_vertices[tr.verts_idxs[2]].v;
//FIXME the normal may likely be pulled from m_triangle_selectors, but it may not be worth the effort //FIXME the normal may likely be pulled from m_triangle_selectors, but it may not be worth the effort
// or the current implementation may be more cache friendly. // or the current implementation may be more cache friendly.
const Vec3f n = (v1 - v0).cross(v2 - v1).normalized(); const Vec3f n = (v1 - v0).cross(v2 - v1).normalized();
iva.push_geometry(v0, n); iva.push_geometry(v0, n);
@ -622,9 +655,87 @@ void TriangleSelectorGUI::update_render_data()
for (auto *iva : {&m_iva_enforcers, &m_iva_blockers}) for (auto *iva : {&m_iva_enforcers, &m_iva_blockers})
iva->finalize_geometry(true); iva->finalize_geometry(true);
for (auto &iva : m_iva_seed_fills)
iva.finalize_geometry(true);
m_paint_contour.release_geometry();
std::vector<Vec2i> contour_edges = this->get_seed_fill_contour();
m_paint_contour.contour_vertices.reserve(contour_edges.size() * 6);
for (const Vec2i &edge : contour_edges) {
m_paint_contour.contour_vertices.emplace_back(m_vertices[edge(0)].v.x());
m_paint_contour.contour_vertices.emplace_back(m_vertices[edge(0)].v.y());
m_paint_contour.contour_vertices.emplace_back(m_vertices[edge(0)].v.z());
m_paint_contour.contour_vertices.emplace_back(m_vertices[edge(1)].v.x());
m_paint_contour.contour_vertices.emplace_back(m_vertices[edge(1)].v.y());
m_paint_contour.contour_vertices.emplace_back(m_vertices[edge(1)].v.z());
}
m_paint_contour.contour_indices.assign(m_paint_contour.contour_vertices.size() / 3, 0);
std::iota(m_paint_contour.contour_indices.begin(), m_paint_contour.contour_indices.end(), 0);
m_paint_contour.contour_indices_size = m_paint_contour.contour_indices.size();
m_paint_contour.finalize_geometry();
} }
void GLPaintContour::render() const
{
assert(this->m_contour_VBO_id != 0);
assert(this->m_contour_EBO_id != 0);
glsafe(::glLineWidth(4.0f));
glsafe(::glBindBuffer(GL_ARRAY_BUFFER, this->m_contour_VBO_id));
glsafe(::glVertexPointer(3, GL_FLOAT, 3 * sizeof(float), nullptr));
glsafe(::glEnableClientState(GL_VERTEX_ARRAY));
if (this->contour_indices_size > 0) {
glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, this->m_contour_EBO_id));
glsafe(::glDrawElements(GL_LINES, GLsizei(this->contour_indices_size), GL_UNSIGNED_INT, nullptr));
glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0));
}
glsafe(::glDisableClientState(GL_VERTEX_ARRAY));
glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0));
}
void GLPaintContour::finalize_geometry()
{
assert(this->m_contour_VBO_id == 0);
assert(this->m_contour_EBO_id == 0);
if (!this->contour_vertices.empty()) {
glsafe(::glGenBuffers(1, &this->m_contour_VBO_id));
glsafe(::glBindBuffer(GL_ARRAY_BUFFER, this->m_contour_VBO_id));
glsafe(::glBufferData(GL_ARRAY_BUFFER, this->contour_vertices.size() * sizeof(float), this->contour_vertices.data(), GL_STATIC_DRAW));
glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0));
this->contour_vertices.clear();
}
if (!this->contour_indices.empty()) {
glsafe(::glGenBuffers(1, &this->m_contour_EBO_id));
glsafe(::glBindBuffer(GL_ARRAY_BUFFER, this->m_contour_EBO_id));
glsafe(::glBufferData(GL_ARRAY_BUFFER, this->contour_indices.size() * sizeof(unsigned int), this->contour_indices.data(), GL_STATIC_DRAW));
glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0));
this->contour_indices.clear();
}
}
void GLPaintContour::release_geometry()
{
if (this->m_contour_VBO_id) {
glsafe(::glDeleteBuffers(1, &this->m_contour_VBO_id));
this->m_contour_VBO_id = 0;
}
if (this->m_contour_EBO_id) {
glsafe(::glDeleteBuffers(1, &this->m_contour_EBO_id));
this->m_contour_EBO_id = 0;
}
this->clear();
}
#ifdef PRUSASLICER_TRIANGLE_SELECTOR_DEBUG #ifdef PRUSASLICER_TRIANGLE_SELECTOR_DEBUG
void TriangleSelectorGUI::render_debug(ImGuiWrapper* imgui) void TriangleSelectorGUI::render_debug(ImGuiWrapper* imgui)

View File

@ -10,6 +10,7 @@
#include "libslic3r/Model.hpp" #include "libslic3r/Model.hpp"
#include <cereal/types/vector.hpp> #include <cereal/types/vector.hpp>
#include <GL/glew.h>
@ -26,6 +27,41 @@ enum class PainterGizmoType {
MMU_SEGMENTATION MMU_SEGMENTATION
}; };
class GLPaintContour
{
public:
GLPaintContour() = default;
void render() const;
inline bool has_VBO() const { return this->m_contour_EBO_id != 0; }
// Release the geometry data, release OpenGL VBOs.
void release_geometry();
// Finalize the initialization of the contour geometry and the indices, upload both to OpenGL VBO objects
// and possibly releasing it if it has been loaded into the VBOs.
void finalize_geometry();
void clear()
{
this->contour_vertices.clear();
this->contour_indices.clear();
this->contour_indices_size = 0;
}
std::vector<float> contour_vertices;
std::vector<int> contour_indices;
// When the triangle indices are loaded into the graphics card as Vertex Buffer Objects,
// the above mentioned std::vectors are cleared and the following variables keep their original length.
size_t contour_indices_size{0};
// IDs of the Vertex Array Objects, into which the geometry has been loaded.
// Zero if the VBOs are not sent to GPU yet.
GLuint m_contour_VBO_id{0};
GLuint m_contour_EBO_id{0};
};
class TriangleSelectorGUI : public TriangleSelector { class TriangleSelectorGUI : public TriangleSelector {
public: public:
@ -49,12 +85,18 @@ public:
protected: protected:
bool m_update_render_data = false; bool m_update_render_data = false;
static std::array<float, 4> get_seed_fill_color(const std::array<float, 4> &base_color);
private: private:
void update_render_data(); void update_render_data();
GLIndexedVertexArray m_iva_enforcers; GLIndexedVertexArray m_iva_enforcers;
GLIndexedVertexArray m_iva_blockers; GLIndexedVertexArray m_iva_blockers;
std::array<GLIndexedVertexArray, 3> m_iva_seed_fills;
std::array<GLIndexedVertexArray, 3> m_varrays; std::array<GLIndexedVertexArray, 3> m_varrays;
protected:
GLPaintContour m_paint_contour;
}; };
class GLGizmoTransparentRender class GLGizmoTransparentRender

View File

@ -77,7 +77,7 @@ void GLGizmoSeam::on_render_input_window(float x, float y, float bottom_limit)
if (! m_c->selection_info()->model_object()) if (! m_c->selection_info()->model_object())
return; return;
const float approx_height = m_imgui->scaled(14.0f); const float approx_height = m_imgui->scaled(12.5f);
y = std::min(y, bottom_limit - approx_height); y = std::min(y, bottom_limit - approx_height);
m_imgui->set_next_window_pos(x, y, ImGuiCond_Always); m_imgui->set_next_window_pos(x, y, ImGuiCond_Always);
m_imgui->begin(get_name(), ImGuiWindowFlags_NoMove | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoCollapse); m_imgui->begin(get_name(), ImGuiWindowFlags_NoMove | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoCollapse);
@ -87,27 +87,28 @@ void GLGizmoSeam::on_render_input_window(float x, float y, float bottom_limit)
m_imgui->calc_text_size(m_desc.at("reset_direction")).x) m_imgui->calc_text_size(m_desc.at("reset_direction")).x)
+ m_imgui->scaled(1.5f); + m_imgui->scaled(1.5f);
const float cursor_size_slider_left = m_imgui->calc_text_size(m_desc.at("cursor_size")).x + m_imgui->scaled(1.f); const float cursor_size_slider_left = m_imgui->calc_text_size(m_desc.at("cursor_size")).x + m_imgui->scaled(1.f);
const float cursor_type_radio_left = m_imgui->calc_text_size(m_desc.at("cursor_type")).x + m_imgui->scaled(1.f);
const float cursor_type_radio_width1 = m_imgui->calc_text_size(m_desc["circle"]).x const float cursor_type_radio_left = m_imgui->calc_text_size(m_desc["cursor_type"]).x + m_imgui->scaled(1.f);
+ m_imgui->scaled(2.5f); const float cursor_type_radio_sphere = m_imgui->calc_text_size(m_desc["sphere"]).x + m_imgui->scaled(2.5f);
const float cursor_type_radio_width2 = m_imgui->calc_text_size(m_desc["sphere"]).x const float cursor_type_radio_circle = m_imgui->calc_text_size(m_desc["circle"]).x + m_imgui->scaled(2.5f);
+ m_imgui->scaled(2.5f);
const float button_width = m_imgui->calc_text_size(m_desc.at("remove_all")).x + m_imgui->scaled(1.f); const float button_width = m_imgui->calc_text_size(m_desc.at("remove_all")).x + m_imgui->scaled(1.f);
const float minimal_slider_width = m_imgui->scaled(4.f); const float minimal_slider_width = m_imgui->scaled(4.f);
float caption_max = 0.f; float caption_max = 0.f;
float total_text_max = 0.f; float total_text_max = 0.f;
for (const auto &t : std::array<std::string, 3>{"enforce", "block", "remove"}) { for (const auto &t : std::array<std::string, 3>{"enforce", "block", "remove"}) {
caption_max = std::max(caption_max, m_imgui->calc_text_size(m_desc.at(t + "_caption")).x); caption_max = std::max(caption_max, m_imgui->calc_text_size(m_desc[t + "_caption"]).x);
total_text_max = std::max(total_text_max, caption_max + m_imgui->calc_text_size(m_desc.at(t)).x); total_text_max = std::max(total_text_max, m_imgui->calc_text_size(m_desc[t]).x);
} }
caption_max += m_imgui->scaled(1.f); total_text_max += caption_max + m_imgui->scaled(1.f);
total_text_max += m_imgui->scaled(1.f); caption_max += m_imgui->scaled(1.f);
float window_width = minimal_slider_width + std::max(cursor_size_slider_left, clipping_slider_left); float sliders_width = std::max(cursor_size_slider_left, clipping_slider_left);
float window_width = minimal_slider_width + sliders_width;
window_width = std::max(window_width, total_text_max); window_width = std::max(window_width, total_text_max);
window_width = std::max(window_width, button_width); window_width = std::max(window_width, button_width);
window_width = std::max(window_width, cursor_type_radio_left + cursor_type_radio_width1 + cursor_type_radio_width2); window_width = std::max(window_width, cursor_type_radio_left + cursor_type_radio_sphere + cursor_type_radio_circle);
auto draw_text_with_caption = [this, &caption_max](const wxString& caption, const wxString& text) { auto draw_text_with_caption = [this, &caption_max](const wxString& caption, const wxString& text) {
static const ImVec4 ORANGE(1.0f, 0.49f, 0.22f, 1.0f); static const ImVec4 ORANGE(1.0f, 0.49f, 0.22f, 1.0f);
@ -119,32 +120,15 @@ void GLGizmoSeam::on_render_input_window(float x, float y, float bottom_limit)
for (const auto &t : std::array<std::string, 3>{"enforce", "block", "remove"}) for (const auto &t : std::array<std::string, 3>{"enforce", "block", "remove"})
draw_text_with_caption(m_desc.at(t + "_caption"), m_desc.at(t)); draw_text_with_caption(m_desc.at(t + "_caption"), m_desc.at(t));
m_imgui->text(""); ImGui::Separator();
if (m_imgui->button(m_desc.at("remove_all"))) {
Plater::TakeSnapshot snapshot(wxGetApp().plater(), _L("Reset selection"),
UndoRedo::SnapshotType::GizmoAction);
ModelObject* mo = m_c->selection_info()->model_object();
int idx = -1;
for (ModelVolume* mv : mo->volumes) {
if (mv->is_model_part()) {
++idx;
m_triangle_selectors[idx]->reset();
m_triangle_selectors[idx]->request_update_render_data();
}
}
update_model_object();
m_parent.set_as_dirty();
}
const float max_tooltip_width = ImGui::GetFontSize() * 20.0f; const float max_tooltip_width = ImGui::GetFontSize() * 20.0f;
ImGui::AlignTextToFramePadding(); ImGui::AlignTextToFramePadding();
m_imgui->text(m_desc.at("cursor_size")); m_imgui->text(m_desc.at("cursor_size"));
ImGui::SameLine(cursor_size_slider_left); ImGui::SameLine(sliders_width);
ImGui::PushItemWidth(window_width - cursor_size_slider_left); ImGui::PushItemWidth(window_width - sliders_width);
m_imgui->slider_float(" ", &m_cursor_radius, CursorRadiusMin, CursorRadiusMax, "%.2f"); m_imgui->slider_float("##cursor_radius", &m_cursor_radius, CursorRadiusMin, CursorRadiusMax, "%.2f");
if (ImGui::IsItemHovered()) { if (ImGui::IsItemHovered()) {
ImGui::BeginTooltip(); ImGui::BeginTooltip();
ImGui::PushTextWrapPos(max_tooltip_width); ImGui::PushTextWrapPos(max_tooltip_width);
@ -155,12 +139,12 @@ void GLGizmoSeam::on_render_input_window(float x, float y, float bottom_limit)
ImGui::AlignTextToFramePadding(); ImGui::AlignTextToFramePadding();
m_imgui->text(m_desc.at("cursor_type")); m_imgui->text(m_desc.at("cursor_type"));
ImGui::SameLine(cursor_type_radio_left + m_imgui->scaled(0.f));
ImGui::PushItemWidth(cursor_type_radio_width1);
bool sphere_sel = m_cursor_type == TriangleSelector::CursorType::SPHERE; float cursor_type_offset = cursor_type_radio_left + (window_width - cursor_type_radio_left - cursor_type_radio_sphere - cursor_type_radio_circle + m_imgui->scaled(0.5f)) / 2.f;
if (m_imgui->radio_button(m_desc["sphere"], sphere_sel)) ImGui::SameLine(cursor_type_offset);
sphere_sel = true; ImGui::PushItemWidth(cursor_type_radio_sphere);
if (m_imgui->radio_button(m_desc["sphere"], m_cursor_type == TriangleSelector::CursorType::SPHERE))
m_cursor_type = TriangleSelector::CursorType::SPHERE;
if (ImGui::IsItemHovered()) { if (ImGui::IsItemHovered()) {
ImGui::BeginTooltip(); ImGui::BeginTooltip();
@ -170,11 +154,10 @@ void GLGizmoSeam::on_render_input_window(float x, float y, float bottom_limit)
ImGui::EndTooltip(); ImGui::EndTooltip();
} }
ImGui::SameLine(cursor_type_radio_left + cursor_type_radio_width2 + m_imgui->scaled(0.f)); ImGui::SameLine(cursor_type_offset + cursor_type_radio_sphere);
ImGui::PushItemWidth(cursor_type_radio_width2); ImGui::PushItemWidth(cursor_type_radio_circle);
if (m_imgui->radio_button(m_desc["circle"], m_cursor_type == TriangleSelector::CursorType::CIRCLE))
if (m_imgui->radio_button(m_desc["circle"], ! sphere_sel)) m_cursor_type = TriangleSelector::CursorType::CIRCLE;
sphere_sel = false;
if (ImGui::IsItemHovered()) { if (ImGui::IsItemHovered()) {
ImGui::BeginTooltip(); ImGui::BeginTooltip();
@ -184,12 +167,6 @@ void GLGizmoSeam::on_render_input_window(float x, float y, float bottom_limit)
ImGui::EndTooltip(); ImGui::EndTooltip();
} }
m_cursor_type = sphere_sel
? TriangleSelector::CursorType::SPHERE
: TriangleSelector::CursorType::CIRCLE;
ImGui::Separator(); ImGui::Separator();
if (m_c->object_clipper()->get_position() == 0.f) { if (m_c->object_clipper()->get_position() == 0.f) {
ImGui::AlignTextToFramePadding(); ImGui::AlignTextToFramePadding();
@ -203,10 +180,10 @@ void GLGizmoSeam::on_render_input_window(float x, float y, float bottom_limit)
} }
} }
ImGui::SameLine(clipping_slider_left); ImGui::SameLine(sliders_width);
ImGui::PushItemWidth(window_width - clipping_slider_left); ImGui::PushItemWidth(window_width - sliders_width);
auto clp_dist = float(m_c->object_clipper()->get_position()); auto clp_dist = float(m_c->object_clipper()->get_position());
if (m_imgui->slider_float(" ", &clp_dist, 0.f, 1.f, "%.2f")) if (m_imgui->slider_float("##clp_dist", &clp_dist, 0.f, 1.f, "%.2f"))
m_c->object_clipper()->set_position(clp_dist, true); m_c->object_clipper()->set_position(clp_dist, true);
if (ImGui::IsItemHovered()) { if (ImGui::IsItemHovered()) {
@ -217,6 +194,22 @@ void GLGizmoSeam::on_render_input_window(float x, float y, float bottom_limit)
ImGui::EndTooltip(); ImGui::EndTooltip();
} }
ImGui::Separator();
if (m_imgui->button(m_desc.at("remove_all"))) {
Plater::TakeSnapshot snapshot(wxGetApp().plater(), _L("Reset selection"), UndoRedo::SnapshotType::GizmoAction);
ModelObject *mo = m_c->selection_info()->model_object();
int idx = -1;
for (ModelVolume *mv : mo->volumes)
if (mv->is_model_part()) {
++idx;
m_triangle_selectors[idx]->reset();
m_triangle_selectors[idx]->request_update_render_data();
}
update_model_object();
m_parent.set_as_dirty();
}
m_imgui->end(); m_imgui->end();
} }

View File

@ -548,7 +548,7 @@ bool GLGizmosManager::on_mouse(wxMouseEvent& evt)
// mouse anywhere // mouse anywhere
if (evt.Moving()) { if (evt.Moving()) {
m_tooltip = update_hover_state(mouse_pos); m_tooltip = update_hover_state(mouse_pos);
if (m_current == MmuSegmentation) if (m_current == MmuSegmentation || m_current == FdmSupports)
gizmo_event(SLAGizmoEventType::Moving, mouse_pos, evt.ShiftDown(), evt.AltDown()); gizmo_event(SLAGizmoEventType::Moving, mouse_pos, evt.ShiftDown(), evt.AltDown());
} else if (evt.LeftUp()) { } else if (evt.LeftUp()) {
if (m_mouse_capture.left) { if (m_mouse_capture.left) {

View File

@ -270,7 +270,7 @@ wxPanel* KBShortcutsDialog::create_header(wxWindow* parent, const wxFont& bold_f
sizer->AddStretchSpacer(); sizer->AddStretchSpacer();
// logo // logo
m_logo_bmp = ScalableBitmap(this, wxGetApp().is_editor() ? "PrusaSlicer_32px.png" : "PrusaSlicer-gcodeviewer_32px.png", 32); m_logo_bmp = ScalableBitmap(this, wxGetApp().logo_name(), 32);
m_header_bitmap = new wxStaticBitmap(panel, wxID_ANY, m_logo_bmp.bmp()); m_header_bitmap = new wxStaticBitmap(panel, wxID_ANY, m_logo_bmp.bmp());
sizer->Add(m_header_bitmap, 0, wxEXPAND | wxLEFT | wxRIGHT, 10); sizer->Add(m_header_bitmap, 0, wxEXPAND | wxLEFT | wxRIGHT, 10);

View File

@ -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

View File

@ -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;

View File

@ -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);
@ -2438,6 +2438,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);
@ -4600,14 +4608,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

View File

@ -343,6 +343,7 @@ void PreferencesDialog::build(size_t selected_tab)
m_optgroup_gui->append_single_option_line(option); m_optgroup_gui->append_single_option_line(option);
#ifdef _MSW_DARK_MODE #ifdef _MSW_DARK_MODE
}
def.label = L("Use Dark color mode (experimental)"); def.label = L("Use Dark color mode (experimental)");
def.type = coBool; def.type = coBool;
def.tooltip = L("If enabled, UI will use Dark mode colors. " def.tooltip = L("If enabled, UI will use Dark mode colors. "
@ -351,6 +352,7 @@ void PreferencesDialog::build(size_t selected_tab)
option = Option(def, "dark_color_mode"); option = Option(def, "dark_color_mode");
m_optgroup_gui->append_single_option_line(option); m_optgroup_gui->append_single_option_line(option);
if (is_editor) {
def.label = L("Set settings tabs as menu items (experimental)"); def.label = L("Set settings tabs as menu items (experimental)");
def.type = coBool; def.type = coBool;
def.tooltip = L("If enabled, Settings Tabs will be placed as menu items. " def.tooltip = L("If enabled, Settings Tabs will be placed as menu items. "

View File

@ -94,7 +94,7 @@ SysInfoDialog::SysInfoDialog()
main_sizer->Add(hsizer, 1, wxEXPAND | wxALL, 10); main_sizer->Add(hsizer, 1, wxEXPAND | wxALL, 10);
// logo // logo
m_logo_bmp = ScalableBitmap(this, wxGetApp().is_editor() ? "PrusaSlicer_192px.png" : "PrusaSlicer-gcodeviewer_192px.png", 192); m_logo_bmp = ScalableBitmap(this, wxGetApp().logo_name(), 192);
m_logo = new wxStaticBitmap(this, wxID_ANY, m_logo_bmp.bmp()); m_logo = new wxStaticBitmap(this, wxID_ANY, m_logo_bmp.bmp());
hsizer->Add(m_logo, 0, wxALIGN_CENTER_VERTICAL); hsizer->Add(m_logo, 0, wxALIGN_CENTER_VERTICAL);

View File

@ -421,7 +421,7 @@ bool fix_model_by_win10_sdk_gui(ModelObject &model_object, int volume_idx, wxPro
} }
}); });
while (! finished) { while (! finished) {
condition.wait_for(lock, std::chrono::milliseconds(500), [&progress]{ return progress.updated; }); condition.wait_for(lock, std::chrono::milliseconds(250), [&progress]{ return progress.updated; });
// decrease progress.percent value to avoid closing of the progress dialog // decrease progress.percent value to avoid closing of the progress dialog
if (!progress_dialog.Update(progress.percent-1, msg_header + _(progress.message))) if (!progress_dialog.Update(progress.percent-1, msg_header + _(progress.message)))
canceled = true; canceled = true;