Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/Ultimaker/CuraEngine.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGhostkeeper <rubend@tutanota.com>2022-03-30 12:44:53 +0300
committerGhostkeeper <rubend@tutanota.com>2022-03-30 12:44:53 +0300
commit00c4f2754f1c2ea08603cbef2f0842e5a9232212 (patch)
tree0cd5cfb18db9e2ef2a116444d5612b8df76db96f
parent12993359f5585df80cd00852c2eb2128e81ff60e (diff)
parent9cf1833155cf43f775a2212c2a25235ce3d9e077 (diff)
Merge branch 'master' into VariableWidthPaths_rename
Conflicts: src/infill.cpp -> Modifications to fix density of concentric infill, while a typedef was removed in this branch. Contributes to issue CURA-8998.
-rw-r--r--CMakeLists.txt10
-rw-r--r--src/BeadingStrategy/BeadingStrategyFactory.cpp19
-rw-r--r--src/BeadingStrategy/BeadingStrategyFactory.h12
-rw-r--r--src/BeadingStrategy/CenterDeviationBeadingStrategy.cpp77
-rw-r--r--src/BeadingStrategy/CenterDeviationBeadingStrategy.h43
-rw-r--r--src/FffGcodeWriter.cpp9
-rw-r--r--src/InsetOrderOptimizer.cpp18
-rw-r--r--src/LayerPlan.cpp88
-rw-r--r--src/LayerPlan.h69
-rw-r--r--src/PathOrderOptimizer.h21
-rw-r--r--src/WallToolPaths.cpp3
-rw-r--r--src/WallToolPaths.h1
-rw-r--r--src/gcodeExport.cpp3
-rw-r--r--src/infill.cpp28
-rw-r--r--src/pathPlanning/Comb.cpp26
-rw-r--r--src/pathPlanning/GCodePath.cpp9
-rw-r--r--src/pathPlanning/GCodePath.h6
-rw-r--r--src/settings/Settings.cpp29
-rw-r--r--src/utils/ExtrusionLine.cpp18
-rw-r--r--tests/ExtruderPlanTest.cpp75
-rw-r--r--tests/WallsComputationTest.cpp3
-rw-r--r--tests/beading_strategy/CenterDeviationBeadingStrategyTest.cpp153
-rw-r--r--tests/utils/ExtrusionLineTest.cpp36
23 files changed, 239 insertions, 517 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 039693de9..61fc83b30 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -182,7 +182,6 @@ set(engine_SRCS # Except main.cpp.
src/BeadingStrategy/BeadingStrategy.cpp
src/BeadingStrategy/BeadingStrategyFactory.cpp
- src/BeadingStrategy/CenterDeviationBeadingStrategy.cpp
src/BeadingStrategy/DistributedBeadingStrategy.cpp
src/BeadingStrategy/LimitedBeadingStrategy.cpp
src/BeadingStrategy/RedistributeBeadingStrategy.cpp
@@ -267,9 +266,6 @@ if (ENABLE_ARCUS)
ArcusCommunicationPrivateTest
)
endif ()
-set(engine_TEST_BEADING_STRATEGY
- CenterDeviationBeadingStrategyTest
-)
set(engine_TEST_INFILL
)
set(engine_TEST_INTEGRATION
@@ -383,12 +379,6 @@ if (BUILD_TESTS)
add_dependencies(build_all_tests ${test}) #Make sure that this gets built as part of the build_all_tests target.
endforeach()
endif()
- foreach(test ${engine_TEST_BEADING_STRATEGY})
- add_executable(${test} tests/main.cpp tests/beading_strategy/${test}.cpp)
- target_link_libraries(${test} _CuraEngine ${GTEST_BOTH_LIBRARIES} ${GMOCK_BOTH_LIBRARIES})
- add_test(NAME ${test} COMMAND "${test}" WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/tests/")
- add_dependencies(build_all_tests ${test}) #Make sure that this gets built as part of the build_all_tests target.
- endforeach()
foreach (test ${engine_TEST_INFILL})
add_executable(${test} tests/main.cpp tests/infill/${test}.cpp)
target_link_libraries(${test} _CuraEngine ${GTEST_BOTH_LIBRARIES} ${GMOCK_BOTH_LIBRARIES})
diff --git a/src/BeadingStrategy/BeadingStrategyFactory.cpp b/src/BeadingStrategy/BeadingStrategyFactory.cpp
index 8f07d668c..5e90b1cdb 100644
--- a/src/BeadingStrategy/BeadingStrategyFactory.cpp
+++ b/src/BeadingStrategy/BeadingStrategyFactory.cpp
@@ -4,7 +4,6 @@
#include "BeadingStrategyFactory.h"
#include "LimitedBeadingStrategy.h"
-#include "CenterDeviationBeadingStrategy.h"
#include "WideningBeadingStrategy.h"
#include "DistributedBeadingStrategy.h"
#include "RedistributeBeadingStrategy.h"
@@ -17,7 +16,6 @@ namespace cura
BeadingStrategyPtr BeadingStrategyFactory::makeStrategy
(
- const StrategyType type,
const coord_t preferred_bead_width_outer,
const coord_t preferred_bead_width_inner,
const coord_t preferred_transition_length,
@@ -35,22 +33,7 @@ BeadingStrategyPtr BeadingStrategyFactory::makeStrategy
{
using std::make_unique;
using std::move;
- BeadingStrategyPtr ret;
- switch (type)
- {
- case StrategyType::Center:
- ret = make_unique<CenterDeviationBeadingStrategy>(preferred_bead_width_inner, transitioning_angle, wall_split_middle_threshold, wall_add_middle_threshold);
- break;
- case StrategyType::Distributed:
- ret = make_unique<DistributedBeadingStrategy>(preferred_bead_width_inner, preferred_transition_length, transitioning_angle, wall_split_middle_threshold, wall_add_middle_threshold, std::numeric_limits<int>::max());
- break;
- case StrategyType::InwardDistributed:
- ret = make_unique<DistributedBeadingStrategy>(preferred_bead_width_inner, preferred_transition_length, transitioning_angle, wall_split_middle_threshold, wall_add_middle_threshold, inward_distributed_center_wall_count);
- break;
- default:
- logError("Cannot make strategy!\n");
- return nullptr;
- }
+ BeadingStrategyPtr ret = make_unique<DistributedBeadingStrategy>(preferred_bead_width_inner, preferred_transition_length, transitioning_angle, wall_split_middle_threshold, wall_add_middle_threshold, inward_distributed_center_wall_count);
logDebug("Applying the Redistribute meta-strategy with outer-wall width = %d, inner-wall width = %d\n", preferred_bead_width_outer, preferred_bead_width_inner);
ret = make_unique<RedistributeBeadingStrategy>(preferred_bead_width_outer, minimum_variable_line_ratio, move(ret));
diff --git a/src/BeadingStrategy/BeadingStrategyFactory.h b/src/BeadingStrategy/BeadingStrategyFactory.h
index b0fa5bb64..55cfe6d2a 100644
--- a/src/BeadingStrategy/BeadingStrategyFactory.h
+++ b/src/BeadingStrategy/BeadingStrategyFactory.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2021 Ultimaker B.V.
+// Copyright (c) 2022 Ultimaker B.V.
// CuraEngine is released under the terms of the AGPLv3 or higher.
#ifndef BEADING_STRATEGY_FACTORY_H
@@ -10,21 +10,11 @@
namespace cura
{
-enum class StrategyType
-{
- Center,
- Distributed,
- InwardDistributed,
- None,
- COUNT
-};
-
class BeadingStrategyFactory
{
public:
static BeadingStrategyPtr makeStrategy
(
- const StrategyType type,
const coord_t preferred_bead_width_outer = MM2INT(0.5),
const coord_t preferred_bead_width_inner = MM2INT(0.5),
const coord_t preferred_transition_length = MM2INT(0.4),
diff --git a/src/BeadingStrategy/CenterDeviationBeadingStrategy.cpp b/src/BeadingStrategy/CenterDeviationBeadingStrategy.cpp
deleted file mode 100644
index e8433bd7f..000000000
--- a/src/BeadingStrategy/CenterDeviationBeadingStrategy.cpp
+++ /dev/null
@@ -1,77 +0,0 @@
-// Copyright (c) 2022 Ultimaker B.V.
-// CuraEngine is released under the terms of the AGPLv3 or higher.
-#include <algorithm>
-
-#include "CenterDeviationBeadingStrategy.h"
-
-namespace cura
-{
-CenterDeviationBeadingStrategy::CenterDeviationBeadingStrategy
-(
- const coord_t pref_bead_width,
- const AngleRadians transitioning_angle,
- const Ratio wall_split_middle_threshold,
- const Ratio wall_add_middle_threshold
-) :
- BeadingStrategy(pref_bead_width, wall_split_middle_threshold, wall_add_middle_threshold, pref_bead_width / 2, transitioning_angle)
-{
- name = "CenterDeviationBeadingStrategy";
-}
-
-CenterDeviationBeadingStrategy::Beading CenterDeviationBeadingStrategy::compute(coord_t thickness, coord_t bead_count) const
-{
- Beading ret;
-
- ret.total_thickness = thickness;
- if (bead_count > 0)
- {
- // Set the bead widths
- ret.bead_widths = std::vector<coord_t>(static_cast<size_t>(bead_count), optimal_width);
- coord_t leftover_thickness = ret.total_thickness;
- for (size_t bead_index = 0; bead_index <= bead_count / 2; ++bead_index)
- {
- const size_t opposite_bead_index = bead_count - (1 + bead_index);
- switch (opposite_bead_index - bead_index)
- {
- case 0: // Single bead in the middle:
- ret.bead_widths[bead_index] = leftover_thickness;
- break;
- case 1: // Two beads in the middle:
- ret.bead_widths[bead_index] = leftover_thickness / 2;
- ret.bead_widths[opposite_bead_index] = leftover_thickness / 2;
- break;
- default: // Beads on the outside.
- ret.bead_widths[bead_index] = optimal_width;
- ret.bead_widths[opposite_bead_index] = optimal_width;
- break;
- }
- leftover_thickness -= ret.bead_widths[bead_index] + ret.bead_widths[opposite_bead_index]; // Incorrect when there is a last single middle line, but the loop will exit anyway then.
- }
-
- // Set the center line location of the bead toolpaths.
- ret.toolpath_locations.resize(ret.bead_widths.size());
- ret.toolpath_locations.front() = ret.bead_widths.front() / 2;
- for (size_t bead_idx = 1; bead_idx < ret.bead_widths.size(); ++bead_idx)
- {
- ret.toolpath_locations[bead_idx] =
- ret.toolpath_locations[bead_idx - 1] + (ret.bead_widths[bead_idx] + ret.bead_widths[bead_idx - 1]) / 2;
- }
- ret.left_over = 0;
- }
- else
- {
- ret.left_over = thickness;
- }
-
- return ret;
-}
-
-coord_t CenterDeviationBeadingStrategy::getOptimalBeadCount(coord_t thickness) const
-{
- const coord_t naive_count = thickness / optimal_width; // How many lines we can fit in for sure.
- const coord_t remainder = thickness % optimal_width; // Space left after fitting that many lines.
- const coord_t minimum_line_width = optimal_width * (naive_count % 2 == 1 ? wall_split_middle_threshold : wall_add_middle_threshold);
- return naive_count + (remainder >= minimum_line_width); // If there's enough space, fit an extra one.
-}
-
-} // namespace cura
diff --git a/src/BeadingStrategy/CenterDeviationBeadingStrategy.h b/src/BeadingStrategy/CenterDeviationBeadingStrategy.h
deleted file mode 100644
index 260cae72c..000000000
--- a/src/BeadingStrategy/CenterDeviationBeadingStrategy.h
+++ /dev/null
@@ -1,43 +0,0 @@
-// Copyright (c) 2022 Ultimaker B.V.
-// CuraEngine is released under the terms of the AGPLv3 or higher.
-
-#ifndef CENTER_DEVIATION_BEADING_STRATEGY_H
-#define CENTER_DEVIATION_BEADING_STRATEGY_H
-
-#include "../settings/types/Ratio.h" //For the wall transition threshold.
-#include "BeadingStrategy.h"
-#ifdef BUILD_TESTS
-#include <gtest/gtest_prod.h> //Friend tests, so that they can inspect the privates.
-#endif
-
-namespace cura
-{
-
-/*!
- * This beading strategy makes the deviation in the thickness of the part
- * entirely compensated by the innermost wall.
- *
- * The outermost walls all use the ideal width, as far as possible.
- */
-class CenterDeviationBeadingStrategy : public BeadingStrategy
-{
-#ifdef BUILD_TESTS
- FRIEND_TEST(CenterDeviationBeadingStrategy, Construction);
-#endif
-
- public:
- CenterDeviationBeadingStrategy
- (
- coord_t pref_bead_width,
- AngleRadians transitioning_angle,
- Ratio wall_split_middle_threshold,
- Ratio wall_add_middle_threshold
- );
-
- ~CenterDeviationBeadingStrategy() override{};
- Beading compute(coord_t thickness, coord_t bead_count) const override;
- coord_t getOptimalBeadCount(coord_t thickness) const override;
-};
-
-} // namespace cura
-#endif // CENTER_DEVIATION_BEADING_STRATEGY_H
diff --git a/src/FffGcodeWriter.cpp b/src/FffGcodeWriter.cpp
index 063721ba8..ae0abfffe 100644
--- a/src/FffGcodeWriter.cpp
+++ b/src/FffGcodeWriter.cpp
@@ -976,12 +976,13 @@ LayerPlan& FffGcodeWriter::processLayer(const SliceDataStorage& storage, LayerIn
coord_t max_inner_wall_width = 0;
for (const SliceMeshStorage& mesh : storage.meshes)
{
- max_inner_wall_width = std::max(max_inner_wall_width, mesh.settings.get<coord_t>((mesh.settings.get<size_t>("wall_line_count") > 1) ? "wall_line_width_x" : "wall_line_width_0"));
- if (layer_nr == 0)
+ coord_t mesh_inner_wall_width = mesh.settings.get<coord_t>((mesh.settings.get<size_t>("wall_line_count") > 1) ? "wall_line_width_x" : "wall_line_width_0");
+ if(layer_nr == 0)
{
const ExtruderTrain& train = mesh.settings.get<ExtruderTrain&>((mesh.settings.get<size_t>("wall_line_count") > 1) ? "wall_0_extruder_nr" : "wall_x_extruder_nr");
- max_inner_wall_width *= train.settings.get<Ratio>("initial_layer_line_width_factor");
+ mesh_inner_wall_width *= train.settings.get<Ratio>("initial_layer_line_width_factor");
}
+ max_inner_wall_width = std::max(max_inner_wall_width, mesh_inner_wall_width);
}
const coord_t comb_offset_from_outlines = max_inner_wall_width * 2;
@@ -1453,7 +1454,7 @@ void FffGcodeWriter::addMeshPartToGCode(const SliceDataStorage& storage, const S
{
innermost_wall_line_width *= mesh.settings.get<Ratio>("initial_layer_line_width_factor");
}
- gcode_layer.moveInsideCombBoundary(innermost_wall_line_width);
+ gcode_layer.moveInsideCombBoundary(innermost_wall_line_width, part);
}
gcode_layer.setIsInside(false);
diff --git a/src/InsetOrderOptimizer.cpp b/src/InsetOrderOptimizer.cpp
index 14a1a647c..f606c13bb 100644
--- a/src/InsetOrderOptimizer.cpp
+++ b/src/InsetOrderOptimizer.cpp
@@ -54,7 +54,6 @@ bool InsetOrderOptimizer::addToLayer()
// Settings & configs:
const bool pack_by_inset = ! settings.get<bool>("optimize_wall_printing_order");
const InsetDirection inset_direction = settings.get<InsetDirection>("inset_direction");
- const bool center_last = inset_direction == InsetDirection::CENTER_LAST;
const bool alternate_walls = settings.get<bool>("material_alternate_walls");
const bool outer_to_inner = inset_direction == InsetDirection::OUTSIDE_IN;
@@ -129,23 +128,6 @@ bool InsetOrderOptimizer::addToLayer()
getInsetOrder(walls_to_be_added, outer_to_inner)
: getRegionOrder(walls_to_be_added, outer_to_inner);
- if (center_last)
- {
- for (const ExtrusionLine* line : walls_to_be_added)
- {
- if (line->is_odd)
- {
- for (const ExtrusionLine* other_line : walls_to_be_added)
- {
- if ( ! other_line->is_odd)
- {
- order.emplace(std::make_pair(other_line, line));
- }
- }
- }
- }
- }
-
constexpr Ratio flow = 1.0_r;
bool added_something = false;
diff --git a/src/LayerPlan.cpp b/src/LayerPlan.cpp
index 1fe0d3c47..159c72ab0 100644
--- a/src/LayerPlan.cpp
+++ b/src/LayerPlan.cpp
@@ -1,4 +1,4 @@
-//Copyright (c) 2021 Ultimaker B.V.
+//Copyright (c) 2022 Ultimaker B.V.
//CuraEngine is released under the terms of the AGPLv3 or higher.
#include <cstring>
@@ -85,25 +85,24 @@ void ExtruderPlan::applyBackPressureCompensation(const Ratio back_pressure_compe
constexpr double epsilon_speed_factor = 0.001; // Don't put on actual 'limit double minimum', because we don't want printers to stall.
for (auto& path : paths)
{
- const Ratio nominal_flow_for_path = path.config->getFlowRatio();
const double nominal_width_for_path = static_cast<double>(path.config->getLineWidth());
- if (path.flow <= 0.0 || nominal_flow_for_path <= 0.0 || nominal_width_for_path <= 0.0 || path.config->isTravelPath() || path.config->isBridgePath())
+ if(path.width_factor <= 0.0 || nominal_width_for_path <= 0.0 || path.config->isTravelPath() || path.config->isBridgePath())
{
continue;
}
- const double line_width_for_path = path.flow * nominal_flow_for_path * nominal_width_for_path;
+ const double line_width_for_path = path.width_factor * nominal_width_for_path;
path.speed_back_pressure_factor = std::max(epsilon_speed_factor, 1.0 + (nominal_width_for_path / line_width_for_path - 1.0) * back_pressure_compensation);
}
}
-GCodePath* LayerPlan::getLatestPathWithConfig(const GCodePathConfig& config, SpaceFillType space_fill_type, const Ratio flow, bool spiralize, const Ratio speed_factor)
+GCodePath* LayerPlan::getLatestPathWithConfig(const GCodePathConfig& config, SpaceFillType space_fill_type, const Ratio flow, const Ratio width_factor, bool spiralize, const Ratio speed_factor)
{
std::vector<GCodePath>& paths = extruder_plans.back().paths;
- if (paths.size() > 0 && paths.back().config == &config && !paths.back().done && paths.back().flow == flow && paths.back().speed_factor == speed_factor && paths.back().mesh_id == current_mesh) // spiralize can only change when a travel path is in between
+ if(paths.size() > 0 && paths.back().config == &config && !paths.back().done && paths.back().flow == flow && paths.back().width_factor == width_factor && paths.back().speed_factor == speed_factor && paths.back().mesh_id == current_mesh) // spiralize can only change when a travel path is in between
{
return &paths.back();
}
- paths.emplace_back(config, current_mesh, space_fill_type, flow, spiralize, speed_factor);
+ paths.emplace_back(config, current_mesh, space_fill_type, flow, width_factor, spiralize, speed_factor);
GCodePath* ret = &paths.back();
ret->skip_agressive_merge_hint = mode_skip_agressive_merge;
return ret;
@@ -301,16 +300,17 @@ void LayerPlan::setMesh(const std::string mesh_id)
current_mesh = mesh_id;
}
-void LayerPlan::moveInsideCombBoundary(const coord_t distance)
+void LayerPlan::moveInsideCombBoundary(const coord_t distance, const std::optional<SliceLayerPart>& part)
{
constexpr coord_t 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
+ // this function is to be used to move from the boundary of a part to inside the part
Point p = getLastPlannedPositionOrStartingPosition(); // copy, since we are going to move p
if (PolygonUtils::moveInside(comb_boundary_preferred, p, distance, max_dist2) != NO_INDEX)
{
//Move inside again, so we move out of tight 90deg corners
PolygonUtils::moveInside(comb_boundary_preferred, p, distance, max_dist2);
- if (comb_boundary_preferred.inside(p))
+ if (comb_boundary_preferred.inside(p) &&
+ (part == std::nullopt || part->outline.inside(p)))
{
addTravel_simple(p);
//Make sure the that any retraction happens after this move, not before it by starting a new move path.
@@ -510,9 +510,9 @@ void LayerPlan::planPrime(const float& prime_blob_wipe_length)
forceNewPathStart();
}
-void LayerPlan::addExtrusionMove(Point p, const GCodePathConfig& config, SpaceFillType space_fill_type, const Ratio& flow, bool spiralize, Ratio speed_factor, double fan_speed)
+void LayerPlan::addExtrusionMove(Point p, const GCodePathConfig& config, SpaceFillType space_fill_type, const Ratio& flow, const Ratio width_factor, bool spiralize, Ratio speed_factor, double fan_speed)
{
- GCodePath* path = getLatestPathWithConfig(config, space_fill_type, flow, spiralize, speed_factor);
+ GCodePath* path = getLatestPathWithConfig(config, space_fill_type, flow, width_factor, spiralize, speed_factor);
path->points.push_back(p);
path->setFanSpeed(fan_speed);
last_planned_position = p;
@@ -520,19 +520,20 @@ void LayerPlan::addExtrusionMove(Point p, const GCodePathConfig& config, SpaceFi
void LayerPlan::addPolygon(ConstPolygonRef polygon, int start_idx, const bool backwards, const GCodePathConfig& config, coord_t wall_0_wipe_dist, bool spiralize, const Ratio& flow_ratio, bool always_retract)
{
+ constexpr Ratio width_ratio = 1.0_r; //Not printed with variable line width.
Point p0 = polygon[start_idx];
addTravel(p0, always_retract);
const int direction = backwards ? -1 : 1;
for(size_t point_idx = 1; point_idx < polygon.size(); point_idx++)
{
Point p1 = polygon[(start_idx + point_idx * direction + polygon.size()) % polygon.size()];
- addExtrusionMove(p1, config, SpaceFillType::Polygons, flow_ratio, spiralize);
+ addExtrusionMove(p1, config, SpaceFillType::Polygons, flow_ratio, width_ratio, spiralize);
p0 = p1;
}
if(polygon.size() > 2)
{
const Point& p1 = polygon[start_idx];
- addExtrusionMove(p1, config, SpaceFillType::Polygons, flow_ratio, spiralize);
+ addExtrusionMove(p1, config, SpaceFillType::Polygons, flow_ratio, width_ratio, spiralize);
if(wall_0_wipe_dist > 0)
{ // apply outer wall wipe
@@ -597,7 +598,7 @@ void LayerPlan::addPolygonsByOptimizer(const Polygons& polygons, const GCodePath
static constexpr float max_non_bridge_line_volume = MM2INT(100); // limit to accumulated "volume" of non-bridge lines which is proportional to distance x extrusion rate
-void LayerPlan::addWallLine(const Point& p0, const Point& p1, const Settings& settings, const GCodePathConfig& non_bridge_config, const GCodePathConfig& bridge_config, float flow, float& non_bridge_line_volume, Ratio speed_factor, double distance_to_bridge_start)
+void LayerPlan::addWallLine(const Point& p0, const Point& p1, const Settings& settings, const GCodePathConfig& non_bridge_config, const GCodePathConfig& bridge_config, float flow, const Ratio width_factor, float& non_bridge_line_volume, Ratio speed_factor, double distance_to_bridge_start)
{
const coord_t min_line_len = 5; // we ignore lines less than 5um long
const double acceleration_segment_len = MM2INT(1); // accelerate using segments of this length
@@ -652,15 +653,16 @@ void LayerPlan::addWallLine(const Point& p0, const Point& p1, const Settings& se
if ((len - coast_dist) > min_line_len)
{
// segment is longer than coast distance so extrude using non-bridge config to start of coast
- addExtrusionMove(segment_end + coast_dist * (cur_point - segment_end) / len, non_bridge_config, SpaceFillType::Polygons, segment_flow, spiralize, speed_factor);
+ addExtrusionMove(segment_end + coast_dist * (cur_point - segment_end) / len, non_bridge_config, SpaceFillType::Polygons, segment_flow, width_factor, spiralize, speed_factor);
}
// then coast to start of bridge segment
- addExtrusionMove(segment_end, non_bridge_config, SpaceFillType::Polygons, 0, spiralize, speed_factor);
+ constexpr Ratio flow = 0.0_r; //Coasting has no flow rate.
+ addExtrusionMove(segment_end, non_bridge_config, SpaceFillType::Polygons, flow, width_factor, spiralize, speed_factor);
}
else
{
// no coasting required, just normal segment using non-bridge config
- addExtrusionMove(segment_end, non_bridge_config, SpaceFillType::Polygons, segment_flow, spiralize,
+ addExtrusionMove(segment_end, non_bridge_config, SpaceFillType::Polygons, segment_flow, width_factor, spiralize,
(overhang_mask.empty() || (!overhang_mask.inside(p0, true) && !overhang_mask.inside(p1, true))) ? speed_factor : overhang_speed_factor);
}
@@ -669,10 +671,10 @@ void LayerPlan::addWallLine(const Point& p0, const Point& p1, const Settings& se
else
{
// no coasting required, just normal segment using non-bridge config
- addExtrusionMove(segment_end, non_bridge_config, SpaceFillType::Polygons, segment_flow, spiralize,
+ addExtrusionMove(segment_end, non_bridge_config, SpaceFillType::Polygons, segment_flow, width_factor, spiralize,
(overhang_mask.empty() || (!overhang_mask.inside(p0, true) && !overhang_mask.inside(p1, true))) ? speed_factor : overhang_speed_factor);
}
- non_bridge_line_volume += vSize(cur_point - segment_end) * segment_flow * speed_factor * non_bridge_config.getSpeed();
+ non_bridge_line_volume += vSize(cur_point - segment_end) * segment_flow * width_factor * speed_factor * non_bridge_config.getSpeed();
cur_point = segment_end;
speed_factor = 1 - (1 - speed_factor) * acceleration_factor;
if (speed_factor >= 0.9)
@@ -686,7 +688,7 @@ void LayerPlan::addWallLine(const Point& p0, const Point& p1, const Settings& se
if (bridge_wall_mask.empty())
{
// no bridges required
- addExtrusionMove(p1, non_bridge_config, SpaceFillType::Polygons, flow, spiralize,
+ addExtrusionMove(p1, non_bridge_config, SpaceFillType::Polygons, flow, width_factor, spiralize,
(overhang_mask.empty() || (!overhang_mask.inside(p0, true) && !overhang_mask.inside(p1, true))) ? 1.0_r : overhang_speed_factor);
}
else
@@ -744,7 +746,7 @@ void LayerPlan::addWallLine(const Point& p0, const Point& p1, const Settings& se
if (bridge_line_len > min_line_len)
{
- addExtrusionMove(b1, bridge_config, SpaceFillType::Polygons, flow);
+ addExtrusionMove(b1, bridge_config, SpaceFillType::Polygons, flow, width_factor);
non_bridge_line_volume = 0;
cur_point = b1;
// after a bridge segment, start slow and accelerate to avoid under-extrusion due to extruder lag
@@ -768,7 +770,7 @@ void LayerPlan::addWallLine(const Point& p0, const Point& p1, const Settings& se
else if (bridge_wall_mask.inside(p0, true) && vSize(p0 - p1) >= min_bridge_line_len)
{
// both p0 and p1 must be above air (the result will be ugly!)
- addExtrusionMove(p1, bridge_config, SpaceFillType::Polygons, flow);
+ addExtrusionMove(p1, bridge_config, SpaceFillType::Polygons, flow, width_factor);
non_bridge_line_volume = 0;
}
else
@@ -968,12 +970,12 @@ void LayerPlan::addWall(const ExtrusionLine& wall, int start_idx, const Settings
if(is_small_feature)
{
constexpr bool spiralize = false;
- addExtrusionMove(destination, non_bridge_config, SpaceFillType::Polygons, flow_ratio * (line_width * nominal_line_width_multiplier), spiralize, small_feature_speed_factor);
+ addExtrusionMove(destination, non_bridge_config, SpaceFillType::Polygons, flow_ratio, line_width * nominal_line_width_multiplier, spiralize, small_feature_speed_factor);
}
else
{
const Point origin = p0.p + normal(line_vector, piece_length * piece);
- addWallLine(origin, destination, settings, non_bridge_config, bridge_config, flow_ratio * (line_width * nominal_line_width_multiplier), non_bridge_line_volume, speed_factor, distance_to_bridge_start);
+ addWallLine(origin, destination, settings, non_bridge_config, bridge_config, flow_ratio, line_width * nominal_line_width_multiplier, non_bridge_line_volume, speed_factor, distance_to_bridge_start);
}
}
@@ -1031,9 +1033,10 @@ void LayerPlan::addInfillWall(const ExtrusionLine& wall, const GCodePathConfig&
for (const auto &junction_n : wall)
{
- const double flow = junction_n.w / Ratio(path_config.getLineWidth());
+ const Ratio width_factor = junction_n.w / Ratio(path_config.getLineWidth());
constexpr SpaceFillType space_fill_type = SpaceFillType::Polygons;
- addExtrusionMove(junction_n.p, path_config, space_fill_type, flow);
+ constexpr Ratio flow = 1.0_r;
+ addExtrusionMove(junction_n.p, path_config, space_fill_type, flow, width_factor);
junction = junction_n;
}
}
@@ -1134,7 +1137,11 @@ void LayerPlan::addLinesInGivenOrder(
{
// Instead of doing a small travel that is shorter than the line width (which is generally done at pretty high jerk & move) do a
// "fake" extrusion move
- addExtrusionMove(start, config, space_fill_type, 0, false, 1.0, fan_speed);
+ constexpr Ratio flow = 0.0_r;
+ constexpr Ratio width_factor = 1.0_r;
+ constexpr bool spiralize = false;
+ constexpr Ratio speed_factor = 1.0_r;
+ addExtrusionMove(start, config, space_fill_type, flow, width_factor, spiralize, speed_factor, fan_speed);
}
else
{
@@ -1163,7 +1170,10 @@ void LayerPlan::addLinesInGivenOrder(
// ignore line segments that are less than 5uM long
if (vSize2(p1 - p0) >= MINIMUM_SQUARED_LINE_LENGTH)
{
- addExtrusionMove(p1, config, space_fill_type, flow_ratio, false, 1.0, fan_speed);
+ constexpr Ratio width_factor = 1.0_r;
+ constexpr bool spiralize = false;
+ constexpr Ratio speed_factor = 1.0_r;
+ addExtrusionMove(p1, config, space_fill_type, flow_ratio, width_factor, spiralize, speed_factor, fan_speed);
p0 = p1;
}
}
@@ -1199,7 +1209,11 @@ void LayerPlan::addLinesInGivenOrder(
if (wipe)
{
- addExtrusionMove(p1 + normal(p1 - p0, wipe_dist), config, space_fill_type, 0.0, false, 1.0, fan_speed);
+ constexpr Ratio flow = 0.0_r;
+ constexpr Ratio width_factor = 1.0_r;
+ constexpr bool spiralize = false;
+ constexpr Ratio speed_factor = 1.0_r;
+ addExtrusionMove(p1 + normal(p1 - p0, wipe_dist), config, space_fill_type, flow, width_factor, spiralize, speed_factor, fan_speed);
}
}
}
@@ -1268,6 +1282,8 @@ void LayerPlan::addLinesMonotonic
void LayerPlan::spiralizeWallSlice(const GCodePathConfig& config, ConstPolygonRef wall, ConstPolygonRef last_wall, const int seam_vertex_idx, const int last_seam_vertex_idx, const bool is_top_layer, const bool is_bottom_layer)
{
const bool smooth_contours = Application::getInstance().current_slice->scene.current_mesh_group->settings.get<bool>("smooth_spiralized_contours");
+ constexpr bool spiralize = true; //In addExtrusionMove calls, enable spiralize and use nominal line width.
+ constexpr Ratio width_factor = 1.0_r;
// once we are into the spiral we always start at the end point of the last layer (if any)
const Point origin = (last_seam_vertex_idx >= 0 && !is_bottom_layer) ? last_wall[last_seam_vertex_idx] : wall[seam_vertex_idx];
@@ -1280,7 +1296,8 @@ void LayerPlan::spiralizeWallSlice(const GCodePathConfig& config, ConstPolygonRe
Point join_first_wall_at = LinearAlg2D::getClosestOnLineSegment(origin, wall[seam_vertex_idx], wall[(seam_vertex_idx + 1) % wall.size()]);
if (vSize(join_first_wall_at - origin) > 10)
{
- addExtrusionMove(join_first_wall_at, config, SpaceFillType::Polygons, 1.0, true);
+ constexpr Ratio flow = 1.0_r;
+ addExtrusionMove(join_first_wall_at, config, SpaceFillType::Polygons, flow, width_factor, spiralize);
}
}
@@ -1363,18 +1380,18 @@ void LayerPlan::spiralizeWallSlice(const GCodePathConfig& config, ConstPolygonRe
if (cpp.isValid() && vSize2(cpp.location - p) <= max_dist2)
{
// interpolate between cpp.location and p depending on how far we have progressed along wall
- addExtrusionMove(cpp.location + (p - cpp.location) * (wall_length / total_length), config, SpaceFillType::Polygons, flow, true, speed_factor);
+ addExtrusionMove(cpp.location + (p - cpp.location) * (wall_length / total_length), config, SpaceFillType::Polygons, flow, width_factor, spiralize, speed_factor);
}
else
{
// no point in the last wall was found close enough to the current wall point so don't interpolate
- addExtrusionMove(p, config, SpaceFillType::Polygons, flow, true, speed_factor);
+ addExtrusionMove(p, config, SpaceFillType::Polygons, flow, width_factor, spiralize, speed_factor);
}
}
else
{
// no smoothing, use point verbatim
- addExtrusionMove(p, config, SpaceFillType::Polygons, flow, true, speed_factor);
+ addExtrusionMove(p, config, SpaceFillType::Polygons, flow, width_factor, spiralize, speed_factor);
}
}
@@ -1398,7 +1415,8 @@ void LayerPlan::spiralizeWallSlice(const GCodePathConfig& config, ConstPolygonRe
distance_coasted += seg_length;
}
// reduce number of paths created when polygon has many points by limiting precision of flow
- addExtrusionMove(p, config, SpaceFillType::Polygons, ((int)(flow * 20)) / 20.0, false, speed_factor);
+ constexpr bool no_spiralize = false;
+ addExtrusionMove(p, config, SpaceFillType::Polygons, ((int)(flow * 20)) / 20.0, width_factor, no_spiralize, speed_factor);
}
}
}
diff --git a/src/LayerPlan.h b/src/LayerPlan.h
index 87adc999b..6a0619900 100644
--- a/src/LayerPlan.h
+++ b/src/LayerPlan.h
@@ -1,4 +1,4 @@
-//Copyright (c) 2021 Ultimaker B.V.
+//Copyright (c) 2022 Ultimaker B.V.
//CuraEngine is released under the terms of the AGPLv3 or higher.
#ifndef LAYER_PLAN_H
@@ -283,7 +283,7 @@ private:
* \param speed_factor (optional) a factor which the speed will be multiplied by.
* \return A path with the given config which is now the last path in LayerPlan::paths
*/
- GCodePath* getLatestPathWithConfig(const GCodePathConfig& config, SpaceFillType space_fill_type, const Ratio flow = 1.0_r, bool spiralize = false, const Ratio speed_factor = 1.0_r);
+ GCodePath* getLatestPathWithConfig(const GCodePathConfig& config, SpaceFillType space_fill_type, const Ratio flow = 1.0_r, const Ratio width_factor = 1.0_r, bool spiralize = false, const Ratio speed_factor = 1.0_r);
public:
/*!
@@ -456,13 +456,20 @@ public:
*
* \param p The point to extrude to
* \param config The config with which to extrude
- * \param space_fill_type Of what space filling type this extrusion move is a part
- * \param flow A modifier of the extrusion width which would follow from the \p config
- * \param speed_factor (optional) A factor the travel speed will be multipled by.
- * \param spiralize Whether to gradually increase the z while printing. (Note that this path may be part of a sequence of spiralized paths, forming one polygon)
- * \param fan_speed fan speed override for this path
+ * \param space_fill_type Of what space filling type this extrusion move is
+ * a part.
+ * \param flow A modifier of the flow rate which would follow from the
+ * \p config.
+ * \param width_factor A modifier of the line width which would follow from
+ * the \p config.
+ * \param speed_factor (optional) A factor the travel speed will be
+ * multiplied by.
+ * \param spiralize Whether to gradually increase the z while printing.
+ * (Note that this path may be part of a sequence of spiralized paths,
+ * forming one polygon.)
+ * \param fan_speed Fan speed override for this path.
*/
- void addExtrusionMove(Point p, const GCodePathConfig& config, SpaceFillType space_fill_type, const Ratio& flow = 1.0_r, bool spiralize = false, Ratio speed_factor = 1.0_r, double fan_speed = GCodePathConfig::FAN_SPEED_DEFAULT);
+ void addExtrusionMove(Point p, const GCodePathConfig& config, SpaceFillType space_fill_type, const Ratio& flow = 1.0_r, const Ratio width_factor = 1.0_r, bool spiralize = false, Ratio speed_factor = 1.0_r, double fan_speed = GCodePathConfig::FAN_SPEED_DEFAULT);
/*!
* Add polygon to the gcode starting at vertex \p startIdx
@@ -509,18 +516,25 @@ public:
/*!
* Add a single line that is part of a wall to the gcode.
- * \param p0 The start vertex of the line
- * \param p1 The end vertex of the line
- * \param settings The settings which should apply to this line added to the layer plan.
- * \param non_bridge_config The config with which to print the wall lines that are not spanning a bridge
- * \param bridge_config The config with which to print the wall lines that are spanning a bridge
- * \param flow The ratio with which to multiply the extrusion amount
- * \param non_bridge_line_volume A pseudo-volume that is derived from the print speed and flow of the non-bridge lines that have preceeded this line
- * \param speed_factor This modifies the print speed when accelerating after a bridge line
- * \param distance_to_bridge_start The distance along the wall from p0 to the first bridge segment
+ * \param p0 The start vertex of the line.
+ * \param p1 The end vertex of the line.
+ * \param settings The settings which should apply to this line added to the
+ * layer plan.
+ * \param non_bridge_config The config with which to print the wall lines
+ * that are not spanning a bridge.
+ * \param bridge_config The config with which to print the wall lines that
+ * are spanning a bridge.
+ * \param flow The ratio with which to multiply the extrusion amount.
+ * \param width_ratio The ratio with which to multiply the line width.
+ * \param non_bridge_line_volume A pseudo-volume that is derived from the
+ * print speed and flow of the non-bridge lines that have preceded this
+ * line.
+ * \param speed_factor This modifies the print speed when accelerating after
+ * a bridge line.
+ * \param distance_to_bridge_start The distance along the wall from p0 to
+ * the first bridge segment.
*/
-
- void addWallLine(const Point& p0, const Point& p1, const Settings& settings, const GCodePathConfig& non_bridge_config, const GCodePathConfig& bridge_config, float flow, float& non_bridge_line_volume, Ratio speed_factor, double distance_to_bridge_start);
+ void addWallLine(const Point& p0, const Point& p1, const Settings& settings, const GCodePathConfig& non_bridge_config, const GCodePathConfig& bridge_config, float flow, const Ratio width_factor, float& non_bridge_line_volume, Ratio speed_factor, double distance_to_bridge_start);
/*!
* Add a wall to the g-code starting at vertex \p start_idx
@@ -758,12 +772,17 @@ public:
void processFanSpeedAndMinimalLayerTime(Point starting_position);
/*!
- * Add a travel move to the layer plan to move inside the current layer part by a given distance away from the outline.
- * 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.
- */
- void moveInsideCombBoundary(const coord_t distance);
+ * Add a travel move to the layer plan to move inside the current layer part
+ * by a given distance away from the outline.
+ *
+ * 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 If given, stay within the boundary of this part.
+ */
+ void moveInsideCombBoundary(const coord_t distance, const std::optional<SliceLayerPart>& part = std::nullopt);
/*!
* Apply back-pressure compensation to this layer-plan.
diff --git a/src/PathOrderOptimizer.h b/src/PathOrderOptimizer.h
index c60860d63..e403fe7ac 100644
--- a/src/PathOrderOptimizer.h
+++ b/src/PathOrderOptimizer.h
@@ -208,7 +208,7 @@ public:
assert(before_it != path_to_index.end());
is_blocking[before_it->second].emplace_back(after_it->second);
}
-
+
std::vector<bool> picked(paths.size(), false); //Fixed size boolean flag for whether each path is already in the optimized vector.
Point current_position = start_point;
@@ -414,7 +414,7 @@ protected:
return vert;
}
- // Don't know the path-type here, or wether it has a simplify. Also, simplification occurs in-place, which is not wanted here: Copy the polygon.
+ // Don't know the path-type here, or whether it has a simplify. Also, simplification occurs in-place, which is not wanted here: Copy the polygon.
// A course simplification is needed, since Arachne has a tendency to 'smear' corners out over multiple line segments.
// Which in itself is a good thing, but will mess up the detection of sharp corners and such.
Polygon simple_poly(*path.converted);
@@ -501,7 +501,22 @@ protected:
score += 1000; //1 meter penalty.
}
}
- if(score < best_score)
+
+ constexpr float EPSILON = 25.0;
+ if (fabs(best_score - score) <= EPSILON)
+ {
+ // add breaker for two candidate starting location with similar score
+ // if we don't do this then we (can) get an un-even seam
+ // ties are broken by favouring points with lower x-coord
+ // if x-coord for both points are equal then break ties by
+ // favouring points with lower y-coord
+ if (here.X != best_point.X ? here.X < best_point.X : here.Y < best_point.Y)
+ {
+ best_point = here;
+ }
+ best_score = std::min(best_score, score);
+ }
+ else if(score < best_score)
{
best_point = here;
best_score = score;
diff --git a/src/WallToolPaths.cpp b/src/WallToolPaths.cpp
index 8a8bb3755..a83b82de3 100644
--- a/src/WallToolPaths.cpp
+++ b/src/WallToolPaths.cpp
@@ -22,7 +22,6 @@ WallToolPaths::WallToolPaths(const Polygons& outline, const coord_t nominal_bead
, bead_width_x(nominal_bead_width)
, inset_count(inset_count)
, wall_0_inset(wall_0_inset)
- , strategy_type(settings.get<StrategyType>("beading_strategy_type"))
, print_thin_walls(settings.get<bool>("fill_outline_gaps"))
, min_feature_size(settings.get<coord_t>("min_feature_size"))
, min_bead_width(settings.get<coord_t>("min_bead_width"))
@@ -39,7 +38,6 @@ WallToolPaths::WallToolPaths(const Polygons& outline, const coord_t bead_width_0
, bead_width_x(bead_width_x)
, inset_count(inset_count)
, wall_0_inset(wall_0_inset)
- , strategy_type(settings.get<StrategyType>("beading_strategy_type"))
, print_thin_walls(settings.get<bool>("fill_outline_gaps"))
, min_feature_size(settings.get<coord_t>("min_feature_size"))
, min_bead_width(settings.get<coord_t>("min_bead_width"))
@@ -82,7 +80,6 @@ const std::vector<VariableWidthLines>& WallToolPaths::generate()
const size_t max_bead_count = (inset_count < std::numeric_limits<coord_t>::max() / 2) ? 2 * inset_count : std::numeric_limits<coord_t>::max();
const auto beading_strat = BeadingStrategyFactory::makeStrategy
(
- strategy_type,
bead_width_0,
bead_width_x,
wall_transition_length,
diff --git a/src/WallToolPaths.h b/src/WallToolPaths.h
index fa0ae53c4..96feca430 100644
--- a/src/WallToolPaths.h
+++ b/src/WallToolPaths.h
@@ -111,7 +111,6 @@ private:
coord_t bead_width_x; //<! The subsequently extrusion line width with which libArachne generates its walls if WallToolPaths was called with the nominal_bead_width Constructor this is the same as bead_width_0
size_t inset_count; //<! The maximum number of walls to generate
coord_t wall_0_inset; //<! How far to inset the outer wall. Should only be applied when printing the actual walls, not extra infill/skin/support walls.
- StrategyType strategy_type; //<! The wall generating strategy
bool print_thin_walls; //<! Whether to enable the widening beading meta-strategy for thin features
coord_t min_feature_size; //<! The minimum size of the features that can be widened by the widening beading meta-strategy. Features thinner than that will not be printed
coord_t min_bead_width; //<! The minimum bead size to use when widening thin model features with the widening beading meta-strategy
diff --git a/src/gcodeExport.cpp b/src/gcodeExport.cpp
index 45f472065..c43941674 100644
--- a/src/gcodeExport.cpp
+++ b/src/gcodeExport.cpp
@@ -1172,7 +1172,8 @@ void GCodeExport::writeFanCommand(double speed)
}
else if (speed > 0)
{
- *output_stream << "M106 S" << PrecisionedDouble{1, speed * 255 / 100};
+ const bool should_scale_zero_to_one = Application::getInstance().current_slice->scene.settings.get<bool>("machine_scale_fan_speed_zero_to_one");
+ *output_stream << "M106 S" << PrecisionedDouble{(should_scale_zero_to_one ? 2u : 1u), (should_scale_zero_to_one ? speed : speed * 255) / 100};
if (fan_number)
{
*output_stream << " P" << fan_number;
diff --git a/src/infill.cpp b/src/infill.cpp
index 036d446d1..79c945e1a 100644
--- a/src/infill.cpp
+++ b/src/infill.cpp
@@ -79,7 +79,6 @@ void Infill::generate(std::vector<VariableWidthLines>& toolpaths, Polygons& resu
//The lines along the edge must lie next to the border, not on it.
//This makes those algorithms a lot simpler.
if (pattern == EFillMethod::ZIG_ZAG //Zig-zag prints the zags along the walls.
- || pattern == EFillMethod::CONCENTRIC //Concentric at high densities needs to print alongside the walls, not overlapping them.
|| (zig_zaggify && (pattern == EFillMethod::LINES //Zig-zaggified infill patterns print their zags along the walls.
|| pattern == EFillMethod::TRIANGLES
|| pattern == EFillMethod::GRID
@@ -351,29 +350,28 @@ void Infill::generateLightningInfill(const LightningLayer* trees, Polygons& resu
void Infill::generateConcentricInfill(std::vector<VariableWidthLines>& toolpaths, const Settings& settings)
{
- constexpr coord_t wall_0_inset = 0; // Don't apply any outer wall inset for these. That's just for the outer wall.
- const bool iterative = line_distance > infill_line_width; // Do it all at once if there is not need for a gap, otherwise, iterate.
const coord_t min_area = infill_line_width * infill_line_width;
- Polygons current_inset = inner_contour.offset(infill_line_width / 2);
- do
+
+ Polygons current_inset = inner_contour;
+ while(true)
{
- if (iterative)
- {
- current_inset = current_inset.offset(-infill_line_width * 2).offset(infill_line_width * 2);
- }
- current_inset.simplify();
- if (current_inset.area() <= min_area)
+ //If line_distance is 0, start from the same contour as the previous line, except where the previous line closed up the shape.
+ //So we add the whole nominal line width first (to allow lines to be closer together than 1 line width if the line distance is smaller) and then subtract line_distance.
+ current_inset = current_inset.offset(infill_line_width - line_distance);
+ current_inset.simplify(); //Many insets lead to increasingly detailed shapes. Simplify to speed up processing.
+ if(current_inset.area() < min_area) //So small that it's inconsequential. Stop here.
{
break;
}
- const coord_t inset_wall_count = iterative ? 1 : std::numeric_limits<coord_t>::max();
+ constexpr size_t inset_wall_count = 1; //1 wall at a time.
+ constexpr coord_t wall_0_inset = 0; //Don't apply any outer wall inset for these. That's just for the outer wall.
WallToolPaths wall_toolpaths(current_inset, infill_line_width, inset_wall_count, wall_0_inset, settings);
const std::vector<VariableWidthLines> inset_paths = wall_toolpaths.getToolPaths();
-
toolpaths.insert(toolpaths.end(), inset_paths.begin(), inset_paths.end());
- current_inset = wall_toolpaths.getInnerContour().offset((infill_line_width / 2) - line_distance);
- } while (iterative);
+
+ current_inset = wall_toolpaths.getInnerContour();
+ }
}
void Infill::generateGridInfill(Polygons& result)
diff --git a/src/pathPlanning/Comb.cpp b/src/pathPlanning/Comb.cpp
index 7585d4fef..b10df1aa1 100644
--- a/src/pathPlanning/Comb.cpp
+++ b/src/pathPlanning/Comb.cpp
@@ -33,7 +33,7 @@ Comb::Comb(const SliceDataStorage& storage, const LayerIndex layer_nr, const Pol
: 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_moveInside_distance2(offset_from_outlines * offset_from_outlines)
, offset_from_inside_to_outside(offset_from_outlines + travel_avoid_distance)
, 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
, boundary_inside_minimum( comb_boundary_inside_minimum ) // copy the boundary, because the partsView_inside will reorder the polygons
@@ -80,7 +80,7 @@ bool Comb::calc(const ExtruderTrain& train, Point start_point, Point end_point,
unsigned int end_inside_poly = NO_INDEX;
const bool end_inside = moveInside(boundary_inside_optimal, _end_inside, inside_loc_to_line_optimal.get(), end_point, end_inside_poly);
- unsigned int start_part_boundary_poly_idx = NO_INDEX; // Added initial value to stop MSVC throwing an exception in debug mode
+ unsigned int start_part_boundary_poly_idx = NO_INDEX; // Added initial value to stop MSVC throwing an exception in debug mode
unsigned int end_part_boundary_poly_idx = NO_INDEX;
unsigned int start_part_idx = (start_inside_poly == NO_INDEX)? NO_INDEX : partsView_inside_optimal.getPartContaining(start_inside_poly, &start_part_boundary_poly_idx);
unsigned int end_part_idx = (end_inside_poly == NO_INDEX)? NO_INDEX : partsView_inside_optimal.getPartContaining(end_inside_poly, &end_part_boundary_poly_idx);
@@ -213,11 +213,29 @@ bool Comb::calc(const ExtruderTrain& train, Point start_point, Point end_point,
}
else
{
- bool combing_succeeded = LinePolygonsCrossings::comb(*boundary_outside, getOutsideLocToLine(), start_crossing.out, end_crossing.out, comb_paths.back(), offset_dist_to_get_from_on_the_polygon_to_outside, max_comb_distance_ignored, fail_on_unavoidable_obstacles);
- if (!combing_succeeded)
+ CombPath tmp_comb_path;
+ bool combing_succeeded = LinePolygonsCrossings::comb(*boundary_outside, getOutsideLocToLine(), start_crossing.out, end_crossing.out, tmp_comb_path, offset_dist_to_get_from_on_the_polygon_to_outside, max_comb_distance_ignored, true);
+
+ if (combing_succeeded)
+ {
+ // add combing travel moves if the combing was successful
+ comb_paths.push_back(tmp_comb_path);
+ }
+ else if (fail_on_unavoidable_obstacles)
{
return false;
}
+ else
+ {
+ // if combing is not possible then move directly to the target destination
+ // this happens for instance when trying to avoid skin-regions and combing from
+ // an origin that is on a hole-boundary to a destination that is on the outline-border
+ comb_paths.emplace_back();
+ comb_paths.throughAir = true;
+ comb_paths.back().cross_boundary = true;
+ comb_paths.back().push_back(start_crossing.in_or_mid);
+ comb_paths.back().push_back(end_crossing.in_or_mid);
+ }
}
}
else
diff --git a/src/pathPlanning/GCodePath.cpp b/src/pathPlanning/GCodePath.cpp
index 15dbfa02f..bd0d57578 100644
--- a/src/pathPlanning/GCodePath.cpp
+++ b/src/pathPlanning/GCodePath.cpp
@@ -1,4 +1,4 @@
-//Copyright (c) 2018 Ultimaker B.V.
+//Copyright (c) 2022 Ultimaker B.V.
//CuraEngine is released under the terms of the AGPLv3 or higher.
#include "GCodePath.h"
@@ -6,11 +6,12 @@
namespace cura
{
-GCodePath::GCodePath(const GCodePathConfig& config, std::string mesh_id, const SpaceFillType space_fill_type, const Ratio flow, const bool spiralize, const Ratio speed_factor) :
+GCodePath::GCodePath(const GCodePathConfig& config, std::string mesh_id, const SpaceFillType space_fill_type, const Ratio flow, const Ratio width_factor, const bool spiralize, const Ratio speed_factor) :
config(&config),
mesh_id(mesh_id),
space_fill_type(space_fill_type),
flow(flow),
+width_factor(width_factor),
speed_factor(speed_factor),
speed_back_pressure_factor(1.0),
retract(false),
@@ -33,12 +34,12 @@ bool GCodePath::isTravelPath() const
double GCodePath::getExtrusionMM3perMM() const
{
- return flow * config->getExtrusionMM3perMM();
+ return flow * width_factor * config->getExtrusionMM3perMM();
}
coord_t GCodePath::getLineWidthForLayerView() const
{
- return flow * config->getLineWidth() * config->getFlowRatio();
+ return flow * width_factor * config->getLineWidth() * config->getFlowRatio();
}
void GCodePath::setFanSpeed(double fan_speed)
diff --git a/src/pathPlanning/GCodePath.h b/src/pathPlanning/GCodePath.h
index da6af9320..ec29551e1 100644
--- a/src/pathPlanning/GCodePath.h
+++ b/src/pathPlanning/GCodePath.h
@@ -1,4 +1,4 @@
-//Copyright (c) 2018 Ultimaker B.V.
+//Copyright (c) 2022 Ultimaker B.V.
//CuraEngine is released under the terms of the AGPLv3 or higher.
#ifndef PATH_PLANNING_G_CODE_PATH_H
@@ -32,6 +32,7 @@ public:
std::string mesh_id; //!< Which mesh this path belongs to, if any. If it's not part of any mesh, the mesh ID should be 0.
SpaceFillType space_fill_type; //!< The type of space filling of which this path is a part
Ratio flow; //!< A type-independent flow configuration
+ Ratio width_factor; //!< Adjustment to the line width. Similar to flow, but causes the speed_back_pressure_factor to be adjusted.
Ratio speed_factor; //!< A speed factor that is multiplied with the travel speed. This factor can be used to change the travel speed.
Ratio speed_back_pressure_factor; // <! The factor the (non-travel) speed should be multiplied with as a consequence of back pressure compensation.
bool retract; //!< Whether the path is a move path preceded by a retraction move; whether the path is a retracted move path.
@@ -56,11 +57,12 @@ public:
* \param space_fill_type The type of space filling of which this path is a
* part.
* \param flow The flow rate to print this path with.
+ * \param width_factor A multiplier on the line width.
* \param spiralize Gradually increment the z-coordinate while traversing
* \param speed_factor The factor that the travel speed will be multiplied with
* this path.
*/
- GCodePath(const GCodePathConfig& config, std::string mesh_id, const SpaceFillType space_fill_type, const Ratio flow, const bool spiralize, const Ratio speed_factor = 1.0);
+ GCodePath(const GCodePathConfig& config, std::string mesh_id, const SpaceFillType space_fill_type, const Ratio flow, const Ratio width_factor, const bool spiralize, const Ratio speed_factor = 1.0);
/*!
* Whether this config is the config of a travel path.
diff --git a/src/settings/Settings.cpp b/src/settings/Settings.cpp
index b411f53b1..24b3fc6e8 100644
--- a/src/settings/Settings.cpp
+++ b/src/settings/Settings.cpp
@@ -1,4 +1,4 @@
-//Copyright (c) 2021 Ultimaker B.V.
+//Copyright (c) 2022 Ultimaker B.V.
//CuraEngine is released under the terms of the AGPLv3 or higher.
#include <cctype>
@@ -348,27 +348,6 @@ template<> EFillMethod Settings::get<EFillMethod>(const std::string& key) const
}
}
-template<> StrategyType Settings::get<StrategyType>(const std::string& key) const
-{
- const std::string& value = get<std::string>(key);
- if (value == "center_deviation")
- {
- return StrategyType::Center;
- }
- else if (value == "distributed")
- {
- return StrategyType::Distributed;
- }
- else if (value == "inward_distributed")
- {
- return StrategyType::InwardDistributed;
- }
- else //Default.
- {
- return StrategyType::None;
- }
-}
-
template<> EPlatformAdhesion Settings::get<EPlatformAdhesion>(const std::string& key) const
{
const std::string& value = get<std::string>(key);
@@ -569,11 +548,7 @@ template<> SlicingTolerance Settings::get<SlicingTolerance>(const std::string& k
template<> InsetDirection Settings::get<InsetDirection>(const std::string& key) const
{
const std::string& value = get<std::string>(key);
- if(value == "center_last")
- {
- return InsetDirection::CENTER_LAST;
- }
- else if(value == "outside_in")
+ if(value == "outside_in")
{
return InsetDirection::OUTSIDE_IN;
}
diff --git a/src/utils/ExtrusionLine.cpp b/src/utils/ExtrusionLine.cpp
index 7dd940c93..6523b4428 100644
--- a/src/utils/ExtrusionLine.cpp
+++ b/src/utils/ExtrusionLine.cpp
@@ -128,9 +128,7 @@ void ExtrusionLine::simplify(const coord_t smallest_line_segment_squared, const
// We shouldn't remove middle junctions of colinear segments if the area changed for the C-P segment is exceeding the maximum allowed
&& extrusion_area_error <= maximum_extrusion_area_deviation)
{
- // Adjust the width of the entire P-N line as a weighted average of the widths of the P-C and C-N lines and
- // then remove the current junction (vertex).
- next.w = weighted_average_width;
+ // Remove the current junction (vertex).
continue;
}
@@ -210,8 +208,8 @@ coord_t ExtrusionLine::calculateExtrusionAreaDeviationError(ExtrusionJunction A,
* | |--------------------------| | |***************************|
* | | ------------------------------------------
* --------------- ^ **************
- * ^ C.w ^
- * B.w new_width = weighted_average_width
+ * ^ B.w + C.w / 2 ^
+ * A.w + B.w / 2 new_width = weighted_average_width
*
*
* ******** denote the total extrusion area deviation error in the consecutive segments as a result of using the
@@ -220,18 +218,20 @@ coord_t ExtrusionLine::calculateExtrusionAreaDeviationError(ExtrusionJunction A,
* */
const coord_t ab_length = vSize(B - A);
const coord_t bc_length = vSize(C - B);
- const coord_t width_diff = llabs(B.w - C.w);
+ const coord_t width_diff = std::max(std::abs(B.w - A.w), std::abs(C.w - B.w));
if (width_diff > 1)
{
// Adjust the width only if there is a difference, or else the rounding errors may produce the wrong
// weighted average value.
- weighted_average_width = (ab_length * B.w + bc_length * C.w) / vSize(C - A);
- return llabs(B.w - weighted_average_width) * ab_length + llabs(C.w - weighted_average_width) * bc_length;
+ const coord_t ab_weight = (A.w + B.w) / 2;
+ const coord_t bc_weight = (B.w + C.w) / 2;
+ weighted_average_width = (ab_length * ab_weight + bc_length * bc_weight) / vSize(C - A);
+ return std::abs(ab_weight - weighted_average_width) * ab_length + std::abs(bc_weight - weighted_average_width) * bc_length;
}
else
{
// If the width difference is very small, then select the width of the segment that is longer
- weighted_average_width = ab_length > bc_length ? B.w : C.w;
+ weighted_average_width = ab_length > bc_length ? A.w : B.w;
return ab_length > bc_length ? width_diff * bc_length : width_diff * ab_length;
}
}
diff --git a/tests/ExtruderPlanTest.cpp b/tests/ExtruderPlanTest.cpp
index a8cca147a..e5b9b72d2 100644
--- a/tests/ExtruderPlanTest.cpp
+++ b/tests/ExtruderPlanTest.cpp
@@ -86,9 +86,10 @@ public:
{
const std::string mesh_id = "test_mesh";
constexpr Ratio flow_1 = 1.0_r;
+ constexpr Ratio width_1 = 1.0_r;
constexpr bool no_spiralize = false;
constexpr Ratio speed_1 = 1.0_r;
- square.assign({GCodePath(extrusion_config, mesh_id, SpaceFillType::PolyLines, flow_1, no_spiralize, speed_1)});
+ square.assign({GCodePath(extrusion_config, mesh_id, SpaceFillType::PolyLines, flow_1, width_1, no_spiralize, speed_1)});
square.back().points = {
Point(0, 0),
Point(1000, 0),
@@ -98,11 +99,11 @@ public:
};
lines.assign({
- GCodePath(extrusion_config, mesh_id, SpaceFillType::Lines, flow_1, no_spiralize, speed_1),
- GCodePath(travel_config, mesh_id, SpaceFillType::Lines, flow_1, no_spiralize, speed_1),
- GCodePath(extrusion_config, mesh_id, SpaceFillType::Lines, flow_1, no_spiralize, speed_1),
- GCodePath(travel_config, mesh_id, SpaceFillType::Lines, flow_1, no_spiralize, speed_1),
- GCodePath(extrusion_config, mesh_id, SpaceFillType::Lines, flow_1, no_spiralize, speed_1)
+ GCodePath(extrusion_config, mesh_id, SpaceFillType::Lines, flow_1, width_1, no_spiralize, speed_1),
+ GCodePath(travel_config , mesh_id, SpaceFillType::Lines, flow_1, width_1, no_spiralize, speed_1),
+ GCodePath(extrusion_config, mesh_id, SpaceFillType::Lines, flow_1, width_1, no_spiralize, speed_1),
+ GCodePath(travel_config , mesh_id, SpaceFillType::Lines, flow_1, width_1, no_spiralize, speed_1),
+ GCodePath(extrusion_config, mesh_id, SpaceFillType::Lines, flow_1, width_1, no_spiralize, speed_1)
});
lines[0].points = {Point(0, 0), Point(1000, 0)};
lines[1].points = {Point(1000, 0), Point(1000, 400)};
@@ -114,11 +115,11 @@ public:
constexpr Ratio flow_08 = 0.8_r;
constexpr Ratio flow_04 = 0.4_r;
decreasing_flow.assign({
- GCodePath(extrusion_config, mesh_id, SpaceFillType::Lines, flow_12, no_spiralize, speed_1),
- GCodePath(travel_config, mesh_id, SpaceFillType::Lines, flow_1, no_spiralize, speed_1),
- GCodePath(extrusion_config, mesh_id, SpaceFillType::Lines, flow_08, no_spiralize, speed_1),
- GCodePath(travel_config, mesh_id, SpaceFillType::Lines, flow_1, no_spiralize, speed_1),
- GCodePath(extrusion_config, mesh_id, SpaceFillType::Lines, flow_04, no_spiralize, speed_1)
+ GCodePath(extrusion_config, mesh_id, SpaceFillType::Lines, flow_12, width_1, no_spiralize, speed_1),
+ GCodePath(travel_config , mesh_id, SpaceFillType::Lines, flow_1 , width_1, no_spiralize, speed_1),
+ GCodePath(extrusion_config, mesh_id, SpaceFillType::Lines, flow_08, width_1, no_spiralize, speed_1),
+ GCodePath(travel_config , mesh_id, SpaceFillType::Lines, flow_1 , width_1, no_spiralize, speed_1),
+ GCodePath(extrusion_config, mesh_id, SpaceFillType::Lines, flow_04, width_1, no_spiralize, speed_1)
});
decreasing_flow[0].points = {Point(0, 0), Point(1000, 0)};
decreasing_flow[1].points = {Point(1000, 0), Point(1000, 400)};
@@ -130,11 +131,11 @@ public:
constexpr Ratio speed_08 = 0.8_r;
constexpr Ratio speed_04 = 0.4_r;
decreasing_speed.assign({
- GCodePath(extrusion_config, mesh_id, SpaceFillType::Lines, flow_1, no_spiralize, speed_12),
- GCodePath(travel_config, mesh_id, SpaceFillType::Lines, flow_1, no_spiralize, speed_1),
- GCodePath(extrusion_config, mesh_id, SpaceFillType::Lines, flow_1, no_spiralize, speed_08),
- GCodePath(travel_config, mesh_id, SpaceFillType::Lines, flow_1, no_spiralize, speed_1),
- GCodePath(extrusion_config, mesh_id, SpaceFillType::Lines, flow_1, no_spiralize, speed_04)
+ GCodePath(extrusion_config, mesh_id, SpaceFillType::Lines, flow_1, width_1, no_spiralize, speed_12),
+ GCodePath(travel_config , mesh_id, SpaceFillType::Lines, flow_1, width_1, no_spiralize, speed_1),
+ GCodePath(extrusion_config, mesh_id, SpaceFillType::Lines, flow_1, width_1, no_spiralize, speed_08),
+ GCodePath(travel_config , mesh_id, SpaceFillType::Lines, flow_1, width_1, no_spiralize, speed_1),
+ GCodePath(extrusion_config, mesh_id, SpaceFillType::Lines, flow_1, width_1, no_spiralize, speed_04)
});
decreasing_speed[0].points = {Point(0, 0), Point(1000, 0)};
decreasing_speed[1].points = {Point(1000, 0), Point(1000, 400)};
@@ -143,12 +144,12 @@ public:
decreasing_speed[4].points = {Point(0, 800), Point(1000, 800)};
variable_width.assign({
- GCodePath(extrusion_config, mesh_id, SpaceFillType::Lines, flow_1, no_spiralize, speed_1),
- GCodePath(extrusion_config, mesh_id, SpaceFillType::Lines, 0.8_r, no_spiralize, speed_1),
- GCodePath(extrusion_config, mesh_id, SpaceFillType::Lines, 0.6_r, no_spiralize, speed_1),
- GCodePath(extrusion_config, mesh_id, SpaceFillType::Lines, 0.4_r, no_spiralize, speed_1),
- GCodePath(extrusion_config, mesh_id, SpaceFillType::Lines, 0.2_r, no_spiralize, speed_1),
- GCodePath(extrusion_config, mesh_id, SpaceFillType::Lines, 0.0_r, no_spiralize, speed_1),
+ GCodePath(extrusion_config, mesh_id, SpaceFillType::Lines, flow_1, width_1, no_spiralize, speed_1),
+ GCodePath(extrusion_config, mesh_id, SpaceFillType::Lines, flow_1, 0.8_r, no_spiralize, speed_1),
+ GCodePath(extrusion_config, mesh_id, SpaceFillType::Lines, flow_1, 0.6_r, no_spiralize, speed_1),
+ GCodePath(extrusion_config, mesh_id, SpaceFillType::Lines, flow_1, 0.4_r, no_spiralize, speed_1),
+ GCodePath(extrusion_config, mesh_id, SpaceFillType::Lines, flow_1, 0.2_r, no_spiralize, speed_1),
+ GCodePath(extrusion_config, mesh_id, SpaceFillType::Lines, flow_1, 0.0_r, no_spiralize, speed_1),
});
variable_width[0].points = {Point(0, 0), Point(1000, 0)};
variable_width[1].points = {Point(1000, 0), Point(2000, 0)};
@@ -194,18 +195,20 @@ public:
{}
/*!
- * Helper method to calculate the flow rate of a path in mm3 per second, ignoring any user specified speed alteration other than the back pressure compensation.
+ * Helper method to calculate the flow rate of a path in mm3 per second,
+ * minus the influence of flow rate and ignoring any user specified speed
+ * alteration other than the back pressure compensation.
* \param path The path to calculate the flow rate of.
- * \return The flow rate, in cubic millimeters per second (ignoring any user specified speed alteration other than back-pressure compensation).
+ * \return The flow rate, in cubic millimeters per second.
*/
- double calculatePathFlow(const GCodePath& path)
+ double calculatePathWidth(const GCodePath& path)
{
- return path.getExtrusionMM3perMM() * path.config->getSpeed() * path.speed_back_pressure_factor;
+ return path.getExtrusionMM3perMM() / path.config->getFlowRatio() / path.flow * path.config->getSpeed() * path.speed_back_pressure_factor;
}
bool shouldCountPath(const GCodePath& path) const
{
- return path.flow > 0.0 && path.config->getFlowRatio() > 0.0 && path.config->getLineWidth() > 0.0 && ! path.config->isTravelPath() && ! path.config->isBridgePath();
+ return path.flow > 0.0 && path.width_factor > 0.0 && path.config->getFlowRatio() > 0.0 && path.config->getLineWidth() > 0.0 && ! path.config->isTravelPath() && ! path.config->isBridgePath();
}
};
@@ -250,20 +253,20 @@ public:
TEST_P(ExtruderPlanPathsParameterizedTest, BackPressureCompensationZeroIsUncompensated)
{
extruder_plan.paths = GetParam();
- std::vector<Ratio> original_flows;
+ std::vector<Ratio> original_widths;
std::vector<Ratio> original_speeds;
for(const GCodePath& path : extruder_plan.paths)
{
- original_flows.push_back(path.flow);
+ original_widths.push_back(path.width_factor);
original_speeds.push_back(path.speed_factor);
}
extruder_plan.applyBackPressureCompensation(0.0_r);
- ASSERT_EQ(extruder_plan.paths.size(), original_flows.size()) << "Number of paths may not have changed.";
+ ASSERT_EQ(extruder_plan.paths.size(), original_widths.size()) << "Number of paths may not have changed.";
for(size_t i = 0; i < extruder_plan.paths.size(); ++i)
{
- EXPECT_NEAR(original_flows[i], extruder_plan.paths[i].flow, error_margin) << "The flow rate did not change. Back pressure compensation doesn't adjust flow.";
+ EXPECT_NEAR(original_widths[i], extruder_plan.paths[i].width_factor, error_margin) << "The width did not change. Back pressure compensation doesn't adjust line width.";
EXPECT_NEAR(original_speeds[i], extruder_plan.paths[i].speed_factor, error_margin) << "The speed factor did not change, since the compensation factor was 0.";
}
}
@@ -285,7 +288,7 @@ TEST_P(ExtruderPlanPathsParameterizedTest, BackPressureCompensationFull)
return;
}
//All flow rates must be equal to this one.
- const double first_flow_mm3_per_sec = calculatePathFlow(*first_extrusion);
+ const double first_flow_mm3_per_sec = calculatePathWidth(*first_extrusion);
for(GCodePath& path : extruder_plan.paths)
{
@@ -293,7 +296,7 @@ TEST_P(ExtruderPlanPathsParameterizedTest, BackPressureCompensationFull)
{
continue; //Ignore travel moves.
}
- const double flow_mm3_per_sec = calculatePathFlow(path);
+ const double flow_mm3_per_sec = calculatePathWidth(path);
EXPECT_NEAR(flow_mm3_per_sec, first_flow_mm3_per_sec, error_margin) << "Every path must have a flow rate equal to the first, since the flow changes were completely compensated for.";
}
}
@@ -313,7 +316,7 @@ TEST_P(ExtruderPlanPathsParameterizedTest, BackPressureCompensationHalf)
{
continue; //Ignore travel moves.
}
- original_flows.push_back(calculatePathFlow(path));
+ original_flows.push_back(calculatePathWidth(path));
}
const double original_average = std::accumulate(original_flows.begin(), original_flows.end(), 0.0) / original_flows.size();
@@ -328,7 +331,7 @@ TEST_P(ExtruderPlanPathsParameterizedTest, BackPressureCompensationHalf)
{
continue; //Ignore travel moves.
}
- new_flows.push_back(calculatePathFlow(path));
+ new_flows.push_back(calculatePathWidth(path));
}
const double new_average = std::accumulate(new_flows.begin(), new_flows.end(), 0.0) / new_flows.size();
//Note that the new average doesn't necessarily need to be the same average! It is most likely a higher average in real-world scenarios.
@@ -337,7 +340,7 @@ TEST_P(ExtruderPlanPathsParameterizedTest, BackPressureCompensationHalf)
ASSERT_EQ(original_flows.size(), new_flows.size()) << "We need to have the same number of extrusion moves.";
for(size_t i = 0; i < new_flows.size(); ++i)
{
- EXPECT_NEAR((original_flows[i] - original_average) / 2.0, new_flows[i] - new_average, error_margin);
+ EXPECT_NEAR((original_flows[i] - original_average) / 2.0, new_flows[i] - new_average, error_margin) << "The differences in flow rate needs to be approximately halved, within margin of rounding errors.";
}
}
diff --git a/tests/WallsComputationTest.cpp b/tests/WallsComputationTest.cpp
index 925bf5a80..2210240ba 100644
--- a/tests/WallsComputationTest.cpp
+++ b/tests/WallsComputationTest.cpp
@@ -1,4 +1,4 @@
-//Copyright (c) 2021 Ultimaker B.V.
+//Copyright (c) 2022 Ultimaker B.V.
//CuraEngine is released under the terms of the AGPLv3 or higher.
#include <gtest/gtest.h>
@@ -72,7 +72,6 @@ public:
//Settings for a simple 2 walls, about as basic as possible.
settings.add("alternate_extra_perimeter", "false");
- settings.add("beading_strategy_type", "inward_distributed");
settings.add("fill_outline_gaps", "false");
settings.add("initial_layer_line_width_factor", "100");
settings.add("magic_spiralize", "false");
diff --git a/tests/beading_strategy/CenterDeviationBeadingStrategyTest.cpp b/tests/beading_strategy/CenterDeviationBeadingStrategyTest.cpp
deleted file mode 100644
index 6b9f6f35c..000000000
--- a/tests/beading_strategy/CenterDeviationBeadingStrategyTest.cpp
+++ /dev/null
@@ -1,153 +0,0 @@
-//Copyright (c) 2021 Ultimaker B.V.
-//CuraEngine is released under the terms of the AGPLv3 or higher.
-
-#include <gtest/gtest.h>
-
-#include "../../src/BeadingStrategy/CenterDeviationBeadingStrategy.h" //Code under test.
-
-namespace cura
-{
-
-/*!
- * Tests calling the constructor of the CenterDeviationBeadingStrategy and
- * whether it sets members correctly.
- */
-TEST(CenterDeviationBeadingStrategy, Construction)
-{
- CenterDeviationBeadingStrategy strategy(400, 0.6, 0.5, 0.75);
- EXPECT_EQ(strategy.getSplitMiddleThreshold(), 0.5) << "Split-middle threshold should be the one it's constructed with.";
- EXPECT_EQ(strategy.getAddMiddleThreshold(), 0.75) << "Add-middle threshold should be the one it's constructed with.";
-}
-
-/*!
- * Tests getting the optimal thickness with Center Deviation.
- *
- * This should simply be a multiplication of the line width, when using Center
- * Deviation. It doesn't adjust the line widths by itself.
- */
-TEST(CenterDeviationBeadingStrategy, GetOptimalThickness)
-{
- constexpr coord_t line_width = 400;
- CenterDeviationBeadingStrategy strategy(line_width, 0.6, 0.5, 0.5);
- EXPECT_EQ(strategy.getOptimalThickness(0), 0) << "With 0 beads, you'll fill 0 space.";
- EXPECT_EQ(strategy.getOptimalThickness(1), line_width) << "With 1 bead, optimally you'll want to print that bead at the optimal line width.";
- EXPECT_EQ(strategy.getOptimalThickness(4), 4 * line_width) << "With 4 beads, optimally fill 4 line widths.";
-}
-
-/*!
- * Test getting the width at which we need to transition to a greater number of
- * lines.
- */
-TEST(CenterDeviationBeadingStrategy, GetTransitionThickness)
-{
- constexpr coord_t line_width = 400;
-
- //Transition ratio 25%.
- CenterDeviationBeadingStrategy strategy(line_width, 0.6, 0.25, 0.25);
- EXPECT_EQ(strategy.getTransitionThickness(0), 0.25 * line_width) << "The transition from 0 beads to 1 happens at 25% line width.";
- EXPECT_EQ(strategy.getTransitionThickness(1), 1.25 * line_width) << "The transition from 1 bead to 2 happens at 125% line width.";
- EXPECT_EQ(strategy.getTransitionThickness(4), 4.25 * line_width) << "The transition from 4 beads to 5 happens at 4 + 25% line width.";
-
- //Transition ratio 50%.
- strategy = CenterDeviationBeadingStrategy(line_width, 0.6, 0.5, 0.5);
- EXPECT_EQ(strategy.getTransitionThickness(0), 0.5 * line_width) << "The transition from 0 beads to 1 happens at 50% line width.";
- EXPECT_EQ(strategy.getTransitionThickness(1), 1.5 * line_width) << "The transition from 1 bead to 2 happens at 150% line width.";
- EXPECT_EQ(strategy.getTransitionThickness(5), 5.5 * line_width) << "The transition from 5 beads to 6 happens at 5 + 50% line width.";
-
- //Transition ratio 95%.
- strategy = CenterDeviationBeadingStrategy(line_width, 0.6, 0.95, 0.95);
- EXPECT_EQ(strategy.getTransitionThickness(0), 0.95 * line_width) << "The transition from 0 beads to 1 happens at 95% line width.";
- EXPECT_EQ(strategy.getTransitionThickness(1), 1.95 * line_width) << "The transition from 1 bead to 2 happens at 195% line width.";
- EXPECT_EQ(strategy.getTransitionThickness(3), 3.95 * line_width) << "The transition from 3 beads to 4 happens at 3 + 95% line width.";
-
- //Transition ratio 100%.
- strategy = CenterDeviationBeadingStrategy(line_width, 0.6, 1, 1);
- EXPECT_EQ(strategy.getTransitionThickness(0), line_width) << "Only transition to have a line if it fits completely.";
- EXPECT_EQ(strategy.getTransitionThickness(1), 2 * line_width) << "Only transition to have two lines if they both fit completely.";
- EXPECT_EQ(strategy.getTransitionThickness(2), 3 * line_width) << "Only transition to have three lines if they all fit completely.";
-
- //Transition ratio 0%.
- strategy = CenterDeviationBeadingStrategy(line_width, 0.6, 0, 0);
- EXPECT_EQ(strategy.getTransitionThickness(0), 0) << "Always transition to 1 line. The minimum line width is 0 after all.";
- EXPECT_EQ(strategy.getTransitionThickness(1), line_width) << "If 1 line fits completely, immediately transition to 2 lines.";
- EXPECT_EQ(strategy.getTransitionThickness(6), 6 * line_width) << "If 6 lines fit completely, immediately transition to 7 lines.";
-}
-
-/*!
- * Test getting the optimal bead count for a given shape width.
- */
-TEST(CenterDeviationBeadingStrategy, GetOptimalBeadCount)
-{
- constexpr coord_t line_width = 400;
-
- //Transition ratio 25%.
- CenterDeviationBeadingStrategy strategy(line_width, 0.6, 0.25, 0.25);
- //Anything below 25% line width should then produce 0 lines.
- for(coord_t width = 0; width < 0.25 * line_width; width += 10)
- {
- EXPECT_EQ(strategy.getOptimalBeadCount(width), 0) << "Width is below the transition thickness from 0 to 1 line, so it should produce 0 lines.";
- }
- EXPECT_LE(strategy.getOptimalBeadCount(0.25 * line_width), 1) << "At exactly the transition thickness, either 0 or 1 line is acceptable.";
- for(coord_t width = 0.25 * line_width + 1; width < 1.25 * line_width; width += 10)
- {
- EXPECT_EQ(strategy.getOptimalBeadCount(width), 1) << "Width is above the transition thickness from 0 to 1 line but below 1 to 2 lines, so it should produce 1 line.";
- }
- EXPECT_TRUE(strategy.getOptimalBeadCount(1.25 * line_width) == 1 || strategy.getOptimalBeadCount(1.25 * line_width) == 2) << "At exactly 125% line width, either 1 or 2 lines is acceptable.";
- for(coord_t width = 1.25 * line_width + 1; width < 2.25 * line_width; width += 10)
- {
- EXPECT_EQ(strategy.getOptimalBeadCount(width), 2) << "Width is above the transition thickness from 1 to 2 lines but below 2 to 3 lines, so it should produce 2 lines.";
- }
-
- //Transition ratio 80%.
- strategy = CenterDeviationBeadingStrategy(line_width, 0.6, 0.8, 0.8);
- //Anything below 80% line width should then produce 0 lines.
- for(coord_t width = 0; width < 0.8 * line_width; width += 10)
- {
- EXPECT_EQ(strategy.getOptimalBeadCount(width), 0) << "Width is below the transition thickness from 0 to 1 line, so it should produce 0 lines.";
- }
- EXPECT_LE(strategy.getOptimalBeadCount(0.8 * line_width), 1) << "At exactly the transition thickness, either 0 or 1 line is acceptable.";
- for(coord_t width = 0.8 * line_width + 1; width < 1.8 * line_width; width += 10)
- {
- EXPECT_EQ(strategy.getOptimalBeadCount(width), 1) << "Width is above the transition thickness from 0 to 1 line but below 1 to 2 lines, so it should produce 1 line.";
- }
- EXPECT_TRUE(strategy.getOptimalBeadCount(1.8 * line_width) == 1 || strategy.getOptimalBeadCount(1.8 * line_width) == 2) << "At exactly 180% line width, either 1 or 2 lines is acceptable.";
- for(coord_t width = 1.8 * line_width + 1; width < 2.8 * line_width; width += 10)
- {
- EXPECT_EQ(strategy.getOptimalBeadCount(width), 2) << "Width is above the transition thickness from 1 to 2 lines but below 2 to 3 lines, so it should produce 2 lines.";
- }
-}
-
-/*!
- * Tests whether the line compactness setting does what it is supposed to do,
- * producing fewer, wider lines when the setting is high than when the setting
- * is low.
- *
- * This is a test for requirements. The exact outcome of a function is not
- * tested, but properties of the outcome is tested.
- */
-TEST(CenterDeviationBeadingStrategy, LineCompactnessMonotonic)
-{
- constexpr coord_t line_width = 400;
- constexpr coord_t widths[] = {0, 1, 99, 101, 150, 200, 299, 300, 301, 399, 400, 401, 410, 450, 500, 660, 770, 880, 910, 1000, 1200}; //Bunch of widths to test with.
- constexpr float compactnesses[] = {0, 0.1, 0.2, 0.24, 0.25, 0.26, 0.3, 0.5, 0.7, 0.75, 0.99, 1}; //Bunch of line compactness factors to test with.
- constexpr size_t num_compactnesses = sizeof(compactnesses) / sizeof(float);
-
- for(coord_t width : widths)
- {
- for(size_t low_index = 0; low_index < num_compactnesses; ++low_index)
- {
- const float low_compactness = compactnesses[low_index];
- for(size_t high_index = low_index; high_index < num_compactnesses; ++high_index)
- {
- const float high_compactness = compactnesses[high_index];
-
- EXPECT_GE(
- CenterDeviationBeadingStrategy(line_width, 0.6, low_compactness, low_compactness).getOptimalBeadCount(width),
- CenterDeviationBeadingStrategy(line_width, 0.6, high_compactness, high_compactness).getOptimalBeadCount(width)
- ) << "When the compactness is low, the number of beads should always be greater or equal to when the compactness is high.";
- }
- }
- }
-}
-
-} \ No newline at end of file
diff --git a/tests/utils/ExtrusionLineTest.cpp b/tests/utils/ExtrusionLineTest.cpp
index d26820a98..100ae790f 100644
--- a/tests/utils/ExtrusionLineTest.cpp
+++ b/tests/utils/ExtrusionLineTest.cpp
@@ -8,6 +8,7 @@
#include <../src/utils/linearAlg2D.h>
#include <limits>
+#include <numeric>
namespace cura
{
@@ -405,36 +406,39 @@ namespace cura
TEST(ExtrusionLineTest, simplifyLineWidthVariance)
{
//Generate a line with several vertices halfway.
- constexpr coord_t spacing = 100;
- ExtrusionLine colinear_polylines(0, false);;
+ ExtrusionLine colinear_polylines(0, false);
auto& colinear = colinear_polylines.junctions;
colinear.emplace_back(Point(0, 0), 200, 0);
- colinear.emplace_back(Point(spacing / 4, 0), 200, 0);
- colinear.emplace_back(Point(spacing / 2, 0), 400, 0);
- colinear.emplace_back(Point(spacing / 2 + spacing / 4, 0), 600, 0);
- colinear.emplace_back(Point(spacing, 0), 800, 0);
+ colinear.emplace_back(Point(500, 0), 200, 0);
+ colinear.emplace_back(Point(1000, 0), 400, 0);
+ colinear.emplace_back(Point(1500, 0), 600, 0);
+ colinear.emplace_back(Point(2000, 0), 800, 0);
+
+ // Get 'before' average width:
+ coord_t averge_width_before = 0;
+ for (size_t i_junction = 0; i_junction < (colinear.size() - 1); ++i_junction)
+ {
+ averge_width_before += ((colinear[i_junction].w + colinear[i_junction + 1].w) / 2) * vSize(colinear[i_junction].p - colinear[i_junction + 1].p);
+ }
- colinear_polylines.simplify(25 * 25, 25 * 25, std::numeric_limits<coord_t>::max());
+ colinear_polylines.simplify(20 * 20, 5 * 5, std::numeric_limits<coord_t>::max()); //Regardless of parameters, it should always remove those middle vertices.
ASSERT_EQ(colinear_polylines.junctions.size(), 2) << "The degenerate vertices should have been removed.";
- ASSERT_EQ(colinear[1].w, 500) << "The width of the end-junction should be the average of all removed."; // Since the distances where equal, and they should all have been merged with that one.
}
TEST(ExtrusionLineTest, simplifyNoLineWidthVariance)
{
//Generate a line with several vertices halfway.
- constexpr coord_t spacing = 100;
- ExtrusionLine colinear_polylines(0, false);;
+ ExtrusionLine colinear_polylines(0, false);
auto& colinear = colinear_polylines.junctions;
colinear.emplace_back(Point(0, 0), 200, 0);
- colinear.emplace_back(Point(spacing / 4, 0), 200, 0);
- colinear.emplace_back(Point(spacing / 2, 0), 400, 0);
- colinear.emplace_back(Point(spacing / 2 + spacing / 4, 0), 600, 0);
- colinear.emplace_back(Point(spacing, 0), 800, 0);
+ colinear.emplace_back(Point(500, 0), 200, 0);
+ colinear.emplace_back(Point(1000, 0), 400, 0);
+ colinear.emplace_back(Point(1500, 0), 600, 0);
+ colinear.emplace_back(Point(2000, 0), 800, 0);
- colinear_polylines.simplify(25 * 25, 25 * 25, 1);
+ colinear_polylines.simplify(20 * 20, 5 * 5, 1); // Now it should _not_ remove the vertices, since the total width altered will be more than the max area ...
ASSERT_EQ(colinear_polylines.junctions.size(), 5) << "No junctions should have been removed."; // ... even though they are co-linear!
- ASSERT_EQ(colinear.back().w, 800) << "The width of the end-junction should not have been changed.";
}
}