void SkirtBrim::getFirstLayerOutline(SliceDataStorage& storage, const unsigned int primary_line_count, const int primary_extruder_skirt_brim_line_width, const bool is_skirt, const bool outside_only, Polygons& first_layer_outline) { bool external_only = is_skirt; // whether to include holes or not const int layer_nr = 0; if (is_skirt) { const bool include_helper_parts = true; first_layer_outline = storage.getLayerOutlines(layer_nr, include_helper_parts, external_only); first_layer_outline = first_layer_outline.approxConvexHull(); } else { // add brim underneath support by removing support where there's brim around the model const bool include_helper_parts = false; // include manually below first_layer_outline = storage.getLayerOutlines(layer_nr, include_helper_parts, external_only); first_layer_outline.add(storage.primeTower.ground_poly); // don't remove parts of the prime tower, but make a brim for it if (outside_only) { first_layer_outline = first_layer_outline.removeEmptyHoles(); } if (storage.support.generated && primary_line_count > 0) { // remove model-brim from support // avoid gap in the middle // V // +---+ +----+ // |+-+| |+--+| // || || ||[]|| > expand to fit an extra brim line // |+-+| |+--+| // +---+ +----+ const Polygons& model_brim_covered_area = first_layer_outline.offset(primary_extruder_skirt_brim_line_width * (primary_line_count + primary_line_count % 2)); // always leave a gap of an even number of brim lines, so that it fits if it's generating brim from both sides SupportLayer& support_layer = storage.support.supportLayers[0]; support_layer.supportAreas = support_layer.supportAreas.difference(model_brim_covered_area); first_layer_outline.add(support_layer.supportAreas); first_layer_outline.add(support_layer.skin); } } constexpr int join_distance = 20; first_layer_outline = first_layer_outline.offset(join_distance).offset(-join_distance); // merge adjacent models into single polygon constexpr int smallest_line_length = 200; constexpr int largest_error_of_removed_point = 50; first_layer_outline.simplify(smallest_line_length, largest_error_of_removed_point); // simplify for faster processing of the brim lines }
void SkirtBrim::getFirstLayerOutline(SliceDataStorage& storage, const size_t primary_line_count, const bool is_skirt, Polygons& first_layer_outline) { const ExtruderTrain& train = Application::getInstance().current_slice->scene.current_mesh_group->settings.get<ExtruderTrain&>("adhesion_extruder_nr"); const ExtruderTrain& support_infill_extruder = Application::getInstance().current_slice->scene.current_mesh_group->settings.get<ExtruderTrain&>("support_infill_extruder_nr"); const bool external_only = is_skirt || train.settings.get<bool>("brim_outside_only"); //Whether to include holes or not. Skirt doesn't have any holes. const LayerIndex layer_nr = 0; if (is_skirt) { constexpr bool include_support = true; constexpr bool include_prime_tower = true; first_layer_outline = storage.getLayerOutlines(layer_nr, include_support, include_prime_tower, external_only); first_layer_outline = first_layer_outline.approxConvexHull(); } 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; //Include manually below. constexpr bool external_outlines_only = false; //Remove manually below. first_layer_outline = storage.getLayerOutlines(layer_nr, include_support, include_prime_tower, external_outlines_only); 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) { first_layer_empty_holes = first_layer_outline.getEmptyHoles(); first_layer_outline = first_layer_outline.removeEmptyHoles(); } if (storage.support.generated && primary_line_count > 0 && !storage.support.supportLayers.empty()) { // remove model-brim from support SupportLayer& support_layer = storage.support.supportLayers[0]; if (support_infill_extruder.settings.get<bool>("brim_replaces_support")) { // avoid gap in the middle // V // +---+ +----+ // |+-+| |+--+| // || || ||[]|| > expand to fit an extra brim line // |+-+| |+--+| // +---+ +----+ const coord_t primary_extruder_skirt_brim_line_width = train.settings.get<coord_t>("skirt_brim_line_width") * train.settings.get<Ratio>("initial_layer_line_width_factor"); 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) { // don't remove support within empty holes where no brim is generated. model_brim_covered_area.add(first_layer_empty_holes); } AABB model_brim_covered_area_boundary_box(model_brim_covered_area); support_layer.excludeAreasFromSupportInfillAreas(model_brim_covered_area, model_brim_covered_area_boundary_box); } for (const SupportInfillPart& support_infill_part : support_layer.support_infill_parts) { first_layer_outline.add(support_infill_part.outline); } first_layer_outline.add(support_layer.support_bottom); first_layer_outline.add(support_layer.support_roof); } if (storage.primeTower.enabled) { first_layer_outline.add(storage.primeTower.outer_poly_first_layer); // don't remove parts of the prime tower, but make a brim for it } } constexpr coord_t join_distance = 20; first_layer_outline = first_layer_outline.offset(join_distance).offset(-join_distance); // merge adjacent models into single polygon constexpr coord_t smallest_line_length = 200; constexpr coord_t largest_error_of_removed_point = 50; first_layer_outline.simplify(smallest_line_length, largest_error_of_removed_point); // simplify for faster processing of the brim lines if (first_layer_outline.size() == 0) { logError("Couldn't generate skirt / brim! No polygons on first layer.\n"); } }
void SkirtBrim::generate(SliceDataStorage& storage, Polygons first_layer_outline, int start_distance, unsigned int primary_line_count) { const bool is_skirt = start_distance > 0; Scene& scene = Application::getInstance().current_slice->scene; const size_t adhesion_extruder_nr = scene.current_mesh_group->settings.get<ExtruderTrain&>("adhesion_extruder_nr").extruder_nr; const Settings& adhesion_settings = scene.extruders[adhesion_extruder_nr].settings; const coord_t primary_extruder_skirt_brim_line_width = adhesion_settings.get<coord_t>("skirt_brim_line_width") * adhesion_settings.get<Ratio>("initial_layer_line_width_factor"); const coord_t primary_extruder_minimal_length = adhesion_settings.get<coord_t>("skirt_brim_minimal_length"); Polygons& skirt_brim_primary_extruder = storage.skirt_brim[adhesion_extruder_nr]; const bool has_ooze_shield = storage.oozeShield.size() > 0 && storage.oozeShield[0].size() > 0; const bool has_draft_shield = storage.draft_protection_shield.size() > 0; if (is_skirt && (has_ooze_shield || has_draft_shield)) { // make sure we don't generate skirt through draft / ooze shield first_layer_outline = first_layer_outline.offset(start_distance - primary_extruder_skirt_brim_line_width / 2, ClipperLib::jtRound).unionPolygons(storage.draft_protection_shield); if (has_ooze_shield) { first_layer_outline = first_layer_outline.unionPolygons(storage.oozeShield[0]); } first_layer_outline = first_layer_outline.approxConvexHull(); start_distance = primary_extruder_skirt_brim_line_width / 2; } int offset_distance = generatePrimarySkirtBrimLines(start_distance, primary_line_count, primary_extruder_minimal_length, first_layer_outline, skirt_brim_primary_extruder); // handle support-brim const ExtruderTrain& support_infill_extruder = scene.current_mesh_group->settings.get<ExtruderTrain&>("support_infill_extruder_nr"); if (support_infill_extruder.settings.get<bool>("support_brim_enable")) { generateSupportBrim(storage); } // generate brim for ooze shield and draft shield if (!is_skirt && (has_ooze_shield || has_draft_shield)) { // generate areas where to make extra brim for the shields // avoid gap in the middle // V // +---+ +----+ // |+-+| |+--+| // || || ||[]|| > expand to fit an extra brim line // |+-+| |+--+| // +---+ +----+ const int64_t primary_skirt_brim_width = (primary_line_count + primary_line_count % 2) * primary_extruder_skirt_brim_line_width; // always use an even number, because we will fil the area from both sides Polygons shield_brim; if (has_ooze_shield) { shield_brim = storage.oozeShield[0].difference(storage.oozeShield[0].offset(-primary_skirt_brim_width - primary_extruder_skirt_brim_line_width)); } if (has_draft_shield) { shield_brim = shield_brim.unionPolygons(storage.draft_protection_shield.difference(storage.draft_protection_shield.offset(-primary_skirt_brim_width - primary_extruder_skirt_brim_line_width))); } const Polygons outer_primary_brim = first_layer_outline.offset(offset_distance, ClipperLib::jtRound); shield_brim = shield_brim.difference(outer_primary_brim.offset(primary_extruder_skirt_brim_line_width)); // generate brim within shield_brim skirt_brim_primary_extruder.add(shield_brim); while (shield_brim.size() > 0) { shield_brim = shield_brim.offset(-primary_extruder_skirt_brim_line_width); skirt_brim_primary_extruder.add(shield_brim); } // update parameters to generate secondary skirt around first_layer_outline = outer_primary_brim; if (has_draft_shield) { first_layer_outline = first_layer_outline.unionPolygons(storage.draft_protection_shield); } if (has_ooze_shield) { first_layer_outline = first_layer_outline.unionPolygons(storage.oozeShield[0]); } offset_distance = 0; } { // process other extruders' brim/skirt (as one brim line around the old brim) int last_width = primary_extruder_skirt_brim_line_width; std::vector<bool> extruder_is_used = storage.getExtrudersUsed(); for (size_t extruder_nr = 0; extruder_nr < Application::getInstance().current_slice->scene.extruders.size(); extruder_nr++) { if (extruder_nr == adhesion_extruder_nr || !extruder_is_used[extruder_nr]) { continue; } const ExtruderTrain& train = Application::getInstance().current_slice->scene.extruders[extruder_nr]; const coord_t width = train.settings.get<coord_t>("skirt_brim_line_width") * train.settings.get<Ratio>("initial_layer_line_width_factor"); const coord_t minimal_length = train.settings.get<coord_t>("skirt_brim_minimal_length"); offset_distance += last_width / 2 + width/2; last_width = width; while (storage.skirt_brim[extruder_nr].polygonLength() < minimal_length) { storage.skirt_brim[extruder_nr].add(first_layer_outline.offset(offset_distance, ClipperLib::jtRound)); offset_distance += width; } } } }