Comparar commits
50 Commits
| Autor | SHA1 | Data | |
|---|---|---|---|
| 8b82ec4c95 | |||
| bdb788e3c4 | |||
| 5b00c21a5f | |||
| b546f66bbe | |||
| 2af8320cc9 | |||
| 5fa5c89935 | |||
| 5c40f74c68 | |||
| 60cebc86eb | |||
| 1bb4e03b36 | |||
| 677857a186 | |||
| 156674e452 | |||
| 903b31d381 | |||
| 734978230f | |||
| fa02006a5d | |||
| 6861020c6b | |||
| 2d9a3c83ef | |||
| ab7e035f6e | |||
| d0a149cf26 | |||
| 4d35735aa8 | |||
| 5e831f99e9 | |||
| 04766f663b | |||
| 42684e6368 | |||
| aa14682087 | |||
| 4c5a959c4e | |||
| 21746022c4 | |||
| d6bf9be54e | |||
| fff1164042 | |||
| c7e621eeb5 | |||
| 9c3170b277 | |||
| e2f89778e2 | |||
| 8f74952aca | |||
| 5b6f1db59d | |||
| 17463e1139 | |||
| 8df26ae916 | |||
| 9ac9d1dd59 | |||
| c2aa1d59bc | |||
| 3d476f114b | |||
| 152f6e89a8 | |||
| 113202cd34 | |||
| 4bc706d618 | |||
| 5766e2db11 | |||
| 671ebccdbb | |||
| 2516165c86 | |||
| 0315aaf404 | |||
| b43e4df3aa | |||
| 405c49133b | |||
| 49f09ed204 | |||
| e717404055 | |||
| 3e7d623c86 | |||
| d694bff227 |
@@ -42,6 +42,16 @@ if(NOT APPLE AND NOT WIN32)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -static-libstdc++")
|
||||
endif()
|
||||
|
||||
option (ENABLE_OPENMP
|
||||
"Use OpenMP for parallel code" ON)
|
||||
|
||||
if (ENABLE_OPENMP)
|
||||
FIND_PACKAGE( OpenMP )
|
||||
if( OPENMP_FOUND )
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}" )
|
||||
endif()
|
||||
endif()
|
||||
|
||||
include_directories(${CMAKE_CURRENT_BINARY_DIR} libs)
|
||||
|
||||
add_library(clipper STATIC libs/clipper/clipper.cpp)
|
||||
|
||||
+41
-18
@@ -194,7 +194,17 @@ void FffGcodeWriter::initConfigs(SliceDataStorage& storage)
|
||||
mesh.inset0_config.init(mesh.getSettingInMillimetersPerSecond("speed_wall_0"), mesh.getSettingInMillimetersPerSecond("acceleration_wall_0"), mesh.getSettingInMillimetersPerSecond("jerk_wall_0"), mesh.getSettingInMicrons("wall_line_width_0"), mesh.getSettingInPercentage("material_flow"));
|
||||
mesh.insetX_config.init(mesh.getSettingInMillimetersPerSecond("speed_wall_x"), mesh.getSettingInMillimetersPerSecond("acceleration_wall_x"), mesh.getSettingInMillimetersPerSecond("jerk_wall_x"), mesh.getSettingInMicrons("wall_line_width_x"), mesh.getSettingInPercentage("material_flow"));
|
||||
mesh.skin_config.init(mesh.getSettingInMillimetersPerSecond("speed_topbottom"), mesh.getSettingInMillimetersPerSecond("acceleration_topbottom"), mesh.getSettingInMillimetersPerSecond("jerk_topbottom"), mesh.getSettingInMicrons("skin_line_width"), mesh.getSettingInPercentage("material_flow"));
|
||||
|
||||
|
||||
// The perimeter gap config follows the skin config, but has a different line width:
|
||||
// wall_line_width_x divided by two because the gaps are between 0 and 1 times the wall line width
|
||||
const int perimeter_gaps_line_width = mesh.getSettingInMicrons("wall_line_width_x") / 2;
|
||||
double perimeter_gaps_speed = mesh.getSettingInMillimetersPerSecond("speed_topbottom");
|
||||
if (mesh.getSettingBoolean("speed_equalize_flow_enabled"))
|
||||
{
|
||||
perimeter_gaps_speed = perimeter_gaps_speed * mesh.getSettingInMicrons("skin_line_width") / perimeter_gaps_line_width;
|
||||
}
|
||||
mesh.perimeter_gap_config.init(perimeter_gaps_speed, mesh.getSettingInMillimetersPerSecond("acceleration_topbottom"), mesh.getSettingInMillimetersPerSecond("jerk_topbottom"), perimeter_gaps_line_width, mesh.getSettingInPercentage("material_flow"));
|
||||
|
||||
for (unsigned int idx = 0; idx < MAX_INFILL_COMBINE; idx++)
|
||||
{
|
||||
mesh.infill_config[idx].init(mesh.getSettingInMillimetersPerSecond("speed_infill"), mesh.getSettingInMillimetersPerSecond("acceleration_infill"), mesh.getSettingInMillimetersPerSecond("jerk_infill"), mesh.getSettingInMicrons("infill_line_width") * (idx + 1), mesh.getSettingInPercentage("material_flow"));
|
||||
@@ -864,7 +874,9 @@ void FffGcodeWriter::addMeshPartToGCode(SliceDataStorage& storage, SliceMeshStor
|
||||
processSingleLayerInfill(gcode_layer, mesh, part, layer_nr, infill_line_distance, infill_overlap, infill_angle);
|
||||
}
|
||||
|
||||
EFillMethod skin_pattern = mesh->getSettingAsFillMethod("top_bottom_pattern");
|
||||
EFillMethod skin_pattern = (layer_nr == 0)?
|
||||
mesh->getSettingAsFillMethod("top_bottom_pattern_0") :
|
||||
mesh->getSettingAsFillMethod("top_bottom_pattern");
|
||||
int skin_angle = 45;
|
||||
if ((skin_pattern == EFillMethod::LINES || skin_pattern == EFillMethod::ZIG_ZAG) && layer_nr & 1)
|
||||
{
|
||||
@@ -997,7 +1009,7 @@ void FffGcodeWriter::processInsets(GCodePlanner& gcode_layer, SliceMeshStorage*
|
||||
{ // on the last normal layer first make the outer wall normally and then start a second outer wall from the same hight, but gradually moving upward
|
||||
WallOverlapComputation* wall_overlap_computation(nullptr);
|
||||
int wall_0_wipe_dist(0);
|
||||
gcode_layer.addPolygonsByOptimizer(part.insets[0], &mesh->insetX_config, wall_overlap_computation, EZSeamType::SHORTEST, z_seam_pos, mesh->getSettingInMicrons("wall_0_wipe_dist"), wall_0_wipe_dist);
|
||||
gcode_layer.addPolygonsByOptimizer(part.insets[0], &mesh->insetX_config, wall_overlap_computation, EZSeamType::SHORTEST, z_seam_pos, wall_0_wipe_dist, spiralize);
|
||||
}
|
||||
}
|
||||
int processed_inset_number = -1;
|
||||
@@ -1044,9 +1056,11 @@ void FffGcodeWriter::processSkinAndPerimeterGaps(GCodePlanner& gcode_layer, Slic
|
||||
{
|
||||
int64_t z = layer_nr * getSettingInMicrons("layer_height");
|
||||
const unsigned int skin_line_width = mesh->skin_config.getLineWidth();
|
||||
const unsigned int perimeter_gaps_line_width = mesh->perimeter_gap_config.getLineWidth();
|
||||
|
||||
constexpr int perimeter_gaps_extra_offset = 15; // extra offset so that the perimeter gaps aren't created everywhere due to rounding errors
|
||||
bool fill_perimeter_gaps = mesh->getSettingAsFillPerimeterGapMode("fill_perimeter_gaps") != FillPerimeterGapMode::NOWHERE;
|
||||
bool fill_perimeter_gaps = mesh->getSettingAsFillPerimeterGapMode("fill_perimeter_gaps") != FillPerimeterGapMode::NOWHERE
|
||||
&& !mesh->getSettingBoolean("magic_spiralize");
|
||||
|
||||
Point z_seam_pos(0, 0); // not used
|
||||
PathOrderOptimizer part_order_optimizer(gcode_layer.getLastPosition(), z_seam_pos, EZSeamType::SHORTEST);
|
||||
@@ -1064,7 +1078,9 @@ void FffGcodeWriter::processSkinAndPerimeterGaps(GCodePlanner& gcode_layer, Slic
|
||||
Polygons skin_polygons;
|
||||
Polygons skin_lines;
|
||||
|
||||
EFillMethod pattern = mesh->getSettingAsFillMethod("top_bottom_pattern");
|
||||
EFillMethod pattern = (layer_nr == 0)?
|
||||
mesh->getSettingAsFillMethod("top_bottom_pattern_0") :
|
||||
mesh->getSettingAsFillMethod("top_bottom_pattern");
|
||||
int bridge = -1;
|
||||
if (layer_nr > 0)
|
||||
bridge = bridgeAngle(skin_part.outline, &mesh->layers[layer_nr-1]);
|
||||
@@ -1116,13 +1132,6 @@ void FffGcodeWriter::processSkinAndPerimeterGaps(GCodePlanner& gcode_layer, Slic
|
||||
Infill infill_comp(pattern, *inner_skin_outline, offset_from_inner_skin_outline, skin_line_width, skin_line_width, skin_overlap, skin_angle, z, extra_infill_shift, perimeter_gaps_output);
|
||||
infill_comp.generate(skin_polygons, skin_lines);
|
||||
|
||||
if (fill_perimeter_gaps)
|
||||
{ // handle perimeter_gaps of skin insets
|
||||
int offset = 0;
|
||||
Infill infill_comp(EFillMethod::LINES, perimeter_gaps, offset, skin_line_width, skin_line_width, skin_overlap, skin_angle, z, extra_infill_shift);
|
||||
infill_comp.generate(skin_polygons, skin_lines);
|
||||
}
|
||||
|
||||
gcode_layer.addPolygonsByOptimizer(skin_polygons, &mesh->skin_config);
|
||||
|
||||
if (pattern == EFillMethod::GRID || pattern == EFillMethod::LINES || pattern == EFillMethod::TRIANGLES)
|
||||
@@ -1133,6 +1142,16 @@ void FffGcodeWriter::processSkinAndPerimeterGaps(GCodePlanner& gcode_layer, Slic
|
||||
{
|
||||
gcode_layer.addLinesByOptimizer(skin_lines, &mesh->skin_config, (pattern == EFillMethod::ZIG_ZAG)? SpaceFillType::PolyLines : SpaceFillType::Lines);
|
||||
}
|
||||
|
||||
if (fill_perimeter_gaps)
|
||||
{ // handle perimeter_gaps of skin insets
|
||||
Polygons gap_polygons; // will remain empty
|
||||
Polygons gap_lines;
|
||||
int offset = 0;
|
||||
Infill infill_comp(EFillMethod::LINES, perimeter_gaps, offset, perimeter_gaps_line_width, perimeter_gaps_line_width, skin_overlap, skin_angle, z, extra_infill_shift);
|
||||
infill_comp.generate(gap_polygons, gap_lines);
|
||||
gcode_layer.addLinesByOptimizer(gap_lines, &mesh->perimeter_gap_config, SpaceFillType::Lines);
|
||||
}
|
||||
}
|
||||
|
||||
if (fill_perimeter_gaps)
|
||||
@@ -1148,7 +1167,10 @@ void FffGcodeWriter::processSkinAndPerimeterGaps(GCodePlanner& gcode_layer, Slic
|
||||
perimeter_gaps.add(outer.difference(inner));
|
||||
}
|
||||
{ // gap between inner wall and skin/infill
|
||||
if (mesh->getSettingInMicrons("infill_line_distance") > 0 && !mesh->getSettingBoolean("infill_hollow"))
|
||||
if (mesh->getSettingInMicrons("infill_line_distance") > 0
|
||||
&& !mesh->getSettingBoolean("infill_hollow")
|
||||
&& mesh->getSettingInMicrons("infill_overlap_mm") >= 0
|
||||
)
|
||||
{
|
||||
const Polygons outer = part.insets.back().offset(-1 * line_width / 2 - perimeter_gaps_extra_offset);
|
||||
|
||||
@@ -1157,18 +1179,19 @@ void FffGcodeWriter::processSkinAndPerimeterGaps(GCodePlanner& gcode_layer, Slic
|
||||
{
|
||||
inner.add(skin_part.outline);
|
||||
}
|
||||
inner = inner.unionPolygons();
|
||||
perimeter_gaps.add(outer.difference(inner));
|
||||
}
|
||||
}
|
||||
|
||||
Polygons skin_polygons; // unused
|
||||
Polygons skin_lines; // soon to be generated gap filler lines
|
||||
Polygons gap_polygons; // unused
|
||||
Polygons gap_lines; // soon to be generated gap filler lines
|
||||
int offset = 0;
|
||||
int extra_infill_shift = 0;
|
||||
Infill infill_comp(EFillMethod::LINES, perimeter_gaps, offset, skin_line_width, skin_line_width, skin_overlap, skin_angle, z, extra_infill_shift);
|
||||
infill_comp.generate(skin_polygons, skin_lines);
|
||||
Infill infill_comp(EFillMethod::LINES, perimeter_gaps, offset, perimeter_gaps_line_width, perimeter_gaps_line_width, skin_overlap, skin_angle, z, extra_infill_shift);
|
||||
infill_comp.generate(gap_polygons, gap_lines);
|
||||
|
||||
gcode_layer.addLinesByOptimizer(skin_lines, &mesh->skin_config, SpaceFillType::Lines);
|
||||
gcode_layer.addLinesByOptimizer(gap_lines, &mesh->perimeter_gap_config, SpaceFillType::Lines);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,10 @@
|
||||
#include <algorithm>
|
||||
#include <map> // multimap (ordered map allowing duplicate keys)
|
||||
|
||||
#ifdef _OPENMP
|
||||
#include <omp.h>"
|
||||
#endif
|
||||
|
||||
#include "utils/math.h"
|
||||
#include "utils/algorithm.h"
|
||||
#include "slicer.h"
|
||||
@@ -151,6 +155,10 @@ bool FffPolygonGenerator::sliceModel(MeshGroup* meshgroup, TimeKeeper& timeKeepe
|
||||
SupportLayer& support_layer = storage.support.supportLayers[layer_nr];
|
||||
SlicerLayer& slicer_layer = slicer->layers[layer_nr];
|
||||
support_layer.anti_overhang = support_layer.anti_overhang.unionPolygons(slicer_layer.polygons);
|
||||
meshStorage.layers[layer_nr].printZ =
|
||||
slicer_layer.z
|
||||
+ getSettingInMicrons("layer_height_0")
|
||||
- initial_slice_z;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
@@ -161,6 +169,10 @@ bool FffPolygonGenerator::sliceModel(MeshGroup* meshgroup, TimeKeeper& timeKeepe
|
||||
SupportLayer& support_layer = storage.support.supportLayers[layer_nr];
|
||||
SlicerLayer& slicer_layer = slicer->layers[layer_nr];
|
||||
support_layer.support_mesh.add(slicer_layer.polygons);
|
||||
meshStorage.layers[layer_nr].printZ =
|
||||
slicer_layer.z
|
||||
+ getSettingInMicrons("layer_height_0")
|
||||
- initial_slice_z;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
@@ -337,12 +349,24 @@ void FffPolygonGenerator::processBasicWallsSkinInfill(SliceDataStorage& storage,
|
||||
|
||||
|
||||
// walls
|
||||
unsigned int processed_layer_count = 0;
|
||||
#pragma omp parallel for default(none) shared(mesh_layer_count, mesh, inset_skin_progress_estimate, processed_layer_count) schedule(dynamic)
|
||||
for (unsigned int layer_number = 0; layer_number < mesh.layers.size(); layer_number++)
|
||||
{
|
||||
logDebug("Processing insets for layer %i of %i\n", layer_number, mesh_layer_count);
|
||||
processInsets(mesh, layer_number);
|
||||
double progress = inset_skin_progress_estimate.progress(layer_number);
|
||||
Progress::messageProgress(Progress::Stage::INSET_SKIN, progress * 100, 100);
|
||||
#ifdef _OPENMP
|
||||
if (omp_get_thread_num() == 0)
|
||||
#endif
|
||||
{ // progress estimation is done only in one thread so that no two threads message progress at the same time
|
||||
int _processed_layer_count;
|
||||
#pragma omp atomic read
|
||||
_processed_layer_count = processed_layer_count;
|
||||
double progress = inset_skin_progress_estimate.progress(_processed_layer_count);
|
||||
Progress::messageProgress(Progress::Stage::INSET_SKIN, progress * 100, 100);
|
||||
}
|
||||
#pragma omp atomic
|
||||
processed_layer_count++;
|
||||
}
|
||||
|
||||
ProgressEstimatorLinear* skin_estimator = new ProgressEstimatorLinear(mesh_layer_count);
|
||||
@@ -373,16 +397,33 @@ void FffPolygonGenerator::processBasicWallsSkinInfill(SliceDataStorage& storage,
|
||||
{
|
||||
mesh_max_bottom_layer_count = std::max(mesh_max_bottom_layer_count, mesh.getSettingAsCount("bottom_layers"));
|
||||
}
|
||||
for (unsigned int layer_number = 0; layer_number < mesh.layers.size(); layer_number++)
|
||||
|
||||
processed_layer_count = 0;
|
||||
#pragma omp parallel default(none) shared(mesh_layer_count, mesh, mesh_max_bottom_layer_count, process_infill, inset_skin_progress_estimate, processed_layer_count)
|
||||
{
|
||||
logDebug("Processing skins and infill layer %i of %i\n", layer_number, mesh_layer_count);
|
||||
if (!mesh.getSettingBoolean("magic_spiralize") || static_cast<int>(layer_number) < mesh_max_bottom_layer_count) //Only generate up/downskin and infill for the first X layers when spiralize is choosen.
|
||||
|
||||
#pragma omp for schedule(dynamic)
|
||||
for (unsigned int layer_number = 0; layer_number < mesh.layers.size(); layer_number++)
|
||||
{
|
||||
processSkinsAndInfill(mesh, layer_number, process_infill);
|
||||
logDebug("Processing skins and infill layer %i of %i\n", layer_number, mesh_layer_count);
|
||||
if (!mesh.getSettingBoolean("magic_spiralize") || static_cast<int>(layer_number) < mesh_max_bottom_layer_count) //Only generate up/downskin and infill for the first X layers when spiralize is choosen.
|
||||
{
|
||||
processSkinsAndInfill(mesh, layer_number, process_infill);
|
||||
}
|
||||
#ifdef _OPENMP
|
||||
if (omp_get_thread_num() == 0)
|
||||
#endif
|
||||
{ // progress estimation is done only in one thread so that no two threads message progress at the same time
|
||||
int _processed_layer_count;
|
||||
#pragma omp atomic read
|
||||
_processed_layer_count = processed_layer_count;
|
||||
double progress = inset_skin_progress_estimate.progress(_processed_layer_count);
|
||||
Progress::messageProgress(Progress::Stage::INSET_SKIN, progress * 100, 100);
|
||||
}
|
||||
#pragma omp atomic
|
||||
processed_layer_count++;
|
||||
}
|
||||
}
|
||||
double progress = inset_skin_progress_estimate.progress(layer_number);
|
||||
Progress::messageProgress(Progress::Stage::INSET_SKIN, progress * 100, 100);
|
||||
}
|
||||
}
|
||||
|
||||
void FffPolygonGenerator::processInfillMesh(SliceDataStorage& storage, unsigned int mesh_order_idx, std::vector<unsigned int>& mesh_order)
|
||||
@@ -478,6 +519,12 @@ void FffPolygonGenerator::processDerivedWallsSkinInfill(SliceMeshStorage& mesh)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* This function is executed in a parallel region based on layer_nr.
|
||||
* When modifying make sure any changes does not introduce data races.
|
||||
*
|
||||
* processInsets only reads and writes data for the current layer
|
||||
*/
|
||||
void FffPolygonGenerator::processInsets(SliceMeshStorage& mesh, unsigned int layer_nr)
|
||||
{
|
||||
SliceLayer* layer = &mesh.layers[layer_nr];
|
||||
@@ -516,11 +563,19 @@ void FffPolygonGenerator::removeEmptyFirstLayers(SliceDataStorage& storage, cons
|
||||
for (SliceMeshStorage& mesh : storage.meshes)
|
||||
{
|
||||
SliceLayer& layer = mesh.layers[layer_idx];
|
||||
if (layer.parts.size() > 0 || (mesh.getSettingAsSurfaceMode("magic_mesh_surface_mode") != ESurfaceMode::NORMAL && layer.openPolyLines.size() > 0) )
|
||||
if (mesh.getSettingAsSurfaceMode("magic_mesh_surface_mode") != ESurfaceMode::NORMAL && layer.openPolyLines.size() > 0)
|
||||
{
|
||||
layer_is_empty = false;
|
||||
break;
|
||||
}
|
||||
for (const SliceLayerPart& part : layer.parts)
|
||||
{
|
||||
if (part.print_outline.size() > 0)
|
||||
{
|
||||
layer_is_empty = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (layer_is_empty)
|
||||
@@ -551,8 +606,18 @@ void FffPolygonGenerator::removeEmptyFirstLayers(SliceDataStorage& storage, cons
|
||||
support_layers.erase(support_layers.begin(), support_layers.begin() + n_empty_first_layers);
|
||||
}
|
||||
}
|
||||
|
||||
void FffPolygonGenerator::processSkinsAndInfill(SliceMeshStorage& mesh, unsigned int layer_nr, bool process_infill)
|
||||
|
||||
/*
|
||||
* This function is executed in a parallel region based on layer_nr.
|
||||
* When modifying make sure any changes does not introduce data races.
|
||||
*
|
||||
* generateSkins read (depend on) data from mesh.layers[*].parts[*].insets and write mesh.layers[n].parts[*].skin_parts
|
||||
* generateInfill read mesh.layers[n].parts[*].{insets,skin_parts,boundingBox} and write mesh.layers[n].parts[*].infill_area
|
||||
*
|
||||
* processSkinsAndInfill read (depend on) mesh.layers[*].parts[*].{insets,boundingBox}.
|
||||
* write mesh.layers[n].parts[*].{skin_parts,infill_area}.
|
||||
*/
|
||||
void FffPolygonGenerator::processSkinsAndInfill(SliceMeshStorage& mesh, unsigned int layer_nr, bool process_infill)
|
||||
{
|
||||
if (mesh.getSettingAsSurfaceMode("magic_mesh_surface_mode") == ESurfaceMode::SURFACE)
|
||||
{
|
||||
|
||||
@@ -58,6 +58,10 @@ void SkirtBrim::getFirstLayerOutline(SliceDataStorage& storage, const unsigned i
|
||||
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
|
||||
if (first_layer_outline.size() == 0)
|
||||
{
|
||||
logError("Couldn't generate skirt / brim! No polygons on first layer.");
|
||||
}
|
||||
}
|
||||
|
||||
int SkirtBrim::generatePrimarySkirtBrimLines(SliceDataStorage& storage, int start_distance, unsigned int primary_line_count, const int primary_extruder_skirt_brim_line_width, const int64_t primary_extruder_minimal_length, const Polygons& first_layer_outline, Polygons& skirt_brim_primary_extruder)
|
||||
|
||||
@@ -12,6 +12,12 @@ WallsComputation::WallsComputation(int wall_0_inset, int line_width_0, int line_
|
||||
{
|
||||
}
|
||||
|
||||
/*
|
||||
* This function is executed in a parallel region based on layer_nr.
|
||||
* When modifying make sure any changes does not introduce data races.
|
||||
*
|
||||
* generateInsets only reads and writes data for the current layer
|
||||
*/
|
||||
void WallsComputation::generateInsets(SliceLayerPart* part)
|
||||
{
|
||||
if (insetCount == 0)
|
||||
@@ -58,6 +64,12 @@ void WallsComputation::generateInsets(SliceLayerPart* part)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* This function is executed in a parallel region based on layer_nr.
|
||||
* When modifying make sure any changes does not introduce data races.
|
||||
*
|
||||
* generateInsets only reads and writes data for the current layer
|
||||
*/
|
||||
void WallsComputation::generateInsets(SliceLayer* layer)
|
||||
{
|
||||
for(unsigned int partNr = 0; partNr < layer->parts.size(); partNr++)
|
||||
|
||||
@@ -642,6 +642,7 @@ void CommandSocket::sendLayerData()
|
||||
{
|
||||
for (std::pair<const int, std::shared_ptr<cura::proto::Layer>> entry : data.slice_data) //Note: This is in no particular order!
|
||||
{
|
||||
logDebug("Sending layer data for layer %i of %i.\n", entry.first, data.slice_data.size());
|
||||
private_data->socket->sendMessage(entry.second); //Send the actual layers.
|
||||
}
|
||||
data.sliced_objects = 0;
|
||||
@@ -667,6 +668,7 @@ void CommandSocket::sendOptimizedLayerData()
|
||||
{
|
||||
for (std::pair<const int, std::shared_ptr<cura::proto::LayerOptimized>> entry : data.slice_data) //Note: This is in no particular order!
|
||||
{
|
||||
logDebug("Sending layer data for layer %i of %i.\n", entry.first, data.slice_data.size());
|
||||
private_data->socket->sendMessage(entry.second); //Send the actual layers.
|
||||
}
|
||||
data.sliced_objects = 0;
|
||||
|
||||
@@ -556,8 +556,6 @@ void GCodeExport::writeMove(int x, int y, int z, double speed, double extrusion_
|
||||
assert((Point3(x,y,z) - currentPosition).vSize() < MM2INT(300)); // no crazy positions (this code should not be compiled for release)
|
||||
#endif //ASSERT_INSANE_OUTPUT
|
||||
|
||||
total_bounding_box.include(Point3(x, y, z));
|
||||
|
||||
if (extrusion_mm3_per_mm < 0)
|
||||
logWarning("Warning! Negative extrusion move!");
|
||||
|
||||
@@ -570,6 +568,7 @@ void GCodeExport::writeMove(int x, int y, int z, double speed, double extrusion_
|
||||
double extrusion_per_mm = mm3ToE(extrusion_mm3_per_mm);
|
||||
|
||||
Point gcode_pos = getGcodePos(x,y, current_extruder);
|
||||
total_bounding_box.include(Point3(gcode_pos.X, gcode_pos.Y, z));
|
||||
|
||||
if (extrusion_mm3_per_mm > 0.000001)
|
||||
{
|
||||
@@ -729,7 +728,7 @@ void GCodeExport::writeZhopStart(int hop_height)
|
||||
{
|
||||
isZHopped = hop_height;
|
||||
*output_stream << "G1 Z" << MMtoStream{currentPosition.z + isZHopped} << new_line;
|
||||
total_bounding_box.include(currentPosition + Point3(0, 0, isZHopped));
|
||||
total_bounding_box.includeZ(currentPosition.z + isZHopped);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -923,7 +922,7 @@ void GCodeExport::finalize(const char* endCode)
|
||||
{
|
||||
writeFanCommand(0);
|
||||
writeCode(endCode);
|
||||
long print_time = getTotalPrintTime();
|
||||
int64_t print_time = getTotalPrintTime();
|
||||
int mat_0 = getTotalFilamentUsed(0);
|
||||
log("Print time: %d\n", print_time);
|
||||
log("Print time (readable): %dh %dm %ds\n", print_time / 60 / 60, (print_time / 60) % 60, print_time % 60);
|
||||
|
||||
@@ -897,6 +897,7 @@ void GCodePlanner::completeConfigs()
|
||||
|
||||
mesh.insetX_config.setLayerHeight(layer_thickness);
|
||||
mesh.skin_config.setLayerHeight(layer_thickness);
|
||||
mesh.perimeter_gap_config.setLayerHeight(layer_thickness);
|
||||
for(unsigned int idx=0; idx<MAX_INFILL_COMBINE; idx++)
|
||||
{
|
||||
mesh.infill_config[idx].setLayerHeight(layer_thickness);
|
||||
@@ -955,6 +956,7 @@ void GCodePlanner::processInitialLayersSpeedup()
|
||||
|
||||
//Skin speed (per mesh).
|
||||
mesh.skin_config.smoothSpeed(initial_layer_speed_config, layer_nr, initial_speedup_layers);
|
||||
mesh.perimeter_gap_config.smoothSpeed(initial_layer_speed_config, layer_nr, initial_speedup_layers);
|
||||
|
||||
for (unsigned int idx = 0; idx < MAX_INFILL_COMBINE; idx++)
|
||||
{
|
||||
@@ -976,6 +978,7 @@ void GCodePlanner::processInitialLayersSpeedup()
|
||||
mesh.inset0_config.setSpeedIconic();
|
||||
mesh.insetX_config.setSpeedIconic();
|
||||
mesh.skin_config.setSpeedIconic();
|
||||
mesh.perimeter_gap_config.setSpeedIconic();
|
||||
for (unsigned int idx = 0; idx < MAX_INFILL_COMBINE; idx++)
|
||||
{
|
||||
mesh.infill_config[idx].setSpeedIconic();
|
||||
|
||||
@@ -186,15 +186,15 @@ SubDivCube::SubDivCube(SliceMeshStorage& mesh, Point3& center, unsigned int dept
|
||||
bool SubDivCube::isValidSubdivision(SliceMeshStorage& mesh, Point3& center, int64_t radius)
|
||||
{
|
||||
int64_t distance2;
|
||||
long int sphere_slice_radius2;//!< squared radius of bounding sphere slice on target layer
|
||||
coord_t sphere_slice_radius2;//!< squared radius of bounding sphere slice on target layer
|
||||
bool inside_somewhere = false;
|
||||
bool outside_somewhere = false;
|
||||
int inside;
|
||||
double part_dist;//what percentage of the radius the target layer is away from the center along the z axis. 0 - 1
|
||||
const long int layer_height = mesh.getSettingInMicrons("layer_height");
|
||||
long int bottom_layer = (center.z - radius) / layer_height;
|
||||
long int top_layer = (center.z + radius) / layer_height;
|
||||
for (long int test_layer = bottom_layer; test_layer <= top_layer; test_layer += 3) // steps of three. Low-hanging speed gain.
|
||||
const coord_t layer_height = mesh.getSettingInMicrons("layer_height");
|
||||
int bottom_layer = (center.z - radius) / layer_height;
|
||||
int top_layer = (center.z + radius) / layer_height;
|
||||
for (int test_layer = bottom_layer; test_layer <= top_layer; test_layer += 3) // steps of three. Low-hanging speed gain.
|
||||
{
|
||||
part_dist = (double)(test_layer * layer_height - center.z) / radius;
|
||||
sphere_slice_radius2 = radius * radius * (1.0 - (part_dist * part_dist));
|
||||
@@ -221,9 +221,9 @@ bool SubDivCube::isValidSubdivision(SliceMeshStorage& mesh, Point3& center, int6
|
||||
return false;
|
||||
}
|
||||
|
||||
int SubDivCube::distanceFromPointToMesh(SliceMeshStorage& mesh, long int layer_nr, Point& location, int64_t* distance2)
|
||||
int SubDivCube::distanceFromPointToMesh(SliceMeshStorage& mesh, int layer_nr, Point& location, int64_t* distance2)
|
||||
{
|
||||
if (layer_nr < 0 || (unsigned long int)layer_nr >= mesh.layers.size()) //!< this layer is outside of valid range
|
||||
if (layer_nr < 0 || (unsigned int)layer_nr >= mesh.layers.size()) //!< this layer is outside of valid range
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
|
||||
@@ -74,7 +74,7 @@ private:
|
||||
* \param[out] distance2 the squared distance to the infill border
|
||||
* \return Code 0: outside, 1: inside, 2: boundary does not exist at specified layer
|
||||
*/
|
||||
static int distanceFromPointToMesh(SliceMeshStorage& mesh, long int layer_nr, Point& location, int64_t* distance2);
|
||||
static int distanceFromPointToMesh(SliceMeshStorage& mesh, int layer_nr, Point& location, int64_t* distance2);
|
||||
|
||||
/*!
|
||||
* Adds the defined line to the specified polygons. It assumes that the specified polygons are all parallel lines. Combines line segments with touching ends closer than epsilon.
|
||||
|
||||
+4
-1
@@ -44,7 +44,10 @@ void createLayerWithParts(SliceLayer& storageLayer, SlicerLayer* layer, bool uni
|
||||
}
|
||||
void createLayerParts(SliceMeshStorage& mesh, Slicer* slicer, bool union_layers, bool union_all_remove_holes)
|
||||
{
|
||||
for(unsigned int layer_nr = 0; layer_nr < slicer->layers.size(); layer_nr++)
|
||||
const auto total_layers = slicer->layers.size();
|
||||
assert(mesh.layers.size() == total_layers);
|
||||
#pragma omp parallel for default(none) shared(mesh,slicer) firstprivate(union_layers,union_all_remove_holes) schedule(dynamic)
|
||||
for(unsigned int layer_nr = 0; layer_nr < total_layers; layer_nr++)
|
||||
{
|
||||
mesh.layers[layer_nr].sliceZ = slicer->layers[layer_nr].z;
|
||||
mesh.layers[layer_nr].printZ = slicer->layers[layer_nr].z;
|
||||
|
||||
+18
-2
@@ -20,6 +20,10 @@
|
||||
|
||||
#include "settings/SettingsToGV.h"
|
||||
|
||||
#ifdef _OPENMP
|
||||
#include <omp.h> // omp_get_num_threads
|
||||
#endif
|
||||
|
||||
namespace cura
|
||||
{
|
||||
|
||||
@@ -328,7 +332,19 @@ int main(int argc, char **argv)
|
||||
print_usage();
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
||||
#pragma omp parallel
|
||||
{
|
||||
#pragma omp master
|
||||
{
|
||||
#ifdef _OPENMP
|
||||
log("OpenMP multithreading enabled, likely number of threads to be used: %u\n", omp_get_num_threads());
|
||||
#else
|
||||
log("OpenMP multithreading disabled\n");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
if (stringcasecompare(argv[1], "connect") == 0)
|
||||
{
|
||||
connect(argc, argv);
|
||||
@@ -423,4 +439,4 @@ int main(int argc, char **argv)
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -125,7 +125,7 @@ bool SettingRegistry::getDefinitionFile(const std::string machine_id, std::strin
|
||||
|
||||
int SettingRegistry::loadExtruderJSONsettings(unsigned int extruder_nr, SettingsBase* settings_base)
|
||||
{
|
||||
if (extruder_train_ids.empty()) //... Tough luck, buddy.
|
||||
if (extruder_train_ids.empty())
|
||||
{
|
||||
logError("Couldn't find any extruder trains!\n");
|
||||
return -1;
|
||||
|
||||
@@ -93,21 +93,23 @@ void SettingsBase::setSettingInheritBase(std::string key, const SettingsBaseVirt
|
||||
|
||||
std::string SettingsBase::getSettingString(std::string key) const
|
||||
{
|
||||
if (setting_values.find(key) != setting_values.end())
|
||||
auto value_it = setting_values.find(key);
|
||||
if (value_it != setting_values.end())
|
||||
{
|
||||
return setting_values.at(key);
|
||||
return value_it->second;
|
||||
}
|
||||
if (setting_inherit_base.find(key) != setting_inherit_base.end())
|
||||
auto inherit_override_it = setting_inherit_base.find(key);
|
||||
if (inherit_override_it != setting_inherit_base.end())
|
||||
{
|
||||
return setting_inherit_base.at(key)->getSettingString(key);
|
||||
return inherit_override_it->second->getSettingString(key);
|
||||
}
|
||||
if (parent)
|
||||
{
|
||||
return parent->getSettingString(key);
|
||||
}
|
||||
|
||||
const_cast<SettingsBase&>(*this).setting_values[key] = "";
|
||||
cura::logWarning("Unregistered setting %s\n", key.c_str());
|
||||
cura::logError("Trying to retrieve unregistered setting with no value given: '%s'\n", key.c_str());
|
||||
std::exit(-1);
|
||||
return "";
|
||||
}
|
||||
|
||||
@@ -426,7 +428,7 @@ FillPerimeterGapMode SettingsBaseVirtual::getSettingAsFillPerimeterGapMode(std::
|
||||
return FillPerimeterGapMode::NOWHERE;
|
||||
}
|
||||
|
||||
CombingMode SettingsBaseVirtual::getSettingAsCombingMode(std::string key)
|
||||
CombingMode SettingsBaseVirtual::getSettingAsCombingMode(std::string key) const
|
||||
{
|
||||
std::string value = getSettingString(key);
|
||||
if (value == "off")
|
||||
@@ -444,7 +446,7 @@ CombingMode SettingsBaseVirtual::getSettingAsCombingMode(std::string key)
|
||||
return CombingMode::ALL;
|
||||
}
|
||||
|
||||
SupportDistPriority SettingsBaseVirtual::getSettingAsSupportDistPriority(std::string key)
|
||||
SupportDistPriority SettingsBaseVirtual::getSettingAsSupportDistPriority(std::string key) const
|
||||
{
|
||||
std::string value = getSettingString(key);
|
||||
if (value == "xy_overrides_z")
|
||||
|
||||
@@ -251,8 +251,8 @@ public:
|
||||
EZSeamType getSettingAsZSeamType(std::string key) const;
|
||||
ESurfaceMode getSettingAsSurfaceMode(std::string key) const;
|
||||
FillPerimeterGapMode getSettingAsFillPerimeterGapMode(std::string key) const;
|
||||
CombingMode getSettingAsCombingMode(std::string key);
|
||||
SupportDistPriority getSettingAsSupportDistPriority(std::string key);
|
||||
CombingMode getSettingAsCombingMode(std::string key) const;
|
||||
SupportDistPriority getSettingAsSupportDistPriority(std::string key) const;
|
||||
};
|
||||
|
||||
class SettingRegistry;
|
||||
|
||||
+49
-5
@@ -10,7 +10,16 @@
|
||||
namespace cura
|
||||
{
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* 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
|
||||
* generateSkinInsets only read/writes the skin_parts from the current layer.
|
||||
*
|
||||
* generateSkins therefore reads (depends on) data from mesh.layers[*].parts[*].insets and writes mesh.layers[n].parts[*].skin_parts
|
||||
*/
|
||||
void generateSkins(int layerNr, SliceMeshStorage& mesh, int downSkinCount, int upSkinCount, int wall_line_count, int innermost_wall_line_width, int insetCount, bool no_small_gaps_heuristic)
|
||||
{
|
||||
generateSkinAreas(layerNr, mesh, innermost_wall_line_width, downSkinCount, upSkinCount, wall_line_count, no_small_gaps_heuristic);
|
||||
@@ -23,6 +32,12 @@ void generateSkins(int layerNr, SliceMeshStorage& mesh, int downSkinCount, int u
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* 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 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];
|
||||
@@ -31,7 +46,7 @@ void generateSkinAreas(int layer_nr, SliceMeshStorage& mesh, const int innermost
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int min_infill_area = mesh.getSettingInMillimeters("min_infill_area");
|
||||
for(unsigned int partNr = 0; partNr < layer.parts.size(); partNr++)
|
||||
{
|
||||
SliceLayerPart& part = layer.parts[partNr];
|
||||
@@ -63,12 +78,22 @@ void generateSkinAreas(int layer_nr, SliceMeshStorage& mesh, const int innermost
|
||||
{
|
||||
if (static_cast<int>(layer_nr - downSkinCount) >= 0)
|
||||
{
|
||||
downskin = downskin.difference(getInsidePolygons(mesh.layers[layer_nr - downSkinCount])); // skin overlaps with the walls
|
||||
Polygons not_air = getInsidePolygons(mesh.layers[layer_nr - downSkinCount]);
|
||||
if (min_infill_area > 0)
|
||||
{
|
||||
not_air.removeSmallAreas(min_infill_area);
|
||||
}
|
||||
downskin = downskin.difference(not_air); // 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
|
||||
Polygons not_air = getInsidePolygons(mesh.layers[layer_nr + upSkinCount]);
|
||||
if (min_infill_area > 0)
|
||||
{
|
||||
not_air.removeSmallAreas(min_infill_area);
|
||||
}
|
||||
upskin = upskin.difference(not_air); // skin overlaps with the walls
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -80,6 +105,10 @@ void generateSkinAreas(int layer_nr, SliceMeshStorage& mesh, const int innermost
|
||||
{
|
||||
not_air = not_air.intersection(getInsidePolygons(mesh.layers[downskin_layer_nr]));
|
||||
}
|
||||
if (min_infill_area > 0)
|
||||
{
|
||||
not_air.removeSmallAreas(min_infill_area);
|
||||
}
|
||||
downskin = downskin.difference(not_air); // skin overlaps with the walls
|
||||
}
|
||||
|
||||
@@ -90,6 +119,10 @@ void generateSkinAreas(int layer_nr, SliceMeshStorage& mesh, const int innermost
|
||||
{
|
||||
not_air = not_air.intersection(getInsidePolygons(mesh.layers[upskin_layer_nr]));
|
||||
}
|
||||
if (min_infill_area > 0)
|
||||
{
|
||||
not_air.removeSmallAreas(min_infill_area);
|
||||
}
|
||||
upskin = upskin.difference(not_air); // skin overlaps with the walls
|
||||
}
|
||||
}
|
||||
@@ -106,7 +139,12 @@ void generateSkinAreas(int layer_nr, SliceMeshStorage& mesh, const int innermost
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* This function is executed in a parallel region based on layer_nr.
|
||||
* When modifying make sure any changes does not introduce data races.
|
||||
*
|
||||
* generateSkinInsets only read/writes the skin_parts from the current layer.
|
||||
*/
|
||||
void generateSkinInsets(SliceLayerPart* part, const int wall_line_width, int insetCount)
|
||||
{
|
||||
if (insetCount == 0)
|
||||
@@ -139,6 +177,12 @@ void generateSkinInsets(SliceLayerPart* part, const int wall_line_width, int ins
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* 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 generateInfill(int layerNr, SliceMeshStorage& mesh, const int innermost_wall_line_width, int infill_skin_overlap, int wall_line_count)
|
||||
{
|
||||
SliceLayer& layer = mesh.layers[layerNr];
|
||||
|
||||
@@ -207,7 +207,7 @@ Polygons SliceDataStorage::getLayerSecondOrInnermostWalls(int layer_nr, bool inc
|
||||
{
|
||||
const SliceLayer& layer = mesh.layers[layer_nr];
|
||||
layer.getSecondOrInnermostWalls(total);
|
||||
if (const_cast<SliceMeshStorage&>(mesh).getSettingAsSurfaceMode("magic_mesh_surface_mode") != ESurfaceMode::NORMAL) // TODO: make getSetting const? make settings.setting_values mapping mutable??
|
||||
if (mesh.getSettingAsSurfaceMode("magic_mesh_surface_mode") != ESurfaceMode::NORMAL)
|
||||
{
|
||||
total = total.unionPolygons(layer.openPolyLines.offsetPolyLine(100));
|
||||
}
|
||||
|
||||
@@ -155,6 +155,7 @@ public:
|
||||
GCodePathConfig inset0_config;
|
||||
GCodePathConfig insetX_config;
|
||||
GCodePathConfig skin_config;
|
||||
GCodePathConfig perimeter_gap_config;
|
||||
std::vector<GCodePathConfig> infill_config;
|
||||
|
||||
SubDivCube* base_subdiv_cube;
|
||||
@@ -165,6 +166,7 @@ public:
|
||||
, inset0_config(PrintFeatureType::OuterWall)
|
||||
, insetX_config(PrintFeatureType::InnerWall)
|
||||
, skin_config(PrintFeatureType::Skin)
|
||||
, perimeter_gap_config(PrintFeatureType::Skin)
|
||||
, base_subdiv_cube(nullptr)
|
||||
{
|
||||
layers.resize(slice_layer_count);
|
||||
|
||||
+6
-2
@@ -887,10 +887,14 @@ Slicer::Slicer(Mesh* mesh, int initial, int thickness, int slice_layer_count, bo
|
||||
}
|
||||
}
|
||||
log("slice of mesh took %.3f seconds\n",slice_timer.restart());
|
||||
for(unsigned int layer_nr=0; layer_nr<layers.size(); layer_nr++)
|
||||
|
||||
std::vector<SlicerLayer>& layers_ref = layers; // force layers not to be copied into the threads
|
||||
#pragma omp parallel for default(none) shared(mesh,layers_ref) firstprivate(keep_none_closed, extensive_stitching)
|
||||
for(unsigned int layer_nr=0; layer_nr<layers_ref.size(); layer_nr++)
|
||||
{
|
||||
layers[layer_nr].makePolygons(mesh, keep_none_closed, extensive_stitching);
|
||||
layers_ref[layer_nr].makePolygons(mesh, keep_none_closed, extensive_stitching);
|
||||
}
|
||||
|
||||
mesh->expandXY(mesh->getSettingInMicrons("xy_offset"));
|
||||
log("slice make polygons took %.3f seconds\n",slice_timer.restart());
|
||||
}
|
||||
|
||||
+61
-51
@@ -90,6 +90,7 @@ void AreaSupport::generateSupportAreas(SliceDataStorage& storage, unsigned int l
|
||||
storage.support.supportLayers.resize(layer_count);
|
||||
}
|
||||
|
||||
// generate support areas
|
||||
for (unsigned int mesh_idx = 0; mesh_idx < storage.meshes.size(); mesh_idx++)
|
||||
{
|
||||
SliceMeshStorage& mesh = storage.meshes[mesh_idx];
|
||||
@@ -100,25 +101,33 @@ void AreaSupport::generateSupportAreas(SliceDataStorage& storage, unsigned int l
|
||||
std::vector<Polygons> supportAreas;
|
||||
supportAreas.resize(layer_count, Polygons());
|
||||
generateSupportAreas(storage, mesh_idx, layer_count, supportAreas);
|
||||
|
||||
if (mesh.getSettingBoolean("support_interface_enable"))
|
||||
|
||||
for (unsigned int layer_idx = 0; layer_idx < layer_count; layer_idx++)
|
||||
{
|
||||
generateSupportInterface(storage, mesh, supportAreas, layer_count);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (unsigned int layer_idx = 0; layer_idx < layer_count ; layer_idx++)
|
||||
{
|
||||
storage.support.supportLayers[layer_idx].supportAreas.add(supportAreas[layer_idx]);
|
||||
}
|
||||
storage.support.supportLayers[layer_idx].supportAreas.add(supportAreas[layer_idx]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
for (unsigned int layer_idx = 0; layer_idx < layer_count ; layer_idx++)
|
||||
{
|
||||
Polygons& support_areas = storage.support.supportLayers[layer_idx].supportAreas;
|
||||
support_areas = support_areas.unionPolygons();
|
||||
}
|
||||
|
||||
// handle support interface
|
||||
for (unsigned int mesh_idx = 0; mesh_idx < storage.meshes.size(); mesh_idx++)
|
||||
{
|
||||
SliceMeshStorage& mesh = storage.meshes[mesh_idx];
|
||||
if (mesh.getSettingBoolean("infill_mesh") || mesh.getSettingBoolean("anti_overhang_mesh"))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (mesh.getSettingBoolean("support_interface_enable"))
|
||||
{
|
||||
generateSupportInterface(storage, mesh, layer_count);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -156,6 +165,7 @@ void AreaSupport::generateSupportAreas(SliceDataStorage& storage, unsigned int m
|
||||
const int supportTowerDiameter = mesh.getSettingInMicrons("support_tower_diameter");
|
||||
const int supportMinAreaSqrt = mesh.getSettingInMicrons("support_minimal_diameter");
|
||||
const double supportTowerRoofAngle = mesh.getSettingInAngleRadians("support_tower_roof_angle");
|
||||
const bool use_towers = mesh.getSettingBoolean("support_use_towers") && supportMinAreaSqrt > 0;
|
||||
|
||||
const int layerThickness = storage.getSettingInMicrons("layer_height");
|
||||
const int supportXYDistance = mesh.getSettingInMicrons("support_xy_distance");
|
||||
@@ -225,7 +235,10 @@ void AreaSupport::generateSupportAreas(SliceDataStorage& storage, unsigned int m
|
||||
|
||||
|
||||
std::vector<std::pair<int, std::vector<Polygons>>> overhang_points; // stores overhang_points along with the layer index at which the overhang point occurs
|
||||
AreaSupport::detectOverhangPoints(storage, mesh, overhang_points, layer_count, supportMinAreaSqrt);
|
||||
if (use_towers)
|
||||
{
|
||||
AreaSupport::detectOverhangPoints(storage, mesh, overhang_points, layer_count, supportMinAreaSqrt);
|
||||
}
|
||||
|
||||
std::deque<std::pair<Polygons, Polygons>> basic_and_full_overhang_above;
|
||||
for (unsigned int layer_idx = support_layer_count - 1; layer_idx != support_layer_count - 1 - layerZdistanceTop ; layer_idx--)
|
||||
@@ -255,7 +268,7 @@ void AreaSupport::generateSupportAreas(SliceDataStorage& storage, unsigned int m
|
||||
supportLayer_this = supportLayer_this.offset(extension_offset);
|
||||
}
|
||||
|
||||
if (supportMinAreaSqrt > 0)
|
||||
if (use_towers)
|
||||
{
|
||||
// handle straight walls
|
||||
AreaSupport::handleWallStruts(supportLayer_this, supportMinAreaSqrt, supportTowerDiameter);
|
||||
@@ -342,14 +355,14 @@ void AreaSupport::generateSupportAreas(SliceDataStorage& storage, unsigned int m
|
||||
}
|
||||
|
||||
//Enforce top Z distance.
|
||||
if (layerZdistanceTop > 0)
|
||||
if (layerZdistanceTop > 1)
|
||||
{
|
||||
// this is performed after the main support generation loop above, because it affects the joining of polygons
|
||||
// if this would be performed in the main loop then some support would not have been generated under the overhangs and consequently no support is generated for that,
|
||||
// meaning almost no support would be generated in some cases which definitely need support.
|
||||
for (size_t layer_idx = 0; layer_idx < storage.support.supportLayers.size() && layer_idx < support_layer_count - layerZdistanceTop; layer_idx++)
|
||||
for (size_t layer_idx = 0; layer_idx < storage.support.supportLayers.size() && layer_idx < support_layer_count - (layerZdistanceTop - 1); layer_idx++)
|
||||
{
|
||||
supportAreas[layer_idx] = supportAreas[layer_idx].difference(storage.getLayerOutlines(layer_idx + layerZdistanceTop, false));
|
||||
supportAreas[layer_idx] = supportAreas[layer_idx].difference(storage.getLayerOutlines(layer_idx + layerZdistanceTop - 1, false));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -559,7 +572,7 @@ void AreaSupport::handleWallStruts(
|
||||
}
|
||||
|
||||
|
||||
void AreaSupport::generateSupportInterface(SliceDataStorage& storage, const SliceMeshStorage& mesh, std::vector<Polygons>& support_areas, const unsigned int layer_count)
|
||||
void AreaSupport::generateSupportInterface(SliceDataStorage& storage, const SliceMeshStorage& mesh, 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"));
|
||||
@@ -576,44 +589,41 @@ void AreaSupport::generateSupportInterface(SliceDataStorage& storage, const Slic
|
||||
|
||||
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())
|
||||
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));
|
||||
continue;
|
||||
}
|
||||
else
|
||||
Polygons roofs;
|
||||
if (roof_layer_count > 0)
|
||||
{
|
||||
layer.skin.add(support_areas[layer_idx]);
|
||||
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 = layer.supportAreas.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 = layer.supportAreas.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(layer.supportAreas);
|
||||
skin.removeSmallAreas(1.0);
|
||||
layer.skin.add(skin);
|
||||
layer.supportAreas = layer.supportAreas.difference(layer.skin);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
-2
@@ -36,10 +36,9 @@ private:
|
||||
*
|
||||
* \param storage Output storage: support area + support skin area output
|
||||
* \param mesh The mesh to generate support skins for.
|
||||
* \param support_areas The basic support areas for the current mesh
|
||||
* \param layer_count The number of layers in this mesh group.
|
||||
*/
|
||||
static void generateSupportInterface(SliceDataStorage& storage, const SliceMeshStorage& mesh, std::vector<Polygons>& support_areas, const unsigned int layer_count);
|
||||
static void generateSupportInterface(SliceDataStorage& storage, const SliceMeshStorage& mesh, const unsigned int layer_count);
|
||||
|
||||
/*!
|
||||
* Join current support layer with the support of the layer above, (make support conical) and perform smoothing etc operations.
|
||||
|
||||
@@ -37,6 +37,12 @@ void AABB3D::include(Point3 p)
|
||||
max.z = std::max(max.z, p.z);
|
||||
}
|
||||
|
||||
void AABB3D::includeZ(int32_t z)
|
||||
{
|
||||
min.z = std::min(min.z, z);
|
||||
max.z = std::max(max.z, z);
|
||||
}
|
||||
|
||||
void AABB3D::offset(Point3 offset)
|
||||
{
|
||||
min += offset;
|
||||
|
||||
@@ -38,6 +38,14 @@ struct AABB3D
|
||||
*/
|
||||
void include(Point3 p);
|
||||
|
||||
/*!
|
||||
* Expand the AABB3D to include a z-coordinate.
|
||||
*
|
||||
* This is for including a point of which the X and Y coordinates are
|
||||
* unknown but known to already be included in the bounding box.
|
||||
*/
|
||||
void includeZ(int32_t z);
|
||||
|
||||
/*!
|
||||
* Offset the coordinates of the bounding box.
|
||||
* \param offset The offset with which to offset the AABB3D.
|
||||
|
||||
@@ -837,7 +837,6 @@ void PolygonRef::smooth_corner_simple(ListPolygon& poly, const Point p0, const P
|
||||
Point b;
|
||||
bool success = LinearAlg2D::getPointOnLineWithDist(a, p1, p2, shortcut_length, b);
|
||||
// v02 has to be longer than ab!
|
||||
p1_it.remove();
|
||||
if (success)
|
||||
{ // if not success then assume b is negligibly close to 2, but rounding errors caused a problem
|
||||
#ifdef ASSERT_INSANE_OUTPUT
|
||||
@@ -845,6 +844,7 @@ void PolygonRef::smooth_corner_simple(ListPolygon& poly, const Point p0, const P
|
||||
#endif // #ifdef ASSERT_INSANE_OUTPUT
|
||||
ListPolyIt::insertPointNonDuplicate(p1_it, p2_it, b);
|
||||
}
|
||||
p1_it.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
//Copyright (c) 2017 Ultimaker B.V.
|
||||
//CuraEngine is released under the terms of the AGPLv3 or higher.
|
||||
|
||||
#ifndef UTILS_STRING_H
|
||||
#define UTILS_STRING_H
|
||||
|
||||
@@ -35,7 +38,7 @@ static inline void writeInt2mm(const int64_t coord, std::ostream& ss)
|
||||
{
|
||||
constexpr size_t buffer_size = 24;
|
||||
char buffer[buffer_size];
|
||||
int char_count = sprintf(buffer, "%" PRId64, coord); // convert int to string
|
||||
int char_count = sprintf(buffer, "%d", int(coord)); // convert int to string
|
||||
#ifdef DEBUG
|
||||
if (char_count + 1 >= int(buffer_size)) // + 1 for the null character
|
||||
{
|
||||
|
||||
+4
-1
@@ -235,11 +235,14 @@ class Setting:
|
||||
tree = ast.parse(code, "eval")
|
||||
compiled = compile(code, self._key, "eval")
|
||||
except (SyntaxError, TypeError) as e:
|
||||
print("Parse error in function (" + code + ") for setting", self._key + ":", str(e))
|
||||
print("Parse error in function (" + str(code) + ") for setting", self._key + ":", str(e))
|
||||
return None
|
||||
except IllegalMethodError as e:
|
||||
print("Use of illegal method", str(e), "in function (" + code + ") for setting", self._key)
|
||||
return None
|
||||
except Exception as e:
|
||||
print("Exception in function (" + code + ") for setting", self._key + ":", str(e))
|
||||
return None
|
||||
|
||||
return eval(compiled, globals(), locals)
|
||||
|
||||
|
||||
Referência em uma Nova Issue
Bloquear um usuário