Comparar commits

..

72 Commits

Autor SHA1 Mensagem Data
Tim Kuipers 2926c2e06e fix: handle multithreaded progress messages (CURA-781) 2017-01-30 17:10:25 +01:00
Johan Kristensen 7f9dd1cd81 Make call to GCodePlanner::writeGCode a parallel task
CURA-541
2017-01-24 14:48:01 +01:00
Johan Kristensen bfbfa5c47f Use list for GCodePath insertion in ExtruderPlan
Contributes to CURA-541
2017-01-24 14:43:11 +01:00
Johan K d887b50eed Remove default copy constructor from PolygonRef 2017-01-24 14:34:50 +01:00
Johan K 9712301aa8 Improve const correctness and remove const_cast 2017-01-24 14:24:54 +01:00
Johan Kristensen cdb0a41243 Add OpenMP parallel execution createLayerParts
CURA-541
2017-01-24 13:43:27 +01:00
Johan Kristensen 3235fc856d Add OpenMP parallel execution of slice make polygons
CURA-541
2017-01-24 13:41:16 +01:00
Johan Kristensen d97f67967b Add basic support for multithread abort
Add macro construct to catch exception in parallel for

CURA-541
2017-01-24 13:41:16 +01:00
Johan Kristensen 64abe6b620 Add OpenMP parallel execution of processInsets
CURA-541
2017-01-24 13:41:09 +01:00
Johan Kristensen cfc2dcb0ad Add OpenMP parallel execution of processSkinsAndInfill
CURA-541
2017-01-24 13:40:00 +01:00
Johan K 43a40f86b7 Add cmake option to enable OpenMP
CURA-541
2017-01-24 13:34:01 +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
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
Ghostkeeper 05be030c45 Document range check for pre-computed cubes
Contributes to issue CURA-3137.
2016-12-14 15:15:20 +01:00
Ghostkeeper 3c5e745f83 Reintroduce assert for coordinates exceeding maximum int
Because we might still test with models of 2km size.

Contributes to issue CURA-3137.
2016-12-14 14:09:16 +01:00
Ghostkeeper 2e6cd36f20 Make unused parameters unnamed
This way they cannot be used any more.

Shuts the compiler up for issue CURA-3137.
2016-12-14 12:02:00 +01:00
Ghostkeeper 9fc4a427cd Removed checks of unsigned ints being >= 0
Because that's always true. Even the compiler says that.

Contributes sorta to issue CURA-3137.
2016-12-14 12:00:39 +01:00
Ghostkeeper 5729908023 Remove unused path parameter
According to the compiler, the path parameter of handleChildren was not unused, but that was only because it went recursively to subcalls to handleChildren, so it was actually also unused.

Contributes to issue CURA-3137.
2016-12-14 11:55:40 +01:00
Ghostkeeper c5b90b0ad9 Put check for empty extruder trains before size check
Could save a miniscule amount of time.

Contributes to issue CURA-3137.
2016-12-14 11:50:45 +01:00
Ghostkeeper 382343e558 Make recursion depth unsigned
It can't be negative anyway. And it helps with the signed-unsigned comparison checks.

Contributes to issue CURA-3137.
2016-12-14 11:48:46 +01:00
Ghostkeeper 68b293b880 Make subdivided cubic infill robust to 0% infill
Otherwise it would crash or loop forever.

Contributes to issue CURA-3137.
2016-12-14 11:44:34 +01:00
Ghostkeeper f867c0f53a Prevent crashing when given no extruder trains
Instead we return -1. A bit more robust.

Contributes to issue CURA-3137.
2016-12-14 11:05:05 +01:00
Ghostkeeper ee7e83d138 Merge branch 'mb-layer-height-comment' of https://github.com/smartavionics/CuraEngine into smartavionics-mb-layer-height-comment 2016-12-14 09:29:53 +01:00
Ghostkeeper 50df40c6c6 Revert "Re-use extruder train variable"
This reverts commit c9217d4738.

Contributes to issue CURA-2795.
2016-12-13 15:35:47 +01:00
Ghostkeeper 4d924fd33d Revert "Add park distance information to retraction config"
This reverts commit 23ef513cce.

Contributes to issue CURA-2795.
2016-12-13 15:35:47 +01:00
Ghostkeeper c953a726cb Revert "Add function to move filament to park position"
This reverts commit ae00cbe497.

Contributes to issue CURA-2795.
2016-12-13 15:35:47 +01:00
Ghostkeeper 7c8c0b2417 Revert "Correct speed of retraction"
This reverts commit 6925f39426.

Contributes to issue CURA-2795.
2016-12-13 15:35:47 +01:00
Ghostkeeper a834754d64 Revert "Remove some annoying compile warnings"
This reverts commit d75882a707.

Contributes to issue CURA-2795.
2016-12-13 15:35:47 +01:00
Ghostkeeper 9957a0c733 Revert "Fix updating current E value"
This reverts commit 80f8760f68.

Contributes to issue CURA-2795.
2016-12-13 15:35:47 +01:00
Ghostkeeper f6ce0b4141 Revert "Put filament in parking position when we never use it any more"
This reverts commit 3cb3e5de45.

Contributes to issue CURA-2795.
2016-12-13 15:35:47 +01:00
Ghostkeeper 120a9c440c Revert "Park filament even if printer doesn't support retraction"
This reverts commit 837f992f69.

Contributes to issue CURA-2795.
2016-12-13 15:35:46 +01:00
Ghostkeeper 59f72bdd98 Revert "Expand documentation of writePark"
This reverts commit 4f3b4f429d.

Contributes to issue CURA-2795.
2016-12-13 15:35:46 +01:00
Ghostkeeper abc43302ac Revert "Correct retraction speed"
This reverts commit 36eb3471df.

Contributes to issue CURA-2795.
2016-12-13 15:35:46 +01:00
Mark Burton c2725bdf83 Move layer_height out of the GCodeExport class - it doesn't need to be a member. 2016-12-13 13:47:39 +00:00
Tim Kuipers fb761dfd9d fix: don't generate perimeter_gaps between inner wall and infill/skin when there is no infill (CURA-3108) 2016-12-13 13:53:05 +01:00
Mark Burton 90727a0578 Merge branch 'master' into mb-layer-height-comment 2016-12-13 08:05:31 +00:00
Mark Burton fd7d1a4bd4 Add comment that reports layer height in RepRap flavour gcode. 2016-12-12 16:54:13 +00:00
Ghostkeeper 2b1266c647 Move implementation to CPP file
Contributes to issue CURA-3006.
2016-12-12 14:04:32 +01:00
Ghostkeeper 901bf47610 Move implementation to CPP file
Contributes to issue CURA-3006.
2016-12-12 13:55:47 +01:00
Ghostkeeper 80a6115537 Move implementation to CPP file
Contributes to issue CURA-3006.
2016-12-12 13:44:23 +01:00
Ghostkeeper f94ca645bd Make writeRetraction accept const ref instead of const pointer
This change was already made for CURA-2795, and upon this change was built by other commits for other issues. I had to revert CURA-2795, so that would undo the changes that the other commits depend on. Instead though, I un-reverted the change because it's nice and doesn't have anything inherently to do with CURA-2795.

Contributes to issue CURA-2795.
2016-12-12 13:11:03 +01:00
Ghostkeeper 2067644d30 Revert "Update prime speed corresponding to park retraction"
This reverts commit 6c986e6cfe.

Contributes to issue CURA-2795.
2016-12-12 12:57:15 +01:00
Ghostkeeper 0285e2f025 Revert "Add additional safety check for extruder switching off in later layers"
This reverts commit bc82fd98c9.

Contributes to issue CURA-2795.
2016-12-12 12:57:15 +01:00
Ghostkeeper 38a1ee4270 Revert "Allow going to stand-by temperature if nozzle is later used"
This reverts commit 3c0d3f1b2d.

Contributes to issue CURA-2795.
2016-12-12 12:57:15 +01:00
Ghostkeeper 63459d5cd4 Revert "Correct documentation on why the temperature is switched off later"
This reverts commit 6972101d7e.

Contributes to issue CURA-2795.
2016-12-12 12:57:14 +01:00
Ghostkeeper 138691436e Revert "Correct technicality in documentation"
This reverts commit ab2c2eed4b.

Contributes to issue CURA-2795.
2016-12-12 12:57:14 +01:00
Ghostkeeper b9c5b4593b Revert "Remove unused parameter"
This reverts commit b7e9f72023.

Contributes to issue CURA-2795.
2016-12-12 12:57:14 +01:00
Ghostkeeper a0a3a24dc1 Revert "Restore park distance exception for BFB g-code"
This reverts commit b6355b69e7.

Contributes to issue CURA-2795.
2016-12-12 12:57:14 +01:00
Ghostkeeper 5959b41132 Revert "Use filament park distance setting instead of direct heat & cool zones"
This reverts commit b0487fa4c7.

Contributes to issue CURA-2795.
2016-12-12 12:57:14 +01:00
Ghostkeeper 3d7229c9f2 Revert "Turn extruder temperature off only if it parked the filament"
This reverts commit 84d3381be6.

Contributes to issue CURA-2795.
2016-12-12 12:57:14 +01:00
Ghostkeeper e1cfc3d93b Revert "Break retraction in two"
This reverts commit a0625aa735.

Contributes to issue CURA-2795.
2016-12-12 12:57:14 +01:00
Ghostkeeper 5834540bec Revert "Rename writeRetractionMove to writeMoveFilament"
This reverts commit 7c39b6b26a.

Contributes to issue CURA-2795.
2016-12-12 12:57:14 +01:00
Ghostkeeper f191d23e17 Revert "Pass retraction configs by reference instead of pointer"
This reverts commit 7a8be50b8f.

Contributes to issue CURA-2795.
2016-12-12 12:57:14 +01:00
Ghostkeeper 5114ab4218 Revert "Use writeMoveFilament to retract to parking distance"
This reverts commit cb7b7bf22a.

Contributes to issue CURA-2795.
2016-12-12 12:57:14 +01:00
Ghostkeeper 9f5645ecac Revert "Protect writeMoveFilament"
This reverts commit 52220ccab8.

Contributes to issue CURA-2795.
2016-12-12 12:57:14 +01:00
Ghostkeeper 66befe5827 Revert "Correct documentation of extruder_switch parameter"
This reverts commit 4263801d16.

Contributes to issue CURA-2795.
2016-12-12 12:57:14 +01:00
Ghostkeeper c9de64f946 Revert "Use optional to denote uninitiated previous extruder temperature"
This reverts commit 460c52ea6c.

Contributes to issue CURA-2795.
2016-12-12 12:57:14 +01:00
Ghostkeeper dbfa3a0f4b Revert "Move park distance data to ExtruderTrainAttributes"
This reverts commit 7777668b86.

Contributes to issue CURA-2795.
2016-12-12 12:54:56 +01:00
Ghostkeeper 02268eb7e8 Revert "Park via E-moves instead of via a retraction"
This reverts commit 6350f47cd6.

Contributes to issue CURA-2795.
2016-12-12 12:54:56 +01:00
90 arquivos alterados com 1650 adições e 9135 exclusões
+16 -9
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)
@@ -59,12 +69,12 @@ set(engine_SRCS # Except main.cpp.
src/gcodePlanner.cpp
src/infill.cpp
src/WallsComputation.cpp
src/layerPart.cpp
src/LayerPlanBuffer.cpp
src/Material.cpp
src/MaterialBase.cpp
src/MergeInfillLines.cpp
src/mesh.cpp
src/MeshGroup.cpp
src/multiVolumes.cpp
src/pathOrderOptimizer.cpp
src/Preheat.cpp
src/PrimeTower.cpp
@@ -72,14 +82,14 @@ set(engine_SRCS # Except main.cpp.
src/skin.cpp
src/SkirtBrim.cpp
src/sliceDataStorage.cpp
src/slicer.cpp
src/support.cpp
src/timeEstimate.cpp
src/TexturedMesh.cpp
src/TextureProcessor.cpp
src/WallsComputation.cpp
src/wallOverlap.cpp
src/Weaver.cpp
src/Wireframe2gcode.cpp
src/multithreadOpenMP.cpp
src/infill/NoZigZagConnectorProcessor.cpp
src/infill/ZigzagConnectorProcessorConnectedEndPieces.cpp
@@ -88,13 +98,10 @@ set(engine_SRCS # Except main.cpp.
src/infill/ZigzagConnectorProcessorNoEndPieces.cpp
src/infill/SubDivCube.cpp
src/slicer/LayerPart.cpp
src/slicer/MultiVolumes.cpp
src/slicer/SlicerLayer.cpp
src/slicer/Slicer.cpp
src/pathPlanning/Comb.cpp
src/pathPlanning/GCodePath.cpp
src/pathPlanning/LinePolygonsCrossings.cpp
src/pathPlanning/NozzleTempInsert.cpp
src/pathPlanning/TimeMaterialEstimates.cpp
src/progress/Progress.cpp
Diferenças do arquivo suprimidas por serem muito extensas Carregar Diff
+1 -1
Ver Arquivo
@@ -2,7 +2,7 @@
#ifndef CONICAL_OVERHANG_H
#define CONICAL_OVERHANG_H
#include "slicer/Slicer.h"
#include "slicer.h"
namespace cura {
+91 -58
Ver Arquivo
@@ -1,5 +1,3 @@
//Copyright (c) 2016 Ultimaker B.V.
//CuraEngine is released under the terms of the AGPLv3 or higher.
#include <list>
@@ -93,9 +91,15 @@ void FffGcodeWriter::writeGCode(SliceDataStorage& storage, TimeKeeper& time_keep
}
}
for(unsigned int layer_nr=0; layer_nr<total_layers; layer_nr++)
#pragma omp parallel default(none) shared(storage, total_layers)
{
processLayer(storage, layer_nr, total_layers);
#pragma omp single nowait
{
for(unsigned int layer_nr=0; layer_nr<total_layers; layer_nr++)
{
processLayer(storage, layer_nr, total_layers);
}
}
}
Progress::messageProgressStage(Progress::Stage::FINISH, &time_keeper);
@@ -196,7 +200,10 @@ 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"));
mesh.perimeter_gap_config.init(mesh.getSettingInMillimetersPerSecond("speed_topbottom"), mesh.getSettingInMillimetersPerSecond("acceleration_topbottom"), mesh.getSettingInMillimetersPerSecond("jerk_topbottom"), mesh.getSettingInMicrons("wall_line_width_x") / 2, 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
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"));
@@ -343,7 +350,10 @@ void FffGcodeWriter::processRaft(SliceDataStorage& storage, unsigned int total_l
int layer_height = train->getSettingInMicrons("raft_base_thickness");
z += layer_height;
int64_t comb_offset = train->getSettingInMicrons("raft_base_line_spacing");
GCodePlanner& gcode_layer = layer_plan_buffer.emplace_back(storage, layer_nr, z, layer_height, last_position_planned, current_extruder_planned, is_inside_mesh_layer_part, fan_speed_layer_time_settings_per_extruder, combing_mode, comb_offset, train->getSettingBoolean("travel_avoid_other_parts"), train->getSettingInMicrons("travel_avoid_distance"));
GCodePlanner& gcode_layer = layer_plan_buffer.createPlanner(storage, layer_nr, z, layer_height, last_position_planned, current_extruder_planned, is_inside_mesh_layer_part, fan_speed_layer_time_settings_per_extruder, combing_mode, comb_offset, train->getSettingBoolean("travel_avoid_other_parts"), train->getSettingInMicrons("travel_avoid_distance"));
// There should be a synchronization construct to make sure the writegcode task is complete before trimBuffer is called
#pragma omp taskwait
layer_plan_buffer.trimBuffer();
gcode_layer.setIsInside(true);
gcode_layer.setExtruder(extruder_nr);
@@ -380,7 +390,10 @@ void FffGcodeWriter::processRaft(SliceDataStorage& storage, unsigned int total_l
int layer_height = train->getSettingInMicrons("raft_interface_thickness");
z += layer_height;
int64_t comb_offset = train->getSettingInMicrons("raft_interface_line_spacing");
GCodePlanner& gcode_layer = layer_plan_buffer.emplace_back(storage, layer_nr, z, layer_height, last_position_planned, current_extruder_planned, is_inside_mesh_layer_part, fan_speed_layer_time_settings_per_extruder, combing_mode, comb_offset, train->getSettingBoolean("travel_avoid_other_parts"), train->getSettingInMicrons("travel_avoid_distance"));
GCodePlanner& gcode_layer = layer_plan_buffer.createPlanner(storage, layer_nr, z, layer_height, last_position_planned, current_extruder_planned, is_inside_mesh_layer_part, fan_speed_layer_time_settings_per_extruder, combing_mode, comb_offset, train->getSettingBoolean("travel_avoid_other_parts"), train->getSettingInMicrons("travel_avoid_distance"));
// There should be a synchronization construct to make sure the writegcode task is complete before trimBuffer is called
#pragma omp taskwait
layer_plan_buffer.trimBuffer();
gcode_layer.setIsInside(true);
gcode_layer.setExtruder(extruder_nr); // reset to extruder number, because we might have primed in the last layer
@@ -412,7 +425,10 @@ void FffGcodeWriter::processRaft(SliceDataStorage& storage, unsigned int total_l
const int layer_nr = initial_raft_layer_nr + 2 + raftSurfaceLayer - 1; // 2: 1 base layer, 1 interface layer
z += layer_height;
const int64_t comb_offset = train->getSettingInMicrons("raft_surface_line_spacing");
GCodePlanner& gcode_layer = layer_plan_buffer.emplace_back(storage, layer_nr, z, layer_height, last_position_planned, current_extruder_planned, is_inside_mesh_layer_part, fan_speed_layer_time_settings_per_extruder, combing_mode, comb_offset, train->getSettingBoolean("travel_avoid_other_parts"), train->getSettingInMicrons("travel_avoid_distance"));
GCodePlanner& gcode_layer = layer_plan_buffer.createPlanner(storage, layer_nr, z, layer_height, last_position_planned, current_extruder_planned, is_inside_mesh_layer_part, fan_speed_layer_time_settings_per_extruder, combing_mode, comb_offset, train->getSettingBoolean("travel_avoid_other_parts"), train->getSettingInMicrons("travel_avoid_distance"));
// There should be a synchronization construct to make sure the writegcode task is complete before trimBuffer is called
#pragma omp taskwait
layer_plan_buffer.trimBuffer();
gcode_layer.setIsInside(true);
if (CommandSocket::isInstantiated())
@@ -496,7 +512,7 @@ void FffGcodeWriter::processLayer(SliceDataStorage& storage, int layer_nr, unsig
GCodePlanner& gcode_layer = layer_plan_buffer.emplace_back(storage, layer_nr, z, layer_thickness, last_position_planned, current_extruder_planned, is_inside_mesh_layer_part, fan_speed_layer_time_settings_per_extruder, getSettingAsCombingMode("retraction_combing"), comb_offset_from_outlines, avoid_other_parts, avoid_distance);
GCodePlanner& gcode_layer = layer_plan_buffer.createPlanner(storage, layer_nr, z, layer_thickness, last_position_planned, current_extruder_planned, is_inside_mesh_layer_part, fan_speed_layer_time_settings_per_extruder, getSettingAsCombingMode("retraction_combing"), comb_offset_from_outlines, avoid_other_parts, avoid_distance);
if (include_helper_parts && layer_nr == 0)
{ // process the skirt or the brim of the starting extruder.
@@ -585,7 +601,9 @@ void FffGcodeWriter::processLayer(SliceDataStorage& storage, int layer_nr, unsig
last_position_planned = gcode_layer.getLastPosition();
current_extruder_planned = gcode_layer.getExtruder();
is_inside_mesh_layer_part = gcode_layer.getIsInsideMesh();
// There should be a synchronization construct to make sure the writegcode task is complete before trimBuffer is called
#pragma omp taskwait
layer_plan_buffer.trimBuffer();
gcode_layer.processFanSpeedAndMinimalLayerTime();
}
@@ -626,7 +644,7 @@ void FffGcodeWriter::processSkirtBrim(SliceDataStorage& storage, GCodePlanner& g
{
return;
}
gcode_layer.addTravel(skirt_brim.back().closestPointTo(gcode_layer.getLastPosition()));
gcode_layer.addTravel(PolygonRef{skirt_brim.back()}.closestPointTo(gcode_layer.getLastPosition()));
gcode_layer.addPolygonsByOptimizer(skirt_brim, &storage.skirt_brim_config[extruder_nr]);
}
@@ -698,7 +716,7 @@ std::vector<unsigned int> FffGcodeWriter::calculateMeshOrder(SliceDataStorage& s
SliceMeshStorage& mesh = storage.meshes[mesh_idx];
if (mesh.getSettingAsIndex("extruder_nr") == extruder_nr)
{
Mesh& mesh_data = *storage.meshgroup->meshes[mesh_idx];
Mesh& mesh_data = storage.meshgroup->meshes[mesh_idx];
Point3 middle = (mesh_data.getAABB().min + mesh_data.getAABB().max) / 2;
mesh_idx_order_optimizer.addItem(Point(middle.x, middle.y), mesh_idx);
}
@@ -714,7 +732,7 @@ std::vector<unsigned int> FffGcodeWriter::calculateMeshOrder(SliceDataStorage& s
return ret;
}
void FffGcodeWriter::addMeshLayerToGCode_meshSurfaceMode(SliceDataStorage& storage, SliceMeshStorage* mesh, GCodePlanner& gcode_layer, int layer_nr)
void FffGcodeWriter::addMeshLayerToGCode_meshSurfaceMode(SliceDataStorage& storage, const SliceMeshStorage* mesh, GCodePlanner& gcode_layer, int layer_nr)
{
if (layer_nr > mesh->layer_nr_max_filled_layer)
{
@@ -730,7 +748,7 @@ void FffGcodeWriter::addMeshLayerToGCode_meshSurfaceMode(SliceDataStorage& stora
setExtruder_addPrime(storage, gcode_layer, layer_nr, mesh->getSettingAsIndex("extruder_nr"));
SliceLayer* layer = &mesh->layers[layer_nr];
const SliceLayer* layer = &mesh->layers[layer_nr];
Polygons polygons;
@@ -746,12 +764,12 @@ void FffGcodeWriter::addMeshLayerToGCode_meshSurfaceMode(SliceDataStorage& stora
addMeshOpenPolyLinesToGCode(storage, mesh, gcode_layer, layer_nr);
}
void FffGcodeWriter::addMeshOpenPolyLinesToGCode(SliceDataStorage& storage, SliceMeshStorage* mesh, GCodePlanner& gcode_layer, int layer_nr)
void FffGcodeWriter::addMeshOpenPolyLinesToGCode(SliceDataStorage& storage, const SliceMeshStorage* mesh, GCodePlanner& gcode_layer, int layer_nr)
{
SliceLayer* layer = &mesh->layers[layer_nr];
const SliceLayer* layer = &mesh->layers[layer_nr];
Polygons lines;
for(PolygonRef polyline : layer->openPolyLines)
for(ConstPolygonRef polyline : layer->openPolyLines)
{
for(unsigned int point_idx = 1; point_idx<polyline.size(); point_idx++)
{
@@ -765,7 +783,7 @@ void FffGcodeWriter::addMeshOpenPolyLinesToGCode(SliceDataStorage& storage, Slic
}
void FffGcodeWriter::addMeshLayerToGCode(SliceDataStorage& storage, SliceMeshStorage* mesh, GCodePlanner& gcode_layer, int layer_nr)
void FffGcodeWriter::addMeshLayerToGCode(SliceDataStorage& storage, const SliceMeshStorage* mesh, GCodePlanner& gcode_layer, int layer_nr)
{
if (layer_nr > mesh->layer_nr_max_filled_layer)
{
@@ -779,7 +797,7 @@ void FffGcodeWriter::addMeshLayerToGCode(SliceDataStorage& storage, SliceMeshSto
return;
}
SliceLayer* layer = &mesh->layers[layer_nr];
const SliceLayer* layer = &mesh->layers[layer_nr];
if (layer->parts.size() == 0)
{
@@ -789,7 +807,7 @@ void FffGcodeWriter::addMeshLayerToGCode(SliceDataStorage& storage, SliceMeshSto
if (mesh->getSettingAsCount("wall_line_count") > 0)
{ // don't switch extruder if there's nothing to print
bool empty = true;
for (SliceLayerPart& part : layer->parts)
for (const SliceLayerPart& part : layer->parts)
{
if (part.insets.size() > 0)
{
@@ -821,7 +839,7 @@ void FffGcodeWriter::addMeshLayerToGCode(SliceDataStorage& storage, SliceMeshSto
for (int part_idx : part_order_optimizer.polyOrder)
{
SliceLayerPart& part = layer->parts[part_idx];
const SliceLayerPart& part = layer->parts[part_idx];
addMeshPartToGCode(storage, mesh, part, gcode_layer, layer_nr);
}
if (mesh->getSettingAsSurfaceMode("magic_mesh_surface_mode") != ESurfaceMode::NORMAL)
@@ -830,7 +848,7 @@ void FffGcodeWriter::addMeshLayerToGCode(SliceDataStorage& storage, SliceMeshSto
}
}
void FffGcodeWriter::addMeshPartToGCode(SliceDataStorage& storage, SliceMeshStorage* mesh, SliceLayerPart& part, GCodePlanner& gcode_layer, int layer_nr)
void FffGcodeWriter::addMeshPartToGCode(SliceDataStorage& storage, const SliceMeshStorage* mesh, const SliceLayerPart& part, GCodePlanner& gcode_layer, int layer_nr)
{
bool skin_alternate_rotation = mesh->getSettingBoolean("skin_alternate_rotation") && ( mesh->getSettingAsCount("top_layers") >= 4 || mesh->getSettingAsCount("bottom_layers") >= 4 );
@@ -866,7 +884,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)
{
@@ -890,7 +910,7 @@ void FffGcodeWriter::addMeshPartToGCode(SliceDataStorage& storage, SliceMeshStor
void FffGcodeWriter::processMultiLayerInfill(GCodePlanner& gcode_layer, SliceMeshStorage* mesh, SliceLayerPart& part, unsigned int layer_nr, int infill_line_distance, int infill_overlap, int infill_angle)
void FffGcodeWriter::processMultiLayerInfill(GCodePlanner& gcode_layer, const SliceMeshStorage* mesh, const SliceLayerPart& part, unsigned int layer_nr, int infill_line_distance, int infill_overlap, int infill_angle)
{
int64_t z = layer_nr * getSettingInMicrons("layer_height");
if (infill_line_distance > 0)
@@ -921,7 +941,7 @@ void FffGcodeWriter::processMultiLayerInfill(GCodePlanner& gcode_layer, SliceMes
}
}
void FffGcodeWriter::processSingleLayerInfill(GCodePlanner& gcode_layer, SliceMeshStorage* mesh, SliceLayerPart& part, unsigned int layer_nr, int infill_line_distance, int infill_overlap, int infill_angle)
void FffGcodeWriter::processSingleLayerInfill(GCodePlanner& gcode_layer, const SliceMeshStorage* mesh, const SliceLayerPart& part, unsigned int layer_nr, int infill_line_distance, int infill_overlap, int infill_angle)
{
if (infill_line_distance == 0 || part.infill_area_per_combine_per_density[0].size() == 0)
{
@@ -982,7 +1002,7 @@ void FffGcodeWriter::processSingleLayerInfill(GCodePlanner& gcode_layer, SliceMe
}
}
void FffGcodeWriter::processInsets(GCodePlanner& gcode_layer, SliceMeshStorage* mesh, SliceLayerPart& part, unsigned int layer_nr, EZSeamType z_seam_type, Point z_seam_pos)
void FffGcodeWriter::processInsets(GCodePlanner& gcode_layer, const SliceMeshStorage* mesh, const SliceLayerPart& part, unsigned int layer_nr, EZSeamType z_seam_type, Point z_seam_pos)
{
bool compensate_overlap_0 = mesh->getSettingBoolean("travel_compensate_overlapping_walls_0_enabled");
bool compensate_overlap_x = mesh->getSettingBoolean("travel_compensate_overlapping_walls_x_enabled");
@@ -1019,7 +1039,7 @@ void FffGcodeWriter::processInsets(GCodePlanner& gcode_layer, SliceMeshStorage*
}
else
{
Polygons& outer_wall = part.insets[0];
Polygons outer_wall = part.insets[0];
WallOverlapComputation wall_overlap_computation(outer_wall, mesh->getSettingInMicrons("wall_line_width_0"));
gcode_layer.addPolygonsByOptimizer(outer_wall, &mesh->inset0_config, &wall_overlap_computation, z_seam_type, z_seam_pos, mesh->getSettingInMicrons("wall_0_wipe_dist"), spiralize);
}
@@ -1032,7 +1052,7 @@ void FffGcodeWriter::processInsets(GCodePlanner& gcode_layer, SliceMeshStorage*
}
else
{
Polygons& outer_wall = part.insets[processed_inset_number];
Polygons outer_wall = part.insets[processed_inset_number];
WallOverlapComputation wall_overlap_computation(outer_wall, mesh->getSettingInMicrons("wall_line_width_x"));
gcode_layer.addPolygonsByOptimizer(outer_wall, &mesh->insetX_config, &wall_overlap_computation);
}
@@ -1042,31 +1062,35 @@ void FffGcodeWriter::processInsets(GCodePlanner& gcode_layer, SliceMeshStorage*
}
void FffGcodeWriter::processSkinAndPerimeterGaps(GCodePlanner& gcode_layer, SliceMeshStorage* mesh, SliceLayerPart& part, unsigned int layer_nr, int skin_overlap, int skin_angle)
void FffGcodeWriter::processSkinAndPerimeterGaps(GCodePlanner& gcode_layer, const SliceMeshStorage* mesh, const SliceLayerPart& part, unsigned int layer_nr, int skin_overlap, int skin_angle)
{
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);
for (unsigned int skin_part_idx = 0; skin_part_idx < part.skin_parts.size(); skin_part_idx++)
{
PolygonsPart& outline = part.skin_parts[skin_part_idx].outline;
const PolygonsPart& outline = part.skin_parts[skin_part_idx].outline;
part_order_optimizer.addPolygon(outline.outerPolygon());
}
part_order_optimizer.optimize();
for (int ordered_skin_part_idx : part_order_optimizer.polyOrder)
{
SkinPart& skin_part = part.skin_parts[ordered_skin_part_idx];
const SkinPart& skin_part = part.skin_parts[ordered_skin_part_idx];
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]);
@@ -1078,11 +1102,11 @@ void FffGcodeWriter::processSkinAndPerimeterGaps(GCodePlanner& gcode_layer, Slic
Polygons perimeter_gaps; // the perimeter gaps of the insets of this skin part
Polygons* inner_skin_outline = nullptr;
const Polygons* inner_skin_outline = nullptr;
int offset_from_inner_skin_outline = 0;
if (pattern != EFillMethod::CONCENTRIC)
{
for (Polygons& skin_perimeter : skin_part.insets)
for (const Polygons& skin_perimeter : skin_part.insets)
{
gcode_layer.addPolygonsByOptimizer(skin_perimeter, &mesh->insetX_config); // add polygons to gcode in inward order
}
@@ -1118,13 +1142,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)
@@ -1135,40 +1152,56 @@ 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)
{ // handle perimeter gaps of normal insets
Polygons perimeter_gaps;
int line_width = mesh->inset0_config.getLineWidth();
for (unsigned int inset_idx = 0; inset_idx < part.insets.size(); inset_idx++)
for (unsigned int inset_idx = 0; inset_idx < part.insets.size() - 1; inset_idx++)
{
const Polygons outer = part.insets[inset_idx].offset(-1 * line_width / 2 - perimeter_gaps_extra_offset);
line_width = mesh->insetX_config.getLineWidth();
Polygons inner;
if (inset_idx + 1 < part.insets.size())
Polygons inner = part.insets[inset_idx + 1].offset(line_width / 2);
perimeter_gaps.add(outer.difference(inner));
}
{ // gap between inner wall and skin/infill
if (mesh->getSettingInMicrons("infill_line_distance") > 0
&& !mesh->getSettingBoolean("infill_hollow")
&& mesh->getSettingInMicrons("infill_overlap_mm") >= 0
)
{
inner = part.insets[inset_idx + 1].offset(line_width / 2);
}
else
{
inner = part.infill_area;
for (SkinPart& skin_part : part.skin_parts)
const Polygons outer = part.insets.back().offset(-1 * line_width / 2 - perimeter_gaps_extra_offset);
Polygons inner = part.infill_area;
for (const SkinPart& skin_part : part.skin_parts)
{
inner.add(skin_part.outline);
}
inner = inner.unionPolygons();
perimeter_gaps.add(outer.difference(inner));
}
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);
}
}
@@ -1229,7 +1262,7 @@ bool FffGcodeWriter::addSupportInfillToGCode(SliceDataStorage& storage, GCodePla
PathOrderOptimizer island_order_optimizer(gcode_layer.getLastPosition());
for(unsigned int n=0; n<support_islands.size(); n++)
{
island_order_optimizer.addPolygon(support_islands[n][0]);
island_order_optimizer.addPolygon(PolygonRef{support_islands[n][0]});
}
island_order_optimizer.optimize();
+8 -8
Ver Arquivo
@@ -301,7 +301,7 @@ private:
* \param layer_nr The index of the layer to write the gcode of.
*
*/
void addMeshLayerToGCode_meshSurfaceMode(SliceDataStorage& storage, SliceMeshStorage* mesh, GCodePlanner& gcodeLayer, int layer_nr);
void addMeshLayerToGCode_meshSurfaceMode(SliceDataStorage& storage, const SliceMeshStorage* mesh, GCodePlanner& gcodeLayer, int layer_nr);
/*!
* Add the open polylines from a single layer from a single mesh-volume to the layer plan \p gcodeLayer for mesh the surface modes.
@@ -312,7 +312,7 @@ private:
* \param layer_nr The index of the layer to write the gcode of.
*
*/
void addMeshOpenPolyLinesToGCode(SliceDataStorage& storage, SliceMeshStorage* mesh, GCodePlanner& gcode_layer, int layer_nr);
void addMeshOpenPolyLinesToGCode(SliceDataStorage& storage, const SliceMeshStorage* mesh, GCodePlanner& gcode_layer, int layer_nr);
/*!
* Add a single layer from a single mesh-volume to the layer plan \p gcode_layer.
@@ -323,7 +323,7 @@ private:
* \param layer_nr The index of the layer to write the gcode of.
*
*/
void addMeshLayerToGCode(SliceDataStorage& storage, SliceMeshStorage* mesh, GCodePlanner& gcode_layer, int layer_nr);
void addMeshLayerToGCode(SliceDataStorage& storage, const SliceMeshStorage* mesh, GCodePlanner& gcode_layer, int layer_nr);
/*!
* Add a single part from a given layer of a mesh-volume to the layer plan \p gcode_layer.
@@ -335,7 +335,7 @@ private:
* \param layer_nr The index of the layer to write the gcode of.
*
*/
void addMeshPartToGCode(SliceDataStorage& storage, SliceMeshStorage* mesh, SliceLayerPart& part, GCodePlanner& gcode_layer, int layer_nr);
void addMeshPartToGCode(SliceDataStorage& storage, const SliceMeshStorage* mesh, const SliceLayerPart& part, GCodePlanner& gcode_layer, int layer_nr);
/*!
* Add thicker (multiple layers) sparse infill for a given part in a layer plan.
@@ -348,7 +348,7 @@ private:
* \param infill_overlap The distance by which the infill overlaps with the wall insets.
* \param fillAngle The angle in the XY plane at which the infill is generated.
*/
void processMultiLayerInfill(GCodePlanner& gcodeLayer, SliceMeshStorage* mesh, SliceLayerPart& part, unsigned int layer_nr, int infill_line_distance, int infill_overlap, int fillAngle);
void processMultiLayerInfill(GCodePlanner& gcodeLayer, const SliceMeshStorage* mesh, const SliceLayerPart& part, unsigned int layer_nr, int infill_line_distance, int infill_overlap, int fillAngle);
/*!
* Add normal sparse infill for a given part in a layer.
@@ -360,7 +360,7 @@ private:
* \param infill_overlap The distance by which the infill overlaps with the wall insets.
* \param fillAngle The angle in the XY plane at which the infill is generated.
*/
void processSingleLayerInfill(GCodePlanner& gcodeLayer, SliceMeshStorage* mesh, SliceLayerPart& part, unsigned int layer_nr, int infill_line_distance, int infill_overlap, int fillAngle);
void processSingleLayerInfill(GCodePlanner& gcodeLayer, const SliceMeshStorage* mesh, const SliceLayerPart& part, unsigned int layer_nr, int infill_line_distance, int infill_overlap, int fillAngle);
/*!
* Generate the insets for the walls of a given layer part.
@@ -371,7 +371,7 @@ private:
* \param z_seam_type dir3ective for where to start the outer paerimeter of a part
* \param z_seam_pos The location near where to start the outer inset in case \p z_seam_type is 'back'
*/
void processInsets(GCodePlanner& gcodeLayer, SliceMeshStorage* mesh, SliceLayerPart& part, unsigned int layer_nr, EZSeamType z_seam_type, Point z_seam_pos);
void processInsets(GCodePlanner& gcodeLayer, const SliceMeshStorage* mesh, const SliceLayerPart& part, unsigned int layer_nr, EZSeamType z_seam_type, Point z_seam_pos);
/*!
@@ -387,7 +387,7 @@ private:
* \param skin_overlap The distance by which the skin overlaps with the wall insets and the distance by which the perimeter gaps overlap with adjacent print features.
* \param fillAngle The angle in the XY plane at which the infill is generated.
*/
void processSkinAndPerimeterGaps(cura::GCodePlanner& gcode_layer, cura::SliceMeshStorage* mesh, cura::SliceLayerPart& part, unsigned int layer_nr, int skin_overlap, int infill_angle);
void processSkinAndPerimeterGaps(cura::GCodePlanner& gcode_layer, const cura::SliceMeshStorage* mesh, const cura::SliceLayerPart& part, unsigned int layer_nr, int skin_overlap, int infill_angle);
/*!
* Add the support to the layer plan \p gcodeLayer of the current layer for all support parts with the given \p extruder_nr.
+99 -26
Ver Arquivo
@@ -2,17 +2,17 @@
#include <algorithm>
#include <map> // multimap (ordered map allowing duplicate keys)
#include <omp.h>
#include "utils/math.h"
#include "slicer/Slicer.h"
#include "utils/algorithm.h"
#include "slicer.h"
#include "utils/gettime.h"
#include "utils/logoutput.h"
#include "MeshGroup.h"
#include "support.h"
#include "slicer/MultiVolumes.h"
#include "slicer/LayerPart.h"
#include "TextureProcessor.h"
#include "multiVolumes.h"
#include "layerPart.h"
#include "WallsComputation.h"
#include "SkirtBrim.h"
#include "skin.h"
@@ -24,7 +24,7 @@
#include "progress/ProgressEstimator.h"
#include "progress/ProgressStageEstimator.h"
#include "progress/ProgressEstimatorLinear.h"
#include "multithreadOpenMP.h"
namespace cura
{
@@ -32,6 +32,17 @@ namespace cura
bool FffPolygonGenerator::generateAreas(SliceDataStorage& storage, MeshGroup* meshgroup, TimeKeeper& timeKeeper)
{
#pragma omp parallel
{
#pragma omp master
{
#ifdef _OPENMP
log("OpenMP enabled, number of threads used: %u\n", omp_get_num_threads());
#else
log("OpenMP disabled\n");
#endif
}
}
if (!sliceModel(meshgroup, timeKeeper, storage))
{
return false;
@@ -89,7 +100,7 @@ bool FffPolygonGenerator::sliceModel(MeshGroup* meshgroup, TimeKeeper& timeKeepe
std::vector<Slicer*> slicerList;
for(unsigned int mesh_idx = 0; mesh_idx < meshgroup->meshes.size(); mesh_idx++)
{
Mesh& mesh = *meshgroup->meshes[mesh_idx];
Mesh& mesh = meshgroup->meshes[mesh_idx];
Slicer* slicer = new Slicer(&mesh, initial_slice_z, layer_thickness, slice_layer_count, mesh.getSettingBoolean("meshfix_keep_open_polygons"), mesh.getSettingBoolean("meshfix_extensive_stitching"));
slicerList.push_back(slicer);
/*
@@ -108,7 +119,7 @@ bool FffPolygonGenerator::sliceModel(MeshGroup* meshgroup, TimeKeeper& timeKeepe
for(unsigned int meshIdx=0; meshIdx < slicerList.size(); meshIdx++)
{
Mesh& mesh = *storage.meshgroup->meshes[meshIdx];
Mesh& mesh = storage.meshgroup->meshes[meshIdx];
if (mesh.getSettingBoolean("conical_overhang_enabled") && !mesh.getSettingBoolean("anti_overhang_mesh"))
{
ConicalOverhang::apply(slicerList[meshIdx], mesh.getSettingInAngleRadians("conical_overhang_angle"), layer_thickness);
@@ -117,7 +128,6 @@ bool FffPolygonGenerator::sliceModel(MeshGroup* meshgroup, TimeKeeper& timeKeepe
Progress::messageProgressStage(Progress::Stage::PARTS, &timeKeeper);
if (storage.getSettingBoolean("carve_multiple_volumes"))
{
carveMultipleVolumes(slicerList, storage.getSettingBoolean("alternate_carve_order"));
@@ -127,7 +137,7 @@ bool FffPolygonGenerator::sliceModel(MeshGroup* meshgroup, TimeKeeper& timeKeepe
storage.print_layer_count = 0;
for (unsigned int meshIdx = 0; meshIdx < slicerList.size(); meshIdx++)
{
Mesh& mesh = *storage.meshgroup->meshes[meshIdx];
Mesh& mesh = storage.meshgroup->meshes[meshIdx];
Slicer* slicer = slicerList[meshIdx];
if (!mesh.getSettingBoolean("anti_overhang_mesh") && !mesh.getSettingBoolean("infill_mesh"))
{
@@ -140,10 +150,10 @@ bool FffPolygonGenerator::sliceModel(MeshGroup* meshgroup, TimeKeeper& timeKeepe
for (unsigned int meshIdx = 0; meshIdx < slicerList.size(); meshIdx++)
{
Slicer* slicer = slicerList[meshIdx];
Mesh& mesh = *storage.meshgroup->meshes[meshIdx];
Mesh& mesh = storage.meshgroup->meshes[meshIdx];
// always make a new SliceMeshStorage, so that they have the same ordering / indexing as meshgroup.meshes
storage.meshes.emplace_back(meshgroup->meshes[meshIdx], slicer->layers.size()); // new mesh in storage had settings from the Mesh
storage.meshes.emplace_back(&meshgroup->meshes[meshIdx], slicer->layers.size()); // new mesh in storage had settings from the Mesh
SliceMeshStorage& meshStorage = storage.meshes.back();
if (mesh.getSettingBoolean("anti_overhang_mesh"))
@@ -153,6 +163,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;
}
@@ -163,6 +177,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;
}
@@ -339,12 +357,24 @@ void FffPolygonGenerator::processBasicWallsSkinInfill(SliceDataStorage& storage,
// walls
for (unsigned int layer_number = 0; layer_number < mesh.layers.size(); layer_number++)
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);
@@ -359,8 +389,8 @@ void FffPolygonGenerator::processBasicWallsSkinInfill(SliceDataStorage& storage,
SliceMeshStorage& other_mesh = storage.meshes[other_mesh_idx];
if (other_mesh.getSettingBoolean("infill_mesh"))
{
AABB3D aabb = storage.meshgroup->meshes[mesh_idx]->getAABB();
AABB3D other_aabb = storage.meshgroup->meshes[other_mesh_idx]->getAABB();
AABB3D aabb = storage.meshgroup->meshes[mesh_idx].getAABB();
AABB3D other_aabb = storage.meshgroup->meshes[other_mesh_idx].getAABB();
if (aabb.hit(other_aabb))
{
process_infill = true;
@@ -375,15 +405,32 @@ 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);
}
}
@@ -423,7 +470,7 @@ void FffPolygonGenerator::processInfillMesh(SliceDataStorage& storage, unsigned
if (new_outline.size() == 1)
{ // we don't have to call splitIntoParts, because a single polygon can only be a single part
PolygonsPart outline_part_here;
outline_part_here.add(new_outline[0]);
outline_part_here.add(PolygonRef{new_outline[0]});
new_parts.push_back(outline_part_here);
}
else if (new_outline.size() > 1)
@@ -480,6 +527,14 @@ 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.
*
* generateInsets only reads and writes data for the current layer
*
* 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];
@@ -518,11 +573,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)
@@ -553,8 +616,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)
{
+3 -3
Ver Arquivo
@@ -38,7 +38,7 @@ std::string FffProcessor::getAllSettingsString(MeshGroup& meshgroup, bool first_
}
for (unsigned int mesh_idx = 0; mesh_idx < meshgroup.meshes.size(); mesh_idx++)
{
Mesh& mesh = *meshgroup.meshes[mesh_idx];
Mesh& mesh = meshgroup.meshes[mesh_idx];
sstream << " -e" << mesh.getSettingAsIndex("extruder_nr") << " -l \"" << mesh_idx << "\"" << mesh.getAllLocalSettingsString();
}
sstream << "\n";
@@ -58,9 +58,9 @@ bool FffProcessor::processMeshGroup(MeshGroup* meshgroup)
gcode_writer.setParent(meshgroup);
bool empty = true;
for (Mesh* mesh : meshgroup->meshes)
for (Mesh& mesh : meshgroup->meshes)
{
if (!mesh->getSettingBoolean("infill_mesh") && !mesh->getSettingBoolean("anti_overhang_mesh"))
if (!mesh.getSettingBoolean("infill_mesh") && !mesh.getSettingBoolean("anti_overhang_mesh"))
{
empty = false;
}
+7 -7
Ver Arquivo
@@ -67,37 +67,37 @@ void GCodePathConfig::setSpeedIconic()
current_config.jerk = iconic_config.jerk;
}
double GCodePathConfig::getExtrusionMM3perMM()
double GCodePathConfig::getExtrusionMM3perMM() const
{
return extrusion_mm3_per_mm;
}
double GCodePathConfig::getSpeed()
double GCodePathConfig::getSpeed() const
{
return current_config.speed;
}
double GCodePathConfig::getAcceleration()
double GCodePathConfig::getAcceleration() const
{
return current_config.acceleration;
}
double GCodePathConfig::getJerk()
double GCodePathConfig::getJerk() const
{
return current_config.jerk;
}
int GCodePathConfig::getLineWidth()
int GCodePathConfig::getLineWidth() const
{
return current_config.line_width;
}
bool GCodePathConfig::isTravelPath()
bool GCodePathConfig::isTravelPath() const
{
return current_config.line_width == 0;
}
double GCodePathConfig::getFlowPercentage()
double GCodePathConfig::getFlowPercentage() const
{
return current_config.flow;
}
+7 -7
Ver Arquivo
@@ -79,28 +79,28 @@ public:
/*!
* Can only be called after the layer height has been set (which is done while writing the gcode!)
*/
double getExtrusionMM3perMM();
double getExtrusionMM3perMM() const;
/*!
* Get the movement speed in mm/s
*/
double getSpeed();
double getSpeed() const;
/*!
* Get the current acceleration of this config
*/
double getAcceleration();
double getAcceleration() const;
/*!
* Get the current jerk of this config
*/
double getJerk();
double getJerk() const;
int getLineWidth();
int getLineWidth() const;
bool isTravelPath();
bool isTravelPath() const;
double getFlowPercentage();
double getFlowPercentage() const;
private:
void calculateExtrusion();
+44 -9
Ver Arquivo
@@ -7,6 +7,31 @@
namespace cura {
void issueWriteGCode_impl(
GCodeExport* p_gcode,
GCodePlanner* p_front_buffer
){
#pragma omp task default(none) firstprivate(p_gcode, p_front_buffer)
{ MULTITHREAD_TASK_CATCH_EXCEPTION(
GCodeExport& gcode_ref = *p_gcode;
#ifdef _OPENMP
omp_lock_guard_t<omp_nest_lock_type> gcode_output_lock_guard(gcode_ref.getOutputStreamLock());
#endif
p_front_buffer->writeGCode(gcode_ref);
if (CommandSocket::isInstantiated())
{
CommandSocket::getInstance()->flushGcode();
}
)}
}
void LayerPlanBuffer::issueWriteGCode()
{
assert(!(buffer.front().isGCodeWritten()) && "GCode shouldn't be written more than once");
GCodeExport* p_gcode = &gcode;
GCodePlanner* p_front_buffer = &buffer.front();
issueWriteGCode_impl(p_gcode, p_front_buffer);
}
void LayerPlanBuffer::flush()
@@ -15,6 +40,10 @@ void LayerPlanBuffer::flush()
{
insertTempCommands(); // insert preheat commands of the very last layer
}
#ifdef _OPENMP
omp_lock_guard_t<omp_nest_lock_type> gcode_output_lock_guard(gcode.getOutputStreamLock());
#endif
while (!buffer.empty())
{
buffer.front().writeGCode(gcode);
@@ -30,9 +59,10 @@ void LayerPlanBuffer::flush()
void LayerPlanBuffer::insertPreheatCommand(ExtruderPlan& extruder_plan_before, double time_after_extruder_plan_start, int extruder, double temp)
{
double acc_time = 0.0;
for (unsigned int path_idx = extruder_plan_before.paths.size() - 1; int(path_idx) != -1 ; path_idx--)
std::vector<GCodePath>& extruder_plan_before_paths = extruder_plan_before.getPaths();
for (unsigned int path_idx = extruder_plan_before_paths.size() - 1; int(path_idx) != -1 ; path_idx--)
{
GCodePath& path = extruder_plan_before.paths[path_idx];
GCodePath& path = extruder_plan_before_paths[path_idx];
const double time_this_path = path.estimates.getTotalTime();
acc_time += time_this_path;
if (acc_time > time_after_extruder_plan_start)
@@ -195,9 +225,9 @@ void LayerPlanBuffer::insertPrintTempCommand(ExtruderPlan& extruder_plan)
if (preheat_config.getInitialPrintTemp(extruder) != 0)
{ // handle heating from initial_print_temperature to printing_tempreature
unsigned int path_idx;
for (path_idx = 0; path_idx < extruder_plan.paths.size(); path_idx++)
for (path_idx = 0; path_idx < extruder_plan.getPaths().size(); path_idx++)
{
GCodePath& path = extruder_plan.paths[path_idx];
GCodePath& path = extruder_plan.getPaths()[path_idx];
heated_pre_travel_time += path.estimates.getTotalTime();
if (!path.isTravelPath())
{
@@ -224,9 +254,9 @@ void LayerPlanBuffer::insertFinalPrintTempCommand(std::vector<ExtruderPlan*>& ex
double heated_post_travel_time = 0; // The time after the last extrude move toward the end of the extruder plan during which the nozzle is stable at the final print temperature
{ // compute heated_post_travel_time
unsigned int path_idx;
for (path_idx = last_extruder_plan.paths.size() - 1; int(path_idx) >= 0; path_idx--)
for (path_idx = last_extruder_plan.getPaths().size() - 1; int(path_idx) >= 0; path_idx--)
{
GCodePath& path = last_extruder_plan.paths[path_idx];
GCodePath& path = last_extruder_plan.getPaths()[path_idx];
if (!path.isTravelPath())
{
break;
@@ -306,9 +336,9 @@ void LayerPlanBuffer::insertFinalPrintTempCommand(std::vector<ExtruderPlan*>& ex
{ // insert temp command in precool_extruder_plan
double extrusion_time_seen = 0;
unsigned int path_idx;
for (path_idx = precool_extruder_plan->paths.size() - 1; int(path_idx) >= 0; path_idx--)
for (path_idx = precool_extruder_plan->getPaths().size() - 1; int(path_idx) >= 0; path_idx--)
{
GCodePath& path = precool_extruder_plan->paths[path_idx];
GCodePath& path = precool_extruder_plan->getPaths()[path_idx];
extrusion_time_seen += path.estimates.getTotalTime();
if (extrusion_time_seen >= cool_down_time)
{
@@ -324,11 +354,16 @@ void LayerPlanBuffer::insertFinalPrintTempCommand(std::vector<ExtruderPlan*>& ex
void LayerPlanBuffer::insertTempCommands()
{
if (buffer.back().extruder_plans.size() == 0 || (buffer.back().extruder_plans.size() == 1 && buffer.back().extruder_plans[0].paths.size() == 0))
if (buffer.back().extruder_plans.size() == 0 || (buffer.back().extruder_plans.size() == 1 && buffer.back().extruder_plans[0].getPathsList().empty()))
{ // disregard empty layer
buffer.pop_back();
return;
}
for (ExtruderPlan& plan: buffer.back().extruder_plans)
{
plan.convertListToVector();
}
std::vector<ExtruderPlan*> extruder_plans;
extruder_plans.reserve(buffer.size() * 2);
+20 -8
Ver Arquivo
@@ -57,28 +57,40 @@ public:
/*!
* Place a new layer plan (GcodePlanner) by constructing it with the given arguments.
* Pop back the oldest layer plan is it exceeds the buffer size and write it to gcode.
*/
template<typename... Args>
GCodePlanner& emplace_back(Args&&... constructor_args)
GCodePlanner& createPlanner(Args&&... constructor_args)
{
if (buffer.size() > 0)
{
insertTempCommands(); // insert preheat commands of the just completed layer plan (not the newly emplaced one)
}
buffer.emplace_back(constructor_args...);
if (buffer.size() > buffer_size)
{
buffer.front().writeGCode(gcode);
if (CommandSocket::isInstantiated())
{
CommandSocket::getInstance()->flushGcode();
}
buffer.pop_front();
issueWriteGCode();
}
return buffer.back();
}
/*
* Write GCode for the oldest layer plan.
*/
void issueWriteGCode();
/*
* Pop back the oldest layer plan if it exceeds the buffer size and it has been written to gcode.
*/
void trimBuffer()
{
if (buffer.size() > buffer_size)
{
assert(buffer.front().isGCodeWritten() && "GCode should be written before planner is discarded");
buffer.pop_front();
}
}
/*!
* Write all remaining layer plans (GCodePlanner) to gcode and empty the buffer.
*/
-27
Ver Arquivo
@@ -1,27 +0,0 @@
/** Copyright (C) 2016 Tim Kuipers - Released under terms of the AGPLv3 License */
#ifndef MAT_COORD_H
#define MAT_COORD_H
#include "utils/FPoint.h"
namespace cura
{
/*!
* Coordinates in a specific texture bitmap
*/
struct MatCoord
{
FPoint coords;
int mat_id; //!< Material id
MatCoord() //!< non-initializing constructor
{}
MatCoord(FPoint coords, int mat_id) //!< constructor
: coords(coords)
, mat_id(mat_id)
{}
};
} // namespace cura
#endif // MAT_COORD_H
-27
Ver Arquivo
@@ -1,27 +0,0 @@
/** Copyright (C) 2016 Tim Kuipers - Released under terms of the AGPLv3 License */
#ifndef MAT_SEGMENT_H
#define MAT_SEGMENT_H
#include "MatCoord.h"
namespace cura
{
/*!
* Coordinates in a specific texture bitmap
*/
struct MatSegment
{
MatCoord start;
MatCoord end;
MatSegment() //!< non-initializing constructor
{}
MatSegment(MatCoord start, MatCoord end)
: start(start)
, end(end)
{}
};
} // namespace cura
#endif // MAT_SEGMENT_H
-143
Ver Arquivo
@@ -1,143 +0,0 @@
/** Copyright (C) 2016 Tim Kuipers - Released under terms of the AGPLv3 License */
#include <limits> // numeric limits
#include <algorithm> // min max
#include <iostream>
#include <cassert>
#include "Material.h"
namespace cura
{
Material::Material()
: data(nullptr)
, width(0)
, height(0)
, depth(0)
{
}
void Material::setData(unsigned char* data)
{
this->data = data;
}
void Material::setDimensions(unsigned int width, unsigned int height, unsigned int depth)
{
this->width = width;
this->height = height;
this->depth = depth;
}
float Material::getColor(float x, float y, ColourUsage color) const
{
assert(x >= 0.0f && x <= 1.0f);
assert(y >= 0.0f && y <= 1.0f);
switch (color)
{
case ColourUsage::RED:
case ColourUsage::GREEN:
case ColourUsage::BLUE:
case ColourUsage::ALPHA:
{
assert((int)color >= 0 && (unsigned int)color < depth && "Z out of bounds!");
return getColorData(x, y, (unsigned int) color);
}
case ColourUsage::GREY:
default:
{
float r = getColorData(x, y, (unsigned int) ColourUsage::RED);
float g = getColorData(x, y, (unsigned int) ColourUsage::GREEN);
float b = getColorData(x, y, (unsigned int) ColourUsage::BLUE);
return (r + g + b) / 3.0;
}
}
}
float Material::getColorData(float x, float y, unsigned int z) const
{
unsigned int x_idx = (unsigned int) (x * (width - 1) + 0.5);
assert(x_idx >= 0 && x_idx < width && "requested X is out of bounds!");
unsigned int y_idx = (unsigned int) (y * (height - 1) + 0.5);
assert(y_idx >= 0 && y_idx < height && "requested Y is out of bounds!");
unsigned char col = data[(y_idx * width + x_idx) * depth + z];
return (float) col / std::numeric_limits<unsigned char>::max();
}
void Material::debugOutput(bool dw) const
{
std::cerr << "\nImage size: " << width << " x " << height << " (" << depth << "channels)\n";
std::cerr << '+';
for (unsigned int i = 0; i < width; i++)
{
std::cerr << ((dw)? "--" : "-");
}
std::cerr << "+\n";
for (unsigned int y = 0; y < height; y++)
{
std::cerr << "|";
for (unsigned int x = 0; x < width; x++)
{
int val = (data[(y*width+x)*depth] * 10 / 256);
switch (val)
{
case 0:
std::cerr << ((dw)? " " : " ");
break;
case 1:
std::cerr << ((dw)? ".." : ".");
break;
case 2:
std::cerr << ((dw)? ",," : ",");
break;
case 3:
std::cerr << ((dw)? "::" : ":");
break;
case 4:
std::cerr << ((dw)? ";;" : ";");
break;
case 5:
std::cerr << ((dw)? "++" : "+");
break;
case 6:
std::cerr << ((dw)? "░░" : "");
break;
case 7:
std::cerr << ((dw)? "▒▒" : "");
break;
case 8:
std::cerr << ((dw)? "▓▓" : "");
break;
default:
if (val > 8)
{
std::cerr << ((dw)? "██" : "");
}
else
{
std::cerr << ((dw)? " " : " ");
}
}
}
std::cerr << "|\n";
}
std::cerr << '+';
for (unsigned int i = 0; i < width; i++)
{
std::cerr << ((dw)? "--" : "-");
}
std::cerr << "+\n";
}
} // namespace cura
-67
Ver Arquivo
@@ -1,67 +0,0 @@
/** Copyright (C) 2016 Tim Kuipers - Released under terms of the AGPLv3 License */
#ifndef MATERIAL_H
#define MATERIAL_H
#include "settings/settings.h" // ColourUsage
namespace cura
{
/*!
* The material used in a texture.
*
* This class just holds the image data and has some nice utility functions.
*/
class Material
{
public:
/*!
* non-initializing constructor
*/
Material();
/*!
* Set the pixel data of the image
* \param data pointer to the array of data in RGBA, left-to-right, top-to-bottom
*/
void setData(unsigned char* data);
/*!
* Set the dimensions of the image
* \param width The horizontal length of the imnage
* \param height The vertical length of the imnage
* \param depth The number of color channels
*/
void setDimensions(unsigned int width, unsigned int height, unsigned int depth);
/*!
* get the color value at a particular place in the image
*
* \param x place in the horizontal direction left to right (value between zero and one)
* \param y place in the vertical direction top to bottom (value between zero and one)
* \param color The color channel to check
* \return a value between zero and one
*/
float getColor(float x, float y, ColourUsage color) const;
/*!
* print out something which looks like the picture through std::cerr
* \param double_width Whether to double each character being written, so that the width is visually similar to the height of each pixel.
*/
void debugOutput(bool double_width = true) const;
protected:
unsigned char* data; //!< pixel data in rgb-row-first (or bgr-row first ?)
unsigned int width, height, depth; //!< image dimensions
/*!
* Get a color value from the data
* \param x place in the horizontal direction left to right (value between zero and one)
* \param y place in the vertical direction top to bottom (value between zero and one)
* \return the color data (0-256)
*/
float getColorData(float x, float y, unsigned int z) const;
};
} // namespace cura
#endif // MATERIAL_H
-42
Ver Arquivo
@@ -1,42 +0,0 @@
/** Copyright (C) 2016 Tim Kuipers - Released under terms of the AGPLv3 License */
#include "MaterialBase.h"
namespace cura
{
Material* MaterialBase::add(std::string name)
{
name_to_mat_idx[name] = materials.size();
materials.emplace_back();
return &materials.back();
}
const Material* MaterialBase::getMat(unsigned int id) const
{
if (id < materials.size())
{
return &materials[id];
}
else
{
return nullptr;
}
}
int MaterialBase::getMatId(std::string name) const
{
auto it = name_to_mat_idx.find(name);
if (it == name_to_mat_idx.end())
{
return -1;
}
else
{
return it->second;
}
}
} // namespace cura
-27
Ver Arquivo
@@ -1,27 +0,0 @@
/** Copyright (C) 2016 Tim Kuipers - Released under terms of the AGPLv3 License */
#ifndef MATERIAL_BASE_H
#define MATERIAL_BASE_H
#include <unordered_map>
#include <string>
#include <vector>
#include "Material.h"
namespace cura
{
class MaterialBase
{
public:
int getMatId(std::string name) const;
Material* add(std::string name);
const Material* getMat(unsigned int id) const;
protected:
std::unordered_map<std::string, int> name_to_mat_idx;
std::vector<Material> materials;
};
} // namespace cura
#endif // MATERIAL_BASE_H
+22 -183
Ver Arquivo
@@ -3,9 +3,6 @@
#include <strings.h>
#include <stdio.h>
#define STB_IMAGE_IMPLEMENTATION // needed in order to enable the implementation of libs/std_image.h
#include "stb/stb_image.h"
#include "MeshGroup.h"
#include "utils/gettime.h"
#include "utils/logoutput.h"
@@ -28,10 +25,6 @@ void* fgets_(char* ptr, size_t len, FILE* f)
*ptr = '\0';
return ptr;
}
else if (*ptr =='\0')
{
return ptr;
}
ptr++;
len--;
}
@@ -52,10 +45,6 @@ MeshGroup::~MeshGroup()
delete extruders[extruder];
}
}
for (Mesh* mesh : meshes)
{
delete mesh;
}
}
int MeshGroup::getExtruderCount() const
@@ -101,10 +90,10 @@ Point3 MeshGroup::min() const
{
return Point3(0, 0, 0);
}
Point3 ret = meshes[0]->min();
for (unsigned int i = 1; i < meshes.size(); i++)
Point3 ret = meshes[0].min();
for(unsigned int i=1; i<meshes.size(); i++)
{
Point3 v = meshes[i]->min();
Point3 v = meshes[i].min();
ret.x = std::min(ret.x, v.x);
ret.y = std::min(ret.y, v.y);
ret.z = std::min(ret.z, v.z);
@@ -118,10 +107,10 @@ Point3 MeshGroup::max() const
{
return Point3(0, 0, 0);
}
Point3 ret = meshes[0]->max();
for (unsigned int i = 1; i < meshes.size(); i++)
Point3 ret = meshes[0].max();
for(unsigned int i=1; i<meshes.size(); i++)
{
Point3 v = meshes[i]->max();
Point3 v = meshes[i].max();
ret.x = std::max(ret.x, v.x);
ret.y = std::max(ret.y, v.y);
ret.z = std::max(ret.z, v.z);
@@ -131,9 +120,9 @@ Point3 MeshGroup::max() const
void MeshGroup::clear()
{
for (Mesh* m : meshes)
for(Mesh& m : meshes)
{
m->clear();
m.clear();
}
}
@@ -151,9 +140,9 @@ void MeshGroup::finalize()
continue;
}
for (const Mesh* mesh : meshes)
for (const Mesh& mesh : meshes)
{
if (mesh->getSettingBoolean("support_enable")
if (mesh.getSettingBoolean("support_enable")
&& (
getSettingAsIndex("support_infill_extruder_nr") == extruder_nr
|| getSettingAsIndex("support_extruder_nr_layer_0") == extruder_nr
@@ -167,13 +156,13 @@ void MeshGroup::finalize()
}
}
for (const Mesh* mesh : meshes)
for (const Mesh& mesh : meshes)
{
if (!mesh->getSettingBoolean("anti_overhang_mesh")
&& !mesh->getSettingBoolean("support_mesh")
if (!mesh.getSettingBoolean("anti_overhang_mesh")
&& !mesh.getSettingBoolean("support_mesh")
)
{
getExtruderTrain(mesh->getSettingAsIndex("extruder_nr"))->setIsUsed(true);
getExtruderTrain(mesh.getSettingAsIndex("extruder_nr"))->setIsUsed(true);
}
}
@@ -186,17 +175,17 @@ void MeshGroup::finalize()
}
// If a mesh position was given, put the mesh at this position in 3D space.
for (Mesh* mesh : meshes)
for(Mesh& mesh : meshes)
{
Point3 mesh_offset(mesh->getSettingInMicrons("mesh_position_x"), mesh->getSettingInMicrons("mesh_position_y"), mesh->getSettingInMicrons("mesh_position_z"));
if (mesh->getSettingBoolean("center_object"))
Point3 mesh_offset(mesh.getSettingInMicrons("mesh_position_x"), mesh.getSettingInMicrons("mesh_position_y"), mesh.getSettingInMicrons("mesh_position_z"));
if (mesh.getSettingBoolean("center_object"))
{
Point3 object_min = mesh->min();
Point3 object_max = mesh->max();
Point3 object_min = mesh.min();
Point3 object_max = mesh.max();
Point3 object_size = object_max - object_min;
mesh_offset += Point3(-object_min.x - object_size.x / 2, -object_min.y - object_size.y / 2, -object_min.z);
}
mesh->offset(mesh_offset + meshgroup_offset);
mesh.offset(mesh_offset + meshgroup_offset);
}
}
@@ -340,138 +329,6 @@ bool loadMeshSTL(Mesh* mesh, const char* filename, const FMatrix3x3& matrix)
return loadMeshSTL_binary(mesh, filename, matrix);
}
void loadMatImage(Material* mat, const char* filename)
{
int width;
int height;
int depth;
// in RGBA order
unsigned char* data = stbi_load(filename, &width, &height, &depth, 0);
if (data)
{
mat->setData(data);
mat->setDimensions(width, height, depth);
}
else
{
logError("Cannot load image %s.", filename);
}
}
void loadMaterialBase(TexturedMesh* mesh, const char* filename)
{
FILE* f = fopen(filename, "rt");
if (f == nullptr)
{
logError("ERROR: Couldn't load MTL file %s.\n", filename);
return;
}
char buffer[1024];
char mat_name [100];
char mat_file [100];
char map_type [10];
Material* last_mat = nullptr;
while(fgets_(buffer, sizeof(buffer), f))
{
if (buffer[0] == '#')
{
continue;
}
if (sscanf(buffer, "map_%s %s", map_type, mat_file) == 2 // we don't care what type of map it specifies (currently)
|| sscanf(buffer, "bump %s", mat_file) == 1
|| sscanf(buffer, "disp %s", mat_file) == 1
|| sscanf(buffer, "decal %s", mat_file) == 1
|| sscanf(buffer, "refl %s", mat_file) == 1
)
{
std::string parent_dir = std::string(filename).substr(0, std::string(filename).find_last_of("/\\"));
std::string mtl_file = parent_dir + "/" + mat_file;
if (last_mat)
{
loadMatImage(last_mat, mtl_file.c_str());
}
}
else if (sscanf(buffer, "newmtl %s", mat_name) == 1)
{
last_mat = mesh->addMaterial(mat_name);
}
}
fclose(f);
}
bool loadMeshOBJ(TexturedMesh* mesh, const char* filename, const FMatrix3x3& matrix)
{
FILE* f = fopen(filename, "rt");
if (f == nullptr)
{
return false;
}
char buffer[1024];
FPoint3 vertex;
Point3 vertex_indices;
float texture_x;
float texture_y;
float temp;
char face_index_buffer_1 [100];
char face_index_buffer_2 [100];
char face_index_buffer_3 [100];
char str_buffer [100];
while(fgets_(buffer, sizeof(buffer), f))
{
if (buffer[0] == '#')
{
continue;
}
if (sscanf(buffer, "v %f %f %f", &vertex.x, &vertex.y, &vertex.z) == 3)
{
Point3 v = matrix.apply(vertex);
mesh->addVertex(v);
}
else if (sscanf(buffer, "vt %f %f", &texture_x, &texture_y) == 2)
{
mesh->addTextureCoord(texture_x, texture_y);
}
else if (sscanf(buffer, "f %s %s %s", face_index_buffer_1, face_index_buffer_2, face_index_buffer_3) == 3)
{
int normal_vector_index; // unused
Point3 texture_indices(0, 0, 0); // becomes -1 if no texture data supplied
int n_scanned_1 = sscanf(face_index_buffer_1, "%d/%d/%d", &vertex_indices.x, &texture_indices.x, &normal_vector_index);
int n_scanned_2 = sscanf(face_index_buffer_2, "%d/%d/%d", &vertex_indices.y, &texture_indices.y, &normal_vector_index);
int n_scanned_3 = sscanf(face_index_buffer_3, "%d/%d/%d", &vertex_indices.z, &texture_indices.z, &normal_vector_index);
if (n_scanned_1 > 0 && n_scanned_2 > 0 && n_scanned_3 > 0)
{
mesh->addFace(vertex_indices.x - 1, vertex_indices.y - 1, vertex_indices.z - 1, texture_indices.x - 1, texture_indices.y - 1, texture_indices.z - 1);
// obj files count vertex indices starting from 1!
}
}
else if (sscanf(buffer, "mtllib %s", str_buffer) == 1)
{
std::string parent_dir = std::string(filename).substr(0, std::string(filename).find_last_of("/\\"));
std::string mtl_file = parent_dir + "/" + str_buffer;
loadMaterialBase(mesh, mtl_file.c_str());
}
else if (sscanf(buffer, "usemtl %s", str_buffer) == 1)
{
mesh->setMaterial(str_buffer);
}
else if (sscanf(buffer, "vn %f %f %f", &temp, &temp, &temp) == 3)
{
// do nothing
}
else if (buffer[0] == '\0')
{
// empty line, do nothing
}
else
{
logError("Cannot parse line \"%s\"\n", buffer);
}
}
fclose(f);
mesh->finish();
return true;
}
bool loadMeshIntoMeshGroup(MeshGroup* meshgroup, const char* filename, const FMatrix3x3& transformation, SettingsBaseVirtual* object_parent_settings)
{
TimeKeeper load_timer;
@@ -479,32 +336,14 @@ bool loadMeshIntoMeshGroup(MeshGroup* meshgroup, const char* filename, const FMa
const char* ext = strrchr(filename, '.');
if (ext && (strcmp(ext, ".stl") == 0 || strcmp(ext, ".STL") == 0))
{
Mesh* mesh = new Mesh(object_parent_settings ? object_parent_settings : meshgroup); //If we have object_parent_settings, use them as parent settings. Otherwise, just use meshgroup.
if (loadMeshSTL(mesh,filename,transformation)) //Load it! If successful...
Mesh mesh = object_parent_settings ? Mesh(object_parent_settings) : Mesh(meshgroup); //If we have object_parent_settings, use them as parent settings. Otherwise, just use meshgroup.
if(loadMeshSTL(&mesh,filename,transformation)) //Load it! If successful...
{
meshgroup->meshes.push_back(mesh);
log("loading '%s' took %.3f seconds\n",filename,load_timer.restart());
return true;
}
else
{
delete mesh;
}
}
else if (ext && (strcmp(ext, ".obj") == 0 || strcmp(ext, ".OBJ") == 0))
{
TexturedMesh* mesh = new TexturedMesh(object_parent_settings ? object_parent_settings : meshgroup); //If we have object_parent_settings, use them as parent settings. Otherwise, just use meshgroup.
if (loadMeshOBJ(mesh,filename,transformation)) //Load it! If successful...
{
meshgroup->meshes.push_back(mesh);
return true;
}
else
{
delete mesh;
}
}
return false;
}
+1 -2
Ver Arquivo
@@ -4,7 +4,6 @@
#include "utils/NoCopy.h"
#include "mesh.h"
#include "TexturedMesh.h"
#include "ExtruderTrain.h"
namespace cura
@@ -36,7 +35,7 @@ public:
const ExtruderTrain* getExtruderTrain(unsigned int extruder_nr) const;
std::vector<Mesh*> meshes;
std::vector<Mesh> meshes;
Point3 min() const; //! minimal corner of bounding box
Point3 max() const; //! maximal corner of bounding box
-1
Ver Arquivo
@@ -179,7 +179,6 @@ void PrimeTower::addToGcode_denseInfill(GCodePlanner& gcodeLayer, const int laye
gcodeLayer.addPolygonsByOptimizer(pattern.polygons, &config);
gcodeLayer.addLinesByOptimizer(pattern.lines, &config, SpaceFillType::Lines);
last_prime_tower_poly_printed[extruder] = layer_nr;
}
+5 -1
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)
@@ -73,7 +77,7 @@ int SkirtBrim::generatePrimarySkirtBrimLines(SliceDataStorage& storage, int star
//Remove small inner skirt and brim holes. Holes have a negative area, remove anything smaller then 100x extrusion "area"
for (unsigned int n = 0; n < outer_skirt_brim_line.size(); n++)
{
double area = outer_skirt_brim_line[n].area();
double area = PolygonRef{outer_skirt_brim_line[n]}.area();
if (area < 0 && area > -primary_extruder_skirt_brim_line_width * primary_extruder_skirt_brim_line_width * 100)
{
outer_skirt_brim_line.remove(n--);
-141
Ver Arquivo
@@ -1,141 +0,0 @@
#include "TextureProcessor.h"
#include <algorithm> // swap
#include "utils/optional.h"
#include "slicer/SlicerSegment.h"
namespace cura
{
#define POINT_DIST 400
#define AMPLITUDE 3000
#define EXTRA_OFFSET 3000
/*
void TextureProcessor::process(std::vector< Slicer* >& slicer_list)
{
for (Slicer* slicer : slicer_list)
{
for (SlicerLayer& layer : slicer->layers)
{
process(slicer->mesh, layer);
}
}
}
*/
void TextureProcessor::processSegmentBumpMap(const Mesh* mesh, const SlicerSegment& slicer_segment, const MatSegment& mat, const Point p0, const Point p1, coord_t& dist_left_over, PolygonRef result)
{
MatCoord mat_start = mat.start;
MatCoord mat_end = mat.end;
if (vSize2(slicer_segment.start - p0) > vSize2(slicer_segment.start - p1))
{
std::swap(mat_start, mat_end);
}
Point p0p1 = p1 - p0;
int64_t p0p1_size = vSize(p0p1);
if (dist_left_over >= p0p1_size)
{
dist_left_over -= p0p1_size;
return;
}
Point perp_to_p0p1 = turn90CCW(p0p1);
int64_t dist_last_point = -1; // p0p1_size * 2 - dist_left_over; // so that p0p1_size - dist_last_point evaulates to dist_left_over - p0p1_size
// TODO: move start point (which was already moved last iteration
for (int64_t p0pa_dist = dist_left_over; p0pa_dist < p0p1_size; p0pa_dist += POINT_DIST)
{
assert(p0pa_dist >= 0);
assert(p0pa_dist <= p0p1_size);
MatCoord mat_coord_now = mat_start;
mat_coord_now.coords = mat_start.coords + (mat_end.coords - mat_start.coords) * p0pa_dist / p0p1_size;
float val = mesh->getColor(mat_coord_now, ColourUsage::GREY);
int offset = val * (AMPLITUDE * 2) - AMPLITUDE + EXTRA_OFFSET;
Point fuzz = normal(perp_to_p0p1, offset);
Point pa = p0 + normal(p0p1, p0pa_dist) - fuzz;
result.add(pa);
dist_last_point = p0pa_dist;
}
// TODO: move end point as well
float val = mesh->getColor(mat_end, ColourUsage::GREY);
int r = val * (AMPLITUDE * 2) - AMPLITUDE + EXTRA_OFFSET;
Point fuzz = normal(perp_to_p0p1, r);
result.emplace_back(p1 - fuzz);
assert(dist_last_point >= 0 && "above loop should have run at least once!");
assert(p0p1_size > dist_last_point);
dist_left_over = p0p1_size - dist_last_point;
assert(dist_left_over <= POINT_DIST);
}
void TextureProcessor::processBumpMap(const Mesh* mesh, SlicerLayer& layer)
{
Polygons results;
for (PolygonRef poly : layer.polygons)
{
// generate points in between p0 and p1
PolygonRef result = results.newPoly();
coord_t dist_left_over = (POINT_DIST / 2); // the distance to be traversed on the line before making the first new point
Point* p0 = &poly.back();
for (Point& p1 : poly)
{ // 'a' is the (next) new point between p0 and p1
if (*p0 == p1)
{
continue;
}
SlicerSegment segment(*p0, p1);
std::optional<std::pair<SlicerSegment, MatSegment>> best_mat_segment_it;
coord_t best_dist_score = std::numeric_limits<coord_t>::max();
for (std::unordered_map<SlicerSegment, MatSegment>::iterator it = layer.segment_to_material_segment.begin(); it != layer.segment_to_material_segment.end(); ++it)
{
const SlicerSegment& sliced_segment = it->first;
coord_t dist_score = std::min(
vSize2(sliced_segment.start - segment.start) + vSize2(sliced_segment.end - segment.end)
, vSize2(sliced_segment.end - segment.start) + vSize2(sliced_segment.start - segment.end)
);
if (dist_score < best_dist_score)
{
best_dist_score = dist_score;
best_mat_segment_it = *it;
}
}
if (best_dist_score < 30 * 30) // TODO: magic value of 0.03mm for total stitching distance > should be something like SlicerLayer.cpp::largest_neglected_gap_second_phase (?)
{
assert(best_mat_segment_it);
processSegmentBumpMap(mesh, best_mat_segment_it->first, best_mat_segment_it->second, *p0, p1, dist_left_over, result);
}
else
{
result.emplace_back(p1);
}
p0 = &p1;
}
while (result.size() < 3 )
{
unsigned int point_idx = poly.size() - 2;
result.add(poly[point_idx]);
if (point_idx == 0) { break; }
point_idx--;
}
if (result.size() < 3)
{
result.clear();
for (Point& p : poly)
result.add(p);
}
}
// a negative offset on two sides of a corner, may introduce complexities in the model which should be removed:
// ^↘
// ^ ↘
// <<<<<<<<^<<<< should become <<<<<<<<
// ^ ^
// ^ ^
// ^ ^
layer.polygons = results.removeComplexParts();
}
}//namespace cura
-25
Ver Arquivo
@@ -1,25 +0,0 @@
/** Copyright (C) 2016 Tim Kuipers - Released under terms of the AGPLv3 License */
#ifndef TEXTURE_PROCESSOR_H
#define TEXTURE_PROCESSOR_H
#include <vector>
#include "slicer/Slicer.h"
#include "mesh.h"
namespace cura
{
class TextureProcessor
{
public:
// static void process(std::vector<Slicer*>& slicer_list);
static void processBumpMap(const Mesh* mesh, SlicerLayer& layer);
protected:
static void processSegmentBumpMap(const Mesh* mesh, const SlicerSegment& slicer_segment, const MatSegment& mat, const Point p0, const Point p1, coord_t& dist_left_over, PolygonRef result);
};
} // namespace cura
#endif // TEXTURE_PROCESSOR_H
-137
Ver Arquivo
@@ -1,137 +0,0 @@
/** Copyright (C) 2016 Tim Kuipers - Released under terms of the AGPLv3 License */
#include "TexturedMesh.h"
#include <cassert>
#include "utils/logoutput.h"
namespace cura
{
TexturedMesh::TexturedMesh(SettingsBaseVirtual* sb)
: Mesh(sb)
, current_mat(-1) // not set yet
{
}
void TexturedMesh::addTextureCoord(float x, float y)
{
texture_coords.emplace_back(x, y);
}
void TexturedMesh::addFace(int vi0, int vi1, int vi2, int ti0, int ti1, int ti2)
{
if (vi0 < -1)
{
vi0 = Mesh::faces.size() + vi0 + 1; // + 1 because of relative indexing doesn't start counting from 1
}
if (vi1 < -1)
{
vi1 = Mesh::faces.size() + vi0 + 1; // + 1 because of relative indexing doesn't start counting from 1
}
if (vi2 < -1)
{
vi2 = Mesh::faces.size() + vi0 + 1; // + 1 because of relative indexing doesn't start counting from 1
}
if (ti0 < -1)
{
ti0 = texture_coords.size() + vi0 + 1; // + 1 because of relative indexing doesn't start counting from 1
}
if (ti1 < -1)
{
ti1 = texture_coords.size() + vi0 + 1; // + 1 because of relative indexing doesn't start counting from 1
}
if (ti2 < -1)
{
ti2 = texture_coords.size() + vi0 + 1; // + 1 because of relative indexing doesn't start counting from 1
}
bool made_new_face = Mesh::addFace(vi0, vi1, vi2);
if (made_new_face)
{
face_texture_indices.emplace_back(ti0, ti1, ti2, current_mat);
assert(Mesh::faces.size() == face_texture_indices.size());
}
}
bool TexturedMesh::setMaterial(std::string name)
{
current_mat = material_base.getMatId(name);
return current_mat >= 0;
}
Material* TexturedMesh::addMaterial(std::__cxx11::string name)
{
return material_base.add(name);
}
bool TexturedMesh::getFaceEdgeMatCoord(unsigned int face_idx, int64_t z, unsigned int p0_idx, unsigned int p1_idx, MatCoord& result) const
{
if (face_idx >= face_texture_indices.size() || face_idx >= faces.size())
{
return false;
}
FaceTextureCoordIndices texture_idxs = face_texture_indices[face_idx];
if (texture_idxs.index[0] < 0 || texture_idxs.index[1] < 0 || texture_idxs.index[2] < 0 || texture_idxs.mat_id < 0)
{
return false;
}
const MeshFace& face = faces[face_idx];
Point3 p0(vertices[face.vertex_index[p0_idx]].p);
Point3 p1(vertices[face.vertex_index[p1_idx]].p);
float dzp0 = z - p0.z;
float dp0p1 = p1.z - p0.z;
if (dzp0 * dp0p1 < 0)
{ // z doesn't lie between p0 and p1
return false;
}
if (dzp0 == 0)
{ // edge is not cut by horizontal plane!
return false;
}
float ratio = INT2MM(dzp0) / INT2MM(dp0p1);
FPoint t0 = texture_coords[texture_idxs.index[p0_idx]];
FPoint t1 = texture_coords[texture_idxs.index[p1_idx]];
result.mat_id = texture_idxs.mat_id;
result.coords.x = t0.x + (t1.x - t0.x) * ratio;
result.coords.y = t0.y + (t1.y - t0.y) * ratio;
if (result.coords.x > 1.001 || result.coords.x < -0.001 || result.coords.y > 1.001 || result.coords.y < -0.001)
{
logError("WARNING: wapping material to outside image!");
}
return true;
}
bool TexturedMesh::registerFaceSlice(unsigned int face_idx, unsigned int idx_shared, unsigned int idx_first, unsigned int idx_second, int32_t z, Point segment_start, Point segment_end, MatSegment& result) const
{
if (!getFaceEdgeMatCoord(face_idx, z, idx_shared, idx_first, result.start))
{
return false;
}
if (!getFaceEdgeMatCoord(face_idx, z, idx_shared, idx_second, result.end))
{
return false;
}
return true;
}
float TexturedMesh::getColor(MatCoord bitmap_coord, ColourUsage color) const
{
const Material* mat = material_base.getMat(bitmap_coord.mat_id);
if (mat)
{
return mat->getColor(bitmap_coord.coords.x, bitmap_coord.coords.y, color);
}
else
{
return 0.0f;
}
}
} // namespace cura
-78
Ver Arquivo
@@ -1,78 +0,0 @@
/** Copyright (C) 2016 Tim Kuipers - Released under terms of the AGPLv3 License */
#ifndef TEXTURED_MESH_H
#define TEXTURED_MESH_H
#include <vector>
#include <string>
#include "MaterialBase.h"
#include "mesh.h"
#include "utils/intpoint.h"
#include "MatSegment.h"
namespace cura
{
/*!
* A mesh with bitmap textures to it.
*
* material coordinates are defined separately, and can be reused for different bitmap textures
*/
class TexturedMesh : public Mesh
{
public:
TexturedMesh(SettingsBaseVirtual* sb);
/*!
*
*/
struct FaceTextureCoordIndices
{
int index[3]; //!< indices into texture_coords or -1 if no texture data available
int mat_id; //!< Material id
FaceTextureCoordIndices(int i1, int i2, int i3, int mat_id)
: mat_id(mat_id)
{
index[0] = i1;
index[1] = i2;
index[2] = i3;
}
};
void addTextureCoord(float x, float y);
void addFace(int vi0, int vi1, int vi2, int ti0, int ti1, int ti2);
using Mesh::addFace; // otherwise above addFace would shadow the parent addFace
bool setMaterial(std::string name); //!< set the material to be used in the comming data to be loaded
Material* addMaterial(std::string name);
virtual bool registerFaceSlice(unsigned int face_idx, unsigned int idx_shared, unsigned int idx_first, unsigned int idx_second, int32_t z, Point segment_start, Point segment_end, MatSegment& result) const;
protected:
std::vector<FPoint> texture_coords; //!< all texture coordinates by all faces
std::vector<FaceTextureCoordIndices> face_texture_indices; //!< for each face the corresponding texture coordinates in TexturedMesh::texture_coords
// TODO clean up above lists when super class clear() is called
// TODO when to clean up below material base?
MaterialBase material_base;
/*!
* Get the material coordinate corresponding to the point on a plane cutting a given edge of the face.
* \param face_idx The face for which to get the material coord
* \param z The z of the horizontal plane cutting the face
* \param p0_idx The index into the first vert of the edge
* \param p1_idx The index into the second vert of the edge
* \param result The resulting material Coordinates
* \return Whether a Material coordinate is defined at the given location
*/
bool getFaceEdgeMatCoord(unsigned int face_idx, int64_t z, unsigned int p0_idx, unsigned int p1_idx, MatCoord& result) const;
virtual float getColor(MatCoord bitmap_coord, ColourUsage color) const;
private:
int current_mat; //!< material currently used in loading the face material info
};
} // namespace cura
#endif // TEXTURED_MESH_H
+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++)
+8 -8
Ver Arquivo
@@ -23,9 +23,9 @@ void Weaver::weave(MeshGroup* meshgroup)
std::vector<cura::Slicer*> slicerList;
for (Mesh* mesh : meshgroup->meshes)
for(Mesh& mesh : meshgroup->meshes)
{
cura::Slicer* slicer = new cura::Slicer(mesh, initial_layer_thickness, connectionHeight, layer_count, mesh->getSettingBoolean("meshfix_keep_open_polygons"), mesh->getSettingBoolean("meshfix_extensive_stitching"));
cura::Slicer* slicer = new cura::Slicer(&mesh, initial_layer_thickness, connectionHeight, layer_count, mesh.getSettingBoolean("meshfix_keep_open_polygons"), mesh.getSettingBoolean("meshfix_extensive_stitching"));
slicerList.push_back(slicer);
}
@@ -209,11 +209,11 @@ void Weaver::fillRoofs(Polygons& supporting, Polygons& to_be_supported, int dire
std::vector<PolygonsPart> roof_parts = roofs.splitIntoParts();
for (PolygonsPart& roof_part : roof_parts)
{
roof_outlines.add(roof_part[0]);
roof_outlines.add(PolygonRef{roof_part[0]});
for (unsigned int hole_idx = 1; hole_idx < roof_part.size(); hole_idx++)
{
roof_holes.add(roof_part[hole_idx]);
roof_holes.back().reverse();
roof_holes.add(PolygonRef{roof_part[hole_idx]});
PolygonRef{roof_holes.back()}.reverse();
}
}
}
@@ -223,7 +223,7 @@ void Weaver::fillRoofs(Polygons& supporting, Polygons& to_be_supported, int dire
std::vector<PolygonsPart> supporting_parts = supporting.splitIntoParts();
for (PolygonsPart& supporting_part : supporting_parts)
supporting_outlines.add(supporting_part[0]); // only add outlines, not the holes
supporting_outlines.add(PolygonRef{supporting_part[0]}); // only add outlines, not the holes
@@ -274,10 +274,10 @@ void Weaver::fillFloors(Polygons& supporting, Polygons& to_be_supported, int dir
Polygons floor_holes;
for (PolygonsPart& floor_part : floor_parts)
{
floor_outlines.add(floor_part[0]);
floor_outlines.add(PolygonRef{floor_part[0]});
for (unsigned int hole_idx = 1; hole_idx < floor_part.size(); hole_idx++)
{
floor_holes.add(floor_part[hole_idx]);
floor_holes.add(PolygonRef{floor_part[hole_idx]});
//floor_holes.back().reverse();
}
}
+1 -1
Ver Arquivo
@@ -6,7 +6,7 @@
#include "settings/settings.h"
#include "MeshGroup.h"
#include "slicer/Slicer.h"
#include "slicer.h"
#include "utils/NoCopy.h"
#include "utils/polygon.h"
+1 -1
Ver Arquivo
@@ -11,7 +11,7 @@
#include "settings/settings.h"
#include "MeshGroup.h"
#include "slicer/Slicer.h"
#include "slicer.h"
#include "utils/polygon.h"
#include "Weaver.h"
+5 -5
Ver Arquivo
@@ -5,7 +5,7 @@
namespace cura {
int bridgeAngle(Polygons outline, SliceLayer* prevLayer)
int bridgeAngle(Polygons outline, const SliceLayer* prevLayer)
{
AABB boundaryBox(outline);
//To detect if we have a bridge, first calculate the intersection of the current layer with the previous layer.
@@ -29,9 +29,9 @@ int bridgeAngle(Polygons outline, SliceLayer* prevLayer)
for(unsigned int n=0; n<islands.size(); n++)
{
//Skip internal holes
if (!islands[n].orientation())
if (!PolygonRef{islands[n]}.orientation())
continue;
double area = fabs(islands[n].area());
double area = fabs(PolygonRef{islands[n]}.area());
if (area > area1)
{
if (area1 > area2)
@@ -51,8 +51,8 @@ int bridgeAngle(Polygons outline, SliceLayer* prevLayer)
if (idx1 < 0 || idx2 < 0)
return -1;
Point center1 = islands[idx1].centerOfMass();
Point center2 = islands[idx2].centerOfMass();
Point center1 = PolygonRef{islands[idx1]}.centerOfMass();
Point center2 = PolygonRef{islands[idx2]}.centerOfMass();
return angle(center2 - center1);
}
+1 -1
Ver Arquivo
@@ -6,7 +6,7 @@ namespace cura {
class Polygons;
class SliceLayer;
int bridgeAngle(Polygons outline, SliceLayer* prevLayer);
int bridgeAngle(Polygons outline, const SliceLayer* prevLayer);
}//namespace cura
+7 -7
Ver Arquivo
@@ -215,7 +215,7 @@ public:
/*!
* Adds closed polygon to the current path
*/
void sendPolygon(PrintFeatureType print_feature_type, Polygon poly, int width);
void sendPolygon(PrintFeatureType print_feature_type, ConstPolygonRef poly, int width);
private:
/*!
* Convert and add a point to the points buffer, each point being represented as two consecutive floats. All members adding a 2D point to the data should use this function.
@@ -346,9 +346,9 @@ void CommandSocket::connect(const std::string& ip, int port)
continue;
}
const ExtruderTrain* settings_base = meshgroup->getExtruderTrain(extruder_nr); //The extruder train that the setting should fall back to.
for (Mesh* mesh : meshgroup->meshes)
for (Mesh& mesh : meshgroup->meshes)
{
mesh->setSettingInheritBase(setting_extruder.name(), *settings_base);
mesh.setSettingInheritBase(setting_extruder.name(), *settings_base);
}
}
}
@@ -455,8 +455,8 @@ void CommandSocket::handleObjectList(cura::proto::ObjectList* list, const google
}
SettingsBase* extruder_train = meshgroup->getExtruderTrain(extruder_train_nr);
meshgroup->meshes.push_back(new Mesh(extruder_train)); //Construct a new mesh (with the corresponding extruder train as settings parent object) and put it into MeshGroup's mesh list.
Mesh& mesh = *meshgroup->meshes.back();
meshgroup->meshes.push_back(extruder_train); //Construct a new mesh (with the corresponding extruder train as settings parent object) and put it into MeshGroup's mesh list.
Mesh& mesh = meshgroup->meshes.back();
for (int i = 0; i < face_count; ++i)
{
@@ -522,7 +522,7 @@ void CommandSocket::sendPolygons(PrintFeatureType type, const Polygons& polygons
#endif
}
void CommandSocket::sendPolygon(PrintFeatureType type, Polygon& polygon, int line_width)
void CommandSocket::sendPolygon(PrintFeatureType type, ConstPolygonRef polygon, int line_width)
{
#ifdef ARCUS
if (CommandSocket::isInstantiated())
@@ -797,7 +797,7 @@ void CommandSocket::PathCompiler::sendLineTo(PrintFeatureType print_feature_type
}
}
void CommandSocket::PathCompiler::sendPolygon(PrintFeatureType print_feature_type, Polygon polygon, int width)
void CommandSocket::PathCompiler::sendPolygon(PrintFeatureType print_feature_type, ConstPolygonRef polygon, int width)
{
if (polygon.size() < 2)
{
+1 -1
Ver Arquivo
@@ -64,7 +64,7 @@ public:
/*!
* Send a polygon to the front-end. This is used for the layerview in the GUI
*/
static void sendPolygon(cura::PrintFeatureType type, Polygon& polygon, int line_width);
static void sendPolygon(cura::PrintFeatureType type, ConstPolygonRef polygon, int line_width);
/*!
* Send a line to the front-end. This is used for the layerview in the GUI
+24 -43
Ver Arquivo
@@ -1,7 +1,4 @@
//Copyright (c) 2013 David Braam
//Copyright (c) 2016 Ultimaker B.V.
//CuraEngine is released under the terms of the AGPLv3 or higher.
/** Copyright (C) 2013 David Braam - Released under terms of the AGPLv3 License */
#include <stdarg.h>
#include <iomanip>
#include <cmath>
@@ -14,6 +11,8 @@
namespace cura {
double layer_height; //!< report basic layer height in RepRap gcode file.
GCodeExport::GCodeExport()
: output_stream(&std::cout)
, currentPosition(0,0,MM2INT(20))
@@ -52,13 +51,13 @@ void GCodeExport::preSetup(const MeshGroup* meshgroup)
extruder_count = meshgroup->getSettingAsCount("machine_extruder_count");
for (const Mesh* mesh : meshgroup->meshes)
for (const Mesh& mesh : meshgroup->meshes)
{
if (!mesh->getSettingBoolean("anti_overhang_mesh")
&& !mesh->getSettingBoolean("support_mesh")
if (!mesh.getSettingBoolean("anti_overhang_mesh")
&& !mesh.getSettingBoolean("support_mesh")
)
{
extruder_attr[mesh->getSettingAsIndex("extruder_nr")].is_used = true;
extruder_attr[mesh.getSettingAsIndex("extruder_nr")].is_used = true;
}
}
@@ -70,11 +69,11 @@ void GCodeExport::preSetup(const MeshGroup* meshgroup)
{
extruder_attr[extruder_nr].is_used = true;
}
for (const Mesh* mesh : meshgroup->meshes)
for (const Mesh& mesh : meshgroup->meshes)
{
if ((mesh->getSettingBoolean("support_enable") && mesh->getSettingBoolean("support_interface_enable") && meshgroup->getSettingAsIndex("support_interface_extruder_nr") == int(extruder_nr))
|| (mesh->getSettingBoolean("support_enable") && meshgroup->getSettingAsIndex("support_infill_extruder_nr") == int(extruder_nr))
|| (mesh->getSettingBoolean("support_enable") && meshgroup->getSettingAsIndex("support_extruder_nr_layer_0") == int(extruder_nr))
if ((mesh.getSettingBoolean("support_enable") && mesh.getSettingBoolean("support_interface_enable") && meshgroup->getSettingAsIndex("support_interface_extruder_nr") == int(extruder_nr))
|| (mesh.getSettingBoolean("support_enable") && meshgroup->getSettingAsIndex("support_infill_extruder_nr") == int(extruder_nr))
|| (mesh.getSettingBoolean("support_enable") && meshgroup->getSettingAsIndex("support_extruder_nr_layer_0") == int(extruder_nr))
)
{
extruder_attr[extruder_nr].is_used = true;
@@ -84,7 +83,7 @@ void GCodeExport::preSetup(const MeshGroup* meshgroup)
extruder_attr[extruder_nr].prime_pos = Point3(train->getSettingInMicrons("extruder_prime_pos_x"), train->getSettingInMicrons("extruder_prime_pos_y"), train->getSettingInMicrons("extruder_prime_pos_z"));
extruder_attr[extruder_nr].prime_pos_is_abs = train->getSettingBoolean("extruder_prime_pos_abs");
extruder_attr[extruder_nr].park_distance = train->getSettingInMillimeters("machine_filament_park_distance");
extruder_attr[extruder_nr].nozzle_size = train->getSettingInMicrons("machine_nozzle_size");
extruder_attr[extruder_nr].nozzle_offset = Point(train->getSettingInMicrons("machine_nozzle_offset_x"), train->getSettingInMicrons("machine_nozzle_offset_y"));
extruder_attr[extruder_nr].material_guid = train->getSettingString("material_guid");
@@ -100,6 +99,8 @@ void GCodeExport::preSetup(const MeshGroup* meshgroup)
machine_name = meshgroup->getSettingString("machine_name");
layer_height = meshgroup->getSettingInMillimeters("layer_height");
if (flavor == EGCodeFlavor::BFB)
{
new_line = "\r\n";
@@ -197,6 +198,7 @@ std::string GCodeExport::getFileHeader(const double* print_time, const std::vect
else if (flavor == EGCodeFlavor::REPRAP)
{
prefix << ";Filament used: " << ((filament_used.size() >= 1)? filament_used[0] / (1000 * extruder_attr[0].filament_area) : 0) << "m" << new_line;
prefix << ";Layer height: " << layer_height << new_line;
}
return prefix.str();
}
@@ -554,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!");
@@ -568,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)
{
@@ -689,11 +690,12 @@ void GCodeExport::writeRetraction(const RetractionConfig& config, bool force, bo
extruded_volume_at_previous_n_retractions.pop_back();
}
}
if (firmware_retract)
{
if (extruder_switch && extr_attr.retraction_e_amount_current)
if (extruder_switch && extr_attr.retraction_e_amount_current)
{
return;
return;
}
*output_stream << "G10";
if (extruder_switch)
@@ -704,20 +706,6 @@ void GCodeExport::writeRetraction(const RetractionConfig& config, bool force, bo
//Assume default UM2 retraction settings.
estimateCalculator.plan(TimeEstimateCalculator::Position(INT2MM(currentPosition.x), INT2MM(currentPosition.y), INT2MM(currentPosition.z), eToMm(current_e_value + retraction_diff_e_amount)), 25); // TODO: hardcoded values!
}
writeMoveFilament(config, config.distance);
}
void GCodeExport::writeMoveFilament(const RetractionConfig& config, const double new_retraction_distance)
{
ExtruderTrainAttributes& extr_attr = extruder_attr[current_extruder];
const double old_retraction_e_amount = extr_attr.retraction_e_amount_current;
const double new_retraction_e_amount = mmToE(new_retraction_distance);
const double retraction_diff_e_amount = old_retraction_e_amount - new_retraction_e_amount;
if (std::abs(retraction_diff_e_amount) < 0.000001)
{
return; //No need to have detailed extrusion moves this small.
}
else
{
double speed = ((retraction_diff_e_amount < 0.0)? config.speed : extr_attr.last_retraction_prime_speed) * 60;
@@ -740,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);
}
}
@@ -780,21 +768,14 @@ void GCodeExport::startExtruder(int new_extruder)
currentPosition.z += 1;
}
void GCodeExport::switchExtruder(int new_extruder, const RetractionConfig& retraction_config_old_extruder, const bool turn_off_extruder)
void GCodeExport::switchExtruder(int new_extruder, const RetractionConfig& retraction_config_old_extruder)
{
if (current_extruder == new_extruder)
return;
if (turn_off_extruder)
{
writeMoveFilament(retraction_config_old_extruder, extruder_attr[current_extruder].park_distance);
}
else
{
bool force = true;
bool extruder_switch = true;
writeRetraction(const_cast<RetractionConfig&>(retraction_config_old_extruder), force, extruder_switch);
}
bool force = true;
bool extruder_switch = true;
writeRetraction(retraction_config_old_extruder, force, extruder_switch);
resetExtrusionValue(); // zero the E value on the old extruder, so that the current_e_value is registered on the old extruder
+13 -21
Ver Arquivo
@@ -1,7 +1,4 @@
//Copyright (c) 2013 David Braam
//Copyright (c) 2016 Ultimaker B.V.
//CuraEngine is released under the terms of the AGPLv3 or higher.
/** Copyright (C) 2013 David Braam - Released under terms of the AGPLv3 License */
#ifndef GCODEEXPORT_H
#define GCODEEXPORT_H
@@ -16,6 +13,7 @@
#include "MeshGroup.h"
#include "commandSocket.h"
#include "RetractionConfig.h"
#include "multithreadOpenMP.h"
namespace cura {
@@ -62,7 +60,6 @@ private:
double retraction_e_amount_current; //!< The current retracted amount (in mm or mm^3), or zero(i.e. false) if it is not currently retracted (positive values mean retracted amount, so negative impact on E values)
double retraction_e_amount_at_e_start; //!< The ExtruderTrainAttributes::retraction_amount_current value at E0, i.e. the offset (in mm or mm^3) from E0 to the situation where the filament is at the tip of the nozzle.
double park_distance; //!< The distance from the nozzle at which to park filament after having completed printing with it.
double prime_volume; //!< Amount of material (in mm^3) to be primed after an unretration (due to oozing and/or coasting)
double last_retraction_prime_speed; //!< The last prime speed (in mm/s) of the to-be-primed amount
@@ -83,7 +80,6 @@ private:
, initial_temp(0)
, retraction_e_amount_current(0.0)
, retraction_e_amount_at_e_start(0.0)
, park_distance(0.0)
, prime_volume(0.0)
, last_retraction_prime_speed(0.0)
{ }
@@ -95,6 +91,9 @@ private:
std::string machine_name;
std::ostream* output_stream;
#ifdef _OPENMP
omp_nest_lock_type output_stream_lock;
#endif
std::string new_line;
double current_e_value; //!< The last E value written to gcode (in mm or mm^3)
@@ -163,18 +162,6 @@ protected:
*/
double mmToE(double mm);
/*!
* \brief Write a move in the E-direction such that the filament is
* retracted or unretracted to the specified distance.
*
* No checks are made for the maximum number of retractions.
*
* \param config The configuration from which to get the distance and speed.
* \param new_retraction_distance The distance from the tip of the nozzle
* where the filament is supposed to end up.
*/
void writeMoveFilament(const RetractionConfig& config, const double new_retraction_distance);
public:
GCodeExport();
@@ -194,6 +181,13 @@ public:
void setOutputStream(std::ostream* stream);
#ifdef _OPENMP
omp_nest_lock_type& getOutputStreamLock()
{
return output_stream_lock;
}
#endif
bool getExtruderIsUsed(const int extruder_nr) const; //!< Returns whether the extruder with the given index is used up until the current meshgroup
int getNozzleSize(const int extruder_nr) const;
@@ -313,10 +307,8 @@ public:
*
* \param new_extruder The extruder to switch to
* \param retraction_config_old_extruder The extruder switch retraction config of the old extruder, to perform the extruder switch retraction with.
* \param turn_off_extruder Should the old extruder be turned off
* completely?
*/
void switchExtruder(int new_extruder, const RetractionConfig& retraction_config_old_extruder, const bool turn_off_extruder = false);
void switchExtruder(int new_extruder, const RetractionConfig& retraction_config_old_extruder);
void writeCode(const char* str);
+63 -43
Ver Arquivo
@@ -11,7 +11,8 @@ namespace cura {
ExtruderPlan::ExtruderPlan(int extruder, Point start_position, int layer_nr, bool is_initial_layer, int layer_thickness, FanSpeedLayerTimeSettings& fan_speed_layer_time_settings, const RetractionConfig& retraction_config)
: extruder(extruder)
: is_paths_vector_initialised(false)
, extruder(extruder)
, heated_pre_travel_time(0)
, initial_printing_temperature(-1)
, printing_temperature(-1)
@@ -54,11 +55,24 @@ double ExtruderPlan::getFanSpeed()
{
return fan_speed;
}
GCodePath* GCodePlanner::getLatestPathWithConfig(GCodePathConfig* config, SpaceFillType space_fill_type, float flow, bool spiralize)
void ExtruderPlan::convertListToVector()
{
std::vector<GCodePath>& paths = extruder_plans.back().paths;
unsigned int number_of_paths = paths_list.size();
paths_vector.reserve(number_of_paths);
for (auto path : paths_list)
{
if (path.points.size())
{
paths_vector.emplace_back(std::move(path));
}
}
is_paths_vector_initialised = true;
}
GCodePath* GCodePlanner::getLatestPathWithConfig(const GCodePathConfig* config, SpaceFillType space_fill_type, float flow, bool spiralize)
{
std::list<GCodePath>& paths = extruder_plans.back().getPathsList();
if (paths.size() > 0 && paths.back().config == config && !paths.back().done && paths.back().flow == flow) // spiralize can only change when a travel path is in between
return &paths.back();
paths.emplace_back();
@@ -76,9 +90,9 @@ GCodePath* GCodePlanner::getLatestPathWithConfig(GCodePathConfig* config, SpaceF
void GCodePlanner::forceNewPathStart()
{
std::vector<GCodePath>& paths = extruder_plans.back().paths;
std::list<GCodePath>& paths = extruder_plans.back().getPathsList();
if (paths.size() > 0)
paths[paths.size()-1].done = true;
paths.back().done = true;
}
GCodePlanner::GCodePlanner(SliceDataStorage& storage, int layer_nr, int z, int layer_thickness, Point last_position, int current_extruder, bool is_inside_mesh, std::vector<FanSpeedLayerTimeSettings>& fan_speed_layer_time_settings_per_extruder, CombingMode combing_mode, int64_t comb_boundary_offset, bool travel_avoid_other_parts, int64_t travel_avoid_distance)
@@ -93,6 +107,7 @@ GCodePlanner::GCodePlanner(SliceDataStorage& storage, int layer_nr, int z, int l
, last_planned_extruder_setting_base(storage.meshgroup->getExtruderTrain(current_extruder))
, comb_boundary_inside(computeCombBoundaryInside(combing_mode))
, fan_speed_layer_time_settings_per_extruder(fan_speed_layer_time_settings_per_extruder)
, gcode_written(0)
{
extruder_plans.reserve(storage.meshgroup->getExtruderCount());
extruder_plans.emplace_back(current_extruder, start_position, layer_nr, is_initial_layer, layer_thickness, fan_speed_layer_time_settings_per_extruder[current_extruder], storage.retraction_config_per_extruder[current_extruder]);
@@ -189,7 +204,7 @@ bool GCodePlanner::setExtruder(int extruder)
}
addTravel(end_pos); // + extruder_offset cause it
}
if (extruder_plans.back().paths.empty() && extruder_plans.back().inserts.empty())
if (extruder_plans.back().getPathsList().empty() && extruder_plans.back().inserts.empty())
{ // first extruder plan in a layer might be empty, cause it is made with the last extruder planned in the previous layer
extruder_plans.back().extruder = extruder;
}
@@ -250,7 +265,7 @@ GCodePath& GCodePlanner::addTravel(Point p)
const bool perform_z_hops = extr->getSettingBoolean("retraction_hop_enabled");
const bool is_first_travel_of_extruder_after_switch = extruder_plans.back().paths.size() == 0 && (extruder_plans.size() > 1 || last_extruder_previous_layer != getExtruder());
const bool is_first_travel_of_extruder_after_switch = extruder_plans.back().getPathsList().size() == 0 && (extruder_plans.size() > 1 || last_extruder_previous_layer != getExtruder());
const bool bypass_combing = is_first_travel_of_extruder_after_switch && extr->getSettingBoolean("retraction_hop_after_extruder_switch");
if (comb != nullptr && !bypass_combing && lastPosition != no_point)
@@ -349,13 +364,13 @@ void GCodePlanner::planPrime()
forceNewPathStart();
}
void GCodePlanner::addExtrusionMove(Point p, GCodePathConfig* config, SpaceFillType space_fill_type, float flow, bool spiralize)
void GCodePlanner::addExtrusionMove(Point p, const GCodePathConfig* config, SpaceFillType space_fill_type, float flow, bool spiralize)
{
getLatestPathWithConfig(config, space_fill_type, flow, spiralize)->points.push_back(p);
lastPosition = p;
}
void GCodePlanner::addPolygon(PolygonRef polygon, int start_idx, GCodePathConfig* config, WallOverlapComputation* wall_overlap_computation, coord_t wall_0_wipe_dist, bool spiralize)
void GCodePlanner::addPolygon(ConstPolygonRef polygon, int start_idx, const GCodePathConfig* config, WallOverlapComputation* wall_overlap_computation, coord_t wall_0_wipe_dist, bool spiralize)
{
Point p0 = polygon[start_idx];
addTravel(p0);
@@ -368,7 +383,7 @@ void GCodePlanner::addPolygon(PolygonRef polygon, int start_idx, GCodePathConfig
}
if (polygon.size() > 2)
{
Point& p1 = polygon[start_idx];
const Point& p1 = polygon[start_idx];
float flow = (wall_overlap_computation)? wall_overlap_computation->getFlow(p0, p1) : 1.0;
addExtrusionMove(p1, config, SpaceFillType::Polygons, flow, spiralize);
@@ -403,7 +418,7 @@ void GCodePlanner::addPolygon(PolygonRef polygon, int start_idx, GCodePathConfig
}
}
void GCodePlanner::addPolygonsByOptimizer(Polygons& polygons, GCodePathConfig* config, WallOverlapComputation* wall_overlap_computation, EZSeamType z_seam_type, Point z_seam_pos, coord_t wall_0_wipe_dist, bool spiralize)
void GCodePlanner::addPolygonsByOptimizer(const Polygons& polygons, const GCodePathConfig* config, WallOverlapComputation* wall_overlap_computation, EZSeamType z_seam_type, Point z_seam_pos, coord_t wall_0_wipe_dist, bool spiralize)
{
if (polygons.size() == 0)
{
@@ -420,7 +435,7 @@ void GCodePlanner::addPolygonsByOptimizer(Polygons& polygons, GCodePathConfig* c
addPolygon(polygons[poly_idx], orderOptimizer.polyStart[poly_idx], config, wall_overlap_computation, wall_0_wipe_dist, spiralize);
}
}
void GCodePlanner::addLinesByOptimizer(Polygons& polygons, GCodePathConfig* config, SpaceFillType space_fill_type, int wipe_dist)
void GCodePlanner::addLinesByOptimizer(const Polygons& polygons, const GCodePathConfig* config, SpaceFillType space_fill_type, int wipe_dist)
{
LineOrderOptimizer orderOptimizer(lastPosition);
for (unsigned int line_idx = 0; line_idx < polygons.size(); line_idx++)
@@ -430,12 +445,12 @@ void GCodePlanner::addLinesByOptimizer(Polygons& polygons, GCodePathConfig* conf
orderOptimizer.optimize();
for (int poly_idx : orderOptimizer.polyOrder)
{
PolygonRef polygon = polygons[poly_idx];
ConstPolygonRef polygon = polygons[poly_idx];
int start = orderOptimizer.polyStart[poly_idx];
int end = 1 - start;
Point& p0 = polygon[start];
const Point& p0 = polygon[start];
addTravel(p0);
Point& p1 = polygon[end];
const Point& p1 = polygon[end];
addExtrusionMove(p1, config, space_fill_type);
if (wipe_dist != 0)
{
@@ -458,7 +473,7 @@ void ExtruderPlan::forceMinimalLayerTime(double minTime, double minimalSpeed, do
if (minExtrudeTime < 1)
minExtrudeTime = 1;
double factor = extrudeTime / minExtrudeTime;
for (GCodePath& path : paths)
for (GCodePath& path : getPathsList())
{
if (path.isTravelPath())
continue;
@@ -482,7 +497,7 @@ void ExtruderPlan::forceMinimalLayerTime(double minTime, double minimalSpeed, do
// Adjust stored naive time estimates
estimates.extrude_time *= inv_factor;
for (GCodePath& path : paths)
for (GCodePath& path : getPathsList())
{
path.estimates.extrude_time *= inv_factor;
}
@@ -500,7 +515,7 @@ TimeMaterialEstimates ExtruderPlan::computeNaiveTimeEstimates()
Point p0 = start_position;
bool was_retracted = false; // wrong assumption; won't matter that much. (TODO)
for (GCodePath& path : paths)
for (GCodePath& path : getPathsList())
{
bool is_extrusion_path = false;
double* path_time_estimate;
@@ -653,7 +668,7 @@ void GCodePlanner::writeGCode(GCodeExport& gcode)
gcode.setZ(z);
GCodePathConfig* last_extrusion_config = nullptr; // used to check whether we need to insert a TYPE comment in the gcode.
const GCodePathConfig* last_extrusion_config = nullptr; // used to check whether we need to insert a TYPE comment in the gcode.
int extruder = gcode.getExtruderNr();
bool acceleration_enabled = storage.getSettingBoolean("acceleration_enabled");
@@ -663,17 +678,14 @@ void GCodePlanner::writeGCode(GCodeExport& gcode)
{
ExtruderPlan& extruder_plan = extruder_plans[extruder_plan_idx];
RetractionConfig& retraction_config = storage.retraction_config_per_extruder[extruder_plan.extruder];
const ExtruderTrain* train = storage.meshgroup->getExtruderTrain(extruder);
if (extruder != extruder_plan.extruder)
{
int prev_extruder = extruder;
extruder = extruder_plan.extruder;
gcode.switchExtruder(extruder, storage.extruder_switch_retraction_config_per_extruder[prev_extruder]);
const int prev_layer_nr = (extruder_plan_idx == 0) ? layer_nr - 1 : layer_nr;
const bool turn_off_extruder = prev_layer_nr >= storage.max_print_height_per_extruder[prev_extruder]; //Previous extruder is not used any more in this mesh group.
gcode.switchExtruder(extruder, storage.extruder_switch_retraction_config_per_extruder[prev_extruder], turn_off_extruder);
const ExtruderTrain* train = storage.meshgroup->getExtruderTrain(extruder);
if (train->getSettingInMillimetersPerSecond("max_feedrate_z_override") > 0)
{
gcode.writeMaxZFeedrate(train->getSettingInMillimetersPerSecond("max_feedrate_z_override"));
@@ -684,32 +696,34 @@ void GCodePlanner::writeGCode(GCodeExport& gcode)
gcode.writeTemperatureCommand(extruder, extruder_plan.initial_printing_temperature, wait);
}
std::optional<double> prev_extruder_temp = std::optional<double>();
if (turn_off_extruder)
{
prev_extruder_temp = 0; //Turn previous extruder off entirely. TODO: Should there be a setting for the temperature to turn an extruder off?
}
else if (extruder_plan.prev_extruder_standby_temp)
{
prev_extruder_temp = *extruder_plan.prev_extruder_standby_temp; //Not entirely, but just to stand-by temperature.
}
if (prev_extruder_temp) //One of the if-statements above went through.
{
// prime extruder if it hadn't been used yet
gcode.writePrimeTrain(storage.meshgroup->getExtruderTrain(extruder)->getSettingInMillimetersPerSecond("speed_travel"));
gcode.writeRetraction(retraction_config);
if (extruder_plan.prev_extruder_standby_temp)
{ // turn off previous extruder
constexpr bool wait = false;
gcode.writeTemperatureCommand(prev_extruder, *prev_extruder_temp, wait);
double prev_extruder_temp = *extruder_plan.prev_extruder_standby_temp;
int prev_layer_nr = (extruder_plan_idx == 0)? layer_nr - 1 : layer_nr;
if (prev_layer_nr == storage.max_print_height_per_extruder[prev_extruder])
{
prev_extruder_temp = 0; // TODO ? should there be a setting for extruder_off_temperature ?
}
gcode.writeTemperatureCommand(prev_extruder, prev_extruder_temp, wait);
}
}
else if (extruder_plan_idx == 0 && layer_nr != 0 && train->getSettingBoolean("retract_at_layer_change"))
else if (extruder_plan_idx == 0 && layer_nr != 0 && storage.meshgroup->getExtruderTrain(extruder)->getSettingBoolean("retract_at_layer_change"))
{
gcode.writeRetraction(retraction_config);
}
gcode.writeFanCommand(extruder_plan.getFanSpeed());
std::vector<GCodePath>& paths = extruder_plan.paths;
std::vector<GCodePath>& paths = extruder_plan.getPaths();
extruder_plan.inserts.sort([](const NozzleTempInsert& a, const NozzleTempInsert& b) -> bool {
return a.path_idx < b.path_idx;
} );
const ExtruderTrain* train = storage.meshgroup->getExtruderTrain(extruder);
if (train->getSettingInMillimetersPerSecond("max_feedrate_z_override") > 0)
{
gcode.writeMaxZFeedrate(train->getSettingInMillimetersPerSecond("max_feedrate_z_override"));
@@ -876,6 +890,9 @@ void GCodePlanner::writeGCode(GCodeExport& gcode)
} // extruder plans /\ .
gcode.updateTotalPrintTime();
#pragma omp flush
#pragma omp atomic update
++gcode_written;
}
void GCodePlanner::overrideFanSpeeds(double speed)
@@ -898,6 +915,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);
@@ -956,6 +974,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++)
{
@@ -977,6 +996,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();
@@ -987,9 +1007,9 @@ void GCodePlanner::processInitialLayersSpeedup()
bool GCodePlanner::makeRetractSwitchRetract(unsigned int extruder_plan_idx, unsigned int path_idx)
bool GCodePlanner::makeRetractSwitchRetract(GCodeExport& gcode, unsigned int extruder_plan_idx, unsigned int path_idx)
{
std::vector<GCodePath>& paths = extruder_plans[extruder_plan_idx].paths;
std::vector<GCodePath>& paths = extruder_plans[extruder_plan_idx].getPaths();
for (unsigned int path_idx2 = path_idx + 1; path_idx2 < paths.size(); path_idx2++)
{
if (paths[path_idx2].getExtrusionMM3perMM() > 0)
@@ -1020,7 +1040,7 @@ bool GCodePlanner::writePathWithCoasting(GCodeExport& gcode, unsigned int extrud
return false;
}
ExtruderPlan& extruder_plan = extruder_plans[extruder_plan_idx];
std::vector<GCodePath>& paths = extruder_plan.paths;
std::vector<GCodePath>& paths = extruder_plan.getPaths();
GCodePath& path = paths[path_idx];
if (path_idx + 1 >= paths.size()
||
+58 -10
Ver Arquivo
@@ -37,9 +37,12 @@ class ExtruderPlan
friend class GCodePlanner; // TODO: GCodePlanner still does a lot which should actually be handled in this class.
friend class LayerPlanBuffer; // TODO: LayerPlanBuffer handles paths directly
protected:
std::vector<GCodePath> paths; //!< The paths planned for this extruder
std::list<GCodePath> paths_list; //!< The paths planned for this extruder
std::vector<GCodePath> paths_vector; //!< The paths planned for this extruder
std::list<NozzleTempInsert> inserts; //!< The nozzle temperature command inserts, to be inserted in between paths
bool is_paths_vector_initialised; //!< Keeps information if content of \p paths_list has been copied to \p paths_vector
int extruder; //!< The extruder used for this paths in the current plan.
double heated_pre_travel_time; //!< The time at the start of this ExtruderPlan during which the head travels and has a temperature of initial_print_temperature
double initial_printing_temperature; //!< The required temperature at the start of this extruder plan.
@@ -101,7 +104,7 @@ public:
while ( ! inserts.empty() )
{ // handle the Insert to be inserted before this path_idx (and all inserts not handled yet)
NozzleTempInsert& insert = inserts.front();
assert(insert.path_idx == paths.size());
assert(insert.path_idx == getPaths().size());
insert.write(gcode);
inserts.pop_front();
}
@@ -156,6 +159,39 @@ public:
* \return The fan speed computed in processFanSpeedAndMinimalLayerTime
*/
double getFanSpeed();
/*!
* Move the paths data from the input list to the vector container
*
* \warning empties the \p paths_list which will no longer contain data. No references to the paths in \p paths_list should be kept.
*/
void convertListToVector();
/*!
* Get the paths in a list container
*
* \warning should not be called after paths_list has been converted to paths variable
*
* \return The paths as a list
*/
std::list<GCodePath>& getPathsList()
{
assert(!is_paths_vector_initialised);
return paths_list;
}
/*!
* Get the paths in a vector container
*
* \warning should not be called before paths_list has been converted to paths variable
*
* \return The paths as a vector
*/
std::vector<GCodePath>& getPaths()
{
assert(is_paths_vector_initialised);
return paths_vector;
}
protected:
Point start_position; //!< The position the print head was at at the start of this extruder plan
@@ -240,6 +276,8 @@ private:
std::vector<FanSpeedLayerTimeSettings>& fan_speed_layer_time_settings_per_extruder;
int gcode_written;
private:
/*!
* Either create a new path with the given config or return the last path if it already had that config.
@@ -251,7 +289,7 @@ private:
* \param spiralize Whether to gradually increase the z while printing. (Note that this path may be part of a sequence of spiralized paths, forming one polygon)
* \return A path with the given config which is now the last path in GCodePlanner::paths
*/
GCodePath* getLatestPathWithConfig(GCodePathConfig* config, SpaceFillType space_fill_type, float flow = 1.0, bool spiralize = false);
GCodePath* getLatestPathWithConfig(const GCodePathConfig* config, SpaceFillType space_fill_type, float flow = 1.0, bool spiralize = false);
public:
/*!
@@ -377,7 +415,7 @@ public:
* \param flow A modifier of the extrusion width which would follow from the \p config
* \param spiralize Whether to gradually increase the z while printing. (Note that this path may be part of a sequence of spiralized paths, forming one polygon)
*/
void addExtrusionMove(Point p, GCodePathConfig* config, SpaceFillType space_fill_type, float flow = 1.0, bool spiralize = false);
void addExtrusionMove(Point p, const GCodePathConfig* config, SpaceFillType space_fill_type, float flow = 1.0, bool spiralize = false);
/*!
* Add polygon to the gcode starting at vertex \p startIdx
@@ -388,7 +426,7 @@ public:
* \param wall_0_wipe_dist The distance to travel along the polygon after it has been laid down, in order to wipe the start and end of the wall together
* \param spiralize Whether to gradually increase the z height from the normal layer height to the height of the next layer over this polygon
*/
void addPolygon(PolygonRef polygon, int startIdx, GCodePathConfig* config, WallOverlapComputation* wall_overlap_computation = nullptr, coord_t wall_0_wipe_dist = 0, bool spiralize = false);
void addPolygon(ConstPolygonRef polygon, int startIdx, const GCodePathConfig* config, WallOverlapComputation* wall_overlap_computation = nullptr, coord_t wall_0_wipe_dist = 0, bool spiralize = false);
/*!
* Add polygons to the gcode with optimized order.
@@ -407,7 +445,7 @@ public:
* \param wall_0_wipe_dist The distance to travel along each polygon after it has been laid down, in order to wipe the start and end of the wall together
* \param spiralize Whether to gradually increase the z height from the normal layer height to the height of the next layer over each polygon printed
*/
void addPolygonsByOptimizer(Polygons& polygons, GCodePathConfig* config, WallOverlapComputation* wall_overlap_computation = nullptr, EZSeamType z_seam_type = EZSeamType::SHORTEST, Point z_seam_pos = Point(0, 0), coord_t wall_0_wipe_dist = 0, bool spiralize = false);
void addPolygonsByOptimizer(const Polygons& polygons, const GCodePathConfig* config, WallOverlapComputation* wall_overlap_computation = nullptr, EZSeamType z_seam_type = EZSeamType::SHORTEST, Point z_seam_pos = Point(0, 0), coord_t wall_0_wipe_dist = 0, bool spiralize = false);
/*!
* Add lines to the gcode with optimized order.
@@ -416,7 +454,7 @@ public:
* \param space_fill_type The type of space filling used to generate the line segments (should be either Lines or PolyLines!)
* \param wipe_dist (optional) the distance wiped without extruding after laying down a line.
*/
void addLinesByOptimizer(Polygons& polygons, GCodePathConfig* config, SpaceFillType space_fill_type, int wipe_dist = 0);
void addLinesByOptimizer(const Polygons& polygons, const GCodePathConfig* config, SpaceFillType space_fill_type, int wipe_dist = 0);
/*!
* Compute naive time estimates (without accounting for slow down at corners etc.) and naive material estimates (without accounting for MergeInfillLines)
@@ -434,7 +472,16 @@ public:
* \param gcode The gcode to write the planned paths to
*/
void writeGCode(GCodeExport& gcode);
/*!
* Has the planned paths been written to gcode
*/
int isGCodeWritten()
{
int gcode_written_tmp;
#pragma omp atomic read
gcode_written_tmp = gcode_written;
return gcode_written_tmp;
}
/*!
* Complete all GcodePathConfigs by
* - altering speeds to conform to speed_print_layer_0 and
@@ -451,12 +498,13 @@ public:
/*!
* Whether the current retracted path is to be an extruder switch retraction.
* This function is used to avoid a G10 S1 after a G10.
*
*
* \param gcode The gcode to write the planned paths to
* \param extruder_plan_idx The index of the current extruder plan
* \param path_idx The index of the current retracted path
* \return Whether the path should be an extgruder switch retracted path
*/
bool makeRetractSwitchRetract(unsigned int extruder_plan_idx, unsigned int path_idx);
bool makeRetractSwitchRetract(GCodeExport& gcode, unsigned int extruder_plan_idx, unsigned int path_idx);
/*!
* Writes a path to GCode and performs coasting, or returns false if it did nothing.
+2 -2
Ver Arquivo
@@ -17,7 +17,7 @@ int Infill::computeScanSegmentIdx(int x, int line_width)
return x / line_width;
}
void Infill::generate(Polygons& result_polygons, Polygons& result_lines, SliceMeshStorage* mesh)
void Infill::generate(Polygons& result_polygons, Polygons& result_lines, const SliceMeshStorage* mesh)
{
if (in_outline.size() == 0) return;
if (line_distance == 0) return;
@@ -144,7 +144,7 @@ void Infill::generateTriangleInfill(Polygons& result)
generateLineInfill(result, line_distance, fill_angle + 120, 0);
}
void Infill::generateCubicSubDivInfill(Polygons& result, SliceMeshStorage& mesh)
void Infill::generateCubicSubDivInfill(Polygons& result, const SliceMeshStorage& mesh)
{
Polygons uncropped;
mesh.base_subdiv_cube->generateSubdivisionLines(z, uncropped);
+3 -3
Ver Arquivo
@@ -80,7 +80,7 @@ public:
* \param result_lines (output) The resulting line segments (from linear infill types)
* \param mesh The mesh for which to geenrate infill (should only be used for non-helper objects)
*/
void generate(Polygons& result_polygons, Polygons& result_lines, SliceMeshStorage* mesh = nullptr);
void generate(Polygons& result_polygons, Polygons& result_lines, const SliceMeshStorage* mesh = nullptr);
private:
/*!
@@ -148,8 +148,8 @@ private:
* \param[out] result The resulting lines
* \param[in] mesh Where the Cubic Subdivision Infill precomputation is stored
*/
void generateCubicSubDivInfill(Polygons& result, SliceMeshStorage& mesh);
void generateCubicSubDivInfill(Polygons& result, const SliceMeshStorage& mesh);
/*!
* Convert a mapping from scanline to line_segment-scanline-intersections (\p cut_list) into line segments, using the even-odd rule
* \param result (output) The resulting lines
+31 -19
Ver Arquivo
@@ -41,16 +41,20 @@ void SubDivCube::precomputeOctree(SliceMeshStorage& mesh)
coord_t max_side_length = furthest_dist_from_origin * 2;
int curr_recursion_depth = 0;
for (int64_t curr_side_length = mesh.getSettingInMicrons("infill_line_distance") * 2; curr_side_length < max_side_length * 2; curr_side_length *= 2)
const int64_t infill_line_distance = mesh.getSettingInMicrons("infill_line_distance");
if (infill_line_distance > 0)
{
cube_properties_per_recursion_step.emplace_back();
CubeProperties& cube_properties_here = cube_properties_per_recursion_step.back();
cube_properties_here.side_length = curr_side_length;
cube_properties_here.height = sqrt(3) * curr_side_length;
cube_properties_here.square_height = sqrt(2) * curr_side_length;
cube_properties_here.max_draw_z_diff = ONE_OVER_SQRT_3 * curr_side_length;
cube_properties_here.max_line_offset = ONE_OVER_SQRT_6 * curr_side_length;
curr_recursion_depth++;
for (int64_t curr_side_length = infill_line_distance * 2; curr_side_length < max_side_length * 2; curr_side_length *= 2)
{
cube_properties_per_recursion_step.emplace_back();
CubeProperties& cube_properties_here = cube_properties_per_recursion_step.back();
cube_properties_here.side_length = curr_side_length;
cube_properties_here.height = sqrt(3) * curr_side_length;
cube_properties_here.square_height = sqrt(2) * curr_side_length;
cube_properties_here.max_draw_z_diff = ONE_OVER_SQRT_3 * curr_side_length;
cube_properties_here.max_line_offset = ONE_OVER_SQRT_6 * curr_side_length;
curr_recursion_depth++;
}
}
Point3 center(0, 0, 0);
@@ -80,6 +84,10 @@ void SubDivCube::precomputeOctree(SliceMeshStorage& mesh)
void SubDivCube::generateSubdivisionLines(int64_t z, Polygons& result)
{
if (cube_properties_per_recursion_step.empty()) //Infill is set to 0%.
{
return;
}
Polygons directional_line_groups[3];
generateSubdivisionLines(z, result, directional_line_groups);
@@ -136,17 +144,21 @@ void SubDivCube::generateSubdivisionLines(int64_t z, Polygons& result, Polygons
}
}
SubDivCube::SubDivCube(SliceMeshStorage& mesh, Point3& center, int depth)
SubDivCube::SubDivCube(SliceMeshStorage& mesh, Point3& center, unsigned int depth)
{
this->depth = depth;
this->center = center;
CubeProperties cube_properties = cube_properties_per_recursion_step[depth];
if (depth == 0) // lowest layer, no need for subdivision, exit.
{
return;
}
if (depth >= cube_properties_per_recursion_step.size()) //Depth is out of bounds of what we pre-computed.
{
return;
}
CubeProperties cube_properties = cube_properties_per_recursion_step[depth];
Point3 child_center;
coord_t radius = double(radius_multiplier * double(cube_properties.height)) / 4.0 + radius_addition;
@@ -174,15 +186,15 @@ SubDivCube::SubDivCube(SliceMeshStorage& mesh, Point3& center, int depth)
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));
@@ -209,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;
}
+3 -3
Ver Arquivo
@@ -17,7 +17,7 @@ public:
* \param my_center the center of the cube
* \param depth the recursion depth of the cube (0 is most recursed)
*/
SubDivCube(SliceMeshStorage& mesh, Point3& center, int depth);
SubDivCube(SliceMeshStorage& mesh, Point3& center, unsigned int depth);
~SubDivCube(); //!< destructor (also destroys children
@@ -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.
@@ -84,7 +84,7 @@ private:
*/
void addLineAndCombine(Polygons& group, Point from, Point to);
int depth; //!< the recursion depth of the cube (0 is most recursed)
unsigned int depth; //!< the recursion depth of the cube (0 is most recursed)
Point3 center; //!< center location of the cube in absolute coordinates
SubDivCube* children[8] = {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr}; //!< pointers to this cube's eight octree children
static std::vector<CubeProperties> cube_properties_per_recursion_step; //!< precomputed array of basic properties of cubes based on recursion depth.
+15 -9
Ver Arquivo
@@ -1,10 +1,11 @@
/** Copyright (C) 2013 David Braam - Released under terms of the AGPLv3 License */
#include "LayerPart.h"
#include "../settings/settings.h"
#include "../progress/Progress.h"
#include "layerPart.h"
#include "settings/settings.h"
#include "progress/Progress.h"
#include "multithreadOpenMP.h"
#include "../utils/SVG.h" // debug output
#include "utils/SVG.h" // debug output
/*
The layer-part creation step is the first step in creating actual useful data for 3D printing.
@@ -28,8 +29,8 @@ void createLayerWithParts(SliceLayer& storageLayer, SlicerLayer* layer, bool uni
{
for(unsigned int i=0; i<layer->polygons.size(); i++)
{
if (layer->polygons[i].orientation())
layer->polygons[i].reverse();
if (PolygonRef{layer->polygons[i]}.orientation())
PolygonRef{layer->polygons[i]}.reverse();
}
}
@@ -44,12 +45,17 @@ 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();
// mesh.layers.resize(total_layers); TODO: put this back?
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++)
{ MULTITHREAD_FOR_CATCH_EXCEPTION(
mesh.layers[layer_nr].sliceZ = slicer->layers[layer_nr].z;
mesh.layers[layer_nr].printZ = slicer->layers[layer_nr].z;
createLayerWithParts(mesh.layers[layer_nr], &slicer->layers[layer_nr], union_layers, union_all_remove_holes);
}
)}
handleMultithreadAbort();
}
void layerparts2HTML(SliceDataStorage& storage, const char* filename, bool all_layers, int layer_nr)
+6 -6
Ver Arquivo
@@ -1,10 +1,10 @@
/** Copyright (C) 2013 David Braam - Released under terms of the AGPLv3 License */
#ifndef SLICER_LAYERPART_H
#define SLICER_LAYERPART_H
#ifndef LAYERPART_H
#define LAYERPART_H
#include "../sliceDataStorage.h"
#include "Slicer.h"
#include "../commandSocket.h"
#include "sliceDataStorage.h"
#include "slicer.h"
#include "commandSocket.h"
/*
The layer-part creation step is the first step in creating actual useful data for 3D printing.
@@ -28,4 +28,4 @@ void layerparts2HTML(SliceDataStorage& mesh, const char* filename, bool all_laye
}//namespace cura
#endif//SLICER_LAYERPART_H
#endif//LAYERPART_H
+1 -1
Ver Arquivo
@@ -210,7 +210,7 @@ void slice(int argc, char **argv)
}
else
{
last_settings_object = meshgroup->meshes.back();
last_settings_object = &(meshgroup->meshes.back()); // pointer is valid until a new object is added, so this is OK
}
break;
case 'o':
+2 -33
Ver Arquivo
@@ -19,21 +19,12 @@ Mesh::Mesh(SettingsBaseVirtual* parent)
{
}
bool Mesh::addFace(Point3& v0, Point3& v1, Point3& v2)
void Mesh::addFace(Point3& v0, Point3& v1, Point3& v2)
{
int vi0 = findIndexOfVertex(v0);
int vi1 = findIndexOfVertex(v1);
int vi2 = findIndexOfVertex(v2);
return addFace(vi0, vi1, vi2);
}
bool Mesh::addFace(int vi0, int vi1, int vi2)
{
if (vi0 == vi1 || vi1 == vi2 || vi0 == vi2)
{
// the face has two vertices which get assigned the same location. Don't add the face.
return false;
}
if (vi0 == vi1 || vi1 == vi2 || vi0 == vi2) return; // the face has two vertices which get assigned the same location. Don't add the face.
int idx = faces.size(); // index of face to be added
faces.emplace_back();
@@ -44,8 +35,6 @@ bool Mesh::addFace(int vi0, int vi1, int vi2)
vertices[face.vertex_index[0]].connected_faces.push_back(idx);
vertices[face.vertex_index[1]].connected_faces.push_back(idx);
vertices[face.vertex_index[2]].connected_faces.push_back(idx);
return true;
}
void Mesh::clear()
@@ -92,14 +81,6 @@ void Mesh::expandXY(int64_t offset)
}
void Mesh::addVertex(const Point3& v)
{
uint32_t hash = pointHash(v);
vertex_hash_map[hash].push_back(vertices.size());
vertices.emplace_back(v);
aabb.include(v);
}
int Mesh::findIndexOfVertex(const Point3& v)
{
uint32_t hash = pointHash(v);
@@ -208,16 +189,4 @@ int Mesh::getFaceIdxWithPoints(int idx0, int idx1, int notFaceIdx, int notFaceVe
return bestIdx;
}
bool Mesh::registerFaceSlice(unsigned int face_idx, unsigned int idx_shared, unsigned int idx_first, unsigned int idx_second, int32_t z, Point segment_start, Point segment_end, MatSegment& result) const
{
// do nothing for a non-textured mesh
return false;
}
float Mesh::getColor(MatCoord, ColourUsage) const
{
return 0.0f;
}
}//namespace cura
+1 -28
Ver Arquivo
@@ -3,7 +3,6 @@
#include "settings/settings.h"
#include "utils/AABB3D.h"
#include "MatSegment.h"
namespace cura
{
@@ -66,26 +65,7 @@ public:
Mesh(SettingsBaseVirtual* parent); //!< initializes the settings
virtual ~Mesh() {} //!< Destructor
/*!
* add a face to the mesh without settings it's connected_faces.
*
* Don't add a face when the surface is zero mm^2
*
* \return whether a face has been added
*/
bool addFace(Point3& v0, Point3& v1, Point3& v2);
/*!
* add a face to the mesh without settings it's connected_faces.
*
* Don't add a face when the surface is zero mm^2
*
* \return whether a face has been added
*/
bool addFace(int vi0, int vi1, int vi2);
void addVertex(const Point3& v);
void addFace(Point3& v0, Point3& v1, Point3& v2); //!< add a face to the mesh without settings it's connected_faces.
void clear(); //!< clears all data
void finish(); //!< complete the model : set the connected_face_index fields of the faces.
@@ -106,13 +86,6 @@ public:
aabb.offset(offset);
}
/*!
* \return Whether a texture line segment has been created
*/
virtual bool registerFaceSlice(unsigned int face_idx, unsigned int idx_shared, unsigned int idx_first, unsigned int idx_second, int32_t z, Point segment_start, Point segment_end, MatSegment& result) const;
virtual float getColor(MatCoord bitmap_coord, ColourUsage color) const;
private:
int findIndexOfVertex(const Point3& v); //!< find index of vertex close to the given point, or create a new vertex and return its index.
@@ -1,4 +1,4 @@
#include "MultiVolumes.h"
#include "multiVolumes.h"
namespace cura
{
@@ -1,8 +1,8 @@
#ifndef SLICER_MULTIVOLUMES_H
#define SLICER_MULTIVOLUMES_H
#ifndef MULTIVOLUMES_H
#define MULTIVOLUMES_H
#include "../sliceDataStorage.h"
#include "Slicer.h"
#include "sliceDataStorage.h"
#include "slicer.h"
/* This file contains code to help fixing up and changing layers that are build from multiple volumes. */
namespace cura {
@@ -21,4 +21,4 @@ void generateMultipleVolumesOverlap(std::vector<Slicer*> &meshes);
}//namespace cura
#endif//SLICER_MULTIVOLUMES_H
#endif//MULTIVOLUMES_H
+21
Ver Arquivo
@@ -0,0 +1,21 @@
/** Copyright (C) 2016 Ultimaker - Released under terms of the AGPLv3 License */
#include "multithreadOpenMP.h"
#include <cstdlib>
namespace cura
{
bool abort_execution = false;
#ifdef _OPENMP
void handleMultithreadAbort()
{
if (checkMultithreadAbort())
{
std::exit(17);
}
}
#endif
}//namespace cura
+182
Ver Arquivo
@@ -0,0 +1,182 @@
/** Copyright (C) 2016 Ultimaker - Released under terms of the AGPLv3 License */
#ifndef MULTITHREAD_OPENMP_H
#define MULTITHREAD_OPENMP_H
#include <omp.h>
namespace cura
{
// TODO: remove
extern bool abort_execution;
#ifdef _OPENMP
class omp_lock_type
{
public:
omp_lock_type()
{
omp_init_lock(&lock_object);
}
~omp_lock_type()
{
omp_destroy_lock(&lock_object);
}
void lock()
{
omp_set_lock(&lock_object);
}
void unlock()
{
omp_unset_lock(&lock_object);
}
int test_lock()
{
return omp_test_lock(&lock_object);
}
private:
omp_lock_t lock_object;
omp_lock_type( const omp_lock_type& ) = delete;
omp_lock_type& operator=( const omp_lock_type& ) = delete;
};
class omp_nest_lock_type
{
public:
omp_nest_lock_type()
{
omp_init_nest_lock(&lock_object);
}
~omp_nest_lock_type()
{
omp_destroy_nest_lock(&lock_object);
}
void lock()
{
omp_set_nest_lock(&lock_object);
}
void unlock()
{
omp_unset_nest_lock(&lock_object);
}
int test_lock()
{
return omp_test_nest_lock(&lock_object);
}
private:
omp_nest_lock_t lock_object;
omp_nest_lock_type( const omp_nest_lock_type& ) = delete;
omp_nest_lock_type& operator=( const omp_nest_lock_type& ) = delete;
};
template <typename LockType>
class omp_try_lock_guard_t
{
public:
omp_try_lock_guard_t( LockType& lock_)
: lock(lock_)
{
has_lock = lock.test_lock();
}
~omp_try_lock_guard_t()
{
if (has_lock)
{
lock.unlock();
}
}
int isLocked()
{
return has_lock;
}
private:
LockType& lock;
int has_lock;
omp_try_lock_guard_t( const omp_try_lock_guard_t& ) = delete;
omp_try_lock_guard_t<LockType>& operator=( const omp_try_lock_guard_t& ) = delete;
};
template <typename LockType>
class omp_lock_guard_t
{
public:
omp_lock_guard_t( LockType& lock_)
: lock(lock_)
{
lock.lock();
}
~omp_lock_guard_t()
{
lock.unlock();
}
private:
LockType& lock;
omp_lock_guard_t( const omp_lock_guard_t& ) = delete;
omp_lock_guard_t& operator=( const omp_lock_guard_t& ) = delete;
};
#endif
// TODO: remove
inline bool checkMultithreadAbort()
{
bool tmp_abort_execution;
#pragma omp atomic read
tmp_abort_execution = abort_execution;
return tmp_abort_execution;
}
// TODO: remove
inline void setMultithreadAbort()
{
#pragma omp atomic write
abort_execution = true;
}
// TODO: remove
#ifdef _OPENMP
void handleMultithreadAbort();
#else
inline void handleMultithreadAbort(){}
#endif
// TODO: remove old code below
#ifdef _OPENMP
#define MULTITHREAD_FOR_CATCH_EXCEPTION(code) \
if (checkMultithreadAbort()) \
{ \
continue; \
} \
try \
{ \
code \
} \
catch (...) \
{ \
setMultithreadAbort(); \
}
#else
#define MULTITHREAD_FOR_CATCH_EXCEPTION(code) code
#endif
#ifdef _OPENMP
#define MULTITHREAD_TASK_CATCH_EXCEPTION(code) \
if (!checkMultithreadAbort()) \
{ \
try \
{ \
code \
} \
catch (...) \
{ \
setMultithreadAbort(); \
} \
}
#else
#define MULTITHREAD_TASK_CATCH_EXCEPTION(code) code
#endif
}//namespace cura
#endif // MULTITHREAD_OPENMP_H
+10 -10
Ver Arquivo
@@ -16,7 +16,7 @@ void PathOrderOptimizer::optimize()
bool picked[polygons.size()];
memset(picked, false, sizeof(bool) * polygons.size());/// initialized as falses
for (PolygonRef poly : polygons) /// find closest point to initial starting point within each polygon +initialize picked
for (ConstPolygonRef poly : polygons) /// find closest point to initial starting point within each polygon +initialize picked
{
int best = -1;
float bestDist = std::numeric_limits<float>::infinity();
@@ -102,15 +102,15 @@ int PathOrderOptimizer::getPolyStart(Point prev_point, int poly_idx)
int PathOrderOptimizer::getClosestPointInPolygon(Point prev_point, int poly_idx)
{
PolygonRef poly = polygons[poly_idx];
ConstPolygonRef poly = polygons[poly_idx];
int best_point_idx = -1;
float best_point_score = std::numeric_limits<float>::infinity();
Point p0 = poly.back();
for (unsigned int point_idx = 0; point_idx < poly.size(); point_idx++)
{
Point& p1 = poly[point_idx];
Point& p2 = poly[(point_idx + 1) % poly.size()];
const Point& p1 = poly[point_idx];
const Point& p2 = poly[(point_idx + 1) % poly.size()];
int64_t dist = vSize2(p1 - prev_point);
float is_on_inside_corner_score = -LinearAlg2D::getAngleLeft(p0, p1, p2) / M_PI * 5000 * 5000; // prefer inside corners
// this score is in the order of 5 mm
@@ -143,7 +143,7 @@ void LineOrderOptimizer::optimize()
{
int best_point_idx = -1;
float best_point_dist = std::numeric_limits<float>::infinity();
PolygonRef poly = polygons[poly_idx];
ConstPolygonRef poly = polygons[poly_idx];
for (unsigned int point_idx = 0; point_idx < poly.size(); point_idx++) /// get closest point from polygon
{
float dist = vSize2f(poly[point_idx] - startPoint);
@@ -199,13 +199,13 @@ void LineOrderOptimizer::optimize()
if (best_line_idx > -1) /// should always be true; we should have been able to identify the best next polygon
{
PolygonRef best_line = polygons[best_line_idx];
ConstPolygonRef best_line = polygons[best_line_idx];
assert(best_line.size() == 2);
int line_start_point_idx = polyStart[best_line_idx];
int line_end_point_idx = line_start_point_idx * -1 + 1; /// 1 -> 0 , 0 -> 1
Point& line_start = best_line[line_start_point_idx];
Point& line_end = best_line[line_end_point_idx];
const Point& line_start = best_line[line_start_point_idx];
const Point& line_end = best_line[line_end_point_idx];
prev_point = line_end;
incoming_perpundicular_normal = turn90CCW(normal(line_end - line_start, 1000));
@@ -221,8 +221,8 @@ void LineOrderOptimizer::optimize()
inline void LineOrderOptimizer::updateBestLine(unsigned int poly_idx, int& best, float& best_score, Point prev_point, Point incoming_perpundicular_normal)
{
Point& p0 = polygons[poly_idx][0];
Point& p1 = polygons[poly_idx][1];
const Point& p0 = polygons[poly_idx][0];
const Point& p1 = polygons[poly_idx][1];
float dot_score = getAngleScore(incoming_perpundicular_normal, p0, p1);
{ /// check distance to first point on line (0)
float score = vSize2f(p0 - prev_point) + dot_score; // prefer 90 degree corners
+14 -4
Ver Arquivo
@@ -20,7 +20,7 @@ public:
EZSeamType type;
Point startPoint; //!< A location near the prefered start location
Point z_seam_pos; //!< The position near where to create the z_seam (if \ref PathOrderOptimizer::type == 'back')
std::vector<PolygonRef> polygons; //!< the parts of the layer (in arbitrary order)
std::vector<ConstPolygonRef> polygons; //!< the parts of the layer (in arbitrary order)
std::vector<int> polyStart; //!< polygons[i][polyStart[i]] = point of polygon i which is to be the starting point in printing the polygon
std::vector<int> polyOrder; //!< the optimized order as indices in #polygons
@@ -33,10 +33,15 @@ public:
void addPolygon(PolygonRef polygon)
{
this->polygons.push_back(polygon);
this->polygons.emplace_back(polygon);
}
void addPolygons(Polygons& polygons)
void addPolygon(ConstPolygonRef polygon)
{
this->polygons.emplace_back(polygon);
}
void addPolygons(const Polygons& polygons)
{
for(unsigned int i=0;i<polygons.size(); i++)
this->polygons.push_back(polygons[i]);
@@ -66,7 +71,7 @@ class LineOrderOptimizer
{
public:
Point startPoint; //!< The location of the nozzle before starting to print the current layer
std::vector<PolygonRef> polygons; //!< the parts of the layer (in arbitrary order)
std::vector<ConstPolygonRef> polygons; //!< the parts of the layer (in arbitrary order)
std::vector<int> polyStart; //!< polygons[i][polyStart[i]] = point of polygon i which is to be the starting point in printing the polygon
std::vector<int> polyOrder; //!< the optimized order as indices in #polygons
@@ -80,6 +85,11 @@ public:
this->polygons.push_back(polygon);
}
void addPolygon(ConstPolygonRef polygon)
{
this->polygons.push_back(polygon);
}
void addPolygons(Polygons& polygons)
{
for(unsigned int i=0;i<polygons.size(); i++)
+1 -1
Ver Arquivo
@@ -332,7 +332,7 @@ bool Comb::Crossing::findOutside(const Polygons& outside, const Point close_to,
}
std::shared_ptr<std::pair<ClosestPolygonPoint, ClosestPolygonPoint>> Comb::Crossing::findBestCrossing(const Polygons& outside, const PolygonRef from, const Point estimated_start, const Point estimated_end, Comb& comber)
std::shared_ptr<std::pair<ClosestPolygonPoint, ClosestPolygonPoint>> Comb::Crossing::findBestCrossing(const Polygons& outside, ConstPolygonRef from, const Point estimated_start, const Point estimated_end, Comb& comber)
{
ClosestPolygonPoint* best_in = nullptr;
ClosestPolygonPoint* best_out = nullptr;
+2 -2
Ver Arquivo
@@ -48,7 +48,7 @@ private:
Point in_or_mid; //!< The point on the inside boundary, or in between the inside and outside boundary if the start/end point isn't inside the inside boudary
Point out; //!< The point on the outside boundary
PolygonsPart dest_part; //!< The assembled inside-boundary PolygonsPart in which the dest_point lies. (will only be initialized when Crossing::dest_is_inside holds)
std::optional<PolygonRef> dest_crossing_poly; //!< The polygon of the part in which dest_point lies, which will be crossed (often will be the outside polygon)
std::optional<ConstPolygonRef> dest_crossing_poly; //!< The polygon of the part in which dest_point lies, which will be crossed (often will be the outside polygon)
const Polygons& boundary_inside; //!< The inside boundary as in \ref Comb::boundary_inside
const LocToLineGrid* inside_loc_to_line; //!< The loc to line grid \ref Comb::inside_loc_to_line
@@ -97,7 +97,7 @@ private:
* \param comber[in] The combing calculator which has references to the offsets and boundaries to use in combing.
* \return A pair of which the first is the crossing point on the inside boundary and the second the crossing point on the outside boundary
*/
std::shared_ptr<std::pair<ClosestPolygonPoint, ClosestPolygonPoint>> findBestCrossing(const Polygons& outside, const PolygonRef from, Point estimated_start, Point estimated_end, Comb& comber);
std::shared_ptr<std::pair<ClosestPolygonPoint, ClosestPolygonPoint>> findBestCrossing(const Polygons& outside, ConstPolygonRef from, Point estimated_start, Point estimated_end, Comb& comber);
};
+24
Ver Arquivo
@@ -0,0 +1,24 @@
//Copyright (C) 2016 Ultimaker
//Released under terms of the AGPLv3 License
#include "GCodePath.h"
namespace cura
{
bool GCodePath::isTravelPath()
{
return config->isTravelPath();
}
double GCodePath::getExtrusionMM3perMM()
{
return flow * config->getExtrusionMM3perMM();
}
int GCodePath::getLineWidth()
{
return flow * config->getLineWidth() * config->getFlowPercentage() / 100.0;
}
}
+4 -13
Ver Arquivo
@@ -23,7 +23,7 @@ namespace cura
class GCodePath
{
public:
GCodePathConfig* config; //!< The configuration settings of the path.
const GCodePathConfig* config; //!< The configuration settings of the path.
SpaceFillType space_fill_type; //!< The type of space filling of which this path is a part
float flow; //!< A type-independent flow configuration (used for wall overlap compensation)
bool retract; //!< Whether the path is a move path preceded by a retraction move; whether the path is a retracted move path.
@@ -41,10 +41,7 @@ public:
*
* \return Whether this config is the config of a travel path.
*/
bool isTravelPath()
{
return config->isTravelPath();
}
bool isTravelPath();
/*!
* Get the material flow in mm^3 per mm traversed.
@@ -53,19 +50,13 @@ public:
*
* \return The flow
*/
double getExtrusionMM3perMM()
{
return flow * config->getExtrusionMM3perMM();
}
double getExtrusionMM3perMM();
/*!
* Get the actual line width (modulated by the flow)
* \return the actual line width as shown in layer view
*/
int getLineWidth()
{
return flow * config->getLineWidth() * config->getFlowPercentage() / 100.0;
}
int getLineWidth();
};
}//namespace cura
+24
Ver Arquivo
@@ -0,0 +1,24 @@
//Copyright (C) 2016 Ultimaker
//Released under terms of the AGPLv3 License
#include "NozzleTempInsert.h"
namespace cura
{
NozzleTempInsert::NozzleTempInsert(unsigned int path_idx, int extruder, double temperature, bool wait, double time_after_path_start)
: path_idx(path_idx)
, time_after_path_start(time_after_path_start)
, extruder(extruder)
, temperature(temperature)
, wait(wait)
{
assert(temperature != 0 && temperature != -1 && "Temperature command must be set!");
}
void NozzleTempInsert::write(GCodeExport& gcode)
{
gcode.writeTemperatureCommand(extruder, temperature, wait);
}
}
+2 -13
Ver Arquivo
@@ -19,24 +19,13 @@ struct NozzleTempInsert
int extruder; //!< The extruder for which to set the temp
double temperature; //!< The temperature of the temperature command to insert
bool wait; //!< Whether to wait for the temperature to be reached
NozzleTempInsert(unsigned int path_idx, int extruder, double temperature, bool wait, double time_after_path_start = 0.0)
: path_idx(path_idx)
, time_after_path_start(time_after_path_start)
, extruder(extruder)
, temperature(temperature)
, wait(wait)
{
assert(temperature != 0 && temperature != -1 && "Temperature command must be set!");
}
NozzleTempInsert(unsigned int path_idx, int extruder, double temperature, bool wait, double time_after_path_start = 0.0);
/*!
* Write the temperature command at the current position in the gcode.
* \param gcode The actual gcode writer
*/
void write(GCodeExport& gcode)
{
gcode.writeTemperatureCommand(extruder, temperature, wait);
}
void write(GCodeExport& gcode);
};
}//namespace cura
+63
Ver Arquivo
@@ -4,6 +4,22 @@
namespace cura
{
TimeMaterialEstimates::TimeMaterialEstimates(double extrude_time, double unretracted_travel_time, double retracted_travel_time, double material)
: extrude_time(extrude_time)
, unretracted_travel_time(unretracted_travel_time)
, retracted_travel_time(retracted_travel_time)
, material(material)
{
}
TimeMaterialEstimates::TimeMaterialEstimates()
: extrude_time(0.0)
, unretracted_travel_time(0.0)
, retracted_travel_time(0.0)
, material(0.0)
{
}
TimeMaterialEstimates TimeMaterialEstimates::operator-(const TimeMaterialEstimates& other)
{
return TimeMaterialEstimates(extrude_time - other.extrude_time,unretracted_travel_time - other.unretracted_travel_time,retracted_travel_time - other.retracted_travel_time,material - other.material);
@@ -18,4 +34,51 @@ TimeMaterialEstimates& TimeMaterialEstimates::operator-=(const TimeMaterialEstim
return *this;
}
TimeMaterialEstimates TimeMaterialEstimates::operator+(const TimeMaterialEstimates& other)
{
return TimeMaterialEstimates(extrude_time+other.extrude_time, unretracted_travel_time+other.unretracted_travel_time, retracted_travel_time+other.retracted_travel_time, material+other.material);
}
TimeMaterialEstimates& TimeMaterialEstimates::operator+=(const TimeMaterialEstimates& other)
{
extrude_time += other.extrude_time;
unretracted_travel_time += other.unretracted_travel_time;
retracted_travel_time += other.retracted_travel_time;
material += other.material;
return *this;
}
double TimeMaterialEstimates::getExtrudeTime() const
{
return extrude_time;
}
double TimeMaterialEstimates::getMaterial() const
{
return material;
}
double TimeMaterialEstimates::getTotalTime() const
{
return extrude_time + unretracted_travel_time + retracted_travel_time;
}
double TimeMaterialEstimates::getTotalUnretractedTime() const
{
return extrude_time + unretracted_travel_time;
}
double TimeMaterialEstimates::getTravelTime() const
{
return retracted_travel_time + unretracted_travel_time;
}
void TimeMaterialEstimates::reset()
{
extrude_time = 0.0;
unretracted_travel_time = 0.0;
retracted_travel_time = 0.0;
material = 0.0;
}
}//namespace cura
+10 -53
Ver Arquivo
@@ -29,35 +29,17 @@ public:
* \param retracted_travel_time Time in seconds occupied by retracted travel (non-extrusion)
* \param material Material used (in mm^3)
*/
TimeMaterialEstimates(double extrude_time, double unretracted_travel_time, double retracted_travel_time, double material)
: extrude_time(extrude_time)
, unretracted_travel_time(unretracted_travel_time)
, retracted_travel_time(retracted_travel_time)
, material(material)
{
}
TimeMaterialEstimates(double extrude_time, double unretracted_travel_time, double retracted_travel_time, double material);
/*!
* Basic constructor initializing all estimates to zero.
*/
TimeMaterialEstimates()
: extrude_time(0.0)
, unretracted_travel_time(0.0)
, retracted_travel_time(0.0)
, material(0.0)
{
}
TimeMaterialEstimates();
/*!
* Set all estimates to zero.
*/
void reset()
{
extrude_time = 0.0;
unretracted_travel_time = 0.0;
retracted_travel_time = 0.0;
material = 0.0;
}
void reset();
/*!
* Pointwise addition of estimate stats
@@ -65,10 +47,7 @@ public:
* \param other The estimates to add to these estimates.
* \return The resulting estimates
*/
TimeMaterialEstimates operator+(const TimeMaterialEstimates& other)
{
return TimeMaterialEstimates(extrude_time+other.extrude_time, unretracted_travel_time+other.unretracted_travel_time, retracted_travel_time+other.retracted_travel_time, material+other.material);
}
TimeMaterialEstimates operator+(const TimeMaterialEstimates& other);
/*!
* In place pointwise addition of estimate stats
@@ -76,14 +55,7 @@ public:
* \param other The estimates to add to these estimates.
* \return These estimates
*/
TimeMaterialEstimates& operator+=(const TimeMaterialEstimates& other)
{
extrude_time += other.extrude_time;
unretracted_travel_time += other.unretracted_travel_time;
retracted_travel_time += other.retracted_travel_time;
material += other.material;
return *this;
}
TimeMaterialEstimates& operator+=(const TimeMaterialEstimates& other);
/*!
* \brief Subtracts the specified estimates from these estimates and returns
@@ -112,10 +84,7 @@ public:
*
* \return the total of all different time estimate values
*/
double getTotalTime() const
{
return extrude_time + unretracted_travel_time + retracted_travel_time;
}
double getTotalTime() const;
/*!
* Get the total time during which the head is not retracted.
@@ -124,10 +93,7 @@ public:
*
* \return the total time during which the head is not retracted.
*/
double getTotalUnretractedTime() const
{
return extrude_time + unretracted_travel_time;
}
double getTotalUnretractedTime() const;
/*!
* Get the total travel time.
@@ -136,30 +102,21 @@ public:
*
* \return the total travel time.
*/
double getTravelTime() const
{
return retracted_travel_time + unretracted_travel_time;
}
double getTravelTime() const;
/*!
* Get the extrusion time.
*
* \return extrusion time.
*/
double getExtrudeTime() const
{
return extrude_time;
}
double getExtrudeTime() const;
/*!
* Get the amount of material used in mm^3.
*
* \return amount of material
*/
double getMaterial() const
{
return material;
}
double getMaterial() const;
};
}//namespace cura
+10 -8
Ver Arquivo
@@ -125,6 +125,11 @@ 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())
{
logError("Couldn't find any extruder trains!\n");
return -1;
}
if (extruder_nr >= extruder_train_ids.size())
{
logWarning("Couldn't load extruder.def.json file for extruder %i. Index out of bounds.\n Loading first extruder definition instead.\n", extruder_nr);
@@ -220,8 +225,7 @@ int SettingRegistry::loadJSONsettingsFromDoc(rapidjson::Document& json_document,
if (json_document.HasMember("settings"))
{
std::list<std::string> path;
handleChildren(json_document["settings"], path, settings_base, warn_duplicates);
handleChildren(json_document["settings"], settings_base, warn_duplicates);
}
if (json_document.HasMember("overrides"))
@@ -243,7 +247,7 @@ int SettingRegistry::loadJSONsettingsFromDoc(rapidjson::Document& json_document,
return 0;
}
void SettingRegistry::handleChildren(const rapidjson::Value& settings_list, std::list<std::string>& path, SettingsBase* settings_base, bool warn_duplicates)
void SettingRegistry::handleChildren(const rapidjson::Value& settings_list, SettingsBase* settings_base, bool warn_duplicates)
{
if (!settings_list.IsObject())
{
@@ -252,12 +256,10 @@ void SettingRegistry::handleChildren(const rapidjson::Value& settings_list, std:
}
for (rapidjson::Value::ConstMemberIterator setting_iterator = settings_list.MemberBegin(); setting_iterator != settings_list.MemberEnd(); ++setting_iterator)
{
handleSetting(setting_iterator, path, settings_base, warn_duplicates);
handleSetting(setting_iterator, settings_base, warn_duplicates);
if (setting_iterator->value.HasMember("children"))
{
std::list<std::string> path_here = path;
path_here.push_back(setting_iterator->name.GetString());
handleChildren(setting_iterator->value["children"], path_here, settings_base, warn_duplicates);
handleChildren(setting_iterator->value["children"], settings_base, warn_duplicates);
}
}
}
@@ -275,7 +277,7 @@ bool SettingRegistry::settingIsUsedByEngine(const rapidjson::Value& setting)
}
void SettingRegistry::handleSetting(const rapidjson::Value::ConstMemberIterator& json_setting_it, std::list<std::string>& path, SettingsBase* settings_base, bool warn_duplicates)
void SettingRegistry::handleSetting(const rapidjson::Value::ConstMemberIterator& json_setting_it, SettingsBase* settings_base, bool warn_duplicates)
{
const rapidjson::Value& json_setting = json_setting_it->value;
if (!json_setting.IsObject())
+2 -3
Ver Arquivo
@@ -174,17 +174,16 @@ private:
* \param settings_base The settings base where to store the default values.
* \param warn_duplicates whether to warn for duplicate setting definitions
*/
void handleChildren(const rapidjson::Value& settings_list, std::list<std::string>& path, SettingsBase* settings_base, bool warn_duplicates);
void handleChildren(const rapidjson::Value& settings_list, SettingsBase* settings_base, bool warn_duplicates);
/*!
* Handle a json object for a setting.
*
* \param json_setting_it Iterator for the setting which contains the key (setting name) and attributes info
* \param path The path of (internal) setting names traversed to get to this object
* \param settings_base The settings base where to store the default values.
* \param warn_duplicates whether to warn for duplicate setting definitions
*/
void handleSetting(const rapidjson::Value::ConstMemberIterator& json_setting_it, std::list<std::string>& path, SettingsBase* settings_base, bool warn_duplicates);
void handleSetting(const rapidjson::Value::ConstMemberIterator& json_setting_it, SettingsBase* settings_base, bool warn_duplicates);
};
}//namespace cura
-12
Ver Arquivo
@@ -177,18 +177,6 @@ enum class SupportDistPriority
Z_OVERRIDES_XY
};
/*!
* Which color(s) of a texture to use
*/
enum class ColourUsage
{
RED = 0,
GREEN = 1,
BLUE = 2,
ALPHA = 3,
GREY // use red, green and blue channels
};
#define MAX_EXTRUDERS 16
//Maximum number of infill layers that can be combined into a single infill extrusion area.
+28 -2
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];
@@ -106,7 +121,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 +159,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];
+5 -5
Ver Arquivo
@@ -35,7 +35,7 @@ void SliceLayer::getOutlines(Polygons& result, bool external_polys_only) const
{
if (external_polys_only)
{
result.add(const_cast<SliceLayerPart&>(part).outline.outerPolygon()); // TODO: make a const version of outerPolygon()
result.add(part.outline.outerPolygon());
}
else
{
@@ -57,12 +57,12 @@ void SliceLayer::getSecondOrInnermostWalls(Polygons& layer_walls) const
{
// we want the 2nd inner walls
if (part.insets.size() >= 2) {
layer_walls.add(const_cast<SliceLayerPart&>(part).insets[1]); // TODO const cast!
layer_walls.add(part.insets[1]);
continue;
}
// but we'll also take the inner wall if the 2nd doesn't exist
if (part.insets.size() == 1) {
layer_walls.add(const_cast<SliceLayerPart&>(part).insets[0]); // TODO const cast!
layer_walls.add(part.insets[0]);
continue;
}
// offset_from_outlines was so large that it completely destroyed our isle,
@@ -163,7 +163,7 @@ Polygons SliceDataStorage::getLayerOutlines(int layer_nr, bool include_helper_pa
}
const SliceLayer& layer = mesh.layers[layer_nr];
layer.getOutlines(total, external_polys_only);
if (const_cast<SliceMeshStorage&>(mesh).getSettingAsSurfaceMode("magic_mesh_surface_mode") != ESurfaceMode::NORMAL) // TODO: make all getSetting functions const??
if (mesh.getSettingAsSurfaceMode("magic_mesh_surface_mode") != ESurfaceMode::NORMAL)
{
total = total.unionPolygons(layer.openPolyLines.offsetPolyLine(100));
}
@@ -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));
}
+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);
+138 -20
Ver Arquivo
@@ -1,11 +1,17 @@
/** Copyright (C) 2016 Tim Kuipers - Released under terms of the AGPLv3 License */
/** Copyright (C) 2013 David Braam - Released under terms of the AGPLv3 License */
#include <stdio.h>
#include "SlicerLayer.h"
#include "../TextureProcessor.h"
#include "../utils/SparsePointGridInclusive.h"
#include <algorithm> // remove_if
namespace cura
{
#include "utils/gettime.h"
#include "utils/logoutput.h"
#include "utils/SparsePointGridInclusive.h"
#include "slicer.h"
#include "multithreadOpenMP.h"
namespace cura {
int largest_neglected_gap_first_phase = MM2INT(0.01); //!< distance between two line segments regarded as connected
int largest_neglected_gap_second_phase = MM2INT(0.02); //!< distance between two line segments regarded as connected
@@ -211,7 +217,7 @@ SlicerLayer::findPossibleStitches(
// insert the starts of the polylines).
for(unsigned int polyline_0_idx = 0; polyline_0_idx < open_polylines.size(); polyline_0_idx++)
{
const PolygonRef polyline_0 = open_polylines[polyline_0_idx];
ConstPolygonRef polyline_0 = open_polylines[polyline_0_idx];
if (polyline_0.size() < 1) continue;
@@ -226,7 +232,7 @@ SlicerLayer::findPossibleStitches(
{
for(unsigned int polyline_0_idx = 0; polyline_0_idx < open_polylines.size(); polyline_0_idx++)
{
const PolygonRef polyline_0 = open_polylines[polyline_0_idx];
ConstPolygonRef polyline_0 = open_polylines[polyline_0_idx];
if (polyline_0.size() < 1) continue;
@@ -240,7 +246,7 @@ SlicerLayer::findPossibleStitches(
// search for nearby end points
for(unsigned int polyline_1_idx = 0; polyline_1_idx < open_polylines.size(); polyline_1_idx++)
{
const PolygonRef polyline_1 = open_polylines[polyline_1_idx];
ConstPolygonRef polyline_1 = open_polylines[polyline_1_idx];
if (polyline_1.size() < 1) continue;
@@ -584,7 +590,7 @@ void SlicerLayer::stitch_extensive(Polygons& open_polylines)
{
if (best_result.pointIdxA == best_result.pointIdxB)
{
polygons.add(open_polylines[best_polyline_1_idx]);
polygons.add(PolygonRef{open_polylines[best_polyline_1_idx]});
open_polylines[best_polyline_1_idx].clear();
}
else if (best_result.AtoB)
@@ -599,9 +605,9 @@ void SlicerLayer::stitch_extensive(Polygons& open_polylines)
else
{
unsigned int n = polygons.size();
polygons.add(open_polylines[best_polyline_1_idx]);
polygons.add(PolygonRef{open_polylines[best_polyline_1_idx]});
for(unsigned int j = best_result.pointIdxB; j != best_result.pointIdxA; j = (j + 1) % polygons[best_result.polygonIdx].size())
polygons[n].add(polygons[best_result.polygonIdx][j]);
PolygonRef{polygons[n]}.add(polygons[best_result.polygonIdx][j]);
open_polylines[best_polyline_1_idx].clear();
}
}
@@ -610,7 +616,7 @@ void SlicerLayer::stitch_extensive(Polygons& open_polylines)
if (best_result.pointIdxA == best_result.pointIdxB)
{
for(unsigned int n=0; n<open_polylines[best_polyline_1_idx].size(); n++)
open_polylines[best_polyline_2_idx].add(open_polylines[best_polyline_1_idx][n]);
PolygonRef{open_polylines[best_polyline_2_idx]}.add(open_polylines[best_polyline_1_idx][n]);
open_polylines[best_polyline_1_idx].clear();
}
else if (best_result.AtoB)
@@ -619,17 +625,17 @@ void SlicerLayer::stitch_extensive(Polygons& open_polylines)
for(unsigned int n = best_result.pointIdxA; n != best_result.pointIdxB; n = (n + 1) % polygons[best_result.polygonIdx].size())
poly.add(polygons[best_result.polygonIdx][n]);
for(unsigned int n=poly.size()-1;int(n) >= 0; n--)
open_polylines[best_polyline_2_idx].add(poly[n]);
PolygonRef{open_polylines[best_polyline_2_idx]}.add(poly[n]);
for(unsigned int n=0; n<open_polylines[best_polyline_1_idx].size(); n++)
open_polylines[best_polyline_2_idx].add(open_polylines[best_polyline_1_idx][n]);
PolygonRef{open_polylines[best_polyline_2_idx]}.add(open_polylines[best_polyline_1_idx][n]);
open_polylines[best_polyline_1_idx].clear();
}
else
{
for(unsigned int n = best_result.pointIdxB; n != best_result.pointIdxA; n = (n + 1) % polygons[best_result.polygonIdx].size())
open_polylines[best_polyline_2_idx].add(polygons[best_result.polygonIdx][n]);
PolygonRef{open_polylines[best_polyline_2_idx]}.add(polygons[best_result.polygonIdx][n]);
for(unsigned int n = open_polylines[best_polyline_1_idx].size() - 1; int(n) >= 0; n--)
open_polylines[best_polyline_2_idx].add(open_polylines[best_polyline_1_idx][n]);
PolygonRef{open_polylines[best_polyline_2_idx]}.add(open_polylines[best_polyline_1_idx][n]);
open_polylines[best_polyline_1_idx].clear();
}
}
@@ -769,8 +775,6 @@ void SlicerLayer::makePolygons(const Mesh* mesh, bool keep_none_closed, bool ext
auto it = std::remove_if(polygons.begin(), polygons.end(), [snapDistance](PolygonRef poly) { return poly.shorterThan(snapDistance); });
polygons.erase(it, polygons.end());
TextureProcessor::processBumpMap(mesh, *this);
//Finally optimize all the polygons. Every point removed saves time in the long run.
polygons.simplify();
@@ -783,4 +787,118 @@ void SlicerLayer::makePolygons(const Mesh* mesh, bool keep_none_closed, bool ext
}
}
} // namespace cura
Slicer::Slicer(Mesh* mesh, int initial, int thickness, int slice_layer_count, bool keep_none_closed, bool extensive_stitching)
: mesh(mesh)
{
assert(slice_layer_count > 0);
TimeKeeper slice_timer;
layers.resize(slice_layer_count);
for(int32_t layer_nr = 0; layer_nr < slice_layer_count; layer_nr++)
{
layers[layer_nr].z = initial + thickness * layer_nr;
}
for(unsigned int mesh_idx = 0; mesh_idx < mesh->faces.size(); mesh_idx++)
{
const MeshFace& face = mesh->faces[mesh_idx];
const MeshVertex& v0 = mesh->vertices[face.vertex_index[0]];
const MeshVertex& v1 = mesh->vertices[face.vertex_index[1]];
const MeshVertex& v2 = mesh->vertices[face.vertex_index[2]];
Point3 p0 = v0.p;
Point3 p1 = v1.p;
Point3 p2 = v2.p;
int32_t minZ = p0.z;
int32_t maxZ = p0.z;
if (p1.z < minZ) minZ = p1.z;
if (p2.z < minZ) minZ = p2.z;
if (p1.z > maxZ) maxZ = p1.z;
if (p2.z > maxZ) maxZ = p2.z;
int32_t layer_max = (maxZ - initial) / thickness;
for(int32_t layer_nr = (minZ - initial) / thickness; layer_nr <= layer_max; layer_nr++)
{
int32_t z = layer_nr * thickness + initial;
if (z < minZ) continue;
if (layer_nr < 0) continue;
SlicerSegment s;
s.endVertex = nullptr;
int end_edge_idx = -1;
if (p0.z < z && p1.z >= z && p2.z >= z)
{
s = project2D(p0, p2, p1, z);
end_edge_idx = 0;
if (p1.z == z)
{
s.endVertex = &v1;
}
}
else if (p0.z > z && p1.z < z && p2.z < z)
{
s = project2D(p0, p1, p2, z);
end_edge_idx = 2;
}
else if (p1.z < z && p0.z >= z && p2.z >= z)
{
s = project2D(p1, p0, p2, z);
end_edge_idx = 1;
if (p2.z == z)
{
s.endVertex = &v2;
}
}
else if (p1.z > z && p0.z < z && p2.z < z)
{
s = project2D(p1, p2, p0, z);
end_edge_idx = 0;
}
else if (p2.z < z && p1.z >= z && p0.z >= z)
{
s = project2D(p2, p1, p0, z);
end_edge_idx = 2;
if (p0.z == z)
{
s.endVertex = &v0;
}
}
else if (p2.z > z && p1.z < z && p0.z < z)
{
s = project2D(p2, p0, p1, z);
end_edge_idx = 1;
}
else
{
//Not all cases create a segment, because a point of a face could create just a dot, and two touching faces
// on the slice would create two segments
continue;
}
layers[layer_nr].face_idx_to_segment_idx.insert(std::make_pair(mesh_idx, layers[layer_nr].segments.size()));
s.faceIndex = mesh_idx;
s.endOtherFaceIdx = face.connected_face_index[end_edge_idx];
s.addedToPolygon = false;
layers[layer_nr].segments.push_back(s);
}
}
log("slice of mesh took %.3f seconds\n",slice_timer.restart());
auto& layers_ref = layers;
#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++)
{ MULTITHREAD_FOR_CATCH_EXCEPTION(
layers_ref[layer_nr].makePolygons(mesh, keep_none_closed, extensive_stitching);
)}
handleMultithreadAbort();
mesh->expandXY(mesh->getSettingInMicrons("xy_offset"));
log("slice make polygons took %.3f seconds\n",slice_timer.restart());
}
}//namespace cura
+80 -18
Ver Arquivo
@@ -1,21 +1,47 @@
/** Copyright (C) 2016 Tim Kuipers - Released under terms of the AGPLv3 License */
#ifndef SLICER_SLICER_LAYER_H
#define SLICER_SLICER_LAYER_H
/** Copyright (C) 2013 David Braam - Released under terms of the AGPLv3 License */
#ifndef SLICER_H
#define SLICER_H
#include <unordered_map>
#include <queue>
#include "../mesh.h"
#include "../utils/intpoint.h"
#include "../utils/polygon.h"
#include "mesh.h"
#include "utils/polygon.h"
/*
The Slicer creates layers of polygons from an optimized 3D model.
The result of the Slicer is a list of polygons without any order or structure.
*/
namespace cura {
#include "SlicerSegment.h"
#include "GapCloserResult.h"
#include "ClosePolygonResult.h"
#include "../MatSegment.h"
namespace cura
class SlicerSegment
{
public:
Point start, end;
int faceIndex = -1;
// The index of the other face connected via the edge that created end
int endOtherFaceIdx = -1;
// If end corresponds to a vertex of the mesh, then this is populated
// with the vertex that it ended on.
const MeshVertex *endVertex = nullptr;
bool addedToPolygon = false;
};
class ClosePolygonResult
{ //The result of trying to find a point on a closed polygon line. This gives back the point index, the polygon index, and the point of the connection.
//The line on which the point lays is between pointIdx-1 and pointIdx
public:
Point intersectionPoint;
int polygonIdx = -1;
unsigned int pointIdx = -1;
};
class GapCloserResult
{
public:
int64_t len = -1;
int polygonIdx = -1;
unsigned int pointIdxA = -1;
unsigned int pointIdxB = -1;
bool AtoB = false;
};
class SlicerLayer
{
@@ -26,8 +52,6 @@ public:
int z = -1;
Polygons polygons;
Polygons openPolylines;
std::unordered_map<SlicerSegment, MatSegment> segment_to_material_segment;
/*!
* Connect the segments into polygons for this layer of this \p mesh
@@ -459,6 +483,44 @@ private:
bool allow_reverse);
};
} // namespace cura
class Slicer
{
public:
std::vector<SlicerLayer> layers;
#endif // SLICER_SLICER_LAYER_H
const Mesh* mesh = nullptr; //!< The sliced mesh
Slicer(Mesh* mesh, int initial, int thickness, int slice_layer_count, bool keepNoneClosed, bool extensiveStitching);
/*!
* Linear interpolation
*
* Get the Y of a point with X \p x in the line through (\p x0, \p y0) and (\p x1, \p y1)
*/
int64_t interpolate(int64_t x, int64_t x0, int64_t x1, int64_t y0, int64_t y1) const
{
int64_t dx_01 = x1 - x0;
int64_t num = (y1 - y0) * (x - x0);
num += num > 0 ? dx_01/2 : -dx_01/2; // add in offset to round result
int64_t y = y0 + num / dx_01;
return y;
}
SlicerSegment project2D(Point3& p0, Point3& p1, Point3& p2, int32_t z) const
{
SlicerSegment seg;
seg.start.X = interpolate(z, p0.z, p1.z, p0.x, p1.x);
seg.start.Y = interpolate(z, p0.z, p1.z, p0.y, p1.y);
seg.end .X = interpolate(z, p0.z, p2.z, p0.x, p2.x);
seg.end .Y = interpolate(z, p0.z, p2.z, p0.y, p2.y);
return seg;
}
void dumpSegmentsToHTML(const char* filename);
};
}//namespace cura
#endif//SLICER_H
-21
Ver Arquivo
@@ -1,21 +0,0 @@
/** Copyright (C) 2016 Tim Kuipers - Released under terms of the AGPLv3 License */
#ifndef SLICER_CLOSE_POLYGON_RESULT_H
#define SLICER_CLOSE_POLYGON_RESULT_H
#include "../utils/intpoint.h"
namespace cura
{
class ClosePolygonResult
{ //The result of trying to find a point on a closed polygon line. This gives back the point index, the polygon index, and the point of the connection.
//The line on which the point lays is between pointIdx-1 and pointIdx
public:
Point intersectionPoint;
int polygonIdx = -1;
unsigned int pointIdx = -1;
};
} // namespace cura
#endif // SLICER_CLOSE_POLYGON_RESULT_H
-22
Ver Arquivo
@@ -1,22 +0,0 @@
/** Copyright (C) 2016 Tim Kuipers - Released under terms of the AGPLv3 License */
#ifndef SLICER_GAP_CLOSER_RESULT_H
#define SLICER_GAP_CLOSER_RESULT_H
#include "../utils/intpoint.h"
namespace cura
{
class GapCloserResult
{
public:
int64_t len = -1;
int polygonIdx = -1;
unsigned int pointIdxA = -1;
unsigned int pointIdxB = -1;
bool AtoB = false;
};
} // namespace cura
#endif // SLICER_GAP_CLOSER_RESULT_H
-147
Ver Arquivo
@@ -1,147 +0,0 @@
/** Copyright (C) 2013 David Braam - Released under terms of the AGPLv3 License */
#include <stdio.h>
#include "../utils/gettime.h"
#include "../utils/logoutput.h"
#include "../MatCoord.h"
#include "Slicer.h"
namespace cura {
SlicerSegment Slicer::project2D(unsigned int face_idx, const Point3 p[3], unsigned int idx_shared, unsigned int idx_first, unsigned int idx_second, int32_t z, int32_t layer_nr)
{
const Point3& p0 = p[idx_shared];
const Point3& p1 = p[idx_first];
const Point3& p2 = p[idx_second];
SlicerSegment seg;
seg.start.X = interpolate(z, p0.z, p1.z, p0.x, p1.x);
seg.start.Y = interpolate(z, p0.z, p1.z, p0.y, p1.y);
seg.end .X = interpolate(z, p0.z, p2.z, p0.x, p2.x);
seg.end .Y = interpolate(z, p0.z, p2.z, p0.y, p2.y);
MatSegment mat_segment;
bool got_texture_coords = mesh->registerFaceSlice(face_idx, idx_shared, idx_first, idx_second, z, seg.start, seg.end, mat_segment);
if (got_texture_coords)
{
SlicerLayer& layer = layers[layer_nr];
layer.segment_to_material_segment.emplace(seg, mat_segment);
}
return seg;
}
Slicer::Slicer(Mesh* mesh, int initial, int thickness, int slice_layer_count, bool keep_none_closed, bool extensive_stitching)
: mesh(mesh)
{
assert(slice_layer_count > 0);
TimeKeeper slice_timer;
layers.resize(slice_layer_count);
for(int32_t layer_nr = 0; layer_nr < slice_layer_count; layer_nr++)
{
layers[layer_nr].z = initial + thickness * layer_nr;
}
for(unsigned int face_idx = 0; face_idx < mesh->faces.size(); face_idx++)
{
const MeshFace& face = mesh->faces[face_idx];
const MeshVertex& v0 = mesh->vertices[face.vertex_index[0]];
const MeshVertex& v1 = mesh->vertices[face.vertex_index[1]];
const MeshVertex& v2 = mesh->vertices[face.vertex_index[2]];
Point3 p[3] =
{ mesh->vertices[face.vertex_index[0]].p
, mesh->vertices[face.vertex_index[1]].p
, mesh->vertices[face.vertex_index[2]].p };
Point3& p0 = p[0];
Point3& p1 = p[1];
Point3& p2 = p[2];
int32_t minZ = p0.z;
int32_t maxZ = p0.z;
if (p1.z < minZ) minZ = p1.z;
if (p2.z < minZ) minZ = p2.z;
if (p1.z > maxZ) maxZ = p1.z;
if (p2.z > maxZ) maxZ = p2.z;
int32_t layer_max = (maxZ - initial) / thickness;
int32_t z = 0;
for (int32_t layer_nr = (minZ - initial + thickness - 1) / thickness; layer_nr < layer_max; layer_nr++) // + thickness - 1 to get the first layer above or at minZ
{
z = layer_nr * thickness + initial;
if (z < minZ) continue;
if (layer_nr < 0) continue;
SlicerSegment s;
s.endVertex = nullptr;
int end_edge_idx = -1;
if (p0.z < z && p1.z >= z && p2.z >= z)
{
s = project2D(face_idx, p, 0, 2, 1, z, layer_nr);
end_edge_idx = 0;
if (p1.z == z)
{
s.endVertex = &v1;
}
}
else if (p0.z > z && p1.z < z && p2.z < z)
{
s = project2D(face_idx, p, 0, 1, 2, z, layer_nr);
end_edge_idx = 2;
}
else if (p1.z < z && p0.z >= z && p2.z >= z)
{
s = project2D(face_idx, p, 1, 0, 2, z, layer_nr);
end_edge_idx = 1;
if (p2.z == z)
{
s.endVertex = &v2;
}
}
else if (p1.z > z && p0.z < z && p2.z < z)
{
s = project2D(face_idx, p, 1, 2, 0, z, layer_nr);
end_edge_idx = 0;
}
else if (p2.z < z && p1.z >= z && p0.z >= z)
{
s = project2D(face_idx, p, 2, 1, 0, z, layer_nr);
end_edge_idx = 2;
if (p0.z == z)
{
s.endVertex = &v0;
}
}
else if (p2.z > z && p1.z < z && p0.z < z)
{
s = project2D(face_idx, p, 2, 0, 1, z, layer_nr);
end_edge_idx = 1;
}
else
{
//Not all cases create a segment, because a point of a face could create just a dot, and two touching faces
// on the slice would create two segments
continue;
}
layers[layer_nr].face_idx_to_segment_idx.insert(std::make_pair(face_idx, layers[layer_nr].segments.size()));
s.faceIndex = face_idx;
s.endOtherFaceIdx = face.connected_face_index[end_edge_idx];
s.addedToPolygon = false;
layers[layer_nr].segments.push_back(s);
}
}
log("slice of mesh took %.3f seconds\n",slice_timer.restart());
for(unsigned int layer_nr=0; layer_nr<layers.size(); layer_nr++)
{
layers[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());
}
}//namespace cura
-60
Ver Arquivo
@@ -1,60 +0,0 @@
/** Copyright (C) 2013 David Braam - Released under terms of the AGPLv3 License */
#ifndef SLICER_SLICER_H
#define SLICER_SLICER_H
#include <queue>
#include "../mesh.h"
#include "../utils/polygon.h"
#include "SlicerSegment.h"
#include "ClosePolygonResult.h"
#include "SlicerLayer.h"
#include "../MatSegment.h"
/*
The Slicer creates layers of polygons from an optimized 3D model.
The result of the Slicer is a list of polygons without any order or structure.
*/
namespace cura {
class Slicer
{
public:
std::vector<SlicerLayer> layers;
const Mesh* mesh = nullptr; //!< The sliced mesh
Slicer(Mesh* mesh, int initial, int thickness, int slice_layer_count, bool keepNoneClosed, bool extensiveStitching);
/*!
* Linear interpolation
*
* Get the Y of a point with X \p x in the line through (\p x0, \p y0) and (\p x1, \p y1)
*
* \param p The face vertice locations in the order the vertices are given in the face
*/
int64_t interpolate(int64_t x, int64_t x0, int64_t x1, int64_t y0, int64_t y1) const
{
int64_t dx_01 = x1 - x0;
int64_t num = (y1 - y0) * (x - x0);
num += num > 0 ? dx_01/2 : -dx_01/2; // add in offset to round result
int64_t y = y0 + num / dx_01;
return y;
}
SlicerSegment project2D(unsigned int face_idx, const Point3 p[3], unsigned int idx_shared, unsigned int idx_first, unsigned int idx_second, int32_t z, int32_t layer_nr);
void dumpSegmentsToHTML(const char* filename);
};
}//namespace cura
#endif//SLICER_SLICER_H
-57
Ver Arquivo
@@ -1,57 +0,0 @@
/** Copyright (C) 2016 Tim Kuipers - Released under terms of the AGPLv3 License */
#ifndef SLICER_SLICER_SEGMENT_H
#define SLICER_SLICER_SEGMENT_H
#include <functional>
#include "../utils/intpoint.h"
namespace cura
{
class SlicerSegment
{
public:
Point start, end;
int faceIndex = -1;
// The index of the other face connected via the edge that created end
int endOtherFaceIdx = -1;
// If end corresponds to a vertex of the mesh, then this is populated
// with the vertex that it ended on.
const MeshVertex *endVertex = nullptr;
bool addedToPolygon = false;
SlicerSegment() //!< non-initializing constructor
{}
SlicerSegment(Point start, Point end) //!< partially initializing constructor
: start(start)
, end(end)
{}
/*!
* equivalence testing irrespective of start/end order
*/
bool operator==(const SlicerSegment& b) const
{
return (start == b.start && end == b.end) || (start == b.end && end == b.start);
}
};
} // namespace cura
namespace std
{
/*!
* hash function irrespective of start/end order
*/
template<> struct hash<cura::SlicerSegment>
{
typedef std::size_t result_type;
result_type operator()(cura::SlicerSegment const& s) const
{
return std::hash<cura::Point>()(cura::operator+(s.start, s.end));
}
};
} // namespace std
#endif // SLICER_SLICER_SEGMENT_H
+56 -50
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));
}
}
@@ -499,7 +508,7 @@ void AreaSupport::handleTowers(
{
supportLayer_this = supportLayer_this.unionPolygons(tower_roof);
if (tower_roof[0].area() < supportTowerDiameter * supportTowerDiameter)
if (PolygonRef{tower_roof[0]}.area() < supportTowerDiameter * supportTowerDiameter)
{
tower_roof = tower_roof.offset(towerRoofExpansionDistance);
}
@@ -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.
+2 -2
Ver Arquivo
@@ -24,7 +24,7 @@ AABB::AABB(const Polygons& polys)
calculate(polys);
}
AABB::AABB(const PolygonRef poly)
AABB::AABB(const PolygonRef& poly)
: min(POINT_MAX, POINT_MAX), max(POINT_MIN, POINT_MIN)
{
calculate(poly);
@@ -43,7 +43,7 @@ void AABB::calculate(const Polygons& polys)
}
}
void AABB::calculate(const PolygonRef poly)
void AABB::calculate(const PolygonRef& poly)
{
min = Point(POINT_MAX, POINT_MAX);
max = Point(POINT_MIN, POINT_MIN);
+2 -2
Ver Arquivo
@@ -20,10 +20,10 @@ public:
AABB(); //!< initializes with invalid min and max
AABB(Point& min, Point& max); //!< initializes with given min and max
AABB(const Polygons& polys); //!< Computes the boundary box for the given polygons
AABB(const PolygonRef poly); //!< Computes the boundary box for the given polygons
AABB(const PolygonRef& poly); //!< Computes the boundary box for the given polygons
void calculate(const Polygons& polys); //!< Calculates the aabb for the given polygons (throws away old min and max data of this aabb)
void calculate(const PolygonRef poly); //!< Calculates the aabb for the given polygon (throws away old min and max data of this aabb)
void calculate(const PolygonRef& poly); //!< Calculates the aabb for the given polygon (throws away old min and max data of this aabb)
/*!
* Check whether this aabb overlaps with another.
+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.
-74
Ver Arquivo
@@ -1,74 +0,0 @@
/** Copyright (C) 2016 Tim Kuipers - Released under terms of the AGPLv3 License */
#ifndef UTILS_F_POINT_H
#define UTILS_F_POINT_H
#include <cmath> // sqrt
#include <iostream> // auto-serialization / auto-toString() '<<'
namespace cura
{
/*!
* 2D coordinates represented by floats
*/
class FPoint
{
public:
float x, y; //!< Coordinates
FPoint() //!< non-initializing constructor
{}
FPoint(float x, float y) //!< constructor
: x(x)
, y(y)
{}
FPoint operator+(const FPoint& p) const { return FPoint(x+p.x, y+p.y); }
FPoint operator-(const FPoint& p) const { return FPoint(x-p.x, y-p.y); }
FPoint operator/(const float i) const { return FPoint(x/i, y/i); }
FPoint operator*(const float i) const { return FPoint(x*i, y*i); }
FPoint& operator += (const FPoint& p) { x += p.x; y += p.y; return *this; }
FPoint& operator -= (const FPoint& p) { x -= p.x; y -= p.y; return *this; }
bool operator==(const FPoint& p) const { return x == p.x && y == p.y; }
bool operator!=(const FPoint& p) const { return x != p.x || y != p.y; }
/*!
* output to string stream in standard format
*/
template<class CharT, class TraitsT>
friend
std::basic_ostream<CharT, TraitsT>&
operator <<(std::basic_ostream<CharT, TraitsT>& os, const FPoint& p)
{
return os << "(" << p.x << ", " << p.y << ")";
}
/*!
* squared vector size
*/
float vSize2() const
{
return x * x + y * y;
}
/*!
* vector size
*/
float vSize() const
{
return sqrt(vSize2());
}
/*!
* dot product
*/
float dot(const FPoint& p) const
{
return x * p.x + y * p.y;
}
};
} // namespace cura
#endif // UTILS_F_POINT_H
+2 -2
Ver Arquivo
@@ -19,12 +19,12 @@ void ListPolyIt::convertPolygonsToLists(Polygons& polys, ListPolygons& result)
}
}
void ListPolyIt::convertPolygonToList(PolygonRef poly, ListPolygon& result)
void ListPolyIt::convertPolygonToList(const PolygonRef& poly, ListPolygon& result)
{
#ifdef DEBUG
Point last = poly.back();
#endif // DEBUG
for (Point& p : poly)
for (const Point& p : poly)
{
result.push_back(p);
#ifdef DEBUG
+1 -1
Ver Arquivo
@@ -101,7 +101,7 @@ public:
* \param polys The polygons to convert
* \param result The converted polygons
*/
static void convertPolygonToList(PolygonRef poly, ListPolygon& result);
static void convertPolygonToList(const PolygonRef& poly, ListPolygon& result);
/*!
* Convert ListPolygons to Polygons
*
+1 -1
Ver Arquivo
@@ -46,7 +46,7 @@ public:
/*!
* Get the polygon to which this PolygonsPointIndex refers
*/
const PolygonRef getPolygon() const
const ConstPolygonRef getPolygon() const
{
return (*polygons)[poly_idx];
}
+5 -5
Ver Arquivo
@@ -93,7 +93,7 @@ public:
{
for(unsigned int j=0;j<parts.size();j++)
{
Polygon poly = parts[j];
Polygon poly = PolygonRef{parts[j]};
fprintf(out, "<polygon points=\"");
for(Point& p : poly)
{
@@ -130,9 +130,9 @@ public:
}
}
void writePoints(PolygonRef poly, bool write_coords=false, int size = 5, Color color = Color::BLACK)
void writePoints(ConstPolygonRef poly, bool write_coords=false, int size = 5, Color color = Color::BLACK)
{
for (Point& p : poly)
for (const Point& p : poly)
{
writePoint(p, write_coords, size, color);
}
@@ -209,12 +209,12 @@ public:
}
void writePolygons(const Polygons& polys, Color color = Color::BLACK)
{
for (const PolygonRef poly : const_cast<Polygons&>(polys))
for (ConstPolygonRef poly : polys)
{
writePolygon(poly, color);
}
}
void writePolygon(const PolygonRef poly, Color color = Color::BLACK)
void writePolygon(ConstPolygonRef poly, Color color = Color::BLACK)
{
Point p0 = poly.back();
for (Point p1 : poly)
+68 -41
Ver Arquivo
@@ -8,6 +8,23 @@
namespace cura
{
/*
* Implementation of offset polygon used by PolygonRef and ConstPolygonRef
*
* \param ret_paths[out] where the offset polygon is stored.
* \param path the path to be offset.
* \param distance the distance to offset path.
* \param joinType See ClipperLib documentation.
* \param miter_limit See ClipperLib documentation.
*/
inline void PolygonRef_offset_impl(ClipperLib::Paths& ret_path, const ClipperLib::Path& path, int distance, ClipperLib::JoinType join_type, double miter_limit)
{
ClipperLib::ClipperOffset clipper(miter_limit, 10.0);
clipper.AddPath(path, join_type, ClipperLib::etClosedPolygon);
clipper.MiterLimit = miter_limit;
clipper.Execute(ret_path, distance);
}
bool PolygonRef::shorterThan(int64_t check_length) const
{
const PolygonRef& polygon = *this;
@@ -27,7 +44,7 @@ bool PolygonRef::shorterThan(int64_t check_length) const
bool PolygonRef::_inside(Point p, bool border_result) const
{
PolygonRef thiss = *this;
const PolygonRef& thiss = *this;
if (size() < 1)
{
return false;
@@ -190,16 +207,6 @@ unsigned int Polygons::findInside(Point p, bool border_result)
return ret;
}
Polygons Polygons::removeComplexParts() const
{
Polygons ret;
ClipperLib::Clipper clipper(clipper_init);
clipper.AddPaths(paths, ClipperLib::ptSubject, true);
clipper.Execute(ClipperLib::ctUnion, ret.paths, ClipperLib::pftPositive);
return ret;
}
Polygons Polygons::offset(int distance, ClipperLib::JoinType join_type, double miter_limit) const
{
Polygons ret;
@@ -213,10 +220,7 @@ Polygons Polygons::offset(int distance, ClipperLib::JoinType join_type, double m
Polygons PolygonRef::offset(int distance, ClipperLib::JoinType joinType, double miter_limit) const
{
Polygons ret;
ClipperLib::ClipperOffset clipper(miter_limit, 10.0);
clipper.AddPath(*path, joinType, ClipperLib::etClosedPolygon);
clipper.MiterLimit = miter_limit;
clipper.Execute(ret.paths, distance);
PolygonRef_offset_impl(ret.paths, *path, distance, joinType, miter_limit);
return ret;
}
@@ -962,7 +966,7 @@ Polygons Polygons::smooth_outward(float max_angle, int shortcut_length)
return ret;
}
void PolygonRef::smooth(int remove_length, PolygonRef result)
inline void PolygonRef_smooth_impl(const ClipperLib::Path& thiss, int remove_length, ClipperLib::Path* poly)
{
// a typical zigzag with the middle part to be removed by removing (1) :
//
@@ -977,9 +981,7 @@ void PolygonRef::smooth(int remove_length, PolygonRef result)
// |
// |
// 0
PolygonRef& thiss = *this;
ClipperLib::Path* poly = result.path;
if (size() > 0)
if (thiss.size() > 0)
{
poly->push_back(thiss[0]);
}
@@ -1013,11 +1015,11 @@ void PolygonRef::smooth(int remove_length, PolygonRef result)
Point v02T = turn90CCW(v02);
int64_t v02_size = vSize(v02);
bool force_push = false;
for (unsigned int poly_idx = 1; poly_idx < size(); poly_idx++)
for (unsigned int poly_idx = 1; poly_idx < thiss.size(); poly_idx++)
{
const Point& p1 = thiss[poly_idx];
const Point& p2 = thiss[(poly_idx + 1) % size()];
const Point& p3 = thiss[(poly_idx + 2) % size()];
const Point& p2 = thiss[(poly_idx + 1) % thiss.size()];
const Point& p3 = thiss[(poly_idx + 2) % thiss.size()];
// v02 computed in last iteration
// v02_size as well
const Point v12 = p2 - p1;
@@ -1046,12 +1048,22 @@ void PolygonRef::smooth(int remove_length, PolygonRef result)
}
}
Polygons Polygons::smooth(int remove_length)
void PolygonRef::smooth(int remove_length, PolygonRef result) const
{
PolygonRef_smooth_impl(*path, remove_length, result.path);
}
void ConstPolygonRef::smooth(int remove_length, PolygonRef result) const
{
PolygonRef_smooth_impl(*path, remove_length, &(*result));
}
Polygons Polygons::smooth(int remove_length) const
{
Polygons ret;
for (unsigned int p = 0; p < size(); p++)
{
PolygonRef poly(paths[p]);
ConstPolygonRef poly(paths[p]);
if (poly.size() < 3)
{
continue;
@@ -1071,23 +1083,21 @@ Polygons Polygons::smooth(int remove_length)
return ret;
}
void PolygonRef::smooth2(int remove_length, PolygonRef result)
inline void PolygonRef_smooth2_impl(const ClipperLib::Path& thiss, int remove_length, ClipperLib::Path* poly)
{
PolygonRef& thiss = *this;
ClipperLib::Path* poly = result.path;
if (size() > 0)
if (thiss.size() > 0)
{
poly->push_back(thiss[0]);
}
for (unsigned int poly_idx = 1; poly_idx < size(); poly_idx++)
for (unsigned int poly_idx = 1; poly_idx < thiss.size(); poly_idx++)
{
Point& last = thiss[poly_idx - 1];
Point& now = thiss[poly_idx];
Point& next = thiss[(poly_idx + 1) % size()];
if (shorterThen(last - now, remove_length) && shorterThen(now - next, remove_length))
const Point& last = thiss[poly_idx - 1];
const Point& now = thiss[poly_idx];
const Point& next = thiss[(poly_idx + 1) % thiss.size()];
if (shorterThen(last - now, remove_length) && shorterThen(now - next, remove_length))
{
poly_idx++; // skip the next line piece (dont escalate the removal of edges)
if (poly_idx < size())
if (poly_idx < thiss.size())
{
poly->push_back(thiss[poly_idx]);
}
@@ -1099,12 +1109,22 @@ void PolygonRef::smooth2(int remove_length, PolygonRef result)
}
}
Polygons Polygons::smooth2(int remove_length, int min_area)
void PolygonRef::smooth2(int remove_length, PolygonRef result) const
{
PolygonRef_smooth2_impl(*path, remove_length, result.path);
}
void ConstPolygonRef::smooth2(int remove_length, PolygonRef result) const
{
PolygonRef_smooth2_impl(*path, remove_length, &(*result));
}
Polygons Polygons::smooth2(int remove_length, int min_area) const
{
Polygons ret;
for (unsigned int p = 0; p < size(); p++)
{
PolygonRef poly(paths[p]);
ConstPolygonRef poly(paths[p]);
if (poly.size() == 0)
{
continue;
@@ -1126,6 +1146,13 @@ Polygons Polygons::smooth2(int remove_length, int min_area)
return ret;
}
Polygons ConstPolygonRef::offset(int distance, ClipperLib::JoinType joinType, double miter_limit) const
{
Polygons ret;
PolygonRef_offset_impl(ret.paths, *path, distance, joinType, miter_limit);
return ret;
}
std::vector<PolygonsPart> Polygons::splitIntoParts(bool unionAll) const
{
std::vector<PolygonsPart> ret;
@@ -1147,10 +1174,10 @@ void Polygons::splitIntoParts_processPolyTreeNode(ClipperLib::PolyNode* node, st
{
ClipperLib::PolyNode* child = node->Childs[n];
PolygonsPart part;
part.add(child->Contour);
part.add(ConstPolygonRef{child->Contour});
for(int i=0; i<child->ChildCount(); i++)
{
part.add(child->Childs[i]->Contour);
part.add(ConstPolygonRef{child->Childs[i]->Contour});
splitIntoParts_processPolyTreeNode(child->Childs[i], ret);
}
ret.push_back(part);
@@ -1182,7 +1209,7 @@ PolygonsPart PartsView::assemblePart(unsigned int part_idx) const
{
for (unsigned int poly_idx_ff : partsView[part_idx])
{
ret.add(polygons[poly_idx_ff]);
ret.add(PolygonRef{polygons[poly_idx_ff]});
}
}
return ret;
@@ -1225,11 +1252,11 @@ void Polygons::splitIntoPartsView_processPolyTreeNode(PartsView& partsView, Poly
partsView.emplace_back();
unsigned int pos = partsView.size() - 1;
partsView[pos].push_back(reordered.size());
reordered.add(child->Contour);
reordered.add(ConstPolygonRef{child->Contour}); //TODO: should this steal the internal representation for speed?
for(int i = 0; i < child->ChildCount(); i++)
{
partsView[pos].push_back(reordered.size());
reordered.add(child->Childs[i]->Contour);
reordered.add(ConstPolygonRef{child->Childs[i]->Contour});
splitIntoPartsView_processPolyTreeNode(partsView, reordered, child->Childs[i]);
}
}
+231 -40
Ver Arquivo
@@ -43,6 +43,12 @@ class PolygonRef
: path(nullptr)
{}
public:
PolygonRef(PolygonRef& polygon)
:path{polygon.path}
{}
PolygonRef(PolygonRef&& polygon)
:path{polygon.path}
{}
PolygonRef(ClipperLib::Path& polygon)
: path(&polygon)
{}
@@ -54,7 +60,7 @@ public:
Point& operator[] (unsigned int index) const
{
POLY_ASSERT(index < size() && index >= 0);
POLY_ASSERT(index < size() && index <= std::numeric_limits<int>::max());
return (*path)[index];
}
@@ -78,7 +84,9 @@ public:
bool operator==(const PolygonRef& other) const =delete;
ClipperLib::Path& operator*() { return *path; }
const ClipperLib::Path& operator*() const { return *path; }
template <typename... Args>
void emplace_back(Args&&... args)
{
@@ -87,7 +95,7 @@ public:
void remove(unsigned int index)
{
POLY_ASSERT(index < size() && index >= 0);
POLY_ASSERT(index < size() && index <= std::numeric_limits<int>::max());
path->erase(path->begin() + index);
}
@@ -190,7 +198,7 @@ public:
return Point(x, y);
}
Point closestPointTo(Point p)
Point closestPointTo(Point p) const
{
Point ret = p;
float bestDist = FLT_MAX;
@@ -253,7 +261,7 @@ public:
* \param remove_length The length of the largest segment removed
* \param result (output) The result polygon, assumed to be empty
*/
void smooth(int remove_length, PolygonRef result);
void smooth(int remove_length, PolygonRef result) const;
/*!
* Smooth out sharp inner corners, by taking a shortcut which bypasses the corner
@@ -271,7 +279,7 @@ public:
* \param remove_length The length of the largest segment removed
* \param result (output) The result polygon, assumed to be empty
*/
void smooth2(int remove_length, PolygonRef result);
void smooth2(int remove_length, PolygonRef result) const;
/*!
* Removes consecutive line segments with same orientation and changes this polygon.
@@ -375,6 +383,193 @@ private:
static void smooth_outward_step(const Point p1, const int64_t shortcut_length2, ListPolyIt& p0_it, ListPolyIt& p2_it, bool& forward_is_blocked, bool& backward_is_blocked, bool& forward_is_too_far, bool& backward_is_too_far);
};
class ConstPolygonRef
{
const ClipperLib::Path* path;
ConstPolygonRef()
: path(nullptr)
{}
public:
ConstPolygonRef(const ClipperLib::Path& polygon)
: path(&polygon)
{}
ConstPolygonRef(const PolygonRef& polygon)
: path(&(*polygon))
{}
unsigned int size() const
{
return path->size();
}
const Point& operator[] (unsigned int index) const
{
POLY_ASSERT(index < size());
return (*path)[index];
}
const void* data() const
{
return path->data();
}
ConstPolygonRef& operator=(const ConstPolygonRef& other) { path = other.path; return *this; }
ConstPolygonRef& operator=(const PolygonRef& other) { path = &(*other); return *this; }
bool operator==(const ConstPolygonRef& other) const =delete;
const ClipperLib::Path& operator*() const { return *path; }
/*!
* On Y-axis positive upward displays, Orientation will return true if the polygon's orientation is counter-clockwise.
*
* from http://www.angusj.com/delphi/clipper/documentation/Docs/Units/ClipperLib/Functions/Orientation.htm
*/
bool orientation() const
{
return ClipperLib::Orientation(*path);
}
Polygons offset(int distance, ClipperLib::JoinType joinType = ClipperLib::jtMiter, double miter_limit = 1.2) const;
int64_t polygonLength() const
{
int64_t length = 0;
Point p0 = (*path)[path->size()-1];
for(unsigned int n=0; n<path->size(); n++)
{
Point p1 = (*path)[n];
length += vSize(p0 - p1);
p0 = p1;
}
return length;
}
bool shorterThan(int64_t check_length) const;
Point min() const
{
Point ret = Point(POINT_MAX, POINT_MAX);
for(Point p : *path)
{
ret.X = std::min(ret.X, p.X);
ret.Y = std::min(ret.Y, p.Y);
}
return ret;
}
Point max() const
{
Point ret = Point(POINT_MIN, POINT_MIN);
for(Point p : *path)
{
ret.X = std::max(ret.X, p.X);
ret.Y = std::max(ret.Y, p.Y);
}
return ret;
}
double area() const
{
return ClipperLib::Area(*path);
}
Point centerOfMass() const
{
double x = 0, y = 0;
Point p0 = (*path)[path->size()-1];
for(unsigned int n=0; n<path->size(); n++)
{
Point p1 = (*path)[n];
double second_factor = (p0.X * p1.Y) - (p1.X * p0.Y);
x += double(p0.X + p1.X) * second_factor;
y += double(p0.Y + p1.Y) * second_factor;
p0 = p1;
}
double area = Area(*path);
x = x / 6 / area;
y = y / 6 / area;
return Point(x, y);
}
Point closestPointTo(Point p) const
{
Point ret = p;
float bestDist = FLT_MAX;
for(unsigned int n=0; n<path->size(); n++)
{
float dist = vSize2f(p - (*path)[n]);
if (dist < bestDist)
{
ret = (*path)[n];
bestDist = dist;
}
}
return ret;
}
/*!
* Clipper function.
* Returns false if outside, true if inside; if the point lies exactly on the border, will return 'border_result'.
*
* http://www.angusj.com/delphi/clipper/documentation/Docs/Units/ClipperLib/Functions/PointInPolygon.htm
*/
bool inside(Point p, bool border_result = false) const
{
int res = ClipperLib::PointInPolygon(p, *path);
if (res == -1)
{
return border_result;
}
return res == 1;
}
/*!
* Smooth out small perpendicular segments and store the result in \p result.
* Smoothing is performed by removing the inner most vertex of a line segment smaller than \p remove_length
* which has an angle with the next and previous line segment smaller than roughly 150*
*
* Note that in its current implementation this function doesn't remove line segments with an angle smaller than 30*
* Such would be the case for an N shape.
*
* \param remove_length The length of the largest segment removed
* \param result (output) The result polygon, assumed to be empty
*/
void smooth(int remove_length, PolygonRef result) const;
/*!
* Smooth out the polygon and store the result in \p result.
* Smoothing is performed by removing vertices for which both connected line segments are smaller than \p remove_length
*
* \param remove_length The length of the largest segment removed
* \param result (output) The result polygon, assumed to be empty
*/
void smooth2(int remove_length, PolygonRef result) const;
ClipperLib::Path::const_reference back() const
{
return path->back();
}
ClipperLib::Path::const_iterator begin() const
{
return path->begin();
}
ClipperLib::Path::const_iterator end() const
{
return path->end();
}
friend class Polygons;
friend class Polygon;
};
class Polygon : public PolygonRef
{
ClipperLib::Path poly;
@@ -397,6 +592,7 @@ class Polygons
{
friend class Polygon;
friend class PolygonRef;
friend class ConstPolygonRef;
protected:
ClipperLib::Paths paths;
public:
@@ -407,14 +603,14 @@ public:
unsigned int pointCount() const; //!< Return the amount of points in all polygons
PolygonRef operator[] (unsigned int index)
ClipperLib::Path& operator[] (unsigned int index)
{
POLY_ASSERT(index < size() && index >= 0);
return PolygonRef(paths[index]);
POLY_ASSERT(index < size() && index <= std::numeric_limits<int>::max());
return paths[index];
}
const PolygonRef operator[] (unsigned int index) const
ConstPolygonRef operator[] (unsigned int index) const
{
return const_cast<Polygons*>(this)->operator[](index);
return paths[index];
}
ClipperLib::Paths::iterator begin()
{
@@ -439,7 +635,7 @@ public:
*/
void remove(unsigned int index)
{
POLY_ASSERT(index < size() && index >= 0);
POLY_ASSERT(index < size() && index <= std::numeric_limits<int>::max());
if (index < paths.size() - 1)
{
paths[index] = std::move(paths.back());
@@ -461,6 +657,10 @@ public:
{
paths.push_back(*poly.path);
}
void add(const ConstPolygonRef& poly)
{
paths.push_back(*poly.path);
}
void add(Polygon&& other_poly)
{
paths.emplace_back(std::move(*other_poly));
@@ -484,14 +684,14 @@ public:
paths.emplace_back(args...);
}
PolygonRef newPoly()
ClipperLib::Path& newPoly()
{
paths.emplace_back();
return PolygonRef(paths.back());
return paths.back();
}
PolygonRef back()
ClipperLib::Path& back()
{
return PolygonRef(paths.back());
return paths.back();
}
Polygons() {}
@@ -647,7 +847,7 @@ public:
* \param remove_length The length of the largest segment removed
* \return The smoothed polygon
*/
Polygons smooth(int remove_length);
Polygons smooth(int remove_length) const;
/*!
* Smooth out sharp inner corners, by taking a shortcut which bypasses the corner
@@ -658,7 +858,7 @@ public:
*/
Polygons smooth_outward(float angle, int shortcut_length);
Polygons smooth2(int remove_length, int min_area); //!< removes points connected to small lines
Polygons smooth2(int remove_length, int min_area) const; //!< removes points connected to small lines
/*!
* removes points connected to similarly oriented lines
@@ -673,7 +873,7 @@ public:
Polygons& thiss = *this;
for (unsigned int p = 0; p < size(); p++)
{
thiss[p].simplify(smallest_line_segment_squared, allowed_error_distance_squared);
PolygonRef{thiss[p]}.simplify(smallest_line_segment_squared, allowed_error_distance_squared);
if (thiss[p].size() < 3)
{
remove(p);
@@ -734,7 +934,7 @@ public:
Polygons& thiss = *this;
for(unsigned int i=0; i<size(); i++)
{
double area = INT2MM(INT2MM(fabs(thiss[i].area())));
double area = INT2MM(INT2MM(fabs(PolygonRef{thiss[i]}.area())));
if (area < minAreaSize) // Only create an up/down skin if the area is large enough. So you do not create tiny blobs of "trying to fill"
{
remove(i);
@@ -798,16 +998,16 @@ public:
* Removes the same polygons from this set (and also empty polygons).
* Polygons are considered the same if all points lie within [same_distance] of their counterparts.
*/
Polygons remove(Polygons& to_be_removed, int same_distance = 0)
Polygons remove(const Polygons& to_be_removed, int same_distance = 0) const
{
Polygons result;
for (unsigned int poly_keep_idx = 0; poly_keep_idx < size(); poly_keep_idx++)
{
PolygonRef poly_keep = (*this)[poly_keep_idx];
ConstPolygonRef poly_keep = (*this)[poly_keep_idx];
bool should_be_removed = false;
if (poly_keep.size() > 0)
// for (int hole_poly_idx = 0; hole_poly_idx < to_be_removed.size(); hole_poly_idx++)
for (PolygonRef poly_rem : to_be_removed)
for (ConstPolygonRef poly_rem : to_be_removed)
{
// PolygonRef poly_rem = to_be_removed[hole_poly_idx];
if (poly_rem.size() != poly_keep.size() || poly_rem.size() == 0) continue;
@@ -859,18 +1059,6 @@ public:
return ret;
}
/*!
* Remove holes which are lying outside of parts, and outlines inside of parts
*
* ^
* ^
* <<<<<<<<^<<<< should become <<<<<<<<
* ^ ^
* ^ ^
* ^ ^
*/
Polygons removeComplexParts() const;
int64_t polygonLength() const
{
int64_t length = 0;
@@ -935,21 +1123,24 @@ public:
class PolygonsPart : public Polygons
{
public:
PolygonRef outerPolygon()
PolygonRef outerPolygon()
{
Polygons& thiss = *this;
return thiss[0];
return this->paths[0];
}
ConstPolygonRef outerPolygon() const
{
return this->paths[0];
}
bool inside(Point p)
{
if (size() < 1)
return false;
if (!(*this)[0].inside(p))
if (!PolygonRef{(*this)[0]}.inside(p))
return false;
for(unsigned int n=1; n<paths.size(); n++)
{
if ((*this)[n].inside(p))
if (PolygonRef{(*this)[n]}.inside(p))
return false;
}
return true;
+38 -38
Ver Arquivo
@@ -22,7 +22,7 @@ int64_t PolygonUtils::segmentLength(PolygonsPointIndex start, PolygonsPointIndex
assert(start.poly_idx == end.poly_idx);
int64_t segment_length = 0;
Point prev_vert = start.p();
const PolygonRef poly = (*start.polygons)[start.poly_idx];
ConstPolygonRef poly = (*start.polygons)[start.poly_idx];
for (unsigned int point_idx = 1; point_idx <= poly.size(); point_idx++)
{
unsigned int vert_idx = (start.point_idx + point_idx) % poly.size();
@@ -44,7 +44,7 @@ void PolygonUtils::spreadDots(PolygonsPointIndex start, PolygonsPointIndex end,
assert(start.poly_idx == end.poly_idx);
int64_t segment_length = segmentLength(start, end);
const PolygonRef poly = (*start.polygons)[start.poly_idx];
ConstPolygonRef poly = (*start.polygons)[start.poly_idx];
unsigned int n_dots_in_between = n_dots;
if (start == end)
{
@@ -80,7 +80,7 @@ void PolygonUtils::spreadDots(PolygonsPointIndex start, PolygonsPointIndex end,
assert(result.size() == n_dots && "we didn't generate as many wipe locations as we asked for.");
}
Point PolygonUtils::getVertexInwardNormal(PolygonRef poly, unsigned int point_idx)
Point PolygonUtils::getVertexInwardNormal(ConstPolygonRef poly, unsigned int point_idx)
{
Point p1 = poly[point_idx];
@@ -110,7 +110,7 @@ Point PolygonUtils::getVertexInwardNormal(PolygonRef poly, unsigned int point_id
break;
}
}
Point& p2 = poly[p2_idx];
const Point& p2 = poly[p2_idx];
Point off0 = turn90CCW(normal(p1 - p0, MM2INT(10.0))); // 10.0 for some precision
Point off1 = turn90CCW(normal(p2 - p1, MM2INT(10.0))); // 10.0 for some precision
@@ -119,7 +119,7 @@ Point PolygonUtils::getVertexInwardNormal(PolygonRef poly, unsigned int point_id
}
Point PolygonUtils::getBoundaryPointWithOffset(PolygonRef poly, unsigned int point_idx, int64_t offset)
Point PolygonUtils::getBoundaryPointWithOffset(ConstPolygonRef poly, unsigned int point_idx, int64_t offset)
{
return poly[point_idx] + normal(getVertexInwardNormal(poly, point_idx), -offset);
}
@@ -130,7 +130,7 @@ Point PolygonUtils::moveInsideDiagonally(ClosestPolygonPoint point_on_boundary,
{
return no_point;
}
PolygonRef poly = *point_on_boundary.poly;
ConstPolygonRef poly = *point_on_boundary.poly;
Point p0 = poly[point_on_boundary.point_idx];
Point p1 = poly[(point_on_boundary.point_idx + 1) % poly.size()];
if (vSize2(p0 - point_on_boundary.location) < vSize2(p1 - point_on_boundary.location))
@@ -163,7 +163,7 @@ ClosestPolygonPoint PolygonUtils::moveInside2(const Polygons& polygons, Point& f
return _moveInside2(*closest_polygon_point, distance, from, max_dist2);
}
ClosestPolygonPoint PolygonUtils::moveInside2(const Polygons& loc_to_line_polygons, const PolygonRef polygon, Point& from, const int distance, const int64_t max_dist2, const LocToLineGrid* loc_to_line_grid, const std::function<int(Point)>& penalty_function)
ClosestPolygonPoint PolygonUtils::moveInside2(const Polygons& loc_to_line_polygons, ConstPolygonRef polygon, Point& from, const int distance, const int64_t max_dist2, const LocToLineGrid* loc_to_line_grid, const std::function<int(Point)>& penalty_function)
{
std::optional<ClosestPolygonPoint> closest_polygon_point;
if (loc_to_line_grid)
@@ -225,7 +225,7 @@ unsigned int PolygonUtils::moveInside(const Polygons& polygons, Point& from, int
bool is_already_on_correct_side_of_boundary = false; // whether [from] is already on the right side of the boundary
for (unsigned int poly_idx = 0; poly_idx < polygons.size(); poly_idx++)
{
const PolygonRef poly = polygons[poly_idx];
ConstPolygonRef poly = polygons[poly_idx];
if (poly.size() < 2)
continue;
Point p0 = poly[poly.size()-2];
@@ -344,11 +344,11 @@ Point PolygonUtils::moveInside(const ClosestPolygonPoint& cpp, const int distanc
{ // the point which is assumed to be on the boundary doesn't have to be moved
return cpp.location;
}
const PolygonRef poly = *cpp.poly;
ConstPolygonRef poly = *cpp.poly;
unsigned int point_idx = cpp.point_idx;
const Point& on_boundary = cpp.location;
Point& p1 = poly[point_idx];
const Point& p1 = poly[point_idx];
unsigned int p2_idx;
for (p2_idx = point_idx + 1; p2_idx != point_idx; p2_idx = p2_idx + 1)
{ // find the next point different from p1
@@ -361,7 +361,7 @@ Point PolygonUtils::moveInside(const ClosestPolygonPoint& cpp, const int distanc
break;
}
}
Point& p2 = poly[p2_idx];
const Point& p2 = poly[p2_idx];
if (on_boundary == p1)
{
@@ -392,7 +392,7 @@ ClosestPolygonPoint PolygonUtils::ensureInsideOrOutside(const Polygons& polygons
{
return ClosestPolygonPoint(); // we couldn't move inside
}
PolygonRef closest_poly = *closest_polygon_point.poly;
ConstPolygonRef closest_poly = *closest_polygon_point.poly;
bool is_outside_boundary = closest_poly.orientation();
{
@@ -481,8 +481,8 @@ void PolygonUtils::findSmallestConnection(ClosestPolygonPoint& poly1_result, Clo
{
return;
}
PolygonRef poly1 = *poly1_result.poly;
PolygonRef poly2 = *poly2_result.poly;
ConstPolygonRef poly1 = *poly1_result.poly;
ConstPolygonRef poly2 = *poly2_result.poly;
if (poly1.size() == 0 || poly2.size() == 0)
{
return;
@@ -515,8 +515,8 @@ void PolygonUtils::walkToNearestSmallestConnection(ClosestPolygonPoint& poly1_re
{
return;
}
PolygonRef poly1 = *poly1_result.poly;
PolygonRef poly2 = *poly2_result.poly;
ConstPolygonRef poly1 = *poly1_result.poly;
ConstPolygonRef poly2 = *poly2_result.poly;
if (poly1_result.point_idx < 0 || poly2_result.point_idx < 0)
{
return;
@@ -537,7 +537,7 @@ void PolygonUtils::walkToNearestSmallestConnection(ClosestPolygonPoint& poly1_re
}
}
ClosestPolygonPoint PolygonUtils::findNearestClosest(Point from, PolygonRef polygon, int start_idx)
ClosestPolygonPoint PolygonUtils::findNearestClosest(Point from, ConstPolygonRef polygon, int start_idx)
{
ClosestPolygonPoint forth = findNearestClosest(from, polygon, start_idx, 1);
if (!forth.isValid())
@@ -556,7 +556,7 @@ ClosestPolygonPoint PolygonUtils::findNearestClosest(Point from, PolygonRef poly
}
}
ClosestPolygonPoint PolygonUtils::findNearestClosest(Point from, PolygonRef polygon, int start_idx, int direction)
ClosestPolygonPoint PolygonUtils::findNearestClosest(Point from, ConstPolygonRef polygon, int start_idx, int direction)
{
if (polygon.size() == 0)
{
@@ -572,8 +572,8 @@ ClosestPolygonPoint PolygonUtils::findNearestClosest(Point from, PolygonRef poly
{
int p1_idx = (polygon.size() + direction*p + start_idx) % polygon.size();
int p2_idx = (polygon.size() + direction*(p+1) + start_idx) % polygon.size();
Point& p1 = polygon[p1_idx];
Point& p2 = polygon[p2_idx];
const Point& p1 = polygon[p1_idx];
const Point& p2 = polygon[p2_idx];
Point closest_here = LinearAlg2D::getClosestOnLineSegment(from, p1 ,p2);
int64_t dist = vSize2(from - closest_here);
@@ -600,7 +600,7 @@ ClosestPolygonPoint PolygonUtils::findClosest(Point from, const Polygons& polygo
{
return none;
}
PolygonRef any_polygon = polygons[0];
ConstPolygonRef any_polygon = polygons[0];
unsigned int any_poly_idx;
for (any_poly_idx = 0; any_poly_idx < polygons.size(); any_poly_idx++)
{ // find first point in all polygons
@@ -620,7 +620,7 @@ ClosestPolygonPoint PolygonUtils::findClosest(Point from, const Polygons& polygo
for (unsigned int ply = 0; ply < polygons.size(); ply++)
{
const PolygonRef poly = polygons[ply];
ConstPolygonRef poly = polygons[ply];
if (poly.size() == 0) continue;
ClosestPolygonPoint closest_here = findClosest(from, poly, penalty_function);
if (!closest_here.isValid())
@@ -639,7 +639,7 @@ ClosestPolygonPoint PolygonUtils::findClosest(Point from, const Polygons& polygo
return best;
}
ClosestPolygonPoint PolygonUtils::findClosest(Point from, const PolygonRef polygon, const std::function<int(Point)>& penalty_function)
ClosestPolygonPoint PolygonUtils::findClosest(Point from, ConstPolygonRef polygon, const std::function<int(Point)>& penalty_function)
{
if (polygon.size() == 0)
{
@@ -653,11 +653,11 @@ ClosestPolygonPoint PolygonUtils::findClosest(Point from, const PolygonRef polyg
//
for (unsigned int p = 0; p<polygon.size(); p++)
{
Point& p1 = polygon[p];
const Point& p1 = polygon[p];
unsigned int p2_idx = p+1;
if (p2_idx >= polygon.size()) p2_idx = 0;
Point& p2 = polygon[p2_idx];
const Point& p2 = polygon[p2_idx];
Point closest_here = LinearAlg2D::getClosestOnLineSegment(from, p1 ,p2);
int64_t dist2_score = vSize2(from - closest_here) + penalty_function(closest_here);
@@ -678,7 +678,7 @@ PolygonsPointIndex PolygonUtils::findNearestVert(const Point from, const Polygon
PolygonsPointIndex closest_vert;
for (unsigned int poly_idx = 0; poly_idx < polys.size(); poly_idx++)
{
const PolygonRef poly = polys[poly_idx];
ConstPolygonRef poly = polys[poly_idx];
for (unsigned int point_idx = 0; point_idx < poly.size(); point_idx++)
{
int64_t dist2 = vSize2(poly[point_idx] - from);
@@ -721,7 +721,7 @@ LocToLineGrid* PolygonUtils::createLocToLineGrid(const Polygons& polygons, int s
for (unsigned int poly_idx = 0; poly_idx < polygons.size(); poly_idx++)
{
const PolygonRef poly = polygons[poly_idx];
ConstPolygonRef poly = polygons[poly_idx];
for (unsigned int point_idx = 0; point_idx < poly.size(); point_idx++)
{
ret->insert(PolygonsPointIndex(&polygons, poly_idx, point_idx));
@@ -752,9 +752,9 @@ std::optional<ClosestPolygonPoint> PolygonUtils::findClose(
PolygonsPointIndex best_point_poly_idx(nullptr, NO_INDEX, NO_INDEX);
for (PolygonsPointIndex& point_poly_index : near_lines)
{
const PolygonRef poly = polygons[point_poly_index.poly_idx];
Point& p1 = poly[point_poly_index.point_idx];
Point& p2 = poly[(point_poly_index.point_idx + 1) % poly.size()];
ConstPolygonRef poly = polygons[point_poly_index.poly_idx];
const Point& p1 = poly[point_poly_index.point_idx];
const Point& p2 = poly[(point_poly_index.point_idx + 1) % poly.size()];
Point closest_here = LinearAlg2D::getClosestOnLineSegment(from, p1 ,p2);
int64_t dist2_score = vSize2(from - closest_here) + penalty_function(closest_here);
@@ -778,7 +778,7 @@ std::optional<ClosestPolygonPoint> PolygonUtils::findClose(
std::vector<std::pair<ClosestPolygonPoint, ClosestPolygonPoint>> PolygonUtils::findClose(
const PolygonRef from, const Polygons& destination,
ConstPolygonRef from, const Polygons& destination,
const LocToLineGrid& destination_loc_to_line,
const std::function<int(Point)>& penalty_function)
{
@@ -817,7 +817,7 @@ std::vector<std::pair<ClosestPolygonPoint, ClosestPolygonPoint>> PolygonUtils::f
bool PolygonUtils::getNextPointWithDistance(Point from, int64_t dist, const PolygonRef poly, int start_idx, int poly_start_idx, GivenDistPoint& result)
bool PolygonUtils::getNextPointWithDistance(Point from, int64_t dist, ConstPolygonRef poly, int start_idx, int poly_start_idx, GivenDistPoint& result)
{
Point prev_poly_point = poly[(start_idx + poly_start_idx) % poly.size()];
@@ -825,7 +825,7 @@ bool PolygonUtils::getNextPointWithDistance(Point from, int64_t dist, const Poly
for (unsigned int prev_idx = start_idx; prev_idx < poly.size(); prev_idx++)
{
int next_idx = (prev_idx + 1 + poly_start_idx) % poly.size(); // last checked segment is between last point in poly and poly[0]...
Point& next_poly_point = poly[next_idx];
const Point& next_poly_point = poly[next_idx];
if ( !shorterThen(next_poly_point - from, dist) )
{
/*
@@ -932,7 +932,7 @@ bool PolygonUtils::polygonCollidesWithLineSegment(const Point from, const Point
return ret;
}
bool PolygonUtils::polygonCollidesWithLineSegment(const PolygonRef poly, Point& transformed_startPoint, Point& transformed_endPoint, PointMatrix transformation_matrix)
bool PolygonUtils::polygonCollidesWithLineSegment(ConstPolygonRef poly, const Point& transformed_startPoint, const Point& transformed_endPoint, PointMatrix transformation_matrix)
{
Point p0 = transformation_matrix.apply(poly.back());
for(Point p1_ : poly)
@@ -947,7 +947,7 @@ bool PolygonUtils::polygonCollidesWithLineSegment(const PolygonRef poly, Point&
return false;
}
bool PolygonUtils::polygonCollidesWithLineSegment(const PolygonRef poly, Point& startPoint, Point& endPoint)
bool PolygonUtils::polygonCollidesWithLineSegment(PolygonRef poly, const Point& startPoint, const Point& endPoint)
{
Point diff = endPoint - startPoint;
@@ -958,9 +958,9 @@ bool PolygonUtils::polygonCollidesWithLineSegment(const PolygonRef poly, Point&
return PolygonUtils::polygonCollidesWithLineSegment(poly, transformed_startPoint, transformed_endPoint, transformation_matrix);
}
bool PolygonUtils::polygonCollidesWithLineSegment(const Polygons& polys, Point& transformed_startPoint, Point& transformed_endPoint, PointMatrix transformation_matrix)
bool PolygonUtils::polygonCollidesWithLineSegment(const Polygons& polys, const Point& transformed_startPoint, const Point& transformed_endPoint, PointMatrix transformation_matrix)
{
for (const PolygonRef poly : const_cast<Polygons&>(polys))
for (ConstPolygonRef poly : polys)
{
if (poly.size() == 0) { continue; }
if (PolygonUtils::polygonCollidesWithLineSegment(poly, transformed_startPoint, transformed_endPoint, transformation_matrix))
@@ -973,7 +973,7 @@ bool PolygonUtils::polygonCollidesWithLineSegment(const Polygons& polys, Point&
}
bool PolygonUtils::polygonCollidesWithLineSegment(const Polygons& polys, Point& startPoint, Point& endPoint)
bool PolygonUtils::polygonCollidesWithLineSegment(const Polygons& polys, const Point& startPoint, const Point& endPoint)
{
Point diff = endPoint - startPoint;
+17 -17
Ver Arquivo
@@ -20,12 +20,12 @@ namespace cura
struct ClosestPolygonPoint
{
Point location; //!< Result location
std::optional<PolygonRef> poly; //!< Polygon in which the result was found (or none if no result was found)
std::optional<ConstPolygonRef> poly; //!< Polygon in which the result was found (or none if no result was found)
unsigned int poly_idx; //!< The index of the polygon in some Polygons where ClosestPolygonPoint::poly can be found
unsigned int point_idx; //!< Index to the first point in the polygon of the line segment on which the result was found
ClosestPolygonPoint(Point p, int pos, PolygonRef poly) : location(p), poly(true, poly), poly_idx(NO_INDEX), point_idx(pos) {};
ClosestPolygonPoint(Point p, int pos, PolygonRef poly, int poly_idx) : location(p), poly(true, poly), poly_idx(poly_idx), point_idx(pos) {};
ClosestPolygonPoint(PolygonRef poly) : poly(true, poly), poly_idx(NO_INDEX), point_idx(NO_INDEX) {};
ClosestPolygonPoint(Point p, int pos, ConstPolygonRef poly) : location(p), poly(true, poly), poly_idx(NO_INDEX), point_idx(pos) {};
ClosestPolygonPoint(Point p, int pos, ConstPolygonRef poly, int poly_idx) : location(p), poly(true, poly), poly_idx(poly_idx), point_idx(pos) {};
ClosestPolygonPoint(ConstPolygonRef poly) : poly(true, poly), poly_idx(NO_INDEX), point_idx(NO_INDEX) {};
ClosestPolygonPoint() : poly_idx(NO_INDEX), point_idx(NO_INDEX) {};
Point p() const
{ // conformity with other classes
@@ -53,7 +53,7 @@ struct PolygonsPointIndexSegmentLocator
{
std::pair<Point, Point> operator()(const PolygonsPointIndex& val) const
{
PolygonRef poly = (*val.polygons)[val.poly_idx];
ConstPolygonRef poly = (*val.polygons)[val.poly_idx];
Point start = poly[val.point_idx];
unsigned int next_point_idx = (val.point_idx + 1) % poly.size();
Point end = poly[next_point_idx];
@@ -104,7 +104,7 @@ public:
* \param poly The polygon.
* \param point_idx The index of the point in the polygon.
*/
static Point getVertexInwardNormal(PolygonRef poly, unsigned int point_idx);
static Point getVertexInwardNormal(ConstPolygonRef poly, unsigned int point_idx);
/*!
* Get a point from the \p poly with a given \p offset.
@@ -114,7 +114,7 @@ public:
* \param offset The distance the point has to be moved outward from the polygon.
* \return A point at the given distance inward from the point on the boundary polygon.
*/
static Point getBoundaryPointWithOffset(PolygonRef poly, unsigned int point_idx, int64_t offset);
static Point getBoundaryPointWithOffset(ConstPolygonRef poly, unsigned int point_idx, int64_t offset);
/*!
* Move a point away from the boundary by looking at the boundary normal of the nearest vert.
@@ -178,7 +178,7 @@ public:
* \param penalty_function A function returning a penalty term on the squared distance score of a candidate point.
* \return The point on the polygon closest to \p from
*/
static ClosestPolygonPoint moveInside2(const Polygons& loc_to_line_polygons, const PolygonRef polygon, Point& from, const int distance = 0, const int64_t max_dist2 = std::numeric_limits<int64_t>::max(), const LocToLineGrid* loc_to_line_grid = nullptr, const std::function<int(Point)>& penalty_function = no_penalty_function);
static ClosestPolygonPoint moveInside2(const Polygons& loc_to_line_polygons, ConstPolygonRef polygon, Point& from, const int distance = 0, const int64_t max_dist2 = std::numeric_limits<int64_t>::max(), const LocToLineGrid* loc_to_line_grid = nullptr, const std::function<int(Point)>& penalty_function = no_penalty_function);
/*!
* The opposite of moveInside.
@@ -298,7 +298,7 @@ public:
* \param start_idx The index of the point in the polygon from which to start looking.
* \return The nearest point from \p start_idx going along the \p polygon (in both directions) with a locally minimal distance to \p from.
*/
static ClosestPolygonPoint findNearestClosest(Point from, const PolygonRef polygon, int start_idx);
static ClosestPolygonPoint findNearestClosest(Point from, ConstPolygonRef polygon, int start_idx);
/*!
* Find the nearest closest point on a polygon from a given index walking in one direction along the polygon.
@@ -309,7 +309,7 @@ public:
* \param direction The direction to walk: 1 for walking along the \p polygon, -1 for walking in opposite direction
* \return The nearest point from \p start_idx going along the \p polygon with a locally minimal distance to \p from.
*/
static ClosestPolygonPoint findNearestClosest(const Point from, const PolygonRef polygon, int start_idx, int direction);
static ClosestPolygonPoint findNearestClosest(const Point from, ConstPolygonRef polygon, int start_idx, int direction);
/*!
* Find the point closest to \p from in all polygons in \p polygons.
@@ -327,7 +327,7 @@ public:
*
* \param penalty_function A function returning a penalty term on the squared distance score of a candidate point.
*/
static ClosestPolygonPoint findClosest(Point from, const PolygonRef polygon, const std::function<int(Point)>& penalty_function = no_penalty_function);
static ClosestPolygonPoint findClosest(Point from, ConstPolygonRef polygon, const std::function<int(Point)>& penalty_function = no_penalty_function);
/*!
* Find the nearest vertex to \p from in \p polys
@@ -382,7 +382,7 @@ public:
* \param penalty_function A function returning a penalty term on the squared distance score of a candidate point.
* \return A collection of near crossing from the \p from polygon to the \p destination polygon. Each element in the sollection is a pair with as first a cpp in the \p from polygon and as second a cpp in the \p destination polygon.
*/
static std::vector<std::pair<ClosestPolygonPoint, ClosestPolygonPoint>> findClose(const PolygonRef from, const Polygons& destination, const LocToLineGrid& destination_loc_to_line, const std::function<int(Point)>& penalty_function = no_penalty_function);
static std::vector<std::pair<ClosestPolygonPoint, ClosestPolygonPoint>> findClose(ConstPolygonRef from, const Polygons& destination, const LocToLineGrid& destination_loc_to_line, const std::function<int(Point)>& penalty_function = no_penalty_function);
/*!
* Checks whether a given line segment collides with polygons as given in a loc_to_line grid.
@@ -409,7 +409,7 @@ public:
* \param start_idx the index of the prev poly point on the poly.
* \param poly_start_idx The index of the point in the polygon which is to be handled as the start of the polygon. No point further than this point will be the result.
*/
static bool getNextPointWithDistance(Point from, int64_t dist, const PolygonRef poly, int start_idx, int poly_start_idx, GivenDistPoint& result);
static bool getNextPointWithDistance(Point from, int64_t dist, ConstPolygonRef poly, int start_idx, int poly_start_idx, GivenDistPoint& result);
@@ -433,7 +433,7 @@ public:
* \return whether the line segment collides with the boundary of the
* polygon(s)
*/
static bool polygonCollidesWithLineSegment(const PolygonRef poly, Point& transformed_startPoint, Point& transformed_endPoint, PointMatrix transformation_matrix);
static bool polygonCollidesWithLineSegment(ConstPolygonRef poly, const Point& transformed_startPoint, const Point& transformed_endPoint, PointMatrix transformation_matrix);
/*!
* Checks whether a given line segment collides with a given polygon(s).
@@ -449,7 +449,7 @@ public:
* \return whether the line segment collides with the boundary of the
* polygon(s)
*/
static bool polygonCollidesWithLineSegment(const PolygonRef poly, Point& startPoint, Point& endPoint);
static bool polygonCollidesWithLineSegment(const PolygonRef poly, const Point& startPoint, const Point& endPoint);
/*!
* Checks whether a given line segment collides with a given polygon(s).
@@ -471,7 +471,7 @@ public:
* \return whether the line segment collides with the boundary of the
* polygon(s)
*/
static bool polygonCollidesWithLineSegment(const Polygons& polys, Point& transformed_startPoint, Point& transformed_endPoint, PointMatrix transformation_matrix);
static bool polygonCollidesWithLineSegment(const Polygons& polys, const Point& transformed_startPoint, const Point& transformed_endPoint, PointMatrix transformation_matrix);
/*!
* Checks whether a given line segment collides with a given polygon(s).
@@ -487,7 +487,7 @@ public:
* \return whether the line segment collides with the boundary of the
* polygon(s)
*/
static bool polygonCollidesWithLineSegment(const Polygons& polys, Point& startPoint, Point& endPoint);
static bool polygonCollidesWithLineSegment(const Polygons& polys, const Point& startPoint, const Point& endPoint);
private:
/*!
+1 -1
Ver Arquivo
@@ -18,7 +18,7 @@ WallOverlapComputation::WallOverlapComputation(Polygons& polygons, int line_widt
}
float WallOverlapComputation::getFlow(Point& from, Point& to)
float WallOverlapComputation::getFlow(const Point& from, const Point& to)
{
using Point2LinkIt = PolygonProximityLinker::Point2Link::iterator;
+1 -1
Ver Arquivo
@@ -60,7 +60,7 @@ public:
* \param to The ending of the line segment
* \return a value between zero and one representing the reduced flow of the line segment
*/
float getFlow(Point& from, Point& to);
float getFlow(const Point& from, const Point& to);
/*!
* Computes the neccesary priliminaries in order to efficiently compute the flow when generatign gcode paths.