Comparar commits
17 Commits
| Autor | SHA1 | Data | |
|---|---|---|---|
| 903b31d381 | |||
| 734978230f | |||
| fa02006a5d | |||
| 6861020c6b | |||
| 2d9a3c83ef | |||
| 4c5a959c4e | |||
| 21746022c4 | |||
| d6bf9be54e | |||
| fff1164042 | |||
| c7e621eeb5 | |||
| 5b6f1db59d | |||
| 9ac9d1dd59 | |||
| 3d476f114b | |||
| 152f6e89a8 | |||
| b43e4df3aa | |||
| 405c49133b | |||
| e717404055 |
@@ -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)
|
||||
|
||||
@@ -874,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)
|
||||
{
|
||||
@@ -1007,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, wall_0_wipe_dist, spiralize);
|
||||
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);
|
||||
}
|
||||
}
|
||||
int processed_inset_number = -1;
|
||||
@@ -1076,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]);
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
#include <algorithm>
|
||||
#include <map> // multimap (ordered map allowing duplicate keys)
|
||||
#include <omp.h>
|
||||
|
||||
#include "utils/math.h"
|
||||
#include "utils/algorithm.h"
|
||||
@@ -345,12 +346,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);
|
||||
@@ -381,16 +394,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)
|
||||
@@ -486,6 +516,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];
|
||||
@@ -524,11 +560,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)
|
||||
@@ -559,8 +603,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++)
|
||||
|
||||
@@ -226,7 +226,6 @@ int SubDivCube::distanceFromPointToMesh(SliceMeshStorage& mesh, int layer_nr, Po
|
||||
if (layer_nr < 0 || (unsigned int)layer_nr >= mesh.layers.size()) //!< this layer is outside of valid range
|
||||
{
|
||||
return 2;
|
||||
*distance2 = 0;
|
||||
}
|
||||
Polygons collide;
|
||||
mesh.layers[layer_nr].getSecondOrInnermostWalls(collide);
|
||||
|
||||
+15
-1
@@ -20,6 +20,8 @@
|
||||
|
||||
#include "settings/SettingsToGV.h"
|
||||
|
||||
#include <omp.h> // omp_get_num_threads
|
||||
|
||||
namespace cura
|
||||
{
|
||||
|
||||
@@ -328,7 +330,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);
|
||||
|
||||
+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];
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
//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
|
||||
|
||||
@@ -38,7 +35,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, "%d", int(coord)); // convert int to string
|
||||
int char_count = sprintf(buffer, "%" PRId64, coord); // convert int to string
|
||||
#ifdef DEBUG
|
||||
if (char_count + 1 >= int(buffer_size)) // + 1 for the null character
|
||||
{
|
||||
|
||||
Referência em uma Nova Issue
Bloquear um usuário