diff --git a/doc/How to build - Mac OS.md b/doc/How to build - Mac OS.md index 5c2019454..113c5cec0 100644 --- a/doc/How to build - Mac OS.md +++ b/doc/How to build - Mac OS.md @@ -71,7 +71,7 @@ is currently unsupported because some of the dependencies don't support this, mo Please note that the `CMAKE_OSX_DEPLOYMENT_TARGET` and `CMAKE_OSX_SYSROOT` options need to be set the same on both the dependencies bundle as well as PrusaSlicer itself. -Official Mac PrusaSlicer builds are currently built against SDK 10.9 to ensure compatibility with older Macs. +Official macOS PrusaSlicer builds are currently (as of PrusaSlicer 2.5) built against SDK 10.12 to ensure compatibility with older Macs. _Warning:_ XCode may be set such that it rejects SDKs bellow some version (silently, more or less). This is set in the property list file diff --git a/resources/profiles/RatRig.idx b/resources/profiles/RatRig.idx index a86724f1d..f0c117464 100644 --- a/resources/profiles/RatRig.idx +++ b/resources/profiles/RatRig.idx @@ -1,2 +1,3 @@ min_slic3r_version = 2.4.1-alpha0 +1.0.1 Various fixes and improvements. Commented filament sensor initialisation for v-Minion (optional HW). 1.0.0 Initial RatRig bundle \ No newline at end of file diff --git a/resources/profiles/RatRig.ini b/resources/profiles/RatRig.ini index 69379e781..5558cf698 100644 --- a/resources/profiles/RatRig.ini +++ b/resources/profiles/RatRig.ini @@ -9,7 +9,7 @@ name = RatRig # Configuration version of this file. Config file will only be installed, if the config_version differs. # This means, the server may force the Slic3r configuration to be downgraded. -config_version = 1.0.0 +config_version = 1.0.1 # Where to get the updates from? config_update_url = https://files.prusa3d.com/wp-content/uploads/repository/PrusaSlicer-settings-master/live/RatRig/ # The printer models will be shown by the Configuration Wizard in this order, @@ -25,7 +25,7 @@ technology = FFF family = V-Core-3 bed_model = rr-vc-300.stl bed_texture = rr-vc-300.svg -default_materials = Generic PETG V6 @RatRig; Generic PETG HF @RatRig; Generic PLA @RatRig; Esun ePA-CF @RatRig; Generic ABS @RatRig +default_materials = Generic PETG V6 @RatRig; Generic PETG HF @RatRig; Generic PLA @RatRig; Esun ePA-CF @RatRig; Generic ABS @RatRig; Generic TPU @RatRig [printer_model:VC3_400] name = RatRig V-Core-3 400mm @@ -33,7 +33,7 @@ variants = 0.4 family = V-Core-3 bed_model = rr-vc-400.stl bed_texture = rr-vc-400.svg -default_materials = Generic PETG V6 @RatRig; Generic PETG HF @RatRig; Generic PLA @RatRig; Esun ePA-CF @RatRig; Generic ABS @RatRig +default_materials = Generic PETG V6 @RatRig; Generic PETG HF @RatRig; Generic PLA @RatRig; Esun ePA-CF @RatRig; Generic ABS @RatRig; Generic TPU @RatRig [printer_model:VC3_500] name = RatRig V-Core-3 500mm @@ -41,7 +41,7 @@ variants = 0.4 family = V-Core-3 bed_model = rr-vc-500.stl bed_texture = rr-vc-500.svg -default_materials = Generic PETG V6 @RatRig; Generic PETG HF @RatRig; Generic PLA @RatRig; Esun ePA-CF @RatRig; Generic ABS @RatRig +default_materials = Generic PETG V6 @RatRig; Generic PETG HF @RatRig; Generic PLA @RatRig; Esun ePA-CF @RatRig; Generic ABS @RatRig; Generic TPU @RatRig [printer_model:VMINION] name = RatRig V-Minion @@ -50,7 +50,7 @@ technology = FFF family = V-Minion bed_model = rr-vminion.stl bed_texture = rr-vminion.svg -default_materials = Generic PETG V6 @RatRig; Generic PETG HF @RatRig; Generic PLA @RatRig; @Esun ePA-CF RatRig; Generic ABS @RatRig +default_materials = Generic PETG V6 @RatRig; Generic PETG HF @RatRig; Generic PLA @RatRig; @Esun ePA-CF RatRig; Generic ABS @RatRig; Generic TPU @RatRig [print:*common*] compatible_printers_condition = printer_model=~/.*VC3_.*/ and nozzle_diameter[0]==0.4 @@ -75,7 +75,6 @@ dont_support_bridges = 1 draft_shield = 0 ensure_vertical_shell_thickness = 1 exact_last_layer_height = 0 -external_infill_margin = 150% external_perimeter_extrusion_width = 0.4 external_perimeter_speed = 90% extruder_clearance_height = 25 @@ -116,7 +115,6 @@ notes = only_retract_when_crossing_perimeters = 0 ooze_prevention = 0 output_filename_format = {input_filename_base}_{layer_height}mm_{filament_type[0]}_{print_time}.gcode -over_bridge_flow_ratio = 100% perimeter_acceleration = 3000 perimeter_extruder = 1 perimeter_extrusion_width = 0.4 @@ -163,7 +161,6 @@ support_material_threshold = 65 support_material_with_sheath = 0 support_material_xy_spacing = 60% thin_walls = 0 -threads = 4 top_fill_pattern = monotonic top_infill_extrusion_width = 0.4 top_solid_infill_speed = 60% @@ -437,7 +434,7 @@ retract_speed = 40 silent_mode = 0 single_extruder_multi_material = 0 start_gcode = M190 S0 ; Prevents prusaslicer from prepending m190 to the gcode interfering with the macro\nM109 S0 ; Prevents prusaslicer from prepending m109 to the gcode interfering with the macro\nSTART_PRINT EXTRUDER_TEMP=[first_layer_temperature] BED_TEMP=[first_layer_bed_temperature]\n;enable this if you have a BTT Smart Filament Sensor\nSET_FILAMENT_SENSOR SENSOR=my_sensor ENABLE=0\n -thumbnails = 16x16,220x220 +thumbnails = 64x64,400x300 toolchange_gcode = use_firmware_retraction = 0 use_relative_e_distances = 1 @@ -499,10 +496,10 @@ retract_restart_extra_toolchange = 0 retract_speed = 40 silent_mode = 0 single_extruder_multi_material = 0 -start_gcode = M190 S0 ; Prevents prusaslicer from prepending m190 to the gcode interfering with the macro\nM109 S0 ; Prevents prusaslicer from prepending m109 to the gcode interfering with the macro\nSTART_PRINT EXTRUDER_TEMP=[first_layer_temperature] BED_TEMP=[first_layer_bed_temperature]\n;enable this if you have a BTT Smart Filament Sensor\nSET_FILAMENT_SENSOR SENSOR=my_sensor ENABLE=0\n +start_gcode = M190 S0 ; Prevents prusaslicer from prepending m190 to the gcode interfering with the macro\nM109 S0 ; Prevents prusaslicer from prepending m109 to the gcode interfering with the macro\nSTART_PRINT EXTRUDER_TEMP=[first_layer_temperature] BED_TEMP=[first_layer_bed_temperature]\n;enable this if you have a BTT Smart Filament Sensor\n; SET_FILAMENT_SENSOR SENSOR=my_sensor ENABLE=0\n start_gcode_manual = 0 template_custom_gcode = -thumbnails = 16x16,220x220 +thumbnails = 64x64,400x300 thumbnails_color = #018aff thumbnails_custom_color = 0 thumbnails_with_bed = 1 @@ -744,4 +741,87 @@ min_fan_speed = 0 min_print_speed = 15 slowdown_below_layer_time = 10 start_filament_gcode = "; Filament gcode\nSET_GCODE_OFFSET Z=0.0\n\n{if nozzle_diameter[0]==0.4} SET_PRESSURE_ADVANCE ADVANCE=0.045{elsif nozzle_diameter[0]==0.6}SET_PRESSURE_ADVANCE ADVANCE=0.02{endif}\n\n" -temperature = 270 \ No newline at end of file +temperature = 270 + +[filament:Generic TPU @RatRig] +inherits = Generic PLA @RatRig +bed_temperature = 30 +bridge_fan_speed = 100 +bridge_internal_fan_speed = -1 +chamber_temperature = 0 +compatible_printers = +compatible_printers_condition = +compatible_prints = +compatible_prints_condition = +cooling = 1 +disable_fan_first_layers = 2 +end_filament_gcode = "; Filament-specific end gcode \n;END gcode for filament\n" +external_perimeter_fan_speed = -1 +extrusion_multiplier = 0.89 +fan_always_on = 1 +fan_below_layer_time = 100 +filament_colour = #FF00FF +filament_cooling_final_speed = 3.4 +filament_cooling_initial_speed = 2.2 +filament_cooling_moves = 4 +filament_cooling_zone_pause = 0 +filament_cost = 20 +filament_custom_variables = "" +filament_density = 1.24 +filament_deretract_speed = nil +filament_diameter = 1.75 +filament_dip_extraction_speed = 70 +filament_dip_insertion_speed = 33 +filament_enable_toolchange_part_fan = 0 +filament_enable_toolchange_temp = 0 +filament_load_time = 0 +filament_loading_speed = 28 +filament_loading_speed_start = 3 +filament_max_overlap = 100% +filament_max_speed = 0 +filament_max_volumetric_speed = 5 +filament_max_wipe_tower_speed = 0 +filament_melt_zone_pause = 0 +filament_minimal_purge_on_wipe_tower = 15 +filament_notes = "This is a profile for TPU95A. It was tested with Anycubic TPU95A, but most of the economy TPU filaments behave pretty similar.\n\nYou will want to optimize the temperature. Even different colors of the same brand can require 10° more or less.\n\nIf you experience clogs or grinding, reduce the maximum volumetric speed!" +filament_ramming_parameters = "120 100 6.6 6.8 7.2 7.6 7.9 8.2 8.7 9.4 9.9 10.0| 0.05 6.6 0.45 6.8 0.95 7.8 1.45 8.3 1.95 9.7 2.45 10 2.95 7.6 3.45 7.6 3.95 7.6 4.45 7.6 4.95 7.6" +filament_retract_before_travel = nil +filament_retract_before_wipe = nil +filament_retract_layer_change = nil +filament_retract_length = 1 +filament_retract_lift = 0.1 +filament_retract_lift_above = nil +filament_retract_lift_below = nil +filament_retract_restart_extra = nil +filament_retract_speed = nil +filament_seam_gap = nil +filament_shrink = 100% +filament_skinnydip_distance = 31 +filament_soluble = 0 +filament_spool_weight = 0 +filament_toolchange_delay = 0 +filament_toolchange_part_fan_speed = 50 +filament_toolchange_temp = 200 +filament_type = FLEX +filament_unload_time = 0 +filament_unloading_speed = 90 +filament_unloading_speed_start = 100 +filament_use_fast_skinnydip = 0 +filament_use_skinnydip = 0 +filament_vendor = Generic +filament_wipe = nil +filament_wipe_advanced_pigment = 0.5 +filament_wipe_extra_perimeter = nil +filament_wipe_only_crossing = nil +filament_wipe_speed = nil +first_layer_bed_temperature = 30 +first_layer_temperature = 220 +full_fan_speed_layer = 4 +max_fan_speed = 100 +max_speed_reduction = 95% +min_fan_speed = 100 +min_print_speed = 10 +slowdown_below_layer_time = 8 +start_filament_gcode = "; Filament gcode\nSET_GCODE_OFFSET Z=0\nSET_PRESSURE_ADVANCE ADVANCE=0.1" +temperature = 220 +top_fan_speed = -1 diff --git a/src/libslic3r/ClipperUtils.cpp b/src/libslic3r/ClipperUtils.cpp index d03cb5a70..650cfca15 100644 --- a/src/libslic3r/ClipperUtils.cpp +++ b/src/libslic3r/ClipperUtils.cpp @@ -710,6 +710,8 @@ Slic3r::Polylines diff_pl(const Slic3r::Polygons &subject, const Slic3r::Polygon { return _clipper_pl_closed(ClipperLib::ctDifference, ClipperUtils::PolygonsProvider(subject), ClipperUtils::PolygonsProvider(clip)); } Slic3r::Polylines intersection_pl(const Slic3r::Polylines &subject, const Slic3r::Polygon &clip) { return _clipper_pl_open(ClipperLib::ctIntersection, ClipperUtils::PolylinesProvider(subject), ClipperUtils::SinglePathProvider(clip.points)); } +Slic3r::Polylines intersection_pl(const Slic3r::Polyline &subject, const Slic3r::ExPolygon &clip) + { return _clipper_pl_open(ClipperLib::ctIntersection, ClipperUtils::SinglePathProvider(subject.points), ClipperUtils::ExPolygonProvider(clip)); } Slic3r::Polylines intersection_pl(const Slic3r::Polylines &subject, const Slic3r::ExPolygon &clip) { return _clipper_pl_open(ClipperLib::ctIntersection, ClipperUtils::PolylinesProvider(subject), ClipperUtils::ExPolygonProvider(clip)); } Slic3r::Polylines intersection_pl(const Slic3r::Polyline &subject, const Slic3r::Polygons &clip) diff --git a/src/libslic3r/ClipperUtils.hpp b/src/libslic3r/ClipperUtils.hpp index 0388af9a3..50d96142d 100644 --- a/src/libslic3r/ClipperUtils.hpp +++ b/src/libslic3r/ClipperUtils.hpp @@ -437,6 +437,7 @@ Slic3r::ExPolygons intersection_ex(const Slic3r::Surfaces &subject, const Slic3r Slic3r::ExPolygons intersection_ex(const Slic3r::Surfaces &subject, const Slic3r::Surfaces &clip, ApplySafetyOffset do_safety_offset = ApplySafetyOffset::No); Slic3r::ExPolygons intersection_ex(const Slic3r::SurfacesPtr &subject, const Slic3r::ExPolygons &clip, ApplySafetyOffset do_safety_offset = ApplySafetyOffset::No); Slic3r::Polylines intersection_pl(const Slic3r::Polylines &subject, const Slic3r::Polygon &clip); +Slic3r::Polylines intersection_pl(const Slic3r::Polyline &subject, const Slic3r::ExPolygon &clip); Slic3r::Polylines intersection_pl(const Slic3r::Polylines &subject, const Slic3r::ExPolygon &clip); Slic3r::Polylines intersection_pl(const Slic3r::Polyline &subject, const Slic3r::Polygons &clip); Slic3r::Polylines intersection_pl(const Slic3r::Polyline &subject, const Slic3r::ExPolygons &clip); diff --git a/src/libslic3r/Fill/FillPlanePath.cpp b/src/libslic3r/Fill/FillPlanePath.cpp index 49b02b542..183d4bf96 100644 --- a/src/libslic3r/Fill/FillPlanePath.cpp +++ b/src/libslic3r/Fill/FillPlanePath.cpp @@ -6,6 +6,66 @@ namespace Slic3r { +class InfillPolylineClipper : public FillPlanePath::InfillPolylineOutput { +public: + InfillPolylineClipper(const BoundingBox bbox, const double scale_out) : FillPlanePath::InfillPolylineOutput(scale_out), m_bbox(bbox) {} + + void add_point(const Vec2d &pt); + Points&& result() { return std::move(m_out); } + bool clips() const override { return true; } + +private: + enum class Side { + Left = 1, + Right = 2, + Top = 4, + Bottom = 8 + }; + + int sides(const Point &p) const { + return int(p.x() < m_bbox.min.x()) * int(Side::Left) + + int(p.x() > m_bbox.max.x()) * int(Side::Right) + + int(p.y() < m_bbox.min.y()) * int(Side::Bottom) + + int(p.y() > m_bbox.max.y()) * int(Side::Top); + }; + + // Bounding box to clip the polyline with. + BoundingBox m_bbox; + + // Classification of the two last points processed. + int m_sides_prev; + int m_sides_this; +}; + +void InfillPolylineClipper::add_point(const Vec2d &fpt) +{ + const Point pt{ this->scaled(fpt) }; + + if (m_out.size() < 2) { + // Collect the two first points and their status. + (m_out.empty() ? m_sides_prev : m_sides_this) = sides(pt); + m_out.emplace_back(pt); + } else { + // Classify the last inserted point, possibly remove it. + int sides_next = sides(pt); + if (// This point is inside. Take it. + m_sides_this == 0 || + // Either this point is outside and previous or next is inside, or + // the edge possibly cuts corner of the bounding box. + (m_sides_prev & m_sides_this & sides_next) == 0) { + // Keep the last point. + m_sides_prev = m_sides_this; + } else { + // All the three points (this, prev, next) are outside at the same side. + // Ignore the last point. + m_out.pop_back(); + } + // And save the current point. + m_out.emplace_back(pt); + m_sides_this = sides_next; + } +} + void FillPlanePath::_fill_surface_single( const FillParams ¶ms, unsigned int thickness_layers, @@ -13,37 +73,52 @@ void FillPlanePath::_fill_surface_single( ExPolygon expolygon, Polylines &polylines_out) { - expolygon.rotate(- direction.first); + expolygon.rotate(-direction.first); - coord_t distance_between_lines = coord_t(scale_(this->spacing) / params.density); - - // align infill across layers using the object's bounding box - // Rotated bounding box of the whole object. - BoundingBox bounding_box = this->bounding_box.rotated(- direction.first); - - Point shift = this->_centered() ? + //FIXME Vojtech: We are not sure whether the user expects the fill patterns on visible surfaces to be aligned across all the islands of a single layer. + // One may align for this->centered() to align the patterns for Archimedean Chords and Octagram Spiral patterns. + const bool align = params.density < 0.995; + + BoundingBox snug_bounding_box = get_extents(expolygon).inflated(SCALED_EPSILON); + + // Rotated bounding box of the area to fill in with the pattern. + BoundingBox bounding_box = align ? + // Sparse infill needs to be aligned across layers. Align infill across layers using the object's bounding box. + this->bounding_box.rotated(-direction.first) : + // Solid infill does not need to be aligned across layers, generate the infill pattern + // around the clipping expolygon only. + snug_bounding_box; + + Point shift = this->centered() ? bounding_box.center() : bounding_box.min; expolygon.translate(-shift.x(), -shift.y()); bounding_box.translate(-shift.x(), -shift.y()); - Pointfs pts = _generate( - coord_t(ceil(coordf_t(bounding_box.min.x()) / distance_between_lines)), - coord_t(ceil(coordf_t(bounding_box.min.y()) / distance_between_lines)), - coord_t(ceil(coordf_t(bounding_box.max.x()) / distance_between_lines)), - coord_t(ceil(coordf_t(bounding_box.max.y()) / distance_between_lines)), - params.resolution); + Polyline polyline; + { + auto distance_between_lines = scaled(this->spacing) / params.density; + auto min_x = coord_t(ceil(coordf_t(bounding_box.min.x()) / distance_between_lines)); + auto min_y = coord_t(ceil(coordf_t(bounding_box.min.y()) / distance_between_lines)); + auto max_x = coord_t(ceil(coordf_t(bounding_box.max.x()) / distance_between_lines)); + auto max_y = coord_t(ceil(coordf_t(bounding_box.max.y()) / distance_between_lines)); + auto resolution = scaled(params.resolution) / distance_between_lines; + if (align) { + // Filling in a bounding box over the whole object, clip generated polyline against the snug bounding box. + snug_bounding_box.translate(-shift.x(), -shift.y()); + InfillPolylineClipper output(snug_bounding_box, distance_between_lines); + this->generate(min_x, min_y, max_x, max_y, resolution, output); + polyline.points = std::move(output.result()); + } else { + // Filling in a snug bounding box, no need to clip. + InfillPolylineOutput output(distance_between_lines); + this->generate(min_x, min_y, max_x, max_y, resolution, output); + polyline.points = std::move(output.result()); + } + } - if (pts.size() >= 2) { - // Convert points to a polyline, upscale. - Polylines polylines(1, Polyline()); - Polyline &polyline = polylines.front(); - polyline.points.reserve(pts.size()); - for (const Vec2d &pt : pts) - polyline.points.emplace_back( - coord_t(floor(pt.x() * distance_between_lines + 0.5)), - coord_t(floor(pt.y() * distance_between_lines + 0.5))); - polylines = intersection_pl(polylines, expolygon); + if (polyline.size() >= 2) { + Polylines polylines = intersection_pl(polyline, expolygon); Polylines chained; if (params.dont_connect() || params.density > 0.5 || polylines.size() <= 1) chained = chain_polylines(std::move(polylines)); @@ -59,7 +134,8 @@ void FillPlanePath::_fill_surface_single( } // Follow an Archimedean spiral, in polar coordinates: r=a+b\theta -Pointfs FillArchimedeanChords::_generate(coord_t min_x, coord_t min_y, coord_t max_x, coord_t max_y, const double resolution) +template +static void generate_archimedean_chords(coord_t min_x, coord_t min_y, coord_t max_x, coord_t max_y, const double resolution, Output &output) { // Radius to achieve. coordf_t rmax = std::sqrt(coordf_t(max_x)*coordf_t(max_x)+coordf_t(max_y)*coordf_t(max_y)) * std::sqrt(2.) + 1.5; @@ -70,15 +146,22 @@ Pointfs FillArchimedeanChords::_generate(coord_t min_x, coord_t min_y, coord_t m coordf_t r = 1; Pointfs out; //FIXME Vojtech: If used as a solid infill, there is a gap left at the center. - out.emplace_back(0, 0); - out.emplace_back(1, 0); + output.add_point({ 0, 0 }); + output.add_point({ 1, 0 }); while (r < rmax) { // Discretization angle to achieve a discretization error lower than resolution. theta += 2. * acos(1. - resolution / r); r = a + b * theta; - out.emplace_back(r * cos(theta), r * sin(theta)); + output.add_point({ r * cos(theta), r * sin(theta) }); } - return out; +} + +void FillArchimedeanChords::generate(coord_t min_x, coord_t min_y, coord_t max_x, coord_t max_y, const double resolution, InfillPolylineOutput &output) +{ + if (output.clips()) + generate_archimedean_chords(min_x, min_y, max_x, max_y, resolution, static_cast(output)); + else + generate_archimedean_chords(min_x, min_y, max_x, max_y, resolution, output); } // Adapted from @@ -126,7 +209,8 @@ static inline Point hilbert_n_to_xy(const size_t n) return Point(x, y); } -Pointfs FillHilbertCurve::_generate(coord_t min_x, coord_t min_y, coord_t max_x, coord_t max_y, const double /* resolution */) +template +static void generate_hilbert_curve(coord_t min_x, coord_t min_y, coord_t max_x, coord_t max_y, Output &output) { // Minimum power of two square to fit the domain. size_t sz = 2; @@ -140,46 +224,59 @@ Pointfs FillHilbertCurve::_generate(coord_t min_x, coord_t min_y, coord_t max_x, } size_t sz2 = sz * sz; - Pointfs line; - line.reserve(sz2); + output.reserve(sz2); for (size_t i = 0; i < sz2; ++ i) { Point p = hilbert_n_to_xy(i); - line.emplace_back(p.x() + min_x, p.y() + min_y); + output.add_point({ p.x() + min_x, p.y() + min_y }); } - return line; } -Pointfs FillOctagramSpiral::_generate(coord_t min_x, coord_t min_y, coord_t max_x, coord_t max_y, const double /* resolution */) +void FillHilbertCurve::generate(coord_t min_x, coord_t min_y, coord_t max_x, coord_t max_y, const double /* resolution */, InfillPolylineOutput &output) +{ + if (output.clips()) + generate_hilbert_curve(min_x, min_y, max_x, max_y, static_cast(output)); + else + generate_hilbert_curve(min_x, min_y, max_x, max_y, output); +} + +template +static void generate_octagram_spiral(coord_t min_x, coord_t min_y, coord_t max_x, coord_t max_y, Output &output) { // Radius to achieve. coordf_t rmax = std::sqrt(coordf_t(max_x)*coordf_t(max_x)+coordf_t(max_y)*coordf_t(max_y)) * std::sqrt(2.) + 1.5; // Now unwind the spiral. coordf_t r = 0; coordf_t r_inc = sqrt(2.); - Pointfs out; - out.emplace_back(0., 0.); + output.add_point({ 0., 0. }); while (r < rmax) { r += r_inc; coordf_t rx = r / sqrt(2.); coordf_t r2 = r + rx; - out.emplace_back( r, 0.); - out.emplace_back( r2, rx); - out.emplace_back( rx, rx); - out.emplace_back( rx, r2); - out.emplace_back( 0., r); - out.emplace_back(-rx, r2); - out.emplace_back(-rx, rx); - out.emplace_back(-r2, rx); - out.emplace_back(- r, 0.); - out.emplace_back(-r2, -rx); - out.emplace_back(-rx, -rx); - out.emplace_back(-rx, -r2); - out.emplace_back( 0., -r); - out.emplace_back( rx, -r2); - out.emplace_back( rx, -rx); - out.emplace_back( r2+r_inc, -rx); + output.add_point({ r, 0. }); + output.add_point({ r2, rx }); + output.add_point({ rx, rx }); + output.add_point({ rx, r2 }); + output.add_point({ 0., r }); + output.add_point({-rx, r2 }); + output.add_point({-rx, rx }); + output.add_point({-r2, rx }); + output.add_point({- r, 0. }); + output.add_point({-r2, -rx }); + output.add_point({-rx, -rx }); + output.add_point({-rx, -r2 }); + output.add_point({ 0., -r }); + output.add_point({ rx, -r2 }); + output.add_point({ rx, -rx }); + output.add_point({ r2+r_inc, -rx }); } - return out; +} + +void FillOctagramSpiral::generate(coord_t min_x, coord_t min_y, coord_t max_x, coord_t max_y, const double /* resolution */, InfillPolylineOutput &output) +{ + if (output.clips()) + generate_octagram_spiral(min_x, min_y, max_x, max_y, static_cast(output)); + else + generate_octagram_spiral(min_x, min_y, max_x, max_y, output); } } // namespace Slic3r diff --git a/src/libslic3r/Fill/FillPlanePath.hpp b/src/libslic3r/Fill/FillPlanePath.hpp index 075f17433..4c6539f96 100644 --- a/src/libslic3r/Fill/FillPlanePath.hpp +++ b/src/libslic3r/Fill/FillPlanePath.hpp @@ -27,8 +27,30 @@ protected: Polylines &polylines_out) override; float _layer_angle(size_t idx) const override { return 0.f; } - virtual bool _centered() const = 0; - virtual Pointfs _generate(coord_t min_x, coord_t min_y, coord_t max_x, coord_t max_y, const double resolution) = 0; + virtual bool centered() const = 0; + + friend class InfillPolylineClipper; + class InfillPolylineOutput { + public: + InfillPolylineOutput(const double scale_out) : m_scale_out(scale_out) {} + + void reserve(size_t n) { m_out.reserve(n); } + void add_point(const Vec2d& pt) { m_out.emplace_back(this->scaled(pt)); } + Points&& result() { return std::move(m_out); } + virtual bool clips() const { return false; } + + protected: + const Point scaled(const Vec2d &fpt) const { return { coord_t(floor(fpt.x() * m_scale_out + 0.5)), coord_t(floor(fpt.y() * m_scale_out + 0.5)) }; } + + // Output polyline. + Points m_out; + + private: + // Scaling coefficient of the generated points before tested against m_bbox and clipped by bbox. + double m_scale_out; + }; + + virtual void generate(coord_t min_x, coord_t min_y, coord_t max_x, coord_t max_y, const double resolution, InfillPolylineOutput &output) = 0; }; class FillArchimedeanChords : public FillPlanePath @@ -38,8 +60,8 @@ public: ~FillArchimedeanChords() override = default; protected: - bool _centered() const override { return true; } - Pointfs _generate(coord_t min_x, coord_t min_y, coord_t max_x, coord_t max_y, const double resolution) override; + bool centered() const override { return true; } + void generate(coord_t min_x, coord_t min_y, coord_t max_x, coord_t max_y, const double resolution, InfillPolylineOutput &output) override; }; class FillHilbertCurve : public FillPlanePath @@ -49,8 +71,8 @@ public: ~FillHilbertCurve() override = default; protected: - bool _centered() const override { return false; } - Pointfs _generate(coord_t min_x, coord_t min_y, coord_t max_x, coord_t max_y, const double resolution) override; + bool centered() const override { return false; } + void generate(coord_t min_x, coord_t min_y, coord_t max_x, coord_t max_y, const double resolution, InfillPolylineOutput &output) override; }; class FillOctagramSpiral : public FillPlanePath @@ -60,8 +82,8 @@ public: ~FillOctagramSpiral() override = default; protected: - bool _centered() const override { return true; } - Pointfs _generate(coord_t min_x, coord_t min_y, coord_t max_x, coord_t max_y, const double resolution) override; + bool centered() const override { return true; } + void generate(coord_t min_x, coord_t min_y, coord_t max_x, coord_t max_y, const double resolution, InfillPolylineOutput &output) override; }; } // namespace Slic3r diff --git a/src/libslic3r/GCode/GCodeProcessor.cpp b/src/libslic3r/GCode/GCodeProcessor.cpp index 3bc1f622d..c82fd38e5 100644 --- a/src/libslic3r/GCode/GCodeProcessor.cpp +++ b/src/libslic3r/GCode/GCodeProcessor.cpp @@ -199,9 +199,7 @@ void GCodeProcessor::TimeMachine::reset() max_travel_acceleration = 0.0f; extrude_factor_override_percentage = 1.0f; time = 0.0f; -#if ENABLE_TRAVEL_TIME travel_time = 0.0f; -#endif // ENABLE_TRAVEL_TIME stop_times = std::vector(); curr.reset(); prev.reset(); @@ -317,17 +315,12 @@ void GCodeProcessor::TimeMachine::calculate_time(size_t keep_last_n_blocks, floa block_time += additional_time; time += block_time; -#if ENABLE_TRAVEL_TIME if (block.move_type == EMoveType::Travel) travel_time += block_time; else roles_time[static_cast(block.role)] += block_time; -#endif // ENABLE_TRAVEL_TIME gcode_time.cache += block_time; moves_time[static_cast(block.move_type)] += block_time; -#if !ENABLE_TRAVEL_TIME - roles_time[static_cast(block.role)] += block_time; -#endif // !ENABLE_TRAVEL_TIME if (block.layer_id >= layers_time.size()) { const size_t curr_size = layers_time.size(); layers_time.resize(block.layer_id); @@ -1465,7 +1458,6 @@ std::string GCodeProcessor::get_time_dhm(PrintEstimatedStatistics::ETimeMode mod return (mode < PrintEstimatedStatistics::ETimeMode::Count) ? short_time(get_time_dhms(m_time_processor.machines[static_cast(mode)].time)) : std::string("N/A"); } -#if ENABLE_TRAVEL_TIME float GCodeProcessor::get_travel_time(PrintEstimatedStatistics::ETimeMode mode) const { return (mode < PrintEstimatedStatistics::ETimeMode::Count) ? m_time_processor.machines[static_cast(mode)].travel_time : 0.0f; @@ -1475,7 +1467,6 @@ std::string GCodeProcessor::get_travel_time_dhm(PrintEstimatedStatistics::ETimeM { return (mode < PrintEstimatedStatistics::ETimeMode::Count) ? short_time(get_time_dhms(m_time_processor.machines[static_cast(mode)].travel_time)) : std::string("N/A"); } -#endif // ENABLE_TRAVEL_TIME std::vector>> GCodeProcessor::get_custom_gcode_times(PrintEstimatedStatistics::ETimeMode mode, bool include_remaining) const { @@ -4327,9 +4318,7 @@ void GCodeProcessor::update_estimated_times_stats() auto update_mode = [this](PrintEstimatedStatistics::ETimeMode mode) { PrintEstimatedStatistics::Mode& data = m_result.print_statistics.modes[static_cast(mode)]; data.time = get_time(mode); -#if ENABLE_TRAVEL_TIME data.travel_time = get_travel_time(mode); -#endif // ENABLE_TRAVEL_TIME data.custom_gcode_times = get_custom_gcode_times(mode, true); data.moves_times = get_moves_time(mode); data.roles_times = get_roles_time(mode); diff --git a/src/libslic3r/GCode/GCodeProcessor.hpp b/src/libslic3r/GCode/GCodeProcessor.hpp index a7bf0cd07..37c0eda41 100644 --- a/src/libslic3r/GCode/GCodeProcessor.hpp +++ b/src/libslic3r/GCode/GCodeProcessor.hpp @@ -44,9 +44,7 @@ namespace Slic3r { struct Mode { float time; -#if ENABLE_TRAVEL_TIME float travel_time; -#endif // ENABLE_TRAVEL_TIME std::vector>> custom_gcode_times; std::vector> moves_times; std::vector> roles_times; @@ -54,9 +52,7 @@ namespace Slic3r { void reset() { time = 0.0f; -#if ENABLE_TRAVEL_TIME travel_time = 0.0f; -#endif // ENABLE_TRAVEL_TIME custom_gcode_times.clear(); moves_times.clear(); roles_times.clear(); @@ -307,9 +303,7 @@ namespace Slic3r { float max_travel_acceleration; // mm/s^2 float extrude_factor_override_percentage; float time; // s -#if ENABLE_TRAVEL_TIME float travel_time; // s -#endif // ENABLE_TRAVEL_TIME struct StopTime { unsigned int g1_line_id; @@ -635,10 +629,8 @@ namespace Slic3r { float get_time(PrintEstimatedStatistics::ETimeMode mode) const; std::string get_time_dhm(PrintEstimatedStatistics::ETimeMode mode) const; -#if ENABLE_TRAVEL_TIME float get_travel_time(PrintEstimatedStatistics::ETimeMode mode) const; std::string get_travel_time_dhm(PrintEstimatedStatistics::ETimeMode mode) const; -#endif // ENABLE_TRAVEL_TIME std::vector>> get_custom_gcode_times(PrintEstimatedStatistics::ETimeMode mode, bool include_remaining) const; std::vector> get_moves_time(PrintEstimatedStatistics::ETimeMode mode) const; diff --git a/src/libslic3r/Technologies.hpp b/src/libslic3r/Technologies.hpp index 5a060db09..5e4118408 100644 --- a/src/libslic3r/Technologies.hpp +++ b/src/libslic3r/Technologies.hpp @@ -39,12 +39,6 @@ //==================== #define ENABLE_2_5_0_ALPHA1 1 -// Enable changes in preview layout -#define ENABLE_PREVIEW_LAYOUT (1 && ENABLE_2_5_0_ALPHA1) -// Enable drawing the items in legend toolbar using icons -#define ENABLE_LEGEND_TOOLBAR_ICONS (1 && ENABLE_PREVIEW_LAYOUT) -// Enable showing time estimate for travel moves in legend -#define ENABLE_TRAVEL_TIME (1 && ENABLE_2_5_0_ALPHA1) // Enable removal of wipe tower magic object_id equal to 1000 #define ENABLE_WIPETOWER_OBJECTID_1000_REMOVAL (1 && ENABLE_2_5_0_ALPHA1) // Enable removal of legacy OpenGL calls diff --git a/src/libslic3r/TreeSupport.cpp b/src/libslic3r/TreeSupport.cpp index 4892564b5..c408b2f85 100644 --- a/src/libslic3r/TreeSupport.cpp +++ b/src/libslic3r/TreeSupport.cpp @@ -174,7 +174,7 @@ static std::vector>> group_me std::vector>> grouped_meshes; //FIXME this is ugly, it does not belong here. - for (size_t object_id = 0; object_id < print_object_ids.size(); ++ object_id) { + for (size_t object_id : print_object_ids) { const PrintObject &print_object = *print.get_object(object_id); const PrintObjectConfig &object_config = print_object.config(); if (object_config.support_material_contact_distance < EPSILON) @@ -186,7 +186,7 @@ static std::vector>> group_me // Group all meshes that can be processed together. NOTE this is different from mesh-groups! Only one setting object is needed per group, // as different settings in the same group may only occur in the tip, which uses the original settings objects from the meshes. - for (size_t object_id = 0; object_id < print_object_ids.size(); ++ object_id) { + for (size_t object_id : print_object_ids) { const PrintObject &print_object = *print.get_object(object_id); #ifndef NDEBUG const PrintObjectConfig &object_config = print_object.config(); @@ -868,6 +868,7 @@ inline SupportGeneratorLayer& layer_allocate( return layer_initialize(layer_storage.back(), layer_type, slicing_params, layer_idx); } +using SupportElements = std::deque; /*! * \brief Creates the initial influence areas (that can later be propagated down) by placing them below the overhang. * @@ -878,14 +879,14 @@ inline SupportGeneratorLayer& layer_allocate( * \param storage[in] Background storage, required for adding roofs. */ static void generate_initial_areas( - const PrintObject &print_object, - const TreeModelVolumes &volumes, - const TreeSupportSettings &config, - const std::vector &overhangs, - std::vector> &move_bounds, - SupportGeneratorLayersPtr &top_contacts, - SupportGeneratorLayersPtr &top_interface_layers, - SupportGeneratorLayerStorage &layer_storage) + const PrintObject &print_object, + const TreeModelVolumes &volumes, + const TreeSupportSettings &config, + const std::vector &overhangs, + std::vector &move_bounds, + SupportGeneratorLayersPtr &top_contacts, + SupportGeneratorLayersPtr &top_interface_layers, + SupportGeneratorLayerStorage &layer_storage) { using AvoidanceType = TreeModelVolumes::AvoidanceType; static constexpr const auto base_radius = scaled(0.01); @@ -950,10 +951,9 @@ static void generate_initial_areas( // take the least restrictive avoidance possible Polygons relevant_forbidden; { - const Polygons &relevant_forbidden_raw = (mesh_config.support_rests_on_model ? - (SUPPORT_TREE_ONLY_GRACIOUS_TO_MODEL ? volumes.getAvoidance(mesh_config.getRadius(0), layer_idx, AvoidanceType::Fast, true, min_xy_dist) : - volumes.getCollision(mesh_config.getRadius(0), layer_idx, min_xy_dist)) : - volumes.getAvoidance(mesh_config.getRadius(0), layer_idx, AvoidanceType::Fast, false, min_xy_dist)); + const Polygons &relevant_forbidden_raw = mesh_config.support_rests_on_model ? + volumes.getCollision(mesh_config.getRadius(0), layer_idx, min_xy_dist) : + volumes.getAvoidance(mesh_config.getRadius(0), layer_idx, AvoidanceType::Fast, false, min_xy_dist); // prevent rounding errors down the line, points placed directly on the line of the forbidden area may not be added otherwise. relevant_forbidden = offset(union_ex(relevant_forbidden_raw), scaled(0.005), jtMiter, 1.2); } @@ -991,7 +991,7 @@ static void generate_initial_areas( state.target_height = insert_layer; state.target_position = p.first; state.next_position = p.first; - state.next_height = insert_layer; + state.layer_idx = insert_layer; state.effective_radius_height = dtt; state.to_buildplate = to_bp; state.distance_to_top = dtt; @@ -1006,7 +1006,7 @@ static void generate_initial_areas( state.can_use_safe_radius = safe_radius; state.missing_roof_layers = force_tip_to_roof ? dont_move_until : 0; state.skip_ovalisation = skip_ovalisation; - move_bounds[insert_layer].emplace(new SupportElement(state, std::move(circle))); + move_bounds[insert_layer].emplace_back(state, std::move(circle)); } } }; @@ -1134,10 +1134,9 @@ static void generate_initial_areas( } for (size_t lag_ctr = 1; lag_ctr <= max_overhang_insert_lag && !overhang_lines.empty() && layer_idx - coord_t(lag_ctr) >= 1; lag_ctr++) { // get least restricted avoidance for layer_idx-lag_ctr - const Polygons &relevant_forbidden_below = (mesh_config.support_rests_on_model ? - (SUPPORT_TREE_ONLY_GRACIOUS_TO_MODEL ? volumes.getAvoidance(mesh_config.getRadius(0), layer_idx - lag_ctr, AvoidanceType::Fast, true, min_xy_dist) : - volumes.getCollision(mesh_config.getRadius(0), layer_idx - lag_ctr, min_xy_dist)) : - volumes.getAvoidance(mesh_config.getRadius(0), layer_idx - lag_ctr, AvoidanceType::Fast, false, min_xy_dist)); + const Polygons &relevant_forbidden_below = mesh_config.support_rests_on_model ? + volumes.getCollision(mesh_config.getRadius(0), layer_idx - lag_ctr, min_xy_dist) : + volumes.getAvoidance(mesh_config.getRadius(0), layer_idx - lag_ctr, AvoidanceType::Fast, false, min_xy_dist); // it is not required to offset the forbidden area here as the points wont change: If points here are not inside the forbidden area neither will they be later when placing these points, as these are the same points. auto evaluatePoint = [&](std::pair p) { return contains(relevant_forbidden_below, p.first); }; @@ -1193,9 +1192,7 @@ static void generate_initial_areas( Polygons forbidden_next; { const Polygons &forbidden_next_raw = mesh_config.support_rests_on_model ? - (SUPPORT_TREE_ONLY_GRACIOUS_TO_MODEL ? - volumes.getAvoidance(mesh_config.getRadius(0), layer_idx - (dtt_roof + 1), AvoidanceType::Fast, true, min_xy_dist) : - volumes.getCollision(mesh_config.getRadius(0), layer_idx - (dtt_roof + 1), min_xy_dist)) : + volumes.getCollision(mesh_config.getRadius(0), layer_idx - (dtt_roof + 1), min_xy_dist) : volumes.getAvoidance(mesh_config.getRadius(0), layer_idx - (dtt_roof + 1), AvoidanceType::Fast, false, min_xy_dist); // prevent rounding errors down the line //FIXME maybe use SafetyOffset::Yes at the following diff() instead? @@ -1390,6 +1387,13 @@ static unsigned int move_inside(const Polygons &polygons, Point &from, int dista return -1; } +static Point move_inside_if_outside(const Polygons &polygons, Point from, int distance = 0, int64_t maxDist2 = std::numeric_limits::max()) +{ + if (! contains(polygons, from)) + move_inside(polygons, from); + return from; +} + /*! * \brief Checks if an influence area contains a valid subsection and returns the corresponding metadata and the new Influence area. * @@ -1558,24 +1562,24 @@ struct SupportElementInfluenceAreas { }; struct SupportElementMerging { - SupportElementState state; + SupportElementState state; /*! * \brief All elements in the layer above the current one that are supported by this element */ - boost::container::small_vector parents; + SupportElement::ParentIndices parents; - SupportElementInfluenceAreas areas; + SupportElementInfluenceAreas areas; // Bounding box of all influence areas. - Eigen::AlignedBox bbox_data; + Eigen::AlignedBox bbox_data; - const Eigen::AlignedBox& bbox() const { return bbox_data;} - const Point centroid() const { return (bbox_data.min() + bbox_data.max()) / 2; } - void set_bbox(const BoundingBox& abbox) + const Eigen::AlignedBox& bbox() const { return bbox_data;} + const Point centroid() const { return (bbox_data.min() + bbox_data.max()) / 2; } + void set_bbox(const BoundingBox& abbox) { Point eps { coord_t(SCALED_EPSILON), coord_t(SCALED_EPSILON) }; bbox_data = { abbox.min - eps, abbox.max + eps }; } // Called by the AABBTree builder to get an index into the vector of source elements. // Not needed, thus zero is returned. - static size_t idx() { return 0; } + static size_t idx() { return 0; } }; // #define TREESUPPORT_DEBUG_SVG @@ -1599,8 +1603,16 @@ struct SupportElementMerging { * \param mergelayer[in] Will the merge method be called on this layer. This information is required as some calculation can be avoided if they are not required for merging. */ static void increase_areas_one_layer( - const TreeModelVolumes &volumes, const TreeSupportSettings &config, - std::vector &merging_areas, const LayerIndex layer_idx, const bool mergelayer) + const TreeModelVolumes &volumes, + const TreeSupportSettings &config, + // New areas at the layer below layer_idx + std::vector &merging_areas, + // Layer above merging_areas. + const LayerIndex layer_idx, + // Layer elements above merging_areas. + SupportElements &layer_elements, + // If false, the merging_areas will not be merged for performance reasons. + const bool mergelayer) { using AvoidanceType = TreeModelVolumes::AvoidanceType; @@ -1609,7 +1621,7 @@ static void increase_areas_one_layer( for (size_t merging_area_idx = range.begin(); merging_area_idx < range.end(); ++ merging_area_idx) { SupportElementMerging &merging_area = merging_areas[merging_area_idx]; assert(merging_area.parents.size() == 1); - SupportElement &parent = *merging_area.parents.front(); + SupportElement &parent = layer_elements[merging_area.parents.front()]; SupportElementState elem = SupportElementState::propagate_down(parent.state); const Polygons &wall_restriction = // Abstract representation of the model outline. If an influence area would move through it, it could teleport through a wall. @@ -1786,10 +1798,10 @@ static void increase_areas_one_layer( BOOST_LOG_TRIVIAL(warning) #endif // TREE_SUPPORT_SHOW_ERRORS << "Influence area could not be increased! Data about the Influence area: " - "Radius: " << radius << " at layer: " << layer_idx - 1 << " NextTarget: " << elem.next_height << " Distance to top: " << elem.distance_to_top << + "Radius: " << radius << " at layer: " << layer_idx - 1 << " NextTarget: " << elem.layer_idx << " Distance to top: " << elem.distance_to_top << " Elephant foot increases " << elem.elephant_foot_increases << " use_min_xy_dist " << elem.use_min_xy_dist << " to buildplate " << elem.to_buildplate << " gracious " << elem.to_model_gracious << " safe " << elem.can_use_safe_radius << " until move " << elem.dont_move_until << " \n " - "Parent " << &parent << ": Radius: " << config.getCollisionRadius(parent.state) << " at layer: " << layer_idx << " NextTarget: " << parent.state.next_height << + "Parent " << &parent << ": Radius: " << config.getCollisionRadius(parent.state) << " at layer: " << layer_idx << " NextTarget: " << parent.state.layer_idx << " Distance to top: " << parent.state.distance_to_top << " Elephant foot increases " << parent.state.elephant_foot_increases << " use_min_xy_dist " << parent.state.use_min_xy_dist << " to buildplate " << parent.state.to_buildplate << " gracious " << parent.state.to_model_gracious << " safe " << parent.state.can_use_safe_radius << " until move " << parent.state.dont_move_until; tree_supports_show_error("Potentially lost branch!", true); @@ -1852,12 +1864,12 @@ static void increase_areas_one_layer( } [[nodiscard]] static SupportElementState merge_support_element_states( - const SupportElementState &first, const SupportElementState &second, const Point &next_position, const coord_t next_height, + const SupportElementState &first, const SupportElementState &second, const Point &next_position, const coord_t layer_idx, const TreeSupportSettings &config) { SupportElementState out; - out.next_position = next_position; - out.next_height = next_height; + out.next_position = next_position; + out.layer_idx = layer_idx; out.use_min_xy_dist = first.use_min_xy_dist || second.use_min_xy_dist; out.supports_roof = first.supports_roof || second.supports_roof; out.dont_move_until = std::max(first.dont_move_until, second.dont_move_until); @@ -1998,9 +2010,7 @@ static bool merge_influence_areas_two_elements( // calculate which point is closest to the point of the last merge (or tip center if no merge above it has happened) // used at the end to estimate where to best place the branch on the bottom most layer // could be replaced with a random point inside the new area - Point new_pos = dst.state.next_position; - if (! contains(intersect, new_pos)) - move_inside(intersect, new_pos); + Point new_pos = move_inside_if_outside(intersect, dst.state.next_position); SupportElementState new_state = merge_support_element_states(dst.state, src.state, new_pos, layer_idx - 1, config); new_state.increased_to_model_radius = increased_to_model_radius == 0 ? @@ -2232,7 +2242,7 @@ static void merge_influence_areas( * * \param move_bounds[in,out] All currently existing influence areas */ -static void create_layer_pathing(const TreeModelVolumes &volumes, const TreeSupportSettings &config, std::vector> &move_bounds) +static void create_layer_pathing(const TreeModelVolumes &volumes, const TreeSupportSettings &config, std::vector &move_bounds) { #ifdef SLIC3R_TREESUPPORTS_PROGRESS const double data_size_inverse = 1 / double(move_bounds.size()); @@ -2251,7 +2261,7 @@ static void create_layer_pathing(const TreeModelVolumes &volumes, const TreeSupp // Calculate the influence areas for each layer below (Top down) // This is done by first increasing the influence area by the allowed movement distance, and merging them with other influence areas if possible for (int layer_idx = int(move_bounds.size()) - 1; layer_idx > 0; -- layer_idx) - if (const std::set &prev_layer = move_bounds[layer_idx]; ! prev_layer.empty()) { + if (SupportElements &prev_layer = move_bounds[layer_idx]; ! prev_layer.empty()) { // merging is expensive and only parallelized to a max speedup of 2. As such it may be useful in some cases to only merge every few layers to improve performance. bool had_new_element = new_element; const bool merge_this_layer = had_new_element || size_t(last_merge_layer_idx - layer_idx) >= merge_every_x_layers; @@ -2262,17 +2272,17 @@ static void create_layer_pathing(const TreeModelVolumes &volumes, const TreeSupp // ### Increase the influence areas by the allowed movement distance std::vector influence_areas; influence_areas.reserve(prev_layer.size()); - std::transform(prev_layer.begin(), prev_layer.end(), std::back_inserter(influence_areas), - [](SupportElement* el) { - assert(! el->influence_area.empty()); - boost::container::small_vector parents; - parents.emplace_back(el); - return SupportElementMerging{ el->state, parents }; - }); - increase_areas_one_layer(volumes, config, influence_areas, layer_idx, merge_this_layer); + for (int32_t element_idx = 0; element_idx < int32_t(prev_layer.size()); ++ element_idx) { + SupportElement &el = prev_layer[element_idx]; + assert(!el.influence_area.empty()); + SupportElement::ParentIndices parents; + parents.emplace_back(element_idx); + influence_areas.push_back({ el.state, parents }); + } + increase_areas_one_layer(volumes, config, influence_areas, layer_idx, prev_layer, merge_this_layer); // Place already fully constructed elements to the output, remove them from influence_areas. - std::set &this_layer = move_bounds[layer_idx - 1]; + SupportElements &this_layer = move_bounds[layer_idx - 1]; influence_areas.erase(std::remove_if(influence_areas.begin(), influence_areas.end(), [&this_layer, layer_idx](SupportElementMerging &elem) { if (elem.areas.influence_areas.empty()) @@ -2284,7 +2294,7 @@ static void create_layer_pathing(const TreeModelVolumes &volumes, const TreeSupp tree_supports_show_error("Insert error of area after bypassing merge.\n", true); } // Move the area to output. - this_layer.emplace(new SupportElement(elem.state, std::move(elem.parents), std::move(elem.areas.influence_areas))); + this_layer.emplace_back(elem.state, std::move(elem.parents), std::move(elem.areas.influence_areas)); return true; } // Keep the area. @@ -2316,7 +2326,7 @@ static void create_layer_pathing(const TreeModelVolumes &volumes, const TreeSupp BOOST_LOG_TRIVIAL(error) << "Insert Error of Influence area on layer " << layer_idx - 1 << ". Origin of " << elem.parents.size() << " areas. Was to bp " << elem.state.to_buildplate; tree_supports_show_error("Insert error of area after merge.\n", true); } - this_layer.emplace(new SupportElement(elem.state, std::move(elem.parents), std::move(new_area))); + this_layer.emplace_back(elem.state, std::move(elem.parents), std::move(new_area)); } #ifdef SLIC3R_TREESUPPORTS_PROGRESS @@ -2334,102 +2344,134 @@ static void create_layer_pathing(const TreeModelVolumes &volumes, const TreeSupp * * \param elem[in] The SupportElements, which parent's position should be determined. */ -static void set_points_on_areas(const SupportElement* elem) +static void set_points_on_areas(const SupportElement &elem, SupportElements *layer_above) { - // Based on the branch center point of the current layer, the point on the next (further up) layer is calculated. + assert(!elem.state.deleted); + assert(layer_above != nullptr || elem.parents.empty()); - if (! elem->state.result_on_layer_is_set()) { + // Based on the branch center point of the current layer, the point on the next (further up) layer is calculated. + if (! elem.state.result_on_layer_is_set()) { BOOST_LOG_TRIVIAL(error) << "Uninitialized support element"; tree_supports_show_error("Uninitialized support element. A branch may be missing.\n", true); return; } - for (SupportElement* next_elem : elem->parents) - // if the value was set somewhere else it it kept. This happens when a branch tries not to move after being unable to create a roof. - if (! next_elem->state.result_on_layer_is_set()) { - Point from = elem->state.result_on_layer; - if (! contains(next_elem->influence_area, from)) { - move_inside(next_elem->influence_area, from, 0); // Move inside has edgecases (see tests) so DONT use Polygons.inside to confirm correct move, Error with distance 0 is <= 1 - // it is not required to check if how far this move moved a point as is can be larger than maximum_movement_distance. While this seems like a problem it may for example occur after merges. + if (layer_above) + for (int32_t next_elem_idx : elem.parents) { + assert(next_elem_idx >= 0); + SupportElement &next_elem = (*layer_above)[next_elem_idx]; + assert(! next_elem.state.deleted); + // if the value was set somewhere else it it kept. This happens when a branch tries not to move after being unable to create a roof. + if (! next_elem.state.result_on_layer_is_set()) { + // Move inside has edgecases (see tests) so DONT use Polygons.inside to confirm correct move, Error with distance 0 is <= 1 + // it is not required to check if how far this move moved a point as is can be larger than maximum_movement_distance. + // While this seems like a problem it may for example occur after merges. + next_elem.state.result_on_layer = move_inside_if_outside(next_elem.influence_area, elem.state.result_on_layer); + // do not call recursive because then amount of layers would be restricted by the stack size } - next_elem->state.result_on_layer = from; - // do not call recursive because then amount of layers would be restricted by the stack size } } +static void set_to_model_contact_simple(SupportElement &elem) +{ + const Point best = move_inside_if_outside(elem.influence_area, elem.state.next_position); + elem.state.result_on_layer = best; + BOOST_LOG_TRIVIAL(debug) << "Added NON gracious Support On Model Point (" << best.x() << "," << best.y() << "). The current layer is " << elem.state.layer_idx; +} + /*! * \brief Get the best point to connect to the model and set the result_on_layer of the relevant SupportElement accordingly. * * \param move_bounds[in,out] All currently existing influence areas * \param first_elem[in,out] SupportElement that did not have its result_on_layer set meaning that it does not have a child element. * \param layer_idx[in] The current layer. - * \return Should elem be deleted. */ -static bool set_to_model_contact(const TreeModelVolumes &volumes, const TreeSupportSettings &config, std::vector> &move_bounds, SupportElement *first_elem, const LayerIndex layer_idx) +static void set_to_model_contact_to_model_gracious( + const TreeModelVolumes &volumes, + const TreeSupportSettings &config, + std::vector &move_bounds, + SupportElement &first_elem) { - if (first_elem->state.to_model_gracious) + SupportElement *last_successfull_layer = nullptr; + + // check for every layer upwards, up to the point where this influence area was created (either by initial insert or merge) if the branch could be placed on it, and highest up layer index. { - SupportElement* check = first_elem; - - std::vector checked; - LayerIndex last_successfull_layer = layer_idx; - bool set = false; - - // check for every layer upwards, up to the point where this influence area was created (either by initial insert or merge) if the branch could be placed on it, and highest up layer index. - for (LayerIndex layer_check = layer_idx; check->state.next_height >= layer_check; ++ layer_check) { - if (! intersection(check->influence_area, volumes.getPlaceableAreas(config.getCollisionRadius(check->state), layer_check)).empty()) { - set = true; - last_successfull_layer = layer_check; - } - checked.emplace_back(check); - if (check->parents.size() == 1) - check = check->parents[0]; - else - // reached merge point + SupportElement *elem = &first_elem; + for (LayerIndex layer_check = elem->state.layer_idx; + ! intersection(elem->influence_area, volumes.getPlaceableAreas(config.getCollisionRadius(elem->state), layer_check)).empty(); + elem = &move_bounds[++ layer_check][elem->parents.front()]) { + assert(elem->state.layer_idx == layer_check); + assert(! elem->state.deleted); + assert(elem->state.to_model_gracious); + last_successfull_layer = elem; + if (elem->parents.size() != 1) + // Reached merge point. break; } + } - // Could not find valid placement, even though it should exist => error handling - if (!set) { - if (SUPPORT_TREE_ONLY_GRACIOUS_TO_MODEL) { - BOOST_LOG_TRIVIAL(warning) << "No valid placement found for to model gracious element on layer " << layer_idx << ": REMOVING BRANCH"; - tree_supports_show_error("Could not fine valid placement on model! Removing this branch...", true); - for (LayerIndex layer = layer_idx; layer <= first_elem->state.next_height; ++ layer) { - move_bounds[layer].erase(checked[layer - layer_idx]); - delete checked[layer - layer_idx]; - } - } else { - BOOST_LOG_TRIVIAL(warning) << "No valid placement found for to model gracious element on layer " << layer_idx; - tree_supports_show_error("Could not fine valid placement on model! Just placing it down anyway. Could cause floating branches.", true); - first_elem->state.to_model_gracious = false; - return set_to_model_contact(volumes, config, move_bounds, first_elem, layer_idx); + // Could not find valid placement, even though it should exist => error handling + if (last_successfull_layer == nullptr) { + BOOST_LOG_TRIVIAL(warning) << "No valid placement found for to model gracious element on layer " << first_elem.state.layer_idx; + tree_supports_show_error("Could not fine valid placement on model! Just placing it down anyway. Could cause floating branches.", true); + first_elem.state.to_model_gracious = false; + set_to_model_contact_simple(first_elem); + } else { + // Found a gracious area above first_elem. Remove all below last_successfull_layer. + { + LayerIndex parent_layer_idx = first_elem.state.layer_idx; + for (SupportElement *elem = &first_elem; elem != last_successfull_layer; elem = &move_bounds[++ parent_layer_idx][elem->parents.front()]) { + assert(! elem->state.deleted); + elem->state.deleted = true; } } - - for (LayerIndex layer = layer_idx + 1; layer < last_successfull_layer - 1; ++ layer) { - move_bounds[layer].erase(checked[layer - layer_idx]); - delete checked[layer - layer_idx]; - } - // Guess a point inside the influence area, in which the branch will be placed in. - Point best = checked[last_successfull_layer - layer_idx]->state.next_position; - if (! contains(checked[last_successfull_layer - layer_idx]->influence_area, best)) - move_inside(checked[last_successfull_layer - layer_idx]->influence_area, best); - checked[last_successfull_layer - layer_idx]->state.result_on_layer = best; - + const Point best = move_inside_if_outside(last_successfull_layer->influence_area, last_successfull_layer->state.next_position); + last_successfull_layer->state.result_on_layer = best; BOOST_LOG_TRIVIAL(debug) << "Added gracious Support On Model Point (" << best.x() << "," << best.y() << "). The current layer is " << last_successfull_layer; - - return last_successfull_layer != layer_idx; } - else // can not add graceful => just place it here and hope for the best - { - Point best = first_elem->state.next_position; - if (! contains(first_elem->influence_area, best)) - move_inside(first_elem->influence_area, best); - first_elem->state.result_on_layer = best; - first_elem->state.to_model_gracious = false; - BOOST_LOG_TRIVIAL(debug) << "Added NON gracious Support On Model Point (" << best.x() << "," << best.y() << "). The current layer is " << layer_idx; - return false; +} + +// Remove elements marked as "deleted", update indices to parents. +static void remove_deleted_elements(std::vector &move_bounds) +{ + std::vector map_parents; + std::vector map_current; + for (LayerIndex layer_idx = LayerIndex(move_bounds.size()) - 1; layer_idx >= 0; -- layer_idx) { + SupportElements &layer = move_bounds[layer_idx]; + map_current.clear(); + for (int32_t i = 0; i < int32_t(layer.size());) { + SupportElement &element = layer[i]; + if (element.state.deleted) { + if (map_current.empty()) { + // Initialize with identity map. + map_current.assign(layer.size(), 0); + std::iota(map_current.begin(), map_current.end(), 0); + } + // Delete all "deleted" elements from the end of the layer vector. + while (i < layer.size() && layer.back().state.deleted) { + layer.pop_back(); + // Mark as deleted in the map. + map_current[layer.size()] = -1; + } + assert(i == layer.size() || i + 1 < layer.size()); + if (i + 1 < layer.size()) { + element = std::move(layer.back()); + layer.pop_back(); + // Mark the current element as deleted. + map_current[i] = -1; + // Mark the moved element as moved to index i. + map_current[layer.size()] = i; + } + } else { + // Current element is not deleted. Update its parent indices. + if (! map_parents.empty()) + for (int32_t &parent_idx : element.parents) + parent_idx = map_parents[parent_idx]; + ++ i; + } + } + std::swap(map_current, map_parents); } } @@ -2439,59 +2481,68 @@ static bool set_to_model_contact(const TreeModelVolumes &volumes, const TreeSupp * \param move_bounds[in,out] All currently existing influence areas */ static void create_nodes_from_area( - const TreeModelVolumes &volumes, - const TreeSupportSettings &config, - std::vector> &move_bounds) + const TreeModelVolumes &volumes, + const TreeSupportSettings &config, + std::vector &move_bounds) { - // Initialize points on layer 0, with a "random" point in the influence area. Point is chosen based on an inaccurate estimate where the branches will split into two, but every point inside the influence area would produce a valid result. - for (SupportElement* init : move_bounds[0]) { - Point p = init->state.next_position; - if (! contains(init->influence_area, p)) - move_inside(init->influence_area, p, 0); - init->state.result_on_layer = p; - set_points_on_areas(init); // also set the parent nodes, as these will be required for the first iteration of the loop below + // Initialize points on layer 0, with a "random" point in the influence area. + // Point is chosen based on an inaccurate estimate where the branches will split into two, but every point inside the influence area would produce a valid result. + for (SupportElement &init : move_bounds.front()) { + init.state.result_on_layer = move_inside_if_outside(init.influence_area, init.state.next_position); + // Also set the parent nodes, as these will be required for the first iteration of the loop below. + set_points_on_areas(init, move_bounds.size() > 1 ? &move_bounds[1] : nullptr); } for (LayerIndex layer_idx = 1; layer_idx < LayerIndex(move_bounds.size()); ++ layer_idx) { - std::unordered_set remove; - for (SupportElement* elem : move_bounds[layer_idx]) { - bool removed = false; + auto &layer = move_bounds[layer_idx]; + auto *layer_above = layer_idx + 1 < move_bounds.size() ? &move_bounds[layer_idx + 1] : nullptr; + for (SupportElement &elem : layer) { + assert(! elem.state.deleted); + assert(elem.state.layer_idx == layer_idx); // check if the resulting center point is not yet set - if (! elem->state.result_on_layer_is_set()) { - if (elem->state.to_buildplate || (!elem->state.to_buildplate && elem->state.distance_to_top < config.min_dtt_to_model && !elem->state.supports_roof)) { - if (elem->state.to_buildplate) { - BOOST_LOG_TRIVIAL(error) << "Uninitialized Influence area targeting " << elem->state.target_position.x() << "," << elem->state.target_position.y() << ") " - "at target_height: " << elem->state.target_height << " layer: " << layer_idx; + if (! elem.state.result_on_layer_is_set()) { + if (elem.state.to_buildplate || (elem.state.distance_to_top < config.min_dtt_to_model && ! elem.state.supports_roof)) { + if (elem.state.to_buildplate) { + BOOST_LOG_TRIVIAL(error) << "Uninitialized Influence area targeting " << elem.state.target_position.x() << "," << elem.state.target_position.y() << ") " + "at target_height: " << elem.state.target_height << " layer: " << layer_idx; tree_supports_show_error("Uninitialized support element! A branch could be missing or exist partially.", true); } - remove.emplace(elem); // we dont need to remove yet the parents as they will have a lower dtt and also no result_on_layer set - removed = true; - for (SupportElement* parent : elem->parents) + // we dont need to remove yet the parents as they will have a lower dtt and also no result_on_layer set + elem.state.deleted = true; + for (int32_t parent_idx : elem.parents) // When the roof was not able to generate downwards enough, the top elements may have not moved, and have result_on_layer already set. // As this branch needs to be removed => all parents result_on_layer have to be invalidated. - parent->state.result_on_layer_reset(); + (*layer_above)[parent_idx].state.result_on_layer_reset(); continue; } else { // set the point where the branch will be placed on the model - removed = set_to_model_contact(volumes, config, move_bounds, elem, layer_idx); - if (removed) - remove.emplace(elem); + if (elem.state.to_model_gracious) + set_to_model_contact_to_model_gracious(volumes, config, move_bounds, elem); + else + set_to_model_contact_simple(elem); } } - - if (!removed) - set_points_on_areas(elem); // element is valid now setting points in the layer above + if (! elem.state.deleted) + // element is valid now setting points in the layer above + set_points_on_areas(elem, layer_above); } - - // delete all not needed support elements - for (SupportElement* del : remove) { - move_bounds[layer_idx].erase(del); - delete del; - } - remove.clear(); } + + remove_deleted_elements(move_bounds); } +// For producing circular / elliptical areas from SupportElements (one DrawArea per one SupportElement) +// and for smoothing those areas along the tree branches. +struct DrawArea +{ + // Element to be processed. + SupportElement *element; + // Element below, if there is such an element. nullptr if element is a root of a tree. + SupportElement *child_element; + // Polygons to be extruded for this element. + Polygons polygons; +}; + /*! * \brief Draws circles around result_on_layer points of the influence areas * @@ -2499,63 +2550,55 @@ static void create_nodes_from_area( * \param layer_tree_polygons[out] Resulting branch areas with the layerindex they appear on. layer_tree_polygons.size() has to be at least linear_data.size() as each Influence area in linear_data will save have at least one (that's why it's a vector) corresponding branch area in layer_tree_polygons. * \param inverse_tree_order[in] A mapping that returns the child of every influence area. */ -static void generate_branch_areas( - const TreeModelVolumes &volumes, - const TreeSupportSettings &config, - std::vector> &linear_data, - std::vector> &layer_tree_polygons, - const std::map &inverse_tree_order) +static void generate_branch_areas(const TreeModelVolumes &volumes, const TreeSupportSettings &config, const std::vector &move_bounds, std::vector &linear_data) { #ifdef SLIC3R_TREESUPPORTS_PROGRESS double progress_total = TREE_PROGRESS_PRECALC_AVO + TREE_PROGRESS_PRECALC_COLL + TREE_PROGRESS_GENERATE_NODES + TREE_PROGRESS_AREA_CALC; constexpr int progress_report_steps = 10; + const size_t progress_inserts_check_interval = linear_data.size() / progress_report_steps; + std::mutex critical_sections; #endif // SLIC3R_TREESUPPORTS_PROGRESS // Pre-generate a circle with correct diameter so that we don't have to recompute those (co)sines every time. - const Polygon branch_circle = make_circle(config.branch_radius, SUPPORT_TREE_CIRCLE_RESOLUTION); - std::vector linear_inserts(linear_data.size()); + const Polygon branch_circle = make_circle(config.branch_radius, SUPPORT_TREE_CIRCLE_RESOLUTION); -#ifdef SLIC3R_TREESUPPORTS_PROGRESS - const size_t progress_inserts_check_interval = linear_data.size() / progress_report_steps; -#endif // SLIC3R_TREESUPPORTS_PROGRESS - - std::mutex critical_sections; tbb::parallel_for(tbb::blocked_range(0, linear_data.size()), - [&](const tbb::blocked_range &range) { + [&volumes, &config, &move_bounds, &linear_data, &branch_circle](const tbb::blocked_range &range) { for (size_t idx = range.begin(); idx < range.end(); ++ idx) { - const LayerIndex layer_idx = linear_data[idx].first; - const SupportElement *elem = linear_data[idx].second; - const auto it_elem = inverse_tree_order.find(const_cast(elem)); - const SupportElement* child_elem = it_elem == inverse_tree_order.end() ? nullptr : it_elem->second; - const coord_t radius = config.getRadius(*elem); + DrawArea &draw_area = linear_data[idx]; + const LayerIndex layer_idx = draw_area.element->state.layer_idx; + const coord_t radius = config.getRadius(*draw_area.element); bool parent_uses_min = false; // Calculate multiple ovalized circles, to connect with every parent and child. Also generate regular circle for the current layer. Merge all these into one area. std::vector> movement_directions{ std::pair(Point(0, 0), radius) }; - if (!elem->state.skip_ovalisation) { - if (child_elem != nullptr) { - const Point movement = child_elem->state.result_on_layer - elem->state.result_on_layer; + if (! draw_area.element->state.skip_ovalisation) { + if (draw_area.child_element != nullptr) { + const Point movement = draw_area.child_element->state.result_on_layer - draw_area.element->state.result_on_layer; movement_directions.emplace_back(movement, radius); } - for (SupportElement *parent : elem->parents) { - const Point movement = parent->state.result_on_layer - elem->state.result_on_layer; - movement_directions.emplace_back(movement, std::max(config.getRadius(*parent), config.support_line_width)); - parent_uses_min |= parent->state.use_min_xy_dist; + const SupportElements *layer_above = layer_idx + 1 < move_bounds.size() ? &move_bounds[layer_idx + 1] : nullptr; + for (int32_t parent_idx : draw_area.element->parents) { + const SupportElement &parent = (*layer_above)[parent_idx]; + const Point movement = parent.state.result_on_layer - draw_area.element->state.result_on_layer; + //FIXME why max(..., config.support_line_width)? + movement_directions.emplace_back(movement, std::max(config.getRadius(parent), config.support_line_width)); + parent_uses_min |= parent.state.use_min_xy_dist; } } - double max_speed = 0; - auto generateArea = [&volumes, layer_idx, elem, &branch_circle, branch_radius = config.branch_radius, support_line_width = config.support_line_width, &movement_directions, &max_speed, parent_uses_min]( - coord_t aoffset) { + const Polygons &collision = volumes.getCollision(0, layer_idx, parent_uses_min || draw_area.element->state.use_min_xy_dist); + auto generateArea = [&collision, &draw_area, &branch_circle, branch_radius = config.branch_radius, support_line_width = config.support_line_width, &movement_directions] + (coord_t aoffset, double &max_speed) { Polygons poly; - + max_speed = 0; for (std::pair movement : movement_directions) { max_speed = std::max(max_speed, movement.first.cast().norm()); // Visualization: https://jsfiddle.net/0zvcq39L/2/ // Ovalizes the circle to an ellipse, that contains both old center and new target position. double used_scale = (movement.second + aoffset) / (1.0 * branch_radius); - Point center_position = elem->state.result_on_layer + movement.first / 2; + Point center_position = draw_area.element->state.result_on_layer + movement.first / 2; const double moveX = movement.first.x() / (used_scale * branch_radius); const double moveY = movement.first.y() / (used_scale * branch_radius); const double vsize_inv = 0.5 / (0.01 + std::sqrt(moveX * moveX + moveY * moveY)); @@ -2572,49 +2615,49 @@ static void generate_branch_areas( poly.emplace_back(std::move(circle)); } - poly = diff_clipped(offset(union_(poly), std::min(coord_t(50), support_line_width / 4), jtMiter, 1.2), - // There seem to be some rounding errors, causing a branch to be a tiny bit further away from the model that it has to be. - // This can cause the tip to be slightly further away front the overhang (x/y wise) than optimal. This fixes it, and for every other part, 0.05mm will not be noticed. - volumes.getCollision(0, layer_idx, parent_uses_min || elem->state.use_min_xy_dist)); + // There seem to be some rounding errors, causing a branch to be a tiny bit further away from the model that it has to be. + // This can cause the tip to be slightly further away front the overhang (x/y wise) than optimal. This fixes it, and for every other part, 0.05mm will not be noticed. + poly = diff_clipped(offset(union_(poly), std::min(coord_t(50), support_line_width / 4), jtMiter, 1.2), collision); return poly; }; - bool fast_relative_movement = max_speed > radius * 0.75; + // Ensure branch area will not overlap with model/collision. This can happen because of e.g. ovalization or increase_until_radius. + double max_speed; + Polygons polygons = generateArea(0, max_speed); + const bool fast_relative_movement = max_speed > radius * 0.75; - // ensure branch area will not overlap with model/collision. This can happen because of e.g. ovalization or increase_until_radius. - linear_inserts[idx] = generateArea(0); - - if (fast_relative_movement || config.getRadius(*elem) - config.getCollisionRadius(elem->state) > config.support_line_width) { - // simulate the path the nozzle will take on the outermost wall - // if multiple parts exist, the outer line will not go all around the support part potentially causing support material to be printed mid air - ExPolygons nozzle_path = offset_ex(linear_inserts[idx], -config.support_line_width / 2); + if (fast_relative_movement || config.getRadius(*draw_area.element) - config.getCollisionRadius(draw_area.element->state) > config.support_line_width) { + // Simulate the path the nozzle will take on the outermost wall. + // If multiple parts exist, the outer line will not go all around the support part potentially causing support material to be printed mid air. + ExPolygons nozzle_path = offset_ex(polygons, - config.support_line_width / 2); if (nozzle_path.size() > 1) { // Just try to make the area a tiny bit larger. - linear_inserts[idx] = generateArea(config.support_line_width / 2); - nozzle_path = offset_ex(linear_inserts[idx], -config.support_line_width / 2); - - // if larger area did not fix the problem, all parts off the nozzle path that do not contain the center point are removed, hoping for the best + polygons = generateArea(config.support_line_width / 2, max_speed); + nozzle_path = offset_ex(polygons, -config.support_line_width / 2); + // If larger area did not fix the problem, all parts off the nozzle path that do not contain the center point are removed, hoping for the best. if (nozzle_path.size() > 1) { - Polygons polygons_with_correct_center; + ExPolygons polygons_with_correct_center; for (ExPolygon &part : nozzle_path) { - if (part.contains(elem->state.result_on_layer)) - polygons_with_correct_center = union_(polygons_with_correct_center, part); - else { + bool drop = false; + if (! part.contains(draw_area.element->state.result_on_layer)) { // try a fuzzy inside as sometimes the point should be on the border, but is not because of rounding errors... - Point from = elem->state.result_on_layer; - Polygons to = to_polygons(std::move(part)); - move_inside(to, from, 0); - if ((elem->state.result_on_layer - from).cast().norm() < scaled(0.025)) - polygons_with_correct_center = union_(polygons_with_correct_center, to); + Point pt = draw_area.element->state.result_on_layer; + move_inside(to_polygons(part), pt, 0); + drop = (draw_area.element->state.result_on_layer - pt).cast().norm() >= scaled(0.025); } + if (! drop) + polygons_with_correct_center.emplace_back(std::move(part)); } // Increase the area again, to ensure the nozzle path when calculated later is very similar to the one assumed above. - linear_inserts[idx] = offset(polygons_with_correct_center, config.support_line_width / 2, jtMiter, 1.2); - linear_inserts[idx] = diff_clipped(linear_inserts[idx], volumes.getCollision(0, linear_data[idx].first, parent_uses_min || elem->state.use_min_xy_dist)); + polygons = diff_clipped(offset(polygons_with_correct_center, config.support_line_width / 2, jtMiter, 1.2), + //FIXME Vojtech: Clipping may split the region into multiple pieces again, reversing the fixing effort. + collision); } } } + draw_area.polygons = std::move(polygons); + #ifdef SLIC3R_TREESUPPORTS_PROGRESS if (idx % progress_inserts_check_interval == 0) { std::lock_guard critical_section_progress(critical_sections); @@ -2624,10 +2667,6 @@ static void generate_branch_areas( #endif } }); - - // single threaded combining all elements to the right layers. ONLY COPYS DATA! - for (coord_t i = 0; i < static_cast(linear_data.size()); i++) - layer_tree_polygons[linear_data[i].first].emplace(linear_data[i].second, linear_inserts[i]); } /*! @@ -2635,7 +2674,11 @@ static void generate_branch_areas( * * \param layer_tree_polygons[in,out] Resulting branch areas with the layerindex they appear on. */ -static void smooth_branch_areas(const TreeSupportSettings &config, std::vector> &layer_tree_polygons) +static void smooth_branch_areas( + const TreeSupportSettings &config, + std::vector &move_bounds, + std::vector &linear_data, + const std::vector &linear_data_layers) { #ifdef SLIC3R_TREESUPPORTS_PROGRESS double progress_total = TREE_PROGRESS_PRECALC_AVO + TREE_PROGRESS_PRECALC_COLL + TREE_PROGRESS_GENERATE_NODES + TREE_PROGRESS_AREA_CALC + TREE_PROGRESS_GENERATE_BRANCH_AREAS; @@ -2644,35 +2687,38 @@ static void smooth_branch_areas(const TreeSupportSettings &config, std::vector> processing; - processing.insert(processing.end(), layer_tree_polygons[layer_idx].begin(), layer_tree_polygons[layer_idx].end()); - std::vector>> update_next(processing.size()); // with this a lock can be avoided - - tbb::parallel_for(tbb::blocked_range(0, processing.size()), + for (LayerIndex layer_idx = 0; layer_idx < LayerIndex(move_bounds.size()) - 1; ++ layer_idx) { + const size_t processing_base = linear_data_layers[layer_idx]; + const size_t processing_base_above = linear_data_layers[layer_idx + 1]; + const SupportElements &layer_above = move_bounds[layer_idx + 1]; + tbb::parallel_for(tbb::blocked_range(0, processing_base_above - processing_base), [&](const tbb::blocked_range &range) { for (size_t processing_idx = range.begin(); processing_idx < range.end(); ++ processing_idx) { - std::pair data_pair = processing[processing_idx]; - double max_outer_wall_distance = 0; - bool do_something = false; - for (SupportElement* parent : data_pair.first->parents) - if (config.getRadius(parent->state) != config.getCollisionRadius(parent->state)) { + DrawArea &draw_area = linear_data[processing_base + processing_idx]; + double max_outer_wall_distance = 0; + bool do_something = false; + for (int32_t parent_idx : draw_area.element->parents) { + const SupportElement &parent = layer_above[parent_idx]; + if (config.getRadius(parent.state) != config.getCollisionRadius(parent.state)) { do_something = true; - max_outer_wall_distance = std::max(max_outer_wall_distance, (data_pair.first->state.result_on_layer - parent->state.result_on_layer).cast().norm() - (config.getRadius(*data_pair.first) - config.getRadius(*parent))); + max_outer_wall_distance = std::max(max_outer_wall_distance, (draw_area.element->state.result_on_layer - parent.state.result_on_layer).cast().norm() - (config.getRadius(*draw_area.element) - config.getRadius(parent))); } + } max_outer_wall_distance += max_radius_change_per_layer; // As this change is a bit larger than what usually appears, lost radius can be slowly reclaimed over the layers. if (do_something) { - Polygons max_allowed_area = offset(data_pair.second, float(max_outer_wall_distance), jtMiter, 1.2); - for (SupportElement* parent : data_pair.first->parents) - if (config.getRadius(parent->state) != config.getCollisionRadius(parent->state)) - update_next[processing_idx].emplace_back(std::pair(parent, intersection(layer_tree_polygons[layer_idx + 1][parent], max_allowed_area))); + Polygons max_allowed_area = offset(draw_area.polygons, float(max_outer_wall_distance), jtMiter, 1.2); + for (int32_t parent_idx : draw_area.element->parents) { + const SupportElement &parent = layer_above[parent_idx]; + if (config.getRadius(parent.state) != config.getCollisionRadius(parent.state)) { + // No other element on this layer than the current one may be connected to &parent, + // thus it is safe to update parent's DrawArea directly. + Polygons &dst = linear_data[processing_base_above + parent_idx].polygons; + dst = intersection(dst, max_allowed_area); + } + } } } }); - - for (std::vector> data_vector : update_next) - for (std::pair data_pair : data_vector) - layer_tree_polygons[layer_idx + 1][data_pair.first] = data_pair.second; } #ifdef SLIC3R_TREESUPPORTS_PROGRESS @@ -2681,45 +2727,41 @@ static void smooth_branch_areas(const TreeSupportSettings &config, std::vector updated_last_iteration; - for (int layer_idx = int(layer_tree_polygons.size()) - 2; layer_idx >= 0; -- layer_idx) { - std::vector> processing; - processing.insert(processing.end(), layer_tree_polygons[layer_idx].begin(), layer_tree_polygons[layer_idx].end()); - std::vector> update_next(processing.size(), std::pair(nullptr, Polygons())); // with this a lock can be avoided - - tbb::parallel_for(tbb::blocked_range(0, processing.size()), + for (auto& element : move_bounds.back()) + element.state.marked = false; + for (int layer_idx = int(move_bounds.size()) - 2; layer_idx >= 0; -- layer_idx) { + const size_t processing_base = linear_data_layers[layer_idx]; + const size_t processing_base_above = linear_data_layers[layer_idx + 1]; + const SupportElements &layer_above = move_bounds[layer_idx + 1]; + tbb::parallel_for(tbb::blocked_range(0, processing_base_above - processing_base), [&](const tbb::blocked_range &range) { for (size_t processing_idx = range.begin(); processing_idx < range.end(); ++ processing_idx) { - std::pair data_pair = processing[processing_idx]; - bool do_something = false; + DrawArea &draw_area = linear_data[processing_base + processing_idx]; + bool do_something = false; Polygons max_allowed_area; - for (size_t idx = 0; idx < data_pair.first->parents.size(); ++ idx) { - SupportElement* parent = data_pair.first->parents[idx]; + for (int32_t parent_idx : draw_area.element->parents) { + const SupportElement &parent = layer_above[parent_idx]; coord_t max_outer_line_increase = max_radius_change_per_layer; - Polygons result = offset(layer_tree_polygons[layer_idx + 1][parent], max_outer_line_increase, jtMiter, 1.2); - Point direction = data_pair.first->state.result_on_layer - parent->state.result_on_layer; + Polygons result = offset(linear_data[processing_base_above + parent_idx].polygons, max_outer_line_increase, jtMiter, 1.2); + Point direction = draw_area.element->state.result_on_layer - parent.state.result_on_layer; // move the polygons object - for (auto& outer : result) + for (auto &outer : result) for (Point& p : outer) p += direction; append(max_allowed_area, std::move(result)); - do_something = do_something || updated_last_iteration.count(parent) || config.getCollisionRadius(parent->state) != config.getRadius(parent->state); + do_something = do_something || parent.state.marked || config.getCollisionRadius(parent.state) != config.getRadius(parent.state); } - if (do_something) { - Polygons result = intersection(max_allowed_area, data_pair.second); - if (area(result) < area(data_pair.second)) - update_next[processing_idx] = std::pair(data_pair.first, result); + // Trim the current drawing areas with max_allowed_area. + Polygons result = intersection(max_allowed_area, draw_area.polygons); + if (area(result) < area(draw_area.polygons)) { + // Mark parent as modified to propagate down. + draw_area.element->state.marked = true; + draw_area.polygons = std::move(result); + } } } }); - - updated_last_iteration.clear(); - for (const std::pair &data_pair : update_next) - if (data_pair.first != nullptr) { - updated_last_iteration.emplace(data_pair.first); - layer_tree_polygons[layer_idx][data_pair.first] = data_pair.second; - } } #ifdef SLIC3R_TREESUPPORTS_PROGRESS @@ -2738,27 +2780,27 @@ static void smooth_branch_areas(const TreeSupportSettings &config, std::vector> &layer_tree_polygons, - const std::vector> &linear_data, - std::vector>> &dropped_down_areas, - const std::map &inverse_tree_order) + const std::vector &linear_data, + std::vector &support_layer_storage) { + std::vector>> dropped_down_areas(linear_data.size()); tbb::parallel_for(tbb::blocked_range(0, linear_data.size()), [&](const tbb::blocked_range &range) { - for (size_t idx = range.begin(); idx < range.end(); ++ idx) { - SupportElement* elem = linear_data[idx].second; - bool non_gracious_model_contact = !elem->state.to_model_gracious && !inverse_tree_order.count(elem); // if a element has no child, it connects to whatever is below as no support further down for it will exist. - if (non_gracious_model_contact) { - Polygons rest_support = layer_tree_polygons[linear_data[idx].first][elem]; - LayerIndex counter = 1; - while (area(rest_support) > tiny_area_threshold && counter < linear_data[idx].first) { - rest_support = diff_clipped(rest_support, volumes.getCollision(0, linear_data[idx].first - counter, false)); - dropped_down_areas[idx].emplace_back(linear_data[idx].first - counter, rest_support); - counter++; + for (size_t idx = range.begin(); idx < range.end(); ++ idx) + // If a element has no child, it connects to whatever is below as no support further down for it will exist. + if (const DrawArea &draw_element = linear_data[idx]; ! draw_element.element->state.to_model_gracious && draw_element.child_element == nullptr) { + Polygons rest_support; + const LayerIndex layer_idx_first = draw_element.element->state.layer_idx - 1; + for (LayerIndex layer_idx = layer_idx_first; area(rest_support) > tiny_area_threshold && layer_idx >= 0; -- layer_idx) { + rest_support = diff_clipped(layer_idx == layer_idx_first ? draw_element.polygons : rest_support, volumes.getCollision(0, layer_idx, false)); + dropped_down_areas[idx].emplace_back(layer_idx, rest_support); } } - } }); + + for (coord_t i = 0; i < static_cast(dropped_down_areas.size()); i++) + for (std::pair &pair : dropped_down_areas[i]) + append(support_layer_storage[pair.first], std::move(pair.second)); } /*! @@ -2907,65 +2949,82 @@ static void finalize_interface_and_support_areas( * \param storage[in,out] The storage where the support should be stored. */ static void draw_areas( - PrintObject &print_object, - const TreeModelVolumes &volumes, - const TreeSupportSettings &config, - const std::vector &overhangs, - std::vector> &move_bounds, + PrintObject &print_object, + const TreeModelVolumes &volumes, + const TreeSupportSettings &config, + const std::vector &overhangs, + std::vector &move_bounds, - SupportGeneratorLayersPtr &bottom_contacts, - SupportGeneratorLayersPtr &top_contacts, - SupportGeneratorLayersPtr &intermediate_layers, - SupportGeneratorLayerStorage &layer_storage) + SupportGeneratorLayersPtr &bottom_contacts, + SupportGeneratorLayersPtr &top_contacts, + SupportGeneratorLayersPtr &intermediate_layers, + SupportGeneratorLayerStorage &layer_storage) { std::vector support_layer_storage(move_bounds.size()); std::vector support_roof_storage(move_bounds.size()); - std::map inverese_tree_order; // in the tree structure only the parents can be accessed. Inverse this to be able to access the children. - std::vector> linear_data; // All SupportElements are put into a layer independent storage to improve parallelization. Was added at a point in time where this function had performance issues. - // These were fixed by creating less initial points, but i do not see a good reason to remove a working performance optimization. - for (LayerIndex layer_idx = 0; layer_idx < LayerIndex(move_bounds.size()); ++ layer_idx) { - for (SupportElement* elem : move_bounds[layer_idx]) { - // We either come from nowhere at the final layer or we had invalid parents 2. should never happen but just to be sure - if ((layer_idx > 0 && ((!inverese_tree_order.count(elem) && elem->state.target_height == layer_idx) || (inverese_tree_order.count(elem) && ! inverese_tree_order[elem]->state.result_on_layer_is_set())))) - continue; - for (SupportElement* par : elem->parents) - if (par->state.result_on_layer_is_set()) - inverese_tree_order.emplace(par, elem); - linear_data.emplace_back(layer_idx, elem); + // All SupportElements are put into a layer independent storage to improve parallelization. + std::vector linear_data; + std::vector linear_data_layers; + { + std::vector> map_downwards_old; + std::vector> map_downwards_new; + for (LayerIndex layer_idx = 0; layer_idx < LayerIndex(move_bounds.size()); ++ layer_idx) { + SupportElements *layer_above = layer_idx + 1 < move_bounds.size() ? &move_bounds[layer_idx + 1] : nullptr; + map_downwards_new.clear(); + linear_data_layers.emplace_back(linear_data.size()); + std::sort(map_downwards_old.begin(), map_downwards_old.end(), [](auto &l, auto &r) { return l.first < r.first; }); + for (SupportElement &elem : move_bounds[layer_idx]) { + SupportElement *child = nullptr; + if (layer_idx > 0) { + auto it = std::lower_bound(map_downwards_old.begin(), map_downwards_old.end(), &elem, [](auto &l, const SupportElement *r) { return l.first < r; }); + if (it != map_downwards_old.end() && it->first == &elem) { + child = it->second; + // Only one link points to a node above from below. + assert(! (++ it != map_downwards_old.end() && it->first == &elem)); + } + if ((! child && elem.state.target_height == layer_idx) || (child && !child->state.result_on_layer_is_set())) + // We either come from nowhere at the final layer or we had invalid parents 2. should never happen but just to be sure + continue; + } + for (int32_t parent_idx : elem.parents) { + SupportElement &parent = (*layer_above)[parent_idx]; + if (parent.state.result_on_layer_is_set()) + map_downwards_new.emplace_back(&parent, &elem); + } + linear_data.push_back({ &elem, child }); + } + std::swap(map_downwards_old, map_downwards_new); } + linear_data_layers.emplace_back(linear_data.size()); } - std::vector> layer_tree_polygons(move_bounds.size()); // reorder the processed data by layers again. The map also could be a vector>. auto t_start = std::chrono::high_resolution_clock::now(); // Generate the circles that will be the branches. - generate_branch_areas(volumes, config, linear_data, layer_tree_polygons, inverese_tree_order); + generate_branch_areas(volumes, config, move_bounds, linear_data); auto t_generate = std::chrono::high_resolution_clock::now(); // In some edgecases a branch may go though a hole, where the regular radius does not fit. This can result in an apparent jump in branch radius. As such this cases need to be caught and smoothed out. - smooth_branch_areas(config, layer_tree_polygons); + smooth_branch_areas(config, move_bounds, linear_data, linear_data_layers); auto t_smooth = std::chrono::high_resolution_clock::now(); // drop down all trees that connect non gracefully with the model - std::vector>> dropped_down_areas(linear_data.size()); - drop_non_gracious_areas(volumes, layer_tree_polygons, linear_data, dropped_down_areas, inverese_tree_order); + drop_non_gracious_areas(volumes, linear_data, support_layer_storage); auto t_drop = std::chrono::high_resolution_clock::now(); - // single threaded combining all dropped down support areas to the right layers. ONLY COPYS DATA! - for (coord_t i = 0; i < static_cast(dropped_down_areas.size()); i++) - for (std::pair &pair : dropped_down_areas[i]) - append(support_layer_storage[pair.first], std::move(pair.second)); - // single threaded combining all support areas to the right layers. ONLY COPYS DATA! - for (LayerIndex layer_idx = 0; layer_idx < LayerIndex(layer_tree_polygons.size()); ++ layer_idx) { - auto &this_layer_tree_polygons = layer_tree_polygons[layer_idx]; - auto &this_roofs = support_roof_storage[layer_idx]; - auto &this_layers = support_layer_storage[layer_idx]; - size_t cnt_roofs = 0; - size_t cnt_layers = 0; - for (const std::pair &data_pair : this_layer_tree_polygons) - ++ (data_pair.first->state.missing_roof_layers > data_pair.first->state.distance_to_top ? cnt_roofs : cnt_layers); - this_roofs.reserve(this_roofs.size() + cnt_roofs); - this_layers.reserve(this_layers.size() + cnt_layers); - for (const std::pair &data_pair : this_layer_tree_polygons) { - auto &src = const_cast(data_pair.second); - std::move(std::begin(src), std::end(src), std::back_inserter(data_pair.first->state.missing_roof_layers > data_pair.first->state.distance_to_top ? this_roofs : this_layers)); + // Single threaded combining all support areas to the right layers. + { + auto begin = linear_data.begin(); + for (LayerIndex layer_idx = 0; layer_idx < LayerIndex(move_bounds.size()); ++ layer_idx) { + size_t cnt_roofs = 0; + size_t cnt_layers = 0; + auto end = begin; + for (; end != linear_data.end() && end->element->state.layer_idx == layer_idx; ++ end) + ++ (end->element->state.missing_roof_layers > end->element->state.distance_to_top ? cnt_roofs : cnt_layers); + auto &this_roofs = support_roof_storage[layer_idx]; + auto &this_layers = support_layer_storage[layer_idx]; + this_roofs.reserve(this_roofs.size() + cnt_roofs); + this_layers.reserve(this_layers.size() + cnt_layers); + for (auto it = begin; it != end; ++ it) + std::move(std::begin(it->polygons), std::end(it->polygons), std::back_inserter(it->element->state.missing_roof_layers > it->element->state.distance_to_top ? this_roofs : this_layers)); + begin = end; } } @@ -3053,7 +3112,7 @@ static void generate_support_areas(Print &print, const BuildVolume &build_volume auto t_precalc = std::chrono::high_resolution_clock::now(); // value is the area where support may be placed. As this is calculated in CreateLayerPathing it is saved and reused in draw_areas - std::vector> move_bounds(num_support_layers); + std::vector move_bounds(num_support_layers); // ### Place tips of the support tree SupportGeneratorLayersPtr bottom_contacts(num_support_layers, nullptr); @@ -3108,9 +3167,7 @@ static void generate_support_areas(Print &print, const BuildVolume &build_volume // if (config.branch_radius==2121) // BOOST_LOG_TRIVIAL(error) << "Why ask questions when you already know the answer twice.\n (This is not a real bug, please dont report it.)"; - for (auto &layer : move_bounds) - for (auto elem : layer) - delete elem; + move_bounds.clear(); auto remove_undefined_layers = [](SupportGeneratorLayersPtr &layers) { layers.erase(std::remove_if(layers.begin(), layers.end(), [](const SupportGeneratorLayer* ptr) { return ptr == nullptr; }), layers.end()); diff --git a/src/libslic3r/TreeSupport.hpp b/src/libslic3r/TreeSupport.hpp index 26ab7fc84..0d5e967d9 100644 --- a/src/libslic3r/TreeSupport.hpp +++ b/src/libslic3r/TreeSupport.hpp @@ -54,7 +54,6 @@ static constexpr const coord_t SUPPORT_TREE_COLLISION_RESOLUTION = scaled::max(), std::numeric_limits::max() }; - bool result_on_layer_is_set() const { return this->result_on_layer != Point{ std::numeric_limits::max(), std::numeric_limits::max() }; } - void result_on_layer_reset() { this->result_on_layer = Point{ std::numeric_limits::max(), std::numeric_limits::max() }; } - /*! - * \brief The amount of extra radius we got from merging branches that could have reached the buildplate, but merged with ones that can not. - */ - coord_t increased_to_model_radius; // how much to model we increased only relevant for merging - - /*! - * \brief Counter about the times the elephant foot was increased. Can be fractions for merge reasons. - */ - double elephant_foot_increases; - - /*! - * \brief The element trys not to move until this dtt is reached, is set to 0 if the element had to move. - */ - uint32_t dont_move_until; - - /*! - * \brief Settings used to increase the influence area to its current state. - */ - AreaIncreaseSettings last_area_increase; - - /*! - * \brief Amount of roof layers that were not yet added, because the branch needed to move. - */ - uint32_t missing_roof_layers; +// C++17 does not support in place initializers of bit values, thus a constructor zeroing the bits is provided. +struct SupportElementStateBits { + SupportElementStateBits() : + to_buildplate(false), + to_model_gracious(false), + use_min_xy_dist(false), + supports_roof(false), + can_use_safe_radius(false), + skip_ovalisation(false), + deleted(false), + marked(false) + {} /*! * \brief The element trys to reach the buildplate @@ -190,11 +135,83 @@ struct SupportElementState : public SupportElementID */ bool skip_ovalisation : 1; + // Not valid anymore, to be deleted. + bool deleted : 1; + + // General purpose flag marking a visited element. + bool marked : 1; +}; + +struct SupportElementState : public SupportElementStateBits +{ + /*! + * \brief The layer this support elements wants reach + */ + LayerIndex target_height; + + /*! + * \brief The position this support elements wants to support on layer=target_height + */ + Point target_position; + + /*! + * \brief The next position this support elements wants to reach. NOTE: This is mainly a suggestion regarding direction inside the influence area. + */ + Point next_position; + + /*! + * \brief The next height this support elements wants to reach + */ + LayerIndex layer_idx; + + /*! + * \brief The Effective distance to top of this element regarding radius increases and collision calculations. + */ + uint32_t effective_radius_height; + + /*! + * \brief The amount of layers this element is below the topmost layer of this branch. + */ + uint32_t distance_to_top; + + /*! + * \brief The resulting center point around which a circle will be drawn later. + * Will be set by setPointsOnAreas + */ + Point result_on_layer { std::numeric_limits::max(), std::numeric_limits::max() }; + bool result_on_layer_is_set() const { return this->result_on_layer != Point{ std::numeric_limits::max(), std::numeric_limits::max() }; } + void result_on_layer_reset() { this->result_on_layer = Point{ std::numeric_limits::max(), std::numeric_limits::max() }; } + /*! + * \brief The amount of extra radius we got from merging branches that could have reached the buildplate, but merged with ones that can not. + */ + coord_t increased_to_model_radius; // how much to model we increased only relevant for merging + + /*! + * \brief Counter about the times the elephant foot was increased. Can be fractions for merge reasons. + */ + double elephant_foot_increases; + + /*! + * \brief The element trys not to move until this dtt is reached, is set to 0 if the element had to move. + */ + uint32_t dont_move_until; + + /*! + * \brief Settings used to increase the influence area to its current state. + */ + AreaIncreaseSettings last_area_increase; + + /*! + * \brief Amount of roof layers that were not yet added, because the branch needed to move. + */ + uint32_t missing_roof_layers; + // called by increase_single_area() and increaseAreas() [[nodiscard]] static SupportElementState propagate_down(const SupportElementState &src) { SupportElementState dst{ src }; ++ dst.distance_to_top; + -- dst.layer_idx; // set to invalid as we are a new node on a new layer dst.result_on_layer_reset(); dst.skip_ovalisation = false; @@ -204,22 +221,32 @@ struct SupportElementState : public SupportElementID struct SupportElement { + using ParentIndices = +#ifdef NDEBUG + // To reduce memory allocation in release mode. + boost::container::small_vector; +#else // NDEBUG + // To ease debugging. + std::vector; +#endif // NDEBUG + // SupportElement(const SupportElementState &state) : SupportElementState(state) {} SupportElement(const SupportElementState &state, Polygons &&influence_area) : state(state), influence_area(std::move(influence_area)) {} - SupportElement(const SupportElementState &state, boost::container::small_vector &&parents, Polygons &&influence_area) : + SupportElement(const SupportElementState &state, ParentIndices &&parents, Polygons &&influence_area) : state(state), parents(std::move(parents)), influence_area(std::move(influence_area)) {} - SupportElementState state; + SupportElementState state; + /*! * \brief All elements in the layer above the current one that are supported by this element */ - boost::container::small_vector parents; + ParentIndices parents; /*! * \brief The resulting influence area. * Will only be set in the results of createLayerPathing, and will be nullptr inside! */ - Polygons influence_area; + Polygons influence_area; }; /*! diff --git a/src/platform/osx/Info.plist.in b/src/platform/osx/Info.plist.in index b53111d1d..d3c913604 100644 --- a/src/platform/osx/Info.plist.in +++ b/src/platform/osx/Info.plist.in @@ -111,7 +111,7 @@ LSMinimumSystemVersion - 10.10 + 10.12 NSPrincipalClass NSApplication NSHighResolutionCapable diff --git a/src/slic3r/GUI/BitmapCache.cpp b/src/slic3r/GUI/BitmapCache.cpp index 7fb0ce635..4a9057514 100644 --- a/src/slic3r/GUI/BitmapCache.cpp +++ b/src/slic3r/GUI/BitmapCache.cpp @@ -34,8 +34,11 @@ void BitmapCache::clear() { for (std::pair &bitmap : m_map) delete bitmap.second; - m_map.clear(); + + for (std::pair &bitmap_bundle : m_bndl_map) + delete bitmap_bundle.second; + m_bndl_map.clear(); } static wxBitmap wxImage_to_wxBitmap_with_alpha(wxImage &&image, float scale = 1.0f) diff --git a/src/slic3r/GUI/GCodeViewer.cpp b/src/slic3r/GUI/GCodeViewer.cpp index a15d73a1e..be232c178 100644 --- a/src/slic3r/GUI/GCodeViewer.cpp +++ b/src/slic3r/GUI/GCodeViewer.cpp @@ -907,21 +907,10 @@ void GCodeViewer::refresh(const GCodeProcessorResult& gcode_result, const std::v #endif // ENABLE_GCODE_VIEWER_STATISTICS // update buffers' render paths -#if ENABLE_PREVIEW_LAYOUT refresh_render_paths(false, false); -#else - refresh_render_paths(); -#endif // ENABLE_PREVIEW_LAYOUT log_memory_used("Refreshed G-code extrusion paths, "); } -#if !ENABLE_PREVIEW_LAYOUT -void GCodeViewer::refresh_render_paths() -{ - refresh_render_paths(false, false); -} -#endif // !ENABLE_PREVIEW_LAYOUT - void GCodeViewer::update_shells_color_by_extruder(const DynamicPrintConfig* config) { if (config != nullptr) @@ -958,9 +947,7 @@ void GCodeViewer::reset() m_statistics.reset_all(); #endif // ENABLE_GCODE_VIEWER_STATISTICS m_contained_in_bed = true; -#if ENABLE_PREVIEW_LAYOUT m_legend_resizer.reset(); -#endif // ENABLE_PREVIEW_LAYOUT } void GCodeViewer::render() @@ -1073,9 +1060,6 @@ unsigned int GCodeViewer::get_options_visibility_flags() const flags = set_flag(flags, static_cast(Preview::OptionType::CenterOfGravity), m_cog.is_visible()); flags = set_flag(flags, static_cast(Preview::OptionType::Shells), m_shells.visible); flags = set_flag(flags, static_cast(Preview::OptionType::ToolMarker), m_sequential_view.marker.is_visible()); -#if !ENABLE_PREVIEW_LAYOUT - flags = set_flag(flags, static_cast(Preview::OptionType::Legend), is_legend_enabled()); -#endif // !ENABLE_PREVIEW_LAYOUT return flags; } @@ -1097,9 +1081,6 @@ void GCodeViewer::set_options_visibility_from_flags(unsigned int flags) m_cog.set_visible(is_flag_set(static_cast(Preview::OptionType::CenterOfGravity))); m_shells.visible = is_flag_set(static_cast(Preview::OptionType::Shells)); m_sequential_view.marker.set_visible(is_flag_set(static_cast(Preview::OptionType::ToolMarker))); -#if !ENABLE_PREVIEW_LAYOUT - enable_legend(is_flag_set(static_cast(Preview::OptionType::Legend))); -#endif // !ENABLE_PREVIEW_LAYOUT } void GCodeViewer::set_layers_z_range(const std::array& layers_z_range) @@ -3434,11 +3415,7 @@ void GCodeViewer::render_legend(float& legend_height) const float max_height = 0.75f * static_cast(cnv_size.get_height()); const float child_height = 0.3333f * max_height; ImGui::SetNextWindowSizeConstraints({ 0.0f, 0.0f }, { -1.0f, max_height }); -#if ENABLE_PREVIEW_LAYOUT imgui.begin(std::string("Legend"), ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove); -#else - imgui.begin(std::string("Legend"), ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoMove); -#endif // ENABLE_PREVIEW_LAYOUT enum class EItemType : unsigned char { @@ -3537,7 +3514,6 @@ void GCodeViewer::render_legend(float& legend_height) } else { imgui.text(label); -#if ENABLE_TRAVEL_TIME if (!time.empty()) { ImGui::SameLine(offsets[0]); imgui.text(time); @@ -3553,9 +3529,6 @@ void GCodeViewer::render_legend(float& legend_height) ImGui::TextUnformatted((percent > 0.0f) ? buf : ""); } else if (used_filament_m > 0.0) { -#else - if (used_filament_m > 0.0) { -#endif // ENABLE_TRAVEL_TIME char buf[64]; ImGui::SameLine(offsets[0]); ::sprintf(buf, imperial_units ? "%.2f in" : "%.2f m", used_filament_m); @@ -3796,7 +3769,6 @@ void GCodeViewer::render_legend(float& legend_height) offsets = calculate_offsets(labels, times, { "Extruder NNN", longest_used_filament_string }, icon_size); } -#if ENABLE_PREVIEW_LAYOUT // selection section bool view_type_changed = false; int old_view_type = static_cast(get_view_type()); @@ -3834,160 +3806,124 @@ void GCodeViewer::render_legend(float& legend_height) append_headers({ _u8L(""), _u8L("Used filament"), _u8L(""), _u8L("") }, offsets); else ImGui::Separator(); -#else - // extrusion paths section -> title - switch (m_view_type) - { - case EViewType::FeatureType: - { - append_headers({ _u8L("Feature type"), _u8L("Time"), _u8L("Percentage"), _u8L("Used filament") }, offsets); - break; - } - case EViewType::Height: { imgui.title(_u8L("Height (mm)")); break; } - case EViewType::Width: { imgui.title(_u8L("Width (mm)")); break; } - case EViewType::Feedrate: { imgui.title(_u8L("Speed (mm/s)")); break; } - case EViewType::FanSpeed: { imgui.title(_u8L("Fan Speed (%)")); break; } - case EViewType::Temperature: { imgui.title(_u8L("Temperature (°C)")); break; } - case EViewType::VolumetricRate: { imgui.title(_u8L("Volumetric flow rate (mm³/s)")); break; } - case EViewType::LayerTimeLinear: { imgui.title(_u8L("Layer time (linear)")); break; } - case EViewType::LayerTimeLogarithmic: { imgui.title(_u8L("Layer time (logarithmic)")); break; } - case EViewType::Tool: { - append_headers({ _u8L("Tool"), _u8L("Used filament") }, offsets); - break; - } - case EViewType::ColorPrint: { imgui.title(_u8L("Color Print")); break; } - default: { break; } - } -#endif // ENABLE_PREVIEW_LAYOUT -#if ENABLE_PREVIEW_LAYOUT if (!view_type_changed) { -#endif // ENABLE_PREVIEW_LAYOUT - // extrusion paths section -> items - switch (m_view_type) - { - case EViewType::FeatureType: - { -#if ENABLE_TRAVEL_TIME - max_time_percent = std::max(max_time_percent, time_mode.travel_time / time_mode.time); -#endif // ENABLE_TRAVEL_TIME + // extrusion paths section -> items + switch (m_view_type) + { + case EViewType::FeatureType: + { + max_time_percent = std::max(max_time_percent, time_mode.travel_time / time_mode.time); - for (size_t i = 0; i < m_roles.size(); ++i) { - ExtrusionRole role = m_roles[i]; - if (role >= erCount) - continue; - const bool visible = is_visible(role); - append_item(EItemType::Rect, Extrusion_Role_Colors[static_cast(role)], labels[i], - visible, times[i], percents[i], max_time_percent, offsets, used_filaments_m[i], used_filaments_g[i], [this, role, visible]() { - m_extrusions.role_visibility_flags = visible ? m_extrusions.role_visibility_flags & ~(1 << role) : m_extrusions.role_visibility_flags | (1 << role); - // update buffers' render paths - refresh_render_paths(false, false); - wxGetApp().plater()->update_preview_moves_slider(); - wxGetApp().plater()->get_current_canvas3D()->set_as_dirty(); -#if !ENABLE_PREVIEW_LAYOUT - wxGetApp().plater()->update_preview_bottom_toolbar(); -#endif // !ENABLE_PREVIEW_LAYOUT - } - ); - } - -#if ENABLE_TRAVEL_TIME - if (m_buffers[buffer_id(EMoveType::Travel)].visible) - append_item(EItemType::Line, Travel_Colors[0], _u8L("Travel"), true, short_time(get_time_dhms(time_mode.travel_time)), - time_mode.travel_time / time_mode.time, max_time_percent, offsets, 0.0f, 0.0f); -#endif // ENABLE_TRAVEL_TIME - - break; - } - case EViewType::Height: { append_range(m_extrusions.ranges.height, 3); break; } - case EViewType::Width: { append_range(m_extrusions.ranges.width, 3); break; } - case EViewType::Feedrate: { append_range(m_extrusions.ranges.feedrate, 1); break; } - case EViewType::FanSpeed: { append_range(m_extrusions.ranges.fan_speed, 0); break; } - case EViewType::Temperature: { append_range(m_extrusions.ranges.temperature, 0); break; } - case EViewType::VolumetricRate: { append_range(m_extrusions.ranges.volumetric_rate, 3); break; } - case EViewType::LayerTimeLinear: { append_time_range(m_extrusions.ranges.layer_time[static_cast(m_time_estimate_mode)], Extrusions::Range::EType::Linear); break; } - case EViewType::LayerTimeLogarithmic: { append_time_range(m_extrusions.ranges.layer_time[static_cast(m_time_estimate_mode)], Extrusions::Range::EType::Logarithmic); break; } - case EViewType::Tool: { - // shows only extruders actually used - for (unsigned char extruder_id : m_extruder_ids) { - if (used_filaments_m[extruder_id] > 0.0 && used_filaments_g[extruder_id] > 0.0) - append_item(EItemType::Rect, m_tool_colors[extruder_id], _u8L("Extruder") + " " + std::to_string(extruder_id + 1), - true, "", 0.0f, 0.0f, offsets, used_filaments_m[extruder_id], used_filaments_g[extruder_id]); - } - break; - } - case EViewType::ColorPrint: - { - const std::vector& custom_gcode_per_print_z = wxGetApp().is_editor() ? wxGetApp().plater()->model().custom_gcode_per_print_z.gcodes : m_custom_gcode_per_print_z; - size_t total_items = 1; - for (unsigned char i : m_extruder_ids) { - total_items += color_print_ranges(i, custom_gcode_per_print_z).size(); - } - - const bool need_scrollable = static_cast(total_items) * icon_size + (static_cast(total_items) - 1.0f) * ImGui::GetStyle().ItemSpacing.y > child_height; - - // add scrollable region, if needed - if (need_scrollable) - ImGui::BeginChild("color_prints", { -1.0f, child_height }, false); - if (m_extruders_count == 1) { // single extruder use case - const std::vector>> cp_values = color_print_ranges(0, custom_gcode_per_print_z); - const int items_cnt = static_cast(cp_values.size()); - if (items_cnt == 0) // There are no color changes, but there are some pause print or custom Gcode - append_item(EItemType::Rect, m_tool_colors.front(), _u8L("Default color")); - else { - for (int i = items_cnt; i >= 0; --i) { - // create label for color change item - if (i == 0) { - append_item(EItemType::Rect, m_tool_colors[0], upto_label(cp_values.front().second.first)); - break; + for (size_t i = 0; i < m_roles.size(); ++i) { + ExtrusionRole role = m_roles[i]; + if (role >= erCount) + continue; + const bool visible = is_visible(role); + append_item(EItemType::Rect, Extrusion_Role_Colors[static_cast(role)], labels[i], + visible, times[i], percents[i], max_time_percent, offsets, used_filaments_m[i], used_filaments_g[i], [this, role, visible]() { + m_extrusions.role_visibility_flags = visible ? m_extrusions.role_visibility_flags & ~(1 << role) : m_extrusions.role_visibility_flags | (1 << role); + // update buffers' render paths + refresh_render_paths(false, false); + wxGetApp().plater()->update_preview_moves_slider(); + wxGetApp().plater()->get_current_canvas3D()->set_as_dirty(); } - else if (i == items_cnt) { - append_item(EItemType::Rect, cp_values[i - 1].first, above_label(cp_values[i - 1].second.second)); - continue; - } - append_item(EItemType::Rect, cp_values[i - 1].first, fromto_label(cp_values[i - 1].second.second, cp_values[i].second.first)); - } + ); } + + if (m_buffers[buffer_id(EMoveType::Travel)].visible) + append_item(EItemType::Line, Travel_Colors[0], _u8L("Travel"), true, short_time(get_time_dhms(time_mode.travel_time)), + time_mode.travel_time / time_mode.time, max_time_percent, offsets, 0.0f, 0.0f); + + break; } - else { // multi extruder use case + case EViewType::Height: { append_range(m_extrusions.ranges.height, 3); break; } + case EViewType::Width: { append_range(m_extrusions.ranges.width, 3); break; } + case EViewType::Feedrate: { append_range(m_extrusions.ranges.feedrate, 1); break; } + case EViewType::FanSpeed: { append_range(m_extrusions.ranges.fan_speed, 0); break; } + case EViewType::Temperature: { append_range(m_extrusions.ranges.temperature, 0); break; } + case EViewType::VolumetricRate: { append_range(m_extrusions.ranges.volumetric_rate, 3); break; } + case EViewType::LayerTimeLinear: { append_time_range(m_extrusions.ranges.layer_time[static_cast(m_time_estimate_mode)], Extrusions::Range::EType::Linear); break; } + case EViewType::LayerTimeLogarithmic: { append_time_range(m_extrusions.ranges.layer_time[static_cast(m_time_estimate_mode)], Extrusions::Range::EType::Logarithmic); break; } + case EViewType::Tool: { // shows only extruders actually used + for (unsigned char extruder_id : m_extruder_ids) { + if (used_filaments_m[extruder_id] > 0.0 && used_filaments_g[extruder_id] > 0.0) + append_item(EItemType::Rect, m_tool_colors[extruder_id], _u8L("Extruder") + " " + std::to_string(extruder_id + 1), + true, "", 0.0f, 0.0f, offsets, used_filaments_m[extruder_id], used_filaments_g[extruder_id]); + } + break; + } + case EViewType::ColorPrint: + { + const std::vector& custom_gcode_per_print_z = wxGetApp().is_editor() ? wxGetApp().plater()->model().custom_gcode_per_print_z.gcodes : m_custom_gcode_per_print_z; + size_t total_items = 1; for (unsigned char i : m_extruder_ids) { - const std::vector>> cp_values = color_print_ranges(i, custom_gcode_per_print_z); + total_items += color_print_ranges(i, custom_gcode_per_print_z).size(); + } + + const bool need_scrollable = static_cast(total_items) * icon_size + (static_cast(total_items) - 1.0f) * ImGui::GetStyle().ItemSpacing.y > child_height; + + // add scrollable region, if needed + if (need_scrollable) + ImGui::BeginChild("color_prints", { -1.0f, child_height }, false); + if (m_extruders_count == 1) { // single extruder use case + const std::vector>> cp_values = color_print_ranges(0, custom_gcode_per_print_z); const int items_cnt = static_cast(cp_values.size()); - if (items_cnt == 0) - // There are no color changes, but there are some pause print or custom Gcode - append_item(EItemType::Rect, m_tool_colors[i], _u8L("Extruder") + " " + std::to_string(i + 1) + " " + _u8L("default color")); + if (items_cnt == 0) // There are no color changes, but there are some pause print or custom Gcode + append_item(EItemType::Rect, m_tool_colors.front(), _u8L("Default color")); else { - for (int j = items_cnt; j >= 0; --j) { + for (int i = items_cnt; i >= 0; --i) { // create label for color change item - std::string label = _u8L("Extruder") + " " + std::to_string(i + 1); - if (j == 0) { - label += " " + upto_label(cp_values.front().second.first); - append_item(EItemType::Rect, m_tool_colors[i], label); + if (i == 0) { + append_item(EItemType::Rect, m_tool_colors[0], upto_label(cp_values.front().second.first)); break; } - else if (j == items_cnt) { - label += " " + above_label(cp_values[j - 1].second.second); - append_item(EItemType::Rect, cp_values[j - 1].first, label); + else if (i == items_cnt) { + append_item(EItemType::Rect, cp_values[i - 1].first, above_label(cp_values[i - 1].second.second)); continue; } - - label += " " + fromto_label(cp_values[j - 1].second.second, cp_values[j].second.first); - append_item(EItemType::Rect, cp_values[j - 1].first, label); + append_item(EItemType::Rect, cp_values[i - 1].first, fromto_label(cp_values[i - 1].second.second, cp_values[i].second.first)); } } } - } - if (need_scrollable) - ImGui::EndChild(); + else { // multi extruder use case + // shows only extruders actually used + for (unsigned char i : m_extruder_ids) { + const std::vector>> cp_values = color_print_ranges(i, custom_gcode_per_print_z); + const int items_cnt = static_cast(cp_values.size()); + if (items_cnt == 0) + // There are no color changes, but there are some pause print or custom Gcode + append_item(EItemType::Rect, m_tool_colors[i], _u8L("Extruder") + " " + std::to_string(i + 1) + " " + _u8L("default color")); + else { + for (int j = items_cnt; j >= 0; --j) { + // create label for color change item + std::string label = _u8L("Extruder") + " " + std::to_string(i + 1); + if (j == 0) { + label += " " + upto_label(cp_values.front().second.first); + append_item(EItemType::Rect, m_tool_colors[i], label); + break; + } + else if (j == items_cnt) { + label += " " + above_label(cp_values[j - 1].second.second); + append_item(EItemType::Rect, cp_values[j - 1].first, label); + continue; + } - break; + label += " " + fromto_label(cp_values[j - 1].second.second, cp_values[j].second.first); + append_item(EItemType::Rect, cp_values[j - 1].first, label); + } + } + } + } + if (need_scrollable) + ImGui::EndChild(); + + break; + } + default: { break; } + } } - default: { break; } - } -#if ENABLE_PREVIEW_LAYOUT - } -#endif // ENABLE_PREVIEW_LAYOUT // partial estimated printing time section if (m_view_type == EViewType::ColorPrint) { @@ -4164,89 +4100,6 @@ void GCodeViewer::render_legend(float& legend_height) } } -#if !ENABLE_PREVIEW_LAYOUT - // travel paths section - if (m_buffers[buffer_id(EMoveType::Travel)].visible) { - switch (m_view_type) - { - case EViewType::Feedrate: - case EViewType::Tool: - case EViewType::ColorPrint: { - break; - } - default: { - // title - ImGui::Spacing(); - imgui.title(_u8L("Travel")); - - // items - append_item(EItemType::Line, Travel_Colors[0], _u8L("Movement")); - append_item(EItemType::Line, Travel_Colors[1], _u8L("Extrusion")); - append_item(EItemType::Line, Travel_Colors[2], _u8L("Retraction")); - - break; - } - } - } - - // wipe paths section - if (m_buffers[buffer_id(EMoveType::Wipe)].visible) { - switch (m_view_type) - { - case EViewType::Feedrate: - case EViewType::Tool: - case EViewType::ColorPrint: { break; } - default: { - // title - ImGui::Spacing(); - imgui.title(_u8L("Wipe")); - - // items - append_item(EItemType::Line, Wipe_Color, _u8L("Wipe")); - - break; - } - } - } - - auto any_option_available = [this]() { - auto available = [this](EMoveType type) { - const TBuffer& buffer = m_buffers[buffer_id(type)]; - return buffer.visible && buffer.has_data(); - }; - - return available(EMoveType::Color_change) || - available(EMoveType::Custom_GCode) || - available(EMoveType::Pause_Print) || - available(EMoveType::Retract) || - available(EMoveType::Tool_change) || - available(EMoveType::Unretract) || - available(EMoveType::Seam); - }; - - auto add_option = [this, append_item](EMoveType move_type, EOptionsColors color, const std::string& text) { - const TBuffer& buffer = m_buffers[buffer_id(move_type)]; - if (buffer.visible && buffer.has_data()) - append_item(EItemType::Circle, Options_Colors[static_cast(color)], text); - }; - - // options section - if (any_option_available()) { - // title - ImGui::Spacing(); - imgui.title(_u8L("Options")); - - // items - add_option(EMoveType::Retract, EOptionsColors::Retractions, _u8L("Retractions")); - add_option(EMoveType::Unretract, EOptionsColors::Unretractions, _u8L("Deretractions")); - add_option(EMoveType::Seam, EOptionsColors::Seams, _u8L("Seams")); - add_option(EMoveType::Tool_change, EOptionsColors::ToolChanges, _u8L("Tool changes")); - add_option(EMoveType::Color_change, EOptionsColors::ColorChanges, _u8L("Color changes")); - add_option(EMoveType::Pause_Print, EOptionsColors::PausePrints, _u8L("Print pauses")); - add_option(EMoveType::Custom_GCode, EOptionsColors::CustomGCodes, _u8L("Custom G-codes")); - } -#endif // !ENABLE_PREVIEW_LAYOUT - auto add_strings_row_to_table = [&imgui](const std::string& col_1, const ImVec4& col_1_color, const std::string& col_2, const ImVec4& col_2_color) { ImGui::TableNextRow(); ImGui::TableSetColumnIndex(0); @@ -4369,7 +4222,6 @@ void GCodeViewer::render_legend(float& legend_height) } } -#if ENABLE_PREVIEW_LAYOUT // toolbar section auto toggle_button = [this, &imgui, icon_size](Preview::OptionType type, const std::string& name, std::function draw_callback) { @@ -4409,7 +4261,6 @@ void GCodeViewer::render_legend(float& legend_height) } }; -#if ENABLE_LEGEND_TOOLBAR_ICONS auto image_icon = [&imgui](ImGuiWindow& window, const ImVec2& pos, float size, const wchar_t& icon_id) { ImGuiIO& io = ImGui::GetIO(); const ImTextureID tex_id = io.Fonts->TexID; @@ -4420,163 +4271,59 @@ void GCodeViewer::render_legend(float& legend_height) const ImVec2 uv1 = { static_cast(rect->X + rect->Width) / tex_w, static_cast(rect->Y + rect->Height) / tex_h }; window.DrawList->AddImage(tex_id, pos, { pos.x + size, pos.y + size }, uv0, uv1, ImGuiWrapper::to_ImU32({ 1.0f, 1.0f, 1.0f, 1.0f })); }; -#else - auto circle_icon = [](ImGuiWindow& window, const ImVec2& pos, float size, const ColorRGBA& color) { - const float margin = 3.0f; - const ImVec2 center(0.5f * (pos.x + pos.x + size), 0.5f * (pos.y + pos.y + size)); - window.DrawList->AddCircleFilled(center, 0.5f * (size - 2.0f * margin), ImGuiWrapper::to_ImU32(color), 16); - }; - auto line_icon = [](ImGuiWindow& window, const ImVec2& pos, float size, const ColorRGBA& color) { - const float margin = 3.0f; - window.DrawList->AddLine({ pos.x + margin, pos.y + size - margin }, { pos.x + size - margin, pos.y + margin }, ImGuiWrapper::to_ImU32(color), 3.0f); - }; -#endif // ENABLE_LEGEND_TOOLBAR_ICONS ImGui::Spacing(); ImGui::Separator(); ImGui::Spacing(); ImGui::Spacing(); -#if ENABLE_LEGEND_TOOLBAR_ICONS toggle_button(Preview::OptionType::Travel, _u8L("Travel"), [image_icon](ImGuiWindow& window, const ImVec2& pos, float size) { image_icon(window, pos, size, ImGui::LegendTravel); -#else - toggle_button(Preview::OptionType::Travel, _u8L("Travel"), [line_icon](ImGuiWindow& window, const ImVec2& pos, float size) { - line_icon(window, pos, size, Travel_Colors[0]); -#endif // ENABLE_LEGEND_TOOLBAR_ICONS }); ImGui::SameLine(); -#if ENABLE_LEGEND_TOOLBAR_ICONS toggle_button(Preview::OptionType::Wipe, _u8L("Wipe"), [image_icon](ImGuiWindow& window, const ImVec2& pos, float size) { image_icon(window, pos, size, ImGui::LegendWipe); -#else - toggle_button(Preview::OptionType::Wipe, _u8L("Wipe"), [line_icon](ImGuiWindow& window, const ImVec2& pos, float size) { - line_icon(window, pos, size, Wipe_Color); -#endif // ENABLE_LEGEND_TOOLBAR_ICONS }); ImGui::SameLine(); -#if ENABLE_LEGEND_TOOLBAR_ICONS toggle_button(Preview::OptionType::Retractions, _u8L("Retractions"), [image_icon](ImGuiWindow& window, const ImVec2& pos, float size) { image_icon(window, pos, size, ImGui::LegendRetract); -#else - toggle_button(Preview::OptionType::Retractions, _u8L("Retractions"), [circle_icon](ImGuiWindow& window, const ImVec2& pos, float size) { - circle_icon(window, pos, size, Options_Colors[static_cast(EOptionsColors::Retractions)]); -#endif // ENABLE_LEGEND_TOOLBAR_ICONS }); ImGui::SameLine(); -#if ENABLE_LEGEND_TOOLBAR_ICONS toggle_button(Preview::OptionType::Unretractions, _u8L("Deretractions"), [image_icon](ImGuiWindow& window, const ImVec2& pos, float size) { image_icon(window, pos, size, ImGui::LegendDeretract); -#else - toggle_button(Preview::OptionType::Unretractions, _u8L("Deretractions"), [circle_icon](ImGuiWindow& window, const ImVec2& pos, float size) { - circle_icon(window, pos, size, Options_Colors[static_cast(EOptionsColors::Unretractions)]); -#endif // ENABLE_LEGEND_TOOLBAR_ICONS }); ImGui::SameLine(); -#if ENABLE_LEGEND_TOOLBAR_ICONS toggle_button(Preview::OptionType::Seams, _u8L("Seams"), [image_icon](ImGuiWindow& window, const ImVec2& pos, float size) { image_icon(window, pos, size, ImGui::LegendSeams); -#else - toggle_button(Preview::OptionType::Seams, _u8L("Seams"), [circle_icon](ImGuiWindow& window, const ImVec2& pos, float size) { - circle_icon(window, pos, size, Options_Colors[static_cast(EOptionsColors::Seams)]); -#endif // ENABLE_LEGEND_TOOLBAR_ICONS }); ImGui::SameLine(); -#if ENABLE_LEGEND_TOOLBAR_ICONS toggle_button(Preview::OptionType::ToolChanges, _u8L("Tool changes"), [image_icon](ImGuiWindow& window, const ImVec2& pos, float size) { image_icon(window, pos, size, ImGui::LegendToolChanges); -#else - toggle_button(Preview::OptionType::ToolChanges, _u8L("Tool changes"), [circle_icon](ImGuiWindow& window, const ImVec2& pos, float size) { - circle_icon(window, pos, size, Options_Colors[static_cast(EOptionsColors::ToolChanges)]); -#endif // ENABLE_LEGEND_TOOLBAR_ICONS }); ImGui::SameLine(); -#if ENABLE_LEGEND_TOOLBAR_ICONS toggle_button(Preview::OptionType::ColorChanges, _u8L("Color changes"), [image_icon](ImGuiWindow& window, const ImVec2& pos, float size) { image_icon(window, pos, size, ImGui::LegendColorChanges); -#else - toggle_button(Preview::OptionType::ColorChanges, _u8L("Color changes"), [circle_icon](ImGuiWindow& window, const ImVec2& pos, float size) { - circle_icon(window, pos, size, Options_Colors[static_cast(EOptionsColors::ColorChanges)]); -#endif // ENABLE_LEGEND_TOOLBAR_ICONS }); ImGui::SameLine(); -#if ENABLE_LEGEND_TOOLBAR_ICONS toggle_button(Preview::OptionType::PausePrints, _u8L("Print pauses"), [image_icon](ImGuiWindow& window, const ImVec2& pos, float size) { image_icon(window, pos, size, ImGui::LegendPausePrints); -#else - toggle_button(Preview::OptionType::PausePrints, _u8L("Print pauses"), [circle_icon](ImGuiWindow& window, const ImVec2& pos, float size) { - circle_icon(window, pos, size, Options_Colors[static_cast(EOptionsColors::PausePrints)]); -#endif // ENABLE_LEGEND_TOOLBAR_ICONS }); ImGui::SameLine(); -#if ENABLE_LEGEND_TOOLBAR_ICONS toggle_button(Preview::OptionType::CustomGCodes, _u8L("Custom G-codes"), [image_icon](ImGuiWindow& window, const ImVec2& pos, float size) { image_icon(window, pos, size, ImGui::LegendCustomGCodes); -#else - toggle_button(Preview::OptionType::CustomGCodes, _u8L("Custom G-codes"), [circle_icon](ImGuiWindow& window, const ImVec2& pos, float size) { - circle_icon(window, pos, size, Options_Colors[static_cast(EOptionsColors::CustomGCodes)]); -#endif // ENABLE_LEGEND_TOOLBAR_ICONS }); ImGui::SameLine(); -#if ENABLE_LEGEND_TOOLBAR_ICONS toggle_button(Preview::OptionType::CenterOfGravity, _u8L("Center of gravity"), [image_icon](ImGuiWindow& window, const ImVec2& pos, float size) { image_icon(window, pos, size, ImGui::LegendCOG); }); -#else - toggle_button(Preview::OptionType::CenterOfGravity, _u8L("Center of gravity"), [](ImGuiWindow& window, const ImVec2& pos, float size) { - const ImU32 black = ImGuiWrapper::to_ImU32({ 0.0f, 0.0f, 0.0f, 1.0f }); - const ImU32 white = ImGuiWrapper::to_ImU32({ 1.0f, 1.0f, 1.0f, 1.0f }); - const float margin = 3.0f; - const ImVec2 center(0.5f * (pos.x + pos.x + size), 0.5f * (pos.y + pos.y + size)); - const float radius = 0.5f * (size - 2.0f * margin); - window.DrawList->PathArcToFast(center, radius, 0, 3); - window.DrawList->PathLineTo(center); - window.DrawList->PathFillConvex(black); - window.DrawList->PathArcToFast(center, radius, 3, 6); - window.DrawList->PathLineTo(center); - window.DrawList->PathFillConvex(white); - window.DrawList->PathArcToFast(center, radius, 6, 9); - window.DrawList->PathLineTo(center); - window.DrawList->PathFillConvex(black); - window.DrawList->PathArcToFast(center, radius, 9, 12); - window.DrawList->PathLineTo(center); - window.DrawList->PathFillConvex(white); - window.DrawList->AddCircle(center, radius, black, 16); - }); -#endif // ENABLE_LEGEND_TOOLBAR_ICONS ImGui::SameLine(); if (!wxGetApp().is_gcode_viewer()) { -#if ENABLE_LEGEND_TOOLBAR_ICONS toggle_button(Preview::OptionType::Shells, _u8L("Shells"), [image_icon](ImGuiWindow& window, const ImVec2& pos, float size) { image_icon(window, pos, size, ImGui::LegendShells); -#else - toggle_button(Preview::OptionType::Shells, _u8L("Shells"), [](ImGuiWindow& window, const ImVec2& pos, float size) { - const ImU32 color = ImGuiWrapper::to_ImU32({ 1.0f, 1.0f, 1.0f, 1.0f }); - const float margin = 3.0f; - const float proj = 0.25f * size; - window.DrawList->AddRect({ pos.x + margin, pos.y + size - margin }, { pos.x + size - margin - proj, pos.y + margin + proj }, color); - window.DrawList->AddLine({ pos.x + margin, pos.y + margin + proj }, { pos.x + margin + proj, pos.y + margin }, color); - window.DrawList->AddLine({ pos.x + size - margin - proj, pos.y + margin + proj }, { pos.x + size - margin, pos.y + margin }, color); - window.DrawList->AddLine({ pos.x + size - margin - proj, pos.y + size - margin }, { pos.x + size - margin, pos.y + size - margin - proj }, color); - window.DrawList->AddLine({ pos.x + margin + proj, pos.y + margin }, { pos.x + size - margin, pos.y + margin }, color); - window.DrawList->AddLine({ pos.x + size - margin, pos.y + margin }, { pos.x + size - margin, pos.y + size - margin - proj }, color); -#endif // ENABLE_LEGEND_TOOLBAR_ICONS }); ImGui::SameLine(); } -#if ENABLE_LEGEND_TOOLBAR_ICONS toggle_button(Preview::OptionType::ToolMarker, _u8L("Tool marker"), [image_icon](ImGuiWindow& window, const ImVec2& pos, float size) { image_icon(window, pos, size, ImGui::LegendToolMarker); -#else - toggle_button(Preview::OptionType::ToolMarker, _u8L("Tool marker"), [](ImGuiWindow& window, const ImVec2& pos, float size) { - const ImU32 color = ImGuiWrapper::to_ImU32({ 1.0f, 1.0f, 1.0f, 0.8f }); - const float margin = 3.0f; - const ImVec2 p1(0.5f * (pos.x + pos.x + size), pos.y + size - margin); - const ImVec2 p2(p1.x + 0.25f * size, p1.y - 0.25f * size); - const ImVec2 p3(p1.x - 0.25f * size, p1.y - 0.25f * size); - window.DrawList->AddTriangleFilled(p1, p2, p3, color); - const float mid_x = 0.5f * (pos.x + pos.x + size); - window.DrawList->AddRectFilled({ mid_x - 0.09375f * size, p1.y - 0.25f * size }, { mid_x + 0.09375f * size, pos.y + margin }, color); -#endif // ENABLE_LEGEND_TOOLBAR_ICONS }); bool size_dirty = !ImGui::GetCurrentWindow()->ScrollbarY && ImGui::CalcWindowNextAutoFitSize(ImGui::GetCurrentWindow()).x != ImGui::GetWindowWidth(); @@ -4585,7 +4332,6 @@ void GCodeViewer::render_legend(float& legend_height) wxGetApp().plater()->get_current_canvas3D()->request_extra_frame(); } m_legend_resizer.dirty = size_dirty; -#endif // ENABLE_PREVIEW_LAYOUT legend_height = ImGui::GetWindowHeight(); diff --git a/src/slic3r/GUI/GCodeViewer.hpp b/src/slic3r/GUI/GCodeViewer.hpp index 6f7f01560..0785f6a04 100644 --- a/src/slic3r/GUI/GCodeViewer.hpp +++ b/src/slic3r/GUI/GCodeViewer.hpp @@ -773,14 +773,12 @@ private: COG m_cog; EViewType m_view_type{ EViewType::FeatureType }; bool m_legend_enabled{ true }; -#if ENABLE_PREVIEW_LAYOUT struct LegendResizer { bool dirty{ true }; void reset() { dirty = true; } }; LegendResizer m_legend_resizer; -#endif // ENABLE_PREVIEW_LAYOUT PrintEstimatedStatistics m_print_statistics; PrintEstimatedStatistics::ETimeMode m_time_estimate_mode{ PrintEstimatedStatistics::ETimeMode::Normal }; #if ENABLE_GCODE_VIEWER_STATISTICS @@ -808,11 +806,7 @@ public: #endif // ENABLE_LEGACY_OPENGL_REMOVAL // recalculate ranges in dependence of what is visible and sets tool/print colors void refresh(const GCodeProcessorResult& gcode_result, const std::vector& str_tool_colors); -#if ENABLE_PREVIEW_LAYOUT void refresh_render_paths(bool keep_sequential_current_first, bool keep_sequential_current_last) const; -#else - void refresh_render_paths(); -#endif // ENABLE_PREVIEW_LAYOUT void update_shells_color_by_extruder(const DynamicPrintConfig* config); void reset(); @@ -857,9 +851,7 @@ public: std::vector& get_custom_gcode_per_print_z() { return m_custom_gcode_per_print_z; } size_t get_extruders_count() { return m_extruders_count; } -#if ENABLE_PREVIEW_LAYOUT void invalidate_legend() { m_legend_resizer.reset(); } -#endif // ENABLE_PREVIEW_LAYOUT private: void load_toolpaths(const GCodeProcessorResult& gcode_result); @@ -868,9 +860,6 @@ private: #else void load_shells(const Print& print, bool initialized); #endif // ENABLE_LEGACY_OPENGL_REMOVAL -#if !ENABLE_PREVIEW_LAYOUT - void refresh_render_paths(bool keep_sequential_current_first, bool keep_sequential_current_last) const; -#endif // !ENABLE_PREVIEW_LAYOUT void render_toolpaths(); void render_shells(); void render_legend(float& legend_height); diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 0284554af..1945aceea 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -2506,21 +2506,12 @@ void GLCanvas3D::load_gcode_preview(const GCodeProcessorResult& gcode_result, co request_extra_frame(); } -#if ENABLE_PREVIEW_LAYOUT void GLCanvas3D::refresh_gcode_preview_render_paths(bool keep_sequential_current_first, bool keep_sequential_current_last) { m_gcode_viewer.refresh_render_paths(keep_sequential_current_first, keep_sequential_current_last); set_as_dirty(); request_extra_frame(); } -#else -void GLCanvas3D::refresh_gcode_preview_render_paths() -{ - m_gcode_viewer.refresh_render_paths(); - set_as_dirty(); - request_extra_frame(); -} -#endif // ENABLE_PREVIEW_LAYOUT void GLCanvas3D::load_sla_preview() { @@ -2827,15 +2818,8 @@ void GLCanvas3D::on_char(wxKeyEvent& evt) case 'k': { wxGetApp().plater()->get_camera().select_next_type(); m_dirty = true; break; } case 'L': case 'l': { - if (!m_main_toolbar.is_enabled()) { -#if ENABLE_PREVIEW_LAYOUT + if (!m_main_toolbar.is_enabled()) show_legend(!is_legend_shown()); -#else - m_gcode_viewer.enable_legend(!m_gcode_viewer.is_legend_enabled()); - m_dirty = true; - wxGetApp().plater()->update_preview_bottom_toolbar(); -#endif // ENABLE_PREVIEW_LAYOUT - } break; } case 'O': @@ -4302,9 +4286,7 @@ void GLCanvas3D::set_cursor(ECursorType type) void GLCanvas3D::msw_rescale() { -#if ENABLE_PREVIEW_LAYOUT m_gcode_viewer.invalidate_legend(); -#endif // ENABLE_PREVIEW_LAYOUT } void GLCanvas3D::update_tooltip_for_settings_item_in_main_toolbar() diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index 1fd24f9ab..8cb0b0e2e 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -817,11 +817,7 @@ public: void reload_scene(bool refresh_immediately, bool force_full_scene_refresh = false); void load_gcode_preview(const GCodeProcessorResult& gcode_result, const std::vector& str_tool_colors); -#if ENABLE_PREVIEW_LAYOUT void refresh_gcode_preview_render_paths(bool keep_sequential_current_first, bool keep_sequential_current_last); -#else - void refresh_gcode_preview_render_paths(); -#endif // ENABLE_PREVIEW_LAYOUT void set_gcode_view_preview_type(GCodeViewer::EViewType type) { return m_gcode_viewer.set_view_type(type); } GCodeViewer::EViewType get_gcode_view_preview_type() const { return m_gcode_viewer.get_view_type(); } void load_sla_preview(); @@ -921,10 +917,8 @@ public: bool are_labels_shown() const { return m_labels.is_shown(); } void show_labels(bool show) { m_labels.show(show); } -#if ENABLE_PREVIEW_LAYOUT bool is_legend_shown() const { return m_gcode_viewer.is_legend_enabled(); } void show_legend(bool show) { m_gcode_viewer.enable_legend(show); m_dirty = true; } -#endif // ENABLE_PREVIEW_LAYOUT bool is_using_slope() const { return m_slope.is_used(); } void use_slope(bool use) { m_slope.use(use); } diff --git a/src/slic3r/GUI/GUI_Preview.cpp b/src/slic3r/GUI/GUI_Preview.cpp index 4f965e604..7989c3cdc 100644 --- a/src/slic3r/GUI/GUI_Preview.cpp +++ b/src/slic3r/GUI/GUI_Preview.cpp @@ -208,73 +208,6 @@ bool Preview::init(wxWindow* parent, Bed3D& bed, Model* model) m_layers_slider_sizer = create_layers_slider_sizer(); wxGetApp().UpdateDarkUI(m_bottom_toolbar_panel = new wxPanel(this)); -#if !ENABLE_PREVIEW_LAYOUT - m_label_view_type = new wxStaticText(m_bottom_toolbar_panel, wxID_ANY, _L("View")); -#ifdef _WIN32 - wxGetApp().UpdateDarkUI(m_choice_view_type = new BitmapComboBox(m_bottom_toolbar_panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0, NULL, wxCB_READONLY)); -#else - m_choice_view_type = new wxComboBox(m_bottom_toolbar_panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0, NULL, wxCB_READONLY); -#endif - m_choice_view_type->Append(_L("Feature type")); - m_choice_view_type->Append(_L("Height")); - m_choice_view_type->Append(_L("Width")); - m_choice_view_type->Append(_L("Speed")); - m_choice_view_type->Append(_L("Fan speed")); - m_choice_view_type->Append(_L("Temperature")); - m_choice_view_type->Append(_L("Volumetric flow rate")); - m_choice_view_type->Append(_L("Layer time (linear)")); - m_choice_view_type->Append(_L("Layer time (logarithmic)")); - m_choice_view_type->Append(_L("Tool")); - m_choice_view_type->Append(_L("Color Print")); - m_choice_view_type->SetSelection(0); - - m_label_show = new wxStaticText(m_bottom_toolbar_panel, wxID_ANY, _L("Show")); - -#ifdef _WIN32 - long combo_style = wxCB_READONLY | wxBORDER_SIMPLE; //set border allows use default color instead of theme color wich is allways light under MSW -#else - long combo_style = wxCB_READONLY; -#endif - - m_combochecklist_features = new wxComboCtrl(); - m_combochecklist_features->Create(m_bottom_toolbar_panel, wxID_ANY, _L("Feature types"), wxDefaultPosition, wxDefaultSize, combo_style); - std::string feature_items = GUI::into_u8( - _L("Unknown") + "|1|" + - _L("Perimeter") + "|1|" + - _L("External perimeter") + "|1|" + - _L("Overhang perimeter") + "|1|" + - _L("Internal infill") + "|1|" + - _L("Solid infill") + "|1|" + - _L("Top solid infill") + "|1|" + - _L("Ironing") + "|1|" + - _L("Bridge infill") + "|1|" + - _L("Gap fill") + "|1|" + - _L("Skirt/Brim") + "|1|" + - _L("Support material") + "|1|" + - _L("Support material interface") + "|1|" + - _L("Wipe tower") + "|1|" + - _L("Custom") + "|1" - ); - Slic3r::GUI::create_combochecklist(m_combochecklist_features, GUI::into_u8(_L("Feature types")), feature_items); - - m_combochecklist_options = new wxComboCtrl(); - m_combochecklist_options->Create(m_bottom_toolbar_panel, wxID_ANY, _L("Options"), wxDefaultPosition, wxDefaultSize, combo_style); - std::string options_items = GUI::into_u8( - get_option_type_string(OptionType::Travel) + "|0|" + - get_option_type_string(OptionType::Wipe) + "|0|" + - get_option_type_string(OptionType::Retractions) + "|0|" + - get_option_type_string(OptionType::Unretractions) + "|0|" + - get_option_type_string(OptionType::Seams) + "|0|" + - get_option_type_string(OptionType::ToolChanges) + "|0|" + - get_option_type_string(OptionType::ColorChanges) + "|0|" + - get_option_type_string(OptionType::PausePrints) + "|0|" + - get_option_type_string(OptionType::CustomGCodes) + "|0|" + - get_option_type_string(OptionType::Shells) + "|0|" + - get_option_type_string(OptionType::ToolMarker) + "|1|" + - get_option_type_string(OptionType::Legend) + "|1" - ); - Slic3r::GUI::create_combochecklist(m_combochecklist_options, GUI::into_u8(_L("Options")), options_items); -#endif // !ENABLE_PREVIEW_LAYOUT m_left_sizer = new wxBoxSizer(wxVERTICAL); m_left_sizer->Add(m_canvas_widget, 1, wxALL | wxEXPAND, 0); @@ -286,19 +219,6 @@ bool Preview::init(wxWindow* parent, Bed3D& bed, Model* model) m_moves_slider->SetDrawMode(DoubleSlider::dmSequentialGCodeView); wxBoxSizer* bottom_toolbar_sizer = new wxBoxSizer(wxHORIZONTAL); -#if !ENABLE_PREVIEW_LAYOUT - bottom_toolbar_sizer->AddSpacer(5); - bottom_toolbar_sizer->Add(m_label_view_type, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 5); - bottom_toolbar_sizer->Add(m_choice_view_type, 0, wxALIGN_CENTER_VERTICAL, 0); - bottom_toolbar_sizer->AddSpacer(5); - bottom_toolbar_sizer->Add(m_label_show, 0, wxALIGN_CENTER_VERTICAL | wxLEFT | wxRIGHT, 5); - bottom_toolbar_sizer->Add(m_combochecklist_options, 0, wxALIGN_CENTER_VERTICAL, 0); - // change the following number if editing the layout of the bottom toolbar sizer. It is used into update_bottom_toolbar() - m_combochecklist_features_pos = 6; - bottom_toolbar_sizer->Add(m_combochecklist_features, 0, wxALIGN_CENTER_VERTICAL | wxLEFT, 5); - bottom_toolbar_sizer->Hide(m_combochecklist_features); - bottom_toolbar_sizer->AddSpacer(5); -#endif // !ENABLE_PREVIEW_LAYOUT bottom_toolbar_sizer->Add(m_moves_slider, 1, wxALL | wxEXPAND, 0); m_bottom_toolbar_panel->SetSizer(bottom_toolbar_sizer); @@ -360,9 +280,6 @@ void Preview::load_print(bool keep_z_range) else if (tech == ptSLA) load_print_as_sla(); -#if !ENABLE_PREVIEW_LAYOUT - update_bottom_toolbar(); -#endif // !ENABLE_PREVIEW_LAYOUT Layout(); } @@ -405,12 +322,6 @@ void Preview::refresh_print() void Preview::msw_rescale() { -#if !ENABLE_PREVIEW_LAYOUT -#ifdef _WIN32 - m_choice_view_type->Rescale(); - m_choice_view_type->SetMinSize(m_choice_view_type->GetSize()); -#endif -#endif // !ENABLE_PREVIEW_LAYOUT // rescale slider if (m_layers_slider != nullptr) m_layers_slider->msw_rescale(); if (m_moves_slider != nullptr) m_moves_slider->msw_rescale(); @@ -426,16 +337,8 @@ void Preview::sys_color_changed() { #ifdef _WIN32 wxWindowUpdateLocker noUpdates(this); - wxGetApp().UpdateAllStaticTextDarkUI(m_bottom_toolbar_panel); -#if !ENABLE_PREVIEW_LAYOUT - wxGetApp().UpdateDarkUI(m_choice_view_type); - wxGetApp().UpdateDarkUI(m_combochecklist_features); - wxGetApp().UpdateDarkUI(static_cast(m_combochecklist_features->GetPopupControl())); - wxGetApp().UpdateDarkUI(m_combochecklist_options); - wxGetApp().UpdateDarkUI(static_cast(m_combochecklist_options->GetPopupControl())); -#endif // !ENABLE_PREVIEW_LAYOUT -#endif +#endif // _WIN32 if (m_layers_slider != nullptr) m_layers_slider->sys_color_changed(); @@ -459,22 +362,12 @@ void Preview::edit_layers_slider(wxKeyEvent& evt) void Preview::bind_event_handlers() { Bind(wxEVT_SIZE, &Preview::on_size, this); -#if !ENABLE_PREVIEW_LAYOUT - m_choice_view_type->Bind(wxEVT_COMBOBOX, &Preview::on_choice_view_type, this); - m_combochecklist_features->Bind(wxEVT_CHECKLISTBOX, &Preview::on_combochecklist_features, this); - m_combochecklist_options->Bind(wxEVT_CHECKLISTBOX, &Preview::on_combochecklist_options, this); -#endif // !ENABLE_PREVIEW_LAYOUT m_moves_slider->Bind(wxEVT_SCROLL_CHANGED, &Preview::on_moves_slider_scroll_changed, this); } void Preview::unbind_event_handlers() { Unbind(wxEVT_SIZE, &Preview::on_size, this); -#if !ENABLE_PREVIEW_LAYOUT - m_choice_view_type->Unbind(wxEVT_COMBOBOX, &Preview::on_choice_view_type, this); - m_combochecklist_features->Unbind(wxEVT_CHECKLISTBOX, &Preview::on_combochecklist_features, this); - m_combochecklist_options->Unbind(wxEVT_CHECKLISTBOX, &Preview::on_combochecklist_options, this); -#endif // !ENABLE_PREVIEW_LAYOUT m_moves_slider->Unbind(wxEVT_SCROLL_CHANGED, &Preview::on_moves_slider_scroll_changed, this); } @@ -495,75 +388,6 @@ void Preview::on_size(wxSizeEvent& evt) Refresh(); } -#if !ENABLE_PREVIEW_LAYOUT -void Preview::on_choice_view_type(wxCommandEvent& evt) -{ - int selection = m_choice_view_type->GetCurrentSelection(); - if (0 <= selection && selection < static_cast(GCodeViewer::EViewType::Count)) { - m_canvas->set_toolpath_view_type(static_cast(selection)); - m_keep_current_preview_type = true; - } - refresh_print(); -} - -void Preview::on_combochecklist_features(wxCommandEvent& evt) -{ - unsigned int flags = Slic3r::GUI::combochecklist_get_flags(m_combochecklist_features); - m_canvas->set_toolpath_role_visibility_flags(flags); - refresh_print(); -} - -void Preview::on_combochecklist_options(wxCommandEvent& evt) -{ - const unsigned int curr_flags = m_canvas->get_gcode_options_visibility_flags(); - const unsigned int new_flags = Slic3r::GUI::combochecklist_get_flags(m_combochecklist_options); - if (curr_flags == new_flags) - return; - - m_canvas->set_gcode_options_visibility_from_flags(new_flags); - 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(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(); -} - -void Preview::update_bottom_toolbar() -{ - combochecklist_set_flags(m_combochecklist_features, m_canvas->get_toolpath_role_visibility_flags()); - combochecklist_set_flags(m_combochecklist_options, m_canvas->get_gcode_options_visibility_flags()); - - // updates visibility of features combobox - if (m_bottom_toolbar_panel->IsShown()) { - wxSizer* sizer = m_bottom_toolbar_panel->GetSizer(); - bool show = !m_canvas->is_gcode_legend_enabled() || m_canvas->get_gcode_view_type() != GCodeViewer::EViewType::FeatureType; - - if (show) { - if (sizer->GetItem(m_combochecklist_features) == nullptr) { - sizer->Insert(m_combochecklist_features_pos, m_combochecklist_features, 0, wxALIGN_CENTER_VERTICAL | wxLEFT, 5); - sizer->Show(m_combochecklist_features); - sizer->Layout(); - Refresh(); - } - } - else { - if (sizer->GetItem(m_combochecklist_features) != nullptr) { - sizer->Hide(m_combochecklist_features); - sizer->Detach(m_combochecklist_features); - sizer->Layout(); - Refresh(); - } - } - } -} -#endif // !ENABLE_PREVIEW_LAYOUT - wxBoxSizer* Preview::create_layers_slider_sizer() { wxBoxSizer* sizer = new wxBoxSizer(wxHORIZONTAL); @@ -1022,7 +846,6 @@ void Preview::load_print_as_fff(bool keep_z_range) m_canvas->get_custom_gcode_per_print_z(); const bool contains_color_gcodes = std::any_of(std::begin(gcodes), std::end(gcodes), [] (auto const& item) { return item.type == CustomGCode::Type::ColorChange; }); -#if ENABLE_PREVIEW_LAYOUT const GCodeViewer::EViewType choice = contains_color_gcodes ? GCodeViewer::EViewType::ColorPrint : (number_extruders > 1) ? GCodeViewer::EViewType::Tool : GCodeViewer::EViewType::FeatureType; @@ -1032,21 +855,6 @@ void Preview::load_print_as_fff(bool keep_z_range) m_keep_current_preview_type = true; refresh_print(); } -#else - const wxString choice = contains_color_gcodes ? - _L("Color Print") : - (number_extruders > 1) ? _L("Tool") : _L("Feature type"); - int type = m_choice_view_type->FindString(choice); - if (m_choice_view_type->GetSelection() != type) { - if (0 <= type && type < static_cast(GCodeViewer::EViewType::Count)) { - m_choice_view_type->SetSelection(type); - m_canvas->set_gcode_view_preview_type(static_cast(type)); - if (wxGetApp().is_gcode_viewer()) - m_keep_current_preview_type = true; - refresh_print(); - } - } -#endif // ENABLE_PREVIEW_LAYOUT } if (zs.empty()) { @@ -1121,27 +929,5 @@ void Preview::on_moves_slider_scroll_changed(wxCommandEvent& event) m_canvas->render(); } -#if !ENABLE_PREVIEW_LAYOUT -wxString Preview::get_option_type_string(OptionType type) const -{ - switch (type) - { - case OptionType::Travel: { return _L("Travel"); } - case OptionType::Wipe: { return _L("Wipe"); } - case OptionType::Retractions: { return _L("Retractions"); } - case OptionType::Unretractions: { return _L("Deretractions"); } - case OptionType::Seams: { return _L("Seams"); } - case OptionType::ToolChanges: { return _L("Tool changes"); } - case OptionType::ColorChanges: { return _L("Color changes"); } - case OptionType::PausePrints: { return _L("Print pauses"); } - case OptionType::CustomGCodes: { return _L("Custom G-codes"); } - case OptionType::Shells: { return _L("Shells"); } - case OptionType::ToolMarker: { return _L("Tool marker"); } - case OptionType::Legend: { return _L("Legend/Estimated printing time"); } - default: { return ""; } - } -} -#endif // !ENABLE_PREVIEW_LAYOUT - } // namespace GUI } // namespace Slic3r diff --git a/src/slic3r/GUI/GUI_Preview.hpp b/src/slic3r/GUI/GUI_Preview.hpp index 1137f11b9..25d9fe084 100644 --- a/src/slic3r/GUI/GUI_Preview.hpp +++ b/src/slic3r/GUI/GUI_Preview.hpp @@ -80,18 +80,6 @@ class Preview : public wxPanel wxBoxSizer* m_left_sizer { nullptr }; wxBoxSizer* m_layers_slider_sizer { nullptr }; wxPanel* m_bottom_toolbar_panel { nullptr }; -#if !ENABLE_PREVIEW_LAYOUT - wxStaticText* m_label_view_type { nullptr }; -#ifdef _WIN32 - BitmapComboBox* m_choice_view_type { nullptr }; -#else - wxComboBox* m_choice_view_type { nullptr }; -#endif - wxStaticText* m_label_show{ nullptr }; - wxComboCtrl* m_combochecklist_features { nullptr }; - size_t m_combochecklist_features_pos { 0 }; - wxComboCtrl* m_combochecklist_options { nullptr }; -#endif // !ENABLE_PREVIEW_LAYOUT DynamicPrintConfig* m_config; BackgroundSlicingProcess* m_process; @@ -129,9 +117,6 @@ public: CenterOfGravity, Shells, ToolMarker, -#if !ENABLE_PREVIEW_LAYOUT - Legend -#endif // !ENABLE_PREVIEW_LAYOUT }; Preview(wxWindow* parent, Bed3D& bed, Model* model, DynamicPrintConfig* config, BackgroundSlicingProcess* process, @@ -159,17 +144,12 @@ public: bool is_loaded() const { return m_loaded; } -#if !ENABLE_PREVIEW_LAYOUT - void update_bottom_toolbar(); -#endif // !ENABLE_PREVIEW_LAYOUT void update_moves_slider(); void enable_moves_slider(bool enable); void move_moves_slider(wxKeyEvent& evt); void hide_layers_slider(); -#if ENABLE_PREVIEW_LAYOUT void set_keep_current_preview_type(bool value) { m_keep_current_preview_type = value; } -#endif // ENABLE_PREVIEW_LAYOUT private: bool init(wxWindow* parent, Bed3D& bed, Model* model); @@ -178,11 +158,6 @@ private: void unbind_event_handlers(); void on_size(wxSizeEvent& evt); -#if !ENABLE_PREVIEW_LAYOUT - void on_choice_view_type(wxCommandEvent& evt); - void on_combochecklist_features(wxCommandEvent& evt); - void on_combochecklist_options(wxCommandEvent& evt); -#endif // !ENABLE_PREVIEW_LAYOUT // Create/Update/Reset double slider on 3dPreview wxBoxSizer* create_layers_slider_sizer(); @@ -199,9 +174,6 @@ private: void on_layers_slider_scroll_changed(wxCommandEvent& event); void on_moves_slider_scroll_changed(wxCommandEvent& event); -#if !ENABLE_PREVIEW_LAYOUT - wxString get_option_type_string(OptionType type) const; -#endif // !ENABLE_PREVIEW_LAYOUT }; } // namespace GUI diff --git a/src/slic3r/GUI/ImGuiWrapper.cpp b/src/slic3r/GUI/ImGuiWrapper.cpp index 79d809947..4cbbca9ca 100644 --- a/src/slic3r/GUI/ImGuiWrapper.cpp +++ b/src/slic3r/GUI/ImGuiWrapper.cpp @@ -62,20 +62,18 @@ static const std::map font_icons = { }; static const std::map font_icons_large = { -#if ENABLE_LEGEND_TOOLBAR_ICONS - {ImGui::LegendTravel , "legend_travel" }, - {ImGui::LegendWipe , "legend_wipe" }, - {ImGui::LegendRetract , "legend_retract" }, - {ImGui::LegendDeretract , "legend_deretract" }, - {ImGui::LegendSeams , "legend_seams" }, - {ImGui::LegendToolChanges , "legend_toolchanges" }, - {ImGui::LegendColorChanges , "legend_colorchanges" }, - {ImGui::LegendPausePrints , "legend_pauseprints" }, - {ImGui::LegendCustomGCodes , "legend_customgcodes" }, - {ImGui::LegendCOG , "legend_cog" }, - {ImGui::LegendShells , "legend_shells" }, - {ImGui::LegendToolMarker , "legend_toolmarker" }, -#endif // ENABLE_LEGEND_TOOLBAR_ICONS + {ImGui::LegendTravel , "legend_travel" }, + {ImGui::LegendWipe , "legend_wipe" }, + {ImGui::LegendRetract , "legend_retract" }, + {ImGui::LegendDeretract , "legend_deretract" }, + {ImGui::LegendSeams , "legend_seams" }, + {ImGui::LegendToolChanges , "legend_toolchanges" }, + {ImGui::LegendColorChanges , "legend_colorchanges" }, + {ImGui::LegendPausePrints , "legend_pauseprints" }, + {ImGui::LegendCustomGCodes , "legend_customgcodes" }, + {ImGui::LegendCOG , "legend_cog" }, + {ImGui::LegendShells , "legend_shells" }, + {ImGui::LegendToolMarker , "legend_toolmarker" }, {ImGui::CloseNotifButton , "notification_close" }, {ImGui::CloseNotifHoverButton , "notification_close_hover" }, {ImGui::EjectButton , "notification_eject_sd" }, @@ -423,7 +421,6 @@ bool ImGuiWrapper::radio_button(const wxString &label, bool active) return ImGui::RadioButton(label_utf8.c_str(), active); } -#if ENABLE_PREVIEW_LAYOUT bool ImGuiWrapper::draw_radio_button(const std::string& name, float size, bool active, std::function draw_callback) { @@ -457,7 +454,6 @@ bool ImGuiWrapper::draw_radio_button(const std::string& name, float size, bool a IMGUI_TEST_ENGINE_ITEM_INFO(id, label, window.DC.LastItemStatusFlags); return pressed; } -#endif // ENABLE_PREVIEW_LAYOUT bool ImGuiWrapper::input_double(const std::string &label, const double &value, const std::string &format) { @@ -602,7 +598,6 @@ bool ImGuiWrapper::slider_float(const char* label, float* v, float v_min, float ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, { 1, style.ItemSpacing.y }); ImGui::SameLine(); -#if ENABLE_LEGEND_TOOLBAR_ICONS ImGuiIO& io = ImGui::GetIO(); assert(io.Fonts->TexWidth > 0 && io.Fonts->TexHeight > 0); float inv_tex_w = 1.0f / float(io.Fonts->TexWidth); @@ -612,13 +607,11 @@ bool ImGuiWrapper::slider_float(const char* label, float* v, float v_min, float const ImVec2 size = { float(rect->Width), float(rect->Height) }; const ImVec2 uv0 = ImVec2(float(rect->X) * inv_tex_w, float(rect->Y) * inv_tex_h); const ImVec2 uv1 = ImVec2(float(rect->X + rect->Width) * inv_tex_w, float(rect->Y + rect->Height) * inv_tex_h); -#endif // ENABLE_LEGEND_TOOLBAR_ICONS ImGui::PushStyleColor(ImGuiCol_Button, { 0.25f, 0.25f, 0.25f, 0.0f }); ImGui::PushStyleColor(ImGuiCol_ButtonHovered, { 0.4f, 0.4f, 0.4f, 1.0f }); ImGui::PushStyleColor(ImGuiCol_ButtonActive, { 0.4f, 0.4f, 0.4f, 1.0f }); -#if ENABLE_LEGEND_TOOLBAR_ICONS const ImTextureID tex_id = io.Fonts->TexID; if (image_button(tex_id, size, uv0, uv1, -1, ImVec4(0.0, 0.0, 0.0, 0.0), ImVec4(1.0, 1.0, 1.0, 1.0), ImGuiButtonFlags_PressedOnClick)) { if (!slider_editing) @@ -627,13 +620,6 @@ bool ImGuiWrapper::slider_float(const char* label, float* v, float v_min, float ImGui::ClearActiveID(); this->set_requires_extra_frame(); } -#else - std::wstring btn_name = ImGui::SliderFloatEditBtnIcon + boost::nowide::widen(str_label); - if (ImGui::Button(into_u8(btn_name).c_str())) { - ImGui::SetKeyboardFocusHere(-1); - this->set_requires_extra_frame(); - } -#endif // ENABLE_LEGEND_TOOLBAR_ICONS ImGui::PopStyleColor(3); @@ -715,14 +701,10 @@ bool ImGuiWrapper::image_button(ImTextureID user_texture_id, const ImVec2& size, bool ImGuiWrapper::combo(const wxString& label, const std::vector& options, int& selection, ImGuiComboFlags flags) { // this is to force the label to the left of the widget: -#if ENABLE_PREVIEW_LAYOUT if (!label.empty()) { -#endif // ENABLE_PREVIEW_LAYOUT text(label); ImGui::SameLine(); -#if ENABLE_PREVIEW_LAYOUT } -#endif // ENABLE_PREVIEW_LAYOUT int selection_out = selection; bool res = false; @@ -1172,13 +1154,11 @@ bool ImGuiWrapper::want_any_input() const return io.WantCaptureMouse || io.WantCaptureKeyboard || io.WantTextInput; } -#if ENABLE_LEGEND_TOOLBAR_ICONS ImFontAtlasCustomRect* ImGuiWrapper::GetTextureCustomRect(const wchar_t& tex_id) { auto item = m_custom_glyph_rects_ids.find(tex_id); return (item != m_custom_glyph_rects_ids.end()) ? ImGui::GetIO().Fonts->GetCustomRectByIndex(m_custom_glyph_rects_ids[tex_id]) : nullptr; } -#endif // ENABLE_LEGEND_TOOLBAR_ICONS ImU32 ImGuiWrapper::to_ImU32(const ColorRGBA& color) { @@ -1602,7 +1582,6 @@ void ImGuiWrapper::init_font(bool compress) int rect_id = io.Fonts->CustomRects.Size; // id of the rectangle added next // add rectangles for the icons to the font atlas -#if ENABLE_LEGEND_TOOLBAR_ICONS for (auto& icon : font_icons) { m_custom_glyph_rects_ids[icon.first] = io.Fonts->AddCustomRectFontGlyph(font, icon.first, icon_sz, icon_sz, 3.0 * font_scale + icon_sz); @@ -1614,15 +1593,7 @@ void ImGuiWrapper::init_font(bool compress) for (auto& icon : font_icons_extra_large) { m_custom_glyph_rects_ids[icon.first] = io.Fonts->AddCustomRectFontGlyph(font, icon.first, icon_sz * 4, icon_sz * 4, 3.0 * font_scale + icon_sz * 4); -} -#else - for (auto& icon : font_icons) - io.Fonts->AddCustomRectFontGlyph(font, icon.first, icon_sz, icon_sz, 3.0 * font_scale + icon_sz); - for (auto& icon : font_icons_large) - io.Fonts->AddCustomRectFontGlyph(font, icon.first, icon_sz * 2, icon_sz * 2, 3.0 * font_scale + icon_sz * 2); - for (auto& icon : font_icons_extra_large) - io.Fonts->AddCustomRectFontGlyph(font, icon.first, icon_sz * 4, icon_sz * 4, 3.0 * font_scale + icon_sz * 4); -#endif // ENABLE_LEGEND_TOOLBAR_ICONS + } // Build texture atlas unsigned char* pixels; diff --git a/src/slic3r/GUI/ImGuiWrapper.hpp b/src/slic3r/GUI/ImGuiWrapper.hpp index dd5ceb991..02536ed40 100644 --- a/src/slic3r/GUI/ImGuiWrapper.hpp +++ b/src/slic3r/GUI/ImGuiWrapper.hpp @@ -23,9 +23,7 @@ class wxString; class wxMouseEvent; class wxKeyEvent; -#if ENABLE_PREVIEW_LAYOUT struct IMGUI_API ImGuiWindow; -#endif // ENABLE_PREVIEW_LAYOUT namespace Slic3r { namespace GUI { @@ -42,9 +40,7 @@ class ImGuiWrapper bool m_disabled{ false }; bool m_new_frame_open{ false }; bool m_requires_extra_frame{ false }; -#if ENABLE_LEGEND_TOOLBAR_ICONS std::map m_custom_glyph_rects_ids; -#endif // ENABLE_LEGEND_TOOLBAR_ICONS std::string m_clipboard_text; public: @@ -99,9 +95,7 @@ public: bool button(const wxString& label, float width, float height); bool button(const wxString& label, const ImVec2 &size, bool enable); // default size = ImVec2(0.f, 0.f) bool radio_button(const wxString &label, bool active); -#if ENABLE_PREVIEW_LAYOUT bool draw_radio_button(const std::string& name, float size, bool active, std::function draw_callback); -#endif // ENABLE_PREVIEW_LAYOUT bool input_double(const std::string &label, const double &value, const std::string &format = "%.3f"); bool input_double(const wxString &label, const double &value, const std::string &format = "%.3f"); bool input_vec3(const std::string &label, const Vec3d &value, float width, const std::string &format = "%.3f"); @@ -221,9 +215,7 @@ public: static ColorRGBA from_ImU32(const ImU32& color); static ColorRGBA from_ImVec4(const ImVec4& color); -#if ENABLE_LEGEND_TOOLBAR_ICONS ImFontAtlasCustomRect* GetTextureCustomRect(const wchar_t& tex_id); -#endif // ENABLE_LEGEND_TOOLBAR_ICONS static const ImVec4 COL_GREY_DARK; static const ImVec4 COL_GREY_LIGHT; diff --git a/src/slic3r/GUI/MainFrame.cpp b/src/slic3r/GUI/MainFrame.cpp index df531c562..96959f33b 100644 --- a/src/slic3r/GUI/MainFrame.cpp +++ b/src/slic3r/GUI/MainFrame.cpp @@ -1494,11 +1494,9 @@ void MainFrame::init_menubar_as_editor() append_menu_check_item(viewMenu, wxID_ANY, _L("Show &Labels") + sep + "E", _L("Show object/instance labels in 3D scene"), [this](wxCommandEvent&) { m_plater->show_view3D_labels(!m_plater->are_view3D_labels_shown()); }, this, [this]() { return m_plater->is_view3D_shown(); }, [this]() { return m_plater->are_view3D_labels_shown(); }, this); -#if ENABLE_PREVIEW_LAYOUT append_menu_check_item(viewMenu, wxID_ANY, _L("Show Legen&d") + sep + "L", _L("Show legend in preview"), [this](wxCommandEvent&) { m_plater->show_legend(!m_plater->is_legend_shown()); }, this, [this]() { return m_plater->is_preview_shown(); }, [this]() { return m_plater->is_legend_shown(); }, this); -#endif // ENABLE_PREVIEW_LAYOUT append_menu_check_item(viewMenu, wxID_ANY, _L("&Collapse Sidebar") + sep + "Shift+" + sep_space + "Tab", _L("Collapse sidebar"), [this](wxCommandEvent&) { m_plater->collapse_sidebar(!m_plater->is_sidebar_collapsed()); }, this, []() { return true; }, [this]() { return m_plater->is_sidebar_collapsed(); }, this); @@ -1616,12 +1614,10 @@ void MainFrame::init_menubar_as_gcodeviewer() if (m_plater != nullptr) { viewMenu = new wxMenu(); add_common_view_menu_items(viewMenu, this, std::bind(&MainFrame::can_change_view, this)); -#if ENABLE_PREVIEW_LAYOUT viewMenu->AppendSeparator(); append_menu_check_item(viewMenu, wxID_ANY, _L("Show legen&d") + sep + "L", _L("Show legend"), [this](wxCommandEvent&) { m_plater->show_legend(!m_plater->is_legend_shown()); }, this, [this]() { return m_plater->is_preview_shown(); }, [this]() { return m_plater->is_legend_shown(); }, this); -#endif // ENABLE_PREVIEW_LAYOUT } // helpmenu diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 9b212f5b1..aa218d576 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -1767,10 +1767,8 @@ struct Plater::priv bool are_view3D_labels_shown() const { return (current_panel == view3D) && view3D->get_canvas3d()->are_labels_shown(); } void show_view3D_labels(bool show) { if (current_panel == view3D) view3D->get_canvas3d()->show_labels(show); } -#if ENABLE_PREVIEW_LAYOUT bool is_legend_shown() const { return (current_panel == preview) && preview->get_canvas3d()->is_legend_shown(); } void show_legend(bool show) { if (current_panel == preview) preview->get_canvas3d()->show_legend(show); } -#endif // ENABLE_PREVIEW_LAYOUT bool is_sidebar_collapsed() const { return sidebar->is_collapsed(); } void collapse_sidebar(bool collapse); @@ -1785,9 +1783,6 @@ struct Plater::priv bool init_view_toolbar(); bool init_collapse_toolbar(); -#if !ENABLE_PREVIEW_LAYOUT - void update_preview_bottom_toolbar(); -#endif // !ENABLE_PREVIEW_LAYOUT void update_preview_moves_slider(); void enable_preview_moves_slider(bool enable); @@ -4746,13 +4741,6 @@ bool Plater::priv::init_collapse_toolbar() return true; } -#if !ENABLE_PREVIEW_LAYOUT -void Plater::priv::update_preview_bottom_toolbar() -{ - preview->update_bottom_toolbar(); -} -#endif // !ENABLE_PREVIEW_LAYOUT - void Plater::priv::update_preview_moves_slider() { preview->update_moves_slider(); @@ -5733,10 +5721,8 @@ bool Plater::is_view3D_shown() const { return p->is_view3D_shown(); } bool Plater::are_view3D_labels_shown() const { return p->are_view3D_labels_shown(); } void Plater::show_view3D_labels(bool show) { p->show_view3D_labels(show); } -#if ENABLE_PREVIEW_LAYOUT bool Plater::is_legend_shown() const { return p->is_legend_shown(); } void Plater::show_legend(bool show) { p->show_legend(show); } -#endif // ENABLE_PREVIEW_LAYOUT bool Plater::is_sidebar_collapsed() const { return p->is_sidebar_collapsed(); } void Plater::collapse_sidebar(bool show) { p->collapse_sidebar(show); } @@ -7094,13 +7080,6 @@ GLToolbar& Plater::get_collapse_toolbar() return p->collapse_toolbar; } -#if !ENABLE_PREVIEW_LAYOUT -void Plater::update_preview_bottom_toolbar() -{ - p->update_preview_bottom_toolbar(); -} -#endif // !ENABLE_PREVIEW_LAYOUT - void Plater::update_preview_moves_slider() { p->update_preview_moves_slider(); @@ -7209,12 +7188,10 @@ bool Plater::is_render_statistic_dialog_visible() const return p->show_render_statistic_dialog; } -#if ENABLE_PREVIEW_LAYOUT void Plater::set_keep_current_preview_type(bool value) { p->preview->set_keep_current_preview_type(value); } -#endif // ENABLE_PREVIEW_LAYOUT Plater::TakeSnapshot::TakeSnapshot(Plater *plater, const std::string &snapshot_name) : TakeSnapshot(plater, from_u8(snapshot_name)) {} diff --git a/src/slic3r/GUI/Plater.hpp b/src/slic3r/GUI/Plater.hpp index 852926fc0..a51744d06 100644 --- a/src/slic3r/GUI/Plater.hpp +++ b/src/slic3r/GUI/Plater.hpp @@ -225,10 +225,8 @@ public: bool are_view3D_labels_shown() const; void show_view3D_labels(bool show); -#if ENABLE_PREVIEW_LAYOUT bool is_legend_shown() const; void show_legend(bool show); -#endif // ENABLE_PREVIEW_LAYOUT bool is_sidebar_collapsed() const; void collapse_sidebar(bool show); @@ -390,9 +388,6 @@ public: const GLToolbar& get_collapse_toolbar() const; GLToolbar& get_collapse_toolbar(); -#if !ENABLE_PREVIEW_LAYOUT - void update_preview_bottom_toolbar(); -#endif // !ENABLE_PREVIEW_LAYOUT void update_preview_moves_slider(); void enable_preview_moves_slider(bool enable); @@ -458,9 +453,7 @@ public: void toggle_render_statistic_dialog(); bool is_render_statistic_dialog_visible() const; -#if ENABLE_PREVIEW_LAYOUT void set_keep_current_preview_type(bool value); -#endif // ENABLE_PREVIEW_LAYOUT // Wrapper around wxWindow::PopupMenu to suppress error messages popping out while tracking the popup menu. bool PopupMenu(wxMenu *menu, const wxPoint& pos = wxDefaultPosition); diff --git a/tests/libslic3r/test_clipper_utils.cpp b/tests/libslic3r/test_clipper_utils.cpp index a1230ac03..775796ba7 100644 --- a/tests/libslic3r/test_clipper_utils.cpp +++ b/tests/libslic3r/test_clipper_utils.cpp @@ -66,7 +66,7 @@ SCENARIO("Various Clipper operations - xs/t/11_clipper.t", "[ClipperUtils]") { GIVEN("polyline") { Polyline polyline { { 50, 150 }, { 300, 150 } }; WHEN("intersection_pl") { - Polylines result = Slic3r::intersection_pl({ polyline }, { square, hole_in_square }); + Polylines result = Slic3r::intersection_pl(polyline, ExPolygon{ square, hole_in_square }); THEN("correct number of result lines") { REQUIRE(result.size() == 2); } @@ -99,7 +99,7 @@ SCENARIO("Various Clipper operations - xs/t/11_clipper.t", "[ClipperUtils]") { { 74730000, 74730000 }, { 55270000, 74730000 }, { 55270000, 68063296 }, { 44730000, 68063296 }, { 44730000, 74730000 }, { 25270000, 74730000 }, { 25270000, 55270000 }, { 31936670, 55270000 }, { 31936670, 44730000 }, { 25270000, 44730000 }, { 25270000, 25270000 }, { 44730000, 25270000 }, { 44730000, 31936670 } }; Slic3r::Polygon clip { {75200000, 45200000}, {54800000, 45200000}, {54800000, 24800000}, {75200000, 24800000} }; - Slic3r::Polylines result = Slic3r::intersection_pl(subject, { clip }); + Slic3r::Polylines result = Slic3r::intersection_pl(subject, ExPolygon{ clip }); THEN("intersection_pl - result is not empty") { REQUIRE(result.size() == 1); } @@ -117,7 +117,7 @@ SCENARIO("Various Clipper operations - xs/t/11_clipper.t", "[ClipperUtils]") { GIVEN("Clipper bug #126") { Slic3r::Polyline subject { { 200000, 19799999 }, { 200000, 200000 }, { 24304692, 200000 }, { 15102879, 17506106 }, { 13883200, 19799999 }, { 200000, 19799999 } }; Slic3r::Polygon clip { { 15257205, 18493894 }, { 14350057, 20200000 }, { -200000, 20200000 }, { -200000, -200000 }, { 25196917, -200000 } }; - Slic3r::Polylines result = Slic3r::intersection_pl(subject, { clip }); + Slic3r::Polylines result = Slic3r::intersection_pl(subject, ExPolygon{ clip }); THEN("intersection_pl - result is not empty") { REQUIRE(result.size() == 1); }