Comparar commits

..

11 Commits

Autor SHA1 Mensagem Data
Tim Kuipers 1730923083 safety: skip mesh if layer nr too high (CURA-1134) 2016-11-30 17:54:37 +01:00
Tim Kuipers 8e5a936522 fix: wrong indexing in part.insets for GCodePlanner::moveInsideCombBoundary (CURA-1134) 2016-11-30 17:44:03 +01:00
Tim Kuipers d29da8f7f8 refactor: change is_inside and was_inside from bool to SliceLayerPart* so that we know inside what part we were/are inside (CURA-1134)
makes for a better moveInsideCombBoundary functionality
2016-11-30 17:43:25 +01:00
Tim Kuipers ad56ce8866 fix: don't comb on raft layers or filler layers (CURA-1134) 2016-11-30 17:40:04 +01:00
Tim Kuipers 565b09e37d feat: SliceDataStorage::getPartInside (CURA-1134) 2016-11-30 17:38:40 +01:00
Tim Kuipers edc9767912 fix: made Polygons::inside virtual and let PolygonsPart::inside override it (CURA-1134) 2016-11-30 17:38:12 +01:00
Tim Kuipers ce6f58f136 info: comment on combing move inside dist (CURA-1134) 2016-11-30 16:50:58 +01:00
Tim Kuipers 5b941d07ff refactor: max_moveInside_distance2 ==> max_move_inside_distance2 (CURA-1134) 2016-11-30 16:48:01 +01:00
Tim Kuipers 350b42052a fix: better move inside so that we don't move inside the wrong part (CURA-1134)
the move inside is performed so that we don't perform the retraction on the outer wall, which causes a clearly visible z seam
2016-11-28 17:57:01 +01:00
Tim Kuipers 0ba152d081 fix: only conclude the startPoint is not inside after all when it doesn't collide with the outline and we are combing also over skin (CURA-1134) 2016-11-28 17:14:48 +01:00
Tim Kuipers 2c70c2ecb7 refactor/fix: compute was_inside for new layer rather than using the last is_inside of the previous layer heuristically (CURA-1134) 2016-11-28 15:44:09 +01:00
59 arquivos alterados com 799 adições e 1925 exclusões
-14
Ver Arquivo
@@ -42,16 +42,6 @@ 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)
@@ -95,13 +85,9 @@ set(engine_SRCS # Except main.cpp.
src/infill/ZigzagConnectorProcessorDisconnectedEndPieces.cpp
src/infill/ZigzagConnectorProcessorEndPieces.cpp
src/infill/ZigzagConnectorProcessorNoEndPieces.cpp
src/infill/SubDivCube.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
src/progress/ProgressStageEstimator.cpp
+1 -1
Ver Arquivo
@@ -44,7 +44,7 @@
//#define use_xyz
//use_lines: Enables line clipping. Adds a very minor cost to performance.
#define use_lines
//#define use_lines
//use_deprecated: Enables temporary support for the obsolete functions
//#define use_deprecated
+120 -280
Ver Arquivo
@@ -6,7 +6,6 @@
#include "FffProcessor.h"
#include "progress/Progress.h"
#include "wallOverlap.h"
#include "utils/orderOptimizer.h"
namespace cura
{
@@ -19,13 +18,13 @@ void FffGcodeWriter::writeGCode(SliceDataStorage& storage, TimeKeeper& time_keep
if (FffProcessor::getInstance()->getMeshgroupNr() == 0)
{ // first meshgroup
gcode.resetTotalPrintTimeAndFilament();
gcode.setInitialTemps(*storage.meshgroup, getStartExtruder(storage));
gcode.setInitialTemps(*storage.meshgroup);
}
// set the initial extruder of this meshgroup
if (FffProcessor::getInstance()->getMeshgroupNr() == 0)
{ // first meshgroup
current_extruder_planned = getStartExtruder(storage);
current_extruder_planned = getSettingAsIndex("adhesion_extruder_nr");
}
else
{
@@ -55,8 +54,7 @@ void FffGcodeWriter::writeGCode(SliceDataStorage& storage, TimeKeeper& time_keep
if (FffProcessor::getInstance()->getMeshgroupNr() == 0)
{
unsigned int start_extruder_nr = getStartExtruder(storage);
processStartingCode(storage, start_extruder_nr);
processStartingCode(storage);
}
else
{
@@ -82,15 +80,6 @@ void FffGcodeWriter::writeGCode(SliceDataStorage& storage, TimeKeeper& time_keep
}
}
{ // calculate the mesh order for each extruder
int extruder_count = storage.meshgroup->getExtruderCount();
mesh_order_per_extruder.reserve(extruder_count);
for (int extruder_nr = 0; extruder_nr < extruder_count; extruder_nr++)
{
mesh_order_per_extruder.push_back(calculateMeshOrder(storage, extruder_nr));
}
}
for(unsigned int layer_nr=0; layer_nr<total_layers; layer_nr++)
{
processLayer(storage, layer_nr, total_layers);
@@ -104,7 +93,7 @@ void FffGcodeWriter::writeGCode(SliceDataStorage& storage, TimeKeeper& time_keep
layer_plan_buffer.flush();
constexpr bool force = true;
gcode.writeRetraction(storage.retraction_config_per_extruder[gcode.getExtruderNr()], force); // retract after finishing each meshgroup
gcode.writeRetraction(&storage.retraction_config_per_extruder[gcode.getExtruderNr()], force); // retract after finishing each meshgroup
}
void FffGcodeWriter::setConfigFanSpeedLayerTime(SliceDataStorage& storage)
@@ -194,17 +183,7 @@ void FffGcodeWriter::initConfigs(SliceDataStorage& storage)
mesh.inset0_config.init(mesh.getSettingInMillimetersPerSecond("speed_wall_0"), mesh.getSettingInMillimetersPerSecond("acceleration_wall_0"), mesh.getSettingInMillimetersPerSecond("jerk_wall_0"), mesh.getSettingInMicrons("wall_line_width_0"), mesh.getSettingInPercentage("material_flow"));
mesh.insetX_config.init(mesh.getSettingInMillimetersPerSecond("speed_wall_x"), mesh.getSettingInMillimetersPerSecond("acceleration_wall_x"), mesh.getSettingInMillimetersPerSecond("jerk_wall_x"), mesh.getSettingInMicrons("wall_line_width_x"), mesh.getSettingInPercentage("material_flow"));
mesh.skin_config.init(mesh.getSettingInMillimetersPerSecond("speed_topbottom"), mesh.getSettingInMillimetersPerSecond("acceleration_topbottom"), mesh.getSettingInMillimetersPerSecond("jerk_topbottom"), mesh.getSettingInMicrons("skin_line_width"), mesh.getSettingInPercentage("material_flow"));
// The perimeter gap config follows the skin config, but has a different line width:
// wall_line_width_x divided by two because the gaps are between 0 and 1 times the wall line width
const int perimeter_gaps_line_width = mesh.getSettingInMicrons("wall_line_width_x") / 2;
double perimeter_gaps_speed = mesh.getSettingInMillimetersPerSecond("speed_topbottom");
if (mesh.getSettingBoolean("speed_equalize_flow_enabled"))
{
perimeter_gaps_speed = perimeter_gaps_speed * mesh.getSettingInMicrons("skin_line_width") / perimeter_gaps_line_width;
}
mesh.perimeter_gap_config.init(perimeter_gaps_speed, mesh.getSettingInMillimetersPerSecond("acceleration_topbottom"), mesh.getSettingInMillimetersPerSecond("jerk_topbottom"), perimeter_gaps_line_width, mesh.getSettingInPercentage("material_flow"));
for (unsigned int idx = 0; idx < MAX_INFILL_COMBINE; idx++)
{
mesh.infill_config[idx].init(mesh.getSettingInMillimetersPerSecond("speed_infill"), mesh.getSettingInMillimetersPerSecond("acceleration_infill"), mesh.getSettingInMillimetersPerSecond("jerk_infill"), mesh.getSettingInMicrons("infill_line_width") * (idx + 1), mesh.getSettingInPercentage("material_flow"));
@@ -214,26 +193,7 @@ void FffGcodeWriter::initConfigs(SliceDataStorage& storage)
storage.primeTower.initConfigs(storage.meshgroup);
}
unsigned int FffGcodeWriter::getStartExtruder(SliceDataStorage& storage)
{
int start_extruder_nr = getSettingAsIndex("adhesion_extruder_nr");
if (getSettingAsPlatformAdhesion("adhesion_type") == EPlatformAdhesion::NONE)
{
std::vector<bool> extruder_is_used = storage.getExtrudersUsed();
for (unsigned int extruder_nr = 0; extruder_nr < extruder_is_used.size(); extruder_nr++)
{
start_extruder_nr = extruder_nr;
if (extruder_is_used[extruder_nr])
{
break;
}
}
}
assert(start_extruder_nr >= 0 && start_extruder_nr < storage.meshgroup->getExtruderCount() && "start_extruder_nr must be a valid extruder");
return start_extruder_nr;
}
void FffGcodeWriter::processStartingCode(SliceDataStorage& storage, const unsigned int start_extruder_nr)
void FffGcodeWriter::processStartingCode(SliceDataStorage& storage)
{
if (!CommandSocket::isInstantiated())
{
@@ -241,13 +201,15 @@ void FffGcodeWriter::processStartingCode(SliceDataStorage& storage, const unsign
gcode.writeCode(prefix.c_str());
}
int start_extruder_nr = getSettingAsIndex("adhesion_extruder_nr");
gcode.writeComment("Generated with Cura_SteamEngine " VERSION);
if (gcode.getFlavor() != EGCodeFlavor::ULTIGCODE && gcode.getFlavor() != EGCodeFlavor::GRIFFIN)
{
if (getSettingBoolean("material_bed_temp_prepend"))
{
if (getSettingBoolean("machine_heated_bed") && getSettingInDegreeCelsius("material_bed_temperature_layer_0") != 0)
if (getSettingBoolean("machine_heated_bed") && getSettingInDegreeCelsius("material_bed_temperature_layer_0") > 0)
{
gcode.writeBedTemperatureCommand(getSettingInDegreeCelsius("material_bed_temperature_layer_0"), getSettingBoolean("material_bed_temp_wait"));
}
@@ -295,9 +257,8 @@ void FffGcodeWriter::processStartingCode(SliceDataStorage& storage, const unsign
double print_temp_here = (print_temp_0 != 0)? print_temp_0 : train.getSettingInDegreeCelsius("material_print_temperature");
gcode.writeTemperatureCommand(start_extruder_nr, print_temp_here, wait);
gcode.writePrimeTrain(train.getSettingInMillimetersPerSecond("speed_travel"));
extruder_prime_is_planned[start_extruder_nr] = true;
RetractionConfig& retraction_config = storage.retraction_config_per_extruder[start_extruder_nr];
gcode.writeRetraction(retraction_config);
gcode.writeRetraction(&retraction_config);
}
}
@@ -351,11 +312,12 @@ 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"));
gcode_layer.setIsInside(true);
gcode_layer.setExtruder(extruder_nr);
GCodePlanner& gcode_layer = layer_plan_buffer.emplace_back(storage, layer_nr, z, layer_height, last_position_planned, current_extruder_planned, fan_speed_layer_time_settings_per_extruder, combing_mode, comb_offset, train->getSettingBoolean("travel_avoid_other_parts"), train->getSettingInMicrons("travel_avoid_distance"));
if (getSettingAsIndex("adhesion_extruder_nr") > 0)
{
gcode_layer.setExtruder(extruder_nr);
}
if (CommandSocket::isInstantiated())
{
CommandSocket::getInstance()->sendOptimizedLayerInfo(layer_nr, z, layer_height);
@@ -370,14 +332,10 @@ void FffGcodeWriter::processRaft(SliceDataStorage& storage, unsigned int total_l
infill_comp.generate(raft_polygons, raftLines);
gcode_layer.addLinesByOptimizer(raftLines, &storage.raft_base_config, SpaceFillType::Lines);
if (getExtrudersNeedPrimeDuringFirstLayer())
{
ensureAllExtrudersArePrimed(storage, gcode_layer, layer_nr);
}
last_position_planned = gcode_layer.getLastPosition();
current_extruder_planned = gcode_layer.getExtruder();
is_inside_mesh_layer_part = gcode_layer.getIsInsideMesh();
ensureAllExtrudersArePrimed(storage, gcode_layer, layer_nr);
gcode_layer.processFanSpeedAndMinimalLayerTime();
gcode_layer.overrideFanSpeeds(train->getSettingInPercentage("raft_base_fan_speed"));
@@ -388,16 +346,13 @@ 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"));
gcode_layer.setIsInside(true);
gcode_layer.setExtruder(extruder_nr); // reset to extruder number, because we might have primed in the last layer
GCodePlanner& gcode_layer = layer_plan_buffer.emplace_back(storage, layer_nr, z, layer_height, last_position_planned, current_extruder_planned, fan_speed_layer_time_settings_per_extruder, combing_mode, comb_offset, train->getSettingBoolean("travel_avoid_other_parts"), train->getSettingInMicrons("travel_avoid_distance"));
if (CommandSocket::isInstantiated())
{
CommandSocket::getInstance()->sendOptimizedLayerInfo(layer_nr, z, layer_height);
}
Polygons raftLines;
int offset_from_poly_outline = 0;
double fill_angle = train->getSettingAsCount("raft_surface_layers") > 0 ? 45 : 90;
@@ -407,7 +362,6 @@ void FffGcodeWriter::processRaft(SliceDataStorage& storage, unsigned int total_l
last_position_planned = gcode_layer.getLastPosition();
current_extruder_planned = gcode_layer.getExtruder();
is_inside_mesh_layer_part = gcode_layer.getIsInsideMesh();
gcode_layer.processFanSpeedAndMinimalLayerTime();
gcode_layer.overrideFanSpeeds(train->getSettingInPercentage("raft_interface_fan_speed"));
@@ -420,8 +374,7 @@ 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"));
gcode_layer.setIsInside(true);
GCodePlanner& gcode_layer = layer_plan_buffer.emplace_back(storage, layer_nr, z, layer_height, last_position_planned, current_extruder_planned, fan_speed_layer_time_settings_per_extruder, combing_mode, comb_offset, train->getSettingBoolean("travel_avoid_other_parts"), train->getSettingInMicrons("travel_avoid_distance"));
if (CommandSocket::isInstantiated())
{
@@ -437,8 +390,7 @@ void FffGcodeWriter::processRaft(SliceDataStorage& storage, unsigned int total_l
last_position_planned = gcode_layer.getLastPosition();
current_extruder_planned = gcode_layer.getExtruder();
is_inside_mesh_layer_part = gcode_layer.getIsInsideMesh();
gcode_layer.processFanSpeedAndMinimalLayerTime();
gcode_layer.overrideFanSpeeds(train->getSettingInPercentage("raft_surface_fan_speed"));
}
@@ -480,7 +432,7 @@ void FffGcodeWriter::processLayer(SliceDataStorage& storage, int layer_nr, unsig
}
bool avoid_other_parts = false;
coord_t avoid_distance = 0; // minimal avoid distance is zero
int avoid_distance = 0; // minimal avoid distance is zero
for (int extr_nr = 0; extr_nr < storage.meshgroup->getExtruderCount(); extr_nr++)
{
if (gcode.getExtruderIsUsed(extr_nr))
@@ -495,7 +447,7 @@ void FffGcodeWriter::processLayer(SliceDataStorage& storage, int layer_nr, unsig
}
}
coord_t max_inner_wall_width = 0;
int max_inner_wall_width = 0;
for (SettingsBaseVirtual& mesh_settings : storage.meshes)
{
max_inner_wall_width = std::max(max_inner_wall_width, mesh_settings.getSettingInMicrons((mesh_settings.getSettingAsCount("wall_line_count") > 1) ? "wall_line_width_x" : "wall_line_width_0"));
@@ -504,26 +456,22 @@ 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.emplace_back(storage, layer_nr, z, layer_thickness, last_position_planned, current_extruder_planned, 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.
int extruder_nr = gcode_layer.getExtruder();
int extruder_nr = getSettingAsIndex("adhesion_extruder_nr");
if (storage.skirt_brim[extruder_nr].size() > 0)
{
gcode_layer.setExtruder(extruder_nr);
processSkirtBrim(storage, gcode_layer, extruder_nr);
}
}
if (include_helper_parts)
{ // handle shield(s) first in a layer so that chances are higher that the other nozzle is wiped (for the ooze shield)
processOozeShield(storage, gcode_layer, std::max(0, layer_nr));
processDraftShield(storage, gcode_layer, std::max(0, layer_nr));
}
int support_skin_extruder_nr = getSettingAsIndex("support_interface_extruder_nr");
int support_infill_extruder_nr = (layer_nr <= 0)? getSettingAsIndex("support_extruder_nr_layer_0") : getSettingAsIndex("support_infill_extruder_nr");
//Figure out in which order to print the meshes, do this by looking at the current extruder and preferer the meshes that use that extruder.
std::vector<int> extruder_order = calculateExtruderOrder(storage, gcode_layer.getExtruder());
for (int extruder_nr : extruder_order)
{
@@ -535,36 +483,9 @@ void FffGcodeWriter::processLayer(SliceDataStorage& storage, int layer_nr, unsig
if (layer_nr >= 0)
{
std::vector<unsigned int>& mesh_order = mesh_order_per_extruder[extruder_nr];
unsigned int mesh_order_idx_starting_mesh = 0;
{ // calculate mesh_order_idx_starting_mesh
Point layer_start_position = last_position_planned;
if (storage.getSettingBoolean("start_layers_at_same_position"))
{
layer_start_position = Point(storage.getSettingInMicrons("layer_start_x"), storage.getSettingInMicrons("layer_start_y"));
}
coord_t best_dist2 = std::numeric_limits<coord_t>::max();
for (unsigned int mesh_order_idx = 0; mesh_order_idx < mesh_order.size(); mesh_order_idx++)
{
unsigned int mesh_idx = mesh_order[mesh_order_idx];
SliceMeshStorage& mesh = storage.meshes[mesh_idx];
for (SliceLayerPart& part : mesh.layers[layer_nr].parts)
{
Point middle = (part.boundaryBox.min + part.boundaryBox.max) / 2;
coord_t dist2 = vSize2(middle - layer_start_position);
if (dist2 < best_dist2)
{
best_dist2 = dist2;
mesh_order_idx_starting_mesh = mesh_order_idx;
}
}
}
}
for (unsigned int mesh_iterator_idx = 0; mesh_iterator_idx < mesh_order.size(); mesh_iterator_idx++)
std::vector<unsigned int> mesh_order = calculateMeshOrder(storage, extruder_nr);
for (unsigned int mesh_idx : mesh_order)
{
unsigned int mesh_order_idx = (mesh_iterator_idx + mesh_order_idx_starting_mesh) % mesh_order.size();
unsigned int mesh_idx = mesh_order[mesh_order_idx];
SliceMeshStorage* mesh = &storage.meshes[mesh_idx];
if (mesh->getSettingAsSurfaceMode("magic_mesh_surface_mode") == ESurfaceMode::SURFACE)
{
@@ -578,7 +499,7 @@ void FffGcodeWriter::processLayer(SliceDataStorage& storage, int layer_nr, unsig
}
}
if (layer_nr == 0 && getExtrudersNeedPrimeDuringFirstLayer())
if (include_helper_parts && layer_nr == 0)
{
ensureAllExtrudersArePrimed(storage, gcode_layer, layer_nr);
}
@@ -592,31 +513,17 @@ 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();
gcode_layer.processFanSpeedAndMinimalLayerTime();
}
bool FffGcodeWriter::getExtrudersNeedPrimeDuringFirstLayer()
{
switch(gcode.getFlavor())
{
case EGCodeFlavor::GRIFFIN:
return true;
default:
return false; // TODO: change this once priming for other firmware types is implemented
}
gcode_layer.processFanSpeedAndMinimalLayerTime();
}
void FffGcodeWriter::ensureAllExtrudersArePrimed(SliceDataStorage& storage, GCodePlanner& gcode_layer, const int layer_nr)
{
// Add prime for all extruders which haven't primed yet.
std::vector<bool> extruder_is_used = storage.getExtrudersUsed();
//Add skirt for all extruders which haven't primed the skirt or brim yet.
for (int extruder_nr = 0; extruder_nr < storage.meshgroup->getExtruderCount(); extruder_nr++)
{
if (extruder_is_used[extruder_nr] && !extruder_prime_is_planned[extruder_nr])
{ // prime before the current gcode layer plan is written to gcode
if (gcode.getExtruderIsUsed(extruder_nr) && !skirt_brim_is_processed[extruder_nr])
{
setExtruder_addPrime(storage, gcode_layer, layer_nr, extruder_nr);
}
}
@@ -699,26 +606,15 @@ std::vector<int> FffGcodeWriter::calculateExtruderOrder(SliceDataStorage& storag
std::vector<unsigned int> FffGcodeWriter::calculateMeshOrder(SliceDataStorage& storage, int extruder_nr)
{
OrderOptimizer<unsigned int> mesh_idx_order_optimizer;
std::vector<unsigned int> ret;
for (unsigned int mesh_idx = 0; mesh_idx < storage.meshes.size(); mesh_idx++)
{
SliceMeshStorage& mesh = storage.meshes[mesh_idx];
if (mesh.getSettingAsIndex("extruder_nr") == extruder_nr)
{
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);
ret.push_back(mesh_idx);
}
}
std::list<unsigned int> mesh_indices_order = mesh_idx_order_optimizer.optimize();
std::vector<unsigned int> ret;
ret.reserve(mesh_indices_order.size());
for (unsigned int mesh_order_idx : mesh_indices_order)
{
const unsigned int mesh_idx = mesh_idx_order_optimizer.items[mesh_order_idx].second;
ret.push_back(mesh_idx);
}
return ret;
}
@@ -748,8 +644,7 @@ void FffGcodeWriter::addMeshLayerToGCode_meshSurfaceMode(SliceDataStorage& stora
}
EZSeamType z_seam_type = mesh->getSettingAsZSeamType("z_seam_type");
Point z_seam_pos(mesh->getSettingInMicrons("z_seam_x"), mesh->getSettingInMicrons("z_seam_y"));
gcode_layer.addPolygonsByOptimizer(polygons, &mesh->inset0_config, nullptr, z_seam_type, z_seam_pos, mesh->getSettingInMicrons("wall_0_wipe_dist"), mesh->getSettingBoolean("magic_spiralize"));
gcode_layer.addPolygonsByOptimizer(polygons, &mesh->inset0_config, nullptr, z_seam_type, mesh->getSettingInMicrons("wall_0_wipe_dist"), mesh->getSettingBoolean("magic_spiralize"));
addMeshOpenPolyLinesToGCode(storage, mesh, gcode_layer, layer_nr);
}
@@ -814,23 +709,73 @@ void FffGcodeWriter::addMeshLayerToGCode(SliceDataStorage& storage, SliceMeshSto
setExtruder_addPrime(storage, gcode_layer, layer_nr, mesh->getSettingAsIndex("extruder_nr"));
EZSeamType z_seam_type = mesh->getSettingAsZSeamType("z_seam_type");
Point z_seam_pos(mesh->getSettingInMicrons("z_seam_x"), mesh->getSettingInMicrons("z_seam_y"));
Point layer_start_position = last_position_planned;
if (storage.getSettingBoolean("start_layers_at_same_position"))
{
layer_start_position = Point(storage.getSettingInMicrons("layer_start_x"), storage.getSettingInMicrons("layer_start_y"));
}
PathOrderOptimizer part_order_optimizer(layer_start_position, z_seam_pos, z_seam_type);
PathOrderOptimizer part_order_optimizer(layer_start_position, z_seam_type);
for(unsigned int partNr=0; partNr<layer->parts.size(); partNr++)
{
part_order_optimizer.addPolygon(layer->parts[partNr].insets[0][0]);
}
part_order_optimizer.optimize();
for (int part_idx : part_order_optimizer.polyOrder)
bool skin_alternate_rotation = mesh->getSettingBoolean("skin_alternate_rotation") && ( mesh->getSettingAsCount("top_layers") >= 4 || mesh->getSettingAsCount("bottom_layers") >= 4 );
for(int order_idx : part_order_optimizer.polyOrder)
{
SliceLayerPart& part = layer->parts[part_idx];
addMeshPartToGCode(storage, mesh, part, gcode_layer, layer_nr);
SliceLayerPart& part = layer->parts[order_idx];
EFillMethod infill_pattern = mesh->getSettingAsFillMethod("infill_pattern");
int infill_angle = 45;
if ((infill_pattern == EFillMethod::LINES || infill_pattern == EFillMethod::ZIG_ZAG))
{
unsigned int combined_infill_layers = std::max(1U, round_divide(mesh->getSettingInMicrons("infill_sparse_thickness"), std::max(getSettingInMicrons("layer_height"), 1)));
if ((layer_nr / combined_infill_layers) & 1)
{ // switch every [combined_infill_layers] layers
infill_angle += 90;
}
}
int infill_line_distance = mesh->getSettingInMicrons("infill_line_distance");
int infill_overlap = mesh->getSettingInMicrons("infill_overlap_mm");
gcode_layer.setIsInside(&part); // going to print inside stuff below
if (mesh->getSettingBoolean("infill_before_walls"))
{
processMultiLayerInfill(gcode_layer, mesh, part, layer_nr, infill_line_distance, infill_overlap, infill_angle);
processSingleLayerInfill(gcode_layer, mesh, part, layer_nr, infill_line_distance, infill_overlap, infill_angle);
}
processInsets(gcode_layer, mesh, part, layer_nr, z_seam_type);
if (!mesh->getSettingBoolean("infill_before_walls"))
{
processMultiLayerInfill(gcode_layer, mesh, part, layer_nr, infill_line_distance, infill_overlap, infill_angle);
processSingleLayerInfill(gcode_layer, mesh, part, layer_nr, infill_line_distance, infill_overlap, infill_angle);
}
EFillMethod skin_pattern = mesh->getSettingAsFillMethod("top_bottom_pattern");
int skin_angle = 45;
if ((skin_pattern == EFillMethod::LINES || skin_pattern == EFillMethod::ZIG_ZAG) && layer_nr & 1)
{
skin_angle += 90; // should coincide with infill_angle (if both skin and infill are lines) so that the first top layer is orthogonal to the last infill layer
}
if (skin_alternate_rotation && ( layer_nr / 2 ) & 1)
skin_angle -= 45;
int64_t skin_overlap = mesh->getSettingInMicrons("skin_overlap_mm");
processSkin(gcode_layer, mesh, part, layer_nr, skin_overlap, skin_angle);
//After a layer part, make sure the nozzle is inside the comb boundary, so we do not retract on the perimeter.
if (!mesh->getSettingBoolean("magic_spiralize") || static_cast<int>(layer_nr) < mesh->getSettingAsCount("bottom_layers"))
{
gcode_layer.moveInsideCombBoundary(mesh->getSettingInMicrons((mesh->getSettingAsCount("wall_line_count") > 1) ? "wall_line_width_x" : "wall_line_width_0") * 1, part);
}
gcode_layer.setIsInside(nullptr);
}
if (mesh->getSettingAsSurfaceMode("magic_mesh_surface_mode") != ESurfaceMode::NORMAL)
{
@@ -838,64 +783,6 @@ void FffGcodeWriter::addMeshLayerToGCode(SliceDataStorage& storage, SliceMeshSto
}
}
void FffGcodeWriter::addMeshPartToGCode(SliceDataStorage& storage, SliceMeshStorage* mesh, 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 );
EFillMethod infill_pattern = mesh->getSettingAsFillMethod("infill_pattern");
int infill_angle = 45;
if ((infill_pattern == EFillMethod::LINES || infill_pattern == EFillMethod::ZIG_ZAG))
{
unsigned int combined_infill_layers = std::max(1U, round_divide(mesh->getSettingInMicrons("infill_sparse_thickness"), std::max(getSettingInMicrons("layer_height"), (coord_t)1)));
if ((layer_nr / combined_infill_layers) & 1)
{ // switch every [combined_infill_layers] layers
infill_angle += 90;
}
}
int infill_line_distance = mesh->getSettingInMicrons("infill_line_distance");
int infill_overlap = mesh->getSettingInMicrons("infill_overlap_mm");
gcode_layer.setIsInside(true); // going to print inside stuff below
if (mesh->getSettingBoolean("infill_before_walls"))
{
processMultiLayerInfill(gcode_layer, mesh, part, layer_nr, infill_line_distance, infill_overlap, infill_angle);
processSingleLayerInfill(gcode_layer, mesh, part, layer_nr, infill_line_distance, infill_overlap, infill_angle);
}
EZSeamType z_seam_type = mesh->getSettingAsZSeamType("z_seam_type");
Point z_seam_pos(mesh->getSettingInMicrons("z_seam_x"), mesh->getSettingInMicrons("z_seam_y"));
processInsets(gcode_layer, mesh, part, layer_nr, z_seam_type, z_seam_pos);
if (!mesh->getSettingBoolean("infill_before_walls"))
{
processMultiLayerInfill(gcode_layer, mesh, part, layer_nr, infill_line_distance, infill_overlap, infill_angle);
processSingleLayerInfill(gcode_layer, mesh, part, layer_nr, infill_line_distance, infill_overlap, infill_angle);
}
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)
{
skin_angle += 90; // should coincide with infill_angle (if both skin and infill are lines) so that the first top layer is orthogonal to the last infill layer
}
if (skin_alternate_rotation && ( layer_nr / 2 ) & 1)
skin_angle -= 45;
int64_t skin_overlap = mesh->getSettingInMicrons("skin_overlap_mm");
processSkinAndPerimeterGaps(gcode_layer, mesh, part, layer_nr, skin_overlap, skin_angle);
//After a layer part, make sure the nozzle is inside the comb boundary, so we do not retract on the perimeter.
if (!mesh->getSettingBoolean("magic_spiralize") || static_cast<int>(layer_nr) < mesh->getSettingAsCount("bottom_layers"))
{
gcode_layer.moveInsideCombBoundary(mesh->getSettingInMicrons((mesh->getSettingAsCount("wall_line_count") > 1) ? "wall_line_width_x" : "wall_line_width_0") * 1);
}
gcode_layer.setIsInside(false);
}
@@ -923,7 +810,7 @@ void FffGcodeWriter::processMultiLayerInfill(GCodePlanner& gcode_layer, SliceMes
}
Infill infill_comp(infill_pattern, part.infill_area_per_combine_per_density[density_idx][combine_idx], 0, infill_line_width, infill_line_distance_here, infill_overlap, infill_angle, z, infill_shift);
infill_comp.generate(infill_polygons, infill_lines, mesh);
infill_comp.generate(infill_polygons, infill_lines);
}
gcode_layer.addPolygonsByOptimizer(infill_polygons, &mesh->infill_config[combine_idx]);
gcode_layer.addLinesByOptimizer(infill_lines, &mesh->infill_config[combine_idx], (infill_pattern == EFillMethod::ZIG_ZAG)? SpaceFillType::PolyLines : SpaceFillType::Lines);
@@ -979,7 +866,7 @@ void FffGcodeWriter::processSingleLayerInfill(GCodePlanner& gcode_layer, SliceMe
infill_line_distance_here /= 2;
}
Infill infill_comp(pattern, part.infill_area_per_combine_per_density[density_idx][0], 0, infill_line_width, infill_line_distance_here, infill_overlap, infill_angle, z, infill_shift);
infill_comp.generate(infill_polygons, infill_lines, mesh);
infill_comp.generate(infill_polygons, infill_lines);
}
gcode_layer.addPolygonsByOptimizer(infill_polygons, &mesh->infill_config[0]);
if (pattern == EFillMethod::GRID || pattern == EFillMethod::LINES || pattern == EFillMethod::TRIANGLES)
@@ -992,7 +879,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, SliceMeshStorage* mesh, SliceLayerPart& part, unsigned int layer_nr, EZSeamType z_seam_type)
{
bool compensate_overlap_0 = mesh->getSettingBoolean("travel_compensate_overlapping_walls_0_enabled");
bool compensate_overlap_x = mesh->getSettingBoolean("travel_compensate_overlapping_walls_x_enabled");
@@ -1007,9 +894,7 @@ void FffGcodeWriter::processInsets(GCodePlanner& gcode_layer, SliceMeshStorage*
}
if (static_cast<int>(layer_nr) == mesh->getSettingAsCount("bottom_layers") && part.insets.size() > 0)
{ // on the last normal layer first make the outer wall normally and then start a second outer wall from the same hight, but gradually moving upward
WallOverlapComputation* wall_overlap_computation(nullptr);
int wall_0_wipe_dist(0);
gcode_layer.addPolygonsByOptimizer(part.insets[0], &mesh->insetX_config, wall_overlap_computation, EZSeamType::SHORTEST, z_seam_pos, wall_0_wipe_dist, spiralize);
gcode_layer.addPolygonsByOptimizer(part.insets[0], &mesh->insetX_config, nullptr, EZSeamType::SHORTEST, mesh->getSettingInMicrons("wall_0_wipe_dist"), false);
}
}
int processed_inset_number = -1;
@@ -1024,14 +909,13 @@ void FffGcodeWriter::processInsets(GCodePlanner& gcode_layer, SliceMeshStorage*
{
if (!compensate_overlap_0)
{
WallOverlapComputation* wall_overlap_computation(nullptr);
gcode_layer.addPolygonsByOptimizer(part.insets[0], &mesh->inset0_config, wall_overlap_computation, z_seam_type, z_seam_pos, mesh->getSettingInMicrons("wall_0_wipe_dist"), spiralize);
gcode_layer.addPolygonsByOptimizer(part.insets[0], &mesh->inset0_config, nullptr, z_seam_type, mesh->getSettingInMicrons("wall_0_wipe_dist"), spiralize);
}
else
{
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);
gcode_layer.addPolygonsByOptimizer(outer_wall, &mesh->inset0_config, &wall_overlap_computation, z_seam_type, mesh->getSettingInMicrons("wall_0_wipe_dist"), spiralize);
}
}
else
@@ -1052,18 +936,15 @@ 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::processSkin(GCodePlanner& gcode_layer, SliceMeshStorage* mesh, 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
&& !mesh->getSettingBoolean("magic_spiralize");
bool fill_perimeter_gaps = mesh->getSettingAsFillPerimeterGapMode("fill_perimeter_gaps") != FillPerimeterGapMode::NOWHERE;
Point z_seam_pos(0, 0); // not used
PathOrderOptimizer part_order_optimizer(gcode_layer.getLastPosition(), z_seam_pos, EZSeamType::SHORTEST);
PathOrderOptimizer part_order_optimizer(gcode_layer.getLastPosition(), 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;
@@ -1078,9 +959,7 @@ void FffGcodeWriter::processSkinAndPerimeterGaps(GCodePlanner& gcode_layer, Slic
Polygons skin_polygons;
Polygons skin_lines;
EFillMethod pattern = (layer_nr == 0)?
mesh->getSettingAsFillMethod("top_bottom_pattern_0") :
mesh->getSettingAsFillMethod("top_bottom_pattern");
EFillMethod pattern = mesh->getSettingAsFillMethod("top_bottom_pattern");
int bridge = -1;
if (layer_nr > 0)
bridge = bridgeAngle(skin_part.outline, &mesh->layers[layer_nr-1]);
@@ -1109,13 +988,13 @@ void FffGcodeWriter::processSkinAndPerimeterGaps(GCodePlanner& gcode_layer, Slic
{
// add perimeter gaps between the outer skin inset and the innermost wall
const Polygons outer = skin_part.outline;
const Polygons inner = skin_part.insets[0].offset(mesh->insetX_config.getLineWidth() / 2 + perimeter_gaps_extra_offset);
const Polygons inner = skin_part.insets[0].offset(mesh->insetX_config.getLineWidth() / 2 + perimeter_gaps_extra_offset * 2);
perimeter_gaps.add(outer.difference(inner));
for (unsigned int inset_idx = 1; inset_idx < skin_part.insets.size(); inset_idx++)
{ // add perimeter gaps between consecutive skin walls
const Polygons outer = skin_part.insets[inset_idx - 1].offset(-1 * mesh->insetX_config.getLineWidth() / 2 - perimeter_gaps_extra_offset);
const Polygons inner = skin_part.insets[inset_idx].offset(mesh->insetX_config.getLineWidth() / 2);
const Polygons inner = skin_part.insets[inset_idx].offset(mesh->insetX_config.getLineWidth() / 2 + perimeter_gaps_extra_offset);
perimeter_gaps.add(outer.difference(inner));
}
}
@@ -1132,6 +1011,13 @@ 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)
@@ -1142,56 +1028,28 @@ 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() - 1; inset_idx++)
for (unsigned int inset_idx = 1; inset_idx < part.insets.size(); inset_idx++)
{
const Polygons outer = part.insets[inset_idx].offset(-1 * line_width / 2 - perimeter_gaps_extra_offset);
const Polygons outer = part.insets[inset_idx - 1].offset(-1 * line_width / 2 - perimeter_gaps_extra_offset);
line_width = mesh->insetX_config.getLineWidth();
Polygons inner = part.insets[inset_idx + 1].offset(line_width / 2);
const Polygons inner = part.insets[inset_idx].offset(line_width / 2 + perimeter_gaps_extra_offset);
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
)
{
const Polygons outer = part.insets.back().offset(-1 * line_width / 2 - perimeter_gaps_extra_offset);
Polygons inner = part.infill_area;
for (SkinPart& skin_part : part.skin_parts)
{
inner.add(skin_part.outline);
}
inner = inner.unionPolygons();
perimeter_gaps.add(outer.difference(inner));
}
}
Polygons gap_polygons; // unused
Polygons gap_lines; // soon to be generated gap filler lines
Polygons skin_polygons; // unused
Polygons skin_lines; // soon to be generated gap filler lines
int offset = 0;
int extra_infill_shift = 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);
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.addLinesByOptimizer(gap_lines, &mesh->perimeter_gap_config, SpaceFillType::Lines);
gcode_layer.addLinesByOptimizer(skin_lines, &mesh->skin_config, SpaceFillType::Lines);
}
}
@@ -1369,29 +1227,11 @@ void FffGcodeWriter::setExtruder_addPrime(SliceDataStorage& storage, GCodePlanne
if (extruder_changed)
{
if (!extruder_prime_is_planned[extruder_nr])
{
ExtruderTrain* train = storage.meshgroup->getExtruderTrain(extruder_nr);
// move to prime position
bool prime_pos_is_abs = train->getSettingBoolean("extruder_prime_pos_abs");
Point prime_pos = Point(train->getSettingInMicrons("extruder_prime_pos_x"), train->getSettingInMicrons("extruder_prime_pos_y"));
gcode_layer.addTravel(prime_pos_is_abs? prime_pos : gcode_layer.getLastPosition() + prime_pos);
gcode_layer.planPrime();
extruder_prime_is_planned[extruder_nr] = true;
}
assert(extruder_prime_is_planned[extruder_nr] && "extruders should be primed before they are used!");
if (layer_nr == 0 && !skirt_brim_is_processed[extruder_nr])
{
processSkirtBrim(storage, gcode_layer, extruder_nr);
}
if (layer_nr >= -Raft::getFillerLayerCount(storage))
{
addPrimeTower(storage, gcode_layer, layer_nr, previous_extruder);
}
addPrimeTower(storage, gcode_layer, layer_nr, previous_extruder);
}
}
+11 -56
Ver Arquivo
@@ -65,28 +65,18 @@ private:
*/
bool skirt_brim_is_processed[MAX_EXTRUDERS];
std::vector<std::vector<unsigned int>> mesh_order_per_extruder; //!< For each extruder, the cyclic order of the meshes (the first element is not the starting element per se)
/*!
* For each extruder whether priming has already been planned
*/
bool extruder_prime_is_planned[MAX_EXTRUDERS];
std::vector<FanSpeedLayerTimeSettings> fan_speed_layer_time_settings_per_extruder; //!< The settings used relating to minimal layer time and fan speeds. Configured for each extruder.
Point last_position_planned; //!< The position of the head before planning the next layer
int current_extruder_planned; //!< The extruder train in use before planning the next layer
bool is_inside_mesh_layer_part; //!< Whether the last position was inside a layer part (used in combing)
public:
FffGcodeWriter(SettingsBase* settings_)
: SettingsMessenger(settings_)
, max_object_height(0)
, layer_plan_buffer(this, gcode)
, extruder_prime_is_planned {} // initialize all values in array with [false]
, last_position_planned(no_point)
, current_extruder_planned(0) // changed somewhere early in FffGcodeWriter::writeGCode
, is_inside_mesh_layer_part(false)
{
max_object_height = 0;
}
/*!
@@ -183,26 +173,15 @@ private:
* \param[out] storage The data storage to which to save the configurations.
*/
void initConfigs(SliceDataStorage& storage);
/*!
* Get the extruder with which to start the print.
*
* Generally this is the adhesion_extruder_nr, but in case the platform adhesion type is none,
* the extruder with lowest number which is used on the first layer is used as initial extruder.
*
* \param[in] storage where to get settings from.
*/
unsigned int getStartExtruder(SliceDataStorage& storage);
/*!
* Set temperatures and perform initial priming.
*
* Write a stub header if CuraEngine is in command line tool mode. (Cause writing the header afterwards would entail moving all gcode down.)
*
* \param[in] storage where the slice data is stored.
* \param[in] start_extruder_nr The extruder with which to start the print.
*/
void processStartingCode(SliceDataStorage& storage, const unsigned int start_extruder_nr);
void processStartingCode(SliceDataStorage& storage);
/*!
* Move up and over the already printed meshgroups to print the next meshgroup.
@@ -231,13 +210,6 @@ private:
*/
void processLayer(SliceDataStorage& storage, int layer_nr, unsigned int total_layers);
/*!
* Whether the extruders need to be primed separately just before they are used.
*
* \return whether the extruders need to be primed separately just before they are used
*/
bool getExtrudersNeedPrimeDuringFirstLayer();
/*!
* Plan priming of all used extruders which haven't been primed yet
* \param[in] storage where the slice data is stored.
@@ -315,27 +287,15 @@ private:
void addMeshOpenPolyLinesToGCode(SliceDataStorage& storage, SliceMeshStorage* mesh, GCodePlanner& gcode_layer, int layer_nr);
/*!
* Add a single layer from a single mesh-volume to the layer plan \p gcode_layer.
* Add a single layer from a single mesh-volume to the layer plan \p gcodeLayer.
*
* \param[in] storage where the slice data is stored.
* \param mesh The mesh to add to the layer plan \p gcode_layer.
* \param gcode_layer The initial planning of the gcode of the layer.
* \param mesh The mesh to add to the layer plan \p gcodeLayer.
* \param gcodeLayer The initial planning of the gcode of the layer.
* \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);
/*!
* Add a single part from a given layer of a mesh-volume to the layer plan \p gcode_layer.
*
* \param[in] storage where the slice data is stored.
* \param mesh The mesh to add to the layer plan \p gcode_layer.
* \param part The part to add
* \param gcode_layer The initial planning of the gcode of the layer.
* \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 addMeshLayerToGCode(SliceDataStorage& storage, SliceMeshStorage* mesh, GCodePlanner& gcodeLayer, int layer_nr);
/*!
* Add thicker (multiple layers) sparse infill for a given part in a layer plan.
@@ -369,25 +329,20 @@ private:
* \param part The part for which to create gcode
* \param layer_nr The current layer number.
* \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, SliceMeshStorage* mesh, SliceLayerPart& part, unsigned int layer_nr, EZSeamType z_seam_type);
/*!
* Add the gcode of the top/bottom skin of the given part and of the perimeter gaps.
*
* Perimter gaps are generated for skin outlines and printed while the skin fill of the skin part is printed.
* Perimeter gaps between the walls are added to the gcode afterwards.
*
* Add the gcode of the top/bottom skin of the given part.
* \param gcodeLayer The initial planning of the gcode of the layer.
* \param mesh The mesh for which to add to the layer plan \p gcodeLayer.
* \param part The part for which to create gcode
* \param layer_nr The current layer number.
* \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 skin_overlap The distance by which the skin overlaps with the wall insets.
* \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 processSkin(cura::GCodePlanner& gcode_layer, cura::SliceMeshStorage* mesh, 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.
+14 -86
Ver Arquivo
@@ -3,10 +3,6 @@
#include <algorithm>
#include <map> // multimap (ordered map allowing duplicate keys)
#ifdef _OPENMP
#include <omp.h>"
#endif
#include "utils/math.h"
#include "utils/algorithm.h"
#include "slicer.h"
@@ -57,7 +53,7 @@ unsigned int FffPolygonGenerator::getDraftShieldLayerCount(const unsigned int to
case DraftShieldHeightLimitation::FULL:
return total_layers;
case DraftShieldHeightLimitation::LIMITED:
return std::max((coord_t)0, (getSettingInMicrons("draft_shield_height") - getSettingInMicrons("layer_height_0")) / getSettingInMicrons("layer_height") + 1);
return std::max(0, (getSettingInMicrons("draft_shield_height") - getSettingInMicrons("layer_height_0")) / getSettingInMicrons("layer_height") + 1);
}
}
@@ -155,10 +151,6 @@ 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;
}
@@ -169,10 +161,6 @@ 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;
}
@@ -309,7 +297,6 @@ void FffPolygonGenerator::slices2polygons(SliceDataStorage& storage, TimeKeeper&
// handle helpers
storage.primeTower.generatePaths(storage);
storage.primeTower.subtractFromSupport(storage);
logDebug("Processing ooze shield\n");
processOozeShield(storage);
@@ -349,24 +336,12 @@ void FffPolygonGenerator::processBasicWallsSkinInfill(SliceDataStorage& storage,
// walls
unsigned int processed_layer_count = 0;
#pragma omp parallel for default(none) shared(mesh_layer_count, mesh, inset_skin_progress_estimate, processed_layer_count) schedule(dynamic)
for (unsigned int layer_number = 0; layer_number < mesh.layers.size(); layer_number++)
{
logDebug("Processing insets for layer %i of %i\n", layer_number, mesh_layer_count);
processInsets(mesh, layer_number);
#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);
}
ProgressEstimatorLinear* skin_estimator = new ProgressEstimatorLinear(mesh_layer_count);
@@ -397,33 +372,16 @@ void FffPolygonGenerator::processBasicWallsSkinInfill(SliceDataStorage& storage,
{
mesh_max_bottom_layer_count = std::max(mesh_max_bottom_layer_count, mesh.getSettingAsCount("bottom_layers"));
}
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)
for (unsigned int layer_number = 0; layer_number < mesh.layers.size(); layer_number++)
{
#pragma omp for schedule(dynamic)
for (unsigned int layer_number = 0; layer_number < mesh.layers.size(); layer_number++)
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.
{
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++;
}
processSkinsAndInfill(mesh, layer_number, process_infill);
}
double progress = inset_skin_progress_estimate.progress(layer_number);
Progress::messageProgress(Progress::Stage::INSET_SKIN, progress * 100, 100);
}
}
void FffPolygonGenerator::processInfillMesh(SliceDataStorage& storage, unsigned int mesh_order_idx, std::vector<unsigned int>& mesh_order)
@@ -502,14 +460,8 @@ void FffPolygonGenerator::processDerivedWallsSkinInfill(SliceMeshStorage& mesh)
// create gradual infill areas
SkinInfillAreaComputation::generateGradualInfill(mesh, mesh.getSettingInMicrons("gradual_infill_step_height"), mesh.getSettingAsCount("gradual_infill_steps"));
//SubDivCube Pre-compute Octree
if (mesh.getSettingAsFillMethod("infill_pattern") == EFillMethod::CUBICSUBDIV)
{
SubDivCube::precomputeOctree(mesh);
}
// combine infill
unsigned int combined_infill_layers = std::max(1U, round_divide(mesh.getSettingInMicrons("infill_sparse_thickness"), std::max(getSettingInMicrons("layer_height"), (coord_t)1))); //How many infill layers to combine to obtain the requested sparse thickness.
unsigned int combined_infill_layers = std::max(1U, round_divide(mesh.getSettingInMicrons("infill_sparse_thickness"), std::max(getSettingInMicrons("layer_height"), 1))); //How many infill layers to combine to obtain the requested sparse thickness.
combineInfillLayers(mesh,combined_infill_layers);
// fuzzy skin
@@ -519,12 +471,6 @@ void FffPolygonGenerator::processDerivedWallsSkinInfill(SliceMeshStorage& mesh)
}
}
/*
* This function is executed in a parallel region based on layer_nr.
* When modifying make sure any changes does not introduce data races.
*
* processInsets only reads and writes data for the current layer
*/
void FffPolygonGenerator::processInsets(SliceMeshStorage& mesh, unsigned int layer_nr)
{
SliceLayer* layer = &mesh.layers[layer_nr];
@@ -563,19 +509,11 @@ void FffPolygonGenerator::removeEmptyFirstLayers(SliceDataStorage& storage, cons
for (SliceMeshStorage& mesh : storage.meshes)
{
SliceLayer& layer = mesh.layers[layer_idx];
if (mesh.getSettingAsSurfaceMode("magic_mesh_surface_mode") != ESurfaceMode::NORMAL && layer.openPolyLines.size() > 0)
if (layer.parts.size() > 0 || (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)
@@ -606,18 +544,8 @@ void FffPolygonGenerator::removeEmptyFirstLayers(SliceDataStorage& storage, cons
support_layers.erase(support_layers.begin(), support_layers.begin() + n_empty_first_layers);
}
}
/*
* 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)
void FffPolygonGenerator::processSkinsAndInfill(SliceMeshStorage& mesh, unsigned int layer_nr, bool process_infill)
{
if (mesh.getSettingAsSurfaceMode("magic_mesh_surface_mode") == ESurfaceMode::SURFACE)
{
+4 -2
Ver Arquivo
@@ -251,7 +251,7 @@ void LayerPlanBuffer::insertFinalPrintTempCommand(std::vector<ExtruderPlan*>& ex
time_window += prev_extruder_plan_time;
heated_pre_travel_time = prev_extruder_plan.heated_pre_travel_time;
if (prev_extruder_plan.estimates.getTotalUnretractedTime() > 0)
if (prev_extruder_plan.estimates.getTotalUnretractedTime() > 0 && prev_extruder_plan.estimates.getMaterial() > 0)
{ // handle temp statistics
assert(prev_extruder_plan.printing_temperature != -1 && "Previous extruder plan should already have a temperature planned");
weighted_average_print_temp += prev_extruder_plan.printing_temperature * prev_extruder_plan_time;
@@ -349,7 +349,9 @@ void LayerPlanBuffer::insertTempCommands()
ExtruderPlan& extruder_plan = layer_plan.extruder_plans[extruder_plan_idx];
int extruder = extruder_plan.extruder;
double time = extruder_plan.estimates.getTotalUnretractedTime();
if (time <= 0.0)
if (time <= 0.0
|| extruder_plan.estimates.getMaterial() == 0.0 // extruder plan only consists of moves (when an extruder switch occurs at the beginning of a layer)
)
{
continue;
}
-1
Ver Arquivo
@@ -58,7 +58,6 @@ int MeshGroup::getExtruderCount() const
ExtruderTrain* MeshGroup::createExtruderTrain(unsigned int extruder_nr)
{
assert((int)extruder_nr >= 0 && (int)extruder_nr < getSettingAsCount("machine_extruder_count") && "only valid extruder trains may be requested!");
if (!extruders[extruder_nr])
{
extruders[extruder_nr] = new ExtruderTrain(this, extruder_nr);
+24 -13
Ver Arquivo
@@ -82,6 +82,12 @@ Preheat::WarmUpResult Preheat::getWarmUpPointAfterCoolDown(double time_window, u
result.heating_time = extra_heatup_time;
limited_time_window = time_window - extra_heatup_time;
outer_temp = temp_start;
if (limited_time_window < 0.0)
{
result.heating_time = 0.0;
result.lowest_temperature = temp_start;
return result;
}
}
else
{
@@ -89,14 +95,13 @@ Preheat::WarmUpResult Preheat::getWarmUpPointAfterCoolDown(double time_window, u
result.heating_time = 0;
limited_time_window = time_window - extra_cooldown_time;
outer_temp = temp_end;
if (limited_time_window < 0.0)
{
result.heating_time = 0.0;
result.lowest_temperature = temp_end;
return result;
}
}
if (limited_time_window < 0.0)
{
result.heating_time = 0.0;
result.lowest_temperature = std::min(temp_start, temp_end);
return result;
}
double time_ratio_cooldown_heatup = time_to_cooldown_1_degree / time_to_heatup_1_degree;
double time_to_heat_from_standby_to_print_temp = getTimeToGoFromTempToTemp(extruder, temp_mid, outer_temp, during_printing);
double time_needed_to_reach_standby_temp = time_to_heat_from_standby_to_print_temp * (1.0 + time_ratio_cooldown_heatup);
@@ -145,6 +150,12 @@ Preheat::CoolDownResult Preheat::getCoolDownPointAfterWarmUp(double time_window,
result.cooling_time = 0;
limited_time_window = time_window - extra_heatup_time;
outer_temp = temp_end;
if (limited_time_window < 0.0)
{
result.cooling_time = 0.0;
result.highest_temperature = temp_end;
return result;
}
}
else
{
@@ -152,12 +163,12 @@ Preheat::CoolDownResult Preheat::getCoolDownPointAfterWarmUp(double time_window,
result.cooling_time = extra_cooldown_time;
limited_time_window = time_window - extra_cooldown_time;
outer_temp = temp_start;
}
if (limited_time_window < 0.0)
{
result.cooling_time = 0.0;
result.highest_temperature = std::max(temp_start, temp_end);
return result;
if (limited_time_window < 0.0)
{
result.cooling_time = 0.0;
result.highest_temperature = temp_start;
return result;
}
}
double time_ratio_cooldown_heatup = time_to_cooldown_1_degree / time_to_heatup_1_degree;
double cool_down_time = getTimeToGoFromTempToTemp(extruder, temp_mid, outer_temp, during_printing);
+1
Ver Arquivo
@@ -117,6 +117,7 @@ public:
{
return config_per_extruder[extruder_nr].flow_dependent_temperature;
}
public:
/*!
* Get the optimal temperature corresponding to a given average flow,
* or the initial layer temperature.
+12 -23
Ver Arquivo
@@ -12,7 +12,7 @@
namespace cura
{
PrimeTower::PrimeTower(const SliceDataStorage& storage)
PrimeTower::PrimeTower()
: is_hollow(false)
, wipe_from_middle(false)
, current_pre_wipe_location_idx(0)
@@ -21,13 +21,6 @@ PrimeTower::PrimeTower(const SliceDataStorage& storage)
{
last_prime_tower_poly_printed[extruder_nr] = -1;
}
enabled = storage.getSettingBoolean("prime_tower_enable")
&& storage.getSettingInMicrons("prime_tower_wall_thickness") > 10
&& storage.getSettingInMicrons("prime_tower_size") > 10;
if (enabled)
{
generateGroundpoly(storage);
}
}
@@ -90,7 +83,10 @@ void PrimeTower::generateGroundpoly(const SliceDataStorage& storage)
void PrimeTower::generatePaths(const SliceDataStorage& storage)
{
enabled &= storage.max_print_height_second_to_last_extruder >= 0; //Maybe it turns out that we don't need a prime tower after all because there are no layer switches.
enabled = storage.max_print_height_second_to_last_extruder >= 0
&& storage.getSettingBoolean("prime_tower_enable")
&& storage.getSettingInMicrons("prime_tower_wall_thickness") > 10
&& storage.getSettingInMicrons("prime_tower_size") > 10;
if (enabled)
{
generatePaths_denseInfill(storage);
@@ -104,6 +100,8 @@ void PrimeTower::generatePaths_denseInfill(const SliceDataStorage& storage)
int infill_overlap = 60; // so that it can't be zero; EDIT: wtf?
int extra_infill_shift = 0;
generateGroundpoly(storage);
int64_t z = 0; // (TODO) because the prime tower stores the paths for each extruder for once instead of generating each layer, we don't know the z position
for (int extruder = 0; extruder < extruder_count; extruder++)
@@ -162,7 +160,7 @@ void PrimeTower::addToGcode(const SliceDataStorage& storage, GCodePlanner& gcode
preWipe(storage, gcodeLayer, new_extruder);
}
addToGcode_denseInfill(gcodeLayer, layer_nr, new_extruder);
addToGcode_denseInfill(storage, gcodeLayer, gcode, layer_nr, prev_extruder, new_extruder);
// post-wipe:
if (post_wipe)
@@ -171,16 +169,16 @@ void PrimeTower::addToGcode(const SliceDataStorage& storage, GCodePlanner& gcode
}
}
void PrimeTower::addToGcode_denseInfill(GCodePlanner& gcodeLayer, const int layer_nr, const int extruder)
void PrimeTower::addToGcode_denseInfill(const SliceDataStorage& storage, GCodePlanner& gcodeLayer, const GCodeExport& gcode, const int layer_nr, const int prev_extruder, const int new_extruder)
{
ExtrusionMoves& pattern = patterns_per_extruder[extruder][((layer_nr % 2) + 2) % 2]; // +2) %2 to handle negative layer numbers
ExtrusionMoves& pattern = patterns_per_extruder[new_extruder][((layer_nr % 2) + 2) % 2]; // +2) %2 to handle negative layer numbers
GCodePathConfig& config = config_per_extruder[extruder];
GCodePathConfig& config = config_per_extruder[new_extruder];
gcodeLayer.addPolygonsByOptimizer(pattern.polygons, &config);
gcodeLayer.addLinesByOptimizer(pattern.lines, &config, SpaceFillType::Lines);
last_prime_tower_poly_printed[extruder] = layer_nr;
last_prime_tower_poly_printed[new_extruder] = layer_nr;
}
Point PrimeTower::getLocationBeforePrimeTower(const SliceDataStorage& storage)
@@ -297,14 +295,5 @@ void PrimeTower::preWipe(const SliceDataStorage& storage, GCodePlanner& gcode_la
gcode_layer.addExtrusionMove(end, &config_per_extruder[extruder_nr], SpaceFillType::None, flow);
}
void PrimeTower::subtractFromSupport(SliceDataStorage& storage)
{
const Polygons outside_polygon = ground_poly.getOutsidePolygons();
for(size_t layer = 0; layer <= (size_t)storage.max_print_height_second_to_last_extruder + 1 && layer < storage.support.supportLayers.size(); layer++)
{
storage.support.supportLayers[layer].supportAreas = storage.support.supportLayers[layer].supportAreas.difference(outside_polygon);
}
}
}//namespace cura
+10 -26
Ver Arquivo
@@ -1,6 +1,3 @@
//Copyright (c) 2016 Ultimaker B.V.
//CuraEngine is released under the terms of the AGPLv3 or higher.
#ifndef PRIME_TOWER_H
#define PRIME_TOWER_H
@@ -33,6 +30,8 @@ private:
Polygons polygons;
Polygons lines;
};
bool enabled; //!< Whether the prime tower is enabled
int extruder_count; //!< number of extruders
std::vector<GCodePathConfig> config_per_extruder; //!< Path config for prime tower for each extruder
@@ -50,19 +49,10 @@ private:
int current_pre_wipe_location_idx; //!< Index into \ref PrimeTower::wipe_locations of where to pre-wipe the nozzle
public:
bool enabled; //!< Whether the prime tower is enabled.
Polygons ground_poly; //!< The outline of the prime tower to be used for each layer
std::vector<std::vector<ExtrusionMoves>> patterns_per_extruder; //!< for each extruder a vector of patterns to alternate between, over the layers
/*!
* \brief Creates a prime tower instance that will determine where and how
* the prime tower gets printed.
*
* \param storage A storage where it retrieves the prime tower settings.
*/
PrimeTower(const SliceDataStorage& storage);
/*!
* Initialize \ref PrimeTower::config_per_extruder with speed and line width settings.
*
@@ -95,6 +85,8 @@ public:
*/
void generatePaths(const SliceDataStorage& storage);
PrimeTower(); //!< basic constructor
/*!
* Add path plans for the prime tower to the \p gcode_layer
*
@@ -105,15 +97,6 @@ public:
* \param new_extruder The switched to extruder with which the prime tower paths should be generated.
*/
void addToGcode(const SliceDataStorage& storage, GCodePlanner& gcode_layer, const GCodeExport& gcode, const int layer_nr, const int prev_extruder, const int new_extruder);
/*!
* \brief Subtract the prime tower from the support areas in storage.
*
* \param storage The storage where to find the support from which to
* subtract a prime tower.
*/
void subtractFromSupport(SliceDataStorage& storage);
private:
/*!
* Layer number of the last layer in which a prime tower has been printed per extruder train.
@@ -151,15 +134,16 @@ private:
/*!
* \see PrimeTower::addToGcode
*
*
* Add path plans for the prime tower to the \p gcode_layer
*
*
* \param storage where to get settings from; where to get the maximum height of the prime tower from
* \param[in,out] gcode_layer Where to get the current extruder from; where to store the generated layer paths
* \param layer_nr The layer for which to generate the prime tower paths
* \param extruder The extruder we just switched to, with which the prime
* tower paths should be drawn.
* \param prev_extruder The previous extruder with which paths were planned; from which extruder a switch was made
* \param new_extruder The switched to extruder with which the prime tower paths should be generated.
*/
void addToGcode_denseInfill(GCodePlanner& gcode_layer, const int layer_nr, const int extruder);
void addToGcode_denseInfill(const SliceDataStorage& storage, GCodePlanner& gcode_layer, const GCodeExport& gcode, const int layer_nr, const int prev_extruder, const int new_extruder);
/*!
* Plan the moves for wiping the current nozzles oozed material before starting to print the prime tower.
+2 -13
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 "SkirtBrim.h"
#include "support.h"
@@ -22,7 +19,6 @@ void SkirtBrim::getFirstLayerOutline(SliceDataStorage& storage, const unsigned i
{ // add brim underneath support by removing support where there's brim around the model
const bool include_helper_parts = false; // include manually below
first_layer_outline = storage.getLayerOutlines(layer_nr, include_helper_parts, external_only);
first_layer_outline = first_layer_outline.unionPolygons(); //To guard against overlapping outlines, which would produce holes according to the even-odd rule.
Polygons first_layer_empty_holes;
if (outside_only)
{
@@ -48,20 +44,13 @@ void SkirtBrim::getFirstLayerOutline(SliceDataStorage& storage, const unsigned i
first_layer_outline.add(support_layer.supportAreas);
first_layer_outline.add(support_layer.skin);
}
if (storage.primeTower.enabled)
{
first_layer_outline.add(storage.primeTower.ground_poly); // don't remove parts of the prime tower, but make a brim for it
}
first_layer_outline.add(storage.primeTower.ground_poly); // don't remove parts of the prime tower, but make a brim for it
}
constexpr int join_distance = 20;
first_layer_outline = first_layer_outline.offset(join_distance).offset(-join_distance); // merge adjacent models into single polygon
constexpr int smallest_line_length = 200;
constexpr int largest_error_of_removed_point = 50;
first_layer_outline.simplify(smallest_line_length, largest_error_of_removed_point); // simplify for faster processing of the brim lines
if (first_layer_outline.size() == 0)
{
logError("Couldn't generate skirt / brim! No polygons on first layer.");
}
}
int SkirtBrim::generatePrimarySkirtBrimLines(SliceDataStorage& storage, int start_distance, unsigned int primary_line_count, const int primary_extruder_skirt_brim_line_width, const int64_t primary_extruder_minimal_length, const Polygons& first_layer_outline, Polygons& skirt_brim_primary_extruder)
-12
Ver Arquivo
@@ -12,12 +12,6 @@ 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)
@@ -64,12 +58,6 @@ 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++)
+9 -10
Ver Arquivo
@@ -18,9 +18,8 @@ void Wireframe2gcode::writeGCode()
{
gcode.preSetup(wireFrame.meshgroup);
const unsigned int start_extruder_nr = getSettingAsIndex("adhesion_extruder_nr"); // TODO: figure out how Wireframe works with dual extrusion
gcode.setInitialTemps(*wireFrame.meshgroup, start_extruder_nr);
gcode.setInitialTemps(*wireFrame.meshgroup);
if (CommandSocket::getInstance())
CommandSocket::getInstance()->beginGCode();
@@ -160,7 +159,7 @@ void Wireframe2gcode::writeGCode()
gcode.setZ(maxObjectHeight);
gcode.writeRetraction(standard_retraction_config);
gcode.writeRetraction(&standard_retraction_config);
gcode.updateTotalPrintTime();
@@ -260,7 +259,7 @@ void Wireframe2gcode::strategy_retract(WeaveLayer& layer, WeaveConnectionPart& p
Point3 lowering = vec * retract_hop_dist / 2 / vec.vSize();
Point3 lower = to - lowering;
gcode.writeMove(lower, speedUp, extrusion_mm3_per_mm_connection);
gcode.writeRetraction(retraction_config);
gcode.writeRetraction(&retraction_config);
gcode.writeMove(to + lowering, speedUp, 0);
gcode.writeDelay(top_retract_pause);
if (after_retract_hop)
@@ -269,7 +268,7 @@ void Wireframe2gcode::strategy_retract(WeaveLayer& layer, WeaveConnectionPart& p
} else
{
gcode.writeMove(to, speedUp, extrusion_mm3_per_mm_connection);
gcode.writeRetraction(retraction_config);
gcode.writeRetraction(&retraction_config);
gcode.writeMove(to + Point3(0, 0, retract_hop_dist), speedFlat, 0);
gcode.writeDelay(top_retract_pause);
if (after_retract_hop)
@@ -468,14 +467,14 @@ void Wireframe2gcode::writeFill(std::vector<WeaveRoofPart>& infill_insets, Polyg
void Wireframe2gcode::writeMoveWithRetract(Point3 to)
{
if ((gcode.getPosition() - to).vSize2() >= nozzle_top_diameter * nozzle_top_diameter * 2 * 2)
gcode.writeRetraction(standard_retraction_config);
gcode.writeRetraction(&standard_retraction_config);
gcode.writeMove(to, moveSpeed, 0);
}
void Wireframe2gcode::writeMoveWithRetract(Point to)
{
if (vSize2(gcode.getPositionXY() - to) >= nozzle_top_diameter * nozzle_top_diameter * 2 * 2)
gcode.writeRetraction(standard_retraction_config);
gcode.writeRetraction(&standard_retraction_config);
gcode.writeMove(to, moveSpeed, 0);
}
@@ -563,7 +562,7 @@ void Wireframe2gcode::processStartingCode()
{
if (getSettingBoolean("material_bed_temp_prepend"))
{
if (getSettingBoolean("machine_heated_bed") && getSettingInDegreeCelsius("material_bed_temperature") != 0)
if (getSettingBoolean("machine_heated_bed") && getSettingInDegreeCelsius("material_bed_temperature") > 0)
{
gcode.writeBedTemperatureCommand(getSettingInDegreeCelsius("material_bed_temperature"), getSettingBoolean("material_bed_temp_wait"));
}
@@ -604,7 +603,7 @@ void Wireframe2gcode::processStartingCode()
constexpr bool wait = true;
gcode.writeTemperatureCommand(start_extruder_nr, getSettingInDegreeCelsius("material_print_temperature"), wait);
gcode.writePrimeTrain(getSettingInMillimetersPerSecond("speed_travel"));
gcode.writeRetraction(standard_retraction_config);
gcode.writeRetraction(&standard_retraction_config);
}
}
-2
Ver Arquivo
@@ -642,7 +642,6 @@ void CommandSocket::sendLayerData()
{
for (std::pair<const int, std::shared_ptr<cura::proto::Layer>> entry : data.slice_data) //Note: This is in no particular order!
{
logDebug("Sending layer data for layer %i of %i.\n", entry.first, data.slice_data.size());
private_data->socket->sendMessage(entry.second); //Send the actual layers.
}
data.sliced_objects = 0;
@@ -668,7 +667,6 @@ void CommandSocket::sendOptimizedLayerData()
{
for (std::pair<const int, std::shared_ptr<cura::proto::LayerOptimized>> entry : data.slice_data) //Note: This is in no particular order!
{
logDebug("Sending layer data for layer %i of %i.\n", entry.first, data.slice_data.size());
private_data->socket->sendMessage(entry.second); //Send the actual layers.
}
data.sliced_objects = 0;
+23 -26
Ver Arquivo
@@ -11,8 +11,6 @@
namespace cura {
double layer_height; //!< report basic layer height in RepRap gcode file.
GCodeExport::GCodeExport()
: output_stream(&std::cout)
, currentPosition(0,0,MM2INT(20))
@@ -99,8 +97,6 @@ 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";
@@ -113,15 +109,20 @@ void GCodeExport::preSetup(const MeshGroup* meshgroup)
estimateCalculator.setFirmwareDefaults(meshgroup);
}
void GCodeExport::setInitialTemps(const MeshGroup& settings, const unsigned int start_extruder_nr)
void GCodeExport::setInitialTemps(const MeshGroup& settings)
{
int start_extruder_nr = 0;
if (settings.getSettingAsPlatformAdhesion("adhesion_type") != EPlatformAdhesion::NONE)
{
start_extruder_nr = settings.getSettingAsIndex("adhesion_extruder_nr");
}
for (unsigned int extr_nr = 0; extr_nr < extruder_count; extr_nr++)
{
const ExtruderTrain& train = *settings.getExtruderTrain(extr_nr);
double print_temp_0 = train.getSettingInDegreeCelsius("material_print_temperature_layer_0");
double print_temp_here = (print_temp_0 != 0)? print_temp_0 : train.getSettingInDegreeCelsius("material_print_temperature");
double temp = (extr_nr == start_extruder_nr)? print_temp_here : train.getSettingInDegreeCelsius("material_standby_temperature");
double temp = ((int)extr_nr == start_extruder_nr)? print_temp_here : train.getSettingInDegreeCelsius("material_standby_temperature");
setInitialTemp(extr_nr, temp);
}
@@ -195,11 +196,6 @@ std::string GCodeExport::getFileHeader(const double* print_time, const std::vect
prefix << ";NOZZLE_DIAMETER:" << float(INT2MM(getNozzleSize(0))) << new_line;
// TODO: the second nozzle size isn't always initiated! ";NOZZLE_DIAMETER2:"
}
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();
}
}
@@ -556,6 +552,8 @@ 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,7 +566,6 @@ 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)
{
@@ -642,7 +639,7 @@ void GCodeExport::writeMove(int x, int y, int z, double speed, double extrusion_
estimateCalculator.plan(TimeEstimateCalculator::Position(INT2MM(currentPosition.x), INT2MM(currentPosition.y), INT2MM(currentPosition.z), eToMm(current_e_value)), speed);
}
void GCodeExport::writeRetraction(const RetractionConfig& config, bool force, bool extruder_switch)
void GCodeExport::writeRetraction(RetractionConfig* config, bool force, bool extruder_switch)
{
ExtruderTrainAttributes& extr_attr = extruder_attr[current_extruder];
@@ -659,7 +656,7 @@ void GCodeExport::writeRetraction(const RetractionConfig& config, bool force, bo
}
double old_retraction_e_amount = extr_attr.retraction_e_amount_current;
double new_retraction_e_amount = mmToE(config.distance);
double new_retraction_e_amount = mmToE(config->distance);
double retraction_diff_e_amount = old_retraction_e_amount - new_retraction_e_amount;
if (std::abs(retraction_diff_e_amount) < 0.000001)
{
@@ -669,23 +666,23 @@ void GCodeExport::writeRetraction(const RetractionConfig& config, bool force, bo
{ // handle retraction limitation
double current_extruded_volume = getCurrentExtrudedVolume();
std::deque<double>& extruded_volume_at_previous_n_retractions = extr_attr.extruded_volume_at_previous_n_retractions;
while (int(extruded_volume_at_previous_n_retractions.size()) > config.retraction_count_max && !extruded_volume_at_previous_n_retractions.empty())
while (int(extruded_volume_at_previous_n_retractions.size()) > config->retraction_count_max && !extruded_volume_at_previous_n_retractions.empty())
{
// extruder switch could have introduced data which falls outside the retraction window
// also the retraction_count_max could have changed between the last retraction and this
extruded_volume_at_previous_n_retractions.pop_back();
}
if (!force && config.retraction_count_max <= 0)
if (!force && config->retraction_count_max <= 0)
{
return;
}
if (!force && int(extruded_volume_at_previous_n_retractions.size()) == config.retraction_count_max
&& current_extruded_volume < extruded_volume_at_previous_n_retractions.back() + config.retraction_extrusion_window * extr_attr.filament_area)
if (!force && int(extruded_volume_at_previous_n_retractions.size()) == config->retraction_count_max
&& current_extruded_volume < extruded_volume_at_previous_n_retractions.back() + config->retraction_extrusion_window * extr_attr.filament_area)
{
return;
}
extruded_volume_at_previous_n_retractions.push_front(current_extruded_volume);
if (int(extruded_volume_at_previous_n_retractions.size()) == config.retraction_count_max + 1)
if (int(extruded_volume_at_previous_n_retractions.size()) == config->retraction_count_max + 1)
{
extruded_volume_at_previous_n_retractions.pop_back();
}
@@ -708,17 +705,17 @@ void GCodeExport::writeRetraction(const RetractionConfig& config, bool force, bo
}
else
{
double speed = ((retraction_diff_e_amount < 0.0)? config.speed : extr_attr.last_retraction_prime_speed) * 60;
double speed = ((retraction_diff_e_amount < 0.0)? config->speed : extr_attr.last_retraction_prime_speed) * 60;
current_e_value += retraction_diff_e_amount;
*output_stream << "G1 F" << PrecisionedDouble{1, speed} << " "
<< extr_attr.extruderCharacter << PrecisionedDouble{5, current_e_value} << new_line;
currentSpeed = speed;
estimateCalculator.plan(TimeEstimateCalculator::Position(INT2MM(currentPosition.x), INT2MM(currentPosition.y), INT2MM(currentPosition.z), eToMm(current_e_value)), currentSpeed);
extr_attr.last_retraction_prime_speed = config.primeSpeed;
extr_attr.last_retraction_prime_speed = config->primeSpeed;
}
extr_attr.retraction_e_amount_current = new_retraction_e_amount; // suppose that for UM2 the retraction amount in the firmware is equal to the provided amount
extr_attr.prime_volume += config.prime_volume;
extr_attr.prime_volume += config->prime_volume;
}
@@ -728,7 +725,7 @@ void GCodeExport::writeZhopStart(int hop_height)
{
isZHopped = hop_height;
*output_stream << "G1 Z" << MMtoStream{currentPosition.z + isZHopped} << new_line;
total_bounding_box.includeZ(currentPosition.z + isZHopped);
total_bounding_box.include(currentPosition + Point3(0, 0, isZHopped));
}
}
@@ -775,7 +772,7 @@ void GCodeExport::switchExtruder(int new_extruder, const RetractionConfig& retra
bool force = true;
bool extruder_switch = true;
writeRetraction(const_cast<RetractionConfig&>(retraction_config_old_extruder), force, extruder_switch);
writeRetraction(&const_cast<RetractionConfig&>(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
@@ -907,7 +904,7 @@ void GCodeExport::writeMaxZFeedrate(double max_z_feedrate)
{
if (current_max_z_feedrate != max_z_feedrate)
{
*output_stream << "M203 Z" << PrecisionedDouble{2, max_z_feedrate} << new_line;
*output_stream << "M203 Z" << int(max_z_feedrate * 60) << new_line;
current_max_z_feedrate = max_z_feedrate;
estimateCalculator.setMaxZFeedrate(max_z_feedrate);
}
@@ -922,7 +919,7 @@ void GCodeExport::finalize(const char* endCode)
{
writeFanCommand(0);
writeCode(endCode);
int64_t print_time = getTotalPrintTime();
long print_time = getTotalPrintTime();
int mat_0 = getTotalFilamentUsed(0);
log("Print time: %d\n", print_time);
log("Print time (readable): %dh %dm %ds\n", print_time / 60 / 60, (print_time / 60) % 60, print_time % 60);
+2 -6
Ver Arquivo
@@ -261,7 +261,7 @@ private:
*/
void writeMoveBFB(int x, int y, int z, double speed, double extrusion_mm3_per_mm);
public:
void writeRetraction(const RetractionConfig& config, bool force = false, bool extruder_switch = false);
void writeRetraction(RetractionConfig* config, bool force = false, bool extruder_switch = false);
/*!
* Start a z hop with the given \p hop_height
@@ -349,17 +349,13 @@ public:
* See FffGcodeWriter::processStartingCode
*
* \param settings The meshgroup to get the global bed temp from and to get the extruder trains from which to get the nozzle temperatures
* \param start_extruder_nr The extruder with which to start this print
*/
void setInitialTemps(const MeshGroup& settings, const unsigned int start_extruder_nr);
void setInitialTemps(const MeshGroup& settings);
/*!
* Override or set an initial nozzle temperature as written by GCodeExport::setInitialTemps
* This is used primarily during better specification of temperatures in LayerPlanBuffer::insertPreheatCommand
*
* \warning This function must be called before any of the layers in the meshgroup are written to file!
* That's because it sets the current temperature in the gcode!
*
* \param extruder_nr The extruder number for which to better specify the temp
* \param temp The temp at which the nozzle should be at startup
*/
+44 -40
Ver Arquivo
@@ -9,6 +9,19 @@
namespace cura {
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;
}
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)
@@ -64,7 +77,6 @@ GCodePath* GCodePlanner::getLatestPathWithConfig(GCodePathConfig* config, SpaceF
paths.emplace_back();
GCodePath* ret = &paths.back();
ret->retract = false;
ret->perform_prime = false;
ret->perform_z_hop = false;
ret->config = config;
ret->done = false;
@@ -81,7 +93,7 @@ void GCodePlanner::forceNewPathStart()
paths[paths.size()-1].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)
GCodePlanner::GCodePlanner(SliceDataStorage& storage, int layer_nr, int z, int layer_thickness, Point last_position, int current_extruder, 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)
: storage(storage)
, layer_nr(layer_nr)
, is_initial_layer(layer_nr == 0 - Raft::getTotalExtraLayers(storage))
@@ -97,8 +109,8 @@ GCodePlanner::GCodePlanner(SliceDataStorage& storage, int layer_nr, int z, int l
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]);
comb = nullptr;
was_inside = is_inside_mesh;
is_inside = false; // assumes the next move will not be to inside a layer part (overwritten just before going into a layer part)
was_inside = storage.getPartInside(layer_nr, start_position);
is_inside = nullptr; // assumes the next move will not be to inside a layer part (overwritten just before going into a layer part)
if (combing_mode != CombingMode::OFF)
{
comb = new Comb(storage, layer_nr, comb_boundary_inside, comb_boundary_offset, travel_avoid_other_parts, travel_avoid_distance);
@@ -127,14 +139,7 @@ Polygons GCodePlanner::computeCombBoundaryInside(CombingMode combing_mode)
}
if (layer_nr < 0)
{ // when a raft is present
if (combing_mode == CombingMode::NO_SKIN)
{
return Polygons();
}
else
{
return storage.raftOutline.offset(MM2INT(0.1));
}
return Polygons();
}
else
{
@@ -162,7 +167,7 @@ Polygons GCodePlanner::computeCombBoundaryInside(CombingMode combing_mode)
}
}
void GCodePlanner::setIsInside(bool _is_inside)
void GCodePlanner::setIsInside(SliceLayerPart* _is_inside)
{
is_inside = _is_inside;
}
@@ -173,7 +178,7 @@ bool GCodePlanner::setExtruder(int extruder)
{
return false;
}
setIsInside(false);
setIsInside(nullptr);
{ // handle end position of the prev extruder
SettingsBaseVirtual* train = getLastPlannedExtruderTrainSettings();
bool end_pos_absolute = train->getSettingBoolean("machine_extruder_end_pos_abs");
@@ -220,11 +225,27 @@ bool GCodePlanner::setExtruder(int extruder)
return true;
}
void GCodePlanner::moveInsideCombBoundary(int distance)
void GCodePlanner::moveInsideCombBoundary(int distance, const SliceLayerPart& part)
{
int max_dist2 = MM2INT(2.0) * MM2INT(2.0); // if we are further than this distance, we conclude we are not inside even though we thought we were.
// this function is to be used to move from the boudary of a part to inside the part
int max_dist2 = MM2INT(2.0) * MM2INT(2.0); // if we are further than this distance, we conclude we are not inside even though we thought we were.
Point p = lastPosition; // copy, since we are going to move p
{ // first move inside the last part, so that the chance is higher that we move inside the same part
const Polygons* comb_boundary_here;
if (part.insets.size() > 1)
{
comb_boundary_here = &part.insets[1];
}
else if (part.insets.size() == 1)
{
comb_boundary_here = &part.insets[0];
}
else
{
comb_boundary_here = &part.print_outline;
}
PolygonUtils::moveInside(*comb_boundary_here, p, distance);
}
if (PolygonUtils::moveInside(comb_boundary_inside, p, distance, max_dist2) != NO_INDEX)
{
//Move inside again, so we move out of tight 90deg corners
@@ -316,7 +337,7 @@ GCodePath& GCodePlanner::addTravel(Point p)
if (was_inside) // when the previous location was from printing something which is considered inside (not support or prime tower etc)
{ // then move inside the printed part, so that we don't ooze on the outer wall while retraction, but on the inside of the print.
assert (extr != nullptr);
moveInsideCombBoundary(extr->getSettingInMicrons((extr->getSettingAsCount("wall_line_count") > 1) ? "wall_line_width_x" : "wall_line_width_0") * 1);
moveInsideCombBoundary(extr->getSettingInMicrons((extr->getSettingAsCount("wall_line_count") > 1) ? "wall_line_width_x" : "wall_line_width_0") * 1, *was_inside);
}
path = getLatestPathWithConfig(&travel_config, SpaceFillType::None);
path->retract = true;
@@ -340,14 +361,6 @@ GCodePath& GCodePlanner::addTravel_simple(Point p, GCodePath* path)
return *path;
}
void GCodePlanner::planPrime()
{
forceNewPathStart();
GCodePath& prime_travel = addTravel_simple(lastPosition + Point(0, 100));
prime_travel.retract = false;
prime_travel.perform_prime = true;
forceNewPathStart();
}
void GCodePlanner::addExtrusionMove(Point p, GCodePathConfig* config, SpaceFillType space_fill_type, float flow, bool spiralize)
{
@@ -403,13 +416,13 @@ 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(Polygons& polygons, GCodePathConfig* config, WallOverlapComputation* wall_overlap_computation, EZSeamType z_seam_type, coord_t wall_0_wipe_dist, bool spiralize)
{
if (polygons.size() == 0)
{
return;
}
PathOrderOptimizer orderOptimizer(lastPosition, z_seam_pos, z_seam_type);
PathOrderOptimizer orderOptimizer(lastPosition, z_seam_type);
for (unsigned int poly_idx = 0; poly_idx < polygons.size(); poly_idx++)
{
orderOptimizer.addPolygon(polygons[poly_idx]);
@@ -683,7 +696,7 @@ void GCodePlanner::writeGCode(GCodeExport& gcode)
// prime extruder if it hadn't been used yet
gcode.writePrimeTrain(storage.meshgroup->getExtruderTrain(extruder)->getSettingInMillimetersPerSecond("speed_travel"));
gcode.writeRetraction(retraction_config);
gcode.writeRetraction(&retraction_config);
if (extruder_plan.prev_extruder_standby_temp)
{ // turn off previous extruder
@@ -699,7 +712,7 @@ void GCodePlanner::writeGCode(GCodeExport& gcode)
}
else if (extruder_plan_idx == 0 && layer_nr != 0 && storage.meshgroup->getExtruderTrain(extruder)->getSettingBoolean("retract_at_layer_change"))
{
gcode.writeRetraction(retraction_config);
gcode.writeRetraction(&retraction_config);
}
gcode.writeFanCommand(extruder_plan.getFanSpeed());
std::vector<GCodePath>& paths = extruder_plan.paths;
@@ -723,12 +736,6 @@ void GCodePlanner::writeGCode(GCodeExport& gcode)
GCodePath& path = paths[path_idx];
if (path.perform_prime)
{
gcode.writePrimeTrain(train->getSettingInMillimetersPerSecond("speed_travel"));
gcode.writeRetraction(retraction_config);
}
if (acceleration_enabled)
{
gcode.writeAcceleration(path.config->getAcceleration());
@@ -740,7 +747,7 @@ void GCodePlanner::writeGCode(GCodeExport& gcode)
if (path.retract)
{
gcode.writeRetraction(retraction_config);
gcode.writeRetraction(&retraction_config);
if (path.perform_z_hop)
{
gcode.writeZhopStart(retraction_config.zHop);
@@ -859,7 +866,7 @@ void GCodePlanner::writeGCode(GCodeExport& gcode)
{
gcode.writeComment("Small layer, adding delay");
RetractionConfig& retraction_config = storage.retraction_config_per_extruder[gcode.getExtruderNr()];
gcode.writeRetraction(retraction_config);
gcode.writeRetraction(&retraction_config);
if (extruder_plan_idx == extruder_plans.size() - 1 || !train->getSettingBoolean("machine_extruder_end_pos_abs"))
{ // only move the head if it's the last extruder plan; otherwise it's already at the switching bay area
// or do it anyway when we switch extruder in-place
@@ -897,7 +904,6 @@ 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,7 +962,6 @@ 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++)
{
@@ -978,7 +983,6 @@ 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();
+255 -24
Ver Arquivo
@@ -6,9 +6,6 @@
#include "gcodeExport.h"
#include "pathPlanning/Comb.h"
#include "pathPlanning/GCodePath.h"
#include "pathPlanning/NozzleTempInsert.h"
#include "pathPlanning/TimeMaterialEstimates.h"
#include "utils/polygon.h"
#include "utils/logoutput.h"
#include "wallOverlap.h"
@@ -23,6 +20,252 @@ namespace cura
{
class SliceDataStorage;
class SliceLayerPart;
/*!
* A gcode command to insert before a specific path.
*
* Currently only used for preheat commands
*/
struct NozzleTempInsert
{
const unsigned int path_idx; //!< The path before which to insert this command
double time_after_path_start; //!< The time after the start of the path, before which to insert the command // TODO: use this to insert command in between moves in a path!
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!");
}
/*!
* 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);
}
};
class ExtruderPlan; // forward declaration so that TimeMaterialEstimates can be a friend
/*!
* Time and material estimates for a portion of paths, e.g. layer, extruder plan, path.
*/
class TimeMaterialEstimates
{
friend class ExtruderPlan; // cause there the naive estimates are calculated
private:
double extrude_time; //!< Time in seconds occupied by extrusion
double unretracted_travel_time; //!< Time in seconds occupied by non-retracted travel (non-extrusion)
double retracted_travel_time; //!< Time in seconds occupied by retracted travel (non-extrusion)
double material; //!< Material used (in mm^3)
public:
/*!
* Basic contructor
*
* \param extrude_time Time in seconds occupied by extrusion
* \param unretracted_travel_time Time in seconds occupied by non-retracted travel (non-extrusion)
* \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)
{
}
/*!
* 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)
{
}
/*!
* Set all estimates to zero.
*/
void reset()
{
extrude_time = 0.0;
unretracted_travel_time = 0.0;
retracted_travel_time = 0.0;
material = 0.0;
}
/*!
* Pointwise addition of estimate stats
*
* \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);
}
/*!
* In place pointwise addition of estimate stats
*
* \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;
}
/*!
* \brief Subtracts the specified estimates from these estimates and returns
* the result.
*
* Each of the estimates in this class are individually subtracted.
*
* \param other The estimates to subtract from these estimates.
* \return These estimates with the specified estimates subtracted.
*/
TimeMaterialEstimates operator-(const TimeMaterialEstimates& other);
/*!
* \brief Subtracts the specified elements from these estimates.
*
* This causes the estimates in this instance to change. Each of the
* estimates in this class are individually subtracted.
*
* \param other The estimates to subtract from these estimates.
* \return A reference to this instance.
*/
TimeMaterialEstimates& operator-=(const TimeMaterialEstimates& other);
/*!
* Get total time estimate. The different time estimate member values added together.
*
* \return the total of all different time estimate values
*/
double getTotalTime() const
{
return extrude_time + unretracted_travel_time + retracted_travel_time;
}
/*!
* Get the total time during which the head is not retracted.
*
* This includes extrusion time and non-retracted travel time
*
* \return the total time during which the head is not retracted.
*/
double getTotalUnretractedTime() const
{
return extrude_time + unretracted_travel_time;
}
/*!
* Get the total travel time.
*
* This includes the retracted travel time as well as the unretracted travel time.
*
* \return the total travel time.
*/
double getTravelTime() const
{
return retracted_travel_time + unretracted_travel_time;
}
/*!
* Get the extrusion time.
*
* \return extrusion time.
*/
double getExtrudeTime() const
{
return extrude_time;
}
/*!
* Get the amount of material used in mm^3.
*
* \return amount of material
*/
double getMaterial() const
{
return material;
}
};
/*!
* A class for representing a planned path.
*
* A path consists of several segments of the same type of movement: retracted travel, infill extrusion, etc.
*
* This is a compact premature representation in which are line segments have the same config, i.e. the config of this path.
*
* In the final representation (gcode) each line segment may have different properties,
* which are added when the generated GCodePaths are processed.
*/
class GCodePath
{
public:
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.
bool perform_z_hop; //!< Whether to perform a z_hop in this path, which is assumed to be a travel path.
std::vector<Point> points; //!< The points constituting this path.
bool done;//!< Path is finished, no more moves should be added, and a new path should be started instead of any appending done to this one.
bool spiralize; //!< Whether to gradually increment the z position during the printing of this path. A sequence of spiralized paths should start at the given layer height and end in one layer higher.
TimeMaterialEstimates estimates; //!< Naive time and material estimates
/*!
* Whether this config is the config of a travel path.
*
* \return Whether this config is the config of a travel path.
*/
bool isTravelPath()
{
return config->isTravelPath();
}
/*!
* Get the material flow in mm^3 per mm traversed.
*
* \warning Can only be called after the layer height has been set (which is done while writing the gcode!)
*
* \return The flow
*/
double getExtrusionMM3perMM()
{
return flow * config->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;
}
};
class GCodePlanner; // forward declaration so that ExtruderPlan can be a friend
class LayerPlanBuffer; // forward declaration so that ExtruderPlan can be a friend
@@ -232,8 +475,8 @@ private:
int last_extruder_previous_layer; //!< The last id of the extruder with which was printed in the previous layer
SettingsBaseVirtual* last_planned_extruder_setting_base; //!< The setting base of the last planned extruder.
bool was_inside; //!< Whether the last planned (extrusion) move was inside a layer part
bool is_inside; //!< Whether the destination of the next planned travel move is inside a layer part
SliceLayerPart* was_inside; //!< The layer part the last planned (extrusion) move was inside (if any)
SliceLayerPart* is_inside; //!< The layer part the destination of the next planned travel move is inside (if any)
Polygons comb_boundary_inside; //!< The boundary within which to comb, or to move into when performing a retraction.
Comb* comb;
@@ -274,7 +517,7 @@ public:
* \param last_position The position of the head at the start of this gcode layer
* \param combing_mode Whether combing is enabled and full or within infill only.
*/
GCodePlanner(SliceDataStorage& storage, int layer_nr, int z, int layer_height, 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);
GCodePlanner(SliceDataStorage& storage, int layer_nr, int z, int layer_height, Point last_position, int current_extruder, 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);
~GCodePlanner();
void overrideFanSpeeds(double speed);
@@ -322,15 +565,10 @@ public:
*
* Features like infill, walls, skin etc. are considered inside.
* Features like prime tower and support are considered outside.
* \param inside_part The part in which the newly planned position is inside, or nullptr if not inside anything
*/
void setIsInside(bool going_to_comb);
/*!
* Plan a switch to a new extruder
*
* \param extruder The extruder number to which to switch
* \return whether the extruder has changed
*/
void setIsInside(SliceLayerPart* inside_part);
bool setExtruder(int extruder);
/*!
@@ -361,13 +599,6 @@ public:
*/
GCodePath& addTravel_simple(Point p, GCodePath* path = nullptr);
/*!
* Plan a prime poop at the current location.
*
* \warning A nonretracted move is introduced so that the LayerPlanBuffer classifies this move as an extrusion move.
*/
void planPrime();
/*!
* Add an extrusion move to a certain point, optionally with a different flow than the one in the \p config.
*
@@ -403,11 +634,10 @@ public:
* \param config The config with which to print the polygon lines
* \param wall_overlap_computation The wall overlap compensation calculator for each given segment (optionally nullptr)
* \param z_seam_type The seam type / poly start optimizer
* \param z_seam_pos The location near where to start each part in case \p z_seam_type is 'back'
* \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(Polygons& polygons, GCodePathConfig* config, WallOverlapComputation* wall_overlap_computation = nullptr, EZSeamType z_seam_type = EZSeamType::SHORTEST, coord_t wall_0_wipe_dist = 0, bool spiralize = false);
/*!
* Add lines to the gcode with optimized order.
@@ -485,8 +715,9 @@ public:
* This is supposed to be called when the nozzle is around the boundary of a layer part, not when the nozzle is in the middle of support, or in the middle of the air.
*
* \param distance The distance to the comb boundary after we moved inside it.
* \param part_outline The part in which we last resided
*/
void moveInsideCombBoundary(int distance);
void moveInsideCombBoundary(int distance, const SliceLayerPart& part);
};
}//namespace cura
+11 -30
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)
{
if (in_outline.size() == 0) return;
if (line_distance == 0) return;
@@ -48,14 +48,6 @@ void Infill::generate(Polygons& result_polygons, Polygons& result_lines, SliceMe
case EFillMethod::ZIG_ZAG:
generateZigZagInfill(result_lines, line_distance, fill_angle, connected_zigzags, use_endpieces);
break;
case EFillMethod::CUBICSUBDIV:
if (!mesh)
{
logError("Cannot generate Cubic Subdivision infill without a mesh!\n");
break;
}
generateCubicSubDivInfill(result_lines, *mesh);
break;
default:
logError("Fill pattern has unknown value.\n");
break;
@@ -66,6 +58,7 @@ void Infill::generateConcentricInfill(Polygons& result, int inset_value)
{
Polygons first_concentric_wall = in_outline.offset(outline_offset - line_distance + infill_line_width / 2); // - infill_line_width / 2 cause generateConcentricInfill expects [outline] to be the outer most polygon instead of the outer outline
result.add(first_concentric_wall);
if (perimeter_gaps)
{
const Polygons inner = first_concentric_wall.offset(infill_line_width / 2 + perimeter_gaps_extra_offset);
@@ -77,7 +70,6 @@ void Infill::generateConcentricInfill(Polygons& result, int inset_value)
void Infill::generateConcentricInfill(Polygons& first_concentric_wall, Polygons& result, int inset_value)
{
result.add(first_concentric_wall);
Polygons* prev_inset = &first_concentric_wall;
Polygons next_inset;
while (prev_inset->size() > 0)
@@ -87,7 +79,7 @@ void Infill::generateConcentricInfill(Polygons& first_concentric_wall, Polygons&
if (perimeter_gaps)
{
const Polygons outer = prev_inset->offset(-infill_line_width / 2 - perimeter_gaps_extra_offset);
const Polygons inner = next_inset.offset(infill_line_width / 2);
const Polygons inner = next_inset.offset(infill_line_width / 2 + perimeter_gaps_extra_offset);
const Polygons gaps_here = outer.difference(inner);
perimeter_gaps->add(gaps_here);
}
@@ -144,26 +136,15 @@ void Infill::generateTriangleInfill(Polygons& result)
generateLineInfill(result, line_distance, fill_angle + 120, 0);
}
void Infill::generateCubicSubDivInfill(Polygons& result, SliceMeshStorage& mesh)
{
Polygons uncropped;
mesh.base_subdiv_cube->generateSubdivisionLines(z, uncropped);
addLineSegmentsInfill(result, uncropped);
}
void Infill::addLineSegmentsInfill(Polygons& result, Polygons& input)
{
ClipperLib::PolyTree interior_segments_tree = in_outline.lineSegmentIntersection(input);
ClipperLib::Paths interior_segments;
ClipperLib::OpenPathsFromPolyTree(interior_segments_tree, interior_segments);
for (uint64_t idx = 0; idx < interior_segments.size(); idx++)
{
result.addLine(interior_segments[idx][0], interior_segments[idx][1]);
}
}
void Infill::addLineInfill(Polygons& result, const PointMatrix& rotation_matrix, const int scanline_min_idx, const int line_distance, const AABB boundary, std::vector<std::vector<int64_t>>& cut_list, int64_t shift)
{
auto addLine = [&](Point from, Point to)
{
PolygonRef p = result.newPoly();
p.add(rotation_matrix.unapply(from));
p.add(rotation_matrix.unapply(to));
};
auto compare_int64_t = [](const void* a, const void* b)
{
int64_t n = (*(int64_t*)a) - (*(int64_t*)b);
@@ -189,7 +170,7 @@ void Infill::addLineInfill(Polygons& result, const PointMatrix& rotation_matrix,
{ // segment is too short to create infill
continue;
}
result.addLine(rotation_matrix.unapply(Point(x, crossings[crossing_idx])), rotation_matrix.unapply(Point(x, crossings[crossing_idx + 1])));
addLine(Point(x, crossings[crossing_idx]), Point(x, crossings[crossing_idx + 1]));
}
scanline_idx += 1;
}
+1 -17
Ver Arquivo
@@ -12,7 +12,6 @@
#include "infill/ZigzagConnectorProcessorEndPieces.h"
#include "infill/ZigzagConnectorProcessorConnectedEndPieces.h"
#include "infill/ZigzagConnectorProcessorDisconnectedEndPieces.h"
#include "infill/SubDivCube.h"
#include "utils/intpoint.h"
#include "utils/AABB.h"
@@ -78,9 +77,8 @@ public:
*
* \param result_polygons (output) The resulting polygons (from concentric infill)
* \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);
private:
/*!
@@ -142,13 +140,6 @@ private:
* \param result (output) The resulting lines
*/
void generateTriangleInfill(Polygons& result);
/*!
* Generate a 3d pattern of subdivided cubes on their points
* \param[out] result The resulting lines
* \param[in] mesh Where the Cubic Subdivision Infill precomputation is stored
*/
void generateCubicSubDivInfill(Polygons& result, SliceMeshStorage& mesh);
/*!
* Convert a mapping from scanline to line_segment-scanline-intersections (\p cut_list) into line segments, using the even-odd rule
@@ -162,13 +153,6 @@ private:
*/
void addLineInfill(Polygons& result, const PointMatrix& rotation_matrix, const int scanline_min_idx, const int line_distance, const AABB boundary, std::vector<std::vector<int64_t>>& cut_list, int64_t total_shift);
/*!
* Crop line segments by the infill polygon using Clipper
* \param result (output) The resulting lines
* \param input The line segments to be cropped
*/
void addLineSegmentsInfill(Polygons& result, Polygons& input);
/*!
* generate lines within the area of \p in_outline, at regular intervals of \p line_distance
*
-282
Ver Arquivo
@@ -1,282 +0,0 @@
#include "SubDivCube.h"
#include <functional>
#include "../utils/polygonUtils.h"
#include "../sliceDataStorage.h"
#include "../utils/math.h"
#define ONE_OVER_SQRT_2 0.7071067811865475244008443621048490392848359376884740 //1 / sqrt(2)
#define ONE_OVER_SQRT_3 0.577350269189625764509148780501957455647601751270126876018 //1 / sqrt(3)
#define ONE_OVER_SQRT_6 0.408248290463863016366214012450981898660991246776111688072 //1 / sqrt(6)
#define SQRT_TWO_THIRD 0.816496580927726032732428024901963797321982493552223376144 //sqrt(2 / 3)
namespace cura
{
std::vector<SubDivCube::CubeProperties> SubDivCube::cube_properties_per_recursion_step;
double SubDivCube::radius_multiplier = 1;
int32_t SubDivCube::radius_addition = 0;
Point3Matrix SubDivCube::rotation_matrix;
PointMatrix SubDivCube::infill_rotation_matrix;
SubDivCube::~SubDivCube()
{
for (int child_idx = 0; child_idx < 8; child_idx++)
{
if (children[child_idx])
{
delete children[child_idx];
}
}
}
void SubDivCube::precomputeOctree(SliceMeshStorage& mesh)
{
radius_multiplier = mesh.getSettingAsRatio("sub_div_rad_mult");
radius_addition = mesh.getSettingInMicrons("sub_div_rad_add");
double infill_angle = M_PI / 4.0;
coord_t furthest_dist_from_origin = std::sqrt(square(mesh.getSettingInMicrons("machine_height")) + square(mesh.getSettingInMicrons("machine_depth") / 2) + square(mesh.getSettingInMicrons("machine_width") / 2));
coord_t max_side_length = furthest_dist_from_origin * 2;
int curr_recursion_depth = 0;
const int64_t infill_line_distance = mesh.getSettingInMicrons("infill_line_distance");
if (infill_line_distance > 0)
{
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);
Point3Matrix tilt; // rotation matrix to get from axis aligned cubes to cubes standing on their tip
// The Z axis is transformed to go in positive Y direction
//
// cross section in a horizontal plane horizontal plane showing
// looking down at the origin O positive X and positive Y
// Z .
// /:\ Y .
// / : \ ^ .
// / : \ | .
// / .O. \ | .
// /.~' '~.\ O---->X .
// X """"""""""" Y .
tilt.matrix[0] = -ONE_OVER_SQRT_2; tilt.matrix[1] = ONE_OVER_SQRT_2; tilt.matrix[2] = 0;
tilt.matrix[3] = -ONE_OVER_SQRT_6; tilt.matrix[4] = -ONE_OVER_SQRT_6; tilt.matrix[5] = SQRT_TWO_THIRD ;
tilt.matrix[6] = ONE_OVER_SQRT_3; tilt.matrix[7] = ONE_OVER_SQRT_3; tilt.matrix[8] = ONE_OVER_SQRT_3;
infill_rotation_matrix = PointMatrix(infill_angle);
Point3Matrix infill_angle_mat(infill_rotation_matrix);
rotation_matrix = infill_angle_mat.compose(tilt);
mesh.base_subdiv_cube = new SubDivCube(mesh, center, curr_recursion_depth - 1);
}
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);
for (int dir_idx = 0; dir_idx < 3; dir_idx++)
{
Polygons& line_group = directional_line_groups[dir_idx];
for (unsigned int line_idx = 0; line_idx < line_group.size(); line_idx++)
{
result.addLine(line_group[line_idx][0], line_group[line_idx][1]);
}
}
}
void SubDivCube::generateSubdivisionLines(int64_t z, Polygons& result, Polygons (&directional_line_groups)[3])
{
CubeProperties cube_properties = cube_properties_per_recursion_step[depth];
int32_t z_diff = std::abs(z - center.z); //!< the difference between the cube center and the target layer.
if (z_diff > cube_properties.height / 2) //!< this cube does not touch the target layer. Early exit.
{
return;
}
if (z_diff < cube_properties.max_draw_z_diff) //!< this cube has lines that need to be drawn.
{
Point relative_a, relative_b; //!< relative coordinates of line endpoints around cube center
Point a, b; //!< absolute coordinates of line endpoints
relative_a.X = (cube_properties.square_height / 2) * (cube_properties.max_draw_z_diff - z_diff) / cube_properties.max_draw_z_diff;
relative_b.X = -relative_a.X;
relative_a.Y = cube_properties.max_line_offset - ((z - (center.z - cube_properties.max_draw_z_diff)) * ONE_OVER_SQRT_2);
relative_b.Y = relative_a.Y;
rotatePointInitial(relative_a);
rotatePointInitial(relative_b);
for (int dir_idx = 0; dir_idx < 3; dir_idx++)//!< draw the line, then rotate 120 degrees.
{
a.X = center.x + relative_a.X;
a.Y = center.y + relative_a.Y;
b.X = center.x + relative_b.X;
b.Y = center.y + relative_b.Y;
addLineAndCombine(directional_line_groups[dir_idx], a, b);
if (dir_idx < 2)
{
rotatePoint120(relative_a);
rotatePoint120(relative_b);
}
}
}
for (int idx = 0; idx < 8; idx++) //!< draws the eight children
{
if (children[idx] != nullptr)
{
children[idx]->generateSubdivisionLines(z, result, directional_line_groups);
}
}
}
SubDivCube::SubDivCube(SliceMeshStorage& mesh, Point3& center, unsigned int depth)
{
this->depth = depth;
this->center = center;
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;
int child_nr = 0;
std::vector<Point3> rel_child_centers;
rel_child_centers.emplace_back(1, 1, 1); // top
rel_child_centers.emplace_back(-1, 1, 1); // top three
rel_child_centers.emplace_back(1, -1, 1);
rel_child_centers.emplace_back(1, 1, -1);
rel_child_centers.emplace_back(-1, -1, -1); // bottom
rel_child_centers.emplace_back(1, -1, -1); // bottom three
rel_child_centers.emplace_back(-1, 1, -1);
rel_child_centers.emplace_back(-1, -1, 1);
for (Point3 rel_child_center : rel_child_centers)
{
child_center = center + rotation_matrix.apply(rel_child_center * int32_t(cube_properties.side_length / 4));
if (isValidSubdivision(mesh, child_center, radius))
{
children[child_nr] = new SubDivCube(mesh, child_center, depth - 1);
child_nr++;
}
}
}
bool SubDivCube::isValidSubdivision(SliceMeshStorage& mesh, Point3& center, int64_t radius)
{
int64_t distance2;
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 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));
Point loc(center.x, center.y);
inside = distanceFromPointToMesh(mesh, test_layer, loc, &distance2);
if (inside == 1)
{
inside_somewhere = true;
}
else
{
outside_somewhere = true;
}
if (outside_somewhere && inside_somewhere)
{
return true;
}
if ((inside != 2) && distance2 < sphere_slice_radius2)
{
return true;
}
}
return false;
}
int SubDivCube::distanceFromPointToMesh(SliceMeshStorage& mesh, int layer_nr, Point& location, int64_t* distance2)
{
if (layer_nr < 0 || (unsigned int)layer_nr >= mesh.layers.size()) //!< this layer is outside of valid range
{
return 2;
}
Polygons collide;
mesh.layers[layer_nr].getSecondOrInnermostWalls(collide);
Point centerpoint = location;
bool inside = collide.inside(centerpoint);
ClosestPolygonPoint border_point = PolygonUtils::moveInside2(collide, centerpoint);
Point diff = border_point.location - location;
*distance2 = vSize2(diff);
if (inside)
{
return 1;
}
return 0;
}
void SubDivCube::rotatePointInitial(Point& target)
{
target = infill_rotation_matrix.apply(target);
}
void SubDivCube::rotatePoint120(Point& target)
{
constexpr double sqrt_three_fourths = 0.8660254037844386467637231707529361834714026269051903; //!< sqrt(3.0 / 4.0) = sqrt(3) / 2
int64_t x;
x = (-0.5) * target.X - sqrt_three_fourths * target.Y;
target.Y = (-0.5)*target.Y + sqrt_three_fourths * target.X;
target.X = x;
}
void SubDivCube::addLineAndCombine(Polygons& group, Point from, Point to)
{
int epsilon = 10; // the smallest distance of two points which are viewed as coincident (dist > 0 due to rounding errors)
for (unsigned int idx = 0; idx < group.size(); idx++)
{
if (std::abs(from.X - group[idx][1].X) < epsilon && std::abs(from.Y - group[idx][1].Y) < epsilon)
{
from = group[idx][0];
group.remove(idx);
idx--;
continue;
}
if (std::abs(to.X - group[idx][0].X) < epsilon && std::abs(to.Y - group[idx][0].Y) < epsilon)
{
to = group[idx][1];
group.remove(idx);
idx--;
continue;
}
}
group.addLine(from, to);
}
}//namespace cura
-98
Ver Arquivo
@@ -1,98 +0,0 @@
#ifndef INFILL_SUBDIVCUBE_H
#define INFILL_SUBDIVCUBE_H
#include "../sliceDataStorage.h"
namespace cura
{
class Infill;
class SubDivCube
{
public:
/*!
* Constructor for SubDivCube. Recursively calls itself eight times to flesh out the octree.
* \param mesh contains infill layer data and settings
* \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, unsigned int depth);
~SubDivCube(); //!< destructor (also destroys children
/*!
* Precompute the octree of subdivided cubes
* \param mesh contains infill layer data and settings
*/
static void precomputeOctree(SliceMeshStorage& mesh);
/*!
* Generates the lines of subdivision of the specific cube at the specific layer. It recursively calls itself, so it ends up drawing all the subdivision lines of sub-cubes too.
* \param z the specified layer height
* \param result (output) The resulting lines
*/
void generateSubdivisionLines(int64_t z, Polygons& result);
private:
/*!
* Generates the lines of subdivision of the specific cube at the specific layer. It recursively calls itself, so it ends up drawing all the subdivision lines of sub-cubes too.
* \param z the specified layer height
* \param result (output) The resulting lines
* \param directional_line_groups Array of 3 times a polylines. Used to keep track of line segments that are all pointing the same direction for line segment combining
*/
void generateSubdivisionLines(int64_t z, Polygons& result, Polygons (&directional_line_groups)[3]);
struct CubeProperties
{
int64_t side_length; //!< side length of cubes
int64_t height; //!< height of cubes based. This is the distance from one point of a cube to its 3d opposite.
int64_t square_height; //!< square cut across lengths. This is the diagonal distance across a face of the cube.
int64_t max_draw_z_diff; //!< maximum draw z differences. This is the maximum difference in z at which lines need to be drawn.
int64_t max_line_offset; //!< maximum line offsets. This is the maximum distance at which subdivision lines should be drawn from the 2d cube center.
};
/*!
* Rotates a point 120 degrees about the origin.
* \param target the point to rotate.
*/
static void rotatePoint120(Point& target);
/*!
* Rotates a point to align it with the orientation of the infill.
* \param target the point to rotate.
*/
static void rotatePointInitial(Point& target);
/*!
* Determines if a described theoretical cube should be subdivided based on if a sphere that encloses the cube touches the infill mesh.
* \param mesh contains infill layer data and settings
* \param center the center of the described cube
* \param radius the radius of the enclosing sphere
* \return the described cube should be subdivided
*/
static bool isValidSubdivision(SliceMeshStorage& mesh, Point3& center, int64_t radius);
/*!
* Finds the distance to the infill border at the specified layer from the specified point.
* \param mesh contains infill layer data and settings
* \param layer_nr the number of the specified layer
* \param location the location of the specified point
* \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, 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.
* \param[out] group the polygons to add the line to
* \param from the first endpoint of the line
* \param to the second endpoint of the line
*/
void addLineAndCombine(Polygons& group, Point from, Point to);
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.
static double radius_multiplier; //!< multiplier for the bounding radius when determining if a cube should be subdivided
static Point3Matrix rotation_matrix; //!< The rotation matrix to get from axis aligned cubes to cubes standing on a corner point aligned with the infill_angle
static PointMatrix infill_rotation_matrix; //!< Horizontal rotation applied to infill
static int32_t radius_addition; //!< addition to the bounding radius when determining if a cube should be subdivided
};
}
#endif //INFILL_SUBDIVCUBE_H
+3 -1
Ver Arquivo
@@ -109,7 +109,9 @@ protected:
*/
void addLine(Point from, Point to)
{
result.addLine(rotation_matrix.unapply(from), rotation_matrix.unapply(to));
PolygonRef line_poly = result.newPoly();
line_poly.add(rotation_matrix.unapply(from));
line_poly.add(rotation_matrix.unapply(to));
}
/*!
+1 -4
Ver Arquivo
@@ -44,10 +44,7 @@ void createLayerWithParts(SliceLayer& storageLayer, SlicerLayer* layer, bool uni
}
void createLayerParts(SliceMeshStorage& mesh, Slicer* slicer, bool union_layers, bool union_all_remove_holes)
{
const auto total_layers = slicer->layers.size();
assert(mesh.layers.size() == total_layers);
#pragma omp parallel for default(none) shared(mesh,slicer) firstprivate(union_layers,union_all_remove_holes) schedule(dynamic)
for(unsigned int layer_nr = 0; layer_nr < total_layers; layer_nr++)
for(unsigned int layer_nr = 0; layer_nr < slicer->layers.size(); layer_nr++)
{
mesh.layers[layer_nr].sliceZ = slicer->layers[layer_nr].z;
mesh.layers[layer_nr].printZ = slicer->layers[layer_nr].z;
+2 -18
Ver Arquivo
@@ -20,10 +20,6 @@
#include "settings/SettingsToGV.h"
#ifdef _OPENMP
#include <omp.h> // omp_get_num_threads
#endif
namespace cura
{
@@ -332,19 +328,7 @@ int main(int argc, char **argv)
print_usage();
exit(1);
}
#pragma omp parallel
{
#pragma omp master
{
#ifdef _OPENMP
log("OpenMP multithreading enabled, likely number of threads to be used: %u\n", omp_get_num_threads());
#else
log("OpenMP multithreading disabled\n");
#endif
}
}
if (stringcasecompare(argv[1], "connect") == 0)
{
connect(argc, argv);
@@ -439,4 +423,4 @@ int main(int argc, char **argv)
}
return 0;
}
}
+19 -1
Ver Arquivo
@@ -92,7 +92,7 @@ int PathOrderOptimizer::getPolyStart(Point prev_point, int poly_idx)
{
switch (type)
{
case EZSeamType::BACK: return getClosestPointInPolygon(z_seam_pos, poly_idx);
case EZSeamType::BACK: return getFarthestPointInPolygon(poly_idx);
case EZSeamType::RANDOM: return getRandomPointInPolygon(poly_idx);
case EZSeamType::SHORTEST: return getClosestPointInPolygon(prev_point, poly_idx);
default: return getClosestPointInPolygon(prev_point, poly_idx);
@@ -129,6 +129,24 @@ int PathOrderOptimizer::getRandomPointInPolygon(int poly_idx)
return rand() % polygons[poly_idx].size();
}
int PathOrderOptimizer::getFarthestPointInPolygon(int poly_idx)
{
PolygonRef poly = polygons[poly_idx];
int best_point_idx = -1;
float best_y = std::numeric_limits<float>::min();
for(unsigned int point_idx=0 ; point_idx<poly.size() ; point_idx++)
{
if (poly[point_idx].Y > best_y)
{
best_point_idx = point_idx;
best_y = poly[point_idx].Y;
}
}
return best_point_idx;
}
/**
*
*/
+2 -10
Ver Arquivo
@@ -19,15 +19,13 @@ class PathOrderOptimizer
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<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
PathOrderOptimizer(Point startPoint, Point z_seam_pos = Point(0, 0), EZSeamType type = EZSeamType::SHORTEST)
PathOrderOptimizer(Point startPoint, EZSeamType type = EZSeamType::SHORTEST)
: type(type)
, startPoint(startPoint)
, z_seam_pos(z_seam_pos)
{
}
@@ -45,15 +43,9 @@ public:
void optimize(); //!< sets #polyStart and #polyOrder
private:
/*!
* Get the starting vertex of a polygon, depending on the \ref PathOrderOptimizer::type
* \param prev_point The previous planned location
* \param poly_idx The index of the polygon in \ref PathOrderOptimizer::polygons
* \return the index of the starting vertex in \ref PathOrderOptimizer::polygons[\p poly_idx]
*/
int getPolyStart(Point prev_point, int poly_idx);
int getClosestPointInPolygon(Point prev, int i_polygon); //!< returns the index of the closest point
int getFarthestPointInPolygon(int poly_idx); //!< return the index to the point farthest from the front (highest y)
int getRandomPointInPolygon(int poly_idx);
+34 -5
Ver Arquivo
@@ -12,6 +12,19 @@
namespace cura {
Polygons Comb::getCombOutlines()
{
if (layer_nr >= 0)
{
bool include_helper_parts = false;
return storage.getLayerOutlines(layer_nr, include_helper_parts);
}
else
{
return storage.raftOutline;
}
}
LocToLineGrid& Comb::getOutsideLocToLine()
{
return *outside_loc_to_line;
@@ -26,13 +39,14 @@ Comb::Comb(SliceDataStorage& storage, int layer_nr, Polygons& comb_boundary_insi
: storage(storage)
, layer_nr(layer_nr)
, offset_from_outlines(comb_boundary_offset) // between second wall and infill / other walls
, max_moveInside_distance2(offset_from_outlines * 2 * offset_from_outlines * 2)
, max_move_inside_distance2(offset_from_outlines * 2 * offset_from_outlines * 2)
, offset_from_outlines_outside(travel_avoid_distance)
, offset_from_inside_to_outside(offset_from_outlines + offset_from_outlines_outside)
, max_crossing_dist2(offset_from_inside_to_outside * offset_from_inside_to_outside * 2) // so max_crossing_dist = offset_from_inside_to_outside * sqrt(2) =approx 1.5 to allow for slightly diagonal crossings and slightly inaccurate crossing computation
, avoid_other_parts(travel_avoid_other_parts)
, boundary_inside( comb_boundary_inside )
, partsView_inside( boundary_inside.splitIntoPartsView() ) // WARNING !! changes the order of boundary_inside !!
, outlines(getCombOutlines())
, inside_loc_to_line(PolygonUtils::createLocToLineGrid(boundary_inside, comb_boundary_offset))
, boundary_outside(
[&storage, layer_nr, travel_avoid_distance]()
@@ -221,15 +235,30 @@ bool Comb::moveInside(bool is_inside, Point& dest_point, unsigned int& inside_po
{
if (is_inside)
{
ClosestPolygonPoint cpp = PolygonUtils::ensureInsideOrOutside(boundary_inside, dest_point, offset_extra_start_end, max_moveInside_distance2, &boundary_inside, inside_loc_to_line);
coord_t max_move_inside_distance2_here = std::numeric_limits<coord_t>::max(); // the distance which would make the moveInside fail
if (storage.getSettingAsCombingMode("retraction_combing") == cura::CombingMode::NO_SKIN)
{ // if we perform no_skin combing, then a far move inside is likely a consequence of there meing skin in between the destination point and the inside comb boundary
// if we perform normal combing, then a far move inside is likely to be a consequence of sharp pointy segments in the layer part
max_move_inside_distance2_here = max_move_inside_distance2;
}
Point original_dest_point = dest_point;
ClosestPolygonPoint cpp = PolygonUtils::ensureInsideOrOutside(boundary_inside, dest_point, offset_extra_start_end, max_move_inside_distance2_here, &boundary_inside, inside_loc_to_line);
if (!cpp.isValid())
{
return false;
}
else
{
inside_poly = cpp.poly_idx;
return true;
if (vSize2(dest_point - original_dest_point) > max_move_inside_distance2 // only check for collision with outlines for long moves
&& PolygonUtils::polygonCollidesWithLineSegment(outlines, dest_point, original_dest_point))
{
return false;
}
else
{
inside_poly = cpp.poly_idx;
return true;
}
}
}
return false;
@@ -245,7 +274,7 @@ void Comb::Crossing::findCrossingInOrMid(const PartsView& partsView_inside, cons
dest_part = partsView_inside.assemblePart(dest_part_idx);
ClosestPolygonPoint boundary_crossing_point;
{ // set [result] to a point on the destination part closest to close_to (but also a bit close to _dest_point)
{ // set [result] to a point on the destination part closest to close_to (but also a bit close to fest_point)
std::unordered_set<unsigned int> dest_part_poly_indices;
for (unsigned int poly_idx : partsView_inside[dest_part_idx])
{
+8 -2
Ver Arquivo
@@ -105,7 +105,7 @@ private:
const int layer_nr; //!< The layer number for the layer for which to compute the outside boundary, when needed.
const int64_t offset_from_outlines; //!< Offset from the boundary of a part to the comb path. (nozzle width / 2)
const int64_t max_moveInside_distance2; //!< Maximal distance of a point to the Comb::boundary_inside which is still to be considered inside. (very sharp corners not allowed :S)
const int64_t max_move_inside_distance2; //!< Maximal distance of a point to the Comb::boundary_inside which is still to be considered inside. (very sharp corners not allowed :S)
const int64_t offset_from_outlines_outside; //!< Offset from the boundary of a part to a travel path which avoids it by this distance.
const int64_t offset_from_inside_to_outside; //!< The sum of the offsets for the inside and outside boundary Comb::offset_from_outlines and Comb::offset_from_outlines_outside
const int64_t max_crossing_dist2; //!< The maximal distance by which to cross the in_between area between inside and outside
@@ -114,13 +114,19 @@ private:
static const int64_t offset_extra_start_end = 100; //!< Distance to move start point and end point toward eachother to extra avoid collision with the boundaries.
const bool avoid_other_parts; //!< Whether to perform inverse combing a.k.a. avoid parts.
Polygons& boundary_inside; //!< The boundary within which to comb.
PartsView partsView_inside; //!< Structured indices onto boundary_inside which shows which polygons belong to which part.
Polygons outlines; //!< The actual boundary between the model and air
LocToLineGrid* inside_loc_to_line; //!< The SparsePointGridInclusive mapping locations to line segments of the inner boundary.
LazyInitialization<Polygons> boundary_outside; //!< The boundary outside of which to stay to avoid collision with other layer parts. This is a pointer cause we only compute it when we move outside the boundary (so not when there is only a single part in the layer)
LazyInitialization<LocToLineGrid, Comb*, const int64_t> outside_loc_to_line; //!< The SparsePointGridInclusive mapping locations to line segments of the outside boundary.
/*!
* Get the outlines of the meshes or raft for this layer
*/
Polygons getCombOutlines();
/*!
* Get the SparsePointGridInclusive mapping locations to line segments of the outside boundary. Calculate it when it hasn't been calculated yet.
*/
-24
Ver Arquivo
@@ -1,24 +0,0 @@
//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;
}
}
-64
Ver Arquivo
@@ -1,64 +0,0 @@
/** Copyright (C) 2016 Ultimaker - Released under terms of the AGPLv3 License */
#ifndef PATH_PLANNING_G_CODE_PATH_H
#define PATH_PLANNING_G_CODE_PATH_H
#include "../SpaceFillType.h"
#include "../GCodePathConfig.h"
#include "TimeMaterialEstimates.h"
namespace cura
{
/*!
* A class for representing a planned path.
*
* A path consists of several segments of the same type of movement: retracted travel, infill extrusion, etc.
*
* This is a compact premature representation in which are line segments have the same config, i.e. the config of this path.
*
* In the final representation (gcode) each line segment may have different properties,
* which are added when the generated GCodePaths are processed.
*/
class GCodePath
{
public:
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.
bool perform_z_hop; //!< Whether to perform a z_hop in this path, which is assumed to be a travel path.
bool perform_prime; //!< Whether this path is preceded by a prime (poop)
std::vector<Point> points; //!< The points constituting this path.
bool done;//!< Path is finished, no more moves should be added, and a new path should be started instead of any appending done to this one.
bool spiralize; //!< Whether to gradually increment the z position during the printing of this path. A sequence of spiralized paths should start at the given layer height and end in one layer higher.
TimeMaterialEstimates estimates; //!< Naive time and material estimates
/*!
* Whether this config is the config of a travel path.
*
* \return Whether this config is the config of a travel path.
*/
bool isTravelPath();
/*!
* Get the material flow in mm^3 per mm traversed.
*
* \warning Can only be called after the layer height has been set (which is done while writing the gcode!)
*
* \return The flow
*/
double getExtrusionMM3perMM();
/*!
* Get the actual line width (modulated by the flow)
* \return the actual line width as shown in layer view
*/
int getLineWidth();
};
}//namespace cura
#endif//PATH_PLANNING_G_CODE_PATH_H
-24
Ver Arquivo
@@ -1,24 +0,0 @@
//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);
}
}
-32
Ver Arquivo
@@ -1,32 +0,0 @@
/** Copyright (C) 2016 Ultimaker - Released under terms of the AGPLv3 License */
#ifndef PATH_PLANNING_NOZZLE_TEMP_INSERT_H
#define PATH_PLANNING_NOZZLE_TEMP_INSERT_H
#include "../gcodeExport.h"
namespace cura
{
/*!
* A gcode command to insert before a specific path.
*
* Currently only used for preheat commands
*/
struct NozzleTempInsert
{
const unsigned int path_idx; //!< The path before which to insert this command
double time_after_path_start; //!< The time after the start of the path, before which to insert the command // TODO: use this to insert command in between moves in a path!
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);
/*!
* Write the temperature command at the current position in the gcode.
* \param gcode The actual gcode writer
*/
void write(GCodeExport& gcode);
};
}//namespace cura
#endif//PATH_PLANNING_NOZZLE_TEMP_INSERT_H
-84
Ver Arquivo
@@ -1,84 +0,0 @@
/** Copyright (C) 2016 Ultimaker - Released under terms of the AGPLv3 License */
#include "TimeMaterialEstimates.h"
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);
}
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;
}
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
-124
Ver Arquivo
@@ -1,124 +0,0 @@
/** Copyright (C) 2016 Ultimaker - Released under terms of the AGPLv3 License */
#ifndef PATH_PLANNING_TIME_MATERIAL_ESTIMATES_H
#define PATH_PLANNING_TIME_MATERIAL_ESTIMATES_H
#include "../gcodeExport.h"
namespace cura
{
class ExtruderPlan; // forward declaration so that TimeMaterialEstimates can be a friend
/*!
* Time and material estimates for a portion of paths, e.g. layer, extruder plan, path.
*/
class TimeMaterialEstimates
{
friend class ExtruderPlan; // cause there the naive estimates are calculated
private:
double extrude_time; //!< Time in seconds occupied by extrusion
double unretracted_travel_time; //!< Time in seconds occupied by non-retracted travel (non-extrusion)
double retracted_travel_time; //!< Time in seconds occupied by retracted travel (non-extrusion)
double material; //!< Material used (in mm^3)
public:
/*!
* Basic contructor
*
* \param extrude_time Time in seconds occupied by extrusion
* \param unretracted_travel_time Time in seconds occupied by non-retracted travel (non-extrusion)
* \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);
/*!
* Basic constructor initializing all estimates to zero.
*/
TimeMaterialEstimates();
/*!
* Set all estimates to zero.
*/
void reset();
/*!
* Pointwise addition of estimate stats
*
* \param other The estimates to add to these estimates.
* \return The resulting estimates
*/
TimeMaterialEstimates operator+(const TimeMaterialEstimates& other);
/*!
* In place pointwise addition of estimate stats
*
* \param other The estimates to add to these estimates.
* \return These estimates
*/
TimeMaterialEstimates& operator+=(const TimeMaterialEstimates& other);
/*!
* \brief Subtracts the specified estimates from these estimates and returns
* the result.
*
* Each of the estimates in this class are individually subtracted.
*
* \param other The estimates to subtract from these estimates.
* \return These estimates with the specified estimates subtracted.
*/
TimeMaterialEstimates operator-(const TimeMaterialEstimates& other);
/*!
* \brief Subtracts the specified elements from these estimates.
*
* This causes the estimates in this instance to change. Each of the
* estimates in this class are individually subtracted.
*
* \param other The estimates to subtract from these estimates.
* \return A reference to this instance.
*/
TimeMaterialEstimates& operator-=(const TimeMaterialEstimates& other);
/*!
* Get total time estimate. The different time estimate member values added together.
*
* \return the total of all different time estimate values
*/
double getTotalTime() const;
/*!
* Get the total time during which the head is not retracted.
*
* This includes extrusion time and non-retracted travel time
*
* \return the total time during which the head is not retracted.
*/
double getTotalUnretractedTime() const;
/*!
* Get the total travel time.
*
* This includes the retracted travel time as well as the unretracted travel time.
*
* \return the total travel time.
*/
double getTravelTime() const;
/*!
* Get the extrusion time.
*
* \return extrusion time.
*/
double getExtrudeTime() const;
/*!
* Get the amount of material used in mm^3.
*
* \return amount of material
*/
double getMaterial() const;
};
}//namespace cura
#endif//PATH_PLANNING_TIME_MATERIAL_ESTIMATES_H
+1 -1
Ver Arquivo
@@ -43,7 +43,7 @@ int Raft::getZdiffBetweenRaftAndLayer1(const SliceDataStorage& storage)
{
return 0;
}
const int64_t airgap = std::max((coord_t)0, train.getSettingInMicrons("raft_airgap"));
const int64_t airgap = std::max(0, train.getSettingInMicrons("raft_airgap"));
const int64_t layer_0_overlap = storage.getSettingInMicrons("layer_0_z_overlap");
const int64_t layer_height_0 = storage.getSettingInMicrons("layer_height_0");
+8 -10
Ver Arquivo
@@ -125,11 +125,6 @@ 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);
@@ -225,7 +220,8 @@ int SettingRegistry::loadJSONsettingsFromDoc(rapidjson::Document& json_document,
if (json_document.HasMember("settings"))
{
handleChildren(json_document["settings"], settings_base, warn_duplicates);
std::list<std::string> path;
handleChildren(json_document["settings"], path, settings_base, warn_duplicates);
}
if (json_document.HasMember("overrides"))
@@ -247,7 +243,7 @@ int SettingRegistry::loadJSONsettingsFromDoc(rapidjson::Document& json_document,
return 0;
}
void SettingRegistry::handleChildren(const rapidjson::Value& settings_list, SettingsBase* settings_base, bool warn_duplicates)
void SettingRegistry::handleChildren(const rapidjson::Value& settings_list, std::list<std::string>& path, SettingsBase* settings_base, bool warn_duplicates)
{
if (!settings_list.IsObject())
{
@@ -256,10 +252,12 @@ void SettingRegistry::handleChildren(const rapidjson::Value& settings_list, Sett
}
for (rapidjson::Value::ConstMemberIterator setting_iterator = settings_list.MemberBegin(); setting_iterator != settings_list.MemberEnd(); ++setting_iterator)
{
handleSetting(setting_iterator, settings_base, warn_duplicates);
handleSetting(setting_iterator, path, settings_base, warn_duplicates);
if (setting_iterator->value.HasMember("children"))
{
handleChildren(setting_iterator->value["children"], settings_base, warn_duplicates);
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);
}
}
}
@@ -277,7 +275,7 @@ bool SettingRegistry::settingIsUsedByEngine(const rapidjson::Value& setting)
}
void SettingRegistry::handleSetting(const rapidjson::Value::ConstMemberIterator& json_setting_it, SettingsBase* settings_base, bool warn_duplicates)
void SettingRegistry::handleSetting(const rapidjson::Value::ConstMemberIterator& json_setting_it, std::list<std::string>& path, SettingsBase* settings_base, bool warn_duplicates)
{
const rapidjson::Value& json_setting = json_setting_it->value;
if (!json_setting.IsObject())
+3 -2
Ver Arquivo
@@ -174,16 +174,17 @@ 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, SettingsBase* settings_base, bool warn_duplicates);
void handleChildren(const rapidjson::Value& settings_list, std::list<std::string>& path, 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, SettingsBase* settings_base, bool warn_duplicates);
void handleSetting(const rapidjson::Value::ConstMemberIterator& json_setting_it, std::list<std::string>& path, SettingsBase* settings_base, bool warn_duplicates);
};
}//namespace cura
+9 -19
Ver Arquivo
@@ -93,23 +93,21 @@ void SettingsBase::setSettingInheritBase(std::string key, const SettingsBaseVirt
std::string SettingsBase::getSettingString(std::string key) const
{
auto value_it = setting_values.find(key);
if (value_it != setting_values.end())
if (setting_values.find(key) != setting_values.end())
{
return value_it->second;
return setting_values.at(key);
}
auto inherit_override_it = setting_inherit_base.find(key);
if (inherit_override_it != setting_inherit_base.end())
if (setting_inherit_base.find(key) != setting_inherit_base.end())
{
return inherit_override_it->second->getSettingString(key);
return setting_inherit_base.at(key)->getSettingString(key);
}
if (parent)
{
return parent->getSettingString(key);
}
cura::logError("Trying to retrieve unregistered setting with no value given: '%s'\n", key.c_str());
std::exit(-1);
const_cast<SettingsBase&>(*this).setting_values[key] = "";
cura::logWarning("Unregistered setting %s\n", key.c_str());
return "";
}
@@ -158,7 +156,7 @@ double SettingsBaseVirtual::getSettingInMillimeters(std::string key) const
return atof(value.c_str());
}
coord_t SettingsBaseVirtual::getSettingInMicrons(std::string key) const
int SettingsBaseVirtual::getSettingInMicrons(std::string key) const
{
return getSettingInMillimeters(key) * 1000.0;
}
@@ -212,12 +210,6 @@ double SettingsBaseVirtual::getSettingInPercentage(std::string key) const
return std::max(0.0, atof(value.c_str()));
}
double SettingsBaseVirtual::getSettingAsRatio(std::string key) const
{
std::string value = getSettingString(key);
return atof(value.c_str()) / 100.0;
}
double SettingsBaseVirtual::getSettingInSeconds(std::string key) const
{
std::string value = getSettingString(key);
@@ -353,8 +345,6 @@ EFillMethod SettingsBaseVirtual::getSettingAsFillMethod(std::string key) const
return EFillMethod::GRID;
if (value == "cubic")
return EFillMethod::CUBIC;
if (value == "cubicsubdiv")
return EFillMethod::CUBICSUBDIV;
if (value == "tetrahedral")
return EFillMethod::TETRAHEDRAL;
if (value == "triangles")
@@ -428,7 +418,7 @@ FillPerimeterGapMode SettingsBaseVirtual::getSettingAsFillPerimeterGapMode(std::
return FillPerimeterGapMode::NOWHERE;
}
CombingMode SettingsBaseVirtual::getSettingAsCombingMode(std::string key) const
CombingMode SettingsBaseVirtual::getSettingAsCombingMode(std::string key)
{
std::string value = getSettingString(key);
if (value == "off")
@@ -446,7 +436,7 @@ CombingMode SettingsBaseVirtual::getSettingAsCombingMode(std::string key) const
return CombingMode::ALL;
}
SupportDistPriority SettingsBaseVirtual::getSettingAsSupportDistPriority(std::string key) const
SupportDistPriority SettingsBaseVirtual::getSettingAsSupportDistPriority(std::string key)
{
std::string value = getSettingString(key);
if (value == "xy_overrides_z")
+3 -5
Ver Arquivo
@@ -105,7 +105,6 @@ enum class EFillMethod
LINES,
GRID,
CUBIC,
CUBICSUBDIV,
TETRAHEDRAL,
TRIANGLES,
CONCENTRIC,
@@ -231,13 +230,12 @@ public:
double getSettingInAngleDegrees(std::string key) const;
double getSettingInAngleRadians(std::string key) const;
double getSettingInMillimeters(std::string key) const;
coord_t getSettingInMicrons(std::string key) const;
int getSettingInMicrons(std::string key) const;
bool getSettingBoolean(std::string key) const;
double getSettingInDegreeCelsius(std::string key) const;
double getSettingInMillimetersPerSecond(std::string key) const;
double getSettingInCubicMillimeters(std::string key) const;
double getSettingInPercentage(std::string key) const;
double getSettingAsRatio(std::string key) const; //!< For settings which are provided in percentage
double getSettingInSeconds(std::string key) const;
FlowTempGraph getSettingAsFlowTempGraph(std::string key) const;
@@ -251,8 +249,8 @@ public:
EZSeamType getSettingAsZSeamType(std::string key) const;
ESurfaceMode getSettingAsSurfaceMode(std::string key) const;
FillPerimeterGapMode getSettingAsFillPerimeterGapMode(std::string key) const;
CombingMode getSettingAsCombingMode(std::string key) const;
SupportDistPriority getSettingAsSupportDistPriority(std::string key) const;
CombingMode getSettingAsCombingMode(std::string key);
SupportDistPriority getSettingAsSupportDistPriority(std::string key);
};
class SettingRegistry;
+5 -50
Ver Arquivo
@@ -10,16 +10,7 @@
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);
@@ -32,12 +23,6 @@ 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];
@@ -46,7 +31,7 @@ void generateSkinAreas(int layer_nr, SliceMeshStorage& mesh, const int innermost
{
return;
}
int min_infill_area = mesh.getSettingInMillimeters("min_infill_area");
for(unsigned int partNr = 0; partNr < layer.parts.size(); partNr++)
{
SliceLayerPart& part = layer.parts[partNr];
@@ -78,22 +63,12 @@ void generateSkinAreas(int layer_nr, SliceMeshStorage& mesh, const int innermost
{
if (static_cast<int>(layer_nr - downSkinCount) >= 0)
{
Polygons not_air = getInsidePolygons(mesh.layers[layer_nr - downSkinCount]);
if (min_infill_area > 0)
{
not_air.removeSmallAreas(min_infill_area);
}
downskin = downskin.difference(not_air); // skin overlaps with the walls
downskin = downskin.difference(getInsidePolygons(mesh.layers[layer_nr - downSkinCount])); // skin overlaps with the walls
}
if (static_cast<int>(layer_nr + upSkinCount) < static_cast<int>(mesh.layers.size()))
{
Polygons not_air = getInsidePolygons(mesh.layers[layer_nr + upSkinCount]);
if (min_infill_area > 0)
{
not_air.removeSmallAreas(min_infill_area);
}
upskin = upskin.difference(not_air); // skin overlaps with the walls
upskin = upskin.difference(getInsidePolygons(mesh.layers[layer_nr + upSkinCount])); // skin overlaps with the walls
}
}
else
@@ -105,10 +80,6 @@ void generateSkinAreas(int layer_nr, SliceMeshStorage& mesh, const int innermost
{
not_air = not_air.intersection(getInsidePolygons(mesh.layers[downskin_layer_nr]));
}
if (min_infill_area > 0)
{
not_air.removeSmallAreas(min_infill_area);
}
downskin = downskin.difference(not_air); // skin overlaps with the walls
}
@@ -119,10 +90,6 @@ void generateSkinAreas(int layer_nr, SliceMeshStorage& mesh, const int innermost
{
not_air = not_air.intersection(getInsidePolygons(mesh.layers[upskin_layer_nr]));
}
if (min_infill_area > 0)
{
not_air.removeSmallAreas(min_infill_area);
}
upskin = upskin.difference(not_air); // skin overlaps with the walls
}
}
@@ -139,12 +106,7 @@ 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)
@@ -177,12 +139,6 @@ 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];
@@ -190,7 +146,6 @@ void generateInfill(int layerNr, SliceMeshStorage& mesh, const int innermost_wal
int extra_offset = 0;
EFillMethod fill_pattern = mesh.getSettingAsFillMethod("infill_pattern");
if ((fill_pattern == EFillMethod::CONCENTRIC || fill_pattern == EFillMethod::CONCENTRIC_3D)
&& mesh.getSettingBoolean("alternate_extra_perimeter")
&& layerNr % 2 == 0
&& mesh.getSettingInMicrons("infill_line_distance") > mesh.getSettingInMicrons("infill_line_width") * 2)
{
+31 -24
Ver Arquivo
@@ -1,11 +1,6 @@
//Copyright (c) 2016 Ultimaker B.V.
//CuraEngine is released under the terms of the AGPLv3 or higher.
#include "sliceDataStorage.h"
#include "FffProcessor.h" //To create a mesh group with if none is provided.
#include "infill/SubDivCube.h" // For the destructor
namespace cura
{
@@ -72,14 +67,6 @@ void SliceLayer::getSecondOrInnermostWalls(Polygons& layer_walls) const
}
}
SliceMeshStorage::~SliceMeshStorage()
{
if (base_subdiv_cube)
{
delete base_subdiv_cube;
}
}
std::vector<RetractionConfig> SliceDataStorage::initializeRetractionConfigs()
{
std::vector<RetractionConfig> ret;
@@ -119,11 +106,37 @@ SliceDataStorage::SliceDataStorage(MeshGroup* meshgroup) : SettingsMessenger(mes
raft_surface_config(PrintFeatureType::SupportInterface),
support_config(PrintFeatureType::Support),
support_skin_config(PrintFeatureType::SupportInterface),
max_print_height_second_to_last_extruder(-1),
primeTower(*this)
max_print_height_second_to_last_extruder(-1)
{
}
SliceLayerPart* SliceDataStorage::getPartInside(int layer_nr, Point location)
{
if (layer_nr >= 0)
{
for (SliceMeshStorage& mesh : meshes)
{
if ((unsigned int)layer_nr >= mesh.layers.size())
{
continue;
}
SliceLayer& layer = mesh.layers[layer_nr];
for (SliceLayerPart& part : layer.parts)
{
if (part.outline.inside(location))
{
return &part;
}
}
}
return nullptr;
}
else
{
return nullptr;
}
}
Polygons SliceDataStorage::getLayerOutlines(int layer_nr, bool include_helper_parts, bool external_polys_only) const
{
if (layer_nr < 0 && layer_nr < -Raft::getFillerLayerCount(*this))
@@ -176,10 +189,7 @@ Polygons SliceDataStorage::getLayerOutlines(int layer_nr, bool include_helper_pa
total.add(support.supportLayers[std::max(0, layer_nr)].supportAreas);
total.add(support.supportLayers[std::max(0, layer_nr)].skin);
}
if (primeTower.enabled)
{
total.add(primeTower.ground_poly);
}
total.add(primeTower.ground_poly);
}
return total;
}
@@ -207,7 +217,7 @@ Polygons SliceDataStorage::getLayerSecondOrInnermostWalls(int layer_nr, bool inc
{
const SliceLayer& layer = mesh.layers[layer_nr];
layer.getSecondOrInnermostWalls(total);
if (mesh.getSettingAsSurfaceMode("magic_mesh_surface_mode") != ESurfaceMode::NORMAL)
if (const_cast<SliceMeshStorage&>(mesh).getSettingAsSurfaceMode("magic_mesh_surface_mode") != ESurfaceMode::NORMAL) // TODO: make getSetting const? make settings.setting_values mapping mutable??
{
total = total.unionPolygons(layer.openPolyLines.offsetPolyLine(100));
}
@@ -220,10 +230,7 @@ Polygons SliceDataStorage::getLayerSecondOrInnermostWalls(int layer_nr, bool inc
total.add(support.supportLayers[std::max(0, layer_nr)].supportAreas);
total.add(support.supportLayers[std::max(0, layer_nr)].skin);
}
if (primeTower.enabled)
{
total.add(primeTower.ground_poly);
}
total.add(primeTower.ground_poly);
}
return total;
}
+9 -9
Ver Arquivo
@@ -143,8 +143,6 @@ public:
};
/******************/
class SubDivCube; // forward declaration to prevent dependency loop
class SliceMeshStorage : public SettingsMessenger // passes on settings from a Mesh object
{
public:
@@ -155,27 +153,20 @@ public:
GCodePathConfig inset0_config;
GCodePathConfig insetX_config;
GCodePathConfig skin_config;
GCodePathConfig perimeter_gap_config;
std::vector<GCodePathConfig> infill_config;
SubDivCube* base_subdiv_cube;
SliceMeshStorage(SettingsBaseVirtual* settings, unsigned int slice_layer_count)
: SettingsMessenger(settings)
, layer_nr_max_filled_layer(0)
, 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);
infill_config.reserve(MAX_INFILL_COMBINE);
for(int n=0; n<MAX_INFILL_COMBINE; n++)
infill_config.emplace_back(PrintFeatureType::Infill);
}
virtual ~SliceMeshStorage();
};
class SliceDataStorage : public SettingsMessenger, NoCopy
@@ -248,6 +239,15 @@ public:
{
}
/*!
* Check in which part \p location lies, if in any.
*
* \param layer_nr The layer for which to check
* \param location The location to check
* \return The part in which \p location lie, or nullptr, if it's outside all parts.
*/
SliceLayerPart* getPartInside(int layer_nr, Point location);
/*!
* Get all outlines within a given layer.
*
+3 -7
Ver Arquivo
@@ -759,7 +759,7 @@ void SlicerLayer::makePolygons(const Mesh* mesh, bool keep_none_closed, bool ext
for (PolygonRef polyline : open_polylines)
{
if (polyline.size() > 0)
polygons.add(polyline);
openPolylines.add(polyline);
}
}
@@ -887,14 +887,10 @@ Slicer::Slicer(Mesh* mesh, int initial, int thickness, int slice_layer_count, bo
}
}
log("slice of mesh took %.3f seconds\n",slice_timer.restart());
std::vector<SlicerLayer>& layers_ref = layers; // force layers not to be copied into the threads
#pragma omp parallel for default(none) shared(mesh,layers_ref) firstprivate(keep_none_closed, extensive_stitching)
for(unsigned int layer_nr=0; layer_nr<layers_ref.size(); layer_nr++)
for(unsigned int layer_nr=0; layer_nr<layers.size(); layer_nr++)
{
layers_ref[layer_nr].makePolygons(mesh, keep_none_closed, extensive_stitching);
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());
}
+51 -78
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 <cmath> // sqrt
#include <utility> // pair
#include <deque>
@@ -90,7 +87,6 @@ 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];
@@ -101,33 +97,25 @@ void AreaSupport::generateSupportAreas(SliceDataStorage& storage, unsigned int l
std::vector<Polygons> supportAreas;
supportAreas.resize(layer_count, Polygons());
generateSupportAreas(storage, mesh_idx, layer_count, supportAreas);
for (unsigned int layer_idx = 0; layer_idx < layer_count; layer_idx++)
if (mesh.getSettingBoolean("support_interface_enable"))
{
storage.support.supportLayers[layer_idx].supportAreas.add(supportAreas[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]);
}
}
}
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);
}
}
}
/*
@@ -165,7 +153,6 @@ void AreaSupport::generateSupportAreas(SliceDataStorage& storage, unsigned int m
const int supportTowerDiameter = mesh.getSettingInMicrons("support_tower_diameter");
const int supportMinAreaSqrt = mesh.getSettingInMicrons("support_minimal_diameter");
const double supportTowerRoofAngle = mesh.getSettingInAngleRadians("support_tower_roof_angle");
const bool use_towers = mesh.getSettingBoolean("support_use_towers") && supportMinAreaSqrt > 0;
const int layerThickness = storage.getSettingInMicrons("layer_height");
const int supportXYDistance = mesh.getSettingInMicrons("support_xy_distance");
@@ -235,10 +222,7 @@ void AreaSupport::generateSupportAreas(SliceDataStorage& storage, unsigned int m
std::vector<std::pair<int, std::vector<Polygons>>> overhang_points; // stores overhang_points along with the layer index at which the overhang point occurs
if (use_towers)
{
AreaSupport::detectOverhangPoints(storage, mesh, overhang_points, layer_count, supportMinAreaSqrt);
}
AreaSupport::detectOverhangPoints(storage, mesh, overhang_points, layer_count, supportMinAreaSqrt);
std::deque<std::pair<Polygons, Polygons>> basic_and_full_overhang_above;
for (unsigned int layer_idx = support_layer_count - 1; layer_idx != support_layer_count - 1 - layerZdistanceTop ; layer_idx--)
@@ -268,7 +252,7 @@ void AreaSupport::generateSupportAreas(SliceDataStorage& storage, unsigned int m
supportLayer_this = supportLayer_this.offset(extension_offset);
}
if (use_towers)
if (supportMinAreaSqrt > 0)
{
// handle straight walls
AreaSupport::handleWallStruts(supportLayer_this, supportMinAreaSqrt, supportTowerDiameter);
@@ -290,8 +274,8 @@ void AreaSupport::generateSupportAreas(SliceDataStorage& storage, unsigned int m
int bottomLayer = ((layer_idx - layerZdistanceBottom) / stepHeight) * stepHeight;
supportLayer_this = supportLayer_this.difference(storage.getLayerOutlines(bottomLayer, false));
}
supportLayer_last = supportLayer_this;
@@ -311,7 +295,7 @@ void AreaSupport::generateSupportAreas(SliceDataStorage& storage, unsigned int m
}
else
{
supportLayer_this = supportLayer_this.difference(outlines.offset(supportXYDistance));
supportLayer_this = supportLayer_this.difference(storage.getLayerOutlines(layer_idx, false).offset(supportXYDistance));
}
}
@@ -354,17 +338,6 @@ void AreaSupport::generateSupportAreas(SliceDataStorage& storage, unsigned int m
}
}
//Enforce top Z distance.
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 - 1); layer_idx++)
{
supportAreas[layer_idx] = supportAreas[layer_idx].difference(storage.getLayerOutlines(layer_idx + layerZdistanceTop - 1, false));
}
}
for (unsigned int layer_idx = supportAreas.size() - 1; layer_idx != (unsigned int) std::max(-1, storage.support.layer_nr_max_filled_layer) ; layer_idx--)
{
@@ -400,10 +373,7 @@ std::pair<Polygons, Polygons> AreaSupport::computeBasicAndFullOverhang(const Sli
Polygons basic_overhang = supportLayer_supportee.difference(supportLayer_supported);
const SupportLayer& support_layer = storage.support.supportLayers[layer_idx];
if (support_layer.anti_overhang.size())
{
basic_overhang = basic_overhang.difference(support_layer.anti_overhang);
}
basic_overhang = basic_overhang.difference(support_layer.anti_overhang);
// Polygons support_extension = basic_overhang.offset(max_dist_from_lower_layer);
// support_extension = support_extension.intersection(supportLayer_supported);
@@ -572,7 +542,7 @@ void AreaSupport::handleWallStruts(
}
void AreaSupport::generateSupportInterface(SliceDataStorage& storage, const SliceMeshStorage& mesh, const unsigned int layer_count)
void AreaSupport::generateSupportInterface(SliceDataStorage& storage, const SliceMeshStorage& mesh, std::vector<Polygons>& support_areas, const unsigned int layer_count)
{
const unsigned int roof_layer_count = round_divide(mesh.getSettingInMicrons("support_roof_height"), storage.getSettingInMicrons("layer_height"));
const unsigned int bottom_layer_count = round_divide(mesh.getSettingInMicrons("support_bottom_height"), storage.getSettingInMicrons("layer_height"));
@@ -589,41 +559,44 @@ 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())
{
continue;
}
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)
Polygons roofs;
if (roof_layer_count > 0)
{
const Polygons outlines_above = mesh.layers[std::round(layer_idx_above)].getOutlines();
model = model.unionPolygons(outlines_above);
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);
}
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)
Polygons bottoms;
if (bottom_layer_count > 0)
{
const Polygons outlines_below = mesh.layers[std::round(layer_idx_below)].getOutlines();
model = model.unionPolygons(outlines_below);
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);
}
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(support_areas[layer_idx]);
skin.removeSmallAreas(1.0);
layer.skin.add(skin);
layer.supportAreas.add(support_areas[layer_idx].difference(layer.skin));
}
else
{
layer.skin.add(support_areas[layer_idx]);
}
// 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);
}
}
+2 -1
Ver Arquivo
@@ -36,9 +36,10 @@ 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, const unsigned int layer_count);
static void generateSupportInterface(SliceDataStorage& storage, const SliceMeshStorage& mesh, std::vector<Polygons>& support_areas, const unsigned int layer_count);
/*!
* Join current support layer with the support of the layer above, (make support conical) and perform smoothing etc operations.
+1 -1
Ver Arquivo
@@ -57,7 +57,7 @@ public:
};
private:
double max_feedrate[NUM_AXIS] = {600, 600, 40, 25}; // mm/s
double max_feedrate[NUM_AXIS] = {600, 600, 40, 25};
double minimumfeedrate = 0.01;
double acceleration = 3000;
double max_acceleration[NUM_AXIS] = {9000, 9000, 100, 10000};
-6
Ver Arquivo
@@ -37,12 +37,6 @@ 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,14 +38,6 @@ 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.
-60
Ver Arquivo
@@ -285,66 +285,6 @@ public:
}
};
class Point3Matrix
{
public:
double matrix[9];
Point3Matrix()
{
matrix[0] = 1;
matrix[1] = 0;
matrix[2] = 0;
matrix[3] = 0;
matrix[4] = 1;
matrix[5] = 0;
matrix[6] = 0;
matrix[7] = 0;
matrix[8] = 1;
}
/*!
* Initializes the top left corner with the values of \p b
* and the rest as if it's a unit matrix
*/
Point3Matrix(const PointMatrix& b)
{
matrix[0] = b.matrix[0];
matrix[1] = b.matrix[1];
matrix[2] = 0;
matrix[3] = b.matrix[2];
matrix[4] = b.matrix[3];
matrix[5] = 0;
matrix[6] = 0;
matrix[7] = 0;
matrix[8] = 1;
}
Point3 apply(const Point3 p) const
{
return Point3(p.x * matrix[0] + p.y * matrix[1] + p.z * matrix[2]
, p.x * matrix[3] + p.y * matrix[4] + p.z * matrix[5]
, p.x * matrix[6] + p.y * matrix[7] + p.z * matrix[8]);
}
Point3Matrix compose(const Point3Matrix& b)
{
Point3Matrix ret;
for (int outx = 0; outx < 3; outx++)
{
for (int outy = 0; outy < 3; outy++)
{
ret.matrix[outy * 3 + outx] = 0;
for (int in = 0; in < 3; in++)
{
ret.matrix[outy * 3 + outx] += matrix[outy * 3 + in] * b.matrix[in * 3 + outx];
}
}
}
return ret;
}
};
inline Point3 operator+(const Point3& p3, const Point& p2) {
return Point3(p3.x + p2.X, p3.y + p2.Y, p3.z);
+4 -4
Ver Arquivo
@@ -45,7 +45,7 @@ public:
other.instance = nullptr;
}
template<class... Args>
constexpr explicit optional(bool, Args&&... args ) //!< construct the value in place
constexpr explicit optional(bool not_used, Args&&... args ) //!< construct the value in place
: instance(new T(args...))
{
}
@@ -62,7 +62,7 @@ public:
* \param null_ptr exactly [nullptr]
* \return this
*/
optional& operator=(std::nullptr_t)
optional& operator=(std::nullptr_t null_ptr)
{
if (instance)
{
@@ -121,12 +121,12 @@ public:
}
constexpr T* operator->() const
{
assert(instance && "Instance should be instantiated!");
assert(instance && "instance should be instatiated!");
return instance;
}
constexpr T& operator*() const&
{
assert(instance && "Instance should be instantiated!");
assert(instance && "instance should be instatiated!");
return *instance;
}
constexpr explicit operator bool() const
-99
Ver Arquivo
@@ -1,99 +0,0 @@
/** Copyright (C) 2016 Ultimaker B.V. - Released under terms of the AGPLv3 License */
#ifndef UTILS_ORDER_OPTIMIZER_H
#define UTILS_ORDER_OPTIMIZER_H
#include <stdint.h>
#include <vector>
#include <list>
#include <utility> // pair
#include "intpoint.h"
namespace cura {
/*!
* Order optimization class.
*
* Utility class for optimizing the path order by minimizing the cyclic distance traveled between several items.
*
* The path is heuristically optimized in a way such that each node is visited and the salesman which is travelling ends up where he started.
*/
template <typename T>
class OrderOptimizer
{
public:
std::vector<std::pair<const Point, T>> items; //!< the items in arbitrary order
OrderOptimizer()
{
}
void addItem(const Point location, const T item);
/*!
* Optimize the order of \ref OrderOptimizer::items
* \return A vector of the ordered indices into \ref OrderOptimizer::items
*/
std::list<unsigned int> optimize();
};
template <typename T>
void OrderOptimizer<T>::addItem(const Point location, const T item)
{
this->items.emplace_back(location, item);
}
template <typename T>
std::list<unsigned int> OrderOptimizer<T>::optimize()
{
// least detour insertion algorithm
std::list<unsigned int> order;
if (items.size() == 0)
{
return order;
}
order.push_back(0u);
if (items.size() == 1)
{
return order;
}
order.push_back(1u);
if (items.size() == 2)
{
return order;
}
order.push_back(2u);
for (unsigned int item_idx = 3; item_idx < items.size(); item_idx++)
{
Point to_insert_item_location = items[item_idx].first;
// find best_item_to_insert_before
std::list<unsigned int>::iterator best_item_to_insert_before = order.begin();
coord_t best_detour_dist = vSize(items[*best_item_to_insert_before].first - to_insert_item_location)
+ vSize(to_insert_item_location - items[order.back()].first)
- vSize(items[*best_item_to_insert_before].first - items[order.back()].first);
std::list<unsigned int>::iterator prev = order.begin();
for (std::list<unsigned int>::iterator nearby = ++order.begin(); nearby != order.end(); ++nearby)
{
coord_t detour_dist = vSize(items[*nearby].first - to_insert_item_location)
+ vSize(to_insert_item_location - items[*prev].first)
- vSize(items[*nearby].first - items[*prev].first);
if (detour_dist < best_detour_dist)
{
best_detour_dist = detour_dist;
best_item_to_insert_before = nearby;
}
prev = nearby;
}
order.insert(best_item_to_insert_before, item_idx);
}
return order;
}
}//namespace cura
#endif//UTILS_ORDER_OPTIMIZER_H
+22 -1
Ver Arquivo
@@ -97,6 +97,27 @@ bool Polygons::inside(Point p, bool border_result) const
return (poly_count_inside % 2) == 1;
}
bool PolygonsPart::inside(Point p, bool border_result) const
{
if (size() < 1)
{
return false;
}
if (!(*this)[0].inside(p, border_result))
{
return false;
}
for (unsigned int n = 1; n < paths.size(); n++)
{
if ((*this)[n].inside(p, !border_result))
{
return false;
}
}
return true;
}
bool Polygons::insideOld(Point p, bool border_result) const
{
const Polygons& thiss = *this;
@@ -837,6 +858,7 @@ void PolygonRef::smooth_corner_simple(ListPolygon& poly, const Point p0, const P
Point b;
bool success = LinearAlg2D::getPointOnLineWithDist(a, p1, p2, shortcut_length, b);
// v02 has to be longer than ab!
p1_it.remove();
if (success)
{ // if not success then assume b is negligibly close to 2, but rounding errors caused a problem
#ifdef ASSERT_INSANE_OUTPUT
@@ -844,7 +866,6 @@ void PolygonRef::smooth_corner_simple(ListPolygon& poly, const Point p0, const P
#endif // #ifdef ASSERT_INSANE_OUTPUT
ListPolyIt::insertPointNonDuplicate(p1_it, p2_it, b);
}
p1_it.remove();
}
}
}
+23 -55
Ver Arquivo
@@ -11,8 +11,6 @@
#include <limits> // int64_t.min
#include <list>
#include <initializer_list>
#include "intpoint.h"
#define CHECK_POLY_ACCESS
@@ -54,7 +52,7 @@ public:
Point& operator[] (unsigned int index) const
{
POLY_ASSERT(index < size() && index <= std::numeric_limits<int>::max());
POLY_ASSERT(index < size() && index >= 0);
return (*path)[index];
}
@@ -87,7 +85,7 @@ public:
void remove(unsigned int index)
{
POLY_ASSERT(index < size() && index <= std::numeric_limits<int>::max());
POLY_ASSERT(index < size() && index >= 0);
path->erase(path->begin() + index);
}
@@ -409,7 +407,7 @@ public:
PolygonRef operator[] (unsigned int index)
{
POLY_ASSERT(index < size() && index <= std::numeric_limits<int>::max());
POLY_ASSERT(index < size() && index >= 0);
return PolygonRef(paths[index]);
}
const PolygonRef operator[] (unsigned int index) const
@@ -432,23 +430,11 @@ public:
{
return paths.end();
}
/*!
* Remove a polygon from the list and move the last polygon to its place
*
* \warning changes the order of the polygons!
*/
void remove(unsigned int index)
{
POLY_ASSERT(index < size() && index <= std::numeric_limits<int>::max());
if (index < paths.size() - 1)
{
paths[index] = std::move(paths.back());
}
paths.resize(paths.size() - 1);
POLY_ASSERT(index < size() && index >= 0);
paths.erase(paths.begin() + index);
}
/*!
* Remove a range of polygons
*/
void erase(ClipperLib::Paths::iterator start, ClipperLib::Paths::iterator end)
{
paths.erase(start, end);
@@ -470,13 +456,6 @@ public:
for(unsigned int n=0; n<other.paths.size(); n++)
paths.push_back(other.paths[n]);
}
/*!
* Add a 'polygon' consisting of two points
*/
void addLine(const Point from, const Point to)
{
paths.emplace_back((std::initializer_list<Point>){from, to});
}
template<typename... Args>
void emplace_back(Args... args)
@@ -497,6 +476,9 @@ public:
Polygons() {}
Polygons(const Polygons& other) { paths = other.paths; }
virtual ~Polygons() {}
Polygons& operator=(const Polygons& other) { paths = other.paths; return *this; }
bool operator==(const Polygons& other) const =delete;
@@ -535,20 +517,6 @@ public:
clipper.Execute(ClipperLib::ctIntersection, ret.paths);
return ret;
}
/*!
* Clips input line segments by this Polygons.
* \param other Input line segments to be cropped
* \return the resulting interior line segments
*/
ClipperLib::PolyTree lineSegmentIntersection(const Polygons& other) const
{
ClipperLib::PolyTree ret;
ClipperLib::Clipper clipper(clipper_init);
clipper.AddPaths(paths, ClipperLib::ptClip, true);
clipper.AddPaths(other.paths, ClipperLib::ptSubject, false);
clipper.Execute(ClipperLib::ctIntersection, ret);
return ret;
}
Polygons xorPolygons(const Polygons& other) const
{
Polygons ret;
@@ -584,7 +552,7 @@ public:
* \param border_result What to return when the point is exactly on the border
* \return Whether the point \p p is inside this polygon (or \p border_result when it is on the border)
*/
bool inside(Point p, bool border_result = false) const;
virtual bool inside(Point p, bool border_result = false) const;
/*!
* Check if we are inside the polygon. We do this by tracing from the point towards the positive X direction,
@@ -928,20 +896,20 @@ public:
Polygons& thiss = *this;
return thiss[0];
}
bool inside(Point p)
{
if (size() < 1)
return false;
if (!(*this)[0].inside(p))
return false;
for(unsigned int n=1; n<paths.size(); n++)
{
if ((*this)[n].inside(p))
return false;
}
return true;
}
/*!
* Check if we are inside the polygon.
*
* We do this by counting the number of polygons inside which this point lies.
* An odd number is inside, while an even number is outside.
*
* Returns false if outside, true if inside; if the point lies exactly on the border, will return \p border_result.
*
* \param p The point for which to check if it is inside this polygon
* \param border_result What to return when the point is exactly on the border
* \return Whether the point \p p is inside this polygon (or \p border_result when it is on the border)
*/
virtual bool inside(Point p, bool border_result = false) const;
};
/*!
+6 -19
Ver Arquivo
@@ -596,25 +596,12 @@ ClosestPolygonPoint PolygonUtils::findClosest(Point from, const Polygons& polygo
{
ClosestPolygonPoint none;
if (polygons.size() == 0)
{
return none;
}
PolygonRef 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
if (polygons[any_poly_idx].size() > 0)
{
any_polygon = polygons[any_poly_idx];
break;
}
}
if (any_polygon.size() == 0)
{
return none;
}
ClosestPolygonPoint best(any_polygon[0], 0, any_polygon, any_poly_idx);
if (polygons.size() == 0) return none;
PolygonRef aPolygon = polygons[0];
if (aPolygon.size() == 0) return none;
Point aPoint = aPolygon[0];
ClosestPolygonPoint best(aPoint, 0, aPolygon, 0);
int64_t closestDist2_score = vSize2(from - best.location) + penalty_function(best.location);
+1 -4
Ver Arquivo
@@ -1,6 +1,3 @@
//Copyright (c) 2017 Ultimaker B.V.
//CuraEngine is released under the terms of the AGPLv3 or higher.
#ifndef UTILS_STRING_H
#define UTILS_STRING_H
@@ -38,7 +35,7 @@ static inline void writeInt2mm(const int64_t coord, std::ostream& ss)
{
constexpr size_t buffer_size = 24;
char buffer[buffer_size];
int char_count = sprintf(buffer, "%d", int(coord)); // convert int to string
int char_count = sprintf(buffer, "%" PRId64, coord); // convert int to string
#ifdef DEBUG
if (char_count + 1 >= int(buffer_size)) // + 1 for the null character
{
+3 -3
Ver Arquivo
@@ -36,9 +36,9 @@ void GCodePlannerTest::setUp()
fan_speed_layer_time_settings.cool_min_speed = 0.5;
std::vector<FanSpeedLayerTimeSettings> fan_speed_layer_time_settings_per_extruder;
fan_speed_layer_time_settings_per_extruder.push_back(fan_speed_layer_time_settings);
// Slice layer z layer last current is inside fan speed and layer combing comb travel travel avoid
// storage nr height position extruder mesh time settings mode offset avoid distance
gCodePlanner = new GCodePlanner(*storage, 0, 0, 0.1, Point(0,0), 0, false, fan_speed_layer_time_settings_per_extruder, CombingMode::OFF, 100, false, 50 );
// Slice layer z layer last current fan speed and layer combing comb travel travel avoid
// storage nr height position extruder time settings mode offset avoid distance
gCodePlanner = new GCodePlanner(*storage, 0, 0, 0.1, Point(0,0), 0, fan_speed_layer_time_settings_per_extruder, CombingMode::OFF, 100, false, 50 );
}
void GCodePlannerTest::tearDown()
+1 -4
Ver Arquivo
@@ -235,14 +235,11 @@ class Setting:
tree = ast.parse(code, "eval")
compiled = compile(code, self._key, "eval")
except (SyntaxError, TypeError) as e:
print("Parse error in function (" + str(code) + ") for setting", self._key + ":", str(e))
return None
print("Parse error in function (" + code + ") for setting", self._key + ":", str(e))
except IllegalMethodError as e:
print("Use of illegal method", str(e), "in function (" + code + ") for setting", self._key)
return None
except Exception as e:
print("Exception in function (" + code + ") for setting", self._key + ":", str(e))
return None
return eval(compiled, globals(), locals)