Comparar commits

...

32 Commits

Autor SHA1 Mensagem Data
Tim Kuipers 903b31d381 Merge branch 'feature_omp_skin_infill' of github.com:Ultimaker/CuraEngine into feature_omp_skin_infill 2017-02-09 17:41:49 +01:00
Tim Kuipers 734978230f lil (CURA-3330) 2017-02-09 17:41:45 +01:00
Tim Kuipers fa02006a5d fix: logging of OpenMP threads in main (CURA-3330) 2017-02-09 15:30:45 +01:00
Ghostkeeper 6861020c6b Remove irrelevant documentation of different function
This documentation of processInsets reports on one of the generateInsets functions. Probably a copy-paste mistake.

Contributes to issue CURA-3330.
2017-02-08 16:43:13 +01:00
Ghostkeeper 2d9a3c83ef Code style: Space after for keyword
Contributes to issue CURA-3330.
2017-02-08 16:29:02 +01:00
Tim Kuipers 4c5a959c4e fix: handle multithreaded progress messages (CURA-781) 2017-01-30 17:41:33 +01:00
Johan Kristensen 21746022c4 Add OpenMP parallel execution of processInsets
CURA-541
2017-01-30 17:36:12 +01:00
Johan Kristensen d6bf9be54e Add OpenMP parallel execution of processSkinsAndInfill
CURA-541
2017-01-30 17:35:59 +01:00
Johan K fff1164042 Add cmake option to enable OpenMP
CURA-541
2017-01-30 17:30:44 +01:00
Ghostkeeper c7e621eeb5 Merge branch '2.4' 2017-01-25 17:46:07 +01:00
Ghostkeeper 9c3170b277 Print debug message upon sending layer data
This should help a bit with debugging the slice loop. I hope.

Contributes to issue CURA-3274.
2017-01-25 17:45:34 +01:00
Ghostkeeper e2f89778e2 Remove p1 after inserting point next to it
Because this insertion requires dereferencing p1. If it has been removed from the list, dereferencing it would remove it from memory so that would be an invalid pointer reference.

Contributes to debugging issue CURA-3274.
2017-01-25 14:40:11 +01:00
Ghostkeeper 8f74952aca Replace last long in gcodeExport with int64_t
Previously we had a crash only on windows because the long was not long enough. Perhaps this fixes something with the slicing loop.

Contributes to issue CURA-3274.
2017-01-25 13:36:14 +01:00
Ghostkeeper 5b6f1db59d Merge branch 'mb-min-infill-area' of https://github.com/smartavionics/CuraEngine into smartavionics-mb-min-infill-area 2017-01-24 11:40:03 +01:00
Tim Kuipers 17463e1139 quick fix: accidental const (CURA-3309) 2017-01-23 17:37:17 +01:00
Tim Kuipers 8df26ae916 fix: equalize flow still equalizes after halving the line width for perimeter gaps (CURA-3309) 2017-01-23 17:36:24 +01:00
Tim Kuipers 9ac9d1dd59 Merge branch '2.4' 2017-01-23 14:54:16 +01:00
Tim Kuipers c2aa1d59bc fix: add perimeter_gaps config with line width of half the inner wall line width (CURA-3309)
also the perimeter gaps of the skin walls now have to be generated separately
2017-01-23 14:53:57 +01:00
Tim Kuipers 3d476f114b Merge branch '2.4' 2017-01-23 10:22:54 +01:00
Tim Kuipers 152f6e89a8 fix: more safety against empty layers (CURA-3290) 2017-01-20 16:56:01 +01:00
Tim Kuipers 113202cd34 fix: types in CubicSubdiv were wrong (CURA-3196)
the sphere_slice_radius2 was a long rather than a coord_t (long long)
2017-01-20 15:23:34 +01:00
Tim Kuipers 4bc706d618 fix: perimeter gaps were introduced for the overlap between infill and skin (CURA-3179)
this caused extra overextrusion where infill and skin meet
2017-01-20 15:01:51 +01:00
Tim Kuipers 5766e2db11 fix: don't fill gaps for outer wall when spiralize is enabled (CURA-3152) 2017-01-20 14:21:14 +01:00
Tim Kuipers 671ebccdbb fix: indentation only (CURA-3271) 2017-01-20 14:08:56 +01:00
Tim Kuipers 2516165c86 fix: there were no support bottoms on top of the first model in support of the second model (CURA-3271)
All support areas are now generated before generating the interface. They are stored in supportLayer.supportAreas right after generation of the areas.
generateSupportInterface then operates on the merged supportAreas.

Note that this has a performace impact: while evaluating support interface, the support of all models is considered, rather than only the support it introduced itself.
2017-01-20 14:08:29 +01:00
Tim Kuipers 0315aaf404 fix: support top distance was one layer too high (CURA-3269) 2017-01-20 13:26:39 +01:00
Mark Burton b43e4df3aa Remove areas of infill smaller than min_infill_area.
When you have a small feature above an outer layer (e.g. raised text), the
area under the feature will be infill rather than skin and so the skin is
composed of multiple segments around the feature. Better surface quality is
obtained if the area under the raised feature is treated as skin thus allowing
more of the outer layer to be printed as a single segment. This setting
specifies the minimum area (in mm^2) of a filled region. Areas smaller than
this will be filled with skin rather than infill.
2017-01-19 11:44:22 +00:00
Ghostkeeper 405c49133b Merge branch 'first-layer-skin-pattern' of https://github.com/14bitVoid/CuraEngine into 14bitVoid-first-layer-skin-pattern 2017-01-03 10:42:31 +01:00
Tim Kuipers 49f09ed204 fix: (anti) support meshes could f*ck up the printZ of each layer (CURA-3198)
those meshes didn't call createLayerParts and so their printZ was never set.
To determine the print height of a layer an arbitrary mesh was used to see the printZ.
2017-01-02 23:03:40 +01:00
14bitVoid e717404055 Use different skin pattern on first layer 2017-01-02 22:30:41 +01:00
Ghostkeeper 3e7d623c86 Make total bounding box use head coordinates
Instead of nozzle coordinates.
2016-12-20 15:49:37 +01:00
Ghostkeeper d694bff227 Remove superfluous comment
A bit witty, perhaps, but unnecessary.

Contributes to issue CURA-3137.
2016-12-15 12:03:28 +01:00
19 arquivos alterados com 294 adições e 100 exclusões
+10
Ver Arquivo
@@ -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)
+40 -17
Ver Arquivo
@@ -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)
{
@@ -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);
}
}
+74 -12
Ver Arquivo
@@ -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"
@@ -151,6 +152,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 +166,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 +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);
@@ -373,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)
@@ -478,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];
@@ -516,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)
@@ -551,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)
{
+4
Ver Arquivo
@@ -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
Ver Arquivo
@@ -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++)
+2
Ver Arquivo
@@ -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;
+3 -4
Ver Arquivo
@@ -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);
+3
Ver Arquivo
@@ -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();
+7 -7
Ver Arquivo
@@ -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;
}
+1 -1
Ver Arquivo
@@ -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.
+15 -1
Ver Arquivo
@@ -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);
+1 -1
Ver Arquivo
@@ -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;
+49 -5
Ver Arquivo
@@ -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];
+2
Ver Arquivo
@@ -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);
+55 -49
Ver Arquivo
@@ -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);
}
}
}
/*
@@ -342,14 +351,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 +568,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 +585,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
Ver Arquivo
@@ -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.
+6
Ver Arquivo
@@ -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;
+8
Ver Arquivo
@@ -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.
+1 -1
Ver Arquivo
@@ -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();
}
}
}