From ac86f2a98d0a30838b5889db39aed97915e4e8f1 Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Wed, 6 Apr 2022 22:32:55 +0200 Subject: [PATCH 001/201] Basically working version of the optimized prime tower --- src/FffGcodeWriter.cpp | 58 ++++++++-- src/FffGcodeWriter.h | 2 + src/FffPolygonGenerator.cpp | 1 - src/PrimeTower.cpp | 215 +++++++++++++++++++++++++++++++++--- src/PrimeTower.h | 42 +++++-- src/settings/EnumSettings.h | 29 ++++- src/settings/Settings.cpp | 21 ++++ src/utils/polygonUtils.cpp | 38 ++++++- src/utils/polygonUtils.h | 15 ++- 9 files changed, 386 insertions(+), 35 deletions(-) diff --git a/src/FffGcodeWriter.cpp b/src/FffGcodeWriter.cpp index cb088ee561..5395fdda6d 100644 --- a/src/FffGcodeWriter.cpp +++ b/src/FffGcodeWriter.cpp @@ -1236,11 +1236,43 @@ void FffGcodeWriter::calculateExtruderOrderPerLayer(const SliceDataStorage& stor { last_extruder = gcode.getExtruderNr(); } + + size_t extruder_count = Application::getInstance().current_slice->scene.extruders.size(); for (LayerIndex layer_nr = -Raft::getTotalExtraLayers(); layer_nr < static_cast(storage.print_layer_count); layer_nr++) { std::vector>& extruder_order_per_layer_here = (layer_nr < 0) ? extruder_order_per_layer_negative_layers : extruder_order_per_layer; - extruder_order_per_layer_here.push_back(getUsedExtrudersOnLayerExcludingStartingExtruder(storage, last_extruder, layer_nr)); - last_extruder = extruder_order_per_layer_here.back().back(); + std::vector extruder_order = getUsedExtrudersOnLayerExcludingStartingExtruder(storage, last_extruder, layer_nr); + extruder_order_per_layer_here.push_back(extruder_order); + + if(layer_nr >= 0 && !extruder_order_per_layer_here.empty()) + { + std::vector extruder_prime_required(extruder_count, false); + + // First used extruder only needs to be primed if an other extruder has been used before + if(extruder_order.front() != last_extruder) + { + extruder_prime_required[last_extruder] = true; + } + + // All other used extruders need to be primed + for(size_t index = 1 ; index < extruder_order.size() ; ++index) + { + extruder_prime_required[extruder_order[index]] = true; + } + + extruder_prime_required_by_layer.push_back(extruder_prime_required); + + #warning remove this + #if 0 + log("##### Required primes for layer %d:\n", layer_nr); + for(const size_t &extruder_nr : extruder_prime_required) + { + log("##### %d\n", extruder_nr); + } + #endif + } + + last_extruder = extruder_order.back(); } } @@ -1265,11 +1297,11 @@ std::vector FffGcodeWriter::getUsedExtrudersOnLayerExcludingStartingExtr size_t extruder_count = Application::getInstance().current_slice->scene.extruders.size(); assert(static_cast(extruder_count) > 0); std::vector ret; - ret.push_back(start_extruder); std::vector extruder_is_used_on_this_layer = storage.getExtrudersUsed(layer_nr); + PrimeTowerMethod method = mesh_group_settings.get("prime_tower_mode"); //The outermost prime tower extruder is always used if there is a prime tower, apart on layers with negative index (e.g. for the raft) - if (mesh_group_settings.get("prime_tower_enable") && layer_nr >= 0 && layer_nr <= storage.max_print_height_second_to_last_extruder) + if (method == PrimeTowerMethod::DEFAULT && layer_nr >= 0 && layer_nr <= storage.max_print_height_second_to_last_extruder) { extruder_is_used_on_this_layer[storage.primeTower.extruder_order[0]] = true; } @@ -1288,18 +1320,30 @@ std::vector FffGcodeWriter::getUsedExtrudersOnLayerExcludingStartingExtr } } + if (method != PrimeTowerMethod::OPTIMIZED || extruder_is_used_on_this_layer[start_extruder]) + { + ret.push_back(start_extruder); + } + for (size_t extruder_nr = 0; extruder_nr < extruder_count; extruder_nr++) { if (extruder_nr == start_extruder) { // skip the current extruder, it's the one we started out planning continue; } - if (!extruder_is_used_on_this_layer[extruder_nr]) + if (!extruder_is_used_on_this_layer[extruder_nr] && method != PrimeTowerMethod::OPTIMIZED_CONSISTENT) { continue; } ret.push_back(extruder_nr); } + + log("===== Used extruders for layer %d method %d\n", layer_nr.value, static_cast(method)); + for(auto &ext : ret) + { + log("===== %d\n", ext); + } + assert(ret.size() <= (size_t)extruder_count && "Not more extruders may be planned in a layer than there are extruders!"); return ret; } @@ -3025,12 +3069,12 @@ void FffGcodeWriter::setExtruder_addPrime(const SliceDataStorage& storage, Layer void FffGcodeWriter::addPrimeTower(const SliceDataStorage& storage, LayerPlan& gcode_layer, const size_t prev_extruder) const { - if (!Application::getInstance().current_slice->scene.current_mesh_group->settings.get("prime_tower_enable")) + if (!storage.primeTower.enabled) { return; } - storage.primeTower.addToGcode(storage, gcode_layer, prev_extruder, gcode_layer.getExtruder()); + storage.primeTower.addToGcode(storage, gcode_layer, extruder_prime_required_by_layer.at(gcode_layer.getLayerNr()), prev_extruder, gcode_layer.getExtruder()); } void FffGcodeWriter::finalize() diff --git a/src/FffGcodeWriter.h b/src/FffGcodeWriter.h index 63594f1726..7503ef5934 100644 --- a/src/FffGcodeWriter.h +++ b/src/FffGcodeWriter.h @@ -70,6 +70,8 @@ class FffGcodeWriter : public NoCopy std::vector> mesh_order_per_extruder; //!< For each extruder, the order of the meshes (first element is first mesh to be printed) + std::vector> extruder_prime_required_by_layer; //!< For each layer, indicates which extruders actually require to be primed + /*! * For each extruder on which layer the prime will be planned, * or a large negative number if it's already planned outside of \ref FffGcodeWriter::processLayer diff --git a/src/FffPolygonGenerator.cpp b/src/FffPolygonGenerator.cpp index 2ae646aec7..2c411dd5c2 100644 --- a/src/FffPolygonGenerator.cpp +++ b/src/FffPolygonGenerator.cpp @@ -409,7 +409,6 @@ void FffPolygonGenerator::slices2polygons(SliceDataStorage& storage, TimeKeeper& computePrintHeightStatistics(storage); // handle helpers - storage.primeTower.generateGroundpoly(); storage.primeTower.generatePaths(storage); storage.primeTower.subtractFromSupport(storage); diff --git a/src/PrimeTower.cpp b/src/PrimeTower.cpp index ceb8ec1676..600dac80dc 100644 --- a/src/PrimeTower.cpp +++ b/src/PrimeTower.cpp @@ -15,8 +15,10 @@ #include "Scene.h" #include "Slice.h" #include "sliceDataStorage.h" +#include "utils/logoutput.h" #define CIRCLE_RESOLUTION 32 //The number of vertices in each circle. +#define ARC_RESOLUTION 4 //The number of segments in each arc of a wheel namespace cura @@ -41,7 +43,7 @@ PrimeTower::PrimeTower() multiple_extruders_on_first_layer = scene.current_mesh_group->settings.get("machine_extruders_share_nozzle") && ((adhesion_type != EPlatformAdhesion::SKIRT) && (adhesion_type != EPlatformAdhesion::BRIM)); } - enabled = scene.current_mesh_group->settings.get("prime_tower_enable") + enabled = scene.current_mesh_group->settings.get("prime_tower_mode") != PrimeTowerMethod::NONE && scene.current_mesh_group->settings.get("prime_tower_min_volume") > 10 && scene.current_mesh_group->settings.get("prime_tower_size") > 10; @@ -63,11 +65,6 @@ PrimeTower::PrimeTower() void PrimeTower::generateGroundpoly() { - if (!enabled) - { - return; - } - const Settings& mesh_group_settings = Application::getInstance().current_slice->scene.current_mesh_group->settings; const coord_t tower_size = mesh_group_settings.get("prime_tower_size"); @@ -95,12 +92,18 @@ void PrimeTower::generatePaths(const SliceDataStorage& storage) enabled &= storage.max_print_height_second_to_last_extruder >= 0; //Maybe it turns out that we don't need a prime tower after all because there are no layer switches. if (enabled) { - generatePaths_denseInfill(); + generateGroundpoly(); + + std::vector cumulative_insets; + generatePaths_denseInfill(cumulative_insets); + generateStartLocations(); + + generatePaths_sparseInfill(cumulative_insets); } } -void PrimeTower::generatePaths_denseInfill() +void PrimeTower::generatePaths_denseInfill(std::vector &cumulative_insets) { const Scene& scene = Application::getInstance().current_slice->scene; const Settings& mesh_group_settings = scene.current_mesh_group->settings; @@ -125,12 +128,12 @@ void PrimeTower::generatePaths_denseInfill() Polygons polygons = outer_poly.offset(-cumulative_inset - wall_nr * line_width - line_width / 2); pattern.polygons.add(polygons); current_volume += polygons.polygonLength() * line_width * layer_height * flow; - if (polygons.empty()) //Don't continue. We won't ever reach the required volume because it doesn't fit. - { - break; - } + + //Don't continue. We won't ever reach the required volume because it doesn't fit. + assert(!polygons.empty() && "Prime tower is not large enough to generate the required volume"); } cumulative_inset += wall_nr * line_width; + cumulative_insets.push_back(cumulative_inset); if (multiple_extruders_on_first_layer) { @@ -156,6 +159,79 @@ void PrimeTower::generatePaths_denseInfill() } } +void PrimeTower::generatePaths_sparseInfill(const std::vector &cumulative_insets) +{ + const Scene& scene = Application::getInstance().current_slice->scene; + const Settings& mesh_group_settings = scene.current_mesh_group->settings; + const PrimeTowerMethod method = mesh_group_settings.get("prime_tower_mode"); + + if(method == PrimeTowerMethod::OPTIMIZED || method == PrimeTowerMethod::OPTIMIZED_CONSISTENT) + { + const size_t nb_extruders = scene.extruders.size(); + + // Pre-compute radiuses of each extruder ring + std::vector rings_radii; + const coord_t tower_size = mesh_group_settings.get("prime_tower_size"); + const coord_t tower_radius = tower_size / 2; + + rings_radii.push_back(tower_radius); + for(const coord_t &cumulative_inset : cumulative_insets) + { + rings_radii.push_back(tower_radius - cumulative_inset); + } + + // Generate all possible extruders combinations, e.g. if there are 4 extruders, we have combinations + // 0 / 0-1 / 0-1-2 / 0-1-2-3 / 1 / 1-2 / 1-2-3 / 2 / 2-3 / 3 + // A combination is represented by a bitmask + std::vector extruders_combinations; + + for(size_t first_extruder = 0 ; first_extruder < nb_extruders ; ++first_extruder) + { + for(size_t last_extruder = first_extruder ; last_extruder < nb_extruders ; ++last_extruder) + { + size_t extruders_combination = 0; + for(size_t extruder_nr = first_extruder ; extruder_nr <= last_extruder ; ++extruder_nr) + { + extruders_combination |= (1 << extruder_nr); + } + + sparse_pattern_per_extruders[extruders_combination] = generatePath_sparseInfill(first_extruder, last_extruder, rings_radii); + } + } + } +} + +PrimeTower::ExtrusionMoves PrimeTower::generatePath_sparseInfill(const size_t first_extruder, const size_t last_extruder, const std::vector &rings_radii) +{ + const Scene& scene = Application::getInstance().current_slice->scene; + const Settings& mesh_group_settings = scene.current_mesh_group->settings; + const coord_t max_bridging_distance = mesh_group_settings.get("prime_tower_max_briding_distance"); + const coord_t outer_radius = rings_radii[first_extruder]; + const coord_t inner_radius = rings_radii[last_extruder + 1]; + const coord_t radius_delta = outer_radius - inner_radius; + + // Split ring according to max bridging distance + const size_t nb_rings = std::ceil(static_cast(radius_delta) / max_bridging_distance); + const coord_t actual_radius_step = radius_delta / nb_rings; + + ExtrusionMoves pattern; + for(size_t i = 0 ; i < nb_rings ; ++i) + { + const coord_t ring_inner_radius = inner_radius + i * actual_radius_step; + const coord_t ring_outer_radius = inner_radius + (i + 1) * actual_radius_step; + + const size_t semi_nb_spokes = std::ceil((M_PI * ring_outer_radius) / max_bridging_distance); + + pattern.polygons.add(PolygonUtils::makeWheel(middle, + ring_inner_radius, + ring_outer_radius, + semi_nb_spokes, + ARC_RESOLUTION)); + } + + return pattern; +} + void PrimeTower::generateStartLocations() { // Evenly spread out a number of dots along the prime tower's outline. This is done for the complete outline, @@ -166,12 +242,14 @@ void PrimeTower::generateStartLocations() PolygonUtils::spreadDots(segment_start, segment_end, number_of_prime_tower_start_locations, prime_tower_start_locations); } -void PrimeTower::addToGcode(const SliceDataStorage& storage, LayerPlan& gcode_layer, const size_t prev_extruder, const size_t new_extruder) const +void PrimeTower::addToGcode(const SliceDataStorage& storage, LayerPlan& gcode_layer, const std::vector &required_extruder_prime, const size_t prev_extruder, const size_t new_extruder) const { if (!enabled) { return; } + #warning remove this + //log("add to gcode %d %d %d\n", static_cast(gcode_layer.getLayerNr()), prev_extruder, new_extruder); if (gcode_layer.getPrimeTowerIsPlanned(new_extruder)) { // don't print the prime tower if it has been printed already with this extruder. return; @@ -197,7 +275,32 @@ void PrimeTower::addToGcode(const SliceDataStorage& storage, LayerPlan& gcode_la gotoStartLocation(gcode_layer, new_extruder); } - addToGcode_denseInfill(gcode_layer, new_extruder); + PrimeTowerMethod method = Application::getInstance().current_slice->scene.current_mesh_group->settings.get("prime_tower_mode"); + std::vector primed_extruders; + + switch(method) + { + case PrimeTowerMethod::NONE: + // This should actually not happen + break; + + case PrimeTowerMethod::DEFAULT: + addToGcode_denseInfill(gcode_layer, new_extruder); + primed_extruders.push_back(new_extruder); + break; + + case PrimeTowerMethod::OPTIMIZED: + if(required_extruder_prime[new_extruder]) + { + // Extruder really needs to be prime + addToGcode_denseInfill(gcode_layer, new_extruder); + primed_extruders.push_back(new_extruder); + } + + // Whatever happens before and after, use the current extruder to prime all the non-required extruders now + addToGcode_optimizedInfill(gcode_layer, required_extruder_prime, new_extruder, primed_extruders); + break; + } // post-wipe: if (post_wipe) @@ -210,7 +313,10 @@ void PrimeTower::addToGcode(const SliceDataStorage& storage, LayerPlan& gcode_la gcode_layer.addTravel(post_wipe_point - previous_nozzle_offset + new_nozzle_offset); } - gcode_layer.setPrimeTowerIsPlanned(new_extruder); + for (const size_t &primed_extruder : primed_extruders) + { + gcode_layer.setPrimeTowerIsPlanned(primed_extruder); + } } void PrimeTower::addToGcode_denseInfill(LayerPlan& gcode_layer, const size_t extruder_nr) const @@ -225,6 +331,85 @@ void PrimeTower::addToGcode_denseInfill(LayerPlan& gcode_layer, const size_t ext gcode_layer.addLinesByOptimizer(pattern.lines, config, SpaceFillType::Lines); } +void PrimeTower::addToGcode_optimizedInfill(LayerPlan& gcode_layer, const std::vector &required_extruder_prime, const size_t current_extruder, std::vector &primed_extruders) const +{ + std::vector extruders_to_prime; + + // First, gather all extruders to be primed : we are going to process them all now, even if + // the rings are not besides each other + for(size_t extruder_nr = 0 ; extruder_nr < required_extruder_prime.size() ; ++extruder_nr) + { + if (!required_extruder_prime[extruder_nr] && !gcode_layer.getPrimeTowerIsPlanned(extruder_nr)) + { + extruders_to_prime.push_back(extruder_nr); + primed_extruders.push_back(extruder_nr); + } + } + + // Now, group extruders which are besides each other + std::vector> extruders_to_prime_grouped; + for(const size_t &extruder_to_prime : extruders_to_prime) + { + if(extruders_to_prime_grouped.empty()) + { + // First extruder : create new group + extruders_to_prime_grouped.push_back({extruder_to_prime}); + } + else + { + std::vector &last_group = extruders_to_prime_grouped.back(); + if(last_group.back() == extruder_to_prime - 1) + { + // New extruders which belongs to same group + last_group.push_back(extruder_to_prime); + } + else + { + // New extruders which belongs to new group + extruders_to_prime_grouped.push_back({extruder_to_prime}); + } + } + } + + #warning remove this + #if 0 + log("GROUPS\n"); + for(auto &group : extruders_to_prime_grouped) + { + log("NEW GROUP\n"); + for(auto &extruder : group) + { + log("E%d\n", extruder); + } + } + log("GROUPS END\n"); + #endif + + #warning What should we do in case of extruders with different lines widths ? + // And finally, append patterns for each group + const GCodePathConfig& config = gcode_layer.configs_storage.prime_tower_config_per_extruder[current_extruder]; + log("line width %d %d\n", config.getLineWidth(), current_extruder); + for(const std::vector &group : extruders_to_prime_grouped) + { + size_t mask = 0; + for(const size_t &extruder : group) + { + mask |= (1 << extruder); + } + + auto iterator = sparse_pattern_per_extruders.find(mask); + if(iterator != sparse_pattern_per_extruders.end()) + { + + gcode_layer.addPolygonsByOptimizer(iterator->second.polygons, config); + } + else + { + logWarning("Sparse pattern not found for group %d, skipping\n", mask); + } + } +} + void PrimeTower::subtractFromSupport(SliceDataStorage& storage) { const Polygons outside_polygon = outer_poly.getOutsidePolygons(); diff --git a/src/PrimeTower.h b/src/PrimeTower.h index f89240737d..6076155366 100644 --- a/src/PrimeTower.h +++ b/src/PrimeTower.h @@ -5,6 +5,7 @@ #define PRIME_TOWER_H #include +#include #include "utils/polygon.h" // Polygons #include "utils/polygonUtils.h" @@ -41,6 +42,7 @@ class PrimeTower std::vector pattern_per_extruder; //!< For each extruder the pattern to print on all layers of the prime tower. std::vector pattern_per_extruder_layer0; //!< For each extruder the pattern to print on the first layer + std::map sparse_pattern_per_extruders; //!< For each extruders combination, the pattern to print on all layers where extruders are actually useless. public: bool enabled; //!< Whether the prime tower is enabled. @@ -65,13 +67,6 @@ class PrimeTower */ PrimeTower(); - /*! - * Generate the prime tower area to be used on each layer - * - * Fills \ref PrimeTower::inner_poly and sets \ref PrimeTower::middle - */ - void generateGroundpoly(); - /*! * Generate the area where the prime tower should be. */ @@ -82,10 +77,11 @@ class PrimeTower * * \param storage where to get settings from; where to get the maximum height of the prime tower from * \param[in,out] gcode_layer Where to get the current extruder from; where to store the generated layer paths + * \param required_extruder_prime the extruders which actually required to be primed at this layer * \param prev_extruder The previous extruder with which paths were planned; from which extruder a switch was made * \param new_extruder The switched to extruder with which the prime tower paths should be generated. */ - void addToGcode(const SliceDataStorage& storage, LayerPlan& gcode_layer, const size_t prev_extruder, const size_t new_extruder) const; + void addToGcode(const SliceDataStorage& storage, LayerPlan& gcode_layer, const std::vector &required_extruder_prime, const size_t prev_extruder, const size_t new_extruder) const; /*! * \brief Subtract the prime tower from the support areas in storage. @@ -97,13 +93,38 @@ class PrimeTower private: + /*! + * Generate the prime tower area to be used on each layer + * + * Fills \ref PrimeTower::inner_poly and sets \ref PrimeTower::middle + */ + void generateGroundpoly(); + /*! * \see WipeTower::generatePaths * * Generate the extrude paths for each extruder on even and odd layers * Fill the ground poly with dense infill. + * \param cumulative_insets [in, out] The insets added to each extruder to compute the radius of its ring + */ + void generatePaths_denseInfill(std::vector &cumulative_insets); + + /*! + * \see WipeTower::generatePaths + * + * \brief Generate the sparse extrude paths for each extruders combination + * \param cumulative_insets The insets added to each extruder to compute the radius of its ring + */ + void generatePaths_sparseInfill(const std::vector &cumulative_insets); + + /*! + * \brief Generate the sparse extrude paths for an extruders combination + * + * \param first_extruder The index of the first extruder to be pseudo-primed + * \param last_extruder The index of the last extruder to be pseudo-primed + * \param rings_radii The external radii of each extruder ring, plus the internal radius of the internal ring */ - void generatePaths_denseInfill(); + ExtrusionMoves generatePath_sparseInfill(const size_t first_extruder, const size_t last_extruder, const std::vector &rings_radii); /*! * Generate start locations on the prime tower. The locations are evenly spread around the prime tower's perimeter. @@ -124,6 +145,9 @@ class PrimeTower */ void addToGcode_denseInfill(LayerPlan& gcode_layer, const size_t extruder) const; + #warning TBD documentation + void addToGcode_optimizedInfill(LayerPlan& gcode_layer, const std::vector& required_extruder_prime, const size_t current_extruder, std::vector& primed_extruders) const; + /*! * For an extruder switch that happens not on the first layer, the extruder needs to be primed on the prime tower. * This function picks a start location for this extruder on the prime tower's perimeter and travels there to avoid diff --git a/src/settings/EnumSettings.h b/src/settings/EnumSettings.h index 0dfe19c903..b71074bc44 100644 --- a/src/settings/EnumSettings.h +++ b/src/settings/EnumSettings.h @@ -225,6 +225,33 @@ enum class InsetDirection CENTER_LAST }; +/*! + * Method used for prime tower generation + */ +enum class PrimeTowerMethod +{ + /*! + * No prime tower is generated. + */ + NONE, + + /*! + * Basic full prime tower with only discs. + */ + DEFAULT, + + /*! + * Prime tower that minimizes time and used filament as much as possible. + */ + OPTIMIZED, + + /*! + * Prime tower that minimizes time and used filament, but doesn't allow + * for printing two different filaments over each other. + */ + OPTIMIZED_CONSISTENT, +}; + } //Cura namespace. -#endif //ENUMSETTINGS_H \ No newline at end of file +#endif //ENUMSETTINGS_H diff --git a/src/settings/Settings.cpp b/src/settings/Settings.cpp index b411f53b11..ab75e034a8 100644 --- a/src/settings/Settings.cpp +++ b/src/settings/Settings.cpp @@ -583,6 +583,27 @@ template<> InsetDirection Settings::get(const std::string& key) } } +template<> PrimeTowerMethod Settings::get(const std::string& key) const +{ + const std::string& value = get(key); + if(value == "default") + { + return PrimeTowerMethod::DEFAULT; + } + else if(value == "optimized") + { + return PrimeTowerMethod::OPTIMIZED; + } + else if(value == "optimized_consistent") + { + return PrimeTowerMethod::OPTIMIZED_CONSISTENT; + } + else //Default. + { + return PrimeTowerMethod::NONE; + } +} + template<> std::vector Settings::get>(const std::string& key) const { const std::string& value_string = get(key); diff --git a/src/utils/polygonUtils.cpp b/src/utils/polygonUtils.cpp index fc5ad39b04..c2785732a4 100644 --- a/src/utils/polygonUtils.cpp +++ b/src/utils/polygonUtils.cpp @@ -1359,7 +1359,7 @@ double PolygonUtils::relativeHammingDistance(const Polygons& poly_a, const Polyg return hamming_distance / total_area; } -Polygon PolygonUtils::makeCircle(const Point mid, const coord_t radius, const AngleRadians a_step) +Polygon PolygonUtils::makeCircle(const Point &mid, const coord_t radius, const AngleRadians a_step) { Polygon circle; for (float a = 0; a < 2 * M_PI; a += a_step) @@ -1369,6 +1369,42 @@ Polygon PolygonUtils::makeCircle(const Point mid, const coord_t radius, const An return circle; } +Polygon PolygonUtils::makeWheel(const Point &mid, const coord_t inner_radius, const coord_t outer_radius, const size_t semi_nb_spokes, const size_t arc_angle_resolution) +{ + Polygon wheel; + + std::vector> target_radii; + target_radii.push_back({inner_radius, outer_radius}); + target_radii.push_back({outer_radius, inner_radius}); + + const size_t nb_spokes = semi_nb_spokes * 2; + const float angle_step = TAU / nb_spokes; + const float arc_step = angle_step / arc_angle_resolution; + float angle = 0.0; + for(size_t spoke = 0 ; spoke < nb_spokes ; ++spoke) + { + const std::pair &radii = target_radii.at(spoke % 2); + + angle = spoke * angle_step; + float cos_angle = cos(angle); + float sin_angle = sin(angle); + wheel.emplace_back(mid + Point(radii.first * cos_angle, radii.first * sin_angle)); + + for(size_t arc_part = 0 ; arc_part < arc_angle_resolution ; ++arc_part) + { + wheel.emplace_back(mid + Point(radii.second * cos_angle, radii.second * sin_angle)); + if(arc_part < arc_angle_resolution - 1) + { + angle += arc_step; + cos_angle = cos(angle); + sin_angle = sin(angle); + } + } + } + + return wheel; +} + Polygons PolygonUtils::connect(const Polygons& input) { diff --git a/src/utils/polygonUtils.h b/src/utils/polygonUtils.h index 489130bea8..a38159eef3 100644 --- a/src/utils/polygonUtils.h +++ b/src/utils/polygonUtils.h @@ -597,7 +597,20 @@ class PolygonUtils * \param a_step The angle between segments of the circle. * \return A new Polygon containing the circle. */ - static Polygon makeCircle(const Point mid, const coord_t radius, const AngleRadians a_step = M_PI / 8); + static Polygon makeCircle(const Point &mid, const coord_t radius, const AngleRadians a_step = M_PI / 8); + + /*! + * Create a "wheel" shape. + * + * This creates a polygon which represents the shape of a wheel. + * \param mid The center of the circle. + * \param inner_radius The radius of the wheel inner circle. + * \param outer_radius The radius of the wheel outer circle. + * \param semi_nb_spokes The semi number of spokes in the wheel. There will actually be N*2 spokes. + * \param arc_angle_resolution The number of segment on each arc. + * \return A new Polygon containing the circle. + */ + static Polygon makeWheel(const Point &mid, const coord_t inner_radius, const coord_t outer_radius, const size_t semi_nb_spokes, const size_t arc_angle_resolution); /*! * Connect all polygons to their holes using zero widths hole channels, so that the polygons and their outlines are connected together From e2526fe0c5c0cc8ab1dcff5197d77e07b7318eb1 Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Thu, 7 Apr 2022 21:32:00 +0200 Subject: [PATCH 002/201] Optimized prime tower takes care of extruders with various lines widts --- src/PrimeTower.cpp | 43 +++++++++++++++++++++++++++++++++++-------- src/PrimeTower.h | 5 +++-- 2 files changed, 38 insertions(+), 10 deletions(-) diff --git a/src/PrimeTower.cpp b/src/PrimeTower.cpp index 600dac80dc..e861d09cc9 100644 --- a/src/PrimeTower.cpp +++ b/src/PrimeTower.cpp @@ -61,6 +61,7 @@ PrimeTower::PrimeTower() const Ratio adhesion_b = scene_pointer->extruders[extruder_nr_b].settings.get("material_adhesion_tendency"); return adhesion_a < adhesion_b; }); + #warning TBD take care of actual extruder order for optimized tower ! } void PrimeTower::generateGroundpoly() @@ -165,6 +166,13 @@ void PrimeTower::generatePaths_sparseInfill(const std::vector &cumulati const Settings& mesh_group_settings = scene.current_mesh_group->settings; const PrimeTowerMethod method = mesh_group_settings.get("prime_tower_mode"); + std::set lines_widths; + for(size_t extruder_nr : extruder_order) + { + const coord_t line_width = scene.extruders[extruder_nr].settings.get("prime_tower_line_width"); + lines_widths.insert(line_width); + } + if(method == PrimeTowerMethod::OPTIMIZED || method == PrimeTowerMethod::OPTIMIZED_CONSISTENT) { const size_t nb_extruders = scene.extruders.size(); @@ -195,13 +203,20 @@ void PrimeTower::generatePaths_sparseInfill(const std::vector &cumulati extruders_combination |= (1 << extruder_nr); } - sparse_pattern_per_extruders[extruders_combination] = generatePath_sparseInfill(first_extruder, last_extruder, rings_radii); + std::map infills_for_combination; + for(coord_t line_width : lines_widths) + { + ExtrusionMoves infill = generatePath_sparseInfill(first_extruder, last_extruder, rings_radii, line_width); + infills_for_combination[line_width] = infill; + } + + sparse_pattern_per_extruders[extruders_combination] = infills_for_combination; } } } } -PrimeTower::ExtrusionMoves PrimeTower::generatePath_sparseInfill(const size_t first_extruder, const size_t last_extruder, const std::vector &rings_radii) +PrimeTower::ExtrusionMoves PrimeTower::generatePath_sparseInfill(const size_t first_extruder, const size_t last_extruder, const std::vector &rings_radii, const coord_t line_width) { const Scene& scene = Application::getInstance().current_slice->scene; const Settings& mesh_group_settings = scene.current_mesh_group->settings; @@ -209,6 +224,7 @@ PrimeTower::ExtrusionMoves PrimeTower::generatePath_sparseInfill(const size_t fi const coord_t outer_radius = rings_radii[first_extruder]; const coord_t inner_radius = rings_radii[last_extruder + 1]; const coord_t radius_delta = outer_radius - inner_radius; + const coord_t semi_line_width = line_width / 2; // Split ring according to max bridging distance const size_t nb_rings = std::ceil(static_cast(radius_delta) / max_bridging_distance); @@ -217,8 +233,8 @@ PrimeTower::ExtrusionMoves PrimeTower::generatePath_sparseInfill(const size_t fi ExtrusionMoves pattern; for(size_t i = 0 ; i < nb_rings ; ++i) { - const coord_t ring_inner_radius = inner_radius + i * actual_radius_step; - const coord_t ring_outer_radius = inner_radius + (i + 1) * actual_radius_step; + const coord_t ring_inner_radius = (inner_radius + i * actual_radius_step) + semi_line_width; + const coord_t ring_outer_radius = (inner_radius + (i + 1) * actual_radius_step) - semi_line_width; const size_t semi_nb_spokes = std::ceil((M_PI * ring_outer_radius) / max_bridging_distance); @@ -388,7 +404,9 @@ void PrimeTower::addToGcode_optimizedInfill(LayerPlan& gcode_layer, const std::v #warning What should we do in case of extruders with different lines widths ? // And finally, append patterns for each group const GCodePathConfig& config = gcode_layer.configs_storage.prime_tower_config_per_extruder[current_extruder]; - log("line width %d %d\n", config.getLineWidth(), current_extruder); + const Scene& scene = Application::getInstance().current_slice->scene; + const coord_t line_width = scene.extruders[current_extruder].settings.get("prime_tower_line_width"); + for(const std::vector &group : extruders_to_prime_grouped) { size_t mask = 0; @@ -397,11 +415,20 @@ void PrimeTower::addToGcode_optimizedInfill(LayerPlan& gcode_layer, const std::v mask |= (1 << extruder); } - auto iterator = sparse_pattern_per_extruders.find(mask); - if(iterator != sparse_pattern_per_extruders.end()) + auto iterator_combination = sparse_pattern_per_extruders.find(mask); + if(iterator_combination != sparse_pattern_per_extruders.end()) { + const std::map &infill_for_combination = iterator_combination->second; - gcode_layer.addPolygonsByOptimizer(iterator->second.polygons, config); + auto iterator_line_width = infill_for_combination.find(line_width); + if(iterator_line_width != infill_for_combination.end()) + { + gcode_layer.addPolygonsByOptimizer(iterator_line_width->second.polygons, config); + } + else + { + logWarning("Sparse pattern not found for line width %d, skipping\n", line_width); + } } else { diff --git a/src/PrimeTower.h b/src/PrimeTower.h index 6076155366..6220eb7c81 100644 --- a/src/PrimeTower.h +++ b/src/PrimeTower.h @@ -42,7 +42,7 @@ class PrimeTower std::vector pattern_per_extruder; //!< For each extruder the pattern to print on all layers of the prime tower. std::vector pattern_per_extruder_layer0; //!< For each extruder the pattern to print on the first layer - std::map sparse_pattern_per_extruders; //!< For each extruders combination, the pattern to print on all layers where extruders are actually useless. + std::map> sparse_pattern_per_extruders; //!< For each extruders combination, and for each possible line width, the pattern to print on all layers where extruders are actually useless. public: bool enabled; //!< Whether the prime tower is enabled. @@ -123,8 +123,9 @@ class PrimeTower * \param first_extruder The index of the first extruder to be pseudo-primed * \param last_extruder The index of the last extruder to be pseudo-primed * \param rings_radii The external radii of each extruder ring, plus the internal radius of the internal ring + * \param line_width The actual line width of the extruder */ - ExtrusionMoves generatePath_sparseInfill(const size_t first_extruder, const size_t last_extruder, const std::vector &rings_radii); + ExtrusionMoves generatePath_sparseInfill(const size_t first_extruder, const size_t last_extruder, const std::vector &rings_radii, const coord_t line_width); /*! * Generate start locations on the prime tower. The locations are evenly spread around the prime tower's perimeter. From 0323644c61758201c74b97ff39b19d7bc7aa1e65 Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Mon, 2 May 2022 21:48:59 +0200 Subject: [PATCH 003/201] Minor fix --- src/PrimeTower.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/PrimeTower.cpp b/src/PrimeTower.cpp index e861d09cc9..dde71780f4 100644 --- a/src/PrimeTower.cpp +++ b/src/PrimeTower.cpp @@ -109,6 +109,7 @@ void PrimeTower::generatePaths_denseInfill(std::vector &cumulative_inse const Scene& scene = Application::getInstance().current_slice->scene; const Settings& mesh_group_settings = scene.current_mesh_group->settings; const coord_t layer_height = mesh_group_settings.get("layer_height"); + const PrimeTowerMethod method = mesh_group_settings.get("prime_tower_mode"); pattern_per_extruder.resize(extruder_count); pattern_per_extruder_layer0.resize(extruder_count); @@ -136,7 +137,7 @@ void PrimeTower::generatePaths_denseInfill(std::vector &cumulative_inse cumulative_inset += wall_nr * line_width; cumulative_insets.push_back(cumulative_inset); - if (multiple_extruders_on_first_layer) + if (multiple_extruders_on_first_layer || method != PrimeTowerMethod::DEFAULT) { //With a raft there is no difference for the first layer (of the prime tower) pattern_per_extruder_layer0 = pattern_per_extruder; From 04246e03e9a529e56e4715c76b3334ebc5f7f862 Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Mon, 6 Jun 2022 21:25:32 +0200 Subject: [PATCH 004/201] Prime tower now takes care of extruders with different lines widths --- src/PrimeTower.cpp | 43 +++++++++++++++++++++++-------------------- src/PrimeTower.h | 5 +++-- 2 files changed, 26 insertions(+), 22 deletions(-) diff --git a/src/PrimeTower.cpp b/src/PrimeTower.cpp index dde71780f4..8b4d56ded3 100644 --- a/src/PrimeTower.cpp +++ b/src/PrimeTower.cpp @@ -28,6 +28,7 @@ PrimeTower::PrimeTower() : wipe_from_middle(false) { const Scene& scene = Application::getInstance().current_slice->scene; + PrimeTowerMethod method = scene.current_mesh_group->settings.get("prime_tower_mode"); { EPlatformAdhesion adhesion_type = scene.current_mesh_group->settings.get("adhesion_type"); @@ -43,7 +44,7 @@ PrimeTower::PrimeTower() multiple_extruders_on_first_layer = scene.current_mesh_group->settings.get("machine_extruders_share_nozzle") && ((adhesion_type != EPlatformAdhesion::SKIRT) && (adhesion_type != EPlatformAdhesion::BRIM)); } - enabled = scene.current_mesh_group->settings.get("prime_tower_mode") != PrimeTowerMethod::NONE + enabled = method != PrimeTowerMethod::NONE && scene.current_mesh_group->settings.get("prime_tower_min_volume") > 10 && scene.current_mesh_group->settings.get("prime_tower_size") > 10; @@ -167,11 +168,18 @@ void PrimeTower::generatePaths_sparseInfill(const std::vector &cumulati const Settings& mesh_group_settings = scene.current_mesh_group->settings; const PrimeTowerMethod method = mesh_group_settings.get("prime_tower_mode"); - std::set lines_widths; + struct ActualExtruder + { + size_t number; + coord_t line_width; + }; + + std::vector actual_extruders; + actual_extruders.reserve(extruder_order.size()); for(size_t extruder_nr : extruder_order) { const coord_t line_width = scene.extruders[extruder_nr].settings.get("prime_tower_line_width"); - lines_widths.insert(line_width); + actual_extruders.push_back({extruder_nr, line_width}); } if(method == PrimeTowerMethod::OPTIMIZED || method == PrimeTowerMethod::OPTIMIZED_CONSISTENT) @@ -192,8 +200,6 @@ void PrimeTower::generatePaths_sparseInfill(const std::vector &cumulati // Generate all possible extruders combinations, e.g. if there are 4 extruders, we have combinations // 0 / 0-1 / 0-1-2 / 0-1-2-3 / 1 / 1-2 / 1-2-3 / 2 / 2-3 / 3 // A combination is represented by a bitmask - std::vector extruders_combinations; - for(size_t first_extruder = 0 ; first_extruder < nb_extruders ; ++first_extruder) { for(size_t last_extruder = first_extruder ; last_extruder < nb_extruders ; ++last_extruder) @@ -204,11 +210,11 @@ void PrimeTower::generatePaths_sparseInfill(const std::vector &cumulati extruders_combination |= (1 << extruder_nr); } - std::map infills_for_combination; - for(coord_t line_width : lines_widths) + std::map infills_for_combination; + for(const ActualExtruder &actual_extruder : actual_extruders) { - ExtrusionMoves infill = generatePath_sparseInfill(first_extruder, last_extruder, rings_radii, line_width); - infills_for_combination[line_width] = infill; + ExtrusionMoves infill = generatePath_sparseInfill(first_extruder, last_extruder, rings_radii, actual_extruder.line_width, actual_extruder.number); + infills_for_combination[actual_extruder.number] = infill; } sparse_pattern_per_extruders[extruders_combination] = infills_for_combination; @@ -217,11 +223,10 @@ void PrimeTower::generatePaths_sparseInfill(const std::vector &cumulati } } -PrimeTower::ExtrusionMoves PrimeTower::generatePath_sparseInfill(const size_t first_extruder, const size_t last_extruder, const std::vector &rings_radii, const coord_t line_width) +PrimeTower::ExtrusionMoves PrimeTower::generatePath_sparseInfill(const size_t first_extruder, const size_t last_extruder, const std::vector &rings_radii, const coord_t line_width, const size_t actual_extruder_nr) { const Scene& scene = Application::getInstance().current_slice->scene; - const Settings& mesh_group_settings = scene.current_mesh_group->settings; - const coord_t max_bridging_distance = mesh_group_settings.get("prime_tower_max_briding_distance"); + const coord_t max_bridging_distance = scene.extruders[actual_extruder_nr].settings.get("prime_tower_max_bridging_distance"); const coord_t outer_radius = rings_radii[first_extruder]; const coord_t inner_radius = rings_radii[last_extruder + 1]; const coord_t radius_delta = outer_radius - inner_radius; @@ -266,7 +271,7 @@ void PrimeTower::addToGcode(const SliceDataStorage& storage, LayerPlan& gcode_la return; } #warning remove this - //log("add to gcode %d %d %d\n", static_cast(gcode_layer.getLayerNr()), prev_extruder, new_extruder); + logAlways("add to gcode %d %d %d\n", static_cast(gcode_layer.getLayerNr()), prev_extruder, new_extruder); if (gcode_layer.getPrimeTowerIsPlanned(new_extruder)) { // don't print the prime tower if it has been printed already with this extruder. return; @@ -405,8 +410,6 @@ void PrimeTower::addToGcode_optimizedInfill(LayerPlan& gcode_layer, const std::v #warning What should we do in case of extruders with different lines widths ? // And finally, append patterns for each group const GCodePathConfig& config = gcode_layer.configs_storage.prime_tower_config_per_extruder[current_extruder]; - const Scene& scene = Application::getInstance().current_slice->scene; - const coord_t line_width = scene.extruders[current_extruder].settings.get("prime_tower_line_width"); for(const std::vector &group : extruders_to_prime_grouped) { @@ -419,16 +422,16 @@ void PrimeTower::addToGcode_optimizedInfill(LayerPlan& gcode_layer, const std::v auto iterator_combination = sparse_pattern_per_extruders.find(mask); if(iterator_combination != sparse_pattern_per_extruders.end()) { - const std::map &infill_for_combination = iterator_combination->second; + const std::map &infill_for_combination = iterator_combination->second; - auto iterator_line_width = infill_for_combination.find(line_width); - if(iterator_line_width != infill_for_combination.end()) + auto iterator_extruder_nr = infill_for_combination.find(current_extruder); + if(iterator_extruder_nr != infill_for_combination.end()) { - gcode_layer.addPolygonsByOptimizer(iterator_line_width->second.polygons, config); + gcode_layer.addPolygonsByOptimizer(iterator_extruder_nr->second.polygons, config); } else { - logWarning("Sparse pattern not found for line width %d, skipping\n", line_width); + logWarning("Sparse pattern not found for extruder %d, skipping\n", current_extruder); } } else diff --git a/src/PrimeTower.h b/src/PrimeTower.h index 6220eb7c81..5e45cad900 100644 --- a/src/PrimeTower.h +++ b/src/PrimeTower.h @@ -42,7 +42,7 @@ class PrimeTower std::vector pattern_per_extruder; //!< For each extruder the pattern to print on all layers of the prime tower. std::vector pattern_per_extruder_layer0; //!< For each extruder the pattern to print on the first layer - std::map> sparse_pattern_per_extruders; //!< For each extruders combination, and for each possible line width, the pattern to print on all layers where extruders are actually useless. + std::map> sparse_pattern_per_extruders; //!< For each extruders combination, and for each actual extruder, the pattern to print on all layers where extruders are actually useless. public: bool enabled; //!< Whether the prime tower is enabled. @@ -124,8 +124,9 @@ class PrimeTower * \param last_extruder The index of the last extruder to be pseudo-primed * \param rings_radii The external radii of each extruder ring, plus the internal radius of the internal ring * \param line_width The actual line width of the extruder + * \param actual_extruder_nr The actual extruder to be used */ - ExtrusionMoves generatePath_sparseInfill(const size_t first_extruder, const size_t last_extruder, const std::vector &rings_radii, const coord_t line_width); + ExtrusionMoves generatePath_sparseInfill(const size_t first_extruder, const size_t last_extruder, const std::vector &rings_radii, const coord_t line_width, const size_t actual_extruder_nr); /*! * Generate start locations on the prime tower. The locations are evenly spread around the prime tower's perimeter. From 0ab6b16c0a40f8e7594cad742bbb1f2919a58901 Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Mon, 6 Jun 2022 21:26:06 +0200 Subject: [PATCH 005/201] Fixed optimized prime tower first layer --- src/PrimeTower.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/PrimeTower.cpp b/src/PrimeTower.cpp index 8b4d56ded3..5e600b2ff5 100644 --- a/src/PrimeTower.cpp +++ b/src/PrimeTower.cpp @@ -41,7 +41,10 @@ PrimeTower::PrimeTower() //used (sacrifying for this purpose the usual single-extruder first layer, that would be better for prime-tower //adhesion). - multiple_extruders_on_first_layer = scene.current_mesh_group->settings.get("machine_extruders_share_nozzle") && ((adhesion_type != EPlatformAdhesion::SKIRT) && (adhesion_type != EPlatformAdhesion::BRIM)); + multiple_extruders_on_first_layer = (method == PrimeTowerMethod::OPTIMIZED) || + (method == PrimeTowerMethod::OPTIMIZED_CONSISTENT) || + (scene.current_mesh_group->settings.get("machine_extruders_share_nozzle") && + ((adhesion_type != EPlatformAdhesion::SKIRT) && (adhesion_type != EPlatformAdhesion::BRIM))); } enabled = method != PrimeTowerMethod::NONE From 9f91619012ddbbaff7406a8f85bda15f89a29f50 Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Tue, 7 Jun 2022 22:01:40 +0200 Subject: [PATCH 006/201] Fixed wrong prime tower generation --- src/FffGcodeWriter.cpp | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/src/FffGcodeWriter.cpp b/src/FffGcodeWriter.cpp index d0ba5c7472..d4e2d29642 100644 --- a/src/FffGcodeWriter.cpp +++ b/src/FffGcodeWriter.cpp @@ -1244,6 +1244,15 @@ void FffGcodeWriter::calculateExtruderOrderPerLayer(const SliceDataStorage& stor std::vector extruder_order = getUsedExtrudersOnLayerExcludingStartingExtruder(storage, last_extruder, layer_nr); extruder_order_per_layer_here.push_back(extruder_order); + #warning remove this + #if 0 + logAlways("##### Used extruders for layer %d (last %d)\n", layer_nr, last_extruder); + for(const size_t &extruder_nr : extruder_order) + { + logAlways("##### %d\n", extruder_nr); + } + #endif + if(layer_nr >= 0 && !extruder_order_per_layer_here.empty()) { std::vector extruder_prime_required(extruder_count, false); @@ -1251,7 +1260,7 @@ void FffGcodeWriter::calculateExtruderOrderPerLayer(const SliceDataStorage& stor // First used extruder only needs to be primed if an other extruder has been used before if(extruder_order.front() != last_extruder) { - extruder_prime_required[last_extruder] = true; + extruder_prime_required[extruder_order.front()] = true; } // All other used extruders need to be primed @@ -1264,10 +1273,10 @@ void FffGcodeWriter::calculateExtruderOrderPerLayer(const SliceDataStorage& stor #warning remove this #if 0 - log("##### Required primes for layer %d:\n", layer_nr); - for(const size_t &extruder_nr : extruder_prime_required) + logAlways("##### Required primes for layer %d:\n", layer_nr); + for(size_t extruder_nr = 0 ; extruder_nr < extruder_count ; ++extruder_nr) { - log("##### %d\n", extruder_nr); + logAlways("##### EX%d %d\n", extruder_nr, extruder_prime_required[extruder_nr] ? 1 : 0); } #endif } From 5ee834effb3481752d05ec14e87b6d89c635dbd3 Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Sat, 1 Apr 2023 08:19:54 +0200 Subject: [PATCH 007/201] Fixed wrong inset computation --- src/PrimeTower.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/PrimeTower.cpp b/src/PrimeTower.cpp index e466008285..4f7ccb142b 100644 --- a/src/PrimeTower.cpp +++ b/src/PrimeTower.cpp @@ -140,12 +140,11 @@ void PrimeTower::generatePaths_denseInfill(std::vector &cumulative_inse Polygons polygons = outer_poly.offset(-cumulative_inset - wall_nr * line_width - line_width / 2); pattern.polygons.add(polygons); current_volume += polygons.polygonLength() * line_width * layer_height * flow; - - //Don't continue. We won't ever reach the required volume because it doesn't fit. - assert(!polygons.empty() && "Prime tower is not large enough to generate the required volume"); + if(polygons.empty()) //Don't continue. We won't ever reach the required volume because it doesn't fit. + { + break; + } } - cumulative_inset += wall_nr * line_width; - cumulative_insets.push_back(cumulative_inset); //Only the most inside extruder needs to fill the inside of the prime tower if (extruder_nr != extruder_order.back() || method != PrimeTowerMethod::DEFAULT) @@ -169,6 +168,7 @@ void PrimeTower::generatePaths_denseInfill(std::vector &cumulative_inse } } cumulative_inset += wall_nr * line_width; + cumulative_insets.push_back(cumulative_inset); } } From dcd15aa839a52573e31b1c819ddfb72a794bf4c6 Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Mon, 3 Apr 2023 21:42:56 +0200 Subject: [PATCH 008/201] Fixed shields generation --- src/FffPolygonGenerator.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/FffPolygonGenerator.cpp b/src/FffPolygonGenerator.cpp index 6a4057157d..200c1d927b 100644 --- a/src/FffPolygonGenerator.cpp +++ b/src/FffPolygonGenerator.cpp @@ -927,7 +927,7 @@ void FffPolygonGenerator::processOozeShield(SliceDataStorage& storage) { storage.oozeShield[layer_nr].removeSmallAreas(largest_printed_area); } - if (mesh_group_settings.get("prime_tower_enable")) + if (mesh_group_settings.get("prime_tower_mode") != PrimeTowerMethod::NONE) { coord_t max_line_width = 0; { // compute max_line_width @@ -979,7 +979,7 @@ void FffPolygonGenerator::processDraftShield(SliceDataStorage& storage) maximum_deviation = std::min(maximum_deviation, extruder.settings.get("meshfix_maximum_deviation")); } storage.draft_protection_shield = Simplify(maximum_resolution, maximum_deviation, 0).polygon(storage.draft_protection_shield); - if (mesh_group_settings.get("prime_tower_enable")) + if (mesh_group_settings.get("prime_tower_mode") != PrimeTowerMethod::NONE) { coord_t max_line_width = 0; { // compute max_line_width From a01543afc90104c2895ee770c069e49fef84d9ca Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Mon, 3 Apr 2023 21:43:15 +0200 Subject: [PATCH 009/201] Fixed (maybe) unit tests --- tests/LayerPlanTest.cpp | 32 ++++++++++++++------------------ 1 file changed, 14 insertions(+), 18 deletions(-) diff --git a/tests/LayerPlanTest.cpp b/tests/LayerPlanTest.cpp index b583005053..adc5c888db 100644 --- a/tests/LayerPlanTest.cpp +++ b/tests/LayerPlanTest.cpp @@ -6,8 +6,8 @@ #include "RetractionConfig.h" //To provide retraction settings. #include "Slice.h" //To provide settings for the layer plan. #include "pathPlanning/Comb.h" //To create a combing path around the layer plan. -#include "sliceDataStorage.h" //To provide slice data as input for the planning stage. #include "pathPlanning/NozzleTempInsert.h" //To provide nozzle temperature commands. +#include "sliceDataStorage.h" //To provide slice data as input for the planning stage. #include "utils/Coord_t.h" #include @@ -119,7 +119,7 @@ class LayerPlanTest : public testing::Test settings->add("machine_width", "1000"); settings->add("material_flow_layer_0", "100"); settings->add("meshfix_maximum_travel_resolution", "0"); - settings->add("prime_tower_enable", "true"); + settings->add("prime_tower_mode", "default"); settings->add("prime_tower_flow", "108"); settings->add("prime_tower_line_width", "0.48"); settings->add("prime_tower_min_volume", "10"); @@ -385,14 +385,13 @@ class AddTravelTest : public LayerPlanTest, public testing::WithParamInterface nozzle_temp_inserts { - { .path_idx = 1, .extruder = 1, .temperature = 100., .wait = true }, - { .path_idx = 2, .extruder = 1, .temperature = 110., .wait = false, .time_after_path_start = 2. }, - { .path_idx = 1, .extruder = 1, .temperature = 120., .wait = true }, - { .path_idx = 5, .extruder = 1, .temperature = 130., .wait = false, .time_after_path_start = 1. }, - { .path_idx = 5, .extruder = 1, .temperature = 140., .wait = true }, - { .path_idx = 2, .extruder = 1, .temperature = 150., .wait = false, .time_after_path_start = 1. }, + std::vector nozzle_temp_inserts{ + { .path_idx = 1, .extruder = 1, .temperature = 100., .wait = true }, { .path_idx = 2, .extruder = 1, .temperature = 110., .wait = false, .time_after_path_start = 2. }, + { .path_idx = 1, .extruder = 1, .temperature = 120., .wait = true }, { .path_idx = 5, .extruder = 1, .temperature = 130., .wait = false, .time_after_path_start = 1. }, + { .path_idx = 5, .extruder = 1, .temperature = 140., .wait = true }, { .path_idx = 2, .extruder = 1, .temperature = 150., .wait = false, .time_after_path_start = 1. }, }; std::sort(nozzle_temp_inserts.begin(), nozzle_temp_inserts.end()); EXPECT_EQ(nozzle_temp_inserts[0].temperature, 100.); @@ -571,4 +567,4 @@ TEST(NozzleTempInsertTest, SortNozzleTempInsterts) } } // namespace cura -// NOLINTEND(*-magic-numbers) \ No newline at end of file +// NOLINTEND(*-magic-numbers) From 685a5265579086b043180a467edd5751a4de93b3 Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Mon, 3 Apr 2023 21:55:53 +0200 Subject: [PATCH 010/201] Fixed optimized-consistent generation --- src/PrimeTower.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/PrimeTower.cpp b/src/PrimeTower.cpp index 4f7ccb142b..77e029bc60 100644 --- a/src/PrimeTower.cpp +++ b/src/PrimeTower.cpp @@ -322,6 +322,7 @@ void PrimeTower::addToGcode(const SliceDataStorage& storage, LayerPlan& gcode_la break; case PrimeTowerMethod::OPTIMIZED: + case PrimeTowerMethod::OPTIMIZED_CONSISTENT: if(required_extruder_prime[new_extruder]) { // Extruder really needs to be prime From 135e0a528a29f15974106d83e50cac6c0916e2d7 Mon Sep 17 00:00:00 2001 From: casperlamboo Date: Tue, 22 Aug 2023 11:46:05 +0000 Subject: [PATCH 011/201] Applied clang-format. --- include/FffGcodeWriter.h | 232 +++-- include/SkeletalTrapezoidation.h | 136 ++- include/SkeletalTrapezoidationEdge.h | 38 +- include/SkeletalTrapezoidationGraph.h | 52 +- include/SkirtBrim.h | 82 +- include/SupportInfillPart.h | 18 +- include/TreeModelVolumes.h | 54 +- include/TreeSupport.h | 105 +- include/TreeSupportBaseCircle.h | 5 +- include/TreeSupportElement.h | 272 +++--- include/TreeSupportEnums.h | 4 +- include/TreeSupportSettings.h | 317 +++--- include/TreeSupportTipGenerator.h | 58 +- include/TreeSupportUtils.h | 124 ++- include/WallToolPaths.h | 34 +- include/WallsComputation.h | 8 +- include/utils/HalfEdge.h | 14 +- include/utils/HalfEdgeNode.h | 14 +- include/utils/Simplify.h | 82 +- include/utils/polygonUtils.h | 318 +++--- include/utils/types/get.h | 4 +- include/utils/views/dfs.h | 20 +- src/Application.cpp | 33 +- src/MeshGroup.cpp | 29 +- src/SupportInfillPart.cpp | 11 +- src/TreeSupport.cpp | 1280 +++++++++++++------------ src/WallsComputation.cpp | 29 +- src/settings/Settings.cpp | 8 +- src/utils/LinearAlg2D.cpp | 56 +- src/utils/polygonUtils.cpp | 131 ++- 30 files changed, 1929 insertions(+), 1639 deletions(-) diff --git a/include/FffGcodeWriter.h b/include/FffGcodeWriter.h index 36d934504e..aa2264be8c 100644 --- a/include/FffGcodeWriter.h +++ b/include/FffGcodeWriter.h @@ -4,17 +4,17 @@ #ifndef GCODE_WRITER_H #define GCODE_WRITER_H -#include -#include - #include "FanSpeedLayerTime.h" -#include "gcodeExport.h" #include "LayerPlanBuffer.h" +#include "gcodeExport.h" #include "settings/PathConfigStorage.h" //For the MeshPathConfigs subclass. #include "utils/ExtrusionLine.h" //Processing variable-width paths. #include "utils/NoCopy.h" -namespace cura +#include +#include + +namespace cura { class AngleDegrees; @@ -28,28 +28,28 @@ class TimeKeeper; /*! * Secondary stage in Fused Filament Fabrication processing: The generated polygons are used in the gcode generation. - * Some polygons in the SliceDataStorage signify areas which are to be filled with parallel lines, + * Some polygons in the SliceDataStorage signify areas which are to be filled with parallel lines, * while other polygons signify the contours which should be printed. - * + * * The main function of this class is FffGcodeWriter::writeGCode(). */ class FffGcodeWriter : public NoCopy { - friend class FffProcessor; //Because FffProcessor exposes finalize (TODO) + friend class FffProcessor; // Because FffProcessor exposes finalize (TODO) private: coord_t max_object_height; //!< The maximal height of all previously sliced meshgroups, used to avoid collision when moving to the next meshgroup to print. /* * Buffer for all layer plans (of type LayerPlan) - * + * * The layer plans are buffered so that we can start heating up a nozzle several layers before it needs to be used. * Another reason is to perform Auto Temperature. */ - LayerPlanBuffer layer_plan_buffer; + LayerPlanBuffer layer_plan_buffer; /*! * The class holding the current state of the gcode being written. - * + * * It holds information such as the last written position etc. */ GCodeExport gcode; @@ -106,18 +106,18 @@ class FffGcodeWriter : public NoCopy /*! * Set the target to write gcode to: an output stream. - * + * * Used when CuraEngine is NOT used as command line tool. - * + * * \param stream The stream to write gcode to. */ void setTargetStream(std::ostream* stream); /*! * Get the total extruded volume for a specific extruder in mm^3 - * + * * Retractions and unretractions don't contribute to this. - * + * * \param extruder_nr The extruder number for which to get the total netto extruded volume * \return total filament printed in mm^3 */ @@ -125,7 +125,7 @@ class FffGcodeWriter : public NoCopy /*! * Get the total estimated print time in seconds for each feature - * + * * \return total print time in seconds for each feature */ std::vector getTotalPrintTimePerFeature(); @@ -133,7 +133,7 @@ class FffGcodeWriter : public NoCopy /*! * Write all the gcode for the current meshgroup. * This is the primary function of this class. - * + * * \param[in] storage The data storage from which to get the polygons to print and the areas to fill. * \param timeKeeper The stop watch to see how long it takes for each of the stages in the slicing process. */ @@ -148,28 +148,28 @@ class FffGcodeWriter : public NoCopy /*! * Set the retraction and wipe config globally, per extruder and per mesh. - * + * * \param[out] storage The data storage to which to save the configurations */ void setConfigRetractionAndWipe(SliceDataStorage& storage); /*! * Get the extruder with which to start the print. - * + * * Generally this is the extruder of the adhesion type in use, but in case * the platform adhesion type is none, the support extruder is used. If * support is also disabled, the extruder with lowest number which is used * on the first layer is used as initial extruder. - * + * * \param[in] storage where to get settings from. */ size_t getStartExtruder(const SliceDataStorage& storage); /*! * Set the infill angles and skin angles in the SliceDataStorage. - * + * * These lists of angles are cycled through to get the infill angle of a specific layer. - * + * * \param mesh The mesh for which to determine the infill and skin angles. */ void setInfillAndSkinAngles(SliceMeshStorage& mesh); @@ -188,24 +188,24 @@ class FffGcodeWriter : public NoCopy /*! * Move up and over the already printed meshgroups to print the next meshgroup. - * + * * \param[in] storage where the slice data is stored. */ void processNextMeshGroupCode(const SliceDataStorage& storage); - + /*! * Add raft layer plans onto the FffGcodeWriter::layer_plan_buffer - * + * * \param[in,out] storage where the slice data is stored. */ void processRaft(const SliceDataStorage& storage); /*! * Convert the polygon data of a layer into a layer plan on the FffGcodeWriter::layer_plan_buffer - * + * * In case of negative layer numbers, create layers only containing the data from * the helper parts (support etc) to fill up the gap between the raft and the model. - * + * * \param[in] storage where the slice data is stored. * \param layer_nr The index of the layer to write the gcode of. * \param total_layers The total number of layers. @@ -219,17 +219,17 @@ class FffGcodeWriter : public NoCopy * * Technically, this function checks whether any extruder needs to be primed (with a prime blob) * separately just before they are used. - * + * * \return whether any extruder need to be primed separately just before they are used */ bool getExtruderNeedPrimeBlobDuringFirstLayer(const SliceDataStorage& storage, const size_t extruder_nr) const; /*! * Add the skirt or the brim to the layer plan \p gcodeLayer if it hasn't already been added yet. - * + * * This function should be called for only one layer; * calling it for multiple layers results in the skirt/brim being printed on multiple layers. - * + * * \param storage where the slice data is stored. * \param gcodeLayer The initial planning of the g-code of the layer. * \param extruder_nr The extruder train for which to process the skirt or @@ -240,15 +240,15 @@ class FffGcodeWriter : public NoCopy /*! * Adds the ooze shield to the layer plan \p gcodeLayer. - * + * * \param[in] storage where the slice data is stored. * \param gcodeLayer The initial planning of the gcode of the layer. */ void processOozeShield(const SliceDataStorage& storage, LayerPlan& gcodeLayer) const; - + /*! * Adds the draft protection screen to the layer plan \p gcodeLayer. - * + * * \param[in] storage where the slice data is stored. * \param gcodeLayer The initial planning of the gcode of the layer. */ @@ -258,14 +258,14 @@ class FffGcodeWriter : public NoCopy * Calculate in which order to plan the extruders for each layer * Store the order of extruders for each layer in extruder_order_per_layer for normal layers * and the order of extruders for raft/filler layers in extruder_order_per_layer_negative_layers. - * + * * Only extruders which are (most probably) going to be used are planned - * + * * \note At the planning stage we only have information on areas, not how those are filled. * If an area is too small to be filled with anything it will still get specified as being used with the extruder for that area. - * + * * Computes \ref FffGcodeWriter::extruder_order_per_layer and \ref FffGcodeWriter::extruder_order_per_layer_negative_layers - * + * * \param[in] storage where the slice data is stored. */ void calculateExtruderOrderPerLayer(const SliceDataStorage& storage); @@ -282,10 +282,10 @@ class FffGcodeWriter : public NoCopy /*! * Gets a list of extruders that are used on the given layer, but excluding the given starting extruder. * When it's on the first layer, the prime blob will also be taken into account. - * + * * \note At the planning stage we only have information on areas, not how those are filled. * If an area is too small to be filled with anything it will still get specified as being used with the extruder for that area. - * + * * \param[in] storage where the slice data is stored. * \param current_extruder The current extruder with which we last printed * \return The order of extruders for a layer beginning with \p current_extruder @@ -296,7 +296,7 @@ class FffGcodeWriter : public NoCopy * Calculate in which order to plan the meshes of a specific extruder * Each mesh which has some feature printed with the extruder is included in this order. * One mesh can occur in the mesh order of multiple extruders. - * + * * \param[in] storage where the slice data is stored. * \param extruder_nr The extruder for which to determine the order * \return A vector of mesh indices ordered on print order for that extruder. @@ -305,41 +305,50 @@ class FffGcodeWriter : public NoCopy /*! * Add a single layer from a single mesh-volume to the layer plan \p gcodeLayer in mesh surface mode. - * + * * \param[in] storage where the slice data is stored. * \param mesh The mesh to add to the layer plan \p gcodeLayer. * \param mesh_config the line config with which to print a print feature * \param gcodeLayer The initial planning of the gcode of the layer. */ - void addMeshLayerToGCode_meshSurfaceMode(const SliceDataStorage& storage, const SliceMeshStorage& mesh, const PathConfigStorage::MeshPathConfigs& mesh_config, LayerPlan& gcodeLayer) const; - + void addMeshLayerToGCode_meshSurfaceMode( + const SliceDataStorage& storage, + const SliceMeshStorage& mesh, + const PathConfigStorage::MeshPathConfigs& mesh_config, + LayerPlan& gcodeLayer) const; + /*! * Add the open polylines from a single layer from a single mesh-volume to the layer plan \p gcodeLayer for mesh the surface modes. - * + * * \param[in] storage where the slice data is stored. * \param mesh The mesh for which to add to the layer plan \p gcodeLayer. * \param mesh_config the line config with which to print a print feature * \param gcodeLayer The initial planning of the gcode of the layer. */ void addMeshOpenPolyLinesToGCode(const SliceMeshStorage& mesh, const PathConfigStorage::MeshPathConfigs& mesh_config, LayerPlan& gcode_layer) const; - + /*! * Add all features of a given extruder from a single layer from a single mesh-volume to the layer plan \p gcode_layer. - * + * * This adds all features (e.g. walls, skin etc.) of this \p mesh to the gcode which are printed using \p extruder_nr - * + * * \param[in] storage where the slice data is stored. * \param mesh The mesh to add to the layer plan \p gcode_layer. * \param extruder_nr The extruder for which to print all features of the mesh which should be printed with this extruder * \param mesh_config the line config with which to print a print feature * \param gcode_layer The initial planning of the gcode of the layer. */ - void addMeshLayerToGCode(const SliceDataStorage& storage, const SliceMeshStorage& mesh, const size_t extruder_nr, const PathConfigStorage::MeshPathConfigs& mesh_config, LayerPlan& gcode_layer) const; + void addMeshLayerToGCode( + const SliceDataStorage& storage, + const SliceMeshStorage& mesh, + const size_t extruder_nr, + const PathConfigStorage::MeshPathConfigs& mesh_config, + LayerPlan& gcode_layer) const; /*! * Add all features of the given extruder from a single part from a given layer of a mesh-volume to the layer plan \p gcode_layer. * This only adds the features which are printed with \p extruder_nr. - * + * * \param[in] storage where the slice data is stored. * \param storage Storage to get global settings from. * \param mesh The mesh to add to the layer plan \p gcode_layer. @@ -348,7 +357,13 @@ class FffGcodeWriter : public NoCopy * \param part The part to add * \param gcode_layer The initial planning of the gcode of the layer. */ - void addMeshPartToGCode(const SliceDataStorage& storage, const SliceMeshStorage& mesh, const size_t extruder_nr, const PathConfigStorage::MeshPathConfigs& mesh_config, const SliceLayerPart& part, LayerPlan& gcode_layer) const; + void addMeshPartToGCode( + const SliceDataStorage& storage, + const SliceMeshStorage& mesh, + const size_t extruder_nr, + const PathConfigStorage::MeshPathConfigs& mesh_config, + const SliceLayerPart& part, + LayerPlan& gcode_layer) const; /*! * \brief Add infill for a given part in a layer plan. @@ -361,12 +376,18 @@ class FffGcodeWriter : public NoCopy * \param part The part for which to create gcode. * \return Whether this function added anything to the layer plan. */ - bool processInfill(const SliceDataStorage& storage, LayerPlan& gcodeLayer, const SliceMeshStorage& mesh, const size_t extruder_nr, const PathConfigStorage::MeshPathConfigs& mesh_config, const SliceLayerPart& part) const; + bool processInfill( + const SliceDataStorage& storage, + LayerPlan& gcodeLayer, + const SliceMeshStorage& mesh, + const size_t extruder_nr, + const PathConfigStorage::MeshPathConfigs& mesh_config, + const SliceLayerPart& part) const; /*! * \brief Add thicker (multiple layers) sparse infill for a given part in a * layer plan. - * + * * \param gcodeLayer The initial planning of the gcode of the layer. * \param mesh The mesh for which to add to the layer plan \p gcodeLayer. * \param extruder_nr The extruder for which to print all features of the @@ -375,7 +396,13 @@ class FffGcodeWriter : public NoCopy * \param part The part for which to create gcode. * \return Whether this function added anything to the layer plan. */ - bool processMultiLayerInfill(const SliceDataStorage& storage, LayerPlan& gcodeLayer, const SliceMeshStorage& mesh, const size_t extruder_nr, const PathConfigStorage::MeshPathConfigs& mesh_config, const SliceLayerPart& part) const; + bool processMultiLayerInfill( + const SliceDataStorage& storage, + LayerPlan& gcodeLayer, + const SliceMeshStorage& mesh, + const size_t extruder_nr, + const PathConfigStorage::MeshPathConfigs& mesh_config, + const SliceLayerPart& part) const; /*! * \brief Add normal sparse infill for a given part in a layer. @@ -387,7 +414,13 @@ class FffGcodeWriter : public NoCopy * \param part The part for which to create gcode. * \return Whether this function added anything to the layer plan. */ - bool processSingleLayerInfill(const SliceDataStorage& storage, LayerPlan& gcodeLayer, const SliceMeshStorage& mesh, const size_t extruder_nr, const PathConfigStorage::MeshPathConfigs& mesh_config, const SliceLayerPart& part) const; + bool processSingleLayerInfill( + const SliceDataStorage& storage, + LayerPlan& gcodeLayer, + const SliceMeshStorage& mesh, + const size_t extruder_nr, + const PathConfigStorage::MeshPathConfigs& mesh_config, + const SliceLayerPart& part) const; /*! * Generate the insets for the walls of a given layer part. @@ -399,7 +432,13 @@ class FffGcodeWriter : public NoCopy * \param part The part for which to create gcode * \return Whether this function added anything to the layer plan */ - bool processInsets(const SliceDataStorage& storage, LayerPlan& gcodeLayer, const SliceMeshStorage& mesh, const size_t extruder_nr, const PathConfigStorage::MeshPathConfigs& mesh_config, const SliceLayerPart& part) const; + bool processInsets( + const SliceDataStorage& storage, + LayerPlan& gcodeLayer, + const SliceMeshStorage& mesh, + const size_t extruder_nr, + const PathConfigStorage::MeshPathConfigs& mesh_config, + const SliceLayerPart& part) const; /*! * Generate the a spiralized wall for a given layer part. @@ -409,7 +448,12 @@ class FffGcodeWriter : public NoCopy * \param part The part for which to create gcode * \param mesh The mesh for which to add to the layer plan \p gcodeLayer. */ - void processSpiralizedWall(const SliceDataStorage& storage, LayerPlan& gcode_layer, const PathConfigStorage::MeshPathConfigs& mesh_config, const SliceLayerPart& part, const SliceMeshStorage& mesh) const; + void processSpiralizedWall( + const SliceDataStorage& storage, + LayerPlan& gcode_layer, + const PathConfigStorage::MeshPathConfigs& mesh_config, + const SliceLayerPart& part, + const SliceMeshStorage& mesh) const; /*! * Add the gcode of the top/bottom skin of the given part and of the perimeter gaps. @@ -422,21 +466,27 @@ class FffGcodeWriter : public NoCopy * \param part The part for which to create gcode * \return Whether this function added anything to the layer plan */ - bool processSkin(const SliceDataStorage& storage, LayerPlan& gcode_layer, const SliceMeshStorage& mesh, const size_t extruder_nr, const PathConfigStorage::MeshPathConfigs& mesh_config, const SliceLayerPart& part) const; + bool processSkin( + const SliceDataStorage& storage, + LayerPlan& gcode_layer, + const SliceMeshStorage& mesh, + const size_t extruder_nr, + const PathConfigStorage::MeshPathConfigs& mesh_config, + const SliceLayerPart& part) const; /*! * Add the gcode of the top/bottom skin of the given skin part and of the perimeter gaps. - * + * * Perimeter gaps are handled for the current extruder for the following features if they are printed with this extruder. * - skin outlines * - roofing (if concentric) * - top/bottom (if concentric) * They are all printed at the end of printing the skin part features which are printed with this extruder. - * + * * Note that the normal perimeter gaps are printed with the outer wall extruder, * while newly generated perimeter gaps * are printed with the extruder with which the feature was printed which generated the gaps. - * + * * \param[in] storage where the slice data is stored. * \param gcode_layer The initial planning of the gcode of the layer. * \param mesh The mesh for which to add to the layer plan \p gcode_layer. @@ -445,7 +495,13 @@ class FffGcodeWriter : public NoCopy * \param skin_part The skin part for which to create gcode * \return Whether this function added anything to the layer plan */ - bool processSkinPart(const SliceDataStorage& storage, LayerPlan& gcode_layer, const SliceMeshStorage& mesh, const size_t extruder_nr, const PathConfigStorage::MeshPathConfigs& mesh_config, const SkinPart& skin_part) const; + bool processSkinPart( + const SliceDataStorage& storage, + LayerPlan& gcode_layer, + const SliceMeshStorage& mesh, + const size_t extruder_nr, + const PathConfigStorage::MeshPathConfigs& mesh_config, + const SkinPart& skin_part) const; /*! * Add the roofing which is the area inside the innermost skin inset which has air 'directly' above @@ -458,7 +514,14 @@ class FffGcodeWriter : public NoCopy * \param skin_part The skin part for which to create gcode * \param[out] added_something Whether this function added anything to the layer plan */ - void processRoofing(const SliceDataStorage& storage, LayerPlan& gcode_layer, const SliceMeshStorage& mesh, const size_t extruder_nr, const PathConfigStorage::MeshPathConfigs& mesh_config, const SkinPart& skin_part, bool& added_something) const; + void processRoofing( + const SliceDataStorage& storage, + LayerPlan& gcode_layer, + const SliceMeshStorage& mesh, + const size_t extruder_nr, + const PathConfigStorage::MeshPathConfigs& mesh_config, + const SkinPart& skin_part, + bool& added_something) const; /*! * Add the normal skinfill which is the area inside the innermost skin inset @@ -472,11 +535,18 @@ class FffGcodeWriter : public NoCopy * \param skin_part The skin part for which to create gcode * \param[out] added_something Whether this function added anything to the layer plan */ - void processTopBottom(const SliceDataStorage& storage, LayerPlan& gcode_layer, const SliceMeshStorage& mesh, const size_t extruder_nr, const PathConfigStorage::MeshPathConfigs& mesh_config, const SkinPart& skin_part, bool& added_something) const; + void processTopBottom( + const SliceDataStorage& storage, + LayerPlan& gcode_layer, + const SliceMeshStorage& mesh, + const size_t extruder_nr, + const PathConfigStorage::MeshPathConfigs& mesh_config, + const SkinPart& skin_part, + bool& added_something) const; /*! * Process a dense skin feature like roofing or top/bottom - * + * * \param[in] storage where the slice data is stored. * \param gcode_layer The initial planning of the gcode of the layer. * \param mesh The mesh for which to add to the layer plan \p gcode_layer. @@ -493,7 +563,21 @@ class FffGcodeWriter : public NoCopy * \param[out] added_something Whether this function added anything to the layer plan * \param fan_speed fan speed override for this skin area */ - void processSkinPrintFeature(const SliceDataStorage& storage, LayerPlan& gcode_layer, const SliceMeshStorage& mesh, const PathConfigStorage::MeshPathConfigs& mesh_config, const size_t extruder_nr, const Polygons& area, const GCodePathConfig& config, EFillMethod pattern, const AngleDegrees skin_angle, const coord_t skin_overlap, const Ratio skin_density, const bool monotonic, bool& added_something, double fan_speed = GCodePathConfig::FAN_SPEED_DEFAULT) const; + void processSkinPrintFeature( + const SliceDataStorage& storage, + LayerPlan& gcode_layer, + const SliceMeshStorage& mesh, + const PathConfigStorage::MeshPathConfigs& mesh_config, + const size_t extruder_nr, + const Polygons& area, + const GCodePathConfig& config, + EFillMethod pattern, + const AngleDegrees skin_angle, + const coord_t skin_overlap, + const Ratio skin_density, + const bool monotonic, + bool& added_something, + double fan_speed = GCodePathConfig::FAN_SPEED_DEFAULT) const; /*! * see if we can avoid printing a lines or zig zag style skin part in multiple segments by moving to @@ -512,7 +596,7 @@ class FffGcodeWriter : public NoCopy * +------+ +------+ * 1, 2 = start locations of skin segments * # = seam - * + * * \param filling_part The part which we are going to fill with a linear filling type * \param filling_angle The angle of the filling lines * \param last_position The position the print head is in before going to fill the part @@ -575,9 +659,9 @@ class FffGcodeWriter : public NoCopy /*! * Change to a new extruder, and add the prime tower instructions if the new extruder is different from the last. - * + * * On layer 0 this function adds the skirt for the nozzle it switches to, instead of the prime tower. - * + * * \param[in] storage where the slice data is stored. * \param gcode_layer The initial planning of the gcode of the layer. * \param extruder_nr The extruder to switch to. @@ -591,7 +675,7 @@ class FffGcodeWriter : public NoCopy * \param prev_extruder The current extruder with which we last printed. */ void addPrimeTower(const SliceDataStorage& storage, LayerPlan& gcodeLayer, const size_t prev_extruder) const; - + /*! * Add the end gcode and set all temperatures to zero. */ @@ -630,9 +714,15 @@ class FffGcodeWriter : public NoCopy * \param infill_line_width line width of the infill * \return true if there needs to be a skin edge support wall in this layer, otherwise false */ - static bool partitionInfillBySkinAbove(Polygons& infill_below_skin, Polygons& infill_not_below_skin, const LayerPlan& gcode_layer, const SliceMeshStorage& mesh, const SliceLayerPart& part, coord_t infill_line_width) ; + static bool partitionInfillBySkinAbove( + Polygons& infill_below_skin, + Polygons& infill_not_below_skin, + const LayerPlan& gcode_layer, + const SliceMeshStorage& mesh, + const SliceLayerPart& part, + coord_t infill_line_width); }; -}//namespace cura +} // namespace cura #endif // GCODE_WRITER_H diff --git a/include/SkeletalTrapezoidation.h b/include/SkeletalTrapezoidation.h index 2b920465c4..07968972cf 100644 --- a/include/SkeletalTrapezoidation.h +++ b/include/SkeletalTrapezoidation.h @@ -4,39 +4,38 @@ #ifndef SKELETAL_TRAPEZOIDATION_H #define SKELETAL_TRAPEZOIDATION_H -#include +#include "BeadingStrategy/BeadingStrategy.h" +#include "SkeletalTrapezoidationEdge.h" +#include "SkeletalTrapezoidationGraph.h" +#include "SkeletalTrapezoidationJoint.h" +#include "settings/types/Ratio.h" +#include "utils/ExtrusionJunction.h" +#include "utils/ExtrusionLine.h" +#include "utils/HalfEdgeGraph.h" +#include "utils/PolygonsSegmentIndex.h" +#include "utils/polygon.h" +#include "utils/section_type.h" +#include #include // smart pointers #include #include // pair -#include "utils/HalfEdgeGraph.h" -#include "utils/polygon.h" -#include "utils/PolygonsSegmentIndex.h" -#include "utils/ExtrusionJunction.h" -#include "utils/ExtrusionLine.h" -#include "utils/section_type.h" -#include "settings/types/Ratio.h" -#include "SkeletalTrapezoidationEdge.h" -#include "SkeletalTrapezoidationJoint.h" -#include "BeadingStrategy/BeadingStrategy.h" -#include "SkeletalTrapezoidationGraph.h" - namespace cura { /*! * Main class of the dynamic beading strategies. - * + * * The input polygon region is decomposed into trapezoids and represented as a half-edge data-structure. - * + * * We determine which edges are 'central' accordinding to the transitioning_angle of the beading strategy, * and determine the bead count for these central regions and apply them outward when generating toolpaths. [oversimplified] - * + * * The method can be visually explained as generating the 3D union of cones surface on the outline polygons, - * and changing the heights along central regions of that surface so that they are flat. + * and changing the heights along central regions of that surface so that they are flat. * For more info, please consult the paper "A framework for adaptive width control of dense contour-parallel toolpaths in fused -deposition modeling" by Kuipers et al. +deposition modeling" by Kuipers et al. * This visual explanation aid explains the use of "upward", "lower" etc, * i.e. the radial distance and/or the bead count are used as heights of this visualization, there is no coordinate called 'Z'. * @@ -66,7 +65,7 @@ class SkeletalTrapezoidation coord_t beading_propagation_transition_dist; //!< When there are different beadings propagated from below and from above, use this transitioning distance static constexpr coord_t central_filter_dist = 20; //!< Filter areas marked as 'central' smaller than this static constexpr coord_t snap_dist = 20; //!< Generic arithmatic inaccuracy. Only used to determine whether a transition really needs to insert an extra edge. - int layer_idx { }; + int layer_idx{}; SectionType section_type; /*! @@ -99,16 +98,16 @@ class SkeletalTrapezoidation * beadings propagated from below and from above, use this transitioning * distance. */ - SkeletalTrapezoidation(const Polygons& polys, - const BeadingStrategy& beading_strategy, - AngleRadians transitioning_angle, - coord_t discretization_step_size, - coord_t transition_filter_dist, - coord_t allowed_filter_deviation, - coord_t beading_propagation_transition_dist, - int layer_idx, - SectionType section_type - ); + SkeletalTrapezoidation( + const Polygons& polys, + const BeadingStrategy& beading_strategy, + AngleRadians transitioning_angle, + coord_t discretization_step_size, + coord_t transition_filter_dist, + coord_t allowed_filter_deviation, + coord_t beading_propagation_transition_dist, + int layer_idx, + SectionType section_type); /*! * A skeletal graph through the polygons that we need to fill with beads. @@ -141,19 +140,20 @@ class SkeletalTrapezoidation TransitionMidRef(edge_t* edge, std::list::iterator transition_it) : edge(edge) , transition_it(transition_it) - {} + { + } }; /*! * Compute the skeletal trapezoidation decomposition of the input shape. - * + * * Compute the Voronoi Diagram (VD) and transfer all inside edges into our half-edge (HE) datastructure. - * + * * The algorithm is currently a bit overcomplicated, because the discretization of parabolic edges is performed at the same time as all edges are being transfered, * which means that there is no one-to-one mapping from VD edges to HE edges. * Instead we map from a VD edge to the last HE edge. * This could be cimplified by recording the edges which should be discretized and discretizing the mafterwards. - * + * * Another complication arises because the VD uses floating logic, which can result in zero-length segments after rounding to integers. * We therefore collapse edges and their whole cells afterwards. */ @@ -169,7 +169,7 @@ class SkeletalTrapezoidation /*! * (Eventual) returned 'polylines per index' result (from generateToolpaths): - * + * * Binned by inset_idx. */ std::vector* p_generated_toolpaths; @@ -178,7 +178,15 @@ class SkeletalTrapezoidation * Transfer an edge from the VD to the HE and perform discretization of parabolic edges (and vertex-vertex edges) * \p prev_edge serves as input and output. May be null as input. */ - void transferEdge(Point from, Point to, vd_t::edge_type& vd_edge, edge_t*& prev_edge, Point& start_source_point, Point& end_source_point, const std::vector& points, const std::vector& segments); + void transferEdge( + Point from, + Point to, + vd_t::edge_type& vd_edge, + edge_t*& prev_edge, + Point& start_source_point, + Point& end_source_point, + const std::vector& points, + const std::vector& segments); /*! * Discretize a Voronoi edge that represents the medial axis of a vertex- @@ -231,7 +239,14 @@ class SkeletalTrapezoidation * /return Whether the cell is inside of the polygon. If it's outside of the * polygon we should skip processing it altogether. */ - bool computePointCellRange(vd_t::cell_type& cell, Point& start_source_point, Point& end_source_point, vd_t::edge_type*& starting_vd_edge, vd_t::edge_type*& ending_vd_edge, const std::vector& points, const std::vector& segments); + bool computePointCellRange( + vd_t::cell_type& cell, + Point& start_source_point, + Point& end_source_point, + vd_t::edge_type*& starting_vd_edge, + vd_t::edge_type*& ending_vd_edge, + const std::vector& points, + const std::vector& segments); /*! * Compute the range of line segments that surround a cell of the skeletal @@ -257,7 +272,14 @@ class SkeletalTrapezoidation * /return Whether the cell is inside of the polygon. If it's outside of the * polygon we should skip processing it altogether. */ - void computeSegmentCellRange(vd_t::cell_type& cell, Point& start_source_point, Point& end_source_point, vd_t::edge_type*& starting_vd_edge, vd_t::edge_type*& ending_vd_edge, const std::vector& points, const std::vector& segments); + void computeSegmentCellRange( + vd_t::cell_type& cell, + Point& start_source_point, + Point& end_source_point, + vd_t::edge_type*& starting_vd_edge, + vd_t::edge_type*& ending_vd_edge, + const std::vector& points, + const std::vector& segments); /*! * For VD cells associated with an input polygon vertex, we need to separate the node at the end and start of the cell into two @@ -273,7 +295,7 @@ class SkeletalTrapezoidation /*! * Filter out small central areas. - * + * * Only used to get rid of small edges which get marked as central because * of rounding errors because the region is so small. */ @@ -289,9 +311,9 @@ class SkeletalTrapezoidation /*! * Unmark the outermost edges directly connected to the outline, as not * being central. - * + * * Only used to emulate some related literature. - * + * * The paper shows that this function is bad for the stability of the framework. */ void filterOuterCentral(); @@ -429,7 +451,15 @@ class SkeletalTrapezoidation * \return Whether the given edge is going downward (i.e. towards a thinner * region of the polygon). */ - bool generateTransitionEnd(edge_t& edge, coord_t start_pos, coord_t end_pos, coord_t transition_half_length, Ratio start_rest, Ratio end_rest, coord_t transition_lower_bead_count, ptr_vector_t>& edge_transition_ends); + bool generateTransitionEnd( + edge_t& edge, + coord_t start_pos, + coord_t end_pos, + coord_t transition_half_length, + Ratio start_rest, + Ratio end_rest, + coord_t transition_lower_bead_count, + ptr_vector_t>& edge_transition_ends); /*! * Determines whether an edge is going downwards or upwards in the graph. @@ -488,28 +518,30 @@ class SkeletalTrapezoidation /*! * Propagate beading information from nodes that are closer to the edge * (low radius R) to nodes that are farther from the edge (high R). - * + * * only propagate from nodes with beading info upward to nodes without beading info - * + * * Edges are sorted by their radius, so that we can do a depth-first walk * without employing a recursive algorithm. - * + * * In upward propagated beadings we store the distance traveled, so that we can merge these beadings with the downward propagated beadings in \ref propagateBeadingsDownward(.) - * - * \param upward_quad_mids all upward halfedges of the inner skeletal edges (not directly connected to the outline) sorted on their highest [distance_to_boundary]. Higher dist first. + * + * \param upward_quad_mids all upward halfedges of the inner skeletal edges (not directly connected to the outline) sorted on their highest [distance_to_boundary]. Higher dist + * first. */ void propagateBeadingsUpward(std::vector& upward_quad_mids, ptr_vector_t& node_beadings); /*! * propagate beading info from higher R nodes to lower R nodes - * + * * merge with upward propagated beadings if they are encountered - * + * * don't transfer to nodes which lie on the outline polygon - * + * * edges are sorted so that we can do a depth-first walk without employing a recursive algorithm - * - * \param upward_quad_mids all upward halfedges of the inner skeletal edges (not directly connected to the outline) sorted on their highest [distance_to_boundary]. Higher dist first. + * + * \param upward_quad_mids all upward halfedges of the inner skeletal edges (not directly connected to the outline) sorted on their highest [distance_to_boundary]. Higher dist + * first. */ void propagateBeadingsDownward(std::vector& upward_quad_mids, ptr_vector_t& node_beadings); @@ -580,7 +612,7 @@ class SkeletalTrapezoidation /*! * Add a new toolpath segment, defined between two extrusion-juntions. - * + * * \param from The junction from which to add a segment. * \param to The junction to which to add a segment. * \param is_odd Whether this segment is an odd gap filler along the middle of the skeleton. diff --git a/include/SkeletalTrapezoidationEdge.h b/include/SkeletalTrapezoidationEdge.h index aa897d830f..a39bee637c 100644 --- a/include/SkeletalTrapezoidationEdge.h +++ b/include/SkeletalTrapezoidationEdge.h @@ -4,19 +4,24 @@ #ifndef SKELETAL_TRAPEZOIDATION_EDGE_H #define SKELETAL_TRAPEZOIDATION_EDGE_H -#include // smart pointers +#include "utils/ExtrusionJunction.h" + #include +#include // smart pointers #include -#include "utils/ExtrusionJunction.h" - namespace cura { class SkeletalTrapezoidationEdge { private: - enum class Central : int { UNKNOWN = -1, NO = 0, YES = 1}; + enum class Central : int + { + UNKNOWN = -1, + NO = 0, + YES = 1 + }; public: /*! @@ -28,9 +33,11 @@ class SkeletalTrapezoidationEdge int lower_bead_count; coord_t feature_radius; // The feature radius at which this transition is placed TransitionMiddle(coord_t pos, int lower_bead_count, coord_t feature_radius) - : pos(pos), lower_bead_count(lower_bead_count) + : pos(pos) + , lower_bead_count(lower_bead_count) , feature_radius(feature_radius) - {} + { + } }; /*! @@ -42,8 +49,11 @@ class SkeletalTrapezoidationEdge int lower_bead_count; bool is_lower_end; // Whether this is the ed of the transition with lower bead count TransitionEnd(coord_t pos, int lower_bead_count, bool is_lower_end) - : pos(pos), lower_bead_count(lower_bead_count), is_lower_end(is_lower_end) - {} + : pos(pos) + , lower_bead_count(lower_bead_count) + , is_lower_end(is_lower_end) + { + } }; enum class EdgeType : int @@ -55,12 +65,14 @@ class SkeletalTrapezoidationEdge EdgeType type; SkeletalTrapezoidationEdge() - : SkeletalTrapezoidationEdge(EdgeType::NORMAL) - {} + : SkeletalTrapezoidationEdge(EdgeType::NORMAL) + { + } SkeletalTrapezoidationEdge(const EdgeType& type) - : type(type) - , is_central(Central::UNKNOWN) - {} + : type(type) + , is_central(Central::UNKNOWN) + { + } bool isCentral() const { diff --git a/include/SkeletalTrapezoidationGraph.h b/include/SkeletalTrapezoidationGraph.h index 4a3f9bc594..76fdecb93a 100644 --- a/include/SkeletalTrapezoidationGraph.h +++ b/include/SkeletalTrapezoidationGraph.h @@ -4,12 +4,12 @@ #ifndef SKELETAL_TRAPEZOIDATION_GRAPH_H #define SKELETAL_TRAPEZOIDATION_GRAPH_H -#include - #include "SkeletalTrapezoidationEdge.h" #include "SkeletalTrapezoidationJoint.h" #include "utils/HalfEdgeGraph.h" +#include + namespace cura { @@ -19,28 +19,29 @@ class STHalfEdge : public HalfEdge distToGoUp() const; STHalfEdge* getNextUnconnected(); @@ -50,6 +51,7 @@ class STHalfEdgeNode : public HalfEdgeNode +class SkeletalTrapezoidationGraph : public HalfEdgeGraph { using edge_t = STHalfEdge; using node_t = STHalfEdgeNode; -public: +public: /*! * If an edge is too small, collapse it and its twin and fix the surrounding edges to ensure a consistent graph. - * + * * Don't collapse support edges, unless we can collapse the whole quad. - * + * * o-, * | "-o * | | > Don't collapse this edge only. @@ -87,7 +89,7 @@ class SkeletalTrapezoidationGraph: public HalfEdgeGraph getSource(const edge_t& edge); }; -} -#endif +} // namespace cura +#endif diff --git a/include/SkirtBrim.h b/include/SkirtBrim.h index aefbd5bdd6..e7deb028a6 100644 --- a/include/SkirtBrim.h +++ b/include/SkirtBrim.h @@ -1,17 +1,17 @@ -//Copyright (c) 2023 UltiMaker -//CuraEngine is released under the terms of the AGPLv3 or higher. +// Copyright (c) 2023 UltiMaker +// CuraEngine is released under the terms of the AGPLv3 or higher. #ifndef SKIRT_BRIM_H #define SKIRT_BRIM_H -#include "utils/Coord_t.h" #include "ExtruderTrain.h" #include "settings/EnumSettings.h" #include "sliceDataStorage.h" +#include "utils/Coord_t.h" #include -namespace cura +namespace cura { class Polygons; @@ -27,26 +27,25 @@ class SkirtBrim */ struct Offset { - Offset - ( + Offset( const std::variant& reference_outline_or_index, const bool external_only, const coord_t offset_value, const coord_t total_offset, const size_t inset_idx, const int extruder_nr, - const bool is_last - ) : - reference_outline_or_index(reference_outline_or_index), - external_only(external_only), - offset_value(offset_value), - total_offset(total_offset), - inset_idx(inset_idx), - extruder_nr(extruder_nr), - is_last(is_last) - {} - - std::variant reference_outline_or_index; + const bool is_last) + : reference_outline_or_index(reference_outline_or_index) + , external_only(external_only) + , offset_value(offset_value) + , total_offset(total_offset) + , inset_idx(inset_idx) + , extruder_nr(extruder_nr) + , is_last(is_last) + { + } + + std::variant reference_outline_or_index; bool external_only; //!< Wether to only offset outward from the reference polygons coord_t offset_value; //!< Distance by which to offset from the reference coord_t total_offset; //!< Total distance from the model @@ -58,15 +57,12 @@ class SkirtBrim /*! * Defines an order on offsets (potentially from different extruders) based on how far the offset is from the original outline. */ - static inline const auto OffsetSorter - { - [](const Offset& a, const Offset& b) - { - // Use extruder_nr in case both extruders have the same offset settings. - return a.total_offset != b.total_offset ? a.total_offset < b.total_offset : a.extruder_nr < b.extruder_nr; - } - }; - + static inline const auto OffsetSorter{ [](const Offset& a, const Offset& b) + { + // Use extruder_nr in case both extruders have the same offset settings. + return a.total_offset != b.total_offset ? a.total_offset < b.total_offset : a.extruder_nr < b.extruder_nr; + } }; + SliceDataStorage& storage; //!< Where to retrieve settings and store brim lines. const EPlatformAdhesion adhesion_type; //!< Whether we are generating brim, skirt, or raft const bool has_ooze_shield; //!< Whether the meshgroup has an ooze shield @@ -85,17 +81,17 @@ class SkirtBrim public: /*! * Precomputes some values used in several functions when calling \ref generate - * + * * \param storage Storage containing the parts at the first layer. */ SkirtBrim(SliceDataStorage& storage); /*! * Generate skirt or brim (depending on parameters). - * + * * When \p distance > 0 and \p count == 1 a skirt is generated, which has * slightly different configuration. Otherwise, a brim is generated. - * + * * \param storage Storage containing the parts at the first layer. * \param first_layer_outline The outline to generate skirt or brim around. * \param distance The distance of the first outset from the parts at the first @@ -108,7 +104,7 @@ class SkirtBrim private: /*! * Plan the offsets which we will be going to perform and put them in the right order. - * + * * In order for brims of different materials to grow toward the middle, * we need to perform the offsets alternatingly. * We therefore first create all planned Offset objects, @@ -129,7 +125,7 @@ class SkirtBrim /*! * Generate the primary skirt/brim of the one skirt_brim_extruder or of all extruders simultaneously. - * + * * \param[in,out] all_brim_offsets The offsets to perform. Adjusted when the minimal length constraint isn't met yet. * \param[in,out] covered_area The area of the first layer covered by model or generated brim lines. * \param[in,out] allowed_areas_per_extruder The difference between the machine bed area (offsetted by the nozzle offset) and the covered_area. @@ -139,9 +135,9 @@ class SkirtBrim /*! * Generate the brim inside the ooze shield and draft shield - * + * * \warning Adjusts brim_covered_area - * + * * \param storage Storage containing the parts at the first layer. * \param[in,out] brim_covered_area The area that was covered with brim before (in) and after (out) adding the shield brims * \param[in,out] allowed_areas_per_extruder The difference between the machine areas and the \p covered_area @@ -163,10 +159,10 @@ class SkirtBrim /*! * The disallowed area around the internal holes of parts with other parts inside which would get an external brim. - * + * * In order to prevent the external_only brim of a part inside another part to overlap with the internal holes of the outer part, * we generate a disallowed area around those internal hole polygons. - * + * * \param outline The full layer outlines * \param extruder_nr The extruder for which to compute disallowed areas * \return The disallowed areas @@ -175,9 +171,9 @@ class SkirtBrim /*! * Generate a brim line with offset parameters given by \p offset from the \p starting_outlines and store it in the \ref storage. - * + * * \warning Has side effects on \p covered_area, \p allowed_areas_per_extruder and \p total_length - * + * * \param offset The parameters with which to perform the offset * \param[in,out] covered_area The total area covered by the brims (and models) on the first layer. * \param[in,out] allowed_areas_per_extruder The difference between the machine areas and the \p covered_area @@ -188,11 +184,11 @@ class SkirtBrim /*! * Generate a skirt of extruders which don't yet comply with the minimum length requirement. - * + * * This skirt goes directly adjacent to all primary brims. - * + * * The skirt is stored in storage.skirt_brim. - * + * * \param[in,out] covered_area The total area covered by the brims (and models) on the first layer. * \param[in,out] allowed_areas_per_extruder The difference between the machine areas and the \p covered_area * \param[in,out] total_length The total length of the brim lines for each extruder. @@ -205,6 +201,6 @@ class SkirtBrim */ void generateSupportBrim(); }; -}//namespace cura +} // namespace cura -#endif //SKIRT_BRIM_H +#endif // SKIRT_BRIM_H diff --git a/include/SupportInfillPart.h b/include/SupportInfillPart.h index 2a1849ab55..b22fdaef5a 100644 --- a/include/SupportInfillPart.h +++ b/include/SupportInfillPart.h @@ -4,12 +4,12 @@ #ifndef SUPPORT_INFILL_PART_H #define SUPPORT_INFILL_PART_H -#include - #include "utils/AABB.h" #include "utils/ExtrusionLine.h" #include "utils/polygon.h" +#include + namespace cura { @@ -25,17 +25,17 @@ namespace cura class SupportInfillPart { public: - PolygonsPart outline; //!< The outline of the support infill area - AABB outline_boundary_box; //!< The boundary box for the infill area - coord_t support_line_width; //!< The support line width - int inset_count_to_generate; //!< The number of insets need to be generated from the outline. This is not the actual insets that will be generated. - std::vector> infill_area_per_combine_per_density; //!< a list of separated sub-areas which requires different infill densities and combined thicknesses - // for infill_areas[x][n], x means the density level and n means the thickness + PolygonsPart outline; //!< The outline of the support infill area + AABB outline_boundary_box; //!< The boundary box for the infill area + coord_t support_line_width; //!< The support line width + int inset_count_to_generate; //!< The number of insets need to be generated from the outline. This is not the actual insets that will be generated. + std::vector> infill_area_per_combine_per_density; //!< a list of separated sub-areas which requires different infill densities and combined thicknesses + // for infill_areas[x][n], x means the density level and n means the thickness std::vector wall_toolpaths; //!< Any walls go here, not in the areas, where they could be combined vertically (don't combine walls). Binned by inset_idx. coord_t custom_line_distance; - SupportInfillPart(const PolygonsPart& outline, coord_t support_line_width, int inset_count_to_generate = 0, coord_t custom_line_distance = 0 ); + SupportInfillPart(const PolygonsPart& outline, coord_t support_line_width, int inset_count_to_generate = 0, coord_t custom_line_distance = 0); const Polygons& getInfillArea() const; }; diff --git a/include/TreeModelVolumes.h b/include/TreeModelVolumes.h index 4454dc3b6a..f8a45c993c 100644 --- a/include/TreeModelVolumes.h +++ b/include/TreeModelVolumes.h @@ -4,11 +4,6 @@ #ifndef TREEMODELVOLUMES_H #define TREEMODELVOLUMES_H -#include -#include -#include -#include - #include "TreeSupportSettings.h" #include "settings/EnumSettings.h" //To store whether X/Y or Z distance gets priority. #include "settings/types/LayerIndex.h" //Part of the RadiusLayerPair. @@ -16,6 +11,11 @@ #include "utils/Simplify.h" #include "utils/polygon.h" //For polygon parameters. +#include +#include +#include +#include + namespace cura { constexpr coord_t EPSILON = 5; @@ -33,8 +33,7 @@ class TreeModelVolumes { public: TreeModelVolumes() = default; - TreeModelVolumes - ( + TreeModelVolumes( const SliceDataStorage& storage, coord_t max_move, coord_t max_move_slow, @@ -42,8 +41,7 @@ class TreeModelVolumes size_t current_mesh_idx, double progress_multiplier, double progress_offset, - const std::vector& additional_excluded_areas = std::vector() - ); + const std::vector& additional_excluded_areas = std::vector()); TreeModelVolumes(TreeModelVolumes&&) = default; TreeModelVolumes& operator=(TreeModelVolumes&&) = default; @@ -123,11 +121,9 @@ class TreeModelVolumes const Polygons& getPlaceableAreas(coord_t radius, LayerIndex layer_idx); /*! - * \brief Provides the area that represents the walls, as in the printed area, of the model. This is an abstract representation not equal with the outline. See calculateWallRestrictions for better description. - * \param radius The radius of the node of interest. - * \param layer_idx The layer of interest. - * \param min_xy_dist is the minimum xy distance used. - * \return Polygons object + * \brief Provides the area that represents the walls, as in the printed area, of the model. This is an abstract representation not equal with the outline. See + * calculateWallRestrictions for better description. \param radius The radius of the node of interest. \param layer_idx The layer of interest. \param min_xy_dist is the minimum + * xy distance used. \return Polygons object */ const Polygons& getWallRestriction(coord_t radius, LayerIndex layer_idx, bool min_xy_dist); @@ -289,7 +285,8 @@ class TreeModelVolumes void calculatePlaceables(const std::deque& keys); /*! - * \brief Creates the areas that have to be avoided by the tree's branches to prevent collision with the model without being able to place a branch with given radius on a single layer. + * \brief Creates the areas that have to be avoided by the tree's branches to prevent collision with the model without being able to place a branch with given radius on a + * single layer. * * The result is a 2D area that would cause nodes of radius \p radius to * collide with the model in a not wanted way. Result is saved in the cache. @@ -299,7 +296,8 @@ class TreeModelVolumes void calculateAvoidanceToModel(const std::deque& keys); /*! - * \brief Creates the areas that have to be avoided by the tree's branches to prevent collision with the model without being able to place a branch with given radius on a single layer. + * \brief Creates the areas that have to be avoided by the tree's branches to prevent collision with the model without being able to place a branch with given radius on a + * single layer. * * The result is a 2D area that would cause nodes of radius \p radius to * collide with the model in a not wanted way. Result is saved in the cache. @@ -311,9 +309,11 @@ class TreeModelVolumes } /*! - * \brief Creates the areas that can not be passed when expanding an area downwards. As such these areas are an somewhat abstract representation of a wall (as in a printed object). + * \brief Creates the areas that can not be passed when expanding an area downwards. As such these areas are an somewhat abstract representation of a wall (as in a printed + * object). * - * These areas are at least xy_min_dist wide. When calculating it is always assumed that every wall is printed on top of another (as in has an overlap with the wall a layer below). Result is saved in the corresponding cache. + * These areas are at least xy_min_dist wide. When calculating it is always assumed that every wall is printed on top of another (as in has an overlap with the wall a layer + * below). Result is saved in the corresponding cache. * * \param keys RadiusLayerPairs of all requested areas. Every radius will be calculated up to the provided layer. * @@ -322,9 +322,9 @@ class TreeModelVolumes void calculateWallRestrictions(const std::deque& keys); /*! - * \brief Creates the areas that can not be passed when expanding an area downwards. As such these areas are an somewhat abstract representation of a wall (as in a printed object). - * These areas are at least xy_min_dist wide. When calculating it is always assumed that every wall is printed on top of another (as in has an overlap with the wall a layer below). Result is saved in the corresponding cache. - * \param key RadiusLayerPair of the requested area. It well be will be calculated up to the provided layer. + * \brief Creates the areas that can not be passed when expanding an area downwards. As such these areas are an somewhat abstract representation of a wall (as in a printed + * object). These areas are at least xy_min_dist wide. When calculating it is always assumed that every wall is printed on top of another (as in has an overlap with the wall a + * layer below). Result is saved in the corresponding cache. \param key RadiusLayerPair of the requested area. It well be will be calculated up to the provided layer. */ void calculateWallRestrictions(RadiusLayerPair key) { @@ -336,7 +336,7 @@ class TreeModelVolumes * \param key RadiusLayerPair of the requested areas. The radius will be calculated up to the provided layer. * \return A wrapped optional reference of the requested area (if it was found, an empty optional if nothing was found) */ - template + template const std::optional> getArea(const std::unordered_map& cache, const KEY key) const; bool checkSettingsEquality(const Settings& me, const Settings& other) const; @@ -499,7 +499,8 @@ class TreeModelVolumes std::unique_ptr critical_placeable_areas_cache_ = std::make_unique(); /*! - * \brief Caches to avoid holes smaller than the radius until which the radius is always increased, as they are free of holes. Also called safe avoidances, as they are safe regarding not running into holes. + * \brief Caches to avoid holes smaller than the radius until which the radius is always increased, as they are free of holes. Also called safe avoidances, as they are safe + * regarding not running into holes. */ mutable std::unordered_map avoidance_cache_hole_; std::unique_ptr critical_avoidance_cache_holefree_ = std::make_unique(); @@ -513,7 +514,8 @@ class TreeModelVolumes mutable std::unordered_map wall_restrictions_cache_; std::unique_ptr critical_wall_restrictions_cache_ = std::make_unique(); - // A different cache for min_xy_dist as the maximal safe distance an influence area can be increased(guaranteed overlap of two walls in consecutive layer) is much smaller when min_xy_dist is used. This causes the area of the wall restriction to be thinner and as such just using the min_xy_dist wall restriction would be slower. + // A different cache for min_xy_dist as the maximal safe distance an influence area can be increased(guaranteed overlap of two walls in consecutive layer) is much smaller when + // min_xy_dist is used. This causes the area of the wall restriction to be thinner and as such just using the min_xy_dist wall restriction would be slower. mutable std::unordered_map wall_restrictions_cache_min_; std::unique_ptr critical_wall_restrictions_cache_min_ = std::make_unique(); @@ -522,6 +524,6 @@ class TreeModelVolumes Simplify simplifier = Simplify(0, 0, 0); // a simplifier to simplify polygons. Will be properly initialised in the constructor. }; -} +} // namespace cura -#endif //TREEMODELVOLUMES_H +#endif // TREEMODELVOLUMES_H diff --git a/include/TreeSupport.h b/include/TreeSupport.h index 32f67cd074..9f99c62010 100644 --- a/include/TreeSupport.h +++ b/include/TreeSupport.h @@ -1,5 +1,5 @@ -//Copyright (c) 2021 Ultimaker B.V. -//CuraEngine is released under the terms of the AGPLv3 or higher. +// Copyright (c) 2021 Ultimaker B.V. +// CuraEngine is released under the terms of the AGPLv3 or higher. #ifndef TREESUPPORT_H #define TREESUPPORT_H @@ -69,8 +69,6 @@ class TreeSupport private: - - /*! * \brief Precalculates all avoidances, that could be required. * @@ -101,17 +99,14 @@ class TreeSupport * \param reduced_aabb[in,out] The already processed elements. * \param input_aabb[in] Not yet processed elements * \param to_bp_areas[in] The Elements of the current Layer that will reach the buildplate. Value is the influence area where the center of a circle of support may be placed. - * \param to_model_areas[in] The Elements of the current Layer that do not have to reach the buildplate. Also contains main as every element that can reach the buildplate is not forced to. - * Value is the influence area where the center of a circle of support may be placed. - * \param influence_areas[in] The influence areas without avoidance removed. + * \param to_model_areas[in] The Elements of the current Layer that do not have to reach the buildplate. Also contains main as every element that can reach the buildplate is + * not forced to. Value is the influence area where the center of a circle of support may be placed. \param influence_areas[in] The influence areas without avoidance removed. * \param insert_bp_areas[out] Elements to be inserted into the main dictionary after the Helper terminates. * \param insert_model_areas[out] Elements to be inserted into the secondary dictionary after the Helper terminates. - * \param insert_influence[out] Elements to be inserted into the dictionary containing the largest possibly valid influence area (ignoring if the area may not be there because of avoidance) - * \param erase[out] Elements that should be deleted from the above dictionaries. - * \param layer_idx[in] The Index of the current Layer. + * \param insert_influence[out] Elements to be inserted into the dictionary containing the largest possibly valid influence area (ignoring if the area may not be there because + * of avoidance) \param erase[out] Elements that should be deleted from the above dictionaries. \param layer_idx[in] The Index of the current Layer. */ - void mergeHelper - ( + void mergeHelper( std::map& reduced_aabb, std::map& input_aabb, const PropertyAreasUnordered& to_bp_areas, @@ -121,8 +116,7 @@ class TreeSupport PropertyAreasUnordered& insert_model_areas, PropertyAreasUnordered& insert_influence, std::vector& erase, - const LayerIndex layer_idx - ); + const LayerIndex layer_idx); /*! * \brief Merges Influence Areas if possible. @@ -132,28 +126,23 @@ class TreeSupport * * \param to_bp_areas[in] The Elements of the current Layer that will reach the buildplate. * Value is the influence area where the center of a circle of support may be placed. - * \param to_model_areas[in] The Elements of the current Layer that do not have to reach the buildplate. Also contains main as every element that can reach the buildplate is not forced to. - * Value is the influence area where the center of a circle of support may be placed. - * \param influence_areas[in] The Elements of the current Layer without avoidances removed. This is the largest possible influence area for this layer. - * Value is the influence area where the center of a circle of support may be placed. - * \param layer_idx[in] The current layer. + * \param to_model_areas[in] The Elements of the current Layer that do not have to reach the buildplate. Also contains main as every element that can reach the buildplate is + * not forced to. Value is the influence area where the center of a circle of support may be placed. \param influence_areas[in] The Elements of the current Layer without + * avoidances removed. This is the largest possible influence area for this layer. Value is the influence area where the center of a circle of support may be placed. \param + * layer_idx[in] The current layer. */ - void mergeInfluenceAreas - ( - PropertyAreasUnordered& to_bp_areas, - PropertyAreas& to_model_areas, - PropertyAreas& influence_areas, - LayerIndex layer_idx - ); + void mergeInfluenceAreas(PropertyAreasUnordered& to_bp_areas, PropertyAreas& to_model_areas, PropertyAreas& influence_areas, LayerIndex layer_idx); /*! * \brief Checks if an influence area contains a valid subsection and returns the corresponding metadata and the new Influence area. * * Calculates an influence areas of the layer below, based on the influence area of one element on the current layer. - * Increases every influence area by maximum_move_distance_slow. If this is not enough, as in we would change our gracious or to_buildplate status the influence areas are instead increased by maximum_move_distance_slow. - * Also ensures that increasing the radius of a branch, does not cause it to change its status (like to_buildplate ). If this were the case, the radius is not increased instead. + * Increases every influence area by maximum_move_distance_slow. If this is not enough, as in we would change our gracious or to_buildplate status the influence areas are + * instead increased by maximum_move_distance_slow. Also ensures that increasing the radius of a branch, does not cause it to change its status (like to_buildplate ). If this + * were the case, the radius is not increased instead. * - * Warning: The used format inside this is different as the SupportElement does not have a valid area member. Instead this area is saved as value of the dictionary. This was done to avoid not needed heap allocations. + * Warning: The used format inside this is different as the SupportElement does not have a valid area member. Instead this area is saved as value of the dictionary. This was + * done to avoid not needed heap allocations. * * \param settings[in] Which settings have to be used to check validity. * \param layer_idx[in] Number of the current layer. @@ -161,13 +150,12 @@ class TreeSupport * \param relevant_offset[in] The maximal possible influence area. No guarantee regarding validity with current layer collision required, as it is ensured in-function! * \param to_bp_data[out] The part of the Influence area that can reach the buildplate. * \param to_model_data[out] The part of the Influence area that do not have to reach the buildplate. This has overlap with new_layer_data. - * \param increased[out] Area than can reach all further up support points. No assurance is made that the buildplate or the model can be reached in accordance to the user-supplied settings. - * \param overspeed[in] How much should the already offset area be offset again. Usually this is 0. - * \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. - * \return A valid support element for the next layer regarding the calculated influence areas. Empty if no influence are can be created using the supplied influence area and settings. + * \param increased[out] Area than can reach all further up support points. No assurance is made that the buildplate or the model can be reached in accordance to the + * user-supplied settings. \param overspeed[in] How much should the already offset area be offset again. Usually this is 0. \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. \return A valid support element for the next + * layer regarding the calculated influence areas. Empty if no influence are can be created using the supplied influence area and settings. */ - std::optional increaseSingleArea - ( + std::optional increaseSingleArea( AreaIncreaseSettings settings, LayerIndex layer_idx, TreeSupportElement* parent, @@ -176,37 +164,35 @@ class TreeSupport Polygons& to_model_data, Polygons& increased, const coord_t overspeed, - const bool mergelayer - ); + const bool mergelayer); /*! * \brief Increases influence areas as far as required. * * Calculates influence areas of the layer below, based on the influence areas of the current layer. - * Increases every influence area by maximum_move_distance_slow. If this is not enough, as in it would change the gracious or to_buildplate status, the influence areas are instead increased by maximum_move_distance. - * Also ensures that increasing the radius of a branch, does not cause it to change its status (like to_buildplate ). If this were the case, the radius is not increased instead. + * Increases every influence area by maximum_move_distance_slow. If this is not enough, as in it would change the gracious or to_buildplate status, the influence areas are + * instead increased by maximum_move_distance. Also ensures that increasing the radius of a branch, does not cause it to change its status (like to_buildplate ). If this were + * the case, the radius is not increased instead. * - * Warning: The used format inside this is different as the SupportElement does not have a valid area member. Instead this area is saved as value of the dictionary. This was done to avoid not needed heap allocations. + * Warning: The used format inside this is different as the SupportElement does not have a valid area member. Instead this area is saved as value of the dictionary. This was + * done to avoid not needed heap allocations. * * \param to_bp_areas[out] Influence areas that can reach the buildplate - * \param to_model_areas[out] Influence areas that do not have to reach the buildplate. This has overlap with new_layer_data, as areas that can reach the buildplate are also considered valid areas to the model. - * This redundancy is required if a to_buildplate influence area is allowed to merge with a to model influence area. - * \param influence_areas[out] Area than can reach all further up support points. No assurance is made that the buildplate or the model can be reached in accordance to the user-supplied settings. - * \param bypass_merge_areas[out] Influence areas ready to be added to the layer below that do not need merging. - * \param last_layer[in] Influence areas of the current layer. - * \param layer_idx[in] Number of the current layer. - * \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. + * \param to_model_areas[out] Influence areas that do not have to reach the buildplate. This has overlap with new_layer_data, as areas that can reach the buildplate are also + * considered valid areas to the model. This redundancy is required if a to_buildplate influence area is allowed to merge with a to model influence area. \param + * influence_areas[out] Area than can reach all further up support points. No assurance is made that the buildplate or the model can be reached in accordance to the + * user-supplied settings. \param bypass_merge_areas[out] Influence areas ready to be added to the layer below that do not need merging. \param last_layer[in] Influence areas + * of the current layer. \param layer_idx[in] Number of the current layer. \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. */ - void increaseAreas - ( + void increaseAreas( PropertyAreasUnordered& to_bp_areas, PropertyAreas& to_model_areas, PropertyAreas& influence_areas, std::vector& bypass_merge_areas, const std::vector& last_layer, const LayerIndex layer_idx, - const bool mergelayer - ); + const bool mergelayer); /*! * \brief Propagates influence downwards, and merges overlapping ones. @@ -245,15 +231,13 @@ class TreeSupport * * \param linear_data[in] All currently existing influence areas with the layer they are on * \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. + * 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. */ - void generateBranchAreas - ( + void generateBranchAreas( std::vector>& linear_data, std::vector>& layer_tree_polygons, - const std::map& inverse_tree_order - ); + const std::map& inverse_tree_order); /*! * \brief Applies some smoothing to the outer wall, intended to smooth out sudden jumps as they can happen when a branch moves though a hole. @@ -270,13 +254,11 @@ class TreeSupport * \param dropped_down_areas[out] Areas that have to be added to support all non-graceful areas. * \param inverse_tree_order[in] A mapping that returns the child of every influence area. */ - void dropNonGraciousAreas - ( + void dropNonGraciousAreas( std::vector>& layer_tree_polygons, const std::vector>& linear_data, std::vector>>& dropped_down_areas, - const std::map& inverse_tree_order - ); + const std::map& inverse_tree_order); void filterFloatingLines(std::vector& support_layer_storage); @@ -335,7 +317,6 @@ class TreeSupport * Required for the progress bar the behave as expected when areas have to be calculated multiple times */ double progress_offset = 0; - }; diff --git a/include/TreeSupportBaseCircle.h b/include/TreeSupportBaseCircle.h index ac9410bfbd..7dea35b31b 100644 --- a/include/TreeSupportBaseCircle.h +++ b/include/TreeSupportBaseCircle.h @@ -1,4 +1,4 @@ -//CuraEngine is released under the terms of the AGPLv3 or higher. +// CuraEngine is released under the terms of the AGPLv3 or higher. #ifndef TREESUPPORTCIRCLE_H #define TREESUPPORTCIRCLE_H @@ -6,9 +6,10 @@ #include "utils/Coord_t.h" #include "utils/polygon.h" -#include #include +#include + namespace cura { diff --git a/include/TreeSupportElement.h b/include/TreeSupportElement.h index 237e22baa2..baa946d627 100644 --- a/include/TreeSupportElement.h +++ b/include/TreeSupportElement.h @@ -1,4 +1,4 @@ -//CuraEngine is released under the terms of the AGPLv3 or higher. +// CuraEngine is released under the terms of the AGPLv3 or higher. #ifndef TREESUPPORTELEMENT_H #define TREESUPPORTELEMENT_H @@ -8,8 +8,8 @@ #include "settings/types/LayerIndex.h" #include "utils/Coord_t.h" #include "utils/polygon.h" -#include +#include #include #include @@ -18,31 +18,23 @@ namespace cura struct AreaIncreaseSettings { - AreaIncreaseSettings() : - type(AvoidanceType::FAST), - increase_speed(0), - increase_radius(false), - no_error(false), - use_min_distance(false), - move(false) + AreaIncreaseSettings() + : type(AvoidanceType::FAST) + , increase_speed(0) + , increase_radius(false) + , no_error(false) + , use_min_distance(false) + , move(false) { } - AreaIncreaseSettings - ( - AvoidanceType type, - coord_t increase_speed, - bool increase_radius, - bool simplify, - bool use_min_distance, - bool move - ) : - type(type), - increase_speed(increase_speed), - increase_radius(increase_radius), - no_error(simplify), - use_min_distance(use_min_distance), - move(move) + AreaIncreaseSettings(AvoidanceType type, coord_t increase_speed, bool increase_radius, bool simplify, bool use_min_distance, bool move) + : type(type) + , increase_speed(increase_speed) + , increase_radius(increase_radius) + , no_error(simplify) + , use_min_distance(use_min_distance) + , move(move) { } @@ -55,20 +47,14 @@ struct AreaIncreaseSettings bool operator==(const AreaIncreaseSettings& other) const { - return - increase_radius == other.increase_radius && - increase_speed == other.increase_speed && - type == other.type && - no_error == other.no_error && - use_min_distance == other.use_min_distance && - move == other.move; + return increase_radius == other.increase_radius && increase_speed == other.increase_speed && type == other.type && no_error == other.no_error + && use_min_distance == other.use_min_distance && move == other.move; } }; struct TreeSupportElement { - TreeSupportElement - ( + TreeSupportElement( coord_t distance_to_top, size_t target_height, Point target_position, @@ -81,59 +67,58 @@ struct TreeSupportElement bool force_tips_to_roof, bool skip_ovalisation, bool influence_area_limit_active, - coord_t influence_area_limit_range - ) : - target_height(target_height), - target_position(target_position), - next_position(target_position), - next_height(target_height), - effective_radius_height(distance_to_top), - to_buildplate(to_buildplate), - distance_to_top(distance_to_top), - area(nullptr), - result_on_layer(target_position), - increased_to_model_radius(0), - to_model_gracious(to_model_gracious), - buildplate_radius_increases(0), - use_min_xy_dist(use_min_xy_dist), - supports_roof(supports_roof), - dont_move_until(dont_move_until), - can_use_safe_radius(can_use_safe_radius), - last_area_increase(AreaIncreaseSettings(AvoidanceType::FAST, 0, false, false, false, false)), - missing_roof_layers(force_tips_to_roof ? dont_move_until : 0), - skip_ovalisation(skip_ovalisation), - all_tips({ target_position }), - influence_area_limit_active(influence_area_limit_active), - influence_area_limit_range(influence_area_limit_range - ) + coord_t influence_area_limit_range) + : target_height(target_height) + , target_position(target_position) + , next_position(target_position) + , next_height(target_height) + , effective_radius_height(distance_to_top) + , to_buildplate(to_buildplate) + , distance_to_top(distance_to_top) + , area(nullptr) + , result_on_layer(target_position) + , increased_to_model_radius(0) + , to_model_gracious(to_model_gracious) + , buildplate_radius_increases(0) + , use_min_xy_dist(use_min_xy_dist) + , supports_roof(supports_roof) + , dont_move_until(dont_move_until) + , can_use_safe_radius(can_use_safe_radius) + , last_area_increase(AreaIncreaseSettings(AvoidanceType::FAST, 0, false, false, false, false)) + , missing_roof_layers(force_tips_to_roof ? dont_move_until : 0) + , skip_ovalisation(skip_ovalisation) + , all_tips({ target_position }) + , influence_area_limit_active(influence_area_limit_active) + , influence_area_limit_range(influence_area_limit_range) { RecreateInfluenceLimitArea(); } - TreeSupportElement(const TreeSupportElement& elem, Polygons* newArea = nullptr) : // copy constructor with possibility to set a new area - target_height(elem.target_height), - target_position(elem.target_position), - next_position(elem.next_position), - next_height(elem.next_height), - effective_radius_height(elem.effective_radius_height), - to_buildplate(elem.to_buildplate), - distance_to_top(elem.distance_to_top), - area(newArea != nullptr ? newArea : elem.area), - result_on_layer(elem.result_on_layer), - increased_to_model_radius(elem.increased_to_model_radius), - to_model_gracious(elem.to_model_gracious), - buildplate_radius_increases(elem.buildplate_radius_increases), - use_min_xy_dist(elem.use_min_xy_dist), - supports_roof(elem.supports_roof), - dont_move_until(elem.dont_move_until), - can_use_safe_radius(elem.can_use_safe_radius), - last_area_increase(elem.last_area_increase), - missing_roof_layers(elem.missing_roof_layers), - skip_ovalisation(elem.skip_ovalisation), - all_tips(elem.all_tips), - influence_area_limit_area(elem.influence_area_limit_area), - influence_area_limit_range(elem.influence_area_limit_range), - influence_area_limit_active(elem.influence_area_limit_active) + TreeSupportElement(const TreeSupportElement& elem, Polygons* newArea = nullptr) + : // copy constructor with possibility to set a new area + target_height(elem.target_height) + , target_position(elem.target_position) + , next_position(elem.next_position) + , next_height(elem.next_height) + , effective_radius_height(elem.effective_radius_height) + , to_buildplate(elem.to_buildplate) + , distance_to_top(elem.distance_to_top) + , area(newArea != nullptr ? newArea : elem.area) + , result_on_layer(elem.result_on_layer) + , increased_to_model_radius(elem.increased_to_model_radius) + , to_model_gracious(elem.to_model_gracious) + , buildplate_radius_increases(elem.buildplate_radius_increases) + , use_min_xy_dist(elem.use_min_xy_dist) + , supports_roof(elem.supports_roof) + , dont_move_until(elem.dont_move_until) + , can_use_safe_radius(elem.can_use_safe_radius) + , last_area_increase(elem.last_area_increase) + , missing_roof_layers(elem.missing_roof_layers) + , skip_ovalisation(elem.skip_ovalisation) + , all_tips(elem.all_tips) + , influence_area_limit_area(elem.influence_area_limit_area) + , influence_area_limit_range(elem.influence_area_limit_range) + , influence_area_limit_active(elem.influence_area_limit_active) { parents.insert(parents.begin(), elem.parents.begin(), elem.parents.end()); } @@ -141,37 +126,37 @@ struct TreeSupportElement /*! * \brief Create a new Element for one layer below the element of the pointer supplied. */ - TreeSupportElement(TreeSupportElement* element_above) : - target_height(element_above->target_height), - target_position(element_above->target_position), - next_position(element_above->next_position), - next_height(element_above->next_height), - effective_radius_height(element_above->effective_radius_height), - to_buildplate(element_above->to_buildplate), - distance_to_top(element_above->distance_to_top + 1), - area(element_above->area), - result_on_layer(Point(-1, -1)), // set to invalid as we are a new node on a new layer - increased_to_model_radius(element_above->increased_to_model_radius), - to_model_gracious(element_above->to_model_gracious), - buildplate_radius_increases(element_above->buildplate_radius_increases), - use_min_xy_dist(element_above->use_min_xy_dist), - supports_roof(element_above->supports_roof), - dont_move_until(element_above->dont_move_until), - can_use_safe_radius(element_above->can_use_safe_radius), - last_area_increase(element_above->last_area_increase), - missing_roof_layers(element_above->missing_roof_layers), - skip_ovalisation(false), - all_tips(element_above->all_tips), - influence_area_limit_area(element_above->influence_area_limit_area), - influence_area_limit_range(element_above->influence_area_limit_range), - influence_area_limit_active(element_above->influence_area_limit_active) + TreeSupportElement(TreeSupportElement* element_above) + : target_height(element_above->target_height) + , target_position(element_above->target_position) + , next_position(element_above->next_position) + , next_height(element_above->next_height) + , effective_radius_height(element_above->effective_radius_height) + , to_buildplate(element_above->to_buildplate) + , distance_to_top(element_above->distance_to_top + 1) + , area(element_above->area) + , result_on_layer(Point(-1, -1)) + , // set to invalid as we are a new node on a new layer + increased_to_model_radius(element_above->increased_to_model_radius) + , to_model_gracious(element_above->to_model_gracious) + , buildplate_radius_increases(element_above->buildplate_radius_increases) + , use_min_xy_dist(element_above->use_min_xy_dist) + , supports_roof(element_above->supports_roof) + , dont_move_until(element_above->dont_move_until) + , can_use_safe_radius(element_above->can_use_safe_radius) + , last_area_increase(element_above->last_area_increase) + , missing_roof_layers(element_above->missing_roof_layers) + , skip_ovalisation(false) + , all_tips(element_above->all_tips) + , influence_area_limit_area(element_above->influence_area_limit_area) + , influence_area_limit_range(element_above->influence_area_limit_range) + , influence_area_limit_active(element_above->influence_area_limit_active) { parents = { element_above }; } // ONLY to be called in merge as it assumes a few assurances made by it. - TreeSupportElement - ( + TreeSupportElement( const TreeSupportElement& first, const TreeSupportElement& second, size_t next_height, @@ -180,18 +165,17 @@ struct TreeSupportElement const std::function& getRadius, double diameter_scale_bp_radius, coord_t branch_radius, - double diameter_angle_scale_factor - ) : - next_position(next_position), - next_height(next_height), - area(nullptr), - increased_to_model_radius(increased_to_model_radius), - use_min_xy_dist(first.use_min_xy_dist || second.use_min_xy_dist), - supports_roof(first.supports_roof || second.supports_roof), - dont_move_until(std::max(first.dont_move_until, second.dont_move_until)), - can_use_safe_radius(first.can_use_safe_radius || second.can_use_safe_radius), - missing_roof_layers(std::min(first.missing_roof_layers, second.missing_roof_layers)), - skip_ovalisation(false) + double diameter_angle_scale_factor) + : next_position(next_position) + , next_height(next_height) + , area(nullptr) + , increased_to_model_radius(increased_to_model_radius) + , use_min_xy_dist(first.use_min_xy_dist || second.use_min_xy_dist) + , supports_roof(first.supports_roof || second.supports_roof) + , dont_move_until(std::max(first.dont_move_until, second.dont_move_until)) + , can_use_safe_radius(first.can_use_safe_radius || second.can_use_safe_radius) + , missing_roof_layers(std::min(first.missing_roof_layers, second.missing_roof_layers)) + , skip_ovalisation(false) { if (first.target_height > second.target_height) { @@ -215,38 +199,29 @@ struct TreeSupportElement buildplate_radius_increases = 0; if (diameter_scale_bp_radius > 0) { - const coord_t foot_increase_radius = - std::abs - ( - std::max - ( - getRadius(second.effective_radius_height, second.buildplate_radius_increases), - getRadius(first.effective_radius_height, first.buildplate_radius_increases)) - getRadius(effective_radius_height, buildplate_radius_increases - ) - ); + const coord_t foot_increase_radius = std::abs( + std::max(getRadius(second.effective_radius_height, second.buildplate_radius_increases), getRadius(first.effective_radius_height, first.buildplate_radius_increases)) + - getRadius(effective_radius_height, buildplate_radius_increases)); // 'buildplate_radius_increases' has to be recalculated, as when a smaller tree with a larger buildplate_radius_increases merge with a larger branch, // the buildplate_radius_increases may have to be lower as otherwise the radius suddenly increases. This results often in a non integer value. buildplate_radius_increases = foot_increase_radius / (branch_radius * (diameter_scale_bp_radius - diameter_angle_scale_factor)); } // set last settings to the best out of both parents. If this is wrong, it will only cause a small performance penalty instead of weird behavior. - last_area_increase = - AreaIncreaseSettings - ( - std::min(first.last_area_increase.type, second.last_area_increase.type), - std::min(first.last_area_increase.increase_speed, second.last_area_increase.increase_speed), - first.last_area_increase.increase_radius || second.last_area_increase.increase_radius, - first.last_area_increase.no_error || second.last_area_increase.no_error, - first.last_area_increase.use_min_distance && second.last_area_increase.use_min_distance, - first.last_area_increase.move || second.last_area_increase.move - ); + last_area_increase = AreaIncreaseSettings( + std::min(first.last_area_increase.type, second.last_area_increase.type), + std::min(first.last_area_increase.increase_speed, second.last_area_increase.increase_speed), + first.last_area_increase.increase_radius || second.last_area_increase.increase_radius, + first.last_area_increase.no_error || second.last_area_increase.no_error, + first.last_area_increase.use_min_distance && second.last_area_increase.use_min_distance, + first.last_area_increase.move || second.last_area_increase.move); all_tips = first.all_tips; all_tips.insert(all_tips.end(), second.all_tips.begin(), second.all_tips.end()); influence_area_limit_range = std::max(first.influence_area_limit_range, second.influence_area_limit_range); influence_area_limit_active = first.influence_area_limit_active || second.influence_area_limit_active; RecreateInfluenceLimitArea(); - if(first.to_buildplate != second.to_buildplate) + if (first.to_buildplate != second.to_buildplate) { setToBuildplateForAllParents(to_buildplate); } @@ -388,7 +363,7 @@ struct TreeSupportElement bool operator<(const TreeSupportElement& other) const // true if me < other { - return !(*this == other) && !(*this > other); + return ! (*this == other) && ! (*this > other); } bool operator>(const TreeSupportElement& other) const @@ -440,29 +415,30 @@ struct TreeSupportElement void setToBuildplateForAllParents(bool new_value) { to_buildplate = new_value; - std::vector grandparents {parents}; - while (!grandparents.empty()){ + std::vector grandparents{ parents }; + while (! grandparents.empty()) + { std::vector next_parents; - for (TreeSupportElement* grandparent:grandparents){ - next_parents.insert(next_parents.end(),grandparent->parents.begin(),grandparent->parents.end()); + for (TreeSupportElement* grandparent : grandparents) + { + next_parents.insert(next_parents.end(), grandparent->parents.begin(), grandparent->parents.end()); grandparent->to_buildplate = new_value; } grandparents = next_parents; } } - + inline bool isResultOnLayerSet() const { return result_on_layer != Point(-1, -1); } - }; } // namespace cura namespace std { -template <> +template<> struct hash { size_t operator()(const cura::TreeSupportElement& node) const diff --git a/include/TreeSupportEnums.h b/include/TreeSupportEnums.h index 4c2238f9cd..f3c959c8dd 100644 --- a/include/TreeSupportEnums.h +++ b/include/TreeSupportEnums.h @@ -1,4 +1,4 @@ -//CuraEngine is released under the terms of the AGPLv3 or higher. +// CuraEngine is released under the terms of the AGPLv3 or higher. #ifndef CURAENGINE_TREESUPPORTENUMS_H #define CURAENGINE_TREESUPPORTENUMS_H @@ -28,6 +28,6 @@ enum class AvoidanceType COLLISION }; -}//end namespace +} // namespace cura #endif // CURAENGINE_TREESUPPORTENUMS_H diff --git a/include/TreeSupportSettings.h b/include/TreeSupportSettings.h index 06a6292230..3b786cca66 100644 --- a/include/TreeSupportSettings.h +++ b/include/TreeSupportSettings.h @@ -1,4 +1,4 @@ -//CuraEngine is released under the terms of the AGPLv3 or higher. +// CuraEngine is released under the terms of the AGPLv3 or higher. #ifndef TREESUPPORTSETTINGS_H #define TREESUPPORTSETTINGS_H @@ -10,6 +10,7 @@ #include "settings/types/Angle.h" #include "utils/Coord_t.h" #include "utils/Simplify.h" + #include namespace cura @@ -22,60 +23,68 @@ struct TreeSupportSettings { TreeSupportSettings() = default; // required for the definition of the config variable in the TreeSupport class. - TreeSupportSettings(const Settings& mesh_group_settings) : - angle(mesh_group_settings.get("support_tree_angle")), - angle_slow(mesh_group_settings.get("support_tree_angle_slow")), - support_line_width(mesh_group_settings.get("support_line_width")), - layer_height(mesh_group_settings.get("layer_height")), - branch_radius(mesh_group_settings.get("support_tree_branch_diameter") / 2), - min_radius(mesh_group_settings.get("support_tree_tip_diameter") / 2), // The actual radius is 50 microns larger as the resulting branches will be increased by 50 microns to avoid rounding errors effectively increasing the xydistance - max_radius(mesh_group_settings.get("support_tree_max_diameter")/2), - maximum_move_distance((angle < TAU / 4) ? (coord_t)(tan(angle) * layer_height) : std::numeric_limits::max()), - maximum_move_distance_slow((angle_slow < TAU / 4) ? (coord_t)(tan(angle_slow) * layer_height) : std::numeric_limits::max()), - support_bottom_layers(mesh_group_settings.get("support_bottom_enable") ? round_divide(mesh_group_settings.get("support_bottom_height"), layer_height) : 0), - tip_layers(std::max((branch_radius - min_radius) / (support_line_width / 3), branch_radius / layer_height)), // Ensure lines always stack nicely even if layer height is large - diameter_angle_scale_factor(sin(mesh_group_settings.get("support_tree_branch_diameter_angle")) * layer_height / branch_radius), - max_to_model_radius_increase(mesh_group_settings.get("support_tree_max_diameter_increase_by_merges_when_support_to_model") / 2), - min_dtt_to_model(round_up_divide(mesh_group_settings.get("support_tree_min_height_to_model"), layer_height)), - increase_radius_until_radius(mesh_group_settings.get("support_tree_branch_diameter") / 2), - increase_radius_until_dtt(increase_radius_until_radius <= branch_radius ? tip_layers * (increase_radius_until_radius / branch_radius) : (increase_radius_until_radius - branch_radius) / (branch_radius * diameter_angle_scale_factor)), - support_rests_on_model(mesh_group_settings.get("support_type") == ESupportType::EVERYWHERE), - support_rest_preference((support_rests_on_model && mesh_group_settings.get("support_tree_rest_preference") == "graceful") ? RestPreference::GRACEFUL : RestPreference::BUILDPLATE), - xy_distance(mesh_group_settings.get("support_xy_distance")), - bp_radius(mesh_group_settings.get("support_tree_bp_diameter") / 2), - diameter_scale_bp_radius(std::min(sin(0.7) * layer_height / branch_radius, 1.0 / (branch_radius / (support_line_width / 2.0)))), // Either 40° or as much as possible so that 2 lines will overlap by at least 50%, whichever is smaller. - support_overrides(mesh_group_settings.get("support_xy_overrides_z")), - xy_min_distance(support_overrides == SupportDistPriority::Z_OVERRIDES_XY ? mesh_group_settings.get("support_xy_distance_overhang") : xy_distance), - z_distance_top_layers(round_up_divide(mesh_group_settings.get("support_top_distance"), layer_height)), - z_distance_bottom_layers(round_up_divide(mesh_group_settings.get("support_bottom_distance"), layer_height)), - performance_interface_skip_layers(round_up_divide(mesh_group_settings.get("support_interface_skip_height"), layer_height)), - support_infill_angles(mesh_group_settings.get>("support_infill_angles")), - support_roof_angles(mesh_group_settings.get>("support_roof_angles")), - roof_pattern(mesh_group_settings.get("support_roof_pattern")), - support_pattern(mesh_group_settings.get("support_pattern")), - support_roof_line_width(mesh_group_settings.get("support_roof_line_width")), - support_line_distance(mesh_group_settings.get("support_line_distance")), - support_bottom_offset(mesh_group_settings.get("support_bottom_offset")), - support_wall_count(mesh_group_settings.get("support_wall_count")), - support_roof_wall_count(mesh_group_settings.get("support_roof_wall_count")), - zig_zaggify_support(mesh_group_settings.get("zig_zaggify_support")), - maximum_deviation(mesh_group_settings.get("meshfix_maximum_deviation")), - maximum_resolution(mesh_group_settings.get("meshfix_maximum_resolution")), - support_roof_line_distance(mesh_group_settings.get("support_roof_line_distance")), // in the end the actual infill has to be calculated to subtract interface from support areas according to interface_preference. - skip_some_zags(mesh_group_settings.get("support_skip_some_zags")), - zag_skip_count(mesh_group_settings.get("support_zag_skip_count")), - connect_zigzags(mesh_group_settings.get("support_connect_zigzags")), - settings(mesh_group_settings), - min_feature_size(mesh_group_settings.get("min_feature_size")), - min_wall_line_width(settings.get("min_wall_line_width")), - fill_outline_gaps(settings.get("fill_outline_gaps")), - simplifier(Simplify(mesh_group_settings)) + TreeSupportSettings(const Settings& mesh_group_settings) + : angle(mesh_group_settings.get("support_tree_angle")) + , angle_slow(mesh_group_settings.get("support_tree_angle_slow")) + , support_line_width(mesh_group_settings.get("support_line_width")) + , layer_height(mesh_group_settings.get("layer_height")) + , branch_radius(mesh_group_settings.get("support_tree_branch_diameter") / 2) + , min_radius(mesh_group_settings.get("support_tree_tip_diameter") / 2) + , // The actual radius is 50 microns larger as the resulting branches will be increased by 50 microns to avoid rounding errors effectively increasing the xydistance + max_radius(mesh_group_settings.get("support_tree_max_diameter") / 2) + , maximum_move_distance((angle < TAU / 4) ? (coord_t)(tan(angle) * layer_height) : std::numeric_limits::max()) + , maximum_move_distance_slow((angle_slow < TAU / 4) ? (coord_t)(tan(angle_slow) * layer_height) : std::numeric_limits::max()) + , support_bottom_layers(mesh_group_settings.get("support_bottom_enable") ? round_divide(mesh_group_settings.get("support_bottom_height"), layer_height) : 0) + , tip_layers(std::max((branch_radius - min_radius) / (support_line_width / 3), branch_radius / layer_height)) + , // Ensure lines always stack nicely even if layer height is large + diameter_angle_scale_factor(sin(mesh_group_settings.get("support_tree_branch_diameter_angle")) * layer_height / branch_radius) + , max_to_model_radius_increase(mesh_group_settings.get("support_tree_max_diameter_increase_by_merges_when_support_to_model") / 2) + , min_dtt_to_model(round_up_divide(mesh_group_settings.get("support_tree_min_height_to_model"), layer_height)) + , increase_radius_until_radius(mesh_group_settings.get("support_tree_branch_diameter") / 2) + , increase_radius_until_dtt( + increase_radius_until_radius <= branch_radius ? tip_layers * (increase_radius_until_radius / branch_radius) + : (increase_radius_until_radius - branch_radius) / (branch_radius * diameter_angle_scale_factor)) + , support_rests_on_model(mesh_group_settings.get("support_type") == ESupportType::EVERYWHERE) + , support_rest_preference( + (support_rests_on_model && mesh_group_settings.get("support_tree_rest_preference") == "graceful") ? RestPreference::GRACEFUL + : RestPreference::BUILDPLATE) + , xy_distance(mesh_group_settings.get("support_xy_distance")) + , bp_radius(mesh_group_settings.get("support_tree_bp_diameter") / 2) + , diameter_scale_bp_radius(std::min(sin(0.7) * layer_height / branch_radius, 1.0 / (branch_radius / (support_line_width / 2.0)))) + , // Either 40° or as much as possible so that 2 lines will overlap by at least 50%, whichever is smaller. + support_overrides(mesh_group_settings.get("support_xy_overrides_z")) + , xy_min_distance(support_overrides == SupportDistPriority::Z_OVERRIDES_XY ? mesh_group_settings.get("support_xy_distance_overhang") : xy_distance) + , z_distance_top_layers(round_up_divide(mesh_group_settings.get("support_top_distance"), layer_height)) + , z_distance_bottom_layers(round_up_divide(mesh_group_settings.get("support_bottom_distance"), layer_height)) + , performance_interface_skip_layers(round_up_divide(mesh_group_settings.get("support_interface_skip_height"), layer_height)) + , support_infill_angles(mesh_group_settings.get>("support_infill_angles")) + , support_roof_angles(mesh_group_settings.get>("support_roof_angles")) + , roof_pattern(mesh_group_settings.get("support_roof_pattern")) + , support_pattern(mesh_group_settings.get("support_pattern")) + , support_roof_line_width(mesh_group_settings.get("support_roof_line_width")) + , support_line_distance(mesh_group_settings.get("support_line_distance")) + , support_bottom_offset(mesh_group_settings.get("support_bottom_offset")) + , support_wall_count(mesh_group_settings.get("support_wall_count")) + , support_roof_wall_count(mesh_group_settings.get("support_roof_wall_count")) + , zig_zaggify_support(mesh_group_settings.get("zig_zaggify_support")) + , maximum_deviation(mesh_group_settings.get("meshfix_maximum_deviation")) + , maximum_resolution(mesh_group_settings.get("meshfix_maximum_resolution")) + , support_roof_line_distance(mesh_group_settings.get("support_roof_line_distance")) + , // in the end the actual infill has to be calculated to subtract interface from support areas according to interface_preference. + skip_some_zags(mesh_group_settings.get("support_skip_some_zags")) + , zag_skip_count(mesh_group_settings.get("support_zag_skip_count")) + , connect_zigzags(mesh_group_settings.get("support_connect_zigzags")) + , settings(mesh_group_settings) + , min_feature_size(mesh_group_settings.get("min_feature_size")) + , min_wall_line_width(settings.get("min_wall_line_width")) + , fill_outline_gaps(settings.get("fill_outline_gaps")) + , simplifier(Simplify(mesh_group_settings)) { layer_start_bp_radius = (bp_radius - branch_radius) / (branch_radius * diameter_scale_bp_radius); - // safeOffsetInc can only work in steps of the size xy_min_distance in the worst case => xy_min_distance has to be a bit larger than 0 in this worst case and should be large enough for performance to not suffer extremely - // When for all meshes the z bottom and top distance is more than one layer though the worst case is xy_min_distance + min_feature_size - // This is not the best solution, but the only one to ensure areas can not lag though walls at high maximum_move_distance. + // safeOffsetInc can only work in steps of the size xy_min_distance in the worst case => xy_min_distance has to be a bit larger than 0 in this worst case and should be + // large enough for performance to not suffer extremely When for all meshes the z bottom and top distance is more than one layer though the worst case is xy_min_distance + + // min_feature_size This is not the best solution, but the only one to ensure areas can not lag though walls at high maximum_move_distance. if (has_to_rely_on_min_xy_dist_only) { xy_min_distance = std::max(coord_t(100), xy_min_distance); // If set to low rounding errors WILL cause errors. Best to keep it above 25. @@ -83,49 +92,47 @@ struct TreeSupportSettings xy_distance = std::max(xy_distance, xy_min_distance); - const std::function&, EFillMethod)> getInterfaceAngles = - [&](std::vector& angles, EFillMethod pattern) { // (logic) from getInterfaceAngles in FFFGcodeWriter. - if (angles.empty()) - { - if (pattern == EFillMethod::CONCENTRIC) - { - angles.push_back(0); // Concentric has no rotation. - } - else if (pattern == EFillMethod::TRIANGLES) - { - angles.push_back(90); // Triangular support interface shouldn't alternate every layer. - } - else - { - if (TreeSupportSettings::some_model_contains_thick_roof) - { - // Some roofs are quite thick. - // Alternate between the two kinds of diagonal: / and \ . - angles.push_back(45); - angles.push_back(135); - } - if (angles.empty()) - { - angles.push_back(90); // Perpendicular to support lines. - } - } - } - }; - - if(support_infill_angles.empty()) + const std::function&, EFillMethod)> getInterfaceAngles + = [&](std::vector& angles, EFillMethod pattern) { // (logic) from getInterfaceAngles in FFFGcodeWriter. + if (angles.empty()) + { + if (pattern == EFillMethod::CONCENTRIC) + { + angles.push_back(0); // Concentric has no rotation. + } + else if (pattern == EFillMethod::TRIANGLES) + { + angles.push_back(90); // Triangular support interface shouldn't alternate every layer. + } + else + { + if (TreeSupportSettings::some_model_contains_thick_roof) + { + // Some roofs are quite thick. + // Alternate between the two kinds of diagonal: / and \ . + angles.push_back(45); + angles.push_back(135); + } + if (angles.empty()) + { + angles.push_back(90); // Perpendicular to support lines. + } + } + } + }; + + if (support_infill_angles.empty()) { support_infill_angles.push_back(0); } getInterfaceAngles(support_roof_angles, roof_pattern); - const std::unordered_map interface_map = - { - { "support_area_overwrite_interface_area", InterfacePreference::SUPPORT_AREA_OVERWRITES_INTERFACE }, + const std::unordered_map interface_map + = { { "support_area_overwrite_interface_area", InterfacePreference::SUPPORT_AREA_OVERWRITES_INTERFACE }, { "interface_area_overwrite_support_area", InterfacePreference::INTERFACE_AREA_OVERWRITES_SUPPORT }, { "support_lines_overwrite_interface_area", InterfacePreference::SUPPORT_LINES_OVERWRITE_INTERFACE }, { "interface_lines_overwrite_support_area", InterfacePreference::INTERFACE_LINES_OVERWRITE_SUPPORT }, - { "nothing", InterfacePreference::NOTHING } - }; + { "nothing", InterfacePreference::NOTHING } }; interface_preference = interface_map.at(mesh_group_settings.get("support_interface_priority")); } @@ -236,7 +243,8 @@ struct TreeSupportSettings coord_t layer_start_bp_radius; /*! - * \brief Factor by which to increase the branch radius to reach the required bp_radius at layer 0. Note that this radius increase will not happen in the tip, to ensure the tip is structurally sound. + * \brief Factor by which to increase the branch radius to reach the required bp_radius at layer 0. Note that this radius increase will not happen in the tip, to ensure the tip + * is structurally sound. */ double diameter_scale_bp_radius; @@ -321,7 +329,8 @@ struct TreeSupportSettings coord_t maximum_deviation; /*! - * \brief Maximum allowed resolution (length of a line segment) when simplifying. The resolution is higher when this variable is smaller => Minimum size a line segment may have. + * \brief Maximum allowed resolution (length of a line segment) when simplifying. The resolution is higher when this variable is smaller => Minimum size a line segment may + * have. */ coord_t maximum_resolution; @@ -375,83 +384,55 @@ struct TreeSupportSettings */ Simplify simplifier = Simplify(0, 0, 0); - public: +public: bool operator==(const TreeSupportSettings& other) const { - return - branch_radius == other.branch_radius && - tip_layers == other.tip_layers && - diameter_angle_scale_factor == other.diameter_angle_scale_factor && - layer_start_bp_radius == other.layer_start_bp_radius && - bp_radius == other.bp_radius && - diameter_scale_bp_radius == other.diameter_scale_bp_radius && - min_radius == other.min_radius && - xy_min_distance == other.xy_min_distance && // as a recalculation of the collision areas is required to set a new min_radius. - xy_distance - xy_min_distance == other.xy_distance - other.xy_min_distance && // if the delta of xy_min_distance and xy_distance is different the collision areas have to be recalculated. - support_rests_on_model == other.support_rests_on_model && - increase_radius_until_dtt == other.increase_radius_until_dtt && - min_dtt_to_model == other.min_dtt_to_model && - max_to_model_radius_increase == other.max_to_model_radius_increase && - maximum_move_distance == other.maximum_move_distance && - maximum_move_distance_slow == other.maximum_move_distance_slow && - z_distance_bottom_layers == other.z_distance_bottom_layers && - support_line_width == other.support_line_width && - support_overrides == other.support_overrides && - support_line_distance == other.support_line_distance && - support_roof_line_width == other.support_roof_line_width && // can not be set on a per-mesh basis currently, so code to enable processing different roof line width in the same iteration seems useless. - support_bottom_offset == other.support_bottom_offset && - support_wall_count == other.support_wall_count && - support_pattern == other.support_pattern && - roof_pattern == other.roof_pattern && // can not be set on a per-mesh basis currently, so code to enable processing different roof patterns in the same iteration seems useless. - support_roof_angles == other.support_roof_angles && - support_infill_angles == other.support_infill_angles && - increase_radius_until_radius == other.increase_radius_until_radius && - support_bottom_layers == other.support_bottom_layers && - layer_height == other.layer_height && - z_distance_top_layers == other.z_distance_top_layers && - maximum_deviation == other.maximum_deviation && // Infill generation depends on deviation and resolution. - maximum_resolution == other.maximum_resolution && - support_roof_line_distance == other.support_roof_line_distance && - skip_some_zags == other.skip_some_zags && - zag_skip_count == other.zag_skip_count && - connect_zigzags == other.connect_zigzags && - interface_preference == other.interface_preference && - min_feature_size == other.min_feature_size && // interface_preference should be identical to ensure the tree will correctly interact with the roof. - support_rest_preference == other.support_rest_preference && - max_radius == other.max_radius && - min_wall_line_width == other.min_wall_line_width && - fill_outline_gaps == other.fill_outline_gaps && - // The infill class now wants the settings object and reads a lot of settings, and as the infill class is used to calculate support roof lines for interface-preference. Not all of these may be required to be identical, but as I am not sure, better safe than sorry - ( - interface_preference == InterfacePreference::INTERFACE_AREA_OVERWRITES_SUPPORT || - interface_preference == InterfacePreference::SUPPORT_AREA_OVERWRITES_INTERFACE || - ( - settings.get("fill_outline_gaps") == other.settings.get("fill_outline_gaps") && - settings.get("min_bead_width") == other.settings.get("min_bead_width") && - settings.get("wall_transition_angle") == other.settings.get("wall_transition_angle") && - settings.get("wall_transition_length") == other.settings.get("wall_transition_length") && - settings.get("min_odd_wall_line_width") == other.settings.get("min_odd_wall_line_width") && - settings.get("min_even_wall_line_width") == other.settings.get("min_even_wall_line_width") && - settings.get("wall_distribution_count") == other.settings.get("wall_distribution_count") && - settings.get("wall_transition_filter_distance") == other.settings.get("wall_transition_filter_distance") && - settings.get("wall_transition_filter_deviation") == other.settings.get("wall_transition_filter_deviation") && - settings.get("wall_line_width_x") == other.settings.get("wall_line_width_x") && - settings.get("meshfix_maximum_extrusion_area_deviation") == other.settings.get("meshfix_maximum_extrusion_area_deviation") - ) - ); + return branch_radius == other.branch_radius && tip_layers == other.tip_layers && diameter_angle_scale_factor == other.diameter_angle_scale_factor + && layer_start_bp_radius == other.layer_start_bp_radius && bp_radius == other.bp_radius && diameter_scale_bp_radius == other.diameter_scale_bp_radius + && min_radius == other.min_radius && xy_min_distance == other.xy_min_distance && // as a recalculation of the collision areas is required to set a new min_radius. + xy_distance - xy_min_distance == other.xy_distance - other.xy_min_distance + && // if the delta of xy_min_distance and xy_distance is different the collision areas have to be recalculated. + support_rests_on_model == other.support_rests_on_model && increase_radius_until_dtt == other.increase_radius_until_dtt && min_dtt_to_model == other.min_dtt_to_model + && max_to_model_radius_increase == other.max_to_model_radius_increase && maximum_move_distance == other.maximum_move_distance + && maximum_move_distance_slow == other.maximum_move_distance_slow && z_distance_bottom_layers == other.z_distance_bottom_layers + && support_line_width == other.support_line_width && support_overrides == other.support_overrides && support_line_distance == other.support_line_distance + && support_roof_line_width == other.support_roof_line_width + && // can not be set on a per-mesh basis currently, so code to enable processing different roof line width in the same iteration seems useless. + support_bottom_offset == other.support_bottom_offset && support_wall_count == other.support_wall_count && support_pattern == other.support_pattern + && roof_pattern == other.roof_pattern + && // can not be set on a per-mesh basis currently, so code to enable processing different roof patterns in the same iteration seems useless. + support_roof_angles == other.support_roof_angles && support_infill_angles == other.support_infill_angles + && increase_radius_until_radius == other.increase_radius_until_radius && support_bottom_layers == other.support_bottom_layers && layer_height == other.layer_height + && z_distance_top_layers == other.z_distance_top_layers && maximum_deviation == other.maximum_deviation && // Infill generation depends on deviation and resolution. + maximum_resolution == other.maximum_resolution && support_roof_line_distance == other.support_roof_line_distance && skip_some_zags == other.skip_some_zags + && zag_skip_count == other.zag_skip_count && connect_zigzags == other.connect_zigzags && interface_preference == other.interface_preference + && min_feature_size == other.min_feature_size && // interface_preference should be identical to ensure the tree will correctly interact with the roof. + support_rest_preference == other.support_rest_preference && max_radius == other.max_radius && min_wall_line_width == other.min_wall_line_width + && fill_outline_gaps == other.fill_outline_gaps && + // The infill class now wants the settings object and reads a lot of settings, and as the infill class is used to calculate support roof lines for + // interface-preference. Not all of these may be required to be identical, but as I am not sure, better safe than sorry + (interface_preference == InterfacePreference::INTERFACE_AREA_OVERWRITES_SUPPORT || interface_preference == InterfacePreference::SUPPORT_AREA_OVERWRITES_INTERFACE + || (settings.get("fill_outline_gaps") == other.settings.get("fill_outline_gaps") + && settings.get("min_bead_width") == other.settings.get("min_bead_width") + && settings.get("wall_transition_angle") == other.settings.get("wall_transition_angle") + && settings.get("wall_transition_length") == other.settings.get("wall_transition_length") + && settings.get("min_odd_wall_line_width") == other.settings.get("min_odd_wall_line_width") + && settings.get("min_even_wall_line_width") == other.settings.get("min_even_wall_line_width") + && settings.get("wall_distribution_count") == other.settings.get("wall_distribution_count") + && settings.get("wall_transition_filter_distance") == other.settings.get("wall_transition_filter_distance") + && settings.get("wall_transition_filter_deviation") == other.settings.get("wall_transition_filter_deviation") + && settings.get("wall_line_width_x") == other.settings.get("wall_line_width_x") + && settings.get("meshfix_maximum_extrusion_area_deviation") == other.settings.get("meshfix_maximum_extrusion_area_deviation"))); } /*! - * \brief Get the Distance to top regarding the real radius this part will have. This is different from distance_to_top, which is can be used to calculate the top most layer of the branch. - * \param elem[in] The SupportElement one wants to know the effectiveDTT - * \return The Effective DTT. + * \brief Get the Distance to top regarding the real radius this part will have. This is different from distance_to_top, which is can be used to calculate the top most layer of + * the branch. \param elem[in] The SupportElement one wants to know the effectiveDTT \return The Effective DTT. */ [[nodiscard]] inline size_t getEffectiveDTT(const TreeSupportElement& elem) const { - return - elem.effective_radius_height < increase_radius_until_dtt ? - (elem.distance_to_top < increase_radius_until_dtt ? elem.distance_to_top : increase_radius_until_dtt) : - elem.effective_radius_height; + return elem.effective_radius_height < increase_radius_until_dtt ? (elem.distance_to_top < increase_radius_until_dtt ? elem.distance_to_top : increase_radius_until_dtt) + : elem.effective_radius_height; } /*! @@ -462,15 +443,13 @@ struct TreeSupportSettings */ [[nodiscard]] inline coord_t getRadius(size_t distance_to_top, const double buildplate_radius_increases = 0) const { - coord_t uncapped_radius = - ( - distance_to_top <= tip_layers ? - /* tip */ min_radius + (branch_radius - min_radius) * distance_to_top / tip_layers : - /* base */ branch_radius + - /* gradual increase */ branch_radius * (distance_to_top - tip_layers) * diameter_angle_scale_factor) + - branch_radius * buildplate_radius_increases * (std::max(diameter_scale_bp_radius - diameter_angle_scale_factor, 0.0) - ); - return std::min(uncapped_radius,max_radius); + coord_t uncapped_radius = (distance_to_top <= tip_layers ? + /* tip */ min_radius + (branch_radius - min_radius) * distance_to_top / tip_layers + : + /* base */ branch_radius + + /* gradual increase */ branch_radius * (distance_to_top - tip_layers) * diameter_angle_scale_factor) + + branch_radius * buildplate_radius_increases * (std::max(diameter_scale_bp_radius - diameter_angle_scale_factor, 0.0)); + return std::min(uncapped_radius, max_radius); } /*! @@ -480,7 +459,7 @@ struct TreeSupportSettings */ [[nodiscard]] inline coord_t getRadius(const TreeSupportElement& elem) const { - return getRadius(getEffectiveDTT(elem), (elem.isResultOnLayerSet() || !support_rests_on_model) && elem.to_buildplate ? elem.buildplate_radius_increases : 0); + return getRadius(getEffectiveDTT(elem), (elem.isResultOnLayerSet() || ! support_rests_on_model) && elem.to_buildplate ? elem.buildplate_radius_increases : 0); } /*! @@ -501,7 +480,7 @@ struct TreeSupportSettings [[nodiscard]] inline coord_t recommendedMinRadius(LayerIndex layer_idx) const { const double scale = (layer_start_bp_radius - layer_idx) * diameter_scale_bp_radius; - return scale > 0 ? std::min(coord_t(branch_radius + branch_radius * scale),max_radius) : 0; + return scale > 0 ? std::min(coord_t(branch_radius + branch_radius * scale), max_radius) : 0; } /*! diff --git a/include/TreeSupportTipGenerator.h b/include/TreeSupportTipGenerator.h index 16985e90dc..a22417dc3c 100644 --- a/include/TreeSupportTipGenerator.h +++ b/include/TreeSupportTipGenerator.h @@ -2,6 +2,7 @@ #define TREESUPPORTTIPGENERATOR_H #include "TreeModelVolumes.h" +#include "TreeSupport.h" #include "TreeSupportBaseCircle.h" #include "TreeSupportElement.h" #include "TreeSupportEnums.h" @@ -12,7 +13,6 @@ #include "sliceDataStorage.h" #include "utils/Coord_t.h" #include "utils/polygon.h" -#include "TreeSupport.h" namespace cura { @@ -20,12 +20,10 @@ namespace cura class TreeSupportTipGenerator { - public: - TreeSupportTipGenerator(const SliceDataStorage& storage, const SliceMeshStorage& mesh, TreeModelVolumes& volumes_); - ~ TreeSupportTipGenerator() + ~TreeSupportTipGenerator() { if (cross_fill_provider) { @@ -43,10 +41,14 @@ class TreeSupportTipGenerator * \return All lines of the \p polylines object, with information for each point regarding in which avoidance it is currently valid in. */ - void generateTips(SliceDataStorage& storage,const SliceMeshStorage& mesh ,std::vector>& move_bounds, std::vector& additional_support_areas, std::vector& placed_support_lines_support_areas); + void generateTips( + SliceDataStorage& storage, + const SliceMeshStorage& mesh, + std::vector>& move_bounds, + std::vector& additional_support_areas, + std::vector& placed_support_lines_support_areas); private: - enum class LineStatus { INVALID, @@ -85,17 +87,16 @@ class TreeSupportTipGenerator std::function)> getEvaluatePointForNextLayerFunction(size_t current_layer); /*! - * \brief Evaluates which points of some lines are not valid one layer below and which are. Assumes all points are valid on the current layer. Validity is evaluated using supplied lambda. + * \brief Evaluates which points of some lines are not valid one layer below and which are. Assumes all points are valid on the current layer. Validity is evaluated using + * supplied lambda. * * \param lines[in] The lines that have to be evaluated. * \param evaluatePoint[in] The function used to evaluate the points. * \return A pair with which points are still valid in the first slot and which are not in the second slot. */ - std::pair, std::vector> splitLines - ( - std::vector lines, - std::function)> evaluatePoint - ); // assumes all Points on the current line are valid + std::pair, std::vector> splitLines( + std::vector lines, + std::function)> evaluatePoint); // assumes all Points on the current line are valid /*! * \brief Ensures that every line segment is about distance in length. The resulting lines may differ from the original but all points are on the original @@ -125,7 +126,7 @@ class TreeSupportTipGenerator * \param result[out] The dropped overhang ares * \param roof[in] Whether the result is for roof generation. */ - void dropOverhangAreas(const SliceMeshStorage& mesh, std::vector& result, bool roof ); + void dropOverhangAreas(const SliceMeshStorage& mesh, std::vector& result, bool roof); /*! * \brief Calculates which areas should be supported with roof, and saves these in roof support_roof_drawn @@ -143,7 +144,15 @@ class TreeSupportTipGenerator * \param roof[in] Whether the tip supports a roof. * \param skip_ovalisation[in] Whether the tip may be ovalized when drawn later. */ - void addPointAsInfluenceArea(std::vector>& move_bounds, std::pair p, size_t dtt, LayerIndex insert_layer, size_t dont_move_until, bool roof, bool skip_ovalisation, std::vector additional_ovalization_targets = std::vector()); + void addPointAsInfluenceArea( + std::vector>& move_bounds, + std::pair p, + size_t dtt, + LayerIndex insert_layer, + size_t dont_move_until, + bool roof, + bool skip_ovalisation, + std::vector additional_ovalization_targets = std::vector()); /*! @@ -155,7 +164,14 @@ class TreeSupportTipGenerator * \param supports_roof[in] Whether the tip supports a roof. * \param dont_move_until[in] Until which dtt the branch should not move if possible. */ - void addLinesAsInfluenceAreas(std::vector>& move_bounds, std::vector lines, size_t roof_tip_layers, LayerIndex insert_layer_idx, bool supports_roof, size_t dont_move_until, bool connect_points); + void addLinesAsInfluenceAreas( + std::vector>& move_bounds, + std::vector lines, + size_t roof_tip_layers, + LayerIndex insert_layer_idx, + bool supports_roof, + size_t dont_move_until, + bool connect_points); /*! * \brief Remove tips that should not have been added in the first place. @@ -163,7 +179,7 @@ class TreeSupportTipGenerator * \param storage[in] Background storage, required for adding roofs. * \param additional_support_areas[in] Areas that should have been roofs, but are now support, as they would not generate any lines as roof. */ - void removeUselessAddedPoints(std::vector>& move_bounds,SliceDataStorage& storage, std::vector& additional_support_areas); + void removeUselessAddedPoints(std::vector>& move_bounds, SliceDataStorage& storage, std::vector& additional_support_areas); /*! @@ -264,7 +280,8 @@ class TreeSupportTipGenerator const bool only_gracious = SUPPORT_TREE_ONLY_GRACIOUS_TO_MODEL; /*! - * \brief Whether minimum_roof_area is a hard limit. If false the roof will be combined with roof above and below, to see if a part of this roof may be part of a valid roof further up/down. + * \brief Whether minimum_roof_area is a hard limit. If false the roof will be combined with roof above and below, to see if a part of this roof may be part of a valid roof + * further up/down. */ const bool force_minimum_roof_area = SUPPORT_TREE_MINIMUM_ROOF_AREA_HARD_LIMIT; @@ -294,15 +311,10 @@ class TreeSupportTipGenerator std::vector roof_tips_drawn; - - std::mutex critical_move_bounds; std::mutex critical_roof_tips; - - - }; -} +} // namespace cura #endif /* TREESUPPORT_H */ \ No newline at end of file diff --git a/include/TreeSupportUtils.h b/include/TreeSupportUtils.h index 2f6378dc20..f8ed1ef211 100644 --- a/include/TreeSupportUtils.h +++ b/include/TreeSupportUtils.h @@ -7,21 +7,20 @@ #include "TreeSupportEnums.h" #include "TreeSupportSettings.h" #include "boost/functional/hash.hpp" // For combining hashes +#include "infill.h" #include "polyclipping/clipper.hpp" #include "settings/EnumSettings.h" #include "sliceDataStorage.h" #include "utils/Coord_t.h" #include "utils/polygon.h" + #include -#include "infill.h" namespace cura { class TreeSupportUtils { - - public: /*! * \brief Adds the implicit line from the last vertex of a Polygon to the first one. @@ -81,7 +80,6 @@ class TreeSupportUtils } - /*! * \brief Returns Polylines representing the (infill) lines that will result in slicing the given area * @@ -95,7 +93,15 @@ class TreeSupportUtils * todo doku * \return A Polygons object that represents the resulting infill lines. */ - [[nodiscard]] static Polygons generateSupportInfillLines(const Polygons& area,const TreeSupportSettings& config, bool roof, LayerIndex layer_idx, coord_t support_infill_distance, SierpinskiFillProvider* cross_fill_provider, bool include_walls, bool generate_support_supporting = false) + [[nodiscard]] static Polygons generateSupportInfillLines( + const Polygons& area, + const TreeSupportSettings& config, + bool roof, + LayerIndex layer_idx, + coord_t support_infill_distance, + SierpinskiFillProvider* cross_fill_provider, + bool include_walls, + bool generate_support_supporting = false) { Polygons gaps; // As we effectivly use lines to place our supportPoints we may use the Infill class for it, while not made for it, it works perfectly. @@ -107,7 +113,7 @@ class TreeSupportUtils constexpr coord_t support_roof_overlap = 0; constexpr size_t infill_multiplier = 1; const int support_shift = roof ? 0 : support_infill_distance / 2; - const size_t wall_line_count = include_walls ? (!roof ? config.support_wall_count : config.support_roof_wall_count):0; + const size_t wall_line_count = include_walls ? (! roof ? config.support_wall_count : config.support_roof_wall_count) : 0; constexpr coord_t narrow_area_width = 0; const Point infill_origin; constexpr bool skip_stitching = false; @@ -124,32 +130,30 @@ class TreeSupportUtils const size_t divisor = angles.size(); const size_t index = ((layer_idx % divisor) + divisor) % divisor; const AngleDegrees fill_angle = angles[index]; - Infill roof_computation - ( - pattern, - zig_zaggify_infill, - connect_polygons, - area, - roof ? config.support_roof_line_width : config.support_line_width, - support_infill_distance, - support_roof_overlap, - infill_multiplier, - fill_angle, - z, - support_shift, - config.maximum_resolution, - config.maximum_deviation, - wall_line_count, - narrow_area_width, - infill_origin, - skip_stitching, - fill_gaps, - connected_zigzags, - use_endpieces, - skip_some_zags, - zag_skip_count, - pocket_size - ); + Infill roof_computation( + pattern, + zig_zaggify_infill, + connect_polygons, + area, + roof ? config.support_roof_line_width : config.support_line_width, + support_infill_distance, + support_roof_overlap, + infill_multiplier, + fill_angle, + z, + support_shift, + config.maximum_resolution, + config.maximum_deviation, + wall_line_count, + narrow_area_width, + infill_origin, + skip_stitching, + fill_gaps, + connected_zigzags, + use_endpieces, + skip_some_zags, + zag_skip_count, + pocket_size); Polygons areas; Polygons lines; @@ -168,8 +172,8 @@ class TreeSupportUtils [[nodiscard]] static Polygons safeUnion(const Polygons& first, const Polygons& second = Polygons()) { // The unionPolygons function can slowly remove Polygons under certain circumstances, because of rounding issues (Polygons that have a thin area). - // This does not cause a problem when actually using it on large areas, but as influence areas (representing centerpoints) can be very thin, this does occur so this ugly workaround is needed - // Here is an example of a Polygons object that will loose vertices when unioning, and will be gone after a few times unionPolygons was called: + // This does not cause a problem when actually using it on large areas, but as influence areas (representing centerpoints) can be very thin, this does occur so this ugly + // workaround is needed Here is an example of a Polygons object that will loose vertices when unioning, and will be gone after a few times unionPolygons was called: /* 120410,83599 120384,83643 @@ -198,14 +202,12 @@ class TreeSupportUtils * \param distance[in] The distance by which me should be offset. Expects values >=0. * \param collision[in] The area representing obstacles. * \param last_step_offset_without_check[in] The most it is allowed to offset in one step. - * \param min_amount_offset[in] How many steps have to be done at least. As this uses round offset this increases the amount of vertices, which may be required if Polygons get very small. - * Required as arcTolerance is not exposed in offset, which should result with a similar result, benefit may be eliminated by simplifying. - * \param min_offset_per_step Don't get below this amount of offset per step taken. Fine-tune tradeoff between speed and accuracy. - * \param simplifier[in] Pointer to Simplify object if the offset operation also simplify the Polygon. Improves performance. - * \return The resulting Polygons object. + * \param min_amount_offset[in] How many steps have to be done at least. As this uses round offset this increases the amount of vertices, which may be required if Polygons get + * very small. Required as arcTolerance is not exposed in offset, which should result with a similar result, benefit may be eliminated by simplifying. \param + * min_offset_per_step Don't get below this amount of offset per step taken. Fine-tune tradeoff between speed and accuracy. \param simplifier[in] Pointer to Simplify object if + * the offset operation also simplify the Polygon. Improves performance. \return The resulting Polygons object. */ - [[nodiscard]] static Polygons safeOffsetInc - ( + [[nodiscard]] static Polygons safeOffsetInc( const Polygons& me, coord_t distance, const Polygons& collision, @@ -213,8 +215,7 @@ class TreeSupportUtils coord_t last_step_offset_without_check, size_t min_amount_offset, coord_t min_offset_per_step, - Simplify* simplifier - ) + Simplify* simplifier) { bool do_final_difference = last_step_offset_without_check == 0; Polygons ret = safeUnion(me); // Ensure sane input. @@ -267,7 +268,7 @@ class TreeSupportUtils } } ret = ret.offset(distance - steps * step_size, ClipperLib::jtRound); // Offset the remainder. - if(simplifier) + if (simplifier) { ret = simplifier->polygon(ret); } @@ -284,31 +285,30 @@ class TreeSupportUtils * * \param polylines[in] The polyline object from which the lines are moved. * \param area[in] The area the points are moved out of. - * \param max_allowed_distance[in] The maximum distance a point may be moved. If not possible the point will be moved as far as possible in the direction of the outside of the provided area. - * \return A Polyline object containing the moved points. + * \param max_allowed_distance[in] The maximum distance a point may be moved. If not possible the point will be moved as far as possible in the direction of the outside of the + * provided area. \return A Polyline object containing the moved points. */ - [[nodiscard]]static Polygons movePointsOutside(const Polygons& polylines, const Polygons& area, coord_t max_allowed_distance) + [[nodiscard]] static Polygons movePointsOutside(const Polygons& polylines, const Polygons& area, coord_t max_allowed_distance) { Polygons result; - for (auto line:polylines) + for (auto line : polylines) { Polygon next_line; - for (Point p:line) + for (Point p : line) { - if (area.inside(p)) { Point next_outside = p; - PolygonUtils::moveOutside(area,next_outside); - if (vSize2(p-next_outside)0) + if (next_line.size() > 0) { result.add(next_line); } @@ -326,25 +326,23 @@ class TreeSupportUtils return result; } - [[nodiscard]]static VariableWidthLines polyLineToVWL(const Polygons& polylines, coord_t line_width) + [[nodiscard]] static VariableWidthLines polyLineToVWL(const Polygons& polylines, coord_t line_width) { VariableWidthLines result; - for (auto path: polylines) + for (auto path : polylines) { - ExtrusionLine vwl_line(1,true); + ExtrusionLine vwl_line(1, true); - for(Point p: path) + for (Point p : path) { - vwl_line.emplace_back(p,line_width,1); + vwl_line.emplace_back(p, line_width, 1); } result.emplace_back(vwl_line); } return result; } - - }; -} //namespace cura +} // namespace cura #endif // TREESUPPORTTUTILS_H diff --git a/include/WallToolPaths.h b/include/WallToolPaths.h index 810357a7a6..dad108c2df 100644 --- a/include/WallToolPaths.h +++ b/include/WallToolPaths.h @@ -4,14 +4,14 @@ #ifndef CURAENGINE_WALLTOOLPATHS_H #define CURAENGINE_WALLTOOLPATHS_H -#include - #include "BeadingStrategy/BeadingStrategyFactory.h" #include "settings/Settings.h" #include "utils/ExtrusionLine.h" #include "utils/polygon.h" #include "utils/section_type.h" +#include + namespace cura { class WallToolPaths @@ -25,7 +25,14 @@ class WallToolPaths * \param wall_0_inset How far to inset the outer wall, to make it adhere better to other walls. * \param settings The settings as provided by the user */ - WallToolPaths(const Polygons& outline, const coord_t nominal_bead_width, const size_t inset_count, const coord_t wall_0_inset, const Settings& settings, const int layer_idx, SectionType section_type); + WallToolPaths( + const Polygons& outline, + const coord_t nominal_bead_width, + const size_t inset_count, + const coord_t wall_0_inset, + const Settings& settings, + const int layer_idx, + SectionType section_type); /*! * A class that creates the toolpaths given an outline, nominal bead width and maximum amount of walls @@ -36,7 +43,15 @@ class WallToolPaths * \param wall_0_inset How far to inset the outer wall, to make it adhere better to other walls. * \param settings The settings as provided by the user */ - WallToolPaths(const Polygons& outline, const coord_t bead_width_0, const coord_t bead_width_x, const size_t inset_count, const coord_t wall_0_inset, const Settings& settings, const int layer_idx, SectionType section_type); + WallToolPaths( + const Polygons& outline, + const coord_t bead_width_0, + const coord_t bead_width_x, + const size_t inset_count, + const coord_t wall_0_inset, + const Settings& settings, + const int layer_idx, + SectionType section_type); /*! * Generates the Toolpaths @@ -87,9 +102,9 @@ class WallToolPaths protected: /*! * Stitch the polylines together and form closed polygons. - * + * * Works on both toolpaths and inner contours simultaneously. - * + * * \param settings The settings as provided by the user */ static void stitchToolPaths(std::vector& toolpaths, const Settings& settings); @@ -109,17 +124,18 @@ class WallToolPaths private: const Polygons& outline; // toolpaths; // -#include - #include "../utils/IntPoint.h" #include "Coord_t.h" +#include +#include + namespace cura { @@ -18,6 +18,7 @@ class HalfEdge { using edge_t = derived_edge_t; using node_t = derived_node_t; + public: edge_data_t data; edge_t* twin = nullptr; @@ -26,8 +27,9 @@ class HalfEdge node_t* from = nullptr; node_t* to = nullptr; HalfEdge(edge_data_t data) - : data(data) - {} + : data(data) + { + } bool operator==(const edge_t& other) { return this == &other; @@ -35,7 +37,5 @@ class HalfEdge }; - - } // namespace cura #endif // UTILS_HALF_EDGE_H diff --git a/include/utils/HalfEdgeNode.h b/include/utils/HalfEdgeNode.h index b22a7fa804..53e6522307 100644 --- a/include/utils/HalfEdgeNode.h +++ b/include/utils/HalfEdgeNode.h @@ -4,10 +4,10 @@ #ifndef UTILS_HALF_EDGE_NODE_H #define UTILS_HALF_EDGE_NODE_H -#include - #include "IntPoint.h" +#include + namespace cura { @@ -16,14 +16,16 @@ class HalfEdgeNode { using edge_t = derived_edge_t; using node_t = derived_node_t; + public: node_data_t data; Point p; edge_t* incident_edge = nullptr; HalfEdgeNode(node_data_t data, Point p) - : data(data) - , p(p) - {} + : data(data) + , p(p) + { + } bool operator==(const node_t& other) { @@ -32,7 +34,5 @@ class HalfEdgeNode }; - - } // namespace cura #endif // UTILS_HALF_EDGE_NODE_H diff --git a/include/utils/Simplify.h b/include/utils/Simplify.h index 6cad5fcaf5..71a17ad3c8 100644 --- a/include/utils/Simplify.h +++ b/include/utils/Simplify.h @@ -1,13 +1,13 @@ -//Copyright (c) 2022 Ultimaker B.V. -//CuraEngine is released under the terms of the AGPLv3 or higher. +// Copyright (c) 2022 Ultimaker B.V. +// CuraEngine is released under the terms of the AGPLv3 or higher. #ifndef UTILS_SIMPLIFY_H #define UTILS_SIMPLIFY_H -#include "polygon.h" +#include "../settings/Settings.h" //To load the parameters from a Settings object. #include "ExtrusionLine.h" #include "linearAlg2D.h" //To calculate line deviations and intersecting lines. -#include "../settings/Settings.h" //To load the parameters from a Settings object. +#include "polygon.h" namespace cura { @@ -131,12 +131,12 @@ class Simplify * If a vertex causes deviation of less than this, it should always be * removed. */ - constexpr static coord_t min_resolution = 5; //5 units, regardless of how big those are, to allow for rounding errors. + constexpr static coord_t min_resolution = 5; // 5 units, regardless of how big those are, to allow for rounding errors. template bool detectSmall(const Polygonal& polygon, const coord_t& min_size) const { - if (polygon.size() < min_size) //For polygon, 2 or fewer vertices is degenerate. Delete it. For polyline, 1 vertex is degenerate. + if (polygon.size() < min_size) // For polygon, 2 or fewer vertices is degenerate. Delete it. For polyline, 1 vertex is degenerate. { return true; } @@ -169,7 +169,7 @@ class Simplify { return createEmpty(polygon); } - if(polygon.size() == min_size) //For polygon, don't reduce below 3. For polyline, not below 2. + if (polygon.size() == min_size) // For polygon, don't reduce below 3. For polyline, not below 2. { return polygon; } @@ -181,12 +181,12 @@ class Simplify }; std::priority_queue, std::vector>, decltype(comparator)> by_importance(comparator); - Polygonal result = polygon; //Make a copy so that we can also shift vertices. + Polygonal result = polygon; // Make a copy so that we can also shift vertices. for (int64_t current_removed = -1; (polygon.size() - current_removed) > min_size && current_removed != 0;) { current_removed = 0; - //Add the initial points. + // Add the initial points. for (size_t i = 0; i < result.size(); ++i) { if (to_delete[i]) @@ -197,18 +197,18 @@ class Simplify by_importance.emplace(i, vertex_importance); } - //Iteratively remove the least important point until a threshold. + // Iteratively remove the least important point until a threshold. coord_t vertex_importance = 0; while (! by_importance.empty() && (polygon.size() - current_removed) > min_size) { std::pair vertex = by_importance.top(); by_importance.pop(); - //The importance may have changed since this vertex was inserted. Re-compute it now. - //If it doesn't change, it's safe to process. + // The importance may have changed since this vertex was inserted. Re-compute it now. + // If it doesn't change, it's safe to process. vertex_importance = importance(result, to_delete, vertex.first, is_closed); if (vertex_importance != vertex.second) { - by_importance.emplace(vertex.first, vertex_importance); //Re-insert with updated importance. + by_importance.emplace(vertex.first, vertex_importance); // Re-insert with updated importance. continue; } @@ -219,11 +219,11 @@ class Simplify } } - //Now remove the marked vertices in one sweep. + // Now remove the marked vertices in one sweep. Polygonal filtered = createEmpty(polygon); - for(size_t i = 0; i < result.size(); ++i) + for (size_t i = 0; i < result.size(); ++i) { - if(!to_delete[i]) + if (! to_delete[i]) { appendVertex(filtered, result[i]); } @@ -251,18 +251,18 @@ class Simplify coord_t importance(const Polygonal& polygon, const std::vector& to_delete, const size_t index, const bool is_closed) const { const size_t poly_size = polygon.size(); - if(!is_closed && (index == 0 || index == poly_size - 1)) + if (! is_closed && (index == 0 || index == poly_size - 1)) { - return std::numeric_limits::max(); //Endpoints of the polyline must always be retained. + return std::numeric_limits::max(); // Endpoints of the polyline must always be retained. } - //From here on out we can safely look at the vertex neighbors and assume it's a polygon. We won't go out of bounds of the polyline. + // From here on out we can safely look at the vertex neighbors and assume it's a polygon. We won't go out of bounds of the polyline. const Point& vertex = getPosition(polygon[index]); const size_t before_index = previousNotDeleted(index, to_delete); const size_t after_index = nextNotDeleted(index, to_delete); const coord_t area_deviation = getAreaDeviation(polygon[before_index], polygon[index], polygon[after_index]); - if(area_deviation > max_area_deviation) //Removing this line causes the variable line width to get flattened out too much. + if (area_deviation > max_area_deviation) // Removing this line causes the variable line width to get flattened out too much. { return std::numeric_limits::max(); } @@ -270,13 +270,13 @@ class Simplify const Point& before = getPosition(polygon[before_index]); const Point& after = getPosition(polygon[after_index]); const coord_t deviation2 = LinearAlg2D::getDist2FromLine(vertex, before, after); - if(deviation2 <= min_resolution * min_resolution) //Deviation so small that it's always desired to remove them. + if (deviation2 <= min_resolution * min_resolution) // Deviation so small that it's always desired to remove them. { return deviation2; } - if(vSize2(before - vertex) > max_resolution * max_resolution && vSize2(after - vertex) > max_resolution * max_resolution) + if (vSize2(before - vertex) > max_resolution * max_resolution && vSize2(after - vertex) > max_resolution * max_resolution) { - return std::numeric_limits::max(); //Long line segments, no need to remove this one. + return std::numeric_limits::max(); // Long line segments, no need to remove this one. } return deviation2; } @@ -300,10 +300,10 @@ class Simplify template bool remove(Polygonal& polygon, std::vector& to_delete, const size_t vertex, const coord_t deviation2, const bool is_closed) const { - if(deviation2 <= min_resolution * min_resolution) + if (deviation2 <= min_resolution * min_resolution) { - //At less than the minimum resolution we're always allowed to delete the vertex. - //Even if the adjacent line segments are very long. + // At less than the minimum resolution we're always allowed to delete the vertex. + // Even if the adjacent line segments are very long. to_delete[vertex] = true; return true; } @@ -316,22 +316,22 @@ class Simplify const coord_t length2_before = vSize2(vertex_position - before_position); const coord_t length2_after = vSize2(vertex_position - after_position); - if(length2_before <= max_resolution * max_resolution && length2_after <= max_resolution * max_resolution) //Both adjacent line segments are short. + if (length2_before <= max_resolution * max_resolution && length2_after <= max_resolution * max_resolution) // Both adjacent line segments are short. { - //Removing this vertex does little harm. No long lines will be shifted. + // Removing this vertex does little harm. No long lines will be shifted. to_delete[vertex] = true; return true; } - //Otherwise, one edge next to this vertex is longer than max_resolution. The other is shorter. - //In this case we want to remove the short edge by replacing it with a vertex where the two surrounding edges intersect. - //Find the two line segments surrounding the short edge here ("before" and "after" edges). + // Otherwise, one edge next to this vertex is longer than max_resolution. The other is shorter. + // In this case we want to remove the short edge by replacing it with a vertex where the two surrounding edges intersect. + // Find the two line segments surrounding the short edge here ("before" and "after" edges). Point before_from, before_to, after_from, after_to; - if(length2_before <= length2_after) //Before is the shorter line. + if (length2_before <= length2_after) // Before is the shorter line. { - if(!is_closed && before == 0) //No edge before the short edge. + if (! is_closed && before == 0) // No edge before the short edge. { - return false; //Edge cannot be deleted without shifting a long edge. Don't remove anything. + return false; // Edge cannot be deleted without shifting a long edge. Don't remove anything. } const size_t before_before = previousNotDeleted(before, to_delete); before_from = getPosition(polygon[before_before]); @@ -341,9 +341,9 @@ class Simplify } else { - if(!is_closed && after == polygon.size() - 1) //No edge after the short edge. + if (! is_closed && after == polygon.size() - 1) // No edge after the short edge. { - return false; //Edge cannot be deleted without shifting a long edge. Don't remove anything. + return false; // Edge cannot be deleted without shifting a long edge. Don't remove anything. } const size_t after_after = nextNotDeleted(after, to_delete); before_from = getPosition(polygon[before]); @@ -353,12 +353,12 @@ class Simplify } Point intersection; const bool did_intersect = LinearAlg2D::lineLineIntersection(before_from, before_to, after_from, after_to, intersection); - if(!did_intersect) //Lines are parallel. + if (! did_intersect) // Lines are parallel. { - return false; //Cannot remove edge without shifting a long edge. Don't remove anything. + return false; // Cannot remove edge without shifting a long edge. Don't remove anything. } const coord_t intersection_deviation = LinearAlg2D::getDist2FromLineSegment(before_to, intersection, after_from); - if(intersection_deviation <= max_deviation * max_deviation) //Intersection point doesn't deviate too much. Use it! + if (intersection_deviation <= max_deviation * max_deviation) // Intersection point doesn't deviate too much. Use it! { to_delete[vertex] = true; polygon[length2_before <= length2_after ? before : after] = createIntersection(polygon[before], intersection, polygon[after]); @@ -490,6 +490,6 @@ class Simplify coord_t getAreaDeviation(const ExtrusionJunction& before, const ExtrusionJunction& vertex, const ExtrusionJunction& after) const; }; -} //namespace cura +} // namespace cura -#endif //UTILS_SIMPLIFY_H +#endif // UTILS_SIMPLIFY_H diff --git a/include/utils/polygonUtils.h b/include/utils/polygonUtils.h index cebfc08884..fd3c51f3a8 100644 --- a/include/utils/polygonUtils.h +++ b/include/utils/polygonUtils.h @@ -1,20 +1,20 @@ -//Copyright (c) 2021 Ultimaker B.V. -//CuraEngine is released under the terms of the AGPLv3 or higher. +// Copyright (c) 2021 Ultimaker B.V. +// CuraEngine is released under the terms of the AGPLv3 or higher. #ifndef UTILS_POLYGON_UTILS_H #define UTILS_POLYGON_UTILS_H +#include "PolygonsPointIndex.h" +#include "SparseLineGrid.h" +#include "SparsePointGridInclusive.h" +#include "polygon.h" + #include // function #include -#include #include // unique_ptr +#include -#include "polygon.h" -#include "SparsePointGridInclusive.h" -#include "SparseLineGrid.h" -#include "PolygonsPointIndex.h" - -namespace cura +namespace cura { /*! @@ -26,10 +26,23 @@ struct ClosestPolygonPoint ConstPolygonPointer poly; //!< Polygon in which the result was found (or nullptr if no result was found) unsigned int poly_idx; //!< The index of the polygon in some Polygons where ClosestPolygonPoint::poly can be found unsigned int point_idx; //!< Index to the first point in the polygon of the line segment on which the result was found - ClosestPolygonPoint(Point p, int pos, ConstPolygonRef poly) : location(p), poly(poly), poly_idx(NO_INDEX), point_idx(pos) {}; - ClosestPolygonPoint(Point p, int pos, ConstPolygonRef poly, int poly_idx) : location(p), poly(poly), poly_idx(poly_idx), point_idx(pos) {}; - ClosestPolygonPoint(ConstPolygonRef poly) : poly(poly), poly_idx(NO_INDEX), point_idx(NO_INDEX) {}; - ClosestPolygonPoint() : poly_idx(NO_INDEX), point_idx(NO_INDEX) {}; + ClosestPolygonPoint(Point p, int pos, ConstPolygonRef poly) + : location(p) + , poly(poly) + , poly_idx(NO_INDEX) + , point_idx(pos){}; + ClosestPolygonPoint(Point p, int pos, ConstPolygonRef poly, int poly_idx) + : location(p) + , poly(poly) + , poly_idx(poly_idx) + , point_idx(pos){}; + ClosestPolygonPoint(ConstPolygonRef poly) + : poly(poly) + , poly_idx(NO_INDEX) + , point_idx(NO_INDEX){}; + ClosestPolygonPoint() + : poly_idx(NO_INDEX) + , point_idx(NO_INDEX){}; Point p() const { // conformity with other classes return location; @@ -50,7 +63,7 @@ struct ClosestPolygonPoint namespace std { -template <> +template<> struct hash { size_t operator()(const cura::ClosestPolygonPoint& cpp) const @@ -58,12 +71,12 @@ struct hash return std::hash()(cpp.p()); } }; -}//namespace std +} // namespace std namespace std { -template +template struct hash> { size_t operator()(const std::pair& pair) const @@ -71,7 +84,7 @@ struct hash> return 31 * std::hash()(pair.first) + 59 * std::hash()(pair.second); } }; -}//namespace std +} // namespace std namespace cura @@ -88,18 +101,18 @@ struct GivenDistPoint typedef SparseLineGrid LocToLineGrid; -class PolygonUtils +class PolygonUtils { public: static const std::function no_penalty_function; //!< Function always returning zero /*! * compute the length of a segment of a polygon - * + * * if \p end == \p start then the full polygon is taken - * + * * \warning assumes that start and end lie on the same polygon! - * + * * \param start The start vertex of the segment * \param end the end vertex of the segment * \return the total length of all the line segments in between the two vertices. @@ -108,12 +121,12 @@ class PolygonUtils /*! * Generate evenly spread out dots along a segment of a polygon - * + * * Start at a distance from \p start and end at a distance from \p end, * unless \p end == \p start; then that point is in the result - * + * * \warning Assumes that start and end lie on the same polygon! - * + * * \param start The start vertex of the segment * \param end the end vertex of the segment * \param n_dots number of dots to spread out @@ -131,48 +144,54 @@ class PolygonUtils /*! * Whether a polygon intersects with a line-segment. If true, the closest collision point to 'b' is stored in the result. */ - static bool lineSegmentPolygonsIntersection(const Point& a, const Point& b, const Polygons& current_outlines, const LocToLineGrid& outline_locator, Point& result, const coord_t within_max_dist); + static bool lineSegmentPolygonsIntersection( + const Point& a, + const Point& b, + const Polygons& current_outlines, + const LocToLineGrid& outline_locator, + Point& result, + const coord_t within_max_dist); /*! * Get the normal of a boundary point, pointing outward. * Only the direction is set. * Nothing is said about the length of the vector returned. - * + * * \param poly The polygon. * \param point_idx The index of the point in the polygon. */ static Point getVertexInwardNormal(ConstPolygonRef poly, unsigned int point_idx); /*! - * Get a point from the \p poly with a given \p offset. - * - * \param poly The polygon. - * \param point_idx The index of the point in the polygon. - * \param offset The distance the point has to be moved outward from the polygon. - * \return A point at the given distance inward from the point on the boundary polygon. - */ + * Get a point from the \p poly with a given \p offset. + * + * \param poly The polygon. + * \param point_idx The index of the point in the polygon. + * \param offset The distance the point has to be moved outward from the polygon. + * \return A point at the given distance inward from the point on the boundary polygon. + */ static Point getBoundaryPointWithOffset(ConstPolygonRef poly, unsigned int point_idx, int64_t offset); /*! * Move a point away from the boundary by looking at the boundary normal of the nearest vert. - * + * * \param point_on_boundary The object holding the point on the boundary along with the information of which line segment the point is on. * \param offset The distance the point has to be moved inward from the polygon. */ static Point moveInsideDiagonally(ClosestPolygonPoint point_on_boundary, int64_t inset); /*! - * Moves the point \p from onto the nearest polygon or leaves the point as-is, when the comb boundary is not within the root of \p max_dist2 distance. - * Given a \p distance more than zero, the point will end up inside, and conversely outside. - * When the point is already in/outside by more than \p distance, \p from is unaltered, but the polygon is returned. - * When the point is in/outside by less than \p distance, \p from is moved to the correct place. - * - * \param polygons The polygons onto which to move the point - * \param from[in,out] The point to move. - * \param distance The distance by which to move the point. - * \param max_dist2 The squared maximal allowed distance from the point to the nearest polygon. - * \return The index to the polygon onto which we have moved the point. - */ + * Moves the point \p from onto the nearest polygon or leaves the point as-is, when the comb boundary is not within the root of \p max_dist2 distance. + * Given a \p distance more than zero, the point will end up inside, and conversely outside. + * When the point is already in/outside by more than \p distance, \p from is unaltered, but the polygon is returned. + * When the point is in/outside by less than \p distance, \p from is moved to the correct place. + * + * \param polygons The polygons onto which to move the point + * \param from[in,out] The point to move. + * \param distance The distance by which to move the point. + * \param max_dist2 The squared maximal allowed distance from the point to the nearest polygon. + * \return The index to the polygon onto which we have moved the point. + */ static unsigned int moveInside(const Polygons& polygons, Point& from, int distance = 0, int64_t max_dist2 = std::numeric_limits::max()); /** @@ -198,11 +217,11 @@ class PolygonUtils * Given a \p distance more than zero, the point will end up inside, and conversely outside. * When the point is already in/outside by more than \p distance, \p from is unaltered, but the polygon is returned. * When the point is in/outside by less than \p distance, \p from is moved to the correct place. - * + * * \warning If \p loc_to_line_grid is used, it's best to have all and only \p polygons in there. * If \p from is not closest to \p polygons this function may * return a ClosestPolygonPoint on a polygon in \p loc_to_line_grid which is not in \p polygons. - * + * * \param polygons The polygons onto which to move the point * \param from[in,out] The point to move. * \param distance The distance by which to move the point. @@ -212,18 +231,25 @@ class PolygonUtils * \param penalty_function A function returning a penalty term on the squared distance score of a candidate point. * \return The point on the polygon closest to \p from */ - static ClosestPolygonPoint moveInside2(const Polygons& polygons, Point& from, const int distance = 0, const int64_t max_dist2 = std::numeric_limits::max(), const Polygons* loc_to_line_polygons = nullptr, const LocToLineGrid* loc_to_line_grid = nullptr, const std::function& penalty_function = no_penalty_function); + static ClosestPolygonPoint moveInside2( + const Polygons& polygons, + Point& from, + const int distance = 0, + const int64_t max_dist2 = std::numeric_limits::max(), + const Polygons* loc_to_line_polygons = nullptr, + const LocToLineGrid* loc_to_line_grid = nullptr, + const std::function& penalty_function = no_penalty_function); /*! * Moves the point \p from onto the nearest segment of \p polygon or leaves the point as-is, when the comb boundary is not within the root of \p max_dist2 distance. * Given a \p distance more than zero, the point will end up inside, and conversely outside. * When the point is already in/outside by more than \p distance, \p from is unaltered, but the polygon is returned. * When the point is in/outside by less than \p distance, \p from is moved to the correct place. - * + * * \warning When a \p loc_to_line is given this function only considers nearby elements. * Even when the penalty function favours elements farther away. * Also using the \p loc_to_line_grid automatically considers \p all_polygons - * + * * \param loc_to_line_polygons All polygons which are present in the \p loc_to_line_grid of which \p polygon is an element * \param polygon The polygon onto which to move the point * \param from[in,out] The point to move. @@ -233,16 +259,23 @@ class PolygonUtils * \param penalty_function A function returning a penalty term on the squared distance score of a candidate point. * \return The point on the polygon closest to \p from */ - static ClosestPolygonPoint moveInside2(const Polygons& loc_to_line_polygons, ConstPolygonRef polygon, Point& from, const int distance = 0, const int64_t max_dist2 = std::numeric_limits::max(), const LocToLineGrid* loc_to_line_grid = nullptr, const std::function& penalty_function = no_penalty_function); + static ClosestPolygonPoint moveInside2( + const Polygons& loc_to_line_polygons, + ConstPolygonRef polygon, + Point& from, + const int distance = 0, + const int64_t max_dist2 = std::numeric_limits::max(), + const LocToLineGrid* loc_to_line_grid = nullptr, + const std::function& penalty_function = no_penalty_function); /*! * The opposite of moveInside. - * + * * Moves the point \p from onto the nearest polygon or leaves the point as-is, when the comb boundary is not within \p distance. * Given a \p distance more than zero, the point will end up outside, and conversely inside. * When the point is already in/outside by more than \p distance, \p from is unaltered, but the polygon is returned. * When the point is in/outside by less than \p distance, \p from is moved to the correct place. - * + * * \param polygons The polygons onto which to move the point * \param from[in,out] The point to move. * \param distance The distance by which to move the point. @@ -251,23 +284,23 @@ class PolygonUtils * \return The index to the polygon onto which we have moved the point. */ static unsigned int moveOutside(const Polygons& polygons, Point& from, int distance = 0, int64_t max_dist2 = std::numeric_limits::max()); - + /*! * Compute a point at a distance from a point on the boundary in orthogonal direction to the boundary. * Given a \p distance more than zero, the point will end up inside, and conversely outside. - * + * * \param cpp The object holding the point on the boundary along with the information of which line segment the point is on. * \param distance The distance by which to move the point. * \return A point at a \p distance from the point in \p cpp orthogonal to the boundary there. */ static Point moveInside(const ClosestPolygonPoint& cpp, const int distance); - + /*! * The opposite of moveInside. - * + * * Compute a point at a distance from a point on the boundary in orthogonal direction to the boundary. * Given a \p distance more than zero, the point will end up outside, and conversely inside. - * + * * \param cpp The object holding the point on the boundary along with the information of which line segment the point is on. * \param distance The distance by which to move the point. * \return A point at a \p distance from the point in \p cpp orthogonal to the boundary there. @@ -279,15 +312,15 @@ class PolygonUtils * Given a \p distance more than zero, the point will end up inside, and conversely outside. * When the point is already in/outside by more than \p distance, \p from is unaltered, but the polygon is returned. * When the point is in/outside by less than \p distance, \p from is moved to the correct place. - * + * * \warning May give false positives. - * Some checking is done to make sure we end up inside the polygon, + * Some checking is done to make sure we end up inside the polygon, * but it might still be the case that we end up outside: * when the closest point on the boundary is very close to another polygon - * + * * \warning When using a \p loc_to_line_grid which contains more polygons than just \p polygons, * the results is only correct if \p from is already closest to \p polygons, rather than other polygons in the \p loc_to_line_grid. - * + * * \param polygons The polygons onto which to move the point * \param from[in,out] The point to move. * \param preferred_dist_inside The preferred distance from the boundary to the point @@ -297,22 +330,29 @@ class PolygonUtils * \param penalty_function A function returning a penalty term on the squared distance score of a candidate point. * \return The point on the polygon closest to \p from */ - static ClosestPolygonPoint ensureInsideOrOutside(const Polygons& polygons, Point& from, int preferred_dist_inside, int64_t max_dist2 = std::numeric_limits::max(), const Polygons* loc_to_line_polygons = nullptr, const LocToLineGrid* loc_to_line_grid = nullptr, const std::function& penalty_function = no_penalty_function); + static ClosestPolygonPoint ensureInsideOrOutside( + const Polygons& polygons, + Point& from, + int preferred_dist_inside, + int64_t max_dist2 = std::numeric_limits::max(), + const Polygons* loc_to_line_polygons = nullptr, + const LocToLineGrid* loc_to_line_grid = nullptr, + const std::function& penalty_function = no_penalty_function); /*! * Moves the point \p from onto the nearest polygon or leaves the point as-is, when the comb boundary is not within \p distance. * Given a \p distance more than zero, the point will end up inside, and conversely outside. * When the point is already in/outside by more than \p distance, \p from is unaltered, but the polygon is returned. * When the point is in/outside by less than \p distance, \p from is moved to the correct place. - * + * * \warning May give false positives. - * Some checking is done to make sure we end up inside the polygon, + * Some checking is done to make sure we end up inside the polygon, * but it might still be the case that we end up outside: * when the closest point on the boundary is very close to another polygon - * + * * \warning When using a \p loc_to_line_grid which contains more polygons than just \p polygons, * the results is only correct if \p from is already closest to \p polygons, rather than other polygons in the \p loc_to_line_grid. - * + * * \param polygons The polygons onto which to move the point * \param from[in,out] The point to move. * \param closest_polygon_point The point on \p polygons closest to \p from @@ -322,49 +362,56 @@ class PolygonUtils * \param penalty_function A function returning a penalty term on the squared distance score of a candidate point. * \return The point on the polygon closest to \p from */ - static ClosestPolygonPoint ensureInsideOrOutside(const Polygons& polygons, Point& from, const ClosestPolygonPoint& closest_polygon_point, int preferred_dist_inside, const Polygons* loc_to_line_polygons = nullptr, const LocToLineGrid* loc_to_line_grid = nullptr, const std::function& penalty_function = no_penalty_function); + static ClosestPolygonPoint ensureInsideOrOutside( + const Polygons& polygons, + Point& from, + const ClosestPolygonPoint& closest_polygon_point, + int preferred_dist_inside, + const Polygons* loc_to_line_polygons = nullptr, + const LocToLineGrid* loc_to_line_grid = nullptr, + const std::function& penalty_function = no_penalty_function); /*! - * - * \warning Assumes \p poly1_result and \p poly2_result have their pos and poly fields initialized! - */ + * + * \warning Assumes \p poly1_result and \p poly2_result have their pos and poly fields initialized! + */ static void walkToNearestSmallestConnection(ClosestPolygonPoint& poly1_result, ClosestPolygonPoint& poly2_result); /*! - * Find the nearest closest point on a polygon from a given index. - * - * \param from The point from which to get the smallest distance. - * \param polygon The polygon on which to find the point with the smallest distance. - * \param start_idx The index of the point in the polygon from which to start looking. - * \return The nearest point from \p start_idx going along the \p polygon (in both directions) with a locally minimal distance to \p from. - */ + * Find the nearest closest point on a polygon from a given index. + * + * \param from The point from which to get the smallest distance. + * \param polygon The polygon on which to find the point with the smallest distance. + * \param start_idx The index of the point in the polygon from which to start looking. + * \return The nearest point from \p start_idx going along the \p polygon (in both directions) with a locally minimal distance to \p from. + */ static ClosestPolygonPoint findNearestClosest(Point from, ConstPolygonRef polygon, int start_idx); /*! - * Find the nearest closest point on a polygon from a given index walking in one direction along the polygon. - * - * \param from The point from which to get the smallest distance. - * \param polygon The polygon on which to find the point with the smallest distance. - * \param start_idx The index of the point in the polygon from which to start looking. - * \param direction The direction to walk: 1 for walking along the \p polygon, -1 for walking in opposite direction - * \return The nearest point from \p start_idx going along the \p polygon with a locally minimal distance to \p from. - */ + * Find the nearest closest point on a polygon from a given index walking in one direction along the polygon. + * + * \param from The point from which to get the smallest distance. + * \param polygon The polygon on which to find the point with the smallest distance. + * \param start_idx The index of the point in the polygon from which to start looking. + * \param direction The direction to walk: 1 for walking along the \p polygon, -1 for walking in opposite direction + * \return The nearest point from \p start_idx going along the \p polygon with a locally minimal distance to \p from. + */ static ClosestPolygonPoint findNearestClosest(const Point from, ConstPolygonRef polygon, int start_idx, int direction); /*! * Find the point closest to \p from in all polygons in \p polygons. - * + * * \note The penalty term is applied to the *squared* distance score - * + * * \param penalty_function A function returning a penalty term on the squared distance score of a candidate point. */ static ClosestPolygonPoint findClosest(Point from, const Polygons& polygons, const std::function& penalty_function = no_penalty_function); - + /*! * Find the point closest to \p from in the polygon \p polygon. - * + * * \note The penalty term is applied to the *squared* distance score - * + * * \param penalty_function A function returning a penalty term on the squared distance score of a candidate point. */ static ClosestPolygonPoint findClosest(Point from, ConstPolygonRef polygon, const std::function& penalty_function = no_penalty_function); @@ -387,9 +434,9 @@ class PolygonUtils /*! * Create a SparsePointGridInclusive mapping from locations to line segments occurring in the \p polygons - * + * * \warning The caller of this function is responsible for deleting the returned object - * + * * \param polygons The polygons for which to create the mapping * \param square_size The cell size used to bundle line segments (also used to chop up lines so that multiple cells contain the same long line) * \return A bucket grid mapping spatial locations to poly-point indices into \p polygons @@ -398,57 +445,63 @@ class PolygonUtils /*! * Find the line segment closest to a given point \p from within a cell-block of a size defined in the SparsePointGridInclusive \p loc_to_line - * + * * \note The penalty term is applied to the *squared* distance score. * Note also that almost only nearby points are considered even when the penalty function would favour points farther away. - * + * * \param from The location to find a polygon edge close to * \param polygons The polygons for which the \p loc_to_line has been built up - * \param loc_to_line A SparsePointGridInclusive mapping locations to starting vertices of line segmetns of the \p polygons + * \param loc_to_line A SparsePointGridInclusive mapping locations to starting vertices of line segmetns of the \p polygons * \param penalty_function A function returning a penalty term on the squared distance score of a candidate point. * \return The nearest point on the polygon if the polygon was within a distance equal to the cell_size of the SparsePointGridInclusive */ - static std::optional findClose(Point from, const Polygons& polygons, const LocToLineGrid& loc_to_line, const std::function& penalty_function = no_penalty_function); + static std::optional + findClose(Point from, const Polygons& polygons, const LocToLineGrid& loc_to_line, const std::function& penalty_function = no_penalty_function); /*! * Find the line segment closest to any point on \p from within cell-blocks of a size defined in the SparsePointGridInclusive \p destination_loc_to_line - * + * * \note The penalty term is applied to the *squared* distance score. * Note also that almost only nearby points are considered even when the penalty function would favour points farther away. - * + * * \param from The polygon for which to find a polygon edge close to * \param destination The polygons for which the \p destination_loc_to_line has been built up - * \param destination_loc_to_line A SparsePointGridInclusive mapping locations to starting vertices of line segments of the \p destination + * \param destination_loc_to_line A SparsePointGridInclusive mapping locations to starting vertices of line segments of the \p destination * \param penalty_function A function returning a penalty term on the squared distance score of a candidate point. - * \return A collection of near crossing from the \p from polygon to the \p destination polygon. Each element in the sollection is a pair with as first a cpp in the \p from polygon and as second a cpp in the \p destination polygon. + * \return A collection of near crossing from the \p from polygon to the \p destination polygon. Each element in the sollection is a pair with as first a cpp in the \p from + * polygon and as second a cpp in the \p destination polygon. */ - static std::vector> findClose(ConstPolygonRef from, const Polygons& destination, const LocToLineGrid& destination_loc_to_line, const std::function& penalty_function = no_penalty_function); + static std::vector> findClose( + ConstPolygonRef from, + const Polygons& destination, + const LocToLineGrid& destination_loc_to_line, + const std::function& penalty_function = no_penalty_function); /*! * Checks whether a given line segment collides with polygons as given in a loc_to_line grid. - * + * * If the line segment doesn't intersect with any edge of the polygon, but * merely touches it, a collision is also reported. For instance, a * collision is reported when the an endpoint of the line is exactly on the * polygon, and when the line coincides with an edge. - * + * * \param[in] from The start point * \param[in] to The end point - * \param[in] loc_to_line A SparsePointGridInclusive mapping locations to starting vertices of line segmetns of the \p polygons + * \param[in] loc_to_line A SparsePointGridInclusive mapping locations to starting vertices of line segmetns of the \p polygons * \param[out] collision_result (optional) The polygons segment intersecting with the line segment * \return whether the line segment collides with the boundary of the polygons */ static bool polygonCollidesWithLineSegment(const Point from, const Point to, const LocToLineGrid& loc_to_line, PolygonsPointIndex* collision_result = nullptr); /*! - * Find the next point (going along the direction of the polygon) with a distance \p dist from the point \p from within the \p poly. - * Returns whether another point could be found within the \p poly which can be found before encountering the point at index \p start_idx. - * The point \p from and the polygon \p poly are assumed to lie on the same plane. - * - * \param from The point from whitch to find a point on the polygon satisfying the conditions - * \param start_idx the index of the prev poly point on the poly. - * \param poly_start_idx The index of the point in the polygon which is to be handled as the start of the polygon. No point further than this point will be the result. - */ + * Find the next point (going along the direction of the polygon) with a distance \p dist from the point \p from within the \p poly. + * Returns whether another point could be found within the \p poly which can be found before encountering the point at index \p start_idx. + * The point \p from and the polygon \p poly are assumed to lie on the same plane. + * + * \param from The point from whitch to find a point on the polygon satisfying the conditions + * \param start_idx the index of the prev poly point on the poly. + * \param poly_start_idx The index of the point in the polygon which is to be handled as the start of the polygon. No point further than this point will be the result. + */ static bool getNextPointWithDistance(Point from, int64_t dist, ConstPolygonRef poly, int start_idx, int poly_start_idx, GivenDistPoint& result); /*! @@ -458,10 +511,10 @@ class PolygonUtils /*! * Get the point on a polygon which intersects a line parallel to a line going through the starting point and through another point. - * + * * Note that the looking direction \p forward doesn't neccesarily determine on which side of the line we cross a parallel line. * Depending on the geometry of the polygon the next intersection may be left or right of the input line. - * + * * \param start The starting point of the search and the starting point of the line * \param line_to The end point of the line * \param dist The distance from the parallel line to the line defined by the previous two parameters @@ -474,12 +527,12 @@ class PolygonUtils * Checks whether a given line segment collides with a given polygon(s). * The transformed_startPoint and transformed_endPoint should have the same * Y coordinate. - * + * * If the line segment doesn't intersect with any edge of the polygon, but * merely touches it, a collision is also reported. For instance, a * collision is reported when the an endpoint of the line is exactly on the * polygon, and when the line coincides with an edge. - * + * * \param poly The polygon * \param transformed_startPoint The start point transformed such that it is * on the same horizontal line as the end point @@ -494,12 +547,12 @@ class PolygonUtils /*! * Checks whether a given line segment collides with a given polygon(s). - * + * * If the line segment doesn't intersect with any edge of the polygon, but * merely touches it, a collision is also reported. For instance, a * collision is reported when the an endpoint of the line is exactly on the * polygon, and when the line coincides with an edge. - * + * * \param poly The polygon * \param startPoint The start point * \param endPoint The end point @@ -512,12 +565,12 @@ class PolygonUtils * Checks whether a given line segment collides with a given polygon(s). * The transformed_startPoint and transformed_endPoint should have the same * Y coordinate. - * + * * If the line segment doesn't intersect with any edge of the polygon, but * merely touches it, a collision is also reported. For instance, a * collision is reported when the an endpoint of the line is exactly on the * polygon, and when the line coincides with an edge. - * + * * \param poly The polygon * \param transformed_startPoint The start point transformed such that it is * on the same horizontal line as the end point @@ -532,12 +585,12 @@ class PolygonUtils /*! * Checks whether a given line segment collides with a given polygon(s). - * + * * If the line segment doesn't intersect with any edge of the polygon, but * merely touches it, a collision is also reported. For instance, a * collision is reported when the an endpoint of the line is exactly on the * polygon, and when the line coincides with an edge. - * + * * \param poly The polygon * \param startPoint The start point * \param endPoint The end point @@ -573,7 +626,11 @@ class PolygonUtils * \param[in] possible_adjacent_polys The vector of polygons we are testing. * \param[in] max_gap Polygons must be closer together than this distance to be considered adjacent. */ - static void findAdjacentPolygons(std::vector& adjacent_poly_indices, const ConstPolygonRef& poly, const std::vector& possible_adjacent_polys, const coord_t max_gap); + static void findAdjacentPolygons( + std::vector& adjacent_poly_indices, + const ConstPolygonRef& poly, + const std::vector& possible_adjacent_polys, + const coord_t max_gap); /*! * Calculate the Hamming Distance between two polygons relative to their own @@ -599,7 +656,7 @@ class PolygonUtils * \param a_step The angle between segments of the circle. * \return A new Polygon containing the circle. */ - static Polygon makeCircle(const Point &mid, const coord_t radius, const AngleRadians a_step = M_PI / 8); + static Polygon makeCircle(const Point& mid, const coord_t radius, const AngleRadians a_step = M_PI / 8); /*! * Create a "wheel" shape. @@ -612,7 +669,7 @@ class PolygonUtils * \param arc_angle_resolution The number of segment on each arc. * \return A new Polygon containing the circle. */ - static Polygon makeWheel(const Point &mid, const coord_t inner_radius, const coord_t outer_radius, const size_t semi_nb_spokes, const size_t arc_angle_resolution); + static Polygon makeWheel(const Point& mid, const coord_t inner_radius, const coord_t outer_radius, const size_t semi_nb_spokes, const size_t arc_angle_resolution); /*! * Connect all polygons to their holes using zero widths hole channels, so that the polygons and their outlines are connected together @@ -634,8 +691,9 @@ class PolygonUtils private: /*! - * Helper function for PolygonUtils::moveInside2: moves a point \p from which was moved onto \p closest_polygon_point towards inside/outside when it's not already inside/outside by enough distance. - * + * Helper function for PolygonUtils::moveInside2: moves a point \p from which was moved onto \p closest_polygon_point towards inside/outside when it's not already + * inside/outside by enough distance. + * * \param closest_polygon_point The ClosestPolygonPoint we have to move inside * \param distance The distance by which to move the point. * \param from[in,out] The point to move. @@ -646,6 +704,6 @@ class PolygonUtils }; -}//namespace cura +} // namespace cura -#endif//POLYGON_OPTIMIZER_H +#endif // POLYGON_OPTIMIZER_H diff --git a/include/utils/types/get.h b/include/utils/types/get.h index 4df9c0f494..a1b6774aa8 100644 --- a/include/utils/types/get.h +++ b/include/utils/types/get.h @@ -103,7 +103,9 @@ constexpr auto& get(cura::utils::point3d auto& point) noexcept { constexpr std::string_view idx = C.value; static_assert(idx.size() == 1, "Only one character allowed"); - static_assert(idx.starts_with("X") || idx.starts_with("x") || idx.starts_with("Y") || idx.starts_with("y") || idx.starts_with("Z") || idx.starts_with("z"), "Index out of bounds"); + static_assert( + idx.starts_with("X") || idx.starts_with("x") || idx.starts_with("Y") || idx.starts_with("y") || idx.starts_with("Z") || idx.starts_with("z"), + "Index out of bounds"); if constexpr (idx.starts_with("X") || idx.starts_with("x")) { return std::get<0>(point); diff --git a/include/utils/views/dfs.h b/include/utils/views/dfs.h index 0d509b8004..268e4d5f33 100644 --- a/include/utils/views/dfs.h +++ b/include/utils/views/dfs.h @@ -4,11 +4,11 @@ #ifndef CURAENGINE_DFS_SORT_H #define CURAENGINE_DFS_SORT_H +#include "utils/types/graph.h" + #include #include -#include "utils/types/graph.h" - namespace cura::actions { /* # dfs utility @@ -39,14 +39,14 @@ std::function(const Node, const Graph&)> get_neighbours = [](c }; template -constexpr void dfs( - const Node& current_node, - const Graph& graph, - std::function handle_node, - std::unordered_set& visited, - const State& state = nullptr, - std::function(const Node, const Graph&)> get_neighbours = details::get_neighbours -) { +constexpr void + dfs(const Node& current_node, + const Graph& graph, + std::function handle_node, + std::unordered_set& visited, + const State& state = nullptr, + std::function(const Node, const Graph&)> get_neighbours = details::get_neighbours) +{ if (visited.contains(current_node)) { return; diff --git a/src/Application.cpp b/src/Application.cpp index c5a3a6f102..2209118a2b 100644 --- a/src/Application.cpp +++ b/src/Application.cpp @@ -3,25 +3,25 @@ #include "Application.h" -#include -#include -#include +#include "FffProcessor.h" +#include "communication/ArcusCommunication.h" //To connect via Arcus to the front-end. +#include "communication/CommandLine.h" //To use the command line to slice stuff. +#include "progress/Progress.h" +#include "utils/ThreadPool.h" +#include "utils/string.h" //For stringcasecompare. #include #include +#include +#include +#include #include #include #include -#include -#include -#include -#include "FffProcessor.h" -#include "communication/ArcusCommunication.h" //To connect via Arcus to the front-end. -#include "communication/CommandLine.h" //To use the command line to slice stuff. -#include "progress/Progress.h" -#include "utils/ThreadPool.h" -#include "utils/string.h" //For stringcasecompare. +#include +#include +#include namespace cura { @@ -32,7 +32,8 @@ Application::Application() auto base_sink = std::make_shared(); dup_sink->add_sink(base_sink); - spdlog::default_logger()->sinks() = std::vector>{ dup_sink }; // replace default_logger sinks with the duplicating filtering sink to avoid spamming + spdlog::default_logger()->sinks() + = std::vector>{ dup_sink }; // replace default_logger sinks with the duplicating filtering sink to avoid spamming if (auto spdlog_val = spdlog::details::os::getenv("CURAENGINE_LOG_LEVEL"); ! spdlog_val.empty()) { @@ -135,9 +136,11 @@ void Application::printHelp() const fmt::print(" -o \n\tSpecify a file to which to write the generated gcode.\n"); fmt::print("\n"); fmt::print("The settings are appended to the last supplied object:\n"); - fmt::print("CuraEngine slice [general settings] \n\t-g [current group settings] \n\t-e0 [extruder train 0 settings] \n\t-l obj_inheriting_from_last_extruder_train.stl [object settings] \n\t--next [next group settings]\n\t... etc.\n"); + fmt::print("CuraEngine slice [general settings] \n\t-g [current group settings] \n\t-e0 [extruder train 0 settings] \n\t-l obj_inheriting_from_last_extruder_train.stl [object " + "settings] \n\t--next [next group settings]\n\t... etc.\n"); fmt::print("\n"); - fmt::print("In order to load machine definitions from custom locations, you need to create the environment variable CURA_ENGINE_SEARCH_PATH, which should contain all search paths delimited by a (semi-)colon.\n"); + fmt::print("In order to load machine definitions from custom locations, you need to create the environment variable CURA_ENGINE_SEARCH_PATH, which should contain all search " + "paths delimited by a (semi-)colon.\n"); fmt::print("\n"); } diff --git a/src/MeshGroup.cpp b/src/MeshGroup.cpp index 1516e64190..3376e07c7e 100644 --- a/src/MeshGroup.cpp +++ b/src/MeshGroup.cpp @@ -1,16 +1,8 @@ // Copyright (c) 2023 UltiMaker // CuraEngine is released under the terms of the AGPLv3 or higher -#include -#include -#include - -#include -#include -#include -#include - #include "MeshGroup.h" + #include "settings/types/Ratio.h" //For the shrinkage percentage and scale factor. #include "utils/FMatrix4x3.h" //To transform the input meshes for shrinkage compensation and to align in command line mode. #include "utils/floatpoint.h" //To accept incoming meshes with floating point vertices. @@ -18,6 +10,15 @@ #include "utils/section_type.h" #include "utils/string.h" +#include +#include +#include +#include + +#include +#include +#include + namespace cura { @@ -48,7 +49,8 @@ Point3 MeshGroup::min() const Point3 ret(std::numeric_limits::max(), std::numeric_limits::max(), std::numeric_limits::max()); for (const Mesh& mesh : meshes) { - if (mesh.settings.get("infill_mesh") || mesh.settings.get("cutting_mesh") || mesh.settings.get("anti_overhang_mesh")) // Don't count pieces that are not printed. + if (mesh.settings.get("infill_mesh") || mesh.settings.get("cutting_mesh") + || mesh.settings.get("anti_overhang_mesh")) // Don't count pieces that are not printed. { continue; } @@ -69,7 +71,8 @@ Point3 MeshGroup::max() const Point3 ret(std::numeric_limits::min(), std::numeric_limits::min(), std::numeric_limits::min()); for (const Mesh& mesh : meshes) { - if (mesh.settings.get("infill_mesh") || mesh.settings.get("cutting_mesh") || mesh.settings.get("anti_overhang_mesh")) // Don't count pieces that are not printed. + if (mesh.settings.get("infill_mesh") || mesh.settings.get("cutting_mesh") + || mesh.settings.get("anti_overhang_mesh")) // Don't count pieces that are not printed. { continue; } @@ -112,7 +115,9 @@ void MeshGroup::finalize() } mesh.translate(mesh_offset + meshgroup_offset); } - scaleFromBottom(settings.get("material_shrinkage_percentage_xy"), settings.get("material_shrinkage_percentage_z")); // Compensate for the shrinkage of the material. + scaleFromBottom( + settings.get("material_shrinkage_percentage_xy"), + settings.get("material_shrinkage_percentage_z")); // Compensate for the shrinkage of the material. for (const auto& [idx, mesh] : meshes | ranges::views::enumerate) { scripta::log(fmt::format("mesh_{}", idx), mesh, SectionType::NA); diff --git a/src/SupportInfillPart.cpp b/src/SupportInfillPart.cpp index 76344af468..b53d50e251 100644 --- a/src/SupportInfillPart.cpp +++ b/src/SupportInfillPart.cpp @@ -2,17 +2,18 @@ // CuraEngine is released under the terms of the AGPLv3 or higher. #include "SupportInfillPart.h" + #include "support.h" using namespace cura; SupportInfillPart::SupportInfillPart(const PolygonsPart& outline, coord_t support_line_width, int inset_count_to_generate, coord_t custom_line_distance) -: outline(outline) -, outline_boundary_box(outline) -, support_line_width(support_line_width) -, inset_count_to_generate(inset_count_to_generate) -, custom_line_distance(custom_line_distance) + : outline(outline) + , outline_boundary_box(outline) + , support_line_width(support_line_width) + , inset_count_to_generate(inset_count_to_generate) + , custom_line_distance(custom_line_distance) { infill_area_per_combine_per_density.clear(); } diff --git a/src/TreeSupport.cpp b/src/TreeSupport.cpp index 5c7585cfbb..3421751024 100644 --- a/src/TreeSupport.cpp +++ b/src/TreeSupport.cpp @@ -2,6 +2,7 @@ // CuraEngine is released under the terms of the AGPLv3 or higher #include "TreeSupport.h" + #include "Application.h" //To get settings. #include "TreeSupportTipGenerator.h" #include "TreeSupportUtils.h" @@ -17,20 +18,20 @@ #include "utils/polygonUtils.h" //For moveInside. #include "utils/section_type.h" -#include -#include -#include #include #include #include #include +#include #include + +#include +#include +#include #include #include #include -#include - namespace cura { @@ -40,10 +41,10 @@ TreeSupport::TreeSupport(const SliceDataStorage& storage) for (const SliceMeshStorage& mesh : storage.meshes) { - TreeSupportSettings::some_model_contains_thick_roof |= - mesh.settings.get("support_roof_height") >= 2 * mesh.settings.get("layer_height"); - TreeSupportSettings::has_to_rely_on_min_xy_dist_only |= - mesh.settings.get("support_top_distance") == 0 || mesh.settings.get("support_bottom_distance") == 0 || mesh.settings.get("min_feature_size") < (FUDGE_LENGTH * 2); + TreeSupportSettings::some_model_contains_thick_roof |= mesh.settings.get("support_roof_height") >= 2 * mesh.settings.get("layer_height"); + TreeSupportSettings::has_to_rely_on_min_xy_dist_only |= mesh.settings.get("support_top_distance") == 0 + || mesh.settings.get("support_bottom_distance") == 0 + || mesh.settings.get("min_feature_size") < (FUDGE_LENGTH * 2); } // Group all meshes that can be processed together. NOTE this is different from mesh-groups! @@ -66,8 +67,10 @@ TreeSupport::TreeSupport(const SliceDataStorage& storage) { added = true; grouped_mesh.second.emplace_back(mesh_idx); - // Handle some settings that are only used for performance reasons. This ensures that a horrible set setting intended to improve performance can not reduce it drastically. - grouped_mesh.first.performance_interface_skip_layers = std::min(grouped_mesh.first.performance_interface_skip_layers, next_settings.performance_interface_skip_layers); + // Handle some settings that are only used for performance reasons. This ensures that a horrible set setting intended to improve performance can not reduce it + // drastically. + grouped_mesh.first.performance_interface_skip_layers + = std::min(grouped_mesh.first.performance_interface_skip_layers, next_settings.performance_interface_skip_layers); } } if (! added) @@ -93,8 +96,7 @@ TreeSupport::TreeSupport(const SliceDataStorage& storage) mesh.first.setActualZ(known_z); } - placed_support_lines_support_areas = std::vector(storage.support.supportLayers.size(),Polygons()); - + placed_support_lines_support_areas = std::vector(storage.support.supportLayers.size(), Polygons()); } void TreeSupport::generateSupportAreas(SliceDataStorage& storage) @@ -110,12 +112,14 @@ void TreeSupport::generateSupportAreas(SliceDataStorage& storage) } // Process every mesh group. These groups can not be processed parallel, as the processing in each group is parallelized, and nested parallelization is disables and slow. - for (auto [counter, processing] : grouped_meshes | ranges::views::enumerate ) + for (auto [counter, processing] : grouped_meshes | ranges::views::enumerate) { // process each combination of meshes - std::vector> move_bounds(storage.support.supportLayers.size()); // Value is the area where support may be placed. As this is calculated in CreateLayerPathing it is saved and reused in drawAreas. + std::vector> move_bounds( + storage.support.supportLayers + .size()); // Value is the area where support may be placed. As this is calculated in CreateLayerPathing it is saved and reused in drawAreas. - additional_required_support_area=std::vector(storage.support.supportLayers.size(),Polygons()); + additional_required_support_area = std::vector(storage.support.supportLayers.size(), Polygons()); spdlog::info("Processing support tree mesh group {} of {} containing {} meshes.", counter + 1, grouped_meshes.size(), grouped_meshes[counter].second.size()); @@ -123,8 +127,7 @@ void TreeSupport::generateSupportAreas(SliceDataStorage& storage) auto t_start = std::chrono::high_resolution_clock::now(); // get all already existing support areas and exclude them - cura::parallel_for - ( + cura::parallel_for( LayerIndex(0), LayerIndex(storage.support.supportLayers.size()), [&](const LayerIndex layer_idx) @@ -138,12 +141,20 @@ void TreeSupport::generateSupportAreas(SliceDataStorage& storage) } exclude[layer_idx] = exlude_at_layer.unionPolygons(); scripta::log("tree_support_exclude", exclude[layer_idx], SectionType::SUPPORT, layer_idx); - } - ); - config = processing.first; // This struct is used to easy retrieve setting. No other function except those in TreeModelVolumes and generateInitialAreas have knowledge of the existence of multiple meshes being processed. + }); + config = processing.first; // This struct is used to easy retrieve setting. No other function except those in TreeModelVolumes and generateInitialAreas have knowledge of + // the existence of multiple meshes being processed. progress_multiplier = 1.0 / double(grouped_meshes.size()); progress_offset = counter == 0 ? 0 : TREE_PROGRESS_TOTAL * (double(counter) * progress_multiplier); - volumes_ = TreeModelVolumes(storage, config.maximum_move_distance, config.maximum_move_distance_slow, config.support_line_width / 2, processing.second.front(), progress_multiplier, progress_offset, exclude); + volumes_ = TreeModelVolumes( + storage, + config.maximum_move_distance, + config.maximum_move_distance_slow, + config.support_line_width / 2, + processing.second.front(), + progress_multiplier, + progress_offset, + exclude); // ### Precalculate avoidances, collision etc. precalculate(storage, processing.second); @@ -174,19 +185,18 @@ void TreeSupport::generateSupportAreas(SliceDataStorage& storage) const auto dur_place = 0.001 * std::chrono::duration_cast(t_place - t_path).count(); const auto dur_draw = 0.001 * std::chrono::duration_cast(t_draw - t_place).count(); const auto dur_total = 0.001 * std::chrono::duration_cast(t_draw - t_start).count(); - spdlog::info - ( + spdlog::info( "Total time used creating Tree support for the currently grouped meshes: {} ms. Different subtasks:\n" - "Calculating Avoidance: {} ms Creating inital influence areas: {} ms Influence area creation: {} ms Placement of Points in InfluenceAreas: {} ms Drawing result as support {} ms", + "Calculating Avoidance: {} ms Creating inital influence areas: {} ms Influence area creation: {} ms Placement of Points in InfluenceAreas: {} ms Drawing result as " + "support {} ms", dur_total, dur_pre_gen, dur_gen, dur_path, dur_place, - dur_draw - ); + dur_draw); + - for (auto& layer : move_bounds) { for (auto elem : layer) @@ -210,7 +220,7 @@ void TreeSupport::precalculate(const SliceDataStorage& storage, std::vector("layer_height"); const coord_t z_distance_top = mesh.settings.get("support_top_distance"); const size_t z_distance_top_layers = round_up_divide(z_distance_top, - layer_height) + 1; // Support must always be 1 layer below overhang. + layer_height) + 1; // Support must always be 1 layer below overhang. if (mesh.overhang_areas.size() <= z_distance_top_layers) { continue; @@ -220,7 +230,7 @@ void TreeSupport::precalculate(const SliceDataStorage& storage, std::vector max_layer) // iterates over multiple meshes { @@ -242,8 +252,7 @@ void TreeSupport::generateInitialAreas(const SliceMeshStorage& mesh, std::vector tip_gen.generateTips(storage, mesh, move_bounds, additional_required_support_area, placed_support_lines_support_areas); } -void TreeSupport::mergeHelper -( +void TreeSupport::mergeHelper( std::map& reduced_aabb, std::map& input_aabb, const PropertyAreasUnordered& to_bp_areas, @@ -252,12 +261,14 @@ void TreeSupport::mergeHelper PropertyAreasUnordered& insert_bp_areas, PropertyAreasUnordered& insert_model_areas, PropertyAreasUnordered& insert_influence, - std::vector& erase, const LayerIndex layer_idx -) + std::vector& erase, + const LayerIndex layer_idx) { const bool first_merge_iteration = reduced_aabb.empty(); // If this is the first iteration, all elements in input have to be merged with each other - const std::function getRadiusFunction = - [&](const size_t distance_to_top, const double buildplate_radius_increases) { return config.getRadius(distance_to_top, buildplate_radius_increases); }; + const std::function getRadiusFunction = [&](const size_t distance_to_top, const double buildplate_radius_increases) + { + return config.getRadius(distance_to_top, buildplate_radius_increases); + }; for (auto& influence : input_aabb) { bool merged = false; @@ -269,7 +280,7 @@ void TreeSupport::mergeHelper AABB aabb = reduced_check.second; if (aabb.hit(influence_aabb)) { - if (!first_merge_iteration && input_aabb.count(reduced_check.first)) + if (! first_merge_iteration && input_aabb.count(reduced_check.first)) { break; // Do not try to merge elements that already should have been merged. Done for potential performance improvement. } @@ -278,14 +289,15 @@ void TreeSupport::mergeHelper // ^^^ We do not want to merge a gracious with a non gracious area as bad placement could negatively impact the dependability of the whole subtree. const bool merging_to_bp = reduced_check.first.to_buildplate && influence.first.to_buildplate; const bool merging_min_and_regular_xy = reduced_check.first.use_min_xy_dist != influence.first.use_min_xy_dist; - // ^^^ Could cause some issues with the increase of one area, as it is assumed that if the smaller is increased by the delta to the larger it is engulfed by it already. + // ^^^ Could cause some issues with the increase of one area, as it is assumed that if the smaller is increased by the delta to the larger it is engulfed by it + // already. // But because a different collision may be removed from the in drawArea generated circles, this assumption could be wrong. - const bool merging_different_range_limits = - reduced_check.first.influence_area_limit_active && influence.first.influence_area_limit_active && influence.first.influence_area_limit_range != reduced_check.first.influence_area_limit_range; + const bool merging_different_range_limits = reduced_check.first.influence_area_limit_active && influence.first.influence_area_limit_active + && influence.first.influence_area_limit_range != reduced_check.first.influence_area_limit_range; coord_t increased_to_model_radius = 0; size_t larger_to_model_dtt = 0; - if (!merging_to_bp) + if (! merging_to_bp) { const coord_t infl_radius = config.getRadius(influence.first); // Get the real radius increase as the user does not care for the collision model. const coord_t redu_radius = config.getRadius(reduced_check.first); @@ -311,14 +323,9 @@ void TreeSupport::mergeHelper // If a merge could place a stable branch on unstable ground, would be increasing the radius further than allowed to when merging to model and to_bp trees or // would merge to model before it is known they will even been drawn the merge is skipped - if - ( - merging_min_and_regular_xy || - merging_gracious_and_non_gracious || - increased_to_model_radius > config.max_to_model_radius_increase || - (!merging_to_bp && larger_to_model_dtt < config.min_dtt_to_model && !reduced_check.first.supports_roof && !influence.first.supports_roof) || - merging_different_range_limits - ) + if (merging_min_and_regular_xy || merging_gracious_and_non_gracious || increased_to_model_radius > config.max_to_model_radius_increase + || (! merging_to_bp && larger_to_model_dtt < config.min_dtt_to_model && ! reduced_check.first.supports_roof && ! influence.first.supports_roof) + || merging_different_range_limits) { continue; } @@ -327,41 +334,29 @@ void TreeSupport::mergeHelper Polygons relevant_redu; if (merging_to_bp) { - relevant_infl = to_bp_areas.count(influence.first) ? to_bp_areas.at(influence.first) : Polygons(); // influence.first is a new element => not required to check if it was changed - relevant_redu = - insert_bp_areas.count - ( - reduced_check.first) ? - insert_bp_areas[reduced_check.first] : - (to_bp_areas.count(reduced_check.first) ? to_bp_areas.at(reduced_check.first) : Polygons() - ); + relevant_infl = to_bp_areas.count(influence.first) ? to_bp_areas.at(influence.first) + : Polygons(); // influence.first is a new element => not required to check if it was changed + relevant_redu = insert_bp_areas.count(reduced_check.first) ? insert_bp_areas[reduced_check.first] + : (to_bp_areas.count(reduced_check.first) ? to_bp_areas.at(reduced_check.first) : Polygons()); } else { relevant_infl = to_model_areas.count(influence.first) ? to_model_areas.at(influence.first) : Polygons(); - relevant_redu = - insert_model_areas.count - ( - reduced_check.first) ? - insert_model_areas[reduced_check.first] : - (to_model_areas.count(reduced_check.first) ? to_model_areas.at(reduced_check.first) : Polygons() - ); + relevant_redu = insert_model_areas.count(reduced_check.first) + ? insert_model_areas[reduced_check.first] + : (to_model_areas.count(reduced_check.first) ? to_model_areas.at(reduced_check.first) : Polygons()); } const bool red_bigger = config.getCollisionRadius(reduced_check.first) > config.getCollisionRadius(influence.first); - std::pair smaller_rad = - red_bigger ? - std::pair(influence.first, relevant_infl) : - std::pair(reduced_check.first, relevant_redu); - std::pair bigger_rad = - red_bigger ? - std::pair(reduced_check.first, relevant_redu) : - std::pair(influence.first, relevant_infl); + std::pair smaller_rad = red_bigger ? std::pair(influence.first, relevant_infl) + : std::pair(reduced_check.first, relevant_redu); + std::pair bigger_rad = red_bigger ? std::pair(reduced_check.first, relevant_redu) + : std::pair(influence.first, relevant_infl); const coord_t real_radius_delta = std::abs(config.getRadius(bigger_rad.first) - config.getRadius(smaller_rad.first)); const coord_t smaller_collision_radius = config.getCollisionRadius(smaller_rad.first); // the area of the bigger radius is used to ensure correct placement regarding the relevant avoidance, so if that would change an invalid area may be created - if (!bigger_rad.first.can_use_safe_radius && smaller_rad.first.can_use_safe_radius) + if (! bigger_rad.first.can_use_safe_radius && smaller_rad.first.can_use_safe_radius) { continue; } @@ -376,23 +371,23 @@ void TreeSupport::mergeHelper // a branch (of the larger collision radius) placed in this intersection, has already engulfed the branch of the smaller collision radius. // Because of this a merge may happen even if the influence areas (that represent possible center points of branches) do not intersect yet. // Remember that collision radius <= real radius as otherwise this assumption would be false. - const Polygons small_rad_increased_by_big_minus_small = - TreeSupportUtils::safeOffsetInc - ( - smaller_rad.second, - real_radius_delta, volumes_.getCollision(smaller_collision_radius, layer_idx - 1, use_min_radius), - 2 * (config.xy_distance + smaller_collision_radius - EPSILON), // Epsilon avoids possible rounding errors - 0, - 0, - config.support_line_distance / 2, - &config.simplifier - ); + const Polygons small_rad_increased_by_big_minus_small = TreeSupportUtils::safeOffsetInc( + smaller_rad.second, + real_radius_delta, + volumes_.getCollision(smaller_collision_radius, layer_idx - 1, use_min_radius), + 2 * (config.xy_distance + smaller_collision_radius - EPSILON), // Epsilon avoids possible rounding errors + 0, + 0, + config.support_line_distance / 2, + &config.simplifier); Polygons intersect = small_rad_increased_by_big_minus_small.intersection(bigger_rad.second); - if (intersect.area() > 1) // dont use empty as a line is not empty, but for this use-case it very well may be (and would be one layer down as union does not keep lines) + if (intersect.area() + > 1) // dont use empty as a line is not empty, but for this use-case it very well may be (and would be one layer down as union does not keep lines) { - // Check if the overlap is large enough (Small ares tend to attract rounding errors in clipper). While 25 was guessed as enough, i did not have reason to change it. - if (intersect.offset(-FUDGE_LENGTH/2).area() <= 1) + // Check if the overlap is large enough (Small ares tend to attract rounding errors in clipper). While 25 was guessed as enough, i did not have reason to change + // it. + if (intersect.offset(-FUDGE_LENGTH / 2).area() <= 1) { continue; } @@ -413,8 +408,7 @@ void TreeSupport::mergeHelper increased_to_model_radius = std::max(reduced_check.first.increased_to_model_radius, influence.first.increased_to_model_radius); } - const TreeSupportElement key - ( + const TreeSupportElement key( reduced_check.first, influence.first, layer_idx - 1, @@ -423,31 +417,30 @@ void TreeSupport::mergeHelper getRadiusFunction, config.diameter_scale_bp_radius, config.branch_radius, - config.diameter_angle_scale_factor - ); + config.diameter_angle_scale_factor); - const auto getIntersectInfluence = - [&] (const PropertyAreasUnordered& insert_infl, const PropertyAreas& infl_areas) - { - const Polygons infl_small = insert_infl.count(smaller_rad.first) ? insert_infl.at(smaller_rad.first) : (infl_areas.count(smaller_rad.first) ? infl_areas.at(smaller_rad.first) : Polygons()); - const Polygons infl_big = insert_infl.count(bigger_rad.first) ? insert_infl.at(bigger_rad.first) : (infl_areas.count(bigger_rad.first) ? infl_areas.at(bigger_rad.first) : Polygons()); - const Polygons small_rad_increased_by_big_minus_small_infl = - TreeSupportUtils::safeOffsetInc - ( - infl_small, - real_radius_delta, - volumes_.getCollision(smaller_collision_radius, layer_idx - 1, use_min_radius), - 2 * (config.xy_distance + smaller_collision_radius - EPSILON), - 0, - 0, - config.support_line_distance / 2, - &config.simplifier - ); - return small_rad_increased_by_big_minus_small_infl.intersection(infl_big); // If the one with the bigger radius with the lower radius removed overlaps we can merge. - }; + const auto getIntersectInfluence = [&](const PropertyAreasUnordered& insert_infl, const PropertyAreas& infl_areas) + { + const Polygons infl_small = insert_infl.count(smaller_rad.first) ? insert_infl.at(smaller_rad.first) + : (infl_areas.count(smaller_rad.first) ? infl_areas.at(smaller_rad.first) : Polygons()); + const Polygons infl_big = insert_infl.count(bigger_rad.first) ? insert_infl.at(bigger_rad.first) + : (infl_areas.count(bigger_rad.first) ? infl_areas.at(bigger_rad.first) : Polygons()); + const Polygons small_rad_increased_by_big_minus_small_infl = TreeSupportUtils::safeOffsetInc( + infl_small, + real_radius_delta, + volumes_.getCollision(smaller_collision_radius, layer_idx - 1, use_min_radius), + 2 * (config.xy_distance + smaller_collision_radius - EPSILON), + 0, + 0, + config.support_line_distance / 2, + &config.simplifier); + return small_rad_increased_by_big_minus_small_infl.intersection( + infl_big); // If the one with the bigger radius with the lower radius removed overlaps we can merge. + }; Polygons intersect_influence; - intersect_influence = TreeSupportUtils::safeUnion(intersect, getIntersectInfluence(insert_influence, influence_areas)); // Rounding errors again. Do not ask me where or why. + intersect_influence + = TreeSupportUtils::safeUnion(intersect, getIntersectInfluence(insert_influence, influence_areas)); // Rounding errors again. Do not ask me where or why. Polygons intersect_to_model; if (merging_to_bp && config.support_rests_on_model) @@ -473,8 +466,10 @@ void TreeSupport::mergeHelper erase.emplace_back(reduced_check.first); erase.emplace_back(influence.first); - const Polygons merge = intersect.unionPolygons(intersect_to_model).offset(config.getRadius(key), ClipperLib::jtRound).difference(volumes_.getCollision(0, layer_idx - 1)); - // ^^^ Regular union should be preferable here as Polygons tend to only become smaller through rounding errors (smaller!=has smaller area as holes have a negative area.). + const Polygons merge + = intersect.unionPolygons(intersect_to_model).offset(config.getRadius(key), ClipperLib::jtRound).difference(volumes_.getCollision(0, layer_idx - 1)); + // ^^^ Regular union should be preferable here as Polygons tend to only become smaller through rounding errors (smaller!=has smaller area as holes have a + // negative area.). // And if this area disappears because of rounding errors, the only downside is that it can not merge again on this layer. reduced_aabb.erase(reduced_check.first); // This invalidates reduced_check. @@ -493,13 +488,7 @@ void TreeSupport::mergeHelper } } -void TreeSupport::mergeInfluenceAreas -( - PropertyAreasUnordered& to_bp_areas, - PropertyAreas& to_model_areas, - PropertyAreas& influence_areas, - LayerIndex layer_idx -) +void TreeSupport::mergeInfluenceAreas(PropertyAreasUnordered& to_bp_areas, PropertyAreas& to_model_areas, PropertyAreas& influence_areas, LayerIndex layer_idx) { /* * Idea behind this is that the calculation of merges can be accelerated a bit using divide and conquer: @@ -519,13 +508,15 @@ void TreeSupport::mergeInfluenceAreas // max_bucket_count is input_size/min_elements_per_bucket round down to the next 2^n. // The rounding to 2^n is to ensure improved performance, as every iteration two buckets will be merged, halving the amount of buckets. - // If halving would cause an uneven count, e.g. 3 Then bucket 0 and 1 would have to be merged, and in the next iteration the last remaining buckets. This is assumed to not be optimal performance-wise. + // If halving would cause an uneven count, e.g. 3 Then bucket 0 and 1 would have to be merged, and in the next iteration the last remaining buckets. This is assumed to not be + // optimal performance-wise. const size_t max_bucket_count = std::pow(2, std::floor(std::log(round_up_divide(input_size, min_elements_per_bucket)))); int bucket_count = std::min(max_bucket_count, num_threads); // do not use more buckets than available threads. // To achieve that every element in a bucket is already correctly merged with other elements in this bucket // an extra empty bucket is created for each bucket, and the elements are merged into the empty one. - // Each thread will then process two buckets by merging all elements in the second bucket into the first one as mergeHelper will disable not trying to merge elements from the same bucket in this case. + // Each thread will then process two buckets by merging all elements in the second bucket into the first one as mergeHelper will disable not trying to merge elements from the + // same bucket in this case. std::vector buckets_area(2 * bucket_count); std::vector> buckets_aabb(2 * bucket_count); @@ -549,8 +540,7 @@ void TreeSupport::mergeInfluenceAreas } // Precalculate the AABBs from the influence areas. - cura::parallel_for - ( + cura::parallel_for( 0, buckets_area.size() / 2, [&](size_t idx) // +=2 as in the beginning only uneven buckets will be filled @@ -562,8 +552,7 @@ void TreeSupport::mergeInfluenceAreas outer_support_wall_aabb.expand(config.getRadius(input_pair.first)); buckets_aabb[idx].emplace(input_pair.first, outer_support_wall_aabb); } - } - ); + }); while (buckets_area.size() > 1) { @@ -573,16 +562,14 @@ void TreeSupport::mergeInfluenceAreas std::vector insert_influence(buckets_area.size() / 2); std::vector> erase(buckets_area.size() / 2); - cura::parallel_for - ( + cura::parallel_for( 0, (coord_t)buckets_area.size() / 2, [&](size_t bucket_pair_idx) { bucket_pair_idx *= 2; // this is eqivalent to a parallel for(size_t idx=0;idx x) mutable { return x.empty(); }); + const auto position_aabb = std::remove_if( + buckets_aabb.begin(), + buckets_aabb.end(), + [&](const std::map x) mutable + { + return x.empty(); + }); buckets_aabb.erase(position_aabb, buckets_aabb.end()); } } -std::optional TreeSupport::increaseSingleArea -( +std::optional TreeSupport::increaseSingleArea( AreaIncreaseSettings settings, LayerIndex layer_idx, TreeSupportElement* parent, const Polygons& relevant_offset, - Polygons& to_bp_data, Polygons& to_model_data, + Polygons& to_bp_data, + Polygons& to_model_data, Polygons& increased, const coord_t overspeed, - const bool mergelayer -) + const bool mergelayer) { TreeSupportElement current_elem(parent); // Also increases DTT by one. Polygons check_layer_data; @@ -657,22 +653,19 @@ std::optional TreeSupport::increaseSingleArea increased = relevant_offset; if (overspeed > 0) { - const coord_t safe_movement_distance = - (current_elem.use_min_xy_dist ? config.xy_min_distance : config.xy_distance) + (std::min(config.z_distance_top_layers, config.z_distance_bottom_layers) > 0 ? config.min_feature_size : 0); + const coord_t safe_movement_distance = (current_elem.use_min_xy_dist ? config.xy_min_distance : config.xy_distance) + + (std::min(config.z_distance_top_layers, config.z_distance_bottom_layers) > 0 ? config.min_feature_size : 0); // The difference to ensure that the result not only conforms to wall_restriction, but collision/avoidance is done later. // The higher last_safe_step_movement_distance comes exactly from the fact that the collision will be subtracted later. - increased = - TreeSupportUtils::safeOffsetInc - ( - increased, - overspeed, - volumes_.getWallRestriction(config.getCollisionRadius(*parent), layer_idx, parent->use_min_xy_dist), - safe_movement_distance, - safe_movement_distance + radius, - 1, - config.support_line_distance / 2, - nullptr - ); + increased = TreeSupportUtils::safeOffsetInc( + increased, + overspeed, + volumes_.getWallRestriction(config.getCollisionRadius(*parent), layer_idx, parent->use_min_xy_dist), + safe_movement_distance, + safe_movement_distance + radius, + 1, + config.support_line_distance / 2, + nullptr); } if (settings.no_error && settings.move) { @@ -709,7 +702,8 @@ std::optional TreeSupport::increaseSingleArea } else { - to_model_data = TreeSupportUtils::safeUnion(increased.difference(volumes_.getAvoidance(radius, layer_idx - 1, AvoidanceType::COLLISION, true, settings.use_min_distance))); + to_model_data + = TreeSupportUtils::safeUnion(increased.difference(volumes_.getAvoidance(radius, layer_idx - 1, AvoidanceType::COLLISION, true, settings.use_min_distance))); } } } @@ -718,29 +712,35 @@ std::optional TreeSupport::increaseSingleArea if (settings.increase_radius && check_layer_data.area() > 1) { - std::function validWithRadius = - [&](coord_t next_radius) + std::function validWithRadius = [&](coord_t next_radius) + { + if (volumes_.ceilRadius(next_radius, settings.use_min_distance) <= volumes_.ceilRadius(radius, settings.use_min_distance)) { - if (volumes_.ceilRadius(next_radius, settings.use_min_distance) <= volumes_.ceilRadius(radius, settings.use_min_distance)) - { - return true; - } + return true; + } - Polygons to_bp_data_2; - if (current_elem.to_buildplate) - { - // Regular union as output will not be used later => this area should always be a subset of the safeUnion one. - to_bp_data_2 = increased.difference(volumes_.getAvoidance(next_radius, layer_idx - 1, settings.type, false, settings.use_min_distance)).unionPolygons(); - } - Polygons to_model_data_2; - if (config.support_rests_on_model && !current_elem.to_buildplate) - { - to_model_data_2 = increased.difference(volumes_.getAvoidance(next_radius, layer_idx - 1, current_elem.to_model_gracious? settings.type:AvoidanceType::COLLISION, true, settings.use_min_distance)).unionPolygons(); - } - Polygons check_layer_data_2 = current_elem.to_buildplate ? to_bp_data_2 : to_model_data_2; + Polygons to_bp_data_2; + if (current_elem.to_buildplate) + { + // Regular union as output will not be used later => this area should always be a subset of the safeUnion one. + to_bp_data_2 = increased.difference(volumes_.getAvoidance(next_radius, layer_idx - 1, settings.type, false, settings.use_min_distance)).unionPolygons(); + } + Polygons to_model_data_2; + if (config.support_rests_on_model && ! current_elem.to_buildplate) + { + to_model_data_2 = increased + .difference(volumes_.getAvoidance( + next_radius, + layer_idx - 1, + current_elem.to_model_gracious ? settings.type : AvoidanceType::COLLISION, + true, + settings.use_min_distance)) + .unionPolygons(); + } + Polygons check_layer_data_2 = current_elem.to_buildplate ? to_bp_data_2 : to_model_data_2; - return check_layer_data_2.area() > 1; - }; + return check_layer_data_2.area() > 1; + }; coord_t ceil_radius_before = volumes_.ceilRadius(radius, settings.use_min_distance); // If the Collision Radius is smaller than the actual radius, check if it can catch up without violating the avoidance. @@ -754,18 +754,15 @@ std::optional TreeSupport::increaseSingleArea current_ceil_radius = volumes_.getRadiusNextCeil(current_ceil_radius + 1, settings.use_min_distance); } size_t resulting_eff_dtt = current_elem.effective_radius_height; - while - ( - resulting_eff_dtt + 1 < current_elem.distance_to_top && - config.getRadius(resulting_eff_dtt + 1, current_elem.buildplate_radius_increases) <= current_ceil_radius && - config.getRadius(resulting_eff_dtt + 1, current_elem.buildplate_radius_increases) <= config.getRadius(current_elem) - ) + while (resulting_eff_dtt + 1 < current_elem.distance_to_top && config.getRadius(resulting_eff_dtt + 1, current_elem.buildplate_radius_increases) <= current_ceil_radius + && config.getRadius(resulting_eff_dtt + 1, current_elem.buildplate_radius_increases) <= config.getRadius(current_elem)) { resulting_eff_dtt++; } current_elem.effective_radius_height = resulting_eff_dtt; - // If catchup is not possible, it is likely that there is a hole below. Assuming the branches are in some kind of bowl, the branches should still stay away from the wall of the bowl if possible. + // If catchup is not possible, it is likely that there is a hole below. Assuming the branches are in some kind of bowl, the branches should still stay away from the + // wall of the bowl if possible. if (config.getCollisionRadius(current_elem) < config.increase_radius_until_radius && config.getCollisionRadius(current_elem) < config.getRadius(current_elem)) { Polygons new_to_bp_data; @@ -779,7 +776,7 @@ std::optional TreeSupport::increaseSingleArea to_bp_data = new_to_bp_data; } } - if (config.support_rests_on_model && (!current_elem.to_buildplate || mergelayer)) + if (config.support_rests_on_model && (! current_elem.to_buildplate || mergelayer)) { new_to_model_data = to_model_data.difference(volumes_.getCollision(config.getRadius(current_elem), layer_idx - 1, current_elem.use_min_xy_dist)); if (new_to_model_data.area() > EPSILON) @@ -788,21 +785,24 @@ std::optional TreeSupport::increaseSingleArea } } } - } radius = config.getCollisionRadius(current_elem); const coord_t foot_radius_increase = config.branch_radius * (std::max(config.diameter_scale_bp_radius - config.diameter_angle_scale_factor, 0.0)); const double planned_foot_increase = std::min(1.0, double(config.recommendedMinRadius(layer_idx - 1) - config.getRadius(current_elem)) / foot_radius_increase); - // ^^^ Is nearly all of the time 1, but sometimes an increase of 1 could cause the radius to become bigger than recommendedMinRadius, which could cause the radius to become bigger than precalculated. + // ^^^ Is nearly all of the time 1, but sometimes an increase of 1 could cause the radius to become bigger than recommendedMinRadius, which could cause the radius to become + // bigger than precalculated. - // If the support_rest_preference is GRACEFUL, increase buildplate_radius_increases anyway. This does ONLY affect the CollisionRadius, as the regular radius only includes the buildplate_radius_increases when the SupportElement is to_buildplate (which it can not be when support_rest_preference is GRACEFUL). - // If the branch later rests on the buildplate the to_buildplate flag will only need to be updated to ensure that the radius is also correctly increased. - // Downside is that the enlargement of the CollisionRadius can cause branches, that could rest on the model if the radius was not increased, to instead rest on the buildplate. - // A better way could be changing avoidance to model to not include the buildplate and then calculate avoidances by combining the to model avoidance without the radius increase with the to buildplate avoidance with the larger radius. - // This would require ensuring all requests for the avoidance would have to ensure that the correct hybrid avoidance is requested (which would only be relevant when support_rest_preference is GRACEFUL) - // Also unioning areas when an avoidance is requested may also have a relevant performance impact, so there can be an argument made that the current workaround is preferable. - const bool increase_bp_foot = planned_foot_increase > 0 && (current_elem.to_buildplate || (current_elem.to_model_gracious && config.support_rest_preference == RestPreference::GRACEFUL)); + // If the support_rest_preference is GRACEFUL, increase buildplate_radius_increases anyway. This does ONLY affect the CollisionRadius, as the regular radius only includes + // the buildplate_radius_increases when the SupportElement is to_buildplate (which it can not be when support_rest_preference is GRACEFUL). If the branch later rests on the + // buildplate the to_buildplate flag will only need to be updated to ensure that the radius is also correctly increased. Downside is that the enlargement of the + // CollisionRadius can cause branches, that could rest on the model if the radius was not increased, to instead rest on the buildplate. A better way could be changing + // avoidance to model to not include the buildplate and then calculate avoidances by combining the to model avoidance without the radius increase with the to buildplate + // avoidance with the larger radius. This would require ensuring all requests for the avoidance would have to ensure that the correct hybrid avoidance is requested (which + // would only be relevant when support_rest_preference is GRACEFUL) Also unioning areas when an avoidance is requested may also have a relevant performance impact, so there + // can be an argument made that the current workaround is preferable. + const bool increase_bp_foot + = planned_foot_increase > 0 && (current_elem.to_buildplate || (current_elem.to_model_gracious && config.support_rest_preference == RestPreference::GRACEFUL)); if (increase_bp_foot && config.getRadius(current_elem) >= config.branch_radius && config.getRadius(current_elem) >= config.increase_radius_until_radius) @@ -820,26 +820,30 @@ std::optional TreeSupport::increaseSingleArea { to_bp_data = TreeSupportUtils::safeUnion(increased.difference(volumes_.getAvoidance(radius, layer_idx - 1, settings.type, false, settings.use_min_distance))); } - if (config.support_rests_on_model && (!current_elem.to_buildplate || mergelayer)) + if (config.support_rests_on_model && (! current_elem.to_buildplate || mergelayer)) { - to_model_data = TreeSupportUtils::safeUnion(increased.difference(volumes_.getAvoidance(radius, layer_idx - 1, current_elem.to_model_gracious? settings.type:AvoidanceType::COLLISION, true, settings.use_min_distance))); + to_model_data = TreeSupportUtils::safeUnion(increased.difference( + volumes_.getAvoidance(radius, layer_idx - 1, current_elem.to_model_gracious ? settings.type : AvoidanceType::COLLISION, true, settings.use_min_distance))); } check_layer_data = current_elem.to_buildplate ? to_bp_data : to_model_data; if (check_layer_data.area() < 1) { - spdlog::error("Lost area by doing catch up from {} to radius {}", ceil_radius_before, volumes_.ceilRadius(config.getCollisionRadius(current_elem), settings.use_min_distance)); + spdlog::error( + "Lost area by doing catch up from {} to radius {}", + ceil_radius_before, + volumes_.ceilRadius(config.getCollisionRadius(current_elem), settings.use_min_distance)); } } } - if (current_elem.influence_area_limit_active && !current_elem.use_min_xy_dist && check_layer_data.area() > 1 && (current_elem.to_model_gracious || current_elem.distance_to_top <= config.min_dtt_to_model)) + if (current_elem.influence_area_limit_active && ! current_elem.use_min_xy_dist && check_layer_data.area() > 1 + && (current_elem.to_model_gracious || current_elem.distance_to_top <= config.min_dtt_to_model)) { - const coord_t max_radius_increase = - std::max - ( - static_cast((config.branch_radius - config.min_radius) / config.tip_layers), - static_cast((config.branch_radius * config.diameter_angle_scale_factor) + config.branch_radius * (std::max(config.diameter_scale_bp_radius - config.diameter_angle_scale_factor, 0.0))) - ); + const coord_t max_radius_increase = std::max( + static_cast((config.branch_radius - config.min_radius) / config.tip_layers), + static_cast( + (config.branch_radius * config.diameter_angle_scale_factor) + + config.branch_radius * (std::max(config.diameter_scale_bp_radius - config.diameter_angle_scale_factor, 0.0)))); bool limit_range_validated = false; // Rounding errors in a while loop can cause non-termination, so better safe than sorry. See https://github.com/Ultimaker/Cura/issues/14133 for an example. to_bp_data = TreeSupportUtils::safeUnion(to_bp_data); @@ -866,7 +870,7 @@ std::optional TreeSupport::increaseSingleArea limit_range_validated = true; } } - if (!limit_range_validated) + if (! limit_range_validated) { const coord_t reach_increase = std::max(current_elem.influence_area_limit_range / 4, (config.maximum_move_distance + max_radius_increase)); current_elem.influence_area_limit_range += reach_increase; @@ -878,19 +882,17 @@ std::optional TreeSupport::increaseSingleArea return check_layer_data.area() > 1 ? std::optional(current_elem) : std::optional(); } -void TreeSupport::increaseAreas -( +void TreeSupport::increaseAreas( PropertyAreasUnordered& to_bp_areas, PropertyAreas& to_model_areas, PropertyAreas& influence_areas, std::vector& bypass_merge_areas, const std::vector& last_layer, - const LayerIndex layer_idx, const bool mergelayer -) + const LayerIndex layer_idx, + const bool mergelayer) { std::mutex critical_sections; - cura::parallel_for - ( + cura::parallel_for( 0, last_layer.size(), [&](const size_t idx) @@ -910,25 +912,28 @@ void TreeSupport::increaseAreas // As the branch may have become larger the distance between these 2 walls is smaller than the distance of the center points. // These extra distance is added to the movement distance possible for this layer. - coord_t extra_speed = EPSILON; // The extra speed is added to both movement distances. Also move 5 microns faster than allowed to avoid rounding errors, this may cause issues at VERY VERY small layer heights. + coord_t extra_speed = EPSILON; // The extra speed is added to both movement distances. Also move 5 microns faster than allowed to avoid rounding errors, this may cause + // issues at VERY VERY small layer heights. coord_t extra_slow_speed = 0; // Only added to the slow movement distance. const coord_t ceiled_parent_radius = volumes_.ceilRadius(config.getCollisionRadius(*parent), parent->use_min_xy_dist); const coord_t projected_radius_increased = config.getRadius(parent->effective_radius_height + 1, parent->buildplate_radius_increases); const coord_t projected_radius_delta = projected_radius_increased - config.getCollisionRadius(*parent); - // When z distance is more than one layer up and down the Collision used to calculate the wall restriction will always include the wall (and not just the xy_min_distance) of the layer above and below like this (d = blocked area because of z distance): + // When z distance is more than one layer up and down the Collision used to calculate the wall restriction will always include the wall (and not just the + // xy_min_distance) of the layer above and below like this (d = blocked area because of z distance): /* * layer z+1:dddddiiiiiioooo * layer z+0:xxxxxdddddddddd * layer z-1:dddddxxxxxxxxxx * For more detailed visualisation see calculateWallRestrictions */ - const coord_t safe_movement_distance = - (elem.use_min_xy_dist ? config.xy_min_distance : config.xy_distance) + - (std::min(config.z_distance_top_layers, config.z_distance_bottom_layers) > 0 ? config.min_feature_size : 0); - if (ceiled_parent_radius == volumes_.ceilRadius(projected_radius_increased, parent->use_min_xy_dist) || projected_radius_increased < config.increase_radius_until_radius) + const coord_t safe_movement_distance = (elem.use_min_xy_dist ? config.xy_min_distance : config.xy_distance) + + (std::min(config.z_distance_top_layers, config.z_distance_bottom_layers) > 0 ? config.min_feature_size : 0); + if (ceiled_parent_radius == volumes_.ceilRadius(projected_radius_increased, parent->use_min_xy_dist) + || projected_radius_increased < config.increase_radius_until_radius) { - // If it is guaranteed possible to increase the radius, the maximum movement speed can be increased, as it is assumed that the maximum movement speed is the one of the slower moving wall + // If it is guaranteed possible to increase the radius, the maximum movement speed can be increased, as it is assumed that the maximum movement speed is the one of + // the slower moving wall extra_speed += projected_radius_delta; } else @@ -938,16 +943,20 @@ void TreeSupport::increaseAreas extra_slow_speed += std::min(projected_radius_delta, (config.maximum_move_distance + extra_speed) - (config.maximum_move_distance_slow + extra_slow_speed)); } - if (config.layer_start_bp_radius > layer_idx && config.recommendedMinRadius(layer_idx - 1) < config.getRadius(elem.effective_radius_height + 1, elem.buildplate_radius_increases)) + if (config.layer_start_bp_radius > layer_idx + && config.recommendedMinRadius(layer_idx - 1) < config.getRadius(elem.effective_radius_height + 1, elem.buildplate_radius_increases)) { // Can guarantee elephant foot radius increase. - if (ceiled_parent_radius == volumes_.ceilRadius(config.getRadius(parent->effective_radius_height + 1, parent->buildplate_radius_increases + 1), parent->use_min_xy_dist)) + if (ceiled_parent_radius + == volumes_.ceilRadius(config.getRadius(parent->effective_radius_height + 1, parent->buildplate_radius_increases + 1), parent->use_min_xy_dist)) { extra_speed += config.branch_radius * config.diameter_scale_bp_radius; } else { - extra_slow_speed += std::min(coord_t(config.branch_radius * config.diameter_scale_bp_radius), config.maximum_move_distance - (config.maximum_move_distance_slow + extra_slow_speed)); + extra_slow_speed += std::min( + coord_t(config.branch_radius * config.diameter_scale_bp_radius), + config.maximum_move_distance - (config.maximum_move_distance_slow + extra_slow_speed)); } } @@ -968,60 +977,70 @@ void TreeSupport::increaseAreas // Determine in which order configurations are checked if they result in a valid influence area. Check will stop if a valid area is found std::deque order; - std::function insertSetting = - [&](const AreaIncreaseSettings& settings, bool back) + std::function insertSetting = [&](const AreaIncreaseSettings& settings, bool back) + { + if (std::find(order.begin(), order.end(), settings) == order.end()) { - if (std::find(order.begin(), order.end(), settings) == order.end()) + if (back) { - if (back) - { - order.emplace_back(settings); - } - else - { - order.emplace_front(settings); - } + order.emplace_back(settings); } - }; + else + { + order.emplace_front(settings); + } + } + }; const bool parent_moved_slow = elem.last_area_increase.increase_speed < config.maximum_move_distance; const bool avoidance_speed_mismatch = parent_moved_slow && elem.last_area_increase.type != AvoidanceType::SLOW; - if - ( - elem.last_area_increase.move && - elem.last_area_increase.no_error && - elem.can_use_safe_radius && - ! mergelayer && - ! avoidance_speed_mismatch && - (elem.distance_to_top >= config.tip_layers || parent_moved_slow) - ) + if (elem.last_area_increase.move && elem.last_area_increase.no_error && elem.can_use_safe_radius && ! mergelayer && ! avoidance_speed_mismatch + && (elem.distance_to_top >= config.tip_layers || parent_moved_slow)) { // Assume that the avoidance type that was best for the parent is best for me. Makes this function about 7% faster. const auto slow_or_fast = elem.last_area_increase.increase_speed < config.maximum_move_distance ? slow_speed : fast_speed; - insertSetting(AreaIncreaseSettings(elem.last_area_increase.type, slow_or_fast, increase_radius, elem.last_area_increase.no_error, ! use_min_radius, elem.last_area_increase.move), true); - insertSetting(AreaIncreaseSettings(elem.last_area_increase.type, slow_or_fast, ! increase_radius, elem.last_area_increase.no_error, ! use_min_radius, elem.last_area_increase.move), true); + insertSetting( + AreaIncreaseSettings( + elem.last_area_increase.type, + slow_or_fast, + increase_radius, + elem.last_area_increase.no_error, + ! use_min_radius, + elem.last_area_increase.move), + true); + insertSetting( + AreaIncreaseSettings( + elem.last_area_increase.type, + slow_or_fast, + ! increase_radius, + elem.last_area_increase.no_error, + ! use_min_radius, + elem.last_area_increase.move), + true); } // Branch may still go though a hole, so a check has to be done whether the hole was already passed, and the regular avoidance can be used. if (! elem.can_use_safe_radius) { // If the radius until which it is always increased can not be guaranteed, move fast. This is to avoid holes smaller than the real branch radius. // This does not guarantee the avoidance of such holes, but ensures they are avoided if possible. - insertSetting(AreaIncreaseSettings(AvoidanceType::SLOW, slow_speed, increase_radius, no_error, ! use_min_radius, !move), true); // Did we go through the hole. + insertSetting(AreaIncreaseSettings(AvoidanceType::SLOW, slow_speed, increase_radius, no_error, ! use_min_radius, ! move), true); // Did we go through the hole. // In many cases the definition of hole is overly restrictive, so to avoid unnecessary fast movement in the tip, it is ignored there for a bit. // This CAN cause a branch to go though a hole it otherwise may have avoided. if (elem.distance_to_top < round_up_divide(config.tip_layers, 2)) { - insertSetting(AreaIncreaseSettings(AvoidanceType::FAST, slow_speed, increase_radius, no_error, ! use_min_radius, !move), true); + insertSetting(AreaIncreaseSettings(AvoidanceType::FAST, slow_speed, increase_radius, no_error, ! use_min_radius, ! move), true); } - insertSetting(AreaIncreaseSettings(AvoidanceType::FAST_SAFE, fast_speed, increase_radius, no_error, ! use_min_radius, !move), true); // Did we manage to avoid the hole, - insertSetting(AreaIncreaseSettings(AvoidanceType::FAST_SAFE, fast_speed, !increase_radius, no_error, ! use_min_radius, move), true); - insertSetting(AreaIncreaseSettings(AvoidanceType::FAST, fast_speed, !increase_radius, no_error, ! use_min_radius, move), true); + insertSetting( + AreaIncreaseSettings(AvoidanceType::FAST_SAFE, fast_speed, increase_radius, no_error, ! use_min_radius, ! move), + true); // Did we manage to avoid the hole, + insertSetting(AreaIncreaseSettings(AvoidanceType::FAST_SAFE, fast_speed, ! increase_radius, no_error, ! use_min_radius, move), true); + insertSetting(AreaIncreaseSettings(AvoidanceType::FAST, fast_speed, ! increase_radius, no_error, ! use_min_radius, move), true); } else { insertSetting(AreaIncreaseSettings(AvoidanceType::SLOW, slow_speed, increase_radius, no_error, ! use_min_radius, move), true); - // While moving fast to be able to increase the radius (b) may seems preferable (over a) this can cause the a sudden skip in movement, which looks similar to a layer shift and can reduce stability. - // As such idx have chosen to only use the user setting for radius increases as a friendly recommendation. + // While moving fast to be able to increase the radius (b) may seems preferable (over a) this can cause the a sudden skip in movement, which looks similar to a + // layer shift and can reduce stability. As such idx have chosen to only use the user setting for radius increases as a friendly recommendation. insertSetting(AreaIncreaseSettings(AvoidanceType::SLOW, slow_speed, ! increase_radius, no_error, ! use_min_radius, move), true); // a (See above.) if (elem.distance_to_top < config.tip_layers) { @@ -1044,43 +1063,48 @@ void TreeSupport::increaseAreas order = new_order; } - insertSetting(AreaIncreaseSettings(AvoidanceType::FAST, fast_speed, !increase_radius, !no_error, elem.use_min_xy_dist, move), true); //simplifying is very important for performance, but before an error is compensated by moving faster it makes sense to check to see if the simplifying has caused issues + insertSetting( + AreaIncreaseSettings(AvoidanceType::FAST, fast_speed, ! increase_radius, ! no_error, elem.use_min_xy_dist, move), + true); // simplifying is very important for performance, but before an error is compensated by moving faster it makes sense to check to see if the simplifying has + // caused issues // The getAccumulatedPlaceable0 intersection is just a quick and dirty check to see that at least a part of the branch would correctly rest on the model. - // Proper way would be to offset getAccumulatedPlaceable0 by -radius first, but the small benefit to maybe detect an error, that should not be happening anyway is not worth the performance impact in the expected case when a branch rests on the model. - if (elem.to_buildplate || (elem.to_model_gracious && (parent->area->intersection(volumes_.getPlaceableAreas(radius, layer_idx)).empty())) || (!elem.to_model_gracious && (parent->area->intersection(volumes_.getAccumulatedPlaceable0(layer_idx)).empty())) ) // Error case. + // Proper way would be to offset getAccumulatedPlaceable0 by -radius first, but the small benefit to maybe detect an error, that should not be happening anyway is not + // worth the performance impact in the expected case when a branch rests on the model. + if (elem.to_buildplate || (elem.to_model_gracious && (parent->area->intersection(volumes_.getPlaceableAreas(radius, layer_idx)).empty())) + || (! elem.to_model_gracious && (parent->area->intersection(volumes_.getAccumulatedPlaceable0(layer_idx)).empty()))) // Error case. { // It is normal that we won't be able to find a new area at some point in time if we won't be able to reach layer 0 aka have to connect with the model. - insertSetting(AreaIncreaseSettings(AvoidanceType::FAST, fast_speed * 1.5, !increase_radius, !no_error, elem.use_min_xy_dist, move), true); + insertSetting(AreaIncreaseSettings(AvoidanceType::FAST, fast_speed * 1.5, ! increase_radius, ! no_error, elem.use_min_xy_dist, move), true); } if (elem.distance_to_top < elem.dont_move_until && elem.can_use_safe_radius) // Only do not move when holes would be avoided in every case. { - insertSetting(AreaIncreaseSettings(AvoidanceType::SLOW, 0, increase_radius, no_error, !use_min_radius, !move), false); // Only do not move when already in a no hole avoidance with the regular xy distance. + insertSetting( + AreaIncreaseSettings(AvoidanceType::SLOW, 0, increase_radius, no_error, ! use_min_radius, ! move), + false); // Only do not move when already in a no hole avoidance with the regular xy distance. } Polygons inc_wo_collision; - // Check whether it is faster to calculate the area increased with the fast speed independently from the slow area, or time could be saved by reusing the slow area to calculate the fast one. - // Calculated by comparing the steps saved when calculating independently with the saved steps when not. - const bool offset_independent_faster = - (radius / safe_movement_distance - (((config.maximum_move_distance + extra_speed) < (radius + safe_movement_distance)) ? 1 : 0)) > - (round_up_divide((extra_speed + extra_slow_speed + config.maximum_move_distance_slow), safe_movement_distance)); + // Check whether it is faster to calculate the area increased with the fast speed independently from the slow area, or time could be saved by reusing the slow area to + // calculate the fast one. Calculated by comparing the steps saved when calculating independently with the saved steps when not. + const bool offset_independent_faster = (radius / safe_movement_distance - (((config.maximum_move_distance + extra_speed) < (radius + safe_movement_distance)) ? 1 : 0)) + > (round_up_divide((extra_speed + extra_slow_speed + config.maximum_move_distance_slow), safe_movement_distance)); for (AreaIncreaseSettings settings : order) { if (settings.move) { if (offset_slow.empty() && (settings.increase_speed == slow_speed || ! offset_independent_faster)) { - offset_slow = - TreeSupportUtils::safeOffsetInc - ( - *parent->area, - extra_speed + extra_slow_speed + config.maximum_move_distance_slow, - wall_restriction, - safe_movement_distance, offset_independent_faster ? safe_movement_distance + radius : 0, - 2, // Offsetting in 2 steps makes our offsetted area rounder preventing (rounding) errors created by to pointy areas. - config.support_line_distance / 2, - &config.simplifier - ).unionPolygons(); + offset_slow = TreeSupportUtils::safeOffsetInc( + *parent->area, + extra_speed + extra_slow_speed + config.maximum_move_distance_slow, + wall_restriction, + safe_movement_distance, + offset_independent_faster ? safe_movement_distance + radius : 0, + 2, // Offsetting in 2 steps makes our offsetted area rounder preventing (rounding) errors created by to pointy areas. + config.support_line_distance / 2, + &config.simplifier) + .unionPolygons(); // At this point one can see that the Polygons class was never made for precision in the single digit micron range. } @@ -1088,22 +1112,30 @@ void TreeSupport::increaseAreas { if (offset_independent_faster) { - offset_fast = - TreeSupportUtils::safeOffsetInc - ( - *parent->area, - extra_speed + config.maximum_move_distance, - wall_restriction, - safe_movement_distance, offset_independent_faster ? safe_movement_distance + radius : 0, - 1, - config.support_line_distance / 2, - &config.simplifier - ).unionPolygons(); + offset_fast = TreeSupportUtils::safeOffsetInc( + *parent->area, + extra_speed + config.maximum_move_distance, + wall_restriction, + safe_movement_distance, + offset_independent_faster ? safe_movement_distance + radius : 0, + 1, + config.support_line_distance / 2, + &config.simplifier) + .unionPolygons(); } else { const coord_t delta_slow_fast = config.maximum_move_distance - (config.maximum_move_distance_slow + extra_slow_speed); - offset_fast = TreeSupportUtils::safeOffsetInc(offset_slow, delta_slow_fast, wall_restriction, safe_movement_distance, safe_movement_distance + radius, offset_independent_faster ? 2 : 1, config.support_line_distance / 2, &config.simplifier).unionPolygons(); + offset_fast = TreeSupportUtils::safeOffsetInc( + offset_slow, + delta_slow_fast, + wall_restriction, + safe_movement_distance, + safe_movement_distance + radius, + offset_independent_faster ? 2 : 1, + config.support_line_distance / 2, + &config.simplifier) + .unionPolygons(); } } } @@ -1112,20 +1144,22 @@ void TreeSupport::increaseAreas // Check for errors! if (! settings.no_error) { - - // If the area becomes for whatever reason something that clipper sees as a line, offset would stop working, so ensure that even if if wrongly would be a line, it still actually has an area that can be increased + // If the area becomes for whatever reason something that clipper sees as a line, offset would stop working, so ensure that even if if wrongly would be a line, + // it still actually has an area that can be increased Polygons lines_offset = TreeSupportUtils::toPolylines(*parent->area).offsetPolyLine(EPSILON); Polygons base_error_area = parent->area->unionPolygons(lines_offset); result = increaseSingleArea(settings, layer_idx, parent, base_error_area, to_bp_data, to_model_data, inc_wo_collision, settings.increase_speed, mergelayer); - if(fast_speed < settings.increase_speed) + if (fast_speed < settings.increase_speed) { - spdlog::warn - ( + spdlog::warn( "Influence area could not be increased! Data about the Influence area: " - "Radius: {} at layer: {} NextTarget: {} Distance to top: {} Elephant foot increases {} use_min_xy_dist {} to buildplate {} gracious {} safe {} until move {} \n " - "Parent {}: Radius: {} at layer: {} NextTarget: {} Distance to top: {} Elephant foot increases {} use_min_xy_dist {} to buildplate {} gracious {} safe {} until move {}", - radius, layer_idx - 1, + "Radius: {} at layer: {} NextTarget: {} Distance to top: {} Elephant foot increases {} use_min_xy_dist {} to buildplate {} gracious {} safe {} until " + "move {} \n " + "Parent {}: Radius: {} at layer: {} NextTarget: {} Distance to top: {} Elephant foot increases {} use_min_xy_dist {} to buildplate {} gracious {} " + "safe {} until move {}", + radius, + layer_idx - 1, elem.next_height, elem.distance_to_top, elem.buildplate_radius_increases, @@ -1136,20 +1170,29 @@ void TreeSupport::increaseAreas elem.dont_move_until, fmt::ptr(parent), config.getCollisionRadius(*parent), - layer_idx, parent->next_height, + layer_idx, + parent->next_height, parent->distance_to_top, parent->buildplate_radius_increases, parent->use_min_xy_dist, parent->to_buildplate, parent->to_model_gracious, parent->can_use_safe_radius, - parent->dont_move_until - ); + parent->dont_move_until); } } else { - result = increaseSingleArea(settings, layer_idx, parent, settings.increase_speed == slow_speed ? offset_slow : offset_fast, to_bp_data, to_model_data, inc_wo_collision, std::max(settings.increase_speed-fast_speed,coord_t(0)), mergelayer); + result = increaseSingleArea( + settings, + layer_idx, + parent, + settings.increase_speed == slow_speed ? offset_slow : offset_fast, + to_bp_data, + to_model_data, + inc_wo_collision, + std::max(settings.increase_speed - fast_speed, coord_t(0)), + mergelayer); } if (result) @@ -1158,7 +1201,10 @@ void TreeSupport::increaseAreas radius = config.getCollisionRadius(elem); elem.last_area_increase = settings; add = true; - bypass_merge = ! settings.move || (settings.use_min_distance && elem.distance_to_top < config.tip_layers); // Do not merge if the branch should not move or the priority has to be to get farther away from the model. + bypass_merge + = ! settings.move + || (settings.use_min_distance + && elem.distance_to_top < config.tip_layers); // Do not merge if the branch should not move or the priority has to be to get farther away from the model. if (settings.move) { elem.dont_move_until = 0; @@ -1188,7 +1234,9 @@ void TreeSupport::increaseAreas if (add) { - Polygons max_influence_area = TreeSupportUtils::safeUnion(inc_wo_collision.difference(volumes_.getCollision(radius, layer_idx - 1, elem.use_min_xy_dist)), TreeSupportUtils::safeUnion(to_bp_data, to_model_data)); + Polygons max_influence_area = TreeSupportUtils::safeUnion( + inc_wo_collision.difference(volumes_.getCollision(radius, layer_idx - 1, elem.use_min_xy_dist)), + TreeSupportUtils::safeUnion(to_bp_data, to_model_data)); // ^^^ Note: union seems useless, but some rounding errors somewhere can cause to_bp_data to be slightly bigger than it should be { @@ -1220,8 +1268,7 @@ void TreeSupport::increaseAreas // A point can be set on the top most tip layer (maybe more if it should not move for a few layers). parent->result_on_layer = Point(-1, -1); } - } - ); + }); } void TreeSupport::createLayerPathing(std::vector>& move_bounds) @@ -1239,7 +1286,9 @@ void TreeSupport::createLayerPathing(std::vector>& bool new_element = false; // Ensure at least one merge operation per 3mm height, 50 layers, 1 mm movement of slow speed or 5mm movement of fast speed (whatever is lowest). Values were guessed. - size_t max_merge_every_x_layers = std::min(std::min(5000 / (std::max(config.maximum_move_distance, static_cast(100))), 1000 / std::max(config.maximum_move_distance_slow, static_cast(20))), 3000 / config.layer_height); + size_t max_merge_every_x_layers = std::min( + std::min(5000 / (std::max(config.maximum_move_distance, static_cast(100))), 1000 / std::max(config.maximum_move_distance_slow, static_cast(20))), + 3000 / config.layer_height); size_t merge_every_x_layers = 1; // Calculate the influence areas for each layer below (Top down) @@ -1257,7 +1306,8 @@ void TreeSupport::createLayerPathing(std::vector>& PropertyAreas influence_areas; // Over this map will be iterated when merging, as such it has to be ordered to ensure deterministic results. PropertyAreas to_model_areas; // The area of these SupportElement is not set, to avoid to much allocation and deallocation on the heap. PropertyAreasUnordered to_bp_areas; // Same. - std::vector bypass_merge_areas; // Different to the other maps of SupportElements as these here have the area already set, as they are already to be inserted into move_bounds. + std::vector + bypass_merge_areas; // Different to the other maps of SupportElements as these here have the area already set, as they are already to be inserted into move_bounds. const auto time_a = std::chrono::high_resolution_clock::now(); @@ -1277,7 +1327,7 @@ void TreeSupport::createLayerPathing(std::vector>& last_merge = layer_idx; reduced_by_merging = count_before_merge > influence_areas.size(); - if (! reduced_by_merging && !new_element) + if (! reduced_by_merging && ! new_element) { merge_every_x_layers = std::min(max_merge_every_x_layers, merge_every_x_layers + 1); } @@ -1332,16 +1382,21 @@ void TreeSupport::setPointsOnAreas(const TreeSupportElement* elem) for (TreeSupportElement* next_elem : elem->parents) { - if (next_elem->result_on_layer != Point(-1, -1)) // 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->result_on_layer + != Point(-1, -1)) // 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. { continue; } Point from = elem->result_on_layer; - if (!(next_elem->area->inside(from, true))) + if (! (next_elem->area->inside(from, true))) { - PolygonUtils::moveInside(*next_elem->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. + PolygonUtils::moveInside( + *next_elem->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. } next_elem->result_on_layer = from; // Do not call recursive because then amount of layers would be restricted by the stack size. @@ -1365,7 +1420,8 @@ bool TreeSupport::setToModelContact(std::vector>& Polygons valid_place_area; - // 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. + // 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->next_height >= layer_check; layer_check++) { Polygons check_valid_place_area = check->area->intersection(volumes_.getPlaceableAreas(config.getCollisionRadius(*check), layer_check)); @@ -1409,7 +1465,8 @@ bool TreeSupport::setToModelContact(std::vector>& } } - for (LayerIndex layer = layer_idx + 1; layer < last_successfull_layer - 1; ++layer) // NOTE: Use of 'itoa' will make this crash in the loop, even though the operation should be equivalent. + for (LayerIndex layer = layer_idx + 1; layer < last_successfull_layer - 1; + ++layer) // NOTE: Use of 'itoa' will make this crash in the loop, even though the operation should be equivalent. { move_bounds[layer].erase(checked[layer - layer_idx]); delete checked[layer - layer_idx]->area; @@ -1438,29 +1495,36 @@ bool TreeSupport::setToModelContact(std::vector>& else // can not add graceful => just place it here and hope for the best { Point best = first_elem->next_position; - Polygons valid_place_area = first_elem->area->difference(volumes_.getAvoidance(config.getCollisionRadius(first_elem), layer_idx, AvoidanceType::COLLISION, first_elem->use_min_xy_dist)); + Polygons valid_place_area + = first_elem->area->difference(volumes_.getAvoidance(config.getCollisionRadius(first_elem), layer_idx, AvoidanceType::COLLISION, first_elem->use_min_xy_dist)); - if (!valid_place_area.inside(best, true)) + if (! valid_place_area.inside(best, true)) { - if (!valid_place_area.empty()) + if (! valid_place_area.empty()) { PolygonUtils::moveInside(valid_place_area, best); } else { bool found_partial_placement; - for (coord_t radius_offset : { -config.getCollisionRadius(first_elem), -config.getCollisionRadius(first_elem) / 2, coord_t(0) }) // Interestingly the first radius is working most of the time, even though it seems like it shouldn't. + for (coord_t radius_offset : { -config.getCollisionRadius(first_elem), + -config.getCollisionRadius(first_elem) / 2, + coord_t(0) }) // Interestingly the first radius is working most of the time, even though it seems like it shouldn't. { valid_place_area = first_elem->area->intersection(volumes_.getAccumulatedPlaceable0(layer_idx).offset(radius_offset)); - if (!valid_place_area.empty()) + if (! valid_place_area.empty()) { PolygonUtils::moveInside(valid_place_area, best); - spdlog::warn("Not able to place branch fully on non support blocker at layer {} using offset {} for radius {}", layer_idx, radius_offset, config.getCollisionRadius(first_elem)); + spdlog::warn( + "Not able to place branch fully on non support blocker at layer {} using offset {} for radius {}", + layer_idx, + radius_offset, + config.getCollisionRadius(first_elem)); found_partial_placement = true; break; } } - if (!found_partial_placement) + if (! found_partial_placement) { PolygonUtils::moveInside(*first_elem->area, best); spdlog::warn("Not able to place branch on non support blocker at layer {}", layer_idx); @@ -1476,7 +1540,8 @@ bool TreeSupport::setToModelContact(std::vector>& void TreeSupport::createNodesFromArea(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. + // 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. std::unordered_set remove; for (TreeSupportElement* init : move_bounds[0]) { @@ -1497,7 +1562,8 @@ void TreeSupport::createNodesFromArea(std::vector> } else { - // If the support_rest_preference is GRACEFUL the collision radius is increased, but the radius will only be increased if the element is to_buildplate, so if the branch rests on the buildplate, the element will have to be updated to include this information. + // If the support_rest_preference is GRACEFUL the collision radius is increased, but the radius will only be increased if the element is to_buildplate, so if the + // branch rests on the buildplate, the element will have to be updated to include this information. init->setToBuildplateForAllParents(true); } } @@ -1518,17 +1584,23 @@ void TreeSupport::createNodesFromArea(std::vector> bool removed = false; if (elem->result_on_layer == Point(-1, -1)) // Check if the resulting center point is not yet set. { - if (elem->to_buildplate || (!elem->to_buildplate && elem->distance_to_top < config.min_dtt_to_model && !elem->supports_roof)) + if (elem->to_buildplate || (! elem->to_buildplate && elem->distance_to_top < config.min_dtt_to_model && ! elem->supports_roof)) { if (elem->to_buildplate) { - spdlog::error("Uninitialized Influence area targeting ({},{}) at target_height: {} layer: {}", elem->target_position.X, elem->target_position.Y, elem->target_height, layer_idx); + spdlog::error( + "Uninitialized Influence area targeting ({},{}) at target_height: {} layer: {}", + elem->target_position.X, + elem->target_position.Y, + elem->target_height, + layer_idx); } 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 (TreeSupportElement* parent : 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. + // 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->result_on_layer = Point(-1, -1); } continue; @@ -1544,7 +1616,7 @@ void TreeSupport::createNodesFromArea(std::vector> } } - if (!removed) + if (! removed) { setPointsOnAreas(elem); // Element is valid now setting points in the layer above. } @@ -1561,7 +1633,10 @@ void TreeSupport::createNodesFromArea(std::vector> } } -void TreeSupport::generateBranchAreas(std::vector>& linear_data, std::vector>& layer_tree_polygons, const std::map& inverse_tree_order) +void TreeSupport::generateBranchAreas( + std::vector>& linear_data, + std::vector>& layer_tree_polygons, + const std::map& inverse_tree_order) { 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; @@ -1580,136 +1655,135 @@ void TreeSupport::generateBranchAreas(std::vector - ( - 0, - linear_data.size(), - [&](const size_t idx) - { - TreeSupportElement* elem = linear_data[idx].second; - coord_t radius = config.getRadius(*elem); - bool parent_uses_min = false; - TreeSupportElement* child_elem = inverse_tree_order.count(elem) ? inverse_tree_order.at(elem) : nullptr; + cura::parallel_for( + 0, + linear_data.size(), + [&](const size_t idx) + { + TreeSupportElement* elem = linear_data[idx].second; + coord_t radius = config.getRadius(*elem); + bool parent_uses_min = false; + TreeSupportElement* child_elem = inverse_tree_order.count(elem) ? inverse_tree_order.at(elem) : nullptr; - // 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->skip_ovalisation) + // 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->skip_ovalisation) + { + if (child_elem != nullptr) { - if (child_elem != nullptr) - { - Point movement = (child_elem->result_on_layer - elem->result_on_layer); - movement_directions.emplace_back(movement, radius); - } - for (TreeSupportElement* parent : elem->parents) - { - Point movement = (parent->result_on_layer - elem->result_on_layer); - movement_directions.emplace_back(movement, std::max(config.getRadius(parent), config.support_line_width)); - parent_uses_min |= parent->use_min_xy_dist; - } - - for (Point target: elem->additional_ovalization_targets) - { - Point movement = (target - elem->result_on_layer); - movement_directions.emplace_back(movement, std::max(radius, config.support_line_width)); - } - + Point movement = (child_elem->result_on_layer - elem->result_on_layer); + movement_directions.emplace_back(movement, radius); } - - coord_t max_speed_sqd = 0; - std::function generateArea = - [&](coord_t offset) + for (TreeSupportElement* parent : elem->parents) { - Polygons poly; + Point movement = (parent->result_on_layer - elem->result_on_layer); + movement_directions.emplace_back(movement, std::max(config.getRadius(parent), config.support_line_width)); + parent_uses_min |= parent->use_min_xy_dist; + } - for (std::pair movement : movement_directions) - { - max_speed_sqd = std::max(max_speed_sqd, vSize2(movement.first)); + for (Point target : elem->additional_ovalization_targets) + { + Point movement = (target - elem->result_on_layer); + movement_directions.emplace_back(movement, std::max(radius, config.support_line_width)); + } + } - // 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 + offset) / (1.0 * config.branch_radius); - Point center_position = elem->result_on_layer + movement.first / 2; - const double moveX = movement.first.X / (used_scale * config.branch_radius); - const double moveY = movement.first.Y / (used_scale * config.branch_radius); - const double vsize_inv = 0.5 / (0.01 + std::sqrt(moveX * moveX + moveY * moveY)); + coord_t max_speed_sqd = 0; + std::function generateArea = [&](coord_t offset) + { + Polygons poly; - std::array matrix = - { - used_scale * (1 + moveX * moveX * vsize_inv), - used_scale * (0 + moveX * moveY * vsize_inv), - used_scale * (0 + moveX * moveY * vsize_inv), - used_scale * (1 + moveY * moveY * vsize_inv), - }; - Polygon circle; - for (Point vertex : branch_circle) - { - vertex = Point(matrix[0] * vertex.X + matrix[1] * vertex.Y, matrix[2] * vertex.X + matrix[3] * vertex.Y); - circle.add(center_position + vertex); - } - poly.add(circle.offset(0)); + for (std::pair movement : movement_directions) + { + max_speed_sqd = std::max(max_speed_sqd, vSize2(movement.first)); + + // 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 + offset) / (1.0 * config.branch_radius); + Point center_position = elem->result_on_layer + movement.first / 2; + const double moveX = movement.first.X / (used_scale * config.branch_radius); + const double moveY = movement.first.Y / (used_scale * config.branch_radius); + const double vsize_inv = 0.5 / (0.01 + std::sqrt(moveX * moveX + moveY * moveY)); + + std::array matrix = { + used_scale * (1 + moveX * moveX * vsize_inv), + used_scale * (0 + moveX * moveY * vsize_inv), + used_scale * (0 + moveX * moveY * vsize_inv), + used_scale * (1 + moveY * moveY * vsize_inv), + }; + Polygon circle; + for (Point vertex : branch_circle) + { + vertex = Point(matrix[0] * vertex.X + matrix[1] * vertex.Y, matrix[2] * vertex.X + matrix[3] * vertex.Y); + circle.add(center_position + vertex); } + poly.add(circle.offset(0)); + } - poly = poly.unionPolygons().offset(std::min(static_cast(FUDGE_LENGTH), config.support_line_width / 4)).difference(volumes_.getCollision(0, linear_data[idx].first, parent_uses_min || elem->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. - return poly; - }; + poly = poly.unionPolygons() + .offset(std::min(static_cast(FUDGE_LENGTH), config.support_line_width / 4)) + .difference(volumes_.getCollision(0, linear_data[idx].first, parent_uses_min || elem->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. + return poly; + }; - constexpr auto three_quarters_sqd = 0.75 * 0.75; - const bool fast_relative_movement = max_speed_sqd > (radius * radius * three_quarters_sqd); + constexpr auto three_quarters_sqd = 0.75 * 0.75; + const bool fast_relative_movement = max_speed_sqd > (radius * radius * three_quarters_sqd); - // 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); + // 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) > config.support_line_width) + if (fast_relative_movement || config.getRadius(*elem) - config.getCollisionRadius(*elem) > 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. + Polygons nozzle_path = linear_inserts[idx].offset(-config.support_line_width / 2); + if (nozzle_path.splitIntoParts(false).size() > 1) { - // 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. - Polygons nozzle_path = linear_inserts[idx].offset(-config.support_line_width / 2); + // Just try to make the area a tiny bit larger. + linear_inserts[idx] = generateArea(config.support_line_width / 2); + nozzle_path = linear_inserts[idx].offset(-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.splitIntoParts(false).size() > 1) { - // Just try to make the area a tiny bit larger. - linear_inserts[idx] = generateArea(config.support_line_width / 2); - nozzle_path = linear_inserts[idx].offset(-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.splitIntoParts(false).size() > 1) + Polygons polygons_with_correct_center; + for (PolygonsPart part : nozzle_path.splitIntoParts(false)) { - Polygons polygons_with_correct_center; - for (PolygonsPart part : nozzle_path.splitIntoParts(false)) + if (part.inside(elem->result_on_layer, true)) { - if (part.inside(elem->result_on_layer, true)) + polygons_with_correct_center = polygons_with_correct_center.unionPolygons(part); + } + else + { + // Try a fuzzy inside as sometimes the point should be on the border, but is not because of rounding errors... + Point from = elem->result_on_layer; + PolygonUtils::moveInside(part, from, 0); + if (vSize2(elem->result_on_layer - from) < (FUDGE_LENGTH * FUDGE_LENGTH) / 4) { polygons_with_correct_center = polygons_with_correct_center.unionPolygons(part); } - else - { - // Try a fuzzy inside as sometimes the point should be on the border, but is not because of rounding errors... - Point from = elem->result_on_layer; - PolygonUtils::moveInside(part, from, 0); - if (vSize2(elem->result_on_layer - from) < (FUDGE_LENGTH * FUDGE_LENGTH) / 4) - { - polygons_with_correct_center = polygons_with_correct_center.unionPolygons(part); - } - } } - // Increase the area again, to ensure the nozzle path when calculated later is very similar to the one assumed above. - linear_inserts[idx] = polygons_with_correct_center.offset(config.support_line_width / 2).unionPolygons(); - linear_inserts[idx] = linear_inserts[idx].difference(volumes_.getCollision(0, linear_data[idx].first, parent_uses_min || elem->use_min_xy_dist)).unionPolygons(); } + // Increase the area again, to ensure the nozzle path when calculated later is very similar to the one assumed above. + linear_inserts[idx] = polygons_with_correct_center.offset(config.support_line_width / 2).unionPolygons(); + linear_inserts[idx] + = linear_inserts[idx].difference(volumes_.getCollision(0, linear_data[idx].first, parent_uses_min || elem->use_min_xy_dist)).unionPolygons(); } } + } - if (idx % progress_inserts_check_interval == 0) + if (idx % progress_inserts_check_interval == 0) + { { - { - std::lock_guard critical_section_progress(critical_sections); - progress_total += TREE_PROGRESS_GENERATE_BRANCH_AREAS / progress_report_steps; - Progress::messageProgress(Progress::Stage::SUPPORT, progress_total * progress_multiplier + progress_offset, TREE_PROGRESS_TOTAL); - } + std::lock_guard critical_section_progress(critical_sections); + progress_total += TREE_PROGRESS_GENERATE_BRANCH_AREAS / progress_report_steps; + Progress::messageProgress(Progress::Stage::SUPPORT, progress_total * progress_multiplier + progress_offset, TREE_PROGRESS_TOTAL); } } - ); + }); // Single threaded combining all elements to the right layers. Only copies data! for (const coord_t i : ranges::views::iota(0UL, linear_data.size())) @@ -1729,8 +1803,7 @@ void TreeSupport::smoothBranchAreas(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. - cura::parallel_for - ( + cura::parallel_for( 0, processing.size(), [&](const size_t processing_idx) @@ -1744,10 +1817,13 @@ void TreeSupport::smoothBranchAreas(std::vectorresult_on_layer - parent->result_on_layer) - (config.getRadius(*data_pair.first) - config.getRadius(*parent))); + max_outer_wall_distance = std::max( + max_outer_wall_distance, + vSize(data_pair.first->result_on_layer - parent->result_on_layer) - (config.getRadius(*data_pair.first) - 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. + 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 = data_pair.second.offset(max_outer_wall_distance); @@ -1755,12 +1831,12 @@ void TreeSupport::smoothBranchAreas(std::vector(parent, layer_tree_polygons[layer_idx + 1][parent].intersection(max_allowed_area))); + update_next[processing_idx].emplace_back( + std::pair(parent, layer_tree_polygons[layer_idx + 1][parent].intersection(max_allowed_area))); } } } - } - ); + }); for (std::vector> data_vector : update_next) { @@ -1782,10 +1858,11 @@ void TreeSupport::smoothBranchAreas(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. + std::vector> update_next( + processing.size(), + std::pair(nullptr, Polygons())); // With this a lock can be avoided. - cura::parallel_for - ( + cura::parallel_for( 0, processing.size(), [&](const size_t processing_idx) @@ -1819,8 +1896,7 @@ void TreeSupport::smoothBranchAreas(std::vector(data_pair.first, result); } } - } - ); + }); updated_last_iteration.clear(); for (std::pair data_pair : update_next) @@ -1837,22 +1913,21 @@ void TreeSupport::smoothBranchAreas(std::vector>& layer_tree_polygons, const std::vector>& linear_data, std::vector>>& dropped_down_areas, - const std::map& inverse_tree_order -) + const std::map& inverse_tree_order) { - cura::parallel_for - ( + cura::parallel_for( 0, linear_data.size(), [&](const size_t idx) { TreeSupportElement* elem = linear_data[idx].second; - bool non_gracious_model_contact = ! elem->to_model_gracious && ! inverse_tree_order.count(elem); // If an element has no child, it connects to whatever is below as no support further down for it will exist. + bool non_gracious_model_contact + = ! elem->to_model_gracious + && ! inverse_tree_order.count(elem); // If an 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].intersection(volumes_.getAccumulatedPlaceable0(linear_data[idx].first)); @@ -1862,8 +1937,7 @@ void TreeSupport::dropNonGraciousAreas dropped_down_areas[idx].emplace_back(linear_data[idx].first - counter, rest_support); } } - } - ); + }); } @@ -1871,8 +1945,8 @@ void TreeSupport::filterFloatingLines(std::vector& support_layer_stora { const auto t_start = std::chrono::high_resolution_clock::now(); - const coord_t closing_dist=config.support_line_width*config.support_wall_count; - const coord_t open_close_distance = config.fill_outline_gaps ? config.min_feature_size/ 2 - 5 : config.min_wall_line_width/ 2 - 5; // based on calculation in WallToolPath + const coord_t closing_dist = config.support_line_width * config.support_wall_count; + const coord_t open_close_distance = config.fill_outline_gaps ? config.min_feature_size / 2 - 5 : config.min_wall_line_width / 2 - 5; // based on calculation in WallToolPath const double small_area_length = INT2MM(static_cast(config.support_line_width) / 2); std::function reversePolygon = [&](Polygons& poly) @@ -1884,107 +1958,103 @@ void TreeSupport::filterFloatingLines(std::vector& support_layer_stora }; - std::vector support_holes(support_layer_storage.size(),Polygons()); - //Extract all holes as polygon objects - cura::parallel_for - ( - 0, - support_layer_storage.size(), - [&](const LayerIndex layer_idx) - { - - - support_layer_storage[layer_idx] = config.simplifier.polygon(PolygonUtils::unionManySmall(support_layer_storage[layer_idx].smooth(FUDGE_LENGTH))).offset(-open_close_distance).offset(open_close_distance * 2).offset(-open_close_distance); - support_layer_storage[layer_idx].removeSmallAreas(small_area_length * small_area_length, false); + std::vector support_holes(support_layer_storage.size(), Polygons()); + // Extract all holes as polygon objects + cura::parallel_for( + 0, + support_layer_storage.size(), + [&](const LayerIndex layer_idx) + { + support_layer_storage[layer_idx] = config.simplifier.polygon(PolygonUtils::unionManySmall(support_layer_storage[layer_idx].smooth(FUDGE_LENGTH))) + .offset(-open_close_distance) + .offset(open_close_distance * 2) + .offset(-open_close_distance); + support_layer_storage[layer_idx].removeSmallAreas(small_area_length * small_area_length, false); - std::vector parts = support_layer_storage[layer_idx].sortByNesting(); + std::vector parts = support_layer_storage[layer_idx].sortByNesting(); - if (parts.size() <= 1) - { - return; - } + if (parts.size() <= 1) + { + return; + } - Polygons holes_original; - for (const size_t idx : ranges::views::iota(1UL, parts.size())) - { - Polygons area = parts[idx]; - reversePolygon(area); - holes_original.add(area); - } - support_holes[layer_idx] = holes_original; + Polygons holes_original; + for (const size_t idx : ranges::views::iota(1UL, parts.size())) + { + Polygons area = parts[idx]; + reversePolygon(area); + holes_original.add(area); } - ); + support_holes[layer_idx] = holes_original; + }); const auto t_union = std::chrono::high_resolution_clock::now(); std::vector> holeparts(support_layer_storage.size()); - //Split all holes into parts - cura::parallel_for - ( - 0, - support_layer_storage.size(), - [&](const LayerIndex layer_idx) + // Split all holes into parts + cura::parallel_for( + 0, + support_layer_storage.size(), + [&](const LayerIndex layer_idx) + { + for (Polygons hole : support_holes[layer_idx].splitIntoParts()) { - for (Polygons hole:support_holes[layer_idx].splitIntoParts()) - { - holeparts[layer_idx].emplace_back(hole); - } + holeparts[layer_idx].emplace_back(hole); } - ); - std::vector>> hole_rest_map (holeparts.size()); - std::vector> holes_resting_outside (holeparts.size()); + }); + std::vector>> hole_rest_map(holeparts.size()); + std::vector> holes_resting_outside(holeparts.size()); - //Figure out which hole rests on which other hole - cura::parallel_for - ( - 1, - support_layer_storage.size(), - [&](const LayerIndex layer_idx) + // Figure out which hole rests on which other hole + cura::parallel_for( + 1, + support_layer_storage.size(), + [&](const LayerIndex layer_idx) + { + if (holeparts[layer_idx].empty()) { - if (holeparts[layer_idx].empty()) - { - return; - } + return; + } - Polygons outer_walls = - TreeSupportUtils::toPolylines(support_layer_storage[layer_idx - 1].getOutsidePolygons()).tubeShape(closing_dist,0);//.unionPolygons(volumes_.getCollision(0, layer_idx - 1, true).offset(-(config.support_line_width+config.xy_min_distance))); + Polygons outer_walls + = TreeSupportUtils::toPolylines(support_layer_storage[layer_idx - 1].getOutsidePolygons()) + .tubeShape(closing_dist, 0); //.unionPolygons(volumes_.getCollision(0, layer_idx - 1, true).offset(-(config.support_line_width+config.xy_min_distance))); - Polygons holes_below; + Polygons holes_below; - for (auto poly: holeparts[layer_idx - 1]) + for (auto poly : holeparts[layer_idx - 1]) + { + holes_below.add(poly); + } + + for (auto [idx, hole] : holeparts[layer_idx] | ranges::views::enumerate) + { + AABB hole_aabb = AABB(hole); + hole_aabb.expand(EPSILON); + if (! hole.intersection(PolygonUtils::clipPolygonWithAABB(outer_walls, hole_aabb)).empty()) { - holes_below.add(poly); + holes_resting_outside[layer_idx].emplace(idx); } - - for (auto [idx, hole] : holeparts[layer_idx] | ranges::views::enumerate) + else { - AABB hole_aabb = AABB(hole); - hole_aabb.expand(EPSILON); - if (!hole.intersection(PolygonUtils::clipPolygonWithAABB(outer_walls,hole_aabb)).empty()) - { - holes_resting_outside[layer_idx].emplace(idx); - } - else + for (auto [idx2, hole2] : holeparts[layer_idx - 1] | ranges::views::enumerate) { - for (auto [idx2, hole2] : holeparts[layer_idx - 1] | ranges::views::enumerate) + if (hole_aabb.hit(AABB(hole2)) + && ! hole.intersection(hole2).empty()) // TODO should technically be outline: Check if this is fine either way as it would save an offset { - - if (hole_aabb.hit(AABB(hole2)) && ! hole.intersection(hole2).empty() ) // TODO should technically be outline: Check if this is fine either way as it would save an offset - { - hole_rest_map[layer_idx][idx].emplace_back(idx2); - } + hole_rest_map[layer_idx][idx].emplace_back(idx2); } } } } - ); + }); const auto t_hole_rest_ordering = std::chrono::high_resolution_clock::now(); std::unordered_set removed_holes_by_idx; std::vector valid_holes(support_holes.size(), Polygons()); - //Check which holes have to be removed as they do not rest on anything. Only keep holes that have to be removed + // Check which holes have to be removed as they do not rest on anything. Only keep holes that have to be removed for (const size_t layer_idx : ranges::views::iota(1UL, support_holes.size())) { std::unordered_set next_removed_holes_by_idx; @@ -1998,7 +2068,8 @@ void TreeSupport::filterFloatingLines(std::vector& support_layer_stora } else { - if(hole_rest_map[layer_idx].contains(idx)){ + if (hole_rest_map[layer_idx].contains(idx)) + { for (size_t resting_idx : hole_rest_map[layer_idx][idx]) { if (! removed_holes_by_idx.contains(resting_idx)) @@ -2023,24 +2094,22 @@ void TreeSupport::filterFloatingLines(std::vector& support_layer_stora } const auto t_hole_removal_tagging = std::chrono::high_resolution_clock::now(); - //Check if holes are so close to each other that two lines will be printed directly next to each other, which is assumed stable (as otherwise the simulated support pattern will not work correctly) and remove all remaining, invalid holes - cura::parallel_for - ( - 1, - support_layer_storage.size(), - [&](const LayerIndex layer_idx) + // Check if holes are so close to each other that two lines will be printed directly next to each other, which is assumed stable (as otherwise the simulated support pattern + // will not work correctly) and remove all remaining, invalid holes + cura::parallel_for( + 1, + support_layer_storage.size(), + [&](const LayerIndex layer_idx) + { + if (holeparts[layer_idx].empty()) { - if (holeparts[layer_idx].empty()) - { - return; - } - - support_layer_storage[layer_idx] = support_layer_storage[layer_idx].getOutsidePolygons(); - reversePolygon(valid_holes[layer_idx]); - support_layer_storage[layer_idx].add(valid_holes[layer_idx]); + return; } - ); + support_layer_storage[layer_idx] = support_layer_storage[layer_idx].getOutsidePolygons(); + reversePolygon(valid_holes[layer_idx]); + support_layer_storage[layer_idx].add(valid_holes[layer_idx]); + }); const auto t_end = std::chrono::high_resolution_clock::now(); @@ -2050,19 +2119,24 @@ void TreeSupport::filterFloatingLines(std::vector& support_layer_stora const auto dur_hole_removal_tagging = 0.001 * std::chrono::duration_cast(t_hole_removal_tagging - t_hole_rest_ordering).count(); const auto dur_hole_removal = 0.001 * std::chrono::duration_cast(t_end - t_hole_removal_tagging).count(); - spdlog::debug("Time to union areas: {} ms Time to evaluate which hole rest on which other hole: {} ms Time to see which holes are not resting on anything valid: {} ms remove all holes that are invalid and not close enough to a valid hole: {} ms", dur_union,dur_hole_rest_ordering,dur_hole_removal_tagging, dur_hole_removal); - + spdlog::debug( + "Time to union areas: {} ms Time to evaluate which hole rest on which other hole: {} ms Time to see which holes are not resting on anything valid: {} ms remove all holes " + "that are invalid and not close enough to a valid hole: {} ms", + dur_union, + dur_hole_rest_ordering, + dur_hole_removal_tagging, + dur_hole_removal); } void TreeSupport::finalizeInterfaceAndSupportAreas(std::vector& support_layer_storage, std::vector& support_roof_storage, SliceDataStorage& storage) { InterfacePreference interface_pref = config.interface_preference; // InterfacePreference::SUPPORT_LINES_OVERWRITE_INTERFACE; - double progress_total = TREE_PROGRESS_PRECALC_AVO + TREE_PROGRESS_PRECALC_COLL + TREE_PROGRESS_GENERATE_NODES + TREE_PROGRESS_AREA_CALC + TREE_PROGRESS_GENERATE_BRANCH_AREAS + TREE_PROGRESS_SMOOTH_BRANCH_AREAS; + double progress_total = TREE_PROGRESS_PRECALC_AVO + TREE_PROGRESS_PRECALC_COLL + TREE_PROGRESS_GENERATE_NODES + TREE_PROGRESS_AREA_CALC + TREE_PROGRESS_GENERATE_BRANCH_AREAS + + TREE_PROGRESS_SMOOTH_BRANCH_AREAS; // Iterate over the generated circles in parallel and clean them up. Also add support floor. std::mutex critical_sections; - cura::parallel_for - ( + cura::parallel_for( 0, support_layer_storage.size(), [&](const LayerIndex layer_idx) @@ -2071,43 +2145,53 @@ void TreeSupport::finalizeInterfaceAndSupportAreas(std::vector& suppor // Subtract support lines of the branches from the roof storage.support.supportLayers[layer_idx].support_roof = storage.support.supportLayers[layer_idx].support_roof.unionPolygons(support_roof_storage[layer_idx]); - if (!storage.support.supportLayers[layer_idx].support_roof.empty() && support_layer_storage[layer_idx].intersection(storage.support.supportLayers[layer_idx].support_roof).area() > 1) + if (! storage.support.supportLayers[layer_idx].support_roof.empty() + && support_layer_storage[layer_idx].intersection(storage.support.supportLayers[layer_idx].support_roof).area() > 1) { switch (interface_pref) { - case InterfacePreference::INTERFACE_AREA_OVERWRITES_SUPPORT: - support_layer_storage[layer_idx] = support_layer_storage[layer_idx].difference(storage.support.supportLayers[layer_idx].support_roof); - break; - - case InterfacePreference::SUPPORT_AREA_OVERWRITES_INTERFACE: - storage.support.supportLayers[layer_idx].support_roof = storage.support.supportLayers[layer_idx].support_roof.difference(support_layer_storage[layer_idx]); - break; - - case InterfacePreference::INTERFACE_LINES_OVERWRITE_SUPPORT: - { - Polygons interface_lines = - TreeSupportUtils::generateSupportInfillLines(storage.support.supportLayers[layer_idx].support_roof, config, true, layer_idx, config.support_roof_line_distance, storage.support.cross_fill_provider, true) - .offsetPolyLine(config.support_roof_line_width / 2); - support_layer_storage[layer_idx] = support_layer_storage[layer_idx].difference(interface_lines); - } + case InterfacePreference::INTERFACE_AREA_OVERWRITES_SUPPORT: + support_layer_storage[layer_idx] = support_layer_storage[layer_idx].difference(storage.support.supportLayers[layer_idx].support_roof); break; - case InterfacePreference::SUPPORT_LINES_OVERWRITE_INTERFACE: - { - Polygons tree_lines; - tree_lines = - tree_lines.unionPolygons - ( - TreeSupportUtils::generateSupportInfillLines(support_layer_storage[layer_idx], config, false, layer_idx, config.support_line_distance, storage.support.cross_fill_provider, true) - .offsetPolyLine(config.support_line_width / 2) - ); - storage.support.supportLayers[layer_idx].support_roof = storage.support.supportLayers[layer_idx].support_roof.difference(tree_lines); - // Do not draw roof where the tree is. I prefer it this way as otherwise the roof may cut of a branch from its support below. - } + case InterfacePreference::SUPPORT_AREA_OVERWRITES_INTERFACE: + storage.support.supportLayers[layer_idx].support_roof = storage.support.supportLayers[layer_idx].support_roof.difference(support_layer_storage[layer_idx]); break; - case InterfacePreference::NOTHING: - break; + case InterfacePreference::INTERFACE_LINES_OVERWRITE_SUPPORT: + { + Polygons interface_lines = TreeSupportUtils::generateSupportInfillLines( + storage.support.supportLayers[layer_idx].support_roof, + config, + true, + layer_idx, + config.support_roof_line_distance, + storage.support.cross_fill_provider, + true) + .offsetPolyLine(config.support_roof_line_width / 2); + support_layer_storage[layer_idx] = support_layer_storage[layer_idx].difference(interface_lines); + } + break; + + case InterfacePreference::SUPPORT_LINES_OVERWRITE_INTERFACE: + { + Polygons tree_lines; + tree_lines = tree_lines.unionPolygons(TreeSupportUtils::generateSupportInfillLines( + support_layer_storage[layer_idx], + config, + false, + layer_idx, + config.support_line_distance, + storage.support.cross_fill_provider, + true) + .offsetPolyLine(config.support_line_width / 2)); + storage.support.supportLayers[layer_idx].support_roof = storage.support.supportLayers[layer_idx].support_roof.difference(tree_lines); + // Do not draw roof where the tree is. I prefer it this way as otherwise the roof may cut of a branch from its support below. + } + break; + + case InterfacePreference::NOTHING: + break; } } @@ -2119,8 +2203,10 @@ void TreeSupport::finalizeInterfaceAndSupportAreas(std::vector& suppor size_t layers_below = 0; while (layers_below <= config.support_bottom_layers) { - // One sample at 0 layers below, another at config.support_bottom_layers. In-between samples at config.performance_interface_skip_layers distance from each other. - const size_t sample_layer = static_cast(std::max(0, (static_cast(layer_idx) - static_cast(layers_below)) - static_cast(config.z_distance_bottom_layers))); + // One sample at 0 layers below, another at config.support_bottom_layers. In-between samples at config.performance_interface_skip_layers distance from each + // other. + const size_t sample_layer + = static_cast(std::max(0, (static_cast(layer_idx) - static_cast(layers_below)) - static_cast(config.z_distance_bottom_layers))); constexpr bool no_support = false; constexpr bool no_prime_tower = false; floor_layer.add(layer_outset.intersection(storage.getLayerOutlines(sample_layer, no_support, no_prime_tower))); @@ -2151,32 +2237,31 @@ void TreeSupport::finalizeInterfaceAndSupportAreas(std::vector& suppor { std::lock_guard critical_section_storage(critical_sections); - if (!storage.support.supportLayers[layer_idx].support_infill_parts.empty() || !storage.support.supportLayers[layer_idx].support_roof.empty()) + if (! storage.support.supportLayers[layer_idx].support_infill_parts.empty() || ! storage.support.supportLayers[layer_idx].support_roof.empty()) { storage.support.layer_nr_max_filled_layer = std::max(storage.support.layer_nr_max_filled_layer, static_cast(layer_idx)); } } - } - ); + }); } void TreeSupport::drawAreas(std::vector>& move_bounds, SliceDataStorage& storage) { std::vector support_layer_storage(move_bounds.size()); std::vector support_roof_storage(move_bounds.size()); - std::map inverse_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. + std::map + inverse_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 (const auto layer_idx : ranges::views::iota(0UL, move_bounds.size())) { for (TreeSupportElement* elem : move_bounds[layer_idx]) { // (Check if) 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 && ((!inverse_tree_order.count(elem) && elem->target_height == layer_idx && config.min_dtt_to_model > 0 && !elem->to_buildplate) || - (inverse_tree_order.count(elem) && inverse_tree_order[elem]->result_on_layer == Point(-1, -1)))) - ) + if ((layer_idx > 0 + && ((! inverse_tree_order.count(elem) && elem->target_height == layer_idx && config.min_dtt_to_model > 0 && ! elem->to_buildplate) + || (inverse_tree_order.count(elem) && inverse_tree_order[elem]->result_on_layer == Point(-1, -1))))) { continue; } @@ -2202,7 +2287,8 @@ void TreeSupport::drawAreas(std::vector>& move_bou generateBranchAreas(linear_data, layer_tree_polygons, inverse_tree_order); const auto t_generate = std::chrono::high_resolution_clock::now(); - // In some edge-cases a branch may go through 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. + // In some edge-cases a branch may go through 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. smoothBranchAreas(layer_tree_polygons); const auto t_smooth = std::chrono::high_resolution_clock::now(); @@ -2221,19 +2307,15 @@ void TreeSupport::drawAreas(std::vector>& move_bou } // ensure all branch areas added as roof actually cause a roofline to generate. Else disable turning the branch to roof going down - cura::parallel_for - ( + cura::parallel_for( 0, layer_tree_polygons.size(), [&](const size_t layer_idx) { for (std::pair data_pair : layer_tree_polygons[layer_idx]) { - if - ( - data_pair.first->missing_roof_layers > data_pair.first->distance_to_top && - TreeSupportUtils::generateSupportInfillLines(data_pair.second, config, true, layer_idx, config.support_roof_line_distance, nullptr, true).empty() - ) + if (data_pair.first->missing_roof_layers > data_pair.first->distance_to_top + && TreeSupportUtils::generateSupportInfillLines(data_pair.second, config, true, layer_idx, config.support_roof_line_distance, nullptr, true).empty()) { std::vector to_disable_roofs; to_disable_roofs.emplace_back(data_pair.first); @@ -2252,8 +2334,7 @@ void TreeSupport::drawAreas(std::vector>& move_bou } } } - } - ); + }); // Single threaded combining all support areas to the right layers. // Only copies data! @@ -2261,15 +2342,13 @@ void TreeSupport::drawAreas(std::vector>& move_bou { for (std::pair data_pair : layer_tree_polygons[layer_idx]) { - ( - (data_pair.first->missing_roof_layers > data_pair.first->distance_to_top) ? support_roof_storage : support_layer_storage - )[layer_idx].add(data_pair.second); + ((data_pair.first->missing_roof_layers > data_pair.first->distance_to_top) ? support_roof_storage : support_layer_storage)[layer_idx].add(data_pair.second); } } for (const auto layer_idx : ranges::views::iota(0UL, additional_required_support_area.size())) { - if(support_layer_storage.size() > layer_idx) + if (support_layer_storage.size() > layer_idx) { support_layer_storage[layer_idx].add(additional_required_support_area[layer_idx]); } @@ -2287,7 +2366,14 @@ void TreeSupport::drawAreas(std::vector>& move_bou const auto dur_drop = 0.001 * std::chrono::duration_cast(t_drop - t_smooth).count(); const auto dur_filter = 0.001 * std::chrono::duration_cast(t_filter - t_drop).count(); const auto dur_finalize = 0.001 * std::chrono::duration_cast(t_end - t_filter).count(); - spdlog::info("Time used for drawing subfuctions: generateBranchAreas: {} ms smoothBranchAreas: {} ms dropNonGraciousAreas: {} ms filterFloatingLines: {} ms finalizeInterfaceAndSupportAreas {} ms", dur_gen_tips, dur_smooth, dur_drop, dur_filter, dur_finalize); + spdlog::info( + "Time used for drawing subfuctions: generateBranchAreas: {} ms smoothBranchAreas: {} ms dropNonGraciousAreas: {} ms filterFloatingLines: {} ms " + "finalizeInterfaceAndSupportAreas {} ms", + dur_gen_tips, + dur_smooth, + dur_drop, + dur_filter, + dur_finalize); } } // namespace cura diff --git a/src/WallsComputation.cpp b/src/WallsComputation.cpp index 09dfa368ed..61b8d80fa6 100644 --- a/src/WallsComputation.cpp +++ b/src/WallsComputation.cpp @@ -2,6 +2,7 @@ // CuraEngine is released under the terms of the AGPLv3 or higher #include "WallsComputation.h" + #include "Application.h" #include "ExtruderTrain.h" #include "Slice.h" @@ -13,7 +14,9 @@ namespace cura { -WallsComputation::WallsComputation(const Settings& settings, const LayerIndex layer_nr) : settings(settings), layer_nr(layer_nr) +WallsComputation::WallsComputation(const Settings& settings, const LayerIndex layer_nr) + : settings(settings) + , layer_nr(layer_nr) { } @@ -35,7 +38,8 @@ void WallsComputation::generateWalls(SliceLayerPart* part, SectionType section_t const bool spiralize = settings.get("magic_spiralize"); const size_t alternate = ((layer_nr % 2) + 2) % 2; - if (spiralize && layer_nr < LayerIndex(settings.get("initial_bottom_layers")) && alternate == 1) //Add extra insets every 2 layers when spiralizing. This makes bottoms of cups watertight. + if (spiralize && layer_nr < LayerIndex(settings.get("initial_bottom_layers")) + && alternate == 1) // Add extra insets every 2 layers when spiralizing. This makes bottoms of cups watertight. { wall_count += 5; } @@ -55,8 +59,7 @@ void WallsComputation::generateWalls(SliceLayerPart* part, SectionType section_t // When spiralizing, generate the spiral insets using simple offsets instead of generating toolpaths if (spiralize) { - const bool recompute_outline_based_on_outer_wall = - settings.get("support_enable") && !settings.get("fill_outline_gaps"); + const bool recompute_outline_based_on_outer_wall = settings.get("support_enable") && ! settings.get("fill_outline_gaps"); generateSpiralInsets(part, line_width_0, wall_0_inset, recompute_outline_based_on_outer_wall); if (layer_nr <= static_cast(settings.get("initial_bottom_layers"))) @@ -72,7 +75,7 @@ void WallsComputation::generateWalls(SliceLayerPart* part, SectionType section_t part->wall_toolpaths = wall_tool_paths.getToolPaths(); part->inner_area = wall_tool_paths.getInnerContour(); } - part->outline = PolygonsPart { Simplify(settings).polygon(part->outline) }; + part->outline = PolygonsPart{ Simplify(settings).polygon(part->outline) }; part->print_outline = part->outline; } @@ -84,16 +87,16 @@ void WallsComputation::generateWalls(SliceLayerPart* part, SectionType section_t */ void WallsComputation::generateWalls(SliceLayer* layer, SectionType section) { - for(SliceLayerPart& part : layer->parts) + for (SliceLayerPart& part : layer->parts) { generateWalls(&part, section); } - //Remove the parts which did not generate a wall. As these parts are too small to print, - // and later code can now assume that there is always minimal 1 wall line. - if(settings.get("wall_line_count") >= 1 && !settings.get("fill_outline_gaps")) + // Remove the parts which did not generate a wall. As these parts are too small to print, + // and later code can now assume that there is always minimal 1 wall line. + if (settings.get("wall_line_count") >= 1 && ! settings.get("fill_outline_gaps")) { - for(size_t part_idx = 0; part_idx < layer->parts.size(); part_idx++) + for (size_t part_idx = 0; part_idx < layer->parts.size(); part_idx++) { if (layer->parts[part_idx].wall_toolpaths.empty() && layer->parts[part_idx].spiral_wall.empty()) { @@ -108,11 +111,11 @@ void WallsComputation::generateWalls(SliceLayer* layer, SectionType section) } } -void WallsComputation::generateSpiralInsets(SliceLayerPart *part, coord_t line_width_0, coord_t wall_0_inset, bool recompute_outline_based_on_outer_wall) +void WallsComputation::generateSpiralInsets(SliceLayerPart* part, coord_t line_width_0, coord_t wall_0_inset, bool recompute_outline_based_on_outer_wall) { part->spiral_wall = part->outline.offset(-line_width_0 / 2 - wall_0_inset); - //Optimize the wall. This prevents buffer underruns in the printer firmware, and reduces processing time in CuraEngine. + // Optimize the wall. This prevents buffer underruns in the printer firmware, and reduces processing time in CuraEngine. const ExtruderTrain& train_wall = settings.get("wall_0_extruder_nr"); part->spiral_wall = Simplify(train_wall.settings).polygon(part->spiral_wall); part->spiral_wall.removeDegenerateVerts(); @@ -126,4 +129,4 @@ void WallsComputation::generateSpiralInsets(SliceLayerPart *part, coord_t line_w } } -}//namespace cura +} // namespace cura diff --git a/src/settings/Settings.cpp b/src/settings/Settings.cpp index 895da1e644..41c3ed1f31 100644 --- a/src/settings/Settings.cpp +++ b/src/settings/Settings.cpp @@ -686,19 +686,19 @@ template<> PrimeTowerMethod Settings::get(const std::string& key) const { const std::string& value = get(key); - if(value == "default") + if (value == "default") { return PrimeTowerMethod::DEFAULT; } - else if(value == "optimized") + else if (value == "optimized") { return PrimeTowerMethod::OPTIMIZED; } - else if(value == "optimized_consistent") + else if (value == "optimized_consistent") { return PrimeTowerMethod::OPTIMIZED_CONSISTENT; } - else //Default. + else // Default. { return PrimeTowerMethod::NONE; } diff --git a/src/utils/LinearAlg2D.cpp b/src/utils/LinearAlg2D.cpp index 4a5c2d1cd3..6de830d72b 100644 --- a/src/utils/LinearAlg2D.cpp +++ b/src/utils/LinearAlg2D.cpp @@ -1,15 +1,15 @@ -//Copyright (c) 2022 Ultimaker B.V. -//CuraEngine is released under the terms of the AGPLv3 or higher. +// Copyright (c) 2022 Ultimaker B.V. +// CuraEngine is released under the terms of the AGPLv3 or higher. #include "utils/linearAlg2D.h" -#include // atan2 -#include -#include // swap - #include "utils/IntPoint.h" // dot -namespace cura +#include // swap +#include +#include // atan2 + +namespace cura { float LinearAlg2D::getAngleLeft(const Point& a, const Point& b, const Point& c) @@ -20,10 +20,7 @@ float LinearAlg2D::getAngleLeft(const Point& a, const Point& b, const Point& c) const coord_t det = ba.X * bc.Y - ba.Y * bc.X; // determinant if (det == 0) { - if ( - (ba.X != 0 && (ba.X > 0) == (bc.X > 0)) - || (ba.X == 0 && (ba.Y > 0) == (bc.Y > 0)) - ) + if ((ba.X != 0 && (ba.X > 0) == (bc.X > 0)) || (ba.X == 0 && (ba.Y > 0) == (bc.Y > 0))) { return 0; // pointy bit } @@ -37,7 +34,7 @@ float LinearAlg2D::getAngleLeft(const Point& a, const Point& b, const Point& c) { return angle; } - else + else { return M_PI * 2 + angle; } @@ -55,7 +52,7 @@ bool LinearAlg2D::getPointOnLineWithDist(const Point& p, const Point& a, const P const Point ab = b - a; const coord_t ab_size = vSize(ab); const Point ap = p - a; - const coord_t ax_size = (ab_size < 50)? dot(normal(ab, 1000), ap) / 1000 : dot(ab, ap) / ab_size; + const coord_t ax_size = (ab_size < 50) ? dot(normal(ab, 1000), ap) / 1000 : dot(ab, ap) / ab_size; const coord_t ap_size2 = vSize2(ap); const coord_t px_size = sqrt(std::max(coord_t(0), ap_size2 - ax_size * ax_size)); if (px_size > dist) @@ -159,9 +156,10 @@ bool LinearAlg2D::lineSegmentsCollide(const Point& a_from_transformed, const Poi { assert(std::abs(a_from_transformed.Y - a_to_transformed.Y) < 2 && "line a is supposed to be transformed to be aligned with the X axis!"); assert(a_from_transformed.X - 2 <= a_to_transformed.X && "line a is supposed to be aligned with X axis in positive direction!"); - if ((b_from_transformed.Y >= a_from_transformed.Y && b_to_transformed.Y <= a_from_transformed.Y) || (b_to_transformed.Y >= a_from_transformed.Y && b_from_transformed.Y <= a_from_transformed.Y)) + if ((b_from_transformed.Y >= a_from_transformed.Y && b_to_transformed.Y <= a_from_transformed.Y) + || (b_to_transformed.Y >= a_from_transformed.Y && b_from_transformed.Y <= a_from_transformed.Y)) { - if(b_to_transformed.Y == b_from_transformed.Y) + if (b_to_transformed.Y == b_from_transformed.Y) { if (b_to_transformed.X < b_from_transformed.X) { @@ -179,7 +177,8 @@ bool LinearAlg2D::lineSegmentsCollide(const Point& a_from_transformed, const Poi } else { - const coord_t x = b_from_transformed.X + (b_to_transformed.X - b_from_transformed.X) * (a_from_transformed.Y - b_from_transformed.Y) / (b_to_transformed.Y - b_from_transformed.Y); + const coord_t x + = b_from_transformed.X + (b_to_transformed.X - b_from_transformed.X) * (a_from_transformed.Y - b_from_transformed.Y) / (b_to_transformed.Y - b_from_transformed.Y); if (x >= a_from_transformed.X && x <= a_to_transformed.X) { return true; @@ -214,26 +213,25 @@ bool LinearAlg2D::isInsideCorner(const Point a, const Point b, const Point c, co */ - - constexpr coord_t normal_length = 10000; //Create a normal vector of reasonable length in order to reduce rounding error. + constexpr coord_t normal_length = 10000; // Create a normal vector of reasonable length in order to reduce rounding error. const Point ba = normal(a - b, normal_length); const Point bc = normal(c - b, normal_length); const Point bq = query_point - b; - const Point perpendicular = turn90CCW(bq); //The query projects to this perpendicular to coordinate 0. - const coord_t project_a_perpendicular = dot(ba, perpendicular); //Project vertex A on the perpendicular line. - const coord_t project_c_perpendicular = dot(bc, perpendicular); //Project vertex C on the perpendicular line. - if ((project_a_perpendicular > 0) != (project_c_perpendicular > 0)) //Query is between A and C on the projection. + const Point perpendicular = turn90CCW(bq); // The query projects to this perpendicular to coordinate 0. + const coord_t project_a_perpendicular = dot(ba, perpendicular); // Project vertex A on the perpendicular line. + const coord_t project_c_perpendicular = dot(bc, perpendicular); // Project vertex C on the perpendicular line. + if ((project_a_perpendicular > 0) != (project_c_perpendicular > 0)) // Query is between A and C on the projection. { - return project_a_perpendicular > 0; //Due to the winding order of corner ABC, this means that the query is inside. + return project_a_perpendicular > 0; // Due to the winding order of corner ABC, this means that the query is inside. } - else //Beyond either A or C, but it could still be inside of the polygon. + else // Beyond either A or C, but it could still be inside of the polygon. { - const coord_t project_a_parallel = dot(ba, bq); //Project not on the perpendicular, but on the original. + const coord_t project_a_parallel = dot(ba, bq); // Project not on the perpendicular, but on the original. const coord_t project_c_parallel = dot(bc, bq); - //Either: - // * A is to the right of B (project_a_perpendicular > 0) and C is below A (project_c_parallel < project_a_parallel), or - // * A is to the left of B (project_a_perpendicular < 0) and C is above A (project_c_parallel > project_a_parallel). + // Either: + // * A is to the right of B (project_a_perpendicular > 0) and C is below A (project_c_parallel < project_a_parallel), or + // * A is to the left of B (project_a_perpendicular < 0) and C is above A (project_c_parallel > project_a_parallel). return (project_c_parallel < project_a_parallel) == (project_a_perpendicular > 0); } } @@ -248,7 +246,7 @@ coord_t LinearAlg2D::getDistFromLine(const Point& p, const Point& a, const Point const Point vab = b - a; const Point vap = p - a; const double ab_size = vSize(vab); - if(ab_size == 0) //Line of 0 length. Assume it's a line perpendicular to the direction to p. + if (ab_size == 0) // Line of 0 length. Assume it's a line perpendicular to the direction to p. { return vSize(vap); } diff --git a/src/utils/polygonUtils.cpp b/src/utils/polygonUtils.cpp index f5bd412f43..7eebc8dc43 100644 --- a/src/utils/polygonUtils.cpp +++ b/src/utils/polygonUtils.cpp @@ -1,27 +1,33 @@ // Copyright (c) 2023 UltiMaker // CuraEngine is released under the terms of the AGPLv3 or higher +#include "utils/polygonUtils.h" + #include "infill.h" #include "utils/SparsePointGridInclusive.h" #include "utils/linearAlg2D.h" -#include "utils/polygonUtils.h" + +#include #include #include #include #include -#include #ifdef DEBUG #include "utils/AABB.h" #include "utils/SVG.h" + #include #endif namespace cura { -const std::function PolygonUtils::no_penalty_function = [](Point) { return 0; }; +const std::function PolygonUtils::no_penalty_function = [](Point) +{ + return 0; +}; int64_t PolygonUtils::segmentLength(PolygonsPointIndex start, PolygonsPointIndex end) { @@ -98,7 +104,7 @@ std::vector PolygonUtils::spreadDotsArea(const Polygons& polygons, Point Infill infill_gen(EFillMethod::LINES, false, false, polygons, 0, grid_size.X, 0, 1, 0, 0, 0, 0, 0); Polygons result_polygons; Polygons result_lines; - infill_gen.generate(dummy_toolpaths, result_polygons, result_lines, dummy_settings, 0, SectionType::DOTS); // FIXME: @jellespijker make sure the propper layer nr is used + infill_gen.generate(dummy_toolpaths, result_polygons, result_lines, dummy_settings, 0, SectionType::DOTS); // FIXME: @jellespijker make sure the propper layer nr is used std::vector result; for (PolygonRef line : result_lines) { @@ -120,7 +126,13 @@ std::vector PolygonUtils::spreadDotsArea(const Polygons& polygons, Point return result; } -bool PolygonUtils::lineSegmentPolygonsIntersection(const Point& a, const Point& b, const Polygons& current_outlines, const LocToLineGrid& outline_locator, Point& result, const coord_t within_max_dist) +bool PolygonUtils::lineSegmentPolygonsIntersection( + const Point& a, + const Point& b, + const Polygons& current_outlines, + const LocToLineGrid& outline_locator, + Point& result, + const coord_t within_max_dist) { const coord_t within_max_dist2 = within_max_dist * within_max_dist; @@ -129,7 +141,8 @@ bool PolygonUtils::lineSegmentPolygonsIntersection(const Point& a, const Point& const auto processOnIntersect = [&result, &closest_dist2, &a, &b, &coll](const Point& p_start, const Point& p_end) { - if (LinearAlg2D::lineLineIntersection(a, b, p_start, p_end, coll) && LinearAlg2D::pointIsProjectedBeyondLine(coll, p_start, p_end) == 0 && LinearAlg2D::pointIsProjectedBeyondLine(coll, a, b) == 0) + if (LinearAlg2D::lineLineIntersection(a, b, p_start, p_end, coll) && LinearAlg2D::pointIsProjectedBeyondLine(coll, p_start, p_end) == 0 + && LinearAlg2D::pointIsProjectedBeyondLine(coll, a, b) == 0) { const coord_t dist2 = vSize2(b - coll); if (dist2 < closest_dist2) @@ -233,13 +246,14 @@ unsigned int PolygonUtils::moveOutside(const Polygons& polygons, Point& from, in return moveInside(polygons, from, -distance, maxDist2); } -ClosestPolygonPoint PolygonUtils::moveInside2(const Polygons& polygons, - Point& from, - const int distance, - const int64_t max_dist2, - const Polygons* loc_to_line_polygons, - const LocToLineGrid* loc_to_line_grid, - const std::function& penalty_function) +ClosestPolygonPoint PolygonUtils::moveInside2( + const Polygons& polygons, + Point& from, + const int distance, + const int64_t max_dist2, + const Polygons* loc_to_line_polygons, + const LocToLineGrid* loc_to_line_grid, + const std::function& penalty_function) { std::optional closest_polygon_point; if (loc_to_line_grid) @@ -253,8 +267,14 @@ ClosestPolygonPoint PolygonUtils::moveInside2(const Polygons& polygons, return _moveInside2(*closest_polygon_point, distance, from, max_dist2); } -ClosestPolygonPoint - PolygonUtils::moveInside2(const Polygons& loc_to_line_polygons, ConstPolygonRef polygon, Point& from, const int distance, const int64_t max_dist2, const LocToLineGrid* loc_to_line_grid, const std::function& penalty_function) +ClosestPolygonPoint PolygonUtils::moveInside2( + const Polygons& loc_to_line_polygons, + ConstPolygonRef polygon, + Point& from, + const int distance, + const int64_t max_dist2, + const LocToLineGrid* loc_to_line_grid, + const std::function& penalty_function) { std::optional closest_polygon_point; if (loc_to_line_grid) @@ -596,25 +616,27 @@ Point PolygonUtils::moveInside(const ClosestPolygonPoint& cpp, const int distanc } } -ClosestPolygonPoint PolygonUtils::ensureInsideOrOutside(const Polygons& polygons, - Point& from, - int preferred_dist_inside, - int64_t max_dist2, - const Polygons* loc_to_line_polygons, - const LocToLineGrid* loc_to_line_grid, - const std::function& penalty_function) +ClosestPolygonPoint PolygonUtils::ensureInsideOrOutside( + const Polygons& polygons, + Point& from, + int preferred_dist_inside, + int64_t max_dist2, + const Polygons* loc_to_line_polygons, + const LocToLineGrid* loc_to_line_grid, + const std::function& penalty_function) { const ClosestPolygonPoint closest_polygon_point = moveInside2(polygons, from, preferred_dist_inside, max_dist2, loc_to_line_polygons, loc_to_line_grid, penalty_function); return ensureInsideOrOutside(polygons, from, closest_polygon_point, preferred_dist_inside, loc_to_line_polygons, loc_to_line_grid, penalty_function); } -ClosestPolygonPoint PolygonUtils::ensureInsideOrOutside(const Polygons& polygons, - Point& from, - const ClosestPolygonPoint& closest_polygon_point, - int preferred_dist_inside, - const Polygons* loc_to_line_polygons, - const LocToLineGrid* loc_to_line_grid, - const std::function& penalty_function) +ClosestPolygonPoint PolygonUtils::ensureInsideOrOutside( + const Polygons& polygons, + Point& from, + const ClosestPolygonPoint& closest_polygon_point, + int preferred_dist_inside, + const Polygons* loc_to_line_polygons, + const LocToLineGrid* loc_to_line_grid, + const std::function& penalty_function) { if (! closest_polygon_point.isValid()) { @@ -646,7 +668,8 @@ ClosestPolygonPoint PolygonUtils::ensureInsideOrOutside(const Polygons& polygons else { const coord_t offset = (is_outside_boundary) ? -preferred_dist_inside : preferred_dist_inside; // perform inset on outer boundary and outset on holes - Polygons insetted = closest_poly.offset(offset / 2); // perform less inset, because chances are (thin parts of) the polygon will disappear, given that moveInside did an overshoot + Polygons insetted + = closest_poly.offset(offset / 2); // perform less inset, because chances are (thin parts of) the polygon will disappear, given that moveInside did an overshoot if (insetted.size() == 0) { return ClosestPolygonPoint(); // we couldn't move inside @@ -666,7 +689,7 @@ ClosestPolygonPoint PolygonUtils::ensureInsideOrOutside(const Polygons& polygons { #ifdef DEBUG static bool has_run = false; - if ( ! has_run) + if (! has_run) { try { @@ -755,7 +778,8 @@ void PolygonUtils::walkToNearestSmallestConnection(ClosestPolygonPoint& poly1_re // \-'| // o o >> should find connection here coord_t best_distance2 = vSize2(poly1_result.p() - poly2_result.p()); - auto check_neighboring_vert = [&best_distance2](ConstPolygonRef from_poly, ConstPolygonRef to_poly, ClosestPolygonPoint& from_poly_result, ClosestPolygonPoint& to_poly_result, bool vertex_after) + auto check_neighboring_vert + = [&best_distance2](ConstPolygonRef from_poly, ConstPolygonRef to_poly, ClosestPolygonPoint& from_poly_result, ClosestPolygonPoint& to_poly_result, bool vertex_after) { const Point after_poly2_result = to_poly[(to_poly_result.point_idx + vertex_after) % to_poly.size()]; const ClosestPolygonPoint poly1_after_poly2_result = findNearestClosest(after_poly2_result, from_poly, from_poly_result.point_idx); @@ -978,7 +1002,8 @@ std::unique_ptr PolygonUtils::createLocToLineGrid(const Polygons& * * We could skip the duplication by keeping a vector of vectors of bools. */ -std::optional PolygonUtils::findClose(Point from, const Polygons& polygons, const LocToLineGrid& loc_to_line, const std::function& penalty_function) +std::optional + PolygonUtils::findClose(Point from, const Polygons& polygons, const LocToLineGrid& loc_to_line, const std::function& penalty_function) { std::vector near_lines = loc_to_line.getNearby(from, loc_to_line.getCellSize()); @@ -1011,7 +1036,8 @@ std::optional PolygonUtils::findClose(Point from, const Pol } } -std::vector> PolygonUtils::findClose(ConstPolygonRef from, const Polygons& destination, const LocToLineGrid& destination_loc_to_line, const std::function& penalty_function) +std::vector> + PolygonUtils::findClose(ConstPolygonRef from, const Polygons& destination, const LocToLineGrid& destination_loc_to_line, const std::function& penalty_function) { std::vector> ret; int p0_idx = from.size() - 1; @@ -1166,7 +1192,8 @@ std::optional PolygonUtils::getNextParallelIntersection(con coord_t prev_projected = 0; for (unsigned int next_point_nr = 0; next_point_nr < poly.size(); next_point_nr++) { - const unsigned int next_point_idx = forward ? (start.point_idx + 1 + next_point_nr) % poly.size() : (static_cast(start.point_idx) - next_point_nr + poly.size()) % poly.size(); // cast in order to accomodate subtracting + const unsigned int next_point_idx = forward ? (start.point_idx + 1 + next_point_nr) % poly.size() + : (static_cast(start.point_idx) - next_point_nr + poly.size()) % poly.size(); // cast in order to accomodate subtracting const Point next_vert = poly[next_point_idx]; const Point so = next_vert - s; const coord_t projected = dot(shift, so) / dist; @@ -1176,7 +1203,8 @@ std::optional PolygonUtils::getNextParallelIntersection(con const coord_t segment_length = vSize(segment_vector); const coord_t projected_segment_length = std::abs(projected - prev_projected); const int16_t sign = (projected > 0) ? 1 : -1; - const coord_t projected_inter_segment_length = dist - sign * prev_projected; // add the prev_projected to dist if it is projected to the other side of the input line than where the intersection occurs. + const coord_t projected_inter_segment_length + = dist - sign * prev_projected; // add the prev_projected to dist if it is projected to the other side of the input line than where the intersection occurs. const coord_t inter_segment_length = segment_length * projected_inter_segment_length / projected_segment_length; const Point intersection = prev_vert + normal(next_vert - prev_vert, inter_segment_length); @@ -1212,7 +1240,8 @@ bool PolygonUtils::polygonCollidesWithLineSegment(const Point from, const Point PolygonsPointIndex result; - std::function process_elem_func = [transformed_from, transformed_to, &transformation_matrix, &result, &ret](const PolygonsPointIndex& line_start) + std::function process_elem_func + = [transformed_from, transformed_to, &transformation_matrix, &result, &ret](const PolygonsPointIndex& line_start) { Point p0 = transformation_matrix.apply(line_start.p()); Point p1 = transformation_matrix.apply(line_start.next().p()); @@ -1331,7 +1360,11 @@ bool PolygonUtils::polygonOutlinesAdjacent(const ConstPolygonRef inner_poly, con return false; } -void PolygonUtils::findAdjacentPolygons(std::vector& adjacent_poly_indices, const ConstPolygonRef& poly, const std::vector& possible_adjacent_polys, const coord_t max_gap) +void PolygonUtils::findAdjacentPolygons( + std::vector& adjacent_poly_indices, + const ConstPolygonRef& poly, + const std::vector& possible_adjacent_polys, + const coord_t max_gap) { // given a polygon, and a vector of polygons, return a vector containing the indices of the polygons that are adjacent to the given polygon for (unsigned poly_idx = 0; poly_idx < possible_adjacent_polys.size(); ++poly_idx) @@ -1381,7 +1414,7 @@ double PolygonUtils::relativeHammingDistance(const Polygons& poly_a, const Polyg return hamming_distance / total_area; } -Polygon PolygonUtils::makeCircle(const Point &mid, const coord_t radius, const AngleRadians a_step) +Polygon PolygonUtils::makeCircle(const Point& mid, const coord_t radius, const AngleRadians a_step) { Polygon circle; for (float a = 0; a < 2 * M_PI; a += a_step) @@ -1391,31 +1424,31 @@ Polygon PolygonUtils::makeCircle(const Point &mid, const coord_t radius, const A return circle; } -Polygon PolygonUtils::makeWheel(const Point &mid, const coord_t inner_radius, const coord_t outer_radius, const size_t semi_nb_spokes, const size_t arc_angle_resolution) +Polygon PolygonUtils::makeWheel(const Point& mid, const coord_t inner_radius, const coord_t outer_radius, const size_t semi_nb_spokes, const size_t arc_angle_resolution) { Polygon wheel; std::vector> target_radii; - target_radii.push_back({inner_radius, outer_radius}); - target_radii.push_back({outer_radius, inner_radius}); + target_radii.push_back({ inner_radius, outer_radius }); + target_radii.push_back({ outer_radius, inner_radius }); const size_t nb_spokes = semi_nb_spokes * 2; const float angle_step = TAU / nb_spokes; const float arc_step = angle_step / arc_angle_resolution; float angle = 0.0; - for(size_t spoke = 0 ; spoke < nb_spokes ; ++spoke) + for (size_t spoke = 0; spoke < nb_spokes; ++spoke) { - const std::pair &radii = target_radii.at(spoke % 2); + const std::pair& radii = target_radii.at(spoke % 2); angle = spoke * angle_step; float cos_angle = cos(angle); float sin_angle = sin(angle); wheel.emplace_back(mid + Point(radii.first * cos_angle, radii.first * sin_angle)); - for(size_t arc_part = 0 ; arc_part < arc_angle_resolution ; ++arc_part) + for (size_t arc_part = 0; arc_part < arc_angle_resolution; ++arc_part) { wheel.emplace_back(mid + Point(radii.second * cos_angle, radii.second * sin_angle)); - if(arc_part < arc_angle_resolution - 1) + if (arc_part < arc_angle_resolution - 1) { angle += arc_step; cos_angle = cos(angle); @@ -1562,7 +1595,11 @@ Polygons PolygonUtils::clipPolygonWithAABB(const Polygons& src, const AABB& aabb Bottom = 8 }; - auto sides = [aabb](const Point& p) { return int(p.X < aabb.min.X) * int(Side::Left) + int(p.X > aabb.max.X) * int(Side::Right) + int(p.Y < aabb.min.Y) * int(Side::Bottom) + int(p.Y > aabb.max.Y) * int(Side::Top); }; + auto sides = [aabb](const Point& p) + { + return int(p.X < aabb.min.X) * int(Side::Left) + int(p.X > aabb.max.X) * int(Side::Right) + int(p.Y < aabb.min.Y) * int(Side::Bottom) + + int(p.Y > aabb.max.Y) * int(Side::Top); + }; int sides_prev = sides(path.back()); int sides_this = sides(path.front()); From d3cf694d24d7256f3988b9a2f51c0088f77016f3 Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Tue, 5 Sep 2023 13:28:48 +0200 Subject: [PATCH 012/201] Fix build --- include/LayerPlanBuffer.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/include/LayerPlanBuffer.h b/include/LayerPlanBuffer.h index 4e05ffcade..fc61f017c1 100644 --- a/include/LayerPlanBuffer.h +++ b/include/LayerPlanBuffer.h @@ -8,11 +8,13 @@ #include "Preheat.h" #include "settings/types/Duration.h" +#include "settings/Settings.h" namespace cura { class ExtruderPlan; +class GCodeExport; class LayerPlan; /*! @@ -204,4 +206,4 @@ class LayerPlanBuffer } // namespace cura -#endif // LAYER_PLAN_BUFFER_H \ No newline at end of file +#endif // LAYER_PLAN_BUFFER_H From a4dfabe33a7e727aff660a3d8b729ea50b3d1523 Mon Sep 17 00:00:00 2001 From: wawanbreton Date: Tue, 5 Sep 2023 11:30:03 +0000 Subject: [PATCH 013/201] Applied clang-format. --- include/LayerPlanBuffer.h | 76 ++++++++++++++++++++------------------- 1 file changed, 40 insertions(+), 36 deletions(-) diff --git a/include/LayerPlanBuffer.h b/include/LayerPlanBuffer.h index fc61f017c1..c2e8aee899 100644 --- a/include/LayerPlanBuffer.h +++ b/include/LayerPlanBuffer.h @@ -1,16 +1,16 @@ -//Copyright (c) 2018 Ultimaker B.V. -//CuraEngine is released under the terms of the AGPLv3 or higher. +// Copyright (c) 2018 Ultimaker B.V. +// CuraEngine is released under the terms of the AGPLv3 or higher. #ifndef LAYER_PLAN_BUFFER_H #define LAYER_PLAN_BUFFER_H -#include - #include "Preheat.h" -#include "settings/types/Duration.h" #include "settings/Settings.h" +#include "settings/types/Duration.h" -namespace cura +#include + +namespace cura { class ExtruderPlan; @@ -19,16 +19,16 @@ class LayerPlan; /*! * Class for buffering multiple layer plans (\ref LayerPlan) / extruder plans within those layer plans, so that temperature commands can be inserted in earlier layer plans. - * + * * This class handles where to insert temperature commands for: * - initial layer temperature * - flow dependent temperature * - starting to heat up from the standby temperature * - initial printing temperature | printing temperature | final printing temperature - * + * * \image html assets/precool.png "Temperature Regulation" width=10cm * \image latex assets/precool.png "Temperature Regulation" width=10cm - * + * */ class LayerPlanBuffer { @@ -36,25 +36,30 @@ class LayerPlanBuffer Preheat preheat_config; //!< the nozzle and material temperature settings for each extruder train. - static constexpr size_t buffer_size = 5; // should be as low as possible while still allowing enough time in the buffer to heat up from standby temp to printing temp // TODO: hardcoded value + static constexpr size_t buffer_size + = 5; // should be as low as possible while still allowing enough time in the buffer to heat up from standby temp to printing temp // TODO: hardcoded value // this value should be higher than 1, cause otherwise each layer is viewed as the first layer and no temp commands are inserted. - static constexpr Duration extra_preheat_time = 1.0_s; //!< Time to start heating earlier than computed to avoid accummulative discrepancy between actual heating times and computed ones. + static constexpr Duration extra_preheat_time + = 1.0_s; //!< Time to start heating earlier than computed to avoid accummulative discrepancy between actual heating times and computed ones. - std::vector extruder_used_in_meshgroup; //!< For each extruder whether it has already been planned once in this meshgroup. This is used to see whether we should heat to the initial_print_temp or to the extrusion_temperature + std::vector extruder_used_in_meshgroup; //!< For each extruder whether it has already been planned once in this meshgroup. This is used to see whether we should heat to + //!< the initial_print_temp or to the extrusion_temperature /*! * The buffer containing several layer plans (LayerPlan) before writing them to gcode. - * + * * The front is the lowest/oldest layer. * The back is the highest/newest layer. */ std::list buffer; + public: LayerPlanBuffer(GCodeExport& gcode) - : gcode(gcode) - , extruder_used_in_meshgroup(MAX_EXTRUDERS, false) - { } + : gcode(gcode) + , extruder_used_in_meshgroup(MAX_EXTRUDERS, false) + { + } void setPreheatConfig(); @@ -66,7 +71,7 @@ class LayerPlanBuffer /*! * Push a new layer onto the buffer and handle the buffer. * Write a layer to gcode if it is popped out of the buffer. - * + * * \param layer_plan The layer to handle * \param gcode The exporter with which to write a layer to gcode if the buffer is too large after pushing the new layer. */ @@ -83,7 +88,7 @@ class LayerPlanBuffer * This inserts the temperature commands to start warming for a given layer in earlier layers; * the fan speeds and layer time settings of the most recently pushed layer are processed; * the correctly combing travel move between the last added layer and the layer before is added. - * + * * Pop out the earliest layer in the buffer if the buffer size is exceeded * \return A nullptr or the popped gcode_layer */ @@ -91,7 +96,7 @@ class LayerPlanBuffer /*! * Add the travel move to properly travel from the end location of the previous layer to the starting location of the next - * + * * \param prev_layer The layer before the just added layer, to which to add the combing travel move. * \param newest_layer The newly added layer, with a non-combing travel move as first path. */ @@ -104,7 +109,7 @@ class LayerPlanBuffer /*! * Insert a preheat command for @p extruder into @p extruder_plan_before - * + * * \param extruder_plan_before An extruder plan before the extruder plan for which the temperature is computed, in which to insert the preheat command * \param time_before_extruder_plan_end The time before the end of the extruder plan, before which to insert the preheat command * \param extruder_nr The extruder for which to set the temperature @@ -115,9 +120,9 @@ class LayerPlanBuffer /*! * Compute the time needed to preheat from standby to required (initial) printing temperature at the start of an extruder plan, * based on the time the extruder has been on standby. - * + * * Also computes the temperature to which we cool before starting to heat agian. - * + * * \param extruder_plans The extruder plans in the buffer, moved to a temporary vector (from lower to upper layers) * \param extruder_plan_idx The index of the extruder plan in \p extruder_plans for which to find the preheat time needed * \return the time needed to preheat and the temperature from which heating starts @@ -125,11 +130,11 @@ class LayerPlanBuffer Preheat::WarmUpResult computeStandbyTempPlan(std::vector& extruder_plans, unsigned int extruder_plan_idx); /*! - * For two consecutive extruder plans of the same extruder (so on different layers), + * For two consecutive extruder plans of the same extruder (so on different layers), * preheat the extruder to the temperature corresponding to the average flow of the second extruder plan. - * + * * The preheat commands are inserted such that the middle of the temperature change coincides with the start of the next layer. - * + * * \param prev_extruder_plan The former extruder plan (of the former layer) * \param extruder_nr The extruder for which too set the temperature * \param required_temp The required temperature for the second extruder plan @@ -141,7 +146,7 @@ class LayerPlanBuffer * Find the time window in which this extruder hasn't been used * and compute at what time the preheat command needs to be inserted. * Then insert the preheat command in the right extruder plan. - * + * * \param extruder_plans The extruder plans in the buffer, moved to a temporary vector (from lower to upper layers) * \param extruder_plan_idx The index of the extruder plan in \p extruder_plans for which to find the preheat time needed */ @@ -150,15 +155,15 @@ class LayerPlanBuffer /*! * Insert temperature commands related to the extruder plan corersponding to @p extruder_plan_idx * and the extruder plan before: - * + * * In case the extruder plan before has the same extruder: * - gradually change printing temperature around the layer change (\ref LayerPlanBuffer::insertPreheatCommand_singleExtrusion) - * + * * In case the previous extruder plan is a different extruder * - insert preheat command from standby to initial temp in the extruder plan(s) before (\ref LayerPlanBuffer::insertPreheatCommand_multiExtrusion) * - insert the final print temp command of the previous extruder plan (\ref LayerPlanBuffer::insertFinalPrintTempCommand) * - insert the normal extrusion temp command for the current extruder plan (\ref LayerPlanBuffer::insertPrintTempCommand) - * + * * \param extruder_plans The extruder plans in the buffer, moved to a temporary vector (from lower to upper layers) * \param extruder_plan_idx The index of the extruder plan in \p extruder_plans for which to generate the preheat command */ @@ -166,20 +171,20 @@ class LayerPlanBuffer /*! * Insert the temperature command to heat from the initial print temperature to the printing temperature - * + * * The temperature command is insert at the start of the very first extrusion move - * + * * \param extruder_plan The extruder plan in which to insert the heat up command */ void insertPrintTempCommand(ExtruderPlan& extruder_plan); /*! * Insert the temp command to start cooling from the printing temperature to the final print temp - * + * * The print temp is inserted before the last extrusion move of the extruder plan corresponding to \p last_extruder_plan_idx - * + * * The command is inserted at a timed offset before the end of the last extrusion move - * + * * \param extruder_plans The extruder plans in the buffer, moved to a temporary vector (from lower to upper layers) * \param last_extruder_plan_idx The index of the last extruder plan in \p extruder_plans with the same extruder as previous extruder plans */ @@ -194,7 +199,7 @@ class LayerPlanBuffer * Reconfigure the standby temperature during which we didn't print with this extruder. * Find the previous extruder plan with the same extruder as layers[layer_plan_idx].extruder_plans[extruder_plan_idx] * Set the prev_extruder_standby_temp in the next extruder plan - * + * * \param extruder_plans The extruder plans in the buffer, moved to a temporary vector (from lower to upper layers) * \param extruder_plan_idx The index of the extruder plan in \p extruder_plans before which to reconfigure the standby temperature * \param standby_temp The temperature to which to cool down when the extruder is in standby mode. @@ -203,7 +208,6 @@ class LayerPlanBuffer }; - } // namespace cura #endif // LAYER_PLAN_BUFFER_H From a04d26e66c3757257e65929cd678cdae14c54e80 Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Wed, 13 Sep 2023 10:25:19 +0200 Subject: [PATCH 014/201] Fixed build --- include/FffGcodeWriter.h | 2 ++ src/FffGcodeWriter.cpp | 1 + 2 files changed, 3 insertions(+) diff --git a/include/FffGcodeWriter.h b/include/FffGcodeWriter.h index 2d2e7c7162..7a2f5f34f2 100644 --- a/include/FffGcodeWriter.h +++ b/include/FffGcodeWriter.h @@ -70,6 +70,8 @@ class FffGcodeWriter : public NoCopy std::vector> mesh_order_per_extruder; //!< For each extruder, the order of the meshes (first element is first mesh to be printed) + std::vector> extruder_prime_required_by_layer; //!< For each layer, indicates which extruders actually require to be primed + /*! * For each extruder on which layer the prime will be planned, * or a large negative number if it's already planned outside of \ref FffGcodeWriter::processLayer diff --git a/src/FffGcodeWriter.cpp b/src/FffGcodeWriter.cpp index 63c1d1b58f..b1643f35ee 100644 --- a/src/FffGcodeWriter.cpp +++ b/src/FffGcodeWriter.cpp @@ -1229,6 +1229,7 @@ void FffGcodeWriter::processSkirtBrim(const SliceDataStorage& storage, LayerPlan // Add the support brim after the skirt_brim to gcode_layer // For support brim we don't care about the order, because support doesn't need to be accurate. + const Settings& mesh_group_settings = Application::getInstance().current_slice->scene.current_mesh_group->settings; if (extruder_nr == mesh_group_settings.get("support_extruder_nr_layer_0").extruder_nr) { total_line_count += storage.support_brim.size(); From d6fd172ae8df0bacb3beed5b14109228583ea8e0 Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Thu, 14 Sep 2023 13:40:35 +0200 Subject: [PATCH 015/201] TO BE DISCUSSED removed assert which crashes --- src/LayerPlanBuffer.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/LayerPlanBuffer.cpp b/src/LayerPlanBuffer.cpp index 6551543bdc..69f858d6ca 100644 --- a/src/LayerPlanBuffer.cpp +++ b/src/LayerPlanBuffer.cpp @@ -89,8 +89,8 @@ void LayerPlanBuffer::addConnectingTravelMove(LayerPlan* prev_layer, const Layer Point first_location_new_layer = new_layer_destination_state->first; - assert(newest_layer->extruder_plans.front().paths[0].points.size() == 1); - assert(newest_layer->extruder_plans.front().paths[0].points[0] == first_location_new_layer); + // assert(newest_layer->extruder_plans.front().paths[0].points.size() == 1); + // assert(newest_layer->extruder_plans.front().paths[0].points[0] == first_location_new_layer); // if the last planned position in the previous layer isn't the same as the first location of the new layer, travel to the new location if (! prev_layer->last_planned_position || *prev_layer->last_planned_position != first_location_new_layer) From d2e737d39886eaa7e7a67b8c17615b23708a6878 Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Fri, 15 Sep 2023 10:15:41 +0200 Subject: [PATCH 016/201] WIP Implement optimized-consistent prime tower --- include/ExtruderPrime.h | 18 +++ include/ExtruderUse.h | 20 +++ include/FffGcodeWriter.h | 11 +- include/PrimeTower.h | 5 +- src/FffGcodeWriter.cpp | 178 +++++++++++++++------ src/PrimeTower.cpp | 338 +++++++++++++++++++++++---------------- 6 files changed, 378 insertions(+), 192 deletions(-) create mode 100644 include/ExtruderPrime.h create mode 100644 include/ExtruderUse.h diff --git a/include/ExtruderPrime.h b/include/ExtruderPrime.h new file mode 100644 index 0000000000..d422b874a9 --- /dev/null +++ b/include/ExtruderPrime.h @@ -0,0 +1,18 @@ +//Copyright (c) 2023 UltiMaker B.V. +//CuraEngine is released under the terms of the AGPLv3 or higher. + +#ifndef EXTRUDERPRIME_H +#define EXTRUDERPRIME_H + +namespace cura +{ + +enum class ExtruderPrime +{ + None, // Do not prime at all for this extruder on this layer + Sparse, // Just extrude a sparse priming which purpose is to make the tower stronger + Prime, // Do an actual prime +}; + +}//namespace cura +#endif // EXTRUDERPRIME_H diff --git a/include/ExtruderUse.h b/include/ExtruderUse.h new file mode 100644 index 0000000000..33e21c5b80 --- /dev/null +++ b/include/ExtruderUse.h @@ -0,0 +1,20 @@ +//Copyright (c) 2023 UltiMaker B.V. +//CuraEngine is released under the terms of the AGPLv3 or higher. + +#ifndef EXTRUDERUSE_H +#define EXTRUDERUSE_H + +#include "ExtruderPrime.h" +#include + +namespace cura +{ + +struct ExtruderUse +{ + size_t extruder_nr; + ExtruderPrime prime; +}; + +}//namespace cura +#endif // EXTRUDERUSE_H diff --git a/include/FffGcodeWriter.h b/include/FffGcodeWriter.h index 7a2f5f34f2..b3078b41e8 100644 --- a/include/FffGcodeWriter.h +++ b/include/FffGcodeWriter.h @@ -4,6 +4,7 @@ #ifndef GCODE_WRITER_H #define GCODE_WRITER_H +#include "ExtruderPrime.h" #include "FanSpeedLayerTime.h" #include "LayerPlanBuffer.h" #include "gcodeExport.h" @@ -70,7 +71,7 @@ class FffGcodeWriter : public NoCopy std::vector> mesh_order_per_extruder; //!< For each extruder, the order of the meshes (first element is first mesh to be printed) - std::vector> extruder_prime_required_by_layer; //!< For each layer, indicates which extruders actually require to be primed + std::vector> extruder_prime_required_by_layer; //!< For each layer, indicates which extruders actually require to be primed /*! * For each extruder on which layer the prime will be planned, @@ -280,6 +281,12 @@ class FffGcodeWriter : public NoCopy */ void calculatePrimeLayerPerExtruder(const SliceDataStorage& storage); + struct ExtruderUse + { + size_t extruder_nr; + ExtruderPrime prime; + }; + /*! * Gets a list of extruders that are used on the given layer, but excluding the given starting extruder. * When it's on the first layer, the prime blob will also be taken into account. @@ -291,7 +298,7 @@ class FffGcodeWriter : public NoCopy * \param current_extruder The current extruder with which we last printed * \return The order of extruders for a layer beginning with \p current_extruder */ - std::vector getUsedExtrudersOnLayerExcludingStartingExtruder(const SliceDataStorage& storage, const size_t start_extruder, const LayerIndex& layer_nr) const; + std::vector getUsedExtrudersOnLayerExcludingStartingExtruder(const SliceDataStorage& storage, const size_t start_extruder, const LayerIndex& layer_nr) const; /*! * Calculate in which order to plan the meshes of a specific extruder diff --git a/include/PrimeTower.h b/include/PrimeTower.h index a4ea3c7bbd..d376dd0a18 100644 --- a/include/PrimeTower.h +++ b/include/PrimeTower.h @@ -9,6 +9,7 @@ #include "utils/polygon.h" // Polygons #include "utils/polygonUtils.h" +#include "ExtruderPrime.h" namespace cura { @@ -86,7 +87,7 @@ class PrimeTower * \param prev_extruder The previous extruder with which paths were planned; from which extruder a switch was made * \param new_extruder The switched to extruder with which the prime tower paths should be generated. */ - void addToGcode(const SliceDataStorage& storage, LayerPlan& gcode_layer, const std::vector &required_extruder_prime, const size_t prev_extruder, const size_t new_extruder) const; + void addToGcode(const SliceDataStorage& storage, LayerPlan& gcode_layer, const std::vector &required_extruder_prime, const size_t prev_extruder, const size_t new_extruder) const; /*! * \brief Subtract the prime tower from the support areas in storage. @@ -153,7 +154,7 @@ class PrimeTower void addToGcode_denseInfill(LayerPlan& gcode_layer, const size_t extruder) const; #warning TBD documentation - void addToGcode_optimizedInfill(LayerPlan& gcode_layer, const std::vector& required_extruder_prime, const size_t current_extruder, std::vector& primed_extruders) const; + void addToGcode_optimizedInfill(LayerPlan& gcode_layer, const std::vector &required_extruder_prime, const size_t current_extruder, std::vector& primed_extruders, bool group_with_next_extruders) const; /*! * For an extruder switch that happens not on the first layer, the extruder needs to be primed on the prime tower. diff --git a/src/FffGcodeWriter.cpp b/src/FffGcodeWriter.cpp index b1643f35ee..62b42371cc 100644 --- a/src/FffGcodeWriter.cpp +++ b/src/FffGcodeWriter.cpp @@ -1309,11 +1309,22 @@ void FffGcodeWriter::calculateExtruderOrderPerLayer(const SliceDataStorage& stor } size_t extruder_count = Application::getInstance().current_slice->scene.extruders.size(); + const Settings& mesh_group_settings = Application::getInstance().current_slice->scene.current_mesh_group->settings; + PrimeTowerMethod prime_tower_mode = mesh_group_settings.get("prime_tower_mode"); for (LayerIndex layer_nr = -Raft::getTotalExtraLayers(); layer_nr < static_cast(storage.print_layer_count); layer_nr++) { std::vector>& extruder_order_per_layer_here = (layer_nr < 0) ? extruder_order_per_layer_negative_layers : extruder_order_per_layer; - std::vector extruder_order = getUsedExtrudersOnLayerExcludingStartingExtruder(storage, last_extruder, layer_nr); - extruder_order_per_layer_here.push_back(extruder_order); + std::vector extruder_order = getUsedExtrudersOnLayerExcludingStartingExtruder(storage, last_extruder, layer_nr); + + std::vector extruder_order_ids; + std::vector extruder_primes; + for (const ExtruderUse& extruder_use : extruder_order) + { + extruder_order_ids.push_back(extruder_use.extruder_nr); + extruder_primes.push_back(extruder_use.prime); + } + extruder_order_per_layer_here.push_back(extruder_order_ids); + extruder_prime_required_by_layer.push_back(extruder_primes); #warning remove this #if 0 @@ -1324,23 +1335,37 @@ void FffGcodeWriter::calculateExtruderOrderPerLayer(const SliceDataStorage& stor } #endif - if (layer_nr >= 0 && ! extruder_order_per_layer_here.empty()) - { - std::vector extruder_prime_required(extruder_count, false); - - // First used extruder only needs to be primed if an other extruder has been used before - if (extruder_order.front() != last_extruder) - { - extruder_prime_required[extruder_order.front()] = true; - } - - // All other used extruders need to be primed - for (size_t index = 1; index < extruder_order.size(); ++index) - { - extruder_prime_required[extruder_order[index]] = true; - } - - extruder_prime_required_by_layer.push_back(extruder_prime_required); + // if (layer_nr >= 0 && ! extruder_order_per_layer_here.empty()) + // { + // ExtruderPrime default_prime; + // switch (prime_tower_mode) + // { + // case PrimeTowerMethod::NONE: + // case PrimeTowerMethod::DEFAULT: + // case PrimeTowerMethod::OPTIMIZED: + // default_prime = ExtruderPrime::None; + // break; + + // case PrimeTowerMethod::OPTIMIZED_CONSISTENT: + // default_prime = ExtruderPrime::Sparse; + // break; + // } + + // std::vector extruder_prime_required(extruder_count, default_prime); + + // // First used extruder only needs to be primed if an other extruder has been used before + // if (extruder_order.front() != last_extruder) + // { + // extruder_prime_required[extruder_order.front()] = ExtruderPrime::Prime; + // } + + // // All other used extruders need to be primed + // for (size_t index = 1; index < extruder_order.size(); ++index) + // { + // extruder_prime_required[extruder_order[index]] = ExtruderPrime::Prime; + // } + + // extruder_prime_required_by_layer.push_back(extruder_prime_required); #warning remove this #if 0 @@ -1350,9 +1375,7 @@ void FffGcodeWriter::calculateExtruderOrderPerLayer(const SliceDataStorage& stor logAlways("##### EX%d %d\n", extruder_nr, extruder_prime_required[extruder_nr] ? 1 : 0); } #endif - } - - last_extruder = extruder_order.back(); + last_extruder = extruder_order.back().extruder_nr; } } @@ -1371,58 +1394,115 @@ void FffGcodeWriter::calculatePrimeLayerPerExtruder(const SliceDataStorage& stor } } -std::vector FffGcodeWriter::getUsedExtrudersOnLayerExcludingStartingExtruder(const SliceDataStorage& storage, const size_t start_extruder, const LayerIndex& layer_nr) const +std::vector + FffGcodeWriter::getUsedExtrudersOnLayerExcludingStartingExtruder(const SliceDataStorage& storage, const size_t start_extruder, const LayerIndex& layer_nr) const { const Settings& mesh_group_settings = Application::getInstance().current_slice->scene.current_mesh_group->settings; size_t extruder_count = Application::getInstance().current_slice->scene.extruders.size(); assert(static_cast(extruder_count) > 0); - std::vector ret; + std::vector ret; std::vector extruder_is_used_on_this_layer = storage.getExtrudersUsed(layer_nr); PrimeTowerMethod method = mesh_group_settings.get("prime_tower_mode"); - // The outermost prime tower extruder is always used if there is a prime tower, apart on layers with negative index (e.g. for the raft) - if (method == PrimeTowerMethod::DEFAULT && layer_nr >= 0 && layer_nr <= storage.max_print_height_second_to_last_extruder) + // Make a temp list with the potential ordered extruders + std::vector ordered_extruders; + ordered_extruders.push_back(start_extruder); + for (size_t extruder_nr = 0; extruder_nr < extruder_count; extruder_nr++) { - extruder_is_used_on_this_layer[storage.primeTower.extruder_order[0]] = true; + if (extruder_nr != start_extruder) + { + ordered_extruders.push_back(extruder_nr); + } } - // check if we are on the first layer - if ((mesh_group_settings.get("adhesion_type") == EPlatformAdhesion::RAFT && layer_nr == -static_cast(Raft::getTotalExtraLayers())) - || (mesh_group_settings.get("adhesion_type") != EPlatformAdhesion::RAFT && layer_nr == 0)) + // Now check whether extuders should really used, and how + for (size_t extruder_nr : ordered_extruders) { - // check if we need prime blob on the first layer - for (size_t used_idx = 0; used_idx < extruder_is_used_on_this_layer.size(); used_idx++) + ExtruderPrime prime = ExtruderPrime::None; + + switch (method) { - if (getExtruderNeedPrimeBlobDuringFirstLayer(storage, used_idx)) + case PrimeTowerMethod::NONE: + break; + + case PrimeTowerMethod::DEFAULT: + if (extruder_nr == storage.primeTower.extruder_order[0] && layer_nr >= 0 && layer_nr <= storage.max_print_height_second_to_last_extruder) { - extruder_is_used_on_this_layer[used_idx] = true; + // The outermost prime tower extruder is always used if there is a prime tower, apart on layers with negative index (e.g. for the raft) + prime = ExtruderPrime::Prime; + } + else if (extruder_is_used_on_this_layer[extruder_nr]) + { + prime = ExtruderPrime::Prime; } + break; + + case PrimeTowerMethod::OPTIMIZED: + case PrimeTowerMethod::OPTIMIZED_CONSISTENT: + if (extruder_is_used_on_this_layer[extruder_nr]) + { +#warning only prime if different from actual extruder (for consistent only) + prime = ExtruderPrime::Prime; + } + else + { + prime = ExtruderPrime::Sparse; + } + break; + } + + if (extruder_is_used_on_this_layer[start_extruder] || prime != ExtruderPrime::None) + { + ret.push_back(ExtruderUse{ extruder_nr, prime }); } } - if (method != PrimeTowerMethod::OPTIMIZED || extruder_is_used_on_this_layer[start_extruder]) + spdlog::info(" {} ################", layer_nr); + for (const ExtruderUse& extruder_use : ret) { - ret.push_back(start_extruder); + spdlog::info("ext {} {}", int(extruder_use.extruder_nr), int(extruder_use.prime)); } - for (size_t extruder_nr = 0; extruder_nr < extruder_count; extruder_nr++) + // The outermost prime tower extruder is always used if there is a prime tower, apart on layers with negative index (e.g. for the raft) + // if (method == PrimeTowerMethod::DEFAULT && layer_nr >= 0 && layer_nr <= storage.max_print_height_second_to_last_extruder) + // { + // extruder_is_used_on_this_layer[storage.primeTower.extruder_order[0]] = true; + // } + +#warning restore this +#if 0 + // check if we are on the first layer + if ((mesh_group_settings.get("adhesion_type") == EPlatformAdhesion::RAFT && layer_nr == -static_cast(Raft::getTotalExtraLayers())) + || (mesh_group_settings.get("adhesion_type") != EPlatformAdhesion::RAFT && layer_nr == 0)) { - if (extruder_nr == start_extruder) - { // skip the current extruder, it's the one we started out planning - continue; - } - if (! extruder_is_used_on_this_layer[extruder_nr] && method != PrimeTowerMethod::OPTIMIZED_CONSISTENT) + // check if we need prime blob on the first layer + for (size_t used_idx = 0; used_idx < extruder_is_used_on_this_layer.size(); used_idx++) { - continue; + if (getExtruderNeedPrimeBlobDuringFirstLayer(storage, used_idx)) + { + extruder_is_used_on_this_layer[used_idx] = true; + } } - ret.push_back(extruder_nr); } +#endif - spdlog::debug("===== Used extruders for layer {} method {}\n", layer_nr.value, static_cast(method)); - for (auto& ext : ret) - { - spdlog::debug("===== {}\n", ext); - } + // if (method != PrimeTowerMethod::OPTIMIZED || extruder_is_used_on_this_layer[start_extruder]) + // { + // ret.push_back(start_extruder); + // } + + // for (size_t extruder_nr = 0; extruder_nr < extruder_count; extruder_nr++) + // { + // if (extruder_nr == start_extruder) + // { // skip the current extruder, it's the one we started out planning + // continue; + // } + // if (! extruder_is_used_on_this_layer[extruder_nr] && method != PrimeTowerMethod::OPTIMIZED_CONSISTENT) + // { + // continue; + // } + // ret.push_back(extruder_nr); + // } assert(ret.size() <= (size_t)extruder_count && "Not more extruders may be planned in a layer than there are extruders!"); return ret; diff --git a/src/PrimeTower.cpp b/src/PrimeTower.cpp index 77e029bc60..c0ee713503 100644 --- a/src/PrimeTower.cpp +++ b/src/PrimeTower.cpp @@ -1,32 +1,33 @@ -//Copyright (c) 2022 Ultimaker B.V. -//CuraEngine is released under the terms of the AGPLv3 or higher. +// Copyright (c) 2022 Ultimaker B.V. +// CuraEngine is released under the terms of the AGPLv3 or higher. -#include -#include - -#include +#include "PrimeTower.h" #include "Application.h" //To get settings. #include "ExtruderTrain.h" -#include "gcodeExport.h" -#include "infill.h" #include "LayerPlan.h" -#include "PrimeTower.h" #include "PrintFeature.h" -#include "raft.h" #include "Scene.h" #include "Slice.h" +#include "gcodeExport.h" +#include "infill.h" +#include "raft.h" #include "sliceDataStorage.h" -#define CIRCLE_RESOLUTION 32 //The number of vertices in each circle. -#define ARC_RESOLUTION 4 //The number of segments in each arc of a wheel +#include + +#include +#include + +#define CIRCLE_RESOLUTION 32 // The number of vertices in each circle. +#define ARC_RESOLUTION 4 // The number of segments in each arc of a wheel namespace cura { PrimeTower::PrimeTower() -: wipe_from_middle(false) + : wipe_from_middle(false) { const Scene& scene = Application::getInstance().current_slice->scene; PrimeTowerMethod method = scene.current_mesh_group->settings.get("prime_tower_mode"); @@ -34,40 +35,41 @@ PrimeTower::PrimeTower() { EPlatformAdhesion adhesion_type = scene.current_mesh_group->settings.get("adhesion_type"); - //When we have multiple extruders sharing the same heater/nozzle, we expect that all the extruders have been + // When we have multiple extruders sharing the same heater/nozzle, we expect that all the extruders have been //'primed' by the print-start gcode script, but we don't know which one has been left at the tip of the nozzle - //and whether it needs 'purging' (before extruding a pure material) or not, so we need to prime (actually purge) - //each extruder before it is used for the model. This can done by the (per-extruder) brim lines or (per-extruder) - //skirt lines when they are used, but we need to do that inside the first prime-tower layer when they are not - //used (sacrifying for this purpose the usual single-extruder first layer, that would be better for prime-tower - //adhesion). - - multiple_extruders_on_first_layer = (method == PrimeTowerMethod::OPTIMIZED) || - (method == PrimeTowerMethod::OPTIMIZED_CONSISTENT) || - (scene.current_mesh_group->settings.get("machine_extruders_share_nozzle") && - ((adhesion_type != EPlatformAdhesion::SKIRT) && (adhesion_type != EPlatformAdhesion::BRIM))); + // and whether it needs 'purging' (before extruding a pure material) or not, so we need to prime (actually purge) + // each extruder before it is used for the model. This can done by the (per-extruder) brim lines or (per-extruder) + // skirt lines when they are used, but we need to do that inside the first prime-tower layer when they are not + // used (sacrifying for this purpose the usual single-extruder first layer, that would be better for prime-tower + // adhesion). + + multiple_extruders_on_first_layer = (method == PrimeTowerMethod::OPTIMIZED) || (method == PrimeTowerMethod::OPTIMIZED_CONSISTENT) + || (scene.current_mesh_group->settings.get("machine_extruders_share_nozzle") + && ((adhesion_type != EPlatformAdhesion::SKIRT) && (adhesion_type != EPlatformAdhesion::BRIM))); } - enabled = method != PrimeTowerMethod::NONE - && scene.current_mesh_group->settings.get("prime_tower_min_volume") > 10 + enabled = method != PrimeTowerMethod::NONE && scene.current_mesh_group->settings.get("prime_tower_min_volume") > 10 && scene.current_mesh_group->settings.get("prime_tower_size") > 10; - would_have_actual_tower = enabled; // Assume so for now. + would_have_actual_tower = enabled; // Assume so for now. extruder_count = scene.extruders.size(); extruder_order.resize(extruder_count); for (unsigned int extruder_nr = 0; extruder_nr < extruder_count; extruder_nr++) { - extruder_order[extruder_nr] = extruder_nr; //Start with default order, then sort. + extruder_order[extruder_nr] = extruder_nr; // Start with default order, then sort. } - //Sort from high adhesion to low adhesion. - const Scene* scene_pointer = &scene; //Communicate to lambda via pointer to prevent copy. - std::stable_sort(extruder_order.begin(), extruder_order.end(), [scene_pointer](const unsigned int& extruder_nr_a, const unsigned int& extruder_nr_b) -> bool - { - const Ratio adhesion_a = scene_pointer->extruders[extruder_nr_a].settings.get("material_adhesion_tendency"); - const Ratio adhesion_b = scene_pointer->extruders[extruder_nr_b].settings.get("material_adhesion_tendency"); - return adhesion_a < adhesion_b; - }); - #warning TBD take care of actual extruder order for optimized tower ! + // Sort from high adhesion to low adhesion. + const Scene* scene_pointer = &scene; // Communicate to lambda via pointer to prevent copy. + std::stable_sort( + extruder_order.begin(), + extruder_order.end(), + [scene_pointer](const unsigned int& extruder_nr_a, const unsigned int& extruder_nr_b) -> bool + { + const Ratio adhesion_a = scene_pointer->extruders[extruder_nr_a].settings.get("material_adhesion_tendency"); + const Ratio adhesion_b = scene_pointer->extruders[extruder_nr_b].settings.get("material_adhesion_tendency"); + return adhesion_a < adhesion_b; + }); +#warning TBD take care of actual extruder order for optimized tower ! } void PrimeTower::checkUsed(const SliceDataStorage& storage) @@ -100,7 +102,8 @@ void PrimeTower::generateGroundpoly() void PrimeTower::generatePaths(const SliceDataStorage& storage) { - would_have_actual_tower = storage.max_print_height_second_to_last_extruder >= 0; //Maybe it turns out that we don't need a prime tower after all because there are no layer switches. + would_have_actual_tower + = storage.max_print_height_second_to_last_extruder >= 0; // Maybe it turns out that we don't need a prime tower after all because there are no layer switches. if (would_have_actual_tower && enabled) { generateGroundpoly(); @@ -114,7 +117,7 @@ void PrimeTower::generatePaths(const SliceDataStorage& storage) } } -void PrimeTower::generatePaths_denseInfill(std::vector &cumulative_insets) +void PrimeTower::generatePaths_denseInfill(std::vector& cumulative_insets) { const Scene& scene = Application::getInstance().current_slice->scene; const Settings& mesh_group_settings = scene.current_mesh_group->settings; @@ -123,7 +126,7 @@ void PrimeTower::generatePaths_denseInfill(std::vector &cumulative_inse pattern_per_extruder.resize(extruder_count); pattern_per_extruder_layer0.resize(extruder_count); - coord_t cumulative_inset = 0; //Each tower shape is going to be printed inside the other. This is the inset we're doing for each extruder. + coord_t cumulative_inset = 0; // Each tower shape is going to be printed inside the other. This is the inset we're doing for each extruder. for (size_t extruder_nr : extruder_order) { const coord_t line_width = scene.extruders[extruder_nr].settings.get("prime_tower_line_width"); @@ -132,28 +135,28 @@ void PrimeTower::generatePaths_denseInfill(std::vector &cumulative_inse coord_t current_volume = 0; ExtrusionMoves& pattern = pattern_per_extruder[extruder_nr]; - //Create the walls of the prime tower. + // Create the walls of the prime tower. unsigned int wall_nr = 0; for (; current_volume < required_volume; wall_nr++) { - //Create a new polygon with an offset from the outer polygon. + // Create a new polygon with an offset from the outer polygon. Polygons polygons = outer_poly.offset(-cumulative_inset - wall_nr * line_width - line_width / 2); pattern.polygons.add(polygons); current_volume += polygons.polygonLength() * line_width * layer_height * flow; - if(polygons.empty()) //Don't continue. We won't ever reach the required volume because it doesn't fit. + if (polygons.empty()) // Don't continue. We won't ever reach the required volume because it doesn't fit. { break; } } - //Only the most inside extruder needs to fill the inside of the prime tower + // Only the most inside extruder needs to fill the inside of the prime tower if (extruder_nr != extruder_order.back() || method != PrimeTowerMethod::DEFAULT) { pattern_per_extruder_layer0 = pattern_per_extruder; } else { - //Generate the pattern for the first layer. + // Generate the pattern for the first layer. coord_t line_width_layer0 = line_width * scene.extruders[extruder_nr].settings.get("initial_layer_line_width_factor"); ExtrusionMoves& pattern_layer0 = pattern_per_extruder_layer0[extruder_nr]; @@ -161,7 +164,7 @@ void PrimeTower::generatePaths_denseInfill(std::vector &cumulative_inse // the infill pattern because the infill pattern tries to connect polygons in different insets which causes the // first layer of the prime tower to not stick well. Polygons inset = outer_poly.offset(-cumulative_inset - line_width_layer0 / 2); - while (!inset.empty()) + while (! inset.empty()) { pattern_layer0.polygons.add(inset); inset = inset.offset(-line_width_layer0); @@ -172,7 +175,7 @@ void PrimeTower::generatePaths_denseInfill(std::vector &cumulative_inse } } -void PrimeTower::generatePaths_sparseInfill(const std::vector &cumulative_insets) +void PrimeTower::generatePaths_sparseInfill(const std::vector& cumulative_insets) { const Scene& scene = Application::getInstance().current_slice->scene; const Settings& mesh_group_settings = scene.current_mesh_group->settings; @@ -186,13 +189,13 @@ void PrimeTower::generatePaths_sparseInfill(const std::vector &cumulati std::vector actual_extruders; actual_extruders.reserve(extruder_order.size()); - for(size_t extruder_nr : extruder_order) + for (size_t extruder_nr : extruder_order) { const coord_t line_width = scene.extruders[extruder_nr].settings.get("prime_tower_line_width"); - actual_extruders.push_back({extruder_nr, line_width}); + actual_extruders.push_back({ extruder_nr, line_width }); } - if(method == PrimeTowerMethod::OPTIMIZED || method == PrimeTowerMethod::OPTIMIZED_CONSISTENT) + if (method == PrimeTowerMethod::OPTIMIZED || method == PrimeTowerMethod::OPTIMIZED_CONSISTENT) { const size_t nb_extruders = scene.extruders.size(); @@ -202,7 +205,7 @@ void PrimeTower::generatePaths_sparseInfill(const std::vector &cumulati const coord_t tower_radius = tower_size / 2; rings_radii.push_back(tower_radius); - for(const coord_t &cumulative_inset : cumulative_insets) + for (const coord_t& cumulative_inset : cumulative_insets) { rings_radii.push_back(tower_radius - cumulative_inset); } @@ -210,18 +213,18 @@ void PrimeTower::generatePaths_sparseInfill(const std::vector &cumulati // Generate all possible extruders combinations, e.g. if there are 4 extruders, we have combinations // 0 / 0-1 / 0-1-2 / 0-1-2-3 / 1 / 1-2 / 1-2-3 / 2 / 2-3 / 3 // A combination is represented by a bitmask - for(size_t first_extruder = 0 ; first_extruder < nb_extruders ; ++first_extruder) + for (size_t first_extruder = 0; first_extruder < nb_extruders; ++first_extruder) { - for(size_t last_extruder = first_extruder ; last_extruder < nb_extruders ; ++last_extruder) + for (size_t last_extruder = first_extruder; last_extruder < nb_extruders; ++last_extruder) { size_t extruders_combination = 0; - for(size_t extruder_nr = first_extruder ; extruder_nr <= last_extruder ; ++extruder_nr) + for (size_t extruder_nr = first_extruder; extruder_nr <= last_extruder; ++extruder_nr) { extruders_combination |= (1 << extruder_nr); } std::map infills_for_combination; - for(const ActualExtruder &actual_extruder : actual_extruders) + for (const ActualExtruder& actual_extruder : actual_extruders) { ExtrusionMoves infill = generatePath_sparseInfill(first_extruder, last_extruder, rings_radii, actual_extruder.line_width, actual_extruder.number); infills_for_combination[actual_extruder.number] = infill; @@ -233,7 +236,12 @@ void PrimeTower::generatePaths_sparseInfill(const std::vector &cumulati } } -PrimeTower::ExtrusionMoves PrimeTower::generatePath_sparseInfill(const size_t first_extruder, const size_t last_extruder, const std::vector &rings_radii, const coord_t line_width, const size_t actual_extruder_nr) +PrimeTower::ExtrusionMoves PrimeTower::generatePath_sparseInfill( + const size_t first_extruder, + const size_t last_extruder, + const std::vector& rings_radii, + const coord_t line_width, + const size_t actual_extruder_nr) { const Scene& scene = Application::getInstance().current_slice->scene; const coord_t max_bridging_distance = scene.extruders[actual_extruder_nr].settings.get("prime_tower_max_bridging_distance"); @@ -247,18 +255,14 @@ PrimeTower::ExtrusionMoves PrimeTower::generatePath_sparseInfill(const size_t fi const coord_t actual_radius_step = radius_delta / nb_rings; ExtrusionMoves pattern; - for(size_t i = 0 ; i < nb_rings ; ++i) + for (size_t i = 0; i < nb_rings; ++i) { const coord_t ring_inner_radius = (inner_radius + i * actual_radius_step) + semi_line_width; const coord_t ring_outer_radius = (inner_radius + (i + 1) * actual_radius_step) - semi_line_width; const size_t semi_nb_spokes = std::ceil((M_PI * ring_outer_radius) / max_bridging_distance); - pattern.polygons.add(PolygonUtils::makeWheel(middle, - ring_inner_radius, - ring_outer_radius, - semi_nb_spokes, - ARC_RESOLUTION)); + pattern.polygons.add(PolygonUtils::makeWheel(middle, ring_inner_radius, ring_outer_radius, semi_nb_spokes, ARC_RESOLUTION)); } return pattern; @@ -274,14 +278,19 @@ void PrimeTower::generateStartLocations() PolygonUtils::spreadDots(segment_start, segment_end, number_of_prime_tower_start_locations, prime_tower_start_locations); } -void PrimeTower::addToGcode(const SliceDataStorage& storage, LayerPlan& gcode_layer, const std::vector &required_extruder_prime, const size_t prev_extruder, const size_t new_extruder) const +void PrimeTower::addToGcode( + const SliceDataStorage& storage, + LayerPlan& gcode_layer, + const std::vector& required_extruder_prime, + const size_t prev_extruder, + const size_t new_extruder) const { if (! (enabled && would_have_actual_tower)) { return; } - #warning remove this - spdlog::debug("add to gcode {} {} {}\n", static_cast(gcode_layer.getLayerNr()), prev_extruder, new_extruder); +#warning remove this + // spdlog::info("add to gcode {} {} {}\n", static_cast(gcode_layer.getLayerNr()), prev_extruder, new_extruder); if (gcode_layer.getPrimeTowerIsPlanned(new_extruder)) { // don't print the prime tower if it has been printed already with this extruder. return; @@ -307,56 +316,94 @@ void PrimeTower::addToGcode(const SliceDataStorage& storage, LayerPlan& gcode_la gotoStartLocation(gcode_layer, new_extruder); } + // spdlog::info("actual prime {}\n", static_cast(required_extruder_prime[new_extruder])); + PrimeTowerMethod method = Application::getInstance().current_slice->scene.current_mesh_group->settings.get("prime_tower_mode"); std::vector primed_extruders; - switch(method) + switch (required_extruder_prime[new_extruder]) { - case PrimeTowerMethod::NONE: - // This should actually not happen - break; - - case PrimeTowerMethod::DEFAULT: - addToGcode_denseInfill(gcode_layer, new_extruder); - primed_extruders.push_back(new_extruder); - break; - - case PrimeTowerMethod::OPTIMIZED: - case PrimeTowerMethod::OPTIMIZED_CONSISTENT: - if(required_extruder_prime[new_extruder]) - { - // Extruder really needs to be prime - addToGcode_denseInfill(gcode_layer, new_extruder); - primed_extruders.push_back(new_extruder); - } + case ExtruderPrime::None: + primed_extruders.push_back(new_extruder); + break; + case ExtruderPrime::Sparse: + addToGcode_optimizedInfill(gcode_layer, required_extruder_prime, new_extruder, primed_extruders, method == PrimeTowerMethod::OPTIMIZED); + break; + + case ExtruderPrime::Prime: + addToGcode_denseInfill(gcode_layer, new_extruder); + + if (method == PrimeTowerMethod::OPTIMIZED) + { // Whatever happens before and after, use the current extruder to prime all the non-required extruders now - addToGcode_optimizedInfill(gcode_layer, required_extruder_prime, new_extruder, primed_extruders); - break; + addToGcode_optimizedInfill(gcode_layer, required_extruder_prime, new_extruder, primed_extruders, true); + } + break; + } + + primed_extruders.push_back(new_extruder); + + // switch (method) + // { + // case PrimeTowerMethod::NONE: + // // This should actually not happen + // break; + + // case PrimeTowerMethod::DEFAULT: + // addToGcode_denseInfill(gcode_layer, new_extruder); + // primed_extruders.push_back(new_extruder); + // break; + + // case PrimeTowerMethod::OPTIMIZED: + // if (required_extruder_prime[new_extruder]) + // { + // // Extruder really needs to be primed + // addToGcode_denseInfill(gcode_layer, new_extruder); + // primed_extruders.push_back(new_extruder); + // } + + // // Whatever happens before and after, use the current extruder to prime all the non-required extruders now + // addToGcode_optimizedInfill(gcode_layer, required_extruder_prime, new_extruder, primed_extruders); + // break; + + // case PrimeTowerMethod::OPTIMIZED_CONSISTENT: + // if (required_extruder_prime[new_extruder]) + // { + // // Extruder really needs to be primed + // addToGcode_denseInfill(gcode_layer, new_extruder); + // } + // else + // { + // addToGcode_optimizedInfill(gcode_layer, std::vector({ new_extruder }), new_extruder, primed_extruders); + // } + // primed_extruders.push_back(new_extruder); + // break; + // } + + for (const size_t& primed_extruder : primed_extruders) + { + gcode_layer.setPrimeTowerIsPlanned(primed_extruder); } // post-wipe: if (post_wipe) { - //Make sure we wipe the old extruder on the prime tower. + // Make sure we wipe the old extruder on the prime tower. const Settings& previous_settings = Application::getInstance().current_slice->scene.extruders[prev_extruder].settings; const Point previous_nozzle_offset = Point(previous_settings.get("machine_nozzle_offset_x"), previous_settings.get("machine_nozzle_offset_y")); const Settings& new_settings = Application::getInstance().current_slice->scene.extruders[new_extruder].settings; const Point new_nozzle_offset = Point(new_settings.get("machine_nozzle_offset_x"), new_settings.get("machine_nozzle_offset_y")); gcode_layer.addTravel(post_wipe_point - previous_nozzle_offset + new_nozzle_offset); } - - for (const size_t &primed_extruder : primed_extruders) - { - gcode_layer.setPrimeTowerIsPlanned(primed_extruder); - } } void PrimeTower::addToGcode_denseInfill(LayerPlan& gcode_layer, const size_t extruder_nr) const { - const ExtrusionMoves& pattern = (gcode_layer.getLayerNr() == -static_cast(Raft::getFillerLayerCount())) - ? pattern_per_extruder_layer0[extruder_nr] - : pattern_per_extruder[extruder_nr]; + spdlog::info("Add dense infill for layer {} ex {}", gcode_layer.getLayerNr().value, int(extruder_nr)); + + const ExtrusionMoves& pattern + = (gcode_layer.getLayerNr() == -static_cast(Raft::getFillerLayerCount())) ? pattern_per_extruder_layer0[extruder_nr] : pattern_per_extruder[extruder_nr]; const GCodePathConfig& config = gcode_layer.configs_storage.prime_tower_config_per_extruder[extruder_nr]; @@ -364,79 +411,92 @@ void PrimeTower::addToGcode_denseInfill(LayerPlan& gcode_layer, const size_t ext gcode_layer.addLinesByOptimizer(pattern.lines, config, SpaceFillType::Lines); } -void PrimeTower::addToGcode_optimizedInfill(LayerPlan& gcode_layer, const std::vector &required_extruder_prime, const size_t current_extruder, std::vector &primed_extruders) const +void PrimeTower::addToGcode_optimizedInfill( + LayerPlan& gcode_layer, + const std::vector& required_extruder_prime, + const size_t current_extruder, + std::vector& primed_extruders, + bool group_with_next_extruders) const { - std::vector extruders_to_prime; + std::vector> extruders_to_prime_grouped; - // First, gather all extruders to be primed : we are going to process them all now, even if - // the rings are not besides each other - for(size_t extruder_nr = 0 ; extruder_nr < required_extruder_prime.size() ; ++extruder_nr) + if (group_with_next_extruders) { - if (!required_extruder_prime[extruder_nr] && !gcode_layer.getPrimeTowerIsPlanned(extruder_nr)) - { - extruders_to_prime.push_back(extruder_nr); - primed_extruders.push_back(extruder_nr); - } - } + std::vector extruders_to_prime; - // Now, group extruders which are besides each other - std::vector> extruders_to_prime_grouped; - for(const size_t &extruder_to_prime : extruders_to_prime) - { - if(extruders_to_prime_grouped.empty()) + // First, gather all extruders to be primed : we are going to process them all now, even if + // the rings are not besides each other + for (size_t extruder_nr = 0; extruder_nr < required_extruder_prime.size(); ++extruder_nr) { - // First extruder : create new group - extruders_to_prime_grouped.push_back({extruder_to_prime}); + if (required_extruder_prime[extruder_nr] == ExtruderPrime::Sparse && ! gcode_layer.getPrimeTowerIsPlanned(extruder_nr)) + { + extruders_to_prime.push_back(extruder_nr); + primed_extruders.push_back(extruder_nr); + } } - else + + // Now, group extruders which are besides each other + std::vector> extruders_to_prime_grouped; + for (const size_t& extruder_to_prime : extruders_to_prime) { - std::vector &last_group = extruders_to_prime_grouped.back(); - if(last_group.back() == extruder_to_prime - 1) + if (extruders_to_prime_grouped.empty()) { - // New extruders which belongs to same group - last_group.push_back(extruder_to_prime); + // First extruder : create new group + extruders_to_prime_grouped.push_back({ extruder_to_prime }); } else { - // New extruders which belongs to new group - extruders_to_prime_grouped.push_back({extruder_to_prime}); + std::vector& last_group = extruders_to_prime_grouped.back(); + if (last_group.back() == extruder_to_prime - 1) + { + // New extruders which belongs to same group + last_group.push_back(extruder_to_prime); + } + else + { + // New extruders which belongs to new group + extruders_to_prime_grouped.push_back({ extruder_to_prime }); + } } } } + else + { + extruders_to_prime_grouped.push_back({ current_extruder }); + } - #warning remove this - #if 0 - log("GROUPS\n"); - for(auto &group : extruders_to_prime_grouped) + std::string grouped_extruders; + for (auto& group : extruders_to_prime_grouped) { - log("NEW GROUP\n"); - for(auto &extruder : group) + grouped_extruders.append("{"); + for (auto& extruder : group) { - log("E%d\n", extruder); + grouped_extruders.append(std::to_string(extruder)); + grouped_extruders.append(","); } + grouped_extruders.append("}"); } - log("GROUPS END\n"); - #endif + spdlog::info("Add sparse infill for layer {} ex {}", gcode_layer.getLayerNr().value, grouped_extruders); - #warning What should we do in case of extruders with different lines widths ? +#warning What should we do in case of extruders with different lines widths ? // And finally, append patterns for each group const GCodePathConfig& config = gcode_layer.configs_storage.prime_tower_config_per_extruder[current_extruder]; - for(const std::vector &group : extruders_to_prime_grouped) + for (const std::vector& group : extruders_to_prime_grouped) { size_t mask = 0; - for(const size_t &extruder : group) + for (const size_t& extruder : group) { mask |= (1 << extruder); } auto iterator_combination = sparse_pattern_per_extruders.find(mask); - if(iterator_combination != sparse_pattern_per_extruders.end()) + if (iterator_combination != sparse_pattern_per_extruders.end()) { - const std::map &infill_for_combination = iterator_combination->second; + const std::map& infill_for_combination = iterator_combination->second; auto iterator_extruder_nr = infill_for_combination.find(current_extruder); - if(iterator_extruder_nr != infill_for_combination.end()) + if (iterator_extruder_nr != infill_for_combination.end()) { gcode_layer.addPolygonsByOptimizer(iterator_extruder_nr->second.polygons, config); } @@ -456,7 +516,7 @@ void PrimeTower::subtractFromSupport(SliceDataStorage& storage) { const Polygons outside_polygon = outer_poly.getOutsidePolygons(); AABB outside_polygon_boundary_box(outside_polygon); - for(size_t layer = 0; layer <= (size_t)storage.max_print_height_second_to_last_extruder + 1 && layer < storage.support.supportLayers.size(); layer++) + for (size_t layer = 0; layer <= (size_t)storage.max_print_height_second_to_last_extruder + 1 && layer < storage.support.supportLayers.size(); layer++) { SupportLayer& support_layer = storage.support.supportLayers[layer]; // take the differences of the support infill parts and the prime tower area @@ -466,13 +526,13 @@ void PrimeTower::subtractFromSupport(SliceDataStorage& storage) void PrimeTower::gotoStartLocation(LayerPlan& gcode_layer, const int extruder_nr) const { - int current_start_location_idx = ((((extruder_nr + 1) * gcode_layer.getLayerNr()) % number_of_prime_tower_start_locations) - + number_of_prime_tower_start_locations) % number_of_prime_tower_start_locations; + int current_start_location_idx = ((((extruder_nr + 1) * gcode_layer.getLayerNr()) % number_of_prime_tower_start_locations) + number_of_prime_tower_start_locations) + % number_of_prime_tower_start_locations; const ClosestPolygonPoint wipe_location = prime_tower_start_locations[current_start_location_idx]; const ExtruderTrain& train = Application::getInstance().current_slice->scene.extruders[extruder_nr]; - const coord_t inward_dist = train.settings.get("machine_nozzle_size") * 3 / 2 ; + const coord_t inward_dist = train.settings.get("machine_nozzle_size") * 3 / 2; const coord_t start_dist = train.settings.get("machine_nozzle_size") * 2; const Point prime_end = PolygonUtils::moveInsideDiagonally(wipe_location, inward_dist); const Point outward_dir = wipe_location.location - prime_end; @@ -481,4 +541,4 @@ void PrimeTower::gotoStartLocation(LayerPlan& gcode_layer, const int extruder_nr gcode_layer.addTravel(prime_start); } -}//namespace cura +} // namespace cura From 2ee15d8a669cf686996bbeea92660ee0042a9914 Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Wed, 4 Oct 2023 14:58:29 +0200 Subject: [PATCH 017/201] Basically working architecture for optimized prime tower --- include/FffGcodeWriter.h | 14 +++----------- include/PrimeTower.h | 6 +++--- src/Application.cpp | 3 ++- src/FffGcodeWriter.cpp | 31 ++++++++++++++++++------------- src/PrimeTower.cpp | 28 +++++++++++++++++++++------- 5 files changed, 47 insertions(+), 35 deletions(-) diff --git a/include/FffGcodeWriter.h b/include/FffGcodeWriter.h index 717ad878eb..61363895fb 100644 --- a/include/FffGcodeWriter.h +++ b/include/FffGcodeWriter.h @@ -4,7 +4,7 @@ #ifndef GCODE_WRITER_H #define GCODE_WRITER_H -#include "ExtruderPrime.h" +#include "ExtruderUse.h" #include "FanSpeedLayerTime.h" #include "LayerPlanBuffer.h" #include "gcodeExport.h" @@ -65,14 +65,12 @@ class FffGcodeWriter : public NoCopy * For each raft/filler layer, the extruders to be used in that layer in the order in which they are going to be used. * The first number is the first raft layer. Indexing is shifted compared to normal negative layer numbers for raft/filler layers. */ - std::vector> extruder_order_per_layer_negative_layers; + std::vector> extruder_order_per_layer_negative_layers; - std::vector> extruder_order_per_layer; //!< For each layer, the extruders to be used in that layer in the order in which they are going to be used + std::vector> extruder_order_per_layer; //!< For each layer, the extruders to be used in that layer in the order in which they are going to be used std::vector> mesh_order_per_extruder; //!< For each extruder, the order of the meshes (first element is first mesh to be printed) - std::vector> extruder_prime_required_by_layer; //!< For each layer, indicates which extruders actually require to be primed - /*! * For each extruder on which layer the prime will be planned, * or a large negative number if it's already planned outside of \ref FffGcodeWriter::processLayer @@ -281,12 +279,6 @@ class FffGcodeWriter : public NoCopy */ void calculatePrimeLayerPerExtruder(const SliceDataStorage& storage); - struct ExtruderUse - { - size_t extruder_nr; - ExtruderPrime prime; - }; - /*! * Gets a list of extruders that are used on the given layer, but excluding the given starting extruder. * When it's on the first layer, the prime blob will also be taken into account. diff --git a/include/PrimeTower.h b/include/PrimeTower.h index d376dd0a18..b5929c57b9 100644 --- a/include/PrimeTower.h +++ b/include/PrimeTower.h @@ -9,7 +9,7 @@ #include "utils/polygon.h" // Polygons #include "utils/polygonUtils.h" -#include "ExtruderPrime.h" +#include "ExtruderUse.h" namespace cura { @@ -87,7 +87,7 @@ class PrimeTower * \param prev_extruder The previous extruder with which paths were planned; from which extruder a switch was made * \param new_extruder The switched to extruder with which the prime tower paths should be generated. */ - void addToGcode(const SliceDataStorage& storage, LayerPlan& gcode_layer, const std::vector &required_extruder_prime, const size_t prev_extruder, const size_t new_extruder) const; + void addToGcode(const SliceDataStorage& storage, LayerPlan& gcode_layer, const std::vector &required_extruder_prime, const size_t prev_extruder, const size_t new_extruder) const; /*! * \brief Subtract the prime tower from the support areas in storage. @@ -154,7 +154,7 @@ class PrimeTower void addToGcode_denseInfill(LayerPlan& gcode_layer, const size_t extruder) const; #warning TBD documentation - void addToGcode_optimizedInfill(LayerPlan& gcode_layer, const std::vector &required_extruder_prime, const size_t current_extruder, std::vector& primed_extruders, bool group_with_next_extruders) const; + void addToGcode_optimizedInfill(LayerPlan& gcode_layer, const std::vector &required_extruder_prime, const size_t current_extruder, std::vector& primed_extruders, bool group_with_next_extruders) const; /*! * For an extruder switch that happens not on the first layer, the extruder needs to be primed on the prime tower. diff --git a/src/Application.cpp b/src/Application.cpp index 0074940150..1635f56f18 100644 --- a/src/Application.cpp +++ b/src/Application.cpp @@ -251,7 +251,8 @@ void Application::startThreadPool(int nworkers) return; // Keep the previous ThreadPool } delete thread_pool; - thread_pool = new ThreadPool(nthreads); + // thread_pool = new ThreadPool(nthreads); + thread_pool = new ThreadPool(0); } } // namespace cura diff --git a/src/FffGcodeWriter.cpp b/src/FffGcodeWriter.cpp index 0583ed537a..f615946052 100644 --- a/src/FffGcodeWriter.cpp +++ b/src/FffGcodeWriter.cpp @@ -262,10 +262,10 @@ void FffGcodeWriter::findLayerSeamsForSpiralize(SliceDataStorage& storage, size_ bool done_this_layer = false; // iterate through extruders until we find a mesh that has a part with insets - const std::vector& extruder_order = extruder_order_per_layer[layer_nr]; + const std::vector& extruder_order = extruder_order_per_layer[layer_nr]; for (unsigned int extruder_idx = 0; ! done_this_layer && extruder_idx < extruder_order.size(); ++extruder_idx) { - const size_t extruder_nr = extruder_order[extruder_idx]; + const size_t extruder_nr = extruder_order[extruder_idx].extruder_nr; // iterate through this extruder's meshes until we find a part with insets const std::vector& mesh_order = mesh_order_per_extruder[extruder_nr]; for (unsigned int mesh_idx : mesh_order) @@ -968,16 +968,16 @@ LayerPlan& FffGcodeWriter::processLayer(const SliceDataStorage& storage, LayerIn assert( static_cast(extruder_order_per_layer_negative_layers.size()) + layer_nr >= 0 && "Layer numbers shouldn't get more negative than there are raft/filler layers"); - const std::vector& extruder_order + const std::vector& extruder_order = (layer_nr < 0) ? extruder_order_per_layer_negative_layers[extruder_order_per_layer_negative_layers.size() + layer_nr] : extruder_order_per_layer[layer_nr]; - const coord_t first_outer_wall_line_width = scene.extruders[extruder_order.front()].settings.get("wall_line_width_0"); + const coord_t first_outer_wall_line_width = scene.extruders[extruder_order.front().extruder_nr].settings.get("wall_line_width_0"); LayerPlan& gcode_layer = *new LayerPlan( storage, layer_nr, z, layer_thickness, - extruder_order.front(), + extruder_order.front().extruder_nr, fan_speed_layer_time_settings_per_extruder, comb_offset_from_outlines, first_outer_wall_line_width, @@ -1002,8 +1002,9 @@ LayerPlan& FffGcodeWriter::processLayer(const SliceDataStorage& storage, LayerIn const size_t support_infill_extruder_nr = (layer_nr <= 0) ? mesh_group_settings.get("support_extruder_nr_layer_0").extruder_nr : mesh_group_settings.get("support_infill_extruder_nr").extruder_nr; - for (const size_t& extruder_nr : extruder_order) + for (const ExtruderUse& extruder_use : extruder_order) { + size_t extruder_nr = extruder_use.extruder_nr; // Everytime you start with a new extruder you want to add a prime tower, unless: // - prime tower is disabled (setExtruder_addPrime takes care of this) // - this is the first (and not the only!) extruder in this layer. Since the previous @@ -1012,7 +1013,7 @@ LayerPlan& FffGcodeWriter::processLayer(const SliceDataStorage& storage, LayerIn // later in the print a prime tower is needed. // - prime tower is already printed this layer (only applicable for more than 2 extruders). // The setExtruder_addPrime takes care of this. - if (extruder_nr != extruder_order.front() || extruder_order.size() == 1) + if (extruder_nr != extruder_order.front().extruder_nr || extruder_order.size() == 1) { setExtruder_addPrime(storage, gcode_layer, extruder_nr); } @@ -1043,7 +1044,7 @@ LayerPlan& FffGcodeWriter::processLayer(const SliceDataStorage& storage, LayerIn // Always print a prime tower before switching extruder. Unless: // - The prime tower is already printed this layer (setExtruder_addPrime takes care of this). // - this is the last extruder of the layer, since the next layer will start with the same extruder. - if (extruder_nr != extruder_order.back()) + if (extruder_nr != extruder_order.back().extruder_nr) { setExtruder_addPrime(storage, gcode_layer, extruder_nr); } @@ -1317,10 +1318,11 @@ void FffGcodeWriter::calculateExtruderOrderPerLayer(const SliceDataStorage& stor PrimeTowerMethod prime_tower_mode = mesh_group_settings.get("prime_tower_mode"); for (LayerIndex layer_nr = -Raft::getTotalExtraLayers(); layer_nr < static_cast(storage.print_layer_count); layer_nr++) { - std::vector>& extruder_order_per_layer_here = (layer_nr < 0) ? extruder_order_per_layer_negative_layers : extruder_order_per_layer; + std::vector>& extruder_order_per_layer_here = (layer_nr < 0) ? extruder_order_per_layer_negative_layers : extruder_order_per_layer; std::vector extruder_order = getUsedExtrudersOnLayerExcludingStartingExtruder(storage, last_extruder, layer_nr); + extruder_order_per_layer_here.push_back(extruder_order); - std::vector extruder_order_ids; + /*std::vector extruder_order_ids; std::vector extruder_primes; for (const ExtruderUse& extruder_use : extruder_order) { @@ -1328,7 +1330,7 @@ void FffGcodeWriter::calculateExtruderOrderPerLayer(const SliceDataStorage& stor extruder_primes.push_back(extruder_use.prime); } extruder_order_per_layer_here.push_back(extruder_order_ids); - extruder_prime_required_by_layer.push_back(extruder_primes); + extruder_prime_required_by_layer.push_back(extruder_primes);*/ #warning remove this #if 0 @@ -1398,7 +1400,7 @@ void FffGcodeWriter::calculatePrimeLayerPerExtruder(const SliceDataStorage& stor } } -std::vector +std::vector FffGcodeWriter::getUsedExtrudersOnLayerExcludingStartingExtruder(const SliceDataStorage& storage, const size_t start_extruder, const LayerIndex& layer_nr) const { const Settings& mesh_group_settings = Application::getInstance().current_slice->scene.current_mesh_group->settings; @@ -3704,7 +3706,10 @@ void FffGcodeWriter::addPrimeTower(const SliceDataStorage& storage, LayerPlan& g return; } - storage.primeTower.addToGcode(storage, gcode_layer, extruder_prime_required_by_layer.at(gcode_layer.getLayerNr()), prev_extruder, gcode_layer.getExtruder()); + LayerIndex layer_nr = gcode_layer.getLayerNr(); + const std::vector& extruder_order + = (layer_nr < 0) ? extruder_order_per_layer_negative_layers[extruder_order_per_layer_negative_layers.size() + layer_nr] : extruder_order_per_layer[layer_nr]; + storage.primeTower.addToGcode(storage, gcode_layer, extruder_order, prev_extruder, gcode_layer.getExtruder()); } void FffGcodeWriter::finalize() diff --git a/src/PrimeTower.cpp b/src/PrimeTower.cpp index c0ee713503..3c9851c4b5 100644 --- a/src/PrimeTower.cpp +++ b/src/PrimeTower.cpp @@ -281,7 +281,7 @@ void PrimeTower::generateStartLocations() void PrimeTower::addToGcode( const SliceDataStorage& storage, LayerPlan& gcode_layer, - const std::vector& required_extruder_prime, + const std::vector& required_extruder_prime, const size_t prev_extruder, const size_t new_extruder) const { @@ -321,7 +321,21 @@ void PrimeTower::addToGcode( PrimeTowerMethod method = Application::getInstance().current_slice->scene.current_mesh_group->settings.get("prime_tower_mode"); std::vector primed_extruders; - switch (required_extruder_prime[new_extruder]) + auto extruder_iterator = std::find_if( + required_extruder_prime.begin(), + required_extruder_prime.end(), + [new_extruder](const ExtruderUse& extruder_use) + { + return extruder_use.extruder_nr == new_extruder; + }); + + if (extruder_iterator == required_extruder_prime.end()) + { + // Extruder is not used on this lyer + return; + } + + switch (extruder_iterator->prime) { case ExtruderPrime::None: primed_extruders.push_back(new_extruder); @@ -413,7 +427,7 @@ void PrimeTower::addToGcode_denseInfill(LayerPlan& gcode_layer, const size_t ext void PrimeTower::addToGcode_optimizedInfill( LayerPlan& gcode_layer, - const std::vector& required_extruder_prime, + const std::vector& required_extruder_prime, const size_t current_extruder, std::vector& primed_extruders, bool group_with_next_extruders) const @@ -426,12 +440,12 @@ void PrimeTower::addToGcode_optimizedInfill( // First, gather all extruders to be primed : we are going to process them all now, even if // the rings are not besides each other - for (size_t extruder_nr = 0; extruder_nr < required_extruder_prime.size(); ++extruder_nr) + for (const ExtruderUse& extruder_use : required_extruder_prime) { - if (required_extruder_prime[extruder_nr] == ExtruderPrime::Sparse && ! gcode_layer.getPrimeTowerIsPlanned(extruder_nr)) + if (extruder_use.prime == ExtruderPrime::Sparse && ! gcode_layer.getPrimeTowerIsPlanned(extruder_use.extruder_nr)) { - extruders_to_prime.push_back(extruder_nr); - primed_extruders.push_back(extruder_nr); + extruders_to_prime.push_back(extruder_use.extruder_nr); + primed_extruders.push_back(extruder_use.extruder_nr); } } From a1b950db3d0435d3ccf7e0b4e1767951a3c446f3 Mon Sep 17 00:00:00 2001 From: wawanbreton Date: Wed, 4 Oct 2023 12:59:34 +0000 Subject: [PATCH 018/201] Applied clang-format. --- include/ExtruderPrime.h | 10 ++++---- include/ExtruderUse.h | 7 +++--- include/PrimeTower.h | 53 +++++++++++++++++++++++++---------------- 3 files changed, 42 insertions(+), 28 deletions(-) diff --git a/include/ExtruderPrime.h b/include/ExtruderPrime.h index d422b874a9..f3c8d3cc48 100644 --- a/include/ExtruderPrime.h +++ b/include/ExtruderPrime.h @@ -1,5 +1,5 @@ -//Copyright (c) 2023 UltiMaker B.V. -//CuraEngine is released under the terms of the AGPLv3 or higher. +// Copyright (c) 2023 UltiMaker B.V. +// CuraEngine is released under the terms of the AGPLv3 or higher. #ifndef EXTRUDERPRIME_H #define EXTRUDERPRIME_H @@ -9,10 +9,10 @@ namespace cura enum class ExtruderPrime { - None, // Do not prime at all for this extruder on this layer + None, // Do not prime at all for this extruder on this layer Sparse, // Just extrude a sparse priming which purpose is to make the tower stronger - Prime, // Do an actual prime + Prime, // Do an actual prime }; -}//namespace cura +} // namespace cura #endif // EXTRUDERPRIME_H diff --git a/include/ExtruderUse.h b/include/ExtruderUse.h index 33e21c5b80..46798d0266 100644 --- a/include/ExtruderUse.h +++ b/include/ExtruderUse.h @@ -1,10 +1,11 @@ -//Copyright (c) 2023 UltiMaker B.V. -//CuraEngine is released under the terms of the AGPLv3 or higher. +// Copyright (c) 2023 UltiMaker B.V. +// CuraEngine is released under the terms of the AGPLv3 or higher. #ifndef EXTRUDERUSE_H #define EXTRUDERUSE_H #include "ExtruderPrime.h" + #include namespace cura @@ -16,5 +17,5 @@ struct ExtruderUse ExtruderPrime prime; }; -}//namespace cura +} // namespace cura #endif // EXTRUDERUSE_H diff --git a/include/PrimeTower.h b/include/PrimeTower.h index b5929c57b9..5c02538c65 100644 --- a/include/PrimeTower.h +++ b/include/PrimeTower.h @@ -1,17 +1,17 @@ -//Copyright (c) 2022 Ultimaker B.V. -//CuraEngine is released under the terms of the AGPLv3 or higher. +// Copyright (c) 2022 Ultimaker B.V. +// CuraEngine is released under the terms of the AGPLv3 or higher. #ifndef PRIME_TOWER_H #define PRIME_TOWER_H -#include -#include - +#include "ExtruderUse.h" #include "utils/polygon.h" // Polygons #include "utils/polygonUtils.h" -#include "ExtruderUse.h" -namespace cura +#include +#include + +namespace cura { class SliceDataStorage; @@ -43,7 +43,8 @@ class PrimeTower std::vector pattern_per_extruder; //!< For each extruder the pattern to print on all layers of the prime tower. std::vector pattern_per_extruder_layer0; //!< For each extruder the pattern to print on the first layer - std::map> sparse_pattern_per_extruders; //!< For each extruders combination, and for each actual extruder, the pattern to print on all layers where extruders are actually useless. + std::map> + sparse_pattern_per_extruders; //!< For each extruders combination, and for each actual extruder, the pattern to print on all layers where extruders are actually useless. public: bool enabled; //!< Whether the prime tower is enabled. @@ -80,14 +81,19 @@ class PrimeTower /*! * Add path plans for the prime tower to the \p gcode_layer - * + * * \param storage where to get settings from; where to get the maximum height of the prime tower from * \param[in,out] gcode_layer Where to get the current extruder from; where to store the generated layer paths * \param required_extruder_prime the extruders which actually required to be primed at this layer * \param prev_extruder The previous extruder with which paths were planned; from which extruder a switch was made * \param new_extruder The switched to extruder with which the prime tower paths should be generated. */ - void addToGcode(const SliceDataStorage& storage, LayerPlan& gcode_layer, const std::vector &required_extruder_prime, const size_t prev_extruder, const size_t new_extruder) const; + void addToGcode( + const SliceDataStorage& storage, + LayerPlan& gcode_layer, + const std::vector& required_extruder_prime, + const size_t prev_extruder, + const size_t new_extruder) const; /*! * \brief Subtract the prime tower from the support areas in storage. @@ -98,7 +104,6 @@ class PrimeTower void subtractFromSupport(SliceDataStorage& storage); private: - /*! * Generate the prime tower area to be used on each layer * @@ -108,12 +113,12 @@ class PrimeTower /*! * \see WipeTower::generatePaths - * + * * Generate the extrude paths for each extruder on even and odd layers * Fill the ground poly with dense infill. * \param cumulative_insets [in, out] The insets added to each extruder to compute the radius of its ring */ - void generatePaths_denseInfill(std::vector &cumulative_insets); + void generatePaths_denseInfill(std::vector& cumulative_insets); /*! * \see WipeTower::generatePaths @@ -121,7 +126,7 @@ class PrimeTower * \brief Generate the sparse extrude paths for each extruders combination * \param cumulative_insets The insets added to each extruder to compute the radius of its ring */ - void generatePaths_sparseInfill(const std::vector &cumulative_insets); + void generatePaths_sparseInfill(const std::vector& cumulative_insets); /*! * \brief Generate the sparse extrude paths for an extruders combination @@ -132,7 +137,12 @@ class PrimeTower * \param line_width The actual line width of the extruder * \param actual_extruder_nr The actual extruder to be used */ - ExtrusionMoves generatePath_sparseInfill(const size_t first_extruder, const size_t last_extruder, const std::vector &rings_radii, const coord_t line_width, const size_t actual_extruder_nr); + ExtrusionMoves generatePath_sparseInfill( + const size_t first_extruder, + const size_t last_extruder, + const std::vector& rings_radii, + const coord_t line_width, + const size_t actual_extruder_nr); /*! * Generate start locations on the prime tower. The locations are evenly spread around the prime tower's perimeter. @@ -153,8 +163,13 @@ class PrimeTower */ void addToGcode_denseInfill(LayerPlan& gcode_layer, const size_t extruder) const; - #warning TBD documentation - void addToGcode_optimizedInfill(LayerPlan& gcode_layer, const std::vector &required_extruder_prime, const size_t current_extruder, std::vector& primed_extruders, bool group_with_next_extruders) const; +#warning TBD documentation + void addToGcode_optimizedInfill( + LayerPlan& gcode_layer, + const std::vector& required_extruder_prime, + const size_t current_extruder, + std::vector& primed_extruders, + bool group_with_next_extruders) const; /*! * For an extruder switch that happens not on the first layer, the extruder needs to be primed on the prime tower. @@ -165,8 +180,6 @@ class PrimeTower }; - - -}//namespace cura +} // namespace cura #endif // PRIME_TOWER_H From 74a66b97cc4a94dea9ecdad9238a2f5c8020113b Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Wed, 18 Oct 2023 16:31:29 +0200 Subject: [PATCH 019/201] All prime tower modes basically working --- include/PrimeTower.h | 13 ++-- src/FffGcodeWriter.cpp | 107 ++++------------------------ src/PrimeTower.cpp | 158 +++++++++++++++++------------------------ 3 files changed, 90 insertions(+), 188 deletions(-) diff --git a/include/PrimeTower.h b/include/PrimeTower.h index 5c02538c65..1e43595a95 100644 --- a/include/PrimeTower.h +++ b/include/PrimeTower.h @@ -5,6 +5,7 @@ #define PRIME_TOWER_H #include "ExtruderUse.h" +#include "settings/EnumSettings.h" #include "utils/polygon.h" // Polygons #include "utils/polygonUtils.h" @@ -59,7 +60,7 @@ class PrimeTower * This is the spatial order from outside to inside. This is NOT the actual * order in time in which they are printed. */ - std::vector extruder_order; + std::vector extruder_order; /*! * \brief Creates a prime tower instance that will determine where and how @@ -164,12 +165,16 @@ class PrimeTower void addToGcode_denseInfill(LayerPlan& gcode_layer, const size_t extruder) const; #warning TBD documentation - void addToGcode_optimizedInfill( + void addToGcode_optimizedInfill(LayerPlan& gcode_layer, + const std::vector& extruders_to_prime, + const size_t current_extruder) const; + + std::vector findExtrudersSparseInfill( LayerPlan& gcode_layer, const std::vector& required_extruder_prime, const size_t current_extruder, - std::vector& primed_extruders, - bool group_with_next_extruders) const; + cura::PrimeTowerMethod method, + const std::vector& initial_list = {}) const; /*! * For an extruder switch that happens not on the first layer, the extruder needs to be primed on the prime tower. diff --git a/src/FffGcodeWriter.cpp b/src/FffGcodeWriter.cpp index f615946052..41f4408cf5 100644 --- a/src/FffGcodeWriter.cpp +++ b/src/FffGcodeWriter.cpp @@ -897,8 +897,6 @@ void FffGcodeWriter::processRaft(const SliceDataStorage& storage) LayerPlan& FffGcodeWriter::processLayer(const SliceDataStorage& storage, LayerIndex layer_nr, const size_t total_layers) const { - spdlog::debug("GcodeWriter processing layer {} of {}", layer_nr, total_layers); - const Settings& mesh_group_settings = Application::getInstance().current_slice->scene.current_mesh_group->settings; coord_t layer_thickness = mesh_group_settings.get("layer_height"); coord_t z; @@ -1322,65 +1320,6 @@ void FffGcodeWriter::calculateExtruderOrderPerLayer(const SliceDataStorage& stor std::vector extruder_order = getUsedExtrudersOnLayerExcludingStartingExtruder(storage, last_extruder, layer_nr); extruder_order_per_layer_here.push_back(extruder_order); - /*std::vector extruder_order_ids; - std::vector extruder_primes; - for (const ExtruderUse& extruder_use : extruder_order) - { - extruder_order_ids.push_back(extruder_use.extruder_nr); - extruder_primes.push_back(extruder_use.prime); - } - extruder_order_per_layer_here.push_back(extruder_order_ids); - extruder_prime_required_by_layer.push_back(extruder_primes);*/ - -#warning remove this -#if 0 - logAlways("##### Used extruders for layer %d (last %d)\n", layer_nr, last_extruder); - for(const size_t &extruder_nr : extruder_order) - { - logAlways("##### %d\n", extruder_nr); - } -#endif - - // if (layer_nr >= 0 && ! extruder_order_per_layer_here.empty()) - // { - // ExtruderPrime default_prime; - // switch (prime_tower_mode) - // { - // case PrimeTowerMethod::NONE: - // case PrimeTowerMethod::DEFAULT: - // case PrimeTowerMethod::OPTIMIZED: - // default_prime = ExtruderPrime::None; - // break; - - // case PrimeTowerMethod::OPTIMIZED_CONSISTENT: - // default_prime = ExtruderPrime::Sparse; - // break; - // } - - // std::vector extruder_prime_required(extruder_count, default_prime); - - // // First used extruder only needs to be primed if an other extruder has been used before - // if (extruder_order.front() != last_extruder) - // { - // extruder_prime_required[extruder_order.front()] = ExtruderPrime::Prime; - // } - - // // All other used extruders need to be primed - // for (size_t index = 1; index < extruder_order.size(); ++index) - // { - // extruder_prime_required[extruder_order[index]] = ExtruderPrime::Prime; - // } - - // extruder_prime_required_by_layer.push_back(extruder_prime_required); - -#warning remove this -#if 0 - logAlways("##### Required primes for layer %d:\n", layer_nr); - for(size_t extruder_nr = 0 ; extruder_nr < extruder_count ; ++extruder_nr) - { - logAlways("##### EX%d %d\n", extruder_nr, extruder_prime_required[extruder_nr] ? 1 : 0); - } -#endif last_extruder = extruder_order.back().extruder_nr; } } @@ -1422,6 +1361,7 @@ std::vector } // Now check whether extuders should really used, and how + size_t last_extruder = start_extruder; for (size_t extruder_nr : ordered_extruders) { ExtruderPrime prime = ExtruderPrime::None; @@ -1443,38 +1383,37 @@ std::vector } break; - case PrimeTowerMethod::OPTIMIZED: case PrimeTowerMethod::OPTIMIZED_CONSISTENT: - if (extruder_is_used_on_this_layer[extruder_nr]) + if (extruder_is_used_on_this_layer[extruder_nr] && extruder_nr != last_extruder) { -#warning only prime if different from actual extruder (for consistent only) prime = ExtruderPrime::Prime; } - else + else if (layer_nr < storage.max_print_height_second_to_last_extruder) { prime = ExtruderPrime::Sparse; } break; + + case PrimeTowerMethod::OPTIMIZED: + if (extruder_is_used_on_this_layer[extruder_nr] && extruder_nr != last_extruder) + { + prime = ExtruderPrime::Prime; + } + break; } - if (extruder_is_used_on_this_layer[start_extruder] || prime != ExtruderPrime::None) + if (extruder_is_used_on_this_layer[extruder_nr] || prime != ExtruderPrime::None) { ret.push_back(ExtruderUse{ extruder_nr, prime }); + last_extruder = extruder_nr; } } - spdlog::info(" {} ################", layer_nr); - for (const ExtruderUse& extruder_use : ret) + if (method == PrimeTowerMethod::OPTIMIZED && ret.size() == 1 && ret.front().prime == ExtruderPrime::None) { - spdlog::info("ext {} {}", int(extruder_use.extruder_nr), int(extruder_use.prime)); + ret.front().prime = ExtruderPrime::Sparse; } - // The outermost prime tower extruder is always used if there is a prime tower, apart on layers with negative index (e.g. for the raft) - // if (method == PrimeTowerMethod::DEFAULT && layer_nr >= 0 && layer_nr <= storage.max_print_height_second_to_last_extruder) - // { - // extruder_is_used_on_this_layer[storage.primeTower.extruder_order[0]] = true; - // } - #warning restore this #if 0 // check if we are on the first layer @@ -1492,24 +1431,6 @@ std::vector } #endif - // if (method != PrimeTowerMethod::OPTIMIZED || extruder_is_used_on_this_layer[start_extruder]) - // { - // ret.push_back(start_extruder); - // } - - // for (size_t extruder_nr = 0; extruder_nr < extruder_count; extruder_nr++) - // { - // if (extruder_nr == start_extruder) - // { // skip the current extruder, it's the one we started out planning - // continue; - // } - // if (! extruder_is_used_on_this_layer[extruder_nr] && method != PrimeTowerMethod::OPTIMIZED_CONSISTENT) - // { - // continue; - // } - // ret.push_back(extruder_nr); - // } - assert(ret.size() <= (size_t)extruder_count && "Not more extruders may be planned in a layer than there are extruders!"); return ret; } diff --git a/src/PrimeTower.cpp b/src/PrimeTower.cpp index 3c9851c4b5..2d65bd58a6 100644 --- a/src/PrimeTower.cpp +++ b/src/PrimeTower.cpp @@ -213,6 +213,7 @@ void PrimeTower::generatePaths_sparseInfill(const std::vector& cumulati // Generate all possible extruders combinations, e.g. if there are 4 extruders, we have combinations // 0 / 0-1 / 0-1-2 / 0-1-2-3 / 1 / 1-2 / 1-2-3 / 2 / 2-3 / 3 // A combination is represented by a bitmask +#warning this should be iterated in outer-to-inner order for (size_t first_extruder = 0; first_extruder < nb_extruders; ++first_extruder) { for (size_t last_extruder = first_extruder; last_extruder < nb_extruders; ++last_extruder) @@ -289,8 +290,7 @@ void PrimeTower::addToGcode( { return; } -#warning remove this - // spdlog::info("add to gcode {} {} {}\n", static_cast(gcode_layer.getLayerNr()), prev_extruder, new_extruder); + if (gcode_layer.getPrimeTowerIsPlanned(new_extruder)) { // don't print the prime tower if it has been printed already with this extruder. return; @@ -316,10 +316,8 @@ void PrimeTower::addToGcode( gotoStartLocation(gcode_layer, new_extruder); } - // spdlog::info("actual prime {}\n", static_cast(required_extruder_prime[new_extruder])); - PrimeTowerMethod method = Application::getInstance().current_slice->scene.current_mesh_group->settings.get("prime_tower_mode"); - std::vector primed_extruders; + std::vector extra_primed_extruders; auto extruder_iterator = std::find_if( required_extruder_prime.begin(), @@ -338,64 +336,31 @@ void PrimeTower::addToGcode( switch (extruder_iterator->prime) { case ExtruderPrime::None: - primed_extruders.push_back(new_extruder); + if (method != PrimeTowerMethod::OPTIMIZED) + { + gcode_layer.setPrimeTowerIsPlanned(new_extruder); + } break; case ExtruderPrime::Sparse: - addToGcode_optimizedInfill(gcode_layer, required_extruder_prime, new_extruder, primed_extruders, method == PrimeTowerMethod::OPTIMIZED); + extra_primed_extruders = findExtrudersSparseInfill(gcode_layer, required_extruder_prime, new_extruder, method, { new_extruder }); + addToGcode_optimizedInfill(gcode_layer, extra_primed_extruders, new_extruder); break; case ExtruderPrime::Prime: addToGcode_denseInfill(gcode_layer, new_extruder); + gcode_layer.setPrimeTowerIsPlanned(new_extruder); - if (method == PrimeTowerMethod::OPTIMIZED) + if (method == PrimeTowerMethod::OPTIMIZED && gcode_layer.getLayerNr() < storage.max_print_height_second_to_last_extruder) { // Whatever happens before and after, use the current extruder to prime all the non-required extruders now - addToGcode_optimizedInfill(gcode_layer, required_extruder_prime, new_extruder, primed_extruders, true); + extra_primed_extruders = findExtrudersSparseInfill(gcode_layer, required_extruder_prime, new_extruder, method); + addToGcode_optimizedInfill(gcode_layer, extra_primed_extruders, new_extruder); } break; } - primed_extruders.push_back(new_extruder); - - // switch (method) - // { - // case PrimeTowerMethod::NONE: - // // This should actually not happen - // break; - - // case PrimeTowerMethod::DEFAULT: - // addToGcode_denseInfill(gcode_layer, new_extruder); - // primed_extruders.push_back(new_extruder); - // break; - - // case PrimeTowerMethod::OPTIMIZED: - // if (required_extruder_prime[new_extruder]) - // { - // // Extruder really needs to be primed - // addToGcode_denseInfill(gcode_layer, new_extruder); - // primed_extruders.push_back(new_extruder); - // } - - // // Whatever happens before and after, use the current extruder to prime all the non-required extruders now - // addToGcode_optimizedInfill(gcode_layer, required_extruder_prime, new_extruder, primed_extruders); - // break; - - // case PrimeTowerMethod::OPTIMIZED_CONSISTENT: - // if (required_extruder_prime[new_extruder]) - // { - // // Extruder really needs to be primed - // addToGcode_denseInfill(gcode_layer, new_extruder); - // } - // else - // { - // addToGcode_optimizedInfill(gcode_layer, std::vector({ new_extruder }), new_extruder, primed_extruders); - // } - // primed_extruders.push_back(new_extruder); - // break; - // } - - for (const size_t& primed_extruder : primed_extruders) + for (const size_t& primed_extruder : extra_primed_extruders) { gcode_layer.setPrimeTowerIsPlanned(primed_extruder); } @@ -414,8 +379,6 @@ void PrimeTower::addToGcode( void PrimeTower::addToGcode_denseInfill(LayerPlan& gcode_layer, const size_t extruder_nr) const { - spdlog::info("Add dense infill for layer {} ex {}", gcode_layer.getLayerNr().value, int(extruder_nr)); - const ExtrusionMoves& pattern = (gcode_layer.getLayerNr() == -static_cast(Raft::getFillerLayerCount())) ? pattern_per_extruder_layer0[extruder_nr] : pattern_per_extruder[extruder_nr]; @@ -425,59 +388,34 @@ void PrimeTower::addToGcode_denseInfill(LayerPlan& gcode_layer, const size_t ext gcode_layer.addLinesByOptimizer(pattern.lines, config, SpaceFillType::Lines); } -void PrimeTower::addToGcode_optimizedInfill( - LayerPlan& gcode_layer, - const std::vector& required_extruder_prime, - const size_t current_extruder, - std::vector& primed_extruders, - bool group_with_next_extruders) const +void PrimeTower::addToGcode_optimizedInfill(LayerPlan& gcode_layer, const std::vector& extruders_to_prime, const size_t current_extruder) const { std::vector> extruders_to_prime_grouped; - if (group_with_next_extruders) + // Group extruders which are besides each other + for (size_t extruder_to_prime : extruders_to_prime) { - std::vector extruders_to_prime; - - // First, gather all extruders to be primed : we are going to process them all now, even if - // the rings are not besides each other - for (const ExtruderUse& extruder_use : required_extruder_prime) + if (extruders_to_prime_grouped.empty()) { - if (extruder_use.prime == ExtruderPrime::Sparse && ! gcode_layer.getPrimeTowerIsPlanned(extruder_use.extruder_nr)) - { - extruders_to_prime.push_back(extruder_use.extruder_nr); - primed_extruders.push_back(extruder_use.extruder_nr); - } + // First extruder : create new group + extruders_to_prime_grouped.push_back({ extruder_to_prime }); } - - // Now, group extruders which are besides each other - std::vector> extruders_to_prime_grouped; - for (const size_t& extruder_to_prime : extruders_to_prime) + else { - if (extruders_to_prime_grouped.empty()) + std::vector& last_group = extruders_to_prime_grouped.back(); +#warning This does not take care of extruders ordering + if (last_group.back() == extruder_to_prime - 1) { - // First extruder : create new group - extruders_to_prime_grouped.push_back({ extruder_to_prime }); + // New extruders which belongs to same group + last_group.push_back(extruder_to_prime); } else { - std::vector& last_group = extruders_to_prime_grouped.back(); - if (last_group.back() == extruder_to_prime - 1) - { - // New extruders which belongs to same group - last_group.push_back(extruder_to_prime); - } - else - { - // New extruders which belongs to new group - extruders_to_prime_grouped.push_back({ extruder_to_prime }); - } + // New extruders which belongs to new group + extruders_to_prime_grouped.push_back({ extruder_to_prime }); } } } - else - { - extruders_to_prime_grouped.push_back({ current_extruder }); - } std::string grouped_extruders; for (auto& group : extruders_to_prime_grouped) @@ -490,7 +428,6 @@ void PrimeTower::addToGcode_optimizedInfill( } grouped_extruders.append("}"); } - spdlog::info("Add sparse infill for layer {} ex {}", gcode_layer.getLayerNr().value, grouped_extruders); #warning What should we do in case of extruders with different lines widths ? // And finally, append patterns for each group @@ -526,6 +463,45 @@ void PrimeTower::addToGcode_optimizedInfill( } } +std::vector PrimeTower::findExtrudersSparseInfill( + LayerPlan& gcode_layer, + const std::vector& required_extruder_prime, + const size_t current_extruder, + PrimeTowerMethod method, + const std::vector& initial_list) const +{ + std::vector extruders_to_prime; + + for (size_t extruder_nr : extruder_order) + { + auto iterator_initial_list = std::find(initial_list.begin(), initial_list.end(), extruder_nr); + bool is_in_initial_list = iterator_initial_list != initial_list.end(); + + if (is_in_initial_list) + { + extruders_to_prime.push_back(extruder_nr); + } + else if (method == PrimeTowerMethod::OPTIMIZED && ! gcode_layer.getPrimeTowerIsPlanned(extruder_nr)) + { + auto iterator_required_list = std::find_if( + required_extruder_prime.begin(), + required_extruder_prime.end(), + [extruder_nr](const ExtruderUse& extruder_use) + { + return extruder_use.extruder_nr == extruder_nr && extruder_use.prime == ExtruderPrime::Prime; + }); + bool is_in_required_list = iterator_required_list != required_extruder_prime.end(); + + if (! is_in_required_list) + { + extruders_to_prime.push_back(extruder_nr); + } + } + } + + return extruders_to_prime; +} + void PrimeTower::subtractFromSupport(SliceDataStorage& storage) { const Polygons outside_polygon = outer_poly.getOutsidePolygons(); From 679537a9a768714052df44ab4a6aef3d9ae0b02a Mon Sep 17 00:00:00 2001 From: wawanbreton Date: Wed, 18 Oct 2023 14:32:19 +0000 Subject: [PATCH 020/201] Applied clang-format. --- include/PrimeTower.h | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/include/PrimeTower.h b/include/PrimeTower.h index 1e43595a95..273e6c7816 100644 --- a/include/PrimeTower.h +++ b/include/PrimeTower.h @@ -165,9 +165,7 @@ class PrimeTower void addToGcode_denseInfill(LayerPlan& gcode_layer, const size_t extruder) const; #warning TBD documentation - void addToGcode_optimizedInfill(LayerPlan& gcode_layer, - const std::vector& extruders_to_prime, - const size_t current_extruder) const; + void addToGcode_optimizedInfill(LayerPlan& gcode_layer, const std::vector& extruders_to_prime, const size_t current_extruder) const; std::vector findExtrudersSparseInfill( LayerPlan& gcode_layer, From 663191955cbdbf80729a7ea7184da5f883224008 Mon Sep 17 00:00:00 2001 From: wawanbreton Date: Thu, 2 Nov 2023 20:25:22 +0000 Subject: [PATCH 021/201] Applied clang-format. --- include/PathOrderOptimizer.h | 20 ++++++++++---------- include/infill.h | 8 ++++---- src/SkeletalTrapezoidationGraph.cpp | 6 +++--- src/gcodeExport.cpp | 14 +++++++------- src/infill.cpp | 14 +++++++------- src/settings/MeshPathConfigs.cpp | 4 ++-- src/skin.cpp | 4 ++-- 7 files changed, 35 insertions(+), 35 deletions(-) diff --git a/include/PathOrderOptimizer.h b/include/PathOrderOptimizer.h index ae7591db45..0406ebc52d 100644 --- a/include/PathOrderOptimizer.h +++ b/include/PathOrderOptimizer.h @@ -4,15 +4,7 @@ #ifndef PATHORDEROPTIMIZER_H #define PATHORDEROPTIMIZER_H -#include "InsetOrderOptimizer.h" // for makeOrderIncludeTransitive -#include "PathOrdering.h" -#include "pathPlanning/CombPath.h" //To calculate the combing distance if we want to use combing. -#include "pathPlanning/LinePolygonsCrossings.h" //To prevent calculating combing distances if we don't cross the combing borders. -#include "settings/EnumSettings.h" //To get the seam settings. -#include "settings/ZSeamConfig.h" //To read the seam configuration. -#include "utils/linearAlg2D.h" //To find the angle of corners to hide seams. -#include "utils/polygonUtils.h" -#include "utils/views/dfs.h" +#include #include #include @@ -23,7 +15,15 @@ #include #include -#include +#include "InsetOrderOptimizer.h" // for makeOrderIncludeTransitive +#include "PathOrdering.h" +#include "pathPlanning/CombPath.h" //To calculate the combing distance if we want to use combing. +#include "pathPlanning/LinePolygonsCrossings.h" //To prevent calculating combing distances if we don't cross the combing borders. +#include "settings/EnumSettings.h" //To get the seam settings. +#include "settings/ZSeamConfig.h" //To read the seam configuration. +#include "utils/linearAlg2D.h" //To find the angle of corners to hide seams. +#include "utils/polygonUtils.h" +#include "utils/views/dfs.h" namespace cura { diff --git a/include/infill.h b/include/infill.h index 289a0850bb..ccea0c71a9 100644 --- a/include/infill.h +++ b/include/infill.h @@ -4,6 +4,10 @@ #ifndef INFILL_H #define INFILL_H +#include + +#include + #include "infill/LightningGenerator.h" #include "infill/ZigzagConnectorProcessor.h" #include "settings/EnumSettings.h" //For infill types. @@ -14,10 +18,6 @@ #include "utils/IntPoint.h" #include "utils/section_type.h" -#include - -#include - namespace cura { diff --git a/src/SkeletalTrapezoidationGraph.cpp b/src/SkeletalTrapezoidationGraph.cpp index 4657b8ee97..5410960b46 100644 --- a/src/SkeletalTrapezoidationGraph.cpp +++ b/src/SkeletalTrapezoidationGraph.cpp @@ -3,12 +3,12 @@ #include "SkeletalTrapezoidationGraph.h" -#include "utils/linearAlg2D.h" -#include "utils/macros.h" +#include #include -#include +#include "utils/linearAlg2D.h" +#include "utils/macros.h" namespace cura { diff --git a/src/gcodeExport.cpp b/src/gcodeExport.cpp index 2ef08a0474..5e37ec6148 100644 --- a/src/gcodeExport.cpp +++ b/src/gcodeExport.cpp @@ -3,6 +3,13 @@ #include "gcodeExport.h" +#include +#include +#include +#include + +#include + #include "Application.h" //To send layer view data. #include "ExtruderTrain.h" #include "PrintFeature.h" @@ -14,13 +21,6 @@ #include "utils/Date.h" #include "utils/string.h" // MMtoStream, PrecisionedDouble -#include - -#include -#include -#include -#include - namespace cura { diff --git a/src/infill.cpp b/src/infill.cpp index 6da3c25c4f..d5850dac08 100644 --- a/src/infill.cpp +++ b/src/infill.cpp @@ -3,6 +3,13 @@ #include "infill.h" +#include //For std::sort. +#include +#include + +#include +#include + #include "WallToolPaths.h" #include "infill/GyroidInfill.h" #include "infill/ImageBasedDensityProvider.h" @@ -21,13 +28,6 @@ #include "utils/linearAlg2D.h" #include "utils/polygonUtils.h" -#include -#include - -#include //For std::sort. -#include -#include - /*! * Function which returns the scanline_idx for a given x coordinate * diff --git a/src/settings/MeshPathConfigs.cpp b/src/settings/MeshPathConfigs.cpp index d91595ce37..635b044db4 100644 --- a/src/settings/MeshPathConfigs.cpp +++ b/src/settings/MeshPathConfigs.cpp @@ -3,11 +3,11 @@ #include "settings/MeshPathConfigs.h" +#include + #include "ExtruderTrain.h" #include "PrintFeature.h" -#include - namespace cura { diff --git a/src/skin.cpp b/src/skin.cpp index 28fc60c238..554d3b9750 100644 --- a/src/skin.cpp +++ b/src/skin.cpp @@ -3,6 +3,8 @@ #include "skin.h" +#include // std::ceil + #include "Application.h" //To get settings. #include "ExtruderTrain.h" #include "Slice.h" @@ -15,8 +17,6 @@ #include "utils/math.h" #include "utils/polygonUtils.h" -#include // std::ceil - #define MIN_AREA_SIZE (0.4 * 0.4) namespace cura From 871ea5e6d664c0ababea06d5093794149d866854 Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Thu, 2 Nov 2023 21:27:52 +0100 Subject: [PATCH 022/201] Fix build --- include/PrimeTower.h | 2 +- src/FffGcodeWriter.cpp | 8 +++----- src/PrimeTower.cpp | 14 +++++++------- 3 files changed, 11 insertions(+), 13 deletions(-) diff --git a/include/PrimeTower.h b/include/PrimeTower.h index 3ea546efa6..8164e01e70 100644 --- a/include/PrimeTower.h +++ b/include/PrimeTower.h @@ -152,7 +152,7 @@ class PrimeTower * \param line_width The actual line width of the extruder * \param actual_extruder_nr The actual extruder to be used */ - ExtrusionMoves generatePath_sparseInfill( + Polygons generatePath_sparseInfill( const size_t first_extruder, const size_t last_extruder, const std::vector& rings_radii, diff --git a/src/FffGcodeWriter.cpp b/src/FffGcodeWriter.cpp index 414eac2a8d..f569b66a9d 100644 --- a/src/FffGcodeWriter.cpp +++ b/src/FffGcodeWriter.cpp @@ -1061,7 +1061,7 @@ LayerPlan& FffGcodeWriter::processLayer(const SliceDataStorage& storage, LayerIn // later in the print a prime tower is needed. // - prime tower is already printed this layer (only applicable for more than 2 extruders). // The setExtruder_addPrime takes care of this. - if (extruder_nr != extruder_order.front() || (extruder_order.size() == 1 && layer_nr >= 0) || extruder_nr == 0) + if (extruder_nr != extruder_order.front().extruder_nr || (extruder_order.size() == 1 && layer_nr >= 0) || extruder_nr == 0) { setExtruder_addPrime(storage, gcode_layer, extruder_nr); } @@ -1092,7 +1092,7 @@ LayerPlan& FffGcodeWriter::processLayer(const SliceDataStorage& storage, LayerIn // Always print a prime tower before switching extruder. Unless: // - The prime tower is already printed this layer (setExtruder_addPrime takes care of this). // - this is the last extruder of the layer, since the next layer will start with the same extruder. - if (extruder_nr != extruder_order.back() && layer_nr >= 0) + if (extruder_nr != extruder_order.back().extruder_nr && layer_nr >= 0) { setExtruder_addPrime(storage, gcode_layer, extruder_nr); } @@ -1403,9 +1403,7 @@ std::vector // Make a temp list with the potential ordered extruders std::vector ordered_extruders; ordered_extruders.push_back(start_extruder); - - // The outermost prime tower extruder is always used if there is a prime tower, apart on layers with negative index (e.g. for the raft) - if (mesh_group_settings.get("prime_tower_enable") && /*layer_nr >= 0 &&*/ layer_nr <= storage.max_print_height_second_to_last_extruder) + for (size_t extruder_nr = 0; extruder_nr < extruder_count; extruder_nr++) { if (extruder_nr != start_extruder) { diff --git a/src/PrimeTower.cpp b/src/PrimeTower.cpp index 7c634c4651..56ef14dc06 100644 --- a/src/PrimeTower.cpp +++ b/src/PrimeTower.cpp @@ -246,10 +246,10 @@ void PrimeTower::generatePaths_sparseInfill(const std::vector& cumulati extruders_combination |= (1 << extruder_nr); } - std::map infills_for_combination; + std::map infills_for_combination; for (const ActualExtruder& actual_extruder : actual_extruders) { - ExtrusionMoves infill = generatePath_sparseInfill(first_extruder, last_extruder, rings_radii, actual_extruder.line_width, actual_extruder.number); + Polygons infill = generatePath_sparseInfill(first_extruder, last_extruder, rings_radii, actual_extruder.line_width, actual_extruder.number); infills_for_combination[actual_extruder.number] = infill; } @@ -259,7 +259,7 @@ void PrimeTower::generatePaths_sparseInfill(const std::vector& cumulati } } -PrimeTower::ExtrusionMoves PrimeTower::generatePath_sparseInfill( +Polygons PrimeTower::generatePath_sparseInfill( const size_t first_extruder, const size_t last_extruder, const std::vector& rings_radii, @@ -277,7 +277,7 @@ PrimeTower::ExtrusionMoves PrimeTower::generatePath_sparseInfill( const size_t nb_rings = std::ceil(static_cast(radius_delta) / max_bridging_distance); const coord_t actual_radius_step = radius_delta / nb_rings; - ExtrusionMoves pattern; + Polygons pattern; for (size_t i = 0; i < nb_rings; ++i) { const coord_t ring_inner_radius = (inner_radius + i * actual_radius_step) + semi_line_width; @@ -285,7 +285,7 @@ PrimeTower::ExtrusionMoves PrimeTower::generatePath_sparseInfill( const size_t semi_nb_spokes = std::ceil((M_PI * ring_outer_radius) / max_bridging_distance); - pattern.polygons.add(PolygonUtils::makeWheel(middle, ring_inner_radius, ring_outer_radius, semi_nb_spokes, ARC_RESOLUTION)); + pattern.add(PolygonUtils::makeWheel(middle, ring_inner_radius, ring_outer_radius, semi_nb_spokes, ARC_RESOLUTION)); } return pattern; @@ -479,12 +479,12 @@ void PrimeTower::addToGcode_optimizedInfill(LayerPlan& gcode_layer, const std::v auto iterator_combination = sparse_pattern_per_extruders.find(mask); if (iterator_combination != sparse_pattern_per_extruders.end()) { - const std::map& infill_for_combination = iterator_combination->second; + const std::map& infill_for_combination = iterator_combination->second; auto iterator_extruder_nr = infill_for_combination.find(current_extruder); if (iterator_extruder_nr != infill_for_combination.end()) { - gcode_layer.addPolygonsByOptimizer(iterator_extruder_nr->second.polygons, config); + gcode_layer.addPolygonsByOptimizer(iterator_extruder_nr->second, config); } else { From 9e95df4474417415345a654964b21b591081e2fa Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Fri, 3 Nov 2023 09:07:11 +0100 Subject: [PATCH 023/201] Restore first layer behavior (WIP) --- include/LayerPlan.h | 11 +++++++++++ include/PrimeTower.h | 2 ++ src/LayerPlan.cpp | 11 +++++++++++ src/PrimeTower.cpp | 29 ++++++++++++++++++++++++----- 4 files changed, 48 insertions(+), 5 deletions(-) diff --git a/include/LayerPlan.h b/include/LayerPlan.h index 972af3e6d3..5e421bb6fe 100644 --- a/include/LayerPlan.h +++ b/include/LayerPlan.h @@ -68,6 +68,7 @@ class LayerPlan : public NoCopy std::vector layer_start_pos_per_extruder; //!< The starting position of a layer for each extruder std::vector has_prime_tower_planned_per_extruder; //!< For each extruder, whether the prime tower is planned yet or not. + bool has_prime_tower_base_planned; //!< Whether the prime tower base is planned yet or not. std::optional last_planned_position; //!< The last planned XY position of the print head (if known) std::shared_ptr current_mesh; //!< The mesh of the last planned move. @@ -203,6 +204,16 @@ class LayerPlan : public NoCopy */ void setPrimeTowerIsPlanned(unsigned int extruder_nr); + /*! + * Whether the prime tower extra base is already planned. + */ + bool getPrimeTowerBaseIsPlanned() const; + + /*! + * Mark the prime tower extra base as planned. + */ + void setPrimeTowerBaseIsPlanned(); + bool getSkirtBrimIsPlanned(unsigned int extruder_nr) const; void setSkirtBrimIsPlanned(unsigned int extruder_nr); diff --git a/include/PrimeTower.h b/include/PrimeTower.h index 8164e01e70..6358a4ef73 100644 --- a/include/PrimeTower.h +++ b/include/PrimeTower.h @@ -178,6 +178,8 @@ class PrimeTower */ void addToGcode_denseInfill(LayerPlan& gcode_layer, const size_t extruder) const; + void addToGcode_base(LayerPlan& gcode_layer, const size_t extruder_nr) const; + #warning TBD documentation void addToGcode_optimizedInfill(LayerPlan& gcode_layer, const std::vector& extruders_to_prime, const size_t current_extruder) const; diff --git a/src/LayerPlan.cpp b/src/LayerPlan.cpp index 52305a9521..772f2792c3 100644 --- a/src/LayerPlan.cpp +++ b/src/LayerPlan.cpp @@ -98,6 +98,7 @@ LayerPlan::LayerPlan( , is_raft_layer(layer_nr < 0 - static_cast(Raft::getFillerLayerCount())) , layer_thickness(layer_thickness) , has_prime_tower_planned_per_extruder(Application::getInstance().current_slice->scene.extruders.size(), false) + , has_prime_tower_base_planned(false) , current_mesh(nullptr) , last_extruder_previous_layer(start_extruder) , last_planned_extruder(&Application::getInstance().current_slice->scene.extruders[start_extruder]) @@ -319,6 +320,16 @@ void LayerPlan::setPrimeTowerIsPlanned(unsigned int extruder_nr) has_prime_tower_planned_per_extruder[extruder_nr] = true; } +bool LayerPlan::getPrimeTowerBaseIsPlanned() const +{ + return has_prime_tower_base_planned; +} + +void LayerPlan::setPrimeTowerBaseIsPlanned() +{ + has_prime_tower_base_planned = true; +} + std::optional> LayerPlan::getFirstTravelDestinationState() const { std::optional> ret; diff --git a/src/PrimeTower.cpp b/src/PrimeTower.cpp index 56ef14dc06..05ca687c44 100644 --- a/src/PrimeTower.cpp +++ b/src/PrimeTower.cpp @@ -163,8 +163,10 @@ void PrimeTower::generatePaths_denseInfill(std::vector& cumulative_inse } } - // The most outside extruder is used for the base - if (extruder_nr == extruder_order.front() && (base_enabled || has_raft) && base_extra_radius > 0 && base_height > 0) + // Generate the base outside extra rings + if ((method == PrimeTowerMethod::OPTIMIZED + || (extruder_nr == extruder_order.front() && (method == PrimeTowerMethod::OPTIMIZED_CONSISTENT || method == PrimeTowerMethod::DEFAULT))) + && (base_enabled || has_raft) && base_extra_radius > 0 && base_height > 0) { for (coord_t z = 0; z < base_height; z += layer_height) { @@ -184,14 +186,19 @@ void PrimeTower::generatePaths_denseInfill(std::vector& cumulative_inse cumulative_inset += wall_nr * line_width; cumulative_insets.push_back(cumulative_inset); + } - // Only the most inside extruder needs to fill the inside of the prime tower - if (extruder_nr == extruder_order.back()) + // Now we have to total cumulative inset, generate the base inside extra rings + for (size_t extruder_nr : extruder_order) + { + const coord_t line_width = scene.extruders[extruder_nr].settings.get("prime_tower_line_width"); + MovesByExtruder& moves = base_extra_moves[extruder_nr]; + if (! moves.empty() && (method == PrimeTowerMethod::OPTIMIZED || extruder_nr == extruder_order.back())) { Polygons pattern = PolygonUtils::generateInset(outer_poly, line_width, cumulative_inset); if (! pattern.empty()) { - base_extra_moves[extruder_nr].push_back(pattern); + moves[0].add(pattern); } } } @@ -382,6 +389,12 @@ void PrimeTower::addToGcode( break; } + if (! gcode_layer.getPrimeTowerBaseIsPlanned()) + { + addToGcode_base(gcode_layer, new_extruder); + gcode_layer.setPrimeTowerBaseIsPlanned(); + } + for (const size_t& primed_extruder : extra_primed_extruders) { gcode_layer.setPrimeTowerIsPlanned(primed_extruder); @@ -412,6 +425,12 @@ void PrimeTower::addToGcode_denseInfill(LayerPlan& gcode_layer, const size_t ext const Polygons& pattern = prime_moves[extruder_nr]; gcode_layer.addPolygonsByOptimizer(pattern, config); } +} + +void PrimeTower::addToGcode_base(LayerPlan& gcode_layer, const size_t extruder_nr) const +{ + const size_t raft_total_extra_layers = Raft::getTotalExtraLayers(); + LayerIndex absolute_layer_number = gcode_layer.getLayerNr() + raft_total_extra_layers; const std::vector& pattern_extra_brim = base_extra_moves[extruder_nr]; if (absolute_layer_number < pattern_extra_brim.size()) From 3ab4f6950ab1182c2497fd4f4cfa4911e1f0a7ef Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Fri, 3 Nov 2023 13:48:42 +0100 Subject: [PATCH 024/201] Fix prime tower base/optimized integration issues --- include/LayerPlan.h | 11 ++++++++++ include/PrimeTower.h | 5 ++++- src/LayerPlan.cpp | 11 ++++++++++ src/PrimeTower.cpp | 49 +++++++++++++++++++++++++++++++++++--------- 4 files changed, 65 insertions(+), 11 deletions(-) diff --git a/include/LayerPlan.h b/include/LayerPlan.h index 5e421bb6fe..1a7d21ef6c 100644 --- a/include/LayerPlan.h +++ b/include/LayerPlan.h @@ -69,6 +69,7 @@ class LayerPlan : public NoCopy std::vector layer_start_pos_per_extruder; //!< The starting position of a layer for each extruder std::vector has_prime_tower_planned_per_extruder; //!< For each extruder, whether the prime tower is planned yet or not. bool has_prime_tower_base_planned; //!< Whether the prime tower base is planned yet or not. + bool has_prime_tower_inset_planned; //!< Whether the prime tower inset is planned yet or not. std::optional last_planned_position; //!< The last planned XY position of the print head (if known) std::shared_ptr current_mesh; //!< The mesh of the last planned move. @@ -214,6 +215,16 @@ class LayerPlan : public NoCopy */ void setPrimeTowerBaseIsPlanned(); + /*! + * Whether the prime tower extra inset is already planned. + */ + bool getPrimeTowerInsetIsPlanned() const; + + /*! + * Mark the prime tower extra inset as planned. + */ + void setPrimeTowerInsetIsPlanned(); + bool getSkirtBrimIsPlanned(unsigned int extruder_nr) const; void setSkirtBrimIsPlanned(unsigned int extruder_nr); diff --git a/include/PrimeTower.h b/include/PrimeTower.h index 6358a4ef73..22f5b6d932 100644 --- a/include/PrimeTower.h +++ b/include/PrimeTower.h @@ -45,6 +45,7 @@ class PrimeTower std::map> sparse_pattern_per_extruders; //!< For each extruders combination, and for each actual extruder, the pattern to print on all layers where extruders are actually useless. MovesByLayer base_extra_moves; //!< For each layer and each extruder, the extra moves to be processed for better adhesion/strength + MovesByExtruder inset_extra_moves; //!< For each extruder, the extra inset moves to be processed for better adhesion on initial layer Polygons outer_poly; //!< The outline of the outermost prime tower. std::vector outer_poly_base; //!< The outline of the layers having extra width for the base @@ -178,7 +179,9 @@ class PrimeTower */ void addToGcode_denseInfill(LayerPlan& gcode_layer, const size_t extruder) const; - void addToGcode_base(LayerPlan& gcode_layer, const size_t extruder_nr) const; + bool addToGcode_base(LayerPlan& gcode_layer, const size_t extruder_nr) const; + + bool addToGcode_inset(LayerPlan& gcode_layer, const size_t extruder_nr) const; #warning TBD documentation void addToGcode_optimizedInfill(LayerPlan& gcode_layer, const std::vector& extruders_to_prime, const size_t current_extruder) const; diff --git a/src/LayerPlan.cpp b/src/LayerPlan.cpp index 772f2792c3..cb445a3e26 100644 --- a/src/LayerPlan.cpp +++ b/src/LayerPlan.cpp @@ -99,6 +99,7 @@ LayerPlan::LayerPlan( , layer_thickness(layer_thickness) , has_prime_tower_planned_per_extruder(Application::getInstance().current_slice->scene.extruders.size(), false) , has_prime_tower_base_planned(false) + , has_prime_tower_inset_planned(false) , current_mesh(nullptr) , last_extruder_previous_layer(start_extruder) , last_planned_extruder(&Application::getInstance().current_slice->scene.extruders[start_extruder]) @@ -330,6 +331,16 @@ void LayerPlan::setPrimeTowerBaseIsPlanned() has_prime_tower_base_planned = true; } +bool LayerPlan::getPrimeTowerInsetIsPlanned() const +{ + return has_prime_tower_inset_planned; +} + +void LayerPlan::setPrimeTowerInsetIsPlanned() +{ + has_prime_tower_inset_planned = true; +} + std::optional> LayerPlan::getFirstTravelDestinationState() const { std::optional> ret; diff --git a/src/PrimeTower.cpp b/src/PrimeTower.cpp index 05ca687c44..4924701f23 100644 --- a/src/PrimeTower.cpp +++ b/src/PrimeTower.cpp @@ -135,10 +135,10 @@ void PrimeTower::generatePaths_denseInfill(std::vector& cumulative_inse const bool has_raft = mesh_group_settings.get("adhesion_type") == EPlatformAdhesion::RAFT; const coord_t base_height = std::max(scene.settings.get("prime_tower_base_height"), has_raft ? layer_height : 0); const double base_curve_magnitude = mesh_group_settings.get("prime_tower_base_curve_magnitude"); - const coord_t line_width = scene.extruders[extruder_order.front()].settings.get("prime_tower_line_width"); prime_moves.resize(extruder_count); base_extra_moves.resize(extruder_count); + inset_extra_moves.resize(extruder_count); coord_t cumulative_inset = 0; // Each tower shape is going to be printed inside the other. This is the inset we're doing for each extruder. for (size_t extruder_nr : extruder_order) @@ -188,17 +188,17 @@ void PrimeTower::generatePaths_denseInfill(std::vector& cumulative_inse cumulative_insets.push_back(cumulative_inset); } - // Now we have to total cumulative inset, generate the base inside extra rings + // Now we have the total cumulative inset, generate the base inside extra rings for (size_t extruder_nr : extruder_order) { const coord_t line_width = scene.extruders[extruder_nr].settings.get("prime_tower_line_width"); - MovesByExtruder& moves = base_extra_moves[extruder_nr]; - if (! moves.empty() && (method == PrimeTowerMethod::OPTIMIZED || extruder_nr == extruder_order.back())) + + if (extruder_nr == extruder_order.back() || method == PrimeTowerMethod::OPTIMIZED) { Polygons pattern = PolygonUtils::generateInset(outer_poly, line_width, cumulative_inset); if (! pattern.empty()) { - moves[0].add(pattern); + inset_extra_moves[extruder_nr].add(pattern); } } } @@ -389,12 +389,16 @@ void PrimeTower::addToGcode( break; } - if (! gcode_layer.getPrimeTowerBaseIsPlanned()) + if (! gcode_layer.getPrimeTowerBaseIsPlanned() && addToGcode_base(gcode_layer, new_extruder)) { - addToGcode_base(gcode_layer, new_extruder); gcode_layer.setPrimeTowerBaseIsPlanned(); } + if (! gcode_layer.getPrimeTowerInsetIsPlanned() && addToGcode_inset(gcode_layer, new_extruder)) + { + gcode_layer.setPrimeTowerInsetIsPlanned(); + } + for (const size_t& primed_extruder : extra_primed_extruders) { gcode_layer.setPrimeTowerIsPlanned(primed_extruder); @@ -427,7 +431,7 @@ void PrimeTower::addToGcode_denseInfill(LayerPlan& gcode_layer, const size_t ext } } -void PrimeTower::addToGcode_base(LayerPlan& gcode_layer, const size_t extruder_nr) const +bool PrimeTower::addToGcode_base(LayerPlan& gcode_layer, const size_t extruder_nr) const { const size_t raft_total_extra_layers = Raft::getTotalExtraLayers(); LayerIndex absolute_layer_number = gcode_layer.getLayerNr() + raft_total_extra_layers; @@ -436,10 +440,35 @@ void PrimeTower::addToGcode_base(LayerPlan& gcode_layer, const size_t extruder_n if (absolute_layer_number < pattern_extra_brim.size()) { // Extra rings for stronger base - const GCodePathConfig& config = gcode_layer.configs_storage.prime_tower_config_per_extruder[extruder_nr]; const Polygons& pattern = pattern_extra_brim[absolute_layer_number]; - gcode_layer.addPolygonsByOptimizer(pattern, config); + if (! pattern.empty()) + { + const GCodePathConfig& config = gcode_layer.configs_storage.prime_tower_config_per_extruder[extruder_nr]; + gcode_layer.addPolygonsByOptimizer(pattern, config); + return true; + } + } + + return false; +} + +bool PrimeTower::addToGcode_inset(LayerPlan& gcode_layer, const size_t extruder_nr) const +{ + const size_t raft_total_extra_layers = Raft::getTotalExtraLayers(); + LayerIndex absolute_layer_number = gcode_layer.getLayerNr() + raft_total_extra_layers; + + if (absolute_layer_number == 0) // Extra-adhesion on very first layer only + { + const Polygons& pattern_extra_inset = inset_extra_moves[extruder_nr]; + if (! pattern_extra_inset.empty()) + { + const GCodePathConfig& config = gcode_layer.configs_storage.prime_tower_config_per_extruder[extruder_nr]; + gcode_layer.addPolygonsByOptimizer(pattern_extra_inset, config); + return true; + } } + + return false; } void PrimeTower::addToGcode_optimizedInfill(LayerPlan& gcode_layer, const std::vector& extruders_to_prime, const size_t current_extruder) const From 4cd93b83fc784607692d73dad44e003b4ca178c3 Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Mon, 6 Nov 2023 11:02:38 +0100 Subject: [PATCH 025/201] Now taking care of extruders ordering --- include/PrimeTower.h | 27 +++---- src/PrimeTower.cpp | 188 ++++++++++++++++++++++--------------------- 2 files changed, 110 insertions(+), 105 deletions(-) diff --git a/include/PrimeTower.h b/include/PrimeTower.h index 22f5b6d932..b1b975f982 100644 --- a/include/PrimeTower.h +++ b/include/PrimeTower.h @@ -95,15 +95,15 @@ class PrimeTower * \param storage where to get settings from; where to get the maximum height of the prime tower from * \param[in,out] gcode_layer Where to get the current extruder from; where to store the generated layer paths * \param required_extruder_prime the extruders which actually required to be primed at this layer - * \param prev_extruder The previous extruder with which paths were planned; from which extruder a switch was made - * \param new_extruder The switched to extruder with which the prime tower paths should be generated. + * \param prev_extruder_nr The previous extruder with which paths were planned; from which extruder a switch was made + * \param new_extruder_nr The switched to extruder with which the prime tower paths should be generated. */ void addToGcode( const SliceDataStorage& storage, LayerPlan& gcode_layer, const std::vector& required_extruder_prime, - const size_t prev_extruder, - const size_t new_extruder) const; + const size_t prev_extruder_nr, + const size_t new_extruder_nr) const; /*! * \brief Subtract the prime tower from the support areas in storage. @@ -147,15 +147,15 @@ class PrimeTower /*! * \brief Generate the sparse extrude paths for an extruders combination * - * \param first_extruder The index of the first extruder to be pseudo-primed - * \param last_extruder The index of the last extruder to be pseudo-primed + * \param first_extruder_nr The index of the first extruder to be pseudo-primed + * \param last_extruder_nr The index of the last extruder to be pseudo-primed * \param rings_radii The external radii of each extruder ring, plus the internal radius of the internal ring * \param line_width The actual line width of the extruder - * \param actual_extruder_nr The actual extruder to be used + * \param actual_extruder_nr The number of the actual extruder to be used */ Polygons generatePath_sparseInfill( - const size_t first_extruder, - const size_t last_extruder, + const size_t first_extruder_idx, + const size_t last_extruder_idx, const std::vector& rings_radii, const coord_t line_width, const size_t actual_extruder_nr); @@ -184,14 +184,13 @@ class PrimeTower bool addToGcode_inset(LayerPlan& gcode_layer, const size_t extruder_nr) const; #warning TBD documentation - void addToGcode_optimizedInfill(LayerPlan& gcode_layer, const std::vector& extruders_to_prime, const size_t current_extruder) const; + void addToGcode_optimizedInfill(LayerPlan& gcode_layer, const std::vector& extruders_to_prime_idx, const size_t current_extruder_nr) const; - std::vector findExtrudersSparseInfill( - LayerPlan& gcode_layer, + std::vector findExtrudersSparseInfill(LayerPlan& gcode_layer, const std::vector& required_extruder_prime, - const size_t current_extruder, + const size_t current_extruder_nr, cura::PrimeTowerMethod method, - const std::vector& initial_list = {}) const; + const std::vector& initial_list_idx = {}) const; /*! * For an extruder switch that happens not on the first layer, the extruder needs to be primed on the prime tower. diff --git a/src/PrimeTower.cpp b/src/PrimeTower.cpp index 4924701f23..eac7249f5e 100644 --- a/src/PrimeTower.cpp +++ b/src/PrimeTower.cpp @@ -70,7 +70,6 @@ PrimeTower::PrimeTower() const Ratio adhesion_b = scene_pointer->extruders[extruder_nr_b].settings.get("material_adhesion_tendency"); return adhesion_a < adhesion_b; }); -#warning TBD take care of actual extruder order for optimized tower ! } void PrimeTower::checkUsed(const SliceDataStorage& storage) @@ -242,21 +241,21 @@ void PrimeTower::generatePaths_sparseInfill(const std::vector& cumulati // Generate all possible extruders combinations, e.g. if there are 4 extruders, we have combinations // 0 / 0-1 / 0-1-2 / 0-1-2-3 / 1 / 1-2 / 1-2-3 / 2 / 2-3 / 3 // A combination is represented by a bitmask -#warning this should be iterated in outer-to-inner order - for (size_t first_extruder = 0; first_extruder < nb_extruders; ++first_extruder) + for (size_t first_extruder_idx = 0; first_extruder_idx < nb_extruders; ++first_extruder_idx) { - for (size_t last_extruder = first_extruder; last_extruder < nb_extruders; ++last_extruder) + for (size_t last_extruder_idx = first_extruder_idx; last_extruder_idx < nb_extruders; ++last_extruder_idx) { size_t extruders_combination = 0; - for (size_t extruder_nr = first_extruder; extruder_nr <= last_extruder; ++extruder_nr) + for (size_t extruder_idx = first_extruder_idx; extruder_idx <= last_extruder_idx; ++extruder_idx) { + size_t extruder_nr = extruder_order.at(extruder_idx); extruders_combination |= (1 << extruder_nr); } std::map infills_for_combination; for (const ActualExtruder& actual_extruder : actual_extruders) { - Polygons infill = generatePath_sparseInfill(first_extruder, last_extruder, rings_radii, actual_extruder.line_width, actual_extruder.number); + Polygons infill = generatePath_sparseInfill(first_extruder_idx, last_extruder_idx, rings_radii, actual_extruder.line_width, actual_extruder.number); infills_for_combination[actual_extruder.number] = infill; } @@ -267,32 +266,36 @@ void PrimeTower::generatePaths_sparseInfill(const std::vector& cumulati } Polygons PrimeTower::generatePath_sparseInfill( - const size_t first_extruder, - const size_t last_extruder, + const size_t first_extruder_idx, + const size_t last_extruder_idx, const std::vector& rings_radii, const coord_t line_width, const size_t actual_extruder_nr) { const Scene& scene = Application::getInstance().current_slice->scene; const coord_t max_bridging_distance = scene.extruders[actual_extruder_nr].settings.get("prime_tower_max_bridging_distance"); - const coord_t outer_radius = rings_radii[first_extruder]; - const coord_t inner_radius = rings_radii[last_extruder + 1]; + const coord_t outer_radius = rings_radii[first_extruder_idx]; + const coord_t inner_radius = rings_radii[last_extruder_idx + 1]; const coord_t radius_delta = outer_radius - inner_radius; const coord_t semi_line_width = line_width / 2; + Polygons pattern; + // Split ring according to max bridging distance const size_t nb_rings = std::ceil(static_cast(radius_delta) / max_bridging_distance); - const coord_t actual_radius_step = radius_delta / nb_rings; - - Polygons pattern; - for (size_t i = 0; i < nb_rings; ++i) + if (nb_rings) { - const coord_t ring_inner_radius = (inner_radius + i * actual_radius_step) + semi_line_width; - const coord_t ring_outer_radius = (inner_radius + (i + 1) * actual_radius_step) - semi_line_width; + const coord_t actual_radius_step = radius_delta / nb_rings; - const size_t semi_nb_spokes = std::ceil((M_PI * ring_outer_radius) / max_bridging_distance); + for (size_t i = 0; i < nb_rings; ++i) + { + const coord_t ring_inner_radius = (inner_radius + i * actual_radius_step) + semi_line_width; + const coord_t ring_outer_radius = (inner_radius + (i + 1) * actual_radius_step) - semi_line_width; + + const size_t semi_nb_spokes = std::ceil((M_PI * ring_outer_radius) / max_bridging_distance); - pattern.add(PolygonUtils::makeWheel(middle, ring_inner_radius, ring_outer_radius, semi_nb_spokes, ARC_RESOLUTION)); + pattern.add(PolygonUtils::makeWheel(middle, ring_inner_radius, ring_outer_radius, semi_nb_spokes, ARC_RESOLUTION)); + } } return pattern; @@ -305,6 +308,7 @@ void PrimeTower::generateStartLocations() PolygonsPointIndex segment_start = PolygonsPointIndex(&outer_poly, 0, 0); PolygonsPointIndex segment_end = segment_start; +#warning Generate dots that are forcibly over a segment, even on sparse infill PolygonUtils::spreadDots(segment_start, segment_end, number_of_prime_tower_start_locations, prime_tower_start_locations); } @@ -312,15 +316,15 @@ void PrimeTower::addToGcode( const SliceDataStorage& storage, LayerPlan& gcode_layer, const std::vector& required_extruder_prime, - const size_t prev_extruder, - const size_t new_extruder) const + const size_t prev_extruder_nr, + const size_t new_extruder_nr) const { if (! (enabled && would_have_actual_tower)) { return; } - if (gcode_layer.getPrimeTowerIsPlanned(new_extruder)) + if (gcode_layer.getPrimeTowerIsPlanned(new_extruder_nr)) { // don't print the prime tower if it has been printed already with this extruder. return; } @@ -331,10 +335,10 @@ void PrimeTower::addToGcode( return; } - bool post_wipe = Application::getInstance().current_slice->scene.extruders[prev_extruder].settings.get("prime_tower_wipe_enabled"); + bool post_wipe = Application::getInstance().current_slice->scene.extruders[prev_extruder_nr].settings.get("prime_tower_wipe_enabled"); // Do not wipe on the first layer, we will generate non-hollow prime tower there for better bed adhesion. - if (prev_extruder == new_extruder || layer_nr == 0) + if (prev_extruder_nr == new_extruder_nr || layer_nr == 0) { post_wipe = false; } @@ -342,18 +346,15 @@ void PrimeTower::addToGcode( // Go to the start location if it's not the first layer if (layer_nr != 0) { - gotoStartLocation(gcode_layer, new_extruder); + gotoStartLocation(gcode_layer, new_extruder_nr); } - PrimeTowerMethod method = Application::getInstance().current_slice->scene.current_mesh_group->settings.get("prime_tower_mode"); - std::vector extra_primed_extruders; - auto extruder_iterator = std::find_if( required_extruder_prime.begin(), required_extruder_prime.end(), - [new_extruder](const ExtruderUse& extruder_use) + [new_extruder_nr](const ExtruderUse& extruder_use) { - return extruder_use.extruder_nr == new_extruder; + return extruder_use.extruder_nr == new_extruder_nr; }); if (extruder_iterator == required_extruder_prime.end()) @@ -362,55 +363,70 @@ void PrimeTower::addToGcode( return; } + size_t new_extruder_idx; + auto iterator = std::find(extruder_order.begin(), extruder_order.end(), new_extruder_nr); + if (iterator != extruder_order.end()) + { + new_extruder_idx = *iterator; + } + else + { + // Given extruder nr is not registered ?! + return; + } + + PrimeTowerMethod method = Application::getInstance().current_slice->scene.current_mesh_group->settings.get("prime_tower_mode"); + std::vector extra_primed_extruders_idx; + switch (extruder_iterator->prime) { case ExtruderPrime::None: if (method != PrimeTowerMethod::OPTIMIZED) { - gcode_layer.setPrimeTowerIsPlanned(new_extruder); + gcode_layer.setPrimeTowerIsPlanned(new_extruder_nr); } break; case ExtruderPrime::Sparse: - extra_primed_extruders = findExtrudersSparseInfill(gcode_layer, required_extruder_prime, new_extruder, method, { new_extruder }); - addToGcode_optimizedInfill(gcode_layer, extra_primed_extruders, new_extruder); + extra_primed_extruders_idx = findExtrudersSparseInfill(gcode_layer, required_extruder_prime, new_extruder_nr, method, { new_extruder_idx }); + addToGcode_optimizedInfill(gcode_layer, extra_primed_extruders_idx, new_extruder_nr); break; case ExtruderPrime::Prime: - addToGcode_denseInfill(gcode_layer, new_extruder); - gcode_layer.setPrimeTowerIsPlanned(new_extruder); + addToGcode_denseInfill(gcode_layer, new_extruder_nr); + gcode_layer.setPrimeTowerIsPlanned(new_extruder_nr); if (method == PrimeTowerMethod::OPTIMIZED && gcode_layer.getLayerNr() < storage.max_print_height_second_to_last_extruder) { // Whatever happens before and after, use the current extruder to prime all the non-required extruders now - extra_primed_extruders = findExtrudersSparseInfill(gcode_layer, required_extruder_prime, new_extruder, method); - addToGcode_optimizedInfill(gcode_layer, extra_primed_extruders, new_extruder); + extra_primed_extruders_idx = findExtrudersSparseInfill(gcode_layer, required_extruder_prime, new_extruder_nr, method); + addToGcode_optimizedInfill(gcode_layer, extra_primed_extruders_idx, new_extruder_nr); } break; } - if (! gcode_layer.getPrimeTowerBaseIsPlanned() && addToGcode_base(gcode_layer, new_extruder)) + if (! gcode_layer.getPrimeTowerBaseIsPlanned() && addToGcode_base(gcode_layer, new_extruder_nr)) { gcode_layer.setPrimeTowerBaseIsPlanned(); } - if (! gcode_layer.getPrimeTowerInsetIsPlanned() && addToGcode_inset(gcode_layer, new_extruder)) + if (! gcode_layer.getPrimeTowerInsetIsPlanned() && addToGcode_inset(gcode_layer, new_extruder_nr)) { gcode_layer.setPrimeTowerInsetIsPlanned(); } - for (const size_t& primed_extruder : extra_primed_extruders) + for (const size_t& primed_extruder_idx : extra_primed_extruders_idx) { - gcode_layer.setPrimeTowerIsPlanned(primed_extruder); + gcode_layer.setPrimeTowerIsPlanned(extruder_order.at(primed_extruder_idx)); } // post-wipe: if (post_wipe) { // Make sure we wipe the old extruder on the prime tower. - const Settings& previous_settings = Application::getInstance().current_slice->scene.extruders[prev_extruder].settings; + const Settings& previous_settings = Application::getInstance().current_slice->scene.extruders[prev_extruder_nr].settings; const Point previous_nozzle_offset = Point(previous_settings.get("machine_nozzle_offset_x"), previous_settings.get("machine_nozzle_offset_y")); - const Settings& new_settings = Application::getInstance().current_slice->scene.extruders[new_extruder].settings; + const Settings& new_settings = Application::getInstance().current_slice->scene.extruders[new_extruder_nr].settings; const Point new_nozzle_offset = Point(new_settings.get("machine_nozzle_offset_x"), new_settings.get("machine_nozzle_offset_y")); gcode_layer.addTravel(post_wipe_point - previous_nozzle_offset + new_nozzle_offset); } @@ -471,57 +487,43 @@ bool PrimeTower::addToGcode_inset(LayerPlan& gcode_layer, const size_t extruder_ return false; } -void PrimeTower::addToGcode_optimizedInfill(LayerPlan& gcode_layer, const std::vector& extruders_to_prime, const size_t current_extruder) const +void PrimeTower::addToGcode_optimizedInfill(LayerPlan& gcode_layer, const std::vector& extruders_to_prime_idx, const size_t current_extruder_nr) const { - std::vector> extruders_to_prime_grouped; + std::vector> extruders_to_prime_idx_grouped; // Group extruders which are besides each other - for (size_t extruder_to_prime : extruders_to_prime) + for (size_t extruder_to_prime_idx : extruders_to_prime_idx) { - if (extruders_to_prime_grouped.empty()) + if (extruders_to_prime_idx_grouped.empty()) { // First extruder : create new group - extruders_to_prime_grouped.push_back({ extruder_to_prime }); + extruders_to_prime_idx_grouped.push_back({ extruder_to_prime_idx }); } else { - std::vector& last_group = extruders_to_prime_grouped.back(); -#warning This does not take care of extruders ordering - if (last_group.back() == extruder_to_prime - 1) + std::vector& last_group = extruders_to_prime_idx_grouped.back(); + if (last_group.back() == extruder_to_prime_idx - 1) { // New extruders which belongs to same group - last_group.push_back(extruder_to_prime); + last_group.push_back(extruder_to_prime_idx); } else { // New extruders which belongs to new group - extruders_to_prime_grouped.push_back({ extruder_to_prime }); + extruders_to_prime_idx_grouped.push_back({ extruder_to_prime_idx }); } } } - std::string grouped_extruders; - for (auto& group : extruders_to_prime_grouped) - { - grouped_extruders.append("{"); - for (auto& extruder : group) - { - grouped_extruders.append(std::to_string(extruder)); - grouped_extruders.append(","); - } - grouped_extruders.append("}"); - } - -#warning What should we do in case of extruders with different lines widths ? // And finally, append patterns for each group - const GCodePathConfig& config = gcode_layer.configs_storage.prime_tower_config_per_extruder[current_extruder]; + const GCodePathConfig& config = gcode_layer.configs_storage.prime_tower_config_per_extruder[current_extruder_nr]; - for (const std::vector& group : extruders_to_prime_grouped) + for (const std::vector& group_idx : extruders_to_prime_idx_grouped) { size_t mask = 0; - for (const size_t& extruder : group) + for (const size_t& extruder_idx : group_idx) { - mask |= (1 << extruder); + mask |= (1 << extruder_order.at(extruder_idx)); } auto iterator_combination = sparse_pattern_per_extruders.find(mask); @@ -529,14 +531,14 @@ void PrimeTower::addToGcode_optimizedInfill(LayerPlan& gcode_layer, const std::v { const std::map& infill_for_combination = iterator_combination->second; - auto iterator_extruder_nr = infill_for_combination.find(current_extruder); + auto iterator_extruder_nr = infill_for_combination.find(current_extruder_nr); if (iterator_extruder_nr != infill_for_combination.end()) { gcode_layer.addPolygonsByOptimizer(iterator_extruder_nr->second, config); } else { - spdlog::warn("Sparse pattern not found for extruder {}, skipping\n", current_extruder); + spdlog::warn("Sparse pattern not found for extruder {}, skipping\n", current_extruder_nr); } } else @@ -549,40 +551,44 @@ void PrimeTower::addToGcode_optimizedInfill(LayerPlan& gcode_layer, const std::v std::vector PrimeTower::findExtrudersSparseInfill( LayerPlan& gcode_layer, const std::vector& required_extruder_prime, - const size_t current_extruder, + const size_t current_extruder_nr, PrimeTowerMethod method, - const std::vector& initial_list) const + const std::vector& initial_list_idx) const { - std::vector extruders_to_prime; + std::vector extruders_to_prime_idx; - for (size_t extruder_nr : extruder_order) + for (size_t extruder_idx = 0; extruder_idx < extruder_order.size(); extruder_idx++) { - auto iterator_initial_list = std::find(initial_list.begin(), initial_list.end(), extruder_nr); - bool is_in_initial_list = iterator_initial_list != initial_list.end(); + auto iterator_initial_list = std::find(initial_list_idx.begin(), initial_list_idx.end(), extruder_idx); + bool is_in_initial_list = iterator_initial_list != initial_list_idx.end(); if (is_in_initial_list) { - extruders_to_prime.push_back(extruder_nr); + extruders_to_prime_idx.push_back(extruder_idx); } - else if (method == PrimeTowerMethod::OPTIMIZED && ! gcode_layer.getPrimeTowerIsPlanned(extruder_nr)) + else { - auto iterator_required_list = std::find_if( - required_extruder_prime.begin(), - required_extruder_prime.end(), - [extruder_nr](const ExtruderUse& extruder_use) - { - return extruder_use.extruder_nr == extruder_nr && extruder_use.prime == ExtruderPrime::Prime; - }); - bool is_in_required_list = iterator_required_list != required_extruder_prime.end(); - - if (! is_in_required_list) + size_t extruder_nr = extruder_order.at(extruder_idx); + if (method == PrimeTowerMethod::OPTIMIZED && ! gcode_layer.getPrimeTowerIsPlanned(extruder_nr)) { - extruders_to_prime.push_back(extruder_nr); + auto iterator_required_list = std::find_if( + required_extruder_prime.begin(), + required_extruder_prime.end(), + [extruder_nr](const ExtruderUse& extruder_use) + { + return extruder_use.extruder_nr == extruder_nr && extruder_use.prime == ExtruderPrime::Prime; + }); + bool is_in_required_list = iterator_required_list != required_extruder_prime.end(); + + if (! is_in_required_list) + { + extruders_to_prime_idx.push_back(extruder_idx); + } } } } - return extruders_to_prime; + return extruders_to_prime_idx; } void PrimeTower::subtractFromSupport(SliceDataStorage& storage) From 2747f3bc2743e3d10640652af1a4009230d4229f Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Mon, 6 Nov 2023 13:43:20 +0100 Subject: [PATCH 026/201] Minor fixes and optimizations --- src/PrimeTower.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/PrimeTower.cpp b/src/PrimeTower.cpp index eac7249f5e..36dd04df07 100644 --- a/src/PrimeTower.cpp +++ b/src/PrimeTower.cpp @@ -190,10 +190,9 @@ void PrimeTower::generatePaths_denseInfill(std::vector& cumulative_inse // Now we have the total cumulative inset, generate the base inside extra rings for (size_t extruder_nr : extruder_order) { - const coord_t line_width = scene.extruders[extruder_nr].settings.get("prime_tower_line_width"); - if (extruder_nr == extruder_order.back() || method == PrimeTowerMethod::OPTIMIZED) { + const coord_t line_width = scene.extruders[extruder_nr].settings.get("prime_tower_line_width"); Polygons pattern = PolygonUtils::generateInset(outer_poly, line_width, cumulative_inset); if (! pattern.empty()) { @@ -243,7 +242,9 @@ void PrimeTower::generatePaths_sparseInfill(const std::vector& cumulati // A combination is represented by a bitmask for (size_t first_extruder_idx = 0; first_extruder_idx < nb_extruders; ++first_extruder_idx) { - for (size_t last_extruder_idx = first_extruder_idx; last_extruder_idx < nb_extruders; ++last_extruder_idx) + size_t nb_extruders_sparse = method == PrimeTowerMethod::OPTIMIZED_CONSISTENT ? first_extruder_idx + 1 : nb_extruders; + + for (size_t last_extruder_idx = first_extruder_idx; last_extruder_idx < nb_extruders_sparse; ++last_extruder_idx) { size_t extruders_combination = 0; for (size_t extruder_idx = first_extruder_idx; extruder_idx <= last_extruder_idx; ++extruder_idx) @@ -367,7 +368,7 @@ void PrimeTower::addToGcode( auto iterator = std::find(extruder_order.begin(), extruder_order.end(), new_extruder_nr); if (iterator != extruder_order.end()) { - new_extruder_idx = *iterator; + new_extruder_idx = iterator - extruder_order.begin(); } else { From b9ca02353cfb856a1c08e0755125a41033ef5a32 Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Mon, 6 Nov 2023 14:02:37 +0100 Subject: [PATCH 027/201] Minor optimization --- src/PrimeTower.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/PrimeTower.cpp b/src/PrimeTower.cpp index 36dd04df07..25eb173829 100644 --- a/src/PrimeTower.cpp +++ b/src/PrimeTower.cpp @@ -256,8 +256,11 @@ void PrimeTower::generatePaths_sparseInfill(const std::vector& cumulati std::map infills_for_combination; for (const ActualExtruder& actual_extruder : actual_extruders) { - Polygons infill = generatePath_sparseInfill(first_extruder_idx, last_extruder_idx, rings_radii, actual_extruder.line_width, actual_extruder.number); - infills_for_combination[actual_extruder.number] = infill; + if (method == PrimeTowerMethod::OPTIMIZED || actual_extruder.number == extruder_order.at(first_extruder_idx)) + { + Polygons infill = generatePath_sparseInfill(first_extruder_idx, last_extruder_idx, rings_radii, actual_extruder.line_width, actual_extruder.number); + infills_for_combination[actual_extruder.number] = infill; + } } sparse_pattern_per_extruders[extruders_combination] = infills_for_combination; From f4b73285d7273fb7ea938dbbc80017ba59e7f78c Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Mon, 6 Nov 2023 14:10:24 +0100 Subject: [PATCH 028/201] Fixed issue with last layers of optimized-consistent mode --- src/FffGcodeWriter.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/FffGcodeWriter.cpp b/src/FffGcodeWriter.cpp index f569b66a9d..c4d189f069 100644 --- a/src/FffGcodeWriter.cpp +++ b/src/FffGcodeWriter.cpp @@ -1439,7 +1439,7 @@ std::vector { prime = ExtruderPrime::Prime; } - else if (layer_nr < storage.max_print_height_second_to_last_extruder) + else if (layer_nr < storage.max_print_height_second_to_last_extruder + 1) { prime = ExtruderPrime::Sparse; } From 0011c1d0ea131c90a231e55f0c2a96bf21dfce8b Mon Sep 17 00:00:00 2001 From: wawanbreton Date: Wed, 8 Nov 2023 12:04:30 +0000 Subject: [PATCH 029/201] Applied clang-format. --- include/PrimeTower.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/PrimeTower.h b/include/PrimeTower.h index b1b975f982..f338de0226 100644 --- a/include/PrimeTower.h +++ b/include/PrimeTower.h @@ -186,7 +186,8 @@ class PrimeTower #warning TBD documentation void addToGcode_optimizedInfill(LayerPlan& gcode_layer, const std::vector& extruders_to_prime_idx, const size_t current_extruder_nr) const; - std::vector findExtrudersSparseInfill(LayerPlan& gcode_layer, + std::vector findExtrudersSparseInfill( + LayerPlan& gcode_layer, const std::vector& required_extruder_prime, const size_t current_extruder_nr, cura::PrimeTowerMethod method, From a1b3e660f1a8e8499682b41dce51e94c4f8c45d4 Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Wed, 8 Nov 2023 13:41:19 +0100 Subject: [PATCH 030/201] Last tests and code cleaning --- src/FffGcodeWriter.cpp | 30 +++++++++++++----------------- src/PrimeTower.cpp | 2 -- 2 files changed, 13 insertions(+), 19 deletions(-) diff --git a/src/FffGcodeWriter.cpp b/src/FffGcodeWriter.cpp index c4d189f069..ca089df0c0 100644 --- a/src/FffGcodeWriter.cpp +++ b/src/FffGcodeWriter.cpp @@ -1400,6 +1400,19 @@ std::vector std::vector extruder_is_used_on_this_layer = storage.getExtrudersUsed(layer_nr); PrimeTowerMethod method = mesh_group_settings.get("prime_tower_mode"); + // check if we are on the first layer + if (layer_nr == -static_cast(Raft::getTotalExtraLayers())) + { + // check if we need prime blob on the first layer + for (size_t used_idx = 0; used_idx < extruder_is_used_on_this_layer.size(); used_idx++) + { + if (getExtruderNeedPrimeBlobDuringFirstLayer(storage, used_idx)) + { + extruder_is_used_on_this_layer[used_idx] = true; + } + } + } + // Make a temp list with the potential ordered extruders std::vector ordered_extruders; ordered_extruders.push_back(start_extruder); @@ -1465,23 +1478,6 @@ std::vector ret.front().prime = ExtruderPrime::Sparse; } -#warning restore this -#if 0 - // check if we are on the first layer - if ((mesh_group_settings.get("adhesion_type") == EPlatformAdhesion::RAFT && layer_nr == -static_cast(Raft::getTotalExtraLayers())) - || (mesh_group_settings.get("adhesion_type") != EPlatformAdhesion::RAFT && layer_nr == 0)) - { - // check if we need prime blob on the first layer - for (size_t used_idx = 0; used_idx < extruder_is_used_on_this_layer.size(); used_idx++) - { - if (getExtruderNeedPrimeBlobDuringFirstLayer(storage, used_idx)) - { - extruder_is_used_on_this_layer[used_idx] = true; - } - } - } -#endif - assert(ret.size() <= (size_t)extruder_count && "Not more extruders may be planned in a layer than there are extruders!"); return ret; } diff --git a/src/PrimeTower.cpp b/src/PrimeTower.cpp index 25eb173829..2ae24f4ea6 100644 --- a/src/PrimeTower.cpp +++ b/src/PrimeTower.cpp @@ -311,8 +311,6 @@ void PrimeTower::generateStartLocations() // so use the same start and end segments for this. PolygonsPointIndex segment_start = PolygonsPointIndex(&outer_poly, 0, 0); PolygonsPointIndex segment_end = segment_start; - -#warning Generate dots that are forcibly over a segment, even on sparse infill PolygonUtils::spreadDots(segment_start, segment_end, number_of_prime_tower_start_locations, prime_tower_start_locations); } From 0b363c8450ee2ee32855c7e4c2c020d054d57b78 Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Wed, 8 Nov 2023 14:25:16 +0100 Subject: [PATCH 031/201] Remove accidentally-pushed code changes --- include/utils/SVG.h | 24 +++---- src/SkirtBrim.cpp | 4 -- src/sliceDataStorage.cpp | 11 +--- src/utils/SVG.cpp | 137 +++++++++------------------------------ 4 files changed, 44 insertions(+), 132 deletions(-) diff --git a/include/utils/SVG.h b/include/utils/SVG.h index eec59d9d0a..d3ac435561 100644 --- a/include/utils/SVG.h +++ b/include/utils/SVG.h @@ -1,5 +1,5 @@ -// Copyright (c) 2022 Ultimaker B.V. -// CuraEngine is released under the terms of the AGPLv3 or higher. +//Copyright (c) 2022 Ultimaker B.V. +//CuraEngine is released under the terms of the AGPLv3 or higher. #ifndef SVG_H #define SVG_H @@ -19,8 +19,7 @@ class FPoint3; class SVG : NoCopy { public: - enum class Color - { + enum class Color { BLACK, WHITE, GRAY, @@ -43,18 +42,16 @@ class SVG : NoCopy ColorObject(Color color) : is_enum(true) , color(color) - { - } + {} ColorObject(int r, int g, int b) : is_enum(false) , r(r) , g(g) , b(b) - { - } + {} }; - private: + std::string toString(const Color color) const; std::string toString(const ColorObject& color) const; @@ -68,8 +65,6 @@ class SVG : NoCopy bool output_is_html; - void writePathPoint(const Point& p) const; - public: SVG(std::string filename, const AABB aabb, const Point canvas_size = Point(1024, 1024), const ColorObject background = Color::NONE); SVG(std::string filename, const AABB aabb, const double scale, const ColorObject background = Color::NONE); @@ -134,16 +129,16 @@ class SVG : NoCopy * \param b The ending endpoint of the line. * \param color The stroke colour of the line. */ - void writeDashedLine(const Point& a, const Point& b, ColorObject color = Color::BLACK) const; + void writeDashedLine(const Point& a,const Point& b, ColorObject color = Color::BLACK) const; template void printf(const char* txt, Args&&... args) const; void writeText(const Point& p, const std::string& txt, const ColorObject color = Color::BLACK, const float font_size = 10) const; - void writePolygons(const Polygons& polys, const ColorObject color = Color::BLACK, const float stroke_width = 1, bool as_path = false) const; + void writePolygons(const Polygons& polys, const ColorObject color = Color::BLACK, const float stroke_width = 1) const; - void writePolygon(ConstPolygonRef poly, const ColorObject color = Color::BLACK, const float stroke_width = 1, bool as_path = false) const; + void writePolygon(ConstPolygonRef poly, const ColorObject color = Color::BLACK, const float stroke_width = 1) const; void writePolylines(const Polygons& polys, const ColorObject color = Color::BLACK, const float stroke_width = 1) const; @@ -192,6 +187,7 @@ class SVG : NoCopy * \param font_size The size of the font to write the coordinates with. */ void writeCoordinateGrid(const coord_t grid_size = MM2INT(1), const Color color = Color::BLACK, const float stroke_width = 0.1, const float font_size = 10) const; + }; template diff --git a/src/SkirtBrim.cpp b/src/SkirtBrim.cpp index 77f9f036c1..4b77b449d3 100644 --- a/src/SkirtBrim.cpp +++ b/src/SkirtBrim.cpp @@ -13,7 +13,6 @@ #include "sliceDataStorage.h" #include "support.h" #include "utils/PolylineStitcher.h" -#include "utils/SVG.h" #include "utils/Simplify.h" //Simplifying the brim/skirt at every inset. namespace cura @@ -122,9 +121,6 @@ void SkirtBrim::generate() const bool has_prime_tower = storage.primeTower.enabled; Polygons covered_area = storage.getLayerOutlines(layer_nr, include_support, include_prime_tower, /*external_polys_only*/ false); - SVG svg("/tmp/machine.svg", storage.machine_size.flatten()); - svg.writePolygons(storage.getMachineBorder(0), SVG::Color::RAINBOW, 1, true); - std::vector allowed_areas_per_extruder(extruder_count); for (int extruder_nr = 0; extruder_nr < extruder_count; extruder_nr++) { diff --git a/src/sliceDataStorage.cpp b/src/sliceDataStorage.cpp index 080d62622b..fbd4a5d1a9 100644 --- a/src/sliceDataStorage.cpp +++ b/src/sliceDataStorage.cpp @@ -560,14 +560,9 @@ Polygons SliceDataStorage::getMachineBorder(int checking_extruder_nr) const Polygons disallowed_areas = mesh_group_settings.get("machine_disallowed_areas"); disallowed_areas = disallowed_areas.unionPolygons(); // union overlapping disallowed areas - - // The disallowed areas are always expressed in buildplate-centered coordinates - // if (! mesh_group_settings.get("machine_center_is_zero")) - { - for (PolygonRef poly : disallowed_areas) - for (Point& p : poly) - p = Point(machine_size.max.x / 2 + p.X, machine_size.max.y / 2 - p.Y); - } + for (PolygonRef poly : disallowed_areas) + for (Point& p : poly) + p = Point(machine_size.max.x / 2 + p.X, machine_size.max.y / 2 - p.Y); // apparently the frontend stores the disallowed areas in a different coordinate system std::vector extruder_is_used = getExtrudersUsed(); diff --git a/src/utils/SVG.cpp b/src/utils/SVG.cpp index 6726ed092e..0b45100b3d 100644 --- a/src/utils/SVG.cpp +++ b/src/utils/SVG.cpp @@ -1,15 +1,12 @@ // Copyright (c) 2022 Ultimaker B.V. // CuraEngine is released under the terms of the AGPLv3 or higher -#include "utils/SVG.h" - #include -#include -#include #include #include "utils/ExtrusionLine.h" +#include "utils/SVG.h" #include "utils/floatpoint.h" #include "utils/polygon.h" @@ -60,34 +57,17 @@ std::string SVG::toString(const ColorObject& color) const } } -void SVG::writePathPoint(const Point& p) const -{ - FPoint3 transformed = transformF(p); - fprintf(out, "%f,%f", transformed.x, transformed.y); -} - SVG::SVG(std::string filename, AABB aabb, Point canvas_size, ColorObject background) - : SVG( - filename, - aabb, - std::min(double(canvas_size.X - canvas_size.X / 5 * 2) / (aabb.max.X - aabb.min.X), double(canvas_size.Y - canvas_size.Y / 5) / (aabb.max.Y - aabb.min.Y)), - canvas_size, - background) + : SVG(filename, aabb, std::min(double(canvas_size.X - canvas_size.X / 5 * 2) / (aabb.max.X - aabb.min.X), double(canvas_size.Y - canvas_size.Y / 5) / (aabb.max.Y - aabb.min.Y)), canvas_size, background) { } -SVG::SVG(std::string filename, AABB aabb, double scale, ColorObject background) - : SVG(filename, aabb, scale, (aabb.max - aabb.min) * scale, background) +SVG::SVG(std::string filename, AABB aabb, double scale, ColorObject background) : SVG(filename, aabb, scale, (aabb.max - aabb.min) * scale, background) { } -SVG::SVG(std::string filename, AABB aabb, double scale, Point canvas_size, ColorObject background) - : aabb(aabb) - , aabb_size(aabb.max - aabb.min) - , canvas_size(canvas_size) - , scale(scale) - , background(background) +SVG::SVG(std::string filename, AABB aabb, double scale, Point canvas_size, ColorObject background) : aabb(aabb), aabb_size(aabb.max - aabb.min), canvas_size(canvas_size), scale(scale), background(background) { output_is_html = strcmp(filename.c_str() + strlen(filename.c_str()) - 4, "html") == 0; out = fopen(filename.c_str(), "w"); @@ -185,12 +165,7 @@ void SVG::writeAreas(const Polygons& polygons, const ColorObject color, const Co void SVG::writeAreas(ConstPolygonRef polygon, const ColorObject color, const ColorObject outline_color, const float stroke_width) const { - fprintf( - out, - "& polyline, const ColorObject color } FPoint3 transformed = transformF(polyline[0]); // Element 0 must exist due to the check above. - fprintf( - out, - "", - toString(color).c_str(), - fa.x, - fa.y, - fb.x, - fb.y, - tip.x, - tip.y, - b_base.x, - b_base.y, - a_base.x, - a_base.y); + fprintf(out, "", toString(color).c_str(), fa.x, fa.y, fb.x, fb.y, tip.x, tip.y, b_base.x, b_base.y, a_base.x, a_base.y); } void SVG::writeLineRGB(const Point& from, const Point& to, const int r, const int g, const int b, const float stroke_width) const @@ -302,70 +259,49 @@ void SVG::writeText(const Point& p, const std::string& txt, const ColorObject co fprintf(out, "%s\n", pf.x, pf.y, font_size, toString(color).c_str(), txt.c_str()); } -void SVG::writePolygons(const Polygons& polys, const ColorObject color, const float stroke_width, bool as_path) const +void SVG::writePolygons(const Polygons& polys, const ColorObject color, const float stroke_width) const { for (ConstPolygonRef poly : polys) { - writePolygon(poly, color, stroke_width, as_path); + writePolygon(poly, color, stroke_width); } } -void SVG::writePolygon(ConstPolygonRef poly, const ColorObject color, const float stroke_width, bool as_path) const +void SVG::writePolygon(ConstPolygonRef poly, const ColorObject color, const float stroke_width) const { if (poly.size() == 0) { return; } - - if (as_path) - { - fprintf(out, " \n"); - } - else + int size = poly.size(); + Point p0 = poly.back(); + int i = 0; + for (Point p1 : poly) { - int size = poly.size(); - Point p0 = poly.back(); - int i = 0; - for (Point p1 : poly) + if (color.color == Color::RAINBOW) { - if (color.color == Color::RAINBOW) + int g = (i * 255 * 11 / size) % (255 * 2); + if (g > 255) { - int g = (i * 255 * 11 / size) % (255 * 2); - if (g > 255) - { - g = 255 * 2 - g; - } - int b = (i * 255 * 5 / size) % (255 * 2); - if (b > 255) - { - b = 255 * 2 - b; - } - writeLineRGB(p0, p1, i * 255 / size, g, b, stroke_width); + g = 255 * 2 - g; } - else + int b = (i * 255 * 5 / size) % (255 * 2); + if (b > 255) { - writeLine(p0, p1, color, stroke_width); + b = 255 * 2 - b; } - p0 = p1; - i++; + writeLineRGB(p0, p1, i * 255 / size, g, b, stroke_width); + } + else + { + writeLine(p0, p1, color, stroke_width); } + p0 = p1; + i++; } } + void SVG::writePolylines(const Polygons& polys, const ColorObject color, const float stroke_width) const { for (ConstPolygonRef poly : polys) @@ -433,7 +369,7 @@ void SVG::writeLine(const ExtrusionLine& line, const ColorObject color, const fl { ExtrusionJunction end_vertex = line.junctions[index]; - // Compute the corners of the trapezoid for this variable-width line segment. + // Compute the corners of the trapezoid for this variable-width line segment. const Point direction_vector = end_vertex.p - start_vertex.p; const Point direction_left = turn90CCW(direction_vector); const Point direction_right = -direction_left; // Opposite of left. @@ -442,18 +378,7 @@ void SVG::writeLine(const ExtrusionLine& line, const ColorObject color, const fl const FPoint3 end_left = transformF(end_vertex.p + normal(direction_left, std::max(minimum_line_width, end_vertex.w * width_factor))); const FPoint3 end_right = transformF(end_vertex.p + normal(direction_right, std::max(minimum_line_width, end_vertex.w * width_factor))); - fprintf( - out, - "\n", - toString(color).c_str(), - start_left.x, - start_left.y, - start_right.x, - start_right.y, - end_right.x, - end_right.y, - end_left.x, - end_left.y); + fprintf(out, "\n", toString(color).c_str(), start_left.x, start_left.y, start_right.x, start_right.y, end_right.x, end_right.y, end_left.x, end_left.y); start_vertex = end_vertex; // For the next line segment. } From 588d44d9280267d8651e95ef1f17655222e13400 Mon Sep 17 00:00:00 2001 From: wawanbreton Date: Wed, 8 Nov 2023 13:25:57 +0000 Subject: [PATCH 032/201] Applied clang-format. --- include/utils/SVG.h | 18 +++++++------ src/utils/SVG.cpp | 64 ++++++++++++++++++++++++++++++++++++++------- 2 files changed, 65 insertions(+), 17 deletions(-) diff --git a/include/utils/SVG.h b/include/utils/SVG.h index d3ac435561..619fd1e5bf 100644 --- a/include/utils/SVG.h +++ b/include/utils/SVG.h @@ -1,5 +1,5 @@ -//Copyright (c) 2022 Ultimaker B.V. -//CuraEngine is released under the terms of the AGPLv3 or higher. +// Copyright (c) 2022 Ultimaker B.V. +// CuraEngine is released under the terms of the AGPLv3 or higher. #ifndef SVG_H #define SVG_H @@ -19,7 +19,8 @@ class FPoint3; class SVG : NoCopy { public: - enum class Color { + enum class Color + { BLACK, WHITE, GRAY, @@ -42,16 +43,18 @@ class SVG : NoCopy ColorObject(Color color) : is_enum(true) , color(color) - {} + { + } ColorObject(int r, int g, int b) : is_enum(false) , r(r) , g(g) , b(b) - {} + { + } }; -private: +private: std::string toString(const Color color) const; std::string toString(const ColorObject& color) const; @@ -129,7 +132,7 @@ class SVG : NoCopy * \param b The ending endpoint of the line. * \param color The stroke colour of the line. */ - void writeDashedLine(const Point& a,const Point& b, ColorObject color = Color::BLACK) const; + void writeDashedLine(const Point& a, const Point& b, ColorObject color = Color::BLACK) const; template void printf(const char* txt, Args&&... args) const; @@ -187,7 +190,6 @@ class SVG : NoCopy * \param font_size The size of the font to write the coordinates with. */ void writeCoordinateGrid(const coord_t grid_size = MM2INT(1), const Color color = Color::BLACK, const float stroke_width = 0.1, const float font_size = 10) const; - }; template diff --git a/src/utils/SVG.cpp b/src/utils/SVG.cpp index 0b45100b3d..e4dddb05e0 100644 --- a/src/utils/SVG.cpp +++ b/src/utils/SVG.cpp @@ -1,12 +1,13 @@ // Copyright (c) 2022 Ultimaker B.V. // CuraEngine is released under the terms of the AGPLv3 or higher +#include "utils/SVG.h" + #include #include #include "utils/ExtrusionLine.h" -#include "utils/SVG.h" #include "utils/floatpoint.h" #include "utils/polygon.h" @@ -59,15 +60,26 @@ std::string SVG::toString(const ColorObject& color) const SVG::SVG(std::string filename, AABB aabb, Point canvas_size, ColorObject background) - : SVG(filename, aabb, std::min(double(canvas_size.X - canvas_size.X / 5 * 2) / (aabb.max.X - aabb.min.X), double(canvas_size.Y - canvas_size.Y / 5) / (aabb.max.Y - aabb.min.Y)), canvas_size, background) + : SVG( + filename, + aabb, + std::min(double(canvas_size.X - canvas_size.X / 5 * 2) / (aabb.max.X - aabb.min.X), double(canvas_size.Y - canvas_size.Y / 5) / (aabb.max.Y - aabb.min.Y)), + canvas_size, + background) { } -SVG::SVG(std::string filename, AABB aabb, double scale, ColorObject background) : SVG(filename, aabb, scale, (aabb.max - aabb.min) * scale, background) +SVG::SVG(std::string filename, AABB aabb, double scale, ColorObject background) + : SVG(filename, aabb, scale, (aabb.max - aabb.min) * scale, background) { } -SVG::SVG(std::string filename, AABB aabb, double scale, Point canvas_size, ColorObject background) : aabb(aabb), aabb_size(aabb.max - aabb.min), canvas_size(canvas_size), scale(scale), background(background) +SVG::SVG(std::string filename, AABB aabb, double scale, Point canvas_size, ColorObject background) + : aabb(aabb) + , aabb_size(aabb.max - aabb.min) + , canvas_size(canvas_size) + , scale(scale) + , background(background) { output_is_html = strcmp(filename.c_str() + strlen(filename.c_str()) - 4, "html") == 0; out = fopen(filename.c_str(), "w"); @@ -165,7 +177,12 @@ void SVG::writeAreas(const Polygons& polygons, const ColorObject color, const Co void SVG::writeAreas(ConstPolygonRef polygon, const ColorObject color, const ColorObject outline_color, const float stroke_width) const { - fprintf(out, "& polyline, const ColorObject color } FPoint3 transformed = transformF(polyline[0]); // Element 0 must exist due to the check above. - fprintf(out, "", toString(color).c_str(), fa.x, fa.y, fb.x, fb.y, tip.x, tip.y, b_base.x, b_base.y, a_base.x, a_base.y); + fprintf( + out, + "", + toString(color).c_str(), + fa.x, + fa.y, + fb.x, + fb.y, + tip.x, + tip.y, + b_base.x, + b_base.y, + a_base.x, + a_base.y); } void SVG::writeLineRGB(const Point& from, const Point& to, const int r, const int g, const int b, const float stroke_width) const @@ -369,7 +404,7 @@ void SVG::writeLine(const ExtrusionLine& line, const ColorObject color, const fl { ExtrusionJunction end_vertex = line.junctions[index]; - // Compute the corners of the trapezoid for this variable-width line segment. + // Compute the corners of the trapezoid for this variable-width line segment. const Point direction_vector = end_vertex.p - start_vertex.p; const Point direction_left = turn90CCW(direction_vector); const Point direction_right = -direction_left; // Opposite of left. @@ -378,7 +413,18 @@ void SVG::writeLine(const ExtrusionLine& line, const ColorObject color, const fl const FPoint3 end_left = transformF(end_vertex.p + normal(direction_left, std::max(minimum_line_width, end_vertex.w * width_factor))); const FPoint3 end_right = transformF(end_vertex.p + normal(direction_right, std::max(minimum_line_width, end_vertex.w * width_factor))); - fprintf(out, "\n", toString(color).c_str(), start_left.x, start_left.y, start_right.x, start_right.y, end_right.x, end_right.y, end_left.x, end_left.y); + fprintf( + out, + "\n", + toString(color).c_str(), + start_left.x, + start_left.y, + start_right.x, + start_right.y, + end_right.x, + end_right.y, + end_left.x, + end_left.y); start_vertex = end_vertex; // For the next line segment. } From e29f6754e6f251a252a36a62dd7387523466d497 Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Wed, 8 Nov 2023 14:33:22 +0100 Subject: [PATCH 033/201] Restore removed error check --- src/LayerPlanBuffer.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/LayerPlanBuffer.cpp b/src/LayerPlanBuffer.cpp index 48437cb56c..d5a033a136 100644 --- a/src/LayerPlanBuffer.cpp +++ b/src/LayerPlanBuffer.cpp @@ -89,8 +89,8 @@ void LayerPlanBuffer::addConnectingTravelMove(LayerPlan* prev_layer, const Layer Point first_location_new_layer = new_layer_destination_state->first; - // assert(newest_layer->extruder_plans.front().paths[0].points.size() == 1); - // assert(newest_layer->extruder_plans.front().paths[0].points[0] == first_location_new_layer); + assert(newest_layer->extruder_plans.front().paths[0].points.size() == 1); + assert(newest_layer->extruder_plans.front().paths[0].points[0] == first_location_new_layer); // if the last planned position in the previous layer isn't the same as the first location of the new layer, travel to the new location if (! prev_layer->last_planned_position || *prev_layer->last_planned_position != first_location_new_layer) From 7f5b45fade84f40943bb33f3f555bd8ca575c9c4 Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Wed, 15 Nov 2023 14:07:59 +0100 Subject: [PATCH 034/201] Minor last prime tower layers optimizations --- src/FffGcodeWriter.cpp | 4 ++-- src/PrimeTower.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/FffGcodeWriter.cpp b/src/FffGcodeWriter.cpp index 285bfa40bd..990f4dfa29 100644 --- a/src/FffGcodeWriter.cpp +++ b/src/FffGcodeWriter.cpp @@ -1470,7 +1470,7 @@ std::vector { prime = ExtruderPrime::Prime; } - else if (layer_nr < storage.max_print_height_second_to_last_extruder + 1) + else if (layer_nr < storage.max_print_height_second_to_last_extruder) { prime = ExtruderPrime::Sparse; } @@ -1491,7 +1491,7 @@ std::vector } } - if (method == PrimeTowerMethod::OPTIMIZED && ret.size() == 1 && ret.front().prime == ExtruderPrime::None) + if (method == PrimeTowerMethod::OPTIMIZED && ret.size() == 1 && ret.front().prime == ExtruderPrime::None && layer_nr <= storage.max_print_height_second_to_last_extruder) { ret.front().prime = ExtruderPrime::Sparse; } diff --git a/src/PrimeTower.cpp b/src/PrimeTower.cpp index 38cdadd286..094604ca0c 100644 --- a/src/PrimeTower.cpp +++ b/src/PrimeTower.cpp @@ -398,7 +398,7 @@ void PrimeTower::addToGcode( addToGcode_denseInfill(gcode_layer, new_extruder_nr); gcode_layer.setPrimeTowerIsPlanned(new_extruder_nr); - if (method == PrimeTowerMethod::OPTIMIZED && gcode_layer.getLayerNr() < storage.max_print_height_second_to_last_extruder) + if (method == PrimeTowerMethod::OPTIMIZED && gcode_layer.getLayerNr() <= storage.max_print_height_second_to_last_extruder) { // Whatever happens before and after, use the current extruder to prime all the non-required extruders now extra_primed_extruders_idx = findExtrudersSparseInfill(gcode_layer, required_extruder_prime, method); From 7c97bad396d8f7e1e10f578c29b1deee583aed2d Mon Sep 17 00:00:00 2001 From: Remco Burema Date: Thu, 16 Nov 2023 13:12:10 +0100 Subject: [PATCH 035/201] Add .z_offset to gcode-path. The 'just get it working' version. Needs updated grpc-definitions! part of CURA-11265 --- src/LayerPlan.cpp | 4 ++++ src/plugins/converters.cpp | 5 ++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/LayerPlan.cpp b/src/LayerPlan.cpp index 52305a9521..78887c04a4 100644 --- a/src/LayerPlan.cpp +++ b/src/LayerPlan.cpp @@ -2036,6 +2036,10 @@ void LayerPlan::writeGCode(GCodeExport& gcode) else { gcode.writeZhopEnd(); + if (z > 0 && path.z_offset != 0) + { + gcode.setZ(z + path.z_offset); + } } } const auto& extruder_changed = ! last_extrusion_config.has_value() || (last_extrusion_config.value().type != path.config.type); diff --git a/src/plugins/converters.cpp b/src/plugins/converters.cpp index 72a8166de7..f3cb1268c0 100644 --- a/src/plugins/converters.cpp +++ b/src/plugins/converters.cpp @@ -358,6 +358,7 @@ gcode_paths_modify_request::value_type gcode_path->set_layer_thickness(path.config.getLayerThickness()); gcode_path->set_flow_ratio(path.config.getFlowRatio()); gcode_path->set_is_bridge_path(path.config.isBridgePath()); + gcode_path->set_z_offset(path.config.z_offset); } return message; @@ -417,7 +418,8 @@ gcode_paths_modify_request::value_type [[nodiscard]] GCodePathConfig gcode_paths_modify_response::buildConfig(const v0::GCodePath& path) { - return { .type = getPrintFeatureType(path.feature()), + return { .z_offset = path.z_offset(), + .type = getPrintFeatureType(path.feature()), .line_width = path.line_width(), .layer_thickness = path.layer_thickness(), .flow = path.flow_ratio(), @@ -448,6 +450,7 @@ gcode_paths_modify_response::native_value_type for (const auto& gcode_path_msg : message.gcode_paths()) { GCodePath path{ + .z_offset = gcode_path_msg.z_offset(), .config = buildConfig(gcode_path_msg), .mesh = gcode_path_msg.mesh_name().empty() ? nullptr : meshes.at(gcode_path_msg.mesh_name()), .space_fill_type = getSpaceFillType(gcode_path_msg.space_fill_type()), From 7b9a72303112f31175f6d56cae357afcbdbf5f96 Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Thu, 30 Nov 2023 15:22:50 +0100 Subject: [PATCH 036/201] Restore multi-threading --- src/Application.cpp | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/src/Application.cpp b/src/Application.cpp index 1635f56f18..71c6cf913a 100644 --- a/src/Application.cpp +++ b/src/Application.cpp @@ -3,13 +3,9 @@ #include "Application.h" -#include "FffProcessor.h" -#include "communication/ArcusCommunication.h" //To connect via Arcus to the front-end. -#include "communication/CommandLine.h" //To use the command line to slice stuff. -#include "plugins/slots.h" -#include "progress/Progress.h" -#include "utils/ThreadPool.h" -#include "utils/string.h" //For stringcasecompare. +#include +#include +#include #include //For generating a UUID. #include //For generating a UUID. @@ -22,9 +18,13 @@ #include #include -#include -#include -#include +#include "FffProcessor.h" +#include "communication/ArcusCommunication.h" //To connect via Arcus to the front-end. +#include "communication/CommandLine.h" //To use the command line to slice stuff. +#include "plugins/slots.h" +#include "progress/Progress.h" +#include "utils/ThreadPool.h" +#include "utils/string.h" //For stringcasecompare. namespace cura { @@ -251,8 +251,7 @@ void Application::startThreadPool(int nworkers) return; // Keep the previous ThreadPool } delete thread_pool; - // thread_pool = new ThreadPool(nthreads); - thread_pool = new ThreadPool(0); + thread_pool = new ThreadPool(nthreads); } } // namespace cura From a79170bf5d64f85790171d9ed2f24366b071f570 Mon Sep 17 00:00:00 2001 From: wawanbreton Date: Wed, 10 Jan 2024 16:02:18 +0000 Subject: [PATCH 037/201] Applied clang-format. --- include/SkeletalTrapezoidationGraph.h | 4 ++-- include/TreeModelVolumes.h | 10 +++++----- include/utils/views/dfs.h | 4 ++-- src/PrimeTower.cpp | 6 +++--- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/include/SkeletalTrapezoidationGraph.h b/include/SkeletalTrapezoidationGraph.h index 5922a774ce..6f6bb99ebc 100644 --- a/include/SkeletalTrapezoidationGraph.h +++ b/include/SkeletalTrapezoidationGraph.h @@ -4,12 +4,12 @@ #ifndef SKELETAL_TRAPEZOIDATION_GRAPH_H #define SKELETAL_TRAPEZOIDATION_GRAPH_H +#include + #include "SkeletalTrapezoidationEdge.h" #include "SkeletalTrapezoidationJoint.h" #include "utils/HalfEdgeGraph.h" -#include - namespace cura { diff --git a/include/TreeModelVolumes.h b/include/TreeModelVolumes.h index beaee2df67..9c9013888d 100644 --- a/include/TreeModelVolumes.h +++ b/include/TreeModelVolumes.h @@ -4,6 +4,11 @@ #ifndef TREEMODELVOLUMES_H #define TREEMODELVOLUMES_H +#include +#include +#include +#include + #include "TreeSupportSettings.h" #include "settings/EnumSettings.h" //To store whether X/Y or Z distance gets priority. #include "settings/types/LayerIndex.h" //Part of the RadiusLayerPair. @@ -11,11 +16,6 @@ #include "utils/Simplify.h" #include "utils/polygon.h" //For polygon parameters. -#include -#include -#include -#include - namespace cura { constexpr coord_t EPSILON = 5; diff --git a/include/utils/views/dfs.h b/include/utils/views/dfs.h index 0d7df3678a..3a64e8c8d8 100644 --- a/include/utils/views/dfs.h +++ b/include/utils/views/dfs.h @@ -4,11 +4,11 @@ #ifndef CURAENGINE_DFS_SORT_H #define CURAENGINE_DFS_SORT_H -#include "utils/types/graph.h" - #include #include +#include "utils/types/graph.h" + namespace cura::actions { /* # dfs utility diff --git a/src/PrimeTower.cpp b/src/PrimeTower.cpp index 58543e748e..ce546fd0e3 100644 --- a/src/PrimeTower.cpp +++ b/src/PrimeTower.cpp @@ -44,12 +44,12 @@ PrimeTower::PrimeTower() // adhesion). multiple_extruders_on_first_layer_ = (method == PrimeTowerMethod::OPTIMIZED) || (method == PrimeTowerMethod::OPTIMIZED_CONSISTENT) - || (scene.current_mesh_group->settings.get("machine_extruders_share_nozzle") - && ((adhesion_type != EPlatformAdhesion::SKIRT) && (adhesion_type != EPlatformAdhesion::BRIM))); + || (scene.current_mesh_group->settings.get("machine_extruders_share_nozzle") + && ((adhesion_type != EPlatformAdhesion::SKIRT) && (adhesion_type != EPlatformAdhesion::BRIM))); } enabled_ = method != PrimeTowerMethod::NONE && scene.current_mesh_group->settings.get("prime_tower_min_volume") > 10 - && scene.current_mesh_group->settings.get("prime_tower_size") > 10; + && scene.current_mesh_group->settings.get("prime_tower_size") > 10; would_have_actual_tower_ = enabled_; // Assume so for now. From 1cf20c1bec0f669b378e2358e452b35d11e42e07 Mon Sep 17 00:00:00 2001 From: "c.lamboo" Date: Mon, 8 Jan 2024 13:52:49 +0100 Subject: [PATCH 038/201] Split up raft margin setting per raft-type Added the following settings - raft_base_margin - raft_interface_margin - raft_surface_margin since these are all child settings of raft_margin, the raft_margin setting should now not be used anymore CURA-11395 --- include/LayerPlan.h | 3 +- include/raft.h | 16 +++++++ include/sliceDataStorage.h | 6 ++- src/FffGcodeWriter.cpp | 6 +-- src/LayerPlan.cpp | 33 +++++++++---- src/raft.cpp | 62 +++++++++++++++++++++---- src/sliceDataStorage.cpp | 43 ++++++++++++++--- src/support.cpp | 6 +-- stress_benchmark/resources/001.settings | 4 +- stress_benchmark/resources/002.settings | 8 +++- stress_benchmark/resources/003.settings | 8 +++- stress_benchmark/resources/004.settings | 8 +++- stress_benchmark/resources/005.settings | 8 +++- stress_benchmark/resources/006.settings | 8 +++- stress_benchmark/resources/007.settings | 8 +++- stress_benchmark/resources/008.settings | 8 +++- stress_benchmark/resources/009.settings | 8 +++- stress_benchmark/resources/010.settings | 8 +++- stress_benchmark/resources/011.settings | 8 +++- stress_benchmark/resources/012.settings | 4 +- stress_benchmark/resources/013.settings | 4 +- stress_benchmark/resources/014.settings | 4 +- stress_benchmark/resources/015.settings | 4 +- stress_benchmark/resources/016.settings | 4 +- stress_benchmark/resources/017.settings | 4 +- stress_benchmark/resources/018.settings | 4 +- stress_benchmark/resources/019.settings | 4 +- stress_benchmark/resources/020.settings | 4 +- stress_benchmark/resources/021.settings | 4 +- stress_benchmark/resources/022.settings | 4 +- stress_benchmark/resources/023.settings | 4 +- stress_benchmark/resources/024.settings | 4 +- stress_benchmark/resources/025.settings | 4 +- stress_benchmark/resources/026.settings | 4 +- stress_benchmark/resources/027.settings | 4 +- stress_benchmark/resources/028.settings | 4 +- stress_benchmark/resources/029.settings | 4 +- stress_benchmark/resources/030.settings | 4 +- stress_benchmark/resources/031.settings | 4 +- stress_benchmark/resources/032.settings | 4 +- stress_benchmark/resources/033.settings | 4 +- stress_benchmark/resources/034.settings | 4 +- stress_benchmark/resources/035.settings | 4 +- stress_benchmark/resources/036.settings | 4 +- stress_benchmark/resources/037.settings | 4 +- stress_benchmark/resources/038.settings | 4 +- stress_benchmark/resources/039.settings | 4 +- stress_benchmark/resources/040.settings | 4 +- stress_benchmark/resources/041.settings | 4 +- stress_benchmark/resources/042.settings | 4 +- stress_benchmark/resources/043.settings | 4 +- stress_benchmark/resources/044.settings | 4 +- stress_benchmark/resources/045.settings | 4 +- stress_benchmark/resources/046.settings | 4 +- stress_benchmark/resources/047.settings | 4 +- stress_benchmark/resources/048.settings | 4 +- stress_benchmark/resources/049.settings | 4 +- stress_benchmark/resources/050.settings | 4 +- stress_benchmark/resources/051.settings | 4 +- stress_benchmark/resources/052.settings | 4 +- stress_benchmark/resources/053.settings | 4 +- stress_benchmark/resources/054.settings | 4 +- stress_benchmark/resources/055.settings | 4 +- stress_benchmark/resources/056.settings | 4 +- stress_benchmark/resources/057.settings | 4 +- stress_benchmark/resources/058.settings | 4 +- stress_benchmark/resources/059.settings | 4 +- stress_benchmark/resources/060.settings | 4 +- stress_benchmark/resources/061.settings | 4 +- stress_benchmark/resources/062.settings | 4 +- stress_benchmark/resources/063.settings | 4 +- stress_benchmark/resources/064.settings | 4 +- stress_benchmark/resources/065.settings | 4 +- stress_benchmark/resources/066.settings | 4 +- stress_benchmark/resources/067.settings | 4 +- tests/test_global_settings.txt | 4 +- 76 files changed, 378 insertions(+), 109 deletions(-) diff --git a/include/LayerPlan.h b/include/LayerPlan.h index 6bafb46064..4e59e6f211 100644 --- a/include/LayerPlan.h +++ b/include/LayerPlan.h @@ -13,6 +13,7 @@ #include "pathPlanning/GCodePath.h" #include "pathPlanning/NozzleTempInsert.h" #include "pathPlanning/TimeMaterialEstimates.h" +#include "raft.h" #include "settings/PathConfigStorage.h" #include "settings/types/LayerIndex.h" #include "utils/ExtrusionJunction.h" @@ -63,7 +64,7 @@ class LayerPlan : public NoCopy const SliceDataStorage& storage_; //!< The polygon data obtained from FffPolygonProcessor const LayerIndex layer_nr_; //!< The layer number of this layer plan const bool is_initial_layer_; //!< Whether this is the first layer (which might be raft) - const bool is_raft_layer_; //!< Whether this is a layer which is part of the raft + const Raft::LayerType layer_type_; //!< Which part of the raft, airgap or model this layer is. coord_t layer_thickness_; std::vector layer_start_pos_per_extruder_; //!< The starting position of a layer for each extruder diff --git a/include/raft.h b/include/raft.h index 1019bef761..11f0fffdf6 100644 --- a/include/raft.h +++ b/include/raft.h @@ -4,6 +4,7 @@ #ifndef RAFT_H #define RAFT_H +#include "settings/types/LayerIndex.h" #include "utils/Coord_t.h" namespace cura @@ -54,6 +55,21 @@ class Raft */ static size_t getTotalExtraLayers(); + enum LayerType { + RaftBase, + RaftInterface, + RaftSurface, + Airgap, + Model + }; + + /*! + * \brief Get the type of layer at the given layer index. + * \param layer_index The layer index to get the type of. + * \return The type of layer at the given layer index. + */ + static LayerType getLayerType(LayerIndex layer_index); + }; }//namespace cura diff --git a/include/sliceDataStorage.h b/include/sliceDataStorage.h index 74d2047336..e18a3783d3 100644 --- a/include/sliceDataStorage.h +++ b/include/sliceDataStorage.h @@ -355,7 +355,11 @@ class SliceDataStorage : public NoCopy std::vector skirt_brim[MAX_EXTRUDERS]; //!< Skirt/brim polygons per extruder, ordered from inner to outer polygons. Polygons support_brim; //!< brim lines for support, going from the edge of the support inward. \note Not ordered by inset. - Polygons raftOutline; // Storage for the outline of the raft. Will be filled with lines when the GCode is generated. + + // Storage for the outline of the raft-parts. Will be filled with lines when the GCode is generated. + Polygons raftBaseOutline; + Polygons raftInterfaceOutline; + Polygons raftSurfaceOutline; int max_print_height_second_to_last_extruder; //!< Used in multi-extrusion: the layer number beyond which all models are printed with the same extruder std::vector max_print_height_per_extruder; //!< For each extruder the highest layer number at which it is used. diff --git a/src/FffGcodeWriter.cpp b/src/FffGcodeWriter.cpp index a720e59a49..a603aaf962 100644 --- a/src/FffGcodeWriter.cpp +++ b/src/FffGcodeWriter.cpp @@ -630,7 +630,7 @@ void FffGcodeWriter::processRaft(const SliceDataStorage& storage) }; std::vector raft_outline_paths; - raft_outline_paths.emplace_back(ParameterizedRaftPath{ line_spacing, storage.raftOutline }); + raft_outline_paths.emplace_back(ParameterizedRaftPath{ line_spacing, storage.raftBaseOutline }); if (storage.primeTower.enabled_) { const Polygons& raft_outline_prime_tower = storage.primeTower.getOuterPoly(layer_nr); @@ -761,7 +761,7 @@ void FffGcodeWriter::processRaft(const SliceDataStorage& storage) Polygons raft_outline_path; const coord_t small_offset = gcode_layer.configs_storage_.raft_interface_config.getLineWidth() / 2; // Do this manually because of micron-movement created in corners when insetting a polygon that was offset with round joint type. - raft_outline_path = storage.raftOutline.offset(-small_offset); + raft_outline_path = storage.raftInterfaceOutline.offset(-small_offset); raft_outline_path = Simplify(interface_settings).polygon(raft_outline_path); // Remove those micron-movements. const coord_t infill_outline_width = gcode_layer.configs_storage_.raft_interface_config.getLineWidth(); Polygons raft_lines; @@ -903,7 +903,7 @@ void FffGcodeWriter::processRaft(const SliceDataStorage& storage) Polygons raft_outline_path; const coord_t small_offset = gcode_layer.configs_storage_.raft_interface_config.getLineWidth() / 2; // Do this manually because of micron-movement created in corners when insetting a polygon that was offset with round joint type. - raft_outline_path = storage.raftOutline.offset(-small_offset); + raft_outline_path = storage.raftSurfaceOutline.offset(-small_offset); raft_outline_path = Simplify(interface_settings).polygon(raft_outline_path); // Remove those micron-movements. const coord_t infill_outline_width = gcode_layer.configs_storage_.raft_surface_config.getLineWidth(); Polygons raft_lines; diff --git a/src/LayerPlan.cpp b/src/LayerPlan.cpp index 0e2d7b341f..99051a38c8 100644 --- a/src/LayerPlan.cpp +++ b/src/LayerPlan.cpp @@ -95,7 +95,7 @@ LayerPlan::LayerPlan( , storage_(storage) , layer_nr_(layer_nr) , is_initial_layer_(layer_nr == 0 - static_cast(Raft::getTotalExtraLayers())) - , is_raft_layer_(layer_nr < 0 - static_cast(Raft::getFillerLayerCount())) + , layer_type_(Raft::getLayerType(layer_nr)) , layer_thickness_(layer_thickness) , has_prime_tower_planned_per_extruder_(Application::getInstance().current_slice_->scene.extruders.size(), false) , has_prime_tower_base_planned_(false) @@ -126,11 +126,12 @@ LayerPlan::LayerPlan( layer_start_pos_per_extruder_.emplace_back(extruder.settings_.get("layer_start_x"), extruder.settings_.get("layer_start_y")); } extruder_plans_.reserve(Application::getInstance().current_slice_->scene.extruders.size()); + const auto is_raft_layer = layer_type_ == Raft::LayerType::RaftBase || layer_type_ == Raft::LayerType::RaftInterface || layer_type_ == Raft::LayerType::RaftSurface; extruder_plans_.emplace_back( current_extruder, layer_nr, is_initial_layer_, - is_raft_layer_, + is_raft_layer, layer_thickness, fan_speed_layer_time_settings_per_extruder[current_extruder], storage.retraction_wipe_config_per_extruder[current_extruder].retraction_config); @@ -158,12 +159,25 @@ Polygons LayerPlan::computeCombBoundary(const CombBoundary boundary_type) const CombingMode mesh_combing_mode = Application::getInstance().current_slice_->scene.current_mesh_group->settings.get("retraction_combing"); if (mesh_combing_mode != CombingMode::OFF && (layer_nr_ >= 0 || mesh_combing_mode != CombingMode::NO_SKIN)) { - if (layer_nr_ < 0) - { - comb_boundary = storage_.raftOutline.offset(MM2INT(0.1)); - } - else + switch (layer_type_) { + case Raft::LayerType::RaftBase: + comb_boundary = storage_.raftBaseOutline.offset(MM2INT(0.1)); + break; + + case Raft::LayerType::RaftInterface: + comb_boundary = storage_.raftInterfaceOutline.offset(MM2INT(0.1)); + break; + + case Raft::LayerType::RaftSurface: + comb_boundary = storage_.raftSurfaceOutline.offset(MM2INT(0.1)); + break; + + case Raft::LayerType::Airgap: + // do nothing for airgap + break; + + case Raft::LayerType::Model: for (const std::shared_ptr& mesh_ptr : storage_.meshes) { const auto& mesh = *mesh_ptr; @@ -218,6 +232,7 @@ Polygons LayerPlan::computeCombBoundary(const CombBoundary boundary_type) } } } + break; } } return comb_boundary; @@ -257,11 +272,13 @@ bool LayerPlan::setExtruder(const size_t extruder_nr) { // first extruder plan in a layer might be empty, cause it is made with the last extruder planned in the previous layer extruder_plans_.back().extruder_nr_ = extruder_nr; } + + const auto is_raft_layer = layer_type_ == Raft::LayerType::RaftBase || layer_type_ == Raft::LayerType::RaftInterface || layer_type_ == Raft::LayerType::RaftSurface; extruder_plans_.emplace_back( extruder_nr, layer_nr_, is_initial_layer_, - is_raft_layer_, + is_raft_layer, layer_thickness_, fan_speed_layer_time_settings_per_extruder_[extruder_nr], storage_.retraction_wipe_config_per_extruder[extruder_nr].retraction_config); diff --git a/src/raft.cpp b/src/raft.cpp index 0bdc72bbfe..b42e3e2491 100644 --- a/src/raft.cpp +++ b/src/raft.cpp @@ -19,36 +19,50 @@ void Raft::generate(SliceDataStorage& storage) { assert(storage.raftOutline.size() == 0 && "Raft polygon isn't generated yet, so should be empty!"); const Settings& settings = Application::getInstance().current_slice_->scene.current_mesh_group->settings.get("raft_base_extruder_nr").settings_; - const coord_t distance = settings.get("raft_margin"); constexpr bool include_support = true; constexpr bool dont_include_prime_tower = false; // Prime tower raft will be handled separately in 'storage.primeRaftOutline'; see below. - storage.raftOutline = storage.getLayerOutlines(0, include_support, dont_include_prime_tower).offset(distance, ClipperLib::jtRound); + + storage.raftBaseOutline = storage.raftSurfaceOutline = storage.raftInterfaceOutline = storage.getLayerOutlines(0, include_support, dont_include_prime_tower); + storage.raftBaseOutline = storage.raftBaseOutline.offset(settings.get("raft_base_margin"), ClipperLib::jtRound); + storage.raftInterfaceOutline = storage.raftInterfaceOutline.offset(settings.get("raft_interface_margin"), ClipperLib::jtRound); + storage.raftSurfaceOutline = storage.raftSurfaceOutline.offset(settings.get("raft_surface_margin"), ClipperLib::jtRound); + const coord_t shield_line_width_layer0 = settings.get("skirt_brim_line_width"); + const coord_t max_raft_distance = std::max(std::max(settings.get("raft_base_margin"), settings.get("raft_interface_margin")), settings.get("raft_surface_margin")); if (storage.draft_protection_shield.size() > 0) { Polygons draft_shield_raft = storage.draft_protection_shield .offset(shield_line_width_layer0) // start half a line width outside shield - .difference(storage.draft_protection_shield.offset(-distance - shield_line_width_layer0 / 2, ClipperLib::jtRound)); // end distance inside shield - storage.raftOutline = storage.raftOutline.unionPolygons(draft_shield_raft); + .difference(storage.draft_protection_shield.offset(-max_raft_distance - shield_line_width_layer0 / 2, ClipperLib::jtRound)); // end distance inside shield + storage.raftBaseOutline = storage.raftBaseOutline.unionPolygons(draft_shield_raft); + storage.raftSurfaceOutline = storage.raftSurfaceOutline.unionPolygons(draft_shield_raft); + storage.raftInterfaceOutline = storage.raftInterfaceOutline.unionPolygons(draft_shield_raft); } if (storage.oozeShield.size() > 0 && storage.oozeShield[0].size() > 0) { const Polygons& ooze_shield = storage.oozeShield[0]; Polygons ooze_shield_raft = ooze_shield .offset(shield_line_width_layer0) // start half a line width outside shield - .difference(ooze_shield.offset(-distance - shield_line_width_layer0 / 2, ClipperLib::jtRound)); // end distance inside shield - storage.raftOutline = storage.raftOutline.unionPolygons(ooze_shield_raft); + .difference(ooze_shield.offset(-max_raft_distance - shield_line_width_layer0 / 2, ClipperLib::jtRound)); // end distance inside shield + storage.raftBaseOutline = storage.raftBaseOutline.unionPolygons(ooze_shield_raft); + storage.raftSurfaceOutline = storage.raftSurfaceOutline.unionPolygons(ooze_shield_raft); + storage.raftInterfaceOutline = storage.raftInterfaceOutline.unionPolygons(ooze_shield_raft); } if (settings.get("raft_remove_inside_corners")) { - storage.raftOutline.makeConvex(); + storage.raftBaseOutline.makeConvex(); + storage.raftSurfaceOutline.makeConvex(); + storage.raftInterfaceOutline.makeConvex(); } else { const coord_t smoothing = settings.get("raft_smoothing"); - storage.raftOutline = storage.raftOutline.offset(smoothing, ClipperLib::jtRound).offset(-smoothing, ClipperLib::jtRound); // remove small holes and smooth inward corners + // remove small holes and smooth inward corners + storage.raftBaseOutline = storage.raftBaseOutline.offset(smoothing, ClipperLib::jtRound).offset(-smoothing, ClipperLib::jtRound); + storage.raftSurfaceOutline = storage.raftSurfaceOutline.offset(smoothing, ClipperLib::jtRound).offset(-smoothing, ClipperLib::jtRound); + storage.raftInterfaceOutline = storage.raftInterfaceOutline.offset(smoothing, ClipperLib::jtRound).offset(-smoothing, ClipperLib::jtRound); } if (storage.primeTower.enabled_ && ! storage.primeTower.would_have_actual_tower_) @@ -121,5 +135,37 @@ size_t Raft::getTotalExtraLayers() return 1 + interface_train.settings_.get("raft_interface_layers") + surface_train.settings_.get("raft_surface_layers") + getFillerLayerCount(); } +Raft::LayerType Raft::getLayerType(LayerIndex layer_index) +{ + const Settings& mesh_group_settings = Application::getInstance().current_slice_->scene.current_mesh_group->settings; + const ExtruderTrain& base_train = mesh_group_settings.get("raft_base_extruder_nr"); + const ExtruderTrain& interface_train = mesh_group_settings.get("raft_interface_extruder_nr"); + const ExtruderTrain& surface_train = mesh_group_settings.get("raft_surface_extruder_nr"); + const auto airgap = Raft::getFillerLayerCount(); + const auto interface_layers = interface_train.settings_.get("raft_interface_layers"); + const auto surface_layers = surface_train.settings_.get("raft_surface_layers"); + + if (layer_index < - airgap - surface_layers - interface_layers) + { + return LayerType::RaftBase; + } + if (layer_index < - airgap - surface_layers) + { + return LayerType::RaftInterface; + } + if (layer_index < - airgap) + { + return LayerType::RaftSurface; + } + else if (layer_index < 0) + { + return LayerType::Airgap; + } + else + { + return LayerType::Model; + } +} + } // namespace cura diff --git a/src/sliceDataStorage.cpp b/src/sliceDataStorage.cpp index 94e2ccf16f..1af95d5027 100644 --- a/src/sliceDataStorage.cpp +++ b/src/sliceDataStorage.cpp @@ -271,13 +271,41 @@ Polygons const { const Settings& mesh_group_settings = Application::getInstance().current_slice_->scene.current_mesh_group->settings; - if (layer_nr < 0 && layer_nr < -static_cast(Raft::getFillerLayerCount())) - { // when processing raft - if (include_support && (extruder_nr == -1 || extruder_nr == int(mesh_group_settings.get("adhesion_extruder_nr").extruder_nr_))) + + const auto layer_type = Raft::getLayerType(layer_nr); + switch (layer_type) + { + case Raft::LayerType::RaftBase: + case Raft::LayerType::RaftInterface: + case Raft::LayerType::RaftSurface: + { + const Polygons* raftOutline; + bool use_current_extruder_for_raft = extruder_nr == -1; + + switch (layer_type) + { + case Raft::LayerType::RaftBase: + raftOutline = &raftBaseOutline; + use_current_extruder_for_raft |= extruder_nr == int(mesh_group_settings.get("raft_base_extruder_nr").extruder_nr_); + break; + case Raft::LayerType::RaftInterface: + raftOutline = &raftInterfaceOutline; + use_current_extruder_for_raft |= extruder_nr == int(mesh_group_settings.get("raft_interface_extruder_nr").extruder_nr_); + break; + case Raft::LayerType::RaftSurface: + raftOutline = &raftSurfaceOutline; + use_current_extruder_for_raft |= extruder_nr == int(mesh_group_settings.get("raft_surface_extruder_nr").extruder_nr_); + break; + default: + assert(false << "unreachable due to outer switch statement"); + return Polygons(); + } + + if (include_support && use_current_extruder_for_raft) { if (external_polys_only) { - std::vector parts = raftOutline.splitIntoParts(); + std::vector parts = raftOutline->splitIntoParts(); Polygons result; for (PolygonsPart& part : parts) { @@ -287,16 +315,17 @@ Polygons } else { - return raftOutline; + return *raftOutline; } } else { return Polygons(); } + break; } - else - { + case Raft::LayerType::Airgap: + case Raft::LayerType::Model: Polygons total; if (layer_nr >= 0) { diff --git a/src/support.cpp b/src/support.cpp index 5db274bfdd..09aff457c7 100644 --- a/src/support.cpp +++ b/src/support.cpp @@ -539,9 +539,9 @@ Polygons AreaSupport::join(const SliceDataStorage& storage, const Polygons& supp break; case EPlatformAdhesion::RAFT: { - adhesion_size = std::max({ mesh_group_settings.get("raft_base_extruder_nr").settings_.get("raft_margin"), - mesh_group_settings.get("raft_interface_extruder_nr").settings_.get("raft_margin"), - mesh_group_settings.get("raft_surface_extruder_nr").settings_.get("raft_margin") }); + adhesion_size = std::max({ mesh_group_settings.get("raft_base_extruder_nr").settings_.get("raft_base_margin"), + mesh_group_settings.get("raft_interface_extruder_nr").settings_.get("raft_interface_margin"), + mesh_group_settings.get("raft_surface_extruder_nr").settings_.get("raft_surface_margin") }); break; } case EPlatformAdhesion::NONE: diff --git a/stress_benchmark/resources/001.settings b/stress_benchmark/resources/001.settings index d56461c776..d72d076797 100644 --- a/stress_benchmark/resources/001.settings +++ b/stress_benchmark/resources/001.settings @@ -502,7 +502,9 @@ acceleration_infill=300 support_skip_some_zags=False material_end_of_filament_purge_speed=0.5 machine_max_jerk_e=5.0 -raft_margin=3 +raft_base_margin=3 +raft_interface_margin=3 +raft_surface_margin=3 support_interface_angles=[] support_roof_height=1.015 smooth_spiralized_contours=True diff --git a/stress_benchmark/resources/002.settings b/stress_benchmark/resources/002.settings index c5ec85db58..c9dfb14cc0 100644 --- a/stress_benchmark/resources/002.settings +++ b/stress_benchmark/resources/002.settings @@ -83,7 +83,9 @@ ironing_line_spacing=0.1 support_infill_sparse_thickness=0.2 material_bed_temperature_layer_0=50 machine_max_jerk_e=5 -raft_margin=5 +raft_base_margin=5 +raft_interface_margin=5 +raft_surface_margin=5 machine_scale_fan_speed_zero_to_one=False wall_x_material_flow=100 cool_fan_speed=100.0 @@ -1057,7 +1059,9 @@ bridge_skin_density_3=80 min_feature_size=0.1 infill_sparse_thickness=0.2 command_line_settings=0 -raft_margin=5 +raft_base_margin=5 +raft_interface_margin=5 +raft_surface_margin=5 material_end_of_filament_purge_speed=0.5 speed_support=25.0 machine_extruder_cooling_fan_number=0 diff --git a/stress_benchmark/resources/003.settings b/stress_benchmark/resources/003.settings index d0fd7a001a..b6aa5b0d7a 100644 --- a/stress_benchmark/resources/003.settings +++ b/stress_benchmark/resources/003.settings @@ -83,7 +83,9 @@ ironing_line_spacing=0.1 support_infill_sparse_thickness=0.12 material_bed_temperature_layer_0=65 machine_max_jerk_e=5 -raft_margin=15 +raft_base_margin=15 +raft_interface_margin=15 +raft_surface_margin=15 machine_scale_fan_speed_zero_to_one=False wall_x_material_flow=100 cool_fan_speed=100.0 @@ -1058,7 +1060,9 @@ bridge_skin_density_3=80 min_feature_size=0.105 infill_sparse_thickness=0.12 command_line_settings=0 -raft_margin=15 +raft_base_margin=15 +raft_interface_margin=15 +raft_surface_margin=15 material_end_of_filament_purge_speed=0.5 speed_support=25.0 machine_extruder_cooling_fan_number=0 diff --git a/stress_benchmark/resources/004.settings b/stress_benchmark/resources/004.settings index 4683743db7..a4c2afe92e 100644 --- a/stress_benchmark/resources/004.settings +++ b/stress_benchmark/resources/004.settings @@ -83,7 +83,9 @@ ironing_line_spacing=0.1 support_infill_sparse_thickness=0.1 material_bed_temperature_layer_0=70 machine_max_jerk_e=5 -raft_margin=15 +raft_base_margin=15 +raft_interface_margin=15 +raft_surface_margin=15 machine_scale_fan_speed_zero_to_one=False wall_x_material_flow=100 cool_fan_speed=100.0 @@ -1058,7 +1060,9 @@ bridge_skin_density_3=80 min_feature_size=0.1 infill_sparse_thickness=0.1 command_line_settings=0 -raft_margin=15 +raft_base_margin=15 +raft_interface_margin=15 +raft_surface_margin=15 material_end_of_filament_purge_speed=0.5 speed_support=30 machine_extruder_cooling_fan_number=0 diff --git a/stress_benchmark/resources/005.settings b/stress_benchmark/resources/005.settings index b4ee5d4563..f54b1d867c 100644 --- a/stress_benchmark/resources/005.settings +++ b/stress_benchmark/resources/005.settings @@ -83,7 +83,9 @@ ironing_line_spacing=0.1 support_infill_sparse_thickness=0.2 material_bed_temperature_layer_0=55 machine_max_jerk_e=5 -raft_margin=5.0 +raft_base_margin=5 +raft_interface_margin=5 +raft_surface_margin=5 machine_scale_fan_speed_zero_to_one=False wall_x_material_flow=100 cool_fan_speed=100.0 @@ -1059,7 +1061,9 @@ bridge_skin_density_3=80 min_feature_size=0.1 infill_sparse_thickness=0.2 command_line_settings=0 -raft_margin=5.0 +raft_base_margin=5 +raft_interface_margin=5 +raft_surface_margin=5 material_end_of_filament_purge_speed=0.5 speed_support=25.0 machine_extruder_cooling_fan_number=0 diff --git a/stress_benchmark/resources/006.settings b/stress_benchmark/resources/006.settings index ec75660851..956d6691a6 100644 --- a/stress_benchmark/resources/006.settings +++ b/stress_benchmark/resources/006.settings @@ -83,7 +83,9 @@ ironing_line_spacing=0.1 support_infill_sparse_thickness=0.2 material_bed_temperature_layer_0=60 machine_max_jerk_e=5 -raft_margin=15 +raft_base_margin=15 +raft_interface_margin=15 +raft_surface_margin=15 machine_scale_fan_speed_zero_to_one=False wall_x_material_flow=100 cool_fan_speed=100.0 @@ -1059,7 +1061,9 @@ bridge_skin_density_3=80 min_feature_size=0.1 infill_sparse_thickness=0.2 command_line_settings=0 -raft_margin=15 +raft_base_margin=15 +raft_interface_margin=15 +raft_surface_margin=15 material_end_of_filament_purge_speed=0.5 speed_support=25.0 machine_extruder_cooling_fan_number=0 diff --git a/stress_benchmark/resources/007.settings b/stress_benchmark/resources/007.settings index 635226ed8c..424a7b4afa 100644 --- a/stress_benchmark/resources/007.settings +++ b/stress_benchmark/resources/007.settings @@ -83,7 +83,9 @@ ironing_line_spacing=0.1 support_infill_sparse_thickness=0.2 material_bed_temperature_layer_0=60 machine_max_jerk_e=5 -raft_margin=15 +raft_base_margin=15 +raft_interface_margin=15 +raft_surface_margin=15 machine_scale_fan_speed_zero_to_one=False wall_x_material_flow=100 cool_fan_speed=100.0 @@ -1059,7 +1061,9 @@ bridge_skin_density_3=80 min_feature_size=0.1 infill_sparse_thickness=0.2 command_line_settings=0 -raft_margin=15 +raft_base_margin=15 +raft_interface_margin=15 +raft_surface_margin=15 material_end_of_filament_purge_speed=0.5 speed_support=40.0 machine_extruder_cooling_fan_number=0 diff --git a/stress_benchmark/resources/008.settings b/stress_benchmark/resources/008.settings index f4771e572b..cfcd6b234c 100644 --- a/stress_benchmark/resources/008.settings +++ b/stress_benchmark/resources/008.settings @@ -370,7 +370,9 @@ support_tree_top_rate=10 cross_infill_pocket_size=6.0 material_end_of_filament_purge_speed=0.5 machine_max_jerk_e=5.0 -raft_margin=15 +raft_base_margin=15 +raft_interface_margin=15 +raft_surface_margin=15 acceleration_support_roof=1000 support_roof_offset=0.0 wipe_retraction_prime_speed=45 @@ -899,7 +901,9 @@ wall_line_width_0=0.4 support_tree_top_rate=10 cross_infill_pocket_size=6.0 material_end_of_filament_purge_speed=0.5 -raft_margin=15 +raft_base_margin=15 +raft_interface_margin=15 +raft_surface_margin=15 material_break_preparation_temperature=210 wall_transition_filter_deviation=0.1 support_tree_max_diameter_increase_by_merges_when_support_to_model=1 diff --git a/stress_benchmark/resources/009.settings b/stress_benchmark/resources/009.settings index f4771e572b..cfcd6b234c 100644 --- a/stress_benchmark/resources/009.settings +++ b/stress_benchmark/resources/009.settings @@ -370,7 +370,9 @@ support_tree_top_rate=10 cross_infill_pocket_size=6.0 material_end_of_filament_purge_speed=0.5 machine_max_jerk_e=5.0 -raft_margin=15 +raft_base_margin=15 +raft_interface_margin=15 +raft_surface_margin=15 acceleration_support_roof=1000 support_roof_offset=0.0 wipe_retraction_prime_speed=45 @@ -899,7 +901,9 @@ wall_line_width_0=0.4 support_tree_top_rate=10 cross_infill_pocket_size=6.0 material_end_of_filament_purge_speed=0.5 -raft_margin=15 +raft_base_margin=15 +raft_interface_margin=15 +raft_surface_margin=15 material_break_preparation_temperature=210 wall_transition_filter_deviation=0.1 support_tree_max_diameter_increase_by_merges_when_support_to_model=1 diff --git a/stress_benchmark/resources/010.settings b/stress_benchmark/resources/010.settings index f4771e572b..cfcd6b234c 100644 --- a/stress_benchmark/resources/010.settings +++ b/stress_benchmark/resources/010.settings @@ -370,7 +370,9 @@ support_tree_top_rate=10 cross_infill_pocket_size=6.0 material_end_of_filament_purge_speed=0.5 machine_max_jerk_e=5.0 -raft_margin=15 +raft_base_margin=15 +raft_interface_margin=15 +raft_surface_margin=15 acceleration_support_roof=1000 support_roof_offset=0.0 wipe_retraction_prime_speed=45 @@ -899,7 +901,9 @@ wall_line_width_0=0.4 support_tree_top_rate=10 cross_infill_pocket_size=6.0 material_end_of_filament_purge_speed=0.5 -raft_margin=15 +raft_base_margin=15 +raft_interface_margin=15 +raft_surface_margin=15 material_break_preparation_temperature=210 wall_transition_filter_deviation=0.1 support_tree_max_diameter_increase_by_merges_when_support_to_model=1 diff --git a/stress_benchmark/resources/011.settings b/stress_benchmark/resources/011.settings index 3f63e86a10..08b6ec47db 100644 --- a/stress_benchmark/resources/011.settings +++ b/stress_benchmark/resources/011.settings @@ -83,7 +83,9 @@ ironing_line_spacing=0.1 support_infill_sparse_thickness=0.2 material_bed_temperature_layer_0=60 machine_max_jerk_e=5.0 -raft_margin=15 +raft_base_margin=15 +raft_interface_margin=15 +raft_surface_margin=15 machine_scale_fan_speed_zero_to_one=False wall_x_material_flow=100 cool_fan_speed=100.0 @@ -1059,7 +1061,9 @@ bridge_skin_density_3=80 min_feature_size=0.1 infill_sparse_thickness=0.2 command_line_settings=0 -raft_margin=15 +raft_base_margin=15 +raft_interface_margin=15 +raft_surface_margin=15 material_end_of_filament_purge_speed=0.5 speed_support=60 machine_extruder_cooling_fan_number=0 diff --git a/stress_benchmark/resources/012.settings b/stress_benchmark/resources/012.settings index 712087c5e2..521724273d 100644 --- a/stress_benchmark/resources/012.settings +++ b/stress_benchmark/resources/012.settings @@ -28,7 +28,9 @@ material_initial_print_temperature=250 jerk_skirt_brim=12.5 roofing_monotonic=True machine_max_jerk_e=5.0 -raft_margin=3 +raft_base_margin=3 +raft_interface_margin=3 +raft_surface_margin=3 bottom_thickness=1.0 skirt_height=3 speed_travel_layer_0=250.0 diff --git a/stress_benchmark/resources/013.settings b/stress_benchmark/resources/013.settings index dd1893e2c9..311beb6893 100644 --- a/stress_benchmark/resources/013.settings +++ b/stress_benchmark/resources/013.settings @@ -134,7 +134,9 @@ raft_interface_jerk=8 material_shrinkage_percentage=100.0 support_interface_wall_count=0 machine_max_jerk_e=5 -raft_margin=15 +raft_base_margin=15 +raft_interface_margin=15 +raft_surface_margin=15 roofing_monotonic=True skin_overlap_mm=0.04 small_feature_max_length=0.0 diff --git a/stress_benchmark/resources/014.settings b/stress_benchmark/resources/014.settings index 3838f85463..93487b5295 100644 --- a/stress_benchmark/resources/014.settings +++ b/stress_benchmark/resources/014.settings @@ -134,7 +134,9 @@ raft_interface_jerk=8 material_shrinkage_percentage=100.0 support_interface_wall_count=0 machine_max_jerk_e=5.0 -raft_margin=15 +raft_base_margin=15 +raft_interface_margin=15 +raft_surface_margin=15 roofing_monotonic=True skin_overlap_mm=0.02 small_feature_max_length=0.0 diff --git a/stress_benchmark/resources/015.settings b/stress_benchmark/resources/015.settings index b2a53600c9..1159c55eba 100644 --- a/stress_benchmark/resources/015.settings +++ b/stress_benchmark/resources/015.settings @@ -134,7 +134,9 @@ raft_interface_jerk=20 material_shrinkage_percentage=100.0 support_interface_wall_count=0 machine_max_jerk_e=5.0 -raft_margin=15 +raft_base_margin=15 +raft_interface_margin=15 +raft_surface_margin=15 roofing_monotonic=True skin_overlap_mm=0.02 small_feature_max_length=0.0 diff --git a/stress_benchmark/resources/016.settings b/stress_benchmark/resources/016.settings index af2f42cf1e..de11857273 100644 --- a/stress_benchmark/resources/016.settings +++ b/stress_benchmark/resources/016.settings @@ -134,7 +134,9 @@ raft_interface_jerk=8 material_shrinkage_percentage=100.0 support_interface_wall_count=0 machine_max_jerk_e=5 -raft_margin=5 +raft_base_margin=5 +raft_interface_margin=5 +raft_surface_margin=5 roofing_monotonic=True skin_overlap_mm=0.04 small_feature_max_length=0.0 diff --git a/stress_benchmark/resources/017.settings b/stress_benchmark/resources/017.settings index 02d045445e..76a4b98128 100644 --- a/stress_benchmark/resources/017.settings +++ b/stress_benchmark/resources/017.settings @@ -134,7 +134,9 @@ raft_interface_jerk=12.0 material_shrinkage_percentage=100.0 support_interface_wall_count=0 machine_max_jerk_e=5 -raft_margin=15 +raft_base_margin=15 +raft_interface_margin=15 +raft_surface_margin=15 roofing_monotonic=True skin_overlap_mm=0.12 small_feature_max_length=0.0 diff --git a/stress_benchmark/resources/018.settings b/stress_benchmark/resources/018.settings index 2b377d53e0..4c6b5a3bf1 100644 --- a/stress_benchmark/resources/018.settings +++ b/stress_benchmark/resources/018.settings @@ -134,7 +134,9 @@ raft_interface_jerk=8 material_shrinkage_percentage=100.0 support_interface_wall_count=0 machine_max_jerk_e=5 -raft_margin=5.0 +raft_base_margin=5 +raft_interface_margin=5 +raft_surface_margin=5 roofing_monotonic=True skin_overlap_mm=0.04 small_feature_max_length=0.0 diff --git a/stress_benchmark/resources/019.settings b/stress_benchmark/resources/019.settings index 8910e83a35..443bd2d9a1 100644 --- a/stress_benchmark/resources/019.settings +++ b/stress_benchmark/resources/019.settings @@ -134,7 +134,9 @@ raft_interface_jerk=8 material_shrinkage_percentage=100.0 support_interface_wall_count=0 machine_max_jerk_e=5 -raft_margin=15 +raft_base_margin=15 +raft_interface_margin=15 +raft_surface_margin=15 roofing_monotonic=True skin_overlap_mm=0.04 small_feature_max_length=0.0 diff --git a/stress_benchmark/resources/020.settings b/stress_benchmark/resources/020.settings index 87cecf33c7..d96be4bd5a 100644 --- a/stress_benchmark/resources/020.settings +++ b/stress_benchmark/resources/020.settings @@ -134,7 +134,9 @@ raft_interface_jerk=20 material_shrinkage_percentage=100.0 support_interface_wall_count=0 machine_max_jerk_e=5.0 -raft_margin=15 +raft_base_margin=15 +raft_interface_margin=15 +raft_surface_margin=15 roofing_monotonic=True skin_overlap_mm=0.04 small_feature_max_length=0.0 diff --git a/stress_benchmark/resources/021.settings b/stress_benchmark/resources/021.settings index 8ddb9175ff..802d2c4733 100644 --- a/stress_benchmark/resources/021.settings +++ b/stress_benchmark/resources/021.settings @@ -135,7 +135,9 @@ raft_interface_jerk=30 material_shrinkage_percentage=100.1 support_interface_wall_count=1 machine_max_jerk_e=5.0 -raft_margin=15 +raft_base_margin=15 +raft_interface_margin=15 +raft_surface_margin=15 roofing_monotonic=True skin_overlap_mm=0.08 small_feature_max_length=0.0 diff --git a/stress_benchmark/resources/022.settings b/stress_benchmark/resources/022.settings index 6d484adf38..1384179d85 100644 --- a/stress_benchmark/resources/022.settings +++ b/stress_benchmark/resources/022.settings @@ -134,7 +134,9 @@ raft_interface_jerk=20 material_shrinkage_percentage=100.0 support_interface_wall_count=0 machine_max_jerk_e=5.0 -raft_margin=15.0 +raft_base_margin=15 +raft_interface_margin=15 +raft_surface_margin=15 roofing_monotonic=True skin_overlap_mm=0.084 small_feature_max_length=0.0 diff --git a/stress_benchmark/resources/023.settings b/stress_benchmark/resources/023.settings index abc56c6905..2313a61291 100644 --- a/stress_benchmark/resources/023.settings +++ b/stress_benchmark/resources/023.settings @@ -134,7 +134,9 @@ raft_interface_jerk=10.0 material_shrinkage_percentage=100.0 support_interface_wall_count=1 machine_max_jerk_e=5.0 -raft_margin=15 +raft_base_margin=15 +raft_interface_margin=15 +raft_surface_margin=15 roofing_monotonic=True skin_overlap_mm=0.044000000000000004 small_feature_max_length=15.707963267948966 diff --git a/stress_benchmark/resources/024.settings b/stress_benchmark/resources/024.settings index 05c420b03e..15d687c588 100644 --- a/stress_benchmark/resources/024.settings +++ b/stress_benchmark/resources/024.settings @@ -135,7 +135,9 @@ raft_interface_jerk=8 material_shrinkage_percentage=100.0 support_interface_wall_count=1 machine_max_jerk_e=5 -raft_margin=15 +raft_base_margin=15 +raft_interface_margin=15 +raft_surface_margin=15 roofing_monotonic=True skin_overlap_mm=0.08 small_feature_max_length=0.0 diff --git a/stress_benchmark/resources/025.settings b/stress_benchmark/resources/025.settings index a6e3d3500e..60b63ed7ab 100644 --- a/stress_benchmark/resources/025.settings +++ b/stress_benchmark/resources/025.settings @@ -134,7 +134,9 @@ raft_interface_jerk=20 material_shrinkage_percentage=100.0 support_interface_wall_count=0 machine_max_jerk_e=5.0 -raft_margin=15 +raft_base_margin=15 +raft_interface_margin=15 +raft_surface_margin=15 roofing_monotonic=True skin_overlap_mm=0.02 small_feature_max_length=0.0 diff --git a/stress_benchmark/resources/026.settings b/stress_benchmark/resources/026.settings index a008515e9f..92acf19566 100644 --- a/stress_benchmark/resources/026.settings +++ b/stress_benchmark/resources/026.settings @@ -135,7 +135,9 @@ raft_interface_jerk=20 material_shrinkage_percentage=100.2 support_interface_wall_count=1 machine_max_jerk_e=5.0 -raft_margin=15 +raft_base_margin=15 +raft_interface_margin=15 +raft_surface_margin=15 roofing_monotonic=True skin_overlap_mm=0.08 small_feature_max_length=0.0 diff --git a/stress_benchmark/resources/027.settings b/stress_benchmark/resources/027.settings index 1b4b00078a..8617f7f696 100644 --- a/stress_benchmark/resources/027.settings +++ b/stress_benchmark/resources/027.settings @@ -135,7 +135,9 @@ raft_interface_jerk=50.0 material_shrinkage_percentage=100.3 support_interface_wall_count=1 machine_max_jerk_e=5.0 -raft_margin=15 +raft_base_margin=15 +raft_interface_margin=15 +raft_surface_margin=15 roofing_monotonic=True skin_overlap_mm=0.08 small_feature_max_length=0.0 diff --git a/stress_benchmark/resources/028.settings b/stress_benchmark/resources/028.settings index 7f958d05c2..0ffc6d9b51 100644 --- a/stress_benchmark/resources/028.settings +++ b/stress_benchmark/resources/028.settings @@ -134,7 +134,9 @@ raft_interface_jerk=20 material_shrinkage_percentage=100.0 support_interface_wall_count=0 machine_max_jerk_e=5.0 -raft_margin=15 +raft_base_margin=15 +raft_interface_margin=15 +raft_surface_margin=15 roofing_monotonic=True skin_overlap_mm=0.1 small_feature_max_length=0.0 diff --git a/stress_benchmark/resources/029.settings b/stress_benchmark/resources/029.settings index 823bf8129b..5b9c43af5e 100644 --- a/stress_benchmark/resources/029.settings +++ b/stress_benchmark/resources/029.settings @@ -134,7 +134,9 @@ raft_interface_jerk=20 material_shrinkage_percentage=100.0 support_interface_wall_count=0 machine_max_jerk_e=5.0 -raft_margin=15 +raft_base_margin=15 +raft_interface_margin=15 +raft_surface_margin=15 roofing_monotonic=True skin_overlap_mm=0.04 small_feature_max_length=15.707963267948966 diff --git a/stress_benchmark/resources/030.settings b/stress_benchmark/resources/030.settings index f003931b0a..47809b68eb 100644 --- a/stress_benchmark/resources/030.settings +++ b/stress_benchmark/resources/030.settings @@ -135,7 +135,9 @@ raft_interface_jerk=20 material_shrinkage_percentage=100.2 support_interface_wall_count=1 machine_max_jerk_e=5.0 -raft_margin=15 +raft_base_margin=15 +raft_interface_margin=15 +raft_surface_margin=15 roofing_monotonic=True skin_overlap_mm=0.08 small_feature_max_length=0.0 diff --git a/stress_benchmark/resources/031.settings b/stress_benchmark/resources/031.settings index 35ea2a8526..31984edfe1 100644 --- a/stress_benchmark/resources/031.settings +++ b/stress_benchmark/resources/031.settings @@ -134,7 +134,9 @@ raft_interface_jerk=8 material_shrinkage_percentage=100.0 support_interface_wall_count=0 machine_max_jerk_e=5 -raft_margin=15 +raft_base_margin=15 +raft_interface_margin=15 +raft_surface_margin=15 roofing_monotonic=True skin_overlap_mm=0.04 small_feature_max_length=0.0 diff --git a/stress_benchmark/resources/032.settings b/stress_benchmark/resources/032.settings index 8187ab3099..16d3b15c9c 100644 --- a/stress_benchmark/resources/032.settings +++ b/stress_benchmark/resources/032.settings @@ -555,7 +555,9 @@ wipe_pause=0 material_standby_temperature=175 jerk_wall=8 machine_nozzle_cool_down_speed=2.0 -raft_margin=15 +raft_base_margin=15 +raft_interface_margin=15 +raft_surface_margin=15 raft_acceleration=1000 support_roof_wall_count=0 raft_jerk=8 diff --git a/stress_benchmark/resources/033.settings b/stress_benchmark/resources/033.settings index 5783e17291..efb082178b 100644 --- a/stress_benchmark/resources/033.settings +++ b/stress_benchmark/resources/033.settings @@ -557,7 +557,9 @@ wipe_pause=0 material_standby_temperature=175 jerk_wall=20 machine_nozzle_cool_down_speed=2.0 -raft_margin=15 +raft_base_margin=15 +raft_interface_margin=15 +raft_surface_margin=15 raft_acceleration=3000 support_roof_wall_count=0 raft_jerk=20 diff --git a/stress_benchmark/resources/034.settings b/stress_benchmark/resources/034.settings index 0ed9af0382..ab7970bc26 100644 --- a/stress_benchmark/resources/034.settings +++ b/stress_benchmark/resources/034.settings @@ -554,7 +554,9 @@ wipe_pause=0 material_standby_temperature=180 jerk_wall=8 machine_nozzle_cool_down_speed=2.0 -raft_margin=5 +raft_base_margin=5 +raft_interface_margin=5 +raft_surface_margin=5 raft_acceleration=500 support_roof_wall_count=0 raft_jerk=8 diff --git a/stress_benchmark/resources/035.settings b/stress_benchmark/resources/035.settings index 0106e70349..186d401196 100644 --- a/stress_benchmark/resources/035.settings +++ b/stress_benchmark/resources/035.settings @@ -556,7 +556,9 @@ wipe_pause=0 material_standby_temperature=180 jerk_wall=8 machine_nozzle_cool_down_speed=2.0 -raft_margin=15 +raft_base_margin=15 +raft_interface_margin=15 +raft_surface_margin=15 raft_acceleration=500 support_roof_wall_count=0 raft_jerk=8 diff --git a/stress_benchmark/resources/036.settings b/stress_benchmark/resources/036.settings index 496ddb57a3..c81e9a4567 100644 --- a/stress_benchmark/resources/036.settings +++ b/stress_benchmark/resources/036.settings @@ -555,7 +555,9 @@ wipe_pause=0 material_standby_temperature=180 jerk_wall=12.0 machine_nozzle_cool_down_speed=2.0 -raft_margin=15 +raft_base_margin=15 +raft_interface_margin=15 +raft_surface_margin=15 raft_acceleration=500 support_roof_wall_count=0 raft_jerk=12.0 diff --git a/stress_benchmark/resources/037.settings b/stress_benchmark/resources/037.settings index 4a40bf459b..3a1ca85c98 100644 --- a/stress_benchmark/resources/037.settings +++ b/stress_benchmark/resources/037.settings @@ -555,7 +555,9 @@ wipe_pause=0 material_standby_temperature=175 jerk_wall=8 machine_nozzle_cool_down_speed=2.0 -raft_margin=15 +raft_base_margin=15 +raft_interface_margin=15 +raft_surface_margin=15 raft_acceleration=350 support_roof_wall_count=0 raft_jerk=8 diff --git a/stress_benchmark/resources/038.settings b/stress_benchmark/resources/038.settings index 853b097d2d..789165b2a9 100644 --- a/stress_benchmark/resources/038.settings +++ b/stress_benchmark/resources/038.settings @@ -556,7 +556,9 @@ wipe_pause=0 material_standby_temperature=175 jerk_wall=8 machine_nozzle_cool_down_speed=2.0 -raft_margin=5.0 +raft_base_margin=5 +raft_interface_margin=5 +raft_surface_margin=5 raft_acceleration=500 support_roof_wall_count=0 raft_jerk=8 diff --git a/stress_benchmark/resources/039.settings b/stress_benchmark/resources/039.settings index 3810b98181..b8183c4b0d 100644 --- a/stress_benchmark/resources/039.settings +++ b/stress_benchmark/resources/039.settings @@ -556,7 +556,9 @@ wipe_pause=0 material_standby_temperature=180.0 jerk_wall=8 machine_nozzle_cool_down_speed=2.0 -raft_margin=15 +raft_base_margin=15 +raft_interface_margin=15 +raft_surface_margin=15 raft_acceleration=500 support_roof_wall_count=0 raft_jerk=8 diff --git a/stress_benchmark/resources/040.settings b/stress_benchmark/resources/040.settings index 9df0af97c1..f74194fa38 100644 --- a/stress_benchmark/resources/040.settings +++ b/stress_benchmark/resources/040.settings @@ -556,7 +556,9 @@ wipe_pause=0 material_standby_temperature=175 jerk_wall=20 machine_nozzle_cool_down_speed=2.0 -raft_margin=15 +raft_base_margin=15 +raft_interface_margin=15 +raft_surface_margin=15 raft_acceleration=3000 support_roof_wall_count=0 raft_jerk=20 diff --git a/stress_benchmark/resources/041.settings b/stress_benchmark/resources/041.settings index 6054309199..0f3eaf0020 100644 --- a/stress_benchmark/resources/041.settings +++ b/stress_benchmark/resources/041.settings @@ -559,7 +559,9 @@ wipe_pause=0 material_standby_temperature=180.0 jerk_wall=8 machine_nozzle_cool_down_speed=2.0 -raft_margin=15 +raft_base_margin=15 +raft_interface_margin=15 +raft_surface_margin=15 raft_acceleration=500 support_roof_wall_count=1 raft_jerk=8 diff --git a/stress_benchmark/resources/042.settings b/stress_benchmark/resources/042.settings index 91100ebe88..10f61fa229 100644 --- a/stress_benchmark/resources/042.settings +++ b/stress_benchmark/resources/042.settings @@ -557,7 +557,9 @@ wipe_pause=0 material_standby_temperature=175 jerk_wall=8 machine_nozzle_cool_down_speed=2.0 -raft_margin=15 +raft_base_margin=15 +raft_interface_margin=15 +raft_surface_margin=15 raft_acceleration=500 support_roof_wall_count=0 raft_jerk=8 diff --git a/stress_benchmark/resources/043.settings b/stress_benchmark/resources/043.settings index 6e142cc7e7..85b1c44f4f 100644 --- a/stress_benchmark/resources/043.settings +++ b/stress_benchmark/resources/043.settings @@ -558,7 +558,9 @@ wipe_pause=0 material_standby_temperature=100 jerk_wall=20 machine_nozzle_cool_down_speed=0.75 -raft_margin=15 +raft_base_margin=15 +raft_interface_margin=15 +raft_surface_margin=15 raft_acceleration=3500 support_roof_wall_count=1 raft_jerk=20 diff --git a/stress_benchmark/resources/044.settings b/stress_benchmark/resources/044.settings index db0ea47a59..05e2be11ef 100644 --- a/stress_benchmark/resources/044.settings +++ b/stress_benchmark/resources/044.settings @@ -558,7 +558,9 @@ wipe_pause=0 material_standby_temperature=100 jerk_wall=20 machine_nozzle_cool_down_speed=0.75 -raft_margin=15 +raft_base_margin=15 +raft_interface_margin=15 +raft_surface_margin=15 raft_acceleration=3500 support_roof_wall_count=1 raft_jerk=20 diff --git a/stress_benchmark/resources/045.settings b/stress_benchmark/resources/045.settings index c93fd544aa..601a64d4c9 100644 --- a/stress_benchmark/resources/045.settings +++ b/stress_benchmark/resources/045.settings @@ -558,7 +558,9 @@ wipe_pause=0 material_standby_temperature=175 jerk_wall=20 machine_nozzle_cool_down_speed=2.0 -raft_margin=15 +raft_base_margin=15 +raft_interface_margin=15 +raft_surface_margin=15 raft_acceleration=3000 support_roof_wall_count=0 raft_jerk=20 diff --git a/stress_benchmark/resources/046.settings b/stress_benchmark/resources/046.settings index 2ebb338bdb..ba6d8b93b2 100644 --- a/stress_benchmark/resources/046.settings +++ b/stress_benchmark/resources/046.settings @@ -557,7 +557,9 @@ wipe_pause=0 material_standby_temperature=175 jerk_wall=5 machine_nozzle_cool_down_speed=2.0 -raft_margin=15 +raft_base_margin=15 +raft_interface_margin=15 +raft_surface_margin=15 raft_acceleration=1500 support_roof_wall_count=0 raft_jerk=5 diff --git a/stress_benchmark/resources/047.settings b/stress_benchmark/resources/047.settings index 49e632dc16..c1439409f0 100644 --- a/stress_benchmark/resources/047.settings +++ b/stress_benchmark/resources/047.settings @@ -557,7 +557,9 @@ wipe_pause=0 material_standby_temperature=175 jerk_wall=8 machine_nozzle_cool_down_speed=2.0 -raft_margin=15 +raft_base_margin=15 +raft_interface_margin=15 +raft_surface_margin=15 raft_acceleration=1800 support_roof_wall_count=0 raft_jerk=8 diff --git a/stress_benchmark/resources/048.settings b/stress_benchmark/resources/048.settings index 73eacc8380..62bc6888fa 100644 --- a/stress_benchmark/resources/048.settings +++ b/stress_benchmark/resources/048.settings @@ -555,7 +555,9 @@ wipe_pause=0 material_standby_temperature=180 jerk_wall=8 machine_nozzle_cool_down_speed=2.0 -raft_margin=15 +raft_base_margin=15 +raft_interface_margin=15 +raft_surface_margin=15 raft_acceleration=500 support_roof_wall_count=0 raft_jerk=8 diff --git a/stress_benchmark/resources/049.settings b/stress_benchmark/resources/049.settings index 8a534c14c4..4b0f97c5cc 100644 --- a/stress_benchmark/resources/049.settings +++ b/stress_benchmark/resources/049.settings @@ -67,7 +67,9 @@ material_initial_print_temperature=205.0 layer_0_z_overlap=0.15 support_roof_enable=True acceleration_wall_x_roofing=500 -raft_margin=15 +raft_base_margin=15 +raft_interface_margin=15 +raft_surface_margin=15 support_tree_branch_diameter_angle=7 prime_tower_base_height=0.12 machine_nozzle_head_distance=3 diff --git a/stress_benchmark/resources/050.settings b/stress_benchmark/resources/050.settings index bee0e8f4ce..f1fa5a28e8 100644 --- a/stress_benchmark/resources/050.settings +++ b/stress_benchmark/resources/050.settings @@ -67,7 +67,9 @@ material_initial_print_temperature=220 layer_0_z_overlap=0.15 support_roof_enable=False acceleration_wall_x_roofing=1000 -raft_margin=15 +raft_base_margin=15 +raft_interface_margin=15 +raft_surface_margin=15 support_tree_branch_diameter_angle=7 prime_tower_base_height=0.2 machine_nozzle_head_distance=3 diff --git a/stress_benchmark/resources/051.settings b/stress_benchmark/resources/051.settings index fd55479c67..1d7a79f521 100644 --- a/stress_benchmark/resources/051.settings +++ b/stress_benchmark/resources/051.settings @@ -67,7 +67,9 @@ material_initial_print_temperature=210.0 layer_0_z_overlap=0.15 support_roof_enable=True acceleration_wall_x_roofing=400.0 -raft_margin=0 +raft_base_margin=0 +raft_interface_margin=0 +raft_surface_margin=0 support_tree_branch_diameter_angle=7 prime_tower_base_height=0.12 machine_nozzle_head_distance=3 diff --git a/stress_benchmark/resources/052.settings b/stress_benchmark/resources/052.settings index 629a0a2715..c46d63e5e4 100644 --- a/stress_benchmark/resources/052.settings +++ b/stress_benchmark/resources/052.settings @@ -67,7 +67,9 @@ material_initial_print_temperature=200 layer_0_z_overlap=0.15 support_roof_enable=False acceleration_wall_x_roofing=500 -raft_margin=5 +raft_base_margin=5 +raft_interface_margin=5 +raft_surface_margin=5 support_tree_branch_diameter_angle=7 prime_tower_base_height=0.28 machine_nozzle_head_distance=3 diff --git a/stress_benchmark/resources/053.settings b/stress_benchmark/resources/053.settings index 5f59343201..2e5e59b2b3 100644 --- a/stress_benchmark/resources/053.settings +++ b/stress_benchmark/resources/053.settings @@ -67,7 +67,9 @@ material_initial_print_temperature=190 layer_0_z_overlap=0.15 support_roof_enable=False acceleration_wall_x_roofing=3000 -raft_margin=15 +raft_base_margin=15 +raft_interface_margin=15 +raft_surface_margin=15 support_tree_branch_diameter_angle=7 prime_tower_base_height=0.1 machine_nozzle_head_distance=5 diff --git a/stress_benchmark/resources/054.settings b/stress_benchmark/resources/054.settings index 41766d28d4..ed5709fe6d 100644 --- a/stress_benchmark/resources/054.settings +++ b/stress_benchmark/resources/054.settings @@ -67,7 +67,9 @@ material_initial_print_temperature=225.0 layer_0_z_overlap=0.15 support_roof_enable=False acceleration_wall_x_roofing=1800 -raft_margin=15 +raft_base_margin=15 +raft_interface_margin=15 +raft_surface_margin=15 support_tree_branch_diameter_angle=7 prime_tower_base_height=0.2 machine_nozzle_head_distance=3 diff --git a/stress_benchmark/resources/055.settings b/stress_benchmark/resources/055.settings index d4d7856ea3..14025ad607 100644 --- a/stress_benchmark/resources/055.settings +++ b/stress_benchmark/resources/055.settings @@ -67,7 +67,9 @@ material_initial_print_temperature=190 layer_0_z_overlap=0.15 support_roof_enable=False acceleration_wall_x_roofing=3000 -raft_margin=15 +raft_base_margin=15 +raft_interface_margin=15 +raft_surface_margin=15 support_tree_branch_diameter_angle=7 prime_tower_base_height=0.2 machine_nozzle_head_distance=3 diff --git a/stress_benchmark/resources/056.settings b/stress_benchmark/resources/056.settings index ae77715c21..427a32768d 100644 --- a/stress_benchmark/resources/056.settings +++ b/stress_benchmark/resources/056.settings @@ -67,7 +67,9 @@ material_initial_print_temperature=180 layer_0_z_overlap=0.15 support_roof_enable=True acceleration_wall_x_roofing=3000 -raft_margin=15 +raft_base_margin=15 +raft_interface_margin=15 +raft_surface_margin=15 support_tree_branch_diameter_angle=7 prime_tower_base_height=0.1 machine_nozzle_head_distance=3 diff --git a/stress_benchmark/resources/057.settings b/stress_benchmark/resources/057.settings index e69a30998b..22c8b9dd7b 100644 --- a/stress_benchmark/resources/057.settings +++ b/stress_benchmark/resources/057.settings @@ -67,7 +67,9 @@ material_initial_print_temperature=183 layer_0_z_overlap=0.15 support_roof_enable=True acceleration_wall_x_roofing=500 -raft_margin=15 +raft_base_margin=15 +raft_interface_margin=15 +raft_surface_margin=15 support_tree_branch_diameter_angle=7 prime_tower_base_height=0.5 machine_nozzle_head_distance=3 diff --git a/stress_benchmark/resources/058.settings b/stress_benchmark/resources/058.settings index 146ed80f11..7562c7a7bd 100644 --- a/stress_benchmark/resources/058.settings +++ b/stress_benchmark/resources/058.settings @@ -67,7 +67,9 @@ material_initial_print_temperature=200 layer_0_z_overlap=0.15 support_roof_enable=True acceleration_wall_x_roofing=500 -raft_margin=15 +raft_base_margin=15 +raft_interface_margin=15 +raft_surface_margin=15 support_tree_branch_diameter_angle=7 prime_tower_base_height=0.12 machine_nozzle_head_distance=3 diff --git a/stress_benchmark/resources/059.settings b/stress_benchmark/resources/059.settings index 878cc7f8b5..c8c547a1de 100644 --- a/stress_benchmark/resources/059.settings +++ b/stress_benchmark/resources/059.settings @@ -221,7 +221,9 @@ acceleration_support_bottom=500 bridge_skin_density=100 raft_airgap=0.3 mold_angle=40 -raft_margin=15 +raft_base_margin=15 +raft_interface_margin=15 +raft_surface_margin=15 speed_print_layer_0=25 hole_xy_offset_max_diameter=0 cool_fan_full_layer=2 diff --git a/stress_benchmark/resources/060.settings b/stress_benchmark/resources/060.settings index 9fd982aca1..afff41c33d 100644 --- a/stress_benchmark/resources/060.settings +++ b/stress_benchmark/resources/060.settings @@ -221,7 +221,9 @@ acceleration_support_bottom=500 bridge_skin_density=100 raft_airgap=0.3 mold_angle=40 -raft_margin=15 +raft_base_margin=15 +raft_interface_margin=15 +raft_surface_margin=15 speed_print_layer_0=20.0 hole_xy_offset_max_diameter=0 cool_fan_full_layer=4 diff --git a/stress_benchmark/resources/061.settings b/stress_benchmark/resources/061.settings index 3a05b93091..18d0f316fd 100644 --- a/stress_benchmark/resources/061.settings +++ b/stress_benchmark/resources/061.settings @@ -222,7 +222,9 @@ bridge_skin_density=100 raft_airgap=0.3 mold_angle=40 quality_name=Draft -raft_margin=15 +raft_base_margin=15 +raft_interface_margin=15 +raft_surface_margin=15 speed_print_layer_0=10.0 hole_xy_offset_max_diameter=0 cool_fan_full_layer=2 diff --git a/stress_benchmark/resources/062.settings b/stress_benchmark/resources/062.settings index d6c59d5fec..96d4a28dd1 100644 --- a/stress_benchmark/resources/062.settings +++ b/stress_benchmark/resources/062.settings @@ -221,7 +221,9 @@ acceleration_support_bottom=3000 bridge_skin_density=100 raft_airgap=0.3 mold_angle=40 -raft_margin=15 +raft_base_margin=15 +raft_interface_margin=15 +raft_surface_margin=15 speed_print_layer_0=30.0 hole_xy_offset_max_diameter=0 cool_fan_full_layer=2 diff --git a/stress_benchmark/resources/063.settings b/stress_benchmark/resources/063.settings index 4757dbfedc..d300bfc633 100644 --- a/stress_benchmark/resources/063.settings +++ b/stress_benchmark/resources/063.settings @@ -222,7 +222,9 @@ bridge_skin_density=100 raft_airgap=0.3 mold_angle=40 quality_name=Draft -raft_margin=15 +raft_base_margin=15 +raft_interface_margin=15 +raft_surface_margin=15 speed_print_layer_0=75.0 hole_xy_offset_max_diameter=0 cool_fan_full_layer=2 diff --git a/stress_benchmark/resources/064.settings b/stress_benchmark/resources/064.settings index ad14e390a1..1739abbb7e 100644 --- a/stress_benchmark/resources/064.settings +++ b/stress_benchmark/resources/064.settings @@ -220,7 +220,9 @@ acceleration_support_bottom=400 bridge_skin_density=100 raft_airgap=0.3 mold_angle=40 -raft_margin=15 +raft_base_margin=15 +raft_interface_margin=15 +raft_surface_margin=15 speed_print_layer_0=10 hole_xy_offset_max_diameter=0 cool_fan_full_layer=45 diff --git a/stress_benchmark/resources/065.settings b/stress_benchmark/resources/065.settings index e82e8ae600..a32ec18ddb 100644 --- a/stress_benchmark/resources/065.settings +++ b/stress_benchmark/resources/065.settings @@ -223,7 +223,9 @@ bridge_skin_density=80 raft_airgap=0 mold_angle=40 quality_name=Fine -raft_margin=15 +raft_base_margin=15 +raft_interface_margin=15 +raft_surface_margin=15 speed_print_layer_0=10.0 roofing_angles=[] hole_xy_offset_max_diameter=0 diff --git a/stress_benchmark/resources/066.settings b/stress_benchmark/resources/066.settings index 3b324482ff..9a50e01066 100644 --- a/stress_benchmark/resources/066.settings +++ b/stress_benchmark/resources/066.settings @@ -223,7 +223,9 @@ bridge_skin_density=80 raft_airgap=0.3 mold_angle=40 quality_name=Fine -raft_margin=15 +raft_base_margin=15 +raft_interface_margin=15 +raft_surface_margin=15 speed_print_layer_0=16.0 roofing_angles=[] hole_xy_offset_max_diameter=0 diff --git a/stress_benchmark/resources/067.settings b/stress_benchmark/resources/067.settings index 8fead7495b..f0aaccedf9 100644 --- a/stress_benchmark/resources/067.settings +++ b/stress_benchmark/resources/067.settings @@ -221,7 +221,9 @@ acceleration_support_bottom=500.0 bridge_skin_density=100 raft_airgap=0.3 mold_angle=40 -raft_margin=15 +raft_base_margin=15 +raft_interface_margin=15 +raft_surface_margin=15 speed_print_layer_0=25 roofing_angles=[45,135] hole_xy_offset_max_diameter=0 diff --git a/tests/test_global_settings.txt b/tests/test_global_settings.txt index cb0c373c6a..7861bc4139 100644 --- a/tests/test_global_settings.txt +++ b/tests/test_global_settings.txt @@ -260,7 +260,9 @@ jerk_ironing=5 retraction_combing_max_distance=0 acceleration_layer_0=500 coasting_min_volume=0.8 -raft_margin=15 +raft_base_margin=15 +raft_interface_margin=15 +raft_surface_margin=15 support_tower_diameter=3.0 cool_fan_speed_max=100 machine_endstop_positive_direction_x=False From 211c7a9138b0e0054d74bccfb309fc216cde5640 Mon Sep 17 00:00:00 2001 From: "c.lamboo" Date: Mon, 8 Jan 2024 14:49:34 +0100 Subject: [PATCH 039/201] Make remove inside corners configurable per raft type CURA-11395 --- src/raft.cpp | 27 +++++++++++++++++++------ stress_benchmark/resources/001.settings | 4 +++- stress_benchmark/resources/002.settings | 4 +++- stress_benchmark/resources/003.settings | 4 +++- stress_benchmark/resources/004.settings | 4 +++- stress_benchmark/resources/005.settings | 4 +++- stress_benchmark/resources/006.settings | 4 +++- stress_benchmark/resources/007.settings | 4 +++- stress_benchmark/resources/008.settings | 4 +++- stress_benchmark/resources/009.settings | 4 +++- stress_benchmark/resources/010.settings | 4 +++- stress_benchmark/resources/011.settings | 4 +++- stress_benchmark/resources/012.settings | 4 +++- stress_benchmark/resources/013.settings | 4 +++- stress_benchmark/resources/014.settings | 4 +++- stress_benchmark/resources/015.settings | 4 +++- stress_benchmark/resources/016.settings | 4 +++- stress_benchmark/resources/017.settings | 4 +++- stress_benchmark/resources/018.settings | 4 +++- stress_benchmark/resources/019.settings | 4 +++- stress_benchmark/resources/020.settings | 4 +++- stress_benchmark/resources/021.settings | 4 +++- stress_benchmark/resources/022.settings | 4 +++- stress_benchmark/resources/023.settings | 4 +++- stress_benchmark/resources/024.settings | 4 +++- stress_benchmark/resources/025.settings | 4 +++- stress_benchmark/resources/026.settings | 4 +++- stress_benchmark/resources/027.settings | 4 +++- stress_benchmark/resources/028.settings | 4 +++- stress_benchmark/resources/029.settings | 4 +++- stress_benchmark/resources/030.settings | 4 +++- stress_benchmark/resources/031.settings | 4 +++- stress_benchmark/resources/032.settings | 4 +++- stress_benchmark/resources/033.settings | 4 +++- stress_benchmark/resources/034.settings | 4 +++- stress_benchmark/resources/035.settings | 4 +++- stress_benchmark/resources/036.settings | 4 +++- stress_benchmark/resources/037.settings | 4 +++- stress_benchmark/resources/038.settings | 4 +++- stress_benchmark/resources/039.settings | 4 +++- stress_benchmark/resources/040.settings | 4 +++- stress_benchmark/resources/041.settings | 4 +++- stress_benchmark/resources/042.settings | 4 +++- stress_benchmark/resources/043.settings | 4 +++- stress_benchmark/resources/044.settings | 4 +++- stress_benchmark/resources/045.settings | 4 +++- stress_benchmark/resources/046.settings | 4 +++- stress_benchmark/resources/047.settings | 4 +++- stress_benchmark/resources/048.settings | 4 +++- stress_benchmark/resources/049.settings | 4 +++- stress_benchmark/resources/050.settings | 4 +++- stress_benchmark/resources/051.settings | 4 +++- stress_benchmark/resources/052.settings | 4 +++- stress_benchmark/resources/053.settings | 4 +++- stress_benchmark/resources/054.settings | 4 +++- stress_benchmark/resources/055.settings | 4 +++- stress_benchmark/resources/056.settings | 4 +++- stress_benchmark/resources/057.settings | 4 +++- stress_benchmark/resources/058.settings | 4 +++- stress_benchmark/resources/059.settings | 4 +++- stress_benchmark/resources/060.settings | 4 +++- stress_benchmark/resources/061.settings | 4 +++- stress_benchmark/resources/062.settings | 4 +++- stress_benchmark/resources/063.settings | 4 +++- stress_benchmark/resources/064.settings | 4 +++- stress_benchmark/resources/065.settings | 4 +++- stress_benchmark/resources/066.settings | 4 +++- stress_benchmark/resources/067.settings | 4 +++- 68 files changed, 222 insertions(+), 73 deletions(-) diff --git a/src/raft.cpp b/src/raft.cpp index b42e3e2491..c299b79061 100644 --- a/src/raft.cpp +++ b/src/raft.cpp @@ -50,21 +50,36 @@ void Raft::generate(SliceDataStorage& storage) storage.raftInterfaceOutline = storage.raftInterfaceOutline.unionPolygons(ooze_shield_raft); } - if (settings.get("raft_remove_inside_corners")) + if (settings.get("raft_base_remove_inside_corners")) { storage.raftBaseOutline.makeConvex(); - storage.raftSurfaceOutline.makeConvex(); - storage.raftInterfaceOutline.makeConvex(); } else { - const coord_t smoothing = settings.get("raft_smoothing"); - // remove small holes and smooth inward corners + const coord_t smoothing = settings.get("raft_base_smoothing"); storage.raftBaseOutline = storage.raftBaseOutline.offset(smoothing, ClipperLib::jtRound).offset(-smoothing, ClipperLib::jtRound); - storage.raftSurfaceOutline = storage.raftSurfaceOutline.offset(smoothing, ClipperLib::jtRound).offset(-smoothing, ClipperLib::jtRound); + } + + if (settings.get("raft_interface_remove_inside_corners")) + { + storage.raftInterfaceOutline.makeConvex(); + } + else + { + const coord_t smoothing = settings.get("raft_interface_smoothing"); storage.raftInterfaceOutline = storage.raftInterfaceOutline.offset(smoothing, ClipperLib::jtRound).offset(-smoothing, ClipperLib::jtRound); } + if (settings.get("raft_surface_remove_inside_corners")) + { + storage.raftSurfaceOutline.makeConvex(); + } + else + { + const coord_t smoothing = settings.get("raft_surface_smoothing"); + storage.raftSurfaceOutline = storage.raftSurfaceOutline.offset(smoothing, ClipperLib::jtRound).offset(-smoothing, ClipperLib::jtRound); + } + if (storage.primeTower.enabled_ && ! storage.primeTower.would_have_actual_tower_) { // Find out if the prime-tower part of the raft still needs to be printed, even if there is no actual tower. diff --git a/stress_benchmark/resources/001.settings b/stress_benchmark/resources/001.settings index d72d076797..71ee472bd9 100644 --- a/stress_benchmark/resources/001.settings +++ b/stress_benchmark/resources/001.settings @@ -271,7 +271,9 @@ infill_mesh_order=0 retraction_prime_speed=5 z_seam_type=sharpest_corner ironing_only_highest_layer=False -raft_remove_inside_corners=False +raft_base_remove_inside_corners=False +raft_interface_remove_inside_corners=False +raft_surface_remove_inside_corners=False acceleration_topbottom=300 machine_settings=0 travel_retract_before_outer_wall=False diff --git a/stress_benchmark/resources/002.settings b/stress_benchmark/resources/002.settings index c9dfb14cc0..c63aba30f3 100644 --- a/stress_benchmark/resources/002.settings +++ b/stress_benchmark/resources/002.settings @@ -598,7 +598,9 @@ support_bottom_wall_count=0 jerk_wall_x=8 draft_shield_height_limitation=full bridge_sparse_infill_max_density=0 -raft_remove_inside_corners=False +raft_base_remove_inside_corners=False +raft_interface_remove_inside_corners=False +raft_surface_remove_inside_corners=False ironing_only_highest_layer=False cooling=0 infill_support_angle=40 diff --git a/stress_benchmark/resources/003.settings b/stress_benchmark/resources/003.settings index b6aa5b0d7a..1a0de365f5 100644 --- a/stress_benchmark/resources/003.settings +++ b/stress_benchmark/resources/003.settings @@ -599,7 +599,9 @@ support_bottom_wall_count=0 jerk_wall_x=8 draft_shield_height_limitation=full bridge_sparse_infill_max_density=0 -raft_remove_inside_corners=False +raft_base_remove_inside_corners=False +raft_interface_remove_inside_corners=False +raft_surface_remove_inside_corners=False ironing_only_highest_layer=False cooling=0 infill_support_angle=40 diff --git a/stress_benchmark/resources/004.settings b/stress_benchmark/resources/004.settings index a4c2afe92e..74603b80f0 100644 --- a/stress_benchmark/resources/004.settings +++ b/stress_benchmark/resources/004.settings @@ -599,7 +599,9 @@ support_bottom_wall_count=0 jerk_wall_x=8 draft_shield_height_limitation=full bridge_sparse_infill_max_density=0 -raft_remove_inside_corners=False +raft_base_remove_inside_corners=False +raft_interface_remove_inside_corners=False +raft_surface_remove_inside_corners=False ironing_only_highest_layer=False cooling=0 infill_support_angle=40 diff --git a/stress_benchmark/resources/005.settings b/stress_benchmark/resources/005.settings index f54b1d867c..4352f108a2 100644 --- a/stress_benchmark/resources/005.settings +++ b/stress_benchmark/resources/005.settings @@ -600,7 +600,9 @@ support_bottom_wall_count=0 jerk_wall_x=8 draft_shield_height_limitation=full bridge_sparse_infill_max_density=0 -raft_remove_inside_corners=False +raft_base_remove_inside_corners=False +raft_interface_remove_inside_corners=False +raft_surface_remove_inside_corners=False ironing_only_highest_layer=False cooling=0 infill_support_angle=40 diff --git a/stress_benchmark/resources/006.settings b/stress_benchmark/resources/006.settings index 956d6691a6..9a94d8f6da 100644 --- a/stress_benchmark/resources/006.settings +++ b/stress_benchmark/resources/006.settings @@ -600,7 +600,9 @@ support_bottom_wall_count=0 jerk_wall_x=8 draft_shield_height_limitation=full bridge_sparse_infill_max_density=0 -raft_remove_inside_corners=False +raft_base_remove_inside_corners=False +raft_interface_remove_inside_corners=False +raft_surface_remove_inside_corners=False ironing_only_highest_layer=False cooling=0 infill_support_angle=40 diff --git a/stress_benchmark/resources/007.settings b/stress_benchmark/resources/007.settings index 424a7b4afa..4e98a3d2e7 100644 --- a/stress_benchmark/resources/007.settings +++ b/stress_benchmark/resources/007.settings @@ -600,7 +600,9 @@ support_bottom_wall_count=0 jerk_wall_x=8 draft_shield_height_limitation=full bridge_sparse_infill_max_density=0 -raft_remove_inside_corners=False +raft_base_remove_inside_corners=False +raft_interface_remove_inside_corners=False +raft_surface_remove_inside_corners=False ironing_only_highest_layer=False cooling=0 infill_support_angle=40 diff --git a/stress_benchmark/resources/008.settings b/stress_benchmark/resources/008.settings index cfcd6b234c..b4aca3d5ff 100644 --- a/stress_benchmark/resources/008.settings +++ b/stress_benchmark/resources/008.settings @@ -347,7 +347,9 @@ wall_0_material_flow=100 meshfix_maximum_extrusion_area_deviation=50000 wall_0_wipe_dist=0.2 ironing_only_highest_layer=False -raft_remove_inside_corners=False +raft_base_remove_inside_corners=False +raft_interface_remove_inside_corners=False +raft_surface_remove_inside_corners=False machine_max_feedrate_e=45 prime_tower_line_width=0.4 wall_line_width_x=0.4 diff --git a/stress_benchmark/resources/009.settings b/stress_benchmark/resources/009.settings index cfcd6b234c..b4aca3d5ff 100644 --- a/stress_benchmark/resources/009.settings +++ b/stress_benchmark/resources/009.settings @@ -347,7 +347,9 @@ wall_0_material_flow=100 meshfix_maximum_extrusion_area_deviation=50000 wall_0_wipe_dist=0.2 ironing_only_highest_layer=False -raft_remove_inside_corners=False +raft_base_remove_inside_corners=False +raft_interface_remove_inside_corners=False +raft_surface_remove_inside_corners=False machine_max_feedrate_e=45 prime_tower_line_width=0.4 wall_line_width_x=0.4 diff --git a/stress_benchmark/resources/010.settings b/stress_benchmark/resources/010.settings index cfcd6b234c..b4aca3d5ff 100644 --- a/stress_benchmark/resources/010.settings +++ b/stress_benchmark/resources/010.settings @@ -347,7 +347,9 @@ wall_0_material_flow=100 meshfix_maximum_extrusion_area_deviation=50000 wall_0_wipe_dist=0.2 ironing_only_highest_layer=False -raft_remove_inside_corners=False +raft_base_remove_inside_corners=False +raft_interface_remove_inside_corners=False +raft_surface_remove_inside_corners=False machine_max_feedrate_e=45 prime_tower_line_width=0.4 wall_line_width_x=0.4 diff --git a/stress_benchmark/resources/011.settings b/stress_benchmark/resources/011.settings index 08b6ec47db..c789ab5a63 100644 --- a/stress_benchmark/resources/011.settings +++ b/stress_benchmark/resources/011.settings @@ -601,7 +601,9 @@ support_bottom_wall_count=0 jerk_wall_x=20 draft_shield_height_limitation=full bridge_sparse_infill_max_density=0 -raft_remove_inside_corners=False +raft_base_remove_inside_corners=False +raft_interface_remove_inside_corners=False +raft_surface_remove_inside_corners=False ironing_only_highest_layer=False cooling=0 infill_support_angle=40 diff --git a/stress_benchmark/resources/012.settings b/stress_benchmark/resources/012.settings index 521724273d..db4584485c 100644 --- a/stress_benchmark/resources/012.settings +++ b/stress_benchmark/resources/012.settings @@ -590,7 +590,9 @@ jerk_infill=12.5 draft_shield_height_limitation=full layer_height_0=0.2 jerk_print=12.5 -raft_remove_inside_corners=False +raft_base_remove_inside_corners=False +raft_interface_remove_inside_corners=False +raft_surface_remove_inside_corners=False support_pattern=lines infill_support_angle=40 raft_base_acceleration=300 diff --git a/stress_benchmark/resources/013.settings b/stress_benchmark/resources/013.settings index 311beb6893..692c6164cc 100644 --- a/stress_benchmark/resources/013.settings +++ b/stress_benchmark/resources/013.settings @@ -214,7 +214,9 @@ support_interface_line_width=0.4 support_skip_zag_per_mm=20 support_angle=55 raft_base_speed=16.875 -raft_remove_inside_corners=False +raft_base_remove_inside_corners=False +raft_interface_remove_inside_corners=False +raft_surface_remove_inside_corners=False ironing_only_highest_layer=False roofing_line_width=0.4 hole_xy_offset=0 diff --git a/stress_benchmark/resources/014.settings b/stress_benchmark/resources/014.settings index 93487b5295..77d3f128f7 100644 --- a/stress_benchmark/resources/014.settings +++ b/stress_benchmark/resources/014.settings @@ -214,7 +214,9 @@ support_interface_line_width=0.4 support_skip_zag_per_mm=20 support_angle=50 raft_base_speed=30.0 -raft_remove_inside_corners=False +raft_base_remove_inside_corners=False +raft_interface_remove_inside_corners=False +raft_surface_remove_inside_corners=False ironing_only_highest_layer=False roofing_line_width=0.4 hole_xy_offset=0 diff --git a/stress_benchmark/resources/015.settings b/stress_benchmark/resources/015.settings index 1159c55eba..55af6339c5 100644 --- a/stress_benchmark/resources/015.settings +++ b/stress_benchmark/resources/015.settings @@ -214,7 +214,9 @@ support_interface_line_width=0.4 support_skip_zag_per_mm=20 support_angle=0 raft_base_speed=37.5 -raft_remove_inside_corners=False +raft_base_remove_inside_corners=False +raft_interface_remove_inside_corners=False +raft_surface_remove_inside_corners=False ironing_only_highest_layer=False roofing_line_width=0.4 hole_xy_offset=0 diff --git a/stress_benchmark/resources/016.settings b/stress_benchmark/resources/016.settings index de11857273..fed8689b55 100644 --- a/stress_benchmark/resources/016.settings +++ b/stress_benchmark/resources/016.settings @@ -214,7 +214,9 @@ support_interface_line_width=0.4 support_skip_zag_per_mm=20 support_angle=45 raft_base_speed=18.75 -raft_remove_inside_corners=False +raft_base_remove_inside_corners=False +raft_interface_remove_inside_corners=False +raft_surface_remove_inside_corners=False ironing_only_highest_layer=False roofing_line_width=0.4 hole_xy_offset=0 diff --git a/stress_benchmark/resources/017.settings b/stress_benchmark/resources/017.settings index 76a4b98128..d63440f363 100644 --- a/stress_benchmark/resources/017.settings +++ b/stress_benchmark/resources/017.settings @@ -214,7 +214,9 @@ support_interface_line_width=0.42 support_skip_zag_per_mm=20 support_angle=40 raft_base_speed=18.75 -raft_remove_inside_corners=False +raft_base_remove_inside_corners=False +raft_interface_remove_inside_corners=False +raft_surface_remove_inside_corners=False ironing_only_highest_layer=False roofing_line_width=0.38 hole_xy_offset=0 diff --git a/stress_benchmark/resources/018.settings b/stress_benchmark/resources/018.settings index 4c6b5a3bf1..64168b1780 100644 --- a/stress_benchmark/resources/018.settings +++ b/stress_benchmark/resources/018.settings @@ -214,7 +214,9 @@ support_interface_line_width=0.4 support_skip_zag_per_mm=20 support_angle=65.0 raft_base_speed=18.75 -raft_remove_inside_corners=False +raft_base_remove_inside_corners=False +raft_interface_remove_inside_corners=False +raft_surface_remove_inside_corners=False ironing_only_highest_layer=False roofing_line_width=0.4 hole_xy_offset=0 diff --git a/stress_benchmark/resources/019.settings b/stress_benchmark/resources/019.settings index 443bd2d9a1..e1a9b826ee 100644 --- a/stress_benchmark/resources/019.settings +++ b/stress_benchmark/resources/019.settings @@ -214,7 +214,9 @@ support_interface_line_width=0.4 support_skip_zag_per_mm=20 support_angle=45 raft_base_speed=30.0 -raft_remove_inside_corners=False +raft_base_remove_inside_corners=False +raft_interface_remove_inside_corners=False +raft_surface_remove_inside_corners=False ironing_only_highest_layer=False roofing_line_width=0.4 hole_xy_offset=0 diff --git a/stress_benchmark/resources/020.settings b/stress_benchmark/resources/020.settings index d96be4bd5a..a38b801b56 100644 --- a/stress_benchmark/resources/020.settings +++ b/stress_benchmark/resources/020.settings @@ -214,7 +214,9 @@ support_interface_line_width=0.8 support_skip_zag_per_mm=20 support_angle=55 raft_base_speed=30.0 -raft_remove_inside_corners=False +raft_base_remove_inside_corners=False +raft_interface_remove_inside_corners=False +raft_surface_remove_inside_corners=False ironing_only_highest_layer=False roofing_line_width=0.8 hole_xy_offset=0 diff --git a/stress_benchmark/resources/021.settings b/stress_benchmark/resources/021.settings index 802d2c4733..8f09ee7382 100644 --- a/stress_benchmark/resources/021.settings +++ b/stress_benchmark/resources/021.settings @@ -215,7 +215,9 @@ support_interface_line_width=0.4 support_skip_zag_per_mm=20 support_angle=60 raft_base_speed=15 -raft_remove_inside_corners=False +raft_base_remove_inside_corners=False +raft_interface_remove_inside_corners=False +raft_surface_remove_inside_corners=False ironing_only_highest_layer=False roofing_line_width=0.4 hole_xy_offset=0 diff --git a/stress_benchmark/resources/022.settings b/stress_benchmark/resources/022.settings index 1384179d85..ca4041d688 100644 --- a/stress_benchmark/resources/022.settings +++ b/stress_benchmark/resources/022.settings @@ -214,7 +214,9 @@ support_interface_line_width=0.42000000000000004 support_skip_zag_per_mm=20 support_angle=50 raft_base_speed=12.0 -raft_remove_inside_corners=False +raft_base_remove_inside_corners=False +raft_interface_remove_inside_corners=False +raft_surface_remove_inside_corners=False ironing_only_highest_layer=False roofing_line_width=0.42000000000000004 hole_xy_offset=0 diff --git a/stress_benchmark/resources/023.settings b/stress_benchmark/resources/023.settings index 2313a61291..c630167843 100644 --- a/stress_benchmark/resources/023.settings +++ b/stress_benchmark/resources/023.settings @@ -214,7 +214,9 @@ support_interface_line_width=0.44 support_skip_zag_per_mm=20 support_angle=50 raft_base_speed=56.25 -raft_remove_inside_corners=False +raft_base_remove_inside_corners=False +raft_interface_remove_inside_corners=False +raft_surface_remove_inside_corners=False ironing_only_highest_layer=True roofing_line_width=0.44 hole_xy_offset=0 diff --git a/stress_benchmark/resources/024.settings b/stress_benchmark/resources/024.settings index 15d687c588..4ccc228f0e 100644 --- a/stress_benchmark/resources/024.settings +++ b/stress_benchmark/resources/024.settings @@ -215,7 +215,9 @@ support_interface_line_width=0.4 support_skip_zag_per_mm=20 support_angle=45 raft_base_speed=26.25 -raft_remove_inside_corners=False +raft_base_remove_inside_corners=False +raft_interface_remove_inside_corners=False +raft_surface_remove_inside_corners=False ironing_only_highest_layer=False roofing_line_width=0.4 hole_xy_offset=0 diff --git a/stress_benchmark/resources/025.settings b/stress_benchmark/resources/025.settings index 60b63ed7ab..70275e935e 100644 --- a/stress_benchmark/resources/025.settings +++ b/stress_benchmark/resources/025.settings @@ -214,7 +214,9 @@ support_interface_line_width=0.4 support_skip_zag_per_mm=20 support_angle=50 raft_base_speed=22.5 -raft_remove_inside_corners=False +raft_base_remove_inside_corners=False +raft_interface_remove_inside_corners=False +raft_surface_remove_inside_corners=False ironing_only_highest_layer=False roofing_line_width=0.4 hole_xy_offset=0 diff --git a/stress_benchmark/resources/026.settings b/stress_benchmark/resources/026.settings index 92acf19566..83110138e7 100644 --- a/stress_benchmark/resources/026.settings +++ b/stress_benchmark/resources/026.settings @@ -215,7 +215,9 @@ support_interface_line_width=0.4 support_skip_zag_per_mm=20 support_angle=45 raft_base_speed=15 -raft_remove_inside_corners=False +raft_base_remove_inside_corners=False +raft_interface_remove_inside_corners=False +raft_surface_remove_inside_corners=False ironing_only_highest_layer=False roofing_line_width=0.4 hole_xy_offset=0 diff --git a/stress_benchmark/resources/027.settings b/stress_benchmark/resources/027.settings index 8617f7f696..6dccc78fad 100644 --- a/stress_benchmark/resources/027.settings +++ b/stress_benchmark/resources/027.settings @@ -215,7 +215,9 @@ support_interface_line_width=0.4 support_skip_zag_per_mm=20 support_angle=45 raft_base_speed=15 -raft_remove_inside_corners=False +raft_base_remove_inside_corners=False +raft_interface_remove_inside_corners=False +raft_surface_remove_inside_corners=False ironing_only_highest_layer=False roofing_line_width=0.4 hole_xy_offset=0 diff --git a/stress_benchmark/resources/028.settings b/stress_benchmark/resources/028.settings index 0ffc6d9b51..7e1d34e6f2 100644 --- a/stress_benchmark/resources/028.settings +++ b/stress_benchmark/resources/028.settings @@ -214,7 +214,9 @@ support_interface_line_width=0.4 support_skip_zag_per_mm=20 support_angle=50 raft_base_speed=22.5 -raft_remove_inside_corners=False +raft_base_remove_inside_corners=False +raft_interface_remove_inside_corners=False +raft_surface_remove_inside_corners=False ironing_only_highest_layer=False roofing_line_width=0.4 hole_xy_offset=0 diff --git a/stress_benchmark/resources/029.settings b/stress_benchmark/resources/029.settings index 5b9c43af5e..2863e74b64 100644 --- a/stress_benchmark/resources/029.settings +++ b/stress_benchmark/resources/029.settings @@ -214,7 +214,9 @@ support_interface_line_width=0.4 support_skip_zag_per_mm=20 support_angle=60 raft_base_speed=56.25 -raft_remove_inside_corners=False +raft_base_remove_inside_corners=False +raft_interface_remove_inside_corners=False +raft_surface_remove_inside_corners=False ironing_only_highest_layer=True roofing_line_width=0.4 hole_xy_offset=0 diff --git a/stress_benchmark/resources/030.settings b/stress_benchmark/resources/030.settings index 47809b68eb..fda295d176 100644 --- a/stress_benchmark/resources/030.settings +++ b/stress_benchmark/resources/030.settings @@ -215,7 +215,9 @@ support_interface_line_width=0.4 support_skip_zag_per_mm=20 support_angle=60 raft_base_speed=15 -raft_remove_inside_corners=False +raft_base_remove_inside_corners=False +raft_interface_remove_inside_corners=False +raft_surface_remove_inside_corners=False ironing_only_highest_layer=False roofing_line_width=0.4 hole_xy_offset=0 diff --git a/stress_benchmark/resources/031.settings b/stress_benchmark/resources/031.settings index 31984edfe1..40d89ac715 100644 --- a/stress_benchmark/resources/031.settings +++ b/stress_benchmark/resources/031.settings @@ -214,7 +214,9 @@ support_interface_line_width=0.4 support_skip_zag_per_mm=20 support_angle=45 raft_base_speed=18.75 -raft_remove_inside_corners=False +raft_base_remove_inside_corners=False +raft_interface_remove_inside_corners=False +raft_surface_remove_inside_corners=False ironing_only_highest_layer=False roofing_line_width=0.4 hole_xy_offset=0 diff --git a/stress_benchmark/resources/032.settings b/stress_benchmark/resources/032.settings index 16d3b15c9c..d27cae81b7 100644 --- a/stress_benchmark/resources/032.settings +++ b/stress_benchmark/resources/032.settings @@ -443,7 +443,9 @@ multiple_mesh_overlap=0.15 z_seam_type=sharpest_corner prime_tower_base_size=7 material_print_temp_wait=True -raft_remove_inside_corners=False +raft_base_remove_inside_corners=False +raft_interface_remove_inside_corners=False +raft_surface_remove_inside_corners=False wall_distribution_count=1 support_roof_offset=0.0 material_shrinkage_percentage_z=100.0 diff --git a/stress_benchmark/resources/033.settings b/stress_benchmark/resources/033.settings index efb082178b..e061183e7e 100644 --- a/stress_benchmark/resources/033.settings +++ b/stress_benchmark/resources/033.settings @@ -445,7 +445,9 @@ multiple_mesh_overlap=0.15 z_seam_type=sharpest_corner prime_tower_base_size=8.0 material_print_temp_wait=True -raft_remove_inside_corners=False +raft_base_remove_inside_corners=False +raft_interface_remove_inside_corners=False +raft_surface_remove_inside_corners=False wall_distribution_count=1 support_roof_offset=0.0 material_shrinkage_percentage_z=100.0 diff --git a/stress_benchmark/resources/034.settings b/stress_benchmark/resources/034.settings index ab7970bc26..ef2d14e75c 100644 --- a/stress_benchmark/resources/034.settings +++ b/stress_benchmark/resources/034.settings @@ -442,7 +442,9 @@ multiple_mesh_overlap=0.15 z_seam_type=back prime_tower_base_size=5 material_print_temp_wait=True -raft_remove_inside_corners=False +raft_base_remove_inside_corners=False +raft_interface_remove_inside_corners=False +raft_surface_remove_inside_corners=False wall_distribution_count=1 support_roof_offset=0.0 material_shrinkage_percentage_z=100.0 diff --git a/stress_benchmark/resources/035.settings b/stress_benchmark/resources/035.settings index 186d401196..07cfade33e 100644 --- a/stress_benchmark/resources/035.settings +++ b/stress_benchmark/resources/035.settings @@ -444,7 +444,9 @@ multiple_mesh_overlap=0.15 z_seam_type=sharpest_corner prime_tower_base_size=8.0 material_print_temp_wait=True -raft_remove_inside_corners=False +raft_base_remove_inside_corners=False +raft_interface_remove_inside_corners=False +raft_surface_remove_inside_corners=False wall_distribution_count=1 support_roof_offset=0.0 material_shrinkage_percentage_z=100.0 diff --git a/stress_benchmark/resources/036.settings b/stress_benchmark/resources/036.settings index c81e9a4567..5a87f6f72f 100644 --- a/stress_benchmark/resources/036.settings +++ b/stress_benchmark/resources/036.settings @@ -443,7 +443,9 @@ multiple_mesh_overlap=0.15 z_seam_type=sharpest_corner prime_tower_base_size=8.0 material_print_temp_wait=True -raft_remove_inside_corners=False +raft_base_remove_inside_corners=False +raft_interface_remove_inside_corners=False +raft_surface_remove_inside_corners=False wall_distribution_count=1 support_roof_offset=0.0 material_shrinkage_percentage_z=100.0 diff --git a/stress_benchmark/resources/037.settings b/stress_benchmark/resources/037.settings index 3a1ca85c98..c3b00ba245 100644 --- a/stress_benchmark/resources/037.settings +++ b/stress_benchmark/resources/037.settings @@ -443,7 +443,9 @@ multiple_mesh_overlap=0.15 z_seam_type=back prime_tower_base_size=8.0 material_print_temp_wait=True -raft_remove_inside_corners=False +raft_base_remove_inside_corners=False +raft_interface_remove_inside_corners=False +raft_surface_remove_inside_corners=False wall_distribution_count=1 support_roof_offset=0.0 material_shrinkage_percentage_z=100.0 diff --git a/stress_benchmark/resources/038.settings b/stress_benchmark/resources/038.settings index 789165b2a9..4fa621641d 100644 --- a/stress_benchmark/resources/038.settings +++ b/stress_benchmark/resources/038.settings @@ -444,7 +444,9 @@ multiple_mesh_overlap=0.15 z_seam_type=back prime_tower_base_size=5.0 material_print_temp_wait=True -raft_remove_inside_corners=False +raft_base_remove_inside_corners=False +raft_interface_remove_inside_corners=False +raft_surface_remove_inside_corners=False wall_distribution_count=1 support_roof_offset=0.0 material_shrinkage_percentage_z=100.0 diff --git a/stress_benchmark/resources/039.settings b/stress_benchmark/resources/039.settings index b8183c4b0d..be719c02d9 100644 --- a/stress_benchmark/resources/039.settings +++ b/stress_benchmark/resources/039.settings @@ -444,7 +444,9 @@ multiple_mesh_overlap=0.15 z_seam_type=back prime_tower_base_size=8.0 material_print_temp_wait=True -raft_remove_inside_corners=False +raft_base_remove_inside_corners=False +raft_interface_remove_inside_corners=False +raft_surface_remove_inside_corners=False wall_distribution_count=1 support_roof_offset=0.0 material_shrinkage_percentage_z=100.0 diff --git a/stress_benchmark/resources/040.settings b/stress_benchmark/resources/040.settings index f74194fa38..86c045c3f9 100644 --- a/stress_benchmark/resources/040.settings +++ b/stress_benchmark/resources/040.settings @@ -443,7 +443,9 @@ multiple_mesh_overlap=0.15 z_seam_type=back prime_tower_base_size=8.0 material_print_temp_wait=True -raft_remove_inside_corners=False +raft_base_remove_inside_corners=False +raft_interface_remove_inside_corners=False +raft_surface_remove_inside_corners=False wall_distribution_count=1 support_roof_offset=0.0 material_shrinkage_percentage_z=100.0 diff --git a/stress_benchmark/resources/041.settings b/stress_benchmark/resources/041.settings index 0f3eaf0020..68d1e291d4 100644 --- a/stress_benchmark/resources/041.settings +++ b/stress_benchmark/resources/041.settings @@ -447,7 +447,9 @@ multiple_mesh_overlap=0.15 z_seam_type=sharpest_corner prime_tower_base_size=8.0 material_print_temp_wait=True -raft_remove_inside_corners=False +raft_base_remove_inside_corners=False +raft_interface_remove_inside_corners=False +raft_surface_remove_inside_corners=False wall_distribution_count=1 support_roof_offset=0 material_shrinkage_percentage_z=100.0 diff --git a/stress_benchmark/resources/042.settings b/stress_benchmark/resources/042.settings index 10f61fa229..6407e893e6 100644 --- a/stress_benchmark/resources/042.settings +++ b/stress_benchmark/resources/042.settings @@ -444,7 +444,9 @@ multiple_mesh_overlap=0.15 z_seam_type=sharpest_corner prime_tower_base_size=8.0 material_print_temp_wait=True -raft_remove_inside_corners=False +raft_base_remove_inside_corners=False +raft_interface_remove_inside_corners=False +raft_surface_remove_inside_corners=False wall_distribution_count=1 support_roof_offset=0.0 material_shrinkage_percentage_z=100.0 diff --git a/stress_benchmark/resources/043.settings b/stress_benchmark/resources/043.settings index 85b1c44f4f..74cf037495 100644 --- a/stress_benchmark/resources/043.settings +++ b/stress_benchmark/resources/043.settings @@ -446,7 +446,9 @@ multiple_mesh_overlap=0 z_seam_type=sharpest_corner prime_tower_base_size=3 material_print_temp_wait=True -raft_remove_inside_corners=False +raft_base_remove_inside_corners=False +raft_interface_remove_inside_corners=False +raft_surface_remove_inside_corners=False wall_distribution_count=1 support_roof_offset=0.8 material_shrinkage_percentage_z=100.0 diff --git a/stress_benchmark/resources/044.settings b/stress_benchmark/resources/044.settings index 05e2be11ef..6c76fcfa34 100644 --- a/stress_benchmark/resources/044.settings +++ b/stress_benchmark/resources/044.settings @@ -446,7 +446,9 @@ multiple_mesh_overlap=0 z_seam_type=sharpest_corner prime_tower_base_size=3 material_print_temp_wait=True -raft_remove_inside_corners=False +raft_base_remove_inside_corners=False +raft_interface_remove_inside_corners=False +raft_surface_remove_inside_corners=False wall_distribution_count=1 support_roof_offset=0.0 material_shrinkage_percentage_z=100.2 diff --git a/stress_benchmark/resources/045.settings b/stress_benchmark/resources/045.settings index 601a64d4c9..442c9a56b7 100644 --- a/stress_benchmark/resources/045.settings +++ b/stress_benchmark/resources/045.settings @@ -445,7 +445,9 @@ multiple_mesh_overlap=0.15 z_seam_type=sharpest_corner prime_tower_base_size=8.0 material_print_temp_wait=True -raft_remove_inside_corners=False +raft_base_remove_inside_corners=False +raft_interface_remove_inside_corners=False +raft_surface_remove_inside_corners=False wall_distribution_count=1 support_roof_offset=0.0 material_shrinkage_percentage_z=100.0 diff --git a/stress_benchmark/resources/046.settings b/stress_benchmark/resources/046.settings index ba6d8b93b2..8d590679fb 100644 --- a/stress_benchmark/resources/046.settings +++ b/stress_benchmark/resources/046.settings @@ -445,7 +445,9 @@ multiple_mesh_overlap=0.15 z_seam_type=back prime_tower_base_size=8.0 material_print_temp_wait=True -raft_remove_inside_corners=False +raft_base_remove_inside_corners=False +raft_interface_remove_inside_corners=False +raft_surface_remove_inside_corners=False wall_distribution_count=1 support_roof_offset=0.0 material_shrinkage_percentage_z=100.0 diff --git a/stress_benchmark/resources/047.settings b/stress_benchmark/resources/047.settings index c1439409f0..0d58cef982 100644 --- a/stress_benchmark/resources/047.settings +++ b/stress_benchmark/resources/047.settings @@ -445,7 +445,9 @@ multiple_mesh_overlap=0.15 z_seam_type=sharpest_corner prime_tower_base_size=4.0 material_print_temp_wait=True -raft_remove_inside_corners=False +raft_base_remove_inside_corners=False +raft_interface_remove_inside_corners=False +raft_surface_remove_inside_corners=False wall_distribution_count=1 support_roof_offset=0.0 material_shrinkage_percentage_z=100.0 diff --git a/stress_benchmark/resources/048.settings b/stress_benchmark/resources/048.settings index 62bc6888fa..d293d5f621 100644 --- a/stress_benchmark/resources/048.settings +++ b/stress_benchmark/resources/048.settings @@ -443,7 +443,9 @@ multiple_mesh_overlap=0.15 z_seam_type=back prime_tower_base_size=8.0 material_print_temp_wait=True -raft_remove_inside_corners=False +raft_base_remove_inside_corners=False +raft_interface_remove_inside_corners=False +raft_surface_remove_inside_corners=False wall_distribution_count=1 support_roof_offset=0.0 material_shrinkage_percentage_z=100.0 diff --git a/stress_benchmark/resources/049.settings b/stress_benchmark/resources/049.settings index 4b0f97c5cc..cc70c56c37 100644 --- a/stress_benchmark/resources/049.settings +++ b/stress_benchmark/resources/049.settings @@ -224,7 +224,9 @@ support_bottom_line_distance=1.800018000180002 support_enable=False adhesion_extruder_nr=-1 print_temperature=210 -raft_remove_inside_corners=False +raft_base_remove_inside_corners=False +raft_interface_remove_inside_corners=False +raft_surface_remove_inside_corners=False wipe_retraction_retract_speed=40 material_anti_ooze_retracted_position=-4 layer_height=0.12 diff --git a/stress_benchmark/resources/050.settings b/stress_benchmark/resources/050.settings index f1fa5a28e8..a16b860daf 100644 --- a/stress_benchmark/resources/050.settings +++ b/stress_benchmark/resources/050.settings @@ -224,7 +224,9 @@ support_bottom_line_distance=0.8 support_enable=False adhesion_extruder_nr=-1 print_temperature=210 -raft_remove_inside_corners=False +raft_base_remove_inside_corners=False +raft_interface_remove_inside_corners=False +raft_surface_remove_inside_corners=False wipe_retraction_retract_speed=50 material_anti_ooze_retracted_position=-4 layer_height=0.2 diff --git a/stress_benchmark/resources/051.settings b/stress_benchmark/resources/051.settings index 1d7a79f521..78c8abbd15 100644 --- a/stress_benchmark/resources/051.settings +++ b/stress_benchmark/resources/051.settings @@ -225,7 +225,9 @@ support_bottom_line_distance=0.5 support_enable=False adhesion_extruder_nr=-1 print_temperature=210 -raft_remove_inside_corners=False +raft_base_remove_inside_corners=False +raft_interface_remove_inside_corners=False +raft_surface_remove_inside_corners=False wipe_retraction_retract_speed=20.0 material_anti_ooze_retracted_position=-4 layer_height=0.12 diff --git a/stress_benchmark/resources/052.settings b/stress_benchmark/resources/052.settings index c46d63e5e4..dfab6c8c61 100644 --- a/stress_benchmark/resources/052.settings +++ b/stress_benchmark/resources/052.settings @@ -224,7 +224,9 @@ support_bottom_line_distance=2.8800288002880032 support_enable=True adhesion_extruder_nr=-1 print_temperature=210 -raft_remove_inside_corners=False +raft_base_remove_inside_corners=False +raft_interface_remove_inside_corners=False +raft_surface_remove_inside_corners=False wipe_retraction_retract_speed=45 material_anti_ooze_retracted_position=-4 layer_height=0.28 diff --git a/stress_benchmark/resources/053.settings b/stress_benchmark/resources/053.settings index 2e5e59b2b3..b8cdb66682 100644 --- a/stress_benchmark/resources/053.settings +++ b/stress_benchmark/resources/053.settings @@ -225,7 +225,9 @@ support_bottom_line_distance=0.4 support_enable=False adhesion_extruder_nr=-1 print_temperature=210 -raft_remove_inside_corners=False +raft_base_remove_inside_corners=False +raft_interface_remove_inside_corners=False +raft_surface_remove_inside_corners=False wipe_retraction_retract_speed=25 material_anti_ooze_retracted_position=-4 layer_height=0.1 diff --git a/stress_benchmark/resources/054.settings b/stress_benchmark/resources/054.settings index ed5709fe6d..4903e9647f 100644 --- a/stress_benchmark/resources/054.settings +++ b/stress_benchmark/resources/054.settings @@ -224,7 +224,9 @@ support_bottom_line_distance=0.4 support_enable=True adhesion_extruder_nr=-1 print_temperature=210 -raft_remove_inside_corners=False +raft_base_remove_inside_corners=False +raft_interface_remove_inside_corners=False +raft_surface_remove_inside_corners=False wipe_retraction_retract_speed=25 material_anti_ooze_retracted_position=-4 layer_height=0.2 diff --git a/stress_benchmark/resources/055.settings b/stress_benchmark/resources/055.settings index 14025ad607..6868231de8 100644 --- a/stress_benchmark/resources/055.settings +++ b/stress_benchmark/resources/055.settings @@ -225,7 +225,9 @@ support_bottom_line_distance=0.35 support_enable=False adhesion_extruder_nr=-1 print_temperature=210 -raft_remove_inside_corners=False +raft_base_remove_inside_corners=False +raft_interface_remove_inside_corners=False +raft_surface_remove_inside_corners=False wipe_retraction_retract_speed=50 material_anti_ooze_retracted_position=-4 layer_height=0.2 diff --git a/stress_benchmark/resources/056.settings b/stress_benchmark/resources/056.settings index 427a32768d..8973474b86 100644 --- a/stress_benchmark/resources/056.settings +++ b/stress_benchmark/resources/056.settings @@ -224,7 +224,9 @@ support_bottom_line_distance=0.4 support_enable=False adhesion_extruder_nr=0 print_temperature=210 -raft_remove_inside_corners=False +raft_base_remove_inside_corners=False +raft_interface_remove_inside_corners=False +raft_surface_remove_inside_corners=False wipe_retraction_retract_speed=60 material_anti_ooze_retracted_position=-4 layer_height=0.1 diff --git a/stress_benchmark/resources/057.settings b/stress_benchmark/resources/057.settings index 22c8b9dd7b..bb247ec669 100644 --- a/stress_benchmark/resources/057.settings +++ b/stress_benchmark/resources/057.settings @@ -224,7 +224,9 @@ support_bottom_line_distance=5.333333333333333 support_enable=True adhesion_extruder_nr=-1 print_temperature=210 -raft_remove_inside_corners=False +raft_base_remove_inside_corners=False +raft_interface_remove_inside_corners=False +raft_surface_remove_inside_corners=False wipe_retraction_retract_speed=70 material_anti_ooze_retracted_position=-4 layer_height=0.5 diff --git a/stress_benchmark/resources/058.settings b/stress_benchmark/resources/058.settings index 7562c7a7bd..39446ad26e 100644 --- a/stress_benchmark/resources/058.settings +++ b/stress_benchmark/resources/058.settings @@ -224,7 +224,9 @@ support_bottom_line_distance=2.4000240002400024 support_enable=False adhesion_extruder_nr=-1 print_temperature=210 -raft_remove_inside_corners=False +raft_base_remove_inside_corners=False +raft_interface_remove_inside_corners=False +raft_surface_remove_inside_corners=False wipe_retraction_retract_speed=45 material_anti_ooze_retracted_position=-4 layer_height=0.12 diff --git a/stress_benchmark/resources/059.settings b/stress_benchmark/resources/059.settings index c8c547a1de..97eb1229c2 100644 --- a/stress_benchmark/resources/059.settings +++ b/stress_benchmark/resources/059.settings @@ -192,7 +192,9 @@ roofing_line_width=0.4 material_flow_layer_0=100 minimum_roof_area=10 blackmagic=0 -raft_remove_inside_corners=False +raft_base_remove_inside_corners=False +raft_interface_remove_inside_corners=False +raft_surface_remove_inside_corners=False support_interface_pattern=grid xy_offset=0 prime_tower_brim_enable=True diff --git a/stress_benchmark/resources/060.settings b/stress_benchmark/resources/060.settings index afff41c33d..f07e7c3030 100644 --- a/stress_benchmark/resources/060.settings +++ b/stress_benchmark/resources/060.settings @@ -192,7 +192,9 @@ roofing_line_width=0.4 material_flow_layer_0=100 minimum_roof_area=10 blackmagic=0 -raft_remove_inside_corners=False +raft_base_remove_inside_corners=False +raft_interface_remove_inside_corners=False +raft_surface_remove_inside_corners=False support_interface_pattern=grid xy_offset=0 prime_tower_brim_enable=True diff --git a/stress_benchmark/resources/061.settings b/stress_benchmark/resources/061.settings index 18d0f316fd..9a2e6f80a8 100644 --- a/stress_benchmark/resources/061.settings +++ b/stress_benchmark/resources/061.settings @@ -192,7 +192,9 @@ roofing_line_width=0.4 material_flow_layer_0=100 minimum_roof_area=1.0 blackmagic=0 -raft_remove_inside_corners=False +raft_base_remove_inside_corners=False +raft_interface_remove_inside_corners=False +raft_surface_remove_inside_corners=False support_interface_pattern=concentric xy_offset=0 prime_tower_brim_enable=False diff --git a/stress_benchmark/resources/062.settings b/stress_benchmark/resources/062.settings index 96d4a28dd1..19969a024d 100644 --- a/stress_benchmark/resources/062.settings +++ b/stress_benchmark/resources/062.settings @@ -192,7 +192,9 @@ roofing_line_width=0.4 material_flow_layer_0=100 minimum_roof_area=1.0 blackmagic=0 -raft_remove_inside_corners=False +raft_base_remove_inside_corners=False +raft_interface_remove_inside_corners=False +raft_surface_remove_inside_corners=False support_interface_pattern=concentric xy_offset=0 prime_tower_brim_enable=False diff --git a/stress_benchmark/resources/063.settings b/stress_benchmark/resources/063.settings index d300bfc633..f31688e84e 100644 --- a/stress_benchmark/resources/063.settings +++ b/stress_benchmark/resources/063.settings @@ -192,7 +192,9 @@ roofing_line_width=0.4 material_flow_layer_0=100 minimum_roof_area=1.0 blackmagic=0 -raft_remove_inside_corners=False +raft_base_remove_inside_corners=False +raft_interface_remove_inside_corners=False +raft_surface_remove_inside_corners=False support_interface_pattern=concentric xy_offset=0 prime_tower_brim_enable=False diff --git a/stress_benchmark/resources/064.settings b/stress_benchmark/resources/064.settings index 1739abbb7e..7cf1a24790 100644 --- a/stress_benchmark/resources/064.settings +++ b/stress_benchmark/resources/064.settings @@ -191,7 +191,9 @@ roofing_line_width=0.4 material_flow_layer_0=85 minimum_roof_area=2 blackmagic=0 -raft_remove_inside_corners=False +raft_base_remove_inside_corners=False +raft_interface_remove_inside_corners=False +raft_surface_remove_inside_corners=False support_interface_pattern=grid xy_offset=0 prime_tower_brim_enable=True diff --git a/stress_benchmark/resources/065.settings b/stress_benchmark/resources/065.settings index a32ec18ddb..0515cd4b53 100644 --- a/stress_benchmark/resources/065.settings +++ b/stress_benchmark/resources/065.settings @@ -193,7 +193,9 @@ roofing_line_width=0.25 material_flow_layer_0=100 minimum_roof_area=1.0 blackmagic=0 -raft_remove_inside_corners=False +raft_base_remove_inside_corners=False +raft_interface_remove_inside_corners=False +raft_surface_remove_inside_corners=False support_interface_pattern=zigzag xy_offset=-0.010000000000000002 prime_tower_brim_enable=True diff --git a/stress_benchmark/resources/066.settings b/stress_benchmark/resources/066.settings index 9a50e01066..79f3d54d8b 100644 --- a/stress_benchmark/resources/066.settings +++ b/stress_benchmark/resources/066.settings @@ -193,7 +193,9 @@ roofing_line_width=0.4 material_flow_layer_0=100 minimum_roof_area=1.0 blackmagic=0 -raft_remove_inside_corners=False +raft_base_remove_inside_corners=False +raft_interface_remove_inside_corners=False +raft_surface_remove_inside_corners=False support_interface_pattern=zigzag xy_offset=-0.010000000000000002 prime_tower_brim_enable=False diff --git a/stress_benchmark/resources/067.settings b/stress_benchmark/resources/067.settings index f0aaccedf9..1f04d38ae0 100644 --- a/stress_benchmark/resources/067.settings +++ b/stress_benchmark/resources/067.settings @@ -192,7 +192,9 @@ roofing_line_width=0.45 material_flow_layer_0=100 minimum_roof_area=10 blackmagic=0 -raft_remove_inside_corners=False +raft_base_remove_inside_corners=False +raft_interface_remove_inside_corners=False +raft_surface_remove_inside_corners=False support_interface_pattern=grid xy_offset=0 prime_tower_brim_enable=False From dc134e507b0944f6e1d6d54c9a79966211e89c46 Mon Sep 17 00:00:00 2001 From: casperlamboo Date: Mon, 8 Jan 2024 13:45:56 +0000 Subject: [PATCH 040/201] Applied clang-format. --- include/raft.h | 16 ++++++++-------- src/raft.cpp | 9 +++++---- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/include/raft.h b/include/raft.h index 11f0fffdf6..b6f837f53e 100644 --- a/include/raft.h +++ b/include/raft.h @@ -1,5 +1,5 @@ -//Copyright (c) 2018 Ultimaker B.V. -//CuraEngine is released under the terms of the AGPLv3 or higher. +// Copyright (c) 2018 Ultimaker B.V. +// CuraEngine is released under the terms of the AGPLv3 or higher. #ifndef RAFT_H #define RAFT_H @@ -30,7 +30,7 @@ class Raft /*! * \brief Get the amount of layers to fill the airgap and initial layer with * helper parts (support, prime tower, etc.). - * + * * The initial layer gets a separate filler layer because we don't want to * apply the layer_0_z_overlap to it. */ @@ -50,12 +50,13 @@ class Raft /*! * \brief Get the total amount of extra layers below zero because there is a * raft. - * + * * This includes the filler layers which are introduced in the air gap. */ static size_t getTotalExtraLayers(); - enum LayerType { + enum LayerType + { RaftBase, RaftInterface, RaftSurface, @@ -69,9 +70,8 @@ class Raft * \return The type of layer at the given layer index. */ static LayerType getLayerType(LayerIndex layer_index); - }; -}//namespace cura +} // namespace cura -#endif//RAFT_H +#endif // RAFT_H diff --git a/src/raft.cpp b/src/raft.cpp index c299b79061..233f93a40b 100644 --- a/src/raft.cpp +++ b/src/raft.cpp @@ -28,7 +28,8 @@ void Raft::generate(SliceDataStorage& storage) storage.raftSurfaceOutline = storage.raftSurfaceOutline.offset(settings.get("raft_surface_margin"), ClipperLib::jtRound); const coord_t shield_line_width_layer0 = settings.get("skirt_brim_line_width"); - const coord_t max_raft_distance = std::max(std::max(settings.get("raft_base_margin"), settings.get("raft_interface_margin")), settings.get("raft_surface_margin")); + const coord_t max_raft_distance + = std::max(std::max(settings.get("raft_base_margin"), settings.get("raft_interface_margin")), settings.get("raft_surface_margin")); if (storage.draft_protection_shield.size() > 0) { Polygons draft_shield_raft @@ -160,15 +161,15 @@ Raft::LayerType Raft::getLayerType(LayerIndex layer_index) const auto interface_layers = interface_train.settings_.get("raft_interface_layers"); const auto surface_layers = surface_train.settings_.get("raft_surface_layers"); - if (layer_index < - airgap - surface_layers - interface_layers) + if (layer_index < -airgap - surface_layers - interface_layers) { return LayerType::RaftBase; } - if (layer_index < - airgap - surface_layers) + if (layer_index < -airgap - surface_layers) { return LayerType::RaftInterface; } - if (layer_index < - airgap) + if (layer_index < -airgap) { return LayerType::RaftSurface; } From 3dc1bd27f832ace647de354ebbfc49a6d173db62 Mon Sep 17 00:00:00 2001 From: "c.lamboo" Date: Tue, 9 Jan 2024 09:19:42 +0100 Subject: [PATCH 041/201] Make switch state exhaustive CURA 11395 --- src/sliceDataStorage.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/sliceDataStorage.cpp b/src/sliceDataStorage.cpp index 1af95d5027..bb8182aaee 100644 --- a/src/sliceDataStorage.cpp +++ b/src/sliceDataStorage.cpp @@ -326,6 +326,7 @@ Polygons } case Raft::LayerType::Airgap: case Raft::LayerType::Model: + { Polygons total; if (layer_nr >= 0) { @@ -367,6 +368,10 @@ Polygons } return total; } + default: + assert(false << "unreachable as switch statement is exhaustive"); + return Polygons(); + } } std::vector SliceDataStorage::getExtrudersUsed() const From c3b6558941948cacb0ab1d147ef0147508eb2afb Mon Sep 17 00:00:00 2001 From: "c.lamboo" Date: Tue, 9 Jan 2024 09:23:09 +0100 Subject: [PATCH 042/201] Use lambda to avoid code duplication CURA 11395 --- src/raft.cpp | 42 +++++++++++++----------------------------- 1 file changed, 13 insertions(+), 29 deletions(-) diff --git a/src/raft.cpp b/src/raft.cpp index 233f93a40b..a8a23cf21e 100644 --- a/src/raft.cpp +++ b/src/raft.cpp @@ -51,35 +51,19 @@ void Raft::generate(SliceDataStorage& storage) storage.raftInterfaceOutline = storage.raftInterfaceOutline.unionPolygons(ooze_shield_raft); } - if (settings.get("raft_base_remove_inside_corners")) - { - storage.raftBaseOutline.makeConvex(); - } - else - { - const coord_t smoothing = settings.get("raft_base_smoothing"); - storage.raftBaseOutline = storage.raftBaseOutline.offset(smoothing, ClipperLib::jtRound).offset(-smoothing, ClipperLib::jtRound); - } - - if (settings.get("raft_interface_remove_inside_corners")) - { - storage.raftInterfaceOutline.makeConvex(); - } - else - { - const coord_t smoothing = settings.get("raft_interface_smoothing"); - storage.raftInterfaceOutline = storage.raftInterfaceOutline.offset(smoothing, ClipperLib::jtRound).offset(-smoothing, ClipperLib::jtRound); - } - - if (settings.get("raft_surface_remove_inside_corners")) - { - storage.raftSurfaceOutline.makeConvex(); - } - else - { - const coord_t smoothing = settings.get("raft_surface_smoothing"); - storage.raftSurfaceOutline = storage.raftSurfaceOutline.offset(smoothing, ClipperLib::jtRound).offset(-smoothing, ClipperLib::jtRound); - } + const auto remove_inside_corners = [&settings, &storage](Polygons& outline, bool remove_inside_corners, coord_t smoothing) { + if (remove_inside_corners) + { + outline.makeConvex(); + } + else + { + outline = outline.offset(smoothing, ClipperLib::jtRound).offset(-smoothing, ClipperLib::jtRound); + } + }; + remove_inside_corners(storage.raftBaseOutline, settings.get("raft_base_remove_inside_corners"), settings.get("raft_base_smoothing")); + remove_inside_corners(storage.raftInterfaceOutline, settings.get("raft_interface_remove_inside_corners"), settings.get("raft_interface_smoothing")); + remove_inside_corners(storage.raftSurfaceOutline, settings.get("raft_surface_remove_inside_corners"), settings.get("raft_surface_smoothing")); if (storage.primeTower.enabled_ && ! storage.primeTower.would_have_actual_tower_) { From 75dc0ea4f734fb1b819817ebd8850ebd24874ff9 Mon Sep 17 00:00:00 2001 From: casperlamboo Date: Tue, 9 Jan 2024 08:24:19 +0000 Subject: [PATCH 043/201] Applied clang-format. --- src/raft.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/raft.cpp b/src/raft.cpp index a8a23cf21e..edc5c51fb7 100644 --- a/src/raft.cpp +++ b/src/raft.cpp @@ -51,7 +51,8 @@ void Raft::generate(SliceDataStorage& storage) storage.raftInterfaceOutline = storage.raftInterfaceOutline.unionPolygons(ooze_shield_raft); } - const auto remove_inside_corners = [&settings, &storage](Polygons& outline, bool remove_inside_corners, coord_t smoothing) { + const auto remove_inside_corners = [&settings, &storage](Polygons& outline, bool remove_inside_corners, coord_t smoothing) + { if (remove_inside_corners) { outline.makeConvex(); From aa9be38400cadcca4a66a723a244819da6dbc3f2 Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Tue, 9 Jan 2024 09:30:12 +0100 Subject: [PATCH 044/201] Fix debug build --- src/raft.cpp | 4 +++- src/sliceDataStorage.cpp | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/raft.cpp b/src/raft.cpp index edc5c51fb7..9bb181cf5d 100644 --- a/src/raft.cpp +++ b/src/raft.cpp @@ -17,7 +17,9 @@ namespace cura void Raft::generate(SliceDataStorage& storage) { - assert(storage.raftOutline.size() == 0 && "Raft polygon isn't generated yet, so should be empty!"); + assert( + storage.raftBaseOutline.size() == 0 && storage.raftInterfaceOutline.size() == 0 && storage.raftSurfaceOutline.size() == 0 + && "Raft polygon isn't generated yet, so should be empty!"); const Settings& settings = Application::getInstance().current_slice_->scene.current_mesh_group->settings.get("raft_base_extruder_nr").settings_; constexpr bool include_support = true; constexpr bool dont_include_prime_tower = false; // Prime tower raft will be handled separately in 'storage.primeRaftOutline'; see below. diff --git a/src/sliceDataStorage.cpp b/src/sliceDataStorage.cpp index bb8182aaee..24c4be9bda 100644 --- a/src/sliceDataStorage.cpp +++ b/src/sliceDataStorage.cpp @@ -297,7 +297,7 @@ Polygons use_current_extruder_for_raft |= extruder_nr == int(mesh_group_settings.get("raft_surface_extruder_nr").extruder_nr_); break; default: - assert(false << "unreachable due to outer switch statement"); + assert(false && "unreachable due to outer switch statement"); return Polygons(); } From d53d330354d4270975878f3d74a9748c2e0c9927 Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Tue, 9 Jan 2024 09:53:25 +0100 Subject: [PATCH 045/201] Fix debug build --- src/sliceDataStorage.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sliceDataStorage.cpp b/src/sliceDataStorage.cpp index 24c4be9bda..e87250191b 100644 --- a/src/sliceDataStorage.cpp +++ b/src/sliceDataStorage.cpp @@ -369,7 +369,7 @@ Polygons return total; } default: - assert(false << "unreachable as switch statement is exhaustive"); + assert(false && "unreachable as switch statement is exhaustive"); return Polygons(); } } From f5925ff0fc2eba1487761a68810764a7f8bcf53b Mon Sep 17 00:00:00 2001 From: "c.lamboo" Date: Tue, 9 Jan 2024 10:28:08 +0100 Subject: [PATCH 046/201] Avoid re-use of setting getters by storing setting-value in local variable CURA 11395 --- src/raft.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/raft.cpp b/src/raft.cpp index 9bb181cf5d..a4286c2ce5 100644 --- a/src/raft.cpp +++ b/src/raft.cpp @@ -23,15 +23,17 @@ void Raft::generate(SliceDataStorage& storage) const Settings& settings = Application::getInstance().current_slice_->scene.current_mesh_group->settings.get("raft_base_extruder_nr").settings_; constexpr bool include_support = true; constexpr bool dont_include_prime_tower = false; // Prime tower raft will be handled separately in 'storage.primeRaftOutline'; see below. + const auto raft_base_margin = settings.get("raft_base_margin"); + const auto raft_interface_margin = settings.get("raft_interface_margin"); + const auto raft_surface_margin = settings.get("raft_surface_margin"); storage.raftBaseOutline = storage.raftSurfaceOutline = storage.raftInterfaceOutline = storage.getLayerOutlines(0, include_support, dont_include_prime_tower); - storage.raftBaseOutline = storage.raftBaseOutline.offset(settings.get("raft_base_margin"), ClipperLib::jtRound); - storage.raftInterfaceOutline = storage.raftInterfaceOutline.offset(settings.get("raft_interface_margin"), ClipperLib::jtRound); - storage.raftSurfaceOutline = storage.raftSurfaceOutline.offset(settings.get("raft_surface_margin"), ClipperLib::jtRound); + storage.raftBaseOutline = storage.raftBaseOutline.offset(raft_base_margin, ClipperLib::jtRound); + storage.raftInterfaceOutline = storage.raftInterfaceOutline.offset(raft_interface_margin, ClipperLib::jtRound); + storage.raftSurfaceOutline = storage.raftSurfaceOutline.offset(raft_surface_margin, ClipperLib::jtRound); const coord_t shield_line_width_layer0 = settings.get("skirt_brim_line_width"); - const coord_t max_raft_distance - = std::max(std::max(settings.get("raft_base_margin"), settings.get("raft_interface_margin")), settings.get("raft_surface_margin")); + const coord_t max_raft_distance = std::max(std::max(raft_base_margin, raft_interface_margin), raft_surface_margin); if (storage.draft_protection_shield.size() > 0) { Polygons draft_shield_raft From 140cb1dbde2a3fe299ffccd16c23397992953082 Mon Sep 17 00:00:00 2001 From: "c.lamboo" Date: Tue, 9 Jan 2024 16:41:20 +0100 Subject: [PATCH 047/201] Remove unused environment variable attachment in lambda CURA 11395 --- src/raft.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/raft.cpp b/src/raft.cpp index a4286c2ce5..ee9281e92b 100644 --- a/src/raft.cpp +++ b/src/raft.cpp @@ -55,7 +55,7 @@ void Raft::generate(SliceDataStorage& storage) storage.raftInterfaceOutline = storage.raftInterfaceOutline.unionPolygons(ooze_shield_raft); } - const auto remove_inside_corners = [&settings, &storage](Polygons& outline, bool remove_inside_corners, coord_t smoothing) + const auto remove_inside_corners = [&storage](Polygons& outline, bool remove_inside_corners, coord_t smoothing) { if (remove_inside_corners) { From 770effa84719ee6b0f16c5230949a800e7f9cef1 Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Tue, 9 Jan 2024 16:45:07 +0100 Subject: [PATCH 048/201] Code cleaning CURA-11395 --- src/raft.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/raft.cpp b/src/raft.cpp index ee9281e92b..2fb12e100b 100644 --- a/src/raft.cpp +++ b/src/raft.cpp @@ -55,7 +55,7 @@ void Raft::generate(SliceDataStorage& storage) storage.raftInterfaceOutline = storage.raftInterfaceOutline.unionPolygons(ooze_shield_raft); } - const auto remove_inside_corners = [&storage](Polygons& outline, bool remove_inside_corners, coord_t smoothing) + const auto remove_inside_corners = [](Polygons& outline, bool remove_inside_corners, coord_t smoothing) { if (remove_inside_corners) { From f720cee8aa040c894af86bfe93e26941f619a952 Mon Sep 17 00:00:00 2001 From: Jelle Spijker Date: Tue, 9 Jan 2024 17:29:11 +0100 Subject: [PATCH 049/201] Add slicing time Contribute to CURA-11527 --- .github/workflows/gcodeanalyzer.yml | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/.github/workflows/gcodeanalyzer.yml b/.github/workflows/gcodeanalyzer.yml index b73d5900ad..722985afd9 100644 --- a/.github/workflows/gcodeanalyzer.yml +++ b/.github/workflows/gcodeanalyzer.yml @@ -179,7 +179,7 @@ jobs: run: | for file in `ls ../NightlyTestModels/*.stl`; do - ./build/Release/CuraEngine slice --force-read-parent --force-read-nondefault -v -p -j ../Cura/resources/definitions/ultimaker_s3.def.json -l $file -o ../`basename $file .stl`.gcode + ( time ./build/Release/CuraEngine slice --force-read-parent --force-read-nondefault -v -p -j ../Cura/resources/definitions/ultimaker_s3.def.json -l $file -o ../`basename $file .stl`.gcode ) 2> `basename $file .stl`.time done working-directory: CuraEngine @@ -190,6 +190,7 @@ jobs: import sys import os import json + import re from Charon.filetypes.GCodeFile import GCodeFile sys.path.append(".") @@ -204,6 +205,8 @@ jobs: if ext.lower() != ".gcode": continue infilename = os.path.join(folder_path, filename) + with open(infilename.split(".")[0] + ".time", "r") as f: + timer = float(re.match(r"^.*?cpu (\d+\.\d+)", f.read())[1]) frame = GCodeAnalyzer.DataFrame(infilename) @@ -291,6 +294,11 @@ jobs: "unit": "Celcius", "value": temperatures["50%"], }, + { + "name": f"Slicing time {basename}", + "unit": "s", + "value": timer, + }, ] with open("../output.json", "w") as outfile: From c840410e58e9072c9a3515bfa21141ce9feae7a7 Mon Sep 17 00:00:00 2001 From: Jelle Spijker Date: Tue, 9 Jan 2024 17:42:13 +0100 Subject: [PATCH 050/201] use correct relative path Contribute to CURA-11527 --- .github/workflows/gcodeanalyzer.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/gcodeanalyzer.yml b/.github/workflows/gcodeanalyzer.yml index 722985afd9..fd3c171165 100644 --- a/.github/workflows/gcodeanalyzer.yml +++ b/.github/workflows/gcodeanalyzer.yml @@ -179,7 +179,7 @@ jobs: run: | for file in `ls ../NightlyTestModels/*.stl`; do - ( time ./build/Release/CuraEngine slice --force-read-parent --force-read-nondefault -v -p -j ../Cura/resources/definitions/ultimaker_s3.def.json -l $file -o ../`basename $file .stl`.gcode ) 2> `basename $file .stl`.time + ( time ./build/Release/CuraEngine slice --force-read-parent --force-read-nondefault -v -p -j ../Cura/resources/definitions/ultimaker_s3.def.json -l $file -o ../`basename $file .stl`.gcode ) 2> ../`basename $file .stl`.time done working-directory: CuraEngine From d7d7ffc4493834192c523e1d5427edd8fee7424d Mon Sep 17 00:00:00 2001 From: Jelle Spijker Date: Tue, 9 Jan 2024 17:45:33 +0100 Subject: [PATCH 051/201] Alert on benchmark regression Very low tresshold to test things out Contribute to CURA-11527 --- .github/workflows/benchmark.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/benchmark.yml b/.github/workflows/benchmark.yml index adb24aa2ff..b843ffc052 100644 --- a/.github/workflows/benchmark.yml +++ b/.github/workflows/benchmark.yml @@ -55,4 +55,6 @@ jobs: output_file_path: "build/Release/benchmark_result.json" data_dir: "dev/bench" tool: "googlecpp" + alert_threshold: "101%" + alert_comment_cc_users: "@nallath, @jellespijker, @wawanbreton, @casperlamboo, @saumyaj3, @HellAholic" secrets: inherit From d3cbcc0e0d88de6cba3a93d8bde6aed9995684a0 Mon Sep 17 00:00:00 2001 From: Jelle Spijker Date: Tue, 9 Jan 2024 17:51:59 +0100 Subject: [PATCH 052/201] use .time Contribute to CURA-11527 --- .github/workflows/gcodeanalyzer.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/gcodeanalyzer.yml b/.github/workflows/gcodeanalyzer.yml index fd3c171165..61a5c49a47 100644 --- a/.github/workflows/gcodeanalyzer.yml +++ b/.github/workflows/gcodeanalyzer.yml @@ -179,7 +179,7 @@ jobs: run: | for file in `ls ../NightlyTestModels/*.stl`; do - ( time ./build/Release/CuraEngine slice --force-read-parent --force-read-nondefault -v -p -j ../Cura/resources/definitions/ultimaker_s3.def.json -l $file -o ../`basename $file .stl`.gcode ) 2> ../`basename $file .stl`.time + ( time ./build/Release/CuraEngine slice --force-read-parent --force-read-nondefault -v -p -j ../Cura/resources/definitions/ultimaker_s3.def.json -l $file -o ../`basename $file .stl`.gcode ) 2> ../$file.time done working-directory: CuraEngine @@ -205,7 +205,7 @@ jobs: if ext.lower() != ".gcode": continue infilename = os.path.join(folder_path, filename) - with open(infilename.split(".")[0] + ".time", "r") as f: + with open(infilename + ".time", "r") as f: timer = float(re.match(r"^.*?cpu (\d+\.\d+)", f.read())[1]) frame = GCodeAnalyzer.DataFrame(infilename) From 6ce5a2ee6b7ee45913348da5dd1d7efc83e8d022 Mon Sep 17 00:00:00 2001 From: Jelle Spijker Date: Tue, 9 Jan 2024 17:55:28 +0100 Subject: [PATCH 053/201] realistic alert value Contribute to CURA-11527 --- .github/workflows/benchmark.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/benchmark.yml b/.github/workflows/benchmark.yml index b843ffc052..30ce6205c6 100644 --- a/.github/workflows/benchmark.yml +++ b/.github/workflows/benchmark.yml @@ -55,6 +55,6 @@ jobs: output_file_path: "build/Release/benchmark_result.json" data_dir: "dev/bench" tool: "googlecpp" - alert_threshold: "101%" + alert_threshold: "125%" alert_comment_cc_users: "@nallath, @jellespijker, @wawanbreton, @casperlamboo, @saumyaj3, @HellAholic" secrets: inherit From 49d5ec0cdc7624057651b09654aede16c6816016 Mon Sep 17 00:00:00 2001 From: Jelle Spijker Date: Tue, 9 Jan 2024 18:00:53 +0100 Subject: [PATCH 054/201] different relative path Contribute to CURA-11527 --- .github/workflows/gcodeanalyzer.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/gcodeanalyzer.yml b/.github/workflows/gcodeanalyzer.yml index 61a5c49a47..116937507c 100644 --- a/.github/workflows/gcodeanalyzer.yml +++ b/.github/workflows/gcodeanalyzer.yml @@ -179,7 +179,7 @@ jobs: run: | for file in `ls ../NightlyTestModels/*.stl`; do - ( time ./build/Release/CuraEngine slice --force-read-parent --force-read-nondefault -v -p -j ../Cura/resources/definitions/ultimaker_s3.def.json -l $file -o ../`basename $file .stl`.gcode ) 2> ../$file.time + ( time ./build/Release/CuraEngine slice --force-read-parent --force-read-nondefault -v -p -j ../Cura/resources/definitions/ultimaker_s3.def.json -l $file -o ../`basename $file .stl`.gcode ) 2> $file.time done working-directory: CuraEngine From 0511c4bcf84433207d0dcb10f4cf7f1a072ffda1 Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Wed, 10 Jan 2024 17:20:30 +0100 Subject: [PATCH 055/201] Removed default mode which is no more used --- include/settings/EnumSettings.h | 5 ----- src/FffGcodeWriter.cpp | 12 ------------ src/PrimeTower.cpp | 2 +- src/settings/Settings.cpp | 6 +----- 4 files changed, 2 insertions(+), 23 deletions(-) diff --git a/include/settings/EnumSettings.h b/include/settings/EnumSettings.h index 1ea3e1e099..ccec9c4f7d 100644 --- a/include/settings/EnumSettings.h +++ b/include/settings/EnumSettings.h @@ -255,11 +255,6 @@ enum class PrimeTowerMethod */ NONE, - /*! - * Basic full prime tower with only discs. - */ - DEFAULT, - /*! * Prime tower that minimizes time and used filament as much as possible. */ diff --git a/src/FffGcodeWriter.cpp b/src/FffGcodeWriter.cpp index a603aaf962..70bf3444fa 100644 --- a/src/FffGcodeWriter.cpp +++ b/src/FffGcodeWriter.cpp @@ -1526,18 +1526,6 @@ std::vector case PrimeTowerMethod::NONE: break; - case PrimeTowerMethod::DEFAULT: - if (extruder_nr == storage.primeTower.extruder_order_[0] && layer_nr >= 0 && layer_nr <= storage.max_print_height_second_to_last_extruder) - { - // The outermost prime tower extruder is always used if there is a prime tower, apart on layers with negative index (e.g. for the raft) - prime = ExtruderPrime::Prime; - } - else if (extruder_is_used_on_this_layer[extruder_nr]) - { - prime = ExtruderPrime::Prime; - } - break; - case PrimeTowerMethod::OPTIMIZED_CONSISTENT: if (extruder_is_used_on_this_layer[extruder_nr] && extruder_nr != last_extruder) { diff --git a/src/PrimeTower.cpp b/src/PrimeTower.cpp index ce546fd0e3..f06e3d1ff8 100644 --- a/src/PrimeTower.cpp +++ b/src/PrimeTower.cpp @@ -165,7 +165,7 @@ void PrimeTower::generatePaths_denseInfill(std::vector& cumulative_inse // Generate the base outside extra rings if ((method == PrimeTowerMethod::OPTIMIZED - || (extruder_nr == extruder_order_.front() && (method == PrimeTowerMethod::OPTIMIZED_CONSISTENT || method == PrimeTowerMethod::DEFAULT))) + || (extruder_nr == extruder_order_.front() && method == PrimeTowerMethod::OPTIMIZED_CONSISTENT)) && (base_enabled || has_raft) && base_extra_radius > 0 && base_height > 0) { for (coord_t z = 0; z < base_height; z += layer_height) diff --git a/src/settings/Settings.cpp b/src/settings/Settings.cpp index e2b60aa791..0efd915d9d 100644 --- a/src/settings/Settings.cpp +++ b/src/settings/Settings.cpp @@ -682,11 +682,7 @@ template<> PrimeTowerMethod Settings::get(const std::string& key) const { const std::string& value = get(key); - if (value == "default") - { - return PrimeTowerMethod::DEFAULT; - } - else if (value == "optimized") + if (value == "optimized") { return PrimeTowerMethod::OPTIMIZED; } From 7c46206c81d0d21c71ab88e43b1efa50cbbc4c05 Mon Sep 17 00:00:00 2001 From: wawanbreton Date: Wed, 10 Jan 2024 16:21:05 +0000 Subject: [PATCH 056/201] Applied clang-format. --- src/PrimeTower.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/PrimeTower.cpp b/src/PrimeTower.cpp index f06e3d1ff8..367ea01dbb 100644 --- a/src/PrimeTower.cpp +++ b/src/PrimeTower.cpp @@ -164,9 +164,8 @@ void PrimeTower::generatePaths_denseInfill(std::vector& cumulative_inse } // Generate the base outside extra rings - if ((method == PrimeTowerMethod::OPTIMIZED - || (extruder_nr == extruder_order_.front() && method == PrimeTowerMethod::OPTIMIZED_CONSISTENT)) - && (base_enabled || has_raft) && base_extra_radius > 0 && base_height > 0) + if ((method == PrimeTowerMethod::OPTIMIZED || (extruder_nr == extruder_order_.front() && method == PrimeTowerMethod::OPTIMIZED_CONSISTENT)) && (base_enabled || has_raft) + && base_extra_radius > 0 && base_height > 0) { for (coord_t z = 0; z < base_height; z += layer_height) { From 9d8271a65476e8e3fb8ff41083bb407aba217acf Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Mon, 15 Jan 2024 09:56:51 +0100 Subject: [PATCH 057/201] Settings name consistency --- include/settings/EnumSettings.h | 4 ++-- src/FffGcodeWriter.cpp | 6 +++--- src/PrimeTower.cpp | 19 ++++++++++--------- src/settings/Settings.cpp | 8 ++++---- 4 files changed, 19 insertions(+), 18 deletions(-) diff --git a/include/settings/EnumSettings.h b/include/settings/EnumSettings.h index ccec9c4f7d..054fb3089a 100644 --- a/include/settings/EnumSettings.h +++ b/include/settings/EnumSettings.h @@ -258,13 +258,13 @@ enum class PrimeTowerMethod /*! * Prime tower that minimizes time and used filament as much as possible. */ - OPTIMIZED, + SPARSE, /*! * Prime tower that minimizes time and used filament, but doesn't allow * for printing two different filaments over each other. */ - OPTIMIZED_CONSISTENT, + BUCKET, }; } // namespace cura diff --git a/src/FffGcodeWriter.cpp b/src/FffGcodeWriter.cpp index 70bf3444fa..8d9177c197 100644 --- a/src/FffGcodeWriter.cpp +++ b/src/FffGcodeWriter.cpp @@ -1526,7 +1526,7 @@ std::vector case PrimeTowerMethod::NONE: break; - case PrimeTowerMethod::OPTIMIZED_CONSISTENT: + case PrimeTowerMethod::BUCKET: if (extruder_is_used_on_this_layer[extruder_nr] && extruder_nr != last_extruder) { prime = ExtruderPrime::Prime; @@ -1537,7 +1537,7 @@ std::vector } break; - case PrimeTowerMethod::OPTIMIZED: + case PrimeTowerMethod::SPARSE: if (extruder_is_used_on_this_layer[extruder_nr] && extruder_nr != last_extruder) { prime = ExtruderPrime::Prime; @@ -1552,7 +1552,7 @@ std::vector } } - if (method == PrimeTowerMethod::OPTIMIZED && ret.size() == 1 && ret.front().prime == ExtruderPrime::None && layer_nr <= storage.max_print_height_second_to_last_extruder) + if (method == PrimeTowerMethod::SPARSE && ret.size() == 1 && ret.front().prime == ExtruderPrime::None && layer_nr <= storage.max_print_height_second_to_last_extruder) { ret.front().prime = ExtruderPrime::Sparse; } diff --git a/src/PrimeTower.cpp b/src/PrimeTower.cpp index 367ea01dbb..b63a5ccf77 100644 --- a/src/PrimeTower.cpp +++ b/src/PrimeTower.cpp @@ -43,7 +43,7 @@ PrimeTower::PrimeTower() // used (sacrifying for this purpose the usual single-extruder first layer, that would be better for prime-tower // adhesion). - multiple_extruders_on_first_layer_ = (method == PrimeTowerMethod::OPTIMIZED) || (method == PrimeTowerMethod::OPTIMIZED_CONSISTENT) + multiple_extruders_on_first_layer_ = (method == PrimeTowerMethod::SPARSE) || (method == PrimeTowerMethod::BUCKET) || (scene.current_mesh_group->settings.get("machine_extruders_share_nozzle") && ((adhesion_type != EPlatformAdhesion::SKIRT) && (adhesion_type != EPlatformAdhesion::BRIM))); } @@ -164,7 +164,8 @@ void PrimeTower::generatePaths_denseInfill(std::vector& cumulative_inse } // Generate the base outside extra rings - if ((method == PrimeTowerMethod::OPTIMIZED || (extruder_nr == extruder_order_.front() && method == PrimeTowerMethod::OPTIMIZED_CONSISTENT)) && (base_enabled || has_raft) + if ((method == PrimeTowerMethod::SPARSE + || (extruder_nr == extruder_order_.front() && method == PrimeTowerMethod::BUCKET)) && (base_enabled || has_raft) && base_extra_radius > 0 && base_height > 0) { for (coord_t z = 0; z < base_height; z += layer_height) @@ -190,7 +191,7 @@ void PrimeTower::generatePaths_denseInfill(std::vector& cumulative_inse // Now we have the total cumulative inset, generate the base inside extra rings for (size_t extruder_nr : extruder_order_) { - if (extruder_nr == extruder_order_.back() || method == PrimeTowerMethod::OPTIMIZED) + if (extruder_nr == extruder_order_.back() || method == PrimeTowerMethod::SPARSE) { const coord_t line_width = scene.extruders[extruder_nr].settings_.get("prime_tower_line_width"); Polygons pattern = PolygonUtils::generateInset(outer_poly_, line_width, cumulative_inset); @@ -222,7 +223,7 @@ void PrimeTower::generatePaths_sparseInfill(const std::vector& cumulati actual_extruders.push_back({ extruder_nr, line_width }); } - if (method == PrimeTowerMethod::OPTIMIZED || method == PrimeTowerMethod::OPTIMIZED_CONSISTENT) + if (method == PrimeTowerMethod::SPARSE || method == PrimeTowerMethod::BUCKET) { const size_t nb_extruders = scene.extruders.size(); @@ -242,7 +243,7 @@ void PrimeTower::generatePaths_sparseInfill(const std::vector& cumulati // A combination is represented by a bitmask for (size_t first_extruder_idx = 0; first_extruder_idx < nb_extruders; ++first_extruder_idx) { - size_t nb_extruders_sparse = method == PrimeTowerMethod::OPTIMIZED_CONSISTENT ? first_extruder_idx + 1 : nb_extruders; + size_t nb_extruders_sparse = method == PrimeTowerMethod::BUCKET ? first_extruder_idx + 1 : nb_extruders; for (size_t last_extruder_idx = first_extruder_idx; last_extruder_idx < nb_extruders_sparse; ++last_extruder_idx) { @@ -256,7 +257,7 @@ void PrimeTower::generatePaths_sparseInfill(const std::vector& cumulati std::map infills_for_combination; for (const ActualExtruder& actual_extruder : actual_extruders) { - if (method == PrimeTowerMethod::OPTIMIZED || actual_extruder.number == extruder_order_.at(first_extruder_idx)) + if (method == PrimeTowerMethod::SPARSE || actual_extruder.number == extruder_order_.at(first_extruder_idx)) { Polygons infill = generatePath_sparseInfill(first_extruder_idx, last_extruder_idx, rings_radii, actual_extruder.line_width, actual_extruder.number); infills_for_combination[actual_extruder.number] = infill; @@ -384,7 +385,7 @@ void PrimeTower::addToGcode( switch (extruder_iterator->prime) { case ExtruderPrime::None: - if (method != PrimeTowerMethod::OPTIMIZED) + if (method != PrimeTowerMethod::SPARSE) { gcode_layer.setPrimeTowerIsPlanned(new_extruder_nr); } @@ -399,7 +400,7 @@ void PrimeTower::addToGcode( addToGcode_denseInfill(gcode_layer, new_extruder_nr); gcode_layer.setPrimeTowerIsPlanned(new_extruder_nr); - if (method == PrimeTowerMethod::OPTIMIZED && gcode_layer.getLayerNr() <= storage.max_print_height_second_to_last_extruder) + if (method == PrimeTowerMethod::SPARSE && gcode_layer.getLayerNr() <= storage.max_print_height_second_to_last_extruder) { // Whatever happens before and after, use the current extruder to prime all the non-required extruders now extra_primed_extruders_idx = findExtrudersSparseInfill(gcode_layer, required_extruder_prime, method); @@ -571,7 +572,7 @@ std::vector PrimeTower::findExtrudersSparseInfill( else { size_t extruder_nr = extruder_order_.at(extruder_idx); - if (method == PrimeTowerMethod::OPTIMIZED && ! gcode_layer.getPrimeTowerIsPlanned(extruder_nr)) + if (method == PrimeTowerMethod::SPARSE && ! gcode_layer.getPrimeTowerIsPlanned(extruder_nr)) { auto iterator_required_list = std::find_if( required_extruder_prime.begin(), diff --git a/src/settings/Settings.cpp b/src/settings/Settings.cpp index 0efd915d9d..f4f212b407 100644 --- a/src/settings/Settings.cpp +++ b/src/settings/Settings.cpp @@ -682,13 +682,13 @@ template<> PrimeTowerMethod Settings::get(const std::string& key) const { const std::string& value = get(key); - if (value == "optimized") + if (value == "sparse") { - return PrimeTowerMethod::OPTIMIZED; + return PrimeTowerMethod::SPARSE; } - else if (value == "optimized_consistent") + else if (value == "bucket") { - return PrimeTowerMethod::OPTIMIZED_CONSISTENT; + return PrimeTowerMethod::BUCKET; } else // Default. { From 0141f41fa0eee5f1cec2ccd13c1483a2be6d0737 Mon Sep 17 00:00:00 2001 From: wawanbreton Date: Mon, 15 Jan 2024 08:59:32 +0000 Subject: [PATCH 058/201] Applied clang-format. --- src/PrimeTower.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/PrimeTower.cpp b/src/PrimeTower.cpp index b63a5ccf77..8987bfb8e1 100644 --- a/src/PrimeTower.cpp +++ b/src/PrimeTower.cpp @@ -164,8 +164,7 @@ void PrimeTower::generatePaths_denseInfill(std::vector& cumulative_inse } // Generate the base outside extra rings - if ((method == PrimeTowerMethod::SPARSE - || (extruder_nr == extruder_order_.front() && method == PrimeTowerMethod::BUCKET)) && (base_enabled || has_raft) + if ((method == PrimeTowerMethod::SPARSE || (extruder_nr == extruder_order_.front() && method == PrimeTowerMethod::BUCKET)) && (base_enabled || has_raft) && base_extra_radius > 0 && base_height > 0) { for (coord_t z = 0; z < base_height; z += layer_height) From 0fef7f0128f38705962d660b0b2cbf14a0bf096e Mon Sep 17 00:00:00 2001 From: "c.lamboo" Date: Thu, 11 Jan 2024 10:56:52 +0100 Subject: [PATCH 059/201] Add point ordering to convex hull algorithm MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is the Andrew’s Monotone Chain Convex Hull Algorithm. --- src/utils/polygon.cpp | 55 +++++++++++++++++++++++-------------------- 1 file changed, 29 insertions(+), 26 deletions(-) diff --git a/src/utils/polygon.cpp b/src/utils/polygon.cpp index 853104aada..64685470b7 100644 --- a/src/utils/polygon.cpp +++ b/src/utils/polygon.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2022 Ultimaker B.V. +// Copyright (c) 2023 UltiMaker // CuraEngine is released under the terms of the AGPLv3 or higher. #include "utils/polygon.h" @@ -16,6 +16,8 @@ #include #include #include +#include + #include "utils/ListPolyIt.h" #include "utils/PolylineStitcher.h" @@ -104,43 +106,44 @@ Polygons Polygons::approxConvexHull(int extra_outset) void Polygons::makeConvex() { + // Andrew’s Monotone Chain Convex Hull Algorithm for (PolygonRef poly : *this) { if (poly.size() <= 3) { - continue; // Already convex. + // Already convex. + continue; } Polygon convexified; - - // Start from a vertex that is known to be on the convex hull: The one with the lowest X. - const size_t start_index = std::min_element( - poly.begin(), - poly.end(), - [](Point2LL a, Point2LL b) - { - return a.X == b.X ? a.Y < b.Y : a.X < b.X; - }) - - poly.begin(); - convexified.path->push_back(poly[start_index]); - - for (size_t i = 1; i <= poly.size(); ++i) + auto makeSortedPolyConvex = [&convexified](PolygonRef& poly) { - const Point2LL& current = poly[(start_index + i) % poly.size()]; + convexified.path->push_back(poly[0]); - // Track backwards to make sure we haven't been in a concave pocket for multiple vertices already. - while (convexified.size() >= 2 - && (LinearAlg2D::pointIsLeftOfLine(convexified.path->back(), (*convexified.path)[convexified.size() - 2], current) >= 0 - || LinearAlg2D::pointIsLeftOfLine(convexified.path->back(), (*convexified.path)[convexified.size() - 2], convexified.path->front()) > 0)) + for (const auto window : poly | ranges::views::sliding(2)) { - convexified.path->pop_back(); + const Point2LL& current = window[0]; + const Point2LL& after = window[1]; + + if (LinearAlg2D::pointIsLeftOfLine(current, convexified.path->back(), after) < 0) + { + //Track backwards to make sure we haven't been in a concave pocket for multiple vertices already. + while(convexified.size() >= 2 && LinearAlg2D::pointIsLeftOfLine(convexified.path->back(), (*convexified.path)[convexified.size() - 2], current) > 0) + { + convexified.path->pop_back(); + } + convexified.path->push_back(current); + } } - convexified.path->push_back(current); - } - // remove last vertex as the starting vertex is added in the last iteration of the loop - convexified.path->pop_back(); + }; + + std::sort(poly.begin(), poly.end(), [](Point2LL a, Point2LL b) { return a.X == b.X ? a.Y < b.Y : a.X < b.X; }); + makeSortedPolyConvex(poly); + std::reverse(poly.begin(), poly.end()); + makeSortedPolyConvex(poly); - poly.path->swap(*convexified.path); // Due to vector's implementation, this is constant time. + // Due to vector's implementation, this is constant time + poly.path->swap(*convexified.path); } } From 727a54d060fc3523decdeb149895fac6ec107492 Mon Sep 17 00:00:00 2001 From: "c.lamboo" Date: Thu, 11 Jan 2024 10:59:26 +0100 Subject: [PATCH 060/201] Also add raft polygons to gcode layer for raft base and middle We already implemented it for the raft top, see https://github.com/Ultimaker/CuraEngine/pull/1989 CURA-11395 --- src/FffGcodeWriter.cpp | 71 +++++++++++++++++++++++++++++++++++++----- 1 file changed, 63 insertions(+), 8 deletions(-) diff --git a/src/FffGcodeWriter.cpp b/src/FffGcodeWriter.cpp index 7d01850dac..bcba398875 100644 --- a/src/FffGcodeWriter.cpp +++ b/src/FffGcodeWriter.cpp @@ -575,7 +575,7 @@ void FffGcodeWriter::processRaft(const SliceDataStorage& storage) constexpr bool retract_before_outer_wall = false; constexpr coord_t wipe_dist = 0; - Polygons raft_polygons; // should remain empty, since we only have the lines pattern for the raft... + Polygons raft_polygons; std::optional last_planned_position = std::optional(); unsigned int current_extruder_nr = base_extruder_nr; @@ -604,7 +604,7 @@ void FffGcodeWriter::processRaft(const SliceDataStorage& storage) Application::getInstance().communication_->sendLayerComplete(layer_nr, z, layer_height); - Polygons raftLines; + Polygons raft_lines; AngleDegrees fill_angle = (num_surface_layers + num_interface_layers) % 2 ? 45 : 135; // 90 degrees rotated from the interface layer. constexpr bool zig_zaggify_infill = false; constexpr bool connect_polygons = true; // causes less jerks, so better adhesion @@ -674,7 +674,7 @@ void FffGcodeWriter::processRaft(const SliceDataStorage& storage) zag_skip_count, pocket_size); std::vector raft_paths; - infill_comp.generate(raft_paths, raft_polygons, raftLines, base_settings, layer_nr, SectionType::ADHESION); + infill_comp.generate(raft_paths, raft_polygons, raft_lines, base_settings, layer_nr, SectionType::ADHESION); if (! raft_paths.empty()) { const GCodePathConfig& config = gcode_layer.configs_storage_.raft_base_config; @@ -698,14 +698,40 @@ void FffGcodeWriter::processRaft(const SliceDataStorage& storage) raft_paths); wall_orderer.addToLayer(); } - gcode_layer.addLinesByOptimizer(raftLines, gcode_layer.configs_storage_.raft_base_config, SpaceFillType::Lines); + const auto wipe_dist = 0; + const auto spiralize = false; + const auto flow_ratio = 1.0_r; + const auto enable_travel_optimization = false; + const auto always_retract = false; + const auto reverse_order = false; + + gcode_layer.addLinesByOptimizer( + raft_lines, + gcode_layer.configs_storage_.raft_base_config, + SpaceFillType::Lines, + enable_travel_optimization, + wipe_dist, + flow_ratio, + last_planned_position); + last_planned_position = gcode_layer.getLastPlannedPositionOrStartingPosition(); + gcode_layer.addPolygonsByOptimizer( + raft_polygons, + gcode_layer.configs_storage_.raft_base_config, + ZSeamConfig(), + wipe_dist, + spiralize, + flow_ratio, + always_retract, + reverse_order, + last_planned_position + ); raft_polygons.clear(); - raftLines.clear(); + raft_lines.clear(); + last_planned_position = gcode_layer.getLastPlannedPositionOrStartingPosition(); } layer_plan_buffer.handle(gcode_layer, gcode); - last_planned_position = gcode_layer.getLastPlannedPositionOrStartingPosition(); } const coord_t interface_layer_height = interface_settings.get("raft_interface_thickness"); @@ -834,7 +860,34 @@ void FffGcodeWriter::processRaft(const SliceDataStorage& storage) raft_paths); wall_orderer.addToLayer(); } - gcode_layer.addLinesByOptimizer(raft_lines, gcode_layer.configs_storage_.raft_interface_config, SpaceFillType::Lines, false, 0, 1.0, last_planned_position); + + const auto wipe_dist = 0; + const auto spiralize = false; + const auto flow_ratio = 1.0_r; + const auto enable_travel_optimization = false; + const auto always_retract = false; + const auto reverse_order = false; + + gcode_layer.addLinesByOptimizer( + raft_lines, + gcode_layer.configs_storage_.raft_interface_config, + SpaceFillType::Lines, + enable_travel_optimization, + wipe_dist, + flow_ratio, + last_planned_position); + last_planned_position = gcode_layer.getLastPlannedPositionOrStartingPosition(); + gcode_layer.addPolygonsByOptimizer( + raft_polygons, + gcode_layer.configs_storage_.raft_interface_config, + ZSeamConfig(), + wipe_dist, + spiralize, + flow_ratio, + always_retract, + reverse_order, + last_planned_position + ); raft_polygons.clear(); raft_lines.clear(); @@ -995,6 +1048,7 @@ void FffGcodeWriter::processRaft(const SliceDataStorage& storage) wipe_dist, flow_ratio, last_planned_position); + last_planned_position = gcode_layer.getLastPlannedPositionOrStartingPosition(); gcode_layer.addPolygonsByOptimizer( raft_polygons, gcode_layer.configs_storage_.raft_surface_config, @@ -1004,7 +1058,8 @@ void FffGcodeWriter::processRaft(const SliceDataStorage& storage) flow_ratio, always_retract, reverse_order, - gcode_layer.getLastPlannedPositionOrStartingPosition()); + last_planned_position); + last_planned_position = gcode_layer.getLastPlannedPositionOrStartingPosition(); raft_polygons.clear(); raft_lines.clear(); From 2b9b140a00e756f1d3e765104469a50d7c1d5b0c Mon Sep 17 00:00:00 2001 From: casperlamboo Date: Thu, 11 Jan 2024 09:59:58 +0000 Subject: [PATCH 061/201] Applied clang-format. --- src/FffGcodeWriter.cpp | 6 ++---- src/utils/polygon.cpp | 15 ++++++++++----- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/src/FffGcodeWriter.cpp b/src/FffGcodeWriter.cpp index bcba398875..abc2e0c25c 100644 --- a/src/FffGcodeWriter.cpp +++ b/src/FffGcodeWriter.cpp @@ -724,8 +724,7 @@ void FffGcodeWriter::processRaft(const SliceDataStorage& storage) flow_ratio, always_retract, reverse_order, - last_planned_position - ); + last_planned_position); raft_polygons.clear(); raft_lines.clear(); last_planned_position = gcode_layer.getLastPlannedPositionOrStartingPosition(); @@ -886,8 +885,7 @@ void FffGcodeWriter::processRaft(const SliceDataStorage& storage) flow_ratio, always_retract, reverse_order, - last_planned_position - ); + last_planned_position); raft_polygons.clear(); raft_lines.clear(); diff --git a/src/utils/polygon.cpp b/src/utils/polygon.cpp index 64685470b7..57d2db1810 100644 --- a/src/utils/polygon.cpp +++ b/src/utils/polygon.cpp @@ -14,10 +14,9 @@ #include #include #include +#include #include #include -#include - #include "utils/ListPolyIt.h" #include "utils/PolylineStitcher.h" @@ -127,8 +126,8 @@ void Polygons::makeConvex() if (LinearAlg2D::pointIsLeftOfLine(current, convexified.path->back(), after) < 0) { - //Track backwards to make sure we haven't been in a concave pocket for multiple vertices already. - while(convexified.size() >= 2 && LinearAlg2D::pointIsLeftOfLine(convexified.path->back(), (*convexified.path)[convexified.size() - 2], current) > 0) + // Track backwards to make sure we haven't been in a concave pocket for multiple vertices already. + while (convexified.size() >= 2 && LinearAlg2D::pointIsLeftOfLine(convexified.path->back(), (*convexified.path)[convexified.size() - 2], current) > 0) { convexified.path->pop_back(); } @@ -137,7 +136,13 @@ void Polygons::makeConvex() } }; - std::sort(poly.begin(), poly.end(), [](Point2LL a, Point2LL b) { return a.X == b.X ? a.Y < b.Y : a.X < b.X; }); + std::sort( + poly.begin(), + poly.end(), + [](Point2LL a, Point2LL b) + { + return a.X == b.X ? a.Y < b.Y : a.X < b.X; + }); makeSortedPolyConvex(poly); std::reverse(poly.begin(), poly.end()); makeSortedPolyConvex(poly); From 6bfc431682a02fce6120699a52c283aff2087a01 Mon Sep 17 00:00:00 2001 From: "c.lamboo" Date: Thu, 11 Jan 2024 12:40:18 +0100 Subject: [PATCH 062/201] Fix LayerPlan unit test CURA-11395 --- tests/LayerPlanTest.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/LayerPlanTest.cpp b/tests/LayerPlanTest.cpp index c69223709a..88ebbf4331 100644 --- a/tests/LayerPlanTest.cpp +++ b/tests/LayerPlanTest.cpp @@ -136,11 +136,13 @@ class LayerPlanTest : public testing::Test settings->add("raft_interface_line_width", "0.402"); settings->add("raft_interface_speed", "52"); settings->add("raft_interface_thickness", "0.102"); + settings->add("raft_interface_layers", "3"); settings->add("raft_surface_acceleration", "5003"); settings->add("raft_surface_jerk", "5.3"); settings->add("raft_surface_line_width", "0.403"); settings->add("raft_surface_speed", "53"); settings->add("raft_surface_thickness", "0.103"); + settings->add("raft_surface_layers", "3"); settings->add("retraction_amount", "8"); settings->add("retraction_combing", "off"); settings->add("retraction_count_max", "30"); From 724103113de54ef2f2253b61a6705e12991e5d1e Mon Sep 17 00:00:00 2001 From: "c.lamboo" Date: Thu, 11 Jan 2024 12:50:39 +0100 Subject: [PATCH 063/201] Fix Polygon unit test CURA-11395 --- src/utils/polygon.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/utils/polygon.cpp b/src/utils/polygon.cpp index 57d2db1810..7784e6555c 100644 --- a/src/utils/polygon.cpp +++ b/src/utils/polygon.cpp @@ -127,7 +127,7 @@ void Polygons::makeConvex() if (LinearAlg2D::pointIsLeftOfLine(current, convexified.path->back(), after) < 0) { // Track backwards to make sure we haven't been in a concave pocket for multiple vertices already. - while (convexified.size() >= 2 && LinearAlg2D::pointIsLeftOfLine(convexified.path->back(), (*convexified.path)[convexified.size() - 2], current) > 0) + while (convexified.size() >= 2 && (LinearAlg2D::pointIsLeftOfLine(convexified.path->back(), (*convexified.path)[convexified.size() - 2], current) >= 0 || LinearAlg2D::pointIsLeftOfLine(convexified.path->back(), (*convexified.path)[convexified.size() - 2], convexified.path->front()) > 0)) { convexified.path->pop_back(); } From e9d17a0dc03f6449ab0424710793bf48463a1dbb Mon Sep 17 00:00:00 2001 From: casperlamboo Date: Thu, 11 Jan 2024 11:52:00 +0000 Subject: [PATCH 064/201] Applied clang-format. --- src/utils/polygon.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/utils/polygon.cpp b/src/utils/polygon.cpp index 7784e6555c..fbeedc0199 100644 --- a/src/utils/polygon.cpp +++ b/src/utils/polygon.cpp @@ -127,7 +127,9 @@ void Polygons::makeConvex() if (LinearAlg2D::pointIsLeftOfLine(current, convexified.path->back(), after) < 0) { // Track backwards to make sure we haven't been in a concave pocket for multiple vertices already. - while (convexified.size() >= 2 && (LinearAlg2D::pointIsLeftOfLine(convexified.path->back(), (*convexified.path)[convexified.size() - 2], current) >= 0 || LinearAlg2D::pointIsLeftOfLine(convexified.path->back(), (*convexified.path)[convexified.size() - 2], convexified.path->front()) > 0)) + while (convexified.size() >= 2 + && (LinearAlg2D::pointIsLeftOfLine(convexified.path->back(), (*convexified.path)[convexified.size() - 2], current) >= 0 + || LinearAlg2D::pointIsLeftOfLine(convexified.path->back(), (*convexified.path)[convexified.size() - 2], convexified.path->front()) > 0)) { convexified.path->pop_back(); } From 965974d70bc79aaa2d7ab1bc54e6a68aa98a9126 Mon Sep 17 00:00:00 2001 From: "c.lamboo" Date: Thu, 11 Jan 2024 12:56:24 +0100 Subject: [PATCH 065/201] Don't include holes in convex hull CURA-11395 --- src/utils/polygon.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/utils/polygon.cpp b/src/utils/polygon.cpp index fbeedc0199..1c698598db 100644 --- a/src/utils/polygon.cpp +++ b/src/utils/polygon.cpp @@ -105,6 +105,15 @@ Polygons Polygons::approxConvexHull(int extra_outset) void Polygons::makeConvex() { + // early out if there is nothing to do + if (empty()) + { + return; + } + + // convex hulls cannot have holes, so remove all paths except the outerpath + this->paths.resize(1); + // Andrew’s Monotone Chain Convex Hull Algorithm for (PolygonRef poly : *this) { From 3134eca9e27a988b0f08cad1664b8565869d8c3b Mon Sep 17 00:00:00 2001 From: "c.lamboo" Date: Tue, 16 Jan 2024 13:43:46 +0100 Subject: [PATCH 066/201] Fix convex hull in the case where the convex hull consist of islands CURA-11395 --- src/utils/polygon.cpp | 73 ++++++++++++++++++++----------------------- 1 file changed, 34 insertions(+), 39 deletions(-) diff --git a/src/utils/polygon.cpp b/src/utils/polygon.cpp index 1c698598db..3966b581a7 100644 --- a/src/utils/polygon.cpp +++ b/src/utils/polygon.cpp @@ -17,6 +17,7 @@ #include #include #include +#include #include "utils/ListPolyIt.h" #include "utils/PolylineStitcher.h" @@ -111,56 +112,50 @@ void Polygons::makeConvex() return; } - // convex hulls cannot have holes, so remove all paths except the outerpath - this->paths.resize(1); - // Andrew’s Monotone Chain Convex Hull Algorithm - for (PolygonRef poly : *this) + std::vector points; + + for (const auto& poly : this->paths) { - if (poly.size() <= 3) - { - // Already convex. - continue; - } + points.insert(points.end(), poly.begin(), poly.end()); + } + + ClipperLib::Path convexified; + auto make_sorted_poly_convex = [&convexified](std::vector& poly) + { + convexified.push_back(poly[0]); - Polygon convexified; - auto makeSortedPolyConvex = [&convexified](PolygonRef& poly) + for (const auto window : poly | ranges::views::sliding(2)) { - convexified.path->push_back(poly[0]); + const Point2LL& current = window[0]; + const Point2LL& after = window[1]; - for (const auto window : poly | ranges::views::sliding(2)) + if (LinearAlg2D::pointIsLeftOfLine(current, convexified.back(), after) < 0) { - const Point2LL& current = window[0]; - const Point2LL& after = window[1]; - - if (LinearAlg2D::pointIsLeftOfLine(current, convexified.path->back(), after) < 0) + // Track backwards to make sure we haven't been in a concave pocket for multiple vertices already. + while (convexified.size() >= 2 + && (LinearAlg2D::pointIsLeftOfLine(convexified.back(), convexified[convexified.size() - 2], current) >= 0 + || LinearAlg2D::pointIsLeftOfLine(convexified.back(), convexified[convexified.size() - 2], convexified.front()) > 0)) { - // Track backwards to make sure we haven't been in a concave pocket for multiple vertices already. - while (convexified.size() >= 2 - && (LinearAlg2D::pointIsLeftOfLine(convexified.path->back(), (*convexified.path)[convexified.size() - 2], current) >= 0 - || LinearAlg2D::pointIsLeftOfLine(convexified.path->back(), (*convexified.path)[convexified.size() - 2], convexified.path->front()) > 0)) - { - convexified.path->pop_back(); - } - convexified.path->push_back(current); + convexified.pop_back(); } + convexified.push_back(current); } - }; + } + }; - std::sort( - poly.begin(), - poly.end(), - [](Point2LL a, Point2LL b) - { - return a.X == b.X ? a.Y < b.Y : a.X < b.X; - }); - makeSortedPolyConvex(poly); - std::reverse(poly.begin(), poly.end()); - makeSortedPolyConvex(poly); + std::sort( + points.begin(), + points.end(), + [](Point2LL a, Point2LL b) + { + return a.X == b.X ? a.Y < b.Y : a.X < b.X; + }); + make_sorted_poly_convex(points); + std::reverse(points.begin(), points.end()); + make_sorted_poly_convex(points); - // Due to vector's implementation, this is constant time - poly.path->swap(*convexified.path); - } + this->paths = { convexified }; } size_t Polygons::pointCount() const From ae03217efc170a994e84343e4d0b5cabdb10b849 Mon Sep 17 00:00:00 2001 From: "c.lamboo" Date: Tue, 16 Jan 2024 16:16:47 +0100 Subject: [PATCH 067/201] Only remove inside corners for the raft poly-islands instead of the whole polygon CURA-11395 --- src/raft.cpp | 45 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 44 insertions(+), 1 deletion(-) diff --git a/src/raft.cpp b/src/raft.cpp index 2fb12e100b..627bd87d73 100644 --- a/src/raft.cpp +++ b/src/raft.cpp @@ -5,6 +5,8 @@ #include +#include + #include "Application.h" //To get settings. #include "ExtruderTrain.h" #include "Slice.h" @@ -59,7 +61,48 @@ void Raft::generate(SliceDataStorage& storage) { if (remove_inside_corners) { - outline.makeConvex(); + // Make all parts convex. We could take the convex hull of the union of all parts, but that would + // result in a massive brim if you would have models in all corners of the build plate. We instead + // perform a convex hull operation on each polygon part separately, this will result in much smaller + // raft islands. However, this might result in inside corners in the raft outline in the situation + // where after the merge operations some parts become connected. To properly make sure that there are + // no inside corners we perform a convex hull operation followed by a merge. If the number of polygon + // parts no longer decrease we have found the polygons that have both no longer inside corners and + // occupy the smallest possible area. + outline = outline.unionPolygons(); + auto outline_parts = outline.unionPolygons().splitIntoParts(); + auto nr_of_parts = outline_parts.size(); + + while (true) + { + outline.clear(); + + for (auto& part : outline_parts) + { + part.makeConvex(); + outline.add(part); + } + + outline = outline.unionPolygons(); + outline_parts = outline.splitIntoParts(); + const auto new_nr_of_parts = outline_parts.size(); + + if (new_nr_of_parts > nr_of_parts) + { + // from the recursive convex hull + merge operation the number of parts cannot logically increase + // if it does increase, and allow the loop to continue we might get into an infinite loop; so break out of the loop + // this might produce a raft with inside corners, but that is better than an infinite loop + assert(false); + spdlog::warn("Error while removing inside corners from raft; merge operation increased the number of parts"); + break; + } + + if (new_nr_of_parts == nr_of_parts) + { + break; + } + nr_of_parts = new_nr_of_parts; + } } else { From 25bca4d1357b86d60d7c18ce01bdfb6a7c872ca2 Mon Sep 17 00:00:00 2001 From: "c.lamboo" Date: Tue, 16 Jan 2024 16:22:26 +0100 Subject: [PATCH 068/201] Warn before assert So we get an actual reason for the crash before the program halts CURA-11395 --- src/raft.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/raft.cpp b/src/raft.cpp index 627bd87d73..2115996110 100644 --- a/src/raft.cpp +++ b/src/raft.cpp @@ -92,8 +92,8 @@ void Raft::generate(SliceDataStorage& storage) // from the recursive convex hull + merge operation the number of parts cannot logically increase // if it does increase, and allow the loop to continue we might get into an infinite loop; so break out of the loop // this might produce a raft with inside corners, but that is better than an infinite loop - assert(false); spdlog::warn("Error while removing inside corners from raft; merge operation increased the number of parts"); + assert(false); break; } From 6c2388975cf95be2baaec05167a71533c32e34d7 Mon Sep 17 00:00:00 2001 From: "c.lamboo" Date: Tue, 16 Jan 2024 16:44:18 +0100 Subject: [PATCH 069/201] Update year CURA-11395 --- src/utils/polygon.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/utils/polygon.cpp b/src/utils/polygon.cpp index 3966b581a7..b5a80aacf6 100644 --- a/src/utils/polygon.cpp +++ b/src/utils/polygon.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2023 UltiMaker +// Copyright (c) 2024 UltiMaker // CuraEngine is released under the terms of the AGPLv3 or higher. #include "utils/polygon.h" From 279c1963891cbdf38fbbec7f72f64f0cf6b2c0f0 Mon Sep 17 00:00:00 2001 From: "c.lamboo" Date: Wed, 17 Jan 2024 12:45:09 +0100 Subject: [PATCH 070/201] Use `__FILE__` in favor of `std::source_location` Would rather use modern cpp but compilers :( CURA-11395 --- benchmark/wall_benchmark.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/benchmark/wall_benchmark.h b/benchmark/wall_benchmark.h index fe302d6a02..4c2c597bf3 100644 --- a/benchmark/wall_benchmark.h +++ b/benchmark/wall_benchmark.h @@ -1,4 +1,4 @@ -// Copyright (c) 2023 UltiMaker +// Copyright (c) 2024 UltiMaker // CuraEngine is released under the terms of the AGPLv3 or higher #ifndef CURAENGINE_WALL_BENCHMARK_H @@ -105,7 +105,7 @@ class HolesWallTestFixture : public benchmark::Fixture void SetUp(const ::benchmark::State& state) { - auto wkt_file = std::filesystem::path(std::source_location::current().file_name()).parent_path().append("hole.wkt"); + auto wkt_file = std::filesystem::path(__FILE__).parent_path().append("hole.wkt"); std::ifstream file{ wkt_file }; std::stringstream buffer; From 9bd95908d082af6e4dac9201649f3e46f0456de9 Mon Sep 17 00:00:00 2001 From: "saumya.jain" Date: Wed, 17 Jan 2024 15:08:32 +0100 Subject: [PATCH 071/201] fixing holes.wkt file for benchmark testing CURA-11395 --- benchmark/holes.wkt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/benchmark/holes.wkt b/benchmark/holes.wkt index 8abb597107..2851ade30c 100644 --- a/benchmark/holes.wkt +++ b/benchmark/holes.wkt @@ -1 +1 @@ -POLYGON ((95494 126805, 96503 133622, 98177 140305, 100476 146724, 103404 152913, 106933 158804, 111015 164309, 115613 169380, 120688 173982, 126196 178066, 132082 181592, 138275 184523, 144689 186820, 151369 188494, 158160 189502, 165000 189839, 171805 189505, 178630 188494, 185310 186820, 191724 184524, 197917 181592, 203803 178066, 209312 173982, 214386 169380, 218984 164310, 223066 158803, 226595 152913, 229523 146724, 231822 140305, 233496 133622, 234502 126839, 234839 119992, 234505 113189, 233494 106367, 231822 99694, 229523 93273, 226591 87078, 223066 81196, 218982 75688, 214380 70613, 209312 66017, 203803 61933, 197913 58404, 191724 55476, 185310 53179, 178630 51505, 171839 50497, 165000 50161, 158194 50494, 151369 51505, 144689 53179, 138275 55475, 132086 58404, 126196 61933, 120688 66017, 115613 70619, 111017 75688, 106933 81196, 103404 87086, 100477 93273, 98177 99694, 96503 106375, 95497 113155, 95161 120009, 95494 126805) (96691 120789, 96887 120703, 98972 120702, 99166 120992, 99166 124114, 98876 124308, 96967 124308, 96763 124059, 96609 120962, 96691 120789) (96759 115930, 96854 115769, 97010 115697, 98972 115692, 99166 115982, 99166 119104, 98876 119298, 96750 119298, 96613 119018, 96759 115930) (96932 125803, 97122 125714, 98972 125712, 99166 126002, 99166 129124, 98876 129318, 97454 129315, 97247 129098, 96890 126714, 96854 125972, 96932 125803) (96858 114008, 96890 113284, 97244 110899, 97354 110749, 97488 110687, 98972 110682, 99166 110972, 99166 114094, 98876 114288, 97090 114288, 96970 114241, 96858 114008) (97589 130826, 97798 130725, 98971 130722, 99166 130980, 99166 134134, 98907 134324, 98230 134286, 98073 134133, 97876 133350, 97527 131003, 97589 130826) (97877 106641, 98062 105900, 98230 105714, 99005 105700, 99107 105754, 99166 105897, 99166 109084, 98876 109278, 97718 109272, 97626 109219, 97534 108970, 97877 106641) (100570 98955, 100578 97146, 101040 95847, 101280 95650, 103981 95650, 104176 95908, 104176 99064, 103886 99258, 100761 99258, 100655 99173, 100570 98955) (100575 100863, 100636 100762, 100849 100663, 103982 100662, 104176 100952, 104176 104074, 103886 104268, 100760 104268, 100576 104019, 100575 100863) (100570 105916, 100633 105775, 100849 105673, 103982 105672, 104176 105962, 104176 109084, 103886 109278, 100764 109278, 100571 108999, 100570 105916) (100570 110876, 100849 110683, 103982 110682, 104176 110972, 104176 114094, 103886 114288, 100764 114288, 100571 114009, 100570 110876) (100570 115886, 100849 115693, 103982 115692, 104176 115982, 104176 119104, 103886 119298, 100764 119298, 100571 119019, 100570 115886) (100570 120896, 100849 120703, 103982 120702, 104176 120992, 104176 124114, 103886 124308, 100764 124308, 100571 124029, 100570 120896) (100570 125906, 100849 125713, 103982 125712, 104176 126002, 104176 129124, 103886 129318, 100764 129318, 100571 129039, 100570 125906) (100574 130928, 100632 130826, 100849 130723, 103981 130722, 104176 130980, 104176 134134, 103886 134328, 100764 134328, 100571 134049, 100574 130928) (100632 135836, 100849 135733, 103982 135732, 104176 136022, 104176 139144, 103886 139338, 100760 139338, 100575 139085, 100573 135945, 100632 135836) (100570 140891, 100849 140743, 103982 140742, 104176 141032, 104176 144155, 103883 144349, 101284 144349, 101055 144183, 100576 142857, 100570 140891) (101762 94096, 101717 93926, 103187 90811, 103352 90670, 104018 90669, 104117 90722, 104176 90865, 104176 94052, 103886 94246, 102040 94246, 101762 94096) (101768 146186, 101773 145954, 101866 145779, 103980 145751, 104176 146014, 104176 149172, 104052 149295, 103479 149359, 103204 149218, 101768 146186) (105580 86169, 105913 85710, 106074 85630, 108992 85630, 109186 85920, 109186 89042, 108896 89236, 105770 89236, 105587 88990, 105580 86169) (105580 90884, 105643 90743, 105859 90641, 108992 90640, 109186 90930, 109186 94052, 108896 94246, 105774 94246, 105581 93967, 105580 90884) (105584 95856, 105642 95754, 105859 95651, 108991 95650, 109186 95908, 109186 99064, 108896 99258, 105774 99258, 105581 98979, 105584 95856) (105580 100856, 105859 100663, 108992 100662, 109186 100952, 109186 104074, 108896 104268, 105774 104268, 105581 103989, 105580 100856) (105580 105866, 105859 105673, 108992 105672, 109186 105962, 109186 109084, 108896 109278, 105774 109278, 105581 108999, 105580 105866) (105580 110876, 105859 110683, 108992 110682, 109186 110972, 109186 114094, 108896 114288, 105774 114288, 105581 114009, 105580 110876) (105580 115886, 105859 115693, 108992 115692, 109186 115982, 109186 119104, 108896 119298, 105774 119298, 105581 119019, 105580 115886) (105580 120896, 105859 120703, 108992 120702, 109186 120992, 109186 124114, 108896 124308, 105774 124308, 105581 124029, 105580 120896) (105580 125906, 105859 125713, 108992 125712, 109186 126002, 109186 129124, 108896 129318, 105774 129318, 105581 129039, 105580 125906) (105642 130826, 105859 130723, 108991 130722, 109186 130980, 109186 134134, 108896 134328, 105774 134328, 105581 134049, 105584 130928, 105642 130826) (105580 135926, 105859 135733, 108992 135732, 109186 136022, 109186 139144, 108896 139338, 105774 139338, 105581 139059, 105580 135926) (105580 140936, 105859 140743, 108992 140742, 109186 141032, 109186 144155, 108896 144349, 105774 144349, 105581 144070, 105580 140936) (105584 145960, 105663 145840, 105859 145754, 108991 145753, 109186 146011, 109186 149165, 108896 149359, 105774 149359, 105581 149080, 105584 145960) (105582 150983, 105663 150850, 105859 150764, 108992 150763, 109186 151053, 109186 154175, 108896 154369, 106074 154369, 105922 154300, 105580 153841, 105582 150983) (106981 84045, 106964 83867, 108096 81974, 108677 81190, 108885 81115, 109106 81184, 109186 81345, 109186 84032, 108896 84226, 107276 84226, 106981 84045) (107023 155881, 107166 155776, 108992 155773, 109186 156063, 109184 158675, 109136 158774, 108814 158900, 108710 158847, 108090 158016, 107018 156228, 107023 155881) (110590 78898, 110631 78562, 112103 76572, 112917 75675, 113065 75610, 114007 75610, 114196 75900, 114196 79022, 113906 79216, 110828 79216, 110699 79159, 110590 78898) (110869 80621, 114002 80620, 114196 80910, 114196 84032, 113906 84226, 110784 84226, 110591 83947, 110590 80811, 110869 80621) (110590 85824, 110869 85631, 114002 85630, 114196 85920, 114196 89042, 113906 89236, 110784 89236, 110591 88957, 110590 85824) (110590 90834, 110869 90641, 114002 90640, 114196 90930, 114196 94052, 113906 94246, 110784 94246, 110591 93967, 110590 90834) (110652 95754, 110869 95651, 114001 95650, 114196 95908, 114196 99064, 113906 99258, 110784 99258, 110591 98979, 110594 95856, 110652 95754) (110590 100856, 110869 100663, 114002 100662, 114196 100952, 114196 104074, 113906 104268, 110784 104268, 110591 103989, 110590 100856) (110590 105866, 110869 105673, 114002 105672, 114196 105962, 114196 109084, 113906 109278, 110784 109278, 110591 108999, 110590 105866) (110590 110876, 110869 110683, 114002 110682, 114196 110972, 114196 114094, 113906 114288, 110784 114288, 110591 114009, 110590 110876) (110590 115886, 110869 115693, 114002 115692, 114196 115982, 114196 119104, 113906 119298, 110784 119298, 110591 119019, 110590 115886) (110590 120896, 110869 120703, 114002 120702, 114196 120992, 114196 124114, 113906 124308, 110784 124308, 110591 124029, 110590 120896) (110590 125906, 110869 125713, 114002 125712, 114196 126002, 114196 129124, 113906 129318, 110784 129318, 110591 129039, 110590 125906) (110594 130928, 110652 130826, 110869 130723, 114001 130722, 114196 130980, 114196 134134, 113906 134328, 110784 134328, 110591 134049, 110594 130928) (110590 135926, 110869 135733, 114002 135732, 114196 136022, 114196 139144, 113906 139338, 110784 139338, 110591 139059, 110590 135926) (110590 140936, 110869 140743, 114002 140742, 114196 141032, 114196 144155, 113906 144349, 110784 144349, 110591 144070, 110590 140936) (110594 145959, 110652 145857, 110869 145754, 114001 145753, 114196 146011, 114196 149165, 113906 149359, 110784 149359, 110591 149080, 110594 145959) (110590 150957, 110869 150764, 114002 150763, 114196 151053, 114196 154175, 113906 154369, 110784 154369, 110591 154090, 110590 150957) (110590 155967, 110869 155774, 114002 155773, 114196 156063, 114196 159185, 113906 159379, 110744 159379, 110596 159128, 110590 155967) (110652 160863, 110813 160783, 114002 160783, 114196 161073, 114196 164195, 113939 164389, 112980 164389, 112090 163412, 110649 161467, 110652 160863) (115600 72719, 116607 71604, 117658 70651, 117793 70600, 119017 70600, 119206 70890, 119206 74012, 118916 74206, 115794 74206, 115600 73949, 115600 72719) (115600 75804, 115879 75611, 119012 75610, 119206 75900, 119206 79022, 118916 79216, 115794 79216, 115601 78937, 115600 75804) (115600 80814, 115879 80621, 119012 80620, 119206 80910, 119206 84032, 118916 84226, 115794 84226, 115601 83947, 115600 80814) (115600 85824, 115879 85631, 119012 85630, 119206 85920, 119206 89042, 118916 89236, 115794 89236, 115601 88957, 115600 85824) (115600 90834, 115879 90641, 119012 90640, 119206 90930, 119206 94052, 118916 94246, 115794 94246, 115601 93967, 115600 90834) (115604 95856, 115662 95754, 115879 95651, 119011 95650, 119206 95908, 119206 99064, 118916 99258, 115794 99258, 115601 98979, 115604 95856) (115600 100856, 115879 100663, 119012 100662, 119206 100952, 119206 104074, 118916 104268, 115794 104268, 115601 103989, 115600 100856) (115600 105866, 115879 105673, 119012 105672, 119206 105962, 119206 109084, 118916 109278, 115794 109278, 115601 108999, 115600 105866) (115600 110876, 115879 110683, 119012 110682, 119206 110972, 119206 114094, 118916 114288, 115794 114288, 115601 114009, 115600 110876) (115879 115693, 119012 115692, 119206 115982, 119206 119104, 118916 119298, 115794 119298, 115601 119019, 115600 115886, 115879 115693) (115600 120896, 115879 120703, 119012 120702, 119206 120992, 119206 124114, 118916 124308, 115794 124308, 115601 124029, 115600 120896) (115600 125906, 115879 125713, 119012 125712, 119206 126002, 119206 129124, 118916 129318, 115794 129318, 115601 129039, 115600 125906) (115604 130928, 115662 130826, 115879 130723, 119011 130722, 119206 130980, 119206 134134, 118916 134328, 115794 134328, 115601 134049, 115604 130928) (115600 135926, 115879 135733, 119012 135732, 119206 136022, 119206 139144, 118916 139338, 115794 139338, 115601 139059, 115600 135926) (115600 140936, 115879 140743, 119012 140742, 119206 141032, 119206 144155, 118916 144349, 115794 144349, 115601 144070, 115600 140936) (115604 145959, 115662 145857, 115879 145754, 119011 145753, 119206 146011, 119206 149165, 118916 149359, 115794 149359, 115601 149080, 115604 145959) (115600 150957, 115879 150764, 119012 150763, 119206 151053, 119206 154175, 118916 154369, 115794 154369, 115601 154090, 115600 150957) (115600 155967, 115879 155774, 119012 155773, 119206 156063, 119206 159185, 118916 159379, 115794 159379, 115601 159100, 115600 155967) (115600 160977, 115879 160784, 119012 160783, 119206 161073, 119206 164195, 118916 164389, 115794 164389, 115601 164110, 115600 160977) (115600 165982, 115879 165794, 119012 165793, 119206 166083, 119206 169205, 118949 169399, 117719 169399, 116604 168392, 115651 167341, 115600 167206, 115600 165982) (120610 67980, 121588 67089, 123592 65605, 124136 65652, 124216 65813, 124216 69002, 123926 69196, 120804 69196, 120610 68939, 120610 67980) (120610 70794, 120889 70601, 124022 70600, 124216 70890, 124216 74012, 123926 74206, 120804 74206, 120611 73927, 120610 70794) (120610 75804, 120889 75611, 124022 75610, 124216 75900, 124216 79022, 123926 79216, 120804 79216, 120611 78937, 120610 75804) (120610 80814, 120889 80621, 124022 80620, 124216 80910, 124216 84032, 123926 84226, 120804 84226, 120611 83947, 120610 80814) (120610 85824, 120889 85631, 124022 85630, 124216 85920, 124216 89042, 123926 89236, 120804 89236, 120611 88957, 120610 85824) (120610 90834, 120889 90641, 124022 90640, 124216 90930, 124216 94052, 123926 94246, 120804 94246, 120611 93967, 120610 90834) (120614 95856, 120672 95754, 120889 95651, 124021 95650, 124216 95908, 124216 99064, 123926 99258, 120804 99258, 120611 98979, 120614 95856) (120610 100856, 120889 100663, 124022 100662, 124216 100952, 124216 104074, 123926 104268, 120804 104268, 120611 103989, 120610 100856) (120610 105866, 120889 105673, 124022 105672, 124216 105962, 124216 109084, 123926 109278, 120804 109278, 120611 108999, 120610 105866) (120610 110876, 120889 110683, 124022 110682, 124216 110972, 124216 114094, 123926 114288, 120804 114288, 120611 114009, 120610 110876) (120610 115886, 120889 115693, 124022 115692, 124216 115982, 124216 119104, 123926 119298, 120804 119298, 120611 119019, 120610 115886) (120610 120896, 120889 120703, 124022 120702, 124216 120992, 124216 124114, 123926 124308, 120804 124308, 120611 124029, 120610 120896) (120610 125906, 120889 125713, 124022 125712, 124216 126002, 124216 129124, 123926 129318, 120804 129318, 120611 129039, 120610 125906) (120614 130928, 120672 130826, 120889 130723, 124021 130722, 124216 130980, 124216 134134, 123926 134328, 120804 134328, 120611 134049, 120614 130928) (120610 135926, 120889 135733, 124022 135732, 124216 136022, 124216 139144, 123926 139338, 120804 139338, 120611 139059, 120610 135926) (120610 140936, 120889 140743, 124022 140742, 124216 141032, 124216 144155, 123926 144349, 120804 144349, 120611 144070, 120610 140936) (120614 145959, 120672 145857, 120889 145754, 124021 145753, 124216 146011, 124216 149165, 123926 149359, 120804 149359, 120611 149080, 120614 145959) (120610 150957, 120889 150764, 124022 150763, 124216 151053, 124216 154175, 123926 154369, 120804 154369, 120611 154090, 120610 150957) (120610 155967, 120889 155774, 124022 155773, 124216 156063, 124216 159185, 123926 159379, 120804 159379, 120611 159100, 120610 155967) (120610 160977, 120889 160784, 124022 160783, 124216 161073, 124216 164195, 123926 164389, 120804 164389, 120611 164110, 120610 160977) (120610 165987, 120889 165794, 124022 165793, 124216 166083, 124216 169205, 123926 169399, 120804 169399, 120611 169120, 120610 165987) (120610 170992, 120889 170804, 124022 170803, 124216 171093, 124216 174171, 124159 174300, 123898 174409, 123562 174368, 121571 172895, 120675 172082, 120610 171934, 120610 170992) (125620 65744, 125871 65596, 129032 65590, 129226 65880, 129226 69002, 128936 69196, 125814 69196, 125621 68917, 125620 65744) (125899 70601, 129032 70600, 129226 70890, 129226 74012, 128936 74206, 125814 74206, 125621 73927, 125620 70794, 125899 70601) (125620 75804, 125899 75611, 129032 75610, 129226 75900, 129226 79022, 128936 79216, 125814 79216, 125621 78937, 125620 75804) (125620 80814, 125899 80621, 129032 80620, 129226 80910, 129226 84032, 128936 84226, 125814 84226, 125621 83947, 125620 80814) (125620 85824, 125899 85631, 129032 85630, 129226 85920, 129226 89042, 128936 89236, 125814 89236, 125621 88957, 125620 85824) (125620 90834, 125899 90641, 129032 90640, 129226 90930, 129226 94052, 128936 94246, 125814 94246, 125621 93967, 125620 90834) (125624 95856, 125682 95754, 125899 95651, 129031 95650, 129226 95908, 129226 99064, 128936 99258, 125814 99258, 125621 98979, 125624 95856) (125620 100856, 125899 100663, 129032 100662, 129226 100952, 129226 104074, 128936 104268, 125814 104268, 125621 103989, 125620 100856) (125620 105866, 125899 105673, 129032 105672, 129226 105962, 129226 109084, 128936 109278, 125814 109278, 125621 108999, 125620 105866) (125620 110876, 125899 110683, 129032 110682, 129226 110972, 129226 114094, 128936 114288, 125814 114288, 125621 114009, 125620 110876) (125620 115886, 125899 115693, 129032 115692, 129226 115982, 129226 119104, 128936 119298, 125814 119298, 125621 119019, 125620 115886) (125620 120896, 125899 120703, 129032 120702, 129226 120992, 129226 124114, 128936 124308, 125814 124308, 125621 124029, 125620 120896) (125620 125906, 125899 125713, 129032 125712, 129226 126002, 129226 129124, 128936 129318, 125814 129318, 125621 129039, 125620 125906) (125624 130928, 125682 130826, 125899 130723, 129031 130722, 129226 130980, 129226 134134, 128936 134328, 125814 134328, 125621 134049, 125624 130928) (125620 135926, 125899 135733, 129032 135732, 129226 136022, 129226 139144, 128936 139338, 125814 139338, 125621 139059, 125620 135926) (125899 140743, 129032 140742, 129226 141032, 129226 144155, 128936 144349, 125814 144349, 125621 144070, 125620 140936, 125899 140743) (125624 145959, 125682 145857, 125899 145754, 129031 145753, 129226 146011, 129226 149165, 128936 149359, 125814 149359, 125621 149080, 125624 145959) (125620 150957, 125899 150764, 129032 150763, 129226 151053, 129226 154175, 128936 154369, 125814 154369, 125621 154090, 125620 150957) (125620 155967, 125899 155774, 129032 155773, 129226 156063, 129226 159185, 128936 159379, 125814 159379, 125621 159100, 125620 155967) (125620 160977, 125899 160784, 129032 160783, 129226 161073, 129226 164195, 128936 164389, 125814 164389, 125621 164110, 125620 160977) (125899 165794, 129032 165793, 129226 166083, 129226 169205, 128936 169399, 125814 169399, 125621 169120, 125620 165987, 125899 165794) (125620 170997, 125899 170804, 129032 170803, 129226 171093, 129226 174215, 128936 174409, 125870 174410, 125745 174367, 125621 174130, 125620 170997) (126099 63814, 126152 63710, 126983 63090, 128771 62018, 129118 62023, 129226 62201, 129226 63992, 128936 64186, 126291 64186, 126188 64091, 126099 63814) (126115 176114, 126184 175893, 126310 175816, 129032 175813, 129226 176103, 129224 177758, 129045 178018, 128867 178035, 126972 176902, 126190 176322, 126115 176114) (130699 60922, 131158 60580, 134016 60582, 134132 60642, 134236 60870, 134236 63992, 133946 64186, 130824 64186, 130631 63907, 130630 61074, 130699 60922) (130630 65784, 130909 65591, 134042 65590, 134236 65880, 134236 69002, 133946 69196, 130824 69196, 130631 68917, 130630 65784) (130630 70794, 130909 70601, 134042 70600, 134236 70890, 134236 74012, 133946 74206, 130824 74206, 130631 73927, 130630 70794) (130630 75804, 130909 75611, 134042 75610, 134236 75900, 134236 79022, 133946 79216, 130824 79216, 130631 78937, 130630 75804) (130630 80814, 130909 80621, 134042 80620, 134236 80910, 134236 84032, 133946 84226, 130824 84226, 130631 83947, 130630 80814) (130630 85824, 130909 85631, 134042 85630, 134236 85920, 134236 89042, 133946 89236, 130824 89236, 130631 88957, 130630 85824) (130630 90834, 130909 90641, 134042 90640, 134236 90930, 134236 94052, 133946 94246, 130824 94246, 130631 93967, 130630 90834) (130634 95856, 130692 95754, 130909 95651, 134041 95650, 134236 95908, 134236 99064, 133946 99258, 130824 99258, 130631 98979, 130634 95856) (130630 100856, 130909 100663, 134042 100662, 134236 100952, 134236 104074, 133946 104268, 130824 104268, 130631 103989, 130630 100856) (130630 105866, 130909 105673, 134042 105672, 134236 105962, 134236 109084, 133946 109278, 130824 109278, 130631 108999, 130630 105866) (130630 110876, 130909 110683, 134042 110682, 134236 110972, 134236 114094, 133946 114288, 130824 114288, 130631 114009, 130630 110876) (130630 115886, 130909 115693, 134042 115692, 134236 115982, 134236 119104, 133946 119298, 130824 119298, 130631 119019, 130630 115886) (130630 120896, 130909 120703, 134042 120702, 134236 120992, 134236 124114, 133946 124308, 130824 124308, 130631 124029, 130630 120896) (130909 125713, 134042 125712, 134236 126002, 134236 129124, 133946 129318, 130824 129318, 130631 129039, 130630 125906, 130909 125713) (130634 130928, 130692 130826, 130909 130723, 134041 130722, 134236 130980, 134236 134134, 133946 134328, 130824 134328, 130631 134049, 130634 130928) (130630 135926, 130909 135733, 134042 135732, 134236 136022, 134236 139144, 133946 139338, 130824 139338, 130631 139059, 130630 135926) (130630 140936, 130909 140743, 134042 140742, 134236 141032, 134236 144155, 133946 144349, 130824 144349, 130631 144070, 130630 140936) (130634 145959, 130692 145857, 130909 145754, 134041 145753, 134236 146011, 134236 149165, 133946 149359, 130824 149359, 130631 149080, 130634 145959) (130630 150957, 130909 150764, 134042 150763, 134236 151053, 134236 154175, 133946 154369, 130824 154369, 130631 154090, 130630 150957) (130630 155967, 130909 155774, 134042 155773, 134236 156063, 134236 159185, 133946 159379, 130824 159379, 130631 159100, 130630 155967) (130630 160977, 130909 160784, 134042 160783, 134236 161073, 134236 164195, 133946 164389, 130824 164389, 130631 164110, 130630 160977) (130630 165987, 130909 165794, 134042 165793, 134236 166083, 134236 169205, 133946 169399, 130824 169399, 130631 169120, 130630 165987) (130630 170997, 130909 170804, 134042 170803, 134236 171093, 134236 174215, 133946 174409, 130824 174409, 130631 174130, 130630 170997) (130630 176007, 130909 175814, 134042 175813, 134236 176103, 134236 179229, 133990 179412, 131169 179419, 130710 179086, 130630 178925, 130630 176007) (135781 58204, 138834 56761, 139067 56766, 139202 56838, 139246 56965, 139246 58982, 138956 59176, 135834 59176, 135704 59052, 135640 58479, 135781 58204) (135640 60774, 135919 60581, 139052 60580, 139246 60870, 139246 63992, 138956 64186, 135834 64186, 135641 63907, 135640 60774) (135640 65784, 135919 65591, 139052 65590, 139246 65880, 139246 69002, 138956 69196, 135834 69196, 135641 68917, 135640 65784) (135640 70794, 135919 70601, 139052 70600, 139246 70890, 139246 74012, 138956 74206, 135834 74206, 135641 73927, 135640 70794) (135640 75804, 135919 75611, 139052 75610, 139246 75900, 139246 79022, 138956 79216, 135834 79216, 135641 78937, 135640 75804) (135640 80814, 135919 80621, 139052 80620, 139246 80910, 139246 84032, 138956 84226, 135834 84226, 135641 83947, 135640 80814) (135640 85824, 135919 85631, 139052 85630, 139246 85920, 139246 89042, 138956 89236, 135834 89236, 135641 88957, 135640 85824) (135640 90834, 135919 90641, 139052 90640, 139246 90930, 139246 94052, 138956 94246, 135834 94246, 135641 93967, 135640 90834) (135644 95856, 135702 95754, 135919 95651, 139051 95650, 139246 95908, 139246 99064, 138956 99258, 135834 99258, 135641 98979, 135644 95856) (135640 100856, 135919 100663, 139052 100662, 139246 100952, 139246 104074, 138956 104268, 135834 104268, 135641 103989, 135640 100856) (135640 105866, 135919 105673, 139052 105672, 139246 105962, 139246 109084, 138956 109278, 135834 109278, 135641 108999, 135640 105866) (135640 110876, 135919 110683, 139052 110682, 139246 110972, 139246 114094, 138956 114288, 135834 114288, 135641 114009, 135640 110876) (135640 115886, 135919 115693, 139052 115692, 139246 115982, 139246 119104, 138956 119298, 135834 119298, 135641 119019, 135640 115886) (135640 120896, 135919 120703, 139052 120702, 139246 120992, 139246 124114, 138956 124308, 135834 124308, 135641 124029, 135640 120896) (135640 125906, 135919 125713, 139052 125712, 139246 126002, 139246 129124, 138956 129318, 135834 129318, 135641 129039, 135640 125906) (135702 130826, 135919 130723, 139051 130722, 139246 130980, 139246 134134, 138956 134328, 135834 134328, 135641 134049, 135644 130928, 135702 130826) (135640 135926, 135919 135733, 139052 135732, 139246 136022, 139246 139144, 138956 139338, 135834 139338, 135641 139059, 135640 135926) (135640 140936, 135919 140743, 139052 140742, 139246 141032, 139246 144155, 138956 144349, 135834 144349, 135641 144070, 135640 140936) (135644 145959, 135702 145857, 135919 145754, 139051 145753, 139246 146011, 139246 149165, 138956 149359, 135834 149359, 135641 149080, 135644 145959) (135640 150957, 135919 150764, 139052 150763, 139246 151053, 139246 154175, 138956 154369, 135834 154369, 135641 154090, 135640 150957) (135640 155967, 135919 155774, 139052 155773, 139246 156063, 139246 159185, 138956 159379, 135834 159379, 135641 159100, 135640 155967) (135640 160977, 135919 160784, 139052 160783, 139246 161073, 139246 164195, 138956 164389, 135834 164389, 135641 164110, 135640 160977) (135640 165987, 135919 165794, 139052 165793, 139246 166083, 139246 169205, 138956 169399, 135834 169399, 135641 169120, 135640 165987) (135640 170997, 135919 170804, 139052 170803, 139246 171093, 139246 174215, 138956 174409, 135834 174409, 135641 174130, 135640 170997) (135919 175814, 139052 175813, 139246 176103, 139246 179225, 138956 179419, 135884 179419, 135743 179356, 135641 179140, 135640 176007, 135919 175814) (135669 180980, 135722 180882, 135865 180823, 139052 180823, 139246 181113, 139244 182994, 139096 183237, 138926 183282, 135811 181812, 135670 181647, 135669 180980) (140650 56278, 140816 56055, 142142 55576, 144110 55570, 144258 55860, 144258 58982, 143968 59176, 140844 59176, 140651 58897, 140650 56278) (140650 60774, 140929 60581, 144064 60580, 144258 60870, 144258 63992, 143968 64186, 140844 64186, 140651 63907, 140650 60774) (140650 65784, 140929 65591, 144064 65590, 144258 65880, 144258 69002, 143968 69196, 140844 69196, 140651 68917, 140650 65784) (140650 70794, 140929 70601, 144064 70600, 144258 70890, 144258 74012, 143968 74206, 140844 74206, 140651 73927, 140650 70794) (140650 75804, 140929 75611, 144064 75610, 144258 75900, 144258 79022, 143968 79216, 140844 79216, 140651 78937, 140650 75804) (140650 80814, 140929 80621, 144064 80620, 144258 80910, 144258 84032, 143968 84226, 140844 84226, 140651 83947, 140650 80814) (140650 85824, 140929 85631, 144064 85630, 144258 85920, 144258 89042, 143968 89236, 140844 89236, 140651 88957, 140650 85824) (140650 90834, 140929 90641, 144064 90640, 144258 90930, 144258 94052, 143968 94246, 140844 94246, 140651 93967, 140650 90834) (140654 95856, 140712 95754, 140929 95651, 144063 95650, 144258 95908, 144258 99064, 143968 99258, 140844 99258, 140651 98979, 140654 95856) (140650 100856, 140929 100663, 144064 100662, 144258 100952, 144258 104074, 143968 104268, 140844 104268, 140651 103989, 140650 100856) (140650 105866, 140929 105673, 144064 105672, 144258 105962, 144258 109084, 143968 109278, 140844 109278, 140651 108999, 140650 105866) (140650 110876, 140929 110683, 144064 110682, 144258 110972, 144258 114094, 143968 114288, 140844 114288, 140651 114009, 140650 110876) (140650 115886, 140929 115693, 144064 115692, 144258 115982, 144258 119104, 143968 119298, 140844 119298, 140651 119019, 140650 115886) (140650 120896, 140929 120703, 144064 120702, 144258 120992, 144258 124114, 143968 124308, 140844 124308, 140651 124029, 140650 120896) (140650 125906, 140929 125713, 144064 125712, 144258 126002, 144258 129124, 143968 129318, 140844 129318, 140651 129039, 140650 125906) (140712 130826, 140929 130723, 144063 130722, 144258 130980, 144258 134134, 143968 134328, 140844 134328, 140651 134049, 140654 130928, 140712 130826) (140650 135926, 140929 135733, 144064 135732, 144258 136022, 144258 139144, 143968 139338, 140844 139338, 140651 139059, 140650 135926) (140650 140936, 140929 140743, 144064 140742, 144258 141032, 144258 144155, 143968 144349, 140844 144349, 140651 144070, 140650 140936) (140654 145959, 140712 145857, 140929 145754, 144063 145753, 144258 146011, 144258 149165, 143968 149359, 140844 149359, 140651 149080, 140654 145959) (140929 150764, 144064 150763, 144258 151053, 144258 154175, 143968 154369, 140844 154369, 140651 154090, 140650 150957, 140929 150764) (140650 155967, 140929 155774, 144064 155773, 144258 156063, 144258 159185, 143968 159379, 140844 159379, 140651 159100, 140650 155967) (140650 160977, 140929 160784, 144064 160783, 144258 161073, 144258 164195, 143968 164389, 140844 164389, 140651 164110, 140650 160977) (140650 165987, 140929 165794, 144064 165793, 144258 166083, 144258 169205, 143968 169399, 140844 169399, 140651 169120, 140650 165987) (140650 170997, 140929 170804, 144064 170803, 144258 171093, 144258 174215, 143968 174409, 140844 174409, 140651 174130, 140650 170997) (140650 176007, 140929 175814, 144064 175813, 144258 176103, 144258 179225, 143968 179419, 140844 179419, 140651 179140, 140650 176007) (140650 181017, 140929 180824, 144064 180823, 144258 181113, 144258 184191, 144201 184321, 143955 184429, 142146 184421, 140847 183959, 140650 183719, 140650 181017) (145662 55764, 145915 55575, 149055 55573, 149164 55632, 149268 55860, 149268 58982, 148978 59176, 145856 59176, 145663 58897, 145662 55764) (145662 60774, 145941 60581, 149074 60580, 149268 60870, 149268 63992, 148978 64186, 145856 64186, 145663 63907, 145662 60774) (145662 65784, 145941 65591, 149074 65590, 149268 65880, 149268 69002, 148978 69196, 145856 69196, 145663 68917, 145662 65784) (145662 70794, 145941 70601, 149074 70600, 149268 70890, 149268 74012, 148978 74206, 145856 74206, 145663 73927, 145662 70794) (145941 75611, 149074 75610, 149268 75900, 149268 79022, 148978 79216, 145856 79216, 145663 78937, 145662 75804, 145941 75611) (145662 80814, 145941 80621, 149074 80620, 149268 80910, 149268 84032, 148978 84226, 145856 84226, 145663 83947, 145662 80814) (145941 85631, 149074 85630, 149268 85920, 149268 89042, 148978 89236, 145856 89236, 145663 88957, 145662 85824, 145941 85631) (145662 90834, 145941 90641, 149074 90640, 149268 90930, 149268 94052, 148978 94246, 145856 94246, 145663 93967, 145662 90834) (145666 95856, 145724 95754, 145941 95651, 149073 95650, 149268 95908, 149268 99064, 148978 99258, 145856 99258, 145663 98979, 145666 95856) (145662 100856, 145941 100663, 149074 100662, 149268 100952, 149268 104074, 148978 104268, 145856 104268, 145663 103989, 145662 100856) (145662 105866, 145941 105673, 149074 105672, 149268 105962, 149268 109084, 148978 109278, 145856 109278, 145663 108999, 145662 105866) (145662 110876, 145941 110683, 149074 110682, 149268 110972, 149268 114094, 148978 114288, 145856 114288, 145663 114009, 145662 110876) (145662 115886, 145941 115693, 149074 115692, 149268 115982, 149268 119104, 148978 119298, 145856 119298, 145663 119019, 145662 115886) (145662 120896, 145941 120703, 149074 120702, 149268 120992, 149268 124114, 148978 124308, 145856 124308, 145663 124029, 145662 120896) (145662 125906, 145941 125713, 149074 125712, 149268 126002, 149268 129124, 148978 129318, 145856 129318, 145663 129039, 145662 125906) (145666 130928, 145724 130826, 145941 130723, 149073 130722, 149268 130980, 149268 134134, 148978 134328, 145856 134328, 145663 134049, 145666 130928) (145662 135926, 145941 135733, 149074 135732, 149268 136022, 149268 139144, 148978 139338, 145856 139338, 145663 139059, 145662 135926) (145662 140936, 145941 140743, 149074 140742, 149268 141032, 149268 144155, 148978 144349, 145856 144349, 145663 144070, 145662 140936) (145666 145959, 145724 145857, 145941 145754, 149073 145753, 149268 146011, 149268 149165, 148978 149359, 145856 149359, 145663 149080, 145666 145959) (145662 150957, 145941 150764, 149074 150763, 149268 151053, 149268 154175, 148978 154369, 145856 154369, 145663 154090, 145662 150957) (145662 155967, 145941 155774, 149074 155773, 149268 156063, 149268 159185, 148978 159379, 145856 159379, 145663 159100, 145662 155967) (145662 160977, 145941 160784, 149074 160783, 149268 161073, 149268 164195, 148978 164389, 145856 164389, 145663 164110, 145662 160977) (145662 165987, 145941 165794, 149074 165793, 149268 166083, 149268 169205, 148978 169399, 145856 169399, 145663 169120, 145662 165987) (145662 170997, 145941 170804, 149074 170803, 149268 171093, 149268 174215, 148978 174409, 145856 174409, 145663 174130, 145662 170997) (145662 176007, 145941 175814, 149074 175813, 149268 176103, 149268 179225, 148978 179419, 145856 179419, 145663 179140, 145662 176007) (145662 181017, 145941 180824, 149074 180823, 149268 181113, 149268 184239, 149004 184430, 145863 184424, 145762 184363, 145663 184150, 145662 181017) (150714 53230, 150867 53073, 151640 52877, 153997 52527, 154174 52589, 154278 52784, 154278 53972, 153988 54166, 150866 54166, 150676 53907, 150714 53230) (150672 55764, 150951 55571, 154084 55570, 154278 55860, 154278 58982, 153988 59176, 150866 59176, 150673 58897, 150672 55764) (150672 60774, 150951 60581, 154084 60580, 154278 60870, 154278 63992, 153988 64186, 150866 64186, 150673 63907, 150672 60774) (150672 65784, 150951 65591, 154084 65590, 154278 65880, 154278 69002, 153988 69196, 150866 69196, 150673 68917, 150672 65784) (150672 70794, 150951 70601, 154084 70600, 154278 70890, 154278 74012, 153988 74206, 150866 74206, 150673 73927, 150672 70794) (150672 75804, 150951 75611, 154084 75610, 154278 75900, 154278 79022, 153988 79216, 150866 79216, 150673 78937, 150672 75804) (150672 80814, 150951 80621, 154084 80620, 154278 80910, 154278 84032, 153988 84226, 150866 84226, 150673 83947, 150672 80814) (150672 85824, 150951 85631, 154084 85630, 154278 85920, 154278 89042, 153988 89236, 150866 89236, 150673 88957, 150672 85824) (150672 90834, 150951 90641, 154084 90640, 154278 90930, 154278 94052, 153988 94246, 150866 94246, 150673 93967, 150672 90834) (150676 95856, 150734 95754, 150951 95651, 154083 95650, 154278 95908, 154278 99064, 153988 99258, 150866 99258, 150673 98979, 150676 95856) (150672 100856, 150951 100663, 154084 100662, 154278 100952, 154278 104074, 153988 104268, 150866 104268, 150673 103989, 150672 100856) (150672 105866, 150951 105673, 154084 105672, 154278 105962, 154278 109084, 153988 109278, 150866 109278, 150673 108999, 150672 105866) (150672 110876, 150951 110683, 154084 110682, 154278 110972, 154278 114094, 153988 114288, 150866 114288, 150673 114009, 150672 110876) (150672 115886, 150951 115693, 154084 115692, 154278 115982, 154278 119104, 153988 119298, 150866 119298, 150673 119019, 150672 115886) (150672 120896, 150951 120703, 154084 120702, 154278 120992, 154278 124114, 153988 124308, 150866 124308, 150673 124029, 150672 120896) (150672 125906, 150951 125713, 154084 125712, 154278 126002, 154278 129124, 153988 129318, 150866 129318, 150673 129039, 150672 125906) (150676 130928, 150734 130826, 150951 130723, 154083 130722, 154278 130980, 154278 134134, 153988 134328, 150866 134328, 150673 134049, 150676 130928) (150672 135926, 150951 135733, 154084 135732, 154278 136022, 154278 139144, 153988 139338, 150866 139338, 150673 139059, 150672 135926) (150672 140936, 150951 140743, 154084 140742, 154278 141032, 154278 144155, 153988 144349, 150866 144349, 150673 144070, 150672 140936) (150734 145857, 150951 145754, 154083 145753, 154278 146011, 154278 149165, 153988 149359, 150866 149359, 150673 149080, 150676 145959, 150734 145857) (150672 150957, 150951 150764, 154084 150763, 154278 151053, 154278 154175, 153988 154369, 150866 154369, 150673 154090, 150672 150957) (150672 155967, 150951 155774, 154084 155773, 154278 156063, 154278 159185, 153988 159379, 150866 159379, 150673 159100, 150672 155967) (150672 160977, 150951 160784, 154084 160783, 154278 161073, 154278 164195, 153988 164389, 150866 164389, 150673 164110, 150672 160977) (150672 165987, 150951 165794, 154084 165793, 154278 166083, 154278 169205, 153988 169399, 150866 169399, 150673 169120, 150672 165987) (150672 170997, 150951 170804, 154084 170803, 154278 171093, 154278 174215, 153988 174409, 150866 174409, 150673 174130, 150672 170997) (150951 175814, 154084 175813, 154278 176103, 154278 179225, 153988 179419, 150866 179419, 150673 179140, 150672 176007, 150951 175814) (150672 181017, 150951 180824, 154084 180823, 154278 181113, 154278 184235, 153988 184429, 150916 184429, 150775 184366, 150673 184150, 150672 181017) (150700 185994, 150754 185892, 150897 185833, 154084 185833, 154278 186123, 154276 187265, 154219 187373, 153970 187465, 151640 187122, 150900 186937, 150714 186769, 150700 185994) (155685 52454, 155902 52247, 158285 51890, 159028 51854, 159197 51932, 159286 52123, 159288 53972, 158998 54166, 155876 54166, 155683 53887, 155685 52454) (155682 55764, 155961 55571, 159094 55570, 159288 55860, 159288 58982, 158998 59176, 155876 59176, 155683 58897, 155682 55764) (155682 60774, 155961 60581, 159094 60580, 159288 60870, 159288 63992, 158998 64186, 155876 64186, 155683 63907, 155682 60774) (155682 65784, 155961 65591, 159094 65590, 159288 65880, 159288 69002, 158998 69196, 155876 69196, 155683 68917, 155682 65784) (155682 70794, 155961 70601, 159094 70600, 159288 70890, 159288 74012, 158998 74206, 155876 74206, 155683 73927, 155682 70794) (155682 75804, 155961 75611, 159094 75610, 159288 75900, 159288 79022, 158998 79216, 155876 79216, 155683 78937, 155682 75804) (155682 80814, 155961 80621, 159094 80620, 159288 80910, 159288 84032, 158998 84226, 155876 84226, 155683 83947, 155682 80814) (155682 85824, 155961 85631, 159094 85630, 159288 85920, 159288 89042, 158998 89236, 155876 89236, 155683 88957, 155682 85824) (155961 90641, 159094 90640, 159288 90930, 159288 94052, 158998 94246, 155876 94246, 155683 93967, 155682 90834, 155961 90641) (155686 95856, 155744 95754, 155961 95651, 159093 95650, 159288 95908, 159288 99064, 158998 99258, 155876 99258, 155683 98979, 155686 95856) (155961 100663, 159094 100662, 159288 100952, 159288 104074, 158998 104268, 155876 104268, 155683 103989, 155682 100856, 155961 100663) (155682 105866, 155961 105673, 159094 105672, 159288 105962, 159288 109084, 158998 109278, 155876 109278, 155683 108999, 155682 105866) (155682 110876, 155961 110683, 159094 110682, 159288 110972, 159288 114094, 158998 114288, 155876 114288, 155683 114009, 155682 110876) (155682 115886, 155961 115693, 159094 115692, 159288 115982, 159288 119104, 158998 119298, 155876 119298, 155683 119019, 155682 115886) (155682 120896, 155961 120703, 159094 120702, 159288 120992, 159288 124114, 158998 124308, 155876 124308, 155683 124029, 155682 120896) (155682 125906, 155961 125713, 159094 125712, 159288 126002, 159288 129124, 158998 129318, 155876 129318, 155683 129039, 155682 125906) (155686 130928, 155744 130826, 155961 130723, 159093 130722, 159288 130980, 159288 134134, 158998 134328, 155876 134328, 155683 134049, 155686 130928) (155682 135926, 155961 135733, 159094 135732, 159288 136022, 159288 139144, 158998 139338, 155876 139338, 155683 139059, 155682 135926) (155682 140936, 155961 140743, 159094 140742, 159288 141032, 159288 144155, 158998 144349, 155876 144349, 155683 144070, 155682 140936) (155686 145959, 155744 145857, 155961 145754, 159093 145753, 159288 146011, 159288 149165, 158998 149359, 155876 149359, 155683 149080, 155686 145959) (155682 150957, 155961 150764, 159094 150763, 159288 151053, 159288 154175, 158998 154369, 155876 154369, 155683 154090, 155682 150957) (155682 155967, 155961 155774, 159094 155773, 159288 156063, 159288 159185, 158998 159379, 155876 159379, 155683 159100, 155682 155967) (155682 160977, 155961 160784, 159094 160783, 159288 161073, 159288 164195, 158998 164389, 155876 164389, 155683 164110, 155682 160977) (155682 165987, 155961 165794, 159094 165793, 159288 166083, 159288 169205, 158998 169399, 155876 169399, 155683 169120, 155682 165987) (155682 170997, 155961 170804, 159094 170803, 159288 171093, 159288 174215, 158998 174409, 155876 174409, 155683 174130, 155682 170997) (155682 176007, 155961 175814, 159094 175813, 159288 176103, 159288 179225, 158998 179419, 155876 179419, 155683 179140, 155682 176007) (155682 181017, 155961 180824, 159094 180823, 159288 181113, 159288 184235, 158998 184429, 155876 184429, 155683 184150, 155682 181017) (155682 186027, 155961 185834, 159094 185833, 159288 186123, 159288 187943, 159241 188029, 159008 188141, 158285 188109, 155899 187755, 155749 187645, 155688 187510, 155682 186027) (160692 51969, 160941 51763, 164038 51608, 164211 51690, 164298 51897, 164298 53972, 164008 54166, 160886 54166, 160693 53887, 160692 51969) (160692 55764, 160971 55571, 164104 55570, 164298 55860, 164298 58982, 164008 59176, 160886 59176, 160693 58897, 160692 55764) (160692 60774, 160971 60581, 164104 60580, 164298 60870, 164298 63992, 164008 64186, 160886 64186, 160693 63907, 160692 60774) (160692 65784, 160971 65591, 164104 65590, 164298 65880, 164298 69002, 164008 69196, 160886 69196, 160693 68917, 160692 65784) (160692 70794, 160971 70601, 164104 70600, 164298 70890, 164298 74012, 164008 74206, 160886 74206, 160693 73927, 160692 70794) (160692 75804, 160971 75611, 164104 75610, 164298 75900, 164298 79022, 164008 79216, 160886 79216, 160693 78937, 160692 75804) (160692 80814, 160971 80621, 164104 80620, 164298 80910, 164298 84032, 164008 84226, 160886 84226, 160693 83947, 160692 80814) (160692 85824, 160971 85631, 164104 85630, 164298 85920, 164298 89042, 164008 89236, 160886 89236, 160693 88957, 160692 85824) (160692 90834, 160971 90641, 164104 90640, 164298 90930, 164298 94052, 164008 94246, 160886 94246, 160693 93967, 160692 90834) (160754 95754, 160971 95651, 164103 95650, 164298 95908, 164298 99064, 164008 99258, 160886 99258, 160693 98979, 160696 95856, 160754 95754) (160692 100856, 160971 100663, 164104 100662, 164298 100952, 164298 104074, 164008 104268, 160886 104268, 160693 103989, 160692 100856) (160692 105866, 160971 105673, 164104 105672, 164298 105962, 164298 109084, 164008 109278, 160886 109278, 160693 108999, 160692 105866) (160692 110876, 160971 110683, 164104 110682, 164298 110972, 164298 114094, 164008 114288, 160886 114288, 160693 114009, 160692 110876) (160692 115886, 160971 115693, 164104 115692, 164298 115982, 164298 119104, 164008 119298, 160886 119298, 160693 119019, 160692 115886) (160692 120896, 160971 120703, 164104 120702, 164298 120992, 164298 124114, 164008 124308, 160886 124308, 160693 124029, 160692 120896) (160692 125906, 160971 125713, 164104 125712, 164298 126002, 164298 129124, 164008 129318, 160886 129318, 160693 129039, 160692 125906) (160696 130928, 160754 130826, 160971 130723, 164103 130722, 164298 130980, 164298 134134, 164008 134328, 160886 134328, 160693 134049, 160696 130928) (160692 135926, 160971 135733, 164104 135732, 164298 136022, 164298 139144, 164008 139338, 160886 139338, 160693 139059, 160692 135926) (160692 140936, 160971 140743, 164104 140742, 164298 141032, 164298 144155, 164008 144349, 160886 144349, 160693 144070, 160692 140936) (160754 145857, 160971 145754, 164103 145753, 164298 146011, 164298 149165, 164008 149359, 160886 149359, 160693 149080, 160696 145959, 160754 145857) (160692 150957, 160971 150764, 164104 150763, 164298 151053, 164298 154175, 164008 154369, 160886 154369, 160693 154090, 160692 150957) (160692 155967, 160971 155774, 164104 155773, 164298 156063, 164298 159185, 164008 159379, 160886 159379, 160693 159100, 160692 155967) (160692 160977, 160971 160784, 164104 160783, 164298 161073, 164298 164195, 164008 164389, 160886 164389, 160693 164110, 160692 160977) (160692 165987, 160971 165794, 164104 165793, 164298 166083, 164298 169205, 164008 169399, 160886 169399, 160693 169120, 160692 165987) (160692 170997, 160971 170804, 164104 170803, 164298 171093, 164298 174215, 164008 174409, 160886 174409, 160693 174130, 160692 170997) (160692 176007, 160971 175814, 164104 175813, 164298 176103, 164298 179225, 164008 179419, 160886 179419, 160693 179140, 160692 176007) (160692 181017, 160971 180824, 164104 180823, 164298 181113, 164298 184235, 164008 184429, 160886 184429, 160693 184150, 160692 181017) (160692 186027, 160971 185834, 164104 185833, 164298 186123, 164298 188156, 164254 188271, 164018 188387, 160930 188240, 160769 188145, 160697 187989, 160692 186027) (165746 51728, 165982 51612, 169070 51759, 169231 51854, 169303 52010, 169308 53972, 169018 54166, 165896 54166, 165703 53887, 165702 51854, 165746 51728) (165702 55764, 165981 55571, 169114 55570, 169308 55860, 169308 58982, 169018 59176, 165896 59176, 165703 58897, 165702 55764) (165702 60774, 165981 60581, 169114 60580, 169308 60870, 169308 63992, 169018 64186, 165896 64186, 165703 63907, 165702 60774) (165702 65784, 165981 65591, 169114 65590, 169308 65880, 169308 69002, 169018 69196, 165896 69196, 165703 68917, 165702 65784) (165702 70794, 165981 70601, 169114 70600, 169308 70890, 169308 74012, 169018 74206, 165896 74206, 165703 73927, 165702 70794) (165702 75804, 165981 75611, 169114 75610, 169308 75900, 169308 79022, 169018 79216, 165896 79216, 165703 78937, 165702 75804) (165702 80814, 165981 80621, 169114 80620, 169308 80910, 169308 84032, 169018 84226, 165896 84226, 165703 83947, 165702 80814) (165981 85631, 169114 85630, 169308 85920, 169308 89042, 169018 89236, 165896 89236, 165703 88957, 165702 85824, 165981 85631) (165702 90834, 165981 90641, 169114 90640, 169308 90930, 169308 94052, 169018 94246, 165896 94246, 165703 93967, 165702 90834) (165706 95856, 165764 95754, 165981 95651, 169113 95650, 169308 95908, 169308 99064, 169018 99258, 165896 99258, 165703 98979, 165706 95856) (165702 100856, 165981 100663, 169114 100662, 169308 100952, 169308 104074, 169018 104268, 165896 104268, 165703 103989, 165702 100856) (165702 105866, 165981 105673, 169114 105672, 169308 105962, 169308 109084, 169018 109278, 165896 109278, 165703 108999, 165702 105866) (165702 110876, 165981 110683, 169114 110682, 169308 110972, 169308 114094, 169018 114288, 165896 114288, 165703 114009, 165702 110876) (165702 115886, 165981 115693, 169114 115692, 169308 115982, 169308 119104, 169018 119298, 165896 119298, 165703 119019, 165702 115886) (165702 120896, 165981 120703, 169114 120702, 169308 120992, 169308 124114, 169018 124308, 165896 124308, 165703 124029, 165702 120896) (165702 125906, 165981 125713, 169114 125712, 169308 126002, 169308 129124, 169018 129318, 165896 129318, 165703 129039, 165702 125906) (165706 130928, 165764 130826, 165981 130723, 169113 130722, 169308 130980, 169308 134134, 169018 134328, 165896 134328, 165703 134049, 165706 130928) (165702 135926, 165981 135733, 169114 135732, 169308 136022, 169308 139144, 169018 139338, 165896 139338, 165703 139059, 165702 135926) (165702 140936, 165981 140743, 169114 140742, 169308 141032, 169308 144155, 169018 144349, 165896 144349, 165703 144070, 165702 140936) (165706 145959, 165764 145857, 165981 145754, 169113 145753, 169308 146011, 169308 149165, 169018 149359, 165896 149359, 165703 149080, 165706 145959) (165981 150764, 169114 150763, 169308 151053, 169308 154175, 169018 154369, 165896 154369, 165703 154090, 165702 150957, 165981 150764) (165702 155967, 165981 155774, 169114 155773, 169308 156063, 169308 159185, 169018 159379, 165896 159379, 165703 159100, 165702 155967) (165702 160977, 165981 160784, 169114 160783, 169308 161073, 169308 164195, 169018 164389, 165896 164389, 165703 164110, 165702 160977) (165702 165987, 165981 165794, 169114 165793, 169308 166083, 169308 169205, 169018 169399, 165896 169399, 165703 169120, 165702 165987) (165981 170804, 169114 170803, 169308 171093, 169308 174215, 169018 174409, 165896 174409, 165703 174130, 165702 170997, 165981 170804) (165702 176007, 165981 175814, 169114 175813, 169308 176103, 169308 179225, 169018 179419, 165896 179419, 165703 179140, 165702 176007) (165702 181017, 165981 180824, 169114 180823, 169308 181113, 169308 184235, 169018 184429, 165896 184429, 165703 184150, 165702 181017) (165702 186027, 165981 185834, 169114 185833, 169308 186123, 169308 188030, 169059 188235, 165962 188391, 165789 188309, 165703 188113, 165702 186027) (170712 52090, 170759 51970, 170992 51858, 171714 51890, 174101 52244, 174251 52354, 174313 52488, 174318 53972, 174028 54166, 170906 54166, 170713 53887, 170712 52090) (170712 55764, 170991 55571, 174124 55570, 174318 55860, 174318 58982, 174028 59176, 170906 59176, 170713 58897, 170712 55764) (170712 60774, 170991 60581, 174124 60580, 174318 60870, 174318 63992, 174028 64186, 170906 64186, 170713 63907, 170712 60774) (170712 65784, 170991 65591, 174124 65590, 174318 65880, 174318 69002, 174028 69196, 170906 69196, 170713 68917, 170712 65784) (170712 70794, 170991 70601, 174124 70600, 174318 70890, 174318 74012, 174028 74206, 170906 74206, 170713 73927, 170712 70794) (170712 75804, 170991 75611, 174124 75610, 174318 75900, 174318 79022, 174028 79216, 170906 79216, 170713 78937, 170712 75804) (170712 80814, 170991 80621, 174124 80620, 174318 80910, 174318 84032, 174028 84226, 170906 84226, 170713 83947, 170712 80814) (170712 85824, 170991 85631, 174124 85630, 174318 85920, 174318 89042, 174028 89236, 170906 89236, 170713 88957, 170712 85824) (170712 90834, 170991 90641, 174124 90640, 174318 90930, 174318 94052, 174028 94246, 170906 94246, 170713 93967, 170712 90834) (170716 95856, 170774 95754, 170991 95651, 174123 95650, 174318 95908, 174318 99064, 174028 99258, 170906 99258, 170713 98979, 170716 95856) (170712 100856, 170991 100663, 174124 100662, 174318 100952, 174318 104074, 174028 104268, 170906 104268, 170713 103989, 170712 100856) (170712 105866, 170991 105673, 174124 105672, 174318 105962, 174318 109084, 174028 109278, 170906 109278, 170713 108999, 170712 105866) (170712 110876, 170991 110683, 174124 110682, 174318 110972, 174318 114094, 174028 114288, 170906 114288, 170713 114009, 170712 110876) (170712 115886, 170991 115693, 174124 115692, 174318 115982, 174318 119104, 174028 119298, 170906 119298, 170713 119019, 170712 115886) (170712 120896, 170991 120703, 174124 120702, 174318 120992, 174318 124114, 174028 124308, 170906 124308, 170713 124029, 170712 120896) (170712 125906, 170991 125713, 174124 125712, 174318 126002, 174318 129124, 174028 129318, 170906 129318, 170713 129039, 170712 125906) (170716 130928, 170774 130826, 170991 130723, 174123 130722, 174318 130980, 174318 134134, 174028 134328, 170906 134328, 170713 134049, 170716 130928) (170712 135926, 170991 135733, 174124 135732, 174318 136022, 174318 139144, 174028 139338, 170906 139338, 170713 139059, 170712 135926) (170712 140936, 170991 140743, 174124 140742, 174318 141032, 174318 144155, 174028 144349, 170906 144349, 170713 144070, 170712 140936) (170716 145959, 170774 145857, 170991 145754, 174123 145753, 174318 146011, 174318 149165, 174028 149359, 170906 149359, 170713 149080, 170716 145959) (170712 150957, 170991 150764, 174124 150763, 174318 151053, 174318 154175, 174028 154369, 170906 154369, 170713 154090, 170712 150957) (170712 155967, 170991 155774, 174124 155773, 174318 156063, 174318 159185, 174028 159379, 170906 159379, 170713 159100, 170712 155967) (170712 160977, 170991 160784, 174124 160783, 174318 161073, 174318 164195, 174028 164389, 170906 164389, 170713 164110, 170712 160977) (170991 165794, 174124 165793, 174318 166083, 174318 169205, 174028 169399, 170906 169399, 170713 169120, 170712 165987, 170991 165794) (170712 170997, 170991 170804, 174124 170803, 174318 171093, 174318 174215, 174028 174409, 170906 174409, 170713 174130, 170712 170997) (170991 175814, 174124 175813, 174318 176103, 174318 179225, 174028 179419, 170906 179419, 170713 179140, 170712 176007, 170991 175814) (170712 181017, 170991 180824, 174124 180823, 174318 181113, 174318 184235, 174028 184429, 170906 184429, 170713 184150, 170712 181017) (170712 186027, 170991 185834, 174124 185833, 174318 186123, 174315 187545, 174098 187752, 171714 188109, 170972 188145, 170803 188067, 170714 187877, 170712 186027) (175728 52718, 175781 52626, 176030 52534, 178359 52877, 179100 53062, 179286 53230, 179300 54005, 179118 54166, 175916 54166, 175723 53887, 175728 52718) (175722 55764, 176001 55571, 179098 55570, 179225 55633, 179328 55860, 179328 58982, 179038 59176, 175916 59176, 175723 58897, 175722 55764) (175722 60774, 176001 60581, 179134 60580, 179328 60870, 179328 63992, 179038 64186, 175916 64186, 175723 63907, 175722 60774) (175722 65784, 176001 65591, 179134 65590, 179328 65880, 179328 69002, 179038 69196, 175916 69196, 175723 68917, 175722 65784) (175722 70794, 176001 70601, 179134 70600, 179328 70890, 179328 74012, 179038 74206, 175916 74206, 175723 73927, 175722 70794) (175722 75804, 176001 75611, 179134 75610, 179328 75900, 179328 79022, 179038 79216, 175916 79216, 175723 78937, 175722 75804) (175722 80814, 176001 80621, 179134 80620, 179328 80910, 179328 84032, 179038 84226, 175916 84226, 175723 83947, 175722 80814) (175722 85824, 176001 85631, 179134 85630, 179328 85920, 179328 89042, 179038 89236, 175916 89236, 175723 88957, 175722 85824) (175722 90834, 176001 90641, 179134 90640, 179328 90930, 179328 94052, 179038 94246, 175916 94246, 175723 93967, 175722 90834) (175726 95856, 175784 95754, 176001 95651, 179133 95650, 179328 95908, 179328 99064, 179038 99258, 175916 99258, 175723 98979, 175726 95856) (175722 100856, 176001 100663, 179134 100662, 179328 100952, 179328 104074, 179038 104268, 175916 104268, 175723 103989, 175722 100856) (175722 105866, 176001 105673, 179134 105672, 179328 105962, 179328 109084, 179038 109278, 175916 109278, 175723 108999, 175722 105866) (175722 110876, 176001 110683, 179134 110682, 179328 110972, 179328 114094, 179038 114288, 175916 114288, 175723 114009, 175722 110876) (175722 115886, 176001 115693, 179134 115692, 179328 115982, 179328 119104, 179038 119298, 175916 119298, 175723 119019, 175722 115886) (175722 120896, 176001 120703, 179134 120702, 179328 120992, 179328 124114, 179038 124308, 175916 124308, 175723 124029, 175722 120896) (175722 125906, 176001 125713, 179134 125712, 179328 126002, 179328 129124, 179038 129318, 175916 129318, 175723 129039, 175722 125906) (175726 130928, 175784 130826, 176001 130723, 179133 130722, 179328 130980, 179328 134134, 179038 134328, 175916 134328, 175723 134049, 175726 130928) (175722 135926, 176001 135733, 179134 135732, 179328 136022, 179328 139144, 179038 139338, 175916 139338, 175723 139059, 175722 135926) (175722 140936, 176001 140743, 179134 140742, 179328 141032, 179328 144155, 179038 144349, 175916 144349, 175723 144070, 175722 140936) (175726 145959, 175784 145857, 176001 145754, 179133 145753, 179328 146011, 179328 149165, 179038 149359, 175916 149359, 175723 149080, 175726 145959) (175722 150957, 176001 150764, 179134 150763, 179328 151053, 179328 154175, 179038 154369, 175916 154369, 175723 154090, 175722 150957) (175722 155967, 176001 155774, 179134 155773, 179328 156063, 179328 159185, 179038 159379, 175916 159379, 175723 159100, 175722 155967) (175722 160977, 176001 160784, 179134 160783, 179328 161073, 179328 164195, 179038 164389, 175916 164389, 175723 164110, 175722 160977) (175722 165987, 176001 165794, 179134 165793, 179328 166083, 179328 169205, 179038 169399, 175916 169399, 175723 169120, 175722 165987) (175722 170997, 176001 170804, 179134 170803, 179328 171093, 179328 174215, 179038 174409, 175916 174409, 175723 174130, 175722 170997) (175722 176007, 176001 175814, 179134 175813, 179328 176103, 179328 179225, 179038 179419, 175916 179419, 175723 179140, 175722 176007) (175722 181017, 176001 180824, 179134 180823, 179328 181113, 179328 184235, 179038 184429, 175916 184429, 175723 184150, 175722 181017) (175722 186027, 176001 185834, 179134 185833, 179324 186092, 179286 186769, 179133 186926, 178359 187122, 176003 187472, 175826 187410, 175725 187201, 175722 186027) (180732 55760, 180981 55576, 184137 55575, 184238 55636, 184338 55860, 184338 58982, 184048 59176, 180926 59176, 180733 58897, 180732 55760) (180732 60774, 181011 60581, 184144 60580, 184338 60870, 184338 63992, 184048 64186, 180926 64186, 180733 63907, 180732 60774) (180732 65784, 181011 65591, 184144 65590, 184338 65880, 184338 69002, 184048 69196, 180926 69196, 180733 68917, 180732 65784) (180732 70794, 181011 70601, 184144 70600, 184338 70890, 184338 74012, 184048 74206, 180926 74206, 180733 73927, 180732 70794) (180732 75804, 181011 75611, 184144 75610, 184338 75900, 184338 79022, 184048 79216, 180926 79216, 180733 78937, 180732 75804) (180732 80814, 181011 80621, 184144 80620, 184338 80910, 184338 84032, 184048 84226, 180926 84226, 180733 83947, 180732 80814) (180732 85824, 181011 85631, 184144 85630, 184338 85920, 184338 89042, 184048 89236, 180926 89236, 180733 88957, 180732 85824) (180732 90834, 181011 90641, 184144 90640, 184338 90930, 184338 94052, 184048 94246, 180926 94246, 180733 93967, 180732 90834) (180736 95856, 180794 95754, 181011 95651, 184143 95650, 184338 95908, 184338 99064, 184048 99258, 180926 99258, 180733 98979, 180736 95856) (180732 100856, 181011 100663, 184144 100662, 184338 100952, 184338 104074, 184048 104268, 180926 104268, 180733 103989, 180732 100856) (180732 105866, 181011 105673, 184144 105672, 184338 105962, 184338 109084, 184048 109278, 180926 109278, 180733 108999, 180732 105866) (180732 110876, 181011 110683, 184144 110682, 184338 110972, 184338 114094, 184048 114288, 180926 114288, 180733 114009, 180732 110876) (180732 115886, 181011 115693, 184144 115692, 184338 115982, 184338 119104, 184048 119298, 180926 119298, 180733 119019, 180732 115886) (180732 120896, 181011 120703, 184144 120702, 184338 120992, 184338 124114, 184048 124308, 180926 124308, 180733 124029, 180732 120896) (180732 125906, 181011 125713, 184144 125712, 184338 126002, 184338 129124, 184048 129318, 180926 129318, 180733 129039, 180732 125906) (180736 130928, 180794 130826, 181011 130723, 184143 130722, 184338 130980, 184338 134134, 184048 134328, 180926 134328, 180733 134049, 180736 130928) (180732 135926, 181011 135733, 184144 135732, 184338 136022, 184338 139144, 184048 139338, 180926 139338, 180733 139059, 180732 135926) (180732 140936, 181011 140743, 184144 140742, 184338 141032, 184338 144155, 184048 144349, 180926 144349, 180733 144070, 180732 140936) (180736 145959, 180794 145857, 181011 145754, 184143 145753, 184338 146011, 184338 149165, 184048 149359, 180926 149359, 180733 149080, 180736 145959) (180732 150957, 181011 150764, 184144 150763, 184338 151053, 184338 154175, 184048 154369, 180926 154369, 180733 154090, 180732 150957) (180732 155967, 181011 155774, 184144 155773, 184338 156063, 184338 159185, 184048 159379, 180926 159379, 180733 159100, 180732 155967) (180732 160977, 181011 160784, 184144 160783, 184338 161073, 184338 164195, 184048 164389, 180926 164389, 180733 164110, 180732 160977) (180732 165987, 181011 165794, 184144 165793, 184338 166083, 184338 169205, 184048 169399, 180926 169399, 180733 169120, 180732 165987) (180732 170997, 181011 170804, 184144 170803, 184338 171093, 184338 174215, 184048 174409, 180926 174409, 180733 174130, 180732 170997) (180732 176007, 181011 175814, 184144 175813, 184338 176103, 184338 179225, 184048 179419, 180926 179419, 180733 179140, 180732 176007) (180732 181017, 181011 180824, 184144 180823, 184338 181113, 184338 184191, 184280 184321, 184085 184424, 180945 184426, 180836 184367, 180733 184150, 180732 181017) (185742 55761, 185827 55655, 186045 55570, 187853 55578, 189152 56040, 189350 56283, 189349 58980, 189287 59072, 189059 59176, 185936 59176, 185743 58897, 185742 55761) (185742 60774, 186021 60581, 189155 60580, 189349 60870, 189349 63992, 189059 64186, 185936 64186, 185743 63907, 185742 60774) (185742 65784, 186021 65591, 189155 65590, 189349 65880, 189349 69002, 189059 69196, 185936 69196, 185743 68917, 185742 65784) (185742 70794, 186021 70601, 189155 70600, 189349 70890, 189349 74012, 189059 74206, 185936 74206, 185743 73927, 185742 70794) (185742 75804, 186021 75611, 189155 75610, 189349 75900, 189349 79022, 189059 79216, 185936 79216, 185743 78937, 185742 75804) (185742 80814, 186021 80621, 189155 80620, 189349 80910, 189349 84032, 189059 84226, 185936 84226, 185743 83947, 185742 80814) (185742 85824, 186021 85631, 189155 85630, 189349 85920, 189349 89042, 189059 89236, 185936 89236, 185743 88957, 185742 85824) (185742 90834, 186021 90641, 189155 90640, 189349 90930, 189349 94052, 189059 94246, 185936 94246, 185743 93967, 185742 90834) (185746 95856, 185804 95754, 186021 95651, 189154 95650, 189349 95908, 189349 99064, 189059 99258, 185936 99258, 185743 98979, 185746 95856) (185742 100856, 186021 100663, 189155 100662, 189349 100952, 189349 104074, 189059 104268, 185936 104268, 185743 103989, 185742 100856) (185742 105866, 186021 105673, 189155 105672, 189349 105962, 189349 109084, 189059 109278, 185936 109278, 185743 108999, 185742 105866) (185742 110876, 186021 110683, 189155 110682, 189349 110972, 189349 114094, 189059 114288, 185936 114288, 185743 114009, 185742 110876) (185742 115886, 186021 115693, 189155 115692, 189349 115982, 189349 119104, 189059 119298, 185936 119298, 185743 119019, 185742 115886) (185742 120896, 186021 120703, 189155 120702, 189349 120992, 189349 124114, 189059 124308, 185936 124308, 185743 124029, 185742 120896) (185742 125906, 186021 125713, 189155 125712, 189349 126002, 189349 129124, 189059 129318, 185936 129318, 185743 129039, 185742 125906) (185746 130928, 185804 130826, 186021 130723, 189154 130722, 189349 130980, 189349 134134, 189059 134328, 185936 134328, 185743 134049, 185746 130928) (185742 135926, 186021 135733, 189155 135732, 189349 136022, 189349 139144, 189059 139338, 185936 139338, 185743 139059, 185742 135926) (185742 140936, 186021 140743, 189155 140742, 189349 141032, 189349 144155, 189059 144349, 185936 144349, 185743 144070, 185742 140936) (185746 145959, 185804 145857, 186021 145754, 189154 145753, 189349 146011, 189349 149165, 189059 149359, 185936 149359, 185743 149080, 185746 145959) (185742 150957, 186021 150764, 189155 150763, 189349 151053, 189349 154175, 189059 154369, 185936 154369, 185743 154090, 185742 150957) (185742 155967, 186021 155774, 189155 155773, 189349 156063, 189349 159185, 189059 159379, 185936 159379, 185743 159100, 185742 155967) (185742 160977, 186021 160784, 189155 160783, 189349 161073, 189349 164195, 189059 164389, 185936 164389, 185743 164110, 185742 160977) (185742 165987, 186021 165794, 189155 165793, 189349 166083, 189349 169205, 189059 169399, 185936 169399, 185743 169120, 185742 165987) (185742 170997, 186021 170804, 189155 170803, 189349 171093, 189349 174215, 189059 174409, 185936 174409, 185743 174130, 185742 170997) (185742 176007, 186021 175814, 189155 175813, 189349 176103, 189349 179225, 189059 179419, 185936 179419, 185743 179140, 185742 176007) (185742 181017, 186021 180824, 189155 180823, 189349 181116, 189349 183715, 189183 183944, 187857 184423, 185891 184429, 185743 184150, 185742 181017) (190751 181016, 191032 180824, 194172 180823, 194295 180947, 194359 181520, 194218 181795, 191186 183231, 190954 183227, 190779 183132, 190751 181016) (190775 57044, 190923 56771, 191095 56725, 194188 58187, 194329 58352, 194330 59018, 194149 59176, 190942 59176, 190754 58898, 190775 57044) (190753 60771, 191031 60581, 194129 60580, 194256 60643, 194359 60870, 194359 63992, 194069 64186, 190947 64186, 190754 63907, 190753 60771) (190753 65784, 191032 65591, 194165 65590, 194359 65880, 194359 69002, 194069 69196, 190947 69196, 190754 68917, 190753 65784) (190753 70794, 191032 70601, 194165 70600, 194359 70890, 194359 74012, 194069 74206, 190947 74206, 190754 73927, 190753 70794) (190753 75804, 191032 75611, 194165 75610, 194359 75900, 194359 79022, 194069 79216, 190947 79216, 190754 78937, 190753 75804) (190753 80814, 191032 80621, 194165 80620, 194359 80910, 194359 84032, 194069 84226, 190947 84226, 190754 83947, 190753 80814) (190753 85824, 191032 85631, 194165 85630, 194359 85920, 194359 89042, 194069 89236, 190947 89236, 190754 88957, 190753 85824) (190753 90834, 191032 90641, 194165 90640, 194359 90930, 194359 94052, 194069 94246, 190947 94246, 190754 93967, 190753 90834) (190757 95856, 190815 95754, 191032 95651, 194164 95650, 194359 95908, 194359 99064, 194069 99258, 190947 99258, 190754 98979, 190757 95856) (191032 100663, 194165 100662, 194359 100952, 194359 104074, 194069 104268, 190947 104268, 190754 103989, 190753 100856, 191032 100663) (190753 105866, 191032 105673, 194165 105672, 194359 105962, 194359 109084, 194069 109278, 190947 109278, 190754 108999, 190753 105866) (190753 110876, 191032 110683, 194165 110682, 194359 110972, 194359 114094, 194069 114288, 190947 114288, 190754 114009, 190753 110876) (190753 115886, 191032 115693, 194165 115692, 194359 115982, 194359 119104, 194069 119298, 190947 119298, 190754 119019, 190753 115886) (190753 120896, 191032 120703, 194165 120702, 194359 120992, 194359 124114, 194069 124308, 190947 124308, 190754 124029, 190753 120896) (190753 125906, 191032 125713, 194165 125712, 194359 126002, 194359 129124, 194069 129318, 190947 129318, 190754 129039, 190753 125906) (190757 130928, 190815 130826, 191032 130723, 194164 130722, 194359 130980, 194359 134134, 194069 134328, 190947 134328, 190754 134049, 190757 130928) (190753 135926, 191032 135733, 194165 135732, 194359 136022, 194359 139144, 194069 139338, 190947 139338, 190754 139059, 190753 135926) (190753 140936, 191032 140743, 194165 140742, 194359 141032, 194359 144155, 194069 144349, 190947 144349, 190754 144070, 190753 140936) (190757 145959, 190815 145857, 191032 145754, 194164 145753, 194359 146011, 194359 149165, 194069 149359, 190947 149359, 190754 149080, 190757 145959) (190753 150957, 191032 150764, 194165 150763, 194359 151053, 194359 154175, 194069 154369, 190947 154369, 190754 154090, 190753 150957) (190753 155967, 191032 155774, 194165 155773, 194359 156063, 194359 159185, 194069 159379, 190947 159379, 190754 159100, 190753 155967) (190753 160977, 191032 160784, 194165 160783, 194359 161073, 194359 164195, 194069 164389, 190947 164389, 190754 164110, 190753 160977) (190753 165987, 191032 165794, 194165 165793, 194359 166083, 194359 169205, 194069 169399, 190947 169399, 190754 169120, 190753 165987) (190753 170997, 191032 170804, 194165 170803, 194359 171093, 194359 174215, 194069 174409, 190947 174409, 190754 174130, 190753 170997) (190753 176007, 191032 175814, 194165 175813, 194359 176103, 194359 179225, 194069 179419, 190945 179419, 190754 179140, 190753 176007) (195763 60770, 196009 60587, 198830 60580, 199289 60913, 199369 61074, 199369 63992, 199079 64186, 195957 64186, 195764 63907, 195763 60770) (195763 65784, 196042 65591, 199175 65590, 199369 65880, 199369 69002, 199079 69196, 195957 69196, 195764 68917, 195763 65784) (195763 70794, 196042 70601, 199175 70600, 199369 70890, 199369 74012, 199079 74206, 195957 74206, 195764 73927, 195763 70794) (195763 75804, 196042 75611, 199175 75610, 199369 75900, 199369 79022, 199079 79216, 195957 79216, 195764 78937, 195763 75804) (195763 80814, 196042 80621, 199175 80620, 199369 80910, 199369 84032, 199079 84226, 195957 84226, 195764 83947, 195763 80814) (195763 85824, 196042 85631, 199175 85630, 199369 85920, 199369 89042, 199079 89236, 195957 89236, 195764 88957, 195763 85824) (195763 90834, 196042 90641, 199175 90640, 199369 90930, 199369 94052, 199079 94246, 195957 94246, 195764 93967, 195763 90834) (195767 95856, 195825 95754, 196042 95651, 199174 95650, 199369 95908, 199369 99064, 199079 99258, 195957 99258, 195764 98979, 195767 95856) (195763 100856, 196042 100663, 199175 100662, 199369 100952, 199369 104074, 199079 104268, 195957 104268, 195764 103989, 195763 100856) (195763 105866, 196042 105673, 199175 105672, 199369 105962, 199369 109084, 199079 109278, 195957 109278, 195764 108999, 195763 105866) (195763 110876, 196042 110683, 199175 110682, 199369 110972, 199369 114094, 199079 114288, 195957 114288, 195764 114009, 195763 110876) (195763 115886, 196042 115693, 199175 115692, 199369 115982, 199369 119104, 199079 119298, 195957 119298, 195764 119019, 195763 115886) (195763 120896, 196042 120703, 199175 120702, 199369 120992, 199369 124114, 199079 124308, 195957 124308, 195764 124029, 195763 120896) (195763 125906, 196042 125713, 199175 125712, 199369 126002, 199369 129124, 199079 129318, 195957 129318, 195764 129039, 195763 125906) (195767 130928, 195825 130826, 196042 130723, 199174 130722, 199369 130980, 199369 134134, 199079 134328, 195957 134328, 195764 134049, 195767 130928) (195763 135926, 196042 135733, 199175 135732, 199369 136022, 199369 139144, 199079 139338, 195957 139338, 195764 139059, 195763 135926) (195763 140936, 196042 140743, 199175 140742, 199369 141032, 199369 144155, 199079 144349, 195957 144349, 195764 144070, 195763 140936) (195767 145959, 195825 145857, 196042 145754, 199174 145753, 199369 146011, 199369 149165, 199079 149359, 195957 149359, 195764 149080, 195767 145959) (195763 150957, 196042 150764, 199175 150763, 199369 151053, 199369 154175, 199079 154369, 195957 154369, 195764 154090, 195763 150957) (195763 155967, 196042 155774, 199175 155773, 199369 156063, 199369 159185, 199079 159379, 195957 159379, 195764 159100, 195763 155967) (195763 160977, 196042 160784, 199175 160783, 199369 161073, 199369 164195, 199079 164389, 195957 164389, 195764 164110, 195763 160977) (195763 165987, 196042 165794, 199175 165793, 199369 166083, 199369 169205, 199079 169399, 195957 169399, 195764 169120, 195763 165987) (195763 170997, 196042 170804, 199175 170803, 199369 171093, 199369 174215, 199079 174409, 195957 174409, 195764 174130, 195763 170997) (195763 176007, 196042 175814, 199175 175813, 199369 176103, 199369 178925, 199300 179077, 198841 179419, 195983 179417, 195850 179336, 195764 179140, 195763 176007) (200954 61981, 201132 61964, 203025 63096, 203835 63699, 203884 63885, 203815 64106, 203689 64183, 200967 64186, 200774 63907, 200773 62276, 200954 61981) (200773 65784, 201052 65591, 204188 65590, 204379 65880, 204379 69002, 204089 69196, 200967 69196, 200774 68917, 200773 65784) (200773 70794, 201052 70601, 204185 70600, 204379 70890, 204379 74012, 204089 74206, 200967 74206, 200774 73927, 200773 70794) (200773 75804, 201052 75611, 204185 75610, 204379 75900, 204379 79022, 204089 79216, 200967 79216, 200774 78937, 200773 75804) (200773 80814, 201052 80621, 204185 80620, 204379 80910, 204379 84032, 204089 84226, 200967 84226, 200774 83947, 200773 80814) (200773 85824, 201052 85631, 204185 85630, 204379 85920, 204379 89042, 204089 89236, 200967 89236, 200774 88957, 200773 85824) (200773 90834, 201052 90641, 204185 90640, 204379 90930, 204379 94052, 204089 94246, 200967 94246, 200774 93967, 200773 90834) (200777 95856, 200835 95754, 201052 95651, 204184 95650, 204379 95908, 204379 99064, 204089 99258, 200967 99258, 200774 98979, 200777 95856) (200773 100856, 201052 100663, 204185 100662, 204379 100952, 204379 104074, 204089 104268, 200967 104268, 200774 103989, 200773 100856) (200773 105866, 201052 105673, 204185 105672, 204379 105962, 204379 109084, 204089 109278, 200967 109278, 200774 108999, 200773 105866) (200773 110876, 201052 110683, 204185 110682, 204379 110972, 204379 114094, 204089 114288, 200967 114288, 200774 114009, 200773 110876) (200773 115886, 201052 115693, 204185 115692, 204379 115982, 204379 119104, 204089 119298, 200967 119298, 200774 119019, 200773 115886) (200773 120896, 201052 120703, 204185 120702, 204379 120992, 204379 124114, 204089 124308, 200967 124308, 200774 124029, 200773 120896) (200773 125906, 201052 125713, 204185 125712, 204379 126002, 204379 129124, 204089 129318, 200967 129318, 200774 129039, 200773 125906) (200777 130928, 200835 130826, 201052 130723, 204184 130722, 204379 130980, 204379 134134, 204089 134328, 200967 134328, 200774 134049, 200777 130928) (200773 135926, 201052 135733, 204185 135732, 204379 136022, 204379 139144, 204089 139338, 200967 139338, 200774 139059, 200773 135926) (200773 140936, 201052 140743, 204185 140742, 204379 141032, 204379 144155, 204089 144349, 200967 144349, 200774 144070, 200773 140936) (200777 145959, 200835 145857, 201052 145754, 204184 145753, 204379 146011, 204379 149165, 204089 149359, 200967 149359, 200774 149080, 200777 145959) (200773 150957, 201052 150764, 204185 150763, 204379 151053, 204379 154175, 204089 154369, 200967 154369, 200774 154090, 200773 150957) (200773 155967, 201052 155774, 204185 155773, 204379 156063, 204379 159185, 204089 159379, 200967 159379, 200774 159100, 200773 155967) (200773 160977, 201052 160784, 204185 160783, 204379 161073, 204379 164195, 204089 164389, 200967 164389, 200774 164110, 200773 160977) (200773 165987, 201052 165794, 204185 165793, 204379 166083, 204379 169205, 204089 169399, 200967 169399, 200774 169120, 200773 165987) (200773 170997, 201052 170804, 204185 170803, 204379 171093, 204379 174255, 204128 174403, 200967 174409, 200774 174130, 200773 170997) (200773 176007, 201052 175814, 203708 175813, 203811 175908, 203900 176185, 203822 176312, 203018 176908, 201228 177981, 200881 177976, 200776 177833, 200773 176007) (205783 65785, 205840 65699, 206101 65590, 206437 65631, 208427 67103, 209390 67980, 209389 69007, 209099 69196, 205977 69196, 205784 68917, 205783 65785) (205783 70794, 206062 70601, 209195 70600, 209389 70890, 209389 74012, 209099 74206, 205977 74206, 205784 73927, 205783 70794) (205783 75804, 206062 75611, 209195 75610, 209389 75900, 209389 79022, 209099 79216, 205977 79216, 205784 78937, 205783 75804) (205783 80814, 206062 80621, 209195 80620, 209389 80910, 209389 84032, 209099 84226, 205977 84226, 205784 83947, 205783 80814) (205783 85824, 206062 85631, 209195 85630, 209389 85920, 209389 89042, 209099 89236, 205977 89236, 205784 88957, 205783 85824) (205783 90834, 206062 90641, 209195 90640, 209389 90930, 209389 94052, 209099 94246, 205977 94246, 205784 93967, 205783 90834) (205787 95856, 205845 95754, 206062 95651, 209194 95650, 209389 95908, 209389 99064, 209099 99258, 205977 99258, 205784 98979, 205787 95856) (205783 100856, 206062 100663, 209195 100662, 209389 100952, 209389 104074, 209099 104268, 205977 104268, 205784 103989, 205783 100856) (205783 105866, 206062 105673, 209195 105672, 209389 105962, 209389 109084, 209099 109278, 205977 109278, 205784 108999, 205783 105866) (205783 110876, 206062 110683, 209195 110682, 209389 110972, 209389 114094, 209099 114288, 205977 114288, 205784 114009, 205783 110876) (205783 115886, 206062 115693, 209195 115692, 209389 115982, 209389 119104, 209099 119298, 205977 119298, 205784 119019, 205783 115886) (206062 120703, 209195 120702, 209389 120992, 209389 124114, 209099 124308, 205977 124308, 205784 124029, 205783 120896, 206062 120703) (205783 125906, 206062 125713, 209195 125712, 209389 126002, 209389 129124, 209099 129318, 205977 129318, 205784 129039, 205783 125906) (205787 130928, 205845 130826, 206062 130723, 209194 130722, 209389 130980, 209389 134134, 209099 134328, 205977 134328, 205784 134049, 205787 130928) (205783 135926, 206062 135733, 209195 135732, 209389 136022, 209389 139144, 209099 139338, 205977 139338, 205784 139059, 205783 135926) (205783 140936, 206062 140743, 209195 140742, 209389 141032, 209389 144155, 209099 144349, 205977 144349, 205784 144070, 205783 140936) (205787 145959, 205845 145857, 206062 145754, 209194 145753, 209389 146011, 209389 149165, 209099 149359, 205977 149359, 205784 149080, 205787 145959) (205783 150957, 206062 150764, 209195 150763, 209389 151053, 209389 154175, 209099 154369, 205977 154369, 205784 154090, 205783 150957) (205783 155967, 206062 155774, 209195 155773, 209389 156063, 209389 159185, 209099 159379, 205977 159379, 205784 159100, 205783 155967) (205783 160977, 206062 160784, 209195 160783, 209389 161073, 209389 164195, 209099 164389, 205977 164389, 205784 164110, 205783 160977) (205783 165987, 206062 165794, 209195 165793, 209389 166083, 209389 169205, 209099 169399, 205977 169399, 205784 169120, 205783 165987) (205783 170997, 206062 170804, 209195 170803, 209389 171060, 209390 171934, 209324 172082, 208413 172908, 206467 174350, 205863 174347, 205783 174201, 205783 170997) (210793 70794, 211050 70600, 212280 70600, 213381 71593, 214400 72719, 214399 74017, 214109 74206, 210987 74206, 210794 73927, 210793 70794) (210793 75804, 211072 75611, 214205 75610, 214399 75900, 214399 79022, 214109 79216, 210987 79216, 210794 78937, 210793 75804) (210793 80814, 211072 80621, 214205 80620, 214399 80910, 214399 84032, 214109 84226, 210987 84226, 210794 83947, 210793 80814) (210793 85824, 211072 85631, 214205 85630, 214399 85920, 214399 89042, 214109 89236, 210987 89236, 210794 88957, 210793 85824) (210793 90834, 211072 90641, 214205 90640, 214399 90930, 214399 94052, 214109 94246, 210987 94246, 210794 93967, 210793 90834) (210797 95856, 210855 95754, 211072 95651, 214204 95650, 214399 95908, 214399 99064, 214109 99258, 210987 99258, 210794 98979, 210797 95856) (210793 100856, 211072 100663, 214205 100662, 214399 100952, 214399 104074, 214109 104268, 210987 104268, 210794 103989, 210793 100856) (210793 105866, 211072 105673, 214205 105672, 214399 105962, 214399 109084, 214109 109278, 210987 109278, 210794 108999, 210793 105866) (210793 110876, 211072 110683, 214205 110682, 214399 110972, 214399 114094, 214109 114288, 210987 114288, 210794 114009, 210793 110876) (210793 115886, 211072 115693, 214205 115692, 214399 115982, 214399 119104, 214109 119298, 210987 119298, 210794 119019, 210793 115886) (210793 120896, 211072 120703, 214205 120702, 214399 120992, 214399 124114, 214109 124308, 210987 124308, 210794 124029, 210793 120896) (210793 125906, 211072 125713, 214205 125712, 214399 126002, 214399 129124, 214109 129318, 210987 129318, 210794 129039, 210793 125906) (210797 130928, 210855 130826, 211072 130723, 214204 130722, 214399 130980, 214399 134134, 214109 134328, 210987 134328, 210794 134049, 210797 130928) (210793 135926, 211072 135733, 214205 135732, 214399 136022, 214399 139144, 214109 139338, 210987 139338, 210794 139059, 210793 135926) (210793 140936, 211072 140743, 214205 140742, 214399 141032, 214399 144155, 214109 144349, 210987 144349, 210794 144070, 210793 140936) (210797 145959, 210855 145857, 211072 145754, 214204 145753, 214399 146011, 214399 149165, 214109 149359, 210987 149359, 210794 149080, 210797 145959) (210793 150957, 211072 150764, 214205 150763, 214399 151053, 214399 154175, 214109 154369, 210987 154369, 210794 154090, 210793 150957) (210793 155967, 211072 155774, 214205 155773, 214399 156063, 214399 159185, 214109 159379, 210987 159379, 210794 159100, 210793 155967) (210793 160977, 211072 160784, 214205 160783, 214399 161073, 214399 164195, 214109 164389, 210987 164389, 210794 164110, 210793 160977) (210793 165987, 211072 165794, 214205 165793, 214399 166050, 214399 167206, 214348 167341, 213392 168395, 212341 169348, 212206 169399, 210982 169399, 210794 169120, 210793 165987) (215803 75804, 216060 75610, 217019 75610, 217910 76588, 219350 78532, 219347 79136, 219201 79216, 215997 79216, 215804 78937, 215803 75804) (215803 80814, 216082 80621, 219255 80620, 219403 80871, 219409 84032, 219119 84226, 215997 84226, 215804 83947, 215803 80814) (215803 85824, 216082 85631, 219215 85630, 219409 85920, 219409 89042, 219119 89236, 215997 89236, 215804 88957, 215803 85824) (215803 90834, 216082 90641, 219215 90640, 219409 90930, 219409 94052, 219119 94246, 215997 94246, 215804 93967, 215803 90834) (215807 95856, 215865 95754, 216082 95651, 219214 95650, 219409 95908, 219409 99064, 219119 99258, 215997 99258, 215804 98979, 215807 95856) (215803 100856, 216082 100663, 219215 100662, 219409 100952, 219409 104074, 219119 104268, 215997 104268, 215804 103989, 215803 100856) (215803 105866, 216082 105673, 219215 105672, 219409 105962, 219409 109084, 219119 109278, 215997 109278, 215804 108999, 215803 105866) (215803 110876, 216082 110683, 219215 110682, 219409 110972, 219409 114094, 219119 114288, 215997 114288, 215804 114009, 215803 110876) (215803 115886, 216082 115693, 219215 115692, 219409 115982, 219409 119104, 219119 119298, 215997 119298, 215804 119019, 215803 115886) (215803 120896, 216082 120703, 219215 120702, 219409 120992, 219409 124114, 219119 124308, 215997 124308, 215804 124029, 215803 120896) (215803 125906, 216082 125713, 219215 125712, 219409 126002, 219409 129124, 219119 129318, 215997 129318, 215804 129039, 215803 125906) (215807 130928, 215865 130826, 216082 130723, 219214 130722, 219409 130980, 219409 134134, 219119 134328, 215997 134328, 215804 134049, 215807 130928) (215803 135926, 216082 135733, 219215 135732, 219409 136022, 219409 139144, 219119 139338, 215997 139338, 215804 139059, 215803 135926) (215803 140936, 216082 140743, 219215 140742, 219409 141032, 219409 144155, 219119 144349, 215997 144349, 215804 144070, 215803 140936) (215807 145959, 215865 145857, 216082 145754, 219214 145753, 219409 146011, 219409 149165, 219119 149359, 215997 149359, 215804 149080, 215807 145959) (215803 150957, 216082 150764, 219215 150763, 219409 151053, 219409 154175, 219119 154369, 215997 154369, 215804 154090, 215803 150957) (215803 155967, 216082 155774, 219215 155773, 219409 156063, 219410 159129, 219367 159254, 219119 159379, 215997 159379, 215804 159100, 215803 155967) (215803 160977, 216082 160784, 219214 160783, 219300 160840, 219409 161101, 219368 161437, 217903 163420, 217082 164324, 216934 164389, 215992 164389, 215804 164110, 215803 160977) (220813 81291, 220908 81188, 221185 81099, 221289 81152, 221905 81976, 222996 83801, 222976 84118, 222833 84223, 221007 84226, 220814 83947, 220813 81291) (220813 85824, 221092 85631, 223925 85630, 224077 85699, 224419 86158, 224417 89016, 224357 89132, 224129 89236, 221007 89236, 220814 88957, 220813 85824) (220813 90834, 221092 90641, 224225 90640, 224419 90930, 224419 94008, 224357 94142, 224129 94246, 221007 94246, 220814 93967, 220813 90834) (220817 95856, 220875 95754, 221092 95651, 224224 95650, 224419 95908, 224419 99064, 224129 99258, 221007 99258, 220814 98979, 220817 95856) (220813 100856, 221092 100663, 224225 100662, 224419 100952, 224419 104074, 224129 104268, 221007 104268, 220814 103989, 220813 100856) (220813 105866, 221092 105673, 224225 105672, 224419 105962, 224419 109084, 224129 109278, 221007 109278, 220814 108999, 220813 105866) (220813 110876, 221092 110683, 224225 110682, 224419 110972, 224419 114094, 224129 114288, 221007 114288, 220814 114009, 220813 110876) (220813 115886, 221092 115693, 224225 115692, 224419 115982, 224419 119104, 224129 119298, 221007 119298, 220814 119019, 220813 115886) (220813 120896, 221092 120703, 224225 120702, 224419 120992, 224419 124114, 224129 124308, 221007 124308, 220814 124029, 220813 120896) (220813 125906, 221092 125713, 224225 125712, 224419 126002, 224419 129124, 224129 129318, 221007 129318, 220814 129039, 220813 125906) (220817 130928, 220875 130826, 221092 130723, 224224 130722, 224419 130980, 224419 134134, 224129 134328, 221007 134328, 220814 134049, 220817 130928) (220813 135926, 221092 135733, 224225 135732, 224419 136022, 224419 139144, 224129 139338, 221007 139338, 220814 139059, 220813 135926) (220813 140936, 221092 140743, 224225 140742, 224419 141032, 224419 144155, 224129 144349, 221007 144349, 220814 144070, 220813 140936) (220817 145959, 220875 145857, 221092 145754, 224224 145753, 224419 146011, 224419 149129, 224356 149256, 224129 149359, 221007 149359, 220814 149080, 220817 145959) (220813 150957, 221092 150764, 224229 150763, 224420 151025, 224419 153830, 224086 154289, 223925 154369, 221007 154369, 220814 154090, 220813 150957) (220813 155967, 221092 155774, 222723 155773, 223018 155953, 223020 156163, 221903 158025, 221322 158809, 221114 158884, 220893 158815, 220816 158689, 220813 155967) (225823 90834, 225947 90704, 226647 90670, 226812 90811, 228240 93846, 228144 94220, 226062 94247, 225928 94185, 225824 93967, 225823 90834) (225827 95856, 225885 95754, 226102 95651, 228715 95650, 228959 95847, 229421 97145, 229429 99110, 229139 99258, 226017 99258, 225824 98979, 225827 95856) (225823 100856, 226102 100663, 229235 100662, 229429 100949, 229426 104055, 229367 104164, 229139 104268, 226017 104268, 225824 103989, 225823 100856) (225823 105866, 226102 105673, 229235 105672, 229429 105962, 229429 109084, 229139 109278, 226017 109278, 225824 108999, 225823 105866) (225823 110876, 226102 110683, 229235 110682, 229429 110972, 229429 114094, 229139 114288, 226017 114288, 225824 114009, 225823 110876) (225823 115886, 226102 115693, 229235 115692, 229429 115982, 229429 119104, 229139 119298, 226017 119298, 225824 119019, 225823 115886) (225823 120896, 226102 120703, 229235 120702, 229429 120992, 229429 124114, 229139 124308, 226017 124308, 225824 124029, 225823 120896) (225823 125906, 226102 125713, 229235 125712, 229429 126002, 229429 129124, 229139 129318, 226017 129318, 225824 129039, 225823 125906) (225827 130928, 225885 130826, 226102 130723, 229234 130722, 229429 130980, 229429 134098, 229366 134225, 229139 134328, 226017 134328, 225824 134049, 225827 130928) (225823 135926, 226102 135733, 229239 135732, 229423 135981, 229430 139145, 229139 139338, 226017 139338, 225824 139059, 225823 135926) (225823 140936, 226102 140743, 229234 140742, 229321 140799, 229430 141045, 229424 142854, 228945 144184, 228719 144349, 226017 144349, 225824 144070, 225823 140936) (225827 145959, 225885 145857, 226102 145754, 227959 145753, 228237 145902, 228270 146097, 226795 149218, 226530 149359, 225980 149330, 225823 149149, 225827 145959) (230833 105866, 231092 105676, 231645 105672, 231916 105817, 232120 106630, 232474 109033, 232410 109174, 232201 109275, 231027 109278, 230834 108999, 230833 105866) (230833 110876, 231112 110683, 232545 110685, 232673 110771, 232760 110936, 233109 113291, 233145 114063, 233067 114197, 232876 114286, 231027 114288, 230834 114009, 230833 110876) (230833 115886, 231112 115693, 233030 115692, 233165 115796, 233240 115976, 233390 119073, 233309 119211, 233102 119298, 231027 119298, 230834 119019, 230833 115886) (230833 120896, 231112 120703, 233251 120702, 233388 121017, 233236 124105, 233145 124231, 232989 124303, 231027 124308, 230834 124029, 230833 120896) (230833 125906, 231112 125713, 232943 125712, 233085 125836, 233142 126027, 233109 126714, 232748 129135, 232510 129312, 231027 129318, 230834 129039, 230833 125906) (230837 130928, 230895 130826, 231112 130723, 232281 130728, 232373 130781, 232463 131066, 232122 133357, 231927 134133, 231636 134328, 230994 134300, 230833 134118, 230837 130928) (95562 120036, 95660 121007, 95821 124226, 95776 124749, 95907 126017, 95946 126807, 96326 129356, 96337 129890, 96589 131141, 96947 133546, 97184 134481, 97245 134937, 98560 140189, 98926 141211, 99601 142910, 99694 143206, 100202 144618, 100294 145033, 100690 146135, 102400 149732, 102513 150088, 103757 152724, 104500 153963, 105131 154921, 105724 156050, 106205 156715, 107314 158564, 108020 159510, 108315 159997, 109487 161577, 109886 162031, 111364 164023, 112320 165075, 112712 165586, 114445 167497, 114948 167977, 115940 169069, 117139 170154, 117502 170553, 119413 172286, 120037 172785, 120983 173640, 123094 175204, 123358 175458, 124644 176418, 125625 177083, 126446 177692, 128484 178910, 129267 179440, 130141 179891, 130770 180281, 131038 180492, 132271 181239, 134909 182488, 135406 182669, 138448 184107, 138732 184210, 139778 184655, 140528 184852, 141941 185355, 142078 185426, 143739 186055, 144805 186437, 150062 187753, 150672 187857, 151457 188053, 153951 188422, 154465 188567, 155761 188692, 158216 189055, 159083 189095, 159601 189190, 160884 189186, 164094 189343, 165000 189439, 166007 189340, 169227 189178, 169749 189223, 171017 189092, 171807 189053, 174356 188672, 174880 188663, 176141 188410, 178542 188053, 179480 187816, 179937 187754, 185194 186437, 186211 186073, 187910 185398, 188205 185305, 189618 184797, 190033 184705, 191135 184309, 194734 182600, 195087 182486, 197729 181239, 198963 180499, 199921 179868, 201050 179275, 201715 178794, 203554 177692, 204386 177074, 204998 176683, 206577 175512, 207031 175112, 209026 173634, 209962 172786, 210585 172287, 212496 170554, 212977 170050, 214075 169053, 215051 167978, 215554 167497, 217286 165586, 217785 164962, 218636 164024, 220204 161905, 220458 161642, 221418 160355, 222084 159373, 222692 158553, 223832 156650, 224455 155706, 224891 154858, 225281 154229, 225492 153961, 226242 152724, 227486 150089, 227599 149733, 229107 146551, 229676 145157, 229797 144617, 230305 143206, 230397 142910, 231055 141261, 231439 140189, 232753 134938, 232815 134480, 233056 133522, 233401 131204, 233568 130587, 233667 129393, 234055 126795, 234090 126073, 234195 125463, 234175 124272, 234336 121063, 234405 120666, 234438 119965, 234344 119148, 234189 115930, 234233 115303, 234098 114138, 234053 113187, 233698 110798, 233683 110175, 233430 109014, 233053 106454, 232857 105672, 232755 105062, 231439 99810, 231073 98789, 230427 97079, 230356 96941, 229853 95528, 229705 94966, 229319 93893, 227670 90407, 227489 89910, 226238 87267, 225500 86035, 224869 85078, 224248 83900, 223872 83419, 222692 81446, 221979 80489, 221683 80001, 220512 78422, 220112 77968, 218600 75936, 217678 74924, 217287 74414, 215554 72503, 215153 72139, 214053 70923, 212861 69846, 212497 69445, 210585 67713, 210074 67320, 209026 66365, 206905 64795, 206642 64541, 205355 63581, 204497 63010, 203553 62307, 201515 61089, 200732 60559, 199858 60108, 199229 59718, 198961 59507, 197724 58757, 195090 57511, 194593 57330, 191551 55891, 191289 55799, 190228 55346, 189471 55147, 188058 54644, 187921 54572, 186261 53944, 185194 53562, 179938 52246, 179328 52142, 178530 51944, 176049 51577, 175535 51432, 174239 51307, 171795 50944, 170916 50904, 170394 50809, 169116 50812, 165906 50658, 164965 50562, 163993 50660, 160774 50821, 160253 50776, 158983 50906, 158192 50946, 155644 51327, 155113 51336, 153859 51589, 151457 51946, 150520 52183, 150063 52245, 144805 53562, 143789 53926, 142089 54601, 141794 54694, 140381 55202, 139966 55294, 138897 55677, 135267 57400, 134911 57513, 132275 58757, 131036 59500, 130078 60131, 128949 60724, 128284 61205, 126446 62307, 125489 63020, 125002 63315, 123422 64487, 122968 64887, 120936 66399, 119924 67321, 119414 67712, 117503 69445, 117022 69949, 115923 70946, 114846 72138, 114445 72502, 112713 74413, 112214 75037, 111359 75983, 109795 78094, 109541 78357, 108581 79644, 107915 80626, 107307 81446, 106089 83484, 105559 84267, 105108 85141, 104718 85770, 104507 86038, 103757 87275, 102511 89909, 102330 90406, 100893 93446, 100791 93732, 100346 94774, 100147 95528, 99644 96941, 99572 97078, 98944 98740, 98560 99810, 97245 105061, 97142 105672, 96943 106475, 96577 108951, 96429 109470, 96306 110761, 95944 113211, 95904 114084, 95809 114606, 95812 115885, 95659 119094, 95562 120036) (96456 120465, 96835 120253, 98916 120251, 99293 120434, 99616 120966, 99618 124095, 99434 124435, 98902 124758, 97006 124762, 96668 124602, 96314 124147, 96160 120984, 96456 120465) (96310 115908, 96644 115429, 97058 115241, 98916 115241, 99293 115424, 99616 115956, 99618 119085, 99434 119425, 98902 119748, 96819 119750, 96479 119568, 96157 119063, 96310 115908) (96689 125485, 97047 125267, 98916 125261, 99293 125444, 99616 125976, 99618 129105, 99434 129445, 98901 129768, 97676 129772, 97206 129646, 96817 129240, 96442 126751, 96405 125994, 96689 125485) (96408 114065, 96443 113244, 96800 110833, 97178 110390, 97538 110224, 98916 110231, 99293 110414, 99616 110946, 99618 114075, 99434 114415, 98902 114738, 97069 114739, 96711 114546, 96408 114065) (97317 130532, 97719 130277, 98915 130271, 99209 130398, 99400 130568, 99616 130985, 99618 134115, 99434 134455, 98991 134715, 98354 134728, 97983 134601, 97659 134317, 97435 133440, 97082 131069, 97317 130532) (97435 106557, 97626 105792, 97983 105400, 98379 105272, 99083 105308, 99388 105469, 99617 105897, 99618 109065, 99434 109405, 98902 109728, 97624 109729, 97341 109499, 97081 108982, 97435 106557) (100170 98954, 100142 97041, 100617 95696, 100887 95421, 101159 95272, 102040 95199, 103925 95199, 104219 95326, 104410 95496, 104626 95913, 104628 99045, 104444 99385, 103912 99708, 100783 99710, 100396 99484, 100231 99221, 100170 98954) (100171 100803, 100370 100464, 100797 100213, 103926 100211, 104303 100394, 104626 100926, 104628 104055, 104444 104395, 103912 104718, 100783 104720, 100445 104537, 100173 104087, 100171 100803) (100119 105903, 100360 105483, 100797 105223, 103926 105221, 104303 105404, 104626 105936, 104628 109065, 104444 109405, 103912 109728, 100783 109730, 100443 109546, 100121 109051, 100119 105903) (100302 110555, 100797 110233, 103926 110231, 104303 110414, 104626 110946, 104628 114075, 104444 114415, 103912 114738, 100783 114740, 100443 114556, 100121 114061, 100119 110932, 100302 110555) (100302 115565, 100797 115243, 103926 115241, 104303 115424, 104626 115956, 104628 119085, 104444 119425, 103912 119748, 100783 119750, 100443 119566, 100121 119071, 100119 115942, 100302 115565) (100302 120575, 100797 120253, 103926 120251, 104303 120434, 104626 120966, 104628 124095, 104444 124435, 103912 124758, 100783 124760, 100443 124576, 100121 124081, 100119 120952, 100302 120575) (100302 125585, 100797 125263, 103926 125261, 104303 125444, 104626 125976, 104628 129105, 104444 129445, 103911 129768, 100783 129770, 100443 129586, 100121 129091, 100119 125962, 100302 125585) (100305 130592, 100797 130273, 103925 130271, 104219 130398, 104410 130568, 104626 130985, 104628 134115, 104444 134455, 103912 134778, 100783 134780, 100443 134596, 100121 134101, 100119 130972, 100305 130592) (100295 135615, 100797 135283, 103926 135281, 104303 135464, 104626 135996, 104628 139125, 104444 139465, 103912 139788, 100783 139790, 100326 139480, 100170 139147, 100170 135903, 100295 135615) (100295 140624, 100797 140293, 103926 140291, 104303 140474, 104626 141006, 104628 144136, 104444 144476, 103903 144800, 101814 144808, 101162 144728, 100660 144408, 100111 142891, 100170 140994, 100295 140624) (101452 94348, 101264 93829, 102781 90619, 103140 90331, 103489 90240, 104102 90278, 104398 90437, 104627 90865, 104628 94033, 104444 94373, 103911 94696, 102040 94697, 101722 94556, 101452 94348) (101345 146338, 101375 145912, 101482 145627, 101858 145325, 103917 145301, 104362 145539, 104626 146016, 104628 149146, 104444 149486, 104203 149665, 103517 149757, 103140 149668, 102834 149479, 101345 146338) (105170 85989, 105543 85433, 106074 85230, 107276 85179, 108936 85179, 109313 85362, 109636 85894, 109638 89023, 109454 89363, 108922 89686, 105793 89688, 105337 89378, 105185 89015, 105180 87631, 105170 85989) (105129 90871, 105370 90451, 105807 90191, 108936 90189, 109313 90372, 109636 90904, 109638 94033, 109454 94373, 108921 94696, 105793 94698, 105453 94514, 105131 94019, 105129 90871) (105315 95520, 105807 95201, 108935 95199, 109229 95326, 109420 95496, 109636 95913, 109638 99045, 109454 99385, 108922 99708, 105793 99710, 105453 99526, 105131 99031, 105129 95900, 105315 95520) (105312 100535, 105807 100213, 108936 100211, 109313 100394, 109636 100926, 109638 104055, 109454 104395, 108922 104718, 105793 104720, 105453 104536, 105131 104041, 105129 100912, 105312 100535) (105312 105545, 105807 105223, 108936 105221, 109313 105404, 109636 105936, 109638 109065, 109454 109405, 108922 109728, 105793 109730, 105453 109546, 105131 109051, 105129 105922, 105312 105545) (105312 110555, 105807 110233, 108936 110231, 109313 110414, 109636 110946, 109638 114075, 109454 114415, 108922 114738, 105793 114740, 105453 114556, 105131 114061, 105129 110932, 105312 110555) (105312 115565, 105807 115243, 108936 115241, 109313 115424, 109636 115956, 109638 119085, 109454 119425, 108922 119748, 105793 119750, 105453 119566, 105131 119071, 105129 115942, 105312 115565) (105312 120575, 105807 120253, 108936 120251, 109313 120434, 109636 120966, 109638 124095, 109454 124435, 108922 124758, 105793 124760, 105453 124576, 105131 124081, 105129 120952, 105312 120575) (105312 125585, 105807 125263, 108936 125261, 109313 125444, 109636 125976, 109638 129105, 109454 129445, 108921 129768, 105793 129770, 105453 129586, 105131 129091, 105129 125962, 105312 125585) (105315 130592, 105807 130273, 108935 130271, 109229 130398, 109420 130568, 109636 130985, 109638 134115, 109454 134455, 108922 134778, 105793 134780, 105453 134596, 105131 134101, 105129 130972, 105315 130592) (105312 135605, 105807 135283, 108936 135281, 109313 135464, 109636 135996, 109638 139125, 109454 139465, 108922 139788, 105793 139790, 105453 139606, 105131 139111, 105129 135982, 105312 135605) (105312 140615, 105807 140293, 108936 140291, 109313 140474, 109636 141006, 109638 144136, 109454 144476, 108921 144799, 105793 144801, 105453 144617, 105131 144122, 105129 140992, 105312 140615) (105314 145624, 105807 145304, 108935 145302, 109229 145429, 109420 145599, 109636 146016, 109638 149146, 109454 149486, 108922 149809, 105793 149811, 105453 149627, 105131 149132, 105129 146003, 105314 145624) (105186 150923, 105237 150756, 105429 150526, 105807 150314, 108936 150312, 109313 150495, 109636 151027, 109638 154156, 109454 154496, 108922 154819, 107044 154823, 106074 154769, 105543 154566, 105179 154048, 105186 150923) (106642 84257, 106541 83704, 107721 81725, 108315 80922, 108977 80726, 109345 80863, 109508 81049, 109637 81345, 109638 84013, 109454 84353, 108922 84676, 107276 84677, 106933 84519, 106642 84257) (106602 155929, 106668 155697, 107087 155328, 108936 155322, 109313 155505, 109636 156037, 109632 158754, 109434 159040, 109094 159250, 108747 159294, 108386 159172, 107740 158300, 106633 156459, 106602 155929) (110191 78868, 110225 78358, 111751 76291, 112584 75373, 113065 75210, 114024 75210, 114313 75334, 114646 75874, 114648 79003, 114464 79343, 113932 79666, 110803 79668, 110419 79444, 110251 79178, 110191 78868) (110392 80419, 110817 80171, 113946 80169, 114323 80352, 114646 80884, 114648 84013, 114464 84353, 113932 84676, 110803 84678, 110463 84494, 110141 83999, 110139 81345, 110240 80627, 110392 80419) (110322 85503, 110817 85181, 113946 85179, 114323 85362, 114646 85894, 114648 89023, 114464 89363, 113932 89686, 110803 89688, 110463 89504, 110141 89009, 110139 85880, 110322 85503) (110322 90513, 110817 90191, 113946 90189, 114323 90372, 114646 90904, 114648 94033, 114464 94373, 113931 94696, 110803 94698, 110463 94514, 110141 94019, 110139 90890, 110322 90513) (110325 95520, 110817 95201, 113945 95199, 114239 95326, 114430 95496, 114646 95913, 114648 99045, 114464 99385, 113932 99708, 110803 99710, 110463 99526, 110141 99031, 110139 95900, 110325 95520) (110322 100535, 110817 100213, 113946 100211, 114323 100394, 114646 100926, 114648 104055, 114464 104395, 113932 104718, 110803 104720, 110463 104536, 110141 104041, 110139 100912, 110322 100535) (110322 105545, 110817 105223, 113946 105221, 114323 105404, 114646 105936, 114648 109065, 114464 109405, 113932 109728, 110803 109730, 110463 109546, 110141 109051, 110139 105922, 110322 105545) (110322 110555, 110817 110233, 113946 110231, 114323 110414, 114646 110946, 114648 114075, 114464 114415, 113932 114738, 110803 114740, 110463 114556, 110141 114061, 110139 110932, 110322 110555) (110322 115565, 110817 115243, 113946 115241, 114323 115424, 114646 115956, 114648 119085, 114464 119425, 113932 119748, 110803 119750, 110463 119566, 110141 119071, 110139 115942, 110322 115565) (110322 120575, 110817 120253, 113946 120251, 114323 120434, 114646 120966, 114648 124095, 114464 124435, 113932 124758, 110803 124760, 110463 124576, 110141 124081, 110139 120952, 110322 120575) (110322 125585, 110817 125263, 113946 125261, 114323 125444, 114646 125976, 114648 129105, 114464 129445, 113931 129768, 110803 129770, 110463 129586, 110141 129091, 110139 125962, 110322 125585) (110325 130592, 110817 130273, 113945 130271, 114239 130398, 114430 130568, 114646 130985, 114648 134115, 114464 134455, 113932 134778, 110803 134780, 110463 134596, 110141 134101, 110139 130972, 110325 130592) (110322 135605, 110817 135283, 113946 135281, 114323 135464, 114646 135996, 114648 139125, 114464 139465, 113932 139788, 110803 139790, 110463 139606, 110141 139111, 110139 135982, 110322 135605) (110322 140615, 110817 140293, 113946 140291, 114323 140474, 114646 141006, 114648 144136, 114464 144476, 113931 144799, 110803 144801, 110463 144617, 110141 144122, 110139 140992, 110322 140615) (110325 145623, 110817 145304, 113945 145302, 114239 145429, 114430 145599, 114646 146016, 114648 149146, 114464 149486, 113932 149809, 110803 149811, 110463 149627, 110141 149132, 110139 146003, 110325 145623) (110322 150636, 110817 150314, 113946 150312, 114323 150495, 114646 151027, 114648 154156, 114464 154496, 113932 154819, 110803 154821, 110463 154637, 110141 154142, 110139 151013, 110322 150636) (110322 155646, 110817 155324, 113946 155322, 114323 155505, 114646 156037, 114648 159166, 114464 159506, 113932 159829, 110820 159830, 110488 159666, 110348 159524, 110209 159228, 110136 158797, 110139 156023, 110322 155646) (110213 160978, 110331 160624, 110476 160485, 110813 160332, 113946 160332, 114323 160515, 114646 161047, 114648 164176, 114464 164516, 114022 164789, 113065 164789, 112663 164705, 111728 163680, 110287 161735, 110213 160978) (115200 72495, 116284 71291, 117356 70319, 117793 70200, 119034 70200, 119323 70324, 119656 70864, 119658 73993, 119474 74333, 118942 74656, 115813 74658, 115473 74474, 115200 74035, 115200 72495) (115332 75483, 115827 75161, 118956 75159, 119333 75342, 119656 75874, 119658 79003, 119474 79343, 118942 79666, 115813 79668, 115473 79484, 115151 78989, 115149 75860, 115332 75483) (115332 80493, 115827 80171, 118956 80169, 119333 80352, 119656 80884, 119658 84013, 119474 84353, 118942 84676, 115813 84678, 115473 84494, 115151 83999, 115149 80870, 115332 80493) (115332 85503, 115827 85181, 118956 85179, 119333 85362, 119656 85894, 119658 89023, 119474 89363, 118942 89686, 115813 89688, 115473 89504, 115151 89009, 115149 85880, 115332 85503) (115332 90513, 115827 90191, 118956 90189, 119333 90372, 119656 90904, 119658 94033, 119474 94373, 118941 94696, 115813 94698, 115473 94514, 115151 94019, 115149 90890, 115332 90513) (115335 95520, 115827 95201, 118955 95199, 119249 95326, 119440 95496, 119656 95913, 119658 99045, 119474 99385, 118942 99708, 115813 99710, 115473 99526, 115151 99031, 115149 95900, 115335 95520) (115332 100535, 115827 100213, 118956 100211, 119333 100394, 119656 100926, 119658 104055, 119474 104395, 118942 104718, 115813 104720, 115473 104536, 115151 104041, 115149 100912, 115332 100535) (115332 105545, 115827 105223, 118956 105221, 119333 105404, 119656 105936, 119658 109065, 119474 109405, 118942 109728, 115813 109730, 115473 109546, 115151 109051, 115149 105922, 115332 105545) (115332 110555, 115827 110233, 118956 110231, 119333 110414, 119656 110946, 119658 114075, 119474 114415, 118942 114738, 115813 114740, 115473 114556, 115151 114061, 115149 110932, 115332 110555) (115332 115565, 115827 115243, 118956 115241, 119333 115424, 119656 115956, 119658 119085, 119474 119425, 118942 119748, 115813 119750, 115473 119566, 115151 119071, 115149 115942, 115332 115565) (115332 120575, 115827 120253, 118956 120251, 119333 120434, 119656 120966, 119658 124095, 119474 124435, 118942 124758, 115813 124760, 115473 124576, 115151 124081, 115149 120952, 115332 120575) (115332 125585, 115827 125263, 118956 125261, 119333 125444, 119656 125976, 119658 129105, 119474 129445, 118941 129768, 115813 129770, 115473 129586, 115151 129091, 115149 125962, 115332 125585) (115335 130592, 115827 130273, 118955 130271, 119249 130398, 119440 130568, 119656 130985, 119658 134115, 119474 134455, 118942 134778, 115813 134780, 115473 134596, 115151 134101, 115149 130972, 115335 130592) (115332 135605, 115827 135283, 118956 135281, 119333 135464, 119656 135996, 119658 139125, 119474 139465, 118942 139788, 115813 139790, 115473 139606, 115151 139111, 115149 135982, 115332 135605) (115332 140615, 115827 140293, 118956 140291, 119333 140474, 119656 141006, 119658 144136, 119474 144476, 118941 144799, 115813 144801, 115473 144617, 115151 144122, 115149 140992, 115332 140615) (115335 145623, 115827 145304, 118955 145302, 119249 145429, 119440 145599, 119656 146016, 119658 149146, 119474 149486, 118942 149809, 115813 149811, 115473 149627, 115151 149132, 115149 146003, 115335 145623) (115332 150636, 115827 150314, 118956 150312, 119333 150495, 119656 151027, 119658 154156, 119474 154496, 118942 154819, 115813 154821, 115473 154637, 115151 154142, 115149 151013, 115332 150636) (115332 155646, 115827 155324, 118956 155322, 119333 155505, 119656 156037, 119658 159166, 119474 159506, 118942 159829, 115813 159831, 115473 159647, 115151 159152, 115149 156023, 115332 155646) (115332 160656, 115827 160334, 118956 160332, 119333 160515, 119656 161047, 119658 164176, 119474 164516, 118942 164839, 115813 164841, 115473 164657, 115151 164162, 115149 161033, 115332 160656) (115200 165965, 115325 165676, 115827 165344, 118956 165342, 119333 165525, 119656 166057, 119658 169186, 119474 169526, 119032 169799, 117495 169799, 116287 168711, 115318 167643, 115200 167206, 115200 165965) (120293 67663, 121292 66750, 123264 65287, 124021 65213, 124367 65325, 124514 65476, 124667 65813, 124668 68983, 124484 69323, 123952 69646, 120823 69648, 120483 69464, 120210 69025, 120210 68065, 120293 67663) (120342 70473, 120837 70151, 123966 70149, 124343 70332, 124666 70864, 124668 73993, 124484 74333, 123952 74656, 120823 74658, 120483 74474, 120161 73979, 120159 70850, 120342 70473) (120342 75483, 120837 75161, 123966 75159, 124343 75342, 124666 75874, 124668 79003, 124484 79343, 123952 79666, 120823 79668, 120483 79484, 120161 78989, 120159 75860, 120342 75483) (120342 80493, 120837 80171, 123966 80169, 124343 80352, 124666 80884, 124668 84013, 124484 84353, 123952 84676, 120823 84678, 120483 84494, 120161 83999, 120159 80870, 120342 80493) (120342 85503, 120837 85181, 123966 85179, 124343 85362, 124666 85894, 124668 89023, 124484 89363, 123952 89686, 120823 89688, 120483 89504, 120161 89009, 120159 85880, 120342 85503) (120342 90513, 120837 90191, 123966 90189, 124343 90372, 124666 90904, 124668 94033, 124484 94373, 123951 94696, 120823 94698, 120483 94514, 120161 94019, 120159 90890, 120342 90513) (120345 95520, 120837 95201, 123965 95199, 124259 95326, 124450 95496, 124666 95913, 124668 99045, 124484 99385, 123952 99708, 120823 99710, 120483 99526, 120161 99031, 120159 95900, 120345 95520) (120342 100535, 120837 100213, 123966 100211, 124343 100394, 124666 100926, 124668 104055, 124484 104395, 123952 104718, 120823 104720, 120483 104536, 120161 104041, 120159 100912, 120342 100535) (120342 105545, 120837 105223, 123966 105221, 124343 105404, 124666 105936, 124668 109065, 124484 109405, 123952 109728, 120823 109730, 120483 109546, 120161 109051, 120159 105922, 120342 105545) (120342 110555, 120837 110233, 123966 110231, 124343 110414, 124666 110946, 124668 114075, 124484 114415, 123952 114738, 120823 114740, 120483 114556, 120161 114061, 120159 110932, 120342 110555) (120342 115565, 120837 115243, 123966 115241, 124343 115424, 124666 115956, 124668 119085, 124484 119425, 123952 119748, 120823 119750, 120483 119566, 120161 119071, 120159 115942, 120342 115565) (120342 120575, 120837 120253, 123966 120251, 124343 120434, 124666 120966, 124668 124095, 124484 124435, 123952 124758, 120823 124760, 120483 124576, 120161 124081, 120159 120952, 120342 120575) (120342 125585, 120837 125263, 123966 125261, 124343 125444, 124666 125976, 124668 129105, 124484 129445, 123951 129768, 120823 129770, 120483 129586, 120161 129091, 120159 125962, 120342 125585) (120345 130592, 120837 130273, 123965 130271, 124259 130398, 124450 130568, 124666 130985, 124668 134115, 124484 134455, 123952 134778, 120823 134780, 120483 134596, 120161 134101, 120159 130972, 120345 130592) (120342 135605, 120837 135283, 123966 135281, 124343 135464, 124666 135996, 124668 139125, 124484 139465, 123952 139788, 120823 139790, 120483 139606, 120161 139111, 120159 135982, 120342 135605) (120342 140615, 120837 140293, 123966 140291, 124343 140474, 124666 141006, 124668 144136, 124484 144476, 123951 144799, 120823 144801, 120483 144617, 120161 144122, 120159 140992, 120342 140615) (120345 145623, 120837 145304, 123965 145302, 124259 145429, 124450 145599, 124666 146016, 124668 149146, 124484 149486, 123952 149809, 120823 149811, 120483 149627, 120161 149132, 120159 146003, 120345 145623) (120342 150636, 120837 150314, 123966 150312, 124343 150495, 124666 151027, 124668 154156, 124484 154496, 123952 154819, 120823 154821, 120483 154637, 120161 154142, 120159 151013, 120342 150636) (120342 155646, 120837 155324, 123966 155322, 124343 155505, 124666 156037, 124668 159166, 124484 159506, 123952 159829, 120823 159831, 120483 159647, 120161 159152, 120159 156023, 120342 155646) (120342 160656, 120837 160334, 123966 160332, 124343 160515, 124666 161047, 124668 164176, 124484 164516, 123952 164839, 120823 164841, 120483 164657, 120161 164162, 120159 161033, 120342 160656) (120342 165666, 120837 165344, 123966 165342, 124343 165525, 124666 166057, 124668 169186, 124484 169526, 123952 169849, 120823 169851, 120483 169667, 120161 169172, 120159 166043, 120342 165666) (120210 170975, 120335 170686, 120837 170354, 123966 170352, 124343 170535, 124666 171067, 124668 174196, 124445 174580, 124178 174748, 123868 174808, 123358 174774, 121318 173270, 120373 172415, 120210 171934, 120210 170975) (125169 65820, 125333 65488, 125475 65348, 125770 65208, 126359 65139, 128976 65139, 129353 65322, 129676 65854, 129678 68983, 129494 69323, 128962 69646, 125833 69648, 125493 69464, 125171 68969, 125169 65820) (125352 70473, 125847 70151, 128976 70149, 129353 70332, 129676 70864, 129678 73993, 129494 74333, 128962 74656, 125833 74658, 125493 74474, 125171 73979, 125169 70850, 125352 70473) (125352 75483, 125847 75161, 128976 75159, 129353 75342, 129676 75874, 129678 79003, 129494 79343, 128962 79666, 125833 79668, 125493 79484, 125171 78989, 125169 75860, 125352 75483) (125352 80493, 125847 80171, 128976 80169, 129353 80352, 129676 80884, 129678 84013, 129494 84353, 128962 84676, 125833 84678, 125493 84494, 125171 83999, 125169 80870, 125352 80493) (125352 85503, 125847 85181, 128976 85179, 129353 85362, 129676 85894, 129678 89023, 129494 89363, 128962 89686, 125833 89688, 125493 89504, 125171 89009, 125169 85880, 125352 85503) (125352 90513, 125847 90191, 128976 90189, 129353 90372, 129676 90904, 129678 94033, 129494 94373, 128961 94696, 125833 94698, 125493 94514, 125171 94019, 125169 90890, 125352 90513) (125355 95520, 125847 95201, 128975 95199, 129269 95326, 129460 95496, 129676 95913, 129678 99045, 129494 99385, 128962 99708, 125833 99710, 125493 99526, 125171 99031, 125169 95900, 125355 95520) (125352 100535, 125847 100213, 128976 100211, 129353 100394, 129676 100926, 129678 104055, 129494 104395, 128962 104718, 125833 104720, 125493 104536, 125171 104041, 125169 100912, 125352 100535) (125352 105545, 125847 105223, 128976 105221, 129353 105404, 129676 105936, 129678 109065, 129494 109405, 128962 109728, 125833 109730, 125493 109546, 125171 109051, 125169 105922, 125352 105545) (125352 110555, 125847 110233, 128976 110231, 129353 110414, 129676 110946, 129678 114075, 129494 114415, 128962 114738, 125833 114740, 125493 114556, 125171 114061, 125169 110932, 125352 110555) (125352 115565, 125847 115243, 128976 115241, 129353 115424, 129676 115956, 129678 119085, 129494 119425, 128962 119748, 125833 119750, 125493 119566, 125171 119071, 125169 115942, 125352 115565) (125352 120575, 125847 120253, 128976 120251, 129353 120434, 129676 120966, 129678 124095, 129494 124435, 128962 124758, 125833 124760, 125493 124576, 125171 124081, 125169 120952, 125352 120575) (125352 125585, 125847 125263, 128976 125261, 129353 125444, 129676 125976, 129678 129105, 129494 129445, 128961 129768, 125833 129770, 125493 129586, 125171 129091, 125169 125962, 125352 125585) (125355 130592, 125847 130273, 128975 130271, 129269 130398, 129460 130568, 129676 130985, 129678 134115, 129494 134455, 128962 134778, 125833 134780, 125493 134596, 125171 134101, 125169 130972, 125355 130592) (125352 135605, 125847 135283, 128976 135281, 129353 135464, 129676 135996, 129678 139125, 129494 139465, 128962 139788, 125833 139790, 125493 139606, 125171 139111, 125169 135982, 125352 135605) (125352 140615, 125847 140293, 128976 140291, 129353 140474, 129676 141006, 129678 144136, 129494 144476, 128961 144799, 125833 144801, 125493 144617, 125171 144122, 125169 140992, 125352 140615) (125355 145623, 125847 145304, 128975 145302, 129269 145429, 129460 145599, 129676 146016, 129678 149146, 129494 149486, 128962 149809, 125833 149811, 125493 149627, 125171 149132, 125169 146003, 125355 145623) (125352 150636, 125847 150314, 128976 150312, 129353 150495, 129676 151027, 129678 154156, 129494 154496, 128962 154819, 125833 154821, 125493 154637, 125171 154142, 125169 151013, 125352 150636) (125352 155646, 125847 155324, 128976 155322, 129353 155505, 129676 156037, 129678 159166, 129494 159506, 128962 159829, 125833 159831, 125493 159647, 125171 159152, 125169 156023, 125352 155646) (125352 160656, 125847 160334, 128976 160332, 129353 160515, 129676 161047, 129678 164176, 129494 164516, 128962 164839, 125833 164841, 125493 164657, 125171 164162, 125169 161033, 125352 160656) (125352 165666, 125847 165344, 128976 165342, 129353 165525, 129676 166057, 129678 169186, 129494 169526, 128962 169849, 125833 169851, 125493 169667, 125171 169172, 125169 166043, 125352 165666) (125352 170676, 125847 170354, 128976 170352, 129353 170535, 129676 171067, 129678 174196, 129494 174536, 128962 174859, 126188 174863, 125628 174759, 125420 174607, 125171 174182, 125169 171053, 125352 170676) (125705 63747, 125823 63397, 126723 62722, 128540 61633, 129070 61602, 129302 61668, 129677 62201, 129678 63973, 129494 64313, 128962 64636, 126359 64637, 126084 64520, 125877 64345, 125749 64094, 125705 63747) (125726 176022, 125864 175654, 126231 175368, 128976 175362, 129353 175545, 129676 176077, 129672 177837, 129257 178357, 128704 178458, 126725 177278, 125923 176683, 125726 176022) (130433 60543, 130951 60179, 134076 60186, 134422 60367, 134686 60844, 134688 63973, 134504 64313, 133972 64636, 130843 64638, 130503 64454, 130181 63959, 130179 62201, 130230 61074, 130433 60543) (130362 65463, 130857 65141, 133986 65139, 134363 65322, 134686 65854, 134688 68983, 134504 69323, 133972 69646, 130843 69648, 130503 69464, 130181 68969, 130179 65840, 130362 65463) (130362 70473, 130857 70151, 133986 70149, 134363 70332, 134686 70864, 134688 73993, 134504 74333, 133972 74656, 130843 74658, 130503 74474, 130181 73979, 130179 70850, 130362 70473) (130362 75483, 130857 75161, 133986 75159, 134363 75342, 134686 75874, 134688 79003, 134504 79343, 133972 79666, 130843 79668, 130503 79484, 130181 78989, 130179 75860, 130362 75483) (130362 80493, 130857 80171, 133986 80169, 134363 80352, 134686 80884, 134688 84013, 134504 84353, 133972 84676, 130843 84678, 130503 84494, 130181 83999, 130179 80870, 130362 80493) (130362 85503, 130857 85181, 133986 85179, 134363 85362, 134686 85894, 134688 89023, 134504 89363, 133972 89686, 130843 89688, 130503 89504, 130181 89009, 130179 85880, 130362 85503) (130362 90513, 130857 90191, 133986 90189, 134363 90372, 134686 90904, 134688 94033, 134504 94373, 133971 94696, 130843 94698, 130503 94514, 130181 94019, 130179 90890, 130362 90513) (130365 95520, 130857 95201, 133985 95199, 134279 95326, 134470 95496, 134686 95913, 134688 99045, 134504 99385, 133972 99708, 130843 99710, 130503 99526, 130181 99031, 130179 95900, 130365 95520) (130362 100535, 130857 100213, 133986 100211, 134363 100394, 134686 100926, 134688 104055, 134504 104395, 133972 104718, 130843 104720, 130503 104536, 130181 104041, 130179 100912, 130362 100535) (130362 105545, 130857 105223, 133986 105221, 134363 105404, 134686 105936, 134688 109065, 134504 109405, 133972 109728, 130843 109730, 130503 109546, 130181 109051, 130179 105922, 130362 105545) (130362 110555, 130857 110233, 133986 110231, 134363 110414, 134686 110946, 134688 114075, 134504 114415, 133972 114738, 130843 114740, 130503 114556, 130181 114061, 130179 110932, 130362 110555) (130362 115565, 130857 115243, 133986 115241, 134363 115424, 134686 115956, 134688 119085, 134504 119425, 133972 119748, 130843 119750, 130503 119566, 130181 119071, 130179 115942, 130362 115565) (130362 120575, 130857 120253, 133986 120251, 134363 120434, 134686 120966, 134688 124095, 134504 124435, 133972 124758, 130843 124760, 130503 124576, 130181 124081, 130179 120952, 130362 120575) (130362 125585, 130857 125263, 133986 125261, 134363 125444, 134686 125976, 134688 129105, 134504 129445, 133971 129768, 130843 129770, 130503 129586, 130181 129091, 130179 125962, 130362 125585) (130365 130592, 130857 130273, 133985 130271, 134279 130398, 134470 130568, 134686 130985, 134688 134115, 134504 134455, 133972 134778, 130843 134780, 130503 134596, 130181 134101, 130179 130972, 130365 130592) (130362 135605, 130857 135283, 133986 135281, 134363 135464, 134686 135996, 134688 139125, 134504 139465, 133972 139788, 130843 139790, 130503 139606, 130181 139111, 130179 135982, 130362 135605) (130362 140615, 130857 140293, 133986 140291, 134363 140474, 134686 141006, 134688 144136, 134504 144476, 133971 144799, 130843 144801, 130503 144617, 130181 144122, 130179 140992, 130362 140615) (130365 145623, 130857 145304, 133985 145302, 134279 145429, 134470 145599, 134686 146016, 134688 149146, 134504 149486, 133972 149809, 130843 149811, 130503 149627, 130181 149132, 130179 146003, 130365 145623) (130362 150636, 130857 150314, 133986 150312, 134363 150495, 134686 151027, 134688 154156, 134504 154496, 133972 154819, 130843 154821, 130503 154637, 130181 154142, 130179 151013, 130362 150636) (130362 155646, 130857 155324, 133986 155322, 134363 155505, 134686 156037, 134688 159166, 134504 159506, 133972 159829, 130843 159831, 130503 159647, 130181 159152, 130179 156023, 130362 155646) (130362 160656, 130857 160334, 133986 160332, 134363 160515, 134686 161047, 134688 164176, 134504 164516, 133972 164839, 130843 164841, 130503 164657, 130181 164162, 130179 161033, 130362 160656) (130362 165666, 130857 165344, 133986 165342, 134363 165525, 134686 166057, 134688 169186, 134504 169526, 133972 169849, 130843 169851, 130503 169667, 130181 169172, 130179 166043, 130362 165666) (130362 170676, 130857 170354, 133986 170352, 134363 170535, 134686 171067, 134688 174196, 134504 174536, 133972 174859, 130843 174861, 130503 174677, 130181 174182, 130179 171053, 130362 170676) (130362 175686, 130857 175364, 133986 175362, 134363 175545, 134686 176077, 134688 179206, 134378 179662, 134015 179814, 132626 179819, 130989 179829, 130433 179456, 130230 178925, 130176 177880, 130179 176063, 130362 175686) (135331 58140, 135520 57834, 138682 56338, 139108 56368, 139389 56471, 139512 56585, 139697 56965, 139698 58963, 139514 59303, 138982 59626, 135853 59628, 135454 59389, 135334 59203, 135242 58517, 135331 58140) (135372 60453, 135867 60131, 138996 60129, 139373 60312, 139696 60844, 139698 63973, 139514 64313, 138982 64636, 135853 64638, 135513 64454, 135191 63959, 135189 60830, 135372 60453) (135372 65463, 135867 65141, 138996 65139, 139373 65322, 139696 65854, 139698 68983, 139514 69323, 138982 69646, 135853 69648, 135513 69464, 135191 68969, 135189 65840, 135372 65463) (135372 70473, 135867 70151, 138996 70149, 139373 70332, 139696 70864, 139698 73993, 139514 74333, 138982 74656, 135853 74658, 135513 74474, 135191 73979, 135189 70850, 135372 70473) (135372 75483, 135867 75161, 138996 75159, 139373 75342, 139696 75874, 139698 79003, 139514 79343, 138982 79666, 135853 79668, 135513 79484, 135191 78989, 135189 75860, 135372 75483) (135372 80493, 135867 80171, 138996 80169, 139373 80352, 139696 80884, 139698 84013, 139514 84353, 138982 84676, 135853 84678, 135513 84494, 135191 83999, 135189 80870, 135372 80493) (135372 85503, 135867 85181, 138996 85179, 139373 85362, 139696 85894, 139698 89023, 139514 89363, 138982 89686, 135853 89688, 135513 89504, 135191 89009, 135189 85880, 135372 85503) (135372 90513, 135867 90191, 138996 90189, 139373 90372, 139696 90904, 139698 94033, 139514 94373, 138981 94696, 135853 94698, 135513 94514, 135191 94019, 135189 90890, 135372 90513) (135375 95520, 135867 95201, 138995 95199, 139289 95326, 139480 95496, 139696 95913, 139698 99045, 139514 99385, 138982 99708, 135853 99710, 135513 99526, 135191 99031, 135189 95900, 135375 95520) (135372 100535, 135867 100213, 138996 100211, 139373 100394, 139696 100926, 139698 104055, 139514 104395, 138982 104718, 135853 104720, 135513 104536, 135191 104041, 135189 100912, 135372 100535) (135372 105545, 135867 105223, 138996 105221, 139373 105404, 139696 105936, 139698 109065, 139514 109405, 138982 109728, 135853 109730, 135513 109546, 135191 109051, 135189 105922, 135372 105545) (135372 110555, 135867 110233, 138996 110231, 139373 110414, 139696 110946, 139698 114075, 139514 114415, 138982 114738, 135853 114740, 135513 114556, 135191 114061, 135189 110932, 135372 110555) (135372 115565, 135867 115243, 138996 115241, 139373 115424, 139696 115956, 139698 119085, 139514 119425, 138982 119748, 135853 119750, 135513 119566, 135191 119071, 135189 115942, 135372 115565) (135372 120575, 135867 120253, 138996 120251, 139373 120434, 139696 120966, 139698 124095, 139514 124435, 138982 124758, 135853 124760, 135513 124576, 135191 124081, 135189 120952, 135372 120575) (135372 125585, 135867 125263, 138996 125261, 139373 125444, 139696 125976, 139698 129105, 139514 129445, 138981 129768, 135853 129770, 135513 129586, 135191 129091, 135189 125962, 135372 125585) (135375 130592, 135867 130273, 138995 130271, 139289 130398, 139480 130568, 139696 130985, 139698 134115, 139514 134455, 138982 134778, 135853 134780, 135513 134596, 135191 134101, 135189 130972, 135375 130592) (135372 135605, 135867 135283, 138996 135281, 139373 135464, 139696 135996, 139698 139125, 139514 139465, 138982 139788, 135853 139790, 135513 139606, 135191 139111, 135189 135982, 135372 135605) (135372 140615, 135867 140293, 138996 140291, 139373 140474, 139696 141006, 139698 144136, 139514 144476, 138981 144799, 135853 144801, 135513 144617, 135191 144122, 135189 140992, 135372 140615) (135375 145623, 135867 145304, 138995 145302, 139289 145429, 139480 145599, 139696 146016, 139698 149146, 139514 149486, 138982 149809, 135853 149811, 135513 149627, 135191 149132, 135189 146003, 135375 145623) (135372 150636, 135867 150314, 138996 150312, 139373 150495, 139696 151027, 139698 154156, 139514 154496, 138982 154819, 135853 154821, 135513 154637, 135191 154142, 135189 151013, 135372 150636) (135372 155646, 135867 155324, 138996 155322, 139373 155505, 139696 156037, 139698 159166, 139514 159506, 138982 159829, 135853 159831, 135513 159647, 135191 159152, 135189 156023, 135372 155646) (135372 160656, 135867 160334, 138996 160332, 139373 160515, 139696 161047, 139698 164176, 139514 164516, 138982 164839, 135853 164841, 135513 164657, 135191 164162, 135189 161033, 135372 160656) (135372 165666, 135867 165344, 138996 165342, 139373 165525, 139696 166057, 139698 169186, 139514 169526, 138982 169849, 135853 169851, 135513 169667, 135191 169172, 135189 166043, 135372 165666) (135372 170676, 135867 170354, 138996 170352, 139373 170535, 139696 171067, 139698 174196, 139514 174536, 138982 174859, 135853 174861, 135513 174677, 135191 174182, 135189 171053, 135372 170676) (135372 175686, 135867 175364, 138996 175362, 139373 175545, 139696 176077, 139698 179206, 139514 179546, 138982 179869, 135871 179870, 135451 179629, 135191 179192, 135189 176063, 135372 175686) (135240 181510, 135278 180896, 135438 180601, 135865 180372, 138996 180372, 139373 180555, 139696 181087, 139692 183073, 139348 183547, 138829 183735, 135619 182218, 135331 181859, 135240 181510) (140273 56156, 140591 55660, 142108 55111, 144006 55170, 144376 55295, 144708 55834, 144710 58963, 144526 59303, 143994 59626, 140863 59628, 140523 59444, 140201 58949, 140199 56965, 140273 56156) (140382 60453, 140877 60131, 144008 60129, 144385 60312, 144708 60844, 144710 63973, 144526 64313, 143994 64636, 140863 64638, 140523 64454, 140201 63959, 140199 60830, 140382 60453) (140382 65463, 140877 65141, 144008 65139, 144385 65322, 144708 65854, 144710 68983, 144526 69323, 143994 69646, 140863 69648, 140523 69464, 140201 68969, 140199 65840, 140382 65463) (140382 70473, 140877 70151, 144008 70149, 144385 70332, 144708 70864, 144710 73993, 144526 74333, 143994 74656, 140863 74658, 140523 74474, 140201 73979, 140199 70850, 140382 70473) (140382 75483, 140877 75161, 144008 75159, 144385 75342, 144708 75874, 144710 79003, 144526 79343, 143994 79666, 140863 79668, 140523 79484, 140201 78989, 140199 75860, 140382 75483) (140382 80493, 140877 80171, 144008 80169, 144385 80352, 144708 80884, 144710 84013, 144526 84353, 143994 84676, 140863 84678, 140523 84494, 140201 83999, 140199 80870, 140382 80493) (140382 85503, 140877 85181, 144008 85179, 144385 85362, 144708 85894, 144710 89023, 144526 89363, 143994 89686, 140863 89688, 140523 89504, 140201 89009, 140199 85880, 140382 85503) (140382 90513, 140877 90191, 144008 90189, 144385 90372, 144708 90904, 144710 94033, 144526 94373, 143993 94696, 140863 94698, 140523 94514, 140201 94019, 140199 90890, 140382 90513) (140385 95520, 140877 95201, 144007 95199, 144301 95326, 144492 95496, 144708 95913, 144710 99045, 144526 99385, 143994 99708, 140863 99710, 140523 99526, 140201 99031, 140199 95900, 140385 95520) (140382 100535, 140877 100213, 144008 100211, 144385 100394, 144708 100926, 144710 104055, 144526 104395, 143994 104718, 140863 104720, 140523 104536, 140201 104041, 140199 100912, 140382 100535) (140382 105545, 140877 105223, 144008 105221, 144385 105404, 144708 105936, 144710 109065, 144526 109405, 143994 109728, 140863 109730, 140523 109546, 140201 109051, 140199 105922, 140382 105545) (140382 110555, 140877 110233, 144008 110231, 144385 110414, 144708 110946, 144710 114075, 144526 114415, 143994 114738, 140863 114740, 140523 114556, 140201 114061, 140199 110932, 140382 110555) (140382 115565, 140877 115243, 144008 115241, 144385 115424, 144708 115956, 144710 119085, 144526 119425, 143994 119748, 140863 119750, 140523 119566, 140201 119071, 140199 115942, 140382 115565) (140382 120575, 140877 120253, 144008 120251, 144385 120434, 144708 120966, 144710 124095, 144526 124435, 143994 124758, 140863 124760, 140523 124576, 140201 124081, 140199 120952, 140382 120575) (140382 125585, 140877 125263, 144008 125261, 144385 125444, 144708 125976, 144710 129105, 144526 129445, 143993 129768, 140863 129770, 140523 129586, 140201 129091, 140199 125962, 140382 125585) (140385 130592, 140877 130273, 144007 130271, 144301 130398, 144492 130568, 144708 130985, 144710 134115, 144526 134455, 143994 134778, 140863 134780, 140523 134596, 140201 134101, 140199 130972, 140385 130592) (140382 135605, 140877 135283, 144008 135281, 144385 135464, 144708 135996, 144710 139125, 144526 139465, 143994 139788, 140863 139790, 140523 139606, 140201 139111, 140199 135982, 140382 135605) (140382 140615, 140877 140293, 144008 140291, 144385 140474, 144708 141006, 144710 144136, 144526 144476, 143993 144799, 140863 144801, 140523 144617, 140201 144122, 140199 140992, 140382 140615) (140385 145623, 140877 145304, 144007 145302, 144301 145429, 144492 145599, 144708 146016, 144710 149146, 144526 149486, 143994 149809, 140863 149811, 140523 149627, 140201 149132, 140199 146003, 140385 145623) (140382 150636, 140877 150314, 144008 150312, 144385 150495, 144708 151027, 144710 154156, 144526 154496, 143994 154819, 140863 154821, 140523 154637, 140201 154142, 140199 151013, 140382 150636) (140382 155646, 140877 155324, 144008 155322, 144385 155505, 144708 156037, 144710 159166, 144526 159506, 143994 159829, 140863 159831, 140523 159647, 140201 159152, 140199 156023, 140382 155646) (140382 160656, 140877 160334, 144008 160332, 144385 160515, 144708 161047, 144710 164176, 144526 164516, 143994 164839, 140863 164841, 140523 164657, 140201 164162, 140199 161033, 140382 160656) (140382 165666, 140877 165344, 144008 165342, 144385 165525, 144708 166057, 144710 169186, 144526 169526, 143994 169849, 140863 169851, 140523 169667, 140201 169172, 140199 166043, 140382 165666) (140382 170676, 140877 170354, 144008 170352, 144385 170535, 144708 171067, 144710 174196, 144526 174536, 143994 174859, 140863 174861, 140523 174677, 140201 174182, 140199 171053, 140382 170676) (140382 175686, 140877 175364, 144008 175362, 144385 175545, 144708 176077, 144710 179206, 144526 179546, 143994 179869, 140863 179871, 140523 179687, 140201 179192, 140199 176063, 140382 175686) (140382 180696, 140877 180374, 144008 180372, 144385 180555, 144708 181087, 144710 184216, 144485 184603, 144221 184768, 143954 184829, 142044 184858, 140696 184382, 140421 184112, 140272 183840, 140196 183116, 140199 181073, 140382 180696) (145338 55527, 145520 55326, 145853 55170, 149097 55170, 149385 55294, 149718 55834, 149720 58963, 149536 59303, 149004 59626, 145875 59628, 145535 59444, 145213 58949, 145211 55820, 145338 55527) (145394 60453, 145889 60131, 149018 60129, 149395 60312, 149718 60844, 149720 63973, 149536 64313, 149004 64636, 145875 64638, 145535 64454, 145213 63959, 145211 60830, 145394 60453) (145394 65463, 145889 65141, 149018 65139, 149395 65322, 149718 65854, 149720 68983, 149536 69323, 149004 69646, 145875 69648, 145535 69464, 145213 68969, 145211 65840, 145394 65463) (145394 70473, 145889 70151, 149018 70149, 149395 70332, 149718 70864, 149720 73993, 149536 74333, 149004 74656, 145875 74658, 145535 74474, 145213 73979, 145211 70850, 145394 70473) (145394 75483, 145889 75161, 149018 75159, 149395 75342, 149718 75874, 149720 79003, 149536 79343, 149004 79666, 145875 79668, 145535 79484, 145213 78989, 145211 75860, 145394 75483) (145394 80493, 145889 80171, 149018 80169, 149395 80352, 149718 80884, 149720 84013, 149536 84353, 149004 84676, 145875 84678, 145535 84494, 145213 83999, 145211 80870, 145394 80493) (145394 85503, 145889 85181, 149018 85179, 149395 85362, 149718 85894, 149720 89023, 149536 89363, 149004 89686, 145875 89688, 145535 89504, 145213 89009, 145211 85880, 145394 85503) (145394 90513, 145889 90191, 149018 90189, 149395 90372, 149718 90904, 149720 94033, 149536 94373, 149003 94696, 145875 94698, 145535 94514, 145213 94019, 145211 90890, 145394 90513) (145397 95520, 145889 95201, 149017 95199, 149311 95326, 149502 95496, 149718 95913, 149720 99045, 149536 99385, 149004 99708, 145875 99710, 145535 99526, 145213 99031, 145211 95900, 145397 95520) (145394 100535, 145889 100213, 149018 100211, 149395 100394, 149718 100926, 149720 104055, 149536 104395, 149004 104718, 145875 104720, 145535 104536, 145213 104041, 145211 100912, 145394 100535) (145394 105545, 145889 105223, 149018 105221, 149395 105404, 149718 105936, 149720 109065, 149536 109405, 149004 109728, 145875 109730, 145535 109546, 145213 109051, 145211 105922, 145394 105545) (145394 110555, 145889 110233, 149018 110231, 149395 110414, 149718 110946, 149720 114075, 149536 114415, 149004 114738, 145875 114740, 145535 114556, 145213 114061, 145211 110932, 145394 110555) (145394 115565, 145889 115243, 149018 115241, 149395 115424, 149718 115956, 149720 119085, 149536 119425, 149004 119748, 145875 119750, 145535 119566, 145213 119071, 145211 115942, 145394 115565) (145394 120575, 145889 120253, 149018 120251, 149395 120434, 149718 120966, 149720 124095, 149536 124435, 149004 124758, 145875 124760, 145535 124576, 145213 124081, 145211 120952, 145394 120575) (145394 125585, 145889 125263, 149018 125261, 149395 125444, 149718 125976, 149720 129105, 149536 129445, 149003 129768, 145875 129770, 145535 129586, 145213 129091, 145211 125962, 145394 125585) (145397 130592, 145889 130273, 149017 130271, 149311 130398, 149502 130568, 149718 130985, 149720 134115, 149536 134455, 149004 134778, 145875 134780, 145535 134596, 145213 134101, 145211 130972, 145397 130592) (145394 135605, 145889 135283, 149018 135281, 149395 135464, 149718 135996, 149720 139125, 149536 139465, 149004 139788, 145875 139790, 145535 139606, 145213 139111, 145211 135982, 145394 135605) (145394 140615, 145889 140293, 149018 140291, 149395 140474, 149718 141006, 149720 144136, 149536 144476, 149003 144799, 145875 144801, 145535 144617, 145213 144122, 145211 140992, 145394 140615) (145397 145623, 145889 145304, 149017 145302, 149311 145429, 149502 145599, 149718 146016, 149720 149146, 149536 149486, 149004 149809, 145875 149811, 145535 149627, 145213 149132, 145211 146003, 145397 145623) (145394 150636, 145889 150314, 149018 150312, 149395 150495, 149718 151027, 149720 154156, 149536 154496, 149004 154819, 145875 154821, 145535 154637, 145213 154142, 145211 151013, 145394 150636) (145394 155646, 145889 155324, 149018 155322, 149395 155505, 149718 156037, 149720 159166, 149536 159506, 149004 159829, 145875 159831, 145535 159647, 145213 159152, 145211 156023, 145394 155646) (145394 160656, 145889 160334, 149018 160332, 149395 160515, 149718 161047, 149720 164176, 149536 164516, 149004 164839, 145875 164841, 145535 164657, 145213 164162, 145211 161033, 145394 160656) (145394 165666, 145889 165344, 149018 165342, 149395 165525, 149718 166057, 149720 169186, 149536 169526, 149004 169849, 145875 169851, 145535 169667, 145213 169172, 145211 166043, 145394 165666) (145394 170676, 145889 170354, 149018 170352, 149395 170535, 149718 171067, 149720 174196, 149536 174536, 149004 174859, 145875 174861, 145535 174677, 145213 174182, 145211 171053, 145394 170676) (145394 175686, 145889 175364, 149018 175362, 149395 175545, 149718 176077, 149720 179206, 149536 179546, 149004 179869, 145875 179871, 145535 179687, 145213 179192, 145211 176063, 145394 175686) (145394 180696, 145889 180374, 149018 180372, 149395 180555, 149718 181087, 149720 184216, 149537 184554, 149087 184826, 145803 184828, 145464 184629, 145213 184202, 145211 181073, 145394 180696) (150399 52983, 150683 52659, 151553 52436, 153931 52083, 154468 52318, 154729 52833, 154730 53953, 154546 54293, 154014 54616, 150885 54618, 150545 54434, 150285 53991, 150272 53354, 150399 52983) (150404 55443, 150899 55121, 154028 55119, 154405 55302, 154728 55834, 154730 58963, 154546 59303, 154014 59626, 150885 59628, 150545 59444, 150223 58949, 150221 55820, 150404 55443) (150404 60453, 150899 60131, 154028 60129, 154405 60312, 154728 60844, 154730 63973, 154546 64313, 154014 64636, 150885 64638, 150545 64454, 150223 63959, 150221 60830, 150404 60453) (150404 65463, 150899 65141, 154028 65139, 154405 65322, 154728 65854, 154730 68983, 154546 69323, 154014 69646, 150885 69648, 150545 69464, 150223 68969, 150221 65840, 150404 65463) (150404 70473, 150899 70151, 154028 70149, 154405 70332, 154728 70864, 154730 73993, 154546 74333, 154014 74656, 150885 74658, 150545 74474, 150223 73979, 150221 70850, 150404 70473) (150404 75483, 150899 75161, 154028 75159, 154405 75342, 154728 75874, 154730 79003, 154546 79343, 154014 79666, 150885 79668, 150545 79484, 150223 78989, 150221 75860, 150404 75483) (150404 80493, 150899 80171, 154028 80169, 154405 80352, 154728 80884, 154730 84013, 154546 84353, 154014 84676, 150885 84678, 150545 84494, 150223 83999, 150221 80870, 150404 80493) (150404 85503, 150899 85181, 154028 85179, 154405 85362, 154728 85894, 154730 89023, 154546 89363, 154014 89686, 150885 89688, 150545 89504, 150223 89009, 150221 85880, 150404 85503) (150404 90513, 150899 90191, 154028 90189, 154405 90372, 154728 90904, 154730 94033, 154546 94373, 154013 94696, 150885 94698, 150545 94514, 150223 94019, 150221 90890, 150404 90513) (150407 95520, 150899 95201, 154027 95199, 154321 95326, 154512 95496, 154728 95913, 154730 99045, 154546 99385, 154014 99708, 150885 99710, 150545 99526, 150223 99031, 150221 95900, 150407 95520) (150404 100535, 150899 100213, 154028 100211, 154405 100394, 154728 100926, 154730 104055, 154546 104395, 154014 104718, 150885 104720, 150545 104536, 150223 104041, 150221 100912, 150404 100535) (150404 105545, 150899 105223, 154028 105221, 154405 105404, 154728 105936, 154730 109065, 154546 109405, 154014 109728, 150885 109730, 150545 109546, 150223 109051, 150221 105922, 150404 105545) (150404 110555, 150899 110233, 154028 110231, 154405 110414, 154728 110946, 154730 114075, 154546 114415, 154014 114738, 150885 114740, 150545 114556, 150223 114061, 150221 110932, 150404 110555) (150404 115565, 150899 115243, 154028 115241, 154405 115424, 154728 115956, 154730 119085, 154546 119425, 154014 119748, 150885 119750, 150545 119566, 150223 119071, 150221 115942, 150404 115565) (150404 120575, 150899 120253, 154028 120251, 154405 120434, 154728 120966, 154730 124095, 154546 124435, 154014 124758, 150885 124760, 150545 124576, 150223 124081, 150221 120952, 150404 120575) (150404 125585, 150899 125263, 154028 125261, 154405 125444, 154728 125976, 154730 129105, 154546 129445, 154013 129768, 150885 129770, 150545 129586, 150223 129091, 150221 125962, 150404 125585) (150407 130592, 150899 130273, 154027 130271, 154321 130398, 154512 130568, 154728 130985, 154730 134115, 154546 134455, 154014 134778, 150885 134780, 150545 134596, 150223 134101, 150221 130972, 150407 130592) (150404 135605, 150899 135283, 154028 135281, 154405 135464, 154728 135996, 154730 139125, 154546 139465, 154014 139788, 150885 139790, 150545 139606, 150223 139111, 150221 135982, 150404 135605) (150404 140615, 150899 140293, 154028 140291, 154405 140474, 154728 141006, 154730 144136, 154546 144476, 154013 144799, 150885 144801, 150545 144617, 150223 144122, 150221 140992, 150404 140615) (150407 145623, 150899 145304, 154027 145302, 154321 145429, 154512 145599, 154728 146016, 154730 149146, 154546 149486, 154014 149809, 150885 149811, 150545 149627, 150223 149132, 150221 146003, 150407 145623) (150404 150636, 150899 150314, 154028 150312, 154405 150495, 154728 151027, 154730 154156, 154546 154496, 154014 154819, 150885 154821, 150545 154637, 150223 154142, 150221 151013, 150404 150636) (150404 155646, 150899 155324, 154028 155322, 154405 155505, 154728 156037, 154730 159166, 154546 159506, 154014 159829, 150885 159831, 150545 159647, 150223 159152, 150221 156023, 150404 155646) (150404 160656, 150899 160334, 154028 160332, 154405 160515, 154728 161047, 154730 164176, 154546 164516, 154014 164839, 150885 164841, 150545 164657, 150223 164162, 150221 161033, 150404 160656) (150404 165666, 150899 165344, 154028 165342, 154405 165525, 154728 166057, 154730 169186, 154546 169526, 154014 169849, 150885 169851, 150545 169667, 150223 169172, 150221 166043, 150404 165666) (150404 170676, 150899 170354, 154028 170352, 154405 170535, 154728 171067, 154730 174196, 154546 174536, 154014 174859, 150885 174861, 150545 174677, 150223 174182, 150221 171053, 150404 170676) (150404 175686, 150899 175364, 154028 175362, 154405 175545, 154728 176077, 154730 179206, 154546 179546, 154014 179869, 150885 179871, 150545 179687, 150223 179192, 150221 176063, 150404 175686) (150404 180696, 150899 180374, 154028 180372, 154405 180555, 154728 181087, 154730 184216, 154546 184556, 154014 184879, 150903 184880, 150483 184639, 150223 184202, 150221 181073, 150404 180696) (150272 186620, 150308 185916, 150470 185611, 150897 185382, 154028 185382, 154405 185565, 154728 186097, 154724 187344, 154499 187658, 153982 187918, 151553 187563, 150792 187373, 150399 187016, 150272 186620) (155354 52207, 155759 51817, 158248 51442, 159006 51405, 159515 51689, 159734 52050, 159740 53953, 159556 54293, 159024 54616, 155895 54618, 155555 54434, 155233 53939, 155231 52833, 155354 52207) (155414 55443, 155909 55121, 159038 55119, 159415 55302, 159738 55834, 159740 58963, 159556 59303, 159024 59626, 155895 59628, 155555 59444, 155233 58949, 155231 55820, 155414 55443) (155414 60453, 155909 60131, 159038 60129, 159415 60312, 159738 60844, 159740 63973, 159556 64313, 159024 64636, 155895 64638, 155555 64454, 155233 63959, 155231 60830, 155414 60453) (155414 65463, 155909 65141, 159038 65139, 159415 65322, 159738 65854, 159740 68983, 159556 69323, 159024 69646, 155895 69648, 155555 69464, 155233 68969, 155231 65840, 155414 65463) (155414 70473, 155909 70151, 159038 70149, 159415 70332, 159738 70864, 159740 73993, 159556 74333, 159024 74656, 155895 74658, 155555 74474, 155233 73979, 155231 70850, 155414 70473) (155414 75483, 155909 75161, 159038 75159, 159415 75342, 159738 75874, 159740 79003, 159556 79343, 159024 79666, 155895 79668, 155555 79484, 155233 78989, 155231 75860, 155414 75483) (155414 80493, 155909 80171, 159038 80169, 159415 80352, 159738 80884, 159740 84013, 159556 84353, 159024 84676, 155895 84678, 155555 84494, 155233 83999, 155231 80870, 155414 80493) (155414 85503, 155909 85181, 159038 85179, 159415 85362, 159738 85894, 159740 89023, 159556 89363, 159024 89686, 155895 89688, 155555 89504, 155233 89009, 155231 85880, 155414 85503) (155414 90513, 155909 90191, 159038 90189, 159415 90372, 159738 90904, 159740 94033, 159556 94373, 159023 94696, 155895 94698, 155555 94514, 155233 94019, 155231 90890, 155414 90513) (155417 95520, 155909 95201, 159037 95199, 159331 95326, 159522 95496, 159738 95913, 159740 99045, 159556 99385, 159024 99708, 155895 99710, 155555 99526, 155233 99031, 155231 95900, 155417 95520) (155414 100535, 155909 100213, 159038 100211, 159415 100394, 159738 100926, 159740 104055, 159556 104395, 159024 104718, 155895 104720, 155555 104536, 155233 104041, 155231 100912, 155414 100535) (155414 105545, 155909 105223, 159038 105221, 159415 105404, 159738 105936, 159740 109065, 159556 109405, 159024 109728, 155895 109730, 155555 109546, 155233 109051, 155231 105922, 155414 105545) (155414 110555, 155909 110233, 159038 110231, 159415 110414, 159738 110946, 159740 114075, 159556 114415, 159024 114738, 155895 114740, 155555 114556, 155233 114061, 155231 110932, 155414 110555) (155414 115565, 155909 115243, 159038 115241, 159415 115424, 159738 115956, 159740 119085, 159556 119425, 159024 119748, 155895 119750, 155555 119566, 155233 119071, 155231 115942, 155414 115565) (155414 120575, 155909 120253, 159038 120251, 159415 120434, 159738 120966, 159740 124095, 159556 124435, 159024 124758, 155895 124760, 155555 124576, 155233 124081, 155231 120952, 155414 120575) (155414 125585, 155909 125263, 159038 125261, 159415 125444, 159738 125976, 159740 129105, 159556 129445, 159023 129768, 155895 129770, 155555 129586, 155233 129091, 155231 125962, 155414 125585) (155417 130592, 155909 130273, 159037 130271, 159331 130398, 159522 130568, 159738 130985, 159740 134115, 159556 134455, 159024 134778, 155895 134780, 155555 134596, 155233 134101, 155231 130972, 155417 130592) (155414 135605, 155909 135283, 159038 135281, 159415 135464, 159738 135996, 159740 139125, 159556 139465, 159024 139788, 155895 139790, 155555 139606, 155233 139111, 155231 135982, 155414 135605) (155414 140615, 155909 140293, 159038 140291, 159415 140474, 159738 141006, 159740 144136, 159556 144476, 159023 144799, 155895 144801, 155555 144617, 155233 144122, 155231 140992, 155414 140615) (155417 145623, 155909 145304, 159037 145302, 159331 145429, 159522 145599, 159738 146016, 159740 149146, 159556 149486, 159024 149809, 155895 149811, 155555 149627, 155233 149132, 155231 146003, 155417 145623) (155414 150636, 155909 150314, 159038 150312, 159415 150495, 159738 151027, 159740 154156, 159556 154496, 159024 154819, 155895 154821, 155555 154637, 155233 154142, 155231 151013, 155414 150636) (155414 155646, 155909 155324, 159038 155322, 159415 155505, 159738 156037, 159740 159166, 159556 159506, 159024 159829, 155895 159831, 155555 159647, 155233 159152, 155231 156023, 155414 155646) (155414 160656, 155909 160334, 159038 160332, 159415 160515, 159738 161047, 159740 164176, 159556 164516, 159024 164839, 155895 164841, 155555 164657, 155233 164162, 155231 161033, 155414 160656) (155414 165666, 155909 165344, 159038 165342, 159415 165525, 159738 166057, 159740 169186, 159556 169526, 159024 169849, 155895 169851, 155555 169667, 155233 169172, 155231 166043, 155414 165666) (155414 170676, 155909 170354, 159038 170352, 159415 170535, 159738 171067, 159740 174196, 159556 174536, 159024 174859, 155895 174861, 155555 174677, 155233 174182, 155231 171053, 155414 170676) (155414 175686, 155909 175364, 159038 175362, 159415 175545, 159738 176077, 159740 179206, 159556 179546, 159024 179869, 155895 179871, 155555 179687, 155233 179192, 155231 176063, 155414 175686) (155414 180696, 155909 180374, 159038 180372, 159415 180555, 159738 181087, 159740 184216, 159556 184556, 159024 184879, 155895 184881, 155555 184697, 155233 184202, 155231 181073, 155414 180696) (155414 185706, 155909 185384, 159038 185382, 159415 185565, 159738 186097, 159738 187971, 159546 188288, 159064 188591, 158248 188557, 155833 188199, 155390 187821, 155228 187387, 155231 186083, 155414 185706) (160398 51668, 160853 51314, 164016 51159, 164535 51456, 164748 51869, 164750 53953, 164566 54293, 164034 54616, 160905 54618, 160565 54434, 160243 53939, 160238 52010, 160398 51668) (160424 55443, 160919 55121, 164048 55119, 164425 55302, 164748 55834, 164750 58963, 164566 59303, 164034 59626, 160905 59628, 160565 59444, 160243 58949, 160241 55820, 160424 55443) (160424 60453, 160919 60131, 164048 60129, 164425 60312, 164748 60844, 164750 63973, 164566 64313, 164034 64636, 160905 64638, 160565 64454, 160243 63959, 160241 60830, 160424 60453) (160424 65463, 160919 65141, 164048 65139, 164425 65322, 164748 65854, 164750 68983, 164566 69323, 164034 69646, 160905 69648, 160565 69464, 160243 68969, 160241 65840, 160424 65463) (160424 70473, 160919 70151, 164048 70149, 164425 70332, 164748 70864, 164750 73993, 164566 74333, 164034 74656, 160905 74658, 160565 74474, 160243 73979, 160241 70850, 160424 70473) (160424 75483, 160919 75161, 164048 75159, 164425 75342, 164748 75874, 164750 79003, 164566 79343, 164034 79666, 160905 79668, 160565 79484, 160243 78989, 160241 75860, 160424 75483) (160424 80493, 160919 80171, 164048 80169, 164425 80352, 164748 80884, 164750 84013, 164566 84353, 164034 84676, 160905 84678, 160565 84494, 160243 83999, 160241 80870, 160424 80493) (160424 85503, 160919 85181, 164048 85179, 164425 85362, 164748 85894, 164750 89023, 164566 89363, 164034 89686, 160905 89688, 160565 89504, 160243 89009, 160241 85880, 160424 85503) (160424 90513, 160919 90191, 164048 90189, 164425 90372, 164748 90904, 164750 94033, 164566 94373, 164033 94696, 160905 94698, 160565 94514, 160243 94019, 160241 90890, 160424 90513) (160427 95520, 160919 95201, 164047 95199, 164341 95326, 164532 95496, 164748 95913, 164750 99045, 164566 99385, 164034 99708, 160905 99710, 160565 99526, 160243 99031, 160241 95900, 160427 95520) (160424 100535, 160919 100213, 164048 100211, 164425 100394, 164748 100926, 164750 104055, 164566 104395, 164034 104718, 160905 104720, 160565 104536, 160243 104041, 160241 100912, 160424 100535) (160424 105545, 160919 105223, 164048 105221, 164425 105404, 164748 105936, 164750 109065, 164566 109405, 164034 109728, 160905 109730, 160565 109546, 160243 109051, 160241 105922, 160424 105545) (160424 110555, 160919 110233, 164048 110231, 164425 110414, 164748 110946, 164750 114075, 164566 114415, 164034 114738, 160905 114740, 160565 114556, 160243 114061, 160241 110932, 160424 110555) (160424 115565, 160919 115243, 164048 115241, 164425 115424, 164748 115956, 164750 119085, 164566 119425, 164034 119748, 160905 119750, 160565 119566, 160243 119071, 160241 115942, 160424 115565) (160424 120575, 160919 120253, 164048 120251, 164425 120434, 164748 120966, 164750 124095, 164566 124435, 164034 124758, 160905 124760, 160565 124576, 160243 124081, 160241 120952, 160424 120575) (160424 125585, 160919 125263, 164048 125261, 164425 125444, 164748 125976, 164750 129105, 164566 129445, 164033 129768, 160905 129770, 160565 129586, 160243 129091, 160241 125962, 160424 125585) (160427 130592, 160919 130273, 164047 130271, 164341 130398, 164532 130568, 164748 130985, 164750 134115, 164566 134455, 164034 134778, 160905 134780, 160565 134596, 160243 134101, 160241 130972, 160427 130592) (160424 135605, 160919 135283, 164048 135281, 164425 135464, 164748 135996, 164750 139125, 164566 139465, 164034 139788, 160905 139790, 160565 139606, 160243 139111, 160241 135982, 160424 135605) (160424 140615, 160919 140293, 164048 140291, 164425 140474, 164748 141006, 164750 144136, 164566 144476, 164033 144799, 160905 144801, 160565 144617, 160243 144122, 160241 140992, 160424 140615) (160427 145623, 160919 145304, 164047 145302, 164341 145429, 164532 145599, 164748 146016, 164750 149146, 164566 149486, 164034 149809, 160905 149811, 160565 149627, 160243 149132, 160241 146003, 160427 145623) (160424 150636, 160919 150314, 164048 150312, 164425 150495, 164748 151027, 164750 154156, 164566 154496, 164034 154819, 160905 154821, 160565 154637, 160243 154142, 160241 151013, 160424 150636) (160424 155646, 160919 155324, 164048 155322, 164425 155505, 164748 156037, 164750 159166, 164566 159506, 164034 159829, 160905 159831, 160565 159647, 160243 159152, 160241 156023, 160424 155646) (160424 160656, 160919 160334, 164048 160332, 164425 160515, 164748 161047, 164750 164176, 164566 164516, 164034 164839, 160905 164841, 160565 164657, 160243 164162, 160241 161033, 160424 160656) (160424 165666, 160919 165344, 164048 165342, 164425 165525, 164748 166057, 164750 169186, 164566 169526, 164034 169849, 160905 169851, 160565 169667, 160243 169172, 160241 166043, 160424 165666) (160424 170676, 160919 170354, 164048 170352, 164425 170535, 164748 171067, 164750 174196, 164566 174536, 164034 174859, 160905 174861, 160565 174677, 160243 174182, 160241 171053, 160424 170676) (160424 175686, 160919 175364, 164048 175362, 164425 175545, 164748 176077, 164750 179206, 164566 179546, 164034 179869, 160905 179871, 160565 179687, 160243 179192, 160241 176063, 160424 175686) (160424 180696, 160919 180374, 164048 180372, 164425 180555, 164748 181087, 164750 184216, 164566 184556, 164034 184879, 160905 184881, 160565 184697, 160243 184202, 160241 181073, 160424 180696) (160424 185706, 160919 185384, 164048 185382, 164425 185565, 164748 186097, 164750 188181, 164564 188523, 164063 188843, 160908 188689, 160429 188355, 160241 187983, 160241 186083, 160424 185706) (165435 51476, 165937 51156, 169092 51310, 169571 51644, 169759 52058, 169760 53953, 169576 54293, 169044 54616, 165915 54618, 165575 54434, 165253 53939, 165251 51854, 165435 51476) (165434 55443, 165929 55121, 169058 55119, 169435 55302, 169758 55834, 169760 58963, 169576 59303, 169044 59626, 165915 59628, 165575 59444, 165253 58949, 165251 55820, 165434 55443) (165434 60453, 165929 60131, 169058 60129, 169435 60312, 169758 60844, 169760 63973, 169576 64313, 169044 64636, 165915 64638, 165575 64454, 165253 63959, 165251 60830, 165434 60453) (165434 65463, 165929 65141, 169058 65139, 169435 65322, 169758 65854, 169760 68983, 169576 69323, 169044 69646, 165915 69648, 165575 69464, 165253 68969, 165251 65840, 165434 65463) (165434 70473, 165929 70151, 169058 70149, 169435 70332, 169758 70864, 169760 73993, 169576 74333, 169044 74656, 165915 74658, 165575 74474, 165253 73979, 165251 70850, 165434 70473) (165434 75483, 165929 75161, 169058 75159, 169435 75342, 169758 75874, 169760 79003, 169576 79343, 169044 79666, 165915 79668, 165575 79484, 165253 78989, 165251 75860, 165434 75483) (165434 80493, 165929 80171, 169058 80169, 169435 80352, 169758 80884, 169760 84013, 169576 84353, 169044 84676, 165915 84678, 165575 84494, 165253 83999, 165251 80870, 165434 80493) (165434 85503, 165929 85181, 169058 85179, 169435 85362, 169758 85894, 169760 89023, 169576 89363, 169044 89686, 165915 89688, 165575 89504, 165253 89009, 165251 85880, 165434 85503) (165434 90513, 165929 90191, 169058 90189, 169435 90372, 169758 90904, 169760 94033, 169576 94373, 169043 94696, 165915 94698, 165575 94514, 165253 94019, 165251 90890, 165434 90513) (165437 95520, 165929 95201, 169057 95199, 169351 95326, 169542 95496, 169758 95913, 169760 99045, 169576 99385, 169044 99708, 165915 99710, 165575 99526, 165253 99031, 165251 95900, 165437 95520) (165434 100535, 165929 100213, 169058 100211, 169435 100394, 169758 100926, 169760 104055, 169576 104395, 169044 104718, 165915 104720, 165575 104536, 165253 104041, 165251 100912, 165434 100535) (165434 105545, 165929 105223, 169058 105221, 169435 105404, 169758 105936, 169760 109065, 169576 109405, 169044 109728, 165915 109730, 165575 109546, 165253 109051, 165251 105922, 165434 105545) (165434 110555, 165929 110233, 169058 110231, 169435 110414, 169758 110946, 169760 114075, 169576 114415, 169044 114738, 165915 114740, 165575 114556, 165253 114061, 165251 110932, 165434 110555) (165434 115565, 165929 115243, 169058 115241, 169435 115424, 169758 115956, 169760 119085, 169576 119425, 169044 119748, 165915 119750, 165575 119566, 165253 119071, 165251 115942, 165434 115565) (165434 120575, 165929 120253, 169058 120251, 169435 120434, 169758 120966, 169760 124095, 169576 124435, 169044 124758, 165915 124760, 165575 124576, 165253 124081, 165251 120952, 165434 120575) (165434 125585, 165929 125263, 169058 125261, 169435 125444, 169758 125976, 169760 129105, 169576 129445, 169043 129768, 165915 129770, 165575 129586, 165253 129091, 165251 125962, 165434 125585) (165437 130592, 165929 130273, 169057 130271, 169351 130398, 169542 130568, 169758 130985, 169760 134115, 169576 134455, 169044 134778, 165915 134780, 165575 134596, 165253 134101, 165251 130972, 165437 130592) (165434 135605, 165929 135283, 169058 135281, 169435 135464, 169758 135996, 169760 139125, 169576 139465, 169044 139788, 165915 139790, 165575 139606, 165253 139111, 165251 135982, 165434 135605) (165434 140615, 165929 140293, 169058 140291, 169435 140474, 169758 141006, 169760 144136, 169576 144476, 169043 144799, 165915 144801, 165575 144617, 165253 144122, 165251 140992, 165434 140615) (165437 145623, 165929 145304, 169057 145302, 169351 145429, 169542 145599, 169758 146016, 169760 149146, 169576 149486, 169044 149809, 165915 149811, 165575 149627, 165253 149132, 165251 146003, 165437 145623) (165434 150636, 165929 150314, 169058 150312, 169435 150495, 169758 151027, 169760 154156, 169576 154496, 169044 154819, 165915 154821, 165575 154637, 165253 154142, 165251 151013, 165434 150636) (165434 155646, 165929 155324, 169058 155322, 169435 155505, 169758 156037, 169760 159166, 169576 159506, 169044 159829, 165915 159831, 165575 159647, 165253 159152, 165251 156023, 165434 155646) (165434 160656, 165929 160334, 169058 160332, 169435 160515, 169758 161047, 169760 164176, 169576 164516, 169044 164839, 165915 164841, 165575 164657, 165253 164162, 165251 161033, 165434 160656) (165434 165666, 165929 165344, 169058 165342, 169435 165525, 169758 166057, 169760 169186, 169576 169526, 169044 169849, 165915 169851, 165575 169667, 165253 169172, 165251 166043, 165434 165666) (165434 170676, 165929 170354, 169058 170352, 169435 170535, 169758 171067, 169760 174196, 169576 174536, 169044 174859, 165915 174861, 165575 174677, 165253 174182, 165251 171053, 165434 170676) (165434 175686, 165929 175364, 169058 175362, 169435 175545, 169758 176077, 169760 179206, 169576 179546, 169044 179869, 165915 179871, 165575 179687, 165253 179192, 165251 176063, 165434 175686) (165434 180696, 165929 180374, 169058 180372, 169435 180555, 169758 181087, 169760 184216, 169576 184556, 169044 184879, 165915 184881, 165575 184697, 165253 184202, 165251 181073, 165434 180696) (165434 185706, 165929 185384, 169058 185382, 169435 185565, 169758 186097, 169762 187993, 169602 188331, 169148 188685, 165984 188840, 165465 188543, 165253 188165, 165251 186083, 165434 185706) (170261 52069, 170454 51711, 170935 51408, 171751 51442, 174167 51800, 174610 52178, 174769 52518, 174770 53953, 174586 54293, 174054 54616, 170925 54618, 170585 54434, 170263 53939, 170261 52069) (170444 55443, 170939 55121, 174068 55119, 174445 55302, 174768 55834, 174770 58963, 174586 59303, 174054 59626, 170925 59628, 170585 59444, 170263 58949, 170261 55820, 170444 55443) (170444 60453, 170939 60131, 174068 60129, 174445 60312, 174768 60844, 174770 63973, 174586 64313, 174054 64636, 170925 64638, 170585 64454, 170263 63959, 170261 60830, 170444 60453) (170444 65463, 170939 65141, 174068 65139, 174445 65322, 174768 65854, 174770 68983, 174586 69323, 174054 69646, 170925 69648, 170585 69464, 170263 68969, 170261 65840, 170444 65463) (170444 70473, 170939 70151, 174068 70149, 174445 70332, 174768 70864, 174770 73993, 174586 74333, 174054 74656, 170925 74658, 170585 74474, 170263 73979, 170261 70850, 170444 70473) (170444 75483, 170939 75161, 174068 75159, 174445 75342, 174768 75874, 174770 79003, 174586 79343, 174054 79666, 170925 79668, 170585 79484, 170263 78989, 170261 75860, 170444 75483) (170444 80493, 170939 80171, 174068 80169, 174445 80352, 174768 80884, 174770 84013, 174586 84353, 174054 84676, 170925 84678, 170585 84494, 170263 83999, 170261 80870, 170444 80493) (170444 85503, 170939 85181, 174068 85179, 174445 85362, 174768 85894, 174770 89023, 174586 89363, 174054 89686, 170925 89688, 170585 89504, 170263 89009, 170261 85880, 170444 85503) (170444 90513, 170939 90191, 174068 90189, 174445 90372, 174768 90904, 174770 94033, 174586 94373, 174053 94696, 170925 94698, 170585 94514, 170263 94019, 170261 90890, 170444 90513) (170447 95520, 170939 95201, 174067 95199, 174361 95326, 174552 95496, 174768 95913, 174770 99045, 174586 99385, 174054 99708, 170925 99710, 170585 99526, 170263 99031, 170261 95900, 170447 95520) (170444 100535, 170939 100213, 174068 100211, 174445 100394, 174768 100926, 174770 104055, 174586 104395, 174054 104718, 170925 104720, 170585 104536, 170263 104041, 170261 100912, 170444 100535) (170444 105545, 170939 105223, 174068 105221, 174445 105404, 174768 105936, 174770 109065, 174586 109405, 174054 109728, 170925 109730, 170585 109546, 170263 109051, 170261 105922, 170444 105545) (170444 110555, 170939 110233, 174068 110231, 174445 110414, 174768 110946, 174770 114075, 174586 114415, 174054 114738, 170925 114740, 170585 114556, 170263 114061, 170261 110932, 170444 110555) (170444 115565, 170939 115243, 174068 115241, 174445 115424, 174768 115956, 174770 119085, 174586 119425, 174054 119748, 170925 119750, 170585 119566, 170263 119071, 170261 115942, 170444 115565) (170444 120575, 170939 120253, 174068 120251, 174445 120434, 174768 120966, 174770 124095, 174586 124435, 174054 124758, 170925 124760, 170585 124576, 170263 124081, 170261 120952, 170444 120575) (170444 125585, 170939 125263, 174068 125261, 174445 125444, 174768 125976, 174770 129105, 174586 129445, 174053 129768, 170925 129770, 170585 129586, 170263 129091, 170261 125962, 170444 125585) (170447 130592, 170939 130273, 174067 130271, 174361 130398, 174552 130568, 174768 130985, 174770 134115, 174586 134455, 174054 134778, 170925 134780, 170585 134596, 170263 134101, 170261 130972, 170447 130592) (170444 135605, 170939 135283, 174068 135281, 174445 135464, 174768 135996, 174770 139125, 174586 139465, 174054 139788, 170925 139790, 170585 139606, 170263 139111, 170261 135982, 170444 135605) (170444 140615, 170939 140293, 174068 140291, 174445 140474, 174768 141006, 174770 144136, 174586 144476, 174053 144799, 170925 144801, 170585 144617, 170263 144122, 170261 140992, 170444 140615) (170447 145623, 170939 145304, 174067 145302, 174361 145429, 174552 145599, 174768 146016, 174770 149146, 174586 149486, 174054 149809, 170925 149811, 170585 149627, 170263 149132, 170261 146003, 170447 145623) (170444 150636, 170939 150314, 174068 150312, 174445 150495, 174768 151027, 174770 154156, 174586 154496, 174054 154819, 170925 154821, 170585 154637, 170263 154142, 170261 151013, 170444 150636) (170444 155646, 170939 155324, 174068 155322, 174445 155505, 174768 156037, 174770 159166, 174586 159506, 174054 159829, 170925 159831, 170585 159647, 170263 159152, 170261 156023, 170444 155646) (170444 160656, 170939 160334, 174068 160332, 174445 160515, 174768 161047, 174770 164176, 174586 164516, 174054 164839, 170925 164841, 170585 164657, 170263 164162, 170261 161033, 170444 160656) (170444 165666, 170939 165344, 174068 165342, 174445 165525, 174768 166057, 174770 169186, 174586 169526, 174054 169849, 170925 169851, 170585 169667, 170263 169172, 170261 166043, 170444 165666) (170444 170676, 170939 170354, 174068 170352, 174445 170535, 174768 171067, 174770 174196, 174586 174536, 174054 174859, 170925 174861, 170585 174677, 170263 174182, 170261 171053, 170444 170676) (170444 175686, 170939 175364, 174068 175362, 174445 175545, 174768 176077, 174770 179206, 174586 179546, 174054 179869, 170925 179871, 170585 179687, 170263 179192, 170261 176063, 170444 175686) (170444 180696, 170939 180374, 174068 180372, 174445 180555, 174768 181087, 174770 184216, 174586 184556, 174054 184879, 170925 184881, 170585 184697, 170263 184202, 170261 181073, 170444 180696) (170444 185706, 170939 185384, 174068 185382, 174445 185565, 174768 186097, 174772 187323, 174646 187793, 174241 188182, 171751 188557, 170994 188594, 170485 188310, 170267 187952, 170261 186083, 170444 185706) (175271 52624, 175501 52341, 176018 52081, 178446 52436, 179208 52626, 179601 52983, 179728 53379, 179692 54083, 179531 54388, 179150 54617, 175935 54618, 175595 54434, 175273 53939, 175271 52624) (175454 55443, 175949 55121, 179143 55120, 179517 55360, 179778 55834, 179780 58963, 179596 59303, 179064 59626, 175935 59628, 175595 59444, 175273 58949, 175271 55820, 175454 55443) (175454 60453, 175949 60131, 179078 60129, 179455 60312, 179778 60844, 179780 63973, 179596 64313, 179064 64636, 175935 64638, 175595 64454, 175273 63959, 175271 60830, 175454 60453) (175454 65463, 175949 65141, 179078 65139, 179455 65322, 179778 65854, 179780 68983, 179596 69323, 179064 69646, 175935 69648, 175595 69464, 175273 68969, 175271 65840, 175454 65463) (175454 70473, 175949 70151, 179078 70149, 179455 70332, 179778 70864, 179780 73993, 179596 74333, 179064 74656, 175935 74658, 175595 74474, 175273 73979, 175271 70850, 175454 70473) (175454 75483, 175949 75161, 179078 75159, 179455 75342, 179778 75874, 179780 79003, 179596 79343, 179064 79666, 175935 79668, 175595 79484, 175273 78989, 175271 75860, 175454 75483) (175454 80493, 175949 80171, 179078 80169, 179455 80352, 179778 80884, 179780 84013, 179596 84353, 179064 84676, 175935 84678, 175595 84494, 175273 83999, 175271 80870, 175454 80493) (175454 85503, 175949 85181, 179078 85179, 179455 85362, 179778 85894, 179780 89023, 179596 89363, 179064 89686, 175935 89688, 175595 89504, 175273 89009, 175271 85880, 175454 85503) (175454 90513, 175949 90191, 179078 90189, 179455 90372, 179778 90904, 179780 94033, 179596 94373, 179063 94696, 175935 94698, 175595 94514, 175273 94019, 175271 90890, 175454 90513) (175457 95520, 175949 95201, 179077 95199, 179371 95326, 179562 95496, 179778 95913, 179780 99045, 179596 99385, 179064 99708, 175935 99710, 175595 99526, 175273 99031, 175271 95900, 175457 95520) (175454 100535, 175949 100213, 179078 100211, 179455 100394, 179778 100926, 179780 104055, 179596 104395, 179064 104718, 175935 104720, 175595 104536, 175273 104041, 175271 100912, 175454 100535) (175454 105545, 175949 105223, 179078 105221, 179455 105404, 179778 105936, 179780 109065, 179596 109405, 179064 109728, 175935 109730, 175595 109546, 175273 109051, 175271 105922, 175454 105545) (175454 110555, 175949 110233, 179078 110231, 179455 110414, 179778 110946, 179780 114075, 179596 114415, 179064 114738, 175935 114740, 175595 114556, 175273 114061, 175271 110932, 175454 110555) (175454 115565, 175949 115243, 179078 115241, 179455 115424, 179778 115956, 179780 119085, 179596 119425, 179064 119748, 175935 119750, 175595 119566, 175273 119071, 175271 115942, 175454 115565) (175454 120575, 175949 120253, 179078 120251, 179455 120434, 179778 120966, 179780 124095, 179596 124435, 179064 124758, 175935 124760, 175595 124576, 175273 124081, 175271 120952, 175454 120575) (175454 125585, 175949 125263, 179078 125261, 179455 125444, 179778 125976, 179780 129105, 179596 129445, 179063 129768, 175935 129770, 175595 129586, 175273 129091, 175271 125962, 175454 125585) (175457 130592, 175949 130273, 179077 130271, 179371 130398, 179562 130568, 179778 130985, 179780 134115, 179596 134455, 179064 134778, 175935 134780, 175595 134596, 175273 134101, 175271 130972, 175457 130592) (175454 135605, 175949 135283, 179078 135281, 179455 135464, 179778 135996, 179780 139125, 179596 139465, 179064 139788, 175935 139790, 175595 139606, 175273 139111, 175271 135982, 175454 135605) (175454 140615, 175949 140293, 179078 140291, 179455 140474, 179778 141006, 179780 144136, 179596 144476, 179063 144799, 175935 144801, 175595 144617, 175273 144122, 175271 140992, 175454 140615) (175457 145623, 175949 145304, 179077 145302, 179371 145429, 179562 145599, 179778 146016, 179780 149146, 179596 149486, 179064 149809, 175935 149811, 175595 149627, 175273 149132, 175271 146003, 175457 145623) (175454 150636, 175949 150314, 179078 150312, 179455 150495, 179778 151027, 179780 154156, 179596 154496, 179064 154819, 175935 154821, 175595 154637, 175273 154142, 175271 151013, 175454 150636) (175454 155646, 175949 155324, 179078 155322, 179455 155505, 179778 156037, 179780 159166, 179596 159506, 179064 159829, 175935 159831, 175595 159647, 175273 159152, 175271 156023, 175454 155646) (175454 160656, 175949 160334, 179078 160332, 179455 160515, 179778 161047, 179780 164176, 179596 164516, 179064 164839, 175935 164841, 175595 164657, 175273 164162, 175271 161033, 175454 160656) (175454 165666, 175949 165344, 179078 165342, 179455 165525, 179778 166057, 179780 169186, 179596 169526, 179064 169849, 175935 169851, 175595 169667, 175273 169172, 175271 166043, 175454 165666) (175454 170676, 175949 170354, 179078 170352, 179455 170535, 179778 171067, 179780 174196, 179596 174536, 179064 174859, 175935 174861, 175595 174677, 175273 174182, 175271 171053, 175454 170676) (175454 175686, 175949 175364, 179078 175362, 179455 175545, 179778 176077, 179780 179206, 179596 179546, 179064 179869, 175935 179871, 175595 179687, 175273 179192, 175271 176063, 175454 175686) (175454 180696, 175949 180374, 179078 180372, 179455 180555, 179778 181087, 179780 184216, 179596 184556, 179064 184879, 175935 184881, 175595 184697, 175273 184202, 175271 181073, 175454 180696) (175454 185706, 175949 185384, 179078 185382, 179455 185565, 179715 186008, 179728 186645, 179601 187016, 179317 187340, 178446 187563, 176069 187917, 175532 187682, 175277 187280, 175271 186083, 175454 185706) (180463 55445, 180913 55173, 184197 55171, 184536 55370, 184788 55834, 184790 58963, 184606 59303, 184074 59626, 180945 59628, 180605 59444, 180283 58949, 180281 55820, 180463 55445) (180464 60453, 180959 60131, 184088 60129, 184465 60312, 184788 60844, 184790 63973, 184606 64313, 184074 64636, 180945 64638, 180605 64454, 180283 63959, 180281 60830, 180464 60453) (180464 65463, 180959 65141, 184088 65139, 184465 65322, 184788 65854, 184790 68983, 184606 69323, 184074 69646, 180945 69648, 180605 69464, 180283 68969, 180281 65840, 180464 65463) (180464 70473, 180959 70151, 184088 70149, 184465 70332, 184788 70864, 184790 73993, 184606 74333, 184074 74656, 180945 74658, 180605 74474, 180283 73979, 180281 70850, 180464 70473) (180464 75483, 180959 75161, 184088 75159, 184465 75342, 184788 75874, 184790 79003, 184606 79343, 184074 79666, 180945 79668, 180605 79484, 180283 78989, 180281 75860, 180464 75483) (180464 80493, 180959 80171, 184088 80169, 184465 80352, 184788 80884, 184790 84013, 184606 84353, 184074 84676, 180945 84678, 180605 84494, 180283 83999, 180281 80870, 180464 80493) (180464 85503, 180959 85181, 184088 85179, 184465 85362, 184788 85894, 184790 89023, 184606 89363, 184074 89686, 180945 89688, 180605 89504, 180283 89009, 180281 85880, 180464 85503) (180464 90513, 180959 90191, 184088 90189, 184465 90372, 184788 90904, 184790 94033, 184606 94373, 184073 94696, 180945 94698, 180605 94514, 180283 94019, 180281 90890, 180464 90513) (180467 95520, 180959 95201, 184087 95199, 184381 95326, 184572 95496, 184788 95913, 184790 99045, 184606 99385, 184074 99708, 180945 99710, 180605 99526, 180283 99031, 180281 95900, 180467 95520) (180464 100535, 180959 100213, 184088 100211, 184465 100394, 184788 100926, 184790 104055, 184606 104395, 184074 104718, 180945 104720, 180605 104536, 180283 104041, 180281 100912, 180464 100535) (180464 105545, 180959 105223, 184088 105221, 184465 105404, 184788 105936, 184790 109065, 184606 109405, 184074 109728, 180945 109730, 180605 109546, 180283 109051, 180281 105922, 180464 105545) (180464 110555, 180959 110233, 184088 110231, 184465 110414, 184788 110946, 184790 114075, 184606 114415, 184074 114738, 180945 114740, 180605 114556, 180283 114061, 180281 110932, 180464 110555) (180464 115565, 180959 115243, 184088 115241, 184465 115424, 184788 115956, 184790 119085, 184606 119425, 184074 119748, 180945 119750, 180605 119566, 180283 119071, 180281 115942, 180464 115565) (180464 120575, 180959 120253, 184088 120251, 184465 120434, 184788 120966, 184790 124095, 184606 124435, 184074 124758, 180945 124760, 180605 124576, 180283 124081, 180281 120952, 180464 120575) (180464 125585, 180959 125263, 184088 125261, 184465 125444, 184788 125976, 184790 129105, 184606 129445, 184073 129768, 180945 129770, 180605 129586, 180283 129091, 180281 125962, 180464 125585) (180467 130592, 180959 130273, 184087 130271, 184381 130398, 184572 130568, 184788 130985, 184790 134115, 184606 134455, 184074 134778, 180945 134780, 180605 134596, 180283 134101, 180281 130972, 180467 130592) (180464 135605, 180959 135283, 184088 135281, 184465 135464, 184788 135996, 184790 139125, 184606 139465, 184074 139788, 180945 139790, 180605 139606, 180283 139111, 180281 135982, 180464 135605) (180464 140615, 180959 140293, 184088 140291, 184465 140474, 184788 141006, 184790 144136, 184606 144476, 184073 144799, 180945 144801, 180605 144617, 180283 144122, 180281 140992, 180464 140615) (180467 145623, 180959 145304, 184087 145302, 184381 145429, 184572 145599, 184788 146016, 184790 149146, 184606 149486, 184074 149809, 180945 149811, 180605 149627, 180283 149132, 180281 146003, 180467 145623) (180464 150636, 180959 150314, 184088 150312, 184465 150495, 184788 151027, 184790 154156, 184606 154496, 184074 154819, 180945 154821, 180605 154637, 180283 154142, 180281 151013, 180464 150636) (180464 155646, 180959 155324, 184088 155322, 184465 155505, 184788 156037, 184790 159166, 184606 159506, 184074 159829, 180945 159831, 180605 159647, 180283 159152, 180281 156023, 180464 155646) (180464 160656, 180959 160334, 184088 160332, 184465 160515, 184788 161047, 184790 164176, 184606 164516, 184074 164839, 180945 164841, 180605 164657, 180283 164162, 180281 161033, 180464 160656) (180464 165666, 180959 165344, 184088 165342, 184465 165525, 184788 166057, 184790 169186, 184606 169526, 184074 169849, 180945 169851, 180605 169667, 180283 169172, 180281 166043, 180464 165666) (180464 170676, 180959 170354, 184088 170352, 184465 170535, 184788 171067, 184790 174196, 184606 174536, 184074 174859, 180945 174861, 180605 174677, 180283 174182, 180281 171053, 180464 170676) (180464 175686, 180959 175364, 184088 175362, 184465 175545, 184788 176077, 184790 179206, 184606 179546, 184074 179869, 180945 179871, 180605 179687, 180283 179192, 180281 176063, 180464 175686) (180464 180696, 180959 180374, 184088 180372, 184465 180555, 184788 181087, 184790 184216, 184480 184673, 184147 184829, 180903 184829, 180615 184704, 180283 184202, 180281 181073, 180464 180696) (185418 55527, 185599 55327, 186046 55170, 187958 55142, 189303 55617, 189578 55887, 189728 56165, 189805 57036, 189801 58963, 189500 59414, 189085 59626, 185955 59628, 185615 59444, 185293 58949, 185291 55820, 185418 55527) (185474 60453, 185969 60131, 189099 60129, 189475 60312, 189799 60844, 189801 63973, 189617 64313, 189085 64636, 185955 64638, 185615 64454, 185293 63959, 185291 60830, 185474 60453) (185474 65463, 185969 65141, 189099 65139, 189476 65322, 189799 65854, 189801 68983, 189617 69323, 189085 69646, 185955 69648, 185615 69464, 185293 68969, 185291 65840, 185474 65463) (185474 70473, 185969 70151, 189099 70149, 189476 70332, 189799 70864, 189801 73993, 189617 74333, 189085 74656, 185955 74658, 185615 74474, 185293 73979, 185291 70850, 185474 70473) (185474 75483, 185969 75161, 189099 75159, 189476 75342, 189799 75874, 189801 79003, 189617 79343, 189085 79666, 185955 79668, 185615 79484, 185293 78989, 185291 75860, 185474 75483) (185474 80493, 185969 80171, 189099 80169, 189476 80352, 189799 80884, 189801 84013, 189617 84353, 189085 84676, 185955 84678, 185615 84494, 185293 83999, 185291 80870, 185474 80493) (185474 85503, 185969 85181, 189099 85179, 189476 85362, 189799 85894, 189801 89023, 189617 89363, 189085 89686, 185955 89688, 185615 89504, 185293 89009, 185291 85880, 185474 85503) (185474 90513, 185969 90191, 189099 90189, 189476 90372, 189799 90904, 189801 94033, 189617 94373, 189084 94696, 185955 94698, 185615 94514, 185293 94019, 185291 90890, 185474 90513) (185477 95520, 185969 95201, 189098 95199, 189392 95326, 189583 95496, 189799 95913, 189801 99045, 189617 99385, 189085 99708, 185955 99710, 185615 99526, 185293 99031, 185291 95900, 185477 95520) (185474 100535, 185969 100213, 189099 100211, 189476 100394, 189799 100926, 189801 104055, 189617 104395, 189085 104718, 185955 104720, 185615 104536, 185293 104041, 185291 100912, 185474 100535) (185474 105545, 185969 105223, 189099 105221, 189476 105404, 189799 105936, 189801 109065, 189617 109405, 189085 109728, 185955 109730, 185615 109546, 185293 109051, 185291 105922, 185474 105545) (185474 110555, 185969 110233, 189099 110231, 189476 110414, 189799 110946, 189801 114075, 189617 114415, 189085 114738, 185955 114740, 185615 114556, 185293 114061, 185291 110932, 185474 110555) (185474 115565, 185969 115243, 189099 115241, 189476 115424, 189799 115956, 189801 119085, 189617 119425, 189085 119748, 185955 119750, 185615 119566, 185293 119071, 185291 115942, 185474 115565) (185474 120575, 185969 120253, 189099 120251, 189476 120434, 189799 120966, 189801 124095, 189617 124435, 189085 124758, 185955 124760, 185615 124576, 185293 124081, 185291 120952, 185474 120575) (185474 125585, 185969 125263, 189099 125261, 189476 125444, 189799 125976, 189801 129105, 189617 129445, 189084 129768, 185955 129770, 185615 129586, 185293 129091, 185291 125962, 185474 125585) (185477 130592, 185969 130273, 189098 130271, 189392 130398, 189583 130568, 189799 130985, 189801 134115, 189617 134455, 189085 134778, 185955 134780, 185615 134596, 185293 134101, 185291 130972, 185477 130592) (185474 135605, 185969 135283, 189099 135281, 189476 135464, 189799 135996, 189801 139125, 189617 139465, 189085 139788, 185955 139790, 185615 139606, 185293 139111, 185291 135982, 185474 135605) (185474 140615, 185969 140293, 189099 140291, 189476 140474, 189799 141006, 189801 144136, 189617 144476, 189084 144799, 185955 144801, 185615 144617, 185293 144122, 185291 140992, 185474 140615) (185477 145623, 185969 145304, 189098 145302, 189392 145429, 189583 145599, 189799 146016, 189801 149146, 189617 149486, 189085 149809, 185955 149811, 185615 149627, 185293 149132, 185291 146003, 185477 145623) (185474 150636, 185969 150314, 189099 150312, 189476 150495, 189799 151027, 189801 154156, 189617 154496, 189085 154819, 185955 154821, 185615 154637, 185293 154142, 185291 151013, 185474 150636) (185474 155646, 185969 155324, 189099 155322, 189476 155505, 189799 156037, 189801 159166, 189617 159506, 189085 159829, 185955 159831, 185615 159647, 185293 159152, 185291 156023, 185474 155646) (185474 160656, 185969 160334, 189099 160332, 189476 160515, 189799 161047, 189801 164176, 189617 164516, 189085 164839, 185955 164841, 185615 164657, 185293 164162, 185291 161033, 185474 160656) (185474 165666, 185969 165344, 189099 165342, 189476 165525, 189799 166057, 189801 169186, 189617 169526, 189085 169849, 185955 169851, 185615 169667, 185293 169172, 185291 166043, 185474 165666) (185474 170676, 185969 170354, 189099 170352, 189476 170535, 189799 171067, 189801 174196, 189617 174536, 189085 174859, 185955 174861, 185615 174677, 185293 174182, 185291 171053, 185474 170676) (185474 175686, 185969 175364, 189099 175362, 189476 175545, 189799 176077, 189801 179206, 189617 179546, 189085 179869, 185955 179871, 185615 179687, 185293 179192, 185291 176063, 185474 175686) (185474 180696, 185969 180374, 189099 180372, 189476 180555, 189799 181096, 189808 183185, 189728 183837, 189408 184339, 187891 184888, 185994 184829, 185624 184704, 185293 184202, 185291 181073, 185474 180696) (190428 180780, 190600 180587, 190980 180374, 194109 180372, 194486 180555, 194665 180796, 194757 181482, 194668 181859, 194480 182164, 191338 183654, 190912 183625, 190627 183517, 190325 183141, 190301 181082, 190428 180780) (190319 57039, 190668 56463, 191185 56275, 194380 57781, 194668 58140, 194759 58489, 194721 59102, 194562 59398, 194181 59627, 190963 59628, 190625 59445, 190304 58949, 190319 57039) (190485 60453, 190979 60131, 194174 60130, 194548 60370, 194809 60844, 194811 63973, 194627 64313, 194095 64636, 190966 64638, 190626 64454, 190304 63959, 190302 60830, 190485 60453) (190485 65463, 190980 65141, 194109 65139, 194486 65322, 194809 65854, 194811 68983, 194627 69323, 194095 69646, 190966 69648, 190626 69464, 190304 68969, 190302 65840, 190485 65463) (190485 70473, 190980 70151, 194109 70149, 194486 70332, 194809 70864, 194811 73993, 194627 74333, 194095 74656, 190966 74658, 190626 74474, 190304 73979, 190302 70850, 190485 70473) (190485 75483, 190980 75161, 194109 75159, 194486 75342, 194809 75874, 194811 79003, 194627 79343, 194095 79666, 190966 79668, 190626 79484, 190304 78989, 190302 75860, 190485 75483) (190485 80493, 190980 80171, 194109 80169, 194486 80352, 194809 80884, 194811 84013, 194627 84353, 194095 84676, 190966 84678, 190626 84494, 190304 83999, 190302 80870, 190485 80493) (190485 85503, 190980 85181, 194109 85179, 194486 85362, 194809 85894, 194811 89023, 194627 89363, 194095 89686, 190966 89688, 190626 89504, 190304 89009, 190302 85880, 190485 85503) (190485 90513, 190980 90191, 194109 90189, 194486 90372, 194809 90904, 194811 94033, 194627 94373, 194094 94696, 190966 94698, 190626 94514, 190304 94019, 190302 90890, 190485 90513) (190488 95520, 190980 95201, 194108 95199, 194402 95326, 194593 95496, 194809 95913, 194811 99045, 194627 99385, 194095 99708, 190966 99710, 190626 99526, 190304 99031, 190302 95900, 190488 95520) (190485 100535, 190980 100213, 194109 100211, 194486 100394, 194809 100926, 194811 104055, 194627 104395, 194095 104718, 190966 104720, 190626 104536, 190304 104041, 190302 100912, 190485 100535) (190485 105545, 190980 105223, 194109 105221, 194486 105404, 194809 105936, 194811 109065, 194627 109405, 194095 109728, 190966 109730, 190626 109546, 190304 109051, 190302 105922, 190485 105545) (190485 110555, 190980 110233, 194109 110231, 194486 110414, 194809 110946, 194811 114075, 194627 114415, 194095 114738, 190966 114740, 190626 114556, 190304 114061, 190302 110932, 190485 110555) (190485 115565, 190980 115243, 194109 115241, 194486 115424, 194809 115956, 194811 119085, 194627 119425, 194095 119748, 190966 119750, 190626 119566, 190304 119071, 190302 115942, 190485 115565) (190485 120575, 190980 120253, 194109 120251, 194486 120434, 194809 120966, 194811 124095, 194627 124435, 194095 124758, 190966 124760, 190626 124576, 190304 124081, 190302 120952, 190485 120575) (190485 125585, 190980 125263, 194109 125261, 194486 125444, 194809 125976, 194811 129105, 194627 129445, 194094 129768, 190966 129770, 190626 129586, 190304 129091, 190302 125962, 190485 125585) (190488 130592, 190980 130273, 194108 130271, 194402 130398, 194593 130568, 194809 130985, 194811 134115, 194627 134455, 194095 134778, 190966 134780, 190626 134596, 190304 134101, 190302 130972, 190488 130592) (190485 135605, 190980 135283, 194109 135281, 194486 135464, 194809 135996, 194811 139125, 194627 139465, 194095 139788, 190966 139790, 190626 139606, 190304 139111, 190302 135982, 190485 135605) (190485 140615, 190980 140293, 194109 140291, 194486 140474, 194809 141006, 194811 144136, 194627 144476, 194094 144799, 190966 144801, 190626 144617, 190304 144122, 190302 140992, 190485 140615) (190488 145623, 190980 145304, 194108 145302, 194402 145429, 194593 145599, 194809 146016, 194811 149146, 194627 149486, 194095 149809, 190966 149811, 190626 149627, 190304 149132, 190302 146003, 190488 145623) (190485 150636, 190980 150314, 194109 150312, 194486 150495, 194809 151027, 194811 154156, 194627 154496, 194095 154819, 190966 154821, 190626 154637, 190304 154142, 190302 151013, 190485 150636) (190485 155646, 190980 155324, 194109 155322, 194486 155505, 194809 156037, 194811 159166, 194627 159506, 194095 159829, 190966 159831, 190626 159647, 190304 159152, 190302 156023, 190485 155646) (190485 160656, 190980 160334, 194109 160332, 194486 160515, 194809 161047, 194811 164176, 194627 164516, 194095 164839, 190966 164841, 190626 164657, 190304 164162, 190302 161033, 190485 160656) (190485 165666, 190980 165344, 194109 165342, 194486 165525, 194809 166057, 194811 169186, 194627 169526, 194095 169849, 190966 169851, 190626 169667, 190304 169172, 190302 166043, 190485 165666) (190485 170676, 190980 170354, 194109 170352, 194486 170535, 194809 171067, 194811 174196, 194627 174536, 194095 174859, 190966 174861, 190626 174677, 190304 174182, 190302 171053, 190485 170676) (190485 175686, 190980 175364, 194109 175362, 194486 175545, 194809 176077, 194811 179206, 194627 179546, 194095 179869, 190966 179871, 190625 179686, 190304 179192, 190302 176063, 190485 175686) (195494 60455, 195621 60337, 195984 60185, 197368 60180, 199010 60170, 199566 60543, 199769 61074, 199820 62276, 199821 63973, 199637 64313, 199105 64636, 195976 64638, 195636 64454, 195314 63959, 195312 60830, 195494 60455) (195495 65463, 195990 65141, 199119 65139, 199496 65322, 199819 65854, 199821 68983, 199637 69323, 199105 69646, 195976 69648, 195636 69464, 195314 68969, 195312 65840, 195495 65463) (195495 70473, 195990 70151, 199119 70149, 199496 70332, 199819 70864, 199821 73993, 199637 74333, 199105 74656, 195976 74658, 195636 74474, 195314 73979, 195312 70850, 195495 70473) (195495 75483, 195990 75161, 199119 75159, 199496 75342, 199819 75874, 199821 79003, 199637 79343, 199105 79666, 195976 79668, 195636 79484, 195314 78989, 195312 75860, 195495 75483) (195495 80493, 195990 80171, 199119 80169, 199496 80352, 199819 80884, 199821 84013, 199637 84353, 199105 84676, 195976 84678, 195636 84494, 195314 83999, 195312 80870, 195495 80493) (195495 85503, 195990 85181, 199119 85179, 199496 85362, 199819 85894, 199821 89023, 199637 89363, 199105 89686, 195976 89688, 195636 89504, 195314 89009, 195312 85880, 195495 85503) (195495 90513, 195990 90191, 199119 90189, 199496 90372, 199819 90904, 199821 94033, 199637 94373, 199104 94696, 195976 94698, 195636 94514, 195314 94019, 195312 90890, 195495 90513) (195498 95520, 195990 95201, 199118 95199, 199412 95326, 199603 95496, 199819 95913, 199821 99045, 199637 99385, 199105 99708, 195976 99710, 195636 99526, 195314 99031, 195312 95900, 195498 95520) (195495 100535, 195990 100213, 199119 100211, 199496 100394, 199819 100926, 199821 104055, 199637 104395, 199105 104718, 195976 104720, 195636 104536, 195314 104041, 195312 100912, 195495 100535) (195495 105545, 195990 105223, 199119 105221, 199496 105404, 199819 105936, 199821 109065, 199637 109405, 199105 109728, 195976 109730, 195636 109546, 195314 109051, 195312 105922, 195495 105545) (195495 110555, 195990 110233, 199119 110231, 199496 110414, 199819 110946, 199821 114075, 199637 114415, 199105 114738, 195976 114740, 195636 114556, 195314 114061, 195312 110932, 195495 110555) (195495 115565, 195990 115243, 199119 115241, 199496 115424, 199819 115956, 199821 119085, 199637 119425, 199105 119748, 195976 119750, 195636 119566, 195314 119071, 195312 115942, 195495 115565) (195495 120575, 195990 120253, 199119 120251, 199496 120434, 199819 120966, 199821 124095, 199637 124435, 199105 124758, 195976 124760, 195636 124576, 195314 124081, 195312 120952, 195495 120575) (195495 125585, 195990 125263, 199119 125261, 199496 125444, 199819 125976, 199821 129105, 199637 129445, 199104 129768, 195976 129770, 195636 129586, 195314 129091, 195312 125962, 195495 125585) (195498 130592, 195990 130273, 199118 130271, 199412 130398, 199603 130568, 199819 130985, 199821 134115, 199637 134455, 199105 134778, 195976 134780, 195636 134596, 195314 134101, 195312 130972, 195498 130592) (195495 135605, 195990 135283, 199119 135281, 199496 135464, 199819 135996, 199821 139125, 199637 139465, 199105 139788, 195976 139790, 195636 139606, 195314 139111, 195312 135982, 195495 135605) (195495 140615, 195990 140293, 199119 140291, 199496 140474, 199819 141006, 199821 144136, 199637 144476, 199104 144799, 195976 144801, 195636 144617, 195314 144122, 195312 140992, 195495 140615) (195498 145623, 195990 145304, 199118 145302, 199412 145429, 199603 145599, 199819 146016, 199821 149146, 199637 149486, 199105 149809, 195976 149811, 195636 149627, 195314 149132, 195312 146003, 195498 145623) (195495 150636, 195990 150314, 199119 150312, 199496 150495, 199819 151027, 199821 154156, 199637 154496, 199105 154819, 195976 154821, 195636 154637, 195314 154142, 195312 151013, 195495 150636) (195495 155646, 195990 155324, 199119 155322, 199496 155505, 199819 156037, 199821 159166, 199637 159506, 199105 159829, 195976 159831, 195636 159647, 195314 159152, 195312 156023, 195495 155646) (195495 160656, 195990 160334, 199119 160332, 199496 160515, 199819 161047, 199821 164176, 199637 164516, 199105 164839, 195976 164841, 195636 164657, 195314 164162, 195312 161033, 195495 160656) (195495 165666, 195990 165344, 199119 165342, 199496 165525, 199819 166057, 199821 169186, 199637 169526, 199105 169849, 195976 169851, 195636 169667, 195314 169172, 195312 166043, 195495 165666) (195495 170676, 195990 170354, 199119 170352, 199496 170535, 199819 171067, 199821 174196, 199637 174536, 199105 174859, 195976 174861, 195636 174677, 195314 174182, 195312 171053, 195495 170676) (195495 175686, 195990 175364, 199119 175362, 199496 175545, 199819 176077, 199823 177955, 199769 178925, 199566 179456, 199048 179820, 195923 179813, 195756 179762, 195526 179570, 195314 179192, 195312 176063, 195495 175686) (200480 61933, 200742 61642, 201295 61541, 203274 62721, 204164 63386, 204273 63977, 204136 64345, 203768 64631, 200986 64638, 200646 64454, 200324 63959, 200322 62276, 200480 61933) (200505 65463, 201000 65141, 203811 65136, 204372 65240, 204580 65392, 204829 65854, 204831 68983, 204647 69323, 204115 69646, 200986 69648, 200646 69464, 200324 68969, 200322 65840, 200505 65463) (200505 70473, 201000 70151, 204129 70149, 204506 70332, 204829 70864, 204831 73993, 204647 74333, 204115 74656, 200986 74658, 200646 74474, 200324 73979, 200322 70850, 200505 70473) (200505 75483, 201000 75161, 204129 75159, 204506 75342, 204829 75874, 204831 79003, 204647 79343, 204115 79666, 200986 79668, 200646 79484, 200324 78989, 200322 75860, 200505 75483) (200505 80493, 201000 80171, 204129 80169, 204506 80352, 204829 80884, 204831 84013, 204647 84353, 204115 84676, 200986 84678, 200646 84494, 200324 83999, 200322 80870, 200505 80493) (200505 85503, 201000 85181, 204129 85179, 204506 85362, 204829 85894, 204831 89023, 204647 89363, 204115 89686, 200986 89688, 200646 89504, 200324 89009, 200322 85880, 200505 85503) (200505 90513, 201000 90191, 204129 90189, 204506 90372, 204829 90904, 204831 94033, 204647 94373, 204114 94696, 200986 94698, 200646 94514, 200324 94019, 200322 90890, 200505 90513) (200508 95520, 201000 95201, 204128 95199, 204422 95326, 204613 95496, 204829 95913, 204831 99045, 204647 99385, 204115 99708, 200986 99710, 200646 99526, 200324 99031, 200322 95900, 200508 95520) (200505 100535, 201000 100213, 204129 100211, 204506 100394, 204829 100926, 204831 104055, 204647 104395, 204115 104718, 200986 104720, 200646 104536, 200324 104041, 200322 100912, 200505 100535) (200505 105545, 201000 105223, 204129 105221, 204506 105404, 204829 105936, 204831 109065, 204647 109405, 204115 109728, 200986 109730, 200646 109546, 200324 109051, 200322 105922, 200505 105545) (200505 110555, 201000 110233, 204129 110231, 204506 110414, 204829 110946, 204831 114075, 204647 114415, 204115 114738, 200986 114740, 200646 114556, 200324 114061, 200322 110932, 200505 110555) (200505 115565, 201000 115243, 204129 115241, 204506 115424, 204829 115956, 204831 119085, 204647 119425, 204115 119748, 200986 119750, 200646 119566, 200324 119071, 200322 115942, 200505 115565) (200505 120575, 201000 120253, 204129 120251, 204506 120434, 204829 120966, 204831 124095, 204647 124435, 204115 124758, 200986 124760, 200646 124576, 200324 124081, 200322 120952, 200505 120575) (200505 125585, 201000 125263, 204129 125261, 204506 125444, 204829 125976, 204831 129105, 204647 129445, 204114 129768, 200986 129770, 200646 129586, 200324 129091, 200322 125962, 200505 125585) (200508 130592, 201000 130273, 204128 130271, 204422 130398, 204613 130568, 204829 130985, 204831 134115, 204647 134455, 204115 134778, 200986 134780, 200646 134596, 200324 134101, 200322 130972, 200508 130592) (200505 135605, 201000 135283, 204129 135281, 204506 135464, 204829 135996, 204831 139125, 204647 139465, 204115 139788, 200986 139790, 200646 139606, 200324 139111, 200322 135982, 200505 135605) (200505 140615, 201000 140293, 204129 140291, 204506 140474, 204829 141006, 204831 144136, 204647 144476, 204114 144799, 200986 144801, 200646 144617, 200324 144122, 200322 140992, 200505 140615) (200508 145623, 201000 145304, 204128 145302, 204422 145429, 204613 145599, 204829 146016, 204831 149146, 204647 149486, 204115 149809, 200986 149811, 200646 149627, 200324 149132, 200322 146003, 200508 145623) (200505 150636, 201000 150314, 204129 150312, 204506 150495, 204829 151027, 204831 154156, 204647 154496, 204115 154819, 200986 154821, 200646 154637, 200324 154142, 200322 151013, 200505 150636) (200505 155646, 201000 155324, 204129 155322, 204506 155505, 204829 156037, 204831 159166, 204647 159506, 204115 159829, 200986 159831, 200646 159647, 200324 159152, 200322 156023, 200505 155646) (200505 160656, 201000 160334, 204129 160332, 204506 160515, 204829 161047, 204831 164176, 204647 164516, 204115 164839, 200986 164841, 200646 164657, 200324 164162, 200322 161033, 200505 160656) (200505 165666, 201000 165344, 204129 165342, 204506 165525, 204829 166057, 204831 169186, 204647 169526, 204115 169849, 200986 169851, 200646 169667, 200324 169172, 200322 166043, 200505 165666) (200505 170676, 201000 170354, 204129 170352, 204506 170535, 204829 171067, 204829 174225, 204523 174651, 204228 174790, 203640 174860, 200986 174861, 200646 174677, 200324 174182, 200322 171053, 200505 170676) (200505 175686, 201000 175364, 203640 175362, 204040 175565, 204250 175905, 204294 176251, 204090 176673, 203276 177276, 201459 178366, 200929 178397, 200697 178331, 200328 177912, 200322 176063, 200505 175686) (205459 65547, 205637 65349, 206131 65191, 206641 65225, 208707 66751, 209705 67662, 209790 68065, 209789 69024, 209665 69313, 209125 69646, 205996 69648, 205656 69464, 205334 68969, 205332 65840, 205459 65547) (205515 70473, 206010 70151, 209139 70149, 209516 70332, 209839 70864, 209841 73993, 209657 74333, 209125 74656, 205996 74658, 205656 74474, 205334 73979, 205332 70850, 205515 70473) (205515 75483, 206010 75161, 209139 75159, 209516 75342, 209839 75874, 209841 79003, 209657 79343, 209125 79666, 205996 79668, 205656 79484, 205334 78989, 205332 75860, 205515 75483) (205515 80493, 206010 80171, 209139 80169, 209516 80352, 209839 80884, 209841 84013, 209657 84353, 209125 84676, 205996 84678, 205656 84494, 205334 83999, 205332 80870, 205515 80493) (205515 85503, 206010 85181, 209139 85179, 209516 85362, 209839 85894, 209841 89023, 209657 89363, 209125 89686, 205996 89688, 205656 89504, 205334 89009, 205332 85880, 205515 85503) (205515 90513, 206010 90191, 209139 90189, 209516 90372, 209839 90904, 209841 94033, 209657 94373, 209124 94696, 205996 94698, 205656 94514, 205334 94019, 205332 90890, 205515 90513) (205518 95520, 206010 95201, 209138 95199, 209432 95326, 209623 95496, 209839 95913, 209841 99045, 209657 99385, 209125 99708, 205996 99710, 205656 99526, 205334 99031, 205332 95900, 205518 95520) (205515 100535, 206010 100213, 209139 100211, 209516 100394, 209839 100926, 209841 104055, 209657 104395, 209125 104718, 205996 104720, 205656 104536, 205334 104041, 205332 100912, 205515 100535) (205515 105545, 206010 105223, 209139 105221, 209516 105404, 209839 105936, 209841 109065, 209657 109405, 209125 109728, 205996 109730, 205656 109546, 205334 109051, 205332 105922, 205515 105545) (205515 110555, 206010 110233, 209139 110231, 209516 110414, 209839 110946, 209841 114075, 209657 114415, 209125 114738, 205996 114740, 205656 114556, 205334 114061, 205332 110932, 205515 110555) (205515 115565, 206010 115243, 209139 115241, 209516 115424, 209839 115956, 209841 119085, 209657 119425, 209125 119748, 205996 119750, 205656 119566, 205334 119071, 205332 115942, 205515 115565) (205515 120575, 206010 120253, 209139 120251, 209516 120434, 209839 120966, 209841 124095, 209657 124435, 209125 124758, 205996 124760, 205656 124576, 205334 124081, 205332 120952, 205515 120575) (205515 125585, 206010 125263, 209139 125261, 209516 125444, 209839 125976, 209841 129105, 209657 129445, 209124 129768, 205996 129770, 205656 129586, 205334 129091, 205332 125962, 205515 125585) (205518 130592, 206010 130273, 209138 130271, 209432 130398, 209623 130568, 209839 130985, 209841 134115, 209657 134455, 209125 134778, 205996 134780, 205656 134596, 205334 134101, 205332 130972, 205518 130592) (205515 135605, 206010 135283, 209139 135281, 209516 135464, 209839 135996, 209841 139125, 209657 139465, 209125 139788, 205996 139790, 205656 139606, 205334 139111, 205332 135982, 205515 135605) (205515 140615, 206010 140293, 209139 140291, 209516 140474, 209839 141006, 209841 144136, 209657 144476, 209124 144799, 205996 144801, 205656 144617, 205334 144122, 205332 140992, 205515 140615) (205518 145623, 206010 145304, 209138 145302, 209432 145429, 209623 145599, 209839 146016, 209841 149146, 209657 149486, 209125 149809, 205996 149811, 205656 149627, 205334 149132, 205332 146003, 205518 145623) (205515 150636, 206010 150314, 209139 150312, 209516 150495, 209839 151027, 209841 154156, 209657 154496, 209125 154819, 205996 154821, 205656 154637, 205334 154142, 205332 151013, 205515 150636) (205515 155646, 206010 155324, 209139 155322, 209516 155505, 209839 156037, 209841 159166, 209657 159506, 209125 159829, 205996 159831, 205656 159647, 205334 159152, 205332 156023, 205515 155646) (205515 160656, 206010 160334, 209139 160332, 209516 160515, 209839 161047, 209841 164176, 209657 164516, 209125 164839, 205996 164841, 205656 164657, 205334 164162, 205332 161033, 205515 160656) (205515 165666, 206010 165344, 209139 165342, 209516 165525, 209839 166057, 209841 169186, 209657 169526, 209125 169849, 205996 169851, 205656 169667, 205334 169172, 205332 166043, 205515 165666) (205515 170676, 206010 170354, 209139 170352, 209516 170535, 209789 170977, 209790 171934, 209626 172415, 208681 173270, 206735 174712, 205978 174787, 205633 174674, 205332 174233, 205332 171053, 205515 170676) (210525 70473, 210964 70200, 212504 70200, 213708 71284, 214752 72443, 214800 72793, 214799 74034, 214675 74323, 214135 74656, 211006 74658, 210666 74474, 210344 73979, 210342 70850, 210525 70473) (210525 75483, 211020 75161, 214149 75159, 214526 75342, 214849 75874, 214851 79003, 214667 79343, 214135 79666, 211006 79668, 210666 79484, 210344 78989, 210342 75860, 210525 75483) (210525 80493, 211020 80171, 214149 80169, 214526 80352, 214849 80884, 214851 84013, 214667 84353, 214135 84676, 211006 84678, 210666 84494, 210344 83999, 210342 80870, 210525 80493) (210525 85503, 211020 85181, 214149 85179, 214526 85362, 214849 85894, 214851 89023, 214667 89363, 214135 89686, 211006 89688, 210666 89504, 210344 89009, 210342 85880, 210525 85503) (210525 90513, 211020 90191, 214149 90189, 214526 90372, 214849 90904, 214851 94033, 214667 94373, 214134 94696, 211006 94698, 210666 94514, 210344 94019, 210342 90890, 210525 90513) (210528 95520, 211020 95201, 214148 95199, 214442 95326, 214633 95496, 214849 95913, 214851 99045, 214667 99385, 214135 99708, 211006 99710, 210666 99526, 210344 99031, 210342 95900, 210528 95520) (210525 100535, 211020 100213, 214149 100211, 214526 100394, 214849 100926, 214851 104055, 214667 104395, 214135 104718, 211006 104720, 210666 104536, 210344 104041, 210342 100912, 210525 100535) (210525 105545, 211020 105223, 214149 105221, 214526 105404, 214849 105936, 214851 109065, 214667 109405, 214135 109728, 211006 109730, 210666 109546, 210344 109051, 210342 105922, 210525 105545) (210525 110555, 211020 110233, 214149 110231, 214526 110414, 214849 110946, 214851 114075, 214667 114415, 214135 114738, 211006 114740, 210666 114556, 210344 114061, 210342 110932, 210525 110555) (210525 115565, 211020 115243, 214149 115241, 214526 115424, 214849 115956, 214851 119085, 214667 119425, 214135 119748, 211006 119750, 210666 119566, 210344 119071, 210342 115942, 210525 115565) (210525 120575, 211020 120253, 214149 120251, 214526 120434, 214849 120966, 214851 124095, 214667 124435, 214135 124758, 211006 124760, 210666 124576, 210344 124081, 210342 120952, 210525 120575) (210525 125585, 211020 125263, 214149 125261, 214526 125444, 214849 125976, 214851 129105, 214667 129445, 214134 129768, 211006 129770, 210666 129586, 210344 129091, 210342 125962, 210525 125585) (210528 130592, 211020 130273, 214148 130271, 214442 130398, 214633 130568, 214849 130985, 214851 134115, 214667 134455, 214135 134778, 211006 134780, 210666 134596, 210344 134101, 210342 130972, 210528 130592) (210525 135605, 211020 135283, 214149 135281, 214526 135464, 214849 135996, 214851 139125, 214667 139465, 214135 139788, 211006 139790, 210666 139606, 210344 139111, 210342 135982, 210525 135605) (210525 140615, 211020 140293, 214149 140291, 214526 140474, 214849 141006, 214851 144136, 214667 144476, 214134 144799, 211006 144801, 210666 144617, 210344 144122, 210342 140992, 210525 140615) (210528 145623, 211020 145304, 214148 145302, 214442 145429, 214633 145599, 214849 146016, 214851 149146, 214667 149486, 214135 149809, 211006 149811, 210666 149627, 210344 149132, 210342 146003, 210528 145623) (210525 150636, 211020 150314, 214149 150312, 214526 150495, 214849 151027, 214851 154156, 214667 154496, 214135 154819, 211006 154821, 210666 154637, 210344 154142, 210342 151013, 210525 150636) (210525 155646, 211020 155324, 214149 155322, 214526 155505, 214849 156037, 214851 159166, 214667 159506, 214135 159829, 211006 159831, 210666 159647, 210344 159152, 210342 156023, 210525 155646) (210525 160656, 211020 160334, 214149 160332, 214526 160515, 214849 161047, 214851 164176, 214667 164516, 214135 164839, 211006 164841, 210666 164657, 210344 164162, 210342 161033, 210525 160656) (210525 165666, 211020 165344, 214149 165342, 214526 165525, 214799 165964, 214799 167206, 214681 167643, 213740 168683, 212643 169680, 212206 169799, 210965 169799, 210676 169674, 210344 169172, 210342 166043, 210525 165666) (215535 75483, 215974 75210, 216934 75210, 217336 75293, 218249 76292, 219712 78264, 219787 79021, 219674 79367, 219233 79667, 216016 79668, 215676 79484, 215354 78989, 215352 75860, 215535 75483) (215535 80493, 216030 80171, 219225 80170, 219651 80475, 219791 80770, 219860 81359, 219861 84013, 219677 84353, 219145 84676, 216016 84678, 215676 84494, 215354 83999, 215352 80870, 215535 80493) (215535 85503, 216030 85181, 219159 85179, 219536 85362, 219859 85894, 219861 89023, 219677 89363, 219145 89686, 216016 89688, 215676 89504, 215354 89009, 215352 85880, 215535 85503) (215535 90513, 216030 90191, 219159 90189, 219536 90372, 219859 90904, 219861 94033, 219677 94373, 219144 94696, 216016 94698, 215676 94514, 215354 94019, 215352 90890, 215535 90513) (215538 95520, 216030 95201, 219158 95199, 219452 95326, 219643 95496, 219859 95913, 219861 99045, 219677 99385, 219145 99708, 216016 99710, 215676 99526, 215354 99031, 215352 95900, 215538 95520) (215535 100535, 216030 100213, 219159 100211, 219536 100394, 219859 100926, 219861 104055, 219677 104395, 219145 104718, 216016 104720, 215676 104536, 215354 104041, 215352 100912, 215535 100535) (215535 105545, 216030 105223, 219159 105221, 219536 105404, 219859 105936, 219861 109065, 219677 109405, 219145 109728, 216016 109730, 215676 109546, 215354 109051, 215352 105922, 215535 105545) (215535 110555, 216030 110233, 219159 110231, 219536 110414, 219859 110946, 219861 114075, 219677 114415, 219145 114738, 216016 114740, 215676 114556, 215354 114061, 215352 110932, 215535 110555) (215535 115565, 216030 115243, 219159 115241, 219536 115424, 219859 115956, 219861 119085, 219677 119425, 219145 119748, 216016 119750, 215676 119566, 215354 119071, 215352 115942, 215535 115565) (215535 120575, 216030 120253, 219159 120251, 219536 120434, 219859 120966, 219861 124095, 219677 124435, 219145 124758, 216016 124760, 215676 124576, 215354 124081, 215352 120952, 215535 120575) (215535 125585, 216030 125263, 219159 125261, 219536 125444, 219859 125976, 219861 129105, 219677 129445, 219144 129768, 216016 129770, 215676 129586, 215354 129091, 215352 125962, 215535 125585) (215538 130592, 216030 130273, 219158 130271, 219452 130398, 219643 130568, 219859 130985, 219861 134115, 219677 134455, 219145 134778, 216016 134780, 215676 134596, 215354 134101, 215352 130972, 215538 130592) (215535 135605, 216030 135283, 219159 135281, 219536 135464, 219859 135996, 219861 139125, 219677 139465, 219145 139788, 216016 139790, 215676 139606, 215354 139111, 215352 135982, 215535 135605) (215535 140615, 216030 140293, 219159 140291, 219536 140474, 219859 141006, 219861 144136, 219677 144476, 219144 144799, 216016 144801, 215676 144617, 215354 144122, 215352 140992, 215535 140615) (215538 145623, 216030 145304, 219158 145302, 219452 145429, 219643 145599, 219859 146016, 219861 149146, 219677 149486, 219145 149809, 216016 149811, 215676 149627, 215354 149132, 215352 146003, 215538 145623) (215535 150636, 216030 150314, 219159 150312, 219536 150495, 219859 151027, 219861 154156, 219677 154496, 219145 154819, 216016 154821, 215676 154637, 215354 154142, 215352 151013, 215535 150636) (215535 155646, 216030 155324, 219159 155322, 219536 155505, 219859 156037, 219863 158811, 219759 159371, 219681 159502, 219145 159829, 216016 159831, 215676 159647, 215354 159152, 215352 156023, 215535 155646) (215535 160656, 216030 160334, 219159 160332, 219580 160554, 219748 160821, 219808 161131, 219774 161641, 218249 163706, 217415 164626, 216934 164789, 215975 164789, 215686 164664, 215354 164162, 215352 161033, 215535 160656) (220479 81084, 220654 80877, 220905 80749, 221251 80705, 221602 80823, 222276 81721, 223419 83639, 223332 84302, 222912 84671, 221026 84678, 220686 84494, 220364 83999, 220362 81359, 220479 81084) (220545 85503, 221040 85181, 222955 85176, 223925 85230, 224456 85433, 224820 85951, 224813 89076, 224632 89422, 224155 89686, 221026 89688, 220686 89504, 220364 89009, 220362 85880, 220545 85503) (220545 90513, 221040 90191, 224169 90189, 224546 90372, 224869 90904, 224871 94033, 224686 94374, 224154 94696, 221026 94698, 220686 94514, 220364 94019, 220362 90890, 220545 90513) (220548 95520, 221040 95201, 224168 95199, 224462 95326, 224653 95496, 224869 95913, 224871 99045, 224687 99385, 224155 99708, 221026 99710, 220686 99526, 220364 99031, 220362 95900, 220548 95520) (220545 100535, 221040 100213, 224169 100211, 224546 100394, 224869 100926, 224871 104055, 224687 104395, 224155 104718, 221026 104720, 220686 104536, 220364 104041, 220362 100912, 220545 100535) (220545 105545, 221040 105223, 224169 105221, 224546 105404, 224869 105936, 224871 109065, 224687 109405, 224155 109728, 221026 109730, 220686 109546, 220364 109051, 220362 105922, 220545 105545) (220545 110555, 221040 110233, 224169 110231, 224546 110414, 224869 110946, 224871 114075, 224687 114415, 224155 114738, 221026 114740, 220686 114556, 220364 114061, 220362 110932, 220545 110555) (220545 115565, 221040 115243, 224169 115241, 224546 115424, 224869 115956, 224871 119085, 224687 119425, 224155 119748, 221026 119750, 220686 119566, 220364 119071, 220362 115942, 220545 115565) (220545 120575, 221040 120253, 224169 120251, 224546 120434, 224869 120966, 224871 124095, 224687 124435, 224155 124758, 221026 124760, 220686 124576, 220364 124081, 220362 120952, 220545 120575) (220545 125585, 221040 125263, 224169 125261, 224546 125444, 224869 125976, 224871 129105, 224687 129445, 224154 129768, 221026 129770, 220686 129586, 220364 129091, 220362 125962, 220545 125585) (220548 130592, 221040 130273, 224168 130271, 224462 130398, 224653 130568, 224869 130985, 224871 134115, 224687 134455, 224155 134778, 221026 134780, 220686 134596, 220364 134101, 220362 130972, 220548 130592) (220545 135605, 221040 135283, 224169 135281, 224546 135464, 224869 135996, 224871 139125, 224687 139465, 224155 139788, 221026 139790, 220686 139606, 220364 139111, 220362 135982, 220545 135605) (220545 140615, 221040 140293, 224169 140291, 224546 140474, 224869 141006, 224871 144136, 224687 144476, 224154 144799, 221026 144801, 220686 144617, 220364 144122, 220362 140992, 220545 140615) (220548 145623, 221040 145304, 224168 145302, 224462 145429, 224653 145599, 224869 146016, 224869 149174, 224629 149548, 224155 149809, 221026 149811, 220686 149627, 220364 149132, 220362 146003, 220548 145623) (220545 150636, 221040 150314, 224169 150312, 224544 150494, 224708 150699, 224815 150984, 224819 152368, 224829 154010, 224456 154566, 223925 154769, 222723 154820, 221026 154821, 220686 154637, 220364 154142, 220362 151013, 220545 150636) (220545 155646, 221040 155324, 222723 155322, 223066 155480, 223358 155741, 223406 156394, 222278 158274, 221684 159077, 221022 159273, 220654 159135, 220368 158768, 220362 156023, 220545 155646) (225610 90454, 225796 90334, 226482 90242, 226859 90331, 227218 90619, 228692 93742, 228517 94372, 228141 94674, 226036 94698, 225696 94514, 225374 94019, 225372 90890, 225610 90454) (225558 95520, 226050 95201, 228185 95191, 228837 95271, 229112 95421, 229382 95696, 229857 97034, 229829 99006, 229704 99376, 229165 99708, 226036 99710, 225696 99526, 225374 99031, 225372 95900, 225558 95520) (225555 100535, 226050 100213, 229179 100211, 229472 100338, 229700 100562, 229828 100857, 229829 104097, 229705 104385, 229165 104718, 226036 104720, 225696 104536, 225374 104041, 225372 100912, 225555 100535) (225555 105545, 226050 105223, 229179 105221, 229556 105404, 229879 105936, 229881 109065, 229697 109405, 229165 109728, 226036 109730, 225696 109546, 225374 109051, 225372 105922, 225555 105545) (225555 110555, 226050 110233, 229179 110231, 229556 110414, 229879 110946, 229881 114075, 229697 114415, 229165 114738, 226036 114740, 225696 114556, 225374 114061, 225372 110932, 225555 110555) (225555 115565, 226050 115243, 229179 115241, 229556 115424, 229879 115956, 229881 119085, 229697 119425, 229165 119748, 226036 119750, 225696 119566, 225374 119071, 225372 115942, 225555 115565) (225555 120575, 226050 120253, 229179 120251, 229556 120434, 229879 120966, 229881 124095, 229697 124435, 229165 124758, 226036 124760, 225696 124576, 225374 124081, 225372 120952, 225555 120575) (225555 125585, 226050 125263, 229179 125261, 229556 125444, 229879 125976, 229881 129105, 229697 129445, 229164 129768, 226036 129770, 225696 129586, 225374 129091, 225372 125962, 225555 125585) (225558 130592, 226050 130273, 229178 130271, 229472 130398, 229663 130568, 229879 130985, 229879 134143, 229639 134517, 229165 134778, 226036 134780, 225696 134596, 225374 134101, 225372 130972, 225558 130592) (225555 135605, 226050 135283, 229179 135281, 229554 135463, 229718 135668, 229826 135968, 229830 139088, 229778 139333, 229629 139536, 229165 139788, 226036 139790, 225696 139606, 225374 139111, 225372 135982, 225555 135605) (225555 140615, 226050 140293, 229179 140291, 229603 140515, 229768 140779, 229830 141046, 229889 142889, 229339 144407, 228840 144727, 227959 144800, 226036 144801, 225696 144617, 225374 144122, 225372 140992, 225555 140615) (225558 145623, 226050 145304, 227959 145302, 228548 145650, 228693 146258, 227166 149480, 226860 149669, 226510 149759, 225896 149721, 225601 149561, 225372 149181, 225372 146003, 225558 145623) (230565 105545, 231008 105285, 231645 105272, 232016 105400, 232373 105792, 232556 106521, 232927 109044, 232682 109468, 232280 109723, 231046 109730, 230706 109546, 230384 109051, 230382 105922, 230565 105545) (230565 110555, 231060 110233, 232323 110228, 232793 110354, 233005 110549, 233205 110870, 233552 113205, 233595 114119, 233311 114515, 232949 114734, 231046 114740, 230706 114556, 230384 114061, 230382 110932, 230565 110555) (230565 115565, 231060 115243, 232989 115238, 233332 115398, 233517 115605, 233689 115954, 233841 119129, 233543 119535, 233130 119748, 231046 119750, 230706 119566, 230384 119071, 230382 115942, 230565 115565) (230565 120575, 231060 120253, 233145 120251, 233520 120433, 233701 120674, 233837 121039, 233678 124205, 233355 124572, 232983 124759, 231046 124760, 230706 124576, 230384 124081, 230382 120952, 230565 120575) (230565 125585, 231060 125263, 232971 125262, 233288 125454, 233455 125684, 233591 126049, 233557 126751, 233178 129277, 232821 129610, 232481 129769, 231046 129770, 230706 129586, 230384 129091, 230382 125962, 230565 125585) (230568 130592, 231060 130273, 232375 130271, 232658 130501, 232804 130746, 232907 131132, 232564 133440, 232341 134317, 232016 134600, 231620 134728, 230916 134692, 230611 134530, 230382 134150, 230382 130972, 230568 130592)) +POLYGON ((95494 126805, 96503 133622, 98177 140305, 100476 146724, 103404 152913, 106933 158804, 111015 164309, 115613 169380, 120688 173982, 126196 178066, 132082 181592, 138275 184523, 144689 186820, 151369 188494, 158160 189502, 165000 189839, 171805 189505, 178630 188494, 185310 186820, 191724 184524, 197917 181592, 203803 178066, 209312 173982, 214386 169380, 218984 164310, 223066 158803, 226595 152913, 229523 146724, 231822 140305, 233496 133622, 234502 126839, 234839 119992, 234505 113189, 233494 106367, 231822 99694, 229523 93273, 226591 87078, 223066 81196, 218982 75688, 214380 70613, 209312 66017, 203803 61933, 197913 58404, 191724 55476, 185310 53179, 178630 51505, 171839 50497, 165000 50161, 158194 50494, 151369 51505, 144689 53179, 138275 55475, 132086 58404, 126196 61933, 120688 66017, 115613 70619, 111017 75688, 106933 81196, 103404 87086, 100477 93273, 98177 99694, 96503 106375, 95497 113155, 95161 120009, 95494 126805), (96691 120789, 96887 120703, 98972 120702, 99166 120992, 99166 124114, 98876 124308, 96967 124308, 96763 124059, 96609 120962, 96691 120789), (96759 115930, 96854 115769, 97010 115697, 98972 115692, 99166 115982, 99166 119104, 98876 119298, 96750 119298, 96613 119018, 96759 115930), (96932 125803, 97122 125714, 98972 125712, 99166 126002, 99166 129124, 98876 129318, 97454 129315, 97247 129098, 96890 126714, 96854 125972, 96932 125803), (96858 114008, 96890 113284, 97244 110899, 97354 110749, 97488 110687, 98972 110682, 99166 110972, 99166 114094, 98876 114288, 97090 114288, 96970 114241, 96858 114008), (97589 130826, 97798 130725, 98971 130722, 99166 130980, 99166 134134, 98907 134324, 98230 134286, 98073 134133, 97876 133350, 97527 131003, 97589 130826), (97877 106641, 98062 105900, 98230 105714, 99005 105700, 99107 105754, 99166 105897, 99166 109084, 98876 109278, 97718 109272, 97626 109219, 97534 108970, 97877 106641), (100570 98955, 100578 97146, 101040 95847, 101280 95650, 103981 95650, 104176 95908, 104176 99064, 103886 99258, 100761 99258, 100655 99173, 100570 98955), (100575 100863, 100636 100762, 100849 100663, 103982 100662, 104176 100952, 104176 104074, 103886 104268, 100760 104268, 100576 104019, 100575 100863), (100570 105916, 100633 105775, 100849 105673, 103982 105672, 104176 105962, 104176 109084, 103886 109278, 100764 109278, 100571 108999, 100570 105916), (100570 110876, 100849 110683, 103982 110682, 104176 110972, 104176 114094, 103886 114288, 100764 114288, 100571 114009, 100570 110876), (100570 115886, 100849 115693, 103982 115692, 104176 115982, 104176 119104, 103886 119298, 100764 119298, 100571 119019, 100570 115886), (100570 120896, 100849 120703, 103982 120702, 104176 120992, 104176 124114, 103886 124308, 100764 124308, 100571 124029, 100570 120896), (100570 125906, 100849 125713, 103982 125712, 104176 126002, 104176 129124, 103886 129318, 100764 129318, 100571 129039, 100570 125906), (100574 130928, 100632 130826, 100849 130723, 103981 130722, 104176 130980, 104176 134134, 103886 134328, 100764 134328, 100571 134049, 100574 130928), (100632 135836, 100849 135733, 103982 135732, 104176 136022, 104176 139144, 103886 139338, 100760 139338, 100575 139085, 100573 135945, 100632 135836), (100570 140891, 100849 140743, 103982 140742, 104176 141032, 104176 144155, 103883 144349, 101284 144349, 101055 144183, 100576 142857, 100570 140891), (101762 94096, 101717 93926, 103187 90811, 103352 90670, 104018 90669, 104117 90722, 104176 90865, 104176 94052, 103886 94246, 102040 94246, 101762 94096), (101768 146186, 101773 145954, 101866 145779, 103980 145751, 104176 146014, 104176 149172, 104052 149295, 103479 149359, 103204 149218, 101768 146186), (105580 86169, 105913 85710, 106074 85630, 108992 85630, 109186 85920, 109186 89042, 108896 89236, 105770 89236, 105587 88990, 105580 86169), (105580 90884, 105643 90743, 105859 90641, 108992 90640, 109186 90930, 109186 94052, 108896 94246, 105774 94246, 105581 93967, 105580 90884), (105584 95856, 105642 95754, 105859 95651, 108991 95650, 109186 95908, 109186 99064, 108896 99258, 105774 99258, 105581 98979, 105584 95856), (105580 100856, 105859 100663, 108992 100662, 109186 100952, 109186 104074, 108896 104268, 105774 104268, 105581 103989, 105580 100856), (105580 105866, 105859 105673, 108992 105672, 109186 105962, 109186 109084, 108896 109278, 105774 109278, 105581 108999, 105580 105866), (105580 110876, 105859 110683, 108992 110682, 109186 110972, 109186 114094, 108896 114288, 105774 114288, 105581 114009, 105580 110876), (105580 115886, 105859 115693, 108992 115692, 109186 115982, 109186 119104, 108896 119298, 105774 119298, 105581 119019, 105580 115886), (105580 120896, 105859 120703, 108992 120702, 109186 120992, 109186 124114, 108896 124308, 105774 124308, 105581 124029, 105580 120896), (105580 125906, 105859 125713, 108992 125712, 109186 126002, 109186 129124, 108896 129318, 105774 129318, 105581 129039, 105580 125906), (105642 130826, 105859 130723, 108991 130722, 109186 130980, 109186 134134, 108896 134328, 105774 134328, 105581 134049, 105584 130928, 105642 130826), (105580 135926, 105859 135733, 108992 135732, 109186 136022, 109186 139144, 108896 139338, 105774 139338, 105581 139059, 105580 135926), (105580 140936, 105859 140743, 108992 140742, 109186 141032, 109186 144155, 108896 144349, 105774 144349, 105581 144070, 105580 140936), (105584 145960, 105663 145840, 105859 145754, 108991 145753, 109186 146011, 109186 149165, 108896 149359, 105774 149359, 105581 149080, 105584 145960), (105582 150983, 105663 150850, 105859 150764, 108992 150763, 109186 151053, 109186 154175, 108896 154369, 106074 154369, 105922 154300, 105580 153841, 105582 150983), (106981 84045, 106964 83867, 108096 81974, 108677 81190, 108885 81115, 109106 81184, 109186 81345, 109186 84032, 108896 84226, 107276 84226, 106981 84045), (107023 155881, 107166 155776, 108992 155773, 109186 156063, 109184 158675, 109136 158774, 108814 158900, 108710 158847, 108090 158016, 107018 156228, 107023 155881), (110590 78898, 110631 78562, 112103 76572, 112917 75675, 113065 75610, 114007 75610, 114196 75900, 114196 79022, 113906 79216, 110828 79216, 110699 79159, 110590 78898), (110869 80621, 114002 80620, 114196 80910, 114196 84032, 113906 84226, 110784 84226, 110591 83947, 110590 80811, 110869 80621), (110590 85824, 110869 85631, 114002 85630, 114196 85920, 114196 89042, 113906 89236, 110784 89236, 110591 88957, 110590 85824), (110590 90834, 110869 90641, 114002 90640, 114196 90930, 114196 94052, 113906 94246, 110784 94246, 110591 93967, 110590 90834), (110652 95754, 110869 95651, 114001 95650, 114196 95908, 114196 99064, 113906 99258, 110784 99258, 110591 98979, 110594 95856, 110652 95754), (110590 100856, 110869 100663, 114002 100662, 114196 100952, 114196 104074, 113906 104268, 110784 104268, 110591 103989, 110590 100856), (110590 105866, 110869 105673, 114002 105672, 114196 105962, 114196 109084, 113906 109278, 110784 109278, 110591 108999, 110590 105866), (110590 110876, 110869 110683, 114002 110682, 114196 110972, 114196 114094, 113906 114288, 110784 114288, 110591 114009, 110590 110876), (110590 115886, 110869 115693, 114002 115692, 114196 115982, 114196 119104, 113906 119298, 110784 119298, 110591 119019, 110590 115886), (110590 120896, 110869 120703, 114002 120702, 114196 120992, 114196 124114, 113906 124308, 110784 124308, 110591 124029, 110590 120896), (110590 125906, 110869 125713, 114002 125712, 114196 126002, 114196 129124, 113906 129318, 110784 129318, 110591 129039, 110590 125906), (110594 130928, 110652 130826, 110869 130723, 114001 130722, 114196 130980, 114196 134134, 113906 134328, 110784 134328, 110591 134049, 110594 130928), (110590 135926, 110869 135733, 114002 135732, 114196 136022, 114196 139144, 113906 139338, 110784 139338, 110591 139059, 110590 135926), (110590 140936, 110869 140743, 114002 140742, 114196 141032, 114196 144155, 113906 144349, 110784 144349, 110591 144070, 110590 140936), (110594 145959, 110652 145857, 110869 145754, 114001 145753, 114196 146011, 114196 149165, 113906 149359, 110784 149359, 110591 149080, 110594 145959), (110590 150957, 110869 150764, 114002 150763, 114196 151053, 114196 154175, 113906 154369, 110784 154369, 110591 154090, 110590 150957), (110590 155967, 110869 155774, 114002 155773, 114196 156063, 114196 159185, 113906 159379, 110744 159379, 110596 159128, 110590 155967), (110652 160863, 110813 160783, 114002 160783, 114196 161073, 114196 164195, 113939 164389, 112980 164389, 112090 163412, 110649 161467, 110652 160863), (115600 72719, 116607 71604, 117658 70651, 117793 70600, 119017 70600, 119206 70890, 119206 74012, 118916 74206, 115794 74206, 115600 73949, 115600 72719), (115600 75804, 115879 75611, 119012 75610, 119206 75900, 119206 79022, 118916 79216, 115794 79216, 115601 78937, 115600 75804), (115600 80814, 115879 80621, 119012 80620, 119206 80910, 119206 84032, 118916 84226, 115794 84226, 115601 83947, 115600 80814), (115600 85824, 115879 85631, 119012 85630, 119206 85920, 119206 89042, 118916 89236, 115794 89236, 115601 88957, 115600 85824), (115600 90834, 115879 90641, 119012 90640, 119206 90930, 119206 94052, 118916 94246, 115794 94246, 115601 93967, 115600 90834), (115604 95856, 115662 95754, 115879 95651, 119011 95650, 119206 95908, 119206 99064, 118916 99258, 115794 99258, 115601 98979, 115604 95856), (115600 100856, 115879 100663, 119012 100662, 119206 100952, 119206 104074, 118916 104268, 115794 104268, 115601 103989, 115600 100856), (115600 105866, 115879 105673, 119012 105672, 119206 105962, 119206 109084, 118916 109278, 115794 109278, 115601 108999, 115600 105866), (115600 110876, 115879 110683, 119012 110682, 119206 110972, 119206 114094, 118916 114288, 115794 114288, 115601 114009, 115600 110876), (115879 115693, 119012 115692, 119206 115982, 119206 119104, 118916 119298, 115794 119298, 115601 119019, 115600 115886, 115879 115693), (115600 120896, 115879 120703, 119012 120702, 119206 120992, 119206 124114, 118916 124308, 115794 124308, 115601 124029, 115600 120896), (115600 125906, 115879 125713, 119012 125712, 119206 126002, 119206 129124, 118916 129318, 115794 129318, 115601 129039, 115600 125906), (115604 130928, 115662 130826, 115879 130723, 119011 130722, 119206 130980, 119206 134134, 118916 134328, 115794 134328, 115601 134049, 115604 130928), (115600 135926, 115879 135733, 119012 135732, 119206 136022, 119206 139144, 118916 139338, 115794 139338, 115601 139059, 115600 135926), (115600 140936, 115879 140743, 119012 140742, 119206 141032, 119206 144155, 118916 144349, 115794 144349, 115601 144070, 115600 140936), (115604 145959, 115662 145857, 115879 145754, 119011 145753, 119206 146011, 119206 149165, 118916 149359, 115794 149359, 115601 149080, 115604 145959), (115600 150957, 115879 150764, 119012 150763, 119206 151053, 119206 154175, 118916 154369, 115794 154369, 115601 154090, 115600 150957), (115600 155967, 115879 155774, 119012 155773, 119206 156063, 119206 159185, 118916 159379, 115794 159379, 115601 159100, 115600 155967), (115600 160977, 115879 160784, 119012 160783, 119206 161073, 119206 164195, 118916 164389, 115794 164389, 115601 164110, 115600 160977), (115600 165982, 115879 165794, 119012 165793, 119206 166083, 119206 169205, 118949 169399, 117719 169399, 116604 168392, 115651 167341, 115600 167206, 115600 165982), (120610 67980, 121588 67089, 123592 65605, 124136 65652, 124216 65813, 124216 69002, 123926 69196, 120804 69196, 120610 68939, 120610 67980), (120610 70794, 120889 70601, 124022 70600, 124216 70890, 124216 74012, 123926 74206, 120804 74206, 120611 73927, 120610 70794), (120610 75804, 120889 75611, 124022 75610, 124216 75900, 124216 79022, 123926 79216, 120804 79216, 120611 78937, 120610 75804), (120610 80814, 120889 80621, 124022 80620, 124216 80910, 124216 84032, 123926 84226, 120804 84226, 120611 83947, 120610 80814), (120610 85824, 120889 85631, 124022 85630, 124216 85920, 124216 89042, 123926 89236, 120804 89236, 120611 88957, 120610 85824), (120610 90834, 120889 90641, 124022 90640, 124216 90930, 124216 94052, 123926 94246, 120804 94246, 120611 93967, 120610 90834), (120614 95856, 120672 95754, 120889 95651, 124021 95650, 124216 95908, 124216 99064, 123926 99258, 120804 99258, 120611 98979, 120614 95856), (120610 100856, 120889 100663, 124022 100662, 124216 100952, 124216 104074, 123926 104268, 120804 104268, 120611 103989, 120610 100856), (120610 105866, 120889 105673, 124022 105672, 124216 105962, 124216 109084, 123926 109278, 120804 109278, 120611 108999, 120610 105866), (120610 110876, 120889 110683, 124022 110682, 124216 110972, 124216 114094, 123926 114288, 120804 114288, 120611 114009, 120610 110876), (120610 115886, 120889 115693, 124022 115692, 124216 115982, 124216 119104, 123926 119298, 120804 119298, 120611 119019, 120610 115886), (120610 120896, 120889 120703, 124022 120702, 124216 120992, 124216 124114, 123926 124308, 120804 124308, 120611 124029, 120610 120896), (120610 125906, 120889 125713, 124022 125712, 124216 126002, 124216 129124, 123926 129318, 120804 129318, 120611 129039, 120610 125906), (120614 130928, 120672 130826, 120889 130723, 124021 130722, 124216 130980, 124216 134134, 123926 134328, 120804 134328, 120611 134049, 120614 130928), (120610 135926, 120889 135733, 124022 135732, 124216 136022, 124216 139144, 123926 139338, 120804 139338, 120611 139059, 120610 135926), (120610 140936, 120889 140743, 124022 140742, 124216 141032, 124216 144155, 123926 144349, 120804 144349, 120611 144070, 120610 140936), (120614 145959, 120672 145857, 120889 145754, 124021 145753, 124216 146011, 124216 149165, 123926 149359, 120804 149359, 120611 149080, 120614 145959), (120610 150957, 120889 150764, 124022 150763, 124216 151053, 124216 154175, 123926 154369, 120804 154369, 120611 154090, 120610 150957), (120610 155967, 120889 155774, 124022 155773, 124216 156063, 124216 159185, 123926 159379, 120804 159379, 120611 159100, 120610 155967), (120610 160977, 120889 160784, 124022 160783, 124216 161073, 124216 164195, 123926 164389, 120804 164389, 120611 164110, 120610 160977), (120610 165987, 120889 165794, 124022 165793, 124216 166083, 124216 169205, 123926 169399, 120804 169399, 120611 169120, 120610 165987), (120610 170992, 120889 170804, 124022 170803, 124216 171093, 124216 174171, 124159 174300, 123898 174409, 123562 174368, 121571 172895, 120675 172082, 120610 171934, 120610 170992), (125620 65744, 125871 65596, 129032 65590, 129226 65880, 129226 69002, 128936 69196, 125814 69196, 125621 68917, 125620 65744), (125899 70601, 129032 70600, 129226 70890, 129226 74012, 128936 74206, 125814 74206, 125621 73927, 125620 70794, 125899 70601), (125620 75804, 125899 75611, 129032 75610, 129226 75900, 129226 79022, 128936 79216, 125814 79216, 125621 78937, 125620 75804), (125620 80814, 125899 80621, 129032 80620, 129226 80910, 129226 84032, 128936 84226, 125814 84226, 125621 83947, 125620 80814), (125620 85824, 125899 85631, 129032 85630, 129226 85920, 129226 89042, 128936 89236, 125814 89236, 125621 88957, 125620 85824), (125620 90834, 125899 90641, 129032 90640, 129226 90930, 129226 94052, 128936 94246, 125814 94246, 125621 93967, 125620 90834), (125624 95856, 125682 95754, 125899 95651, 129031 95650, 129226 95908, 129226 99064, 128936 99258, 125814 99258, 125621 98979, 125624 95856), (125620 100856, 125899 100663, 129032 100662, 129226 100952, 129226 104074, 128936 104268, 125814 104268, 125621 103989, 125620 100856), (125620 105866, 125899 105673, 129032 105672, 129226 105962, 129226 109084, 128936 109278, 125814 109278, 125621 108999, 125620 105866), (125620 110876, 125899 110683, 129032 110682, 129226 110972, 129226 114094, 128936 114288, 125814 114288, 125621 114009, 125620 110876), (125620 115886, 125899 115693, 129032 115692, 129226 115982, 129226 119104, 128936 119298, 125814 119298, 125621 119019, 125620 115886), (125620 120896, 125899 120703, 129032 120702, 129226 120992, 129226 124114, 128936 124308, 125814 124308, 125621 124029, 125620 120896), (125620 125906, 125899 125713, 129032 125712, 129226 126002, 129226 129124, 128936 129318, 125814 129318, 125621 129039, 125620 125906), (125624 130928, 125682 130826, 125899 130723, 129031 130722, 129226 130980, 129226 134134, 128936 134328, 125814 134328, 125621 134049, 125624 130928), (125620 135926, 125899 135733, 129032 135732, 129226 136022, 129226 139144, 128936 139338, 125814 139338, 125621 139059, 125620 135926), (125899 140743, 129032 140742, 129226 141032, 129226 144155, 128936 144349, 125814 144349, 125621 144070, 125620 140936, 125899 140743), (125624 145959, 125682 145857, 125899 145754, 129031 145753, 129226 146011, 129226 149165, 128936 149359, 125814 149359, 125621 149080, 125624 145959), (125620 150957, 125899 150764, 129032 150763, 129226 151053, 129226 154175, 128936 154369, 125814 154369, 125621 154090, 125620 150957), (125620 155967, 125899 155774, 129032 155773, 129226 156063, 129226 159185, 128936 159379, 125814 159379, 125621 159100, 125620 155967), (125620 160977, 125899 160784, 129032 160783, 129226 161073, 129226 164195, 128936 164389, 125814 164389, 125621 164110, 125620 160977), (125899 165794, 129032 165793, 129226 166083, 129226 169205, 128936 169399, 125814 169399, 125621 169120, 125620 165987, 125899 165794), (125620 170997, 125899 170804, 129032 170803, 129226 171093, 129226 174215, 128936 174409, 125870 174410, 125745 174367, 125621 174130, 125620 170997), (126099 63814, 126152 63710, 126983 63090, 128771 62018, 129118 62023, 129226 62201, 129226 63992, 128936 64186, 126291 64186, 126188 64091, 126099 63814), (126115 176114, 126184 175893, 126310 175816, 129032 175813, 129226 176103, 129224 177758, 129045 178018, 128867 178035, 126972 176902, 126190 176322, 126115 176114), (130699 60922, 131158 60580, 134016 60582, 134132 60642, 134236 60870, 134236 63992, 133946 64186, 130824 64186, 130631 63907, 130630 61074, 130699 60922), (130630 65784, 130909 65591, 134042 65590, 134236 65880, 134236 69002, 133946 69196, 130824 69196, 130631 68917, 130630 65784), (130630 70794, 130909 70601, 134042 70600, 134236 70890, 134236 74012, 133946 74206, 130824 74206, 130631 73927, 130630 70794), (130630 75804, 130909 75611, 134042 75610, 134236 75900, 134236 79022, 133946 79216, 130824 79216, 130631 78937, 130630 75804), (130630 80814, 130909 80621, 134042 80620, 134236 80910, 134236 84032, 133946 84226, 130824 84226, 130631 83947, 130630 80814), (130630 85824, 130909 85631, 134042 85630, 134236 85920, 134236 89042, 133946 89236, 130824 89236, 130631 88957, 130630 85824), (130630 90834, 130909 90641, 134042 90640, 134236 90930, 134236 94052, 133946 94246, 130824 94246, 130631 93967, 130630 90834), (130634 95856, 130692 95754, 130909 95651, 134041 95650, 134236 95908, 134236 99064, 133946 99258, 130824 99258, 130631 98979, 130634 95856), (130630 100856, 130909 100663, 134042 100662, 134236 100952, 134236 104074, 133946 104268, 130824 104268, 130631 103989, 130630 100856), (130630 105866, 130909 105673, 134042 105672, 134236 105962, 134236 109084, 133946 109278, 130824 109278, 130631 108999, 130630 105866), (130630 110876, 130909 110683, 134042 110682, 134236 110972, 134236 114094, 133946 114288, 130824 114288, 130631 114009, 130630 110876), (130630 115886, 130909 115693, 134042 115692, 134236 115982, 134236 119104, 133946 119298, 130824 119298, 130631 119019, 130630 115886), (130630 120896, 130909 120703, 134042 120702, 134236 120992, 134236 124114, 133946 124308, 130824 124308, 130631 124029, 130630 120896), (130909 125713, 134042 125712, 134236 126002, 134236 129124, 133946 129318, 130824 129318, 130631 129039, 130630 125906, 130909 125713), (130634 130928, 130692 130826, 130909 130723, 134041 130722, 134236 130980, 134236 134134, 133946 134328, 130824 134328, 130631 134049, 130634 130928), (130630 135926, 130909 135733, 134042 135732, 134236 136022, 134236 139144, 133946 139338, 130824 139338, 130631 139059, 130630 135926), (130630 140936, 130909 140743, 134042 140742, 134236 141032, 134236 144155, 133946 144349, 130824 144349, 130631 144070, 130630 140936), (130634 145959, 130692 145857, 130909 145754, 134041 145753, 134236 146011, 134236 149165, 133946 149359, 130824 149359, 130631 149080, 130634 145959), (130630 150957, 130909 150764, 134042 150763, 134236 151053, 134236 154175, 133946 154369, 130824 154369, 130631 154090, 130630 150957), (130630 155967, 130909 155774, 134042 155773, 134236 156063, 134236 159185, 133946 159379, 130824 159379, 130631 159100, 130630 155967), (130630 160977, 130909 160784, 134042 160783, 134236 161073, 134236 164195, 133946 164389, 130824 164389, 130631 164110, 130630 160977), (130630 165987, 130909 165794, 134042 165793, 134236 166083, 134236 169205, 133946 169399, 130824 169399, 130631 169120, 130630 165987), (130630 170997, 130909 170804, 134042 170803, 134236 171093, 134236 174215, 133946 174409, 130824 174409, 130631 174130, 130630 170997), (130630 176007, 130909 175814, 134042 175813, 134236 176103, 134236 179229, 133990 179412, 131169 179419, 130710 179086, 130630 178925, 130630 176007), (135781 58204, 138834 56761, 139067 56766, 139202 56838, 139246 56965, 139246 58982, 138956 59176, 135834 59176, 135704 59052, 135640 58479, 135781 58204), (135640 60774, 135919 60581, 139052 60580, 139246 60870, 139246 63992, 138956 64186, 135834 64186, 135641 63907, 135640 60774), (135640 65784, 135919 65591, 139052 65590, 139246 65880, 139246 69002, 138956 69196, 135834 69196, 135641 68917, 135640 65784), (135640 70794, 135919 70601, 139052 70600, 139246 70890, 139246 74012, 138956 74206, 135834 74206, 135641 73927, 135640 70794), (135640 75804, 135919 75611, 139052 75610, 139246 75900, 139246 79022, 138956 79216, 135834 79216, 135641 78937, 135640 75804), (135640 80814, 135919 80621, 139052 80620, 139246 80910, 139246 84032, 138956 84226, 135834 84226, 135641 83947, 135640 80814), (135640 85824, 135919 85631, 139052 85630, 139246 85920, 139246 89042, 138956 89236, 135834 89236, 135641 88957, 135640 85824), (135640 90834, 135919 90641, 139052 90640, 139246 90930, 139246 94052, 138956 94246, 135834 94246, 135641 93967, 135640 90834), (135644 95856, 135702 95754, 135919 95651, 139051 95650, 139246 95908, 139246 99064, 138956 99258, 135834 99258, 135641 98979, 135644 95856), (135640 100856, 135919 100663, 139052 100662, 139246 100952, 139246 104074, 138956 104268, 135834 104268, 135641 103989, 135640 100856), (135640 105866, 135919 105673, 139052 105672, 139246 105962, 139246 109084, 138956 109278, 135834 109278, 135641 108999, 135640 105866), (135640 110876, 135919 110683, 139052 110682, 139246 110972, 139246 114094, 138956 114288, 135834 114288, 135641 114009, 135640 110876), (135640 115886, 135919 115693, 139052 115692, 139246 115982, 139246 119104, 138956 119298, 135834 119298, 135641 119019, 135640 115886), (135640 120896, 135919 120703, 139052 120702, 139246 120992, 139246 124114, 138956 124308, 135834 124308, 135641 124029, 135640 120896), (135640 125906, 135919 125713, 139052 125712, 139246 126002, 139246 129124, 138956 129318, 135834 129318, 135641 129039, 135640 125906), (135702 130826, 135919 130723, 139051 130722, 139246 130980, 139246 134134, 138956 134328, 135834 134328, 135641 134049, 135644 130928, 135702 130826), (135640 135926, 135919 135733, 139052 135732, 139246 136022, 139246 139144, 138956 139338, 135834 139338, 135641 139059, 135640 135926), (135640 140936, 135919 140743, 139052 140742, 139246 141032, 139246 144155, 138956 144349, 135834 144349, 135641 144070, 135640 140936), (135644 145959, 135702 145857, 135919 145754, 139051 145753, 139246 146011, 139246 149165, 138956 149359, 135834 149359, 135641 149080, 135644 145959), (135640 150957, 135919 150764, 139052 150763, 139246 151053, 139246 154175, 138956 154369, 135834 154369, 135641 154090, 135640 150957), (135640 155967, 135919 155774, 139052 155773, 139246 156063, 139246 159185, 138956 159379, 135834 159379, 135641 159100, 135640 155967), (135640 160977, 135919 160784, 139052 160783, 139246 161073, 139246 164195, 138956 164389, 135834 164389, 135641 164110, 135640 160977), (135640 165987, 135919 165794, 139052 165793, 139246 166083, 139246 169205, 138956 169399, 135834 169399, 135641 169120, 135640 165987), (135640 170997, 135919 170804, 139052 170803, 139246 171093, 139246 174215, 138956 174409, 135834 174409, 135641 174130, 135640 170997), (135919 175814, 139052 175813, 139246 176103, 139246 179225, 138956 179419, 135884 179419, 135743 179356, 135641 179140, 135640 176007, 135919 175814), (135669 180980, 135722 180882, 135865 180823, 139052 180823, 139246 181113, 139244 182994, 139096 183237, 138926 183282, 135811 181812, 135670 181647, 135669 180980), (140650 56278, 140816 56055, 142142 55576, 144110 55570, 144258 55860, 144258 58982, 143968 59176, 140844 59176, 140651 58897, 140650 56278), (140650 60774, 140929 60581, 144064 60580, 144258 60870, 144258 63992, 143968 64186, 140844 64186, 140651 63907, 140650 60774), (140650 65784, 140929 65591, 144064 65590, 144258 65880, 144258 69002, 143968 69196, 140844 69196, 140651 68917, 140650 65784), (140650 70794, 140929 70601, 144064 70600, 144258 70890, 144258 74012, 143968 74206, 140844 74206, 140651 73927, 140650 70794), (140650 75804, 140929 75611, 144064 75610, 144258 75900, 144258 79022, 143968 79216, 140844 79216, 140651 78937, 140650 75804), (140650 80814, 140929 80621, 144064 80620, 144258 80910, 144258 84032, 143968 84226, 140844 84226, 140651 83947, 140650 80814), (140650 85824, 140929 85631, 144064 85630, 144258 85920, 144258 89042, 143968 89236, 140844 89236, 140651 88957, 140650 85824), (140650 90834, 140929 90641, 144064 90640, 144258 90930, 144258 94052, 143968 94246, 140844 94246, 140651 93967, 140650 90834), (140654 95856, 140712 95754, 140929 95651, 144063 95650, 144258 95908, 144258 99064, 143968 99258, 140844 99258, 140651 98979, 140654 95856), (140650 100856, 140929 100663, 144064 100662, 144258 100952, 144258 104074, 143968 104268, 140844 104268, 140651 103989, 140650 100856), (140650 105866, 140929 105673, 144064 105672, 144258 105962, 144258 109084, 143968 109278, 140844 109278, 140651 108999, 140650 105866), (140650 110876, 140929 110683, 144064 110682, 144258 110972, 144258 114094, 143968 114288, 140844 114288, 140651 114009, 140650 110876), (140650 115886, 140929 115693, 144064 115692, 144258 115982, 144258 119104, 143968 119298, 140844 119298, 140651 119019, 140650 115886), (140650 120896, 140929 120703, 144064 120702, 144258 120992, 144258 124114, 143968 124308, 140844 124308, 140651 124029, 140650 120896), (140650 125906, 140929 125713, 144064 125712, 144258 126002, 144258 129124, 143968 129318, 140844 129318, 140651 129039, 140650 125906), (140712 130826, 140929 130723, 144063 130722, 144258 130980, 144258 134134, 143968 134328, 140844 134328, 140651 134049, 140654 130928, 140712 130826), (140650 135926, 140929 135733, 144064 135732, 144258 136022, 144258 139144, 143968 139338, 140844 139338, 140651 139059, 140650 135926), (140650 140936, 140929 140743, 144064 140742, 144258 141032, 144258 144155, 143968 144349, 140844 144349, 140651 144070, 140650 140936), (140654 145959, 140712 145857, 140929 145754, 144063 145753, 144258 146011, 144258 149165, 143968 149359, 140844 149359, 140651 149080, 140654 145959), (140929 150764, 144064 150763, 144258 151053, 144258 154175, 143968 154369, 140844 154369, 140651 154090, 140650 150957, 140929 150764), (140650 155967, 140929 155774, 144064 155773, 144258 156063, 144258 159185, 143968 159379, 140844 159379, 140651 159100, 140650 155967), (140650 160977, 140929 160784, 144064 160783, 144258 161073, 144258 164195, 143968 164389, 140844 164389, 140651 164110, 140650 160977), (140650 165987, 140929 165794, 144064 165793, 144258 166083, 144258 169205, 143968 169399, 140844 169399, 140651 169120, 140650 165987), (140650 170997, 140929 170804, 144064 170803, 144258 171093, 144258 174215, 143968 174409, 140844 174409, 140651 174130, 140650 170997), (140650 176007, 140929 175814, 144064 175813, 144258 176103, 144258 179225, 143968 179419, 140844 179419, 140651 179140, 140650 176007), (140650 181017, 140929 180824, 144064 180823, 144258 181113, 144258 184191, 144201 184321, 143955 184429, 142146 184421, 140847 183959, 140650 183719, 140650 181017), (145662 55764, 145915 55575, 149055 55573, 149164 55632, 149268 55860, 149268 58982, 148978 59176, 145856 59176, 145663 58897, 145662 55764), (145662 60774, 145941 60581, 149074 60580, 149268 60870, 149268 63992, 148978 64186, 145856 64186, 145663 63907, 145662 60774), (145662 65784, 145941 65591, 149074 65590, 149268 65880, 149268 69002, 148978 69196, 145856 69196, 145663 68917, 145662 65784), (145662 70794, 145941 70601, 149074 70600, 149268 70890, 149268 74012, 148978 74206, 145856 74206, 145663 73927, 145662 70794), (145941 75611, 149074 75610, 149268 75900, 149268 79022, 148978 79216, 145856 79216, 145663 78937, 145662 75804, 145941 75611), (145662 80814, 145941 80621, 149074 80620, 149268 80910, 149268 84032, 148978 84226, 145856 84226, 145663 83947, 145662 80814), (145941 85631, 149074 85630, 149268 85920, 149268 89042, 148978 89236, 145856 89236, 145663 88957, 145662 85824, 145941 85631), (145662 90834, 145941 90641, 149074 90640, 149268 90930, 149268 94052, 148978 94246, 145856 94246, 145663 93967, 145662 90834), (145666 95856, 145724 95754, 145941 95651, 149073 95650, 149268 95908, 149268 99064, 148978 99258, 145856 99258, 145663 98979, 145666 95856), (145662 100856, 145941 100663, 149074 100662, 149268 100952, 149268 104074, 148978 104268, 145856 104268, 145663 103989, 145662 100856), (145662 105866, 145941 105673, 149074 105672, 149268 105962, 149268 109084, 148978 109278, 145856 109278, 145663 108999, 145662 105866), (145662 110876, 145941 110683, 149074 110682, 149268 110972, 149268 114094, 148978 114288, 145856 114288, 145663 114009, 145662 110876), (145662 115886, 145941 115693, 149074 115692, 149268 115982, 149268 119104, 148978 119298, 145856 119298, 145663 119019, 145662 115886), (145662 120896, 145941 120703, 149074 120702, 149268 120992, 149268 124114, 148978 124308, 145856 124308, 145663 124029, 145662 120896), (145662 125906, 145941 125713, 149074 125712, 149268 126002, 149268 129124, 148978 129318, 145856 129318, 145663 129039, 145662 125906), (145666 130928, 145724 130826, 145941 130723, 149073 130722, 149268 130980, 149268 134134, 148978 134328, 145856 134328, 145663 134049, 145666 130928), (145662 135926, 145941 135733, 149074 135732, 149268 136022, 149268 139144, 148978 139338, 145856 139338, 145663 139059, 145662 135926), (145662 140936, 145941 140743, 149074 140742, 149268 141032, 149268 144155, 148978 144349, 145856 144349, 145663 144070, 145662 140936), (145666 145959, 145724 145857, 145941 145754, 149073 145753, 149268 146011, 149268 149165, 148978 149359, 145856 149359, 145663 149080, 145666 145959), (145662 150957, 145941 150764, 149074 150763, 149268 151053, 149268 154175, 148978 154369, 145856 154369, 145663 154090, 145662 150957), (145662 155967, 145941 155774, 149074 155773, 149268 156063, 149268 159185, 148978 159379, 145856 159379, 145663 159100, 145662 155967), (145662 160977, 145941 160784, 149074 160783, 149268 161073, 149268 164195, 148978 164389, 145856 164389, 145663 164110, 145662 160977), (145662 165987, 145941 165794, 149074 165793, 149268 166083, 149268 169205, 148978 169399, 145856 169399, 145663 169120, 145662 165987), (145662 170997, 145941 170804, 149074 170803, 149268 171093, 149268 174215, 148978 174409, 145856 174409, 145663 174130, 145662 170997), (145662 176007, 145941 175814, 149074 175813, 149268 176103, 149268 179225, 148978 179419, 145856 179419, 145663 179140, 145662 176007), (145662 181017, 145941 180824, 149074 180823, 149268 181113, 149268 184239, 149004 184430, 145863 184424, 145762 184363, 145663 184150, 145662 181017), (150714 53230, 150867 53073, 151640 52877, 153997 52527, 154174 52589, 154278 52784, 154278 53972, 153988 54166, 150866 54166, 150676 53907, 150714 53230), (150672 55764, 150951 55571, 154084 55570, 154278 55860, 154278 58982, 153988 59176, 150866 59176, 150673 58897, 150672 55764), (150672 60774, 150951 60581, 154084 60580, 154278 60870, 154278 63992, 153988 64186, 150866 64186, 150673 63907, 150672 60774), (150672 65784, 150951 65591, 154084 65590, 154278 65880, 154278 69002, 153988 69196, 150866 69196, 150673 68917, 150672 65784), (150672 70794, 150951 70601, 154084 70600, 154278 70890, 154278 74012, 153988 74206, 150866 74206, 150673 73927, 150672 70794), (150672 75804, 150951 75611, 154084 75610, 154278 75900, 154278 79022, 153988 79216, 150866 79216, 150673 78937, 150672 75804), (150672 80814, 150951 80621, 154084 80620, 154278 80910, 154278 84032, 153988 84226, 150866 84226, 150673 83947, 150672 80814), (150672 85824, 150951 85631, 154084 85630, 154278 85920, 154278 89042, 153988 89236, 150866 89236, 150673 88957, 150672 85824), (150672 90834, 150951 90641, 154084 90640, 154278 90930, 154278 94052, 153988 94246, 150866 94246, 150673 93967, 150672 90834), (150676 95856, 150734 95754, 150951 95651, 154083 95650, 154278 95908, 154278 99064, 153988 99258, 150866 99258, 150673 98979, 150676 95856), (150672 100856, 150951 100663, 154084 100662, 154278 100952, 154278 104074, 153988 104268, 150866 104268, 150673 103989, 150672 100856), (150672 105866, 150951 105673, 154084 105672, 154278 105962, 154278 109084, 153988 109278, 150866 109278, 150673 108999, 150672 105866), (150672 110876, 150951 110683, 154084 110682, 154278 110972, 154278 114094, 153988 114288, 150866 114288, 150673 114009, 150672 110876), (150672 115886, 150951 115693, 154084 115692, 154278 115982, 154278 119104, 153988 119298, 150866 119298, 150673 119019, 150672 115886), (150672 120896, 150951 120703, 154084 120702, 154278 120992, 154278 124114, 153988 124308, 150866 124308, 150673 124029, 150672 120896), (150672 125906, 150951 125713, 154084 125712, 154278 126002, 154278 129124, 153988 129318, 150866 129318, 150673 129039, 150672 125906), (150676 130928, 150734 130826, 150951 130723, 154083 130722, 154278 130980, 154278 134134, 153988 134328, 150866 134328, 150673 134049, 150676 130928), (150672 135926, 150951 135733, 154084 135732, 154278 136022, 154278 139144, 153988 139338, 150866 139338, 150673 139059, 150672 135926), (150672 140936, 150951 140743, 154084 140742, 154278 141032, 154278 144155, 153988 144349, 150866 144349, 150673 144070, 150672 140936), (150734 145857, 150951 145754, 154083 145753, 154278 146011, 154278 149165, 153988 149359, 150866 149359, 150673 149080, 150676 145959, 150734 145857), (150672 150957, 150951 150764, 154084 150763, 154278 151053, 154278 154175, 153988 154369, 150866 154369, 150673 154090, 150672 150957), (150672 155967, 150951 155774, 154084 155773, 154278 156063, 154278 159185, 153988 159379, 150866 159379, 150673 159100, 150672 155967), (150672 160977, 150951 160784, 154084 160783, 154278 161073, 154278 164195, 153988 164389, 150866 164389, 150673 164110, 150672 160977), (150672 165987, 150951 165794, 154084 165793, 154278 166083, 154278 169205, 153988 169399, 150866 169399, 150673 169120, 150672 165987), (150672 170997, 150951 170804, 154084 170803, 154278 171093, 154278 174215, 153988 174409, 150866 174409, 150673 174130, 150672 170997), (150951 175814, 154084 175813, 154278 176103, 154278 179225, 153988 179419, 150866 179419, 150673 179140, 150672 176007, 150951 175814), (150672 181017, 150951 180824, 154084 180823, 154278 181113, 154278 184235, 153988 184429, 150916 184429, 150775 184366, 150673 184150, 150672 181017), (150700 185994, 150754 185892, 150897 185833, 154084 185833, 154278 186123, 154276 187265, 154219 187373, 153970 187465, 151640 187122, 150900 186937, 150714 186769, 150700 185994), (155685 52454, 155902 52247, 158285 51890, 159028 51854, 159197 51932, 159286 52123, 159288 53972, 158998 54166, 155876 54166, 155683 53887, 155685 52454), (155682 55764, 155961 55571, 159094 55570, 159288 55860, 159288 58982, 158998 59176, 155876 59176, 155683 58897, 155682 55764), (155682 60774, 155961 60581, 159094 60580, 159288 60870, 159288 63992, 158998 64186, 155876 64186, 155683 63907, 155682 60774), (155682 65784, 155961 65591, 159094 65590, 159288 65880, 159288 69002, 158998 69196, 155876 69196, 155683 68917, 155682 65784), (155682 70794, 155961 70601, 159094 70600, 159288 70890, 159288 74012, 158998 74206, 155876 74206, 155683 73927, 155682 70794), (155682 75804, 155961 75611, 159094 75610, 159288 75900, 159288 79022, 158998 79216, 155876 79216, 155683 78937, 155682 75804), (155682 80814, 155961 80621, 159094 80620, 159288 80910, 159288 84032, 158998 84226, 155876 84226, 155683 83947, 155682 80814), (155682 85824, 155961 85631, 159094 85630, 159288 85920, 159288 89042, 158998 89236, 155876 89236, 155683 88957, 155682 85824), (155961 90641, 159094 90640, 159288 90930, 159288 94052, 158998 94246, 155876 94246, 155683 93967, 155682 90834, 155961 90641), (155686 95856, 155744 95754, 155961 95651, 159093 95650, 159288 95908, 159288 99064, 158998 99258, 155876 99258, 155683 98979, 155686 95856), (155961 100663, 159094 100662, 159288 100952, 159288 104074, 158998 104268, 155876 104268, 155683 103989, 155682 100856, 155961 100663), (155682 105866, 155961 105673, 159094 105672, 159288 105962, 159288 109084, 158998 109278, 155876 109278, 155683 108999, 155682 105866), (155682 110876, 155961 110683, 159094 110682, 159288 110972, 159288 114094, 158998 114288, 155876 114288, 155683 114009, 155682 110876), (155682 115886, 155961 115693, 159094 115692, 159288 115982, 159288 119104, 158998 119298, 155876 119298, 155683 119019, 155682 115886), (155682 120896, 155961 120703, 159094 120702, 159288 120992, 159288 124114, 158998 124308, 155876 124308, 155683 124029, 155682 120896), (155682 125906, 155961 125713, 159094 125712, 159288 126002, 159288 129124, 158998 129318, 155876 129318, 155683 129039, 155682 125906), (155686 130928, 155744 130826, 155961 130723, 159093 130722, 159288 130980, 159288 134134, 158998 134328, 155876 134328, 155683 134049, 155686 130928), (155682 135926, 155961 135733, 159094 135732, 159288 136022, 159288 139144, 158998 139338, 155876 139338, 155683 139059, 155682 135926), (155682 140936, 155961 140743, 159094 140742, 159288 141032, 159288 144155, 158998 144349, 155876 144349, 155683 144070, 155682 140936), (155686 145959, 155744 145857, 155961 145754, 159093 145753, 159288 146011, 159288 149165, 158998 149359, 155876 149359, 155683 149080, 155686 145959), (155682 150957, 155961 150764, 159094 150763, 159288 151053, 159288 154175, 158998 154369, 155876 154369, 155683 154090, 155682 150957), (155682 155967, 155961 155774, 159094 155773, 159288 156063, 159288 159185, 158998 159379, 155876 159379, 155683 159100, 155682 155967), (155682 160977, 155961 160784, 159094 160783, 159288 161073, 159288 164195, 158998 164389, 155876 164389, 155683 164110, 155682 160977), (155682 165987, 155961 165794, 159094 165793, 159288 166083, 159288 169205, 158998 169399, 155876 169399, 155683 169120, 155682 165987), (155682 170997, 155961 170804, 159094 170803, 159288 171093, 159288 174215, 158998 174409, 155876 174409, 155683 174130, 155682 170997), (155682 176007, 155961 175814, 159094 175813, 159288 176103, 159288 179225, 158998 179419, 155876 179419, 155683 179140, 155682 176007), (155682 181017, 155961 180824, 159094 180823, 159288 181113, 159288 184235, 158998 184429, 155876 184429, 155683 184150, 155682 181017), (155682 186027, 155961 185834, 159094 185833, 159288 186123, 159288 187943, 159241 188029, 159008 188141, 158285 188109, 155899 187755, 155749 187645, 155688 187510, 155682 186027), (160692 51969, 160941 51763, 164038 51608, 164211 51690, 164298 51897, 164298 53972, 164008 54166, 160886 54166, 160693 53887, 160692 51969), (160692 55764, 160971 55571, 164104 55570, 164298 55860, 164298 58982, 164008 59176, 160886 59176, 160693 58897, 160692 55764), (160692 60774, 160971 60581, 164104 60580, 164298 60870, 164298 63992, 164008 64186, 160886 64186, 160693 63907, 160692 60774), (160692 65784, 160971 65591, 164104 65590, 164298 65880, 164298 69002, 164008 69196, 160886 69196, 160693 68917, 160692 65784), (160692 70794, 160971 70601, 164104 70600, 164298 70890, 164298 74012, 164008 74206, 160886 74206, 160693 73927, 160692 70794), (160692 75804, 160971 75611, 164104 75610, 164298 75900, 164298 79022, 164008 79216, 160886 79216, 160693 78937, 160692 75804), (160692 80814, 160971 80621, 164104 80620, 164298 80910, 164298 84032, 164008 84226, 160886 84226, 160693 83947, 160692 80814), (160692 85824, 160971 85631, 164104 85630, 164298 85920, 164298 89042, 164008 89236, 160886 89236, 160693 88957, 160692 85824), (160692 90834, 160971 90641, 164104 90640, 164298 90930, 164298 94052, 164008 94246, 160886 94246, 160693 93967, 160692 90834), (160754 95754, 160971 95651, 164103 95650, 164298 95908, 164298 99064, 164008 99258, 160886 99258, 160693 98979, 160696 95856, 160754 95754), (160692 100856, 160971 100663, 164104 100662, 164298 100952, 164298 104074, 164008 104268, 160886 104268, 160693 103989, 160692 100856), (160692 105866, 160971 105673, 164104 105672, 164298 105962, 164298 109084, 164008 109278, 160886 109278, 160693 108999, 160692 105866), (160692 110876, 160971 110683, 164104 110682, 164298 110972, 164298 114094, 164008 114288, 160886 114288, 160693 114009, 160692 110876), (160692 115886, 160971 115693, 164104 115692, 164298 115982, 164298 119104, 164008 119298, 160886 119298, 160693 119019, 160692 115886), (160692 120896, 160971 120703, 164104 120702, 164298 120992, 164298 124114, 164008 124308, 160886 124308, 160693 124029, 160692 120896), (160692 125906, 160971 125713, 164104 125712, 164298 126002, 164298 129124, 164008 129318, 160886 129318, 160693 129039, 160692 125906), (160696 130928, 160754 130826, 160971 130723, 164103 130722, 164298 130980, 164298 134134, 164008 134328, 160886 134328, 160693 134049, 160696 130928), (160692 135926, 160971 135733, 164104 135732, 164298 136022, 164298 139144, 164008 139338, 160886 139338, 160693 139059, 160692 135926), (160692 140936, 160971 140743, 164104 140742, 164298 141032, 164298 144155, 164008 144349, 160886 144349, 160693 144070, 160692 140936), (160754 145857, 160971 145754, 164103 145753, 164298 146011, 164298 149165, 164008 149359, 160886 149359, 160693 149080, 160696 145959, 160754 145857), (160692 150957, 160971 150764, 164104 150763, 164298 151053, 164298 154175, 164008 154369, 160886 154369, 160693 154090, 160692 150957), (160692 155967, 160971 155774, 164104 155773, 164298 156063, 164298 159185, 164008 159379, 160886 159379, 160693 159100, 160692 155967), (160692 160977, 160971 160784, 164104 160783, 164298 161073, 164298 164195, 164008 164389, 160886 164389, 160693 164110, 160692 160977), (160692 165987, 160971 165794, 164104 165793, 164298 166083, 164298 169205, 164008 169399, 160886 169399, 160693 169120, 160692 165987), (160692 170997, 160971 170804, 164104 170803, 164298 171093, 164298 174215, 164008 174409, 160886 174409, 160693 174130, 160692 170997), (160692 176007, 160971 175814, 164104 175813, 164298 176103, 164298 179225, 164008 179419, 160886 179419, 160693 179140, 160692 176007), (160692 181017, 160971 180824, 164104 180823, 164298 181113, 164298 184235, 164008 184429, 160886 184429, 160693 184150, 160692 181017), (160692 186027, 160971 185834, 164104 185833, 164298 186123, 164298 188156, 164254 188271, 164018 188387, 160930 188240, 160769 188145, 160697 187989, 160692 186027), (165746 51728, 165982 51612, 169070 51759, 169231 51854, 169303 52010, 169308 53972, 169018 54166, 165896 54166, 165703 53887, 165702 51854, 165746 51728), (165702 55764, 165981 55571, 169114 55570, 169308 55860, 169308 58982, 169018 59176, 165896 59176, 165703 58897, 165702 55764), (165702 60774, 165981 60581, 169114 60580, 169308 60870, 169308 63992, 169018 64186, 165896 64186, 165703 63907, 165702 60774), (165702 65784, 165981 65591, 169114 65590, 169308 65880, 169308 69002, 169018 69196, 165896 69196, 165703 68917, 165702 65784), (165702 70794, 165981 70601, 169114 70600, 169308 70890, 169308 74012, 169018 74206, 165896 74206, 165703 73927, 165702 70794), (165702 75804, 165981 75611, 169114 75610, 169308 75900, 169308 79022, 169018 79216, 165896 79216, 165703 78937, 165702 75804), (165702 80814, 165981 80621, 169114 80620, 169308 80910, 169308 84032, 169018 84226, 165896 84226, 165703 83947, 165702 80814), (165981 85631, 169114 85630, 169308 85920, 169308 89042, 169018 89236, 165896 89236, 165703 88957, 165702 85824, 165981 85631), (165702 90834, 165981 90641, 169114 90640, 169308 90930, 169308 94052, 169018 94246, 165896 94246, 165703 93967, 165702 90834), (165706 95856, 165764 95754, 165981 95651, 169113 95650, 169308 95908, 169308 99064, 169018 99258, 165896 99258, 165703 98979, 165706 95856), (165702 100856, 165981 100663, 169114 100662, 169308 100952, 169308 104074, 169018 104268, 165896 104268, 165703 103989, 165702 100856), (165702 105866, 165981 105673, 169114 105672, 169308 105962, 169308 109084, 169018 109278, 165896 109278, 165703 108999, 165702 105866), (165702 110876, 165981 110683, 169114 110682, 169308 110972, 169308 114094, 169018 114288, 165896 114288, 165703 114009, 165702 110876), (165702 115886, 165981 115693, 169114 115692, 169308 115982, 169308 119104, 169018 119298, 165896 119298, 165703 119019, 165702 115886), (165702 120896, 165981 120703, 169114 120702, 169308 120992, 169308 124114, 169018 124308, 165896 124308, 165703 124029, 165702 120896), (165702 125906, 165981 125713, 169114 125712, 169308 126002, 169308 129124, 169018 129318, 165896 129318, 165703 129039, 165702 125906), (165706 130928, 165764 130826, 165981 130723, 169113 130722, 169308 130980, 169308 134134, 169018 134328, 165896 134328, 165703 134049, 165706 130928), (165702 135926, 165981 135733, 169114 135732, 169308 136022, 169308 139144, 169018 139338, 165896 139338, 165703 139059, 165702 135926), (165702 140936, 165981 140743, 169114 140742, 169308 141032, 169308 144155, 169018 144349, 165896 144349, 165703 144070, 165702 140936), (165706 145959, 165764 145857, 165981 145754, 169113 145753, 169308 146011, 169308 149165, 169018 149359, 165896 149359, 165703 149080, 165706 145959), (165981 150764, 169114 150763, 169308 151053, 169308 154175, 169018 154369, 165896 154369, 165703 154090, 165702 150957, 165981 150764), (165702 155967, 165981 155774, 169114 155773, 169308 156063, 169308 159185, 169018 159379, 165896 159379, 165703 159100, 165702 155967), (165702 160977, 165981 160784, 169114 160783, 169308 161073, 169308 164195, 169018 164389, 165896 164389, 165703 164110, 165702 160977), (165702 165987, 165981 165794, 169114 165793, 169308 166083, 169308 169205, 169018 169399, 165896 169399, 165703 169120, 165702 165987), (165981 170804, 169114 170803, 169308 171093, 169308 174215, 169018 174409, 165896 174409, 165703 174130, 165702 170997, 165981 170804), (165702 176007, 165981 175814, 169114 175813, 169308 176103, 169308 179225, 169018 179419, 165896 179419, 165703 179140, 165702 176007), (165702 181017, 165981 180824, 169114 180823, 169308 181113, 169308 184235, 169018 184429, 165896 184429, 165703 184150, 165702 181017), (165702 186027, 165981 185834, 169114 185833, 169308 186123, 169308 188030, 169059 188235, 165962 188391, 165789 188309, 165703 188113, 165702 186027), (170712 52090, 170759 51970, 170992 51858, 171714 51890, 174101 52244, 174251 52354, 174313 52488, 174318 53972, 174028 54166, 170906 54166, 170713 53887, 170712 52090), (170712 55764, 170991 55571, 174124 55570, 174318 55860, 174318 58982, 174028 59176, 170906 59176, 170713 58897, 170712 55764), (170712 60774, 170991 60581, 174124 60580, 174318 60870, 174318 63992, 174028 64186, 170906 64186, 170713 63907, 170712 60774), (170712 65784, 170991 65591, 174124 65590, 174318 65880, 174318 69002, 174028 69196, 170906 69196, 170713 68917, 170712 65784), (170712 70794, 170991 70601, 174124 70600, 174318 70890, 174318 74012, 174028 74206, 170906 74206, 170713 73927, 170712 70794), (170712 75804, 170991 75611, 174124 75610, 174318 75900, 174318 79022, 174028 79216, 170906 79216, 170713 78937, 170712 75804), (170712 80814, 170991 80621, 174124 80620, 174318 80910, 174318 84032, 174028 84226, 170906 84226, 170713 83947, 170712 80814), (170712 85824, 170991 85631, 174124 85630, 174318 85920, 174318 89042, 174028 89236, 170906 89236, 170713 88957, 170712 85824), (170712 90834, 170991 90641, 174124 90640, 174318 90930, 174318 94052, 174028 94246, 170906 94246, 170713 93967, 170712 90834), (170716 95856, 170774 95754, 170991 95651, 174123 95650, 174318 95908, 174318 99064, 174028 99258, 170906 99258, 170713 98979, 170716 95856), (170712 100856, 170991 100663, 174124 100662, 174318 100952, 174318 104074, 174028 104268, 170906 104268, 170713 103989, 170712 100856), (170712 105866, 170991 105673, 174124 105672, 174318 105962, 174318 109084, 174028 109278, 170906 109278, 170713 108999, 170712 105866), (170712 110876, 170991 110683, 174124 110682, 174318 110972, 174318 114094, 174028 114288, 170906 114288, 170713 114009, 170712 110876), (170712 115886, 170991 115693, 174124 115692, 174318 115982, 174318 119104, 174028 119298, 170906 119298, 170713 119019, 170712 115886), (170712 120896, 170991 120703, 174124 120702, 174318 120992, 174318 124114, 174028 124308, 170906 124308, 170713 124029, 170712 120896), (170712 125906, 170991 125713, 174124 125712, 174318 126002, 174318 129124, 174028 129318, 170906 129318, 170713 129039, 170712 125906), (170716 130928, 170774 130826, 170991 130723, 174123 130722, 174318 130980, 174318 134134, 174028 134328, 170906 134328, 170713 134049, 170716 130928), (170712 135926, 170991 135733, 174124 135732, 174318 136022, 174318 139144, 174028 139338, 170906 139338, 170713 139059, 170712 135926), (170712 140936, 170991 140743, 174124 140742, 174318 141032, 174318 144155, 174028 144349, 170906 144349, 170713 144070, 170712 140936), (170716 145959, 170774 145857, 170991 145754, 174123 145753, 174318 146011, 174318 149165, 174028 149359, 170906 149359, 170713 149080, 170716 145959), (170712 150957, 170991 150764, 174124 150763, 174318 151053, 174318 154175, 174028 154369, 170906 154369, 170713 154090, 170712 150957), (170712 155967, 170991 155774, 174124 155773, 174318 156063, 174318 159185, 174028 159379, 170906 159379, 170713 159100, 170712 155967), (170712 160977, 170991 160784, 174124 160783, 174318 161073, 174318 164195, 174028 164389, 170906 164389, 170713 164110, 170712 160977), (170991 165794, 174124 165793, 174318 166083, 174318 169205, 174028 169399, 170906 169399, 170713 169120, 170712 165987, 170991 165794), (170712 170997, 170991 170804, 174124 170803, 174318 171093, 174318 174215, 174028 174409, 170906 174409, 170713 174130, 170712 170997), (170991 175814, 174124 175813, 174318 176103, 174318 179225, 174028 179419, 170906 179419, 170713 179140, 170712 176007, 170991 175814), (170712 181017, 170991 180824, 174124 180823, 174318 181113, 174318 184235, 174028 184429, 170906 184429, 170713 184150, 170712 181017), (170712 186027, 170991 185834, 174124 185833, 174318 186123, 174315 187545, 174098 187752, 171714 188109, 170972 188145, 170803 188067, 170714 187877, 170712 186027), (175728 52718, 175781 52626, 176030 52534, 178359 52877, 179100 53062, 179286 53230, 179300 54005, 179118 54166, 175916 54166, 175723 53887, 175728 52718), (175722 55764, 176001 55571, 179098 55570, 179225 55633, 179328 55860, 179328 58982, 179038 59176, 175916 59176, 175723 58897, 175722 55764), (175722 60774, 176001 60581, 179134 60580, 179328 60870, 179328 63992, 179038 64186, 175916 64186, 175723 63907, 175722 60774), (175722 65784, 176001 65591, 179134 65590, 179328 65880, 179328 69002, 179038 69196, 175916 69196, 175723 68917, 175722 65784), (175722 70794, 176001 70601, 179134 70600, 179328 70890, 179328 74012, 179038 74206, 175916 74206, 175723 73927, 175722 70794), (175722 75804, 176001 75611, 179134 75610, 179328 75900, 179328 79022, 179038 79216, 175916 79216, 175723 78937, 175722 75804), (175722 80814, 176001 80621, 179134 80620, 179328 80910, 179328 84032, 179038 84226, 175916 84226, 175723 83947, 175722 80814), (175722 85824, 176001 85631, 179134 85630, 179328 85920, 179328 89042, 179038 89236, 175916 89236, 175723 88957, 175722 85824), (175722 90834, 176001 90641, 179134 90640, 179328 90930, 179328 94052, 179038 94246, 175916 94246, 175723 93967, 175722 90834), (175726 95856, 175784 95754, 176001 95651, 179133 95650, 179328 95908, 179328 99064, 179038 99258, 175916 99258, 175723 98979, 175726 95856), (175722 100856, 176001 100663, 179134 100662, 179328 100952, 179328 104074, 179038 104268, 175916 104268, 175723 103989, 175722 100856), (175722 105866, 176001 105673, 179134 105672, 179328 105962, 179328 109084, 179038 109278, 175916 109278, 175723 108999, 175722 105866), (175722 110876, 176001 110683, 179134 110682, 179328 110972, 179328 114094, 179038 114288, 175916 114288, 175723 114009, 175722 110876), (175722 115886, 176001 115693, 179134 115692, 179328 115982, 179328 119104, 179038 119298, 175916 119298, 175723 119019, 175722 115886), (175722 120896, 176001 120703, 179134 120702, 179328 120992, 179328 124114, 179038 124308, 175916 124308, 175723 124029, 175722 120896), (175722 125906, 176001 125713, 179134 125712, 179328 126002, 179328 129124, 179038 129318, 175916 129318, 175723 129039, 175722 125906), (175726 130928, 175784 130826, 176001 130723, 179133 130722, 179328 130980, 179328 134134, 179038 134328, 175916 134328, 175723 134049, 175726 130928), (175722 135926, 176001 135733, 179134 135732, 179328 136022, 179328 139144, 179038 139338, 175916 139338, 175723 139059, 175722 135926), (175722 140936, 176001 140743, 179134 140742, 179328 141032, 179328 144155, 179038 144349, 175916 144349, 175723 144070, 175722 140936), (175726 145959, 175784 145857, 176001 145754, 179133 145753, 179328 146011, 179328 149165, 179038 149359, 175916 149359, 175723 149080, 175726 145959), (175722 150957, 176001 150764, 179134 150763, 179328 151053, 179328 154175, 179038 154369, 175916 154369, 175723 154090, 175722 150957), (175722 155967, 176001 155774, 179134 155773, 179328 156063, 179328 159185, 179038 159379, 175916 159379, 175723 159100, 175722 155967), (175722 160977, 176001 160784, 179134 160783, 179328 161073, 179328 164195, 179038 164389, 175916 164389, 175723 164110, 175722 160977), (175722 165987, 176001 165794, 179134 165793, 179328 166083, 179328 169205, 179038 169399, 175916 169399, 175723 169120, 175722 165987), (175722 170997, 176001 170804, 179134 170803, 179328 171093, 179328 174215, 179038 174409, 175916 174409, 175723 174130, 175722 170997), (175722 176007, 176001 175814, 179134 175813, 179328 176103, 179328 179225, 179038 179419, 175916 179419, 175723 179140, 175722 176007), (175722 181017, 176001 180824, 179134 180823, 179328 181113, 179328 184235, 179038 184429, 175916 184429, 175723 184150, 175722 181017), (175722 186027, 176001 185834, 179134 185833, 179324 186092, 179286 186769, 179133 186926, 178359 187122, 176003 187472, 175826 187410, 175725 187201, 175722 186027), (180732 55760, 180981 55576, 184137 55575, 184238 55636, 184338 55860, 184338 58982, 184048 59176, 180926 59176, 180733 58897, 180732 55760), (180732 60774, 181011 60581, 184144 60580, 184338 60870, 184338 63992, 184048 64186, 180926 64186, 180733 63907, 180732 60774), (180732 65784, 181011 65591, 184144 65590, 184338 65880, 184338 69002, 184048 69196, 180926 69196, 180733 68917, 180732 65784), (180732 70794, 181011 70601, 184144 70600, 184338 70890, 184338 74012, 184048 74206, 180926 74206, 180733 73927, 180732 70794), (180732 75804, 181011 75611, 184144 75610, 184338 75900, 184338 79022, 184048 79216, 180926 79216, 180733 78937, 180732 75804), (180732 80814, 181011 80621, 184144 80620, 184338 80910, 184338 84032, 184048 84226, 180926 84226, 180733 83947, 180732 80814), (180732 85824, 181011 85631, 184144 85630, 184338 85920, 184338 89042, 184048 89236, 180926 89236, 180733 88957, 180732 85824), (180732 90834, 181011 90641, 184144 90640, 184338 90930, 184338 94052, 184048 94246, 180926 94246, 180733 93967, 180732 90834), (180736 95856, 180794 95754, 181011 95651, 184143 95650, 184338 95908, 184338 99064, 184048 99258, 180926 99258, 180733 98979, 180736 95856), (180732 100856, 181011 100663, 184144 100662, 184338 100952, 184338 104074, 184048 104268, 180926 104268, 180733 103989, 180732 100856), (180732 105866, 181011 105673, 184144 105672, 184338 105962, 184338 109084, 184048 109278, 180926 109278, 180733 108999, 180732 105866), (180732 110876, 181011 110683, 184144 110682, 184338 110972, 184338 114094, 184048 114288, 180926 114288, 180733 114009, 180732 110876), (180732 115886, 181011 115693, 184144 115692, 184338 115982, 184338 119104, 184048 119298, 180926 119298, 180733 119019, 180732 115886), (180732 120896, 181011 120703, 184144 120702, 184338 120992, 184338 124114, 184048 124308, 180926 124308, 180733 124029, 180732 120896), (180732 125906, 181011 125713, 184144 125712, 184338 126002, 184338 129124, 184048 129318, 180926 129318, 180733 129039, 180732 125906), (180736 130928, 180794 130826, 181011 130723, 184143 130722, 184338 130980, 184338 134134, 184048 134328, 180926 134328, 180733 134049, 180736 130928), (180732 135926, 181011 135733, 184144 135732, 184338 136022, 184338 139144, 184048 139338, 180926 139338, 180733 139059, 180732 135926), (180732 140936, 181011 140743, 184144 140742, 184338 141032, 184338 144155, 184048 144349, 180926 144349, 180733 144070, 180732 140936), (180736 145959, 180794 145857, 181011 145754, 184143 145753, 184338 146011, 184338 149165, 184048 149359, 180926 149359, 180733 149080, 180736 145959), (180732 150957, 181011 150764, 184144 150763, 184338 151053, 184338 154175, 184048 154369, 180926 154369, 180733 154090, 180732 150957), (180732 155967, 181011 155774, 184144 155773, 184338 156063, 184338 159185, 184048 159379, 180926 159379, 180733 159100, 180732 155967), (180732 160977, 181011 160784, 184144 160783, 184338 161073, 184338 164195, 184048 164389, 180926 164389, 180733 164110, 180732 160977), (180732 165987, 181011 165794, 184144 165793, 184338 166083, 184338 169205, 184048 169399, 180926 169399, 180733 169120, 180732 165987), (180732 170997, 181011 170804, 184144 170803, 184338 171093, 184338 174215, 184048 174409, 180926 174409, 180733 174130, 180732 170997), (180732 176007, 181011 175814, 184144 175813, 184338 176103, 184338 179225, 184048 179419, 180926 179419, 180733 179140, 180732 176007), (180732 181017, 181011 180824, 184144 180823, 184338 181113, 184338 184191, 184280 184321, 184085 184424, 180945 184426, 180836 184367, 180733 184150, 180732 181017), (185742 55761, 185827 55655, 186045 55570, 187853 55578, 189152 56040, 189350 56283, 189349 58980, 189287 59072, 189059 59176, 185936 59176, 185743 58897, 185742 55761), (185742 60774, 186021 60581, 189155 60580, 189349 60870, 189349 63992, 189059 64186, 185936 64186, 185743 63907, 185742 60774), (185742 65784, 186021 65591, 189155 65590, 189349 65880, 189349 69002, 189059 69196, 185936 69196, 185743 68917, 185742 65784), (185742 70794, 186021 70601, 189155 70600, 189349 70890, 189349 74012, 189059 74206, 185936 74206, 185743 73927, 185742 70794), (185742 75804, 186021 75611, 189155 75610, 189349 75900, 189349 79022, 189059 79216, 185936 79216, 185743 78937, 185742 75804), (185742 80814, 186021 80621, 189155 80620, 189349 80910, 189349 84032, 189059 84226, 185936 84226, 185743 83947, 185742 80814), (185742 85824, 186021 85631, 189155 85630, 189349 85920, 189349 89042, 189059 89236, 185936 89236, 185743 88957, 185742 85824), (185742 90834, 186021 90641, 189155 90640, 189349 90930, 189349 94052, 189059 94246, 185936 94246, 185743 93967, 185742 90834), (185746 95856, 185804 95754, 186021 95651, 189154 95650, 189349 95908, 189349 99064, 189059 99258, 185936 99258, 185743 98979, 185746 95856), (185742 100856, 186021 100663, 189155 100662, 189349 100952, 189349 104074, 189059 104268, 185936 104268, 185743 103989, 185742 100856), (185742 105866, 186021 105673, 189155 105672, 189349 105962, 189349 109084, 189059 109278, 185936 109278, 185743 108999, 185742 105866), (185742 110876, 186021 110683, 189155 110682, 189349 110972, 189349 114094, 189059 114288, 185936 114288, 185743 114009, 185742 110876), (185742 115886, 186021 115693, 189155 115692, 189349 115982, 189349 119104, 189059 119298, 185936 119298, 185743 119019, 185742 115886), (185742 120896, 186021 120703, 189155 120702, 189349 120992, 189349 124114, 189059 124308, 185936 124308, 185743 124029, 185742 120896), (185742 125906, 186021 125713, 189155 125712, 189349 126002, 189349 129124, 189059 129318, 185936 129318, 185743 129039, 185742 125906), (185746 130928, 185804 130826, 186021 130723, 189154 130722, 189349 130980, 189349 134134, 189059 134328, 185936 134328, 185743 134049, 185746 130928), (185742 135926, 186021 135733, 189155 135732, 189349 136022, 189349 139144, 189059 139338, 185936 139338, 185743 139059, 185742 135926), (185742 140936, 186021 140743, 189155 140742, 189349 141032, 189349 144155, 189059 144349, 185936 144349, 185743 144070, 185742 140936), (185746 145959, 185804 145857, 186021 145754, 189154 145753, 189349 146011, 189349 149165, 189059 149359, 185936 149359, 185743 149080, 185746 145959), (185742 150957, 186021 150764, 189155 150763, 189349 151053, 189349 154175, 189059 154369, 185936 154369, 185743 154090, 185742 150957), (185742 155967, 186021 155774, 189155 155773, 189349 156063, 189349 159185, 189059 159379, 185936 159379, 185743 159100, 185742 155967), (185742 160977, 186021 160784, 189155 160783, 189349 161073, 189349 164195, 189059 164389, 185936 164389, 185743 164110, 185742 160977), (185742 165987, 186021 165794, 189155 165793, 189349 166083, 189349 169205, 189059 169399, 185936 169399, 185743 169120, 185742 165987), (185742 170997, 186021 170804, 189155 170803, 189349 171093, 189349 174215, 189059 174409, 185936 174409, 185743 174130, 185742 170997), (185742 176007, 186021 175814, 189155 175813, 189349 176103, 189349 179225, 189059 179419, 185936 179419, 185743 179140, 185742 176007), (185742 181017, 186021 180824, 189155 180823, 189349 181116, 189349 183715, 189183 183944, 187857 184423, 185891 184429, 185743 184150, 185742 181017), (190751 181016, 191032 180824, 194172 180823, 194295 180947, 194359 181520, 194218 181795, 191186 183231, 190954 183227, 190779 183132, 190751 181016), (190775 57044, 190923 56771, 191095 56725, 194188 58187, 194329 58352, 194330 59018, 194149 59176, 190942 59176, 190754 58898, 190775 57044), (190753 60771, 191031 60581, 194129 60580, 194256 60643, 194359 60870, 194359 63992, 194069 64186, 190947 64186, 190754 63907, 190753 60771), (190753 65784, 191032 65591, 194165 65590, 194359 65880, 194359 69002, 194069 69196, 190947 69196, 190754 68917, 190753 65784), (190753 70794, 191032 70601, 194165 70600, 194359 70890, 194359 74012, 194069 74206, 190947 74206, 190754 73927, 190753 70794), (190753 75804, 191032 75611, 194165 75610, 194359 75900, 194359 79022, 194069 79216, 190947 79216, 190754 78937, 190753 75804), (190753 80814, 191032 80621, 194165 80620, 194359 80910, 194359 84032, 194069 84226, 190947 84226, 190754 83947, 190753 80814), (190753 85824, 191032 85631, 194165 85630, 194359 85920, 194359 89042, 194069 89236, 190947 89236, 190754 88957, 190753 85824), (190753 90834, 191032 90641, 194165 90640, 194359 90930, 194359 94052, 194069 94246, 190947 94246, 190754 93967, 190753 90834), (190757 95856, 190815 95754, 191032 95651, 194164 95650, 194359 95908, 194359 99064, 194069 99258, 190947 99258, 190754 98979, 190757 95856), (191032 100663, 194165 100662, 194359 100952, 194359 104074, 194069 104268, 190947 104268, 190754 103989, 190753 100856, 191032 100663), (190753 105866, 191032 105673, 194165 105672, 194359 105962, 194359 109084, 194069 109278, 190947 109278, 190754 108999, 190753 105866), (190753 110876, 191032 110683, 194165 110682, 194359 110972, 194359 114094, 194069 114288, 190947 114288, 190754 114009, 190753 110876), (190753 115886, 191032 115693, 194165 115692, 194359 115982, 194359 119104, 194069 119298, 190947 119298, 190754 119019, 190753 115886), (190753 120896, 191032 120703, 194165 120702, 194359 120992, 194359 124114, 194069 124308, 190947 124308, 190754 124029, 190753 120896), (190753 125906, 191032 125713, 194165 125712, 194359 126002, 194359 129124, 194069 129318, 190947 129318, 190754 129039, 190753 125906), (190757 130928, 190815 130826, 191032 130723, 194164 130722, 194359 130980, 194359 134134, 194069 134328, 190947 134328, 190754 134049, 190757 130928), (190753 135926, 191032 135733, 194165 135732, 194359 136022, 194359 139144, 194069 139338, 190947 139338, 190754 139059, 190753 135926), (190753 140936, 191032 140743, 194165 140742, 194359 141032, 194359 144155, 194069 144349, 190947 144349, 190754 144070, 190753 140936), (190757 145959, 190815 145857, 191032 145754, 194164 145753, 194359 146011, 194359 149165, 194069 149359, 190947 149359, 190754 149080, 190757 145959), (190753 150957, 191032 150764, 194165 150763, 194359 151053, 194359 154175, 194069 154369, 190947 154369, 190754 154090, 190753 150957), (190753 155967, 191032 155774, 194165 155773, 194359 156063, 194359 159185, 194069 159379, 190947 159379, 190754 159100, 190753 155967), (190753 160977, 191032 160784, 194165 160783, 194359 161073, 194359 164195, 194069 164389, 190947 164389, 190754 164110, 190753 160977), (190753 165987, 191032 165794, 194165 165793, 194359 166083, 194359 169205, 194069 169399, 190947 169399, 190754 169120, 190753 165987), (190753 170997, 191032 170804, 194165 170803, 194359 171093, 194359 174215, 194069 174409, 190947 174409, 190754 174130, 190753 170997), (190753 176007, 191032 175814, 194165 175813, 194359 176103, 194359 179225, 194069 179419, 190945 179419, 190754 179140, 190753 176007), (195763 60770, 196009 60587, 198830 60580, 199289 60913, 199369 61074, 199369 63992, 199079 64186, 195957 64186, 195764 63907, 195763 60770), (195763 65784, 196042 65591, 199175 65590, 199369 65880, 199369 69002, 199079 69196, 195957 69196, 195764 68917, 195763 65784), (195763 70794, 196042 70601, 199175 70600, 199369 70890, 199369 74012, 199079 74206, 195957 74206, 195764 73927, 195763 70794), (195763 75804, 196042 75611, 199175 75610, 199369 75900, 199369 79022, 199079 79216, 195957 79216, 195764 78937, 195763 75804), (195763 80814, 196042 80621, 199175 80620, 199369 80910, 199369 84032, 199079 84226, 195957 84226, 195764 83947, 195763 80814), (195763 85824, 196042 85631, 199175 85630, 199369 85920, 199369 89042, 199079 89236, 195957 89236, 195764 88957, 195763 85824), (195763 90834, 196042 90641, 199175 90640, 199369 90930, 199369 94052, 199079 94246, 195957 94246, 195764 93967, 195763 90834), (195767 95856, 195825 95754, 196042 95651, 199174 95650, 199369 95908, 199369 99064, 199079 99258, 195957 99258, 195764 98979, 195767 95856), (195763 100856, 196042 100663, 199175 100662, 199369 100952, 199369 104074, 199079 104268, 195957 104268, 195764 103989, 195763 100856), (195763 105866, 196042 105673, 199175 105672, 199369 105962, 199369 109084, 199079 109278, 195957 109278, 195764 108999, 195763 105866), (195763 110876, 196042 110683, 199175 110682, 199369 110972, 199369 114094, 199079 114288, 195957 114288, 195764 114009, 195763 110876), (195763 115886, 196042 115693, 199175 115692, 199369 115982, 199369 119104, 199079 119298, 195957 119298, 195764 119019, 195763 115886), (195763 120896, 196042 120703, 199175 120702, 199369 120992, 199369 124114, 199079 124308, 195957 124308, 195764 124029, 195763 120896), (195763 125906, 196042 125713, 199175 125712, 199369 126002, 199369 129124, 199079 129318, 195957 129318, 195764 129039, 195763 125906), (195767 130928, 195825 130826, 196042 130723, 199174 130722, 199369 130980, 199369 134134, 199079 134328, 195957 134328, 195764 134049, 195767 130928), (195763 135926, 196042 135733, 199175 135732, 199369 136022, 199369 139144, 199079 139338, 195957 139338, 195764 139059, 195763 135926), (195763 140936, 196042 140743, 199175 140742, 199369 141032, 199369 144155, 199079 144349, 195957 144349, 195764 144070, 195763 140936), (195767 145959, 195825 145857, 196042 145754, 199174 145753, 199369 146011, 199369 149165, 199079 149359, 195957 149359, 195764 149080, 195767 145959), (195763 150957, 196042 150764, 199175 150763, 199369 151053, 199369 154175, 199079 154369, 195957 154369, 195764 154090, 195763 150957), (195763 155967, 196042 155774, 199175 155773, 199369 156063, 199369 159185, 199079 159379, 195957 159379, 195764 159100, 195763 155967), (195763 160977, 196042 160784, 199175 160783, 199369 161073, 199369 164195, 199079 164389, 195957 164389, 195764 164110, 195763 160977), (195763 165987, 196042 165794, 199175 165793, 199369 166083, 199369 169205, 199079 169399, 195957 169399, 195764 169120, 195763 165987), (195763 170997, 196042 170804, 199175 170803, 199369 171093, 199369 174215, 199079 174409, 195957 174409, 195764 174130, 195763 170997), (195763 176007, 196042 175814, 199175 175813, 199369 176103, 199369 178925, 199300 179077, 198841 179419, 195983 179417, 195850 179336, 195764 179140, 195763 176007), (200954 61981, 201132 61964, 203025 63096, 203835 63699, 203884 63885, 203815 64106, 203689 64183, 200967 64186, 200774 63907, 200773 62276, 200954 61981), (200773 65784, 201052 65591, 204188 65590, 204379 65880, 204379 69002, 204089 69196, 200967 69196, 200774 68917, 200773 65784), (200773 70794, 201052 70601, 204185 70600, 204379 70890, 204379 74012, 204089 74206, 200967 74206, 200774 73927, 200773 70794), (200773 75804, 201052 75611, 204185 75610, 204379 75900, 204379 79022, 204089 79216, 200967 79216, 200774 78937, 200773 75804), (200773 80814, 201052 80621, 204185 80620, 204379 80910, 204379 84032, 204089 84226, 200967 84226, 200774 83947, 200773 80814), (200773 85824, 201052 85631, 204185 85630, 204379 85920, 204379 89042, 204089 89236, 200967 89236, 200774 88957, 200773 85824), (200773 90834, 201052 90641, 204185 90640, 204379 90930, 204379 94052, 204089 94246, 200967 94246, 200774 93967, 200773 90834), (200777 95856, 200835 95754, 201052 95651, 204184 95650, 204379 95908, 204379 99064, 204089 99258, 200967 99258, 200774 98979, 200777 95856), (200773 100856, 201052 100663, 204185 100662, 204379 100952, 204379 104074, 204089 104268, 200967 104268, 200774 103989, 200773 100856), (200773 105866, 201052 105673, 204185 105672, 204379 105962, 204379 109084, 204089 109278, 200967 109278, 200774 108999, 200773 105866), (200773 110876, 201052 110683, 204185 110682, 204379 110972, 204379 114094, 204089 114288, 200967 114288, 200774 114009, 200773 110876), (200773 115886, 201052 115693, 204185 115692, 204379 115982, 204379 119104, 204089 119298, 200967 119298, 200774 119019, 200773 115886), (200773 120896, 201052 120703, 204185 120702, 204379 120992, 204379 124114, 204089 124308, 200967 124308, 200774 124029, 200773 120896), (200773 125906, 201052 125713, 204185 125712, 204379 126002, 204379 129124, 204089 129318, 200967 129318, 200774 129039, 200773 125906), (200777 130928, 200835 130826, 201052 130723, 204184 130722, 204379 130980, 204379 134134, 204089 134328, 200967 134328, 200774 134049, 200777 130928), (200773 135926, 201052 135733, 204185 135732, 204379 136022, 204379 139144, 204089 139338, 200967 139338, 200774 139059, 200773 135926), (200773 140936, 201052 140743, 204185 140742, 204379 141032, 204379 144155, 204089 144349, 200967 144349, 200774 144070, 200773 140936), (200777 145959, 200835 145857, 201052 145754, 204184 145753, 204379 146011, 204379 149165, 204089 149359, 200967 149359, 200774 149080, 200777 145959), (200773 150957, 201052 150764, 204185 150763, 204379 151053, 204379 154175, 204089 154369, 200967 154369, 200774 154090, 200773 150957), (200773 155967, 201052 155774, 204185 155773, 204379 156063, 204379 159185, 204089 159379, 200967 159379, 200774 159100, 200773 155967), (200773 160977, 201052 160784, 204185 160783, 204379 161073, 204379 164195, 204089 164389, 200967 164389, 200774 164110, 200773 160977), (200773 165987, 201052 165794, 204185 165793, 204379 166083, 204379 169205, 204089 169399, 200967 169399, 200774 169120, 200773 165987), (200773 170997, 201052 170804, 204185 170803, 204379 171093, 204379 174255, 204128 174403, 200967 174409, 200774 174130, 200773 170997), (200773 176007, 201052 175814, 203708 175813, 203811 175908, 203900 176185, 203822 176312, 203018 176908, 201228 177981, 200881 177976, 200776 177833, 200773 176007), (205783 65785, 205840 65699, 206101 65590, 206437 65631, 208427 67103, 209390 67980, 209389 69007, 209099 69196, 205977 69196, 205784 68917, 205783 65785), (205783 70794, 206062 70601, 209195 70600, 209389 70890, 209389 74012, 209099 74206, 205977 74206, 205784 73927, 205783 70794), (205783 75804, 206062 75611, 209195 75610, 209389 75900, 209389 79022, 209099 79216, 205977 79216, 205784 78937, 205783 75804), (205783 80814, 206062 80621, 209195 80620, 209389 80910, 209389 84032, 209099 84226, 205977 84226, 205784 83947, 205783 80814), (205783 85824, 206062 85631, 209195 85630, 209389 85920, 209389 89042, 209099 89236, 205977 89236, 205784 88957, 205783 85824), (205783 90834, 206062 90641, 209195 90640, 209389 90930, 209389 94052, 209099 94246, 205977 94246, 205784 93967, 205783 90834), (205787 95856, 205845 95754, 206062 95651, 209194 95650, 209389 95908, 209389 99064, 209099 99258, 205977 99258, 205784 98979, 205787 95856), (205783 100856, 206062 100663, 209195 100662, 209389 100952, 209389 104074, 209099 104268, 205977 104268, 205784 103989, 205783 100856), (205783 105866, 206062 105673, 209195 105672, 209389 105962, 209389 109084, 209099 109278, 205977 109278, 205784 108999, 205783 105866), (205783 110876, 206062 110683, 209195 110682, 209389 110972, 209389 114094, 209099 114288, 205977 114288, 205784 114009, 205783 110876), (205783 115886, 206062 115693, 209195 115692, 209389 115982, 209389 119104, 209099 119298, 205977 119298, 205784 119019, 205783 115886), (206062 120703, 209195 120702, 209389 120992, 209389 124114, 209099 124308, 205977 124308, 205784 124029, 205783 120896, 206062 120703), (205783 125906, 206062 125713, 209195 125712, 209389 126002, 209389 129124, 209099 129318, 205977 129318, 205784 129039, 205783 125906), (205787 130928, 205845 130826, 206062 130723, 209194 130722, 209389 130980, 209389 134134, 209099 134328, 205977 134328, 205784 134049, 205787 130928), (205783 135926, 206062 135733, 209195 135732, 209389 136022, 209389 139144, 209099 139338, 205977 139338, 205784 139059, 205783 135926), (205783 140936, 206062 140743, 209195 140742, 209389 141032, 209389 144155, 209099 144349, 205977 144349, 205784 144070, 205783 140936), (205787 145959, 205845 145857, 206062 145754, 209194 145753, 209389 146011, 209389 149165, 209099 149359, 205977 149359, 205784 149080, 205787 145959), (205783 150957, 206062 150764, 209195 150763, 209389 151053, 209389 154175, 209099 154369, 205977 154369, 205784 154090, 205783 150957), (205783 155967, 206062 155774, 209195 155773, 209389 156063, 209389 159185, 209099 159379, 205977 159379, 205784 159100, 205783 155967), (205783 160977, 206062 160784, 209195 160783, 209389 161073, 209389 164195, 209099 164389, 205977 164389, 205784 164110, 205783 160977), (205783 165987, 206062 165794, 209195 165793, 209389 166083, 209389 169205, 209099 169399, 205977 169399, 205784 169120, 205783 165987), (205783 170997, 206062 170804, 209195 170803, 209389 171060, 209390 171934, 209324 172082, 208413 172908, 206467 174350, 205863 174347, 205783 174201, 205783 170997), (210793 70794, 211050 70600, 212280 70600, 213381 71593, 214400 72719, 214399 74017, 214109 74206, 210987 74206, 210794 73927, 210793 70794), (210793 75804, 211072 75611, 214205 75610, 214399 75900, 214399 79022, 214109 79216, 210987 79216, 210794 78937, 210793 75804), (210793 80814, 211072 80621, 214205 80620, 214399 80910, 214399 84032, 214109 84226, 210987 84226, 210794 83947, 210793 80814), (210793 85824, 211072 85631, 214205 85630, 214399 85920, 214399 89042, 214109 89236, 210987 89236, 210794 88957, 210793 85824), (210793 90834, 211072 90641, 214205 90640, 214399 90930, 214399 94052, 214109 94246, 210987 94246, 210794 93967, 210793 90834), (210797 95856, 210855 95754, 211072 95651, 214204 95650, 214399 95908, 214399 99064, 214109 99258, 210987 99258, 210794 98979, 210797 95856), (210793 100856, 211072 100663, 214205 100662, 214399 100952, 214399 104074, 214109 104268, 210987 104268, 210794 103989, 210793 100856), (210793 105866, 211072 105673, 214205 105672, 214399 105962, 214399 109084, 214109 109278, 210987 109278, 210794 108999, 210793 105866), (210793 110876, 211072 110683, 214205 110682, 214399 110972, 214399 114094, 214109 114288, 210987 114288, 210794 114009, 210793 110876), (210793 115886, 211072 115693, 214205 115692, 214399 115982, 214399 119104, 214109 119298, 210987 119298, 210794 119019, 210793 115886), (210793 120896, 211072 120703, 214205 120702, 214399 120992, 214399 124114, 214109 124308, 210987 124308, 210794 124029, 210793 120896), (210793 125906, 211072 125713, 214205 125712, 214399 126002, 214399 129124, 214109 129318, 210987 129318, 210794 129039, 210793 125906), (210797 130928, 210855 130826, 211072 130723, 214204 130722, 214399 130980, 214399 134134, 214109 134328, 210987 134328, 210794 134049, 210797 130928), (210793 135926, 211072 135733, 214205 135732, 214399 136022, 214399 139144, 214109 139338, 210987 139338, 210794 139059, 210793 135926), (210793 140936, 211072 140743, 214205 140742, 214399 141032, 214399 144155, 214109 144349, 210987 144349, 210794 144070, 210793 140936), (210797 145959, 210855 145857, 211072 145754, 214204 145753, 214399 146011, 214399 149165, 214109 149359, 210987 149359, 210794 149080, 210797 145959), (210793 150957, 211072 150764, 214205 150763, 214399 151053, 214399 154175, 214109 154369, 210987 154369, 210794 154090, 210793 150957), (210793 155967, 211072 155774, 214205 155773, 214399 156063, 214399 159185, 214109 159379, 210987 159379, 210794 159100, 210793 155967), (210793 160977, 211072 160784, 214205 160783, 214399 161073, 214399 164195, 214109 164389, 210987 164389, 210794 164110, 210793 160977), (210793 165987, 211072 165794, 214205 165793, 214399 166050, 214399 167206, 214348 167341, 213392 168395, 212341 169348, 212206 169399, 210982 169399, 210794 169120, 210793 165987), (215803 75804, 216060 75610, 217019 75610, 217910 76588, 219350 78532, 219347 79136, 219201 79216, 215997 79216, 215804 78937, 215803 75804), (215803 80814, 216082 80621, 219255 80620, 219403 80871, 219409 84032, 219119 84226, 215997 84226, 215804 83947, 215803 80814), (215803 85824, 216082 85631, 219215 85630, 219409 85920, 219409 89042, 219119 89236, 215997 89236, 215804 88957, 215803 85824), (215803 90834, 216082 90641, 219215 90640, 219409 90930, 219409 94052, 219119 94246, 215997 94246, 215804 93967, 215803 90834), (215807 95856, 215865 95754, 216082 95651, 219214 95650, 219409 95908, 219409 99064, 219119 99258, 215997 99258, 215804 98979, 215807 95856), (215803 100856, 216082 100663, 219215 100662, 219409 100952, 219409 104074, 219119 104268, 215997 104268, 215804 103989, 215803 100856), (215803 105866, 216082 105673, 219215 105672, 219409 105962, 219409 109084, 219119 109278, 215997 109278, 215804 108999, 215803 105866), (215803 110876, 216082 110683, 219215 110682, 219409 110972, 219409 114094, 219119 114288, 215997 114288, 215804 114009, 215803 110876), (215803 115886, 216082 115693, 219215 115692, 219409 115982, 219409 119104, 219119 119298, 215997 119298, 215804 119019, 215803 115886), (215803 120896, 216082 120703, 219215 120702, 219409 120992, 219409 124114, 219119 124308, 215997 124308, 215804 124029, 215803 120896), (215803 125906, 216082 125713, 219215 125712, 219409 126002, 219409 129124, 219119 129318, 215997 129318, 215804 129039, 215803 125906), (215807 130928, 215865 130826, 216082 130723, 219214 130722, 219409 130980, 219409 134134, 219119 134328, 215997 134328, 215804 134049, 215807 130928), (215803 135926, 216082 135733, 219215 135732, 219409 136022, 219409 139144, 219119 139338, 215997 139338, 215804 139059, 215803 135926), (215803 140936, 216082 140743, 219215 140742, 219409 141032, 219409 144155, 219119 144349, 215997 144349, 215804 144070, 215803 140936), (215807 145959, 215865 145857, 216082 145754, 219214 145753, 219409 146011, 219409 149165, 219119 149359, 215997 149359, 215804 149080, 215807 145959), (215803 150957, 216082 150764, 219215 150763, 219409 151053, 219409 154175, 219119 154369, 215997 154369, 215804 154090, 215803 150957), (215803 155967, 216082 155774, 219215 155773, 219409 156063, 219410 159129, 219367 159254, 219119 159379, 215997 159379, 215804 159100, 215803 155967), (215803 160977, 216082 160784, 219214 160783, 219300 160840, 219409 161101, 219368 161437, 217903 163420, 217082 164324, 216934 164389, 215992 164389, 215804 164110, 215803 160977), (220813 81291, 220908 81188, 221185 81099, 221289 81152, 221905 81976, 222996 83801, 222976 84118, 222833 84223, 221007 84226, 220814 83947, 220813 81291), (220813 85824, 221092 85631, 223925 85630, 224077 85699, 224419 86158, 224417 89016, 224357 89132, 224129 89236, 221007 89236, 220814 88957, 220813 85824), (220813 90834, 221092 90641, 224225 90640, 224419 90930, 224419 94008, 224357 94142, 224129 94246, 221007 94246, 220814 93967, 220813 90834), (220817 95856, 220875 95754, 221092 95651, 224224 95650, 224419 95908, 224419 99064, 224129 99258, 221007 99258, 220814 98979, 220817 95856), (220813 100856, 221092 100663, 224225 100662, 224419 100952, 224419 104074, 224129 104268, 221007 104268, 220814 103989, 220813 100856), (220813 105866, 221092 105673, 224225 105672, 224419 105962, 224419 109084, 224129 109278, 221007 109278, 220814 108999, 220813 105866), (220813 110876, 221092 110683, 224225 110682, 224419 110972, 224419 114094, 224129 114288, 221007 114288, 220814 114009, 220813 110876), (220813 115886, 221092 115693, 224225 115692, 224419 115982, 224419 119104, 224129 119298, 221007 119298, 220814 119019, 220813 115886), (220813 120896, 221092 120703, 224225 120702, 224419 120992, 224419 124114, 224129 124308, 221007 124308, 220814 124029, 220813 120896), (220813 125906, 221092 125713, 224225 125712, 224419 126002, 224419 129124, 224129 129318, 221007 129318, 220814 129039, 220813 125906), (220817 130928, 220875 130826, 221092 130723, 224224 130722, 224419 130980, 224419 134134, 224129 134328, 221007 134328, 220814 134049, 220817 130928), (220813 135926, 221092 135733, 224225 135732, 224419 136022, 224419 139144, 224129 139338, 221007 139338, 220814 139059, 220813 135926), (220813 140936, 221092 140743, 224225 140742, 224419 141032, 224419 144155, 224129 144349, 221007 144349, 220814 144070, 220813 140936), (220817 145959, 220875 145857, 221092 145754, 224224 145753, 224419 146011, 224419 149129, 224356 149256, 224129 149359, 221007 149359, 220814 149080, 220817 145959), (220813 150957, 221092 150764, 224229 150763, 224420 151025, 224419 153830, 224086 154289, 223925 154369, 221007 154369, 220814 154090, 220813 150957), (220813 155967, 221092 155774, 222723 155773, 223018 155953, 223020 156163, 221903 158025, 221322 158809, 221114 158884, 220893 158815, 220816 158689, 220813 155967), (225823 90834, 225947 90704, 226647 90670, 226812 90811, 228240 93846, 228144 94220, 226062 94247, 225928 94185, 225824 93967, 225823 90834), (225827 95856, 225885 95754, 226102 95651, 228715 95650, 228959 95847, 229421 97145, 229429 99110, 229139 99258, 226017 99258, 225824 98979, 225827 95856), (225823 100856, 226102 100663, 229235 100662, 229429 100949, 229426 104055, 229367 104164, 229139 104268, 226017 104268, 225824 103989, 225823 100856), (225823 105866, 226102 105673, 229235 105672, 229429 105962, 229429 109084, 229139 109278, 226017 109278, 225824 108999, 225823 105866), (225823 110876, 226102 110683, 229235 110682, 229429 110972, 229429 114094, 229139 114288, 226017 114288, 225824 114009, 225823 110876), (225823 115886, 226102 115693, 229235 115692, 229429 115982, 229429 119104, 229139 119298, 226017 119298, 225824 119019, 225823 115886), (225823 120896, 226102 120703, 229235 120702, 229429 120992, 229429 124114, 229139 124308, 226017 124308, 225824 124029, 225823 120896), (225823 125906, 226102 125713, 229235 125712, 229429 126002, 229429 129124, 229139 129318, 226017 129318, 225824 129039, 225823 125906), (225827 130928, 225885 130826, 226102 130723, 229234 130722, 229429 130980, 229429 134098, 229366 134225, 229139 134328, 226017 134328, 225824 134049, 225827 130928), (225823 135926, 226102 135733, 229239 135732, 229423 135981, 229430 139145, 229139 139338, 226017 139338, 225824 139059, 225823 135926), (225823 140936, 226102 140743, 229234 140742, 229321 140799, 229430 141045, 229424 142854, 228945 144184, 228719 144349, 226017 144349, 225824 144070, 225823 140936), (225827 145959, 225885 145857, 226102 145754, 227959 145753, 228237 145902, 228270 146097, 226795 149218, 226530 149359, 225980 149330, 225823 149149, 225827 145959), (230833 105866, 231092 105676, 231645 105672, 231916 105817, 232120 106630, 232474 109033, 232410 109174, 232201 109275, 231027 109278, 230834 108999, 230833 105866), (230833 110876, 231112 110683, 232545 110685, 232673 110771, 232760 110936, 233109 113291, 233145 114063, 233067 114197, 232876 114286, 231027 114288, 230834 114009, 230833 110876), (230833 115886, 231112 115693, 233030 115692, 233165 115796, 233240 115976, 233390 119073, 233309 119211, 233102 119298, 231027 119298, 230834 119019, 230833 115886), (230833 120896, 231112 120703, 233251 120702, 233388 121017, 233236 124105, 233145 124231, 232989 124303, 231027 124308, 230834 124029, 230833 120896), (230833 125906, 231112 125713, 232943 125712, 233085 125836, 233142 126027, 233109 126714, 232748 129135, 232510 129312, 231027 129318, 230834 129039, 230833 125906), (230837 130928, 230895 130826, 231112 130723, 232281 130728, 232373 130781, 232463 131066, 232122 133357, 231927 134133, 231636 134328, 230994 134300, 230833 134118, 230837 130928), (95562 120036, 95660 121007, 95821 124226, 95776 124749, 95907 126017, 95946 126807, 96326 129356, 96337 129890, 96589 131141, 96947 133546, 97184 134481, 97245 134937, 98560 140189, 98926 141211, 99601 142910, 99694 143206, 100202 144618, 100294 145033, 100690 146135, 102400 149732, 102513 150088, 103757 152724, 104500 153963, 105131 154921, 105724 156050, 106205 156715, 107314 158564, 108020 159510, 108315 159997, 109487 161577, 109886 162031, 111364 164023, 112320 165075, 112712 165586, 114445 167497, 114948 167977, 115940 169069, 117139 170154, 117502 170553, 119413 172286, 120037 172785, 120983 173640, 123094 175204, 123358 175458, 124644 176418, 125625 177083, 126446 177692, 128484 178910, 129267 179440, 130141 179891, 130770 180281, 131038 180492, 132271 181239, 134909 182488, 135406 182669, 138448 184107, 138732 184210, 139778 184655, 140528 184852, 141941 185355, 142078 185426, 143739 186055, 144805 186437, 150062 187753, 150672 187857, 151457 188053, 153951 188422, 154465 188567, 155761 188692, 158216 189055, 159083 189095, 159601 189190, 160884 189186, 164094 189343, 165000 189439, 166007 189340, 169227 189178, 169749 189223, 171017 189092, 171807 189053, 174356 188672, 174880 188663, 176141 188410, 178542 188053, 179480 187816, 179937 187754, 185194 186437, 186211 186073, 187910 185398, 188205 185305, 189618 184797, 190033 184705, 191135 184309, 194734 182600, 195087 182486, 197729 181239, 198963 180499, 199921 179868, 201050 179275, 201715 178794, 203554 177692, 204386 177074, 204998 176683, 206577 175512, 207031 175112, 209026 173634, 209962 172786, 210585 172287, 212496 170554, 212977 170050, 214075 169053, 215051 167978, 215554 167497, 217286 165586, 217785 164962, 218636 164024, 220204 161905, 220458 161642, 221418 160355, 222084 159373, 222692 158553, 223832 156650, 224455 155706, 224891 154858, 225281 154229, 225492 153961, 226242 152724, 227486 150089, 227599 149733, 229107 146551, 229676 145157, 229797 144617, 230305 143206, 230397 142910, 231055 141261, 231439 140189, 232753 134938, 232815 134480, 233056 133522, 233401 131204, 233568 130587, 233667 129393, 234055 126795, 234090 126073, 234195 125463, 234175 124272, 234336 121063, 234405 120666, 234438 119965, 234344 119148, 234189 115930, 234233 115303, 234098 114138, 234053 113187, 233698 110798, 233683 110175, 233430 109014, 233053 106454, 232857 105672, 232755 105062, 231439 99810, 231073 98789, 230427 97079, 230356 96941, 229853 95528, 229705 94966, 229319 93893, 227670 90407, 227489 89910, 226238 87267, 225500 86035, 224869 85078, 224248 83900, 223872 83419, 222692 81446, 221979 80489, 221683 80001, 220512 78422, 220112 77968, 218600 75936, 217678 74924, 217287 74414, 215554 72503, 215153 72139, 214053 70923, 212861 69846, 212497 69445, 210585 67713, 210074 67320, 209026 66365, 206905 64795, 206642 64541, 205355 63581, 204497 63010, 203553 62307, 201515 61089, 200732 60559, 199858 60108, 199229 59718, 198961 59507, 197724 58757, 195090 57511, 194593 57330, 191551 55891, 191289 55799, 190228 55346, 189471 55147, 188058 54644, 187921 54572, 186261 53944, 185194 53562, 179938 52246, 179328 52142, 178530 51944, 176049 51577, 175535 51432, 174239 51307, 171795 50944, 170916 50904, 170394 50809, 169116 50812, 165906 50658, 164965 50562, 163993 50660, 160774 50821, 160253 50776, 158983 50906, 158192 50946, 155644 51327, 155113 51336, 153859 51589, 151457 51946, 150520 52183, 150063 52245, 144805 53562, 143789 53926, 142089 54601, 141794 54694, 140381 55202, 139966 55294, 138897 55677, 135267 57400, 134911 57513, 132275 58757, 131036 59500, 130078 60131, 128949 60724, 128284 61205, 126446 62307, 125489 63020, 125002 63315, 123422 64487, 122968 64887, 120936 66399, 119924 67321, 119414 67712, 117503 69445, 117022 69949, 115923 70946, 114846 72138, 114445 72502, 112713 74413, 112214 75037, 111359 75983, 109795 78094, 109541 78357, 108581 79644, 107915 80626, 107307 81446, 106089 83484, 105559 84267, 105108 85141, 104718 85770, 104507 86038, 103757 87275, 102511 89909, 102330 90406, 100893 93446, 100791 93732, 100346 94774, 100147 95528, 99644 96941, 99572 97078, 98944 98740, 98560 99810, 97245 105061, 97142 105672, 96943 106475, 96577 108951, 96429 109470, 96306 110761, 95944 113211, 95904 114084, 95809 114606, 95812 115885, 95659 119094, 95562 120036), (96456 120465, 96835 120253, 98916 120251, 99293 120434, 99616 120966, 99618 124095, 99434 124435, 98902 124758, 97006 124762, 96668 124602, 96314 124147, 96160 120984, 96456 120465), (96310 115908, 96644 115429, 97058 115241, 98916 115241, 99293 115424, 99616 115956, 99618 119085, 99434 119425, 98902 119748, 96819 119750, 96479 119568, 96157 119063, 96310 115908), (96689 125485, 97047 125267, 98916 125261, 99293 125444, 99616 125976, 99618 129105, 99434 129445, 98901 129768, 97676 129772, 97206 129646, 96817 129240, 96442 126751, 96405 125994, 96689 125485), (96408 114065, 96443 113244, 96800 110833, 97178 110390, 97538 110224, 98916 110231, 99293 110414, 99616 110946, 99618 114075, 99434 114415, 98902 114738, 97069 114739, 96711 114546, 96408 114065), (97317 130532, 97719 130277, 98915 130271, 99209 130398, 99400 130568, 99616 130985, 99618 134115, 99434 134455, 98991 134715, 98354 134728, 97983 134601, 97659 134317, 97435 133440, 97082 131069, 97317 130532), (97435 106557, 97626 105792, 97983 105400, 98379 105272, 99083 105308, 99388 105469, 99617 105897, 99618 109065, 99434 109405, 98902 109728, 97624 109729, 97341 109499, 97081 108982, 97435 106557), (100170 98954, 100142 97041, 100617 95696, 100887 95421, 101159 95272, 102040 95199, 103925 95199, 104219 95326, 104410 95496, 104626 95913, 104628 99045, 104444 99385, 103912 99708, 100783 99710, 100396 99484, 100231 99221, 100170 98954), (100171 100803, 100370 100464, 100797 100213, 103926 100211, 104303 100394, 104626 100926, 104628 104055, 104444 104395, 103912 104718, 100783 104720, 100445 104537, 100173 104087, 100171 100803), (100119 105903, 100360 105483, 100797 105223, 103926 105221, 104303 105404, 104626 105936, 104628 109065, 104444 109405, 103912 109728, 100783 109730, 100443 109546, 100121 109051, 100119 105903), (100302 110555, 100797 110233, 103926 110231, 104303 110414, 104626 110946, 104628 114075, 104444 114415, 103912 114738, 100783 114740, 100443 114556, 100121 114061, 100119 110932, 100302 110555), (100302 115565, 100797 115243, 103926 115241, 104303 115424, 104626 115956, 104628 119085, 104444 119425, 103912 119748, 100783 119750, 100443 119566, 100121 119071, 100119 115942, 100302 115565), (100302 120575, 100797 120253, 103926 120251, 104303 120434, 104626 120966, 104628 124095, 104444 124435, 103912 124758, 100783 124760, 100443 124576, 100121 124081, 100119 120952, 100302 120575), (100302 125585, 100797 125263, 103926 125261, 104303 125444, 104626 125976, 104628 129105, 104444 129445, 103911 129768, 100783 129770, 100443 129586, 100121 129091, 100119 125962, 100302 125585), (100305 130592, 100797 130273, 103925 130271, 104219 130398, 104410 130568, 104626 130985, 104628 134115, 104444 134455, 103912 134778, 100783 134780, 100443 134596, 100121 134101, 100119 130972, 100305 130592), (100295 135615, 100797 135283, 103926 135281, 104303 135464, 104626 135996, 104628 139125, 104444 139465, 103912 139788, 100783 139790, 100326 139480, 100170 139147, 100170 135903, 100295 135615), (100295 140624, 100797 140293, 103926 140291, 104303 140474, 104626 141006, 104628 144136, 104444 144476, 103903 144800, 101814 144808, 101162 144728, 100660 144408, 100111 142891, 100170 140994, 100295 140624), (101452 94348, 101264 93829, 102781 90619, 103140 90331, 103489 90240, 104102 90278, 104398 90437, 104627 90865, 104628 94033, 104444 94373, 103911 94696, 102040 94697, 101722 94556, 101452 94348), (101345 146338, 101375 145912, 101482 145627, 101858 145325, 103917 145301, 104362 145539, 104626 146016, 104628 149146, 104444 149486, 104203 149665, 103517 149757, 103140 149668, 102834 149479, 101345 146338), (105170 85989, 105543 85433, 106074 85230, 107276 85179, 108936 85179, 109313 85362, 109636 85894, 109638 89023, 109454 89363, 108922 89686, 105793 89688, 105337 89378, 105185 89015, 105180 87631, 105170 85989), (105129 90871, 105370 90451, 105807 90191, 108936 90189, 109313 90372, 109636 90904, 109638 94033, 109454 94373, 108921 94696, 105793 94698, 105453 94514, 105131 94019, 105129 90871), (105315 95520, 105807 95201, 108935 95199, 109229 95326, 109420 95496, 109636 95913, 109638 99045, 109454 99385, 108922 99708, 105793 99710, 105453 99526, 105131 99031, 105129 95900, 105315 95520), (105312 100535, 105807 100213, 108936 100211, 109313 100394, 109636 100926, 109638 104055, 109454 104395, 108922 104718, 105793 104720, 105453 104536, 105131 104041, 105129 100912, 105312 100535), (105312 105545, 105807 105223, 108936 105221, 109313 105404, 109636 105936, 109638 109065, 109454 109405, 108922 109728, 105793 109730, 105453 109546, 105131 109051, 105129 105922, 105312 105545), (105312 110555, 105807 110233, 108936 110231, 109313 110414, 109636 110946, 109638 114075, 109454 114415, 108922 114738, 105793 114740, 105453 114556, 105131 114061, 105129 110932, 105312 110555), (105312 115565, 105807 115243, 108936 115241, 109313 115424, 109636 115956, 109638 119085, 109454 119425, 108922 119748, 105793 119750, 105453 119566, 105131 119071, 105129 115942, 105312 115565), (105312 120575, 105807 120253, 108936 120251, 109313 120434, 109636 120966, 109638 124095, 109454 124435, 108922 124758, 105793 124760, 105453 124576, 105131 124081, 105129 120952, 105312 120575), (105312 125585, 105807 125263, 108936 125261, 109313 125444, 109636 125976, 109638 129105, 109454 129445, 108921 129768, 105793 129770, 105453 129586, 105131 129091, 105129 125962, 105312 125585), (105315 130592, 105807 130273, 108935 130271, 109229 130398, 109420 130568, 109636 130985, 109638 134115, 109454 134455, 108922 134778, 105793 134780, 105453 134596, 105131 134101, 105129 130972, 105315 130592), (105312 135605, 105807 135283, 108936 135281, 109313 135464, 109636 135996, 109638 139125, 109454 139465, 108922 139788, 105793 139790, 105453 139606, 105131 139111, 105129 135982, 105312 135605), (105312 140615, 105807 140293, 108936 140291, 109313 140474, 109636 141006, 109638 144136, 109454 144476, 108921 144799, 105793 144801, 105453 144617, 105131 144122, 105129 140992, 105312 140615), (105314 145624, 105807 145304, 108935 145302, 109229 145429, 109420 145599, 109636 146016, 109638 149146, 109454 149486, 108922 149809, 105793 149811, 105453 149627, 105131 149132, 105129 146003, 105314 145624), (105186 150923, 105237 150756, 105429 150526, 105807 150314, 108936 150312, 109313 150495, 109636 151027, 109638 154156, 109454 154496, 108922 154819, 107044 154823, 106074 154769, 105543 154566, 105179 154048, 105186 150923), (106642 84257, 106541 83704, 107721 81725, 108315 80922, 108977 80726, 109345 80863, 109508 81049, 109637 81345, 109638 84013, 109454 84353, 108922 84676, 107276 84677, 106933 84519, 106642 84257), (106602 155929, 106668 155697, 107087 155328, 108936 155322, 109313 155505, 109636 156037, 109632 158754, 109434 159040, 109094 159250, 108747 159294, 108386 159172, 107740 158300, 106633 156459, 106602 155929), (110191 78868, 110225 78358, 111751 76291, 112584 75373, 113065 75210, 114024 75210, 114313 75334, 114646 75874, 114648 79003, 114464 79343, 113932 79666, 110803 79668, 110419 79444, 110251 79178, 110191 78868), (110392 80419, 110817 80171, 113946 80169, 114323 80352, 114646 80884, 114648 84013, 114464 84353, 113932 84676, 110803 84678, 110463 84494, 110141 83999, 110139 81345, 110240 80627, 110392 80419), (110322 85503, 110817 85181, 113946 85179, 114323 85362, 114646 85894, 114648 89023, 114464 89363, 113932 89686, 110803 89688, 110463 89504, 110141 89009, 110139 85880, 110322 85503), (110322 90513, 110817 90191, 113946 90189, 114323 90372, 114646 90904, 114648 94033, 114464 94373, 113931 94696, 110803 94698, 110463 94514, 110141 94019, 110139 90890, 110322 90513), (110325 95520, 110817 95201, 113945 95199, 114239 95326, 114430 95496, 114646 95913, 114648 99045, 114464 99385, 113932 99708, 110803 99710, 110463 99526, 110141 99031, 110139 95900, 110325 95520), (110322 100535, 110817 100213, 113946 100211, 114323 100394, 114646 100926, 114648 104055, 114464 104395, 113932 104718, 110803 104720, 110463 104536, 110141 104041, 110139 100912, 110322 100535), (110322 105545, 110817 105223, 113946 105221, 114323 105404, 114646 105936, 114648 109065, 114464 109405, 113932 109728, 110803 109730, 110463 109546, 110141 109051, 110139 105922, 110322 105545), (110322 110555, 110817 110233, 113946 110231, 114323 110414, 114646 110946, 114648 114075, 114464 114415, 113932 114738, 110803 114740, 110463 114556, 110141 114061, 110139 110932, 110322 110555), (110322 115565, 110817 115243, 113946 115241, 114323 115424, 114646 115956, 114648 119085, 114464 119425, 113932 119748, 110803 119750, 110463 119566, 110141 119071, 110139 115942, 110322 115565), (110322 120575, 110817 120253, 113946 120251, 114323 120434, 114646 120966, 114648 124095, 114464 124435, 113932 124758, 110803 124760, 110463 124576, 110141 124081, 110139 120952, 110322 120575), (110322 125585, 110817 125263, 113946 125261, 114323 125444, 114646 125976, 114648 129105, 114464 129445, 113931 129768, 110803 129770, 110463 129586, 110141 129091, 110139 125962, 110322 125585), (110325 130592, 110817 130273, 113945 130271, 114239 130398, 114430 130568, 114646 130985, 114648 134115, 114464 134455, 113932 134778, 110803 134780, 110463 134596, 110141 134101, 110139 130972, 110325 130592), (110322 135605, 110817 135283, 113946 135281, 114323 135464, 114646 135996, 114648 139125, 114464 139465, 113932 139788, 110803 139790, 110463 139606, 110141 139111, 110139 135982, 110322 135605), (110322 140615, 110817 140293, 113946 140291, 114323 140474, 114646 141006, 114648 144136, 114464 144476, 113931 144799, 110803 144801, 110463 144617, 110141 144122, 110139 140992, 110322 140615), (110325 145623, 110817 145304, 113945 145302, 114239 145429, 114430 145599, 114646 146016, 114648 149146, 114464 149486, 113932 149809, 110803 149811, 110463 149627, 110141 149132, 110139 146003, 110325 145623), (110322 150636, 110817 150314, 113946 150312, 114323 150495, 114646 151027, 114648 154156, 114464 154496, 113932 154819, 110803 154821, 110463 154637, 110141 154142, 110139 151013, 110322 150636), (110322 155646, 110817 155324, 113946 155322, 114323 155505, 114646 156037, 114648 159166, 114464 159506, 113932 159829, 110820 159830, 110488 159666, 110348 159524, 110209 159228, 110136 158797, 110139 156023, 110322 155646), (110213 160978, 110331 160624, 110476 160485, 110813 160332, 113946 160332, 114323 160515, 114646 161047, 114648 164176, 114464 164516, 114022 164789, 113065 164789, 112663 164705, 111728 163680, 110287 161735, 110213 160978), (115200 72495, 116284 71291, 117356 70319, 117793 70200, 119034 70200, 119323 70324, 119656 70864, 119658 73993, 119474 74333, 118942 74656, 115813 74658, 115473 74474, 115200 74035, 115200 72495), (115332 75483, 115827 75161, 118956 75159, 119333 75342, 119656 75874, 119658 79003, 119474 79343, 118942 79666, 115813 79668, 115473 79484, 115151 78989, 115149 75860, 115332 75483), (115332 80493, 115827 80171, 118956 80169, 119333 80352, 119656 80884, 119658 84013, 119474 84353, 118942 84676, 115813 84678, 115473 84494, 115151 83999, 115149 80870, 115332 80493), (115332 85503, 115827 85181, 118956 85179, 119333 85362, 119656 85894, 119658 89023, 119474 89363, 118942 89686, 115813 89688, 115473 89504, 115151 89009, 115149 85880, 115332 85503), (115332 90513, 115827 90191, 118956 90189, 119333 90372, 119656 90904, 119658 94033, 119474 94373, 118941 94696, 115813 94698, 115473 94514, 115151 94019, 115149 90890, 115332 90513), (115335 95520, 115827 95201, 118955 95199, 119249 95326, 119440 95496, 119656 95913, 119658 99045, 119474 99385, 118942 99708, 115813 99710, 115473 99526, 115151 99031, 115149 95900, 115335 95520), (115332 100535, 115827 100213, 118956 100211, 119333 100394, 119656 100926, 119658 104055, 119474 104395, 118942 104718, 115813 104720, 115473 104536, 115151 104041, 115149 100912, 115332 100535), (115332 105545, 115827 105223, 118956 105221, 119333 105404, 119656 105936, 119658 109065, 119474 109405, 118942 109728, 115813 109730, 115473 109546, 115151 109051, 115149 105922, 115332 105545), (115332 110555, 115827 110233, 118956 110231, 119333 110414, 119656 110946, 119658 114075, 119474 114415, 118942 114738, 115813 114740, 115473 114556, 115151 114061, 115149 110932, 115332 110555), (115332 115565, 115827 115243, 118956 115241, 119333 115424, 119656 115956, 119658 119085, 119474 119425, 118942 119748, 115813 119750, 115473 119566, 115151 119071, 115149 115942, 115332 115565), (115332 120575, 115827 120253, 118956 120251, 119333 120434, 119656 120966, 119658 124095, 119474 124435, 118942 124758, 115813 124760, 115473 124576, 115151 124081, 115149 120952, 115332 120575), (115332 125585, 115827 125263, 118956 125261, 119333 125444, 119656 125976, 119658 129105, 119474 129445, 118941 129768, 115813 129770, 115473 129586, 115151 129091, 115149 125962, 115332 125585), (115335 130592, 115827 130273, 118955 130271, 119249 130398, 119440 130568, 119656 130985, 119658 134115, 119474 134455, 118942 134778, 115813 134780, 115473 134596, 115151 134101, 115149 130972, 115335 130592), (115332 135605, 115827 135283, 118956 135281, 119333 135464, 119656 135996, 119658 139125, 119474 139465, 118942 139788, 115813 139790, 115473 139606, 115151 139111, 115149 135982, 115332 135605), (115332 140615, 115827 140293, 118956 140291, 119333 140474, 119656 141006, 119658 144136, 119474 144476, 118941 144799, 115813 144801, 115473 144617, 115151 144122, 115149 140992, 115332 140615), (115335 145623, 115827 145304, 118955 145302, 119249 145429, 119440 145599, 119656 146016, 119658 149146, 119474 149486, 118942 149809, 115813 149811, 115473 149627, 115151 149132, 115149 146003, 115335 145623), (115332 150636, 115827 150314, 118956 150312, 119333 150495, 119656 151027, 119658 154156, 119474 154496, 118942 154819, 115813 154821, 115473 154637, 115151 154142, 115149 151013, 115332 150636), (115332 155646, 115827 155324, 118956 155322, 119333 155505, 119656 156037, 119658 159166, 119474 159506, 118942 159829, 115813 159831, 115473 159647, 115151 159152, 115149 156023, 115332 155646), (115332 160656, 115827 160334, 118956 160332, 119333 160515, 119656 161047, 119658 164176, 119474 164516, 118942 164839, 115813 164841, 115473 164657, 115151 164162, 115149 161033, 115332 160656), (115200 165965, 115325 165676, 115827 165344, 118956 165342, 119333 165525, 119656 166057, 119658 169186, 119474 169526, 119032 169799, 117495 169799, 116287 168711, 115318 167643, 115200 167206, 115200 165965), (120293 67663, 121292 66750, 123264 65287, 124021 65213, 124367 65325, 124514 65476, 124667 65813, 124668 68983, 124484 69323, 123952 69646, 120823 69648, 120483 69464, 120210 69025, 120210 68065, 120293 67663), (120342 70473, 120837 70151, 123966 70149, 124343 70332, 124666 70864, 124668 73993, 124484 74333, 123952 74656, 120823 74658, 120483 74474, 120161 73979, 120159 70850, 120342 70473), (120342 75483, 120837 75161, 123966 75159, 124343 75342, 124666 75874, 124668 79003, 124484 79343, 123952 79666, 120823 79668, 120483 79484, 120161 78989, 120159 75860, 120342 75483), (120342 80493, 120837 80171, 123966 80169, 124343 80352, 124666 80884, 124668 84013, 124484 84353, 123952 84676, 120823 84678, 120483 84494, 120161 83999, 120159 80870, 120342 80493), (120342 85503, 120837 85181, 123966 85179, 124343 85362, 124666 85894, 124668 89023, 124484 89363, 123952 89686, 120823 89688, 120483 89504, 120161 89009, 120159 85880, 120342 85503), (120342 90513, 120837 90191, 123966 90189, 124343 90372, 124666 90904, 124668 94033, 124484 94373, 123951 94696, 120823 94698, 120483 94514, 120161 94019, 120159 90890, 120342 90513), (120345 95520, 120837 95201, 123965 95199, 124259 95326, 124450 95496, 124666 95913, 124668 99045, 124484 99385, 123952 99708, 120823 99710, 120483 99526, 120161 99031, 120159 95900, 120345 95520), (120342 100535, 120837 100213, 123966 100211, 124343 100394, 124666 100926, 124668 104055, 124484 104395, 123952 104718, 120823 104720, 120483 104536, 120161 104041, 120159 100912, 120342 100535), (120342 105545, 120837 105223, 123966 105221, 124343 105404, 124666 105936, 124668 109065, 124484 109405, 123952 109728, 120823 109730, 120483 109546, 120161 109051, 120159 105922, 120342 105545), (120342 110555, 120837 110233, 123966 110231, 124343 110414, 124666 110946, 124668 114075, 124484 114415, 123952 114738, 120823 114740, 120483 114556, 120161 114061, 120159 110932, 120342 110555), (120342 115565, 120837 115243, 123966 115241, 124343 115424, 124666 115956, 124668 119085, 124484 119425, 123952 119748, 120823 119750, 120483 119566, 120161 119071, 120159 115942, 120342 115565), (120342 120575, 120837 120253, 123966 120251, 124343 120434, 124666 120966, 124668 124095, 124484 124435, 123952 124758, 120823 124760, 120483 124576, 120161 124081, 120159 120952, 120342 120575), (120342 125585, 120837 125263, 123966 125261, 124343 125444, 124666 125976, 124668 129105, 124484 129445, 123951 129768, 120823 129770, 120483 129586, 120161 129091, 120159 125962, 120342 125585), (120345 130592, 120837 130273, 123965 130271, 124259 130398, 124450 130568, 124666 130985, 124668 134115, 124484 134455, 123952 134778, 120823 134780, 120483 134596, 120161 134101, 120159 130972, 120345 130592), (120342 135605, 120837 135283, 123966 135281, 124343 135464, 124666 135996, 124668 139125, 124484 139465, 123952 139788, 120823 139790, 120483 139606, 120161 139111, 120159 135982, 120342 135605), (120342 140615, 120837 140293, 123966 140291, 124343 140474, 124666 141006, 124668 144136, 124484 144476, 123951 144799, 120823 144801, 120483 144617, 120161 144122, 120159 140992, 120342 140615), (120345 145623, 120837 145304, 123965 145302, 124259 145429, 124450 145599, 124666 146016, 124668 149146, 124484 149486, 123952 149809, 120823 149811, 120483 149627, 120161 149132, 120159 146003, 120345 145623), (120342 150636, 120837 150314, 123966 150312, 124343 150495, 124666 151027, 124668 154156, 124484 154496, 123952 154819, 120823 154821, 120483 154637, 120161 154142, 120159 151013, 120342 150636), (120342 155646, 120837 155324, 123966 155322, 124343 155505, 124666 156037, 124668 159166, 124484 159506, 123952 159829, 120823 159831, 120483 159647, 120161 159152, 120159 156023, 120342 155646), (120342 160656, 120837 160334, 123966 160332, 124343 160515, 124666 161047, 124668 164176, 124484 164516, 123952 164839, 120823 164841, 120483 164657, 120161 164162, 120159 161033, 120342 160656), (120342 165666, 120837 165344, 123966 165342, 124343 165525, 124666 166057, 124668 169186, 124484 169526, 123952 169849, 120823 169851, 120483 169667, 120161 169172, 120159 166043, 120342 165666), (120210 170975, 120335 170686, 120837 170354, 123966 170352, 124343 170535, 124666 171067, 124668 174196, 124445 174580, 124178 174748, 123868 174808, 123358 174774, 121318 173270, 120373 172415, 120210 171934, 120210 170975), (125169 65820, 125333 65488, 125475 65348, 125770 65208, 126359 65139, 128976 65139, 129353 65322, 129676 65854, 129678 68983, 129494 69323, 128962 69646, 125833 69648, 125493 69464, 125171 68969, 125169 65820), (125352 70473, 125847 70151, 128976 70149, 129353 70332, 129676 70864, 129678 73993, 129494 74333, 128962 74656, 125833 74658, 125493 74474, 125171 73979, 125169 70850, 125352 70473), (125352 75483, 125847 75161, 128976 75159, 129353 75342, 129676 75874, 129678 79003, 129494 79343, 128962 79666, 125833 79668, 125493 79484, 125171 78989, 125169 75860, 125352 75483), (125352 80493, 125847 80171, 128976 80169, 129353 80352, 129676 80884, 129678 84013, 129494 84353, 128962 84676, 125833 84678, 125493 84494, 125171 83999, 125169 80870, 125352 80493), (125352 85503, 125847 85181, 128976 85179, 129353 85362, 129676 85894, 129678 89023, 129494 89363, 128962 89686, 125833 89688, 125493 89504, 125171 89009, 125169 85880, 125352 85503), (125352 90513, 125847 90191, 128976 90189, 129353 90372, 129676 90904, 129678 94033, 129494 94373, 128961 94696, 125833 94698, 125493 94514, 125171 94019, 125169 90890, 125352 90513), (125355 95520, 125847 95201, 128975 95199, 129269 95326, 129460 95496, 129676 95913, 129678 99045, 129494 99385, 128962 99708, 125833 99710, 125493 99526, 125171 99031, 125169 95900, 125355 95520), (125352 100535, 125847 100213, 128976 100211, 129353 100394, 129676 100926, 129678 104055, 129494 104395, 128962 104718, 125833 104720, 125493 104536, 125171 104041, 125169 100912, 125352 100535), (125352 105545, 125847 105223, 128976 105221, 129353 105404, 129676 105936, 129678 109065, 129494 109405, 128962 109728, 125833 109730, 125493 109546, 125171 109051, 125169 105922, 125352 105545), (125352 110555, 125847 110233, 128976 110231, 129353 110414, 129676 110946, 129678 114075, 129494 114415, 128962 114738, 125833 114740, 125493 114556, 125171 114061, 125169 110932, 125352 110555), (125352 115565, 125847 115243, 128976 115241, 129353 115424, 129676 115956, 129678 119085, 129494 119425, 128962 119748, 125833 119750, 125493 119566, 125171 119071, 125169 115942, 125352 115565), (125352 120575, 125847 120253, 128976 120251, 129353 120434, 129676 120966, 129678 124095, 129494 124435, 128962 124758, 125833 124760, 125493 124576, 125171 124081, 125169 120952, 125352 120575), (125352 125585, 125847 125263, 128976 125261, 129353 125444, 129676 125976, 129678 129105, 129494 129445, 128961 129768, 125833 129770, 125493 129586, 125171 129091, 125169 125962, 125352 125585), (125355 130592, 125847 130273, 128975 130271, 129269 130398, 129460 130568, 129676 130985, 129678 134115, 129494 134455, 128962 134778, 125833 134780, 125493 134596, 125171 134101, 125169 130972, 125355 130592), (125352 135605, 125847 135283, 128976 135281, 129353 135464, 129676 135996, 129678 139125, 129494 139465, 128962 139788, 125833 139790, 125493 139606, 125171 139111, 125169 135982, 125352 135605), (125352 140615, 125847 140293, 128976 140291, 129353 140474, 129676 141006, 129678 144136, 129494 144476, 128961 144799, 125833 144801, 125493 144617, 125171 144122, 125169 140992, 125352 140615), (125355 145623, 125847 145304, 128975 145302, 129269 145429, 129460 145599, 129676 146016, 129678 149146, 129494 149486, 128962 149809, 125833 149811, 125493 149627, 125171 149132, 125169 146003, 125355 145623), (125352 150636, 125847 150314, 128976 150312, 129353 150495, 129676 151027, 129678 154156, 129494 154496, 128962 154819, 125833 154821, 125493 154637, 125171 154142, 125169 151013, 125352 150636), (125352 155646, 125847 155324, 128976 155322, 129353 155505, 129676 156037, 129678 159166, 129494 159506, 128962 159829, 125833 159831, 125493 159647, 125171 159152, 125169 156023, 125352 155646), (125352 160656, 125847 160334, 128976 160332, 129353 160515, 129676 161047, 129678 164176, 129494 164516, 128962 164839, 125833 164841, 125493 164657, 125171 164162, 125169 161033, 125352 160656), (125352 165666, 125847 165344, 128976 165342, 129353 165525, 129676 166057, 129678 169186, 129494 169526, 128962 169849, 125833 169851, 125493 169667, 125171 169172, 125169 166043, 125352 165666), (125352 170676, 125847 170354, 128976 170352, 129353 170535, 129676 171067, 129678 174196, 129494 174536, 128962 174859, 126188 174863, 125628 174759, 125420 174607, 125171 174182, 125169 171053, 125352 170676), (125705 63747, 125823 63397, 126723 62722, 128540 61633, 129070 61602, 129302 61668, 129677 62201, 129678 63973, 129494 64313, 128962 64636, 126359 64637, 126084 64520, 125877 64345, 125749 64094, 125705 63747), (125726 176022, 125864 175654, 126231 175368, 128976 175362, 129353 175545, 129676 176077, 129672 177837, 129257 178357, 128704 178458, 126725 177278, 125923 176683, 125726 176022), (130433 60543, 130951 60179, 134076 60186, 134422 60367, 134686 60844, 134688 63973, 134504 64313, 133972 64636, 130843 64638, 130503 64454, 130181 63959, 130179 62201, 130230 61074, 130433 60543), (130362 65463, 130857 65141, 133986 65139, 134363 65322, 134686 65854, 134688 68983, 134504 69323, 133972 69646, 130843 69648, 130503 69464, 130181 68969, 130179 65840, 130362 65463), (130362 70473, 130857 70151, 133986 70149, 134363 70332, 134686 70864, 134688 73993, 134504 74333, 133972 74656, 130843 74658, 130503 74474, 130181 73979, 130179 70850, 130362 70473), (130362 75483, 130857 75161, 133986 75159, 134363 75342, 134686 75874, 134688 79003, 134504 79343, 133972 79666, 130843 79668, 130503 79484, 130181 78989, 130179 75860, 130362 75483), (130362 80493, 130857 80171, 133986 80169, 134363 80352, 134686 80884, 134688 84013, 134504 84353, 133972 84676, 130843 84678, 130503 84494, 130181 83999, 130179 80870, 130362 80493), (130362 85503, 130857 85181, 133986 85179, 134363 85362, 134686 85894, 134688 89023, 134504 89363, 133972 89686, 130843 89688, 130503 89504, 130181 89009, 130179 85880, 130362 85503), (130362 90513, 130857 90191, 133986 90189, 134363 90372, 134686 90904, 134688 94033, 134504 94373, 133971 94696, 130843 94698, 130503 94514, 130181 94019, 130179 90890, 130362 90513), (130365 95520, 130857 95201, 133985 95199, 134279 95326, 134470 95496, 134686 95913, 134688 99045, 134504 99385, 133972 99708, 130843 99710, 130503 99526, 130181 99031, 130179 95900, 130365 95520), (130362 100535, 130857 100213, 133986 100211, 134363 100394, 134686 100926, 134688 104055, 134504 104395, 133972 104718, 130843 104720, 130503 104536, 130181 104041, 130179 100912, 130362 100535), (130362 105545, 130857 105223, 133986 105221, 134363 105404, 134686 105936, 134688 109065, 134504 109405, 133972 109728, 130843 109730, 130503 109546, 130181 109051, 130179 105922, 130362 105545), (130362 110555, 130857 110233, 133986 110231, 134363 110414, 134686 110946, 134688 114075, 134504 114415, 133972 114738, 130843 114740, 130503 114556, 130181 114061, 130179 110932, 130362 110555), (130362 115565, 130857 115243, 133986 115241, 134363 115424, 134686 115956, 134688 119085, 134504 119425, 133972 119748, 130843 119750, 130503 119566, 130181 119071, 130179 115942, 130362 115565), (130362 120575, 130857 120253, 133986 120251, 134363 120434, 134686 120966, 134688 124095, 134504 124435, 133972 124758, 130843 124760, 130503 124576, 130181 124081, 130179 120952, 130362 120575), (130362 125585, 130857 125263, 133986 125261, 134363 125444, 134686 125976, 134688 129105, 134504 129445, 133971 129768, 130843 129770, 130503 129586, 130181 129091, 130179 125962, 130362 125585), (130365 130592, 130857 130273, 133985 130271, 134279 130398, 134470 130568, 134686 130985, 134688 134115, 134504 134455, 133972 134778, 130843 134780, 130503 134596, 130181 134101, 130179 130972, 130365 130592), (130362 135605, 130857 135283, 133986 135281, 134363 135464, 134686 135996, 134688 139125, 134504 139465, 133972 139788, 130843 139790, 130503 139606, 130181 139111, 130179 135982, 130362 135605), (130362 140615, 130857 140293, 133986 140291, 134363 140474, 134686 141006, 134688 144136, 134504 144476, 133971 144799, 130843 144801, 130503 144617, 130181 144122, 130179 140992, 130362 140615), (130365 145623, 130857 145304, 133985 145302, 134279 145429, 134470 145599, 134686 146016, 134688 149146, 134504 149486, 133972 149809, 130843 149811, 130503 149627, 130181 149132, 130179 146003, 130365 145623), (130362 150636, 130857 150314, 133986 150312, 134363 150495, 134686 151027, 134688 154156, 134504 154496, 133972 154819, 130843 154821, 130503 154637, 130181 154142, 130179 151013, 130362 150636), (130362 155646, 130857 155324, 133986 155322, 134363 155505, 134686 156037, 134688 159166, 134504 159506, 133972 159829, 130843 159831, 130503 159647, 130181 159152, 130179 156023, 130362 155646), (130362 160656, 130857 160334, 133986 160332, 134363 160515, 134686 161047, 134688 164176, 134504 164516, 133972 164839, 130843 164841, 130503 164657, 130181 164162, 130179 161033, 130362 160656), (130362 165666, 130857 165344, 133986 165342, 134363 165525, 134686 166057, 134688 169186, 134504 169526, 133972 169849, 130843 169851, 130503 169667, 130181 169172, 130179 166043, 130362 165666), (130362 170676, 130857 170354, 133986 170352, 134363 170535, 134686 171067, 134688 174196, 134504 174536, 133972 174859, 130843 174861, 130503 174677, 130181 174182, 130179 171053, 130362 170676), (130362 175686, 130857 175364, 133986 175362, 134363 175545, 134686 176077, 134688 179206, 134378 179662, 134015 179814, 132626 179819, 130989 179829, 130433 179456, 130230 178925, 130176 177880, 130179 176063, 130362 175686), (135331 58140, 135520 57834, 138682 56338, 139108 56368, 139389 56471, 139512 56585, 139697 56965, 139698 58963, 139514 59303, 138982 59626, 135853 59628, 135454 59389, 135334 59203, 135242 58517, 135331 58140), (135372 60453, 135867 60131, 138996 60129, 139373 60312, 139696 60844, 139698 63973, 139514 64313, 138982 64636, 135853 64638, 135513 64454, 135191 63959, 135189 60830, 135372 60453), (135372 65463, 135867 65141, 138996 65139, 139373 65322, 139696 65854, 139698 68983, 139514 69323, 138982 69646, 135853 69648, 135513 69464, 135191 68969, 135189 65840, 135372 65463), (135372 70473, 135867 70151, 138996 70149, 139373 70332, 139696 70864, 139698 73993, 139514 74333, 138982 74656, 135853 74658, 135513 74474, 135191 73979, 135189 70850, 135372 70473), (135372 75483, 135867 75161, 138996 75159, 139373 75342, 139696 75874, 139698 79003, 139514 79343, 138982 79666, 135853 79668, 135513 79484, 135191 78989, 135189 75860, 135372 75483), (135372 80493, 135867 80171, 138996 80169, 139373 80352, 139696 80884, 139698 84013, 139514 84353, 138982 84676, 135853 84678, 135513 84494, 135191 83999, 135189 80870, 135372 80493), (135372 85503, 135867 85181, 138996 85179, 139373 85362, 139696 85894, 139698 89023, 139514 89363, 138982 89686, 135853 89688, 135513 89504, 135191 89009, 135189 85880, 135372 85503), (135372 90513, 135867 90191, 138996 90189, 139373 90372, 139696 90904, 139698 94033, 139514 94373, 138981 94696, 135853 94698, 135513 94514, 135191 94019, 135189 90890, 135372 90513), (135375 95520, 135867 95201, 138995 95199, 139289 95326, 139480 95496, 139696 95913, 139698 99045, 139514 99385, 138982 99708, 135853 99710, 135513 99526, 135191 99031, 135189 95900, 135375 95520), (135372 100535, 135867 100213, 138996 100211, 139373 100394, 139696 100926, 139698 104055, 139514 104395, 138982 104718, 135853 104720, 135513 104536, 135191 104041, 135189 100912, 135372 100535), (135372 105545, 135867 105223, 138996 105221, 139373 105404, 139696 105936, 139698 109065, 139514 109405, 138982 109728, 135853 109730, 135513 109546, 135191 109051, 135189 105922, 135372 105545), (135372 110555, 135867 110233, 138996 110231, 139373 110414, 139696 110946, 139698 114075, 139514 114415, 138982 114738, 135853 114740, 135513 114556, 135191 114061, 135189 110932, 135372 110555), (135372 115565, 135867 115243, 138996 115241, 139373 115424, 139696 115956, 139698 119085, 139514 119425, 138982 119748, 135853 119750, 135513 119566, 135191 119071, 135189 115942, 135372 115565), (135372 120575, 135867 120253, 138996 120251, 139373 120434, 139696 120966, 139698 124095, 139514 124435, 138982 124758, 135853 124760, 135513 124576, 135191 124081, 135189 120952, 135372 120575), (135372 125585, 135867 125263, 138996 125261, 139373 125444, 139696 125976, 139698 129105, 139514 129445, 138981 129768, 135853 129770, 135513 129586, 135191 129091, 135189 125962, 135372 125585), (135375 130592, 135867 130273, 138995 130271, 139289 130398, 139480 130568, 139696 130985, 139698 134115, 139514 134455, 138982 134778, 135853 134780, 135513 134596, 135191 134101, 135189 130972, 135375 130592), (135372 135605, 135867 135283, 138996 135281, 139373 135464, 139696 135996, 139698 139125, 139514 139465, 138982 139788, 135853 139790, 135513 139606, 135191 139111, 135189 135982, 135372 135605), (135372 140615, 135867 140293, 138996 140291, 139373 140474, 139696 141006, 139698 144136, 139514 144476, 138981 144799, 135853 144801, 135513 144617, 135191 144122, 135189 140992, 135372 140615), (135375 145623, 135867 145304, 138995 145302, 139289 145429, 139480 145599, 139696 146016, 139698 149146, 139514 149486, 138982 149809, 135853 149811, 135513 149627, 135191 149132, 135189 146003, 135375 145623), (135372 150636, 135867 150314, 138996 150312, 139373 150495, 139696 151027, 139698 154156, 139514 154496, 138982 154819, 135853 154821, 135513 154637, 135191 154142, 135189 151013, 135372 150636), (135372 155646, 135867 155324, 138996 155322, 139373 155505, 139696 156037, 139698 159166, 139514 159506, 138982 159829, 135853 159831, 135513 159647, 135191 159152, 135189 156023, 135372 155646), (135372 160656, 135867 160334, 138996 160332, 139373 160515, 139696 161047, 139698 164176, 139514 164516, 138982 164839, 135853 164841, 135513 164657, 135191 164162, 135189 161033, 135372 160656), (135372 165666, 135867 165344, 138996 165342, 139373 165525, 139696 166057, 139698 169186, 139514 169526, 138982 169849, 135853 169851, 135513 169667, 135191 169172, 135189 166043, 135372 165666), (135372 170676, 135867 170354, 138996 170352, 139373 170535, 139696 171067, 139698 174196, 139514 174536, 138982 174859, 135853 174861, 135513 174677, 135191 174182, 135189 171053, 135372 170676), (135372 175686, 135867 175364, 138996 175362, 139373 175545, 139696 176077, 139698 179206, 139514 179546, 138982 179869, 135871 179870, 135451 179629, 135191 179192, 135189 176063, 135372 175686), (135240 181510, 135278 180896, 135438 180601, 135865 180372, 138996 180372, 139373 180555, 139696 181087, 139692 183073, 139348 183547, 138829 183735, 135619 182218, 135331 181859, 135240 181510), (140273 56156, 140591 55660, 142108 55111, 144006 55170, 144376 55295, 144708 55834, 144710 58963, 144526 59303, 143994 59626, 140863 59628, 140523 59444, 140201 58949, 140199 56965, 140273 56156), (140382 60453, 140877 60131, 144008 60129, 144385 60312, 144708 60844, 144710 63973, 144526 64313, 143994 64636, 140863 64638, 140523 64454, 140201 63959, 140199 60830, 140382 60453), (140382 65463, 140877 65141, 144008 65139, 144385 65322, 144708 65854, 144710 68983, 144526 69323, 143994 69646, 140863 69648, 140523 69464, 140201 68969, 140199 65840, 140382 65463), (140382 70473, 140877 70151, 144008 70149, 144385 70332, 144708 70864, 144710 73993, 144526 74333, 143994 74656, 140863 74658, 140523 74474, 140201 73979, 140199 70850, 140382 70473), (140382 75483, 140877 75161, 144008 75159, 144385 75342, 144708 75874, 144710 79003, 144526 79343, 143994 79666, 140863 79668, 140523 79484, 140201 78989, 140199 75860, 140382 75483), (140382 80493, 140877 80171, 144008 80169, 144385 80352, 144708 80884, 144710 84013, 144526 84353, 143994 84676, 140863 84678, 140523 84494, 140201 83999, 140199 80870, 140382 80493), (140382 85503, 140877 85181, 144008 85179, 144385 85362, 144708 85894, 144710 89023, 144526 89363, 143994 89686, 140863 89688, 140523 89504, 140201 89009, 140199 85880, 140382 85503), (140382 90513, 140877 90191, 144008 90189, 144385 90372, 144708 90904, 144710 94033, 144526 94373, 143993 94696, 140863 94698, 140523 94514, 140201 94019, 140199 90890, 140382 90513), (140385 95520, 140877 95201, 144007 95199, 144301 95326, 144492 95496, 144708 95913, 144710 99045, 144526 99385, 143994 99708, 140863 99710, 140523 99526, 140201 99031, 140199 95900, 140385 95520), (140382 100535, 140877 100213, 144008 100211, 144385 100394, 144708 100926, 144710 104055, 144526 104395, 143994 104718, 140863 104720, 140523 104536, 140201 104041, 140199 100912, 140382 100535), (140382 105545, 140877 105223, 144008 105221, 144385 105404, 144708 105936, 144710 109065, 144526 109405, 143994 109728, 140863 109730, 140523 109546, 140201 109051, 140199 105922, 140382 105545), (140382 110555, 140877 110233, 144008 110231, 144385 110414, 144708 110946, 144710 114075, 144526 114415, 143994 114738, 140863 114740, 140523 114556, 140201 114061, 140199 110932, 140382 110555), (140382 115565, 140877 115243, 144008 115241, 144385 115424, 144708 115956, 144710 119085, 144526 119425, 143994 119748, 140863 119750, 140523 119566, 140201 119071, 140199 115942, 140382 115565), (140382 120575, 140877 120253, 144008 120251, 144385 120434, 144708 120966, 144710 124095, 144526 124435, 143994 124758, 140863 124760, 140523 124576, 140201 124081, 140199 120952, 140382 120575), (140382 125585, 140877 125263, 144008 125261, 144385 125444, 144708 125976, 144710 129105, 144526 129445, 143993 129768, 140863 129770, 140523 129586, 140201 129091, 140199 125962, 140382 125585), (140385 130592, 140877 130273, 144007 130271, 144301 130398, 144492 130568, 144708 130985, 144710 134115, 144526 134455, 143994 134778, 140863 134780, 140523 134596, 140201 134101, 140199 130972, 140385 130592), (140382 135605, 140877 135283, 144008 135281, 144385 135464, 144708 135996, 144710 139125, 144526 139465, 143994 139788, 140863 139790, 140523 139606, 140201 139111, 140199 135982, 140382 135605), (140382 140615, 140877 140293, 144008 140291, 144385 140474, 144708 141006, 144710 144136, 144526 144476, 143993 144799, 140863 144801, 140523 144617, 140201 144122, 140199 140992, 140382 140615), (140385 145623, 140877 145304, 144007 145302, 144301 145429, 144492 145599, 144708 146016, 144710 149146, 144526 149486, 143994 149809, 140863 149811, 140523 149627, 140201 149132, 140199 146003, 140385 145623), (140382 150636, 140877 150314, 144008 150312, 144385 150495, 144708 151027, 144710 154156, 144526 154496, 143994 154819, 140863 154821, 140523 154637, 140201 154142, 140199 151013, 140382 150636), (140382 155646, 140877 155324, 144008 155322, 144385 155505, 144708 156037, 144710 159166, 144526 159506, 143994 159829, 140863 159831, 140523 159647, 140201 159152, 140199 156023, 140382 155646), (140382 160656, 140877 160334, 144008 160332, 144385 160515, 144708 161047, 144710 164176, 144526 164516, 143994 164839, 140863 164841, 140523 164657, 140201 164162, 140199 161033, 140382 160656), (140382 165666, 140877 165344, 144008 165342, 144385 165525, 144708 166057, 144710 169186, 144526 169526, 143994 169849, 140863 169851, 140523 169667, 140201 169172, 140199 166043, 140382 165666), (140382 170676, 140877 170354, 144008 170352, 144385 170535, 144708 171067, 144710 174196, 144526 174536, 143994 174859, 140863 174861, 140523 174677, 140201 174182, 140199 171053, 140382 170676), (140382 175686, 140877 175364, 144008 175362, 144385 175545, 144708 176077, 144710 179206, 144526 179546, 143994 179869, 140863 179871, 140523 179687, 140201 179192, 140199 176063, 140382 175686), (140382 180696, 140877 180374, 144008 180372, 144385 180555, 144708 181087, 144710 184216, 144485 184603, 144221 184768, 143954 184829, 142044 184858, 140696 184382, 140421 184112, 140272 183840, 140196 183116, 140199 181073, 140382 180696), (145338 55527, 145520 55326, 145853 55170, 149097 55170, 149385 55294, 149718 55834, 149720 58963, 149536 59303, 149004 59626, 145875 59628, 145535 59444, 145213 58949, 145211 55820, 145338 55527), (145394 60453, 145889 60131, 149018 60129, 149395 60312, 149718 60844, 149720 63973, 149536 64313, 149004 64636, 145875 64638, 145535 64454, 145213 63959, 145211 60830, 145394 60453), (145394 65463, 145889 65141, 149018 65139, 149395 65322, 149718 65854, 149720 68983, 149536 69323, 149004 69646, 145875 69648, 145535 69464, 145213 68969, 145211 65840, 145394 65463), (145394 70473, 145889 70151, 149018 70149, 149395 70332, 149718 70864, 149720 73993, 149536 74333, 149004 74656, 145875 74658, 145535 74474, 145213 73979, 145211 70850, 145394 70473), (145394 75483, 145889 75161, 149018 75159, 149395 75342, 149718 75874, 149720 79003, 149536 79343, 149004 79666, 145875 79668, 145535 79484, 145213 78989, 145211 75860, 145394 75483), (145394 80493, 145889 80171, 149018 80169, 149395 80352, 149718 80884, 149720 84013, 149536 84353, 149004 84676, 145875 84678, 145535 84494, 145213 83999, 145211 80870, 145394 80493), (145394 85503, 145889 85181, 149018 85179, 149395 85362, 149718 85894, 149720 89023, 149536 89363, 149004 89686, 145875 89688, 145535 89504, 145213 89009, 145211 85880, 145394 85503), (145394 90513, 145889 90191, 149018 90189, 149395 90372, 149718 90904, 149720 94033, 149536 94373, 149003 94696, 145875 94698, 145535 94514, 145213 94019, 145211 90890, 145394 90513), (145397 95520, 145889 95201, 149017 95199, 149311 95326, 149502 95496, 149718 95913, 149720 99045, 149536 99385, 149004 99708, 145875 99710, 145535 99526, 145213 99031, 145211 95900, 145397 95520), (145394 100535, 145889 100213, 149018 100211, 149395 100394, 149718 100926, 149720 104055, 149536 104395, 149004 104718, 145875 104720, 145535 104536, 145213 104041, 145211 100912, 145394 100535), (145394 105545, 145889 105223, 149018 105221, 149395 105404, 149718 105936, 149720 109065, 149536 109405, 149004 109728, 145875 109730, 145535 109546, 145213 109051, 145211 105922, 145394 105545), (145394 110555, 145889 110233, 149018 110231, 149395 110414, 149718 110946, 149720 114075, 149536 114415, 149004 114738, 145875 114740, 145535 114556, 145213 114061, 145211 110932, 145394 110555), (145394 115565, 145889 115243, 149018 115241, 149395 115424, 149718 115956, 149720 119085, 149536 119425, 149004 119748, 145875 119750, 145535 119566, 145213 119071, 145211 115942, 145394 115565), (145394 120575, 145889 120253, 149018 120251, 149395 120434, 149718 120966, 149720 124095, 149536 124435, 149004 124758, 145875 124760, 145535 124576, 145213 124081, 145211 120952, 145394 120575), (145394 125585, 145889 125263, 149018 125261, 149395 125444, 149718 125976, 149720 129105, 149536 129445, 149003 129768, 145875 129770, 145535 129586, 145213 129091, 145211 125962, 145394 125585), (145397 130592, 145889 130273, 149017 130271, 149311 130398, 149502 130568, 149718 130985, 149720 134115, 149536 134455, 149004 134778, 145875 134780, 145535 134596, 145213 134101, 145211 130972, 145397 130592), (145394 135605, 145889 135283, 149018 135281, 149395 135464, 149718 135996, 149720 139125, 149536 139465, 149004 139788, 145875 139790, 145535 139606, 145213 139111, 145211 135982, 145394 135605), (145394 140615, 145889 140293, 149018 140291, 149395 140474, 149718 141006, 149720 144136, 149536 144476, 149003 144799, 145875 144801, 145535 144617, 145213 144122, 145211 140992, 145394 140615), (145397 145623, 145889 145304, 149017 145302, 149311 145429, 149502 145599, 149718 146016, 149720 149146, 149536 149486, 149004 149809, 145875 149811, 145535 149627, 145213 149132, 145211 146003, 145397 145623), (145394 150636, 145889 150314, 149018 150312, 149395 150495, 149718 151027, 149720 154156, 149536 154496, 149004 154819, 145875 154821, 145535 154637, 145213 154142, 145211 151013, 145394 150636), (145394 155646, 145889 155324, 149018 155322, 149395 155505, 149718 156037, 149720 159166, 149536 159506, 149004 159829, 145875 159831, 145535 159647, 145213 159152, 145211 156023, 145394 155646), (145394 160656, 145889 160334, 149018 160332, 149395 160515, 149718 161047, 149720 164176, 149536 164516, 149004 164839, 145875 164841, 145535 164657, 145213 164162, 145211 161033, 145394 160656), (145394 165666, 145889 165344, 149018 165342, 149395 165525, 149718 166057, 149720 169186, 149536 169526, 149004 169849, 145875 169851, 145535 169667, 145213 169172, 145211 166043, 145394 165666), (145394 170676, 145889 170354, 149018 170352, 149395 170535, 149718 171067, 149720 174196, 149536 174536, 149004 174859, 145875 174861, 145535 174677, 145213 174182, 145211 171053, 145394 170676), (145394 175686, 145889 175364, 149018 175362, 149395 175545, 149718 176077, 149720 179206, 149536 179546, 149004 179869, 145875 179871, 145535 179687, 145213 179192, 145211 176063, 145394 175686), (145394 180696, 145889 180374, 149018 180372, 149395 180555, 149718 181087, 149720 184216, 149537 184554, 149087 184826, 145803 184828, 145464 184629, 145213 184202, 145211 181073, 145394 180696), (150399 52983, 150683 52659, 151553 52436, 153931 52083, 154468 52318, 154729 52833, 154730 53953, 154546 54293, 154014 54616, 150885 54618, 150545 54434, 150285 53991, 150272 53354, 150399 52983), (150404 55443, 150899 55121, 154028 55119, 154405 55302, 154728 55834, 154730 58963, 154546 59303, 154014 59626, 150885 59628, 150545 59444, 150223 58949, 150221 55820, 150404 55443), (150404 60453, 150899 60131, 154028 60129, 154405 60312, 154728 60844, 154730 63973, 154546 64313, 154014 64636, 150885 64638, 150545 64454, 150223 63959, 150221 60830, 150404 60453), (150404 65463, 150899 65141, 154028 65139, 154405 65322, 154728 65854, 154730 68983, 154546 69323, 154014 69646, 150885 69648, 150545 69464, 150223 68969, 150221 65840, 150404 65463), (150404 70473, 150899 70151, 154028 70149, 154405 70332, 154728 70864, 154730 73993, 154546 74333, 154014 74656, 150885 74658, 150545 74474, 150223 73979, 150221 70850, 150404 70473), (150404 75483, 150899 75161, 154028 75159, 154405 75342, 154728 75874, 154730 79003, 154546 79343, 154014 79666, 150885 79668, 150545 79484, 150223 78989, 150221 75860, 150404 75483), (150404 80493, 150899 80171, 154028 80169, 154405 80352, 154728 80884, 154730 84013, 154546 84353, 154014 84676, 150885 84678, 150545 84494, 150223 83999, 150221 80870, 150404 80493), (150404 85503, 150899 85181, 154028 85179, 154405 85362, 154728 85894, 154730 89023, 154546 89363, 154014 89686, 150885 89688, 150545 89504, 150223 89009, 150221 85880, 150404 85503), (150404 90513, 150899 90191, 154028 90189, 154405 90372, 154728 90904, 154730 94033, 154546 94373, 154013 94696, 150885 94698, 150545 94514, 150223 94019, 150221 90890, 150404 90513), (150407 95520, 150899 95201, 154027 95199, 154321 95326, 154512 95496, 154728 95913, 154730 99045, 154546 99385, 154014 99708, 150885 99710, 150545 99526, 150223 99031, 150221 95900, 150407 95520), (150404 100535, 150899 100213, 154028 100211, 154405 100394, 154728 100926, 154730 104055, 154546 104395, 154014 104718, 150885 104720, 150545 104536, 150223 104041, 150221 100912, 150404 100535), (150404 105545, 150899 105223, 154028 105221, 154405 105404, 154728 105936, 154730 109065, 154546 109405, 154014 109728, 150885 109730, 150545 109546, 150223 109051, 150221 105922, 150404 105545), (150404 110555, 150899 110233, 154028 110231, 154405 110414, 154728 110946, 154730 114075, 154546 114415, 154014 114738, 150885 114740, 150545 114556, 150223 114061, 150221 110932, 150404 110555), (150404 115565, 150899 115243, 154028 115241, 154405 115424, 154728 115956, 154730 119085, 154546 119425, 154014 119748, 150885 119750, 150545 119566, 150223 119071, 150221 115942, 150404 115565), (150404 120575, 150899 120253, 154028 120251, 154405 120434, 154728 120966, 154730 124095, 154546 124435, 154014 124758, 150885 124760, 150545 124576, 150223 124081, 150221 120952, 150404 120575), (150404 125585, 150899 125263, 154028 125261, 154405 125444, 154728 125976, 154730 129105, 154546 129445, 154013 129768, 150885 129770, 150545 129586, 150223 129091, 150221 125962, 150404 125585), (150407 130592, 150899 130273, 154027 130271, 154321 130398, 154512 130568, 154728 130985, 154730 134115, 154546 134455, 154014 134778, 150885 134780, 150545 134596, 150223 134101, 150221 130972, 150407 130592), (150404 135605, 150899 135283, 154028 135281, 154405 135464, 154728 135996, 154730 139125, 154546 139465, 154014 139788, 150885 139790, 150545 139606, 150223 139111, 150221 135982, 150404 135605), (150404 140615, 150899 140293, 154028 140291, 154405 140474, 154728 141006, 154730 144136, 154546 144476, 154013 144799, 150885 144801, 150545 144617, 150223 144122, 150221 140992, 150404 140615), (150407 145623, 150899 145304, 154027 145302, 154321 145429, 154512 145599, 154728 146016, 154730 149146, 154546 149486, 154014 149809, 150885 149811, 150545 149627, 150223 149132, 150221 146003, 150407 145623), (150404 150636, 150899 150314, 154028 150312, 154405 150495, 154728 151027, 154730 154156, 154546 154496, 154014 154819, 150885 154821, 150545 154637, 150223 154142, 150221 151013, 150404 150636), (150404 155646, 150899 155324, 154028 155322, 154405 155505, 154728 156037, 154730 159166, 154546 159506, 154014 159829, 150885 159831, 150545 159647, 150223 159152, 150221 156023, 150404 155646), (150404 160656, 150899 160334, 154028 160332, 154405 160515, 154728 161047, 154730 164176, 154546 164516, 154014 164839, 150885 164841, 150545 164657, 150223 164162, 150221 161033, 150404 160656), (150404 165666, 150899 165344, 154028 165342, 154405 165525, 154728 166057, 154730 169186, 154546 169526, 154014 169849, 150885 169851, 150545 169667, 150223 169172, 150221 166043, 150404 165666), (150404 170676, 150899 170354, 154028 170352, 154405 170535, 154728 171067, 154730 174196, 154546 174536, 154014 174859, 150885 174861, 150545 174677, 150223 174182, 150221 171053, 150404 170676), (150404 175686, 150899 175364, 154028 175362, 154405 175545, 154728 176077, 154730 179206, 154546 179546, 154014 179869, 150885 179871, 150545 179687, 150223 179192, 150221 176063, 150404 175686), (150404 180696, 150899 180374, 154028 180372, 154405 180555, 154728 181087, 154730 184216, 154546 184556, 154014 184879, 150903 184880, 150483 184639, 150223 184202, 150221 181073, 150404 180696), (150272 186620, 150308 185916, 150470 185611, 150897 185382, 154028 185382, 154405 185565, 154728 186097, 154724 187344, 154499 187658, 153982 187918, 151553 187563, 150792 187373, 150399 187016, 150272 186620), (155354 52207, 155759 51817, 158248 51442, 159006 51405, 159515 51689, 159734 52050, 159740 53953, 159556 54293, 159024 54616, 155895 54618, 155555 54434, 155233 53939, 155231 52833, 155354 52207), (155414 55443, 155909 55121, 159038 55119, 159415 55302, 159738 55834, 159740 58963, 159556 59303, 159024 59626, 155895 59628, 155555 59444, 155233 58949, 155231 55820, 155414 55443), (155414 60453, 155909 60131, 159038 60129, 159415 60312, 159738 60844, 159740 63973, 159556 64313, 159024 64636, 155895 64638, 155555 64454, 155233 63959, 155231 60830, 155414 60453), (155414 65463, 155909 65141, 159038 65139, 159415 65322, 159738 65854, 159740 68983, 159556 69323, 159024 69646, 155895 69648, 155555 69464, 155233 68969, 155231 65840, 155414 65463), (155414 70473, 155909 70151, 159038 70149, 159415 70332, 159738 70864, 159740 73993, 159556 74333, 159024 74656, 155895 74658, 155555 74474, 155233 73979, 155231 70850, 155414 70473), (155414 75483, 155909 75161, 159038 75159, 159415 75342, 159738 75874, 159740 79003, 159556 79343, 159024 79666, 155895 79668, 155555 79484, 155233 78989, 155231 75860, 155414 75483), (155414 80493, 155909 80171, 159038 80169, 159415 80352, 159738 80884, 159740 84013, 159556 84353, 159024 84676, 155895 84678, 155555 84494, 155233 83999, 155231 80870, 155414 80493), (155414 85503, 155909 85181, 159038 85179, 159415 85362, 159738 85894, 159740 89023, 159556 89363, 159024 89686, 155895 89688, 155555 89504, 155233 89009, 155231 85880, 155414 85503), (155414 90513, 155909 90191, 159038 90189, 159415 90372, 159738 90904, 159740 94033, 159556 94373, 159023 94696, 155895 94698, 155555 94514, 155233 94019, 155231 90890, 155414 90513), (155417 95520, 155909 95201, 159037 95199, 159331 95326, 159522 95496, 159738 95913, 159740 99045, 159556 99385, 159024 99708, 155895 99710, 155555 99526, 155233 99031, 155231 95900, 155417 95520), (155414 100535, 155909 100213, 159038 100211, 159415 100394, 159738 100926, 159740 104055, 159556 104395, 159024 104718, 155895 104720, 155555 104536, 155233 104041, 155231 100912, 155414 100535), (155414 105545, 155909 105223, 159038 105221, 159415 105404, 159738 105936, 159740 109065, 159556 109405, 159024 109728, 155895 109730, 155555 109546, 155233 109051, 155231 105922, 155414 105545), (155414 110555, 155909 110233, 159038 110231, 159415 110414, 159738 110946, 159740 114075, 159556 114415, 159024 114738, 155895 114740, 155555 114556, 155233 114061, 155231 110932, 155414 110555), (155414 115565, 155909 115243, 159038 115241, 159415 115424, 159738 115956, 159740 119085, 159556 119425, 159024 119748, 155895 119750, 155555 119566, 155233 119071, 155231 115942, 155414 115565), (155414 120575, 155909 120253, 159038 120251, 159415 120434, 159738 120966, 159740 124095, 159556 124435, 159024 124758, 155895 124760, 155555 124576, 155233 124081, 155231 120952, 155414 120575), (155414 125585, 155909 125263, 159038 125261, 159415 125444, 159738 125976, 159740 129105, 159556 129445, 159023 129768, 155895 129770, 155555 129586, 155233 129091, 155231 125962, 155414 125585), (155417 130592, 155909 130273, 159037 130271, 159331 130398, 159522 130568, 159738 130985, 159740 134115, 159556 134455, 159024 134778, 155895 134780, 155555 134596, 155233 134101, 155231 130972, 155417 130592), (155414 135605, 155909 135283, 159038 135281, 159415 135464, 159738 135996, 159740 139125, 159556 139465, 159024 139788, 155895 139790, 155555 139606, 155233 139111, 155231 135982, 155414 135605), (155414 140615, 155909 140293, 159038 140291, 159415 140474, 159738 141006, 159740 144136, 159556 144476, 159023 144799, 155895 144801, 155555 144617, 155233 144122, 155231 140992, 155414 140615), (155417 145623, 155909 145304, 159037 145302, 159331 145429, 159522 145599, 159738 146016, 159740 149146, 159556 149486, 159024 149809, 155895 149811, 155555 149627, 155233 149132, 155231 146003, 155417 145623), (155414 150636, 155909 150314, 159038 150312, 159415 150495, 159738 151027, 159740 154156, 159556 154496, 159024 154819, 155895 154821, 155555 154637, 155233 154142, 155231 151013, 155414 150636), (155414 155646, 155909 155324, 159038 155322, 159415 155505, 159738 156037, 159740 159166, 159556 159506, 159024 159829, 155895 159831, 155555 159647, 155233 159152, 155231 156023, 155414 155646), (155414 160656, 155909 160334, 159038 160332, 159415 160515, 159738 161047, 159740 164176, 159556 164516, 159024 164839, 155895 164841, 155555 164657, 155233 164162, 155231 161033, 155414 160656), (155414 165666, 155909 165344, 159038 165342, 159415 165525, 159738 166057, 159740 169186, 159556 169526, 159024 169849, 155895 169851, 155555 169667, 155233 169172, 155231 166043, 155414 165666), (155414 170676, 155909 170354, 159038 170352, 159415 170535, 159738 171067, 159740 174196, 159556 174536, 159024 174859, 155895 174861, 155555 174677, 155233 174182, 155231 171053, 155414 170676), (155414 175686, 155909 175364, 159038 175362, 159415 175545, 159738 176077, 159740 179206, 159556 179546, 159024 179869, 155895 179871, 155555 179687, 155233 179192, 155231 176063, 155414 175686), (155414 180696, 155909 180374, 159038 180372, 159415 180555, 159738 181087, 159740 184216, 159556 184556, 159024 184879, 155895 184881, 155555 184697, 155233 184202, 155231 181073, 155414 180696), (155414 185706, 155909 185384, 159038 185382, 159415 185565, 159738 186097, 159738 187971, 159546 188288, 159064 188591, 158248 188557, 155833 188199, 155390 187821, 155228 187387, 155231 186083, 155414 185706), (160398 51668, 160853 51314, 164016 51159, 164535 51456, 164748 51869, 164750 53953, 164566 54293, 164034 54616, 160905 54618, 160565 54434, 160243 53939, 160238 52010, 160398 51668), (160424 55443, 160919 55121, 164048 55119, 164425 55302, 164748 55834, 164750 58963, 164566 59303, 164034 59626, 160905 59628, 160565 59444, 160243 58949, 160241 55820, 160424 55443), (160424 60453, 160919 60131, 164048 60129, 164425 60312, 164748 60844, 164750 63973, 164566 64313, 164034 64636, 160905 64638, 160565 64454, 160243 63959, 160241 60830, 160424 60453), (160424 65463, 160919 65141, 164048 65139, 164425 65322, 164748 65854, 164750 68983, 164566 69323, 164034 69646, 160905 69648, 160565 69464, 160243 68969, 160241 65840, 160424 65463), (160424 70473, 160919 70151, 164048 70149, 164425 70332, 164748 70864, 164750 73993, 164566 74333, 164034 74656, 160905 74658, 160565 74474, 160243 73979, 160241 70850, 160424 70473), (160424 75483, 160919 75161, 164048 75159, 164425 75342, 164748 75874, 164750 79003, 164566 79343, 164034 79666, 160905 79668, 160565 79484, 160243 78989, 160241 75860, 160424 75483), (160424 80493, 160919 80171, 164048 80169, 164425 80352, 164748 80884, 164750 84013, 164566 84353, 164034 84676, 160905 84678, 160565 84494, 160243 83999, 160241 80870, 160424 80493), (160424 85503, 160919 85181, 164048 85179, 164425 85362, 164748 85894, 164750 89023, 164566 89363, 164034 89686, 160905 89688, 160565 89504, 160243 89009, 160241 85880, 160424 85503), (160424 90513, 160919 90191, 164048 90189, 164425 90372, 164748 90904, 164750 94033, 164566 94373, 164033 94696, 160905 94698, 160565 94514, 160243 94019, 160241 90890, 160424 90513), (160427 95520, 160919 95201, 164047 95199, 164341 95326, 164532 95496, 164748 95913, 164750 99045, 164566 99385, 164034 99708, 160905 99710, 160565 99526, 160243 99031, 160241 95900, 160427 95520), (160424 100535, 160919 100213, 164048 100211, 164425 100394, 164748 100926, 164750 104055, 164566 104395, 164034 104718, 160905 104720, 160565 104536, 160243 104041, 160241 100912, 160424 100535), (160424 105545, 160919 105223, 164048 105221, 164425 105404, 164748 105936, 164750 109065, 164566 109405, 164034 109728, 160905 109730, 160565 109546, 160243 109051, 160241 105922, 160424 105545), (160424 110555, 160919 110233, 164048 110231, 164425 110414, 164748 110946, 164750 114075, 164566 114415, 164034 114738, 160905 114740, 160565 114556, 160243 114061, 160241 110932, 160424 110555), (160424 115565, 160919 115243, 164048 115241, 164425 115424, 164748 115956, 164750 119085, 164566 119425, 164034 119748, 160905 119750, 160565 119566, 160243 119071, 160241 115942, 160424 115565), (160424 120575, 160919 120253, 164048 120251, 164425 120434, 164748 120966, 164750 124095, 164566 124435, 164034 124758, 160905 124760, 160565 124576, 160243 124081, 160241 120952, 160424 120575), (160424 125585, 160919 125263, 164048 125261, 164425 125444, 164748 125976, 164750 129105, 164566 129445, 164033 129768, 160905 129770, 160565 129586, 160243 129091, 160241 125962, 160424 125585), (160427 130592, 160919 130273, 164047 130271, 164341 130398, 164532 130568, 164748 130985, 164750 134115, 164566 134455, 164034 134778, 160905 134780, 160565 134596, 160243 134101, 160241 130972, 160427 130592), (160424 135605, 160919 135283, 164048 135281, 164425 135464, 164748 135996, 164750 139125, 164566 139465, 164034 139788, 160905 139790, 160565 139606, 160243 139111, 160241 135982, 160424 135605), (160424 140615, 160919 140293, 164048 140291, 164425 140474, 164748 141006, 164750 144136, 164566 144476, 164033 144799, 160905 144801, 160565 144617, 160243 144122, 160241 140992, 160424 140615), (160427 145623, 160919 145304, 164047 145302, 164341 145429, 164532 145599, 164748 146016, 164750 149146, 164566 149486, 164034 149809, 160905 149811, 160565 149627, 160243 149132, 160241 146003, 160427 145623), (160424 150636, 160919 150314, 164048 150312, 164425 150495, 164748 151027, 164750 154156, 164566 154496, 164034 154819, 160905 154821, 160565 154637, 160243 154142, 160241 151013, 160424 150636), (160424 155646, 160919 155324, 164048 155322, 164425 155505, 164748 156037, 164750 159166, 164566 159506, 164034 159829, 160905 159831, 160565 159647, 160243 159152, 160241 156023, 160424 155646), (160424 160656, 160919 160334, 164048 160332, 164425 160515, 164748 161047, 164750 164176, 164566 164516, 164034 164839, 160905 164841, 160565 164657, 160243 164162, 160241 161033, 160424 160656), (160424 165666, 160919 165344, 164048 165342, 164425 165525, 164748 166057, 164750 169186, 164566 169526, 164034 169849, 160905 169851, 160565 169667, 160243 169172, 160241 166043, 160424 165666), (160424 170676, 160919 170354, 164048 170352, 164425 170535, 164748 171067, 164750 174196, 164566 174536, 164034 174859, 160905 174861, 160565 174677, 160243 174182, 160241 171053, 160424 170676), (160424 175686, 160919 175364, 164048 175362, 164425 175545, 164748 176077, 164750 179206, 164566 179546, 164034 179869, 160905 179871, 160565 179687, 160243 179192, 160241 176063, 160424 175686), (160424 180696, 160919 180374, 164048 180372, 164425 180555, 164748 181087, 164750 184216, 164566 184556, 164034 184879, 160905 184881, 160565 184697, 160243 184202, 160241 181073, 160424 180696), (160424 185706, 160919 185384, 164048 185382, 164425 185565, 164748 186097, 164750 188181, 164564 188523, 164063 188843, 160908 188689, 160429 188355, 160241 187983, 160241 186083, 160424 185706), (165435 51476, 165937 51156, 169092 51310, 169571 51644, 169759 52058, 169760 53953, 169576 54293, 169044 54616, 165915 54618, 165575 54434, 165253 53939, 165251 51854, 165435 51476), (165434 55443, 165929 55121, 169058 55119, 169435 55302, 169758 55834, 169760 58963, 169576 59303, 169044 59626, 165915 59628, 165575 59444, 165253 58949, 165251 55820, 165434 55443), (165434 60453, 165929 60131, 169058 60129, 169435 60312, 169758 60844, 169760 63973, 169576 64313, 169044 64636, 165915 64638, 165575 64454, 165253 63959, 165251 60830, 165434 60453), (165434 65463, 165929 65141, 169058 65139, 169435 65322, 169758 65854, 169760 68983, 169576 69323, 169044 69646, 165915 69648, 165575 69464, 165253 68969, 165251 65840, 165434 65463), (165434 70473, 165929 70151, 169058 70149, 169435 70332, 169758 70864, 169760 73993, 169576 74333, 169044 74656, 165915 74658, 165575 74474, 165253 73979, 165251 70850, 165434 70473), (165434 75483, 165929 75161, 169058 75159, 169435 75342, 169758 75874, 169760 79003, 169576 79343, 169044 79666, 165915 79668, 165575 79484, 165253 78989, 165251 75860, 165434 75483), (165434 80493, 165929 80171, 169058 80169, 169435 80352, 169758 80884, 169760 84013, 169576 84353, 169044 84676, 165915 84678, 165575 84494, 165253 83999, 165251 80870, 165434 80493), (165434 85503, 165929 85181, 169058 85179, 169435 85362, 169758 85894, 169760 89023, 169576 89363, 169044 89686, 165915 89688, 165575 89504, 165253 89009, 165251 85880, 165434 85503), (165434 90513, 165929 90191, 169058 90189, 169435 90372, 169758 90904, 169760 94033, 169576 94373, 169043 94696, 165915 94698, 165575 94514, 165253 94019, 165251 90890, 165434 90513), (165437 95520, 165929 95201, 169057 95199, 169351 95326, 169542 95496, 169758 95913, 169760 99045, 169576 99385, 169044 99708, 165915 99710, 165575 99526, 165253 99031, 165251 95900, 165437 95520), (165434 100535, 165929 100213, 169058 100211, 169435 100394, 169758 100926, 169760 104055, 169576 104395, 169044 104718, 165915 104720, 165575 104536, 165253 104041, 165251 100912, 165434 100535), (165434 105545, 165929 105223, 169058 105221, 169435 105404, 169758 105936, 169760 109065, 169576 109405, 169044 109728, 165915 109730, 165575 109546, 165253 109051, 165251 105922, 165434 105545), (165434 110555, 165929 110233, 169058 110231, 169435 110414, 169758 110946, 169760 114075, 169576 114415, 169044 114738, 165915 114740, 165575 114556, 165253 114061, 165251 110932, 165434 110555), (165434 115565, 165929 115243, 169058 115241, 169435 115424, 169758 115956, 169760 119085, 169576 119425, 169044 119748, 165915 119750, 165575 119566, 165253 119071, 165251 115942, 165434 115565), (165434 120575, 165929 120253, 169058 120251, 169435 120434, 169758 120966, 169760 124095, 169576 124435, 169044 124758, 165915 124760, 165575 124576, 165253 124081, 165251 120952, 165434 120575), (165434 125585, 165929 125263, 169058 125261, 169435 125444, 169758 125976, 169760 129105, 169576 129445, 169043 129768, 165915 129770, 165575 129586, 165253 129091, 165251 125962, 165434 125585), (165437 130592, 165929 130273, 169057 130271, 169351 130398, 169542 130568, 169758 130985, 169760 134115, 169576 134455, 169044 134778, 165915 134780, 165575 134596, 165253 134101, 165251 130972, 165437 130592), (165434 135605, 165929 135283, 169058 135281, 169435 135464, 169758 135996, 169760 139125, 169576 139465, 169044 139788, 165915 139790, 165575 139606, 165253 139111, 165251 135982, 165434 135605), (165434 140615, 165929 140293, 169058 140291, 169435 140474, 169758 141006, 169760 144136, 169576 144476, 169043 144799, 165915 144801, 165575 144617, 165253 144122, 165251 140992, 165434 140615), (165437 145623, 165929 145304, 169057 145302, 169351 145429, 169542 145599, 169758 146016, 169760 149146, 169576 149486, 169044 149809, 165915 149811, 165575 149627, 165253 149132, 165251 146003, 165437 145623), (165434 150636, 165929 150314, 169058 150312, 169435 150495, 169758 151027, 169760 154156, 169576 154496, 169044 154819, 165915 154821, 165575 154637, 165253 154142, 165251 151013, 165434 150636), (165434 155646, 165929 155324, 169058 155322, 169435 155505, 169758 156037, 169760 159166, 169576 159506, 169044 159829, 165915 159831, 165575 159647, 165253 159152, 165251 156023, 165434 155646), (165434 160656, 165929 160334, 169058 160332, 169435 160515, 169758 161047, 169760 164176, 169576 164516, 169044 164839, 165915 164841, 165575 164657, 165253 164162, 165251 161033, 165434 160656), (165434 165666, 165929 165344, 169058 165342, 169435 165525, 169758 166057, 169760 169186, 169576 169526, 169044 169849, 165915 169851, 165575 169667, 165253 169172, 165251 166043, 165434 165666), (165434 170676, 165929 170354, 169058 170352, 169435 170535, 169758 171067, 169760 174196, 169576 174536, 169044 174859, 165915 174861, 165575 174677, 165253 174182, 165251 171053, 165434 170676), (165434 175686, 165929 175364, 169058 175362, 169435 175545, 169758 176077, 169760 179206, 169576 179546, 169044 179869, 165915 179871, 165575 179687, 165253 179192, 165251 176063, 165434 175686), (165434 180696, 165929 180374, 169058 180372, 169435 180555, 169758 181087, 169760 184216, 169576 184556, 169044 184879, 165915 184881, 165575 184697, 165253 184202, 165251 181073, 165434 180696), (165434 185706, 165929 185384, 169058 185382, 169435 185565, 169758 186097, 169762 187993, 169602 188331, 169148 188685, 165984 188840, 165465 188543, 165253 188165, 165251 186083, 165434 185706), (170261 52069, 170454 51711, 170935 51408, 171751 51442, 174167 51800, 174610 52178, 174769 52518, 174770 53953, 174586 54293, 174054 54616, 170925 54618, 170585 54434, 170263 53939, 170261 52069), (170444 55443, 170939 55121, 174068 55119, 174445 55302, 174768 55834, 174770 58963, 174586 59303, 174054 59626, 170925 59628, 170585 59444, 170263 58949, 170261 55820, 170444 55443), (170444 60453, 170939 60131, 174068 60129, 174445 60312, 174768 60844, 174770 63973, 174586 64313, 174054 64636, 170925 64638, 170585 64454, 170263 63959, 170261 60830, 170444 60453), (170444 65463, 170939 65141, 174068 65139, 174445 65322, 174768 65854, 174770 68983, 174586 69323, 174054 69646, 170925 69648, 170585 69464, 170263 68969, 170261 65840, 170444 65463), (170444 70473, 170939 70151, 174068 70149, 174445 70332, 174768 70864, 174770 73993, 174586 74333, 174054 74656, 170925 74658, 170585 74474, 170263 73979, 170261 70850, 170444 70473), (170444 75483, 170939 75161, 174068 75159, 174445 75342, 174768 75874, 174770 79003, 174586 79343, 174054 79666, 170925 79668, 170585 79484, 170263 78989, 170261 75860, 170444 75483), (170444 80493, 170939 80171, 174068 80169, 174445 80352, 174768 80884, 174770 84013, 174586 84353, 174054 84676, 170925 84678, 170585 84494, 170263 83999, 170261 80870, 170444 80493), (170444 85503, 170939 85181, 174068 85179, 174445 85362, 174768 85894, 174770 89023, 174586 89363, 174054 89686, 170925 89688, 170585 89504, 170263 89009, 170261 85880, 170444 85503), (170444 90513, 170939 90191, 174068 90189, 174445 90372, 174768 90904, 174770 94033, 174586 94373, 174053 94696, 170925 94698, 170585 94514, 170263 94019, 170261 90890, 170444 90513), (170447 95520, 170939 95201, 174067 95199, 174361 95326, 174552 95496, 174768 95913, 174770 99045, 174586 99385, 174054 99708, 170925 99710, 170585 99526, 170263 99031, 170261 95900, 170447 95520), (170444 100535, 170939 100213, 174068 100211, 174445 100394, 174768 100926, 174770 104055, 174586 104395, 174054 104718, 170925 104720, 170585 104536, 170263 104041, 170261 100912, 170444 100535), (170444 105545, 170939 105223, 174068 105221, 174445 105404, 174768 105936, 174770 109065, 174586 109405, 174054 109728, 170925 109730, 170585 109546, 170263 109051, 170261 105922, 170444 105545), (170444 110555, 170939 110233, 174068 110231, 174445 110414, 174768 110946, 174770 114075, 174586 114415, 174054 114738, 170925 114740, 170585 114556, 170263 114061, 170261 110932, 170444 110555), (170444 115565, 170939 115243, 174068 115241, 174445 115424, 174768 115956, 174770 119085, 174586 119425, 174054 119748, 170925 119750, 170585 119566, 170263 119071, 170261 115942, 170444 115565), (170444 120575, 170939 120253, 174068 120251, 174445 120434, 174768 120966, 174770 124095, 174586 124435, 174054 124758, 170925 124760, 170585 124576, 170263 124081, 170261 120952, 170444 120575), (170444 125585, 170939 125263, 174068 125261, 174445 125444, 174768 125976, 174770 129105, 174586 129445, 174053 129768, 170925 129770, 170585 129586, 170263 129091, 170261 125962, 170444 125585), (170447 130592, 170939 130273, 174067 130271, 174361 130398, 174552 130568, 174768 130985, 174770 134115, 174586 134455, 174054 134778, 170925 134780, 170585 134596, 170263 134101, 170261 130972, 170447 130592), (170444 135605, 170939 135283, 174068 135281, 174445 135464, 174768 135996, 174770 139125, 174586 139465, 174054 139788, 170925 139790, 170585 139606, 170263 139111, 170261 135982, 170444 135605), (170444 140615, 170939 140293, 174068 140291, 174445 140474, 174768 141006, 174770 144136, 174586 144476, 174053 144799, 170925 144801, 170585 144617, 170263 144122, 170261 140992, 170444 140615), (170447 145623, 170939 145304, 174067 145302, 174361 145429, 174552 145599, 174768 146016, 174770 149146, 174586 149486, 174054 149809, 170925 149811, 170585 149627, 170263 149132, 170261 146003, 170447 145623), (170444 150636, 170939 150314, 174068 150312, 174445 150495, 174768 151027, 174770 154156, 174586 154496, 174054 154819, 170925 154821, 170585 154637, 170263 154142, 170261 151013, 170444 150636), (170444 155646, 170939 155324, 174068 155322, 174445 155505, 174768 156037, 174770 159166, 174586 159506, 174054 159829, 170925 159831, 170585 159647, 170263 159152, 170261 156023, 170444 155646), (170444 160656, 170939 160334, 174068 160332, 174445 160515, 174768 161047, 174770 164176, 174586 164516, 174054 164839, 170925 164841, 170585 164657, 170263 164162, 170261 161033, 170444 160656), (170444 165666, 170939 165344, 174068 165342, 174445 165525, 174768 166057, 174770 169186, 174586 169526, 174054 169849, 170925 169851, 170585 169667, 170263 169172, 170261 166043, 170444 165666), (170444 170676, 170939 170354, 174068 170352, 174445 170535, 174768 171067, 174770 174196, 174586 174536, 174054 174859, 170925 174861, 170585 174677, 170263 174182, 170261 171053, 170444 170676), (170444 175686, 170939 175364, 174068 175362, 174445 175545, 174768 176077, 174770 179206, 174586 179546, 174054 179869, 170925 179871, 170585 179687, 170263 179192, 170261 176063, 170444 175686), (170444 180696, 170939 180374, 174068 180372, 174445 180555, 174768 181087, 174770 184216, 174586 184556, 174054 184879, 170925 184881, 170585 184697, 170263 184202, 170261 181073, 170444 180696), (170444 185706, 170939 185384, 174068 185382, 174445 185565, 174768 186097, 174772 187323, 174646 187793, 174241 188182, 171751 188557, 170994 188594, 170485 188310, 170267 187952, 170261 186083, 170444 185706), (175271 52624, 175501 52341, 176018 52081, 178446 52436, 179208 52626, 179601 52983, 179728 53379, 179692 54083, 179531 54388, 179150 54617, 175935 54618, 175595 54434, 175273 53939, 175271 52624), (175454 55443, 175949 55121, 179143 55120, 179517 55360, 179778 55834, 179780 58963, 179596 59303, 179064 59626, 175935 59628, 175595 59444, 175273 58949, 175271 55820, 175454 55443), (175454 60453, 175949 60131, 179078 60129, 179455 60312, 179778 60844, 179780 63973, 179596 64313, 179064 64636, 175935 64638, 175595 64454, 175273 63959, 175271 60830, 175454 60453), (175454 65463, 175949 65141, 179078 65139, 179455 65322, 179778 65854, 179780 68983, 179596 69323, 179064 69646, 175935 69648, 175595 69464, 175273 68969, 175271 65840, 175454 65463), (175454 70473, 175949 70151, 179078 70149, 179455 70332, 179778 70864, 179780 73993, 179596 74333, 179064 74656, 175935 74658, 175595 74474, 175273 73979, 175271 70850, 175454 70473), (175454 75483, 175949 75161, 179078 75159, 179455 75342, 179778 75874, 179780 79003, 179596 79343, 179064 79666, 175935 79668, 175595 79484, 175273 78989, 175271 75860, 175454 75483), (175454 80493, 175949 80171, 179078 80169, 179455 80352, 179778 80884, 179780 84013, 179596 84353, 179064 84676, 175935 84678, 175595 84494, 175273 83999, 175271 80870, 175454 80493), (175454 85503, 175949 85181, 179078 85179, 179455 85362, 179778 85894, 179780 89023, 179596 89363, 179064 89686, 175935 89688, 175595 89504, 175273 89009, 175271 85880, 175454 85503), (175454 90513, 175949 90191, 179078 90189, 179455 90372, 179778 90904, 179780 94033, 179596 94373, 179063 94696, 175935 94698, 175595 94514, 175273 94019, 175271 90890, 175454 90513), (175457 95520, 175949 95201, 179077 95199, 179371 95326, 179562 95496, 179778 95913, 179780 99045, 179596 99385, 179064 99708, 175935 99710, 175595 99526, 175273 99031, 175271 95900, 175457 95520), (175454 100535, 175949 100213, 179078 100211, 179455 100394, 179778 100926, 179780 104055, 179596 104395, 179064 104718, 175935 104720, 175595 104536, 175273 104041, 175271 100912, 175454 100535), (175454 105545, 175949 105223, 179078 105221, 179455 105404, 179778 105936, 179780 109065, 179596 109405, 179064 109728, 175935 109730, 175595 109546, 175273 109051, 175271 105922, 175454 105545), (175454 110555, 175949 110233, 179078 110231, 179455 110414, 179778 110946, 179780 114075, 179596 114415, 179064 114738, 175935 114740, 175595 114556, 175273 114061, 175271 110932, 175454 110555), (175454 115565, 175949 115243, 179078 115241, 179455 115424, 179778 115956, 179780 119085, 179596 119425, 179064 119748, 175935 119750, 175595 119566, 175273 119071, 175271 115942, 175454 115565), (175454 120575, 175949 120253, 179078 120251, 179455 120434, 179778 120966, 179780 124095, 179596 124435, 179064 124758, 175935 124760, 175595 124576, 175273 124081, 175271 120952, 175454 120575), (175454 125585, 175949 125263, 179078 125261, 179455 125444, 179778 125976, 179780 129105, 179596 129445, 179063 129768, 175935 129770, 175595 129586, 175273 129091, 175271 125962, 175454 125585), (175457 130592, 175949 130273, 179077 130271, 179371 130398, 179562 130568, 179778 130985, 179780 134115, 179596 134455, 179064 134778, 175935 134780, 175595 134596, 175273 134101, 175271 130972, 175457 130592), (175454 135605, 175949 135283, 179078 135281, 179455 135464, 179778 135996, 179780 139125, 179596 139465, 179064 139788, 175935 139790, 175595 139606, 175273 139111, 175271 135982, 175454 135605), (175454 140615, 175949 140293, 179078 140291, 179455 140474, 179778 141006, 179780 144136, 179596 144476, 179063 144799, 175935 144801, 175595 144617, 175273 144122, 175271 140992, 175454 140615), (175457 145623, 175949 145304, 179077 145302, 179371 145429, 179562 145599, 179778 146016, 179780 149146, 179596 149486, 179064 149809, 175935 149811, 175595 149627, 175273 149132, 175271 146003, 175457 145623), (175454 150636, 175949 150314, 179078 150312, 179455 150495, 179778 151027, 179780 154156, 179596 154496, 179064 154819, 175935 154821, 175595 154637, 175273 154142, 175271 151013, 175454 150636), (175454 155646, 175949 155324, 179078 155322, 179455 155505, 179778 156037, 179780 159166, 179596 159506, 179064 159829, 175935 159831, 175595 159647, 175273 159152, 175271 156023, 175454 155646), (175454 160656, 175949 160334, 179078 160332, 179455 160515, 179778 161047, 179780 164176, 179596 164516, 179064 164839, 175935 164841, 175595 164657, 175273 164162, 175271 161033, 175454 160656), (175454 165666, 175949 165344, 179078 165342, 179455 165525, 179778 166057, 179780 169186, 179596 169526, 179064 169849, 175935 169851, 175595 169667, 175273 169172, 175271 166043, 175454 165666), (175454 170676, 175949 170354, 179078 170352, 179455 170535, 179778 171067, 179780 174196, 179596 174536, 179064 174859, 175935 174861, 175595 174677, 175273 174182, 175271 171053, 175454 170676), (175454 175686, 175949 175364, 179078 175362, 179455 175545, 179778 176077, 179780 179206, 179596 179546, 179064 179869, 175935 179871, 175595 179687, 175273 179192, 175271 176063, 175454 175686), (175454 180696, 175949 180374, 179078 180372, 179455 180555, 179778 181087, 179780 184216, 179596 184556, 179064 184879, 175935 184881, 175595 184697, 175273 184202, 175271 181073, 175454 180696), (175454 185706, 175949 185384, 179078 185382, 179455 185565, 179715 186008, 179728 186645, 179601 187016, 179317 187340, 178446 187563, 176069 187917, 175532 187682, 175277 187280, 175271 186083, 175454 185706), (180463 55445, 180913 55173, 184197 55171, 184536 55370, 184788 55834, 184790 58963, 184606 59303, 184074 59626, 180945 59628, 180605 59444, 180283 58949, 180281 55820, 180463 55445), (180464 60453, 180959 60131, 184088 60129, 184465 60312, 184788 60844, 184790 63973, 184606 64313, 184074 64636, 180945 64638, 180605 64454, 180283 63959, 180281 60830, 180464 60453), (180464 65463, 180959 65141, 184088 65139, 184465 65322, 184788 65854, 184790 68983, 184606 69323, 184074 69646, 180945 69648, 180605 69464, 180283 68969, 180281 65840, 180464 65463), (180464 70473, 180959 70151, 184088 70149, 184465 70332, 184788 70864, 184790 73993, 184606 74333, 184074 74656, 180945 74658, 180605 74474, 180283 73979, 180281 70850, 180464 70473), (180464 75483, 180959 75161, 184088 75159, 184465 75342, 184788 75874, 184790 79003, 184606 79343, 184074 79666, 180945 79668, 180605 79484, 180283 78989, 180281 75860, 180464 75483), (180464 80493, 180959 80171, 184088 80169, 184465 80352, 184788 80884, 184790 84013, 184606 84353, 184074 84676, 180945 84678, 180605 84494, 180283 83999, 180281 80870, 180464 80493), (180464 85503, 180959 85181, 184088 85179, 184465 85362, 184788 85894, 184790 89023, 184606 89363, 184074 89686, 180945 89688, 180605 89504, 180283 89009, 180281 85880, 180464 85503), (180464 90513, 180959 90191, 184088 90189, 184465 90372, 184788 90904, 184790 94033, 184606 94373, 184073 94696, 180945 94698, 180605 94514, 180283 94019, 180281 90890, 180464 90513), (180467 95520, 180959 95201, 184087 95199, 184381 95326, 184572 95496, 184788 95913, 184790 99045, 184606 99385, 184074 99708, 180945 99710, 180605 99526, 180283 99031, 180281 95900, 180467 95520), (180464 100535, 180959 100213, 184088 100211, 184465 100394, 184788 100926, 184790 104055, 184606 104395, 184074 104718, 180945 104720, 180605 104536, 180283 104041, 180281 100912, 180464 100535), (180464 105545, 180959 105223, 184088 105221, 184465 105404, 184788 105936, 184790 109065, 184606 109405, 184074 109728, 180945 109730, 180605 109546, 180283 109051, 180281 105922, 180464 105545), (180464 110555, 180959 110233, 184088 110231, 184465 110414, 184788 110946, 184790 114075, 184606 114415, 184074 114738, 180945 114740, 180605 114556, 180283 114061, 180281 110932, 180464 110555), (180464 115565, 180959 115243, 184088 115241, 184465 115424, 184788 115956, 184790 119085, 184606 119425, 184074 119748, 180945 119750, 180605 119566, 180283 119071, 180281 115942, 180464 115565), (180464 120575, 180959 120253, 184088 120251, 184465 120434, 184788 120966, 184790 124095, 184606 124435, 184074 124758, 180945 124760, 180605 124576, 180283 124081, 180281 120952, 180464 120575), (180464 125585, 180959 125263, 184088 125261, 184465 125444, 184788 125976, 184790 129105, 184606 129445, 184073 129768, 180945 129770, 180605 129586, 180283 129091, 180281 125962, 180464 125585), (180467 130592, 180959 130273, 184087 130271, 184381 130398, 184572 130568, 184788 130985, 184790 134115, 184606 134455, 184074 134778, 180945 134780, 180605 134596, 180283 134101, 180281 130972, 180467 130592), (180464 135605, 180959 135283, 184088 135281, 184465 135464, 184788 135996, 184790 139125, 184606 139465, 184074 139788, 180945 139790, 180605 139606, 180283 139111, 180281 135982, 180464 135605), (180464 140615, 180959 140293, 184088 140291, 184465 140474, 184788 141006, 184790 144136, 184606 144476, 184073 144799, 180945 144801, 180605 144617, 180283 144122, 180281 140992, 180464 140615), (180467 145623, 180959 145304, 184087 145302, 184381 145429, 184572 145599, 184788 146016, 184790 149146, 184606 149486, 184074 149809, 180945 149811, 180605 149627, 180283 149132, 180281 146003, 180467 145623), (180464 150636, 180959 150314, 184088 150312, 184465 150495, 184788 151027, 184790 154156, 184606 154496, 184074 154819, 180945 154821, 180605 154637, 180283 154142, 180281 151013, 180464 150636), (180464 155646, 180959 155324, 184088 155322, 184465 155505, 184788 156037, 184790 159166, 184606 159506, 184074 159829, 180945 159831, 180605 159647, 180283 159152, 180281 156023, 180464 155646), (180464 160656, 180959 160334, 184088 160332, 184465 160515, 184788 161047, 184790 164176, 184606 164516, 184074 164839, 180945 164841, 180605 164657, 180283 164162, 180281 161033, 180464 160656), (180464 165666, 180959 165344, 184088 165342, 184465 165525, 184788 166057, 184790 169186, 184606 169526, 184074 169849, 180945 169851, 180605 169667, 180283 169172, 180281 166043, 180464 165666), (180464 170676, 180959 170354, 184088 170352, 184465 170535, 184788 171067, 184790 174196, 184606 174536, 184074 174859, 180945 174861, 180605 174677, 180283 174182, 180281 171053, 180464 170676), (180464 175686, 180959 175364, 184088 175362, 184465 175545, 184788 176077, 184790 179206, 184606 179546, 184074 179869, 180945 179871, 180605 179687, 180283 179192, 180281 176063, 180464 175686), (180464 180696, 180959 180374, 184088 180372, 184465 180555, 184788 181087, 184790 184216, 184480 184673, 184147 184829, 180903 184829, 180615 184704, 180283 184202, 180281 181073, 180464 180696), (185418 55527, 185599 55327, 186046 55170, 187958 55142, 189303 55617, 189578 55887, 189728 56165, 189805 57036, 189801 58963, 189500 59414, 189085 59626, 185955 59628, 185615 59444, 185293 58949, 185291 55820, 185418 55527), (185474 60453, 185969 60131, 189099 60129, 189475 60312, 189799 60844, 189801 63973, 189617 64313, 189085 64636, 185955 64638, 185615 64454, 185293 63959, 185291 60830, 185474 60453), (185474 65463, 185969 65141, 189099 65139, 189476 65322, 189799 65854, 189801 68983, 189617 69323, 189085 69646, 185955 69648, 185615 69464, 185293 68969, 185291 65840, 185474 65463), (185474 70473, 185969 70151, 189099 70149, 189476 70332, 189799 70864, 189801 73993, 189617 74333, 189085 74656, 185955 74658, 185615 74474, 185293 73979, 185291 70850, 185474 70473), (185474 75483, 185969 75161, 189099 75159, 189476 75342, 189799 75874, 189801 79003, 189617 79343, 189085 79666, 185955 79668, 185615 79484, 185293 78989, 185291 75860, 185474 75483), (185474 80493, 185969 80171, 189099 80169, 189476 80352, 189799 80884, 189801 84013, 189617 84353, 189085 84676, 185955 84678, 185615 84494, 185293 83999, 185291 80870, 185474 80493), (185474 85503, 185969 85181, 189099 85179, 189476 85362, 189799 85894, 189801 89023, 189617 89363, 189085 89686, 185955 89688, 185615 89504, 185293 89009, 185291 85880, 185474 85503), (185474 90513, 185969 90191, 189099 90189, 189476 90372, 189799 90904, 189801 94033, 189617 94373, 189084 94696, 185955 94698, 185615 94514, 185293 94019, 185291 90890, 185474 90513), (185477 95520, 185969 95201, 189098 95199, 189392 95326, 189583 95496, 189799 95913, 189801 99045, 189617 99385, 189085 99708, 185955 99710, 185615 99526, 185293 99031, 185291 95900, 185477 95520), (185474 100535, 185969 100213, 189099 100211, 189476 100394, 189799 100926, 189801 104055, 189617 104395, 189085 104718, 185955 104720, 185615 104536, 185293 104041, 185291 100912, 185474 100535), (185474 105545, 185969 105223, 189099 105221, 189476 105404, 189799 105936, 189801 109065, 189617 109405, 189085 109728, 185955 109730, 185615 109546, 185293 109051, 185291 105922, 185474 105545), (185474 110555, 185969 110233, 189099 110231, 189476 110414, 189799 110946, 189801 114075, 189617 114415, 189085 114738, 185955 114740, 185615 114556, 185293 114061, 185291 110932, 185474 110555), (185474 115565, 185969 115243, 189099 115241, 189476 115424, 189799 115956, 189801 119085, 189617 119425, 189085 119748, 185955 119750, 185615 119566, 185293 119071, 185291 115942, 185474 115565), (185474 120575, 185969 120253, 189099 120251, 189476 120434, 189799 120966, 189801 124095, 189617 124435, 189085 124758, 185955 124760, 185615 124576, 185293 124081, 185291 120952, 185474 120575), (185474 125585, 185969 125263, 189099 125261, 189476 125444, 189799 125976, 189801 129105, 189617 129445, 189084 129768, 185955 129770, 185615 129586, 185293 129091, 185291 125962, 185474 125585), (185477 130592, 185969 130273, 189098 130271, 189392 130398, 189583 130568, 189799 130985, 189801 134115, 189617 134455, 189085 134778, 185955 134780, 185615 134596, 185293 134101, 185291 130972, 185477 130592), (185474 135605, 185969 135283, 189099 135281, 189476 135464, 189799 135996, 189801 139125, 189617 139465, 189085 139788, 185955 139790, 185615 139606, 185293 139111, 185291 135982, 185474 135605), (185474 140615, 185969 140293, 189099 140291, 189476 140474, 189799 141006, 189801 144136, 189617 144476, 189084 144799, 185955 144801, 185615 144617, 185293 144122, 185291 140992, 185474 140615), (185477 145623, 185969 145304, 189098 145302, 189392 145429, 189583 145599, 189799 146016, 189801 149146, 189617 149486, 189085 149809, 185955 149811, 185615 149627, 185293 149132, 185291 146003, 185477 145623), (185474 150636, 185969 150314, 189099 150312, 189476 150495, 189799 151027, 189801 154156, 189617 154496, 189085 154819, 185955 154821, 185615 154637, 185293 154142, 185291 151013, 185474 150636), (185474 155646, 185969 155324, 189099 155322, 189476 155505, 189799 156037, 189801 159166, 189617 159506, 189085 159829, 185955 159831, 185615 159647, 185293 159152, 185291 156023, 185474 155646), (185474 160656, 185969 160334, 189099 160332, 189476 160515, 189799 161047, 189801 164176, 189617 164516, 189085 164839, 185955 164841, 185615 164657, 185293 164162, 185291 161033, 185474 160656), (185474 165666, 185969 165344, 189099 165342, 189476 165525, 189799 166057, 189801 169186, 189617 169526, 189085 169849, 185955 169851, 185615 169667, 185293 169172, 185291 166043, 185474 165666), (185474 170676, 185969 170354, 189099 170352, 189476 170535, 189799 171067, 189801 174196, 189617 174536, 189085 174859, 185955 174861, 185615 174677, 185293 174182, 185291 171053, 185474 170676), (185474 175686, 185969 175364, 189099 175362, 189476 175545, 189799 176077, 189801 179206, 189617 179546, 189085 179869, 185955 179871, 185615 179687, 185293 179192, 185291 176063, 185474 175686), (185474 180696, 185969 180374, 189099 180372, 189476 180555, 189799 181096, 189808 183185, 189728 183837, 189408 184339, 187891 184888, 185994 184829, 185624 184704, 185293 184202, 185291 181073, 185474 180696), (190428 180780, 190600 180587, 190980 180374, 194109 180372, 194486 180555, 194665 180796, 194757 181482, 194668 181859, 194480 182164, 191338 183654, 190912 183625, 190627 183517, 190325 183141, 190301 181082, 190428 180780), (190319 57039, 190668 56463, 191185 56275, 194380 57781, 194668 58140, 194759 58489, 194721 59102, 194562 59398, 194181 59627, 190963 59628, 190625 59445, 190304 58949, 190319 57039), (190485 60453, 190979 60131, 194174 60130, 194548 60370, 194809 60844, 194811 63973, 194627 64313, 194095 64636, 190966 64638, 190626 64454, 190304 63959, 190302 60830, 190485 60453), (190485 65463, 190980 65141, 194109 65139, 194486 65322, 194809 65854, 194811 68983, 194627 69323, 194095 69646, 190966 69648, 190626 69464, 190304 68969, 190302 65840, 190485 65463), (190485 70473, 190980 70151, 194109 70149, 194486 70332, 194809 70864, 194811 73993, 194627 74333, 194095 74656, 190966 74658, 190626 74474, 190304 73979, 190302 70850, 190485 70473), (190485 75483, 190980 75161, 194109 75159, 194486 75342, 194809 75874, 194811 79003, 194627 79343, 194095 79666, 190966 79668, 190626 79484, 190304 78989, 190302 75860, 190485 75483), (190485 80493, 190980 80171, 194109 80169, 194486 80352, 194809 80884, 194811 84013, 194627 84353, 194095 84676, 190966 84678, 190626 84494, 190304 83999, 190302 80870, 190485 80493), (190485 85503, 190980 85181, 194109 85179, 194486 85362, 194809 85894, 194811 89023, 194627 89363, 194095 89686, 190966 89688, 190626 89504, 190304 89009, 190302 85880, 190485 85503), (190485 90513, 190980 90191, 194109 90189, 194486 90372, 194809 90904, 194811 94033, 194627 94373, 194094 94696, 190966 94698, 190626 94514, 190304 94019, 190302 90890, 190485 90513), (190488 95520, 190980 95201, 194108 95199, 194402 95326, 194593 95496, 194809 95913, 194811 99045, 194627 99385, 194095 99708, 190966 99710, 190626 99526, 190304 99031, 190302 95900, 190488 95520), (190485 100535, 190980 100213, 194109 100211, 194486 100394, 194809 100926, 194811 104055, 194627 104395, 194095 104718, 190966 104720, 190626 104536, 190304 104041, 190302 100912, 190485 100535), (190485 105545, 190980 105223, 194109 105221, 194486 105404, 194809 105936, 194811 109065, 194627 109405, 194095 109728, 190966 109730, 190626 109546, 190304 109051, 190302 105922, 190485 105545), (190485 110555, 190980 110233, 194109 110231, 194486 110414, 194809 110946, 194811 114075, 194627 114415, 194095 114738, 190966 114740, 190626 114556, 190304 114061, 190302 110932, 190485 110555), (190485 115565, 190980 115243, 194109 115241, 194486 115424, 194809 115956, 194811 119085, 194627 119425, 194095 119748, 190966 119750, 190626 119566, 190304 119071, 190302 115942, 190485 115565), (190485 120575, 190980 120253, 194109 120251, 194486 120434, 194809 120966, 194811 124095, 194627 124435, 194095 124758, 190966 124760, 190626 124576, 190304 124081, 190302 120952, 190485 120575), (190485 125585, 190980 125263, 194109 125261, 194486 125444, 194809 125976, 194811 129105, 194627 129445, 194094 129768, 190966 129770, 190626 129586, 190304 129091, 190302 125962, 190485 125585), (190488 130592, 190980 130273, 194108 130271, 194402 130398, 194593 130568, 194809 130985, 194811 134115, 194627 134455, 194095 134778, 190966 134780, 190626 134596, 190304 134101, 190302 130972, 190488 130592), (190485 135605, 190980 135283, 194109 135281, 194486 135464, 194809 135996, 194811 139125, 194627 139465, 194095 139788, 190966 139790, 190626 139606, 190304 139111, 190302 135982, 190485 135605), (190485 140615, 190980 140293, 194109 140291, 194486 140474, 194809 141006, 194811 144136, 194627 144476, 194094 144799, 190966 144801, 190626 144617, 190304 144122, 190302 140992, 190485 140615), (190488 145623, 190980 145304, 194108 145302, 194402 145429, 194593 145599, 194809 146016, 194811 149146, 194627 149486, 194095 149809, 190966 149811, 190626 149627, 190304 149132, 190302 146003, 190488 145623), (190485 150636, 190980 150314, 194109 150312, 194486 150495, 194809 151027, 194811 154156, 194627 154496, 194095 154819, 190966 154821, 190626 154637, 190304 154142, 190302 151013, 190485 150636), (190485 155646, 190980 155324, 194109 155322, 194486 155505, 194809 156037, 194811 159166, 194627 159506, 194095 159829, 190966 159831, 190626 159647, 190304 159152, 190302 156023, 190485 155646), (190485 160656, 190980 160334, 194109 160332, 194486 160515, 194809 161047, 194811 164176, 194627 164516, 194095 164839, 190966 164841, 190626 164657, 190304 164162, 190302 161033, 190485 160656), (190485 165666, 190980 165344, 194109 165342, 194486 165525, 194809 166057, 194811 169186, 194627 169526, 194095 169849, 190966 169851, 190626 169667, 190304 169172, 190302 166043, 190485 165666), (190485 170676, 190980 170354, 194109 170352, 194486 170535, 194809 171067, 194811 174196, 194627 174536, 194095 174859, 190966 174861, 190626 174677, 190304 174182, 190302 171053, 190485 170676), (190485 175686, 190980 175364, 194109 175362, 194486 175545, 194809 176077, 194811 179206, 194627 179546, 194095 179869, 190966 179871, 190625 179686, 190304 179192, 190302 176063, 190485 175686), (195494 60455, 195621 60337, 195984 60185, 197368 60180, 199010 60170, 199566 60543, 199769 61074, 199820 62276, 199821 63973, 199637 64313, 199105 64636, 195976 64638, 195636 64454, 195314 63959, 195312 60830, 195494 60455), (195495 65463, 195990 65141, 199119 65139, 199496 65322, 199819 65854, 199821 68983, 199637 69323, 199105 69646, 195976 69648, 195636 69464, 195314 68969, 195312 65840, 195495 65463), (195495 70473, 195990 70151, 199119 70149, 199496 70332, 199819 70864, 199821 73993, 199637 74333, 199105 74656, 195976 74658, 195636 74474, 195314 73979, 195312 70850, 195495 70473), (195495 75483, 195990 75161, 199119 75159, 199496 75342, 199819 75874, 199821 79003, 199637 79343, 199105 79666, 195976 79668, 195636 79484, 195314 78989, 195312 75860, 195495 75483), (195495 80493, 195990 80171, 199119 80169, 199496 80352, 199819 80884, 199821 84013, 199637 84353, 199105 84676, 195976 84678, 195636 84494, 195314 83999, 195312 80870, 195495 80493), (195495 85503, 195990 85181, 199119 85179, 199496 85362, 199819 85894, 199821 89023, 199637 89363, 199105 89686, 195976 89688, 195636 89504, 195314 89009, 195312 85880, 195495 85503), (195495 90513, 195990 90191, 199119 90189, 199496 90372, 199819 90904, 199821 94033, 199637 94373, 199104 94696, 195976 94698, 195636 94514, 195314 94019, 195312 90890, 195495 90513), (195498 95520, 195990 95201, 199118 95199, 199412 95326, 199603 95496, 199819 95913, 199821 99045, 199637 99385, 199105 99708, 195976 99710, 195636 99526, 195314 99031, 195312 95900, 195498 95520), (195495 100535, 195990 100213, 199119 100211, 199496 100394, 199819 100926, 199821 104055, 199637 104395, 199105 104718, 195976 104720, 195636 104536, 195314 104041, 195312 100912, 195495 100535), (195495 105545, 195990 105223, 199119 105221, 199496 105404, 199819 105936, 199821 109065, 199637 109405, 199105 109728, 195976 109730, 195636 109546, 195314 109051, 195312 105922, 195495 105545), (195495 110555, 195990 110233, 199119 110231, 199496 110414, 199819 110946, 199821 114075, 199637 114415, 199105 114738, 195976 114740, 195636 114556, 195314 114061, 195312 110932, 195495 110555), (195495 115565, 195990 115243, 199119 115241, 199496 115424, 199819 115956, 199821 119085, 199637 119425, 199105 119748, 195976 119750, 195636 119566, 195314 119071, 195312 115942, 195495 115565), (195495 120575, 195990 120253, 199119 120251, 199496 120434, 199819 120966, 199821 124095, 199637 124435, 199105 124758, 195976 124760, 195636 124576, 195314 124081, 195312 120952, 195495 120575), (195495 125585, 195990 125263, 199119 125261, 199496 125444, 199819 125976, 199821 129105, 199637 129445, 199104 129768, 195976 129770, 195636 129586, 195314 129091, 195312 125962, 195495 125585), (195498 130592, 195990 130273, 199118 130271, 199412 130398, 199603 130568, 199819 130985, 199821 134115, 199637 134455, 199105 134778, 195976 134780, 195636 134596, 195314 134101, 195312 130972, 195498 130592), (195495 135605, 195990 135283, 199119 135281, 199496 135464, 199819 135996, 199821 139125, 199637 139465, 199105 139788, 195976 139790, 195636 139606, 195314 139111, 195312 135982, 195495 135605), (195495 140615, 195990 140293, 199119 140291, 199496 140474, 199819 141006, 199821 144136, 199637 144476, 199104 144799, 195976 144801, 195636 144617, 195314 144122, 195312 140992, 195495 140615), (195498 145623, 195990 145304, 199118 145302, 199412 145429, 199603 145599, 199819 146016, 199821 149146, 199637 149486, 199105 149809, 195976 149811, 195636 149627, 195314 149132, 195312 146003, 195498 145623), (195495 150636, 195990 150314, 199119 150312, 199496 150495, 199819 151027, 199821 154156, 199637 154496, 199105 154819, 195976 154821, 195636 154637, 195314 154142, 195312 151013, 195495 150636), (195495 155646, 195990 155324, 199119 155322, 199496 155505, 199819 156037, 199821 159166, 199637 159506, 199105 159829, 195976 159831, 195636 159647, 195314 159152, 195312 156023, 195495 155646), (195495 160656, 195990 160334, 199119 160332, 199496 160515, 199819 161047, 199821 164176, 199637 164516, 199105 164839, 195976 164841, 195636 164657, 195314 164162, 195312 161033, 195495 160656), (195495 165666, 195990 165344, 199119 165342, 199496 165525, 199819 166057, 199821 169186, 199637 169526, 199105 169849, 195976 169851, 195636 169667, 195314 169172, 195312 166043, 195495 165666), (195495 170676, 195990 170354, 199119 170352, 199496 170535, 199819 171067, 199821 174196, 199637 174536, 199105 174859, 195976 174861, 195636 174677, 195314 174182, 195312 171053, 195495 170676), (195495 175686, 195990 175364, 199119 175362, 199496 175545, 199819 176077, 199823 177955, 199769 178925, 199566 179456, 199048 179820, 195923 179813, 195756 179762, 195526 179570, 195314 179192, 195312 176063, 195495 175686), (200480 61933, 200742 61642, 201295 61541, 203274 62721, 204164 63386, 204273 63977, 204136 64345, 203768 64631, 200986 64638, 200646 64454, 200324 63959, 200322 62276, 200480 61933), (200505 65463, 201000 65141, 203811 65136, 204372 65240, 204580 65392, 204829 65854, 204831 68983, 204647 69323, 204115 69646, 200986 69648, 200646 69464, 200324 68969, 200322 65840, 200505 65463), (200505 70473, 201000 70151, 204129 70149, 204506 70332, 204829 70864, 204831 73993, 204647 74333, 204115 74656, 200986 74658, 200646 74474, 200324 73979, 200322 70850, 200505 70473), (200505 75483, 201000 75161, 204129 75159, 204506 75342, 204829 75874, 204831 79003, 204647 79343, 204115 79666, 200986 79668, 200646 79484, 200324 78989, 200322 75860, 200505 75483), (200505 80493, 201000 80171, 204129 80169, 204506 80352, 204829 80884, 204831 84013, 204647 84353, 204115 84676, 200986 84678, 200646 84494, 200324 83999, 200322 80870, 200505 80493), (200505 85503, 201000 85181, 204129 85179, 204506 85362, 204829 85894, 204831 89023, 204647 89363, 204115 89686, 200986 89688, 200646 89504, 200324 89009, 200322 85880, 200505 85503), (200505 90513, 201000 90191, 204129 90189, 204506 90372, 204829 90904, 204831 94033, 204647 94373, 204114 94696, 200986 94698, 200646 94514, 200324 94019, 200322 90890, 200505 90513), (200508 95520, 201000 95201, 204128 95199, 204422 95326, 204613 95496, 204829 95913, 204831 99045, 204647 99385, 204115 99708, 200986 99710, 200646 99526, 200324 99031, 200322 95900, 200508 95520), (200505 100535, 201000 100213, 204129 100211, 204506 100394, 204829 100926, 204831 104055, 204647 104395, 204115 104718, 200986 104720, 200646 104536, 200324 104041, 200322 100912, 200505 100535), (200505 105545, 201000 105223, 204129 105221, 204506 105404, 204829 105936, 204831 109065, 204647 109405, 204115 109728, 200986 109730, 200646 109546, 200324 109051, 200322 105922, 200505 105545), (200505 110555, 201000 110233, 204129 110231, 204506 110414, 204829 110946, 204831 114075, 204647 114415, 204115 114738, 200986 114740, 200646 114556, 200324 114061, 200322 110932, 200505 110555), (200505 115565, 201000 115243, 204129 115241, 204506 115424, 204829 115956, 204831 119085, 204647 119425, 204115 119748, 200986 119750, 200646 119566, 200324 119071, 200322 115942, 200505 115565), (200505 120575, 201000 120253, 204129 120251, 204506 120434, 204829 120966, 204831 124095, 204647 124435, 204115 124758, 200986 124760, 200646 124576, 200324 124081, 200322 120952, 200505 120575), (200505 125585, 201000 125263, 204129 125261, 204506 125444, 204829 125976, 204831 129105, 204647 129445, 204114 129768, 200986 129770, 200646 129586, 200324 129091, 200322 125962, 200505 125585), (200508 130592, 201000 130273, 204128 130271, 204422 130398, 204613 130568, 204829 130985, 204831 134115, 204647 134455, 204115 134778, 200986 134780, 200646 134596, 200324 134101, 200322 130972, 200508 130592), (200505 135605, 201000 135283, 204129 135281, 204506 135464, 204829 135996, 204831 139125, 204647 139465, 204115 139788, 200986 139790, 200646 139606, 200324 139111, 200322 135982, 200505 135605), (200505 140615, 201000 140293, 204129 140291, 204506 140474, 204829 141006, 204831 144136, 204647 144476, 204114 144799, 200986 144801, 200646 144617, 200324 144122, 200322 140992, 200505 140615), (200508 145623, 201000 145304, 204128 145302, 204422 145429, 204613 145599, 204829 146016, 204831 149146, 204647 149486, 204115 149809, 200986 149811, 200646 149627, 200324 149132, 200322 146003, 200508 145623), (200505 150636, 201000 150314, 204129 150312, 204506 150495, 204829 151027, 204831 154156, 204647 154496, 204115 154819, 200986 154821, 200646 154637, 200324 154142, 200322 151013, 200505 150636), (200505 155646, 201000 155324, 204129 155322, 204506 155505, 204829 156037, 204831 159166, 204647 159506, 204115 159829, 200986 159831, 200646 159647, 200324 159152, 200322 156023, 200505 155646), (200505 160656, 201000 160334, 204129 160332, 204506 160515, 204829 161047, 204831 164176, 204647 164516, 204115 164839, 200986 164841, 200646 164657, 200324 164162, 200322 161033, 200505 160656), (200505 165666, 201000 165344, 204129 165342, 204506 165525, 204829 166057, 204831 169186, 204647 169526, 204115 169849, 200986 169851, 200646 169667, 200324 169172, 200322 166043, 200505 165666), (200505 170676, 201000 170354, 204129 170352, 204506 170535, 204829 171067, 204829 174225, 204523 174651, 204228 174790, 203640 174860, 200986 174861, 200646 174677, 200324 174182, 200322 171053, 200505 170676), (200505 175686, 201000 175364, 203640 175362, 204040 175565, 204250 175905, 204294 176251, 204090 176673, 203276 177276, 201459 178366, 200929 178397, 200697 178331, 200328 177912, 200322 176063, 200505 175686), (205459 65547, 205637 65349, 206131 65191, 206641 65225, 208707 66751, 209705 67662, 209790 68065, 209789 69024, 209665 69313, 209125 69646, 205996 69648, 205656 69464, 205334 68969, 205332 65840, 205459 65547), (205515 70473, 206010 70151, 209139 70149, 209516 70332, 209839 70864, 209841 73993, 209657 74333, 209125 74656, 205996 74658, 205656 74474, 205334 73979, 205332 70850, 205515 70473), (205515 75483, 206010 75161, 209139 75159, 209516 75342, 209839 75874, 209841 79003, 209657 79343, 209125 79666, 205996 79668, 205656 79484, 205334 78989, 205332 75860, 205515 75483), (205515 80493, 206010 80171, 209139 80169, 209516 80352, 209839 80884, 209841 84013, 209657 84353, 209125 84676, 205996 84678, 205656 84494, 205334 83999, 205332 80870, 205515 80493), (205515 85503, 206010 85181, 209139 85179, 209516 85362, 209839 85894, 209841 89023, 209657 89363, 209125 89686, 205996 89688, 205656 89504, 205334 89009, 205332 85880, 205515 85503), (205515 90513, 206010 90191, 209139 90189, 209516 90372, 209839 90904, 209841 94033, 209657 94373, 209124 94696, 205996 94698, 205656 94514, 205334 94019, 205332 90890, 205515 90513), (205518 95520, 206010 95201, 209138 95199, 209432 95326, 209623 95496, 209839 95913, 209841 99045, 209657 99385, 209125 99708, 205996 99710, 205656 99526, 205334 99031, 205332 95900, 205518 95520), (205515 100535, 206010 100213, 209139 100211, 209516 100394, 209839 100926, 209841 104055, 209657 104395, 209125 104718, 205996 104720, 205656 104536, 205334 104041, 205332 100912, 205515 100535), (205515 105545, 206010 105223, 209139 105221, 209516 105404, 209839 105936, 209841 109065, 209657 109405, 209125 109728, 205996 109730, 205656 109546, 205334 109051, 205332 105922, 205515 105545), (205515 110555, 206010 110233, 209139 110231, 209516 110414, 209839 110946, 209841 114075, 209657 114415, 209125 114738, 205996 114740, 205656 114556, 205334 114061, 205332 110932, 205515 110555), (205515 115565, 206010 115243, 209139 115241, 209516 115424, 209839 115956, 209841 119085, 209657 119425, 209125 119748, 205996 119750, 205656 119566, 205334 119071, 205332 115942, 205515 115565), (205515 120575, 206010 120253, 209139 120251, 209516 120434, 209839 120966, 209841 124095, 209657 124435, 209125 124758, 205996 124760, 205656 124576, 205334 124081, 205332 120952, 205515 120575), (205515 125585, 206010 125263, 209139 125261, 209516 125444, 209839 125976, 209841 129105, 209657 129445, 209124 129768, 205996 129770, 205656 129586, 205334 129091, 205332 125962, 205515 125585), (205518 130592, 206010 130273, 209138 130271, 209432 130398, 209623 130568, 209839 130985, 209841 134115, 209657 134455, 209125 134778, 205996 134780, 205656 134596, 205334 134101, 205332 130972, 205518 130592), (205515 135605, 206010 135283, 209139 135281, 209516 135464, 209839 135996, 209841 139125, 209657 139465, 209125 139788, 205996 139790, 205656 139606, 205334 139111, 205332 135982, 205515 135605), (205515 140615, 206010 140293, 209139 140291, 209516 140474, 209839 141006, 209841 144136, 209657 144476, 209124 144799, 205996 144801, 205656 144617, 205334 144122, 205332 140992, 205515 140615), (205518 145623, 206010 145304, 209138 145302, 209432 145429, 209623 145599, 209839 146016, 209841 149146, 209657 149486, 209125 149809, 205996 149811, 205656 149627, 205334 149132, 205332 146003, 205518 145623), (205515 150636, 206010 150314, 209139 150312, 209516 150495, 209839 151027, 209841 154156, 209657 154496, 209125 154819, 205996 154821, 205656 154637, 205334 154142, 205332 151013, 205515 150636), (205515 155646, 206010 155324, 209139 155322, 209516 155505, 209839 156037, 209841 159166, 209657 159506, 209125 159829, 205996 159831, 205656 159647, 205334 159152, 205332 156023, 205515 155646), (205515 160656, 206010 160334, 209139 160332, 209516 160515, 209839 161047, 209841 164176, 209657 164516, 209125 164839, 205996 164841, 205656 164657, 205334 164162, 205332 161033, 205515 160656), (205515 165666, 206010 165344, 209139 165342, 209516 165525, 209839 166057, 209841 169186, 209657 169526, 209125 169849, 205996 169851, 205656 169667, 205334 169172, 205332 166043, 205515 165666), (205515 170676, 206010 170354, 209139 170352, 209516 170535, 209789 170977, 209790 171934, 209626 172415, 208681 173270, 206735 174712, 205978 174787, 205633 174674, 205332 174233, 205332 171053, 205515 170676), (210525 70473, 210964 70200, 212504 70200, 213708 71284, 214752 72443, 214800 72793, 214799 74034, 214675 74323, 214135 74656, 211006 74658, 210666 74474, 210344 73979, 210342 70850, 210525 70473), (210525 75483, 211020 75161, 214149 75159, 214526 75342, 214849 75874, 214851 79003, 214667 79343, 214135 79666, 211006 79668, 210666 79484, 210344 78989, 210342 75860, 210525 75483), (210525 80493, 211020 80171, 214149 80169, 214526 80352, 214849 80884, 214851 84013, 214667 84353, 214135 84676, 211006 84678, 210666 84494, 210344 83999, 210342 80870, 210525 80493), (210525 85503, 211020 85181, 214149 85179, 214526 85362, 214849 85894, 214851 89023, 214667 89363, 214135 89686, 211006 89688, 210666 89504, 210344 89009, 210342 85880, 210525 85503), (210525 90513, 211020 90191, 214149 90189, 214526 90372, 214849 90904, 214851 94033, 214667 94373, 214134 94696, 211006 94698, 210666 94514, 210344 94019, 210342 90890, 210525 90513), (210528 95520, 211020 95201, 214148 95199, 214442 95326, 214633 95496, 214849 95913, 214851 99045, 214667 99385, 214135 99708, 211006 99710, 210666 99526, 210344 99031, 210342 95900, 210528 95520), (210525 100535, 211020 100213, 214149 100211, 214526 100394, 214849 100926, 214851 104055, 214667 104395, 214135 104718, 211006 104720, 210666 104536, 210344 104041, 210342 100912, 210525 100535), (210525 105545, 211020 105223, 214149 105221, 214526 105404, 214849 105936, 214851 109065, 214667 109405, 214135 109728, 211006 109730, 210666 109546, 210344 109051, 210342 105922, 210525 105545), (210525 110555, 211020 110233, 214149 110231, 214526 110414, 214849 110946, 214851 114075, 214667 114415, 214135 114738, 211006 114740, 210666 114556, 210344 114061, 210342 110932, 210525 110555), (210525 115565, 211020 115243, 214149 115241, 214526 115424, 214849 115956, 214851 119085, 214667 119425, 214135 119748, 211006 119750, 210666 119566, 210344 119071, 210342 115942, 210525 115565), (210525 120575, 211020 120253, 214149 120251, 214526 120434, 214849 120966, 214851 124095, 214667 124435, 214135 124758, 211006 124760, 210666 124576, 210344 124081, 210342 120952, 210525 120575), (210525 125585, 211020 125263, 214149 125261, 214526 125444, 214849 125976, 214851 129105, 214667 129445, 214134 129768, 211006 129770, 210666 129586, 210344 129091, 210342 125962, 210525 125585), (210528 130592, 211020 130273, 214148 130271, 214442 130398, 214633 130568, 214849 130985, 214851 134115, 214667 134455, 214135 134778, 211006 134780, 210666 134596, 210344 134101, 210342 130972, 210528 130592), (210525 135605, 211020 135283, 214149 135281, 214526 135464, 214849 135996, 214851 139125, 214667 139465, 214135 139788, 211006 139790, 210666 139606, 210344 139111, 210342 135982, 210525 135605), (210525 140615, 211020 140293, 214149 140291, 214526 140474, 214849 141006, 214851 144136, 214667 144476, 214134 144799, 211006 144801, 210666 144617, 210344 144122, 210342 140992, 210525 140615), (210528 145623, 211020 145304, 214148 145302, 214442 145429, 214633 145599, 214849 146016, 214851 149146, 214667 149486, 214135 149809, 211006 149811, 210666 149627, 210344 149132, 210342 146003, 210528 145623), (210525 150636, 211020 150314, 214149 150312, 214526 150495, 214849 151027, 214851 154156, 214667 154496, 214135 154819, 211006 154821, 210666 154637, 210344 154142, 210342 151013, 210525 150636), (210525 155646, 211020 155324, 214149 155322, 214526 155505, 214849 156037, 214851 159166, 214667 159506, 214135 159829, 211006 159831, 210666 159647, 210344 159152, 210342 156023, 210525 155646), (210525 160656, 211020 160334, 214149 160332, 214526 160515, 214849 161047, 214851 164176, 214667 164516, 214135 164839, 211006 164841, 210666 164657, 210344 164162, 210342 161033, 210525 160656), (210525 165666, 211020 165344, 214149 165342, 214526 165525, 214799 165964, 214799 167206, 214681 167643, 213740 168683, 212643 169680, 212206 169799, 210965 169799, 210676 169674, 210344 169172, 210342 166043, 210525 165666), (215535 75483, 215974 75210, 216934 75210, 217336 75293, 218249 76292, 219712 78264, 219787 79021, 219674 79367, 219233 79667, 216016 79668, 215676 79484, 215354 78989, 215352 75860, 215535 75483), (215535 80493, 216030 80171, 219225 80170, 219651 80475, 219791 80770, 219860 81359, 219861 84013, 219677 84353, 219145 84676, 216016 84678, 215676 84494, 215354 83999, 215352 80870, 215535 80493), (215535 85503, 216030 85181, 219159 85179, 219536 85362, 219859 85894, 219861 89023, 219677 89363, 219145 89686, 216016 89688, 215676 89504, 215354 89009, 215352 85880, 215535 85503), (215535 90513, 216030 90191, 219159 90189, 219536 90372, 219859 90904, 219861 94033, 219677 94373, 219144 94696, 216016 94698, 215676 94514, 215354 94019, 215352 90890, 215535 90513), (215538 95520, 216030 95201, 219158 95199, 219452 95326, 219643 95496, 219859 95913, 219861 99045, 219677 99385, 219145 99708, 216016 99710, 215676 99526, 215354 99031, 215352 95900, 215538 95520), (215535 100535, 216030 100213, 219159 100211, 219536 100394, 219859 100926, 219861 104055, 219677 104395, 219145 104718, 216016 104720, 215676 104536, 215354 104041, 215352 100912, 215535 100535), (215535 105545, 216030 105223, 219159 105221, 219536 105404, 219859 105936, 219861 109065, 219677 109405, 219145 109728, 216016 109730, 215676 109546, 215354 109051, 215352 105922, 215535 105545), (215535 110555, 216030 110233, 219159 110231, 219536 110414, 219859 110946, 219861 114075, 219677 114415, 219145 114738, 216016 114740, 215676 114556, 215354 114061, 215352 110932, 215535 110555), (215535 115565, 216030 115243, 219159 115241, 219536 115424, 219859 115956, 219861 119085, 219677 119425, 219145 119748, 216016 119750, 215676 119566, 215354 119071, 215352 115942, 215535 115565), (215535 120575, 216030 120253, 219159 120251, 219536 120434, 219859 120966, 219861 124095, 219677 124435, 219145 124758, 216016 124760, 215676 124576, 215354 124081, 215352 120952, 215535 120575), (215535 125585, 216030 125263, 219159 125261, 219536 125444, 219859 125976, 219861 129105, 219677 129445, 219144 129768, 216016 129770, 215676 129586, 215354 129091, 215352 125962, 215535 125585), (215538 130592, 216030 130273, 219158 130271, 219452 130398, 219643 130568, 219859 130985, 219861 134115, 219677 134455, 219145 134778, 216016 134780, 215676 134596, 215354 134101, 215352 130972, 215538 130592), (215535 135605, 216030 135283, 219159 135281, 219536 135464, 219859 135996, 219861 139125, 219677 139465, 219145 139788, 216016 139790, 215676 139606, 215354 139111, 215352 135982, 215535 135605), (215535 140615, 216030 140293, 219159 140291, 219536 140474, 219859 141006, 219861 144136, 219677 144476, 219144 144799, 216016 144801, 215676 144617, 215354 144122, 215352 140992, 215535 140615), (215538 145623, 216030 145304, 219158 145302, 219452 145429, 219643 145599, 219859 146016, 219861 149146, 219677 149486, 219145 149809, 216016 149811, 215676 149627, 215354 149132, 215352 146003, 215538 145623), (215535 150636, 216030 150314, 219159 150312, 219536 150495, 219859 151027, 219861 154156, 219677 154496, 219145 154819, 216016 154821, 215676 154637, 215354 154142, 215352 151013, 215535 150636), (215535 155646, 216030 155324, 219159 155322, 219536 155505, 219859 156037, 219863 158811, 219759 159371, 219681 159502, 219145 159829, 216016 159831, 215676 159647, 215354 159152, 215352 156023, 215535 155646), (215535 160656, 216030 160334, 219159 160332, 219580 160554, 219748 160821, 219808 161131, 219774 161641, 218249 163706, 217415 164626, 216934 164789, 215975 164789, 215686 164664, 215354 164162, 215352 161033, 215535 160656), (220479 81084, 220654 80877, 220905 80749, 221251 80705, 221602 80823, 222276 81721, 223419 83639, 223332 84302, 222912 84671, 221026 84678, 220686 84494, 220364 83999, 220362 81359, 220479 81084), (220545 85503, 221040 85181, 222955 85176, 223925 85230, 224456 85433, 224820 85951, 224813 89076, 224632 89422, 224155 89686, 221026 89688, 220686 89504, 220364 89009, 220362 85880, 220545 85503), (220545 90513, 221040 90191, 224169 90189, 224546 90372, 224869 90904, 224871 94033, 224686 94374, 224154 94696, 221026 94698, 220686 94514, 220364 94019, 220362 90890, 220545 90513), (220548 95520, 221040 95201, 224168 95199, 224462 95326, 224653 95496, 224869 95913, 224871 99045, 224687 99385, 224155 99708, 221026 99710, 220686 99526, 220364 99031, 220362 95900, 220548 95520), (220545 100535, 221040 100213, 224169 100211, 224546 100394, 224869 100926, 224871 104055, 224687 104395, 224155 104718, 221026 104720, 220686 104536, 220364 104041, 220362 100912, 220545 100535), (220545 105545, 221040 105223, 224169 105221, 224546 105404, 224869 105936, 224871 109065, 224687 109405, 224155 109728, 221026 109730, 220686 109546, 220364 109051, 220362 105922, 220545 105545), (220545 110555, 221040 110233, 224169 110231, 224546 110414, 224869 110946, 224871 114075, 224687 114415, 224155 114738, 221026 114740, 220686 114556, 220364 114061, 220362 110932, 220545 110555), (220545 115565, 221040 115243, 224169 115241, 224546 115424, 224869 115956, 224871 119085, 224687 119425, 224155 119748, 221026 119750, 220686 119566, 220364 119071, 220362 115942, 220545 115565), (220545 120575, 221040 120253, 224169 120251, 224546 120434, 224869 120966, 224871 124095, 224687 124435, 224155 124758, 221026 124760, 220686 124576, 220364 124081, 220362 120952, 220545 120575), (220545 125585, 221040 125263, 224169 125261, 224546 125444, 224869 125976, 224871 129105, 224687 129445, 224154 129768, 221026 129770, 220686 129586, 220364 129091, 220362 125962, 220545 125585), (220548 130592, 221040 130273, 224168 130271, 224462 130398, 224653 130568, 224869 130985, 224871 134115, 224687 134455, 224155 134778, 221026 134780, 220686 134596, 220364 134101, 220362 130972, 220548 130592), (220545 135605, 221040 135283, 224169 135281, 224546 135464, 224869 135996, 224871 139125, 224687 139465, 224155 139788, 221026 139790, 220686 139606, 220364 139111, 220362 135982, 220545 135605), (220545 140615, 221040 140293, 224169 140291, 224546 140474, 224869 141006, 224871 144136, 224687 144476, 224154 144799, 221026 144801, 220686 144617, 220364 144122, 220362 140992, 220545 140615), (220548 145623, 221040 145304, 224168 145302, 224462 145429, 224653 145599, 224869 146016, 224869 149174, 224629 149548, 224155 149809, 221026 149811, 220686 149627, 220364 149132, 220362 146003, 220548 145623), (220545 150636, 221040 150314, 224169 150312, 224544 150494, 224708 150699, 224815 150984, 224819 152368, 224829 154010, 224456 154566, 223925 154769, 222723 154820, 221026 154821, 220686 154637, 220364 154142, 220362 151013, 220545 150636), (220545 155646, 221040 155324, 222723 155322, 223066 155480, 223358 155741, 223406 156394, 222278 158274, 221684 159077, 221022 159273, 220654 159135, 220368 158768, 220362 156023, 220545 155646), (225610 90454, 225796 90334, 226482 90242, 226859 90331, 227218 90619, 228692 93742, 228517 94372, 228141 94674, 226036 94698, 225696 94514, 225374 94019, 225372 90890, 225610 90454), (225558 95520, 226050 95201, 228185 95191, 228837 95271, 229112 95421, 229382 95696, 229857 97034, 229829 99006, 229704 99376, 229165 99708, 226036 99710, 225696 99526, 225374 99031, 225372 95900, 225558 95520), (225555 100535, 226050 100213, 229179 100211, 229472 100338, 229700 100562, 229828 100857, 229829 104097, 229705 104385, 229165 104718, 226036 104720, 225696 104536, 225374 104041, 225372 100912, 225555 100535), (225555 105545, 226050 105223, 229179 105221, 229556 105404, 229879 105936, 229881 109065, 229697 109405, 229165 109728, 226036 109730, 225696 109546, 225374 109051, 225372 105922, 225555 105545), (225555 110555, 226050 110233, 229179 110231, 229556 110414, 229879 110946, 229881 114075, 229697 114415, 229165 114738, 226036 114740, 225696 114556, 225374 114061, 225372 110932, 225555 110555), (225555 115565, 226050 115243, 229179 115241, 229556 115424, 229879 115956, 229881 119085, 229697 119425, 229165 119748, 226036 119750, 225696 119566, 225374 119071, 225372 115942, 225555 115565), (225555 120575, 226050 120253, 229179 120251, 229556 120434, 229879 120966, 229881 124095, 229697 124435, 229165 124758, 226036 124760, 225696 124576, 225374 124081, 225372 120952, 225555 120575), (225555 125585, 226050 125263, 229179 125261, 229556 125444, 229879 125976, 229881 129105, 229697 129445, 229164 129768, 226036 129770, 225696 129586, 225374 129091, 225372 125962, 225555 125585), (225558 130592, 226050 130273, 229178 130271, 229472 130398, 229663 130568, 229879 130985, 229879 134143, 229639 134517, 229165 134778, 226036 134780, 225696 134596, 225374 134101, 225372 130972, 225558 130592), (225555 135605, 226050 135283, 229179 135281, 229554 135463, 229718 135668, 229826 135968, 229830 139088, 229778 139333, 229629 139536, 229165 139788, 226036 139790, 225696 139606, 225374 139111, 225372 135982, 225555 135605), (225555 140615, 226050 140293, 229179 140291, 229603 140515, 229768 140779, 229830 141046, 229889 142889, 229339 144407, 228840 144727, 227959 144800, 226036 144801, 225696 144617, 225374 144122, 225372 140992, 225555 140615), (225558 145623, 226050 145304, 227959 145302, 228548 145650, 228693 146258, 227166 149480, 226860 149669, 226510 149759, 225896 149721, 225601 149561, 225372 149181, 225372 146003, 225558 145623), (230565 105545, 231008 105285, 231645 105272, 232016 105400, 232373 105792, 232556 106521, 232927 109044, 232682 109468, 232280 109723, 231046 109730, 230706 109546, 230384 109051, 230382 105922, 230565 105545), (230565 110555, 231060 110233, 232323 110228, 232793 110354, 233005 110549, 233205 110870, 233552 113205, 233595 114119, 233311 114515, 232949 114734, 231046 114740, 230706 114556, 230384 114061, 230382 110932, 230565 110555), (230565 115565, 231060 115243, 232989 115238, 233332 115398, 233517 115605, 233689 115954, 233841 119129, 233543 119535, 233130 119748, 231046 119750, 230706 119566, 230384 119071, 230382 115942, 230565 115565), (230565 120575, 231060 120253, 233145 120251, 233520 120433, 233701 120674, 233837 121039, 233678 124205, 233355 124572, 232983 124759, 231046 124760, 230706 124576, 230384 124081, 230382 120952, 230565 120575), (230565 125585, 231060 125263, 232971 125262, 233288 125454, 233455 125684, 233591 126049, 233557 126751, 233178 129277, 232821 129610, 232481 129769, 231046 129770, 230706 129586, 230384 129091, 230382 125962, 230565 125585), (230568 130592, 231060 130273, 232375 130271, 232658 130501, 232804 130746, 232907 131132, 232564 133440, 232341 134317, 232016 134600, 231620 134728, 230916 134692, 230611 134530, 230382 134150, 230382 130972, 230568 130592)) From 2631abaa3d2b8f46c5963b63c5e7ea8d8acbc050 Mon Sep 17 00:00:00 2001 From: Jelle Spijker Date: Sun, 21 Jan 2024 16:01:16 +0100 Subject: [PATCH 072/201] Also run workflows on NP branches Contributes to NP-5 --- .github/workflows/benchmark.yml | 1 + .github/workflows/conan-package.yml | 1 + .github/workflows/gcodeanalyzer.yml | 1 + .github/workflows/stress_benchmark.yml | 1 + .github/workflows/unit-test.yml | 1 + 5 files changed, 5 insertions(+) diff --git a/.github/workflows/benchmark.yml b/.github/workflows/benchmark.yml index 486474a5f5..91943e6dcc 100644 --- a/.github/workflows/benchmark.yml +++ b/.github/workflows/benchmark.yml @@ -21,6 +21,7 @@ on: - main - 'CURA-*' - 'PP-*' + - 'NP-*' - '[0-9]+.[0-9]+' permissions: diff --git a/.github/workflows/conan-package.yml b/.github/workflows/conan-package.yml index 76060d3063..0acc07d220 100644 --- a/.github/workflows/conan-package.yml +++ b/.github/workflows/conan-package.yml @@ -14,6 +14,7 @@ on: - main - 'CURA-*' - 'PP-*' + - 'NP-*' - '[0-9].[0-9]*' - '[0-9].[0-9][0-9]*' tags: diff --git a/.github/workflows/gcodeanalyzer.yml b/.github/workflows/gcodeanalyzer.yml index 141bc61989..29c83817de 100644 --- a/.github/workflows/gcodeanalyzer.yml +++ b/.github/workflows/gcodeanalyzer.yml @@ -17,6 +17,7 @@ on: - main - 'CURA-*' - 'PP-*' + - 'NP-*' - '[0-9]+.[0-9]+' permissions: diff --git a/.github/workflows/stress_benchmark.yml b/.github/workflows/stress_benchmark.yml index 3911302b5d..f09bb61a8b 100644 --- a/.github/workflows/stress_benchmark.yml +++ b/.github/workflows/stress_benchmark.yml @@ -20,6 +20,7 @@ on: - main - 'CURA-*' - 'PP-*' + - 'NP-*' - '[0-9]+.[0-9]+' permissions: diff --git a/.github/workflows/unit-test.yml b/.github/workflows/unit-test.yml index 66e7bc0f82..b8c85c284d 100644 --- a/.github/workflows/unit-test.yml +++ b/.github/workflows/unit-test.yml @@ -15,6 +15,7 @@ on: - main - 'CURA-*' - 'PP-*' + - 'NP-*' - '[0-9]+.[0-9]+' pull_request: From 962fb1fd555df02cda40468bf1c7a25d0a5850a0 Mon Sep 17 00:00:00 2001 From: Jelle Spijker Date: Sun, 21 Jan 2024 16:38:57 +0100 Subject: [PATCH 073/201] Disable plugins during compile time This allows us to drop the requirement of gRPC. This is needed due to the limited WASM cross-platform support of gRPC. See issue https://github.com/grpc/grpc/issues/24166 Contributes to NP-5 --- CMakeLists.txt | 18 ++++++------ benchmark/simplify_benchmark.h | 9 ++++-- conandata.yml | 3 +- conanfile.py | 7 +++-- include/plugins/converters.h | 21 +++++++------- include/plugins/slots.h | 51 +++++++++++++++++++++++++++++++++- include/utils/channel.h | 4 ++- src/infill.cpp | 4 ++- src/plugins/converters.cpp | 5 +++- src/utils/channel.cpp | 5 +++- 10 files changed, 98 insertions(+), 29 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 62dab2e03d..69cc2ca6d8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -20,13 +20,13 @@ option(OLDER_APPLE_CLANG "Apple Clang <= 13 used" OFF) # Generate the plugin types find_package(protobuf REQUIRED) -find_package(asio-grpc REQUIRED) -find_package(gRPC REQUIRED) -find_package(curaengine_grpc_definitions REQUIRED) option(OLDER_APPLE_CLANG "Apple Clang <= 13 used" OFF) MESSAGE(STATUS "Compiling with plugins support: ${ENABLE_PLUGINS}") if (${ENABLE_PLUGINS}) + find_package(asio-grpc REQUIRED) + find_package(gRPC REQUIRED) + find_package(curaengine_grpc_definitions REQUIRED) MESSAGE(STATUS "Plugin secure remotes allowed: ${ENABLE_REMOTE_PLUGINS}") endif () @@ -221,9 +221,9 @@ target_link_libraries(_CuraEngine boost::boost scripta::scripta semver::semver - curaengine_grpc_definitions::curaengine_grpc_definitions - asio-grpc::asio-grpc - grpc::grpc + $<$:curaengine_grpc_definitions::curaengine_grpc_definitions> + $<$:asio-grpc::asio-grpc> + $<$:grpc::grpc> protobuf::libprotobuf $<$:sentry::sentry> $<$:GTest::gtest>) @@ -280,9 +280,9 @@ if (ENABLE_TESTING OR ENABLE_BENCHMARKS) GTest::gtest GTest::gmock clipper::clipper - curaengine_grpc_definitions::curaengine_grpc_definitions - asio-grpc::asio-grpc - grpc::grpc + $<$:curaengine_grpc_definitions::curaengine_grpc_definitions> + $<$:asio-grpc::asio-grpc> + $<$:grpc::grpc> protobuf::libprotobuf) if (ENABLE_ARCUS) target_link_libraries(test_helpers PUBLIC arcus::arcus) diff --git a/benchmark/simplify_benchmark.h b/benchmark/simplify_benchmark.h index d3726bce65..88360af005 100644 --- a/benchmark/simplify_benchmark.h +++ b/benchmark/simplify_benchmark.h @@ -1,11 +1,10 @@ -// Copyright (c) 2023 UltiMaker +// Copyright (c) 2024 UltiMaker // CuraEngine is released under the terms of the AGPLv3 or higher #ifndef CURAENGINE_BENCHMARK_SIMPLIFY_BENCHMARK_H #define CURAENGINE_BENCHMARK_SIMPLIFY_BENCHMARK_H #include "../tests/ReadTestPolygons.h" -#include "plugins/slots.h" #include "utils/Simplify.h" #include "utils/channel.h" @@ -13,7 +12,11 @@ #include #include + +#ifdef ENABLE_PLUGINS +#include "plugins/slots.h" #include +#endif namespace cura { @@ -58,6 +61,7 @@ BENCHMARK_DEFINE_F(SimplifyTestFixture, simplify_local)(benchmark::State& st) BENCHMARK_REGISTER_F(SimplifyTestFixture, simplify_local); +#ifdef ENABLE_PLUGINS BENCHMARK_DEFINE_F(SimplifyTestFixture, simplify_slot_noplugin)(benchmark::State& st) { for (auto _ : st) @@ -71,6 +75,7 @@ BENCHMARK_DEFINE_F(SimplifyTestFixture, simplify_slot_noplugin)(benchmark::State } BENCHMARK_REGISTER_F(SimplifyTestFixture, simplify_slot_noplugin); +#endif } // namespace cura #endif // CURAENGINE_BENCHMARK_SIMPLIFY_BENCHMARK_H diff --git a/conandata.yml b/conandata.yml index a020e5417a..a0e277c652 100644 --- a/conandata.yml +++ b/conandata.yml @@ -1,5 +1,6 @@ version: "5.7.0-alpha.1" requirements: - "arcus/5.3.1" - - "curaengine_grpc_definitions/(latest)@ultimaker/testing" - "scripta/0.1.0@ultimaker/testing" +requirements_plugins: + - "curaengine_grpc_definitions/(latest)@ultimaker/testing" diff --git a/conanfile.py b/conanfile.py index 6c0fe885b4..c183c1a011 100644 --- a/conanfile.py +++ b/conanfile.py @@ -105,8 +105,11 @@ def requirements(self): self.requires(req) if self.options.get_safe("enable_sentry", False): self.requires("sentry-native/0.6.5") - self.requires("asio-grpc/2.6.0") - self.requires("grpc/1.50.1") + if self.options.enable_plugins: + self.requires("asio-grpc/2.6.0") + self.requires("grpc/1.50.1") + for req in self.conan_data["requirements_plugins"]: + self.requires(req) self.requires("clipper/6.4.2@ultimaker/stable") self.requires("boost/1.82.0") self.requires("rapidjson/1.1.0") diff --git a/include/plugins/converters.h b/include/plugins/converters.h index 01870b2056..9af4e7cbae 100644 --- a/include/plugins/converters.h +++ b/include/plugins/converters.h @@ -1,8 +1,17 @@ -// Copyright (c) 2023 UltiMaker +// Copyright (c) 2024 UltiMaker // CuraEngine is released under the terms of the AGPLv3 or higher #ifndef PLUGINS_CONVERTERS_H #define PLUGINS_CONVERTERS_H +#ifdef ENABLE_PLUGINS + +#include +#include +#include + +#include +#include +#include #include "Cura.pb.h" #include "WallToolPaths.h" @@ -26,14 +35,6 @@ #include "settings/types/LayerIndex.h" #include "utils/polygon.h" -#include -#include -#include - -#include -#include -#include - namespace cura::plugins { @@ -128,5 +129,5 @@ struct gcode_paths_modify_response : public details::converter #include #include @@ -237,4 +238,52 @@ using slots = plugins::details::SingletonRegistry::min(), + SlotID_INT_MAX_SENTINEL_DO_NOT_USE_ = std::numeric_limits::max() +}; +} // namespace plugins::v0 + +namespace slots +{ +namespace details +{ +struct Slots +{ + template + constexpr auto modify(auto&& data, auto&&... args) noexcept { return std::forward(data); } + + template + constexpr auto broadcast(auto&&... args) noexcept {} + + constexpr auto connect(auto&&... args) noexcept {} +}; +} // namespace details + +constexpr details::Slots instance() noexcept +{ + return {}; +} +} // namespace slots + +} // namespace cura + + +#endif // ENABLE_PLUGINS + #endif // PLUGINS_SLOTS_H diff --git a/include/utils/channel.h b/include/utils/channel.h index 4ff915ffe7..fb3574d169 100644 --- a/include/utils/channel.h +++ b/include/utils/channel.h @@ -1,9 +1,10 @@ -// Copyright (c) 2023 UltiMaker +// Copyright (c) 2024 UltiMaker // CuraEngine is released under the terms of the AGPLv3 or higher #ifndef CHANNEL_H #define CHANNEL_H +#ifdef ENABLE_PLUGINS #include #include #include @@ -26,4 +27,5 @@ std::shared_ptr createChannel(const ChannelSetupConfiguration& co } // namespace cura::utils +#endif // ENABLE_PLUGINS #endif // CHANNEL_H diff --git a/src/infill.cpp b/src/infill.cpp index e746846c02..f28afe7ab2 100644 --- a/src/infill.cpp +++ b/src/infill.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2023 UltiMaker +// Copyright (c) 2024 UltiMaker // CuraEngine is released under the terms of the AGPLv3 or higher #include "infill.h" @@ -317,6 +317,7 @@ void Infill::_generate( break; case EFillMethod::PLUGIN: { +#ifdef ENABLE_PLUGINS // FIXME: I don't like this conditional block outside of the plugin scope. auto [toolpaths_, generated_result_polygons_, generated_result_lines_] = slots::instance().generate( inner_contour_, mesh ? mesh->settings.get("infill_pattern") : settings.get("infill_pattern"), @@ -324,6 +325,7 @@ void Infill::_generate( toolpaths.insert(toolpaths.end(), toolpaths_.begin(), toolpaths_.end()); result_polygons.add(generated_result_polygons_); result_lines.add(generated_result_lines_); +#endif break; } default: diff --git a/src/plugins/converters.cpp b/src/plugins/converters.cpp index 40988a2f7b..134fec86dd 100644 --- a/src/plugins/converters.cpp +++ b/src/plugins/converters.cpp @@ -1,6 +1,7 @@ -// Copyright (c) 2023 UltiMaker +// Copyright (c) 2024 UltiMaker // CuraEngine is released under the terms of the AGPLv3 or higher +#ifdef ENABLE_PLUGINS #include "plugins/converters.h" @@ -481,3 +482,5 @@ gcode_paths_modify_response::native_value_type return paths; } } // namespace cura::plugins + +#endif // ENABLE_PLUGINS \ No newline at end of file diff --git a/src/utils/channel.cpp b/src/utils/channel.cpp index 45d1711b1b..3b181afa4f 100644 --- a/src/utils/channel.cpp +++ b/src/utils/channel.cpp @@ -1,5 +1,6 @@ -// Copyright (c) 2023 UltiMaker +// Copyright (c) 2024 UltiMaker // CuraEngine is released under the terms of the AGPLv3 or higher +#ifdef ENABLE_PLUGINS #include "utils/channel.h" @@ -45,3 +46,5 @@ std::shared_ptr createChannel(const ChannelSetupConfiguration& co } } // namespace cura::utils + +#endif // ENABLE_PLUGINS \ No newline at end of file From a8ce1d04530b9d46f7d5ad0d49ea8fe138735a73 Mon Sep 17 00:00:00 2001 From: jellespijker Date: Sun, 21 Jan 2024 15:39:23 +0000 Subject: [PATCH 074/201] Applied clang-format. --- include/plugins/slots.h | 13 ++++++++++--- src/infill.cpp | 2 +- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/include/plugins/slots.h b/include/plugins/slots.h index 0435b74882..b5fe0d2869 100644 --- a/include/plugins/slots.h +++ b/include/plugins/slots.h @@ -266,12 +266,19 @@ namespace details struct Slots { template - constexpr auto modify(auto&& data, auto&&... args) noexcept { return std::forward(data); } + constexpr auto modify(auto&& data, auto&&... args) noexcept + { + return std::forward(data); + } template - constexpr auto broadcast(auto&&... args) noexcept {} + constexpr auto broadcast(auto&&... args) noexcept + { + } - constexpr auto connect(auto&&... args) noexcept {} + constexpr auto connect(auto&&... args) noexcept + { + } }; } // namespace details diff --git a/src/infill.cpp b/src/infill.cpp index f28afe7ab2..c085307622 100644 --- a/src/infill.cpp +++ b/src/infill.cpp @@ -317,7 +317,7 @@ void Infill::_generate( break; case EFillMethod::PLUGIN: { -#ifdef ENABLE_PLUGINS // FIXME: I don't like this conditional block outside of the plugin scope. +#ifdef ENABLE_PLUGINS // FIXME: I don't like this conditional block outside of the plugin scope. auto [toolpaths_, generated_result_polygons_, generated_result_lines_] = slots::instance().generate( inner_contour_, mesh ? mesh->settings.get("infill_pattern") : settings.get("infill_pattern"), From 1247d25ccbba084ed7ae9ad3c64553f9fa8056b9 Mon Sep 17 00:00:00 2001 From: Jelle Spijker Date: Sun, 21 Jan 2024 17:05:22 +0100 Subject: [PATCH 075/201] Adhoc disabling of threading support Will figure out why this doesn't work out of the box Contributes to NP-5 --- CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 69cc2ca6d8..1b1ec4bb48 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -154,7 +154,7 @@ set(engine_SRCS # Except main.cpp. ) add_library(_CuraEngine STATIC ${engine_SRCS} ${engine_PB_SRCS}) -use_threads(_CuraEngine) +#use_threads(_CuraEngine) target_include_directories(_CuraEngine PUBLIC @@ -250,7 +250,7 @@ else () endif () endif (NOT WIN32) -use_threads(CuraEngine) +#use_threads(CuraEngine) target_link_libraries(CuraEngine PRIVATE _CuraEngine $<$:sentry::sentry> From 893f56b4d00aaab1567dff1904073e16dc68d4ea Mon Sep 17 00:00:00 2001 From: Jelle Spijker Date: Mon, 22 Jan 2024 17:57:58 +0100 Subject: [PATCH 076/201] Add emscripten logic Based on the CuraEngine patch done by Wakeful-Cloud. Not sure if we want to go the same route but it will give us a quick way forward. https://github.com/Cloud-CNC/cura-wasm Doing the conan install with the following profile ``` include(cura.jinja) [tool_requires] emsdk/3.1.50 [settings] os=Emscripten arch=wasm ``` should do the trick in building it with emsdk. Still very much WIP! Contributes to NP-5 Co-authored-by: Wakeful-Cloud --- CMakeLists.txt | 12 ++++++------ conanfile.py | 3 +++ include/communication/CommandLine.h | 8 ++++++-- src/communication/CommandLine.cpp | 21 ++++++++++++++++++++- 4 files changed, 35 insertions(+), 9 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1b1ec4bb48..f5aca49732 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -151,7 +151,7 @@ set(engine_SRCS # Except main.cpp. src/utils/ToolpathVisualizer.cpp src/utils/VoronoiUtils.cpp src/utils/VoxelUtils.cpp - ) +) add_library(_CuraEngine STATIC ${engine_SRCS} ${engine_PB_SRCS}) #use_threads(_CuraEngine) @@ -162,7 +162,7 @@ target_include_directories(_CuraEngine $ PRIVATE $ # Include Cura.pb.h - ) +) target_compile_definitions(_CuraEngine PUBLIC @@ -180,7 +180,7 @@ target_compile_definitions(_CuraEngine $<$:ASSERT_INSANE_OUTPUT> $<$:USE_CPU_TIME> $<$:DEBUG> - ) +) enable_sanitizers(_CuraEngine) @@ -189,7 +189,7 @@ if (${EXTENSIVE_WARNINGS}) endif () if (ENABLE_ARCUS) - target_link_libraries(_CuraEngine PUBLIC arcus::arcus ) + target_link_libraries(_CuraEngine PUBLIC arcus::arcus) endif () find_package(clipper REQUIRED) @@ -242,7 +242,7 @@ else () SET(CMAKE_RC_COMPILER_INIT windres) SET(CMAKE_RC_COMPILE_OBJECT " -O coff -i -o " - ) + ) endif () add_executable(CuraEngine src/main.cpp ${RES_FILES}) # ..., but don't forget the glitter! if (ENABLE_SENTRY) @@ -293,7 +293,7 @@ if (ENABLE_BENCHMARKS) add_subdirectory(benchmark) if (NOT WIN32) add_subdirectory(stress_benchmark) - endif() + endif () endif () if (ENABLE_TESTING) diff --git a/conanfile.py b/conanfile.py index c183c1a011..e3313e1cbd 100644 --- a/conanfile.py +++ b/conanfile.py @@ -143,6 +143,9 @@ def generate(self): tc.variables["ENABLE_PLUGINS"] = self.options.enable_plugins tc.generate() + if self.settings.arch == "wasm" and self.settings.os == "Emscripten": + self.buildenv.define("EMCC_CFLAGS", "-s ALLOW_MEMORY_GROWTH=1 -s EXPORT_ES6=1 -s EXPORT_NAME='CuraEngine' -s EXPORTED_RUNTIME_METHODS='[\"callMain\", \"FS\"]' -s INVOKE_RUN=0 -s MODULARIZE=1 -s SINGLE_FILE=1 -s ENVIRONMENT=worker -s USE_ES6_IMPORT_META=0") + for dep in self.dependencies.values(): if len(dep.cpp_info.libdirs) > 0: copy(self, "*.dylib", dep.cpp_info.libdirs[0], self.build_folder) diff --git a/include/communication/CommandLine.h b/include/communication/CommandLine.h index ac7c1ccda7..d6ded052d4 100644 --- a/include/communication/CommandLine.h +++ b/include/communication/CommandLine.h @@ -1,5 +1,5 @@ -// Copyright (c) 2018-2022 Ultimaker B.V. -// CuraEngine is released under the terms of the AGPLv3 or higher. +// Copyright (c) 2024 UltiMaker +// CuraEngine is released under the terms of the AGPLv3 or higher #ifndef COMMANDLINE_H #define COMMANDLINE_H @@ -151,6 +151,10 @@ class CommandLine : public Communication void sliceNext() override; private: +#ifdef __EMSCRIPTEN__ + std::string progressHandler; +#endif + /* * \brief The command line arguments that the application was called with. */ diff --git a/src/communication/CommandLine.cpp b/src/communication/CommandLine.cpp index 95359abae4..1ecf3e7a71 100644 --- a/src/communication/CommandLine.cpp +++ b/src/communication/CommandLine.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2022 Ultimaker B.V. +// Copyright (c) 2024 UltiMaker // CuraEngine is released under the terms of the AGPLv3 or higher #include "communication/CommandLine.h" @@ -21,6 +21,10 @@ #include "Slice.h" #include "utils/Matrix4x3D.h" //For the mesh_rotation_matrix setting. +#ifdef __EMSCRIPTEN__ +#include +#endif + namespace cura { @@ -106,6 +110,12 @@ void CommandLine::sendProgress(double progress) const return; } // TODO: Do we want to print a progress bar? We'd need a better solution to not have that progress bar be ruined by any logging. +#ifdef __EMSCRIPTEN__ + // Call progress handler with progress + char js[100]; + std::sprintf(js, "globalThis[\"%s\"](%f)", progressHandler.c_str(), progress); + emscripten_run_script(js); +#endif } void CommandLine::sliceNext() @@ -178,6 +188,15 @@ void CommandLine::sliceNext() force_read_parent = false; force_read_nondefault = false; } +#ifdef __EMSCRIPTEN__ + else if (argument.find("--progress") == 0) + { + // Store progress handler name + argument_index++; + argument = arguments_[argument_index]; + progressHandler = argument; + } +#endif else { spdlog::error("Unknown option: {}", argument); From dbfc66dca734877f0696bb6c53a6901483bd92cc Mon Sep 17 00:00:00 2001 From: Jelle Spijker Date: Wed, 24 Jan 2024 15:41:59 +0100 Subject: [PATCH 077/201] ensure that grpc and protobuf aren't used Contributes to NP-5 --- CMakeLists.txt | 14 ++++++++------ conandata.yml | 3 ++- conanfile.py | 12 ++++++------ 3 files changed, 16 insertions(+), 13 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f5aca49732..908d34746b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -18,20 +18,23 @@ option(ENABLE_MORE_COMPILER_OPTIMIZATION_FLAGS "Enable more optimization flags" option(USE_SYSTEM_LIBS "Use the system libraries if available" OFF) option(OLDER_APPLE_CLANG "Apple Clang <= 13 used" OFF) -# Generate the plugin types -find_package(protobuf REQUIRED) option(OLDER_APPLE_CLANG "Apple Clang <= 13 used" OFF) -MESSAGE(STATUS "Compiling with plugins support: ${ENABLE_PLUGINS}") +if (${ENABLE_ARCUS} OR ${ENABLE_PLUGINS}) + find_package(protobuf REQUIRED) +endif () + +MESSAGE(STATUS "Building with plugins support: ${ENABLE_PLUGINS}") if (${ENABLE_PLUGINS}) find_package(asio-grpc REQUIRED) find_package(gRPC REQUIRED) find_package(curaengine_grpc_definitions REQUIRED) + find_package(semver REQUIRED) MESSAGE(STATUS "Plugin secure remotes allowed: ${ENABLE_REMOTE_PLUGINS}") endif () -if (ENABLE_ARCUS) - message(STATUS "Building with Arcus") +message(STATUS "Building with Arcus: ${ENABLE_ARCUS}") +if (${ENABLE_ARCUS}) find_package(arcus REQUIRED) protobuf_generate_cpp(engine_PB_SRCS engine_PB_HEADERS Cura.proto) endif () @@ -200,7 +203,6 @@ find_package(spdlog REQUIRED) find_package(fmt REQUIRED) find_package(range-v3 REQUIRED) find_package(scripta REQUIRED) -find_package(semver REQUIRED) if (ENABLE_SENTRY) find_package(sentry REQUIRED) diff --git a/conandata.yml b/conandata.yml index a0e277c652..14cf72dc44 100644 --- a/conandata.yml +++ b/conandata.yml @@ -1,6 +1,7 @@ version: "5.7.0-alpha.1" requirements: - - "arcus/5.3.1" - "scripta/0.1.0@ultimaker/testing" +requirements_arcus: + - "arcus/5.3.1" requirements_plugins: - "curaengine_grpc_definitions/(latest)@ultimaker/testing" diff --git a/conanfile.py b/conanfile.py index a1795be99f..c811bc6797 100644 --- a/conanfile.py +++ b/conanfile.py @@ -72,7 +72,8 @@ def config_options(self): def configure(self): self.options["boost"].header_only = True self.options["clipper"].shared = True - self.options["protobuf"].shared = False + if self.options.enable_arcus or self.options.enable_plugins: + self.options["protobuf"].shared = False if self.options.enable_arcus: self.options["arcus"].shared = True if self.settings.os == "Linux": @@ -101,20 +102,20 @@ def build_requirements(self): def requirements(self): for req in self.conan_data["requirements"]: - if "arcus" in req and not self.options.enable_arcus: - continue self.requires(req) + if self.options.enable_arcus: + for req in self.conan_data["requirements_arcus"]: + self.requires(req) if self.options.get_safe("enable_sentry", False): self.requires("sentry-native/0.6.5") if self.options.enable_plugins: + self.requires("neargye-semver/0.3.0") self.requires("asio-grpc/2.6.0") self.requires("grpc/1.50.1") for req in self.conan_data["requirements_plugins"]: self.requires(req) if self.options.enable_arcus or self.options.enable_plugins: self.requires("protobuf/3.21.9") - self.requires("asio-grpc/2.6.0") - self.requires("grpc/1.50.1") self.requires("clipper/6.4.2@ultimaker/stable") self.requires("boost/1.82.0") self.requires("rapidjson/1.1.0") @@ -122,7 +123,6 @@ def requirements(self): self.requires("spdlog/1.12.0") self.requires("fmt/10.1.1") self.requires("range-v3/0.12.0") - self.requires("neargye-semver/0.3.0") self.requires("zlib/1.2.12") self.requires("openssl/3.2.0") From 4445fadd79b1b07902c3abd38d001e866b93e02d Mon Sep 17 00:00:00 2001 From: Jelle Spijker Date: Wed, 24 Jan 2024 15:43:14 +0100 Subject: [PATCH 078/201] Only link against semver when building with plugins Contributes to NP-5 --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 908d34746b..113a3af429 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -222,7 +222,7 @@ target_link_libraries(_CuraEngine stb::stb boost::boost scripta::scripta - semver::semver + $<$:semver::semver> $<$:curaengine_grpc_definitions::curaengine_grpc_definitions> $<$:asio-grpc::asio-grpc> $<$:grpc::grpc> From 6c534e4f2a38cd1093c75dee583a4c285e2d789c Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Thu, 25 Jan 2024 08:24:29 +0100 Subject: [PATCH 079/201] Improve code documentation --- include/PrimeTower.h | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/include/PrimeTower.h b/include/PrimeTower.h index a5b0647130..d08292db59 100644 --- a/include/PrimeTower.h +++ b/include/PrimeTower.h @@ -42,8 +42,15 @@ class PrimeTower const unsigned int number_of_prime_tower_start_locations_ = 21; //!< The required size of \ref PrimeTower::wipe_locations MovesByExtruder prime_moves_; //!< For each extruder, the moves to be processed for actual priming. - std::map> - sparse_pattern_per_extruders_; //!< For each extruders combination, and for each actual extruder, the pattern to print on all layers where extruders are actually useless. + + /* + * The first index is a bitmask representing an extruder combination, e.g. 0x05 for extruders 1+3. + * The second one is the used extruder index, e.g. 1 + * The polygons represent the sparse pattern to be printed when all the given extruders are unused for this layer + * and the given extruder is currently in use + */ + std::map> sparse_pattern_per_extruders_; + MovesByLayer base_extra_moves_; //!< For each layer and each extruder, the extra moves to be processed for better adhesion/strength MovesByExtruder inset_extra_moves_; //!< For each extruder, the extra inset moves to be processed for better adhesion on initial layer From 4c4c565a05f8461bde6c24003ccd18876fa3ca85 Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Thu, 25 Jan 2024 12:51:02 +0100 Subject: [PATCH 080/201] Fix Windows build (remove deprecated use of M_PI) --- src/PrimeTower.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PrimeTower.cpp b/src/PrimeTower.cpp index 8987bfb8e1..a6873cf8cc 100644 --- a/src/PrimeTower.cpp +++ b/src/PrimeTower.cpp @@ -296,7 +296,7 @@ Polygons PrimeTower::generatePath_sparseInfill( const coord_t ring_inner_radius = (inner_radius + i * actual_radius_step) + semi_line_width; const coord_t ring_outer_radius = (inner_radius + (i + 1) * actual_radius_step) - semi_line_width; - const size_t semi_nb_spokes = std::ceil((M_PI * ring_outer_radius) / max_bridging_distance); + const size_t semi_nb_spokes = std::ceil((std::numbers::pi * ring_outer_radius) / max_bridging_distance); pattern.add(PolygonUtils::makeWheel(middle_, ring_inner_radius, ring_outer_radius, semi_nb_spokes, ARC_RESOLUTION)); } From ca56dcf0d5269862613c03f0c515620821883ebf Mon Sep 17 00:00:00 2001 From: Jelle Spijker Date: Thu, 25 Jan 2024 19:57:34 +0100 Subject: [PATCH 081/201] Sync Contributes to NP-5 --- CMakeLists.txt | 4 ++-- conanfile.py | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 113a3af429..199627d0c8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -226,7 +226,7 @@ target_link_libraries(_CuraEngine $<$:curaengine_grpc_definitions::curaengine_grpc_definitions> $<$:asio-grpc::asio-grpc> $<$:grpc::grpc> - protobuf::libprotobuf + $<$:protobuf::libprotobuf> $<$:sentry::sentry> $<$:GTest::gtest>) @@ -285,7 +285,7 @@ if (ENABLE_TESTING OR ENABLE_BENCHMARKS) $<$:curaengine_grpc_definitions::curaengine_grpc_definitions> $<$:asio-grpc::asio-grpc> $<$:grpc::grpc> - protobuf::libprotobuf) + $<$:protobuf::libprotobuf>) if (ENABLE_ARCUS) target_link_libraries(test_helpers PUBLIC arcus::arcus) endif () diff --git a/conanfile.py b/conanfile.py index c811bc6797..5bb90c64c8 100644 --- a/conanfile.py +++ b/conanfile.py @@ -93,7 +93,7 @@ def validate(self): def build_requirements(self): self.test_requires("standardprojectsettings/[>=0.1.0]@ultimaker/stable") if self.options.enable_arcus or self.options.enable_plugins: - self.tool_requires("protobuf/3.21.9") + self.tool_requires("protobuf/3.21.12") if not self.conf.get("tools.build:skip_test", False, check_type=bool): self.test_requires("gtest/1.12.1") if self.options.enable_benchmarks: @@ -115,7 +115,7 @@ def requirements(self): for req in self.conan_data["requirements_plugins"]: self.requires(req) if self.options.enable_arcus or self.options.enable_plugins: - self.requires("protobuf/3.21.9") + self.requires("protobuf/3.21.12") self.requires("clipper/6.4.2@ultimaker/stable") self.requires("boost/1.82.0") self.requires("rapidjson/1.1.0") @@ -148,7 +148,7 @@ def generate(self): tc.generate() if self.settings.arch == "wasm" and self.settings.os == "Emscripten": - self.buildenv.define("EMCC_CFLAGS", "-s ALLOW_MEMORY_GROWTH=1 -s EXPORT_ES6=1 -s EXPORT_NAME='CuraEngine' -s EXPORTED_RUNTIME_METHODS='[\"callMain\", \"FS\"]' -s INVOKE_RUN=0 -s MODULARIZE=1 -s SINGLE_FILE=1 -s ENVIRONMENT=worker -s USE_ES6_IMPORT_META=0") + self.buildenv.define("EMCC_CFLAGS", "-s FORCE_FILESYSTEM -s ALLOW_MEMORY_GROWTH=1 -s EXPORT_ES6=1 -s EXPORT_NAME='CuraEngine' -s EXPORTED_RUNTIME_METHODS='[\"callMain\", \"FS\"]' -s INVOKE_RUN=0 -s MODULARIZE=1 -s SINGLE_FILE=1 -s ENVIRONMENT=worker -s USE_ES6_IMPORT_META=0") for dep in self.dependencies.values(): if len(dep.cpp_info.libdirs) > 0: From 20780667717642209663cb2240387f6ba4aacdca Mon Sep 17 00:00:00 2001 From: Jelle Spijker Date: Fri, 26 Jan 2024 14:40:53 +0100 Subject: [PATCH 082/201] Allow for definition search paths as cmd args Contributes to NP-5 --- include/communication/CommandLine.h | 13 +++--- include/utils/views/split_paths.h | 33 ++++++++++++++++ src/communication/CommandLine.cpp | 61 +++++++++++++---------------- 3 files changed, 65 insertions(+), 42 deletions(-) create mode 100644 include/utils/views/split_paths.h diff --git a/include/communication/CommandLine.h b/include/communication/CommandLine.h index d6ded052d4..87b4a88cf5 100644 --- a/include/communication/CommandLine.h +++ b/include/communication/CommandLine.h @@ -4,6 +4,7 @@ #ifndef COMMANDLINE_H #define COMMANDLINE_H +#include #include //Loading JSON documents to get settings from them. #include //To store the command line arguments. #include @@ -155,6 +156,8 @@ class CommandLine : public Communication std::string progressHandler; #endif + std::unordered_set search_directories_; + /* * \brief The command line arguments that the application was called with. */ @@ -165,12 +168,6 @@ class CommandLine : public Communication */ unsigned int last_shown_progress_; - /* - * \brief Get the default search directories to search for definition files. - * \return The default search directories to search for definition files. - */ - std::unordered_set defaultSearchDirectories(); - /* * \brief Load a JSON file and store the settings inside it. * \param json_filename The location of the JSON file to load settings from. @@ -194,7 +191,7 @@ class CommandLine : public Communication */ int loadJSON( const rapidjson::Document& document, - const std::unordered_set& search_directories, + const std::unordered_set& search_directories, Settings& settings, bool force_read_parent = false, bool force_read_nondefault = false); @@ -215,7 +212,7 @@ class CommandLine : public Communication * \param search_directories The directories to search in. * \return The first definition file that matches the definition ID. */ - const std::string findDefinitionFile(const std::string& definition_id, const std::unordered_set& search_directories); + const std::string findDefinitionFile(const std::string& definition_id, const std::unordered_set& search_directories); }; } // namespace cura diff --git a/include/utils/views/split_paths.h b/include/utils/views/split_paths.h new file mode 100644 index 0000000000..31da465939 --- /dev/null +++ b/include/utils/views/split_paths.h @@ -0,0 +1,33 @@ +// Copyright (c) 2024 UltiMaker +// CuraEngine is released under the terms of the AGPLv3 or higher + +#ifndef CURAENGINE_SPLIT_PATHS_H +#define CURAENGINE_SPLIT_PATHS_H + +#include + +#include +#include +#include + +namespace cura::views +{ +namespace details +{ +#ifdef _WIN32 +constexpr auto path_sep = ";"; +#else +constexpr auto path_sep = ':'; +#endif +} // namespace details + +inline static constexpr auto split_paths = ranges::view::split(details::path_sep) + | ranges::views::transform( + [](auto&& rng) + { + return std::string_view(&*rng.begin(), ranges::distance(rng)); + }); + +} // namespace cura::views + +#endif // CURAENGINE_SPLIT_PATHS_H diff --git a/src/communication/CommandLine.cpp b/src/communication/CommandLine.cpp index 1ecf3e7a71..24dcf79a49 100644 --- a/src/communication/CommandLine.cpp +++ b/src/communication/CommandLine.cpp @@ -4,15 +4,18 @@ #include "communication/CommandLine.h" #include //For strtok and strcopy. -#include // error number when trying to read file +#include // error number when trying to read file #include #include //To check if files exist. #include //For std::accumulate. #include //Loading JSON documents to get settings from them. #include #include +#include #include +#include +#include #include #include "Application.h" //To get the extruders for material estimates. @@ -20,6 +23,7 @@ #include "FffProcessor.h" //To start a slice and get time estimates. #include "Slice.h" #include "utils/Matrix4x3D.h" //For the mesh_rotation_matrix setting. +#include "utils/views/split_paths.h" #ifdef __EMSCRIPTEN__ #include @@ -29,9 +33,13 @@ namespace cura { CommandLine::CommandLine(const std::vector& arguments) - : arguments_(arguments) - , last_shown_progress_(0) + : arguments_{ arguments } + , last_shown_progress_{ 0 } { + if (auto search_paths = spdlog::details::os::getenv("CURA_ENGINE_SEARCH_PATH"); ! search_paths.empty()) + { + search_directories_ = search_paths | views::split_paths | ranges::to>(); + }; } // These are not applicable to command line slicing. @@ -223,6 +231,18 @@ void CommandLine::sliceNext() // enableProgressLogging(); FIXME: how to handle progress logging? Is this still relevant? break; } + case 'd': + { + argument_index++; + if (argument_index >= arguments_.size()) + { + spdlog::error("Missing definition search paths"); + exit(1); + } + argument = arguments_[argument_index]; + search_directories_ = argument | views::split_paths | ranges::to>(); + break; + } case 'j': { argument_index++; @@ -399,40 +419,13 @@ int CommandLine::loadJSON(const std::string& json_filename, Settings& settings, return 2; } - std::unordered_set search_directories = defaultSearchDirectories(); // For finding the inheriting JSON files. - std::string directory = std::filesystem::path(json_filename).parent_path().string(); - search_directories.insert(directory); - - return loadJSON(json_document, search_directories, settings, force_read_parent, force_read_nondefault); -} - -std::unordered_set CommandLine::defaultSearchDirectories() -{ - std::unordered_set result; - - char* search_path_env = getenv("CURA_ENGINE_SEARCH_PATH"); - if (search_path_env) - { -#if defined(__linux__) || (defined(__APPLE__) && defined(__MACH__)) - char delims[] = ":"; // Colon for Unix. -#else - char delims[] = ";"; // Semicolon for Windows. -#endif - char paths[128 * 1024]; // Maximum length of environment variable. - strcpy(paths, search_path_env); // Necessary because strtok actually modifies the original string, and we don't want to modify the environment variable itself. - char* path = strtok(paths, delims); - while (path != nullptr) - { - result.insert(path); - path = strtok(nullptr, delims); // Continue searching in last call to strtok. - } - } - return result; + search_directories_.insert(std::filesystem::path(json_filename).parent_path()); + return loadJSON(json_document, search_directories_, settings, force_read_parent, force_read_nondefault); } int CommandLine::loadJSON( const rapidjson::Document& document, - const std::unordered_set& search_directories, + const std::unordered_set& search_directories, Settings& settings, bool force_read_parent, bool force_read_nondefault) @@ -588,7 +581,7 @@ void CommandLine::loadJSONSettings(const rapidjson::Value& element, Settings& se } } -const std::string CommandLine::findDefinitionFile(const std::string& definition_id, const std::unordered_set& search_directories) +const std::string CommandLine::findDefinitionFile(const std::string& definition_id, const std::unordered_set& search_directories) { for (const std::string& search_directory : search_directories) { From 62490df519312f79e5942c790afb376cdf886945 Mon Sep 17 00:00:00 2001 From: Jelle Spijker Date: Fri, 26 Jan 2024 14:45:43 +0100 Subject: [PATCH 083/201] Modernize json file rading Contributes to NP-5 --- src/communication/CommandLine.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/communication/CommandLine.cpp b/src/communication/CommandLine.cpp index 24dcf79a49..e58709bbd5 100644 --- a/src/communication/CommandLine.cpp +++ b/src/communication/CommandLine.cpp @@ -3,8 +3,8 @@ #include "communication/CommandLine.h" -#include //For strtok and strcopy. #include // error number when trying to read file +#include //For strtok and strcopy. #include #include //To check if files exist. #include //For std::accumulate. @@ -401,18 +401,18 @@ void CommandLine::sliceNext() int CommandLine::loadJSON(const std::string& json_filename, Settings& settings, bool force_read_parent, bool force_read_nondefault) { - FILE* file = fopen(json_filename.c_str(), "rb"); + std::ifstream file(json_filename, std::ios::binary); if (! file) { spdlog::error("Couldn't open JSON file: {}", json_filename); return 1; } + std::vector read_buffer(std::istreambuf_iterator(file), {}); + rapidjson::MemoryStream ms(read_buffer.data(), read_buffer.size()); + rapidjson::Document json_document; - char read_buffer[4096]; - rapidjson::FileReadStream reader_stream(file, read_buffer, sizeof(read_buffer)); - json_document.ParseStream(reader_stream); - fclose(file); + json_document.ParseStream(ms); if (json_document.HasParseError()) { spdlog::error("Error parsing JSON (offset {}): {}", json_document.GetErrorOffset(), GetParseError_En(json_document.GetParseError())); From d790f0648bce8cc10917e33bd946d18c275c1cb8 Mon Sep 17 00:00:00 2001 From: Jelle Spijker Date: Fri, 26 Jan 2024 15:17:58 +0100 Subject: [PATCH 084/201] boy scouting Contributes to NP-5 --- include/communication/CommandLine.h | 2 +- src/communication/CommandLine.cpp | 54 +++++++++++++++-------------- 2 files changed, 29 insertions(+), 27 deletions(-) diff --git a/include/communication/CommandLine.h b/include/communication/CommandLine.h index 87b4a88cf5..9846217ab7 100644 --- a/include/communication/CommandLine.h +++ b/include/communication/CommandLine.h @@ -212,7 +212,7 @@ class CommandLine : public Communication * \param search_directories The directories to search in. * \return The first definition file that matches the definition ID. */ - const std::string findDefinitionFile(const std::string& definition_id, const std::unordered_set& search_directories); + static std::string findDefinitionFile(const std::string& definition_id, const std::unordered_set& search_directories); }; } // namespace cura diff --git a/src/communication/CommandLine.cpp b/src/communication/CommandLine.cpp index e58709bbd5..c017e5514f 100644 --- a/src/communication/CommandLine.cpp +++ b/src/communication/CommandLine.cpp @@ -9,8 +9,9 @@ #include //To check if files exist. #include //For std::accumulate. #include //Loading JSON documents to get settings from them. -#include #include +#include +#include #include #include @@ -106,7 +107,7 @@ void CommandLine::sendPrintTimeMaterialEstimates() const sum = 0.0; for (size_t extruder_nr = 0; extruder_nr < Application::getInstance().current_slice_->scene.extruders.size(); extruder_nr++) { - sum += FffProcessor::getInstance()->getTotalFilamentUsed(extruder_nr); + sum += FffProcessor::getInstance()->getTotalFilamentUsed(static_cast(extruder_nr)); } } @@ -134,7 +135,7 @@ void CommandLine::sliceNext() size_t num_mesh_groups = 1; for (size_t argument_index = 2; argument_index < arguments_.size(); argument_index++) { - if (arguments_[argument_index].find("--next") == 0) // Starts with "--next". + if (arguments_[argument_index].starts_with("--next")) // Starts with "--next". { num_mesh_groups++; } @@ -148,7 +149,7 @@ void CommandLine::sliceNext() slice.scene.extruders.reserve(arguments_.size() >> 1); // Allocate enough memory to prevent moves. slice.scene.extruders.emplace_back(0, &slice.scene.settings); // Always have one extruder. - ExtruderTrain* last_extruder = &slice.scene.extruders[0]; + ExtruderTrain* last_extruder = slice.scene.extruders.data(); bool force_read_parent = false; bool force_read_nondefault = false; @@ -160,7 +161,7 @@ void CommandLine::sliceNext() { if (argument[1] == '-') // Starts with "--". { - if (argument.find("--next") == 0) // Starts with "--next". + if (argument.starts_with("--next")) // Starts with "--next". { try { @@ -179,18 +180,18 @@ void CommandLine::sliceNext() exit(1); } } - else if (argument.find("--force-read-parent") == 0 || argument.find("--force_read_parent") == 0) + else if (argument.starts_with("--force-read-parent") || argument.starts_with("--force_read_parent")) { spdlog::info("From this point on, force the parser to read values of non-leaf settings, instead of skipping over them as is proper."); force_read_parent = true; } - else if (argument.find("--force-read-nondefault") == 0 || argument.find("--force_read_nondefault") == 0) + else if (argument.starts_with("--force-read-nondefault") || argument.starts_with("--force_read_nondefault")) { spdlog::info( "From this point on, if 'default_value' is not available, force the parser to read 'value' (instead of dropping it) to fill the used setting-values."); force_read_nondefault = true; } - else if (argument.find("--end-force-read") == 0 || argument.find("--end_force_read") == 0) + else if (argument.starts_with("--end-force-read") || argument.starts_with("--end_force_read")) { spdlog::info("From this point on, reset all force-XXX values to false (don't 'force read ___' anymore)."); force_read_parent = false; @@ -252,7 +253,7 @@ void CommandLine::sliceNext() exit(1); } argument = arguments_[argument_index]; - if (loadJSON(argument, *last_settings, force_read_parent, force_read_nondefault)) + if (loadJSON(argument, *last_settings, force_read_parent, force_read_nondefault) != 0) { spdlog::error("Failed to load JSON file: {}", argument); exit(1); @@ -261,7 +262,7 @@ void CommandLine::sliceNext() // If this was the global stack, create extruders for the machine_extruder_count setting. if (last_settings == &slice.scene.settings) { - const size_t extruder_count = slice.scene.settings.get("machine_extruder_count"); + const auto extruder_count = slice.scene.settings.get("machine_extruder_count"); while (slice.scene.extruders.size() < extruder_count) { slice.scene.extruders.emplace_back(slice.scene.extruders.size(), &slice.scene.settings); @@ -296,7 +297,7 @@ void CommandLine::sliceNext() } argument = arguments_[argument_index]; - const Matrix4x3D transformation = last_settings->get("mesh_rotation_matrix"); // The transformation applied to the model when loaded. + const auto transformation = last_settings->get("mesh_rotation_matrix"); // The transformation applied to the model when loaded. if (! loadMeshIntoMeshGroup(&slice.scene.mesh_groups[mesh_group_index], argument.c_str(), transformation, last_extruder->settings_)) { @@ -341,7 +342,7 @@ void CommandLine::sliceNext() exit(1); } argument = arguments_[argument_index]; - const size_t value_position = argument.find("="); + const size_t value_position = argument.find('='); std::string key = argument.substr(0, value_position); if (value_position == std::string::npos) { @@ -358,7 +359,6 @@ void CommandLine::sliceNext() Application::getInstance().printCall(); Application::getInstance().printHelp(); exit(1); - break; } } } @@ -409,10 +409,10 @@ int CommandLine::loadJSON(const std::string& json_filename, Settings& settings, } std::vector read_buffer(std::istreambuf_iterator(file), {}); - rapidjson::MemoryStream ms(read_buffer.data(), read_buffer.size()); + rapidjson::MemoryStream memory_stream(read_buffer.data(), read_buffer.size()); rapidjson::Document json_document; - json_document.ParseStream(ms); + json_document.ParseStream(memory_stream); if (json_document.HasParseError()) { spdlog::error("Error parsing JSON (offset {}): {}", json_document.GetErrorOffset(), GetParseError_En(json_document.GetParseError())); @@ -434,13 +434,13 @@ int CommandLine::loadJSON( if (document.HasMember("inherits") && document["inherits"].IsString()) { std::string parent_file = findDefinitionFile(document["inherits"].GetString(), search_directories); - if (parent_file == "") + if (parent_file.empty()) { spdlog::error("Inherited JSON file: {} not found.", document["inherits"].GetString()); return 1; } - int error_code = loadJSON(parent_file, settings, force_read_parent, force_read_nondefault); // Head-recursively load the settings file that we inherit from. - if (error_code) + // Head-recursively load the settings file that we inherit from. + if (const auto error_code = loadJSON(parent_file, settings, force_read_parent, force_read_nondefault); error_code != 0) { return error_code; } @@ -558,12 +558,16 @@ void CommandLine::loadJSONSettings(const rapidjson::Value& element, Settings& se } } - if (! (setting_object.HasMember("default_value") || (force_read_nondefault && setting_object.HasMember("value") && ! settings.has(name)))) + if (! setting_object.HasMember("default_value") && (! force_read_nondefault || ! setting_object.HasMember("value") || settings.has(name))) { if (! setting_object.HasMember("children")) { // Setting has no child-settings, so must be leaf, but also holds no (default) value?! - spdlog::warn("JSON setting {} has no [default_]value!", name); + spdlog::warn("JSON setting '{}' has no [default_]value!", name); + rapidjson::StringBuffer buffer; + rapidjson::Writer writer(buffer); + setting_object.Accept(writer); + spdlog::debug("JSON setting '{}': '{}'", name, buffer.GetString()); } continue; } @@ -581,19 +585,17 @@ void CommandLine::loadJSONSettings(const rapidjson::Value& element, Settings& se } } -const std::string CommandLine::findDefinitionFile(const std::string& definition_id, const std::unordered_set& search_directories) +std::string CommandLine::findDefinitionFile(const std::string& definition_id, const std::unordered_set& search_directories) { - for (const std::string& search_directory : search_directories) + for (const auto& search_directory : search_directories) { - const std::string candidate = search_directory + std::string("/") + definition_id + std::string(".def.json"); - const std::ifstream ifile(candidate.c_str()); // Check whether the file exists and is readable by opening it. - if (ifile) + if (auto candidate = search_directory / (definition_id + ".def.json"); std::filesystem::exists(candidate)) { return candidate; } } spdlog::error("Couldn't find definition file with ID: {}", definition_id); - return std::string(""); + return {}; } } // namespace cura From d6e3b1f63a7fd9410c7aeb8628129d49c9e4d877 Mon Sep 17 00:00:00 2001 From: Jelle Spijker Date: Mon, 29 Jan 2024 14:06:40 +0100 Subject: [PATCH 085/201] Make filesystem path explicit Contributes to NP-5 --- include/communication/CommandLine.h | 2 +- include/utils/views/split_paths.h | 2 +- src/communication/CommandLine.cpp | 5 +++-- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/include/communication/CommandLine.h b/include/communication/CommandLine.h index 9846217ab7..11b86e8e65 100644 --- a/include/communication/CommandLine.h +++ b/include/communication/CommandLine.h @@ -178,7 +178,7 @@ class CommandLine : public Communication * 1, the file could not be opened. If it's 2, there was a syntax error in * the file. */ - int loadJSON(const std::string& json_filename, Settings& settings, bool force_read_parent = false, bool force_read_nondefault = false); + int loadJSON(const std::filesystem::path& json_filename, Settings& settings, bool force_read_parent = false, bool force_read_nondefault = false); /* * \brief Load a JSON document and store the settings inside it. diff --git a/include/utils/views/split_paths.h b/include/utils/views/split_paths.h index 31da465939..926150555a 100644 --- a/include/utils/views/split_paths.h +++ b/include/utils/views/split_paths.h @@ -21,7 +21,7 @@ constexpr auto path_sep = ':'; #endif } // namespace details -inline static constexpr auto split_paths = ranges::view::split(details::path_sep) +inline static constexpr auto split_paths = ranges::views::split(details::path_sep) | ranges::views::transform( [](auto&& rng) { diff --git a/src/communication/CommandLine.cpp b/src/communication/CommandLine.cpp index c017e5514f..17f899670d 100644 --- a/src/communication/CommandLine.cpp +++ b/src/communication/CommandLine.cpp @@ -25,6 +25,7 @@ #include "Slice.h" #include "utils/Matrix4x3D.h" //For the mesh_rotation_matrix setting. #include "utils/views/split_paths.h" +#include "utils/format/filesystem_path.h" #ifdef __EMSCRIPTEN__ #include @@ -253,7 +254,7 @@ void CommandLine::sliceNext() exit(1); } argument = arguments_[argument_index]; - if (loadJSON(argument, *last_settings, force_read_parent, force_read_nondefault) != 0) + if (loadJSON(std::filesystem::path { argument }, *last_settings, force_read_parent, force_read_nondefault) != 0) { spdlog::error("Failed to load JSON file: {}", argument); exit(1); @@ -399,7 +400,7 @@ void CommandLine::sliceNext() FffProcessor::getInstance()->finalize(); } -int CommandLine::loadJSON(const std::string& json_filename, Settings& settings, bool force_read_parent, bool force_read_nondefault) +int CommandLine::loadJSON(const std::filesystem::path& json_filename, Settings& settings, bool force_read_parent, bool force_read_nondefault) { std::ifstream file(json_filename, std::ios::binary); if (! file) From 38ca8791c9759e02cbcf390c2efc01f83f76f4c1 Mon Sep 17 00:00:00 2001 From: jellespijker Date: Mon, 29 Jan 2024 13:06:47 +0000 Subject: [PATCH 086/201] Applied clang-format. --- src/communication/CommandLine.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/communication/CommandLine.cpp b/src/communication/CommandLine.cpp index 17f899670d..f6cd567431 100644 --- a/src/communication/CommandLine.cpp +++ b/src/communication/CommandLine.cpp @@ -24,8 +24,8 @@ #include "FffProcessor.h" //To start a slice and get time estimates. #include "Slice.h" #include "utils/Matrix4x3D.h" //For the mesh_rotation_matrix setting. -#include "utils/views/split_paths.h" #include "utils/format/filesystem_path.h" +#include "utils/views/split_paths.h" #ifdef __EMSCRIPTEN__ #include @@ -254,7 +254,7 @@ void CommandLine::sliceNext() exit(1); } argument = arguments_[argument_index]; - if (loadJSON(std::filesystem::path { argument }, *last_settings, force_read_parent, force_read_nondefault) != 0) + if (loadJSON(std::filesystem::path{ argument }, *last_settings, force_read_parent, force_read_nondefault) != 0) { spdlog::error("Failed to load JSON file: {}", argument); exit(1); From 6ffa5dc82b4d0e81bfce4823ff61db1d490175a0 Mon Sep 17 00:00:00 2001 From: Jelle Spijker Date: Tue, 30 Jan 2024 15:07:28 +0100 Subject: [PATCH 087/201] use cmake targets for compilation options Contributes to NP-5 --- CMakeLists.txt | 17 +++++++++++++---- conanfile.py | 4 +--- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 199627d0c8..11a84d2934 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -17,8 +17,7 @@ option(ENABLE_SENTRY "Send crash data via Sentry" OFF) option(ENABLE_MORE_COMPILER_OPTIMIZATION_FLAGS "Enable more optimization flags" ON) option(USE_SYSTEM_LIBS "Use the system libraries if available" OFF) option(OLDER_APPLE_CLANG "Apple Clang <= 13 used" OFF) - -option(OLDER_APPLE_CLANG "Apple Clang <= 13 used" OFF) +option(ENABLE_THREADING "Enable threading support" ON) if (${ENABLE_ARCUS} OR ${ENABLE_PLUGINS}) find_package(protobuf REQUIRED) @@ -157,7 +156,9 @@ set(engine_SRCS # Except main.cpp. ) add_library(_CuraEngine STATIC ${engine_SRCS} ${engine_PB_SRCS}) -#use_threads(_CuraEngine) +if (ENABLE_THREADING) + use_threads(_CuraEngine) +endif () target_include_directories(_CuraEngine PUBLIC @@ -252,7 +253,15 @@ else () endif () endif (NOT WIN32) -#use_threads(CuraEngine) +if (ENABLE_THREADING) + use_threads(CuraEngine) +endif () + +if (CMAKE_CXX_PLATFORM_ID STREQUAL "emscripten") + message(STATUS "Building for Emscripten") + target_link_options(_CuraEngine PUBLIC -Wno-unused-command-line-argument -sINVOKE_RUN=0 -sEXPORT_NAME=CuraEngine -sEXPORTED_RUNTIME_METHODS=[callMain,FS] -sFORCE_FILESYSTEM=1 -sALLOW_MEMORY_GROWTH=1 -sEXPORT_ES6=1 -sMODULARIZE=1 -sSINGLE_FILE=1 -sENVIRONMENT=worker) +endif () + target_link_libraries(CuraEngine PRIVATE _CuraEngine $<$:sentry::sentry> diff --git a/conanfile.py b/conanfile.py index 5bb90c64c8..1f1735fa91 100644 --- a/conanfile.py +++ b/conanfile.py @@ -137,6 +137,7 @@ def generate(self): tc.variables["ENABLE_BENCHMARKS"] = self.options.enable_benchmarks tc.variables["EXTENSIVE_WARNINGS"] = self.options.enable_extensive_warnings tc.variables["OLDER_APPLE_CLANG"] = self.settings.compiler == "apple-clang" and Version(self.settings.compiler.version) < "14" + tc.variables["ENABLE_THREADING"] = not (self.settings.arch == "wasm" and self.settings.os == "Emscripten") if self.options.get_safe("enable_sentry", False): tc.variables["ENABLE_SENTRY"] = True tc.variables["SENTRY_URL"] = self.conf.get("user.curaengine:sentry_url", "", check_type=str) @@ -147,9 +148,6 @@ def generate(self): tc.variables["ENABLE_PLUGINS"] = self.options.enable_plugins tc.generate() - if self.settings.arch == "wasm" and self.settings.os == "Emscripten": - self.buildenv.define("EMCC_CFLAGS", "-s FORCE_FILESYSTEM -s ALLOW_MEMORY_GROWTH=1 -s EXPORT_ES6=1 -s EXPORT_NAME='CuraEngine' -s EXPORTED_RUNTIME_METHODS='[\"callMain\", \"FS\"]' -s INVOKE_RUN=0 -s MODULARIZE=1 -s SINGLE_FILE=1 -s ENVIRONMENT=worker -s USE_ES6_IMPORT_META=0") - for dep in self.dependencies.values(): if len(dep.cpp_info.libdirs) > 0: copy(self, "*.dylib", dep.cpp_info.libdirs[0], self.build_folder) From 4f1e9fcaed79d67451475a84da7f1da2c9bfa13b Mon Sep 17 00:00:00 2001 From: Jelle Spijker Date: Tue, 30 Jan 2024 15:08:06 +0100 Subject: [PATCH 088/201] Only link to existing targets Contributes to NP-5 --- CMakeLists.txt | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 11a84d2934..5ba77db4d0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -223,13 +223,13 @@ target_link_libraries(_CuraEngine stb::stb boost::boost scripta::scripta - $<$:semver::semver> - $<$:curaengine_grpc_definitions::curaengine_grpc_definitions> - $<$:asio-grpc::asio-grpc> - $<$:grpc::grpc> + $<$:semver::semver> + $<$:curaengine_grpc_definitions::curaengine_grpc_definitions> + $<$:asio-grpc::asio-grpc> + $<$:grpc::grpc> $<$:protobuf::libprotobuf> - $<$:sentry::sentry> - $<$:GTest::gtest>) + $<$:sentry::sentry> + $<$:GTest::gtest>) target_compile_definitions(_CuraEngine PRIVATE $<$:SENTRY_URL=\"${SENTRY_URL}\"> @@ -264,7 +264,7 @@ endif () target_link_libraries(CuraEngine PRIVATE _CuraEngine - $<$:sentry::sentry> + $<$:sentry::sentry> ) target_compile_definitions(CuraEngine PRIVATE $<$:SENTRY_URL=\"${SENTRY_URL}\"> @@ -291,9 +291,9 @@ if (ENABLE_TESTING OR ENABLE_BENCHMARKS) GTest::gtest GTest::gmock clipper::clipper - $<$:curaengine_grpc_definitions::curaengine_grpc_definitions> - $<$:asio-grpc::asio-grpc> - $<$:grpc::grpc> + $<$:curaengine_grpc_definitions::curaengine_grpc_definitions> + $<$:asio-grpc::asio-grpc> + $<$:grpc::grpc> $<$:protobuf::libprotobuf>) if (ENABLE_ARCUS) target_link_libraries(test_helpers PUBLIC arcus::arcus) From aab1f0936045d419738e827c539703d3bb88701a Mon Sep 17 00:00:00 2001 From: Jelle Spijker Date: Tue, 30 Jan 2024 15:29:54 +0100 Subject: [PATCH 089/201] don't bump Protobuf Contributes to NP-5 --- conanfile.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conanfile.py b/conanfile.py index 1f1735fa91..4adb334574 100644 --- a/conanfile.py +++ b/conanfile.py @@ -93,7 +93,7 @@ def validate(self): def build_requirements(self): self.test_requires("standardprojectsettings/[>=0.1.0]@ultimaker/stable") if self.options.enable_arcus or self.options.enable_plugins: - self.tool_requires("protobuf/3.21.12") + self.tool_requires("protobuf/3.21.9") if not self.conf.get("tools.build:skip_test", False, check_type=bool): self.test_requires("gtest/1.12.1") if self.options.enable_benchmarks: From 248403d9d16884328854fee96866ef419e971bd8 Mon Sep 17 00:00:00 2001 From: Jelle Spijker Date: Tue, 30 Jan 2024 15:33:26 +0100 Subject: [PATCH 090/201] add `-d` cmdline option to help Contributes to NP-5 --- src/Application.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Application.cpp b/src/Application.cpp index db6d7b4c2c..897b4c89eb 100644 --- a/src/Application.cpp +++ b/src/Application.cpp @@ -131,6 +131,7 @@ void Application::printHelp() const fmt::print(" -v\n\tIncrease the verbose level (show log messages).\n"); fmt::print(" -m\n\tSet the desired number of threads.\n"); fmt::print(" -p\n\tLog progress information.\n"); + fmt::print(" -d Add definition search paths seperated by a `:` (Unix) or `;` (Windows)\n"); fmt::print(" -j\n\tLoad settings.def.json file to register all settings and their defaults.\n"); fmt::print(" -s =\n\tSet a setting to a value for the last supplied object, \n\textruder train, or general settings.\n"); fmt::print(" -l \n\tLoad an STL model. \n"); @@ -152,7 +153,7 @@ void Application::printLicense() const { fmt::print("\n"); fmt::print("Cura_SteamEngine version {}\n", CURA_ENGINE_VERSION); - fmt::print("Copyright (C) 2023 Ultimaker\n"); + fmt::print("Copyright (C) 2024 Ultimaker\n"); fmt::print("\n"); fmt::print("This program is free software: you can redistribute it and/or modify\n"); fmt::print("it under the terms of the GNU Affero General Public License as published by\n"); From c4f638fa302f36e713383b77b7cb01c392a7626a Mon Sep 17 00:00:00 2001 From: Jelle Spijker Date: Tue, 30 Jan 2024 15:39:56 +0100 Subject: [PATCH 091/201] Add reminder for SlotID shadow facade Contributes to NP-5 --- Cura.proto | 1 + include/plugins/slots.h | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/Cura.proto b/Cura.proto index f1e261bece..e9346a9e05 100644 --- a/Cura.proto +++ b/Cura.proto @@ -12,6 +12,7 @@ message ObjectList // 0 ... 99: Broadcasts // 100 ... 199: Modify // 200 ... 299: Generate +// IMPORTANT: If you add a slot idea also update the SlotID enum in include/plugins/slots.h enum SlotID { SETTINGS_BROADCAST = 0; SIMPLIFY_MODIFY = 100; diff --git a/include/plugins/slots.h b/include/plugins/slots.h index b5fe0d2869..d313b266cf 100644 --- a/include/plugins/slots.h +++ b/include/plugins/slots.h @@ -244,7 +244,7 @@ namespace cura namespace plugins::v0 { -// FIXME: use same SlotID as defined in Cura.proto +// FIXME: use same SlotID as defined in Cura.proto, Maybe revert back to char_range_literal, but that is a lot of work enum SlotID : int { SETTINGS_BROADCAST = 0, From 0fa80186a3d7fc6737931b53f2f6a20ad022f867 Mon Sep 17 00:00:00 2001 From: Jelle Spijker Date: Tue, 30 Jan 2024 15:43:19 +0100 Subject: [PATCH 092/201] Package JS file Contributes to NP-5 --- conanfile.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/conanfile.py b/conanfile.py index 4adb334574..3e56eace49 100644 --- a/conanfile.py +++ b/conanfile.py @@ -210,7 +210,12 @@ def build(self): self.run(f"sentry-cli --auth-token {os.environ['SENTRY_TOKEN']} releases finalize -o {sentry_org} -p {sentry_project} {self.version}") def package(self): - ext = ".exe" if self.settings.os == "Windows" else "" + if self.settings.os == "Windows": + ext = ".exe" + elif self.settings.os == "Emscripten": + ext = ".js" + else: + ext = "" copy(self, f"CuraEngine{ext}", src=self.build_folder, dst=path.join(self.package_folder, "bin")) copy(self, f"_CuraEngine.*", src=self.build_folder, dst=path.join(self.package_folder, "lib")) copy(self, "LICENSE*", src=self.source_folder, dst=path.join(self.package_folder, "license")) From 8907c381a115463379903893fd338be05b39ba03 Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Fri, 9 Feb 2024 09:22:21 +0100 Subject: [PATCH 093/201] Rename prime tower mode --- include/settings/EnumSettings.h | 4 ++-- src/FffGcodeWriter.cpp | 6 +++--- src/PrimeTower.cpp | 18 +++++++++--------- src/settings/Settings.cpp | 8 ++++---- 4 files changed, 18 insertions(+), 18 deletions(-) diff --git a/include/settings/EnumSettings.h b/include/settings/EnumSettings.h index 054fb3089a..7b8c970db4 100644 --- a/include/settings/EnumSettings.h +++ b/include/settings/EnumSettings.h @@ -258,13 +258,13 @@ enum class PrimeTowerMethod /*! * Prime tower that minimizes time and used filament as much as possible. */ - SPARSE, + INTERLEAVED, /*! * Prime tower that minimizes time and used filament, but doesn't allow * for printing two different filaments over each other. */ - BUCKET, + NORMAL, }; } // namespace cura diff --git a/src/FffGcodeWriter.cpp b/src/FffGcodeWriter.cpp index abc2e0c25c..58c1a4f760 100644 --- a/src/FffGcodeWriter.cpp +++ b/src/FffGcodeWriter.cpp @@ -1579,7 +1579,7 @@ std::vector case PrimeTowerMethod::NONE: break; - case PrimeTowerMethod::BUCKET: + case PrimeTowerMethod::NORMAL: if (extruder_is_used_on_this_layer[extruder_nr] && extruder_nr != last_extruder) { prime = ExtruderPrime::Prime; @@ -1590,7 +1590,7 @@ std::vector } break; - case PrimeTowerMethod::SPARSE: + case PrimeTowerMethod::INTERLEAVED: if (extruder_is_used_on_this_layer[extruder_nr] && extruder_nr != last_extruder) { prime = ExtruderPrime::Prime; @@ -1605,7 +1605,7 @@ std::vector } } - if (method == PrimeTowerMethod::SPARSE && ret.size() == 1 && ret.front().prime == ExtruderPrime::None && layer_nr <= storage.max_print_height_second_to_last_extruder) + if (method == PrimeTowerMethod::INTERLEAVED && ret.size() == 1 && ret.front().prime == ExtruderPrime::None && layer_nr <= storage.max_print_height_second_to_last_extruder) { ret.front().prime = ExtruderPrime::Sparse; } diff --git a/src/PrimeTower.cpp b/src/PrimeTower.cpp index a6873cf8cc..5264ecb346 100644 --- a/src/PrimeTower.cpp +++ b/src/PrimeTower.cpp @@ -43,7 +43,7 @@ PrimeTower::PrimeTower() // used (sacrifying for this purpose the usual single-extruder first layer, that would be better for prime-tower // adhesion). - multiple_extruders_on_first_layer_ = (method == PrimeTowerMethod::SPARSE) || (method == PrimeTowerMethod::BUCKET) + multiple_extruders_on_first_layer_ = (method == PrimeTowerMethod::INTERLEAVED) || (method == PrimeTowerMethod::NORMAL) || (scene.current_mesh_group->settings.get("machine_extruders_share_nozzle") && ((adhesion_type != EPlatformAdhesion::SKIRT) && (adhesion_type != EPlatformAdhesion::BRIM))); } @@ -164,7 +164,7 @@ void PrimeTower::generatePaths_denseInfill(std::vector& cumulative_inse } // Generate the base outside extra rings - if ((method == PrimeTowerMethod::SPARSE || (extruder_nr == extruder_order_.front() && method == PrimeTowerMethod::BUCKET)) && (base_enabled || has_raft) + if ((method == PrimeTowerMethod::INTERLEAVED || (extruder_nr == extruder_order_.front() && method == PrimeTowerMethod::NORMAL)) && (base_enabled || has_raft) && base_extra_radius > 0 && base_height > 0) { for (coord_t z = 0; z < base_height; z += layer_height) @@ -190,7 +190,7 @@ void PrimeTower::generatePaths_denseInfill(std::vector& cumulative_inse // Now we have the total cumulative inset, generate the base inside extra rings for (size_t extruder_nr : extruder_order_) { - if (extruder_nr == extruder_order_.back() || method == PrimeTowerMethod::SPARSE) + if (extruder_nr == extruder_order_.back() || method == PrimeTowerMethod::INTERLEAVED) { const coord_t line_width = scene.extruders[extruder_nr].settings_.get("prime_tower_line_width"); Polygons pattern = PolygonUtils::generateInset(outer_poly_, line_width, cumulative_inset); @@ -222,7 +222,7 @@ void PrimeTower::generatePaths_sparseInfill(const std::vector& cumulati actual_extruders.push_back({ extruder_nr, line_width }); } - if (method == PrimeTowerMethod::SPARSE || method == PrimeTowerMethod::BUCKET) + if (method == PrimeTowerMethod::INTERLEAVED || method == PrimeTowerMethod::NORMAL) { const size_t nb_extruders = scene.extruders.size(); @@ -242,7 +242,7 @@ void PrimeTower::generatePaths_sparseInfill(const std::vector& cumulati // A combination is represented by a bitmask for (size_t first_extruder_idx = 0; first_extruder_idx < nb_extruders; ++first_extruder_idx) { - size_t nb_extruders_sparse = method == PrimeTowerMethod::BUCKET ? first_extruder_idx + 1 : nb_extruders; + size_t nb_extruders_sparse = method == PrimeTowerMethod::NORMAL ? first_extruder_idx + 1 : nb_extruders; for (size_t last_extruder_idx = first_extruder_idx; last_extruder_idx < nb_extruders_sparse; ++last_extruder_idx) { @@ -256,7 +256,7 @@ void PrimeTower::generatePaths_sparseInfill(const std::vector& cumulati std::map infills_for_combination; for (const ActualExtruder& actual_extruder : actual_extruders) { - if (method == PrimeTowerMethod::SPARSE || actual_extruder.number == extruder_order_.at(first_extruder_idx)) + if (method == PrimeTowerMethod::INTERLEAVED || actual_extruder.number == extruder_order_.at(first_extruder_idx)) { Polygons infill = generatePath_sparseInfill(first_extruder_idx, last_extruder_idx, rings_radii, actual_extruder.line_width, actual_extruder.number); infills_for_combination[actual_extruder.number] = infill; @@ -384,7 +384,7 @@ void PrimeTower::addToGcode( switch (extruder_iterator->prime) { case ExtruderPrime::None: - if (method != PrimeTowerMethod::SPARSE) + if (method != PrimeTowerMethod::INTERLEAVED) { gcode_layer.setPrimeTowerIsPlanned(new_extruder_nr); } @@ -399,7 +399,7 @@ void PrimeTower::addToGcode( addToGcode_denseInfill(gcode_layer, new_extruder_nr); gcode_layer.setPrimeTowerIsPlanned(new_extruder_nr); - if (method == PrimeTowerMethod::SPARSE && gcode_layer.getLayerNr() <= storage.max_print_height_second_to_last_extruder) + if (method == PrimeTowerMethod::INTERLEAVED && gcode_layer.getLayerNr() <= storage.max_print_height_second_to_last_extruder) { // Whatever happens before and after, use the current extruder to prime all the non-required extruders now extra_primed_extruders_idx = findExtrudersSparseInfill(gcode_layer, required_extruder_prime, method); @@ -571,7 +571,7 @@ std::vector PrimeTower::findExtrudersSparseInfill( else { size_t extruder_nr = extruder_order_.at(extruder_idx); - if (method == PrimeTowerMethod::SPARSE && ! gcode_layer.getPrimeTowerIsPlanned(extruder_nr)) + if (method == PrimeTowerMethod::INTERLEAVED && ! gcode_layer.getPrimeTowerIsPlanned(extruder_nr)) { auto iterator_required_list = std::find_if( required_extruder_prime.begin(), diff --git a/src/settings/Settings.cpp b/src/settings/Settings.cpp index f4f212b407..b94364d9e5 100644 --- a/src/settings/Settings.cpp +++ b/src/settings/Settings.cpp @@ -682,13 +682,13 @@ template<> PrimeTowerMethod Settings::get(const std::string& key) const { const std::string& value = get(key); - if (value == "sparse") + if (value == "interleaved") { - return PrimeTowerMethod::SPARSE; + return PrimeTowerMethod::INTERLEAVED; } - else if (value == "bucket") + else if (value == "normal") { - return PrimeTowerMethod::BUCKET; + return PrimeTowerMethod::NORMAL; } else // Default. { From 05a20cda5609e52cb087920e3362f1ae62da0046 Mon Sep 17 00:00:00 2001 From: Jelle Spijker Date: Wed, 14 Feb 2024 10:40:48 +0100 Subject: [PATCH 094/201] Remove usage of simplify slot This slot wasn't intended to be used and served more as test slot during development Contribute to NP-5 --- src/slicer.cpp | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/slicer.cpp b/src/slicer.cpp index d13908458f..5c7dcfe11e 100644 --- a/src/slicer.cpp +++ b/src/slicer.cpp @@ -784,12 +784,7 @@ void SlicerLayer::makePolygons(const Mesh* mesh) polygons.erase(it, polygons.end()); // Finally optimize all the polygons. Every point removed saves time in the long run. - // polygons = Simplify(mesh->settings).polygon(polygons); - polygons = slots::instance().modify( - polygons, - mesh->settings_.get("meshfix_maximum_resolution"), - mesh->settings_.get("meshfix_maximum_deviation"), - static_cast(mesh->settings_.get("meshfix_maximum_extrusion_area_deviation"))); + polygons = Simplify(mesh->settings_).polygon(polygons); polygons.removeDegenerateVerts(); // remove verts connected to overlapping line segments // Clean up polylines for Surface Mode printing From 1348030c164da0ce534d8cf39eb4a5134182827e Mon Sep 17 00:00:00 2001 From: Jelle Spijker Date: Wed, 14 Feb 2024 10:42:50 +0100 Subject: [PATCH 095/201] Fix typo in comment Contribute to NP-5 --- Cura.proto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cura.proto b/Cura.proto index e9346a9e05..3fc57b7385 100644 --- a/Cura.proto +++ b/Cura.proto @@ -12,7 +12,7 @@ message ObjectList // 0 ... 99: Broadcasts // 100 ... 199: Modify // 200 ... 299: Generate -// IMPORTANT: If you add a slot idea also update the SlotID enum in include/plugins/slots.h +// IMPORTANT: If you add a slot ID also update the SlotID enum in include/plugins/slots.h enum SlotID { SETTINGS_BROADCAST = 0; SIMPLIFY_MODIFY = 100; From aac2a8ae031bd103da34c1540075dec126e25daf Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Fri, 16 Feb 2024 10:56:32 +0100 Subject: [PATCH 096/201] Improve documentation as suggested Co-authored-by: Casper Lamboo --- include/PrimeTower.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/PrimeTower.h b/include/PrimeTower.h index d08292db59..61a0beb901 100644 --- a/include/PrimeTower.h +++ b/include/PrimeTower.h @@ -45,7 +45,7 @@ class PrimeTower /* * The first index is a bitmask representing an extruder combination, e.g. 0x05 for extruders 1+3. - * The second one is the used extruder index, e.g. 1 + * The second index is the used extruder index, e.g. 1 * The polygons represent the sparse pattern to be printed when all the given extruders are unused for this layer * and the given extruder is currently in use */ From c767d5458be60133b8136090d1f94fb5f37f1953 Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Fri, 16 Feb 2024 11:48:07 +0100 Subject: [PATCH 097/201] Fix crash when using raft with airgap pseudo-layers --- src/FffGcodeWriter.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/FffGcodeWriter.cpp b/src/FffGcodeWriter.cpp index 8d39751c5f..ae15349935 100644 --- a/src/FffGcodeWriter.cpp +++ b/src/FffGcodeWriter.cpp @@ -1538,7 +1538,10 @@ void FffGcodeWriter::calculateExtruderOrderPerLayer(const SliceDataStorage& stor std::vector extruder_order = getUsedExtrudersOnLayerExcludingStartingExtruder(storage, last_extruder, layer_nr); extruder_order_per_layer_here.push_back(extruder_order); - last_extruder = extruder_order.back().extruder_nr; + if (! extruder_order.empty()) + { + last_extruder = extruder_order.back().extruder_nr; + } } } From fcd28276da2eb74fac6c855c7358d32812a443fe Mon Sep 17 00:00:00 2001 From: "c.lamboo" Date: Fri, 16 Feb 2024 13:21:42 +0100 Subject: [PATCH 098/201] Add wagyu Note: this still a temporary condition to apply wagyu CURA-11444 --- CMakeLists.txt | 3 ++ conanfile.py | 1 + include/utils/polygon.h | 13 +++++++++ src/WallToolPaths.cpp | 5 ++++ src/utils/polygon.cpp | 61 +++++++++++++++++++++++++++++++++++++++++ 5 files changed, 83 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 62dab2e03d..52dfe4dc50 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -192,6 +192,7 @@ if (ENABLE_ARCUS) target_link_libraries(_CuraEngine PUBLIC arcus::arcus ) endif () +find_package(mapbox-wagyu REQUIRED) find_package(clipper REQUIRED) find_package(RapidJSON REQUIRED) find_package(stb REQUIRED) @@ -216,6 +217,7 @@ target_link_libraries(_CuraEngine range-v3::range-v3 fmt::fmt clipper::clipper + mapbox-wagyu::mapbox-wagyu rapidjson stb::stb boost::boost @@ -280,6 +282,7 @@ if (ENABLE_TESTING OR ENABLE_BENCHMARKS) GTest::gtest GTest::gmock clipper::clipper + mapbox-wagyu::mapbox-wagyu curaengine_grpc_definitions::curaengine_grpc_definitions asio-grpc::asio-grpc grpc::grpc diff --git a/conanfile.py b/conanfile.py index e73ab6fc2e..df916bc55d 100644 --- a/conanfile.py +++ b/conanfile.py @@ -120,6 +120,7 @@ def requirements(self): self.requires("neargye-semver/0.3.0") self.requires("zlib/1.2.12") self.requires("openssl/3.2.0") + self.requires("mapbox-wagyu/0.5.0") def generate(self): deps = CMakeDeps(self) diff --git a/include/utils/polygon.h b/include/utils/polygon.h index 86f9a7aa22..484ded8dd0 100644 --- a/include/utils/polygon.h +++ b/include/utils/polygon.h @@ -15,6 +15,8 @@ #include #include +#include + #include "../settings/types/Angle.h" //For angles between vertices. #include "../settings/types/Ratio.h" #include "Point2LL.h" @@ -1536,6 +1538,17 @@ class Polygons * @return Polygons The polygons read from the stream */ [[maybe_unused]] static Polygons fromWkt(const std::string& wkt); + + /*! + * @brief Remove self-intersections from the polygons + * _note_: this function uses wagyu to remove the self intersections. + * since wagyu uses a different internal representation of the polygons + * we need to convert back and forward between data structures which + * might impact performance, use wisely! + * + * @return Polygons - the cleaned polygons + */ + Polygons removeNearSelfIntersections() const; }; /*! diff --git a/src/WallToolPaths.cpp b/src/WallToolPaths.cpp index 75a98b843a..ccff3641f0 100644 --- a/src/WallToolPaths.cpp +++ b/src/WallToolPaths.cpp @@ -116,6 +116,11 @@ const std::vector& WallToolPaths::generate() return toolpaths_; } + if (settings_.get("use_wagyu")) + { + prepared_outline = prepared_outline.removeNearSelfIntersections(); + } + const coord_t wall_transition_length = settings_.get("wall_transition_length"); // When to split the middle wall into two: diff --git a/src/utils/polygon.cpp b/src/utils/polygon.cpp index decaeb582c..ce2464126a 100644 --- a/src/utils/polygon.cpp +++ b/src/utils/polygon.cpp @@ -1582,6 +1582,67 @@ Polygons Polygons::tubeShape(const coord_t inner_offset, const coord_t outer_off return this->offset(outer_offset).difference(this->offset(-inner_offset)); } +Polygons Polygons::removeNearSelfIntersections() const +{ + using map_pt = mapbox::geometry::point; + using map_ring = mapbox::geometry::linear_ring; + using map_poly = mapbox::geometry::polygon; + using map_mpoly = mapbox::geometry::multi_polygon; + + map_mpoly mwpoly; + + mapbox::geometry::wagyu::wagyu wagyu; + + for (const auto& polygon : splitIntoParts()) + { + mwpoly.emplace_back(); + map_poly& wpoly = mwpoly.back(); + for (const auto& path : polygon) + { + wpoly.emplace_back(); + map_ring& wring = wpoly.back(); + for (const auto& point : path) + { + wring.emplace_back(point.X / 4, point.Y / 4); + } + + wagyu.add_ring(wring); + } + } + + map_mpoly sln; + + wagyu.execute(mapbox::geometry::wagyu::clip_type_union, sln, mapbox::geometry::wagyu::fill_type_even_odd, mapbox::geometry::wagyu::fill_type_even_odd); + + Polygons polys; + + { + for (const auto& poly : sln) + { + for (const auto& ring : poly) + { + Polygon npoly; + auto last = ring.back(); + bool first = true; + for (const auto& pt : ring) + { + if (first || pt != ring.back()) + { + npoly.emplace_back(pt.x * 4, pt.y * 4); + first = false; + } + last = pt; + } + polys.add(npoly); + } + } + polys = polys.unionPolygons(); + polys.removeColinearEdges(); + } + + return polys; +} + size_t PartsView::getPartContaining(size_t poly_idx, size_t* boundary_poly_idx) const { const PartsView& partsView = *this; From 0b95a622341da25015f1c5f7d85b0199ac6809a4 Mon Sep 17 00:00:00 2001 From: "c.lamboo" Date: Fri, 16 Feb 2024 13:22:01 +0100 Subject: [PATCH 099/201] Fix wall ordering issue CURA-11444 --- src/FffGcodeWriter.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/FffGcodeWriter.cpp b/src/FffGcodeWriter.cpp index db6cb931e0..fb07c8bafb 100644 --- a/src/FffGcodeWriter.cpp +++ b/src/FffGcodeWriter.cpp @@ -1442,7 +1442,7 @@ void FffGcodeWriter::processSkirtBrim(const SliceDataStorage& storage, LayerPlan start_close_to, fan_speed, reverse_print_direction, - order_requirements); + layer_nr == 0 ? order_requirements : PathOrderOptimizer::no_order_requirements_); } From 4dfbfcbd954cbf4acd00682beacd2edf1e565a9a Mon Sep 17 00:00:00 2001 From: casperlamboo Date: Fri, 16 Feb 2024 12:22:32 +0000 Subject: [PATCH 100/201] Applied clang-format. --- include/utils/polygon.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/include/utils/polygon.h b/include/utils/polygon.h index 484ded8dd0..89bc261670 100644 --- a/include/utils/polygon.h +++ b/include/utils/polygon.h @@ -11,12 +11,11 @@ #include #include // int64_t.min #include +#include #include #include #include -#include - #include "../settings/types/Angle.h" //For angles between vertices. #include "../settings/types/Ratio.h" #include "Point2LL.h" From 35a9f5ca145acd5ddbfbe9f6dc0f1e7423c8f761 Mon Sep 17 00:00:00 2001 From: casperlamboo Date: Fri, 16 Feb 2024 13:30:34 +0000 Subject: [PATCH 101/201] Applied clang-format. --- include/ExtruderUse.h | 4 ++-- include/TreeSupportBaseCircle.h | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/include/ExtruderUse.h b/include/ExtruderUse.h index 46798d0266..9333adf1d4 100644 --- a/include/ExtruderUse.h +++ b/include/ExtruderUse.h @@ -4,10 +4,10 @@ #ifndef EXTRUDERUSE_H #define EXTRUDERUSE_H -#include "ExtruderPrime.h" - #include +#include "ExtruderPrime.h" + namespace cura { diff --git a/include/TreeSupportBaseCircle.h b/include/TreeSupportBaseCircle.h index 7dea35b31b..fe872ddcc7 100644 --- a/include/TreeSupportBaseCircle.h +++ b/include/TreeSupportBaseCircle.h @@ -3,12 +3,12 @@ #ifndef TREESUPPORTCIRCLE_H #define TREESUPPORTCIRCLE_H -#include "utils/Coord_t.h" -#include "utils/polygon.h" +#include #include -#include +#include "utils/Coord_t.h" +#include "utils/polygon.h" namespace cura { From f2ab613078ceb214d943aea7d864af876803f567 Mon Sep 17 00:00:00 2001 From: Jelle Spijker Date: Sat, 17 Feb 2024 13:17:44 +0100 Subject: [PATCH 102/201] Fix Sentry option --- conanfile.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/conanfile.py b/conanfile.py index e73ab6fc2e..191131c272 100644 --- a/conanfile.py +++ b/conanfile.py @@ -1,6 +1,6 @@ # Copyright (c) 2024 UltiMaker # CuraEngine is released under the terms of the AGPLv3 or higher -from io import StringIO +from shutil import which from os import path import os @@ -66,7 +66,9 @@ def export_sources(self): def config_options(self): if not self.options.enable_plugins: del self.options.enable_remote_plugins - if self.conf.get("user.curaengine:sentry_url", "", check_type=str) == "": + sentry_project = self.conf.get("user.curaengine:sentry_project", "", check_type=str) + sentry_org = self.conf.get("user.curaengine:sentry_org", "", check_type=str) + if os.environ.get('SENTRY_TOKEN', None) is None or sentry_project == "" or sentry_org == "": del self.options.enable_sentry def configure(self): From 7634d40dbdb7231de2c442220824ba51f6406a5d Mon Sep 17 00:00:00 2001 From: "saumya.jain" Date: Mon, 19 Feb 2024 13:11:40 +0100 Subject: [PATCH 103/201] adding local wagyu recipe CURA-11444 --- conanfile.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conanfile.py b/conanfile.py index df916bc55d..8ce5092aab 100644 --- a/conanfile.py +++ b/conanfile.py @@ -120,7 +120,7 @@ def requirements(self): self.requires("neargye-semver/0.3.0") self.requires("zlib/1.2.12") self.requires("openssl/3.2.0") - self.requires("mapbox-wagyu/0.5.0") + self.requires("mapbox-wagyu/0.5.0@ultimaker/cura_11444") def generate(self): deps = CMakeDeps(self) From 838dafcfcce8ff0b9222cdeac3efd44533e3d8d4 Mon Sep 17 00:00:00 2001 From: "c.lamboo" Date: Mon, 19 Feb 2024 14:26:21 +0100 Subject: [PATCH 104/201] Use wagyu stable CURA-11444 --- conanfile.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conanfile.py b/conanfile.py index 8ce5092aab..4bd0afcbb8 100644 --- a/conanfile.py +++ b/conanfile.py @@ -120,7 +120,7 @@ def requirements(self): self.requires("neargye-semver/0.3.0") self.requires("zlib/1.2.12") self.requires("openssl/3.2.0") - self.requires("mapbox-wagyu/0.5.0@ultimaker/cura_11444") + self.requires("mapbox-wagyu/0.5.0@ultimaker/stable") def generate(self): deps = CMakeDeps(self) From 677cb7f1468f7f7be92b0daa930f3ba125b0e995 Mon Sep 17 00:00:00 2001 From: "c.lamboo" Date: Mon, 19 Feb 2024 15:11:28 +0100 Subject: [PATCH 105/201] Add wagyu setting to unit test CURA-11444 --- tests/WallsComputationTest.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/WallsComputationTest.cpp b/tests/WallsComputationTest.cpp index a45cb5464a..e95fb28bfa 100644 --- a/tests/WallsComputationTest.cpp +++ b/tests/WallsComputationTest.cpp @@ -91,6 +91,7 @@ class WallsComputationTest : public testing::Test settings.add("wall_transition_length", "1"); settings.add("wall_x_extruder_nr", "0"); settings.add("wall_distribution_count", "2"); + settings.add("use_wagyu", "true"); } }; From 75885abb542479017276bd9668a587aac6537c35 Mon Sep 17 00:00:00 2001 From: Jelle Spijker Date: Tue, 20 Feb 2024 08:46:41 +0100 Subject: [PATCH 106/201] Create `d.ts` file for CuraEngine Contributes to NP5 and NP-43 --- CMakeLists.txt | 2 +- conanfile.py | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 5ba77db4d0..8a5abfbc30 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -259,7 +259,7 @@ endif () if (CMAKE_CXX_PLATFORM_ID STREQUAL "emscripten") message(STATUS "Building for Emscripten") - target_link_options(_CuraEngine PUBLIC -Wno-unused-command-line-argument -sINVOKE_RUN=0 -sEXPORT_NAME=CuraEngine -sEXPORTED_RUNTIME_METHODS=[callMain,FS] -sFORCE_FILESYSTEM=1 -sALLOW_MEMORY_GROWTH=1 -sEXPORT_ES6=1 -sMODULARIZE=1 -sSINGLE_FILE=1 -sENVIRONMENT=worker) + target_link_options(_CuraEngine PUBLIC -Wno-unused-command-line-argument -sINVOKE_RUN=0 -sEXPORT_NAME=CuraEngine -sEXPORTED_RUNTIME_METHODS=[callMain,FS] -sFORCE_FILESYSTEM=1 -sALLOW_MEMORY_GROWTH=1 -sEXPORT_ES6=1 -sMODULARIZE=1 -sSINGLE_FILE=1 -sENVIRONMENT=worker -sERROR_ON_UNDEFINED_SYMBOLS=0 -lembind --embind-emit-tsd CuraEngine.d.ts) endif () target_link_libraries(CuraEngine PRIVATE diff --git a/conanfile.py b/conanfile.py index 078ff35d11..c54fc9f735 100644 --- a/conanfile.py +++ b/conanfile.py @@ -219,6 +219,7 @@ def package(self): else: ext = "" copy(self, f"CuraEngine{ext}", src=self.build_folder, dst=path.join(self.package_folder, "bin")) + copy(self, f"*.d.ts", src=self.build_folder, dst=path.join(self.package_folder, "bin")) copy(self, f"_CuraEngine.*", src=self.build_folder, dst=path.join(self.package_folder, "lib")) copy(self, "LICENSE*", src=self.source_folder, dst=path.join(self.package_folder, "license")) From de12ba8998a041e587bcebedfa73e663cbb7251a Mon Sep 17 00:00:00 2001 From: Jelle Spijker Date: Tue, 20 Feb 2024 08:53:26 +0100 Subject: [PATCH 107/201] match on OS for extension Co-authored-by: Casper Lamboo --- conanfile.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/conanfile.py b/conanfile.py index c54fc9f735..d20378d7e7 100644 --- a/conanfile.py +++ b/conanfile.py @@ -212,12 +212,13 @@ def build(self): self.run(f"sentry-cli --auth-token {os.environ['SENTRY_TOKEN']} releases finalize -o {sentry_org} -p {sentry_project} {self.version}") def package(self): - if self.settings.os == "Windows": - ext = ".exe" - elif self.settings.os == "Emscripten": - ext = ".js" - else: - ext = "" + match self.setting.os: + case "Windows": + ext = ".exe" + case "Emscripten": + ext = ".js" + case other: + ext = "" copy(self, f"CuraEngine{ext}", src=self.build_folder, dst=path.join(self.package_folder, "bin")) copy(self, f"*.d.ts", src=self.build_folder, dst=path.join(self.package_folder, "bin")) copy(self, f"_CuraEngine.*", src=self.build_folder, dst=path.join(self.package_folder, "lib")) From 0b48b4621fb9cc52b2c55c640c00d3ee33489966 Mon Sep 17 00:00:00 2001 From: Remco Burema Date: Tue, 20 Feb 2024 14:39:16 +0100 Subject: [PATCH 108/201] Make it compile with Win and VS again. --- include/utils/views/split_paths.h | 2 +- src/communication/CommandLine.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/utils/views/split_paths.h b/include/utils/views/split_paths.h index 926150555a..2b68f6b211 100644 --- a/include/utils/views/split_paths.h +++ b/include/utils/views/split_paths.h @@ -15,7 +15,7 @@ namespace cura::views namespace details { #ifdef _WIN32 -constexpr auto path_sep = ";"; +constexpr auto path_sep = ';'; #else constexpr auto path_sep = ':'; #endif diff --git a/src/communication/CommandLine.cpp b/src/communication/CommandLine.cpp index f6cd567431..45b51d8dce 100644 --- a/src/communication/CommandLine.cpp +++ b/src/communication/CommandLine.cpp @@ -592,7 +592,7 @@ std::string CommandLine::findDefinitionFile(const std::string& definition_id, co { if (auto candidate = search_directory / (definition_id + ".def.json"); std::filesystem::exists(candidate)) { - return candidate; + return candidate.string(); } } spdlog::error("Couldn't find definition file with ID: {}", definition_id); From 556df3dae67cb0e84ba4e70bfd1f8b1766b5f7ee Mon Sep 17 00:00:00 2001 From: "c.lamboo" Date: Tue, 20 Feb 2024 17:09:16 +0100 Subject: [PATCH 109/201] Fix building on mac --- include/communication/CommandLine.h | 7 +++---- src/communication/CommandLine.cpp | 10 +++++----- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/include/communication/CommandLine.h b/include/communication/CommandLine.h index 11b86e8e65..d27aa8121b 100644 --- a/include/communication/CommandLine.h +++ b/include/communication/CommandLine.h @@ -7,7 +7,6 @@ #include #include //Loading JSON documents to get settings from them. #include //To store the command line arguments. -#include #include //To store the command line arguments. #include "Communication.h" //The class we're implementing. @@ -156,7 +155,7 @@ class CommandLine : public Communication std::string progressHandler; #endif - std::unordered_set search_directories_; + std::vector search_directories_; /* * \brief The command line arguments that the application was called with. @@ -191,7 +190,7 @@ class CommandLine : public Communication */ int loadJSON( const rapidjson::Document& document, - const std::unordered_set& search_directories, + const std::vector& search_directories, Settings& settings, bool force_read_parent = false, bool force_read_nondefault = false); @@ -212,7 +211,7 @@ class CommandLine : public Communication * \param search_directories The directories to search in. * \return The first definition file that matches the definition ID. */ - static std::string findDefinitionFile(const std::string& definition_id, const std::unordered_set& search_directories); + static std::string findDefinitionFile(const std::string& definition_id, const std::vector& search_directories); }; } // namespace cura diff --git a/src/communication/CommandLine.cpp b/src/communication/CommandLine.cpp index 45b51d8dce..3c31f1f6cd 100644 --- a/src/communication/CommandLine.cpp +++ b/src/communication/CommandLine.cpp @@ -40,7 +40,7 @@ CommandLine::CommandLine(const std::vector& arguments) { if (auto search_paths = spdlog::details::os::getenv("CURA_ENGINE_SEARCH_PATH"); ! search_paths.empty()) { - search_directories_ = search_paths | views::split_paths | ranges::to>(); + search_directories_ = search_paths | views::split_paths | ranges::to>(); }; } @@ -242,7 +242,7 @@ void CommandLine::sliceNext() exit(1); } argument = arguments_[argument_index]; - search_directories_ = argument | views::split_paths | ranges::to>(); + search_directories_ = argument | views::split_paths | ranges::to>(); break; } case 'j': @@ -420,13 +420,13 @@ int CommandLine::loadJSON(const std::filesystem::path& json_filename, Settings& return 2; } - search_directories_.insert(std::filesystem::path(json_filename).parent_path()); + search_directories_.push_back(std::filesystem::path(json_filename).parent_path()); return loadJSON(json_document, search_directories_, settings, force_read_parent, force_read_nondefault); } int CommandLine::loadJSON( const rapidjson::Document& document, - const std::unordered_set& search_directories, + const std::vector& search_directories, Settings& settings, bool force_read_parent, bool force_read_nondefault) @@ -586,7 +586,7 @@ void CommandLine::loadJSONSettings(const rapidjson::Value& element, Settings& se } } -std::string CommandLine::findDefinitionFile(const std::string& definition_id, const std::unordered_set& search_directories) +std::string CommandLine::findDefinitionFile(const std::string& definition_id, const std::vector& search_directories) { for (const auto& search_directory : search_directories) { From 813146c7eecbb1a5ab6f9e7017f2958cb8201b68 Mon Sep 17 00:00:00 2001 From: Remco Burema Date: Wed, 21 Feb 2024 09:23:51 +0100 Subject: [PATCH 110/201] Prefer reinterpret/move rather than copy. It's not the most elegant code, but the alternative would be renaming either all of the x,y to X,Y in wagyu, or all of the X,Y to x,y for clipperlib-intpoints. proposed part of CURA-11444 --- include/utils/polygon.h | 3 +-- src/utils/polygon.cpp | 42 +++++++++++++++++------------------------ 2 files changed, 18 insertions(+), 27 deletions(-) diff --git a/include/utils/polygon.h b/include/utils/polygon.h index 89bc261670..dbf0a97a3d 100644 --- a/include/utils/polygon.h +++ b/include/utils/polygon.h @@ -1,4 +1,4 @@ -// Copyright (c) 2023 UltiMaker +// Copyright (c) 2024 UltiMaker // CuraEngine is released under the terms of the AGPLv3 or higher #ifndef UTILS_POLYGON_H @@ -11,7 +11,6 @@ #include #include // int64_t.min #include -#include #include #include #include diff --git a/src/utils/polygon.cpp b/src/utils/polygon.cpp index ce2464126a..c2a92fb254 100644 --- a/src/utils/polygon.cpp +++ b/src/utils/polygon.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -1593,20 +1594,19 @@ Polygons Polygons::removeNearSelfIntersections() const mapbox::geometry::wagyu::wagyu wagyu; - for (const auto& polygon : splitIntoParts()) + for (auto& polygon : splitIntoParts()) { mwpoly.emplace_back(); map_poly& wpoly = mwpoly.back(); - for (const auto& path : polygon) + for (auto& path : polygon) { - wpoly.emplace_back(); - map_ring& wring = wpoly.back(); - for (const auto& point : path) + wpoly.push_back(std::move(*reinterpret_cast>*>(&path))); + for (auto& point : wpoly.back()) { - wring.emplace_back(point.X / 4, point.Y / 4); + point.x /= 4; + point.y /= 4; } - - wagyu.add_ring(wring); + wagyu.add_ring(wpoly.back()); } } @@ -1616,29 +1616,21 @@ Polygons Polygons::removeNearSelfIntersections() const Polygons polys; + for (auto& poly : sln) { - for (const auto& poly : sln) + for (auto& ring : poly) { - for (const auto& ring : poly) + ring.pop_back(); + for (auto& point : ring) { - Polygon npoly; - auto last = ring.back(); - bool first = true; - for (const auto& pt : ring) - { - if (first || pt != ring.back()) - { - npoly.emplace_back(pt.x * 4, pt.y * 4); - first = false; - } - last = pt; - } - polys.add(npoly); + point.x *= 4; + point.y *= 4; } + polys.add(*reinterpret_cast*>(&ring)); // NOTE: 'add' already moves the vector } - polys = polys.unionPolygons(); - polys.removeColinearEdges(); } + polys = polys.unionPolygons(); + polys.removeColinearEdges(); return polys; } From 44c262f4cd465ee2e0b1b6f3f56d3c5aaff1176c Mon Sep 17 00:00:00 2001 From: rburema Date: Wed, 21 Feb 2024 08:24:38 +0000 Subject: [PATCH 111/201] Applied clang-format. --- src/utils/polygon.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/utils/polygon.cpp b/src/utils/polygon.cpp index c2a92fb254..66f2a3672a 100644 --- a/src/utils/polygon.cpp +++ b/src/utils/polygon.cpp @@ -3,13 +3,13 @@ #include "utils/polygon.h" +#include #include #include #include #include #include -#include #include #include #include @@ -1626,7 +1626,7 @@ Polygons Polygons::removeNearSelfIntersections() const point.x *= 4; point.y *= 4; } - polys.add(*reinterpret_cast*>(&ring)); // NOTE: 'add' already moves the vector + polys.add(*reinterpret_cast*>(&ring)); // NOTE: 'add' already moves the vector } } polys = polys.unionPolygons(); From b664e7738b114cf5f159de2eca1b0938d6c48eba Mon Sep 17 00:00:00 2001 From: Remco Burema Date: Wed, 21 Feb 2024 10:05:36 +0100 Subject: [PATCH 112/201] Remove scaffolding (setting used to test implementation). part of CURA-11444 --- src/WallToolPaths.cpp | 5 +---- tests/WallsComputationTest.cpp | 1 - 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/src/WallToolPaths.cpp b/src/WallToolPaths.cpp index ccff3641f0..055377060d 100644 --- a/src/WallToolPaths.cpp +++ b/src/WallToolPaths.cpp @@ -116,10 +116,7 @@ const std::vector& WallToolPaths::generate() return toolpaths_; } - if (settings_.get("use_wagyu")) - { - prepared_outline = prepared_outline.removeNearSelfIntersections(); - } + prepared_outline = prepared_outline.removeNearSelfIntersections(); const coord_t wall_transition_length = settings_.get("wall_transition_length"); diff --git a/tests/WallsComputationTest.cpp b/tests/WallsComputationTest.cpp index e95fb28bfa..a45cb5464a 100644 --- a/tests/WallsComputationTest.cpp +++ b/tests/WallsComputationTest.cpp @@ -91,7 +91,6 @@ class WallsComputationTest : public testing::Test settings.add("wall_transition_length", "1"); settings.add("wall_x_extruder_nr", "0"); settings.add("wall_distribution_count", "2"); - settings.add("use_wagyu", "true"); } }; From fde7b79b61794124beb9570d1bd85129a7e4e721 Mon Sep 17 00:00:00 2001 From: "c.lamboo" Date: Wed, 21 Feb 2024 17:40:16 +0100 Subject: [PATCH 113/201] Fix building --- conanfile.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conanfile.py b/conanfile.py index 4b2def277d..a696e03a1c 100644 --- a/conanfile.py +++ b/conanfile.py @@ -213,7 +213,7 @@ def build(self): self.run(f"sentry-cli --auth-token {os.environ['SENTRY_TOKEN']} releases finalize -o {sentry_org} -p {sentry_project} {self.version}") def package(self): - match self.setting.os: + match self.settings.os: case "Windows": ext = ".exe" case "Emscripten": From 30ebfa425eb32b056a1e0c35863378ffe2c59eac Mon Sep 17 00:00:00 2001 From: Remco Burema Date: Wed, 21 Feb 2024 19:55:58 +0100 Subject: [PATCH 114/201] Inline definition imported from multiple sources. --- include/utils/format/filesystem_path.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/utils/format/filesystem_path.h b/include/utils/format/filesystem_path.h index f6f8d697a7..e3b7bbecfd 100644 --- a/include/utils/format/filesystem_path.h +++ b/include/utils/format/filesystem_path.h @@ -37,9 +37,9 @@ struct formatter : formatter }; #ifdef _WIN32 -std::string fmt::formatter::USERNAME = std::getenv("USERNAME") != nullptr ? std::getenv("USERNAME") : ""; +inline std::string fmt::formatter::USERNAME = std::getenv("USERNAME") != nullptr ? std::getenv("USERNAME") : ""; #else -std::string fmt::formatter::USERNAME = std::getenv("USER") != nullptr ? std::getenv("USER") : ""; +inline std::string fmt::formatter::USERNAME = std::getenv("USER") != nullptr ? std::getenv("USER") : ""; #endif } // namespace fmt From a3f5fbf5322aba4bee7401a5252d9ae465b16306 Mon Sep 17 00:00:00 2001 From: Saumya Jain Date: Thu, 22 Feb 2024 16:48:03 +0100 Subject: [PATCH 115/201] adding an extra travel move at the beginning to machine_start_pos CURA-11444 --- src/FffGcodeWriter.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/FffGcodeWriter.cpp b/src/FffGcodeWriter.cpp index d4c64cb685..a21081daec 100644 --- a/src/FffGcodeWriter.cpp +++ b/src/FffGcodeWriter.cpp @@ -140,6 +140,12 @@ void FffGcodeWriter::writeGCode(SliceDataStorage& storage, TimeKeeper& time_keep mesh_order_per_extruder.push_back(calculateMeshOrder(storage, extruder_nr)); } } + + // Setting first travel move of the first extruder to the machine start position + const auto extruder_settings = Application::getInstance().current_slice_->scene.extruders[start_extruder_nr].settings_; + Point3LL p(extruder_settings.get("machine_extruder_start_pos_x"), extruder_settings.get("machine_extruder_start_pos_y"), gcode.getPositionZ()); + gcode.writeTravel(p, Application::getInstance().current_slice_->scene.extruders[gcode.getExtruderNr()].settings_.get("speed_travel"));; + calculateExtruderOrderPerLayer(storage); calculatePrimeLayerPerExtruder(storage); From 4548f7253d7ee9518748534e1a27d76e913597cc Mon Sep 17 00:00:00 2001 From: saumyaj3 Date: Thu, 22 Feb 2024 15:48:43 +0000 Subject: [PATCH 116/201] Applied clang-format. --- src/FffGcodeWriter.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/FffGcodeWriter.cpp b/src/FffGcodeWriter.cpp index a21081daec..c014d733f5 100644 --- a/src/FffGcodeWriter.cpp +++ b/src/FffGcodeWriter.cpp @@ -144,7 +144,8 @@ void FffGcodeWriter::writeGCode(SliceDataStorage& storage, TimeKeeper& time_keep // Setting first travel move of the first extruder to the machine start position const auto extruder_settings = Application::getInstance().current_slice_->scene.extruders[start_extruder_nr].settings_; Point3LL p(extruder_settings.get("machine_extruder_start_pos_x"), extruder_settings.get("machine_extruder_start_pos_y"), gcode.getPositionZ()); - gcode.writeTravel(p, Application::getInstance().current_slice_->scene.extruders[gcode.getExtruderNr()].settings_.get("speed_travel"));; + gcode.writeTravel(p, Application::getInstance().current_slice_->scene.extruders[gcode.getExtruderNr()].settings_.get("speed_travel")); + ; calculateExtruderOrderPerLayer(storage); calculatePrimeLayerPerExtruder(storage); From 8ea17cc29f672979dafce2bbc24f5d9c5dfe4b98 Mon Sep 17 00:00:00 2001 From: Saumya Jain Date: Thu, 22 Feb 2024 16:54:32 +0100 Subject: [PATCH 117/201] removing extra semicolon CURA-11553 --- src/FffGcodeWriter.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/FffGcodeWriter.cpp b/src/FffGcodeWriter.cpp index c014d733f5..e6d7980f8b 100644 --- a/src/FffGcodeWriter.cpp +++ b/src/FffGcodeWriter.cpp @@ -145,7 +145,6 @@ void FffGcodeWriter::writeGCode(SliceDataStorage& storage, TimeKeeper& time_keep const auto extruder_settings = Application::getInstance().current_slice_->scene.extruders[start_extruder_nr].settings_; Point3LL p(extruder_settings.get("machine_extruder_start_pos_x"), extruder_settings.get("machine_extruder_start_pos_y"), gcode.getPositionZ()); gcode.writeTravel(p, Application::getInstance().current_slice_->scene.extruders[gcode.getExtruderNr()].settings_.get("speed_travel")); - ; calculateExtruderOrderPerLayer(storage); calculatePrimeLayerPerExtruder(storage); From 404c1c690c82a8863176ab995d3426476a2fb737 Mon Sep 17 00:00:00 2001 From: Saumya Jain Date: Thu, 22 Feb 2024 17:15:03 +0100 Subject: [PATCH 118/201] writeing initial travel move of the extruder to avoid scarring CURA-11553 --- src/FffGcodeWriter.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/FffGcodeWriter.cpp b/src/FffGcodeWriter.cpp index e6d7980f8b..dcef0e3eab 100644 --- a/src/FffGcodeWriter.cpp +++ b/src/FffGcodeWriter.cpp @@ -142,9 +142,9 @@ void FffGcodeWriter::writeGCode(SliceDataStorage& storage, TimeKeeper& time_keep } // Setting first travel move of the first extruder to the machine start position - const auto extruder_settings = Application::getInstance().current_slice_->scene.extruders[start_extruder_nr].settings_; + const auto extruder_settings = Application::getInstance().current_slice_->scene.extruders[gcode.getExtruderNr()].settings_; Point3LL p(extruder_settings.get("machine_extruder_start_pos_x"), extruder_settings.get("machine_extruder_start_pos_y"), gcode.getPositionZ()); - gcode.writeTravel(p, Application::getInstance().current_slice_->scene.extruders[gcode.getExtruderNr()].settings_.get("speed_travel")); + gcode.writeTravel(p, extruder_settings.get("speed_travel")); calculateExtruderOrderPerLayer(storage); calculatePrimeLayerPerExtruder(storage); From e4d47de651763e77567a889a170b68766957ba3a Mon Sep 17 00:00:00 2001 From: "c.lamboo" Date: Thu, 22 Feb 2024 23:03:59 +0100 Subject: [PATCH 119/201] skip first --- .github/workflows/gcodeanalyzer.yml | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/.github/workflows/gcodeanalyzer.yml b/.github/workflows/gcodeanalyzer.yml index 29c83817de..b42ada8717 100644 --- a/.github/workflows/gcodeanalyzer.yml +++ b/.github/workflows/gcodeanalyzer.yml @@ -178,7 +178,7 @@ jobs: - name: Collect STL-files, run CuraEngine, output GCode-files run: | - for file in `ls ../NightlyTestModels/*.stl`; + for file in `ls ../NightlyTestModels/*.stl | tail -n 3`; do ( time ./build/Release/CuraEngine slice --force-read-parent --force-read-nondefault -v -p -j ../Cura/resources/definitions/ultimaker_s3.def.json -l $file -o ../`basename $file .stl`.gcode ) 2> ../`basename $file .stl`.time done @@ -308,15 +308,15 @@ jobs: shell: python working-directory: GCodeAnalyzer - - name: Store benchmark result - uses: benchmark-action/github-action-benchmark@v1 - with: - name: CGcodeAnalyzer - output-file-path: output.json - gh-repository: github.com/Ultimaker/CuraEngineBenchmarks - gh-pages-branch: main - benchmark-data-dir-path: dev/gcodeanalyzer - tool: customBiggerIsBetter - github-token: ${{ secrets.CURA_BENCHMARK_PAT }} - auto-push: true - max-items-in-chart: 250 +# - name: Store benchmark result +# uses: benchmark-action/github-action-benchmark@v1 +# with: +# name: CGcodeAnalyzer +# output-file-path: output.json +# gh-repository: github.com/Ultimaker/CuraEngineBenchmarks +# gh-pages-branch: main +# benchmark-data-dir-path: dev/gcodeanalyzer +# tool: customBiggerIsBetter +# github-token: ${{ secrets.CURA_BENCHMARK_PAT }} +# auto-push: true +# max-items-in-chart: 250 From 01a46f316a7ba9f451a856216ecfab7bbbd90a64 Mon Sep 17 00:00:00 2001 From: "c.lamboo" Date: Fri, 23 Feb 2024 06:43:06 +0100 Subject: [PATCH 120/201] Remove none option --- include/settings/EnumSettings.h | 5 ----- src/FffGcodeWriter.cpp | 2 -- src/FffPolygonGenerator.cpp | 4 ++-- src/PrimeTower.cpp | 2 +- src/settings/Settings.cpp | 10 ++-------- 5 files changed, 5 insertions(+), 18 deletions(-) diff --git a/include/settings/EnumSettings.h b/include/settings/EnumSettings.h index 7b8c970db4..333fa1d07a 100644 --- a/include/settings/EnumSettings.h +++ b/include/settings/EnumSettings.h @@ -250,11 +250,6 @@ enum class InsetDirection */ enum class PrimeTowerMethod { - /*! - * No prime tower is generated. - */ - NONE, - /*! * Prime tower that minimizes time and used filament as much as possible. */ diff --git a/src/FffGcodeWriter.cpp b/src/FffGcodeWriter.cpp index d4c64cb685..e45912fdb9 100644 --- a/src/FffGcodeWriter.cpp +++ b/src/FffGcodeWriter.cpp @@ -1602,8 +1602,6 @@ std::vector switch (method) { - case PrimeTowerMethod::NONE: - break; case PrimeTowerMethod::NORMAL: if (extruder_is_used_on_this_layer[extruder_nr] && extruder_nr != last_extruder) diff --git a/src/FffPolygonGenerator.cpp b/src/FffPolygonGenerator.cpp index c5c33dcc01..f2fcbe8910 100644 --- a/src/FffPolygonGenerator.cpp +++ b/src/FffPolygonGenerator.cpp @@ -972,7 +972,7 @@ void FffPolygonGenerator::processOozeShield(SliceDataStorage& storage) { storage.oozeShield[layer_nr].removeSmallAreas(largest_printed_area); } - if (mesh_group_settings.get("prime_tower_mode") != PrimeTowerMethod::NONE) + if (mesh_group_settings.get("prime_tower_enable")) { coord_t max_line_width = 0; { // compute max_line_width @@ -1024,7 +1024,7 @@ void FffPolygonGenerator::processDraftShield(SliceDataStorage& storage) maximum_deviation = std::min(maximum_deviation, extruder.settings_.get("meshfix_maximum_deviation")); } storage.draft_protection_shield = Simplify(maximum_resolution, maximum_deviation, 0).polygon(storage.draft_protection_shield); - if (mesh_group_settings.get("prime_tower_mode") != PrimeTowerMethod::NONE) + if (mesh_group_settings.get("prime_tower_enable")) { coord_t max_line_width = 0; { // compute max_line_width diff --git a/src/PrimeTower.cpp b/src/PrimeTower.cpp index 5264ecb346..180a79a331 100644 --- a/src/PrimeTower.cpp +++ b/src/PrimeTower.cpp @@ -48,7 +48,7 @@ PrimeTower::PrimeTower() && ((adhesion_type != EPlatformAdhesion::SKIRT) && (adhesion_type != EPlatformAdhesion::BRIM))); } - enabled_ = method != PrimeTowerMethod::NONE && scene.current_mesh_group->settings.get("prime_tower_min_volume") > 10 + enabled_ = scene.current_mesh_group->settings.get("prime_tower_enable") && scene.current_mesh_group->settings.get("prime_tower_min_volume") > 10 && scene.current_mesh_group->settings.get("prime_tower_size") > 10; would_have_actual_tower_ = enabled_; // Assume so for now. diff --git a/src/settings/Settings.cpp b/src/settings/Settings.cpp index b94364d9e5..fb40910eef 100644 --- a/src/settings/Settings.cpp +++ b/src/settings/Settings.cpp @@ -686,14 +686,8 @@ PrimeTowerMethod Settings::get(const std::string& key) const { return PrimeTowerMethod::INTERLEAVED; } - else if (value == "normal") - { - return PrimeTowerMethod::NORMAL; - } - else // Default. - { - return PrimeTowerMethod::NONE; - } + + return PrimeTowerMethod::NORMAL; } template<> From f5ac2b902d3e7395505eb8be0284ee029d23f0a0 Mon Sep 17 00:00:00 2001 From: casperlamboo Date: Fri, 23 Feb 2024 05:43:44 +0000 Subject: [PATCH 121/201] Applied clang-format. --- src/FffGcodeWriter.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/FffGcodeWriter.cpp b/src/FffGcodeWriter.cpp index e45912fdb9..c04c3b45d4 100644 --- a/src/FffGcodeWriter.cpp +++ b/src/FffGcodeWriter.cpp @@ -1602,7 +1602,6 @@ std::vector switch (method) { - case PrimeTowerMethod::NORMAL: if (extruder_is_used_on_this_layer[extruder_nr] && extruder_nr != last_extruder) { From 24cfc945977988b410a2818dd863d04da802273b Mon Sep 17 00:00:00 2001 From: "c.lamboo" Date: Fri, 23 Feb 2024 07:46:07 +0100 Subject: [PATCH 122/201] Add fallback on last extruder of previous layer when used extruder list is empty CURA-11649 --- src/FffGcodeWriter.cpp | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/src/FffGcodeWriter.cpp b/src/FffGcodeWriter.cpp index d4c64cb685..04aacf5deb 100644 --- a/src/FffGcodeWriter.cpp +++ b/src/FffGcodeWriter.cpp @@ -1173,13 +1173,29 @@ FffGcodeWriter::ProcessLayerResult FffGcodeWriter::processLayer(const SliceDataS const std::vector& extruder_order = (layer_nr < 0) ? extruder_order_per_layer_negative_layers[extruder_order_per_layer_negative_layers.size() + layer_nr] : extruder_order_per_layer[layer_nr]; - const coord_t first_outer_wall_line_width = scene.extruders[extruder_order.front().extruder_nr].settings_.get("wall_line_width_0"); + size_t first_extruder; + if (extruder_order.size() > 0) + { + first_extruder = extruder_order.front().extruder_nr; + } + else + { + // find the last extruder used in the previous layer + size_t last_extruder_nr_layer = layer_nr - 1; + while (extruder_order_per_layer[last_extruder_nr_layer].size() == 0 && last_extruder_nr_layer >= 0) + { + last_extruder_nr_layer--; + } + first_extruder = extruder_order_per_layer[last_extruder_nr_layer].back().extruder_nr; + } + + const coord_t first_outer_wall_line_width = scene.extruders[first_extruder].settings_.get("wall_line_width_0"); LayerPlan& gcode_layer = *new LayerPlan( storage, layer_nr, z, layer_thickness, - extruder_order.front().extruder_nr, + first_extruder, fan_speed_layer_time_settings_per_extruder, comb_offset_from_outlines, first_outer_wall_line_width, From 2127371789c489da73ecad8a7ce0ed2aadcd9638 Mon Sep 17 00:00:00 2001 From: "c.lamboo" Date: Fri, 23 Feb 2024 07:47:25 +0100 Subject: [PATCH 123/201] analyse all models again --- .github/workflows/gcodeanalyzer.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/gcodeanalyzer.yml b/.github/workflows/gcodeanalyzer.yml index b42ada8717..310469f4a8 100644 --- a/.github/workflows/gcodeanalyzer.yml +++ b/.github/workflows/gcodeanalyzer.yml @@ -178,7 +178,7 @@ jobs: - name: Collect STL-files, run CuraEngine, output GCode-files run: | - for file in `ls ../NightlyTestModels/*.stl | tail -n 3`; + for file in `ls ../NightlyTestModels/*.stl`; do ( time ./build/Release/CuraEngine slice --force-read-parent --force-read-nondefault -v -p -j ../Cura/resources/definitions/ultimaker_s3.def.json -l $file -o ../`basename $file .stl`.gcode ) 2> ../`basename $file .stl`.time done From 3543e011515f53c07c6225136fab7537019f5f5a Mon Sep 17 00:00:00 2001 From: "c.lamboo" Date: Fri, 23 Feb 2024 07:59:06 +0100 Subject: [PATCH 124/201] Re enable uploading gcode analyser data --- .github/workflows/gcodeanalyzer.yml | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/.github/workflows/gcodeanalyzer.yml b/.github/workflows/gcodeanalyzer.yml index 310469f4a8..29c83817de 100644 --- a/.github/workflows/gcodeanalyzer.yml +++ b/.github/workflows/gcodeanalyzer.yml @@ -308,15 +308,15 @@ jobs: shell: python working-directory: GCodeAnalyzer -# - name: Store benchmark result -# uses: benchmark-action/github-action-benchmark@v1 -# with: -# name: CGcodeAnalyzer -# output-file-path: output.json -# gh-repository: github.com/Ultimaker/CuraEngineBenchmarks -# gh-pages-branch: main -# benchmark-data-dir-path: dev/gcodeanalyzer -# tool: customBiggerIsBetter -# github-token: ${{ secrets.CURA_BENCHMARK_PAT }} -# auto-push: true -# max-items-in-chart: 250 + - name: Store benchmark result + uses: benchmark-action/github-action-benchmark@v1 + with: + name: CGcodeAnalyzer + output-file-path: output.json + gh-repository: github.com/Ultimaker/CuraEngineBenchmarks + gh-pages-branch: main + benchmark-data-dir-path: dev/gcodeanalyzer + tool: customBiggerIsBetter + github-token: ${{ secrets.CURA_BENCHMARK_PAT }} + auto-push: true + max-items-in-chart: 250 From 23188b9686079e949217143049967ab3f0d2d5e3 Mon Sep 17 00:00:00 2001 From: "c.lamboo" Date: Fri, 23 Feb 2024 10:10:07 +0100 Subject: [PATCH 125/201] Revert old prime tower = off logic --- src/FffGcodeWriter.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/FffGcodeWriter.cpp b/src/FffGcodeWriter.cpp index c04c3b45d4..9d674301fe 100644 --- a/src/FffGcodeWriter.cpp +++ b/src/FffGcodeWriter.cpp @@ -1568,7 +1568,8 @@ std::vector assert(static_cast(extruder_count) > 0); std::vector ret; std::vector extruder_is_used_on_this_layer = storage.getExtrudersUsed(layer_nr); - PrimeTowerMethod method = mesh_group_settings.get("prime_tower_mode"); + const auto method = mesh_group_settings.get("prime_tower_mode"); + const auto prime_tower_enable = mesh_group_settings.get("prime_tower_enable"); // check if we are on the first layer if (layer_nr == -static_cast(Raft::getTotalExtraLayers())) @@ -1600,6 +1601,11 @@ std::vector { ExtruderPrime prime = ExtruderPrime::None; + if (!prime_tower_enable) + { + break; + } + switch (method) { case PrimeTowerMethod::NORMAL: From 24ce45e5227e6d0bfd914cdf92d05e8c2277ebd8 Mon Sep 17 00:00:00 2001 From: casperlamboo Date: Fri, 23 Feb 2024 09:10:36 +0000 Subject: [PATCH 126/201] Applied clang-format. --- src/FffGcodeWriter.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/FffGcodeWriter.cpp b/src/FffGcodeWriter.cpp index 9d674301fe..7857be155b 100644 --- a/src/FffGcodeWriter.cpp +++ b/src/FffGcodeWriter.cpp @@ -1601,7 +1601,7 @@ std::vector { ExtruderPrime prime = ExtruderPrime::None; - if (!prime_tower_enable) + if (! prime_tower_enable) { break; } From 44c19f1b8d974e67310e4caee7f856fb66affb72 Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Mon, 26 Feb 2024 11:04:14 +0100 Subject: [PATCH 127/201] Fix crash when prime tower disabled CURA-11645 --- src/FffGcodeWriter.cpp | 38 ++++++++++++++++++-------------------- 1 file changed, 18 insertions(+), 20 deletions(-) diff --git a/src/FffGcodeWriter.cpp b/src/FffGcodeWriter.cpp index 7857be155b..3fef253514 100644 --- a/src/FffGcodeWriter.cpp +++ b/src/FffGcodeWriter.cpp @@ -1601,30 +1601,28 @@ std::vector { ExtruderPrime prime = ExtruderPrime::None; - if (! prime_tower_enable) + if (prime_tower_enable) { - break; - } - - switch (method) - { - case PrimeTowerMethod::NORMAL: - if (extruder_is_used_on_this_layer[extruder_nr] && extruder_nr != last_extruder) + switch (method) { - prime = ExtruderPrime::Prime; - } - else if (layer_nr < storage.max_print_height_second_to_last_extruder) - { - prime = ExtruderPrime::Sparse; - } - break; + case PrimeTowerMethod::NORMAL: + if (extruder_is_used_on_this_layer[extruder_nr] && extruder_nr != last_extruder) + { + prime = ExtruderPrime::Prime; + } + else if (layer_nr < storage.max_print_height_second_to_last_extruder) + { + prime = ExtruderPrime::Sparse; + } + break; - case PrimeTowerMethod::INTERLEAVED: - if (extruder_is_used_on_this_layer[extruder_nr] && extruder_nr != last_extruder) - { - prime = ExtruderPrime::Prime; + case PrimeTowerMethod::INTERLEAVED: + if (extruder_is_used_on_this_layer[extruder_nr] && extruder_nr != last_extruder) + { + prime = ExtruderPrime::Prime; + } + break; } - break; } if (extruder_is_used_on_this_layer[extruder_nr] || prime != ExtruderPrime::None) From 68cc5c594a988eddcc73a6aeb444f207bac8e9e9 Mon Sep 17 00:00:00 2001 From: "c.lamboo" Date: Mon, 26 Feb 2024 12:31:09 +0100 Subject: [PATCH 128/201] Fix travel length regression CURA-11653 --- src/FffGcodeWriter.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/FffGcodeWriter.cpp b/src/FffGcodeWriter.cpp index d9803c93be..0db1fc54f1 100644 --- a/src/FffGcodeWriter.cpp +++ b/src/FffGcodeWriter.cpp @@ -1775,12 +1775,15 @@ void FffGcodeWriter::addMeshLayerToGCode( PathOrderOptimizer part_order_optimizer(gcode_layer.getLastPlannedPositionOrStartingPosition(), z_seam_config); for (const SliceLayerPart& part : layer.parts) { + if (part.outline.empty()) + { + continue; + } part_order_optimizer.addPolygon(&part); } - if (part_order_optimizer.vertices_to_paths_.size() > 1) - { - part_order_optimizer.optimize(false); - } + + part_order_optimizer.optimize(false); + for (const PathOrdering& path : part_order_optimizer.paths_) { addMeshPartToGCode(storage, mesh, extruder_nr, mesh_config, *path.vertices_, gcode_layer); From 22e2e51859b7fc5a424f193946c2209ac0fba3ff Mon Sep 17 00:00:00 2001 From: Saumya Jain Date: Tue, 27 Feb 2024 12:48:06 +0100 Subject: [PATCH 129/201] condition to start position while in case of prime-blob enabled CURA-11553 --- src/FffGcodeWriter.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/FffGcodeWriter.cpp b/src/FffGcodeWriter.cpp index 0db1fc54f1..6b0b9eb498 100644 --- a/src/FffGcodeWriter.cpp +++ b/src/FffGcodeWriter.cpp @@ -140,11 +140,15 @@ void FffGcodeWriter::writeGCode(SliceDataStorage& storage, TimeKeeper& time_keep mesh_order_per_extruder.push_back(calculateMeshOrder(storage, extruder_nr)); } } - - // Setting first travel move of the first extruder to the machine start position const auto extruder_settings = Application::getInstance().current_slice_->scene.extruders[gcode.getExtruderNr()].settings_; - Point3LL p(extruder_settings.get("machine_extruder_start_pos_x"), extruder_settings.get("machine_extruder_start_pos_y"), gcode.getPositionZ()); - gcode.writeTravel(p, extruder_settings.get("speed_travel")); + //in case the prime blob is enabled the brim already starts from the closest start position which is blob location + if (!extruder_settings.get("prime_blob_enable")) + { + // Setting first travel move of the first extruder to the machine start position + Point3LL p(extruder_settings.get("machine_extruder_start_pos_x"), extruder_settings.get("machine_extruder_start_pos_y"), gcode.getPositionZ()); + gcode.writeTravel(p, extruder_settings.get("speed_travel")); + } + calculateExtruderOrderPerLayer(storage); calculatePrimeLayerPerExtruder(storage); From 4788e09de9bdecf458707f61e54a7d3ba3ee1f06 Mon Sep 17 00:00:00 2001 From: saumyaj3 Date: Tue, 27 Feb 2024 11:48:38 +0000 Subject: [PATCH 130/201] Applied clang-format. --- src/FffGcodeWriter.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/FffGcodeWriter.cpp b/src/FffGcodeWriter.cpp index 6b0b9eb498..ea94617139 100644 --- a/src/FffGcodeWriter.cpp +++ b/src/FffGcodeWriter.cpp @@ -141,8 +141,8 @@ void FffGcodeWriter::writeGCode(SliceDataStorage& storage, TimeKeeper& time_keep } } const auto extruder_settings = Application::getInstance().current_slice_->scene.extruders[gcode.getExtruderNr()].settings_; - //in case the prime blob is enabled the brim already starts from the closest start position which is blob location - if (!extruder_settings.get("prime_blob_enable")) + // in case the prime blob is enabled the brim already starts from the closest start position which is blob location + if (! extruder_settings.get("prime_blob_enable")) { // Setting first travel move of the first extruder to the machine start position Point3LL p(extruder_settings.get("machine_extruder_start_pos_x"), extruder_settings.get("machine_extruder_start_pos_y"), gcode.getPositionZ()); From e9df099a44b81eba1038145c7acc08416eaaa446 Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Tue, 27 Feb 2024 13:40:54 +0100 Subject: [PATCH 131/201] Basically working inside-only brim --- include/SkirtBrim.h | 40 ++++-- include/settings/EnumSettings.h | 18 +++ include/sliceDataStorage.h | 23 ++-- include/utils/polygon.h | 15 ++ src/SkirtBrim.cpp | 236 ++++++++++++++++++++++---------- src/TreeModelVolumes.cpp | 3 +- src/settings/Settings.cpp | 18 +++ src/sliceDataStorage.cpp | 47 ++++--- 8 files changed, 286 insertions(+), 114 deletions(-) diff --git a/include/SkirtBrim.h b/include/SkirtBrim.h index af8cbe9f6e..e84d547e1b 100644 --- a/include/SkirtBrim.h +++ b/include/SkirtBrim.h @@ -29,14 +29,16 @@ class SkirtBrim { Offset( const std::variant& reference_outline_or_index, - const bool external_only, + const bool outside, + const bool inside, const coord_t offset_value, const coord_t total_offset, const size_t inset_idx, - const int extruder_nr, + const size_t extruder_nr, const bool is_last) : reference_outline_or_index_(reference_outline_or_index) - , external_only_(external_only) + , outside_(outside) + , inside_(inside) , offset_value_(offset_value) , total_offset_(total_offset) , inset_idx_(inset_idx) @@ -46,14 +48,29 @@ class SkirtBrim } std::variant reference_outline_or_index_; - bool external_only_; //!< Wether to only offset outward from the reference polygons + bool outside_; //!< Wether to offset outward from the reference polygons + bool inside_; //!< Wether to offset inward from the reference polygons coord_t offset_value_; //!< Distance by which to offset from the reference coord_t total_offset_; //!< Total distance from the model int inset_idx_; //!< The outset index of this brimline - int extruder_nr_; //!< The extruder by which to print this brim line + size_t extruder_nr_; //!< The extruder by which to print this brim line bool is_last_; //!< Whether this is the last planned offset for this extruder. }; + /*! + * Container to store the pre-extracted settings of an extruder + */ + struct ExtruderConfig + { + bool extruder_is_used_; //!< Whether the extruder is actually used in this print + bool outside_polys_; //!< Whether to generate brim on the outside + bool inside_polys_; //!< Whether to generate brim on the inside + coord_t line_widths_; //!< The skirt/brim line width + coord_t skirt_brim_minimal_length_; //!< The minimal brim length + int line_count_; //!< The (minimal) number of brim lines to generate + coord_t gap_; //!< The gap between the part and the first brim/skirt line + }; + /*! * Defines an order on offsets (potentially from different extruders) based on how far the offset is from the original outline. */ @@ -68,15 +85,10 @@ class SkirtBrim const bool has_ooze_shield_; //!< Whether the meshgroup has an ooze shield const bool has_draft_shield_; //!< Whether the meshgroup has a draft shield const std::vector& extruders_; //!< The extruders of the current slice - const int extruder_count_; //!< The total number of extruders - const std::vector extruder_is_used_; //!< For each extruder whether it is actually used in this print - int first_used_extruder_nr_; //!< The first extruder which is used + size_t extruder_count_; //!< The total number of extruders + size_t first_used_extruder_nr_; //!< The first extruder which is used int skirt_brim_extruder_nr_; //!< The extruder with which the skirt/brim is printed or -1 if printed with both - std::vector external_polys_only_; //!< For each extruder whether to only generate brim on the outside - std::vector line_widths_; //!< For each extruder the skirt/brim line width - std::vector skirt_brim_minimal_length_; //!< For each extruder the minimal brim length - std::vector line_count_; //!< For each extruder the (minimal) number of brim lines to generate - std::vector gap_; //!< For each extruder the gap between the part and the first brim/skirt line + std::vector extruders_configs_; //!< The brim setup for each extruder public: /*! @@ -158,7 +170,7 @@ class SkirtBrim * \param extruder_nr The extruder for which to compute disallowed areas * \return The disallowed areas */ - Polygons getInternalHoleExclusionArea(const Polygons& outline, const int extruder_nr); + Polygons getInternalHoleExclusionArea(const Polygons& outline, const int extruder_nr) const; /*! * Generate a brim line with offset parameters given by \p offset from the \p starting_outlines and store it in the \ref storage. diff --git a/include/settings/EnumSettings.h b/include/settings/EnumSettings.h index 7b8c970db4..2632fc8957 100644 --- a/include/settings/EnumSettings.h +++ b/include/settings/EnumSettings.h @@ -267,6 +267,24 @@ enum class PrimeTowerMethod NORMAL, }; +/*! + * Brim location, inside, outside or both + */ +enum class BrimLocation +{ + OUTSIDE = 0x01, // Brim only on the outside of the model + INSIDE = 0x02, // Brim only on the inside of the model + EVERYWHERE = 0x03, // Brim on both the outside and inside of the model +}; + +/*! + * Convenience binary operator to allow testing brim location easily, like (actual_location & BrimLocation::OUTSIDE) + */ +static int operator&(BrimLocation location1, BrimLocation location2) +{ + return static_cast(location1) & static_cast(location2); +} + } // namespace cura #endif // ENUMSETTINGS_H diff --git a/include/sliceDataStorage.h b/include/sliceDataStorage.h index e18a3783d3..f6b89273d0 100644 --- a/include/sliceDataStorage.h +++ b/include/sliceDataStorage.h @@ -186,19 +186,21 @@ class SliceLayer /*! * Get the all outlines of all layer parts in this layer. * - * \param external_polys_only Whether to only include the outermost outline of each layer part + * \param outer_polys Whether to include the outermost outline of each layer part + * \param inner_polys Whether to include the inner outlines (holes) of each layer part * \return A collection of all the outline polygons */ - Polygons getOutlines(bool external_polys_only = false) const; + Polygons getOutlines(bool outer_polys = true, bool inner_polys = true) const; /*! * Get the all outlines of all layer parts in this layer. * Add those polygons to @p result. * - * \param external_polys_only Whether to only include the outermost outline of each layer part + * \param outer_polys Whether to include the outermost outline of each layer part + * \param inner_polys Whether to include the inner outlines (holes) of each layer part * \param result The result: a collection of all the outline polygons */ - void getOutlines(Polygons& result, bool external_polys_only = false) const; + void getOutlines(Polygons& result, bool outer_polys = true, bool inner_polys = true) const; ~SliceLayer(); }; @@ -391,12 +393,17 @@ class SliceDataStorage : public NoCopy * \param include_support Whether to include support in the outline. * \param include_prime_tower Whether to include the prime tower in the * outline. - * \param external_polys_only Whether to disregard all hole polygons. + * \param outer_polys Whether to include the outline polygons. + * \param inner_polys Whether to include all hole polygons. * \param extruder_nr (optional) only give back outlines for this extruder (where the walls are printed with this extruder) */ - Polygons - getLayerOutlines(const LayerIndex layer_nr, const bool include_support, const bool include_prime_tower, const bool external_polys_only = false, const int extruder_nr = -1) - const; + Polygons getLayerOutlines( + const LayerIndex layer_nr, + const bool include_support, + const bool include_prime_tower, + const bool outer_polys = true, + const bool inner_polys = true, + const int extruder_nr = -1) const; /*! * Get the extruders used. diff --git a/include/utils/polygon.h b/include/utils/polygon.h index dbf0a97a3d..52f7cdd0ac 100644 --- a/include/utils/polygon.h +++ b/include/utils/polygon.h @@ -1194,6 +1194,11 @@ class Polygons */ double area() const; + void reverse() + { + ClipperLib::ReversePaths(paths); + } + /*! * Smooth out small perpendicular segments * Smoothing is performed by removing the inner most vertex of a line segment smaller than \p remove_length @@ -1566,6 +1571,16 @@ class PolygonsPart : public Polygons return paths[0]; } + Polygons innerPolygons() const + { + Polygons ret; + if (size() > 1) + { + ret.paths = ClipperLib::Paths(std::next(paths.begin()), paths.end()); + } + return ret; + } + /*! * Tests whether the given point is inside this polygon part. * \param p The point to test whether it is inside. diff --git a/src/SkirtBrim.cpp b/src/SkirtBrim.cpp index a2b67503ec..1f5f671101 100644 --- a/src/SkirtBrim.cpp +++ b/src/SkirtBrim.cpp @@ -25,17 +25,23 @@ SkirtBrim::SkirtBrim(SliceDataStorage& storage) , has_draft_shield_(storage.draft_protection_shield.size() > 0) , extruders_(Application::getInstance().current_slice_->scene.extruders) , extruder_count_(extruders_.size()) - , extruder_is_used_(storage.getExtrudersUsed()) + , extruders_configs_(extruder_count_) { - first_used_extruder_nr_ = 0; - for (int extruder_nr = 0; extruder_nr < extruder_count_; extruder_nr++) + const std::vector used_extruders = storage.getExtrudersUsed(); + + std::optional first_used_extruder_nr; + for (size_t extruder_nr = 0; extruder_nr < extruder_count_; extruder_nr++) { - if (extruder_is_used_[extruder_nr]) + const bool extruder_is_used = used_extruders[extruder_nr]; + extruders_configs_[extruder_nr].extruder_is_used_ = extruder_is_used; + if (extruder_is_used && ! first_used_extruder_nr.has_value()) { - first_used_extruder_nr_ = extruder_nr; - break; + first_used_extruder_nr = extruder_nr; } } + first_used_extruder_nr_ = first_used_extruder_nr.value_or(0); + + skirt_brim_extruder_nr_ = Application::getInstance().current_slice_->scene.current_mesh_group->settings.get("skirt_brim_extruder_nr"); if (skirt_brim_extruder_nr_ == -1 && adhesion_type_ == EPlatformAdhesion::SKIRT) { // Skirt is always printed with all extruders in order to satisfy minimum legnth constraint @@ -43,24 +49,23 @@ SkirtBrim::SkirtBrim(SliceDataStorage& storage) skirt_brim_extruder_nr_ = first_used_extruder_nr_; } - line_widths_.resize(extruder_count_); - skirt_brim_minimal_length_.resize(extruder_count_); - external_polys_only_.resize(extruder_count_); - line_count_.resize(extruder_count_); - gap_.resize(extruder_count_); - for (int extruder_nr = 0; extruder_nr < extruder_count_; extruder_nr++) + for (size_t extruder_nr = 0; extruder_nr < extruder_count_; extruder_nr++) { - if (! extruder_is_used_[extruder_nr]) + ExtruderConfig& extruder_config = extruders_configs_[extruder_nr]; + if (! extruder_config.extruder_is_used_) { continue; } - const ExtruderTrain& extruder = extruders_[extruder_nr]; - line_widths_[extruder_nr] = extruder.settings_.get("skirt_brim_line_width") * extruder.settings_.get("initial_layer_line_width_factor"); - skirt_brim_minimal_length_[extruder_nr] = extruder.settings_.get("skirt_brim_minimal_length"); - external_polys_only_[extruder_nr] = adhesion_type_ == EPlatformAdhesion::SKIRT || extruder.settings_.get("brim_outside_only"); - line_count_[extruder_nr] = extruder.settings_.get(adhesion_type_ == EPlatformAdhesion::BRIM ? "brim_line_count" : "skirt_line_count"); - gap_[extruder_nr] = extruder.settings_.get(adhesion_type_ == EPlatformAdhesion::BRIM ? "brim_gap" : "skirt_gap"); + const ExtruderTrain& extruder = extruders_[extruder_nr]; + const BrimLocation location = extruder.settings_.get("brim_location"); + + extruder_config.line_widths_ = extruder.settings_.get("skirt_brim_line_width") * extruder.settings_.get("initial_layer_line_width_factor"); + extruder_config.skirt_brim_minimal_length_ = extruder.settings_.get("skirt_brim_minimal_length"); + extruder_config.outside_polys_ = adhesion_type_ == EPlatformAdhesion::SKIRT || (location & BrimLocation::OUTSIDE); + extruder_config.inside_polys_ = adhesion_type_ == EPlatformAdhesion::BRIM && (location & BrimLocation::INSIDE); + extruder_config.line_count_ = extruder.settings_.get(adhesion_type_ == EPlatformAdhesion::BRIM ? "brim_line_count" : "skirt_line_count"); + extruder_config.gap_ = extruder.settings_.get(adhesion_type_ == EPlatformAdhesion::BRIM ? "brim_gap" : "skirt_gap"); } } @@ -76,7 +81,7 @@ std::vector SkirtBrim::generateBrimOffsetPlan(std::vector SkirtBrim::generateBrimOffsetPlan(std::vector= 0 && extruder_nr != skirt_brim_extruder_nr_) || starting_outlines[extruder_nr].empty()) + const ExtruderConfig& extruder_config = extruders_configs_[extruder_nr]; + + if (! extruder_config.extruder_is_used_ || (skirt_brim_extruder_nr_ >= 0 && extruder_nr != skirt_brim_extruder_nr_) || starting_outlines[extruder_nr].empty()) { continue; // only include offsets for brim extruder } - for (int line_idx = 0; line_idx < line_count_[extruder_nr]; line_idx++) + for (int line_idx = 0; line_idx < extruder_config.line_count_; line_idx++) { - const bool is_last = line_idx == line_count_[extruder_nr] - 1; - coord_t offset = gap_[extruder_nr] + line_widths_[extruder_nr] / 2 + line_widths_[extruder_nr] * line_idx; + const bool is_last = line_idx == extruder_config.line_count_ - 1; + coord_t offset = extruder_config.gap_ + extruder_config.line_widths_ / 2 + extruder_config.line_widths_ * line_idx; if (line_idx == 0) { - all_brim_offsets.emplace_back(&starting_outlines[extruder_nr], external_polys_only_[extruder_nr], offset, offset, line_idx, extruder_nr, is_last); + all_brim_offsets + .emplace_back(&starting_outlines[extruder_nr], extruder_config.outside_polys_, extruder_config.inside_polys_, offset, offset, line_idx, extruder_nr, is_last); } else { - all_brim_offsets.emplace_back(line_idx - 1, external_polys_only_[extruder_nr], line_widths_[extruder_nr], offset, line_idx, extruder_nr, is_last); + all_brim_offsets.emplace_back( + line_idx - 1, + extruder_config.outside_polys_, + extruder_config.inside_polys_, + extruder_config.line_widths_, + offset, + line_idx, + extruder_nr, + is_last); } } } @@ -119,23 +135,36 @@ void SkirtBrim::generate() constexpr bool include_support = true; const bool include_prime_tower = adhesion_type_ == EPlatformAdhesion::SKIRT; const bool has_prime_tower = storage_.primeTower.enabled_; - Polygons covered_area = storage_.getLayerOutlines(layer_nr, include_support, include_prime_tower, /*external_polys_only*/ false); + Polygons covered_area = storage_.getLayerOutlines(layer_nr, include_support, include_prime_tower); std::vector allowed_areas_per_extruder(extruder_count_); for (int extruder_nr = 0; extruder_nr < extruder_count_; extruder_nr++) { - if (! extruder_is_used_[extruder_nr]) + const ExtruderConfig& extruder_config = extruders_configs_[extruder_nr]; + + if (! extruder_config.extruder_is_used_) { continue; } - Polygons machine_area = storage_.getMachineBorder(extruder_nr); - allowed_areas_per_extruder[extruder_nr] = machine_area.difference(covered_area); - if (external_polys_only_[extruder_nr]) + + if (! extruder_config.outside_polys_ && extruder_config.inside_polys_) // inside only { - // Expand covered area on inside of holes when external_only is enabled for any extruder, - // so that the brim lines don't overlap with the holes by half the line width - allowed_areas_per_extruder[extruder_nr] = allowed_areas_per_extruder[extruder_nr].difference(getInternalHoleExclusionArea(covered_area, extruder_nr)); + allowed_areas_per_extruder[extruder_nr] = covered_area.getEmptyHoles(); } + else + { + Polygons machine_area = storage_.getMachineBorder(extruder_nr); + allowed_areas_per_extruder[extruder_nr] = machine_area.difference(covered_area); + if (extruder_config.outside_polys_ && ! extruder_config.inside_polys_) // outside only + { + // Expand covered area on inside of holes when external_only is enabled for any extruder, + // so that the brim lines don't overlap with the holes by half the line width + allowed_areas_per_extruder[extruder_nr] = allowed_areas_per_extruder[extruder_nr].difference(getInternalHoleExclusionArea(covered_area, extruder_nr)); + } + } + + SVG svg("/tmp/allowed_area.svg", AABB(storage_.getMachineBorder(extruder_nr))); + svg.writePolygons(allowed_areas_per_extruder[extruder_nr]); if (has_prime_tower) { @@ -202,7 +231,9 @@ std::vector SkirtBrim::generatePrimaryBrim(std::vector& all_bri } total_length[offset.extruder_nr_] += added_length; - if (offset.is_last_ && total_length[offset.extruder_nr_] < skirt_brim_minimal_length_[offset.extruder_nr_] + const ExtruderConfig& extruder_config = extruders_configs_[offset.extruder_nr_]; + + if (offset.is_last_ && total_length[offset.extruder_nr_] < extruder_config.skirt_brim_minimal_length_ && // This was the last offset of this extruder, but the brim lines don't meet minimal length yet total_length[offset.extruder_nr_] > 0u // No lines got added; we have no extrusion lines to build on ) @@ -211,9 +242,10 @@ std::vector SkirtBrim::generatePrimaryBrim(std::vector& all_bri constexpr bool is_last = true; all_brim_offsets.emplace_back( offset.inset_idx_, - external_polys_only_[offset.extruder_nr_], - line_widths_[offset.extruder_nr_], - offset.total_offset_ + line_widths_[offset.extruder_nr_], + extruder_config.outside_polys_, + extruder_config.inside_polys_, + extruder_config.line_widths_, + offset.total_offset_ + extruder_config.line_widths_, offset.inset_idx_ + 1, offset.extruder_nr_, is_last); @@ -223,12 +255,13 @@ std::vector SkirtBrim::generatePrimaryBrim(std::vector& all_bri return total_length; } -Polygons SkirtBrim::getInternalHoleExclusionArea(const Polygons& outline, const int extruder_nr) +Polygons SkirtBrim::getInternalHoleExclusionArea(const Polygons& outline, const int extruder_nr) const { assert(extruder_nr >= 0); const Settings& settings = Application::getInstance().current_slice_->scene.extruders[extruder_nr].settings_; // If brim is external_only, the distance between the external brim of a part inside a hole and the inside hole of the outer part. const coord_t hole_brim_distance = settings.get("brim_inside_margin"); + const ExtruderConfig& extruder_config = extruders_configs_[extruder_nr]; Polygons ret; std::vector parts = outline.splitIntoParts(); @@ -238,7 +271,7 @@ Polygons SkirtBrim::getInternalHoleExclusionArea(const Polygons& outline, const { Polygon hole_poly = part[hole_idx]; hole_poly.reverse(); - Polygons disallowed_region = hole_poly.offset(10u).difference(hole_poly.offset(-line_widths_[extruder_nr] / 2 - hole_brim_distance)); + Polygons disallowed_region = hole_poly.offset(10u).difference(hole_poly.offset(-extruder_config.line_widths_ / 2 - hole_brim_distance)); ret = ret.unionPolygons(disallowed_region); } } @@ -247,14 +280,19 @@ Polygons SkirtBrim::getInternalHoleExclusionArea(const Polygons& outline, const coord_t SkirtBrim::generateOffset(const Offset& offset, Polygons& covered_area, std::vector& allowed_areas_per_extruder, SkirtBrimLine& result) { + SVG svg("/tmp/polylines.svg", AABB(allowed_areas_per_extruder[offset.extruder_nr_])); + // svg.writePolylines(allowed_areas_per_extruder[offset.extruder_nr_], SVG::Color::BLACK); + coord_t length_added; Polygons brim; Polygons newly_covered; + const ExtruderConfig& extruder_config = extruders_configs_[offset.extruder_nr_]; { if (std::holds_alternative(offset.reference_outline_or_index_)) { Polygons* reference_outline = std::get(offset.reference_outline_or_index_); - if (offset.external_only_) + // svg.writePolylines(*reference_outline, SVG::Color::RED); + if (offset.outside_ && ! offset.inside_) // outside only { // prevent unioning of external polys enclosed by other parts, e.g. a small part inside a hollow cylinder. for (Polygons& polys : reference_outline->sortByNesting()) { // offset external polygons of islands contained within another part in each batch @@ -266,24 +304,42 @@ coord_t SkirtBrim::generateOffset(const Offset& offset, Polygons& covered_area, } } brim.add(polys.offset(offset.offset_value_, ClipperLib::jtRound)); - newly_covered.add(polys.offset(offset.offset_value_ + line_widths_[offset.extruder_nr_] / 2, ClipperLib::jtRound)); - for (PolygonRef poly : polys) - { - poly.reverse(); - } + newly_covered.add(polys.offset(offset.offset_value_ + extruder_config.line_widths_ / 2, ClipperLib::jtRound)); + polys.reverse(); newly_covered.add(polys); // don't remove area inside external polygon } } + else if (! offset.outside_ && offset.inside_) // inside only + { + // We have to use a negative offset in this case, because ClipperLib won't recognize holes without an actual outside + brim = reference_outline->offset(-offset.offset_value_, ClipperLib::jtRound); + brim.reverse(); + + newly_covered = brim.offsetPolyLine(extruder_config.line_widths_ / 2, ClipperLib::jtRound); + + /*newly_covered = reference_outline->offset(-(offset.offset_value_ + extruder_config.line_widths_ / 2), ClipperLib::jtRound); + newly_covered.reverse();*/ + } else { brim = reference_outline->offset(offset.offset_value_, ClipperLib::jtRound); - newly_covered = reference_outline->offset(offset.offset_value_ + line_widths_[offset.extruder_nr_] / 2, ClipperLib::jtRound); + newly_covered = reference_outline->offset(offset.offset_value_ + extruder_config.line_widths_ / 2, ClipperLib::jtRound); } } else { const int reference_idx = std::get(offset.reference_outline_or_index_); - auto offset_dist = line_widths_[offset.extruder_nr_]; + coord_t offset_dist = extruder_config.line_widths_; + coord_t offset_covered = offset_dist / 2; + + if (! offset.outside_ && offset.inside_) // inside only + { + // offset_dist = -offset_dist; + // offset_covered = -offset_covered; + } + + svg.writePolylines(storage_.skirt_brim[offset.extruder_nr_][reference_idx].closed_polygons, SVG::Color::GREEN); + svg.writePolylines(storage_.skirt_brim[offset.extruder_nr_][reference_idx].open_polylines, SVG::Color::GREEN); Polygons local_brim; auto closed_polygons_brim = storage_.skirt_brim[offset.extruder_nr_][reference_idx].closed_polygons.offsetPolyLine(offset_dist, ClipperLib::jtRound, true); @@ -295,17 +351,20 @@ coord_t SkirtBrim::generateOffset(const Offset& offset, Polygons& covered_area, brim.add(local_brim); - newly_covered.add(local_brim.offset(offset_dist / 2, ClipperLib::jtRound)); + newly_covered.add(local_brim.offset(offset_covered, ClipperLib::jtRound)); } } + // svg.writePolylines(brim, SVG::Color::BLUE); + // svg.writePolylines(newly_covered, SVG::Color::MAGENTA); + { // limit brim lines to allowed areas, stitch them and store them in the result brim = Simplify(Application::getInstance().current_slice_->scene.extruders[offset.extruder_nr_].settings_).polygon(brim); brim.toPolylines(); Polygons brim_lines = allowed_areas_per_extruder[offset.extruder_nr_].intersectionPolyLines(brim, false); length_added = brim_lines.polyLineLength(); - const coord_t max_stitch_distance = line_widths_[offset.extruder_nr_]; + const coord_t max_stitch_distance = extruder_config.line_widths_; PolylineStitcher::stitch(brim_lines, result.open_polylines, result.closed_polygons, max_stitch_distance); // clean up too small lines @@ -326,12 +385,19 @@ coord_t SkirtBrim::generateOffset(const Offset& offset, Polygons& covered_area, { // update allowed_areas_per_extruder for (int extruder_nr = 0; extruder_nr < extruder_count_; extruder_nr++) { - if (! extruder_is_used_[extruder_nr]) + if (! extruders_configs_[extruder_nr].extruder_is_used_) { continue; } + svg.writePolylines(covered_area, SVG::Color::BLACK); + svg.writePolylines(newly_covered, SVG::Color::GRAY); + svg.writePolylines(newly_covered.unionPolygons(), SVG::Color::BLUE); covered_area = covered_area.unionPolygons(newly_covered.unionPolygons()); + svg.writePolylines(covered_area, SVG::Color::RED); + + svg.writePolylines(allowed_areas_per_extruder[extruder_nr], SVG::Color::MAGENTA); allowed_areas_per_extruder[extruder_nr] = allowed_areas_per_extruder[extruder_nr].difference(covered_area); + svg.writePolylines(allowed_areas_per_extruder[extruder_nr], SVG::Color::ORANGE); } } return length_added; @@ -347,9 +413,8 @@ Polygons SkirtBrim::getFirstLayerOutline(const int extruder_nr /* = -1 */) { reference_extruder_nr = extruder_nr; } - const int primary_line_count = line_count_[reference_extruder_nr]; - const bool external_only - = adhesion_type_ == EPlatformAdhesion::SKIRT || external_polys_only_[reference_extruder_nr]; // Whether to include holes or not. Skirt doesn't have any holes. + const ExtruderConfig& reference_extruder_config = extruders_configs_[reference_extruder_nr]; + const int primary_line_count = reference_extruder_config.line_count_; const bool has_prime_tower = storage_.primeTower.enabled_; const LayerIndex layer_nr = 0; if (adhesion_type_ == EPlatformAdhesion::SKIRT) @@ -370,10 +435,15 @@ Polygons SkirtBrim::getFirstLayerOutline(const int extruder_nr /* = -1 */) for (int i_layer = layer_nr; i_layer < skirt_height; ++i_layer) { - for (const auto& extruder : Application::getInstance().current_slice_->scene.extruders) + for (const ExtruderTrain& extruder : Application::getInstance().current_slice_->scene.extruders) { - first_layer_outline - = first_layer_outline.unionPolygons(storage_.getLayerOutlines(i_layer, include_support, include_prime_tower, external_only, extruder.extruder_nr_)); + first_layer_outline = first_layer_outline.unionPolygons(storage_.getLayerOutlines( + i_layer, + include_support, + include_prime_tower, + reference_extruder_config.outside_polys_, + reference_extruder_config.inside_polys_, + extruder.extruder_nr_)); } } @@ -392,8 +462,8 @@ Polygons SkirtBrim::getFirstLayerOutline(const int extruder_nr /* = -1 */) shields = shields.unionPolygons(storage_.draft_protection_shield); } first_layer_outline = first_layer_outline.unionPolygons(shields.offset( - line_widths_[reference_extruder_nr] / 2 // because the shield is printed *on* the stored polygons; not inside hteir area - - gap_[reference_extruder_nr])); // so that when we apply the gap we will end up right next to the shield + reference_extruder_config.line_widths_ / 2 // because the shield is printed *on* the stored polygons; not inside hteir area + - reference_extruder_config.gap_)); // so that when we apply the gap we will end up right next to the shield // NOTE: offsetting by -gap here and by +gap in the main brim algorithm effectively performs a morphological close, // so in some cases with a large skirt gap and small models and small shield distance // the skirt lines can cross the shield lines. @@ -404,15 +474,21 @@ Polygons SkirtBrim::getFirstLayerOutline(const int extruder_nr /* = -1 */) { // add brim underneath support by removing support where there's brim around the model constexpr bool include_support = false; // Include manually below. constexpr bool include_prime_tower = false; // Not included. - constexpr bool external_outlines_only = false; // Remove manually below. - first_layer_outline = storage_.getLayerOutlines(layer_nr, include_support, include_prime_tower, external_outlines_only, extruder_nr); + constexpr bool outer_polys = true; // Remove manually below. + constexpr bool inner_polys = true; // Remove manually below. + first_layer_outline = storage_.getLayerOutlines(layer_nr, include_support, include_prime_tower, outer_polys, inner_polys, extruder_nr); first_layer_outline = first_layer_outline.unionPolygons(); // To guard against overlapping outlines, which would produce holes according to the even-odd rule. Polygons first_layer_empty_holes; - if (external_only) + if (! reference_extruder_config.inside_polys_) { first_layer_empty_holes = first_layer_outline.getEmptyHoles(); first_layer_outline = first_layer_outline.removeEmptyHoles(); } + else if (! reference_extruder_config.outside_polys_) + { + first_layer_outline = first_layer_outline.getEmptyHoles(); + } + if (storage_.support.generated && primary_line_count > 0 && ! storage_.support.supportLayers.empty() && (extruder_nr == -1 || extruder_nr == global_settings.get("support_infill_extruder_nr"))) { // remove model-brim from support @@ -427,11 +503,11 @@ Polygons SkirtBrim::getFirstLayerOutline(const int extruder_nr /* = -1 */) // || || ||[]|| > expand to fit an extra brim line // |+-+| |+--+| // +---+ +----+ - const coord_t primary_extruder_skirt_brim_line_width = line_widths_[reference_extruder_nr]; + const coord_t primary_extruder_skirt_brim_line_width = reference_extruder_config.line_widths_; Polygons model_brim_covered_area = first_layer_outline.offset( primary_extruder_skirt_brim_line_width * (primary_line_count + primary_line_count % 2), ClipperLib::jtRound); // always leave a gap of an even number of brim lines, so that it fits if it's generating brim from both sides - if (external_only) + if (! reference_extruder_config.inside_polys_) { // don't remove support within empty holes where no brim is generated. model_brim_covered_area.add(first_layer_empty_holes); } @@ -469,11 +545,13 @@ void SkirtBrim::generateShieldBrim(Polygons& brim_covered_area, std::vector(storage_.skirt_brim[extruder_nr].size() - 1); - offset_from_reference = line_widths_[extruder_nr]; + offset_from_reference = extruder_config.line_widths_; } - constexpr bool external_only = false; // The reference outline may contain both outlines and hole polygons. - Offset extra_offset(ref_polys_or_idx, external_only, offset_from_reference, bogus_total_offset, storage_.skirt_brim[extruder_nr].size(), extruder_nr, is_last); + constexpr bool outside_polys = true; + constexpr bool inside_polys = true; // The reference outline may contain both outlines and hole polygons. + Offset extra_offset( + ref_polys_or_idx, + outside_polys, + inside_polys, + offset_from_reference, + bogus_total_offset, + storage_.skirt_brim[extruder_nr].size(), + extruder_nr, + is_last); storage_.skirt_brim[extruder_nr].emplace_back(); SkirtBrimLine& output_location = storage_.skirt_brim[extruder_nr].back(); diff --git a/src/TreeModelVolumes.cpp b/src/TreeModelVolumes.cpp index fa8fe4bedf..c2a610b4c7 100644 --- a/src/TreeModelVolumes.cpp +++ b/src/TreeModelVolumes.cpp @@ -572,7 +572,6 @@ Polygons TreeModelVolumes::extractOutlineFromMesh(const SliceMeshStorage& mesh, { // Similar to SliceDataStorage.getLayerOutlines but only for one mesh instead of for all of them. - constexpr bool external_polys_only = false; Polygons total; if (mesh.settings.get("infill_mesh") || mesh.settings.get("anti_overhang_mesh")) @@ -581,7 +580,7 @@ Polygons TreeModelVolumes::extractOutlineFromMesh(const SliceMeshStorage& mesh, } const SliceLayer& layer = mesh.layers[layer_idx]; - layer.getOutlines(total, external_polys_only); + layer.getOutlines(total); if (mesh.settings.get("magic_mesh_surface_mode") != ESurfaceMode::NORMAL) { total = total.unionPolygons(layer.openPolyLines.offsetPolyLine(FUDGE_LENGTH * 2)); diff --git a/src/settings/Settings.cpp b/src/settings/Settings.cpp index b94364d9e5..7a299d751c 100644 --- a/src/settings/Settings.cpp +++ b/src/settings/Settings.cpp @@ -696,6 +696,24 @@ PrimeTowerMethod Settings::get(const std::string& key) const } } +template<> +BrimLocation Settings::get(const std::string& key) const +{ + const std::string& value = get(key); + if (value == "everywhere") + { + return BrimLocation::EVERYWHERE; + } + else if (value == "inside") + { + return BrimLocation::INSIDE; + } + else // Default. + { + return BrimLocation::OUTSIDE; + } +} + template<> std::vector Settings::get>(const std::string& key) const { diff --git a/src/sliceDataStorage.cpp b/src/sliceDataStorage.cpp index 3f94495d89..3e8aa2999c 100644 --- a/src/sliceDataStorage.cpp +++ b/src/sliceDataStorage.cpp @@ -68,24 +68,28 @@ SliceLayer::~SliceLayer() { } -Polygons SliceLayer::getOutlines(bool external_polys_only) const +Polygons SliceLayer::getOutlines(bool outer_polys, bool inner_polys) const { Polygons ret; - getOutlines(ret, external_polys_only); + getOutlines(ret, outer_polys, inner_polys); return ret; } -void SliceLayer::getOutlines(Polygons& result, bool external_polys_only) const +void SliceLayer::getOutlines(Polygons& result, bool outer_polys, bool inner_polys) const { for (const SliceLayerPart& part : parts) { - if (external_polys_only) + if (outer_polys && inner_polys) + { + result.add(part.print_outline); + } + else if (outer_polys) { result.add(part.outline.outerPolygon()); } - else + else if (inner_polys) { - result.add(part.print_outline); + result.add(part.outline.innerPolygons()); } } } @@ -266,9 +270,13 @@ SliceDataStorage::SliceDataStorage() machine_size.include(machine_max); } -Polygons - SliceDataStorage::getLayerOutlines(const LayerIndex layer_nr, const bool include_support, const bool include_prime_tower, const bool external_polys_only, const int extruder_nr) - const +Polygons SliceDataStorage::getLayerOutlines( + const LayerIndex layer_nr, + const bool include_support, + const bool include_prime_tower, + const bool outer_polys, + const bool inner_polys, + const int extruder_nr) const { const Settings& mesh_group_settings = Application::getInstance().current_slice_->scene.current_mesh_group->settings; @@ -303,20 +311,27 @@ Polygons if (include_support && use_current_extruder_for_raft) { - if (external_polys_only) + if (outer_polys && inner_polys) + { + return *raftOutline; + } + else { std::vector parts = raftOutline->splitIntoParts(); Polygons result; for (PolygonsPart& part : parts) { - result.add(part.outerPolygon()); + if (outer_polys) + { + result.add(part.outerPolygon()); + } + else if (inner_polys) + { + result.add(part.innerPolygons()); + } } return result; } - else - { - return *raftOutline; - } } else { @@ -338,7 +353,7 @@ Polygons continue; } const SliceLayer& layer = mesh->layers[layer_nr]; - layer.getOutlines(total, external_polys_only); + layer.getOutlines(total, outer_polys, inner_polys); if (mesh->settings.get("magic_mesh_surface_mode") != ESurfaceMode::NORMAL) { total = total.unionPolygons(layer.openPolyLines.offsetPolyLine(MM2INT(0.1))); From cba3c2fe11f778ad9d9dffe89f4b59952d75331e Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Tue, 27 Feb 2024 13:47:42 +0100 Subject: [PATCH 132/201] Revert unnecessary changes CURA-9838 --- include/sliceDataStorage.h | 23 +++++++------------ src/SkirtBrim.cpp | 13 +++-------- src/sliceDataStorage.cpp | 47 +++++++++++++------------------------- 3 files changed, 27 insertions(+), 56 deletions(-) diff --git a/include/sliceDataStorage.h b/include/sliceDataStorage.h index f6b89273d0..e18a3783d3 100644 --- a/include/sliceDataStorage.h +++ b/include/sliceDataStorage.h @@ -186,21 +186,19 @@ class SliceLayer /*! * Get the all outlines of all layer parts in this layer. * - * \param outer_polys Whether to include the outermost outline of each layer part - * \param inner_polys Whether to include the inner outlines (holes) of each layer part + * \param external_polys_only Whether to only include the outermost outline of each layer part * \return A collection of all the outline polygons */ - Polygons getOutlines(bool outer_polys = true, bool inner_polys = true) const; + Polygons getOutlines(bool external_polys_only = false) const; /*! * Get the all outlines of all layer parts in this layer. * Add those polygons to @p result. * - * \param outer_polys Whether to include the outermost outline of each layer part - * \param inner_polys Whether to include the inner outlines (holes) of each layer part + * \param external_polys_only Whether to only include the outermost outline of each layer part * \param result The result: a collection of all the outline polygons */ - void getOutlines(Polygons& result, bool outer_polys = true, bool inner_polys = true) const; + void getOutlines(Polygons& result, bool external_polys_only = false) const; ~SliceLayer(); }; @@ -393,17 +391,12 @@ class SliceDataStorage : public NoCopy * \param include_support Whether to include support in the outline. * \param include_prime_tower Whether to include the prime tower in the * outline. - * \param outer_polys Whether to include the outline polygons. - * \param inner_polys Whether to include all hole polygons. + * \param external_polys_only Whether to disregard all hole polygons. * \param extruder_nr (optional) only give back outlines for this extruder (where the walls are printed with this extruder) */ - Polygons getLayerOutlines( - const LayerIndex layer_nr, - const bool include_support, - const bool include_prime_tower, - const bool outer_polys = true, - const bool inner_polys = true, - const int extruder_nr = -1) const; + Polygons + getLayerOutlines(const LayerIndex layer_nr, const bool include_support, const bool include_prime_tower, const bool external_polys_only = false, const int extruder_nr = -1) + const; /*! * Get the extruders used. diff --git a/src/SkirtBrim.cpp b/src/SkirtBrim.cpp index 1f5f671101..e7b038a0d4 100644 --- a/src/SkirtBrim.cpp +++ b/src/SkirtBrim.cpp @@ -437,13 +437,7 @@ Polygons SkirtBrim::getFirstLayerOutline(const int extruder_nr /* = -1 */) { for (const ExtruderTrain& extruder : Application::getInstance().current_slice_->scene.extruders) { - first_layer_outline = first_layer_outline.unionPolygons(storage_.getLayerOutlines( - i_layer, - include_support, - include_prime_tower, - reference_extruder_config.outside_polys_, - reference_extruder_config.inside_polys_, - extruder.extruder_nr_)); + first_layer_outline = first_layer_outline.unionPolygons(storage_.getLayerOutlines(i_layer, include_support, include_prime_tower, true, extruder.extruder_nr_)); } } @@ -474,9 +468,8 @@ Polygons SkirtBrim::getFirstLayerOutline(const int extruder_nr /* = -1 */) { // add brim underneath support by removing support where there's brim around the model constexpr bool include_support = false; // Include manually below. constexpr bool include_prime_tower = false; // Not included. - constexpr bool outer_polys = true; // Remove manually below. - constexpr bool inner_polys = true; // Remove manually below. - first_layer_outline = storage_.getLayerOutlines(layer_nr, include_support, include_prime_tower, outer_polys, inner_polys, extruder_nr); + constexpr bool external_polys_only = false; // Remove manually below. + first_layer_outline = storage_.getLayerOutlines(layer_nr, include_support, include_prime_tower, external_polys_only, extruder_nr); first_layer_outline = first_layer_outline.unionPolygons(); // To guard against overlapping outlines, which would produce holes according to the even-odd rule. Polygons first_layer_empty_holes; if (! reference_extruder_config.inside_polys_) diff --git a/src/sliceDataStorage.cpp b/src/sliceDataStorage.cpp index 3e8aa2999c..3f94495d89 100644 --- a/src/sliceDataStorage.cpp +++ b/src/sliceDataStorage.cpp @@ -68,28 +68,24 @@ SliceLayer::~SliceLayer() { } -Polygons SliceLayer::getOutlines(bool outer_polys, bool inner_polys) const +Polygons SliceLayer::getOutlines(bool external_polys_only) const { Polygons ret; - getOutlines(ret, outer_polys, inner_polys); + getOutlines(ret, external_polys_only); return ret; } -void SliceLayer::getOutlines(Polygons& result, bool outer_polys, bool inner_polys) const +void SliceLayer::getOutlines(Polygons& result, bool external_polys_only) const { for (const SliceLayerPart& part : parts) { - if (outer_polys && inner_polys) - { - result.add(part.print_outline); - } - else if (outer_polys) + if (external_polys_only) { result.add(part.outline.outerPolygon()); } - else if (inner_polys) + else { - result.add(part.outline.innerPolygons()); + result.add(part.print_outline); } } } @@ -270,13 +266,9 @@ SliceDataStorage::SliceDataStorage() machine_size.include(machine_max); } -Polygons SliceDataStorage::getLayerOutlines( - const LayerIndex layer_nr, - const bool include_support, - const bool include_prime_tower, - const bool outer_polys, - const bool inner_polys, - const int extruder_nr) const +Polygons + SliceDataStorage::getLayerOutlines(const LayerIndex layer_nr, const bool include_support, const bool include_prime_tower, const bool external_polys_only, const int extruder_nr) + const { const Settings& mesh_group_settings = Application::getInstance().current_slice_->scene.current_mesh_group->settings; @@ -311,27 +303,20 @@ Polygons SliceDataStorage::getLayerOutlines( if (include_support && use_current_extruder_for_raft) { - if (outer_polys && inner_polys) - { - return *raftOutline; - } - else + if (external_polys_only) { std::vector parts = raftOutline->splitIntoParts(); Polygons result; for (PolygonsPart& part : parts) { - if (outer_polys) - { - result.add(part.outerPolygon()); - } - else if (inner_polys) - { - result.add(part.innerPolygons()); - } + result.add(part.outerPolygon()); } return result; } + else + { + return *raftOutline; + } } else { @@ -353,7 +338,7 @@ Polygons SliceDataStorage::getLayerOutlines( continue; } const SliceLayer& layer = mesh->layers[layer_nr]; - layer.getOutlines(total, outer_polys, inner_polys); + layer.getOutlines(total, external_polys_only); if (mesh->settings.get("magic_mesh_surface_mode") != ESurfaceMode::NORMAL) { total = total.unionPolygons(layer.openPolyLines.offsetPolyLine(MM2INT(0.1))); From 204f7bf21a7a62dfaddb9900ec83c86f09053fe3 Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Wed, 28 Feb 2024 13:05:09 +0100 Subject: [PATCH 133/201] Mostly working inside/outside brim CURA-9838 --- include/SkirtBrim.h | 4 +- include/sliceDataStorage.h | 14 +- include/utils/polygon.h | 2 + src/SkirtBrim.cpp | 371 ++++++++++++++++++------------------- src/sliceDataStorage.cpp | 12 +- src/utils/SVG.cpp | 2 + src/utils/polygon.cpp | 13 ++ 7 files changed, 217 insertions(+), 201 deletions(-) diff --git a/include/SkirtBrim.h b/include/SkirtBrim.h index e84d547e1b..104728028f 100644 --- a/include/SkirtBrim.h +++ b/include/SkirtBrim.h @@ -65,7 +65,7 @@ class SkirtBrim bool extruder_is_used_; //!< Whether the extruder is actually used in this print bool outside_polys_; //!< Whether to generate brim on the outside bool inside_polys_; //!< Whether to generate brim on the inside - coord_t line_widths_; //!< The skirt/brim line width + coord_t line_width_; //!< The skirt/brim line width coord_t skirt_brim_minimal_length_; //!< The minimal brim length int line_count_; //!< The (minimal) number of brim lines to generate coord_t gap_; //!< The gap between the part and the first brim/skirt line @@ -198,6 +198,8 @@ class SkirtBrim */ void generateSecondarySkirtBrim(Polygons& covered_area, std::vector& allowed_areas_per_extruder, std::vector& total_length); + std::vector generateAllowedAreas() const; + public: /*! * Generate the brim which is printed from the outlines of the support inward. diff --git a/include/sliceDataStorage.h b/include/sliceDataStorage.h index e18a3783d3..22bfca6ea6 100644 --- a/include/sliceDataStorage.h +++ b/include/sliceDataStorage.h @@ -389,14 +389,18 @@ class SliceDataStorage : public NoCopy * \param layer_nr The index of the layer for which to get the outlines * (negative layer numbers indicate the raft). * \param include_support Whether to include support in the outline. - * \param include_prime_tower Whether to include the prime tower in the - * outline. + * \param include_prime_tower Whether to include the prime tower in the outline. + * \param include_models Whether to include the models in the outline * \param external_polys_only Whether to disregard all hole polygons. * \param extruder_nr (optional) only give back outlines for this extruder (where the walls are printed with this extruder) */ - Polygons - getLayerOutlines(const LayerIndex layer_nr, const bool include_support, const bool include_prime_tower, const bool external_polys_only = false, const int extruder_nr = -1) - const; + Polygons getLayerOutlines( + const LayerIndex layer_nr, + const bool include_support, + const bool include_prime_tower, + const bool external_polys_only = false, + const int extruder_nr = -1, + const bool include_models = true) const; /*! * Get the extruders used. diff --git a/include/utils/polygon.h b/include/utils/polygon.h index 52f7cdd0ac..7bca5d7524 100644 --- a/include/utils/polygon.h +++ b/include/utils/polygon.h @@ -1286,6 +1286,8 @@ class Polygons */ Polygons getEmptyHoles() const; + Polygons getHoles() const; + /*! * Split up the polygons into groups according to the even-odd rule. * Each PolygonsPart in the result has an outline as first polygon, whereas the rest are holes. diff --git a/src/SkirtBrim.cpp b/src/SkirtBrim.cpp index e7b038a0d4..295dd3c780 100644 --- a/src/SkirtBrim.cpp +++ b/src/SkirtBrim.cpp @@ -60,7 +60,7 @@ SkirtBrim::SkirtBrim(SliceDataStorage& storage) const ExtruderTrain& extruder = extruders_[extruder_nr]; const BrimLocation location = extruder.settings_.get("brim_location"); - extruder_config.line_widths_ = extruder.settings_.get("skirt_brim_line_width") * extruder.settings_.get("initial_layer_line_width_factor"); + extruder_config.line_width_ = extruder.settings_.get("skirt_brim_line_width") * extruder.settings_.get("initial_layer_line_width_factor"); extruder_config.skirt_brim_minimal_length_ = extruder.settings_.get("skirt_brim_minimal_length"); extruder_config.outside_polys_ = adhesion_type_ == EPlatformAdhesion::SKIRT || (location & BrimLocation::OUTSIDE); extruder_config.inside_polys_ = adhesion_type_ == EPlatformAdhesion::BRIM && (location & BrimLocation::INSIDE); @@ -101,7 +101,7 @@ std::vector SkirtBrim::generateBrimOffsetPlan(std::vector SkirtBrim::generateBrimOffsetPlan(std::vector starting_outlines(extruder_count_); std::vector all_brim_offsets = generateBrimOffsetPlan(starting_outlines); - constexpr LayerIndex layer_nr = 0; - constexpr bool include_support = true; - const bool include_prime_tower = adhesion_type_ == EPlatformAdhesion::SKIRT; - const bool has_prime_tower = storage_.primeTower.enabled_; - Polygons covered_area = storage_.getLayerOutlines(layer_nr, include_support, include_prime_tower); - - std::vector allowed_areas_per_extruder(extruder_count_); - for (int extruder_nr = 0; extruder_nr < extruder_count_; extruder_nr++) - { - const ExtruderConfig& extruder_config = extruders_configs_[extruder_nr]; - - if (! extruder_config.extruder_is_used_) - { - continue; - } - - if (! extruder_config.outside_polys_ && extruder_config.inside_polys_) // inside only - { - allowed_areas_per_extruder[extruder_nr] = covered_area.getEmptyHoles(); - } - else - { - Polygons machine_area = storage_.getMachineBorder(extruder_nr); - allowed_areas_per_extruder[extruder_nr] = machine_area.difference(covered_area); - if (extruder_config.outside_polys_ && ! extruder_config.inside_polys_) // outside only - { - // Expand covered area on inside of holes when external_only is enabled for any extruder, - // so that the brim lines don't overlap with the holes by half the line width - allowed_areas_per_extruder[extruder_nr] = allowed_areas_per_extruder[extruder_nr].difference(getInternalHoleExclusionArea(covered_area, extruder_nr)); - } - } - - SVG svg("/tmp/allowed_area.svg", AABB(storage_.getMachineBorder(extruder_nr))); - svg.writePolygons(allowed_areas_per_extruder[extruder_nr]); - - if (has_prime_tower) - { - allowed_areas_per_extruder[extruder_nr] = allowed_areas_per_extruder[extruder_nr].difference(storage_.primeTower.getGroundPoly()); - } - } + std::vector allowed_areas_per_extruder = generateAllowedAreas(); // Apply 'approximate convex hull' if the adhesion is skirt _after_ any skirt but also prime-tower-brim adhesion. // Otherwise, the now expanded convex hull covered areas will mess with that brim. Fortunately this does not mess // with the other area calculation above, since they are either itself a simple/convex shape or relevant for brim. + Polygons covered_area = storage_.getLayerOutlines( + 0, + /*include_support*/ true, + /*include_prime_tower*/ adhesion_type_ == EPlatformAdhesion::SKIRT); if (adhesion_type_ == EPlatformAdhesion::SKIRT) { covered_area = covered_area.approxConvexHull(); @@ -244,8 +202,8 @@ std::vector SkirtBrim::generatePrimaryBrim(std::vector& all_bri offset.inset_idx_, extruder_config.outside_polys_, extruder_config.inside_polys_, - extruder_config.line_widths_, - offset.total_offset_ + extruder_config.line_widths_, + extruder_config.line_width_, + offset.total_offset_ + extruder_config.line_width_, offset.inset_idx_ + 1, offset.extruder_nr_, is_last); @@ -255,151 +213,96 @@ std::vector SkirtBrim::generatePrimaryBrim(std::vector& all_bri return total_length; } -Polygons SkirtBrim::getInternalHoleExclusionArea(const Polygons& outline, const int extruder_nr) const -{ - assert(extruder_nr >= 0); - const Settings& settings = Application::getInstance().current_slice_->scene.extruders[extruder_nr].settings_; - // If brim is external_only, the distance between the external brim of a part inside a hole and the inside hole of the outer part. - const coord_t hole_brim_distance = settings.get("brim_inside_margin"); - const ExtruderConfig& extruder_config = extruders_configs_[extruder_nr]; - - Polygons ret; - std::vector parts = outline.splitIntoParts(); - for (const PolygonsPart& part : parts) - { - for (size_t hole_idx = 1; hole_idx < part.size(); hole_idx++) - { - Polygon hole_poly = part[hole_idx]; - hole_poly.reverse(); - Polygons disallowed_region = hole_poly.offset(10u).difference(hole_poly.offset(-extruder_config.line_widths_ / 2 - hole_brim_distance)); - ret = ret.unionPolygons(disallowed_region); - } - } - return ret; -} - coord_t SkirtBrim::generateOffset(const Offset& offset, Polygons& covered_area, std::vector& allowed_areas_per_extruder, SkirtBrimLine& result) { - SVG svg("/tmp/polylines.svg", AABB(allowed_areas_per_extruder[offset.extruder_nr_])); - // svg.writePolylines(allowed_areas_per_extruder[offset.extruder_nr_], SVG::Color::BLACK); - coord_t length_added; Polygons brim; - Polygons newly_covered; const ExtruderConfig& extruder_config = extruders_configs_[offset.extruder_nr_]; + + if (std::holds_alternative(offset.reference_outline_or_index_)) { - if (std::holds_alternative(offset.reference_outline_or_index_)) + Polygons* reference_outline = std::get(offset.reference_outline_or_index_); + for (ConstPolygonRef polygon : *reference_outline) { - Polygons* reference_outline = std::get(offset.reference_outline_or_index_); - // svg.writePolylines(*reference_outline, SVG::Color::RED); - if (offset.outside_ && ! offset.inside_) // outside only - { // prevent unioning of external polys enclosed by other parts, e.g. a small part inside a hollow cylinder. - for (Polygons& polys : reference_outline->sortByNesting()) - { // offset external polygons of islands contained within another part in each batch - for (PolygonRef poly : polys) - { - if (poly.area() < 0) - { - poly.reverse(); - } - } - brim.add(polys.offset(offset.offset_value_, ClipperLib::jtRound)); - newly_covered.add(polys.offset(offset.offset_value_ + extruder_config.line_widths_ / 2, ClipperLib::jtRound)); - polys.reverse(); - newly_covered.add(polys); // don't remove area inside external polygon - } - } - else if (! offset.outside_ && offset.inside_) // inside only + coord_t offset_value = offset.offset_value_; + if (polygon.area() > 0) { - // We have to use a negative offset in this case, because ClipperLib won't recognize holes without an actual outside - brim = reference_outline->offset(-offset.offset_value_, ClipperLib::jtRound); - brim.reverse(); - - newly_covered = brim.offsetPolyLine(extruder_config.line_widths_ / 2, ClipperLib::jtRound); - - /*newly_covered = reference_outline->offset(-(offset.offset_value_ + extruder_config.line_widths_ / 2), ClipperLib::jtRound); - newly_covered.reverse();*/ + if (! offset.outside_) + { + continue; + } } else { - brim = reference_outline->offset(offset.offset_value_, ClipperLib::jtRound); - newly_covered = reference_outline->offset(offset.offset_value_ + extruder_config.line_widths_ / 2, ClipperLib::jtRound); + if (! offset.inside_) + { + continue; + } + offset_value = -offset_value; } + + brim.add(polygon.offset(offset_value, ClipperLib::jtRound)); } - else - { - const int reference_idx = std::get(offset.reference_outline_or_index_); - coord_t offset_dist = extruder_config.line_widths_; - coord_t offset_covered = offset_dist / 2; + } + else + { + const int reference_idx = std::get(offset.reference_outline_or_index_); + const coord_t offset_dist = extruder_config.line_width_; - if (! offset.outside_ && offset.inside_) // inside only - { - // offset_dist = -offset_dist; - // offset_covered = -offset_covered; - } + Polygons local_brim; + auto closed_polygons_brim = storage_.skirt_brim[offset.extruder_nr_][reference_idx].closed_polygons.offsetPolyLine(offset_dist, ClipperLib::jtRound, true); + local_brim.add(closed_polygons_brim); - svg.writePolylines(storage_.skirt_brim[offset.extruder_nr_][reference_idx].closed_polygons, SVG::Color::GREEN); - svg.writePolylines(storage_.skirt_brim[offset.extruder_nr_][reference_idx].open_polylines, SVG::Color::GREEN); + auto open_polylines_brim = storage_.skirt_brim[offset.extruder_nr_][reference_idx].open_polylines.offsetPolyLine(offset_dist, ClipperLib::jtRound); + local_brim.add(open_polylines_brim); + local_brim.unionPolygons(); - Polygons local_brim; - auto closed_polygons_brim = storage_.skirt_brim[offset.extruder_nr_][reference_idx].closed_polygons.offsetPolyLine(offset_dist, ClipperLib::jtRound, true); - local_brim.add(closed_polygons_brim); + brim.add(local_brim); + } - auto open_polylines_brim = storage_.skirt_brim[offset.extruder_nr_][reference_idx].open_polylines.offsetPolyLine(offset_dist, ClipperLib::jtRound); - local_brim.add(open_polylines_brim); - local_brim.unionPolygons(); - brim.add(local_brim); + SVG svg(fmt::format("/tmp/result_offset{}_ex{}.svg", offset.total_offset_, offset.extruder_nr_), AABB(allowed_areas_per_extruder[offset.extruder_nr_]), 0.001); + svg.writePolygons(allowed_areas_per_extruder[offset.extruder_nr_], SVG::Color::MAGENTA, 0.1); + svg.writePolygons(brim, SVG::Color::BLACK, extruder_config.line_width_ / 1000.0); - newly_covered.add(local_brim.offset(offset_covered, ClipperLib::jtRound)); - } - } - // svg.writePolylines(brim, SVG::Color::BLUE); - // svg.writePolylines(newly_covered, SVG::Color::MAGENTA); + // limit brim lines to allowed areas, stitch them and store them in the result + brim = Simplify(Application::getInstance().current_slice_->scene.extruders[offset.extruder_nr_].settings_).polygon(brim); + brim.toPolylines(); + + Polygons brim_lines = allowed_areas_per_extruder[offset.extruder_nr_].intersectionPolyLines(brim, false); + length_added = brim_lines.polyLineLength(); - { // limit brim lines to allowed areas, stitch them and store them in the result - brim = Simplify(Application::getInstance().current_slice_->scene.extruders[offset.extruder_nr_].settings_).polygon(brim); - brim.toPolylines(); - Polygons brim_lines = allowed_areas_per_extruder[offset.extruder_nr_].intersectionPolyLines(brim, false); - length_added = brim_lines.polyLineLength(); + Polygons newly_covered = brim_lines.offsetPolyLine(extruder_config.line_width_ / 2 + 10, ClipperLib::jtRound); + svg.writePolygons(newly_covered, SVG::Color::BLUE, 0.1); - const coord_t max_stitch_distance = extruder_config.line_widths_; - PolylineStitcher::stitch(brim_lines, result.open_polylines, result.closed_polygons, max_stitch_distance); + const coord_t max_stitch_distance = extruder_config.line_width_; + PolylineStitcher::stitch(brim_lines, result.open_polylines, result.closed_polygons, max_stitch_distance); - // clean up too small lines - for (size_t line_idx = 0; line_idx < result.open_polylines.size();) + // clean up too small lines + for (size_t line_idx = 0; line_idx < result.open_polylines.size();) + { + PolygonRef line = result.open_polylines[line_idx]; + if (line.shorterThan(min_brim_line_length)) { - PolygonRef line = result.open_polylines[line_idx]; - if (line.shorterThan(min_brim_line_length)) - { - result.open_polylines.remove(line_idx); - } - else - { - line_idx++; - } + result.open_polylines.remove(line_idx); + } + else + { + line_idx++; } } - { // update allowed_areas_per_extruder - for (int extruder_nr = 0; extruder_nr < extruder_count_; extruder_nr++) + // update allowed_areas_per_extruder + covered_area = covered_area.unionPolygons(newly_covered.unionPolygons()); + for (size_t extruder_nr = 0; extruder_nr < extruder_count_; extruder_nr++) + { + if (extruders_configs_[extruder_nr].extruder_is_used_) { - if (! extruders_configs_[extruder_nr].extruder_is_used_) - { - continue; - } - svg.writePolylines(covered_area, SVG::Color::BLACK); - svg.writePolylines(newly_covered, SVG::Color::GRAY); - svg.writePolylines(newly_covered.unionPolygons(), SVG::Color::BLUE); - covered_area = covered_area.unionPolygons(newly_covered.unionPolygons()); - svg.writePolylines(covered_area, SVG::Color::RED); - - svg.writePolylines(allowed_areas_per_extruder[extruder_nr], SVG::Color::MAGENTA); allowed_areas_per_extruder[extruder_nr] = allowed_areas_per_extruder[extruder_nr].difference(covered_area); - svg.writePolylines(allowed_areas_per_extruder[extruder_nr], SVG::Color::ORANGE); } } + return length_added; } @@ -415,13 +318,9 @@ Polygons SkirtBrim::getFirstLayerOutline(const int extruder_nr /* = -1 */) } const ExtruderConfig& reference_extruder_config = extruders_configs_[reference_extruder_nr]; const int primary_line_count = reference_extruder_config.line_count_; - const bool has_prime_tower = storage_.primeTower.enabled_; const LayerIndex layer_nr = 0; if (adhesion_type_ == EPlatformAdhesion::SKIRT) { - constexpr bool include_support = true; - const bool include_prime_tower = ! has_prime_tower; // include manually otherwise - first_layer_outline = Polygons(); int skirt_height = 0; for (const auto& extruder : Application::getInstance().current_slice_->scene.extruders) @@ -435,15 +334,11 @@ Polygons SkirtBrim::getFirstLayerOutline(const int extruder_nr /* = -1 */) for (int i_layer = layer_nr; i_layer < skirt_height; ++i_layer) { - for (const ExtruderTrain& extruder : Application::getInstance().current_slice_->scene.extruders) - { - first_layer_outline = first_layer_outline.unionPolygons(storage_.getLayerOutlines(i_layer, include_support, include_prime_tower, true, extruder.extruder_nr_)); - } - } - - if (has_prime_tower) - { - first_layer_outline = first_layer_outline.unionPolygons(storage_.primeTower.getGroundPoly()); + first_layer_outline = first_layer_outline.unionPolygons(storage_.getLayerOutlines( + i_layer, + /*include_support*/ true, + /*include_prime_tower*/ true, + true)); } Polygons shields; @@ -456,7 +351,7 @@ Polygons SkirtBrim::getFirstLayerOutline(const int extruder_nr /* = -1 */) shields = shields.unionPolygons(storage_.draft_protection_shield); } first_layer_outline = first_layer_outline.unionPolygons(shields.offset( - reference_extruder_config.line_widths_ / 2 // because the shield is printed *on* the stored polygons; not inside hteir area + reference_extruder_config.line_width_ / 2 // because the shield is printed *on* the stored polygons; not inside hteir area - reference_extruder_config.gap_)); // so that when we apply the gap we will end up right next to the shield // NOTE: offsetting by -gap here and by +gap in the main brim algorithm effectively performs a morphological close, // so in some cases with a large skirt gap and small models and small shield distance @@ -477,10 +372,9 @@ Polygons SkirtBrim::getFirstLayerOutline(const int extruder_nr /* = -1 */) first_layer_empty_holes = first_layer_outline.getEmptyHoles(); first_layer_outline = first_layer_outline.removeEmptyHoles(); } - else if (! reference_extruder_config.outside_polys_) - { - first_layer_outline = first_layer_outline.getEmptyHoles(); - } + + SVG svg("/tmp/outline.svg", AABB(storage_.getMachineBorder(extruder_nr))); + svg.writePolygons(first_layer_outline); if (storage_.support.generated && primary_line_count > 0 && ! storage_.support.supportLayers.empty() && (extruder_nr == -1 || extruder_nr == global_settings.get("support_infill_extruder_nr"))) @@ -496,7 +390,7 @@ Polygons SkirtBrim::getFirstLayerOutline(const int extruder_nr /* = -1 */) // || || ||[]|| > expand to fit an extra brim line // |+-+| |+--+| // +---+ +----+ - const coord_t primary_extruder_skirt_brim_line_width = reference_extruder_config.line_widths_; + const coord_t primary_extruder_skirt_brim_line_width = reference_extruder_config.line_width_; Polygons model_brim_covered_area = first_layer_outline.offset( primary_extruder_skirt_brim_line_width * (primary_line_count + primary_line_count % 2), ClipperLib::jtRound); // always leave a gap of an even number of brim lines, so that it fits if it's generating brim from both sides @@ -543,7 +437,7 @@ void SkirtBrim::generateShieldBrim(Polygons& brim_covered_area, std::vector(storage_.skirt_brim[extruder_nr].size() - 1); - offset_from_reference = extruder_config.line_widths_; + offset_from_reference = extruder_config.line_width_; } constexpr bool outside_polys = true; constexpr bool inside_polys = true; // The reference outline may contain both outlines and hole polygons. @@ -655,6 +549,101 @@ void SkirtBrim::generateSecondarySkirtBrim(Polygons& covered_area, std::vector

SkirtBrim::generateAllowedAreas() const +{ + constexpr LayerIndex layer_nr = 0; + + // For each extruder, pre-compute the areas covered by models/supports/prime tower + struct ExtruderOutlines + { + Polygons models_outlines; + Polygons supports_outlines; + }; + + std::vector covered_area_by_extruder; + if (adhesion_type_ == EPlatformAdhesion::BRIM) + { + covered_area_by_extruder.resize(extruder_count_); + for (size_t extruder_nr = 0; extruder_nr < extruder_count_; extruder_nr++) + { + if (extruders_configs_[extruder_nr].extruder_is_used_) + { + // Gather models/support/prime tower areas separately to apply different margins + ExtruderOutlines& extruder_outlines = covered_area_by_extruder[extruder_nr]; + extruder_outlines.models_outlines = storage_.getLayerOutlines( + layer_nr, + /*include_support*/ false, + /*include_prime_tower*/ false, + /*external_polys_only*/ false, + extruder_nr, + /*include_model*/ true); + extruder_outlines.supports_outlines = storage_.getLayerOutlines( + layer_nr, + /*include_support*/ true, + /*include_prime_tower*/ true, + /*external_polys_only*/ false, + extruder_nr, + /*include_model*/ false); + } + } + } + else + { + // Single allowed areas for all extruders + covered_area_by_extruder.emplace_back( + storage_ + .getLayerOutlines( + layer_nr, + /*include_support*/ true, + /*include_prime_tower*/ true, + /*external_polys_only*/ true, + /*extruder_nr*/ -1, + /*include_model*/ true) + .approxConvexHull(), + Polygons()); + } + + std::vector allowed_areas_per_extruder(extruder_count_); + for (size_t extruder_nr = 0; extruder_nr < extruder_count_; extruder_nr++) + { + const ExtruderConfig& extruder_config = extruders_configs_[extruder_nr]; + + if (! extruder_config.extruder_is_used_) + { + continue; + } + + const Settings& settings = Application::getInstance().current_slice_->scene.extruders[extruder_nr].settings_; + const coord_t hole_brim_distance = settings.get("brim_inside_margin"); + + // Initialize allowed area to full build plate, then remove unreachable areas + Polygons& allowed_areas = allowed_areas_per_extruder[extruder_nr]; + allowed_areas = storage_.getMachineBorder(extruder_nr); + + for (size_t other_extruder_nr = 0; other_extruder_nr < covered_area_by_extruder.size(); ++other_extruder_nr) + { + // Remove areas covered by models with a higher margin on those printed with a different extruder + coord_t models_offset = extruder_config.line_width_ / 2; + if (other_extruder_nr == extruder_nr || adhesion_type_ == EPlatformAdhesion::SKIRT) + { + models_offset += extruder_config.gap_ - 50; // Lower margin a bit to avoid discarding legitimate lines + } + else + { + models_offset += hole_brim_distance; + } + + const ExtruderOutlines& extruder_outlines = covered_area_by_extruder[other_extruder_nr]; + allowed_areas = allowed_areas.difference(extruder_outlines.models_outlines.offset(models_offset, ClipperLib::jtRound)); + + // Remove areas covered by support, with a low margin because we don't care if the brim touches it + allowed_areas = allowed_areas.difference(extruder_outlines.supports_outlines.offset(extruder_config.line_width_ / 2)); + } + } + + return allowed_areas_per_extruder; +} + void SkirtBrim::generateSupportBrim() { constexpr coord_t brim_area_minimum_hole_size_multiplier = 100; diff --git a/src/sliceDataStorage.cpp b/src/sliceDataStorage.cpp index 3f94495d89..60d2085b0b 100644 --- a/src/sliceDataStorage.cpp +++ b/src/sliceDataStorage.cpp @@ -266,9 +266,13 @@ SliceDataStorage::SliceDataStorage() machine_size.include(machine_max); } -Polygons - SliceDataStorage::getLayerOutlines(const LayerIndex layer_nr, const bool include_support, const bool include_prime_tower, const bool external_polys_only, const int extruder_nr) - const +Polygons SliceDataStorage::getLayerOutlines( + const LayerIndex layer_nr, + const bool include_support, + const bool include_prime_tower, + const bool external_polys_only, + const int extruder_nr, + const bool include_models) const { const Settings& mesh_group_settings = Application::getInstance().current_slice_->scene.current_mesh_group->settings; @@ -328,7 +332,7 @@ Polygons case Raft::LayerType::Model: { Polygons total; - if (layer_nr >= 0) + if (include_models && layer_nr >= 0) { for (const std::shared_ptr& mesh : meshes) { diff --git a/src/utils/SVG.cpp b/src/utils/SVG.cpp index a5ee2c14b8..88d820b123 100644 --- a/src/utils/SVG.cpp +++ b/src/utils/SVG.cpp @@ -340,6 +340,7 @@ void SVG::writePolygons(const Polygons& polys, const ColorObject color, const do { writePolygon(poly, color, stroke_width); } + fflush(out_); } void SVG::writePolygon(ConstPolygonRef poly, const ColorObject color, const double stroke_width) const @@ -374,6 +375,7 @@ void SVG::writePolygon(ConstPolygonRef poly, const ColorObject color, const doub p0 = p1; i++; } + fflush(out_); } diff --git a/src/utils/polygon.cpp b/src/utils/polygon.cpp index 66f2a3672a..c7e2c1da76 100644 --- a/src/utils/polygon.cpp +++ b/src/utils/polygon.cpp @@ -599,6 +599,19 @@ Polygons Polygons::getEmptyHoles() const return ret; } +Polygons Polygons::getHoles() const +{ + Polygons ret; + for (ConstPolygonRef polygon : *this) + { + if (polygon.area() < 0) + { + ret.add(polygon); + } + } + return ret; +} + void Polygons::removeEmptyHoles_processPolyTreeNode(const ClipperLib::PolyNode& node, const bool remove_holes, Polygons& ret) const { for (int outer_poly_idx = 0; outer_poly_idx < node.ChildCount(); outer_poly_idx++) From 5c0b641d2a18a1dfddd7461c33f16b3030df0736 Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Thu, 29 Feb 2024 10:20:48 +0100 Subject: [PATCH 134/201] Fixed many tricky support/brim interactions --- include/SkirtBrim.h | 2 +- include/utils/polygon.h | 14 ----- src/SkirtBrim.cpp | 133 ++++++++++++++++++++++------------------ src/utils/polygon.cpp | 41 ------------- 4 files changed, 73 insertions(+), 117 deletions(-) diff --git a/include/SkirtBrim.h b/include/SkirtBrim.h index 104728028f..827196d70e 100644 --- a/include/SkirtBrim.h +++ b/include/SkirtBrim.h @@ -198,7 +198,7 @@ class SkirtBrim */ void generateSecondarySkirtBrim(Polygons& covered_area, std::vector& allowed_areas_per_extruder, std::vector& total_length); - std::vector generateAllowedAreas() const; + std::vector generateAllowedAreas(const std::vector& starting_outlines) const; public: /*! diff --git a/include/utils/polygon.h b/include/utils/polygon.h index 7bca5d7524..527e0a3472 100644 --- a/include/utils/polygon.h +++ b/include/utils/polygon.h @@ -1274,20 +1274,6 @@ class Polygons */ Polygons getOutsidePolygons() const; - /*! - * Exclude holes which have no parts inside of them. - * \return the resulting polygons. - */ - Polygons removeEmptyHoles() const; - - /*! - * Return hole polygons which have no parts inside of them. - * \return the resulting polygons. - */ - Polygons getEmptyHoles() const; - - Polygons getHoles() const; - /*! * Split up the polygons into groups according to the even-odd rule. * Each PolygonsPart in the result has an outline as first polygon, whereas the rest are holes. diff --git a/src/SkirtBrim.cpp b/src/SkirtBrim.cpp index 295dd3c780..d7e3487df7 100644 --- a/src/SkirtBrim.cpp +++ b/src/SkirtBrim.cpp @@ -123,8 +123,7 @@ void SkirtBrim::generate() { std::vector starting_outlines(extruder_count_); std::vector all_brim_offsets = generateBrimOffsetPlan(starting_outlines); - - std::vector allowed_areas_per_extruder = generateAllowedAreas(); + std::vector allowed_areas_per_extruder = generateAllowedAreas(starting_outlines); // Apply 'approximate convex hull' if the adhesion is skirt _after_ any skirt but also prime-tower-brim adhesion. // Otherwise, the now expanded convex hull covered areas will mess with that brim. Fortunately this does not mess @@ -260,12 +259,6 @@ coord_t SkirtBrim::generateOffset(const Offset& offset, Polygons& covered_area, brim.add(local_brim); } - - SVG svg(fmt::format("/tmp/result_offset{}_ex{}.svg", offset.total_offset_, offset.extruder_nr_), AABB(allowed_areas_per_extruder[offset.extruder_nr_]), 0.001); - svg.writePolygons(allowed_areas_per_extruder[offset.extruder_nr_], SVG::Color::MAGENTA, 0.1); - svg.writePolygons(brim, SVG::Color::BLACK, extruder_config.line_width_ / 1000.0); - - // limit brim lines to allowed areas, stitch them and store them in the result brim = Simplify(Application::getInstance().current_slice_->scene.extruders[offset.extruder_nr_].settings_).polygon(brim); brim.toPolylines(); @@ -274,7 +267,6 @@ coord_t SkirtBrim::generateOffset(const Offset& offset, Polygons& covered_area, length_added = brim_lines.polyLineLength(); Polygons newly_covered = brim_lines.offsetPolyLine(extruder_config.line_width_ / 2 + 10, ClipperLib::jtRound); - svg.writePolygons(newly_covered, SVG::Color::BLUE, 0.1); const coord_t max_stitch_distance = extruder_config.line_width_; PolylineStitcher::stitch(brim_lines, result.open_polylines, result.closed_polygons, max_stitch_distance); @@ -361,20 +353,11 @@ Polygons SkirtBrim::getFirstLayerOutline(const int extruder_nr /* = -1 */) } else { // add brim underneath support by removing support where there's brim around the model - constexpr bool include_support = false; // Include manually below. - constexpr bool include_prime_tower = false; // Not included. - constexpr bool external_polys_only = false; // Remove manually below. + constexpr bool include_support = false; // Don't include the supports yet because we need to reduce them before + constexpr bool include_prime_tower = false; // Not included, has its own brim + constexpr bool external_polys_only = false; // Gather all polygons and treat them separately. first_layer_outline = storage_.getLayerOutlines(layer_nr, include_support, include_prime_tower, external_polys_only, extruder_nr); first_layer_outline = first_layer_outline.unionPolygons(); // To guard against overlapping outlines, which would produce holes according to the even-odd rule. - Polygons first_layer_empty_holes; - if (! reference_extruder_config.inside_polys_) - { - first_layer_empty_holes = first_layer_outline.getEmptyHoles(); - first_layer_outline = first_layer_outline.removeEmptyHoles(); - } - - SVG svg("/tmp/outline.svg", AABB(storage_.getMachineBorder(extruder_nr))); - svg.writePolygons(first_layer_outline); if (storage_.support.generated && primary_line_count > 0 && ! storage_.support.supportLayers.empty() && (extruder_nr == -1 || extruder_nr == global_settings.get("support_infill_extruder_nr"))) @@ -391,19 +374,39 @@ Polygons SkirtBrim::getFirstLayerOutline(const int extruder_nr /* = -1 */) // |+-+| |+--+| // +---+ +----+ const coord_t primary_extruder_skirt_brim_line_width = reference_extruder_config.line_width_; - Polygons model_brim_covered_area = first_layer_outline.offset( - primary_extruder_skirt_brim_line_width * (primary_line_count + primary_line_count % 2), - ClipperLib::jtRound); // always leave a gap of an even number of brim lines, so that it fits if it's generating brim from both sides - if (! reference_extruder_config.inside_polys_) - { // don't remove support within empty holes where no brim is generated. - model_brim_covered_area.add(first_layer_empty_holes); + Polygons model_brim_covered_area; + + // always leave a gap of an even number of brim lines, so that it fits if it's generating brim from both sides + const coord_t offset = primary_extruder_skirt_brim_line_width * (primary_line_count + primary_line_count % 2); + + for (ConstPolygonRef polygon : first_layer_outline) + { + Polygons outset; + Polygons inset; + + double area = polygon.area(); + if (area > 0 && reference_extruder_config.outside_polys_) + { + outset = polygon.offset(offset, ClipperLib::jtRound); + inset.add(polygon); + } + else if (area < 0 && reference_extruder_config.inside_polys_) + { + outset.add(polygon); + inset = polygon.offset(-offset, ClipperLib::jtRound); + } + + outset = outset.difference(inset); + model_brim_covered_area = model_brim_covered_area.unionPolygons(outset); } + AABB model_brim_covered_area_boundary_box(model_brim_covered_area); support_layer.excludeAreasFromSupportInfillAreas(model_brim_covered_area, model_brim_covered_area_boundary_box); // If the gap between the model and the BP is small enough, support starts with the interface instead, so remove it there as well: support_layer.support_roof = support_layer.support_roof.difference(model_brim_covered_area); } + for (const SupportInfillPart& support_infill_part : support_layer.support_infill_parts) { first_layer_outline.add(support_infill_part.outline_); @@ -549,7 +552,7 @@ void SkirtBrim::generateSecondarySkirtBrim(Polygons& covered_area, std::vector

SkirtBrim::generateAllowedAreas() const +std::vector SkirtBrim::generateAllowedAreas(const std::vector& starting_outlines) const { constexpr LayerIndex layer_nr = 0; @@ -587,21 +590,6 @@ std::vector SkirtBrim::generateAllowedAreas() const } } } - else - { - // Single allowed areas for all extruders - covered_area_by_extruder.emplace_back( - storage_ - .getLayerOutlines( - layer_nr, - /*include_support*/ true, - /*include_prime_tower*/ true, - /*external_polys_only*/ true, - /*extruder_nr*/ -1, - /*include_model*/ true) - .approxConvexHull(), - Polygons()); - } std::vector allowed_areas_per_extruder(extruder_count_); for (size_t extruder_nr = 0; extruder_nr < extruder_count_; extruder_nr++) @@ -613,32 +601,55 @@ std::vector SkirtBrim::generateAllowedAreas() const continue; } - const Settings& settings = Application::getInstance().current_slice_->scene.extruders[extruder_nr].settings_; - const coord_t hole_brim_distance = settings.get("brim_inside_margin"); - - // Initialize allowed area to full build plate, then remove unreachable areas + // Initialize allowed area to full build plate, then remove disallowed areas Polygons& allowed_areas = allowed_areas_per_extruder[extruder_nr]; allowed_areas = storage_.getMachineBorder(extruder_nr); - for (size_t other_extruder_nr = 0; other_extruder_nr < covered_area_by_extruder.size(); ++other_extruder_nr) + if (adhesion_type_ == EPlatformAdhesion::BRIM) { - // Remove areas covered by models with a higher margin on those printed with a different extruder - coord_t models_offset = extruder_config.line_width_ / 2; - if (other_extruder_nr == extruder_nr || adhesion_type_ == EPlatformAdhesion::SKIRT) - { - models_offset += extruder_config.gap_ - 50; // Lower margin a bit to avoid discarding legitimate lines - } - else + const Settings& settings = Application::getInstance().current_slice_->scene.extruders[extruder_nr].settings_; + const coord_t hole_brim_distance = settings.get("brim_inside_margin"); + + for (size_t other_extruder_nr = 0; other_extruder_nr < covered_area_by_extruder.size(); ++other_extruder_nr) { - models_offset += hole_brim_distance; - } + const ExtruderOutlines& extruder_outlines = covered_area_by_extruder[other_extruder_nr]; - const ExtruderOutlines& extruder_outlines = covered_area_by_extruder[other_extruder_nr]; - allowed_areas = allowed_areas.difference(extruder_outlines.models_outlines.offset(models_offset, ClipperLib::jtRound)); + // Remove areas covered by models + for (ConstPolygonRef covered_surface : extruder_outlines.models_outlines) + { + coord_t offset = extruder_config.line_width_ / 2; + double covered_area = covered_surface.area(); + + if (other_extruder_nr == extruder_nr && ((covered_area > 0 && extruder_config.outside_polys_) || (covered_area < 0 && extruder_config.inside_polys_))) + { + // This is an area we are gonna generate brim on with the same extruder, use the actual gap + offset += extruder_config.gap_ - 50; // Lower margin a bit to avoid discarding legitimate lines + } + else + { + // This is an area we are not gonna generate brim in, or with a different extruder, + // use a larger gap to keep the printed surface clean + offset += hole_brim_distance; + } + + if (covered_area < 0) + { + // Invert offset for making holes grow inside + allowed_areas.add(covered_surface.offset(-offset, ClipperLib::jtRound)); + } + else + { + allowed_areas = allowed_areas.difference(covered_surface.offset(offset, ClipperLib::jtRound)); + } + } - // Remove areas covered by support, with a low margin because we don't care if the brim touches it - allowed_areas = allowed_areas.difference(extruder_outlines.supports_outlines.offset(extruder_config.line_width_ / 2)); + // Remove areas covered by support, with a low margin because we don't care if the brim touches it + allowed_areas = allowed_areas.difference(extruder_outlines.supports_outlines.offset(extruder_config.line_width_ / 2)); + } } + + // Anyway, don't allow a brim/skirt to grow inside itself, which may happen e.g. with ooze shield+skirt + allowed_areas = allowed_areas.difference(starting_outlines[extruder_nr].offset(extruder_config.gap_ - 50, ClipperLib::jtRound)); } return allowed_areas_per_extruder; diff --git a/src/utils/polygon.cpp b/src/utils/polygon.cpp index c7e2c1da76..99cb2be1b9 100644 --- a/src/utils/polygon.cpp +++ b/src/utils/polygon.cpp @@ -571,47 +571,6 @@ Polygons Polygons::getOutsidePolygons() const return ret; } -Polygons Polygons::removeEmptyHoles() const -{ - Polygons ret; - ClipperLib::Clipper clipper(clipper_init); - ClipperLib::PolyTree poly_tree; - constexpr bool paths_are_closed_polys = true; - clipper.AddPaths(paths, ClipperLib::ptSubject, paths_are_closed_polys); - clipper.Execute(ClipperLib::ctUnion, poly_tree); - - bool remove_holes = true; - removeEmptyHoles_processPolyTreeNode(poly_tree, remove_holes, ret); - return ret; -} - -Polygons Polygons::getEmptyHoles() const -{ - Polygons ret; - ClipperLib::Clipper clipper(clipper_init); - ClipperLib::PolyTree poly_tree; - constexpr bool paths_are_closed_polys = true; - clipper.AddPaths(paths, ClipperLib::ptSubject, paths_are_closed_polys); - clipper.Execute(ClipperLib::ctUnion, poly_tree); - - bool remove_holes = false; - removeEmptyHoles_processPolyTreeNode(poly_tree, remove_holes, ret); - return ret; -} - -Polygons Polygons::getHoles() const -{ - Polygons ret; - for (ConstPolygonRef polygon : *this) - { - if (polygon.area() < 0) - { - ret.add(polygon); - } - } - return ret; -} - void Polygons::removeEmptyHoles_processPolyTreeNode(const ClipperLib::PolyNode& node, const bool remove_holes, Polygons& ret) const { for (int outer_poly_idx = 0; outer_poly_idx < node.ChildCount(); outer_poly_idx++) From 98bdfc71a512e7ea5fc9a7d91c54173abbcbd2be Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Thu, 29 Feb 2024 10:46:31 +0100 Subject: [PATCH 135/201] Fixed issue when using specific brim extruder CURA-9838 --- src/SkirtBrim.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/SkirtBrim.cpp b/src/SkirtBrim.cpp index d7e3487df7..0ebe002362 100644 --- a/src/SkirtBrim.cpp +++ b/src/SkirtBrim.cpp @@ -620,7 +620,8 @@ std::vector SkirtBrim::generateAllowedAreas(const std::vector 0 && extruder_config.outside_polys_) || (covered_area < 0 && extruder_config.inside_polys_))) + if ((other_extruder_nr == extruder_nr || extruder_nr == skirt_brim_extruder_nr_) + && ((covered_area > 0 && extruder_config.outside_polys_) || (covered_area < 0 && extruder_config.inside_polys_))) { // This is an area we are gonna generate brim on with the same extruder, use the actual gap offset += extruder_config.gap_ - 50; // Lower margin a bit to avoid discarding legitimate lines From d5359cf983e178e9edc0e06f55df0ee6da6f68c1 Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Thu, 29 Feb 2024 11:12:54 +0100 Subject: [PATCH 136/201] Code cleaning and documentation CURA-9838 --- include/SkirtBrim.h | 8 ++++++++ src/SkirtBrim.cpp | 37 +++++++++++++------------------------ 2 files changed, 21 insertions(+), 24 deletions(-) diff --git a/include/SkirtBrim.h b/include/SkirtBrim.h index 827196d70e..3cad8b4f29 100644 --- a/include/SkirtBrim.h +++ b/include/SkirtBrim.h @@ -198,6 +198,14 @@ class SkirtBrim */ void generateSecondarySkirtBrim(Polygons& covered_area, std::vector& allowed_areas_per_extruder, std::vector& total_length); + /*! + * Generate the allowed areas for each extruder. Allowed areas represent where the brim/skirt is allowed to grow + * while adding new outset lines. This is basically the whole build plate, removing the areas where models are + * located, offsetted with some specific margins. + * + * \param[in] starting_outlines The previously generated starting outlines for each extruder + * \return The list of allowed areas for each extruder + */ std::vector generateAllowedAreas(const std::vector& starting_outlines) const; public: diff --git a/src/SkirtBrim.cpp b/src/SkirtBrim.cpp index 0ebe002362..ea8af8fcd3 100644 --- a/src/SkirtBrim.cpp +++ b/src/SkirtBrim.cpp @@ -150,7 +150,7 @@ void SkirtBrim::generate() } } - // Secondary brim of all other materials which don;t meet minimum length constriant yet + // Secondary brim of all other materials which don't meet minimum length constraint yet generateSecondarySkirtBrim(covered_area, allowed_areas_per_extruder, total_length); // simplify paths to prevent buffer unnerruns in firmware @@ -223,24 +223,12 @@ coord_t SkirtBrim::generateOffset(const Offset& offset, Polygons& covered_area, Polygons* reference_outline = std::get(offset.reference_outline_or_index_); for (ConstPolygonRef polygon : *reference_outline) { - coord_t offset_value = offset.offset_value_; - if (polygon.area() > 0) + const coord_t offset_value = offset.offset_value_; + const double area = polygon.area(); + if ((area > 0 && offset.outside_) || (area < 0 && offset.inside_)) { - if (! offset.outside_) - { - continue; - } - } - else - { - if (! offset.inside_) - { - continue; - } - offset_value = -offset_value; + brim.add(polygon.offset(area < 0 ? -offset_value : offset_value, ClipperLib::jtRound)); } - - brim.add(polygon.offset(offset_value, ClipperLib::jtRound)); } } else @@ -381,6 +369,7 @@ Polygons SkirtBrim::getFirstLayerOutline(const int extruder_nr /* = -1 */) for (ConstPolygonRef polygon : first_layer_outline) { + // Compute the fringe that the brim is going to cover around the model Polygons outset; Polygons inset; @@ -613,29 +602,29 @@ std::vector SkirtBrim::generateAllowedAreas(const std::vector 0 && extruder_config.outside_polys_) || (covered_area < 0 && extruder_config.inside_polys_))) { - // This is an area we are gonna generate brim on with the same extruder, use the actual gap + // This is an area we are gonna intentionnally print brim in, use the actual gap offset += extruder_config.gap_ - 50; // Lower margin a bit to avoid discarding legitimate lines } else { - // This is an area we are not gonna generate brim in, or with a different extruder, - // use a larger gap to keep the printed surface clean + // This is an area we do not expect brim to be printed in, use a larger gap to keep the printed surface clean offset += hole_brim_distance; } if (covered_area < 0) { - // Invert offset for making holes grow inside + // Invert offset to make holes grow inside allowed_areas.add(covered_surface.offset(-offset, ClipperLib::jtRound)); } else @@ -645,7 +634,7 @@ std::vector SkirtBrim::generateAllowedAreas(const std::vector Date: Thu, 29 Feb 2024 11:14:20 +0100 Subject: [PATCH 137/201] Fix remove empty layers when layers do not equal layer height. This shouldn't happen, but neither should the hot-end ram into the build-plate (in fact, you want that even less). part of CURA-11537 --- src/FffPolygonGenerator.cpp | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/FffPolygonGenerator.cpp b/src/FffPolygonGenerator.cpp index f2fcbe8910..a8924f0133 100644 --- a/src/FffPolygonGenerator.cpp +++ b/src/FffPolygonGenerator.cpp @@ -769,12 +769,25 @@ bool FffPolygonGenerator::isEmptyLayer(SliceDataStorage& storage, const LayerInd void FffPolygonGenerator::removeEmptyFirstLayers(SliceDataStorage& storage, size_t& total_layers) { + const auto get_highest_z = [&storage](const LayerIndex& layer_idx) + { + coord_t highest_z = 0; + for (std::shared_ptr& mesh_ptr : storage.meshes) + { + auto& mesh = *mesh_ptr; + highest_z = layer_idx >= mesh.layers.size() ? highest_z : std::max(highest_z, mesh.layers[layer_idx].printZ); + } + return highest_z; + }; + size_t n_empty_first_layers = 0; + coord_t hightest_empty_layer = 0; for (size_t layer_idx = 0; layer_idx < total_layers; layer_idx++) { if (isEmptyLayer(storage, layer_idx)) { n_empty_first_layers++; + hightest_empty_layer = get_highest_z(layer_idx); } else { @@ -798,7 +811,7 @@ void FffPolygonGenerator::removeEmptyFirstLayers(SliceDataStorage& storage, size layers.erase(layers.begin(), layers.begin() + n_empty_first_layers); for (SliceLayer& layer : layers) { - layer.printZ -= n_empty_first_layers * layer_height; + layer.printZ -= hightest_empty_layer; } mesh.layer_nr_max_filled_layer -= n_empty_first_layers; } From 70b6447e4be23b8a4aceab1c517f94768b4c5ac0 Mon Sep 17 00:00:00 2001 From: rburema Date: Thu, 29 Feb 2024 10:15:14 +0000 Subject: [PATCH 138/201] Applied clang-format. --- src/FffPolygonGenerator.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/FffPolygonGenerator.cpp b/src/FffPolygonGenerator.cpp index a8924f0133..7c9b188a77 100644 --- a/src/FffPolygonGenerator.cpp +++ b/src/FffPolygonGenerator.cpp @@ -770,15 +770,15 @@ bool FffPolygonGenerator::isEmptyLayer(SliceDataStorage& storage, const LayerInd void FffPolygonGenerator::removeEmptyFirstLayers(SliceDataStorage& storage, size_t& total_layers) { const auto get_highest_z = [&storage](const LayerIndex& layer_idx) + { + coord_t highest_z = 0; + for (std::shared_ptr& mesh_ptr : storage.meshes) { - coord_t highest_z = 0; - for (std::shared_ptr& mesh_ptr : storage.meshes) - { - auto& mesh = *mesh_ptr; - highest_z = layer_idx >= mesh.layers.size() ? highest_z : std::max(highest_z, mesh.layers[layer_idx].printZ); - } - return highest_z; - }; + auto& mesh = *mesh_ptr; + highest_z = layer_idx >= mesh.layers.size() ? highest_z : std::max(highest_z, mesh.layers[layer_idx].printZ); + } + return highest_z; + }; size_t n_empty_first_layers = 0; coord_t hightest_empty_layer = 0; From cb973edccd0142170668a22d4f6c9223de582713 Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Thu, 29 Feb 2024 11:31:47 +0100 Subject: [PATCH 139/201] Fix prime tower brim being generated even when useless CURA-9838 --- src/PrimeTower.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/PrimeTower.cpp b/src/PrimeTower.cpp index 180a79a331..b2afe03d6f 100644 --- a/src/PrimeTower.cpp +++ b/src/PrimeTower.cpp @@ -108,6 +108,8 @@ void PrimeTower::generateGroundpoly() void PrimeTower::generatePaths(const SliceDataStorage& storage) { + checkUsed(storage); + const int raft_total_extra_layers = Raft::getTotalExtraLayers(); would_have_actual_tower_ = storage.max_print_height_second_to_last_extruder >= -raft_total_extra_layers; // Maybe it turns out that we don't need a prime tower after all because there are no layer switches. From 4eb7ec7a4e506732c4dd553740fe71f0a4ae1520 Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Thu, 29 Feb 2024 11:37:48 +0100 Subject: [PATCH 140/201] Fix unit tests build --- tests/utils/PolygonTest.cpp | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/tests/utils/PolygonTest.cpp b/tests/utils/PolygonTest.cpp index bdf84466e1..7c0f5b566f 100644 --- a/tests/utils/PolygonTest.cpp +++ b/tests/utils/PolygonTest.cpp @@ -2,10 +2,12 @@ // CuraEngine is released under the terms of the AGPLv3 or higher. #include "utils/polygon.h" // The class under test. + +#include + #include "utils/Coord_t.h" #include "utils/SVG.h" // helper functions #include "utils/polygonUtils.h" // helper functions -#include // NOLINTBEGIN(*-magic-numbers) namespace cura @@ -79,7 +81,18 @@ class PolygonTest : public testing::Test } void twoPolygonsAreEqual(Polygons& polygon1, Polygons& polygon2) const { - auto poly_cmp = [](const ClipperLib::Path& a, const ClipperLib::Path& b) { return std::lexicographical_compare(a.begin(), a.end(), b.begin(), b.end(), [](const Point2LL& p1, const Point2LL& p2) { return p1 < p2; }); }; + auto poly_cmp = [](const ClipperLib::Path& a, const ClipperLib::Path& b) + { + return std::lexicographical_compare( + a.begin(), + a.end(), + b.begin(), + b.end(), + [](const Point2LL& p1, const Point2LL& p2) + { + return p1 < p2; + }); + }; std::sort(polygon1.begin(), polygon1.end(), poly_cmp); std::sort(polygon2.begin(), polygon2.end(), poly_cmp); @@ -225,18 +238,6 @@ TEST_F(PolygonTest, differenceClockwiseTest) EXPECT_GT(area, 0) << "Inner polygon should be clockwise."; } -TEST_F(PolygonTest, getEmptyHolesTest) -{ - const Polygons holes = clockwise_donut.getEmptyHoles(); - - ASSERT_EQ(holes.size(), 1); - ASSERT_EQ(holes[0].size(), clockwise_small.size()) << "Empty hole should have the same amount of vertices as the original polygon."; - for (size_t point_index = 0; point_index < holes[0].size(); point_index++) - { - EXPECT_EQ(holes[0][point_index], clockwise_small[point_index]) << "Coordinates of the empty hole must be the same as the original polygon."; - } -} - /* * The convex hull of a cube should still be a cube */ From 7df7c64d9dadc861b449bda6792d934a75589002 Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Thu, 29 Feb 2024 11:47:26 +0100 Subject: [PATCH 141/201] Code cleaning --- include/utils/SVG.h | 4 ++-- include/utils/polygon.h | 15 --------------- src/TreeModelVolumes.cpp | 3 ++- src/utils/SVG.cpp | 18 +++++++++++++----- 4 files changed, 17 insertions(+), 23 deletions(-) diff --git a/include/utils/SVG.h b/include/utils/SVG.h index 058bacc414..a67b1d5944 100644 --- a/include/utils/SVG.h +++ b/include/utils/SVG.h @@ -144,9 +144,9 @@ class SVG : NoCopy void writeText(const Point2LL& p, const std::string& txt, const ColorObject color = Color::BLACK, const double font_size = 10.0) const; - void writePolygons(const Polygons& polys, const ColorObject color = Color::BLACK, const double stroke_width = 1.0) const; + void writePolygons(const Polygons& polys, const ColorObject color = Color::BLACK, const double stroke_width = 1.0, const bool flush = true) const; - void writePolygon(ConstPolygonRef poly, const ColorObject color = Color::BLACK, const double stroke_width = 1.0) const; + void writePolygon(ConstPolygonRef poly, const ColorObject color = Color::BLACK, const double stroke_width = 1.0, const bool flush = true) const; void writePolylines(const Polygons& polys, const ColorObject color = Color::BLACK, const double stroke_width = 1.0) const; diff --git a/include/utils/polygon.h b/include/utils/polygon.h index 527e0a3472..e9eb6c2fcb 100644 --- a/include/utils/polygon.h +++ b/include/utils/polygon.h @@ -1194,11 +1194,6 @@ class Polygons */ double area() const; - void reverse() - { - ClipperLib::ReversePaths(paths); - } - /*! * Smooth out small perpendicular segments * Smoothing is performed by removing the inner most vertex of a line segment smaller than \p remove_length @@ -1559,16 +1554,6 @@ class PolygonsPart : public Polygons return paths[0]; } - Polygons innerPolygons() const - { - Polygons ret; - if (size() > 1) - { - ret.paths = ClipperLib::Paths(std::next(paths.begin()), paths.end()); - } - return ret; - } - /*! * Tests whether the given point is inside this polygon part. * \param p The point to test whether it is inside. diff --git a/src/TreeModelVolumes.cpp b/src/TreeModelVolumes.cpp index c2a610b4c7..fa8fe4bedf 100644 --- a/src/TreeModelVolumes.cpp +++ b/src/TreeModelVolumes.cpp @@ -572,6 +572,7 @@ Polygons TreeModelVolumes::extractOutlineFromMesh(const SliceMeshStorage& mesh, { // Similar to SliceDataStorage.getLayerOutlines but only for one mesh instead of for all of them. + constexpr bool external_polys_only = false; Polygons total; if (mesh.settings.get("infill_mesh") || mesh.settings.get("anti_overhang_mesh")) @@ -580,7 +581,7 @@ Polygons TreeModelVolumes::extractOutlineFromMesh(const SliceMeshStorage& mesh, } const SliceLayer& layer = mesh.layers[layer_idx]; - layer.getOutlines(total); + layer.getOutlines(total, external_polys_only); if (mesh.settings.get("magic_mesh_surface_mode") != ESurfaceMode::NORMAL) { total = total.unionPolygons(layer.openPolyLines.offsetPolyLine(FUDGE_LENGTH * 2)); diff --git a/src/utils/SVG.cpp b/src/utils/SVG.cpp index 88d820b123..4da036996a 100644 --- a/src/utils/SVG.cpp +++ b/src/utils/SVG.cpp @@ -334,16 +334,20 @@ void SVG::writeText(const Point2LL& p, const std::string& txt, const ColorObject txt.c_str()); } -void SVG::writePolygons(const Polygons& polys, const ColorObject color, const double stroke_width) const +void SVG::writePolygons(const Polygons& polys, const ColorObject color, const double stroke_width, const bool flush) const { for (ConstPolygonRef poly : polys) { - writePolygon(poly, color, stroke_width); + writePolygon(poly, color, stroke_width, false); + } + + if (flush) + { + fflush(out_); } - fflush(out_); } -void SVG::writePolygon(ConstPolygonRef poly, const ColorObject color, const double stroke_width) const +void SVG::writePolygon(ConstPolygonRef poly, const ColorObject color, const double stroke_width, const bool flush) const { if (poly.size() == 0) { @@ -375,7 +379,11 @@ void SVG::writePolygon(ConstPolygonRef poly, const ColorObject color, const doub p0 = p1; i++; } - fflush(out_); + + if (flush) + { + fflush(out_); + } } From a7047be762d639cf2a42736c8a8c5c7c1c58912f Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Thu, 29 Feb 2024 15:07:34 +0100 Subject: [PATCH 142/201] Fix unit tests CURA-9838 --- tests/LayerPlanTest.cpp | 30 ++++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/tests/LayerPlanTest.cpp b/tests/LayerPlanTest.cpp index 88ebbf4331..421a2caf51 100644 --- a/tests/LayerPlanTest.cpp +++ b/tests/LayerPlanTest.cpp @@ -2,6 +2,9 @@ // CuraEngine is released under the terms of the AGPLv3 or higher #include "LayerPlan.h" //The code under test. + +#include + #include "Application.h" //To provide settings for the layer plan. #include "RetractionConfig.h" //To provide retraction settings. #include "Slice.h" //To provide settings for the layer plan. @@ -9,7 +12,6 @@ #include "pathPlanning/NozzleTempInsert.h" //To provide nozzle temperature commands. #include "sliceDataStorage.h" //To provide slice data as input for the planning stage. #include "utils/Coord_t.h" -#include // NOLINTBEGIN(*-magic-numbers) namespace cura @@ -59,7 +61,9 @@ class LayerPlanTest : public testing::Test */ Mesh mesh; - LayerPlanTest() : storage(setUpStorage()), layer_plan(*storage, 100, 10000, 100, 0, fan_speed_layer_time_settings, 20, 10, 5000) + LayerPlanTest() + : storage(setUpStorage()) + , layer_plan(*storage, 100, 10000, 100, 0, fan_speed_layer_time_settings, 20, 10, 5000) { } @@ -119,7 +123,8 @@ class LayerPlanTest : public testing::Test settings->add("machine_width", "1000"); settings->add("material_flow_layer_0", "100"); settings->add("meshfix_maximum_travel_resolution", "0"); - settings->add("prime_tower_mode", "default"); + settings->add("prime_tower_enable", "false"); + settings->add("prime_tower_mode", "normal"); settings->add("prime_tower_flow", "108"); settings->add("prime_tower_line_width", "0.48"); settings->add("prime_tower_min_volume", "10"); @@ -312,7 +317,8 @@ class AddTravelTest : public LayerPlanTest, public testing::WithParamInterface("false", "false", "off", false, false, AddTravelTestScene::OPEN)) + AddTravelTest() + : parameters(std::make_tuple("false", "false", "off", false, false, AddTravelTestScene::OPEN)) { around_start_end.add(Point2LL(-100, -100)); around_start_end.add(Point2LL(500100, -100)); @@ -353,7 +359,8 @@ class AddTravelTest : public LayerPlanTest, public testing::WithParamInterfaceadd("retraction_hop_enabled", parameters.hop_enable); settings->add("retraction_combing", parameters.combing); settings->add("retraction_min_travel", parameters.is_long ? "1" : "10000"); // If disabled, give it a high minimum travel so we're sure that our travel move is shorter. - storage->retraction_wipe_config_per_extruder[0].retraction_config.retraction_min_travel_distance = settings->get("retraction_min_travel"); // Update the copy that the storage has of this. + storage->retraction_wipe_config_per_extruder[0].retraction_config.retraction_min_travel_distance + = settings->get("retraction_min_travel"); // Update the copy that the storage has of this. settings->add("retraction_combing_max_distance", parameters.is_long_combing ? "1" : "10000"); Polygons slice_data; @@ -411,9 +418,16 @@ class AddTravelTest : public LayerPlanTest, public testing::WithParamInterface Date: Thu, 29 Feb 2024 17:26:28 +0100 Subject: [PATCH 143/201] Apply review comments. Avoid lambda for just one use, use consts more. done as part of CURA-11537 --- src/FffPolygonGenerator.cpp | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/src/FffPolygonGenerator.cpp b/src/FffPolygonGenerator.cpp index 7c9b188a77..b0d5ff5ff2 100644 --- a/src/FffPolygonGenerator.cpp +++ b/src/FffPolygonGenerator.cpp @@ -769,17 +769,6 @@ bool FffPolygonGenerator::isEmptyLayer(SliceDataStorage& storage, const LayerInd void FffPolygonGenerator::removeEmptyFirstLayers(SliceDataStorage& storage, size_t& total_layers) { - const auto get_highest_z = [&storage](const LayerIndex& layer_idx) - { - coord_t highest_z = 0; - for (std::shared_ptr& mesh_ptr : storage.meshes) - { - auto& mesh = *mesh_ptr; - highest_z = layer_idx >= mesh.layers.size() ? highest_z : std::max(highest_z, mesh.layers[layer_idx].printZ); - } - return highest_z; - }; - size_t n_empty_first_layers = 0; coord_t hightest_empty_layer = 0; for (size_t layer_idx = 0; layer_idx < total_layers; layer_idx++) @@ -787,7 +776,14 @@ void FffPolygonGenerator::removeEmptyFirstLayers(SliceDataStorage& storage, size if (isEmptyLayer(storage, layer_idx)) { n_empty_first_layers++; - hightest_empty_layer = get_highest_z(layer_idx); + + coord_t layer_highest_z = 0; + for (const std::shared_ptr& mesh_ptr : storage.meshes) + { + const auto& mesh = *mesh_ptr; + layer_highest_z = layer_idx >= mesh.layers.size() ? layer_highest_z : std::max(layer_highest_z, mesh.layers[layer_idx].printZ); + } + hightest_empty_layer = std::max(hightest_empty_layer, layer_highest_z); } else { From 8c370bdb0d4163eac75c99130f54e0efde47c9a2 Mon Sep 17 00:00:00 2001 From: Remco Burema Date: Tue, 5 Mar 2024 16:35:23 +0100 Subject: [PATCH 144/201] Fix unit-tests. --- tests/LayerPlanTest.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/LayerPlanTest.cpp b/tests/LayerPlanTest.cpp index 88ebbf4331..b65fc37fda 100644 --- a/tests/LayerPlanTest.cpp +++ b/tests/LayerPlanTest.cpp @@ -119,6 +119,7 @@ class LayerPlanTest : public testing::Test settings->add("machine_width", "1000"); settings->add("material_flow_layer_0", "100"); settings->add("meshfix_maximum_travel_resolution", "0"); + settings->add("prime_tower_enable", "false"); settings->add("prime_tower_mode", "default"); settings->add("prime_tower_flow", "108"); settings->add("prime_tower_line_width", "0.48"); From 25e134de6bf62a469ab6806733522f2210efc286 Mon Sep 17 00:00:00 2001 From: Remco Burema Date: Wed, 6 Mar 2024 18:28:47 +0100 Subject: [PATCH 145/201] Update branch to surrounding code. part of CURA-11485 (also ref CURA-11265) --- src/LayerPlan.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/LayerPlan.cpp b/src/LayerPlan.cpp index f0a029cf03..fa4787b24e 100644 --- a/src/LayerPlan.cpp +++ b/src/LayerPlan.cpp @@ -2150,9 +2150,9 @@ void LayerPlan::writeGCode(GCodeExport& gcode) else { gcode.writeZhopEnd(); - if (z > 0 && path.z_offset != 0) + if (z_ > 0 && path.z_offset != 0) { - gcode.setZ(z + path.z_offset); + gcode.setZ(z_ + path.z_offset); } } } From 7b6906a171bac66f09ebf956e811f344f3bde31c Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Thu, 7 Mar 2024 09:01:49 +0100 Subject: [PATCH 146/201] Fix some support brim generation CURA-9838 --- src/SkirtBrim.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/SkirtBrim.cpp b/src/SkirtBrim.cpp index ea8af8fcd3..64c5fa900e 100644 --- a/src/SkirtBrim.cpp +++ b/src/SkirtBrim.cpp @@ -634,7 +634,7 @@ std::vector SkirtBrim::generateAllowedAreas(const std::vector Date: Thu, 7 Mar 2024 09:02:11 +0100 Subject: [PATCH 147/201] Slight optimization CURA-9838 --- src/SkirtBrim.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/SkirtBrim.cpp b/src/SkirtBrim.cpp index 64c5fa900e..569917b222 100644 --- a/src/SkirtBrim.cpp +++ b/src/SkirtBrim.cpp @@ -92,6 +92,7 @@ std::vector SkirtBrim::generateBrimOffsetPlan(std::vector= 0 && extruder_nr != skirt_brim_extruder_nr_) || starting_outlines[extruder_nr].empty()) { @@ -101,7 +102,7 @@ std::vector SkirtBrim::generateBrimOffsetPlan(std::vector Date: Thu, 7 Mar 2024 11:35:13 +0100 Subject: [PATCH 148/201] Keep consistency with code styling CURA-9838 --- src/SkirtBrim.cpp | 35 ++++++++++++++++------------------- 1 file changed, 16 insertions(+), 19 deletions(-) diff --git a/src/SkirtBrim.cpp b/src/SkirtBrim.cpp index 569917b222..24363718b1 100644 --- a/src/SkirtBrim.cpp +++ b/src/SkirtBrim.cpp @@ -315,11 +315,9 @@ Polygons SkirtBrim::getFirstLayerOutline(const int extruder_nr /* = -1 */) for (int i_layer = layer_nr; i_layer < skirt_height; ++i_layer) { - first_layer_outline = first_layer_outline.unionPolygons(storage_.getLayerOutlines( - i_layer, - /*include_support*/ true, - /*include_prime_tower*/ true, - true)); + constexpr bool include_support = true; + constexpr bool include_prime_tower = true; + first_layer_outline = first_layer_outline.unionPolygons(storage_.getLayerOutlines(i_layer, include_support, include_prime_tower, true)); } Polygons shields; @@ -563,20 +561,19 @@ std::vector SkirtBrim::generateAllowedAreas(const std::vector Date: Thu, 7 Mar 2024 11:45:00 +0100 Subject: [PATCH 149/201] Minor code styling fix CURA-9838 --- src/SkirtBrim.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/SkirtBrim.cpp b/src/SkirtBrim.cpp index 24363718b1..013df7e339 100644 --- a/src/SkirtBrim.cpp +++ b/src/SkirtBrim.cpp @@ -222,13 +222,17 @@ coord_t SkirtBrim::generateOffset(const Offset& offset, Polygons& covered_area, if (std::holds_alternative(offset.reference_outline_or_index_)) { Polygons* reference_outline = std::get(offset.reference_outline_or_index_); + const coord_t offset_value = offset.offset_value_; for (ConstPolygonRef polygon : *reference_outline) { - const coord_t offset_value = offset.offset_value_; const double area = polygon.area(); - if ((area > 0 && offset.outside_) || (area < 0 && offset.inside_)) + if (area > 0 && offset.outside_) { - brim.add(polygon.offset(area < 0 ? -offset_value : offset_value, ClipperLib::jtRound)); + brim.add(polygon.offset(offset_value, ClipperLib::jtRound)); + } + else if (area < 0 && offset.inside_) + { + brim.add(polygon.offset(-offset_value, ClipperLib::jtRound)); } } } From 1b9fe0d6f26ab89ade1a5ee897c5cd52411ae426 Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Thu, 7 Mar 2024 16:01:10 +0100 Subject: [PATCH 150/201] Fix previous copy-paste error CURA-9838 --- src/SkirtBrim.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/SkirtBrim.cpp b/src/SkirtBrim.cpp index 013df7e339..18f0d0d13e 100644 --- a/src/SkirtBrim.cpp +++ b/src/SkirtBrim.cpp @@ -576,7 +576,8 @@ std::vector SkirtBrim::generateAllowedAreas(const std::vector Date: Fri, 8 Mar 2024 15:50:23 +0100 Subject: [PATCH 151/201] Pin package and requirements versions --- conandata.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/conandata.yml b/conandata.yml index 14cf72dc44..a5527b0e01 100644 --- a/conandata.yml +++ b/conandata.yml @@ -1,7 +1,7 @@ -version: "5.7.0-alpha.1" +version: "5.7.0-beta.1" requirements: - "scripta/0.1.0@ultimaker/testing" requirements_arcus: - "arcus/5.3.1" requirements_plugins: - - "curaengine_grpc_definitions/(latest)@ultimaker/testing" + - "curaengine_grpc_definitions/0.2.0" From 885690a5c98b1f804d8f319bcce828694c621a6c Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Fri, 8 Mar 2024 16:22:45 +0100 Subject: [PATCH 152/201] Use latest versions --- conandata.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conandata.yml b/conandata.yml index a5527b0e01..abaa39d954 100644 --- a/conandata.yml +++ b/conandata.yml @@ -4,4 +4,4 @@ requirements: requirements_arcus: - "arcus/5.3.1" requirements_plugins: - - "curaengine_grpc_definitions/0.2.0" + - "curaengine_grpc_definitions/(latest)@ultimaker/testing" From 5aa95557eb09c4c4e768649958ceb8d15e636ee4 Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Fri, 8 Mar 2024 16:23:15 +0100 Subject: [PATCH 153/201] Use stable channel --- conandata.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conandata.yml b/conandata.yml index abaa39d954..217683c18c 100644 --- a/conandata.yml +++ b/conandata.yml @@ -4,4 +4,4 @@ requirements: requirements_arcus: - "arcus/5.3.1" requirements_plugins: - - "curaengine_grpc_definitions/(latest)@ultimaker/testing" + - "curaengine_grpc_definitions/(latest)@ultimaker/stable" From 3d265555a830edad1178e067cc5a90e6aceb98aa Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Mon, 11 Mar 2024 08:19:34 +0100 Subject: [PATCH 154/201] Set correct beta version number Co-authored-by: Jelle Spijker --- conandata.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conandata.yml b/conandata.yml index 217683c18c..c6431bf4b4 100644 --- a/conandata.yml +++ b/conandata.yml @@ -1,4 +1,4 @@ -version: "5.7.0-beta.1" +version: "5.7.0-beta.0" requirements: - "scripta/0.1.0@ultimaker/testing" requirements_arcus: From 30e6b720179ef4cb4c9de8681c3441b9a500e75f Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Mon, 11 Mar 2024 08:39:31 +0100 Subject: [PATCH 155/201] Pin grpc_definitions version --- conandata.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conandata.yml b/conandata.yml index c6431bf4b4..cd46bd06a0 100644 --- a/conandata.yml +++ b/conandata.yml @@ -4,4 +4,4 @@ requirements: requirements_arcus: - "arcus/5.3.1" requirements_plugins: - - "curaengine_grpc_definitions/(latest)@ultimaker/stable" + - "curaengine_grpc_definitions/0.2.0" From 74816bf1e6ac8ccf817e128eeaf9b2409e002d63 Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Mon, 11 Mar 2024 09:10:18 +0100 Subject: [PATCH 156/201] Change version to 5.8 alpha --- conandata.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conandata.yml b/conandata.yml index 14cf72dc44..858634c9a0 100644 --- a/conandata.yml +++ b/conandata.yml @@ -1,4 +1,4 @@ -version: "5.7.0-alpha.1" +version: "5.8.0-alpha.0" requirements: - "scripta/0.1.0@ultimaker/testing" requirements_arcus: From 8d297ecb6dff44a8e793a41b2b81fcfbbc468c3c Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Mon, 11 Mar 2024 10:10:57 +0100 Subject: [PATCH 157/201] Fix secondary brim generation CURA-11708 --- src/SkirtBrim.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/SkirtBrim.cpp b/src/SkirtBrim.cpp index 18f0d0d13e..d76a16fc49 100644 --- a/src/SkirtBrim.cpp +++ b/src/SkirtBrim.cpp @@ -508,15 +508,15 @@ void SkirtBrim::generateSecondarySkirtBrim(Polygons& covered_area, std::vector

(storage_.skirt_brim[extruder_nr].size() - 1); offset_from_reference = extruder_config.line_width_; } - constexpr bool outside_polys = true; - constexpr bool inside_polys = true; // The reference outline may contain both outlines and hole polygons. + const bool outside_polys = extruder_config.outside_polys_; + const bool inside_polys = extruder_config.inside_polys_; Offset extra_offset( ref_polys_or_idx, outside_polys, From 3ea6e8f90219342ea8922637e6366f7aa29e795e Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Tue, 12 Mar 2024 16:07:28 +0100 Subject: [PATCH 158/201] Fix unecessary travel move to prime tower CURA-11713 --- src/PrimeTower.cpp | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/src/PrimeTower.cpp b/src/PrimeTower.cpp index b2afe03d6f..57dc4d9853 100644 --- a/src/PrimeTower.cpp +++ b/src/PrimeTower.cpp @@ -348,12 +348,6 @@ void PrimeTower::addToGcode( post_wipe = false; } - // Go to the start location if it's not the first layer - if (layer_nr != 0) - { - gotoStartLocation(gcode_layer, new_extruder_nr); - } - auto extruder_iterator = std::find_if( required_extruder_prime.begin(), required_extruder_prime.end(), @@ -393,11 +387,14 @@ void PrimeTower::addToGcode( break; case ExtruderPrime::Sparse: + gotoStartLocation(gcode_layer, new_extruder_nr); extra_primed_extruders_idx = findExtrudersSparseInfill(gcode_layer, required_extruder_prime, method, { new_extruder_idx }); addToGcode_sparseInfill(gcode_layer, extra_primed_extruders_idx, new_extruder_nr); break; case ExtruderPrime::Prime: + gotoStartLocation(gcode_layer, new_extruder_nr); + addToGcode_denseInfill(gcode_layer, new_extruder_nr); gcode_layer.setPrimeTowerIsPlanned(new_extruder_nr); @@ -627,19 +624,22 @@ const Polygons& PrimeTower::getGroundPoly() const void PrimeTower::gotoStartLocation(LayerPlan& gcode_layer, const int extruder_nr) const { - int current_start_location_idx = ((((extruder_nr + 1) * gcode_layer.getLayerNr()) % number_of_prime_tower_start_locations_) + number_of_prime_tower_start_locations_) - % number_of_prime_tower_start_locations_; + if (gcode_layer.getLayerNr() != 0) + { + int current_start_location_idx = ((((extruder_nr + 1) * gcode_layer.getLayerNr()) % number_of_prime_tower_start_locations_) + number_of_prime_tower_start_locations_) + % number_of_prime_tower_start_locations_; - const ClosestPolygonPoint wipe_location = prime_tower_start_locations_[current_start_location_idx]; + const ClosestPolygonPoint wipe_location = prime_tower_start_locations_[current_start_location_idx]; - const ExtruderTrain& train = Application::getInstance().current_slice_->scene.extruders[extruder_nr]; - const coord_t inward_dist = train.settings_.get("machine_nozzle_size") * 3 / 2; - const coord_t start_dist = train.settings_.get("machine_nozzle_size") * 2; - const Point2LL prime_end = PolygonUtils::moveInsideDiagonally(wipe_location, inward_dist); - const Point2LL outward_dir = wipe_location.location_ - prime_end; - const Point2LL prime_start = wipe_location.location_ + normal(outward_dir, start_dist); + const ExtruderTrain& train = Application::getInstance().current_slice_->scene.extruders[extruder_nr]; + const coord_t inward_dist = train.settings_.get("machine_nozzle_size") * 3 / 2; + const coord_t start_dist = train.settings_.get("machine_nozzle_size") * 2; + const Point2LL prime_end = PolygonUtils::moveInsideDiagonally(wipe_location, inward_dist); + const Point2LL outward_dir = wipe_location.location_ - prime_end; + const Point2LL prime_start = wipe_location.location_ + normal(outward_dir, start_dist); - gcode_layer.addTravel(prime_start); + gcode_layer.addTravel(prime_start); + } } } // namespace cura From a637b9391db34ec650334b3707ce70512f7a8fb5 Mon Sep 17 00:00:00 2001 From: Saumya Jain Date: Tue, 12 Mar 2024 16:47:09 +0100 Subject: [PATCH 159/201] added condition for disabling initial travel in case of one at a time CURA-11724 --- src/FffGcodeWriter.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/FffGcodeWriter.cpp b/src/FffGcodeWriter.cpp index a894421de3..b9ef26566b 100644 --- a/src/FffGcodeWriter.cpp +++ b/src/FffGcodeWriter.cpp @@ -142,7 +142,8 @@ void FffGcodeWriter::writeGCode(SliceDataStorage& storage, TimeKeeper& time_keep } const auto extruder_settings = Application::getInstance().current_slice_->scene.extruders[gcode.getExtruderNr()].settings_; // in case the prime blob is enabled the brim already starts from the closest start position which is blob location - if (! extruder_settings.get("prime_blob_enable")) + // also in case of one at a time printing the first move of every object shouldn't be start position of machine + if (! extruder_settings.get("prime_blob_enable") and ! (extruder_settings.get("print_sequence")=="one_at_a_time") ) { // Setting first travel move of the first extruder to the machine start position Point3LL p(extruder_settings.get("machine_extruder_start_pos_x"), extruder_settings.get("machine_extruder_start_pos_y"), gcode.getPositionZ()); From 91a6a52c326567b49f2e2837a9a0d57d0f9db700 Mon Sep 17 00:00:00 2001 From: saumyaj3 Date: Tue, 12 Mar 2024 15:47:43 +0000 Subject: [PATCH 160/201] Applied clang-format. --- src/FffGcodeWriter.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/FffGcodeWriter.cpp b/src/FffGcodeWriter.cpp index b9ef26566b..1553726810 100644 --- a/src/FffGcodeWriter.cpp +++ b/src/FffGcodeWriter.cpp @@ -143,7 +143,7 @@ void FffGcodeWriter::writeGCode(SliceDataStorage& storage, TimeKeeper& time_keep const auto extruder_settings = Application::getInstance().current_slice_->scene.extruders[gcode.getExtruderNr()].settings_; // in case the prime blob is enabled the brim already starts from the closest start position which is blob location // also in case of one at a time printing the first move of every object shouldn't be start position of machine - if (! extruder_settings.get("prime_blob_enable") and ! (extruder_settings.get("print_sequence")=="one_at_a_time") ) + if (! extruder_settings.get("prime_blob_enable") and ! (extruder_settings.get("print_sequence") == "one_at_a_time")) { // Setting first travel move of the first extruder to the machine start position Point3LL p(extruder_settings.get("machine_extruder_start_pos_x"), extruder_settings.get("machine_extruder_start_pos_y"), gcode.getPositionZ()); From 8003645ede9ab51f7782f940aa6aeb82c99258d0 Mon Sep 17 00:00:00 2001 From: Remco Burema Date: Wed, 13 Mar 2024 16:56:19 +0100 Subject: [PATCH 161/201] Remove outdated documentation parts. done as part of CURA-11424 --- include/FffGcodeWriter.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/FffGcodeWriter.h b/include/FffGcodeWriter.h index c4d536dccd..21b65e76e4 100644 --- a/include/FffGcodeWriter.h +++ b/include/FffGcodeWriter.h @@ -634,8 +634,8 @@ class FffGcodeWriter : public NoCopy * layer. * * \param[in] storage Where the slice data is stored. - * \param[in] support_roof_outlines which polygons to generate roofs for -- originally split-up because of fractional (layer-height) layers - * \param[in] current_roof_config config to be used -- most importantly, support has slightly different configs for fractional (layer-height) layers + * \param[in] support_roof_outlines which polygons to generate roofs for. + * \param[in] current_roof_config config to be used. * \param gcodeLayer The initial planning of the g-code of the layer. * \return Whether any support skin was added to the layer plan. */ From 30880aed6b155f928034225f032e628e128ac1c4 Mon Sep 17 00:00:00 2001 From: Remco Burema Date: Wed, 13 Mar 2024 17:03:56 +0100 Subject: [PATCH 162/201] Get fractional support from model-overhang instead of layer above. The detection of where fractional support layers (where the z-distance between model and support was a fractional value compared to support-layer-height) where supposed to be was handled by looking at the internal structure of the support layers itself, rather than where it's actually needed. This fix replaces the previous mehtod, which looked at if the layer above this one had support, and if not, assumed that the gap with the model nust be directly above it (this was originally done both for performance reasons, and making it less dependant on the model and thus more encapsulated) -- but this has proven to be a mistake, given how many problems it introduces. The new method instead queries the meshes directly for the overhang. Otherwise, any gap between two layers of support would introduce new 'fractional support layers', which aren't supposed to be in those places. part of CURA-11424 --- include/sliceDataStorage.h | 8 ++++++-- src/TreeSupport.cpp | 11 +++++++++-- src/TreeSupportTipGenerator.cpp | 12 ++++++++++-- src/sliceDataStorage.cpp | 21 +++++++++++++++++---- src/support.cpp | 9 ++++++++- 5 files changed, 50 insertions(+), 11 deletions(-) diff --git a/include/sliceDataStorage.h b/include/sliceDataStorage.h index 22bfca6ea6..9689ceb1cd 100644 --- a/include/sliceDataStorage.h +++ b/include/sliceDataStorage.h @@ -230,8 +230,10 @@ class SupportLayer /* Fill up the infill parts for the support with the given support polygons. The support polygons will be split into parts. This also takes into account fractional-height * support layers. * - * \param layer_nr Current layer index. - * \param support_fill_per_layer All of the (infill) support (since the layer above might be needed). + * \param layer_nr The layer-index of the support layer to be filled. + * \param support_fill_per_layer The support polygons to fill up with infill parts. + * \param infill_layer_height The layer height of the support-fill. + * \param meshes The model meshes to be supported, needed here to handle fractional support layer height. * \param support_line_width Line width of the support extrusions. * \param wall_line_count Wall-line count around the fill. * \param grow_layer_above (optional, default to 0) In cases where support shrinks per layer up, an appropriate offset may be nescesary. @@ -241,6 +243,8 @@ class SupportLayer void fillInfillParts( const LayerIndex layer_nr, const std::vector& support_fill_per_layer, + const coord_t infill_layer_height, + const std::vector>& meshes, const coord_t support_line_width, const coord_t wall_line_count, const coord_t grow_layer_above = 0, diff --git a/src/TreeSupport.cpp b/src/TreeSupport.cpp index 9ac7a9eebb..beca41e6d2 100644 --- a/src/TreeSupport.cpp +++ b/src/TreeSupport.cpp @@ -2237,9 +2237,16 @@ void TreeSupport::finalizeInterfaceAndSupportAreas(std::vector& suppor [&](const LayerIndex layer_idx) { constexpr bool convert_every_part = true; // Convert every part into a PolygonsPart for the support. - storage.support.supportLayers[layer_idx] - .fillInfillParts(layer_idx, support_layer_storage, config.support_line_width, config.support_wall_count, config.maximum_move_distance, convert_every_part); + storage.support.supportLayers[layer_idx].fillInfillParts( + layer_idx, + support_layer_storage, + config.layer_height, + storage.meshes, + config.support_line_width, + config.support_wall_count, + config.maximum_move_distance, + convert_every_part); { std::lock_guard critical_section_progress(critical_sections); progress_total += TREE_PROGRESS_FINALIZE_BRANCH_AREAS / support_layer_storage.size(); diff --git a/src/TreeSupportTipGenerator.cpp b/src/TreeSupportTipGenerator.cpp index a908d06d71..969fc1fe58 100644 --- a/src/TreeSupportTipGenerator.cpp +++ b/src/TreeSupportTipGenerator.cpp @@ -1163,8 +1163,16 @@ void TreeSupportTipGenerator::generateTips( { if (use_fake_roof_) { - storage.support.supportLayers[layer_idx] - .fillInfillParts(layer_idx, support_roof_drawn_, config_.support_line_width, 0, config_.maximum_move_distance, false, support_roof_line_distance_); + storage.support.supportLayers[layer_idx].fillInfillParts( + layer_idx, + support_roof_drawn_, + config_.layer_height, + storage.meshes, + config_.support_line_width, + 0, + config_.maximum_move_distance, + false, + support_roof_line_distance_); placed_support_lines_support_areas[layer_idx].add(TreeSupportUtils::generateSupportInfillLines( support_roof_drawn_[layer_idx], config_, diff --git a/src/sliceDataStorage.cpp b/src/sliceDataStorage.cpp index 60d2085b0b..18a1cf9a08 100644 --- a/src/sliceDataStorage.cpp +++ b/src/sliceDataStorage.cpp @@ -759,16 +759,29 @@ void SupportLayer::excludeAreasFromSupportInfillAreas(const Polygons& exclude_po void SupportLayer::fillInfillParts( const LayerIndex layer_nr, const std::vector& support_fill_per_layer, + const coord_t infill_layer_height, + const std::vector>& meshes, const coord_t support_line_width, const coord_t wall_line_count, const coord_t grow_layer_above /*has default 0*/, const bool unionAll /*has default false*/, const coord_t custom_line_distance /*has default 0*/) { - const Polygons& support_this_layer = support_fill_per_layer[layer_nr]; - const Polygons& support_layer_above - = (layer_nr + 1) >= support_fill_per_layer.size() || layer_nr <= 0 ? Polygons() : support_fill_per_layer[layer_nr + 1].offset(grow_layer_above); - const auto all_support_areas_in_layer = { support_this_layer.difference(support_layer_above), support_this_layer.intersection(support_layer_above) }; + // Find the model exactly z-distance above the support layer. + Polygons overhang_z_dist_above; + for (const auto& mesh : meshes) + { + const coord_t mesh_z_distance_top = mesh->settings.get("support_top_distance"); + const size_t overhang_layer_nr = layer_nr + (mesh_z_distance_top / infill_layer_height) + 1; + if (overhang_layer_nr < mesh->overhang_areas.size()) + { + overhang_z_dist_above.add(mesh->overhang_areas[overhang_layer_nr]); + } + } + overhang_z_dist_above = overhang_z_dist_above.unionPolygons(); + + // Split the support outline into areas that are directly under the overhang and areas that are not. + const auto all_support_areas_in_layer = { support_fill_per_layer[layer_nr].intersection(overhang_z_dist_above), support_fill_per_layer[layer_nr].difference(overhang_z_dist_above) }; bool use_fractional_config = true; for (auto& support_areas : all_support_areas_in_layer) { diff --git a/src/support.cpp b/src/support.cpp index 3097afdbbb..9eee8d26f7 100644 --- a/src/support.cpp +++ b/src/support.cpp @@ -120,7 +120,14 @@ void AreaSupport::splitGlobalSupportAreasIntoSupportInfillParts( } // We don't generate insets and infill area for the parts yet because later the skirt/brim and prime // tower will remove themselves from the support, so the outlines of the parts can be changed. - storage.support.supportLayers[layer_nr].fillInfillParts(layer_nr, global_support_areas_per_layer, support_line_width_here, wall_line_count_this_layer); + const coord_t layer_height = infill_extruder.settings_.get("layer_height"); + storage.support.supportLayers[layer_nr].fillInfillParts( + layer_nr, + global_support_areas_per_layer, + layer_height, + storage.meshes, + support_line_width_here, + wall_line_count_this_layer); } } From 17d3906fe36e7dc7e3803d0ff4bccc82ff659430 Mon Sep 17 00:00:00 2001 From: rburema Date: Wed, 13 Mar 2024 16:04:42 +0000 Subject: [PATCH 163/201] Applied clang-format. --- src/sliceDataStorage.cpp | 3 ++- src/support.cpp | 9 ++------- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/src/sliceDataStorage.cpp b/src/sliceDataStorage.cpp index 18a1cf9a08..b369dbb082 100644 --- a/src/sliceDataStorage.cpp +++ b/src/sliceDataStorage.cpp @@ -781,7 +781,8 @@ void SupportLayer::fillInfillParts( overhang_z_dist_above = overhang_z_dist_above.unionPolygons(); // Split the support outline into areas that are directly under the overhang and areas that are not. - const auto all_support_areas_in_layer = { support_fill_per_layer[layer_nr].intersection(overhang_z_dist_above), support_fill_per_layer[layer_nr].difference(overhang_z_dist_above) }; + const auto all_support_areas_in_layer + = { support_fill_per_layer[layer_nr].intersection(overhang_z_dist_above), support_fill_per_layer[layer_nr].difference(overhang_z_dist_above) }; bool use_fractional_config = true; for (auto& support_areas : all_support_areas_in_layer) { diff --git a/src/support.cpp b/src/support.cpp index 9eee8d26f7..cb47d6c20b 100644 --- a/src/support.cpp +++ b/src/support.cpp @@ -121,13 +121,8 @@ void AreaSupport::splitGlobalSupportAreasIntoSupportInfillParts( // We don't generate insets and infill area for the parts yet because later the skirt/brim and prime // tower will remove themselves from the support, so the outlines of the parts can be changed. const coord_t layer_height = infill_extruder.settings_.get("layer_height"); - storage.support.supportLayers[layer_nr].fillInfillParts( - layer_nr, - global_support_areas_per_layer, - layer_height, - storage.meshes, - support_line_width_here, - wall_line_count_this_layer); + storage.support.supportLayers[layer_nr] + .fillInfillParts(layer_nr, global_support_areas_per_layer, layer_height, storage.meshes, support_line_width_here, wall_line_count_this_layer); } } From f49ce7b1929bec23a7cdea0229db34683a2ddc4d Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Fri, 15 Mar 2024 13:47:16 +0100 Subject: [PATCH 164/201] Prepare for 5.7.0-beta.1 release --- conandata.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conandata.yml b/conandata.yml index cd46bd06a0..a5527b0e01 100644 --- a/conandata.yml +++ b/conandata.yml @@ -1,4 +1,4 @@ -version: "5.7.0-beta.0" +version: "5.7.0-beta.1" requirements: - "scripta/0.1.0@ultimaker/testing" requirements_arcus: From 833994551494ef1d0ef2b9d24415c6182b06e7d7 Mon Sep 17 00:00:00 2001 From: "c.lamboo" Date: Mon, 18 Mar 2024 17:17:58 +0100 Subject: [PATCH 165/201] Fix support on top of interface Due to newly added fractional layer height, in combination with the extremely small model height (1 layer) the model was completely missed in the logic that added the roof logic. Added one additional layer in the for loop that checks for model area's in the interface logic to take into account fractional layers. Also removed the "skip layers" logic as this was just a performance optimization that was adding a lot of unneeded complexity in my opinion. CURA-11423 --- include/settings/PathConfigStorage.h | 2 +- src/support.cpp | 16 ++++------------ 2 files changed, 5 insertions(+), 13 deletions(-) diff --git a/include/settings/PathConfigStorage.h b/include/settings/PathConfigStorage.h index feafea23bf..06206f7ebb 100644 --- a/include/settings/PathConfigStorage.h +++ b/include/settings/PathConfigStorage.h @@ -53,7 +53,7 @@ class PathConfigStorage GCodePathConfig support_fractional_roof_config; //!< The config used to print the dense roofs of support on fractional layer-height parts. GCodePathConfig support_bottom_config; //!< The config to use to print the dense bottoms of support - std::vector mesh_configs; //!< For each meash the config for all its feature types + std::vector mesh_configs; //!< For each mesh the config for all its feature types /*! * \warning Note that the layer_nr might be below zero for raft (filler) layers diff --git a/src/support.cpp b/src/support.cpp index 3097afdbbb..fe08055ffc 100644 --- a/src/support.cpp +++ b/src/support.cpp @@ -1680,10 +1680,6 @@ void AreaSupport::generateSupportBottom(SliceDataStorage& storage, const SliceMe const coord_t bottom_line_width = mesh_group_settings.get("support_bottom_extruder_nr").settings_.get("support_bottom_line_width"); const coord_t bottom_outline_offset = mesh_group_settings.get("support_bottom_extruder_nr").settings_.get("support_bottom_offset"); - const size_t scan_count = std::max(size_t(1), (bottom_layer_count - 1)); // How many measurements to take to generate bottom areas. - const double z_skip = std::max( - 1.0, - double(bottom_layer_count - 1) / double(scan_count)); // How many layers to skip between measurements. Using float for better spread, but this is later rounded. const double minimum_bottom_area = mesh.settings.get("minimum_bottom_area"); std::vector& support_layers = storage.support.supportLayers; @@ -1691,9 +1687,9 @@ void AreaSupport::generateSupportBottom(SliceDataStorage& storage, const SliceMe { const unsigned int bottom_layer_idx_below = std::max(0, int(layer_idx) - int(bottom_layer_count) - int(z_distance_bottom)); Polygons mesh_outlines; - for (double layer_idx_below = bottom_layer_idx_below; std::round(layer_idx_below) < (int)(layer_idx - z_distance_bottom); layer_idx_below += z_skip) + for (auto layer_idx_below = bottom_layer_idx_below; layer_idx_below < layer_idx - z_distance_bottom + 1; layer_idx_below += 1) { - mesh_outlines.add(mesh.layers[std::round(layer_idx_below)].getOutlines()); + mesh_outlines.add(mesh.layers[layer_idx_below].getOutlines()); } Polygons bottoms; generateSupportInterfaceLayer(global_support_areas_per_layer[layer_idx], mesh_outlines, bottom_line_width, bottom_outline_offset, minimum_bottom_area, bottoms); @@ -1715,10 +1711,6 @@ void AreaSupport::generateSupportRoof(SliceDataStorage& storage, const SliceMesh const coord_t roof_line_width = mesh_group_settings.get("support_roof_extruder_nr").settings_.get("support_roof_line_width"); const coord_t roof_outline_offset = mesh_group_settings.get("support_roof_extruder_nr").settings_.get("support_roof_offset"); - const size_t scan_count = std::max(size_t(1), (roof_layer_count - 1)); // How many measurements to take to generate roof areas. - const double z_skip = std::max( - 1.0, - double(roof_layer_count - 1) / double(scan_count)); // How many layers to skip between measurements. Using float for better spread, but this is later rounded. const double minimum_roof_area = mesh.settings.get("minimum_roof_area"); std::vector& support_layers = storage.support.supportLayers; @@ -1728,9 +1720,9 @@ void AreaSupport::generateSupportRoof(SliceDataStorage& storage, const SliceMesh std::min(LayerIndex{ support_layers.size() - 1 }, LayerIndex{ layer_idx + roof_layer_count + z_distance_top }) }; // Maximum layer of the model that generates support roof. Polygons mesh_outlines; - for (double layer_idx_above = top_layer_idx_above; layer_idx_above > layer_idx + z_distance_top; layer_idx_above -= z_skip) + for (auto layer_idx_above = top_layer_idx_above; layer_idx_above > layer_idx + z_distance_top - 1; layer_idx_above -= 1) { - mesh_outlines.add(mesh.layers[std::round(layer_idx_above)].getOutlines()); + mesh_outlines.add(mesh.layers[layer_idx_above].getOutlines()); } Polygons roofs; generateSupportInterfaceLayer(global_support_areas_per_layer[layer_idx], mesh_outlines, roof_line_width, roof_outline_offset, minimum_roof_area, roofs); From 27cc0dbc98bd1a0074ebb79d12625abadc526605 Mon Sep 17 00:00:00 2001 From: Saumya Jain Date: Wed, 20 Mar 2024 14:38:22 +0100 Subject: [PATCH 166/201] Added a defensive code. I am not sure how I can reproduce this error. CURA-11742 --- src/LayerPlan.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/LayerPlan.cpp b/src/LayerPlan.cpp index fa4787b24e..56cd17964d 100644 --- a/src/LayerPlan.cpp +++ b/src/LayerPlan.cpp @@ -2206,7 +2206,10 @@ void LayerPlan::writeGCode(GCodeExport& gcode) // We need to unretract before the last travel move of the path if the next path is an outer wall. gcode.writeUnretractionAndPrime(); } - gcode.writeTravel(path.points.back(), speed); + if (!path.points.empty()) + { + gcode.writeTravel(path.points.back(), speed); + } continue; } From bd867c2491514117966a4af0debea5b2206128ff Mon Sep 17 00:00:00 2001 From: saumyaj3 Date: Wed, 20 Mar 2024 13:39:07 +0000 Subject: [PATCH 167/201] Applied clang-format. --- src/LayerPlan.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/LayerPlan.cpp b/src/LayerPlan.cpp index 56cd17964d..f4786aa098 100644 --- a/src/LayerPlan.cpp +++ b/src/LayerPlan.cpp @@ -2206,7 +2206,7 @@ void LayerPlan::writeGCode(GCodeExport& gcode) // We need to unretract before the last travel move of the path if the next path is an outer wall. gcode.writeUnretractionAndPrime(); } - if (!path.points.empty()) + if (! path.points.empty()) { gcode.writeTravel(path.points.back(), speed); } From 794357bf4172660a02c27623b0b1ae055959f6be Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Wed, 20 Mar 2024 16:09:58 +0100 Subject: [PATCH 168/201] Fix double support on first layer CURA-11414 --- src/FffGcodeWriter.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/FffGcodeWriter.cpp b/src/FffGcodeWriter.cpp index 1553726810..c030e11a9d 100644 --- a/src/FffGcodeWriter.cpp +++ b/src/FffGcodeWriter.cpp @@ -3673,7 +3673,7 @@ bool FffGcodeWriter::addSupportRoofsToGCode( // make sure there is a wall if this is on the first layer if (gcode_layer.getLayerNr() == 0) { - wall = support_layer.support_roof.offset(-support_roof_line_width / 2); + wall = support_roof_outlines.offset(-support_roof_line_width / 2); infill_outline = wall.offset(-support_roof_line_width / 2); } infill_outline = Simplify(roof_extruder.settings_).polygon(infill_outline); From 1394f31214a6c59e03b3f26c27470571e9ecb703 Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Fri, 22 Mar 2024 12:25:56 +0100 Subject: [PATCH 169/201] Fix possible crash when retrieving extruders uses Ensure we never try to access elements on an empty or non-existing extruders use list by checking bounds, because in some edge-cases we may want to access extruders uses of empty layers. CURA-11757 --- include/FffGcodeWriter.h | 10 +++-- src/FffGcodeWriter.cpp | 83 ++++++++++++++++++++++++++++------------ 2 files changed, 66 insertions(+), 27 deletions(-) diff --git a/include/FffGcodeWriter.h b/include/FffGcodeWriter.h index 21b65e76e4..3e4fea6f1f 100644 --- a/include/FffGcodeWriter.h +++ b/include/FffGcodeWriter.h @@ -170,7 +170,7 @@ class FffGcodeWriter : public NoCopy * * \param[in] storage where to get settings from. */ - size_t getStartExtruder(const SliceDataStorage& storage); + size_t getStartExtruder(const SliceDataStorage& storage) const; /*! * Set the infill angles and skin angles in the SliceDataStorage. @@ -287,7 +287,7 @@ class FffGcodeWriter : public NoCopy void calculatePrimeLayerPerExtruder(const SliceDataStorage& storage); /*! - * Gets a list of extruders that are used on the given layer, but excluding the given starting extruder. + * Gets a list of extruders that are used on the given layer. * When it's on the first layer, the prime blob will also be taken into account. * * \note At the planning stage we only have information on areas, not how those are filled. @@ -297,7 +297,7 @@ class FffGcodeWriter : public NoCopy * \param current_extruder The current extruder with which we last printed * \return The order of extruders for a layer beginning with \p current_extruder */ - std::vector getUsedExtrudersOnLayerExcludingStartingExtruder(const SliceDataStorage& storage, const size_t start_extruder, const LayerIndex& layer_nr) const; + std::vector getUsedExtrudersOnLayer(const SliceDataStorage& storage, const size_t start_extruder, const LayerIndex& layer_nr) const; /*! * Calculate in which order to plan the meshes of a specific extruder @@ -715,6 +715,10 @@ class FffGcodeWriter : public NoCopy const SliceMeshStorage& mesh, const SliceLayerPart& part, coord_t infill_line_width); + + size_t findUsedExtruderIndex(const SliceDataStorage& storage, const LayerIndex& layer_nr, bool last) const; + + std::vector getExtruderUse(const LayerIndex& layer_nr) const; }; } // namespace cura diff --git a/src/FffGcodeWriter.cpp b/src/FffGcodeWriter.cpp index c030e11a9d..60e116e06e 100644 --- a/src/FffGcodeWriter.cpp +++ b/src/FffGcodeWriter.cpp @@ -278,7 +278,7 @@ void FffGcodeWriter::findLayerSeamsForSpiralize(SliceDataStorage& storage, size_ bool done_this_layer = false; // iterate through extruders until we find a mesh that has a part with insets - const std::vector& extruder_order = extruder_order_per_layer[layer_nr]; + const std::vector extruder_order = getExtruderUse(layer_nr); for (unsigned int extruder_idx = 0; ! done_this_layer && extruder_idx < extruder_order.size(); ++extruder_idx) { const size_t extruder_nr = extruder_order[extruder_idx].extruder_nr; @@ -394,7 +394,7 @@ void FffGcodeWriter::setConfigRetractionAndWipe(SliceDataStorage& storage) } } -size_t FffGcodeWriter::getStartExtruder(const SliceDataStorage& storage) +size_t FffGcodeWriter::getStartExtruder(const SliceDataStorage& storage) const { const Settings& mesh_group_settings = Application::getInstance().current_slice_->scene.current_mesh_group->settings; const EPlatformAdhesion adhesion_type = mesh_group_settings.get("adhesion_type"); @@ -1181,24 +1181,10 @@ FffGcodeWriter::ProcessLayerResult FffGcodeWriter::processLayer(const SliceDataS assert( static_cast(extruder_order_per_layer_negative_layers.size()) + layer_nr >= 0 && "Layer numbers shouldn't get more negative than there are raft/filler layers"); - const std::vector& extruder_order - = (layer_nr < 0) ? extruder_order_per_layer_negative_layers[extruder_order_per_layer_negative_layers.size() + layer_nr] : extruder_order_per_layer[layer_nr]; - size_t first_extruder; - if (extruder_order.size() > 0) - { - first_extruder = extruder_order.front().extruder_nr; - } - else - { - // find the last extruder used in the previous layer - size_t last_extruder_nr_layer = layer_nr - 1; - while (extruder_order_per_layer[last_extruder_nr_layer].size() == 0 && last_extruder_nr_layer >= 0) - { - last_extruder_nr_layer--; - } - first_extruder = extruder_order_per_layer[last_extruder_nr_layer].back().extruder_nr; - } + const size_t first_extruder = findUsedExtruderIndex(storage, layer_nr, false); + + const std::vector extruder_order = getExtruderUse(layer_nr); const coord_t first_outer_wall_line_width = scene.extruders[first_extruder].settings_.get("wall_line_width_0"); LayerPlan& gcode_layer = *new LayerPlan( @@ -1562,7 +1548,7 @@ void FffGcodeWriter::calculateExtruderOrderPerLayer(const SliceDataStorage& stor for (LayerIndex layer_nr = -Raft::getTotalExtraLayers(); layer_nr < static_cast(storage.print_layer_count); layer_nr++) { std::vector>& extruder_order_per_layer_here = (layer_nr < 0) ? extruder_order_per_layer_negative_layers : extruder_order_per_layer; - std::vector extruder_order = getUsedExtrudersOnLayerExcludingStartingExtruder(storage, last_extruder, layer_nr); + std::vector extruder_order = getUsedExtrudersOnLayer(storage, last_extruder, layer_nr); extruder_order_per_layer_here.push_back(extruder_order); if (! extruder_order.empty()) @@ -1587,8 +1573,7 @@ void FffGcodeWriter::calculatePrimeLayerPerExtruder(const SliceDataStorage& stor } } -std::vector - FffGcodeWriter::getUsedExtrudersOnLayerExcludingStartingExtruder(const SliceDataStorage& storage, const size_t start_extruder, const LayerIndex& layer_nr) const +std::vector FffGcodeWriter::getUsedExtrudersOnLayer(const SliceDataStorage& storage, const size_t start_extruder, const LayerIndex& layer_nr) const { const Settings& mesh_group_settings = Application::getInstance().current_slice_->scene.current_mesh_group->settings; size_t extruder_count = Application::getInstance().current_slice_->scene.extruders.size(); @@ -2469,6 +2454,53 @@ bool FffGcodeWriter::partitionInfillBySkinAbove( return ! infill_below_skin_overlap.empty() && ! infill_not_below_skin.empty(); } +size_t FffGcodeWriter::findUsedExtruderIndex(const SliceDataStorage& storage, const LayerIndex& layer_nr, bool last) const +{ + const std::vector extruder_use = getExtruderUse(layer_nr); + + if (! extruder_use.empty()) + { + return last ? extruder_use.back().extruder_nr : extruder_use.front().extruder_nr; + } + else if (layer_nr <= -extruder_order_per_layer_negative_layers.size()) + { + // Asking for extruder use below first layer, give first extruder + return getStartExtruder(storage); + } + else + { + // Asking for extruder on an empty layer, get the one from layer below + return findUsedExtruderIndex(storage, layer_nr - 1, true); + } +} + +std::vector FffGcodeWriter::getExtruderUse(const LayerIndex& layer_nr) const +{ + int layer_index; + const std::vector>* extruder_order; + + if (layer_nr >= 0) + { + layer_index = layer_nr; + extruder_order = &extruder_order_per_layer; + } + else + { + layer_index = extruder_order_per_layer_negative_layers.size() + layer_nr; + extruder_order = &extruder_order_per_layer_negative_layers; + } + + if (layer_index >= 0 && layer_index < extruder_order->size()) + { + return (*extruder_order)[layer_index]; + } + else + { + // No extruder use registered for this layer, which may happen in some edge-cases + return {}; + } +} + void FffGcodeWriter::processSpiralizedWall( const SliceDataStorage& storage, LayerPlan& gcode_layer, @@ -3289,6 +3321,10 @@ bool FffGcodeWriter::addSupportToGCode(const SliceDataStorage& storage, LayerPla if (extruder_nr == support_roof_extruder_nr) { support_added |= addSupportRoofsToGCode(storage, support_layer.support_fractional_roof, gcode_layer.configs_storage_.support_fractional_roof_config, gcode_layer); + /*SVG svg(fmt::format("/tmp/support_{}.svg", gcode_layer.getLayerNr().value), AABB(storage.getMachineBorder()), 0.001); + svg.writePolygons(support_layer.support_roof, SVG::Color::BLACK, 0.15); + svg.writePolygons(support_layer.support_fractional_roof, SVG::Color::MAGENTA, 0.1); + svg.writePolygons(support_layer.support_roof.difference(support_layer.support_fractional_roof), SVG::Color::ORANGE, 0.05);*/ } if (extruder_nr == support_infill_extruder_nr) { @@ -3913,8 +3949,7 @@ void FffGcodeWriter::addPrimeTower(const SliceDataStorage& storage, LayerPlan& g } LayerIndex layer_nr = gcode_layer.getLayerNr(); - const std::vector& extruder_order - = (layer_nr < 0) ? extruder_order_per_layer_negative_layers[extruder_order_per_layer_negative_layers.size() + layer_nr] : extruder_order_per_layer[layer_nr]; + const std::vector extruder_order = getExtruderUse(layer_nr); storage.primeTower.addToGcode(storage, gcode_layer, extruder_order, prev_extruder, gcode_layer.getExtruder()); } From 9d56e35958c7d24c56b205b5f0ac58abc2a9e9f3 Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Fri, 22 Mar 2024 13:21:00 +0100 Subject: [PATCH 170/201] Code documentation for new methods CURA-11757 --- include/FffGcodeWriter.h | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/include/FffGcodeWriter.h b/include/FffGcodeWriter.h index 3e4fea6f1f..4c4061c37b 100644 --- a/include/FffGcodeWriter.h +++ b/include/FffGcodeWriter.h @@ -716,8 +716,24 @@ class FffGcodeWriter : public NoCopy const SliceLayerPart& part, coord_t infill_line_width); + /*! + * Find the first or last extruder used at the given layer. This may loop to lower layers if + * there is no extryder on the one that has been asked. If no extruder can be found at all, the + * very first used extruder will be returned. + * + * \param storage where the slice data is stored + * \param layer_nr The layer for which we want the extruder index + * \param last Indicates whether we want to retrieve the last or the first extruder being used + * \return The first or last exruder used at the given index + */ size_t findUsedExtruderIndex(const SliceDataStorage& storage, const LayerIndex& layer_nr, bool last) const; + /*! + * Get the extruders use at the given layer + * + * \param layer_nr The index of the layer at which we want the extruders uses + * \return The extruders use at the given layer, which may be empty in some cases + */ std::vector getExtruderUse(const LayerIndex& layer_nr) const; }; From 75bd3ff479cdb2850c53e7ee6df727cb926c93f9 Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Fri, 22 Mar 2024 13:30:14 +0100 Subject: [PATCH 171/201] Remove debug code CURA-11757 --- src/FffGcodeWriter.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/FffGcodeWriter.cpp b/src/FffGcodeWriter.cpp index 60e116e06e..a8bdc2608c 100644 --- a/src/FffGcodeWriter.cpp +++ b/src/FffGcodeWriter.cpp @@ -3321,10 +3321,6 @@ bool FffGcodeWriter::addSupportToGCode(const SliceDataStorage& storage, LayerPla if (extruder_nr == support_roof_extruder_nr) { support_added |= addSupportRoofsToGCode(storage, support_layer.support_fractional_roof, gcode_layer.configs_storage_.support_fractional_roof_config, gcode_layer); - /*SVG svg(fmt::format("/tmp/support_{}.svg", gcode_layer.getLayerNr().value), AABB(storage.getMachineBorder()), 0.001); - svg.writePolygons(support_layer.support_roof, SVG::Color::BLACK, 0.15); - svg.writePolygons(support_layer.support_fractional_roof, SVG::Color::MAGENTA, 0.1); - svg.writePolygons(support_layer.support_roof.difference(support_layer.support_fractional_roof), SVG::Color::ORANGE, 0.05);*/ } if (extruder_nr == support_infill_extruder_nr) { From 81803c9136b382c327b79d00592d2316bb0cc04e Mon Sep 17 00:00:00 2001 From: Thomas Rahm <67757218+ThomasRahm@users.noreply.github.com> Date: Mon, 25 Mar 2024 05:29:12 +0100 Subject: [PATCH 172/201] Improve fractional tree support --- include/TreeSupport.h | 35 +++++++++++- include/TreeSupportSettings.h | 10 +++- include/TreeSupportTipGenerator.h | 9 ++- include/sliceDataStorage.h | 23 ++++++++ src/TreeSupport.cpp | 91 +++++++++++++++++++++++++++---- src/TreeSupportTipGenerator.cpp | 47 +++++++++------- 6 files changed, 178 insertions(+), 37 deletions(-) diff --git a/include/TreeSupport.h b/include/TreeSupport.h index b2b12e6531..6bb316363f 100644 --- a/include/TreeSupport.h +++ b/include/TreeSupport.h @@ -45,6 +45,32 @@ constexpr coord_t SUPPORT_TREE_COLLISION_RESOLUTION = 500; // Only has an effect using PropertyAreasUnordered = std::unordered_map; using PropertyAreas = std::map; +struct FakeRoofArea +{ + FakeRoofArea(Polygons area, coord_t line_distance, bool fractional): + area_(area) + , line_distance_(line_distance) + , fractional_(fractional) + { + + } + /*! + * \brief Area that should be a fake roof. + */ + Polygons area_; + + /*! + * \brief Distance between support lines + */ + coord_t line_distance_; + + /*! + * \brief If the area should be added as a fractional support area. + */ + bool fractional_; +}; + + /*! * \brief Generates a tree structure to support your models. */ @@ -271,7 +297,10 @@ class TreeSupport * \param support_roof_storage[in] Areas where support was replaced with roof. * \param storage[in,out] The storage where the support should be stored. */ - void finalizeInterfaceAndSupportAreas(std::vector& support_layer_storage, std::vector& support_roof_storage, SliceDataStorage& storage); + void finalizeInterfaceAndSupportAreas(std::vector& support_layer_storage, + std::vector& support_roof_storage, + std::vector& support_layer_storage_fractional, + SliceDataStorage& storage); /*! * \brief Draws circles around result_on_layer points of the influence areas and applies some post processing. @@ -292,9 +321,9 @@ class TreeSupport std::vector additional_required_support_area; /*! - * \brief A representation of already placed lines. Required for subtracting from new support areas. + * \brief Areas that use a higher density pattern of regular support to support the model (fake_roof). */ - std::vector placed_support_lines_support_areas; + std::vector> fake_roof_areas; /*! * \brief Generator for model collision, avoidance and internal guide volumes. diff --git a/include/TreeSupportSettings.h b/include/TreeSupportSettings.h index 1fe47514ca..b6b38dab4a 100644 --- a/include/TreeSupportSettings.h +++ b/include/TreeSupportSettings.h @@ -54,7 +54,8 @@ struct TreeSupportSettings , // Either 40° or as much as possible so that 2 lines will overlap by at least 50%, whichever is smaller. support_overrides(mesh_group_settings.get("support_xy_overrides_z")) , xy_min_distance(support_overrides == SupportDistPriority::Z_OVERRIDES_XY ? mesh_group_settings.get("support_xy_distance_overhang") : xy_distance) - , z_distance_top_layers(round_up_divide(mesh_group_settings.get("support_top_distance"), layer_height)) + , z_distance_top(mesh_group_settings.get("support_top_distance")) + , z_distance_top_layers(round_up_divide(z_distance_top, layer_height)) , z_distance_bottom_layers(round_up_divide(mesh_group_settings.get("support_bottom_distance"), layer_height)) , support_infill_angles(mesh_group_settings.get>("support_infill_angles")) , support_roof_angles(mesh_group_settings.get>("support_roof_angles")) @@ -257,6 +258,11 @@ struct TreeSupportSettings */ coord_t xy_min_distance; + /*! + * \brief Distance required the top of the support to the model + */ + coord_t z_distance_top; + /*! * \brief Amount of layers distance required the top of the support to the model */ @@ -397,7 +403,7 @@ struct TreeSupportSettings && // can not be set on a per-mesh basis currently, so code to enable processing different roof patterns in the same iteration seems useless. support_roof_angles == other.support_roof_angles && support_infill_angles == other.support_infill_angles && increase_radius_until_radius == other.increase_radius_until_radius && support_bottom_layers == other.support_bottom_layers && layer_height == other.layer_height - && z_distance_top_layers == other.z_distance_top_layers && maximum_deviation == other.maximum_deviation && // Infill generation depends on deviation and resolution. + && z_distance_top == other.z_distance_top && maximum_deviation == other.maximum_deviation && // Infill generation depends on deviation and resolution. maximum_resolution == other.maximum_resolution && support_roof_line_distance == other.support_roof_line_distance && skip_some_zags == other.skip_some_zags && zag_skip_count == other.zag_skip_count && connect_zigzags == other.connect_zigzags && interface_preference == other.interface_preference && min_feature_size == other.min_feature_size && // interface_preference should be identical to ensure the tree will correctly interact with the roof. diff --git a/include/TreeSupportTipGenerator.h b/include/TreeSupportTipGenerator.h index a6e04b0a1b..e2efcda8cb 100644 --- a/include/TreeSupportTipGenerator.h +++ b/include/TreeSupportTipGenerator.h @@ -33,7 +33,7 @@ class TreeSupportTipGenerator * \param mesh[in] The mesh that is currently processed. Contains the overhangs. * \param move_bounds[out] The storage for the tips. * \param additional_support_areas[out] Areas that should have been roofs, but are now support, as they would not generate any lines as roof. Should already be initialised. - + * \param placed_fake_roof_areas[out] Areas where fake roof has to be placed. * \return All lines of the \p polylines object, with information for each point regarding in which avoidance it is currently valid in. */ void generateTips( @@ -41,7 +41,7 @@ class TreeSupportTipGenerator const SliceMeshStorage& mesh, std::vector>& move_bounds, std::vector& additional_support_areas, - std::vector& placed_support_lines_support_areas); + std::vector>& placed_fake_roof_areas); private: enum class LineStatus @@ -298,6 +298,11 @@ class TreeSupportTipGenerator */ std::vector support_roof_drawn_; + /*! + * \brief Areas that will be saved as fractional support roof + */ + std::vector support_roof_drawn_fractional_; + /*! * \brief Areas that will be saved as support roof, originating from tips being replaced with roof areas. */ diff --git a/include/sliceDataStorage.h b/include/sliceDataStorage.h index 9689ceb1cd..07fefd00de 100644 --- a/include/sliceDataStorage.h +++ b/include/sliceDataStorage.h @@ -227,6 +227,29 @@ class SupportLayer */ void excludeAreasFromSupportInfillAreas(const Polygons& exclude_polygons, const AABB& exclude_polygons_boundary_box); + /* Fill up the infill parts for the support with the given support polygons. The support polygons will be split into parts. + * + * \param area The support polygon to fill up with infill parts. + * \param support_fill_per_layer The support polygons to fill up with infill parts. + * \param support_line_width Line width of the support extrusions. + * \param wall_line_count Wall-line count around the fill. + * \param use_fractional_config (optional, default to false) If the area should be added as fractional support. + * \param unionAll (optional, default to false) Wether to 'union all' for the split into parts bit. + * \param custom_line_distance (optional, default to 0) Distance between lines of the infill pattern. custom_line_distance of 0 means use the default instead. + */ + void fillInfillParts(const Polygons& area, + const coord_t support_line_width, + const coord_t wall_line_count, + const bool use_fractional_config = false, + const bool unionAll = false, + const coord_t custom_line_distance = 0) + { + for (const PolygonsPart& island_outline : area.splitIntoParts(unionAll)) + { + support_infill_parts.emplace_back(island_outline, support_line_width, use_fractional_config, wall_line_count, custom_line_distance); + } + } + /* Fill up the infill parts for the support with the given support polygons. The support polygons will be split into parts. This also takes into account fractional-height * support layers. * diff --git a/src/TreeSupport.cpp b/src/TreeSupport.cpp index beca41e6d2..4c650cd682 100644 --- a/src/TreeSupport.cpp +++ b/src/TreeSupport.cpp @@ -94,7 +94,7 @@ TreeSupport::TreeSupport(const SliceDataStorage& storage) mesh.first.setActualZ(known_z); } - placed_support_lines_support_areas = std::vector(storage.support.supportLayers.size(), Polygons()); + fake_roof_areas = std::vector>(storage.support.supportLayers.size(),std::vector()); } void TreeSupport::generateSupportAreas(SliceDataStorage& storage) @@ -256,7 +256,7 @@ LayerIndex TreeSupport::precalculate(const SliceDataStorage& storage, std::vecto void TreeSupport::generateInitialAreas(const SliceMeshStorage& mesh, std::vector>& move_bounds, SliceDataStorage& storage) { TreeSupportTipGenerator tip_gen(mesh, volumes_); - tip_gen.generateTips(storage, mesh, move_bounds, additional_required_support_area, placed_support_lines_support_areas); + tip_gen.generateTips(storage, mesh, move_bounds, additional_required_support_area, fake_roof_areas); } void TreeSupport::mergeHelper( @@ -2135,7 +2135,10 @@ void TreeSupport::filterFloatingLines(std::vector& support_layer_stora dur_hole_removal); } -void TreeSupport::finalizeInterfaceAndSupportAreas(std::vector& support_layer_storage, std::vector& support_roof_storage, SliceDataStorage& storage) +void TreeSupport::finalizeInterfaceAndSupportAreas(std::vector& support_layer_storage, + std::vector& support_roof_storage, + std::vector& support_layer_storage_fractional, + SliceDataStorage& storage) { InterfacePreference interface_pref = config.interface_preference; // InterfacePreference::SUPPORT_LINES_OVERWRITE_INTERFACE; double progress_total = TREE_PROGRESS_PRECALC_AVO + TREE_PROGRESS_PRECALC_COLL + TREE_PROGRESS_GENERATE_NODES + TREE_PROGRESS_AREA_CALC + TREE_PROGRESS_GENERATE_BRANCH_AREAS @@ -2148,7 +2151,22 @@ void TreeSupport::finalizeInterfaceAndSupportAreas(std::vector& suppor support_layer_storage.size(), [&](const LayerIndex layer_idx) { - support_layer_storage[layer_idx] = support_layer_storage[layer_idx].difference(placed_support_lines_support_areas[layer_idx]); + + Polygons fake_roof_lines; + + for(FakeRoofArea& f_roof:fake_roof_areas[layer_idx]) + { + fake_roof_lines.add(TreeSupportUtils::generateSupportInfillLines(f_roof.area_, + config, + false, + layer_idx, + f_roof.line_distance_, + storage.support.cross_fill_provider, + false).offsetPolyLine(config.support_line_width / 2)); + } + fake_roof_lines = fake_roof_lines.unionPolygons(); + + support_layer_storage[layer_idx] = support_layer_storage[layer_idx].difference(fake_roof_lines); // Subtract support lines of the branches from the roof storage.support.supportLayers[layer_idx].support_roof = storage.support.supportLayers[layer_idx].support_roof.unionPolygons(support_roof_storage[layer_idx]); @@ -2238,15 +2256,48 @@ void TreeSupport::finalizeInterfaceAndSupportAreas(std::vector& suppor { constexpr bool convert_every_part = true; // Convert every part into a PolygonsPart for the support. + storage.support.supportLayers[layer_idx].fillInfillParts( - layer_idx, - support_layer_storage, - config.layer_height, - storage.meshes, + support_layer_storage[layer_idx], config.support_line_width, config.support_wall_count, - config.maximum_move_distance, + false, convert_every_part); + + + // This only works because fractional support is always just projected upwards regular support or skin. + // Also technically violates skin height, but there is no good way to prevent that. + Polygons fractional_support; + + if(layer_idx > 0) + { + fractional_support = support_layer_storage_fractional[layer_idx].intersection(support_layer_storage[layer_idx - 1]); + } + else + { + fractional_support = support_layer_storage_fractional[layer_idx]; + } + + storage.support.supportLayers[layer_idx].fillInfillParts( + fractional_support, + config.support_line_width, + config.support_wall_count, + true, + convert_every_part); + + + for(FakeRoofArea& fake_roof : fake_roof_areas[layer_idx]) + { + storage.support.supportLayers[layer_idx].fillInfillParts( + fake_roof.area_, + config.support_line_width, + 0, + fake_roof.fractional_, + convert_every_part, + fake_roof.line_distance_); + } + + { std::lock_guard critical_section_progress(critical_sections); progress_total += TREE_PROGRESS_FINALIZE_BRANCH_AREAS / support_layer_storage.size(); @@ -2266,6 +2317,8 @@ void TreeSupport::finalizeInterfaceAndSupportAreas(std::vector& suppor void TreeSupport::drawAreas(std::vector>& move_bounds, SliceDataStorage& storage) { std::vector support_layer_storage(move_bounds.size()); + std::vector support_layer_storage_fractional(move_bounds.size()); + std::vector support_roof_storage_fractional(move_bounds.size()); std::vector support_roof_storage(move_bounds.size()); std::map inverse_tree_order; // In the tree structure only the parents can be accessed. Inverse this to be able to access the children. @@ -2360,8 +2413,26 @@ void TreeSupport::drawAreas(std::vector>& move_bou { for (std::pair data_pair : layer_tree_polygons[layer_idx]) { + if(data_pair.first->parents_.empty() && !data_pair.first->supports_roof_ && layer_idx + 1 < support_roof_storage_fractional.size()) + { + if(data_pair.first->missing_roof_layers_ > data_pair.first->distance_to_top_) + { + support_roof_storage_fractional[layer_idx+1].add(data_pair.second); + } + else + { + support_layer_storage_fractional[layer_idx+1].add(data_pair.second); + } + + } + ((data_pair.first->missing_roof_layers_ > data_pair.first->distance_to_top_) ? support_roof_storage : support_layer_storage)[layer_idx].add(data_pair.second); } + if(layer_idx + 1< support_roof_storage_fractional.size()) + { + support_roof_storage_fractional[layer_idx+1] = support_roof_storage_fractional[layer_idx+1].unionPolygons(); + support_layer_storage_fractional[layer_idx+1] = support_layer_storage_fractional[layer_idx+1].unionPolygons(); + } } for (const auto layer_idx : ranges::views::iota(0UL, additional_required_support_area.size())) @@ -2376,7 +2447,7 @@ void TreeSupport::drawAreas(std::vector>& move_bou filterFloatingLines(support_layer_storage); const auto t_filter = std::chrono::high_resolution_clock::now(); - finalizeInterfaceAndSupportAreas(support_layer_storage, support_roof_storage, storage); + finalizeInterfaceAndSupportAreas(support_layer_storage, support_roof_storage, support_layer_storage_fractional, storage); const auto t_end = std::chrono::high_resolution_clock::now(); const auto dur_gen_tips = 0.001 * std::chrono::duration_cast(t_generate - t_start).count(); diff --git a/src/TreeSupportTipGenerator.cpp b/src/TreeSupportTipGenerator.cpp index 969fc1fe58..575b447d17 100644 --- a/src/TreeSupportTipGenerator.cpp +++ b/src/TreeSupportTipGenerator.cpp @@ -58,6 +58,7 @@ TreeSupportTipGenerator::TreeSupportTipGenerator(const SliceMeshStorage& mesh, T , force_minimum_roof_area_(use_fake_roof_ || SUPPORT_TREE_MINIMUM_ROOF_AREA_HARD_LIMIT) , already_inserted_(mesh.overhang_areas.size()) , support_roof_drawn_(mesh.overhang_areas.size(), Polygons()) + , support_roof_drawn_fractional_(mesh.overhang_areas.size(), Polygons()) , roof_tips_drawn_(mesh.overhang_areas.size(), Polygons()) { const double support_overhang_angle = mesh.settings.get("support_angle"); @@ -529,6 +530,10 @@ void TreeSupportTipGenerator::calculateRoofAreas(const cura::SliceMeshStorage& m { std::lock_guard critical_section_potential_support_roofs(critical_potential_support_roofs); potential_support_roofs[layer_idx - dtt_roof].add((full_overhang_area)); + if(dtt_roof == 0) + { + support_roof_drawn_fractional_[layer_idx+1].add(full_overhang_area); + } } else { @@ -838,7 +843,7 @@ void TreeSupportTipGenerator::generateTips( const SliceMeshStorage& mesh, std::vector>& move_bounds, std::vector& additional_support_areas, - std::vector& placed_support_lines_support_areas) + std::vector>& placed_fake_roof_areas) { std::vector> new_tips(move_bounds.size()); @@ -1163,30 +1168,32 @@ void TreeSupportTipGenerator::generateTips( { if (use_fake_roof_) { - storage.support.supportLayers[layer_idx].fillInfillParts( - layer_idx, - support_roof_drawn_, - config_.layer_height, - storage.meshes, - config_.support_line_width, - 0, - config_.maximum_move_distance, - false, - support_roof_line_distance_); - placed_support_lines_support_areas[layer_idx].add(TreeSupportUtils::generateSupportInfillLines( - support_roof_drawn_[layer_idx], - config_, - false, - layer_idx, - support_roof_line_distance_, - cross_fill_provider_, - false) - .offsetPolyLine(config_.support_line_width / 2)); + placed_fake_roof_areas[layer_idx].emplace_back(support_roof_drawn_[layer_idx], support_roof_line_distance_, false); + + if (config_.z_distance_top % config_.layer_height != 0) + { + Polygons all_roof = support_roof_drawn_[layer_idx].unionPolygons(roof_tips_drawn_[layer_idx]); + Polygons valid_fractional_roof = support_roof_drawn_fractional_[layer_idx].intersection(all_roof); + + } } else { storage.support.supportLayers[layer_idx].support_roof.add(support_roof_drawn_[layer_idx]); storage.support.supportLayers[layer_idx].support_roof = storage.support.supportLayers[layer_idx].support_roof.unionPolygons(roof_tips_drawn_[layer_idx]); + + if (config_.z_distance_top % config_.layer_height != 0) + { + Polygons all_roof = support_roof_drawn_[layer_idx].unionPolygons(roof_tips_drawn_[layer_idx]); + Polygons valid_fractional_roof = support_roof_drawn_fractional_[layer_idx].intersection(all_roof); + storage.support.supportLayers[layer_idx].support_fractional_roof = + storage.support.supportLayers[layer_idx].support_fractional_roof.unionPolygons(valid_fractional_roof); + + // Fractional roof is a modifier applied to a roof area, which means if only the fractional roof area is set, there will be nothing as there is no roof to modify. + // Because of that the fractional roof has ALSO to be added to the roof. + storage.support.supportLayers[layer_idx].support_roof = + storage.support.supportLayers[layer_idx].support_roof.unionPolygons(valid_fractional_roof); + } } } }); From 9cfea95a4ce3cd9942228c9990a8b1ee696ef02d Mon Sep 17 00:00:00 2001 From: Thomas Rahm <67757218+ThomasRahm@users.noreply.github.com> Date: Mon, 25 Mar 2024 05:32:30 +0100 Subject: [PATCH 173/201] Fix bug causing wrong roof generation when using tree supports --- src/TreeSupportTipGenerator.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/TreeSupportTipGenerator.cpp b/src/TreeSupportTipGenerator.cpp index 575b447d17..b50072f529 100644 --- a/src/TreeSupportTipGenerator.cpp +++ b/src/TreeSupportTipGenerator.cpp @@ -54,7 +54,7 @@ TreeSupportTipGenerator::TreeSupportTipGenerator(const SliceMeshStorage& mesh, T , support_tree_branch_reach_limit_(support_tree_limit_branch_reach_ ? mesh.settings.get("support_tree_branch_reach_limit") : 0) , z_distance_delta_(std::min(config_.z_distance_top_layers + 1, mesh.overhang_areas.size())) , xy_overrides_(config_.support_overrides == SupportDistPriority::XY_OVERRIDES_Z) - , tip_roof_size_(force_tip_to_roof_ ? config_.min_radius * config_.min_radius * std::numbers::pi : 0) + , tip_roof_size_(force_tip_to_roof_ ? INT2MM2(config_.min_radius * config_.min_radius) * std::numbers::pi : 0) , force_minimum_roof_area_(use_fake_roof_ || SUPPORT_TREE_MINIMUM_ROOF_AREA_HARD_LIMIT) , already_inserted_(mesh.overhang_areas.size()) , support_roof_drawn_(mesh.overhang_areas.size(), Polygons()) @@ -663,7 +663,7 @@ void TreeSupportTipGenerator::addPointAsInfluenceArea( dont_move_until, roof, safe_radius, - force_tip_to_roof_, + !roof && force_tip_to_roof_, skip_ovalisation, support_tree_limit_branch_reach_, support_tree_branch_reach_limit_); From f2e9efe515bb4d2bea18a3b13679e81aee2d6a32 Mon Sep 17 00:00:00 2001 From: Thomas Rahm <67757218+ThomasRahm@users.noreply.github.com> Date: Mon, 25 Mar 2024 05:35:30 +0100 Subject: [PATCH 174/201] Parallelize fractional support unioning in TreeSupport --- src/TreeSupport.cpp | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/src/TreeSupport.cpp b/src/TreeSupport.cpp index 4c650cd682..5cbc8af1e1 100644 --- a/src/TreeSupport.cpp +++ b/src/TreeSupport.cpp @@ -2407,33 +2407,33 @@ void TreeSupport::drawAreas(std::vector>& move_bou } }); - // Single threaded combining all support areas to the right layers. - // Only copies data! - for (const auto layer_idx : ranges::views::iota(0UL, layer_tree_polygons.size())) - { - for (std::pair data_pair : layer_tree_polygons[layer_idx]) + cura::parallel_for( + 0, + layer_tree_polygons.size(), + [&](const size_t layer_idx) { - if(data_pair.first->parents_.empty() && !data_pair.first->supports_roof_ && layer_idx + 1 < support_roof_storage_fractional.size()) + for (std::pair data_pair : layer_tree_polygons[layer_idx]) { - if(data_pair.first->missing_roof_layers_ > data_pair.first->distance_to_top_) + if (data_pair.first->parents_.empty() && ! data_pair.first->supports_roof_ && layer_idx + 1 < support_roof_storage_fractional.size()) { - support_roof_storage_fractional[layer_idx+1].add(data_pair.second); - } - else - { - support_layer_storage_fractional[layer_idx+1].add(data_pair.second); + if (data_pair.first->missing_roof_layers_ > data_pair.first->distance_to_top_) + { + support_roof_storage_fractional[layer_idx + 1].add(data_pair.second); + } + else + { + support_layer_storage_fractional[layer_idx + 1].add(data_pair.second); + } } + ((data_pair.first->missing_roof_layers_ > data_pair.first->distance_to_top_) ? support_roof_storage : support_layer_storage)[layer_idx].add(data_pair.second); } - - ((data_pair.first->missing_roof_layers_ > data_pair.first->distance_to_top_) ? support_roof_storage : support_layer_storage)[layer_idx].add(data_pair.second); - } - if(layer_idx + 1< support_roof_storage_fractional.size()) - { - support_roof_storage_fractional[layer_idx+1] = support_roof_storage_fractional[layer_idx+1].unionPolygons(); - support_layer_storage_fractional[layer_idx+1] = support_layer_storage_fractional[layer_idx+1].unionPolygons(); - } - } + if (layer_idx + 1 < support_roof_storage_fractional.size()) + { + support_roof_storage_fractional[layer_idx + 1] = support_roof_storage_fractional[layer_idx + 1].unionPolygons(); + support_layer_storage_fractional[layer_idx + 1] = support_layer_storage_fractional[layer_idx + 1].unionPolygons(); + } + }); for (const auto layer_idx : ranges::views::iota(0UL, additional_required_support_area.size())) { From c37e130048595c17f6a7379560013eebb2fd35e0 Mon Sep 17 00:00:00 2001 From: Thomas Rahm <67757218+ThomasRahm@users.noreply.github.com> Date: Mon, 25 Mar 2024 06:18:14 +0100 Subject: [PATCH 175/201] Fix Z distance wrong if it is a multiple of layer height when using tree support TreeSupport --- src/TreeSupport.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/TreeSupport.cpp b/src/TreeSupport.cpp index 5cbc8af1e1..1db9d7a9b6 100644 --- a/src/TreeSupport.cpp +++ b/src/TreeSupport.cpp @@ -2414,7 +2414,10 @@ void TreeSupport::drawAreas(std::vector>& move_bou { for (std::pair data_pair : layer_tree_polygons[layer_idx]) { - if (data_pair.first->parents_.empty() && ! data_pair.first->supports_roof_ && layer_idx + 1 < support_roof_storage_fractional.size()) + if (data_pair.first->parents_.empty() && + ! data_pair.first->supports_roof_ && + layer_idx + 1 < support_roof_storage_fractional.size() && + config.z_distance_top % config.layer_height > 0) { if (data_pair.first->missing_roof_layers_ > data_pair.first->distance_to_top_) { From 0dfe14be1626aa3427627e8051c4a8c466cbbce8 Mon Sep 17 00:00:00 2001 From: Thomas Rahm <67757218+ThomasRahm@users.noreply.github.com> Date: Mon, 25 Mar 2024 07:25:48 +0100 Subject: [PATCH 176/201] Ensure fractional support roof is applied to roof tips. --- src/TreeSupportTipGenerator.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/TreeSupportTipGenerator.cpp b/src/TreeSupportTipGenerator.cpp index b50072f529..622c68220c 100644 --- a/src/TreeSupportTipGenerator.cpp +++ b/src/TreeSupportTipGenerator.cpp @@ -748,8 +748,12 @@ void TreeSupportTipGenerator::addLinesAsInfluenceAreas( added_roofs = added_roofs.unionPolygons(); { std::lock_guard critical_section_roof(critical_roof_tips_); - roof_tips_drawn_[insert_layer_idx - dtt_roof_tip].add(added_roofs); + + if(dtt_roof_tip == 0) + { + support_roof_drawn_fractional_[insert_layer_idx].add(added_roofs); + } } } } From 41aa901941ecd116d676a929b12d1912009742a2 Mon Sep 17 00:00:00 2001 From: Thomas Rahm <67757218+ThomasRahm@users.noreply.github.com> Date: Mon, 25 Mar 2024 07:27:25 +0100 Subject: [PATCH 177/201] Fix multiple issues with fractional tree support --- include/TreeSupportTipGenerator.h | 2 +- src/TreeSupportTipGenerator.cpp | 38 +++++++++++-------------------- 2 files changed, 14 insertions(+), 26 deletions(-) diff --git a/include/TreeSupportTipGenerator.h b/include/TreeSupportTipGenerator.h index e2efcda8cb..de518f5682 100644 --- a/include/TreeSupportTipGenerator.h +++ b/include/TreeSupportTipGenerator.h @@ -299,7 +299,7 @@ class TreeSupportTipGenerator std::vector support_roof_drawn_; /*! - * \brief Areas that will be saved as fractional support roof + * \brief Areas that require fractional roof above it. */ std::vector support_roof_drawn_fractional_; diff --git a/src/TreeSupportTipGenerator.cpp b/src/TreeSupportTipGenerator.cpp index 622c68220c..2d42bad342 100644 --- a/src/TreeSupportTipGenerator.cpp +++ b/src/TreeSupportTipGenerator.cpp @@ -532,7 +532,7 @@ void TreeSupportTipGenerator::calculateRoofAreas(const cura::SliceMeshStorage& m potential_support_roofs[layer_idx - dtt_roof].add((full_overhang_area)); if(dtt_roof == 0) { - support_roof_drawn_fractional_[layer_idx+1].add(full_overhang_area); + support_roof_drawn_fractional_[layer_idx].add(full_overhang_area); } } else @@ -1174,45 +1174,33 @@ void TreeSupportTipGenerator::generateTips( { placed_fake_roof_areas[layer_idx].emplace_back(support_roof_drawn_[layer_idx], support_roof_line_distance_, false); - if (config_.z_distance_top % config_.layer_height != 0) + if (config_.z_distance_top % config_.layer_height != 0 && layer_idx > 0) { - Polygons all_roof = support_roof_drawn_[layer_idx].unionPolygons(roof_tips_drawn_[layer_idx]); - Polygons valid_fractional_roof = support_roof_drawn_fractional_[layer_idx].intersection(all_roof); - + // Fake roof tips would just be tips, so no need to add them here as all polygons in roof_tips_drawn_ will be empty! + Polygons all_roof_fractional = support_roof_drawn_fractional_[layer_idx - 1].intersection(support_roof_drawn_[layer_idx - 1]); + placed_fake_roof_areas[layer_idx].emplace_back(all_roof_fractional, support_roof_line_distance_, true); } } else { - storage.support.supportLayers[layer_idx].support_roof.add(support_roof_drawn_[layer_idx]); - storage.support.supportLayers[layer_idx].support_roof = storage.support.supportLayers[layer_idx].support_roof.unionPolygons(roof_tips_drawn_[layer_idx]); - - if (config_.z_distance_top % config_.layer_height != 0) + if (config_.z_distance_top % config_.layer_height != 0 && layer_idx > 0) { - Polygons all_roof = support_roof_drawn_[layer_idx].unionPolygons(roof_tips_drawn_[layer_idx]); - Polygons valid_fractional_roof = support_roof_drawn_fractional_[layer_idx].intersection(all_roof); + Polygons all_roof_below = support_roof_drawn_[layer_idx - 1].unionPolygons(roof_tips_drawn_[layer_idx - 1]); + Polygons all_roof_fractional = support_roof_drawn_fractional_[layer_idx - 1].intersection(all_roof_below); storage.support.supportLayers[layer_idx].support_fractional_roof = - storage.support.supportLayers[layer_idx].support_fractional_roof.unionPolygons(valid_fractional_roof); + storage.support.supportLayers[layer_idx].support_fractional_roof.unionPolygons(all_roof_fractional); // Fractional roof is a modifier applied to a roof area, which means if only the fractional roof area is set, there will be nothing as there is no roof to modify. // Because of that the fractional roof has ALSO to be added to the roof. - storage.support.supportLayers[layer_idx].support_roof = - storage.support.supportLayers[layer_idx].support_roof.unionPolygons(valid_fractional_roof); + storage.support.supportLayers[layer_idx].support_roof.add(all_roof_fractional); } + + Polygons all_roof = support_roof_drawn_[layer_idx].unionPolygons(roof_tips_drawn_[layer_idx]); + storage.support.supportLayers[layer_idx].support_roof = storage.support.supportLayers[layer_idx].support_roof.unionPolygons(all_roof); } } }); - cura::parallel_for( - 1, - mesh.overhang_areas.size() - z_distance_delta_, - [&](const LayerIndex layer_idx) - { - if (layer_idx > 0) - { - storage.support.supportLayers[layer_idx].support_fractional_roof.add( - storage.support.supportLayers[layer_idx].support_roof.difference(storage.support.supportLayers[layer_idx + 1].support_roof)); - } - }); removeUselessAddedPoints(new_tips, storage, additional_support_areas); From a9c428fbee71a4b4a1652dc10f61ebfef5ac4f9d Mon Sep 17 00:00:00 2001 From: Saumya Jain Date: Mon, 25 Mar 2024 11:53:45 +0100 Subject: [PATCH 178/201] added same path for extra combing move introduced CURA-11735 --- include/LayerPlan.h | 2 +- src/LayerPlan.cpp | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/include/LayerPlan.h b/include/LayerPlan.h index 62a079c831..999bfd45d9 100644 --- a/include/LayerPlan.h +++ b/include/LayerPlan.h @@ -746,7 +746,7 @@ class LayerPlan : public NoCopy * it. * \param part If given, stay within the boundary of this part. */ - void moveInsideCombBoundary(const coord_t distance, const std::optional& part = std::nullopt); + void moveInsideCombBoundary(const coord_t distance, const std::optional& part = std::nullopt, GCodePath* path = nullptr); /*! * If enabled, apply the modify plugin to the layer-plan. diff --git a/src/LayerPlan.cpp b/src/LayerPlan.cpp index f4786aa098..ceaed89296 100644 --- a/src/LayerPlan.cpp +++ b/src/LayerPlan.cpp @@ -310,7 +310,7 @@ void LayerPlan::setMesh(const std::shared_ptr& mesh) current_mesh_ = mesh; } -void LayerPlan::moveInsideCombBoundary(const coord_t distance, const std::optional& part) +void LayerPlan::moveInsideCombBoundary(const coord_t distance, const std::optional& part, GCodePath* path) { constexpr coord_t max_dist2 = MM2INT(2.0) * MM2INT(2.0); // if we are further than this distance, we conclude we are not inside even though we thought we were. // this function is to be used to move from the boundary of a part to inside the part @@ -321,7 +321,7 @@ void LayerPlan::moveInsideCombBoundary(const coord_t distance, const std::option PolygonUtils::moveInside(comb_boundary_preferred_, p, distance, max_dist2); if (comb_boundary_preferred_.inside(p) && (part == std::nullopt || part->outline.inside(p))) { - addTravel_simple(p); + addTravel_simple(p, path); // Make sure the that any retraction happens after this move, not before it by starting a new move path. forceNewPathStart(); } @@ -507,7 +507,7 @@ GCodePath& LayerPlan::addTravel(const Point2LL& p, const bool force_retract, con { innermost_wall_line_width *= mesh_or_extruder_settings.get("initial_layer_line_width_factor"); } - moveInsideCombBoundary(innermost_wall_line_width); + moveInsideCombBoundary(innermost_wall_line_width, std::nullopt, path); } path->retract = retraction_enable; path->perform_z_hop = retraction_enable && mesh_or_extruder_settings.get("retraction_hop_enabled"); From d3d8f69914f7fee8d6051f12062596c6a9ba83bb Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Mon, 25 Mar 2024 14:02:42 +0100 Subject: [PATCH 179/201] Manually fix clang-formating --- include/TreeSupport.h | 14 ++++---- include/sliceDataStorage.h | 13 ++++---- src/TreeSupport.cpp | 58 +++++++++++---------------------- src/TreeSupportTipGenerator.cpp | 14 ++++---- 4 files changed, 40 insertions(+), 59 deletions(-) diff --git a/include/TreeSupport.h b/include/TreeSupport.h index 6bb316363f..61932f0231 100644 --- a/include/TreeSupport.h +++ b/include/TreeSupport.h @@ -47,12 +47,11 @@ using PropertyAreas = std::map; struct FakeRoofArea { - FakeRoofArea(Polygons area, coord_t line_distance, bool fractional): - area_(area) + FakeRoofArea(Polygons area, coord_t line_distance, bool fractional) + : area_(area) , line_distance_(line_distance) , fractional_(fractional) { - } /*! * \brief Area that should be a fake roof. @@ -297,10 +296,11 @@ class TreeSupport * \param support_roof_storage[in] Areas where support was replaced with roof. * \param storage[in,out] The storage where the support should be stored. */ - void finalizeInterfaceAndSupportAreas(std::vector& support_layer_storage, - std::vector& support_roof_storage, - std::vector& support_layer_storage_fractional, - SliceDataStorage& storage); + void finalizeInterfaceAndSupportAreas( + std::vector& support_layer_storage, + std::vector& support_roof_storage, + std::vector& support_layer_storage_fractional, + SliceDataStorage& storage); /*! * \brief Draws circles around result_on_layer points of the influence areas and applies some post processing. diff --git a/include/sliceDataStorage.h b/include/sliceDataStorage.h index 07fefd00de..ebdf20430b 100644 --- a/include/sliceDataStorage.h +++ b/include/sliceDataStorage.h @@ -237,12 +237,13 @@ class SupportLayer * \param unionAll (optional, default to false) Wether to 'union all' for the split into parts bit. * \param custom_line_distance (optional, default to 0) Distance between lines of the infill pattern. custom_line_distance of 0 means use the default instead. */ - void fillInfillParts(const Polygons& area, - const coord_t support_line_width, - const coord_t wall_line_count, - const bool use_fractional_config = false, - const bool unionAll = false, - const coord_t custom_line_distance = 0) + void fillInfillParts( + const Polygons& area, + const coord_t support_line_width, + const coord_t wall_line_count, + const bool use_fractional_config = false, + const bool unionAll = false, + const coord_t custom_line_distance = 0) { for (const PolygonsPart& island_outline : area.splitIntoParts(unionAll)) { diff --git a/src/TreeSupport.cpp b/src/TreeSupport.cpp index 1db9d7a9b6..2b8a9e03a1 100644 --- a/src/TreeSupport.cpp +++ b/src/TreeSupport.cpp @@ -94,7 +94,7 @@ TreeSupport::TreeSupport(const SliceDataStorage& storage) mesh.first.setActualZ(known_z); } - fake_roof_areas = std::vector>(storage.support.supportLayers.size(),std::vector()); + fake_roof_areas = std::vector>(storage.support.supportLayers.size(), std::vector()); } void TreeSupport::generateSupportAreas(SliceDataStorage& storage) @@ -2135,10 +2135,11 @@ void TreeSupport::filterFloatingLines(std::vector& support_layer_stora dur_hole_removal); } -void TreeSupport::finalizeInterfaceAndSupportAreas(std::vector& support_layer_storage, - std::vector& support_roof_storage, - std::vector& support_layer_storage_fractional, - SliceDataStorage& storage) +void TreeSupport::finalizeInterfaceAndSupportAreas( + std::vector& support_layer_storage, + std::vector& support_roof_storage, + std::vector& support_layer_storage_fractional, + SliceDataStorage& storage) { InterfacePreference interface_pref = config.interface_preference; // InterfacePreference::SUPPORT_LINES_OVERWRITE_INTERFACE; double progress_total = TREE_PROGRESS_PRECALC_AVO + TREE_PROGRESS_PRECALC_COLL + TREE_PROGRESS_GENERATE_NODES + TREE_PROGRESS_AREA_CALC + TREE_PROGRESS_GENERATE_BRANCH_AREAS @@ -2151,18 +2152,13 @@ void TreeSupport::finalizeInterfaceAndSupportAreas(std::vector& suppor support_layer_storage.size(), [&](const LayerIndex layer_idx) { - Polygons fake_roof_lines; - for(FakeRoofArea& f_roof:fake_roof_areas[layer_idx]) + for (FakeRoofArea& f_roof : fake_roof_areas[layer_idx]) { - fake_roof_lines.add(TreeSupportUtils::generateSupportInfillLines(f_roof.area_, - config, - false, - layer_idx, - f_roof.line_distance_, - storage.support.cross_fill_provider, - false).offsetPolyLine(config.support_line_width / 2)); + fake_roof_lines.add( + TreeSupportUtils::generateSupportInfillLines(f_roof.area_, config, false, layer_idx, f_roof.line_distance_, storage.support.cross_fill_provider, false) + .offsetPolyLine(config.support_line_width / 2)); } fake_roof_lines = fake_roof_lines.unionPolygons(); @@ -2257,19 +2253,15 @@ void TreeSupport::finalizeInterfaceAndSupportAreas(std::vector& suppor constexpr bool convert_every_part = true; // Convert every part into a PolygonsPart for the support. - storage.support.supportLayers[layer_idx].fillInfillParts( - support_layer_storage[layer_idx], - config.support_line_width, - config.support_wall_count, - false, - convert_every_part); + storage.support.supportLayers[layer_idx] + .fillInfillParts(support_layer_storage[layer_idx], config.support_line_width, config.support_wall_count, false, convert_every_part); // This only works because fractional support is always just projected upwards regular support or skin. // Also technically violates skin height, but there is no good way to prevent that. Polygons fractional_support; - if(layer_idx > 0) + if (layer_idx > 0) { fractional_support = support_layer_storage_fractional[layer_idx].intersection(support_layer_storage[layer_idx - 1]); } @@ -2278,23 +2270,13 @@ void TreeSupport::finalizeInterfaceAndSupportAreas(std::vector& suppor fractional_support = support_layer_storage_fractional[layer_idx]; } - storage.support.supportLayers[layer_idx].fillInfillParts( - fractional_support, - config.support_line_width, - config.support_wall_count, - true, - convert_every_part); + storage.support.supportLayers[layer_idx].fillInfillParts(fractional_support, config.support_line_width, config.support_wall_count, true, convert_every_part); - for(FakeRoofArea& fake_roof : fake_roof_areas[layer_idx]) + for (FakeRoofArea& fake_roof : fake_roof_areas[layer_idx]) { - storage.support.supportLayers[layer_idx].fillInfillParts( - fake_roof.area_, - config.support_line_width, - 0, - fake_roof.fractional_, - convert_every_part, - fake_roof.line_distance_); + storage.support.supportLayers[layer_idx] + .fillInfillParts(fake_roof.area_, config.support_line_width, 0, fake_roof.fractional_, convert_every_part, fake_roof.line_distance_); } @@ -2414,10 +2396,8 @@ void TreeSupport::drawAreas(std::vector>& move_bou { for (std::pair data_pair : layer_tree_polygons[layer_idx]) { - if (data_pair.first->parents_.empty() && - ! data_pair.first->supports_roof_ && - layer_idx + 1 < support_roof_storage_fractional.size() && - config.z_distance_top % config.layer_height > 0) + if (data_pair.first->parents_.empty() && ! data_pair.first->supports_roof_ && layer_idx + 1 < support_roof_storage_fractional.size() + && config.z_distance_top % config.layer_height > 0) { if (data_pair.first->missing_roof_layers_ > data_pair.first->distance_to_top_) { diff --git a/src/TreeSupportTipGenerator.cpp b/src/TreeSupportTipGenerator.cpp index 2d42bad342..00ce1c46d9 100644 --- a/src/TreeSupportTipGenerator.cpp +++ b/src/TreeSupportTipGenerator.cpp @@ -530,7 +530,7 @@ void TreeSupportTipGenerator::calculateRoofAreas(const cura::SliceMeshStorage& m { std::lock_guard critical_section_potential_support_roofs(critical_potential_support_roofs); potential_support_roofs[layer_idx - dtt_roof].add((full_overhang_area)); - if(dtt_roof == 0) + if (dtt_roof == 0) { support_roof_drawn_fractional_[layer_idx].add(full_overhang_area); } @@ -663,7 +663,7 @@ void TreeSupportTipGenerator::addPointAsInfluenceArea( dont_move_until, roof, safe_radius, - !roof && force_tip_to_roof_, + ! roof && force_tip_to_roof_, skip_ovalisation, support_tree_limit_branch_reach_, support_tree_branch_reach_limit_); @@ -750,7 +750,7 @@ void TreeSupportTipGenerator::addLinesAsInfluenceAreas( std::lock_guard critical_section_roof(critical_roof_tips_); roof_tips_drawn_[insert_layer_idx - dtt_roof_tip].add(added_roofs); - if(dtt_roof_tip == 0) + if (dtt_roof_tip == 0) { support_roof_drawn_fractional_[insert_layer_idx].add(added_roofs); } @@ -1187,11 +1187,11 @@ void TreeSupportTipGenerator::generateTips( { Polygons all_roof_below = support_roof_drawn_[layer_idx - 1].unionPolygons(roof_tips_drawn_[layer_idx - 1]); Polygons all_roof_fractional = support_roof_drawn_fractional_[layer_idx - 1].intersection(all_roof_below); - storage.support.supportLayers[layer_idx].support_fractional_roof = - storage.support.supportLayers[layer_idx].support_fractional_roof.unionPolygons(all_roof_fractional); + storage.support.supportLayers[layer_idx].support_fractional_roof + = storage.support.supportLayers[layer_idx].support_fractional_roof.unionPolygons(all_roof_fractional); - // Fractional roof is a modifier applied to a roof area, which means if only the fractional roof area is set, there will be nothing as there is no roof to modify. - // Because of that the fractional roof has ALSO to be added to the roof. + // Fractional roof is a modifier applied to a roof area, which means if only the fractional roof area is set, there will be nothing as there is no roof to + // modify. Because of that the fractional roof has ALSO to be added to the roof. storage.support.supportLayers[layer_idx].support_roof.add(all_roof_fractional); } From fba372969ed1e7cd3fe661944448ae8e4157b690 Mon Sep 17 00:00:00 2001 From: Remco Burema Date: Tue, 26 Mar 2024 15:45:00 +0100 Subject: [PATCH 180/201] Fix outdated security-badge github-workflow. --- .github/workflows/scorecard.yml | 43 +++++++++++++-------------------- 1 file changed, 17 insertions(+), 26 deletions(-) diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml index 507c1487d0..ebb9b2caf1 100644 --- a/.github/workflows/scorecard.yml +++ b/.github/workflows/scorecard.yml @@ -1,5 +1,5 @@ # NOTE: Best to keep all of these remarks in, they might prove useful in the future. -# This is basically just the standard one that is sugested on 'new workflow'. +# This is basically just the standard one that is suggested on 'new workflow'. name: Scorecard supply-chain security on: @@ -21,51 +21,42 @@ jobs: name: Scorecard analysis runs-on: ubuntu-latest permissions: - # Needed to upload the results to code-scanning dashboard. + # Needed for Code scanning upload security-events: write - # Needed to publish results and get a badge (see publish_results below). + # Needed for GitHub OIDC token if publish_results is true id-token: write - # Uncomment the permissions below if installing in a private repository. - # contents: read - # actions: read steps: - name: "Checkout code" - uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 # v3.1.0 + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 with: persist-credentials: false - name: "Run analysis" - uses: ossf/scorecard-action@e38b1902ae4f44df626f11ba0734b14fb91f8f86 # v2.1.2 + uses: ossf/scorecard-action@0864cf19026789058feabb7e87baa5f140aac736 # v2.3.1 with: results_file: results.sarif results_format: sarif - # (Optional) "write" PAT token. Uncomment the `repo_token` line below if: - # - you want to enable the Branch-Protection check on a *public* repository, or - # - you are installing Scorecard on a *private* repository - # To create the PAT, follow the steps in https://github.com/ossf/scorecard-action#authentication-with-pat. - # repo_token: ${{ secrets.SCORECARD_TOKEN }} - - # Public repositories: - # - Publish results to OpenSSF REST API for easy access by consumers - # - Allows the repository to include the Scorecard badge. - # - See https://github.com/ossf/scorecard-action#publishing-results. - # For private repositories: - # - `publish_results` will always be set to `false`, regardless - # of the value entered here. + # Scorecard team runs a weekly scan of public GitHub repos, + # see https://github.com/ossf/scorecard#public-data. + # Setting `publish_results: true` helps us scale by leveraging your workflow to + # extract the results instead of relying on our own infrastructure to run scans. + # And it's free for you! publish_results: true - # Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF - # format to the repository Actions tab. + # Upload the results as artifacts (optional). Commenting out will disable + # uploads of run results in SARIF format to the repository Actions tab. + # https://docs.github.com/en/actions/advanced-guides/storing-workflow-data-as-artifacts - name: "Upload artifact" - uses: actions/upload-artifact@3cea5372237819ed00197afe530f5a7ea3e805c8 # v3.1.0 + uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1 with: name: SARIF file path: results.sarif retention-days: 5 - # Upload the results to GitHub's code scanning dashboard. + # Upload the results to GitHub's code scanning dashboard (optional). + # Commenting out will disable upload of results to your repo's Code Scanning dashboard - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@17573ee1cc1b9d061760f3a006fc4aac4f944fd5 # v2.2.4 + uses: github/codeql-action/upload-sarif@83a02f7883b12e0e4e1a146174f5e2292a01e601 # v2.16.4 with: sarif_file: results.sarif From 25aca889f8ad6ec7fa3edf5567fc3d44a0e38afa Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Wed, 27 Mar 2024 14:10:36 +0100 Subject: [PATCH 181/201] Add micro Z travel when travelling while on fractional layer CURA-11249 --- src/LayerPlan.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/LayerPlan.cpp b/src/LayerPlan.cpp index f4786aa098..43ef13063f 100644 --- a/src/LayerPlan.cpp +++ b/src/LayerPlan.cpp @@ -2185,6 +2185,13 @@ void LayerPlan::writeGCode(GCodeExport& gcode) ss << "MESH:" << (current_mesh ? current_mesh->mesh_name : "NONMESH"); gcode.writeComment(ss.str()); } + + if (! path.spiralize && (! path.retract || ! path.perform_z_hop) && (z_ + path.z_offset != gcode.getPositionZ()) && (path_idx > 0 || layer_nr_ > 0)) + { + // First move to desired height to then make a plain horizontal move + gcode.writeTravel(Point3LL(gcode.getPosition().x_, gcode.getPosition().y_, z_ + path.z_offset), speed); + } + if (path.config.isTravelPath()) { // early comp for travel paths, which are handled more simply if (! path.perform_z_hop && final_travel_z_ != z_ && extruder_plan_idx == (extruder_plans_.size() - 1) && path_idx == (paths.size() - 1)) From 14268da06d9864d96eb7272937b56f8e7c66c452 Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Wed, 27 Mar 2024 14:10:58 +0100 Subject: [PATCH 182/201] Code sanitization CURA-11249 --- include/LayerPlan.h | 2 +- include/gcodeExport.h | 2 +- src/gcodeExport.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/include/LayerPlan.h b/include/LayerPlan.h index 62a079c831..0e08a55a53 100644 --- a/include/LayerPlan.h +++ b/include/LayerPlan.h @@ -56,7 +56,7 @@ class LayerPlan : public NoCopy public: const PathConfigStorage configs_storage_; //!< The line configs for this layer for each feature type - coord_t z_; + const coord_t z_; coord_t final_travel_z_; bool mode_skip_agressive_merge_; //!< Whether to give every new path the 'skip_agressive_merge_hint' property (see GCodePath); default is false. diff --git a/include/gcodeExport.h b/include/gcodeExport.h index 950fe50824..5edd5dcdda 100644 --- a/include/gcodeExport.h +++ b/include/gcodeExport.h @@ -266,7 +266,7 @@ class GCodeExport : public NoCopy */ void addExtraPrimeAmount(double extra_prime_volume); - Point3LL getPosition() const; + const Point3LL& getPosition() const; Point2LL getPositionXY() const; diff --git a/src/gcodeExport.cpp b/src/gcodeExport.cpp index 3df5147dde..8a3cc11538 100644 --- a/src/gcodeExport.cpp +++ b/src/gcodeExport.cpp @@ -411,7 +411,7 @@ void GCodeExport::setFlowRateExtrusionSettings(double max_extrusion_offset, doub this->extrusion_offset_factor_ = extrusion_offset_factor; } -Point3LL GCodeExport::getPosition() const +const Point3LL& GCodeExport::getPosition() const { return current_position_; } From 5dabc3a0676eba6c12e9c75b43fa750889d24832 Mon Sep 17 00:00:00 2001 From: Remco Burema Date: Wed, 27 Mar 2024 14:43:25 +0100 Subject: [PATCH 183/201] Line-spacing can be 0, causing 0-width grid and div-by 0. If the combing-offset gets set to 0 (because it's set equal to the line-spacing, which can be 0), we attempt to make a lookup-grid with 0-size squares, causing a division by zero later on. Apply some defensive programming. Should fix Sentry-issue CURAENGINE/AC. --- src/FffGcodeWriter.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/FffGcodeWriter.cpp b/src/FffGcodeWriter.cpp index a8bdc2608c..91660000bf 100644 --- a/src/FffGcodeWriter.cpp +++ b/src/FffGcodeWriter.cpp @@ -597,7 +597,12 @@ void FffGcodeWriter::processRaft(const SliceDataStorage& storage) LayerIndex layer_nr = initial_raft_layer_nr; const coord_t layer_height = base_settings.get("raft_base_thickness"); z += layer_height; - const coord_t comb_offset = base_settings.get("raft_base_line_spacing"); + const coord_t comb_offset = + std::max + ( + base_settings.get("raft_base_line_spacing"), + base_settings.get("raft_base_line_width") + ); std::vector fan_speed_layer_time_settings_per_extruder_raft_base = fan_speed_layer_time_settings_per_extruder; // copy so that we change only the local copy @@ -770,7 +775,7 @@ void FffGcodeWriter::processRaft(const SliceDataStorage& storage) fan_speed_layer_time_settings.cool_fan_speed_0 = regular_fan_speed; // ignore initial layer fan speed stuff } - const coord_t comb_offset = interface_line_spacing; + const coord_t comb_offset = std::max(interface_line_spacing, interface_line_width); LayerPlan& gcode_layer = *new LayerPlan( storage, layer_nr, @@ -940,7 +945,7 @@ void FffGcodeWriter::processRaft(const SliceDataStorage& storage) fan_speed_layer_time_settings.cool_fan_speed_0 = regular_fan_speed; // ignore initial layer fan speed stuff } - const coord_t comb_offset = surface_line_spacing; + const coord_t comb_offset = std::max(surface_line_spacing, surface_line_width); LayerPlan& gcode_layer = *new LayerPlan( storage, layer_nr, From 71c8785b1ac9a57a5c732553d16cbf490a6c9759 Mon Sep 17 00:00:00 2001 From: Remco Burema Date: Wed, 27 Mar 2024 14:50:01 +0100 Subject: [PATCH 184/201] Line-spacing can be 0, causing 0-width grid and div-by 0. NOTE: This is the lint-formatted version of this change. See the previous commit for the actual change! -- If the combing-offset gets set to 0 (because it's set equal to the line-spacing, which can be 0), we attempt to make a lookup-grid with 0-size squares, causing a division by zero later on. Apply some defensive programming. Should fix Sentry-issue CURAENGINE/AC. --- src/FffGcodeWriter.cpp | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/FffGcodeWriter.cpp b/src/FffGcodeWriter.cpp index 91660000bf..c71c925ea0 100644 --- a/src/FffGcodeWriter.cpp +++ b/src/FffGcodeWriter.cpp @@ -597,12 +597,7 @@ void FffGcodeWriter::processRaft(const SliceDataStorage& storage) LayerIndex layer_nr = initial_raft_layer_nr; const coord_t layer_height = base_settings.get("raft_base_thickness"); z += layer_height; - const coord_t comb_offset = - std::max - ( - base_settings.get("raft_base_line_spacing"), - base_settings.get("raft_base_line_width") - ); + const coord_t comb_offset = std::max(base_settings.get("raft_base_line_spacing"), base_settings.get("raft_base_line_width")); std::vector fan_speed_layer_time_settings_per_extruder_raft_base = fan_speed_layer_time_settings_per_extruder; // copy so that we change only the local copy From 63a1ca650a6c51e83c4d67794b41b16fb5433707 Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Fri, 29 Mar 2024 11:48:16 +0100 Subject: [PATCH 185/201] Partial revert of 8d297ec which fixes skirt of second extruder I remember adding this while thinking "This should probably be better" but at the time I had no example of processing the secondary skirt/brim. It turns out that assumption was wrong and I should have restrained myself from adding code that I couldn't test. CURA-11718 --- src/SkirtBrim.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/SkirtBrim.cpp b/src/SkirtBrim.cpp index d76a16fc49..74935df98a 100644 --- a/src/SkirtBrim.cpp +++ b/src/SkirtBrim.cpp @@ -508,7 +508,7 @@ void SkirtBrim::generateSecondarySkirtBrim(Polygons& covered_area, std::vector

Date: Fri, 29 Mar 2024 14:06:28 +0100 Subject: [PATCH 186/201] Make prime tower only prime the used extruders CURA-11717 --- include/FffGcodeWriter.h | 4 ++- include/PrimeTower.h | 8 +++-- src/FffGcodeWriter.cpp | 13 ++++++--- src/FffPolygonGenerator.cpp | 2 ++ src/PrimeTower.cpp | 58 ++++++++++++++++++++----------------- 5 files changed, 50 insertions(+), 35 deletions(-) diff --git a/include/FffGcodeWriter.h b/include/FffGcodeWriter.h index 4c4061c37b..251712c8fc 100644 --- a/include/FffGcodeWriter.h +++ b/include/FffGcodeWriter.h @@ -295,9 +295,11 @@ class FffGcodeWriter : public NoCopy * * \param[in] storage where the slice data is stored. * \param current_extruder The current extruder with which we last printed + * \param global_extruders_used The extruders that are at some point used for the print job * \return The order of extruders for a layer beginning with \p current_extruder */ - std::vector getUsedExtrudersOnLayer(const SliceDataStorage& storage, const size_t start_extruder, const LayerIndex& layer_nr) const; + std::vector + getUsedExtrudersOnLayer(const SliceDataStorage& storage, const size_t start_extruder, const LayerIndex& layer_nr, const std::vector& global_extruders_used) const; /*! * Calculate in which order to plan the meshes of a specific extruder diff --git a/include/PrimeTower.h b/include/PrimeTower.h index 61a0beb901..b11522643d 100644 --- a/include/PrimeTower.h +++ b/include/PrimeTower.h @@ -28,8 +28,8 @@ class LayerPlan; class PrimeTower { private: - using MovesByExtruder = std::vector; - using MovesByLayer = std::vector; + using MovesByExtruder = std::map; + using MovesByLayer = std::map>; size_t extruder_count_; //!< Number of extruders @@ -79,10 +79,12 @@ class PrimeTower */ PrimeTower(); + void initializeExtruders(const std::vector& used_extruders); + /*! * Check whether we actually use the prime tower. */ - void checkUsed(const SliceDataStorage& storage); + void checkUsed(); /*! * Generate the prime tower area to be used on each layer diff --git a/src/FffGcodeWriter.cpp b/src/FffGcodeWriter.cpp index c71c925ea0..74343ea99b 100644 --- a/src/FffGcodeWriter.cpp +++ b/src/FffGcodeWriter.cpp @@ -1543,12 +1543,13 @@ void FffGcodeWriter::calculateExtruderOrderPerLayer(const SliceDataStorage& stor } size_t extruder_count = Application::getInstance().current_slice_->scene.extruders.size(); + const std::vector extruders_used = storage.getExtrudersUsed(); const Settings& mesh_group_settings = Application::getInstance().current_slice_->scene.current_mesh_group->settings; PrimeTowerMethod prime_tower_mode = mesh_group_settings.get("prime_tower_mode"); for (LayerIndex layer_nr = -Raft::getTotalExtraLayers(); layer_nr < static_cast(storage.print_layer_count); layer_nr++) { std::vector>& extruder_order_per_layer_here = (layer_nr < 0) ? extruder_order_per_layer_negative_layers : extruder_order_per_layer; - std::vector extruder_order = getUsedExtrudersOnLayer(storage, last_extruder, layer_nr); + std::vector extruder_order = getUsedExtrudersOnLayer(storage, last_extruder, layer_nr, extruders_used); extruder_order_per_layer_here.push_back(extruder_order); if (! extruder_order.empty()) @@ -1573,10 +1574,14 @@ void FffGcodeWriter::calculatePrimeLayerPerExtruder(const SliceDataStorage& stor } } -std::vector FffGcodeWriter::getUsedExtrudersOnLayer(const SliceDataStorage& storage, const size_t start_extruder, const LayerIndex& layer_nr) const +std::vector FffGcodeWriter::getUsedExtrudersOnLayer( + const SliceDataStorage& storage, + const size_t start_extruder, + const LayerIndex& layer_nr, + const std::vector& global_extruders_used) const { const Settings& mesh_group_settings = Application::getInstance().current_slice_->scene.current_mesh_group->settings; - size_t extruder_count = Application::getInstance().current_slice_->scene.extruders.size(); + size_t extruder_count = global_extruders_used.size(); assert(static_cast(extruder_count) > 0); std::vector ret; std::vector extruder_is_used_on_this_layer = storage.getExtrudersUsed(layer_nr); @@ -1601,7 +1606,7 @@ std::vector FffGcodeWriter::getUsedExtrudersOnLayer(const SliceData ordered_extruders.push_back(start_extruder); for (size_t extruder_nr = 0; extruder_nr < extruder_count; extruder_nr++) { - if (extruder_nr != start_extruder) + if (extruder_nr != start_extruder && global_extruders_used[extruder_nr]) { ordered_extruders.push_back(extruder_nr); } diff --git a/src/FffPolygonGenerator.cpp b/src/FffPolygonGenerator.cpp index b0d5ff5ff2..24e23b547a 100644 --- a/src/FffPolygonGenerator.cpp +++ b/src/FffPolygonGenerator.cpp @@ -404,6 +404,8 @@ void FffPolygonGenerator::slices2polygons(SliceDataStorage& storage, TimeKeeper& Progress::messageProgressStage(Progress::Stage::SUPPORT, &time_keeper); + storage.primeTower.initializeExtruders(storage.getExtrudersUsed()); + AreaSupport::generateOverhangAreas(storage); AreaSupport::generateSupportAreas(storage); TreeSupport tree_support_generator(storage); diff --git a/src/PrimeTower.cpp b/src/PrimeTower.cpp index 57dc4d9853..f9ebcb4f4c 100644 --- a/src/PrimeTower.cpp +++ b/src/PrimeTower.cpp @@ -52,35 +52,37 @@ PrimeTower::PrimeTower() && scene.current_mesh_group->settings.get("prime_tower_size") > 10; would_have_actual_tower_ = enabled_; // Assume so for now. +} - extruder_count_ = scene.extruders.size(); - extruder_order_.resize(extruder_count_); - for (unsigned int extruder_nr = 0; extruder_nr < extruder_count_; extruder_nr++) +void PrimeTower::initializeExtruders(const std::vector& used_extruders) +{ + // Add used extruders in default order, then sort. + for (unsigned int extruder_nr = 0; extruder_nr < used_extruders.size(); extruder_nr++) { - extruder_order_[extruder_nr] = extruder_nr; // Start with default order, then sort. + if (used_extruders[extruder_nr]) + { + extruder_order_.push_back(extruder_nr); + } } + + extruder_count_ = extruder_order_.size(); + // Sort from high adhesion to low adhesion. - const Scene* scene_pointer = &scene; // Communicate to lambda via pointer to prevent copy. + const Scene& scene = Application::getInstance().current_slice_->scene; std::stable_sort( extruder_order_.begin(), extruder_order_.end(), - [scene_pointer](const unsigned int& extruder_nr_a, const unsigned int& extruder_nr_b) -> bool + [&scene](const unsigned int& extruder_nr_a, const unsigned int& extruder_nr_b) -> bool { - const Ratio adhesion_a = scene_pointer->extruders[extruder_nr_a].settings_.get("material_adhesion_tendency"); - const Ratio adhesion_b = scene_pointer->extruders[extruder_nr_b].settings_.get("material_adhesion_tendency"); + const Ratio adhesion_a = scene.extruders[extruder_nr_a].settings_.get("material_adhesion_tendency"); + const Ratio adhesion_b = scene.extruders[extruder_nr_b].settings_.get("material_adhesion_tendency"); return adhesion_a < adhesion_b; }); } -void PrimeTower::checkUsed(const SliceDataStorage& storage) +void PrimeTower::checkUsed() { - std::vector extruder_is_used = storage.getExtrudersUsed(); - size_t used_extruder_count = 0; - for (bool is_used : extruder_is_used) - { - used_extruder_count += is_used; - } - if (used_extruder_count <= 1) + if (extruder_count_ <= 1) { enabled_ = false; } @@ -108,7 +110,7 @@ void PrimeTower::generateGroundpoly() void PrimeTower::generatePaths(const SliceDataStorage& storage) { - checkUsed(storage); + checkUsed(); const int raft_total_extra_layers = Raft::getTotalExtraLayers(); would_have_actual_tower_ = storage.max_print_height_second_to_last_extruder @@ -138,9 +140,13 @@ void PrimeTower::generatePaths_denseInfill(std::vector& cumulative_inse const coord_t base_height = std::max(scene.settings.get("prime_tower_base_height"), has_raft ? layer_height : 0); const double base_curve_magnitude = mesh_group_settings.get("prime_tower_base_curve_magnitude"); - prime_moves_.resize(extruder_count_); - base_extra_moves_.resize(extruder_count_); - inset_extra_moves_.resize(extruder_count_); + for (size_t extruder_nr : extruder_order_) + { + // By default, add empty moves for every extruder + prime_moves_[extruder_nr]; + base_extra_moves_[extruder_nr]; + inset_extra_moves_[extruder_nr]; + } coord_t cumulative_inset = 0; // Each tower shape is going to be printed inside the other. This is the inset we're doing for each extruder. for (size_t extruder_nr : extruder_order_) @@ -226,8 +232,6 @@ void PrimeTower::generatePaths_sparseInfill(const std::vector& cumulati if (method == PrimeTowerMethod::INTERLEAVED || method == PrimeTowerMethod::NORMAL) { - const size_t nb_extruders = scene.extruders.size(); - // Pre-compute radiuses of each extruder ring std::vector rings_radii; const coord_t tower_size = mesh_group_settings.get("prime_tower_size"); @@ -242,9 +246,9 @@ void PrimeTower::generatePaths_sparseInfill(const std::vector& cumulati // Generate all possible extruders combinations, e.g. if there are 4 extruders, we have combinations // 0 / 0-1 / 0-1-2 / 0-1-2-3 / 1 / 1-2 / 1-2-3 / 2 / 2-3 / 3 // A combination is represented by a bitmask - for (size_t first_extruder_idx = 0; first_extruder_idx < nb_extruders; ++first_extruder_idx) + for (size_t first_extruder_idx = 0; first_extruder_idx < extruder_count_; ++first_extruder_idx) { - size_t nb_extruders_sparse = method == PrimeTowerMethod::NORMAL ? first_extruder_idx + 1 : nb_extruders; + size_t nb_extruders_sparse = method == PrimeTowerMethod::NORMAL ? first_extruder_idx + 1 : extruder_count_; for (size_t last_extruder_idx = first_extruder_idx; last_extruder_idx < nb_extruders_sparse; ++last_extruder_idx) { @@ -444,7 +448,7 @@ void PrimeTower::addToGcode_denseInfill(LayerPlan& gcode_layer, const size_t ext { // Actual prime pattern const GCodePathConfig& config = gcode_layer.configs_storage_.prime_tower_config_per_extruder[extruder_nr]; - const Polygons& pattern = prime_moves_[extruder_nr]; + const Polygons& pattern = prime_moves_.at(extruder_nr); gcode_layer.addPolygonsByOptimizer(pattern, config); } } @@ -454,7 +458,7 @@ bool PrimeTower::addToGcode_base(LayerPlan& gcode_layer, const size_t extruder_n const size_t raft_total_extra_layers = Raft::getTotalExtraLayers(); LayerIndex absolute_layer_number = gcode_layer.getLayerNr() + raft_total_extra_layers; - const std::vector& pattern_extra_brim = base_extra_moves_[extruder_nr]; + const std::vector& pattern_extra_brim = base_extra_moves_.at(extruder_nr); if (absolute_layer_number < pattern_extra_brim.size()) { // Extra rings for stronger base @@ -477,7 +481,7 @@ bool PrimeTower::addToGcode_inset(LayerPlan& gcode_layer, const size_t extruder_ if (absolute_layer_number == 0) // Extra-adhesion on very first layer only { - const Polygons& pattern_extra_inset = inset_extra_moves_[extruder_nr]; + const Polygons& pattern_extra_inset = inset_extra_moves_.at(extruder_nr); if (! pattern_extra_inset.empty()) { const GCodePathConfig& config = gcode_layer.configs_storage_.prime_tower_config_per_extruder[extruder_nr]; From 1bcc4b6360592fd66b2063568f7e50b62f6b65e6 Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Fri, 29 Mar 2024 16:39:03 +0100 Subject: [PATCH 187/201] Fix uncomplete higher skirt line CURA-10857 --- src/FffGcodeWriter.cpp | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/src/FffGcodeWriter.cpp b/src/FffGcodeWriter.cpp index c71c925ea0..040b7d8376 100644 --- a/src/FffGcodeWriter.cpp +++ b/src/FffGcodeWriter.cpp @@ -1346,6 +1346,12 @@ void FffGcodeWriter::processSkirtBrim(const SliceDataStorage& storage, LayerPlan { total_line_count += line.closed_polygons.size(); total_line_count += line.open_polylines.size(); + + // For layer_nr != 0 add only the innermost brim line (which is only the case if skirt_height > 1) + if (layer_nr != 0) + { + break; + } } Polygons all_brim_lines; @@ -1383,6 +1389,12 @@ void FffGcodeWriter::processSkirtBrim(const SliceDataStorage& storage, LayerPlan } } } + + // For layer_nr != 0 add only the innermost brim line (which is only the case if skirt_height > 1) + if (layer_nr != 0) + { + break; + } } const auto smart_brim_ordering = train.settings_.get("brim_smart_ordering") && train.settings_.get("adhesion_type") == EPlatformAdhesion::BRIM; @@ -1442,12 +1454,8 @@ void FffGcodeWriter::processSkirtBrim(const SliceDataStorage& storage, LayerPlan if (! all_brim_lines.empty()) { - // For layer_nr != 0 add only the innermost brim line (which is only the case if skirt_height > 1) - Polygons inner_brim_line; - inner_brim_line.add(all_brim_lines[0]); - gcode_layer.addLinesByOptimizer( - layer_nr == 0 ? all_brim_lines : inner_brim_line, + all_brim_lines, gcode_layer.configs_storage_.skirt_brim_config_per_extruder[extruder_nr], SpaceFillType::PolyLines, enable_travel_optimization, From 1ee8726e9a149ee1c52ed1ba81fa152f04dfe449 Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Tue, 2 Apr 2024 10:12:02 +0200 Subject: [PATCH 188/201] Fix unit tests Possible crash when finializing a layer plan and prime tower not initialized. Although not possible in normal execution (prime tower is always initialized first), it is still a healthy fix. CURA-11717 --- src/sliceDataStorage.cpp | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/sliceDataStorage.cpp b/src/sliceDataStorage.cpp index b369dbb082..cfc4d32c08 100644 --- a/src/sliceDataStorage.cpp +++ b/src/sliceDataStorage.cpp @@ -362,13 +362,9 @@ Polygons SliceDataStorage::getLayerOutlines( total.add(support_layer.support_roof); } } - int prime_tower_outer_extruder_nr = primeTower.extruder_order_[0]; - if (include_prime_tower && (extruder_nr == -1 || extruder_nr == prime_tower_outer_extruder_nr)) + if (include_prime_tower && primeTower.enabled_ && (extruder_nr == -1 || (! primeTower.extruder_order_.empty() && extruder_nr == primeTower.extruder_order_[0]))) { - if (primeTower.enabled_) - { - total.add(primeTower.getOuterPoly(layer_nr)); - } + total.add(primeTower.getOuterPoly(layer_nr)); } return total; } From 2efbdd2b11f208be0a1bc4a2a646f4c7f7236cf3 Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Tue, 2 Apr 2024 14:23:40 +0200 Subject: [PATCH 189/201] Pin version 5.7.0 --- conandata.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conandata.yml b/conandata.yml index a5527b0e01..e6c16b939b 100644 --- a/conandata.yml +++ b/conandata.yml @@ -1,4 +1,4 @@ -version: "5.7.0-beta.1" +version: "5.7.0" requirements: - "scripta/0.1.0@ultimaker/testing" requirements_arcus: From 928ebe1c3c3c85e0a65be94aa92626b68220622e Mon Sep 17 00:00:00 2001 From: Remco Burema Date: Tue, 2 Apr 2024 15:58:41 +0200 Subject: [PATCH 190/201] Fix overlapping lines with gradual (support) infill. Separate out the areas, since overlapping lines will become a big problem when 'connect infill lines' or 'zig zag' is enabled. This does mean that lines are less well-connected when the pattern _isn't_ already connected in and of itself, like lines. However, such patterns aren't recommended anyway. Also some compensation for the extra density which we _may_ now lose in some cases might need to be done. It should still allow us to to the combine (though I can't see that this happens in practice, either before or after this fix, so we'll may have to look at that in more detail later). part of CURA-11597 --- src/skin.cpp | 6 ++++-- src/support.cpp | 6 ++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/skin.cpp b/src/skin.cpp index 842a6e576f..797fc6b679 100644 --- a/src/skin.cpp +++ b/src/skin.cpp @@ -494,6 +494,7 @@ void SkinInfillAreaComputation::generateGradualInfill(SliceMeshStorage& mesh) continue; } Polygons less_dense_infill = infill_area; // one step less dense with each infill_step + Polygons sum_more_dense; for (size_t infill_step = 0; infill_step < max_infill_steps; infill_step++) { LayerIndex min_layer = layer_idx + infill_step * gradual_infill_step_layer_count + static_cast(layer_skip_count); @@ -526,11 +527,12 @@ void SkinInfillAreaComputation::generateGradualInfill(SliceMeshStorage& mesh) part.infill_area_per_combine_per_density.emplace_back(); std::vector& infill_area_per_combine_current_density = part.infill_area_per_combine_per_density.back(); const Polygons more_dense_infill = infill_area.difference(less_dense_infill); - infill_area_per_combine_current_density.push_back(more_dense_infill); + infill_area_per_combine_current_density.push_back(more_dense_infill.difference(sum_more_dense)); + sum_more_dense = sum_more_dense.unionPolygons(more_dense_infill); } part.infill_area_per_combine_per_density.emplace_back(); std::vector& infill_area_per_combine_current_density = part.infill_area_per_combine_per_density.back(); - infill_area_per_combine_current_density.push_back(infill_area); + infill_area_per_combine_current_density.push_back(infill_area.difference(sum_more_dense)); part.infill_area_own = std::nullopt; // clear infill_area_own, it's not needed any more. assert(! part.infill_area_per_combine_per_density.empty() && "infill_area_per_combine_per_density is now initialized"); } diff --git a/src/support.cpp b/src/support.cpp index 7488c6832f..82b9f22e06 100644 --- a/src/support.cpp +++ b/src/support.cpp @@ -234,6 +234,7 @@ void AreaSupport::generateGradualSupport(SliceDataStorage& storage) // calculate density areas for this island Polygons less_dense_support = infill_area; // one step less dense with each density_step + Polygons sum_more_dense; for (unsigned int density_step = 0; density_step < max_density_steps; ++density_step) { LayerIndex actual_min_layer{ layer_nr + density_step * gradual_support_step_layer_count + static_cast(layer_skip_count) }; @@ -292,12 +293,13 @@ void AreaSupport::generateGradualSupport(SliceDataStorage& storage) support_infill_part.infill_area_per_combine_per_density_.emplace_back(); std::vector& support_area_current_density = support_infill_part.infill_area_per_combine_per_density_.back(); const Polygons more_dense_support = infill_area.difference(less_dense_support); - support_area_current_density.push_back(more_dense_support); + support_area_current_density.push_back(more_dense_support.difference(sum_more_dense)); + sum_more_dense = sum_more_dense.unionPolygons(more_dense_support); } support_infill_part.infill_area_per_combine_per_density_.emplace_back(); std::vector& support_area_current_density = support_infill_part.infill_area_per_combine_per_density_.back(); - support_area_current_density.push_back(infill_area); + support_area_current_density.push_back(infill_area.difference(sum_more_dense)); assert(support_infill_part.infill_area_per_combine_per_density_.size() != 0 && "support_infill_part.infill_area_per_combine_per_density should now be initialized"); #ifdef DEBUG From 51daa75a08b4bbed37ebec25137b49ed13d26466 Mon Sep 17 00:00:00 2001 From: Remco Burema Date: Wed, 3 Apr 2024 13:38:31 +0200 Subject: [PATCH 191/201] Only add zig-zag connector when not 'too close' to scanline. This can in some cases lead to (nearly) doubly printed extrusion-paths (or close enough), especially in support, where it might also present the biggest problems. part of CURA-11597 --- include/infill/NoZigZagConnectorProcessor.h | 2 +- include/infill/ZigzagConnectorProcessor.h | 13 +------------ src/infill.cpp | 6 +++--- src/infill/NoZigZagConnectorProcessor.cpp | 2 +- src/infill/ZigzagConnectorProcessor.cpp | 15 ++++++++++++--- 5 files changed, 18 insertions(+), 20 deletions(-) diff --git a/include/infill/NoZigZagConnectorProcessor.h b/include/infill/NoZigZagConnectorProcessor.h index 002fb0fb7b..6e59dcdaa5 100644 --- a/include/infill/NoZigZagConnectorProcessor.h +++ b/include/infill/NoZigZagConnectorProcessor.h @@ -29,7 +29,7 @@ class NoZigZagConnectorProcessor : public ZigzagConnectorProcessor } void registerVertex(const Point2LL& vertex); - void registerScanlineSegmentIntersection(const Point2LL& intersection, int scanline_index); + void registerScanlineSegmentIntersection(const Point2LL& intersection, int scanline_index, coord_t min_distance_to_scanline); void registerPolyFinished(); }; diff --git a/include/infill/ZigzagConnectorProcessor.h b/include/infill/ZigzagConnectorProcessor.h index 513ad9d8f1..9adb751430 100644 --- a/include/infill/ZigzagConnectorProcessor.h +++ b/include/infill/ZigzagConnectorProcessor.h @@ -137,7 +137,7 @@ class ZigzagConnectorProcessor * \param intersection The intersection * \param scanline_index Index of the current scanline */ - virtual void registerScanlineSegmentIntersection(const Point2LL& intersection, int scanline_index); + virtual void registerScanlineSegmentIntersection(const Point2LL& intersection, int scanline_index, coord_t min_distance_to_scanline); /*! * Handle the end of a polygon and prepare for the next. @@ -166,17 +166,6 @@ class ZigzagConnectorProcessor */ bool shouldAddCurrentConnector(int start_scanline_idx, int end_scanline_idx) const; - /*! - * Checks whether two points are separated at least by "threshold" microns. - * If they are far away from each other enough, the line represented by the two points - * will be added; In case they are close, the second point will be set to be the same - * as the first and this line won't be added. - * - * \param first_point The first of the points - * \param second_point The second of the points - */ - void checkAndAddZagConnectorLine(Point2LL* first_point, Point2LL* second_point); - /*! * Adds a Zag connector represented by the given points. The last line of the connector will not be * added if the given connector is an end piece and "connected_endpieces" is not enabled. diff --git a/src/infill.cpp b/src/infill.cpp index c085307622..ff51356267 100644 --- a/src/infill.cpp +++ b/src/infill.cpp @@ -746,12 +746,12 @@ void Infill::generateLinearBasedInfill( for (int scanline_idx = scanline_idx0; scanline_idx != scanline_idx1 + direction; scanline_idx += direction) { - int x = scanline_idx * line_distance + shift; - int y = p1.Y + (p0.Y - p1.Y) * (x - p1.X) / (p0.X - p1.X); + const int x = scanline_idx * line_distance + shift; + const int y = p1.Y + (p0.Y - p1.Y) * (x - p1.X) / (p0.X - p1.X); assert(scanline_idx - scanline_min_idx >= 0 && scanline_idx - scanline_min_idx < int(cut_list.size()) && "reading infill cutlist index out of bounds!"); cut_list[scanline_idx - scanline_min_idx].push_back(y); Point2LL scanline_linesegment_intersection(x, y); - zigzag_connector_processor.registerScanlineSegmentIntersection(scanline_linesegment_intersection, scanline_idx); + zigzag_connector_processor.registerScanlineSegmentIntersection(scanline_linesegment_intersection, scanline_idx, infill_line_width_); crossings_per_scanline[scanline_idx - min_scanline_index].emplace_back(scanline_linesegment_intersection, poly_idx, point_idx); } zigzag_connector_processor.registerVertex(p1); diff --git a/src/infill/NoZigZagConnectorProcessor.cpp b/src/infill/NoZigZagConnectorProcessor.cpp index 1ffa6532f4..25cb0fa48e 100644 --- a/src/infill/NoZigZagConnectorProcessor.cpp +++ b/src/infill/NoZigZagConnectorProcessor.cpp @@ -14,7 +14,7 @@ void NoZigZagConnectorProcessor::registerVertex(const Point2LL&) // No need to add anything. } -void NoZigZagConnectorProcessor::registerScanlineSegmentIntersection(const Point2LL&, int) +void NoZigZagConnectorProcessor::registerScanlineSegmentIntersection(const Point2LL&, int, coord_t) { // No need to add anything. } diff --git a/src/infill/ZigzagConnectorProcessor.cpp b/src/infill/ZigzagConnectorProcessor.cpp index 7f75b608ff..bb7c1bbbac 100644 --- a/src/infill/ZigzagConnectorProcessor.cpp +++ b/src/infill/ZigzagConnectorProcessor.cpp @@ -84,7 +84,7 @@ bool ZigzagConnectorProcessor::shouldAddCurrentConnector(int start_scanline_idx, } -void ZigzagConnectorProcessor::registerScanlineSegmentIntersection(const Point2LL& intersection, int scanline_index) +void ZigzagConnectorProcessor::registerScanlineSegmentIntersection(const Point2LL& intersection, int scanline_index, coord_t min_distance_to_scanline) { if (is_first_connector_) { @@ -100,8 +100,17 @@ void ZigzagConnectorProcessor::registerScanlineSegmentIntersection(const Point2L if (shouldAddCurrentConnector(last_connector_index_, scanline_index)) { const bool is_this_endpiece = scanline_index == last_connector_index_; - current_connector_.push_back(intersection); - addZagConnector(current_connector_, is_this_endpiece); + bool close_to_line_except_intersect = false; + const coord_t min_dist2 = min_distance_to_scanline * min_distance_to_scanline; + for (const auto& point : current_connector_) + { + close_to_line_except_intersect |= (std::abs(point.X - intersection.X) < min_distance_to_scanline) && (vSize2(point - intersection) > min_dist2); + } + if (! close_to_line_except_intersect) + { + current_connector_.push_back(intersection); + addZagConnector(current_connector_, is_this_endpiece); + } } } From 042745ed7055446f493482c65d58c0b75582df4e Mon Sep 17 00:00:00 2001 From: Remco Burema Date: Wed, 3 Apr 2024 14:28:20 +0200 Subject: [PATCH 192/201] Remove narrow areas from --and simplify-- gradual infill areas. Narrow or small areas can lead to double printing of lines, as a polygon is filled out that can be narrower than the line-width. Also observed what might be micro-segments in the connecting zags (if there are any), so simplify those out as well. part of CURA-11597 --- src/skin.cpp | 7 +++++-- src/support.cpp | 5 +++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/skin.cpp b/src/skin.cpp index 797fc6b679..7dc2993a82 100644 --- a/src/skin.cpp +++ b/src/skin.cpp @@ -16,6 +16,7 @@ #include "sliceDataStorage.h" #include "utils/math.h" #include "utils/polygonUtils.h" +#include "utils/Simplify.h" #define MIN_AREA_SIZE (0.4 * 0.4) @@ -465,6 +466,8 @@ void SkinInfillAreaComputation::generateGradualInfill(SliceMeshStorage& mesh) const LayerIndex mesh_min_layer = mesh.settings.get("initial_bottom_layers"); const LayerIndex mesh_max_layer = mesh.layers.size() - 1 - mesh.settings.get("top_layers"); + const Simplify simplifier(mesh.settings.get("infill_extruder_nr").settings_); + const auto infill_wall_count = mesh.settings.get("infill_wall_line_count"); const auto infill_wall_width = mesh.settings.get("infill_line_width"); const auto infill_overlap = mesh.settings.get("infill_overlap_mm"); @@ -527,12 +530,12 @@ void SkinInfillAreaComputation::generateGradualInfill(SliceMeshStorage& mesh) part.infill_area_per_combine_per_density.emplace_back(); std::vector& infill_area_per_combine_current_density = part.infill_area_per_combine_per_density.back(); const Polygons more_dense_infill = infill_area.difference(less_dense_infill); - infill_area_per_combine_current_density.push_back(more_dense_infill.difference(sum_more_dense)); + infill_area_per_combine_current_density.push_back(simplifier.polygon(more_dense_infill.difference(sum_more_dense).offset(-infill_wall_width).offset(infill_wall_width))); sum_more_dense = sum_more_dense.unionPolygons(more_dense_infill); } part.infill_area_per_combine_per_density.emplace_back(); std::vector& infill_area_per_combine_current_density = part.infill_area_per_combine_per_density.back(); - infill_area_per_combine_current_density.push_back(infill_area.difference(sum_more_dense)); + infill_area_per_combine_current_density.push_back(simplifier.polygon(infill_area.difference(sum_more_dense).offset(-infill_wall_width).offset(infill_wall_width))); part.infill_area_own = std::nullopt; // clear infill_area_own, it's not needed any more. assert(! part.infill_area_per_combine_per_density.empty() && "infill_area_per_combine_per_density is now initialized"); } diff --git a/src/support.cpp b/src/support.cpp index 82b9f22e06..e8546c55f0 100644 --- a/src/support.cpp +++ b/src/support.cpp @@ -187,6 +187,7 @@ void AreaSupport::generateGradualSupport(SliceDataStorage& storage) const size_t max_density_steps = infill_extruder.settings_.get("gradual_support_infill_steps"); const coord_t wall_width = infill_extruder.settings_.get("support_line_width"); + const Simplify simplifier(infill_extruder.settings_); // no early-out for this function; it needs to initialize the [infill_area_per_combine_per_density] double layer_skip_count{ 8.0 }; // skip every so many layers as to ignore small gaps in the model making computation more easy @@ -293,13 +294,13 @@ void AreaSupport::generateGradualSupport(SliceDataStorage& storage) support_infill_part.infill_area_per_combine_per_density_.emplace_back(); std::vector& support_area_current_density = support_infill_part.infill_area_per_combine_per_density_.back(); const Polygons more_dense_support = infill_area.difference(less_dense_support); - support_area_current_density.push_back(more_dense_support.difference(sum_more_dense)); + support_area_current_density.push_back(simplifier.polygon(more_dense_support.difference(sum_more_dense).offset(-wall_width).offset(wall_width))); sum_more_dense = sum_more_dense.unionPolygons(more_dense_support); } support_infill_part.infill_area_per_combine_per_density_.emplace_back(); std::vector& support_area_current_density = support_infill_part.infill_area_per_combine_per_density_.back(); - support_area_current_density.push_back(infill_area.difference(sum_more_dense)); + support_area_current_density.push_back(simplifier.polygon(infill_area.difference(sum_more_dense).offset(-wall_width).offset(wall_width))); assert(support_infill_part.infill_area_per_combine_per_density_.size() != 0 && "support_infill_part.infill_area_per_combine_per_density should now be initialized"); #ifdef DEBUG From 659aa52b08b1b611ad53c87b4946c82ffeb53615 Mon Sep 17 00:00:00 2001 From: rburema Date: Wed, 3 Apr 2024 19:15:52 +0000 Subject: [PATCH 193/201] Applied clang-format. --- src/skin.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/skin.cpp b/src/skin.cpp index 7dc2993a82..e342b58554 100644 --- a/src/skin.cpp +++ b/src/skin.cpp @@ -14,9 +14,9 @@ #include "settings/types/Angle.h" //For the infill support angle. #include "settings/types/Ratio.h" #include "sliceDataStorage.h" +#include "utils/Simplify.h" #include "utils/math.h" #include "utils/polygonUtils.h" -#include "utils/Simplify.h" #define MIN_AREA_SIZE (0.4 * 0.4) @@ -530,7 +530,8 @@ void SkinInfillAreaComputation::generateGradualInfill(SliceMeshStorage& mesh) part.infill_area_per_combine_per_density.emplace_back(); std::vector& infill_area_per_combine_current_density = part.infill_area_per_combine_per_density.back(); const Polygons more_dense_infill = infill_area.difference(less_dense_infill); - infill_area_per_combine_current_density.push_back(simplifier.polygon(more_dense_infill.difference(sum_more_dense).offset(-infill_wall_width).offset(infill_wall_width))); + infill_area_per_combine_current_density.push_back( + simplifier.polygon(more_dense_infill.difference(sum_more_dense).offset(-infill_wall_width).offset(infill_wall_width))); sum_more_dense = sum_more_dense.unionPolygons(more_dense_infill); } part.infill_area_per_combine_per_density.emplace_back(); From ead0ddeb135b271d6d58ec0dbd4923ae96119fc8 Mon Sep 17 00:00:00 2001 From: Remco Burema Date: Wed, 10 Apr 2024 09:08:14 +0200 Subject: [PATCH 194/201] Better metric for when a connection is too close to the scanline. Instead of one point within a very small distance, all points need to be within a slightly larger distance to be ignored. part of CURA-11597 --- src/infill.cpp | 2 +- src/infill/ZigzagConnectorProcessor.cpp | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/infill.cpp b/src/infill.cpp index ff51356267..ce5189973e 100644 --- a/src/infill.cpp +++ b/src/infill.cpp @@ -751,7 +751,7 @@ void Infill::generateLinearBasedInfill( assert(scanline_idx - scanline_min_idx >= 0 && scanline_idx - scanline_min_idx < int(cut_list.size()) && "reading infill cutlist index out of bounds!"); cut_list[scanline_idx - scanline_min_idx].push_back(y); Point2LL scanline_linesegment_intersection(x, y); - zigzag_connector_processor.registerScanlineSegmentIntersection(scanline_linesegment_intersection, scanline_idx, infill_line_width_); + zigzag_connector_processor.registerScanlineSegmentIntersection(scanline_linesegment_intersection, scanline_idx, infill_line_width_ * 2); crossings_per_scanline[scanline_idx - min_scanline_index].emplace_back(scanline_linesegment_intersection, poly_idx, point_idx); } zigzag_connector_processor.registerVertex(p1); diff --git a/src/infill/ZigzagConnectorProcessor.cpp b/src/infill/ZigzagConnectorProcessor.cpp index bb7c1bbbac..315735bb9a 100644 --- a/src/infill/ZigzagConnectorProcessor.cpp +++ b/src/infill/ZigzagConnectorProcessor.cpp @@ -100,13 +100,13 @@ void ZigzagConnectorProcessor::registerScanlineSegmentIntersection(const Point2L if (shouldAddCurrentConnector(last_connector_index_, scanline_index)) { const bool is_this_endpiece = scanline_index == last_connector_index_; - bool close_to_line_except_intersect = false; + bool close_to_line_except_intersect = true; const coord_t min_dist2 = min_distance_to_scanline * min_distance_to_scanline; for (const auto& point : current_connector_) { - close_to_line_except_intersect |= (std::abs(point.X - intersection.X) < min_distance_to_scanline) && (vSize2(point - intersection) > min_dist2); + close_to_line_except_intersect &= std::abs(point.X - intersection.X) < min_distance_to_scanline; } - if (! close_to_line_except_intersect) + if (current_connector_.empty() || ! close_to_line_except_intersect) { current_connector_.push_back(intersection); addZagConnector(current_connector_, is_this_endpiece); From 7206bc92130bb2012df427fcd74758f929447119 Mon Sep 17 00:00:00 2001 From: Remco Burema Date: Wed, 10 Apr 2024 10:59:37 +0200 Subject: [PATCH 195/201] Make min-distance to connecting piece dependant on line-distance. This fixes the issue that (near) 100% fill zig-zags had if you just make it anywhere near larger than a single line-distance. part of CURA-11597 --- src/infill.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/infill.cpp b/src/infill.cpp index ce5189973e..715cce1c61 100644 --- a/src/infill.cpp +++ b/src/infill.cpp @@ -751,7 +751,7 @@ void Infill::generateLinearBasedInfill( assert(scanline_idx - scanline_min_idx >= 0 && scanline_idx - scanline_min_idx < int(cut_list.size()) && "reading infill cutlist index out of bounds!"); cut_list[scanline_idx - scanline_min_idx].push_back(y); Point2LL scanline_linesegment_intersection(x, y); - zigzag_connector_processor.registerScanlineSegmentIntersection(scanline_linesegment_intersection, scanline_idx, infill_line_width_ * 2); + zigzag_connector_processor.registerScanlineSegmentIntersection(scanline_linesegment_intersection, scanline_idx, line_distance / 2); crossings_per_scanline[scanline_idx - min_scanline_index].emplace_back(scanline_linesegment_intersection, poly_idx, point_idx); } zigzag_connector_processor.registerVertex(p1); From f05f5386c7fb2226d3630cebc429ee35f1850eb4 Mon Sep 17 00:00:00 2001 From: Remco Burema Date: Thu, 11 Apr 2024 11:01:19 +0200 Subject: [PATCH 196/201] Make line-overlap detection more conservative. (Tried a lot of other things as well, which makes it less predictable.) Clean up experiments, bring it back to basics, be quite conservative as this is only a patch and solving the whole 'scan-segments can be too close to the connector paths' probably requires properly rewriting the zig-zag algorithm -- which is way more like a feature. part of CURA-11597 --- include/infill/ZigzagConnectorProcessor.h | 2 ++ src/infill.cpp | 2 +- src/infill/ZigzagConnectorProcessor.cpp | 24 +++++++++++------------ 3 files changed, 15 insertions(+), 13 deletions(-) diff --git a/include/infill/ZigzagConnectorProcessor.h b/include/infill/ZigzagConnectorProcessor.h index 9adb751430..9b1b979cf6 100644 --- a/include/infill/ZigzagConnectorProcessor.h +++ b/include/infill/ZigzagConnectorProcessor.h @@ -175,6 +175,8 @@ class ZigzagConnectorProcessor */ void addZagConnector(std::vector& points, bool is_endpiece); + bool handleConnectorToCloseToSegment(const coord_t scanline_x, const coord_t min_distance_to_scanline); + protected: const PointMatrix& rotation_matrix_; //!< The rotation matrix used to enforce the infill angle Polygons& result_; //!< The result of the computation diff --git a/src/infill.cpp b/src/infill.cpp index 715cce1c61..7164da9741 100644 --- a/src/infill.cpp +++ b/src/infill.cpp @@ -751,7 +751,7 @@ void Infill::generateLinearBasedInfill( assert(scanline_idx - scanline_min_idx >= 0 && scanline_idx - scanline_min_idx < int(cut_list.size()) && "reading infill cutlist index out of bounds!"); cut_list[scanline_idx - scanline_min_idx].push_back(y); Point2LL scanline_linesegment_intersection(x, y); - zigzag_connector_processor.registerScanlineSegmentIntersection(scanline_linesegment_intersection, scanline_idx, line_distance / 2); + zigzag_connector_processor.registerScanlineSegmentIntersection(scanline_linesegment_intersection, scanline_idx, line_distance / 4); crossings_per_scanline[scanline_idx - min_scanline_index].emplace_back(scanline_linesegment_intersection, poly_idx, point_idx); } zigzag_connector_processor.registerVertex(p1); diff --git a/src/infill/ZigzagConnectorProcessor.cpp b/src/infill/ZigzagConnectorProcessor.cpp index 315735bb9a..c19cd46b4e 100644 --- a/src/infill/ZigzagConnectorProcessor.cpp +++ b/src/infill/ZigzagConnectorProcessor.cpp @@ -83,6 +83,15 @@ bool ZigzagConnectorProcessor::shouldAddCurrentConnector(int start_scanline_idx, return should_add; } +bool ZigzagConnectorProcessor::handleConnectorToCloseToSegment(const coord_t scanline_x, const coord_t min_distance_to_scanline) +{ + bool all_within_min_dist = ! current_connector_.empty(); + for (const auto& point : current_connector_) + { + all_within_min_dist &= std::abs(point.X - scanline_x) < min_distance_to_scanline; + } + return all_within_min_dist; +} void ZigzagConnectorProcessor::registerScanlineSegmentIntersection(const Point2LL& intersection, int scanline_index, coord_t min_distance_to_scanline) { @@ -97,20 +106,11 @@ void ZigzagConnectorProcessor::registerScanlineSegmentIntersection(const Point2L else { // add the current connector if needed - if (shouldAddCurrentConnector(last_connector_index_, scanline_index)) + if (shouldAddCurrentConnector(last_connector_index_, scanline_index) && ! handleConnectorToCloseToSegment(intersection.X, min_distance_to_scanline)) { const bool is_this_endpiece = scanline_index == last_connector_index_; - bool close_to_line_except_intersect = true; - const coord_t min_dist2 = min_distance_to_scanline * min_distance_to_scanline; - for (const auto& point : current_connector_) - { - close_to_line_except_intersect &= std::abs(point.X - intersection.X) < min_distance_to_scanline; - } - if (current_connector_.empty() || ! close_to_line_except_intersect) - { - current_connector_.push_back(intersection); - addZagConnector(current_connector_, is_this_endpiece); - } + current_connector_.push_back(intersection); + addZagConnector(current_connector_, is_this_endpiece); } } From 449c209cda975a42c37f104286dc3b0443e97db9 Mon Sep 17 00:00:00 2001 From: Remco Burema Date: Thu, 11 Apr 2024 11:28:24 +0200 Subject: [PATCH 197/201] Only split up densities _completely_ when we zig-zaggify infill. Only do the new split-up in the rare cases where stuff goes wrong for now (= gradual fills + connected fill lines). We're not adjusting the percentages for not doubling/tripling/etc over an area anymore, since that would change too much at this juncture, make it less predicatble which lines in the layer below match up, and we have more walls anyway because of the zig-zagging. part of CURA-11597 --- src/skin.cpp | 8 ++++++-- src/support.cpp | 8 ++++++-- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/skin.cpp b/src/skin.cpp index e342b58554..1bd59d165a 100644 --- a/src/skin.cpp +++ b/src/skin.cpp @@ -471,6 +471,7 @@ void SkinInfillAreaComputation::generateGradualInfill(SliceMeshStorage& mesh) const auto infill_wall_count = mesh.settings.get("infill_wall_line_count"); const auto infill_wall_width = mesh.settings.get("infill_line_width"); const auto infill_overlap = mesh.settings.get("infill_overlap_mm"); + const auto is_connected = mesh.settings.get("zig_zaggify_infill") || mesh.settings.get("infill_pattern") == EFillMethod::ZIG_ZAG; for (LayerIndex layer_idx = 0; layer_idx < static_cast(mesh.layers.size()); layer_idx++) { // loop also over layers which don't contain infill cause of bottom_ and top_layer to initialize their infill_area_per_combine_per_density SliceLayer& layer = mesh.layers[layer_idx]; @@ -497,7 +498,7 @@ void SkinInfillAreaComputation::generateGradualInfill(SliceMeshStorage& mesh) continue; } Polygons less_dense_infill = infill_area; // one step less dense with each infill_step - Polygons sum_more_dense; + Polygons sum_more_dense; // NOTE: Only used for zig-zag or connected fills. for (size_t infill_step = 0; infill_step < max_infill_steps; infill_step++) { LayerIndex min_layer = layer_idx + infill_step * gradual_infill_step_layer_count + static_cast(layer_skip_count); @@ -532,7 +533,10 @@ void SkinInfillAreaComputation::generateGradualInfill(SliceMeshStorage& mesh) const Polygons more_dense_infill = infill_area.difference(less_dense_infill); infill_area_per_combine_current_density.push_back( simplifier.polygon(more_dense_infill.difference(sum_more_dense).offset(-infill_wall_width).offset(infill_wall_width))); - sum_more_dense = sum_more_dense.unionPolygons(more_dense_infill); + if (is_connected) + { + sum_more_dense = sum_more_dense.unionPolygons(more_dense_infill); + } } part.infill_area_per_combine_per_density.emplace_back(); std::vector& infill_area_per_combine_current_density = part.infill_area_per_combine_per_density.back(); diff --git a/src/support.cpp b/src/support.cpp index e8546c55f0..4954501e0a 100644 --- a/src/support.cpp +++ b/src/support.cpp @@ -187,6 +187,7 @@ void AreaSupport::generateGradualSupport(SliceDataStorage& storage) const size_t max_density_steps = infill_extruder.settings_.get("gradual_support_infill_steps"); const coord_t wall_width = infill_extruder.settings_.get("support_line_width"); + const bool is_connected = infill_extruder.settings_.get("zig_zaggify_infill") || infill_extruder.settings_.get("infill_pattern") == EFillMethod::ZIG_ZAG; const Simplify simplifier(infill_extruder.settings_); // no early-out for this function; it needs to initialize the [infill_area_per_combine_per_density] @@ -235,7 +236,7 @@ void AreaSupport::generateGradualSupport(SliceDataStorage& storage) // calculate density areas for this island Polygons less_dense_support = infill_area; // one step less dense with each density_step - Polygons sum_more_dense; + Polygons sum_more_dense; // NOTE: Only used for zig-zag or connected fills. for (unsigned int density_step = 0; density_step < max_density_steps; ++density_step) { LayerIndex actual_min_layer{ layer_nr + density_step * gradual_support_step_layer_count + static_cast(layer_skip_count) }; @@ -295,7 +296,10 @@ void AreaSupport::generateGradualSupport(SliceDataStorage& storage) std::vector& support_area_current_density = support_infill_part.infill_area_per_combine_per_density_.back(); const Polygons more_dense_support = infill_area.difference(less_dense_support); support_area_current_density.push_back(simplifier.polygon(more_dense_support.difference(sum_more_dense).offset(-wall_width).offset(wall_width))); - sum_more_dense = sum_more_dense.unionPolygons(more_dense_support); + if (is_connected) + { + sum_more_dense = sum_more_dense.unionPolygons(more_dense_support); + } } support_infill_part.infill_area_per_combine_per_density_.emplace_back(); From 6592e502ead8022d6906d2643213706f54c3c880 Mon Sep 17 00:00:00 2001 From: rburema Date: Thu, 11 Apr 2024 09:29:36 +0000 Subject: [PATCH 198/201] Applied clang-format. --- src/skin.cpp | 2 +- src/support.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/skin.cpp b/src/skin.cpp index 1bd59d165a..32469b2766 100644 --- a/src/skin.cpp +++ b/src/skin.cpp @@ -498,7 +498,7 @@ void SkinInfillAreaComputation::generateGradualInfill(SliceMeshStorage& mesh) continue; } Polygons less_dense_infill = infill_area; // one step less dense with each infill_step - Polygons sum_more_dense; // NOTE: Only used for zig-zag or connected fills. + Polygons sum_more_dense; // NOTE: Only used for zig-zag or connected fills. for (size_t infill_step = 0; infill_step < max_infill_steps; infill_step++) { LayerIndex min_layer = layer_idx + infill_step * gradual_infill_step_layer_count + static_cast(layer_skip_count); diff --git a/src/support.cpp b/src/support.cpp index 4954501e0a..bafce3e6f2 100644 --- a/src/support.cpp +++ b/src/support.cpp @@ -236,7 +236,7 @@ void AreaSupport::generateGradualSupport(SliceDataStorage& storage) // calculate density areas for this island Polygons less_dense_support = infill_area; // one step less dense with each density_step - Polygons sum_more_dense; // NOTE: Only used for zig-zag or connected fills. + Polygons sum_more_dense; // NOTE: Only used for zig-zag or connected fills. for (unsigned int density_step = 0; density_step < max_density_steps; ++density_step) { LayerIndex actual_min_layer{ layer_nr + density_step * gradual_support_step_layer_count + static_cast(layer_skip_count) }; From eeec9636f7b3f749b790a1bea4c2901196cee027 Mon Sep 17 00:00:00 2001 From: Remco Burema Date: Thu, 11 Apr 2024 11:34:17 +0200 Subject: [PATCH 199/201] Morphologic opening operation was causing floating areas. Introduced earlier in this PR to solve some edge cases, but more trouble than it's worth it seems, at the very least when it's for support. part of CURA-11597 --- src/support.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/support.cpp b/src/support.cpp index bafce3e6f2..f5ad514faa 100644 --- a/src/support.cpp +++ b/src/support.cpp @@ -295,7 +295,7 @@ void AreaSupport::generateGradualSupport(SliceDataStorage& storage) support_infill_part.infill_area_per_combine_per_density_.emplace_back(); std::vector& support_area_current_density = support_infill_part.infill_area_per_combine_per_density_.back(); const Polygons more_dense_support = infill_area.difference(less_dense_support); - support_area_current_density.push_back(simplifier.polygon(more_dense_support.difference(sum_more_dense).offset(-wall_width).offset(wall_width))); + support_area_current_density.push_back(simplifier.polygon(more_dense_support.difference(sum_more_dense))); if (is_connected) { sum_more_dense = sum_more_dense.unionPolygons(more_dense_support); @@ -304,7 +304,7 @@ void AreaSupport::generateGradualSupport(SliceDataStorage& storage) support_infill_part.infill_area_per_combine_per_density_.emplace_back(); std::vector& support_area_current_density = support_infill_part.infill_area_per_combine_per_density_.back(); - support_area_current_density.push_back(simplifier.polygon(infill_area.difference(sum_more_dense).offset(-wall_width).offset(wall_width))); + support_area_current_density.push_back(simplifier.polygon(infill_area.difference(sum_more_dense))); assert(support_infill_part.infill_area_per_combine_per_density_.size() != 0 && "support_infill_part.infill_area_per_combine_per_density should now be initialized"); #ifdef DEBUG From 513927496c23425e27539088598d4ee6ae67b008 Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Wed, 17 Apr 2024 14:53:53 +0200 Subject: [PATCH 200/201] Minor code cleaning and optimization CURA-11597 --- include/infill/ZigzagConnectorProcessor.h | 2 +- src/infill/ZigzagConnectorProcessor.cpp | 21 +++++++++++++++------ 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/include/infill/ZigzagConnectorProcessor.h b/include/infill/ZigzagConnectorProcessor.h index 9b1b979cf6..5bc629b685 100644 --- a/include/infill/ZigzagConnectorProcessor.h +++ b/include/infill/ZigzagConnectorProcessor.h @@ -175,7 +175,7 @@ class ZigzagConnectorProcessor */ void addZagConnector(std::vector& points, bool is_endpiece); - bool handleConnectorToCloseToSegment(const coord_t scanline_x, const coord_t min_distance_to_scanline); + bool handleConnectorTooCloseToSegment(const coord_t scanline_x, const coord_t min_distance_to_scanline); protected: const PointMatrix& rotation_matrix_; //!< The rotation matrix used to enforce the infill angle diff --git a/src/infill/ZigzagConnectorProcessor.cpp b/src/infill/ZigzagConnectorProcessor.cpp index c19cd46b4e..4e28dee774 100644 --- a/src/infill/ZigzagConnectorProcessor.cpp +++ b/src/infill/ZigzagConnectorProcessor.cpp @@ -83,14 +83,23 @@ bool ZigzagConnectorProcessor::shouldAddCurrentConnector(int start_scanline_idx, return should_add; } -bool ZigzagConnectorProcessor::handleConnectorToCloseToSegment(const coord_t scanline_x, const coord_t min_distance_to_scanline) +bool ZigzagConnectorProcessor::handleConnectorTooCloseToSegment(const coord_t scanline_x, const coord_t min_distance_to_scanline) { - bool all_within_min_dist = ! current_connector_.empty(); - for (const auto& point : current_connector_) + if (current_connector_.empty()) { - all_within_min_dist &= std::abs(point.X - scanline_x) < min_distance_to_scanline; + return false; + } + else + { + return std::find_if( + current_connector_.begin(), + current_connector_.end(), + [scanline_x, min_distance_to_scanline](const Point2LL& point) + { + return std::abs(point.X - scanline_x) >= min_distance_to_scanline; + }) + == current_connector_.end(); } - return all_within_min_dist; } void ZigzagConnectorProcessor::registerScanlineSegmentIntersection(const Point2LL& intersection, int scanline_index, coord_t min_distance_to_scanline) @@ -106,7 +115,7 @@ void ZigzagConnectorProcessor::registerScanlineSegmentIntersection(const Point2L else { // add the current connector if needed - if (shouldAddCurrentConnector(last_connector_index_, scanline_index) && ! handleConnectorToCloseToSegment(intersection.X, min_distance_to_scanline)) + if (shouldAddCurrentConnector(last_connector_index_, scanline_index) && ! handleConnectorTooCloseToSegment(intersection.X, min_distance_to_scanline)) { const bool is_this_endpiece = scanline_index == last_connector_index_; current_connector_.push_back(intersection); From fe02797035a248840e1cc16c89a723aa7f4ac037 Mon Sep 17 00:00:00 2001 From: Jelle Spijker Date: Mon, 22 Apr 2024 12:39:43 +0200 Subject: [PATCH 201/201] pin version 5.7.1 --- conandata.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conandata.yml b/conandata.yml index e6c16b939b..25ea096dd3 100644 --- a/conandata.yml +++ b/conandata.yml @@ -1,4 +1,4 @@ -version: "5.7.0" +version: "5.7.1" requirements: - "scripta/0.1.0@ultimaker/testing" requirements_arcus: