void generateInfill(int layerNr, SliceMeshStorage& mesh, const int innermost_wall_line_width, int infill_skin_overlap, int wall_line_count) { SliceLayer& layer = mesh.layers[layerNr]; for(SliceLayerPart& part : layer.parts) { if (int(part.insets.size()) < wall_line_count) { continue; // the last wall is not present, the part should only get inter preimeter gaps, but no infill. } Polygons infill = part.insets.back().offset(-innermost_wall_line_width / 2 - infill_skin_overlap); for(SliceLayerPart& part2 : layer.parts) { if (part.boundaryBox.hit(part2.boundaryBox)) { for(SkinPart& skin_part : part2.skin_parts) { infill = infill.difference(skin_part.outline); } } } infill.removeSmallAreas(MIN_AREA_SIZE); part.infill_area = infill.offset(infill_skin_overlap); } }
void AreaSupport::generateSupportInterface(SliceDataStorage& storage, const SliceMeshStorage& mesh, std::vector<Polygons>& support_areas, const unsigned int layer_count) { const unsigned int roof_layer_count = round_divide(mesh.getSettingInMicrons("support_roof_height"), storage.getSettingInMicrons("layer_height")); const unsigned int bottom_layer_count = round_divide(mesh.getSettingInMicrons("support_bottom_height"), storage.getSettingInMicrons("layer_height")); const unsigned int z_distance_bottom = round_up_divide(mesh.getSettingInMicrons("support_bottom_distance"), storage.getSettingInMicrons("layer_height")); const unsigned int z_distance_top = round_up_divide(mesh.getSettingInMicrons("support_top_distance"), storage.getSettingInMicrons("layer_height")); const int skip_layer_count = std::max(1u, round_divide(mesh.getSettingInMicrons("support_interface_skip_height"), storage.getSettingInMicrons("layer_height"))); const int interface_line_width = storage.meshgroup->getExtruderTrain(storage.getSettingAsIndex("support_interface_extruder_nr"))->getSettingInMicrons("support_interface_line_width"); std::vector<SupportLayer>& supportLayers = storage.support.supportLayers; for (unsigned int layer_idx = 0; layer_idx < layer_count; layer_idx++) { SupportLayer& layer = supportLayers[layer_idx]; const unsigned int top_layer_idx_above = layer_idx + roof_layer_count + z_distance_top; const unsigned int bottom_layer_idx_below = std::max(0, int(layer_idx) - int(bottom_layer_count) - int(z_distance_bottom)); if (top_layer_idx_above < supportLayers.size()) { Polygons roofs; if (roof_layer_count > 0) { Polygons model; const unsigned int n_scans = std::max(1u, (roof_layer_count - 1) / skip_layer_count); const float z_skip = std::max(1.0f, float(roof_layer_count - 1) / float(n_scans)); for (float layer_idx_above = top_layer_idx_above; layer_idx_above > layer_idx + z_distance_top; layer_idx_above -= z_skip) { const Polygons outlines_above = mesh.layers[std::round(layer_idx_above)].getOutlines(); model = model.unionPolygons(outlines_above); } roofs = support_areas[layer_idx].intersection(model); } Polygons bottoms; if (bottom_layer_count > 0) { Polygons model; const unsigned int n_scans = std::max(1u, (bottom_layer_count - 1) / skip_layer_count); const float z_skip = std::max(1.0f, float(bottom_layer_count - 1) / float(n_scans)); for (float layer_idx_below = bottom_layer_idx_below; std::round(layer_idx_below) < (int)(layer_idx - z_distance_bottom); layer_idx_below += z_skip) { const Polygons outlines_below = mesh.layers[std::round(layer_idx_below)].getOutlines(); model = model.unionPolygons(outlines_below); } bottoms = support_areas[layer_idx].intersection(model); } // expand skin a bit so that we're sure it's not too thin to be printed. Polygons skin = roofs.unionPolygons(bottoms).offset(interface_line_width).intersection(support_areas[layer_idx]); skin.removeSmallAreas(1.0); layer.skin.add(skin); layer.supportAreas.add(support_areas[layer_idx].difference(layer.skin)); } else { layer.skin.add(support_areas[layer_idx]); } } }
/* * This function is executed in a parallel region based on layer_nr. * When modifying make sure any changes does not introduce data races. * * generateInfill read mesh.layers[n].parts[*].{insets,skin_parts,boundingBox} and write mesh.layers[n].parts[*].infill_area */ void SkinInfillAreaComputation::generateInfill(SliceLayerPart& part, const Polygons& skin) { if (int(part.insets.size()) < wall_line_count) { return; // the last wall is not present, the part should only get inter perimeter gaps, but no infill. } const int wall_line_count = mesh.getSettingAsCount("wall_line_count"); const coord_t infill_line_distance = mesh.getSettingInMicrons("infill_line_distance"); coord_t offset_from_inner_wall = -infill_skin_overlap; if (wall_line_count > 0) { // calculate offset_from_inner_wall coord_t extra_perimeter_offset = 0; // to align concentric polygons across layers EFillMethod fill_pattern = mesh.getSettingAsFillMethod("infill_pattern"); if ((fill_pattern == EFillMethod::CONCENTRIC || fill_pattern == EFillMethod::CONCENTRIC_3D) && infill_line_distance > mesh.getSettingInMicrons("infill_line_width") * 2) { if (mesh.getSettingBoolean("alternate_extra_perimeter") && layer_nr % 2 == 0) { // compensate shifts otherwise caused by alternating an extra perimeter extra_perimeter_offset = -innermost_wall_line_width; } if (layer_nr == 0) { // compensate for shift caused by walls being expanded by the initial line width multiplier const coord_t normal_wall_line_width_0 = mesh.getSettingInMicrons("wall_line_width_0"); const coord_t normal_wall_line_width_x = mesh.getSettingInMicrons("wall_line_width_x"); coord_t normal_walls_width = normal_wall_line_width_0 + (wall_line_count - 1) * normal_wall_line_width_x; coord_t walls_width = normal_walls_width * mesh.getSettingAsRatio("initial_layer_line_width_factor"); extra_perimeter_offset += walls_width - normal_walls_width; while (extra_perimeter_offset > 0) { extra_perimeter_offset -= infill_line_distance; } } } offset_from_inner_wall += extra_perimeter_offset - innermost_wall_line_width / 2; } Polygons infill = part.insets.back().offset(offset_from_inner_wall); infill = infill.difference(skin); infill.removeSmallAreas(MIN_AREA_SIZE); part.infill_area = infill.offset(infill_skin_overlap); }
/* * This function is executed in a parallel region based on layer_nr. * When modifying make sure any changes does not introduce data races. * * generateSkinAreas reads data from mesh.layers[*].parts[*].insets and writes to mesh.layers[n].parts[*].skin_parts */ void SkinInfillAreaComputation::generateSkinAndInfillAreas(SliceLayerPart& part) { int min_infill_area = mesh.getSettingInMillimeters("min_infill_area"); Polygons original_outline = part.insets.back().offset(-innermost_wall_line_width / 2); // make a copy of the outline which we later intersect and union with the resized skins to ensure the resized skin isn't too large or removed completely. Polygons upskin; if (top_layer_count > 0) { upskin = Polygons(original_outline); } Polygons downskin; if (bottom_layer_count > 0) { downskin = Polygons(original_outline); } calculateBottomSkin(part, min_infill_area, downskin); calculateTopSkin(part, min_infill_area, upskin); applySkinExpansion(original_outline, upskin, downskin); // now combine the resized upskin and downskin Polygons skin = upskin.unionPolygons(downskin); skin.removeSmallAreas(MIN_AREA_SIZE); if (process_infill) { // process infill when infill density > 0 // or when other infill meshes want to modify this infill generateInfill(part, skin); } for (PolygonsPart& skin_area_part : skin.splitIntoParts()) { part.skin_parts.emplace_back(); part.skin_parts.back().outline = skin_area_part; } }
void AreaSupport::generateSupportRoofs(SliceDataStorage& storage, std::vector<Polygons>& supportAreas, unsigned int layer_count, int layerThickness, int support_roof_height, CommandSocket* commandSocket) { int roof_layer_count = support_roof_height / layerThickness; std::vector<SupportLayer>& supportLayers = storage.support.supportLayers; for (unsigned int layer_idx = 0; layer_idx < layer_count; layer_idx++) { SupportLayer& layer = supportLayers[layer_idx]; if (layer_idx + roof_layer_count < supportLayers.size()) { Polygons roofs = supportAreas[layer_idx].difference(supportAreas[layer_idx + roof_layer_count]); roofs.removeSmallAreas(1.0); layer.roofs.add(roofs); layer.supportAreas.add(supportAreas[layer_idx].difference(layer.roofs)); } else { layer.roofs.add(layer.supportAreas); } } }
void generateSkinAreas(int layer_nr, SliceMeshStorage& mesh, const int innermost_wall_line_width, int downSkinCount, int upSkinCount, int wall_line_count, bool no_small_gaps_heuristic) { SliceLayer& layer = mesh.layers[layer_nr]; if (downSkinCount == 0 && upSkinCount == 0) { return; } for(unsigned int partNr = 0; partNr < layer.parts.size(); partNr++) { SliceLayerPart& part = layer.parts[partNr]; if (int(part.insets.size()) < wall_line_count) { continue; // the last wall is not present, the part should only get inter perimeter gaps, but no skin. } Polygons upskin = part.insets.back().offset(-innermost_wall_line_width / 2); Polygons downskin = (downSkinCount == 0) ? Polygons() : upskin; if (upSkinCount == 0) upskin = Polygons(); auto getInsidePolygons = [&part, wall_line_count](SliceLayer& layer2) { Polygons result; for(SliceLayerPart& part2 : layer2.parts) { if (part.boundaryBox.hit(part2.boundaryBox)) { unsigned int wall_idx = std::max(0, std::min(wall_line_count, (int) part2.insets.size()) - 1); result.add(part2.insets[wall_idx]); } } return result; }; if (no_small_gaps_heuristic) { if (static_cast<int>(layer_nr - downSkinCount) >= 0) { downskin = downskin.difference(getInsidePolygons(mesh.layers[layer_nr - downSkinCount])); // skin overlaps with the walls } if (static_cast<int>(layer_nr + upSkinCount) < static_cast<int>(mesh.layers.size())) { upskin = upskin.difference(getInsidePolygons(mesh.layers[layer_nr + upSkinCount])); // skin overlaps with the walls } } else { if (layer_nr >= downSkinCount && downSkinCount > 0) { Polygons not_air = getInsidePolygons(mesh.layers[layer_nr - 1]); for (int downskin_layer_nr = layer_nr - downSkinCount; downskin_layer_nr < layer_nr - 1; downskin_layer_nr++) { not_air = not_air.intersection(getInsidePolygons(mesh.layers[downskin_layer_nr])); } downskin = downskin.difference(not_air); // skin overlaps with the walls } if (layer_nr < static_cast<int>(mesh.layers.size()) - 1 - upSkinCount && upSkinCount > 0) { Polygons not_air = getInsidePolygons(mesh.layers[layer_nr + 1]); for (int upskin_layer_nr = layer_nr + 2; upskin_layer_nr < layer_nr + upSkinCount + 1; upskin_layer_nr++) { not_air = not_air.intersection(getInsidePolygons(mesh.layers[upskin_layer_nr])); } upskin = upskin.difference(not_air); // skin overlaps with the walls } } Polygons skin = upskin.unionPolygons(downskin); skin.removeSmallAreas(MIN_AREA_SIZE); for (PolygonsPart& skin_area_part : skin.splitIntoParts()) { part.skin_parts.emplace_back(); part.skin_parts.back().outline = skin_area_part; } } }