Comparar commits

..

3 Commits

Autor SHA1 Mensagem Data
Ghostkeeper fcec461533 Revert "Only draw lines in one direction"
This reverts commit cd32e03a2d.
2017-01-05 10:33:51 +01:00
Ghostkeeper cd32e03a2d Only draw lines in one direction
Another request from Raymond. Do not ever merge this.
2016-12-29 15:02:50 +01:00
Ghostkeeper 74d28c6385 Rotate skin and infill 45 degrees
This is a desire from Raymond.
2016-12-23 10:04:52 +01:00
21 arquivos alterados com 113 adições e 577 exclusões
-11
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)
@@ -91,7 +81,6 @@ set(engine_SRCS # Except main.cpp.
src/Wireframe2gcode.cpp
src/infill/NoZigZagConnectorProcessor.cpp
src/infill/SpaghettiInfill.cpp
src/infill/ZigzagConnectorProcessorConnectedEndPieces.cpp
src/infill/ZigzagConnectorProcessorDisconnectedEndPieces.cpp
src/infill/ZigzagConnectorProcessorEndPieces.cpp
+27 -118
Ver Arquivo
@@ -194,17 +194,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"));
@@ -794,15 +784,12 @@ void FffGcodeWriter::addMeshLayerToGCode(SliceDataStorage& storage, SliceMeshSto
return;
}
if (mesh->getSettingAsCount("wall_line_count") > 0)
{ // don't switch extruder if there's nothing to print
bool empty = true;
const bool use_walls = mesh->getSettingAsCount("wall_line_count") > 0;
for (SliceLayerPart& part : layer->parts)
{
if (
(use_walls && part.insets.size() > 0)
|| (!use_walls && (part.getOwnInfillArea().size() > 0 || part.skin_parts.size() > 0))
)
if (part.insets.size() > 0)
{
empty = false;
break;
@@ -846,7 +833,7 @@ void FffGcodeWriter::addMeshPartToGCode(SliceDataStorage& storage, SliceMeshStor
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;
int infill_angle = 0;
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)));
@@ -863,7 +850,8 @@ void FffGcodeWriter::addMeshPartToGCode(SliceDataStorage& storage, SliceMeshStor
if (mesh->getSettingBoolean("infill_before_walls"))
{
processInfill(gcode_layer, mesh, part, layer_nr, infill_line_distance, infill_overlap, infill_angle);
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");
@@ -872,13 +860,12 @@ void FffGcodeWriter::addMeshPartToGCode(SliceDataStorage& storage, SliceMeshStor
if (!mesh->getSettingBoolean("infill_before_walls"))
{
processInfill(gcode_layer, mesh, part, layer_nr, infill_line_distance, infill_overlap, infill_angle);
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;
EFillMethod skin_pattern = mesh->getSettingAsFillMethod("top_bottom_pattern");
int skin_angle = 0;
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
@@ -899,74 +886,7 @@ void FffGcodeWriter::addMeshPartToGCode(SliceDataStorage& storage, SliceMeshStor
}
void FffGcodeWriter::processInfill(GCodePlanner& gcode_layer, SliceMeshStorage* mesh, SliceLayerPart& part, unsigned int layer_nr, int infill_line_distance, int infill_overlap, int infill_angle)
{
if (mesh->getSettingBoolean("spaghetti_infill_enabled"))
{
processSpaghettiInfill(gcode_layer, mesh, part, layer_nr, infill_line_distance, infill_overlap, infill_angle);
}
else
{
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);
}
}
void FffGcodeWriter::processSpaghettiInfill(GCodePlanner& gcode_layer, SliceMeshStorage* mesh, SliceLayerPart& part, unsigned int layer_nr, int infill_line_distance, int infill_overlap, int infill_angle)
{
GCodePathConfig& config = mesh->infill_config[0];
const EFillMethod pattern = mesh->getSettingAsFillMethod("infill_pattern");
const unsigned int infill_line_width = config.getLineWidth();
const int64_t z = layer_nr * getSettingInMicrons("layer_height");
const int64_t infill_shift = 0;
const int64_t outline_offset = 0;
for (std::pair<PolygonsPart, double>& filling_area : part.spaghetti_infill_volumes)
{
Polygons infill_lines;
Polygons infill_polygons;
const PolygonsPart& area = filling_area.first;
const double total_volume = filling_area.second * getSettingAsRatio("spaghetti_flow");
assert(total_volume > 0.0);
Polygons* perimeter_gaps_output = nullptr;
const bool connected_zigzags = true;
const bool use_endpieces = false;
Infill infill_comp(pattern, area, outline_offset, infill_line_width, infill_line_distance, infill_overlap, infill_angle, z, infill_shift, perimeter_gaps_output, connected_zigzags, use_endpieces);
infill_comp.generate(infill_polygons, infill_lines, mesh);
const coord_t total_length = infill_polygons.polygonLength() + infill_lines.polyLineLength();
if (total_length > 0)
{
const double normal_volume = INT2MM(INT2MM(total_length * infill_line_width)) * mesh->getSettingInMillimeters("layer_height");
const float flow_ratio = total_volume / normal_volume;
assert(flow_ratio >= 0.9);
gcode_layer.addPolygonsByOptimizer(infill_polygons, &config, nullptr, EZSeamType::SHORTEST, Point(0, 0), 0, false, flow_ratio);
if (pattern == EFillMethod::GRID || pattern == EFillMethod::LINES || pattern == EFillMethod::TRIANGLES)
{
gcode_layer.addLinesByOptimizer(infill_lines, &config, SpaceFillType::Lines, mesh->getSettingInMicrons("infill_wipe_dist"), flow_ratio);
}
else
{
gcode_layer.addLinesByOptimizer(infill_lines, &config, (pattern == EFillMethod::ZIG_ZAG)? SpaceFillType::PolyLines : SpaceFillType::Lines, 0, flow_ratio);
}
}
else
{
Point middle = const_cast<PolygonsPart&>(area).outerPolygon().centerOfMass();
if (!area.inside(middle))
{
PolygonUtils::ensureInsideOrOutside(area, middle, infill_line_width / 2);
}
const double normal_volume = INT2MM(INT2MM(10 * infill_line_width)) * mesh->getSettingInMillimeters("layer_height");
const float flow_ratio = total_volume / normal_volume;
gcode_layer.addTravel(middle);
gcode_layer.addExtrusionMove(middle + Point(0,10), &config, SpaceFillType::Lines, flow_ratio);
}
}
}
void FffGcodeWriter::processMultiLayerInfill(GCodePlanner& gcode_layer, SliceMeshStorage* mesh, SliceLayerPart& part, unsigned int layer_nr, int infill_line_distance, int infill_overlap, int infill_angle)
{
@@ -1077,7 +997,7 @@ void FffGcodeWriter::processInsets(GCodePlanner& gcode_layer, SliceMeshStorage*
{ // on the last normal layer first make the outer wall normally and then start a second outer wall from the same hight, but gradually moving upward
WallOverlapComputation* wall_overlap_computation(nullptr);
int wall_0_wipe_dist(0);
gcode_layer.addPolygonsByOptimizer(part.insets[0], &mesh->insetX_config, wall_overlap_computation, EZSeamType::SHORTEST, z_seam_pos, wall_0_wipe_dist, spiralize);
gcode_layer.addPolygonsByOptimizer(part.insets[0], &mesh->insetX_config, wall_overlap_computation, EZSeamType::SHORTEST, z_seam_pos, mesh->getSettingInMicrons("wall_0_wipe_dist"), wall_0_wipe_dist);
}
}
int processed_inset_number = -1;
@@ -1124,11 +1044,9 @@ void FffGcodeWriter::processSkinAndPerimeterGaps(GCodePlanner& gcode_layer, Slic
{
int64_t z = layer_nr * getSettingInMicrons("layer_height");
const unsigned int skin_line_width = mesh->skin_config.getLineWidth();
const unsigned int perimeter_gaps_line_width = mesh->perimeter_gap_config.getLineWidth();
constexpr int perimeter_gaps_extra_offset = 15; // extra offset so that the perimeter gaps aren't created everywhere due to rounding errors
bool fill_perimeter_gaps = mesh->getSettingAsFillPerimeterGapMode("fill_perimeter_gaps") != FillPerimeterGapMode::NOWHERE
&& !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);
@@ -1146,9 +1064,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]);
@@ -1200,6 +1116,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)
@@ -1210,16 +1133,6 @@ 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)
@@ -1235,10 +1148,7 @@ void FffGcodeWriter::processSkinAndPerimeterGaps(GCodePlanner& gcode_layer, Slic
perimeter_gaps.add(outer.difference(inner));
}
{ // gap between inner wall and skin/infill
if (mesh->getSettingInMicrons("infill_line_distance") > 0
&& !mesh->getSettingBoolean("infill_hollow")
&& mesh->getSettingInMicrons("infill_overlap_mm") >= 0
)
if (mesh->getSettingInMicrons("infill_line_distance") > 0 && !mesh->getSettingBoolean("infill_hollow"))
{
const Polygons outer = part.insets.back().offset(-1 * line_width / 2 - perimeter_gaps_extra_offset);
@@ -1247,19 +1157,18 @@ void FffGcodeWriter::processSkinAndPerimeterGaps(GCodePlanner& gcode_layer, Slic
{
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);
}
}
@@ -1402,7 +1311,7 @@ bool FffGcodeWriter::addSupportRoofsToGCode(SliceDataStorage& storage, GCodePlan
}
else
{
fillAngle = 45 + (((layer_nr % 2) + 2) % 2) * 90; // alternate between the two kinds of diagonal: / and \ .
fillAngle = 0 + (((layer_nr % 2) + 2) % 2) * 90; // alternate between the two kinds of diagonal: / and \ .
// +2) %2 to handle negative layer numbers
}
int support_skin_overlap = 0; // the skin (roofs/bottoms) should never be expanded outwards
+1 -27
Ver Arquivo
@@ -336,33 +336,7 @@ private:
*
*/
void addMeshPartToGCode(SliceDataStorage& storage, SliceMeshStorage* mesh, SliceLayerPart& part, GCodePlanner& gcode_layer, int layer_nr);
/*!
* Add sparse infill for a given part in a layer plan.
*
* \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 infill_line_distance The distance between the infill lines
* \param infill_overlap The distance by which the infill overlaps with the wall insets.
* \param fillAngle The angle in the XY plane at which the infill is generated.
*/
void processInfill(GCodePlanner& gcodeLayer, SliceMeshStorage* mesh, SliceLayerPart& part, unsigned int layer_nr, int infill_line_distance, int infill_overlap, int fillAngle);
/*!
* Add spaghetti infill for a given part in a layer plan.
*
* \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 infill_line_distance The distance between the infill lines
* \param infill_overlap The distance by which the infill overlaps with the wall insets.
* \param fillAngle The angle in the XY plane at which the infill is generated.
*/
void processSpaghettiInfill(GCodePlanner& gcodeLayer, SliceMeshStorage* mesh, SliceLayerPart& part, unsigned int layer_nr, int infill_line_distance, int infill_overlap, int fillAngle);
/*!
* Add thicker (multiple layers) sparse infill for a given part in a layer plan.
*
+10 -36
Ver Arquivo
@@ -15,7 +15,6 @@
#include "WallsComputation.h"
#include "SkirtBrim.h"
#include "skin.h"
#include "infill/SpaghettiInfill.h"
#include "infill.h"
#include "raft.h"
#include "progress/Progress.h"
@@ -152,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;
}
@@ -166,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;
}
@@ -467,27 +458,18 @@ void FffPolygonGenerator::processInfillMesh(SliceDataStorage& storage, unsigned
void FffPolygonGenerator::processDerivedWallsSkinInfill(SliceMeshStorage& mesh)
{
// generate spaghetti infill filling areas and volumes
if (mesh.getSettingBoolean("spaghetti_infill_enabled"))
// 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)
{
SpaghettiInfill::generateSpaghettiInfill(mesh);
SubDivCube::precomputeOctree(mesh);
}
else
{
// 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.
combineInfillLayers(mesh,combined_infill_layers);
}
// 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.
combineInfillLayers(mesh,combined_infill_layers);
// fuzzy skin
if (mesh.getSettingBoolean("magic_fuzzy_skin_enabled"))
@@ -534,19 +516,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)
-4
Ver Arquivo
@@ -58,10 +58,6 @@ void SkirtBrim::getFirstLayerOutline(SliceDataStorage& storage, const unsigned i
constexpr int smallest_line_length = 200;
constexpr int largest_error_of_removed_point = 50;
first_layer_outline.simplify(smallest_line_length, largest_error_of_removed_point); // simplify for faster processing of the brim lines
if (first_layer_outline.size() == 0)
{
logError("Couldn't generate skirt / brim! No polygons on first layer.");
}
}
int SkirtBrim::generatePrimarySkirtBrimLines(SliceDataStorage& storage, int start_distance, unsigned int primary_line_count, const int primary_extruder_skirt_brim_line_width, const int64_t primary_extruder_minimal_length, const Polygons& first_layer_outline, Polygons& skirt_brim_primary_extruder)
-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;
+1 -1
Ver Arquivo
@@ -922,7 +922,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);
+7 -10
Ver Arquivo
@@ -355,21 +355,21 @@ void GCodePlanner::addExtrusionMove(Point p, GCodePathConfig* config, SpaceFillT
lastPosition = p;
}
void GCodePlanner::addPolygon(PolygonRef polygon, int start_idx, GCodePathConfig* config, WallOverlapComputation* wall_overlap_computation, coord_t wall_0_wipe_dist, bool spiralize, float flow_ratio)
void GCodePlanner::addPolygon(PolygonRef polygon, int start_idx, GCodePathConfig* config, WallOverlapComputation* wall_overlap_computation, coord_t wall_0_wipe_dist, bool spiralize)
{
Point p0 = polygon[start_idx];
addTravel(p0);
for (unsigned int point_idx = 1; point_idx < polygon.size(); point_idx++)
{
Point p1 = polygon[(start_idx + point_idx) % polygon.size()];
float flow = (wall_overlap_computation)? flow_ratio * wall_overlap_computation->getFlow(p0, p1) : flow_ratio;
float flow = (wall_overlap_computation)? wall_overlap_computation->getFlow(p0, p1) : 1.0;
addExtrusionMove(p1, config, SpaceFillType::Polygons, flow, spiralize);
p0 = p1;
}
if (polygon.size() > 2)
{
Point& p1 = polygon[start_idx];
float flow = (wall_overlap_computation)? flow_ratio * wall_overlap_computation->getFlow(p0, p1) : flow_ratio;
float flow = (wall_overlap_computation)? wall_overlap_computation->getFlow(p0, p1) : 1.0;
addExtrusionMove(p1, config, SpaceFillType::Polygons, flow, spiralize);
if (wall_0_wipe_dist > 0)
@@ -403,7 +403,7 @@ void GCodePlanner::addPolygon(PolygonRef polygon, int start_idx, GCodePathConfig
}
}
void GCodePlanner::addPolygonsByOptimizer(Polygons& polygons, GCodePathConfig* config, WallOverlapComputation* wall_overlap_computation, EZSeamType z_seam_type, Point z_seam_pos, coord_t wall_0_wipe_dist, bool spiralize, float flow_ratio)
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)
{
if (polygons.size() == 0)
{
@@ -417,10 +417,10 @@ void GCodePlanner::addPolygonsByOptimizer(Polygons& polygons, GCodePathConfig* c
orderOptimizer.optimize();
for (unsigned int poly_idx : orderOptimizer.polyOrder)
{
addPolygon(polygons[poly_idx], orderOptimizer.polyStart[poly_idx], config, wall_overlap_computation, wall_0_wipe_dist, spiralize, flow_ratio);
addPolygon(polygons[poly_idx], orderOptimizer.polyStart[poly_idx], config, wall_overlap_computation, wall_0_wipe_dist, spiralize);
}
}
void GCodePlanner::addLinesByOptimizer(Polygons& polygons, GCodePathConfig* config, SpaceFillType space_fill_type, int wipe_dist, float flow_ratio)
void GCodePlanner::addLinesByOptimizer(Polygons& polygons, GCodePathConfig* config, SpaceFillType space_fill_type, int wipe_dist)
{
LineOrderOptimizer orderOptimizer(lastPosition);
for (unsigned int line_idx = 0; line_idx < polygons.size(); line_idx++)
@@ -436,7 +436,7 @@ void GCodePlanner::addLinesByOptimizer(Polygons& polygons, GCodePathConfig* conf
Point& p0 = polygon[start];
addTravel(p0);
Point& p1 = polygon[end];
addExtrusionMove(p1, config, space_fill_type, flow_ratio);
addExtrusionMove(p1, config, space_fill_type);
if (wipe_dist != 0)
{
int line_width = config->getLineWidth();
@@ -897,7 +897,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 +955,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 +976,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();
+3 -6
Ver Arquivo
@@ -387,9 +387,8 @@ public:
* \param wall_overlap_computation The wall overlap compensation calculator for each given segment (optionally nullptr)
* \param wall_0_wipe_dist The distance to travel along the polygon after it has been laid down, in order to wipe the start and end of the wall together
* \param spiralize Whether to gradually increase the z height from the normal layer height to the height of the next layer over this polygon
* \param flow_ratio The ratio with which to multiply the extrusion amount
*/
void addPolygon(PolygonRef polygon, int startIdx, GCodePathConfig* config, WallOverlapComputation* wall_overlap_computation = nullptr, coord_t wall_0_wipe_dist = 0, bool spiralize = false, float flow_ratio = 1.0);
void addPolygon(PolygonRef polygon, int startIdx, GCodePathConfig* config, WallOverlapComputation* wall_overlap_computation = nullptr, coord_t wall_0_wipe_dist = 0, bool spiralize = false);
/*!
* Add polygons to the gcode with optimized order.
@@ -407,9 +406,8 @@ public:
* \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
* \param flow_ratio The ratio with which to multiply the extrusion amount
*/
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, float flow_ratio = 1.0);
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);
/*!
* Add lines to the gcode with optimized order.
@@ -417,9 +415,8 @@ public:
* \param config The config of the lines
* \param space_fill_type The type of space filling used to generate the line segments (should be either Lines or PolyLines!)
* \param wipe_dist (optional) the distance wiped without extruding after laying down a line.
* \param flow_ratio The ratio with which to multiply the extrusion amount
*/
void addLinesByOptimizer(Polygons& polygons, GCodePathConfig* config, SpaceFillType space_fill_type, int wipe_dist = 0, float flow_ratio = 1.0);
void addLinesByOptimizer(Polygons& polygons, GCodePathConfig* config, SpaceFillType space_fill_type, int wipe_dist = 0);
/*!
* Compute naive time estimates (without accounting for slow down at corners etc.) and naive material estimates (without accounting for MergeInfillLines)
-139
Ver Arquivo
@@ -1,139 +0,0 @@
/** Copyright (C) 2017 Ultimaker - Released under terms of the AGPLv3 License */
#include "SpaghettiInfill.h"
namespace cura {
void SpaghettiInfill::generateSpaghettiInfill(SliceMeshStorage& mesh)
{
coord_t layer_height = mesh.getSettingInMicrons("layer_height");
coord_t line_width = mesh.getSettingInMicrons("infill_line_width");
double layer_height_mm = INT2MM(layer_height);
int spaghetti_max_layer_count = std::max(1, static_cast<int>(mesh.getSettingInMicrons("spaghetti_max_height") / layer_height));
// TODO: account for the initial layer height
coord_t filling_area_inset = mesh.getSettingInMicrons("spaghetti_inset");
if (mesh.getSettingInAngleDegrees("spaghetti_max_infill_angle") >= 90)
{
return; // infill cannot be combined into pillars
}
coord_t connection_inset_dist = tan(mesh.getSettingInAngleRadians("spaghetti_max_infill_angle")) * layer_height; // Horizontal component of the spaghetti_max_infill_angle
std::list<SpaghettiInfill::InfillPillar> pillar_base;
size_t min_layer = mesh.getSettingAsCount("bottom_layers") + 1;
size_t max_layer = mesh.layers.size() - 1 - mesh.getSettingAsCount("top_layers");
for (size_t layer_idx = min_layer; layer_idx <= max_layer; layer_idx++) //Skip every few layers, but extrude more.
{
SliceLayer& layer = mesh.layers[layer_idx];
// add infill parts to pillar_base
for (SliceLayerPart& slice_layer_part : layer.parts)
{
std::vector<PolygonsPart> part_infill_parts = slice_layer_part.getOwnInfillArea().splitIntoParts();
// add parts to pillar_base
for (PolygonsPart& infill_part : part_infill_parts)
{
SpaghettiInfill::InfillPillar& pillar = addPartToPillarBase(infill_part, pillar_base, connection_inset_dist);
pillar.top_slice_layer_part = &slice_layer_part;
pillar.last_layer_added = layer_idx;
pillar.layer_count++;
}
}
// handle finished pillars
for (auto it = pillar_base.begin(); it != pillar_base.end();)
{
InfillPillar& pillar = *it;
if (pillar.layer_count >= spaghetti_max_layer_count
|| pillar.last_layer_added < static_cast<int>(layer_idx)
)
{
pillar.addToTopSliceLayerPart(layer_height_mm, filling_area_inset, line_width);
auto to_be_erased = it;
++it;
pillar_base.erase(to_be_erased);
}
else
{
++it;
}
}
}
// handle unfinished pillars
for (auto it = pillar_base.begin(); it != pillar_base.end(); ++it)
{
it->addToTopSliceLayerPart(layer_height_mm, filling_area_inset, line_width);
}
}
void SpaghettiInfill::InfillPillar::addToTopSliceLayerPart(double layer_height_mm, coord_t filling_area_inset, coord_t line_width)
{
SliceLayerPart& slice_layer_part = *top_slice_layer_part;
double volume = total_area_mm2 * layer_height_mm;
assert(volume > 0.0);
// get filling area
Polygons filling_area = top_part.offset(-filling_area_inset);
assert(top_part.size() > 0 && top_part[0].size() > 0 && "the top part must be a non-zero area!");
if (filling_area.size() == 0)
{
AABB aabb(top_part);
Point inside = (aabb.min + aabb.max) / 2;
if (!top_part.inside(inside))
{
inside = top_part[0][0];
}
filling_area = PolygonsPart();
PolygonRef poly = filling_area.newPoly();
poly.emplace_back(inside + Point(-line_width / 2 - 10, line_width / 2 + 10));
poly.emplace_back(inside + Point(line_width / 2 + 10, line_width / 2 + 10));
poly.emplace_back(inside + Point(line_width / 2 + 10, -line_width / 2 - 10));
poly.emplace_back(inside + Point(-line_width / 2 - 10, -line_width / 2 - 10));
}
slice_layer_part.spaghetti_infill_volumes.emplace_back(top_part, volume);
}
bool SpaghettiInfill::InfillPillar::isConnected(const PolygonsPart& infill_part) const
{
Polygons insetted = infill_part.offset(-connection_inset_dist);
if (insetted.intersection(top_part).size() > 0)
{
return true;
}
else
{
return false;
}
}
SpaghettiInfill::InfillPillar& SpaghettiInfill::addPartToPillarBase(const PolygonsPart& infill_part, std::list<SpaghettiInfill::InfillPillar>& pillar_base, coord_t connection_inset_dist)
{
std::list<SpaghettiInfill::InfillPillar>::iterator ret = pillar_base.end();
for (auto it = pillar_base.begin(); it != pillar_base.end(); ++it)
{
InfillPillar& pillar = *it;
if (pillar.isConnected(infill_part))
{
pillar.total_area_mm2 += INT2MM(INT2MM(infill_part.area()));
pillar.top_part = infill_part;
if (ret != pillar_base.end())
{ // connecting two pillars of the layer below via one area on this layer
pillar.total_area_mm2 += ret->total_area_mm2;
pillar_base.erase(ret);
}
ret = it;
}
}
if (ret == pillar_base.end())
{ // couldn't connect to any existing pillar
pillar_base.emplace_back(infill_part, connection_inset_dist);
return pillar_base.back();
}
return *ret;
}
}//namespace cura
-95
Ver Arquivo
@@ -1,95 +0,0 @@
/** Copyright (C) 2017 Ultimaker - Released under terms of the AGPLv3 License */
#ifndef INFILL_SPAGHETTI_INFILL_H
#define INFILL_SPAGHETTI_INFILL_H
#include <list>
#include "../utils/intpoint.h"
#include "../utils/polygon.h"
#include "../sliceDataStorage.h"
namespace cura {
/*!
* Spaghetti infill is a type of infill which fills every so many layers, but extrudes as much filament corresponding to the total unfilled volume under the filling area.
*
* A filling layer is inserted when a a pillar of infill areas is becoming too high, or when the angle between the filling areas is too shallow.
*
* The filling area might be smaller than the actual infill area, so that we fill the pillar from a smaller top area.
*
* Infill pillars can join each other if they are connected on the top. The total volume will then be extruded from the top.
*
* Where the model spits into two from bottom to top, one of the top pieces will be connected to the lower part as one big pillar, while a new pillar will be generated for the other top part.
* Which part the base will be connected to is arbitrary.
*
*/
class SpaghettiInfill
{
public:
/*!
* Generate the filling areas and corresponding volume to extrude over such areas for spaghetti infill.
*/
static void generateSpaghettiInfill(SliceMeshStorage& mesh);
protected:
struct InfillPillar
{
SliceLayerPart* top_slice_layer_part = nullptr; //!< A reference to the slice_layer_part from which the top part is generated
PolygonsPart top_part; //!< The top area of this pillar
double total_area_mm2; //!< The total volume of the pillar divided by the layer height
coord_t connection_inset_dist; //!< Horizontal component of the spaghetti_max_infill_angle: the distance insetted corresponding to the maximum angle which can be filled by spaghetti infill.
int layer_count; //!< The height of the pillar in numer of layers
int last_layer_added = -1; //!< The last layer from which areas got added to this pillar
/*!
* Basic constructor of a pillar from a single area, which is to be the top of the new pillar
*
* \param _top_part The area which is the base and the top of the new pillar
* \param connection_inset_dist Horizontal component of the spaghetti_max_infill_angle
*/
InfillPillar(const PolygonsPart& _top_part, coord_t connection_inset_dist)
: top_part(_top_part) // TODO: prevent copy construction! Is that possible?
, total_area_mm2(INT2MM(INT2MM(top_part.area())))
, connection_inset_dist(connection_inset_dist)
, layer_count(1)
{
}
/*!
* Check whether the top of this pillar is connected (enough) to the given \p infill_part.
* It is assumed the infill_part is on the layer directly above the top part of this pillar.
*
* \param infill_part The part to check for connectivity
* \return Whether the infill part can be incorporated in this pillar
*/
bool isConnected(const PolygonsPart& infill_part) const;
/*!
* Register the volume of this infill pillar in the sliceDataStorage.
* The filling area and the volume are saved in \ref SliceLayerPart::spaghetti_infill_volumes
*
* Note that the filling area is different from the infill area, because the spaghetti can curl toward the sides.
*
* \param layer_height_mm The layer height in millimeters
* \param filling_area_inset The inset from the boundary of the walls to get from the infill area to the filling area
* \param line_width The line width used to generate an area just large enough for infill lines to be generated, when the infill area would otherwise be too small to get infill
*/
void addToTopSliceLayerPart(double layer_height_mm, coord_t filling_area_inset, coord_t line_width);
};
private:
/*!
* Add an area to the pillar base:
* - add it to an existing pillar if possible
* - otherwise create a new pillar for this area
* The pillar to which the area was added is returned
*
* \param infill_part The area to add to the base
* \param pillar_base The collection of pillars used up till the current layer
* \param connection_inset_dist The distance insetted corresponding to the maximum angle which can be filled by spaghetti infill
*/
static InfillPillar& addPartToPillarBase(const PolygonsPart& infill_part, std::list<InfillPillar>& pillar_base, coord_t connection_inset_dist);
};
}//namespace cura
#endif//INFILL_SPAGHETTI_INFILL_H
+7 -7
Ver Arquivo
@@ -186,15 +186,15 @@ SubDivCube::SubDivCube(SliceMeshStorage& mesh, Point3& center, unsigned int dept
bool SubDivCube::isValidSubdivision(SliceMeshStorage& mesh, Point3& center, int64_t radius)
{
int64_t distance2;
coord_t sphere_slice_radius2;//!< squared radius of bounding sphere slice on target layer
long int 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.
const long int layer_height = mesh.getSettingInMicrons("layer_height");
long int bottom_layer = (center.z - radius) / layer_height;
long int top_layer = (center.z + radius) / layer_height;
for (long int test_layer = bottom_layer; test_layer <= top_layer; test_layer += 3) // steps of three. Low-hanging speed gain.
{
part_dist = (double)(test_layer * layer_height - center.z) / radius;
sphere_slice_radius2 = radius * radius * (1.0 - (part_dist * part_dist));
@@ -221,9 +221,9 @@ bool SubDivCube::isValidSubdivision(SliceMeshStorage& mesh, Point3& center, int6
return false;
}
int SubDivCube::distanceFromPointToMesh(SliceMeshStorage& mesh, int layer_nr, Point& location, int64_t* distance2)
int SubDivCube::distanceFromPointToMesh(SliceMeshStorage& mesh, long 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
if (layer_nr < 0 || (unsigned long int)layer_nr >= mesh.layers.size()) //!< this layer is outside of valid range
{
return 2;
}
+1 -1
Ver Arquivo
@@ -74,7 +74,7 @@ private:
* \param[out] distance2 the squared distance to the infill border
* \return Code 0: outside, 1: inside, 2: boundary does not exist at specified layer
*/
static int distanceFromPointToMesh(SliceMeshStorage& mesh, int layer_nr, Point& location, int64_t* distance2);
static int distanceFromPointToMesh(SliceMeshStorage& mesh, long 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.
+3 -21
Ver Arquivo
@@ -31,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];
@@ -63,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
@@ -90,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
}
@@ -104,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
}
}
-4
Ver Arquivo
@@ -74,8 +74,6 @@ public:
* \return the own infill area
*/
Polygons& getOwnInfillArea();
std::vector<std::pair<PolygonsPart, double>> spaghetti_infill_volumes; //!< For each filling volume on this layer, the area within which to fill and the total volume to fill over the area
};
/*!
@@ -157,7 +155,6 @@ public:
GCodePathConfig inset0_config;
GCodePathConfig insetX_config;
GCodePathConfig skin_config;
GCodePathConfig perimeter_gap_config;
std::vector<GCodePathConfig> infill_config;
SubDivCube* base_subdiv_cube;
@@ -168,7 +165,6 @@ public:
, inset0_config(PrintFeatureType::OuterWall)
, insetX_config(PrintFeatureType::InnerWall)
, skin_config(PrintFeatureType::Skin)
, perimeter_gap_config(PrintFeatureType::Skin)
, base_subdiv_cube(nullptr)
{
layers.resize(slice_layer_count);
+47 -53
Ver Arquivo
@@ -90,7 +90,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 +100,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);
}
}
}
/*
@@ -351,14 +342,14 @@ void AreaSupport::generateSupportAreas(SliceDataStorage& storage, unsigned int m
}
//Enforce top Z distance.
if (layerZdistanceTop > 1)
if (layerZdistanceTop > 0)
{
// 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++)
for (size_t layer_idx = 0; layer_idx < storage.support.supportLayers.size() && layer_idx < support_layer_count - layerZdistanceTop; layer_idx++)
{
supportAreas[layer_idx] = supportAreas[layer_idx].difference(storage.getLayerOutlines(layer_idx + layerZdistanceTop - 1, false));
supportAreas[layer_idx] = supportAreas[layer_idx].difference(storage.getLayerOutlines(layer_idx + layerZdistanceTop, false));
}
}
@@ -568,7 +559,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"));
@@ -585,41 +576,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 -28
Ver Arquivo
@@ -190,22 +190,6 @@ unsigned int Polygons::findInside(Point p, bool border_result)
return ret;
}
int64_t Polygons::polyLineLength() const
{
int64_t length = 0;
for (unsigned int poly_idx = 0; poly_idx < paths.size(); poly_idx++)
{
Point p0 = paths[poly_idx][0];
for (unsigned int point_idx = 1; point_idx < paths[poly_idx].size(); point_idx++)
{
Point p1 = paths[poly_idx][point_idx];
length += vSize(p0 - p1);
p0 = p1;
}
}
return length;
}
Polygons Polygons::offset(int distance, ClipperLib::JoinType join_type, double miter_limit) const
{
Polygons ret;
@@ -853,6 +837,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
@@ -860,7 +845,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();
}
}
}
@@ -1132,17 +1116,6 @@ Polygons Polygons::smooth2(int remove_length, int min_area)
return ret;
}
double PolygonsPart::area() const
{
double area = 0;
for (unsigned int poly_idx = 0; poly_idx < size(); poly_idx++)
{
area += operator[](poly_idx).area();
// note: holes have negative area
}
return area;
}
std::vector<PolygonsPart> Polygons::splitIntoParts(bool unionAll) const
{
std::vector<PolygonsPart> ret;
+1 -5
Ver Arquivo
@@ -874,8 +874,6 @@ public:
}
return length;
}
int64_t polyLineLength() const;
Point min() const
{
@@ -931,7 +929,7 @@ public:
return thiss[0];
}
bool inside(Point p) const
bool inside(Point p)
{
if (size() < 1)
return false;
@@ -944,8 +942,6 @@ public:
}
return true;
}
double area() const;
};
/*!
+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
{
+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)