Exemple #1
0
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);
    }
}
Exemple #2
0
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]);
        }
    }
}
Exemple #3
0
/*
 * 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);
}
Exemple #4
0
/*
 * 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;
    }
}
Exemple #5
0
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);
        }
    }
}
Exemple #6
0
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;
        }
    }
}