diff options
author | Enrico Turri <enricoturri@seznam.cz> | 2019-10-10 15:45:09 +0300 |
---|---|---|
committer | Enrico Turri <enricoturri@seznam.cz> | 2019-10-10 15:45:09 +0300 |
commit | cc34860ddd48fb9c68cb5dc1e2058c61f6c95b32 (patch) | |
tree | 1847edc2c7bfcfe6ceb38cd45000fe8736f3c34a /src | |
parent | e51d970b2e04148e272b3bcab67b14a755f944d2 (diff) | |
parent | 0dfbfa62df47e7552f96f0b2f0359788a241d494 (diff) |
Merge branch 'master' of https://github.com/prusa3d/PrusaSlicer
Diffstat (limited to 'src')
-rw-r--r-- | src/libslic3r/CMakeLists.txt | 2 | ||||
-rw-r--r-- | src/libslic3r/GCode.cpp | 2 | ||||
-rw-r--r-- | src/libslic3r/SLA/ConcaveHull.cpp | 171 | ||||
-rw-r--r-- | src/libslic3r/SLA/ConcaveHull.hpp | 53 | ||||
-rw-r--r-- | src/libslic3r/SLA/SLAPad.cpp | 209 | ||||
-rw-r--r-- | src/libslic3r/SLA/SLASupportTreeBuildsteps.hpp | 2 | ||||
-rw-r--r-- | src/slic3r/GUI/wxExtensions.cpp | 7 |
7 files changed, 251 insertions, 195 deletions
diff --git a/src/libslic3r/CMakeLists.txt b/src/libslic3r/CMakeLists.txt index fe8b0f71d..633549b42 100644 --- a/src/libslic3r/CMakeLists.txt +++ b/src/libslic3r/CMakeLists.txt @@ -194,6 +194,8 @@ add_library(libslic3r STATIC SLA/SLARaster.cpp SLA/SLARasterWriter.hpp SLA/SLARasterWriter.cpp + SLA/ConcaveHull.hpp + SLA/ConcaveHull.cpp ) encoding_check(libslic3r) diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index 65264c9cd..3a72657c3 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -507,7 +507,7 @@ std::string WipeTowerIntegration::prime(GCode &gcodegen) std::string WipeTowerIntegration::tool_change(GCode &gcodegen, int extruder_id, bool finish_layer) { std::string gcode; - assert(m_layer_idx >= 0 && size_t(m_layer_idx) <= m_tool_changes.size()); + assert(m_layer_idx >= 0); if (! m_brim_done || gcodegen.writer().need_toolchange(extruder_id) || finish_layer) { if (m_layer_idx < (int)m_tool_changes.size()) { if (! (size_t(m_tool_change_idx) < m_tool_changes[m_layer_idx].size())) diff --git a/src/libslic3r/SLA/ConcaveHull.cpp b/src/libslic3r/SLA/ConcaveHull.cpp new file mode 100644 index 000000000..dff061721 --- /dev/null +++ b/src/libslic3r/SLA/ConcaveHull.cpp @@ -0,0 +1,171 @@ +#include "ConcaveHull.hpp" +#include <libslic3r/MTUtils.hpp> +#include <libslic3r/ClipperUtils.hpp> +#include "SLASpatIndex.hpp" +#include <boost/log/trivial.hpp> + +namespace Slic3r { +namespace sla { + +inline Vec3d to_vec3(const Vec2crd &v2) { return {double(v2(X)), double(v2(Y)), 0.}; } +inline Vec3d to_vec3(const Vec2d &v2) { return {v2(X), v2(Y), 0.}; } +inline Vec2crd to_vec2(const Vec3d &v3) { return {coord_t(v3(X)), coord_t(v3(Y))}; } + +Point ConcaveHull::centroid(const Points &pp) +{ + Point c; + switch(pp.size()) { + case 0: break; + case 1: c = pp.front(); break; + case 2: c = (pp[0] + pp[1]) / 2; break; + default: { + auto MAX = std::numeric_limits<Point::coord_type>::max(); + auto MIN = std::numeric_limits<Point::coord_type>::min(); + Point min = {MAX, MAX}, max = {MIN, MIN}; + + for(auto& p : pp) { + if(p(0) < min(0)) min(0) = p(0); + if(p(1) < min(1)) min(1) = p(1); + if(p(0) > max(0)) max(0) = p(0); + if(p(1) > max(1)) max(1) = p(1); + } + c(0) = min(0) + (max(0) - min(0)) / 2; + c(1) = min(1) + (max(1) - min(1)) / 2; + break; + } + } + + return c; +} + +// As it shows, the current offset_ex in ClipperUtils hangs if used in jtRound +// mode +ClipperLib::Paths fast_offset(const ClipperLib::Paths &paths, + coord_t delta, + ClipperLib::JoinType jointype) +{ + using ClipperLib::ClipperOffset; + using ClipperLib::etClosedPolygon; + using ClipperLib::Paths; + using ClipperLib::Path; + + ClipperOffset offs; + offs.ArcTolerance = scaled<double>(0.01); + + for (auto &p : paths) + // If the input is not at least a triangle, we can not do this algorithm + if(p.size() < 3) { + BOOST_LOG_TRIVIAL(error) << "Invalid geometry for offsetting!"; + return {}; + } + + offs.AddPaths(paths, jointype, etClosedPolygon); + + Paths result; + offs.Execute(result, static_cast<double>(delta)); + + return result; +} + +Points ConcaveHull::calculate_centroids() const +{ + // We get the centroids of all the islands in the 2D slice + Points centroids = reserve_vector<Point>(m_polys.size()); + std::transform(m_polys.begin(), m_polys.end(), + std::back_inserter(centroids), + [this](const Polygon &poly) { return centroid(poly); }); + + return centroids; +} + +void ConcaveHull::merge_polygons() { m_polys = get_contours(union_ex(m_polys)); } + +void ConcaveHull::add_connector_rectangles(const Points ¢roids, + coord_t max_dist, + ThrowOnCancel thr) +{ + // Centroid of the centroids of islands. This is where the additional + // connector sticks are routed. + Point cc = centroid(centroids); + + PointIndex ctrindex; + unsigned idx = 0; + for(const Point &ct : centroids) ctrindex.insert(to_vec3(ct), idx++); + + m_polys.reserve(m_polys.size() + centroids.size()); + + idx = 0; + for (const Point &c : centroids) { + thr(); + + double dx = c.x() - cc.x(), dy = c.y() - cc.y(); + double l = std::sqrt(dx * dx + dy * dy); + double nx = dx / l, ny = dy / l; + + const Point &ct = centroids[idx]; + + std::vector<PointIndexEl> result = ctrindex.nearest(to_vec3(ct), 2); + + double dist = max_dist; + for (const PointIndexEl &el : result) + if (el.second != idx) { + dist = Line(to_vec2(el.first), ct).length(); + break; + } + + idx++; + + if (dist >= max_dist) return; + + Polygon r; + r.points.reserve(3); + r.points.emplace_back(cc); + + Point n(scaled(nx), scaled(ny)); + r.points.emplace_back(c + Point(n.y(), -n.x())); + r.points.emplace_back(c + Point(-n.y(), n.x())); + offset(r, scaled<float>(1.)); + + m_polys.emplace_back(r); + } +} + +ConcaveHull::ConcaveHull(const Polygons &polys, double mergedist, ThrowOnCancel thr) +{ + if(polys.empty()) return; + + m_polys = polys; + merge_polygons(); + + if(m_polys.size() == 1) return; + + Points centroids = calculate_centroids(); + + add_connector_rectangles(centroids, scaled(mergedist), thr); + + merge_polygons(); +} + +ExPolygons ConcaveHull::to_expolygons() const +{ + auto ret = reserve_vector<ExPolygon>(m_polys.size()); + for (const Polygon &p : m_polys) ret.emplace_back(ExPolygon(p)); + return ret; +} + +ExPolygons offset_waffle_style_ex(const ConcaveHull &hull, coord_t delta) +{ + ClipperLib::Paths paths = Slic3rMultiPoints_to_ClipperPaths(hull.polygons()); + paths = fast_offset(paths, 2 * delta, ClipperLib::jtRound); + paths = fast_offset(paths, -delta, ClipperLib::jtRound); + ExPolygons ret = ClipperPaths_to_Slic3rExPolygons(paths); + for (ExPolygon &p : ret) p.holes = {}; + return ret; +} + +Polygons offset_waffle_style(const ConcaveHull &hull, coord_t delta) +{ + return to_polygons(offset_waffle_style_ex(hull, delta)); +} + +}} // namespace Slic3r::sla diff --git a/src/libslic3r/SLA/ConcaveHull.hpp b/src/libslic3r/SLA/ConcaveHull.hpp new file mode 100644 index 000000000..94e16d77c --- /dev/null +++ b/src/libslic3r/SLA/ConcaveHull.hpp @@ -0,0 +1,53 @@ +#ifndef CONCAVEHULL_HPP +#define CONCAVEHULL_HPP + +#include <libslic3r/ExPolygon.hpp> + +namespace Slic3r { +namespace sla { + +inline Polygons get_contours(const ExPolygons &poly) +{ + Polygons ret; ret.reserve(poly.size()); + for (const ExPolygon &p : poly) ret.emplace_back(p.contour); + + return ret; +} + +using ThrowOnCancel = std::function<void()>; + +/// A fake concave hull that is constructed by connecting separate shapes +/// with explicit bridges. Bridges are generated from each shape's centroid +/// to the center of the "scene" which is the centroid calculated from the shape +/// centroids (a star is created...) +class ConcaveHull { + Polygons m_polys; + + static Point centroid(const Points& pp); + + static inline Point centroid(const Polygon &poly) { return poly.centroid(); } + + Points calculate_centroids() const; + + void merge_polygons(); + + void add_connector_rectangles(const Points ¢roids, + coord_t max_dist, + ThrowOnCancel thr); +public: + + ConcaveHull(const ExPolygons& polys, double merge_dist, ThrowOnCancel thr) + : ConcaveHull{to_polygons(polys), merge_dist, thr} {} + + ConcaveHull(const Polygons& polys, double mergedist, ThrowOnCancel thr); + + const Polygons & polygons() const { return m_polys; } + + ExPolygons to_expolygons() const; +}; + +ExPolygons offset_waffle_style_ex(const ConcaveHull &ccvhull, coord_t delta); +Polygons offset_waffle_style(const ConcaveHull &polys, coord_t delta); + +}} // namespace Slic3r::sla +#endif // CONCAVEHULL_HPP diff --git a/src/libslic3r/SLA/SLAPad.cpp b/src/libslic3r/SLA/SLAPad.cpp index 71f8b1c7f..7cd9eb4e4 100644 --- a/src/libslic3r/SLA/SLAPad.cpp +++ b/src/libslic3r/SLA/SLAPad.cpp @@ -1,6 +1,7 @@ #include "SLAPad.hpp" #include "SLABoilerPlate.hpp" #include "SLASpatIndex.hpp" +#include "ConcaveHull.hpp" #include "boost/log/trivial.hpp" #include "SLABoostAdapter.hpp" @@ -206,36 +207,6 @@ Contour3D inline straight_walls(const Polygon &plate, return walls(plate, plate, lo_z, hi_z, .0 /*offset_diff*/, thr); } -// As it shows, the current offset_ex in ClipperUtils hangs if used in jtRound -// mode -ClipperLib::Paths fast_offset(const ClipperLib::Paths &paths, - coord_t delta, - ClipperLib::JoinType jointype) -{ - using ClipperLib::ClipperOffset; - using ClipperLib::etClosedPolygon; - using ClipperLib::Paths; - using ClipperLib::Path; - - ClipperOffset offs; - offs.ArcTolerance = scaled<double>(0.01); - - for (auto &p : paths) - // If the input is not at least a triangle, we can not do this algorithm - if(p.size() < 3) { - BOOST_LOG_TRIVIAL(error) << "Invalid geometry for offsetting!"; - return {}; - } - - offs.AddPaths(paths, jointype, etClosedPolygon); - - Paths result; - offs.Execute(result, static_cast<double>(delta)); - - return result; -} - - // Function to cut tiny connector cavities for a given polygon. The input poly // will be offsetted by "padding" and small rectangle shaped cavities will be // inserted along the perimeter in every "stride" distance. The stick rectangles @@ -322,158 +293,15 @@ ExPolygons breakstick_holes(const ExPolygons &input, Args...args) return ret; } -/// A fake concave hull that is constructed by connecting separate shapes -/// with explicit bridges. Bridges are generated from each shape's centroid -/// to the center of the "scene" which is the centroid calculated from the shape -/// centroids (a star is created...) -class ConcaveHull { - Polygons m_polys; - - Point centroid(const Points& pp) const - { - Point c; - switch(pp.size()) { - case 0: break; - case 1: c = pp.front(); break; - case 2: c = (pp[0] + pp[1]) / 2; break; - default: { - auto MAX = std::numeric_limits<Point::coord_type>::max(); - auto MIN = std::numeric_limits<Point::coord_type>::min(); - Point min = {MAX, MAX}, max = {MIN, MIN}; - - for(auto& p : pp) { - if(p(0) < min(0)) min(0) = p(0); - if(p(1) < min(1)) min(1) = p(1); - if(p(0) > max(0)) max(0) = p(0); - if(p(1) > max(1)) max(1) = p(1); - } - c(0) = min(0) + (max(0) - min(0)) / 2; - c(1) = min(1) + (max(1) - min(1)) / 2; - break; - } - } - - return c; - } - - inline Point centroid(const Polygon &poly) const { return poly.centroid(); } - - Points calculate_centroids() const - { - // We get the centroids of all the islands in the 2D slice - Points centroids = reserve_vector<Point>(m_polys.size()); - std::transform(m_polys.begin(), m_polys.end(), - std::back_inserter(centroids), - [this](const Polygon &poly) { return centroid(poly); }); - - return centroids; - } - - void merge_polygons() { m_polys = union_(m_polys); } - - void add_connector_rectangles(const Points ¢roids, - coord_t max_dist, - ThrowOnCancel thr) - { - namespace bgi = boost::geometry::index; - using PointIndexElement = std::pair<Point, unsigned>; - using PointIndex = bgi::rtree<PointIndexElement, bgi::rstar<16, 4>>; - - // Centroid of the centroids of islands. This is where the additional - // connector sticks are routed. - Point cc = centroid(centroids); - - PointIndex ctrindex; - unsigned idx = 0; - for(const Point &ct : centroids) - ctrindex.insert(std::make_pair(ct, idx++)); - - m_polys.reserve(m_polys.size() + centroids.size()); - - idx = 0; - for (const Point &c : centroids) { - thr(); - - double dx = c.x() - cc.x(), dy = c.y() - cc.y(); - double l = std::sqrt(dx * dx + dy * dy); - double nx = dx / l, ny = dy / l; - - const Point &ct = centroids[idx]; - - std::vector<PointIndexElement> result; - ctrindex.query(bgi::nearest(ct, 2), std::back_inserter(result)); - - double dist = max_dist; - for (const PointIndexElement &el : result) - if (el.second != idx) { - dist = Line(el.first, ct).length(); - break; - } - - idx++; - - if (dist >= max_dist) return; - - Polygon r; - r.points.reserve(3); - r.points.emplace_back(cc); - - Point d(scaled(nx), scaled(ny)); - r.points.emplace_back(c + Point(-d.y(), d.x())); - r.points.emplace_back(c + Point(d.y(), -d.x())); - offset(r, scaled<float>(1.)); - - m_polys.emplace_back(r); - } - } - -public: - - ConcaveHull(const ExPolygons& polys, double merge_dist, ThrowOnCancel thr) - : ConcaveHull{to_polygons(polys), merge_dist, thr} {} - - ConcaveHull(const Polygons& polys, double mergedist, ThrowOnCancel thr) - { - if(polys.empty()) return; - - m_polys = polys; - merge_polygons(); - - if(m_polys.size() == 1) return; - - Points centroids = calculate_centroids(); - - add_connector_rectangles(centroids, scaled(mergedist), thr); - - merge_polygons(); - } - - // const Polygons & polygons() const { return m_polys; } - - ExPolygons to_expolygons() const - { - auto ret = reserve_vector<ExPolygon>(m_polys.size()); - for (const Polygon &p : m_polys) ret.emplace_back(ExPolygon(p)); - return ret; - } - - void offset_waffle_style(coord_t delta) { - ClipperLib::Paths paths = Slic3rMultiPoints_to_ClipperPaths(m_polys); - paths = fast_offset(paths, 2 * delta, ClipperLib::jtRound); - paths = fast_offset(paths, -delta, ClipperLib::jtRound); - m_polys = ClipperPaths_to_Slic3rPolygons(paths); - } - - static inline coord_t get_waffle_offset(const PadConfig &c) - { - return scaled(c.brim_size_mm + c.wing_distance()); - } +static inline coord_t get_waffle_offset(const PadConfig &c) +{ + return scaled(c.brim_size_mm + c.wing_distance()); +} - static inline double get_merge_distance(const PadConfig &c) - { - return 2. * (1.8 * c.wall_thickness_mm) + c.max_merge_dist_mm; - } -}; +static inline double get_merge_distance(const PadConfig &c) +{ + return 2. * (1.8 * c.wall_thickness_mm) + c.max_merge_dist_mm; +} // Part of the pad configuration that is used for 3D geometry generation struct PadConfig3D { @@ -591,7 +419,7 @@ public: scaled<float>(cfg.embed_object.object_gap_mm), ClipperLib::jtMiter, 1); - ConcaveHull fullcvh = + ExPolygons fullcvh = wafflized_concave_hull(support_blueprint, model_bp_offs, cfg, thr); auto model_bp_sticks = @@ -600,7 +428,7 @@ public: cfg.embed_object.stick_width_mm, cfg.embed_object.stick_penetration_mm); - ExPolygons fullpad = diff_ex(fullcvh.to_expolygons(), model_bp_sticks); + ExPolygons fullpad = diff_ex(fullcvh, model_bp_sticks); remove_redundant_parts(fullpad); @@ -619,7 +447,7 @@ private: // Create the wafflized pad around all object in the scene. This pad doesnt // have any holes yet. - ConcaveHull wafflized_concave_hull(const ExPolygons &supp_bp, + ExPolygons wafflized_concave_hull(const ExPolygons &supp_bp, const ExPolygons &model_bp, const PadConfig &cfg, ThrowOnCancel thr) @@ -629,10 +457,8 @@ private: for (auto &ep : supp_bp) allin.emplace_back(ep.contour); for (auto &ep : model_bp) allin.emplace_back(ep.contour); - ConcaveHull ret{allin, ConcaveHull::get_merge_distance(cfg), thr}; - ret.offset_waffle_style(ConcaveHull::get_waffle_offset(cfg)); - - return ret; + ConcaveHull cchull{allin, get_merge_distance(cfg), thr}; + return offset_waffle_style_ex(cchull, get_waffle_offset(cfg)); } // To remove parts of the pad skeleton which do not host any supports @@ -663,10 +489,9 @@ public: for (auto &ep : support_blueprint) outer.emplace_back(ep.contour); for (auto &ep : model_blueprint) outer.emplace_back(ep.contour); - ConcaveHull ochull{outer, ConcaveHull::get_merge_distance(cfg), thr}; + ConcaveHull ochull{outer, get_merge_distance(cfg), thr}; - ochull.offset_waffle_style(ConcaveHull::get_waffle_offset(cfg)); - outer = ochull.to_expolygons(); + outer = offset_waffle_style_ex(ochull, get_waffle_offset(cfg)); } }; @@ -861,7 +686,7 @@ std::string PadConfig::validate() const if (brim_size_mm < MIN_BRIM_SIZE_MM || bottom_offset() > brim_size_mm + wing_distance() || - ConcaveHull::get_waffle_offset(*this) <= MIN_BRIM_SIZE_MM) + get_waffle_offset(*this) <= MIN_BRIM_SIZE_MM) return L("Pad brim size is too small for the current configuration."); return ""; diff --git a/src/libslic3r/SLA/SLASupportTreeBuildsteps.hpp b/src/libslic3r/SLA/SLASupportTreeBuildsteps.hpp index b92e44dbd..e953cc136 100644 --- a/src/libslic3r/SLA/SLASupportTreeBuildsteps.hpp +++ b/src/libslic3r/SLA/SLASupportTreeBuildsteps.hpp @@ -175,7 +175,7 @@ class SupportTreeBuildsteps { // A spatial index to easily find strong pillars to connect to. PillarIndex m_pillar_index; - + // When bridging heads to pillars... TODO: find a cleaner solution ccr::BlockingMutex m_bridge_mutex; diff --git a/src/slic3r/GUI/wxExtensions.cpp b/src/slic3r/GUI/wxExtensions.cpp index f1b658867..06e37fb4f 100644 --- a/src/slic3r/GUI/wxExtensions.cpp +++ b/src/slic3r/GUI/wxExtensions.cpp @@ -2179,7 +2179,12 @@ wxWindow* BitmapChoiceRenderer::CreateEditorCtrl(wxWindow* parent, wxRect labelR c_editor->SetSelection(atoi(data.GetText().c_str())); // to avoid event propagation to other sidebar items - c_editor->Bind(wxEVT_COMBOBOX, [](wxCommandEvent& evt) { evt.StopPropagation(); }); + c_editor->Bind(wxEVT_COMBOBOX, [this](wxCommandEvent& evt) { + evt.StopPropagation(); + // FinishEditing grabs new selection and triggers config update. We better call + // it explicitly, automatic update on KILL_FOCUS didn't work on Linux. + this->FinishEditing(); + }); return c_editor; } |