Skip to content
Open
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ option(ENABLE_MORE_COMPILER_OPTIMIZATION_FLAGS "Enable more optimization flags"
option(USE_SYSTEM_LIBS "Use the system libraries if available" OFF)
option(OLDER_APPLE_CLANG "Apple Clang <= 13 used" OFF)
option(ENABLE_THREADING "Enable threading support" ON)
option(ENABLE_CURAVIZ "Build with CuraViz toolbox" ON)
option(ENABLE_CURAVIZ "Build with CuraViz toolbox" OFF)

if (${ENABLE_ARCUS} OR ${ENABLE_PLUGINS} OR ${ENABLE_CURAVIZ})
find_package(protobuf REQUIRED)
Expand Down
3 changes: 1 addition & 2 deletions include/FffGcodeWriter.h
Original file line number Diff line number Diff line change
Expand Up @@ -105,8 +105,7 @@ class FffGcodeWriter : public NoCopy
struct ProcessLayerResult
{
LayerPlan* layer_plan;
double total_elapsed_time;
TimeKeeper::RegisteredTimes stages_times;
TimeKeeper time_keeper;
};

struct RoofingFlooringSettingsNames
Expand Down
4 changes: 3 additions & 1 deletion include/TreeModelVolumes.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ class SliceDataStorage;
class SliceMeshStorage;
class LayerIndex;
class Settings;
class TimeKeeper;

/*!
* \brief Lazily generates tree guidance volumes.
Expand All @@ -51,12 +52,13 @@ class TreeModelVolumes

/*!
* \brief Precalculate avoidances and collisions up to this layer.
* \param time_keeper The object used to record the duration of the sub-steps
*
* This uses knowledge about branch angle to only calculate avoidances and collisions that could actually be needed.
* Not calling this will cause the class to lazily calculate avoidances and collisions as needed, which will be a lot slower on systems with more then one or two cores!
*
*/
void precalculate(coord_t max_layer);
void precalculate(coord_t max_layer, TimeKeeper& time_keeper);

/*!
* \brief Provides the areas that have to be avoided by the tree's branches to prevent collision with the model on this layer.
Expand Down
16 changes: 13 additions & 3 deletions include/TreeSupport.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ namespace cura
{

class OBJ;
class TimeKeeper;

// The various stages of the process can be weighted differently in the progress bar.
// These weights are obtained experimentally using a small sample size. Sensible weights can differ drastically based on the assumed default settings and model.
Expand Down Expand Up @@ -101,9 +102,10 @@ class TreeSupport
*
* \param storage[in] Background storage to access meshes.
* \param currently_processing_meshes[in] Indexes of all meshes that are processed in this iteration
* \param time_keeper The object used to record the duration of the sub-steps
* \return Uppermost layer precalculated. -1 if no layer were precalculated as no overhang is present.
*/
LayerIndex precalculate(const SliceDataStorage& storage, std::vector<size_t> currently_processing_meshes);
LayerIndex precalculate(const SliceDataStorage& storage, std::vector<size_t> currently_processing_meshes, TimeKeeper& time_keeper);


/*!
Expand Down Expand Up @@ -226,8 +228,9 @@ class TreeSupport
* \brief Propagates influence downwards, and merges overlapping ones.
*
* \param move_bounds[in,out] All currently existing influence areas
* \param time_keeper The object used to record the duration of the sub-steps
*/
void createLayerPathing(std::vector<std::set<TreeSupportElement*>>& move_bounds);
void createLayerPathing(std::vector<std::set<TreeSupportElement*>>& move_bounds, TimeKeeper& time_keeper);


/*!
Expand Down Expand Up @@ -274,6 +277,12 @@ class TreeSupport
*/
void smoothBranchAreas(std::vector<std::unordered_map<TreeSupportElement*, Shape>>& layer_tree_polygons);

/*!
* Smoothes the skeleton of the tree structure according to the smoothing factor
* @param layer_tree_polygons The base tree structure to be smoothed
*/
void smoothBranchSkeletons(std::vector<std::set<TreeSupportElement*>>& layer_tree_polygons);

/*!
* \brief Drop down areas that do rest non-gracefully on the model to ensure the branch actually rests on something.
*
Expand Down Expand Up @@ -309,8 +318,9 @@ class TreeSupport
*
* \param move_bounds[in] All currently existing influence areas
* \param storage[in,out] The storage where the support should be stored.
* \param time_keeper The object used to record the duration of the sub-steps
*/
void drawAreas(std::vector<std::set<TreeSupportElement*>>& move_bounds, SliceDataStorage& storage);
void drawAreas(std::vector<std::set<TreeSupportElement*>>& move_bounds, SliceDataStorage& storage, TimeKeeper& time_keeper);

/*!
* Saves the influence areas and the resulting positions of all the given elements to a 3D object
Expand Down
34 changes: 27 additions & 7 deletions include/TreeSupportElement.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,9 @@ struct AreaIncreaseSettings
bool operator==(const AreaIncreaseSettings& other) const = default;
};

struct TreeSupportElement
class TreeSupportElement
{
public:
TreeSupportElement(
coord_t distance_to_top,
size_t target_height,
Expand Down Expand Up @@ -104,7 +105,20 @@ struct TreeSupportElement
return other.target_position_.X == target_position_.X ? other.target_position_.Y < target_position_.Y : other.target_position_.X < target_position_.X;
}

void AddParents(const std::vector<TreeSupportElement*>& adding);
/*! \brief Gets the list of parent elements, which are those above the current element */
const std::vector<TreeSupportElement*>& getParents() const
{
return parents_;
}

/*! \brief Adds the given elements to be parents of the current element. Parents will also be properly modified to have the element as a child. */
void addParents(const std::vector<TreeSupportElement*>& new_parents);

/*! \brief Gets the child element, which is the one beloe the current element. It could also be null if the element lies on the buildplate or on the model */
TreeSupportElement* getChild() const
{
return child_;
}

void RecreateInfluenceLimitArea();

Expand Down Expand Up @@ -156,11 +170,6 @@ struct TreeSupportElement

bool to_buildplate_;

/*!
* \brief All elements in the layer above the current one that are supported by this element
*/
std::vector<TreeSupportElement*> parents_;

/*!
* \brief The amount of layers this element is below the topmost layer of this branch.
*/
Expand Down Expand Up @@ -250,6 +259,17 @@ struct TreeSupportElement
* \brief Additional locations that the tip should reach
*/
std::vector<Point2LL> additional_ovalization_targets_;

private:
/*!
* \brief All elements in the layer above the current one that are supported by this element
*/
std::vector<TreeSupportElement*> parents_;

/*!
* \brief The element in the layer below that is supporting this element
*/
TreeSupportElement* child_{ nullptr };
};

} // namespace cura
Expand Down
8 changes: 7 additions & 1 deletion include/TreeSupportSettings.h
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ struct TreeSupportSettings
, min_feature_size(mesh_group_settings.get<coord_t>("min_feature_size"))
, min_wall_line_width(settings.get<coord_t>("min_wall_line_width"))
, fill_outline_gaps(settings.get<bool>("fill_outline_gaps"))
, support_tree_smooth_layers(settings.get<size_t>("support_tree_smooth_layers"))
, simplifier(Simplify(mesh_group_settings))
{
layer_start_bp_radius = (bp_radius - branch_radius) / (branch_radius * diameter_scale_bp_radius);
Expand Down Expand Up @@ -383,6 +384,11 @@ struct TreeSupportSettings
*/
bool fill_outline_gaps;

/*!
* \brief Number of layers on which to smooth the tree support branches
*/
size_t support_tree_smooth_layers;

/*!
* \brief Simplifier to simplify polygons.
*/
Expand Down Expand Up @@ -412,7 +418,7 @@ struct TreeSupportSettings
&& zag_skip_count == other.zag_skip_count && connect_zigzags == other.connect_zigzags && interface_preference == other.interface_preference
&& min_feature_size == other.min_feature_size && // interface_preference should be identical to ensure the tree will correctly interact with the roof.
support_rest_preference == other.support_rest_preference && max_radius == other.max_radius && min_wall_line_width == other.min_wall_line_width
&& fill_outline_gaps == other.fill_outline_gaps &&
&& fill_outline_gaps == other.fill_outline_gaps && support_tree_smooth_layers == other.support_tree_smooth_layers &&
// The infill class now wants the settings object and reads a lot of settings, and as the infill class is used to calculate support roof lines for
// interface-preference. Not all of these may be required to be identical, but as I am not sure, better safe than sorry
(interface_preference == InterfacePreference::INTERFACE_AREA_OVERWRITES_SUPPORT || interface_preference == InterfacePreference::SUPPORT_AREA_OVERWRITES_INTERFACE
Expand Down
5 changes: 2 additions & 3 deletions include/progress/Progress.h
Original file line number Diff line number Diff line change
Expand Up @@ -91,12 +91,11 @@ class Progress
*
* \param layer_nr The processed layer number
* \param total_layers The total number of layers to be processed
* \param total_time The total layer processing time, in seconds
* \param stage The detailed stages time reporting for this layer
* \param time_keeper The time keeper containing the detailed stages time reporting for this layer
* \param skip_threshold The time threshold under which we consider that the full layer time reporting should be skipped
* because it is not relevant
*/
static void messageProgressLayer(LayerIndex layer_nr, size_t total_layers, double total_time, const TimeKeeper::RegisteredTimes& stages, double skip_threshold = 0.1);
static void messageProgressLayer(const LayerIndex layer_nr, const size_t total_layers, const TimeKeeper& time_keeper, const std::chrono::milliseconds skip_threshold = 100ms);
};


Expand Down
17 changes: 13 additions & 4 deletions include/utils/gettime.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@

#include <spdlog/stopwatch.h>

using namespace std::chrono_literals;

namespace cura
{

Expand All @@ -19,27 +21,34 @@ class TimeKeeper
struct RegisteredTime
{
std::string stage;
double duration;
std::chrono::milliseconds duration;
};

using RegisteredTimes = std::vector<RegisteredTime>;

private:
spdlog::stopwatch watch;
double start_time;
spdlog::stopwatch watch_total;
RegisteredTimes registered_times;
std::chrono::milliseconds total_duration;

public:
TimeKeeper();

double restart();
std::chrono::milliseconds restart();

void registerTime(const std::string& stage, double threshold = 0.01);
void registerTime(const std::string& stage, const std::chrono::milliseconds threshold = 10ms, const std::optional<std::chrono::milliseconds> duration = std::nullopt);

const RegisteredTimes& getRegisteredTimes() const
{
return registered_times;
}

void end();

std::chrono::milliseconds getTotalDuration() const;

void logRegisteredTimes(const std::string& global_desc) const;
};

} // namespace cura
Expand Down
7 changes: 4 additions & 3 deletions src/FffGcodeWriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ void FffGcodeWriter::writeGCode(SliceDataStorage& storage, TimeKeeper& time_keep
[this, total_layers](std::optional<ProcessLayerResult> result_opt)
{
const ProcessLayerResult& result = result_opt.value();
Progress::messageProgressLayer(result.layer_plan->getLayerNr(), total_layers, result.total_elapsed_time, result.stages_times);
Progress::messageProgressLayer(result.layer_plan->getLayerNr(), total_layers, result.time_keeper);
layer_plan_buffer.handle(*result.layer_plan, gcode);
print_info_.updateWithLayer(result.layer_plan);
});
Expand Down Expand Up @@ -1130,7 +1130,6 @@ FffGcodeWriter::ProcessLayerResult FffGcodeWriter::processLayer(const SliceDataS
{
spdlog::debug("GcodeWriter processing layer {} of {}", layer_nr, total_layers);
TimeKeeper time_keeper;
spdlog::stopwatch timer_total;

const Settings& mesh_group_settings = Application::getInstance().current_slice_->scene.current_mesh_group->settings;
coord_t layer_thickness = mesh_group_settings.get<coord_t>("layer_height");
Expand Down Expand Up @@ -1288,7 +1287,9 @@ FffGcodeWriter::ProcessLayerResult FffGcodeWriter::processLayer(const SliceDataS
gcode_layer.applyBackPressureCompensation();
time_keeper.registerTime("Back pressure comp.");

return { &gcode_layer, timer_total.elapsed().count(), time_keeper.getRegisteredTimes() };
time_keeper.end();

return { &gcode_layer, time_keeper };
}

bool FffGcodeWriter::getExtruderNeedPrimeBlobDuringFirstLayer(const SliceDataStorage& storage, const size_t extruder_nr) const
Expand Down
3 changes: 2 additions & 1 deletion src/MeshGroup.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include <stdio.h>
#include <string.h>

#include <fmt/chrono.h>
#include <fmt/format.h>
#include <range/v3/algorithm/transform.hpp>
#include <range/v3/view/enumerate.hpp>
Expand Down Expand Up @@ -577,7 +578,7 @@ bool loadMeshIntoMeshGroup(MeshGroup* meshgroup, const fs::path& filename, const
}
}

spdlog::info("loading '{}' took {:03.3f} seconds", filename.string(), load_timer.restart());
spdlog::info("loading '{}' took {}", filename.string(), std::chrono::duration<double>(load_timer.restart()));

mesh.mesh_name_ = base_filename.string();
meshgroup->meshes.push_back(mesh);
Expand Down
5 changes: 3 additions & 2 deletions src/Scene.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

#include "Scene.h"

#include <fmt/chrono.h>
#include <spdlog/spdlog.h>

#include "Application.h"
Expand Down Expand Up @@ -81,7 +82,7 @@ void Scene::processMeshGroup(MeshGroup& mesh_group)
if (empty)
{
Progress::messageProgress(Progress::Stage::FINISH, 1, 1); // 100% on this meshgroup
spdlog::info("Total time elapsed {:03.3f}s", time_keeper_total.restart());
spdlog::info("Total time elapsed {}", std::chrono::duration<double>(time_keeper_total.restart()));
return;
}

Expand All @@ -96,7 +97,7 @@ void Scene::processMeshGroup(MeshGroup& mesh_group)

Progress::messageProgress(Progress::Stage::FINISH, 1, 1); // 100% on this meshgroup
Application::getInstance().communication_->sendOptimizedLayerData();
spdlog::info("Total time elapsed {:03.3f}s\n", time_keeper_total.restart());
spdlog::info("Total time elapsed {}\n", std::chrono::duration<double>(time_keeper_total.restart()));
}

} // namespace cura
27 changes: 5 additions & 22 deletions src/TreeModelVolumes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -169,9 +169,8 @@ TreeModelVolumes::TreeModelVolumes(
simplifier_ = Simplify(min_maximum_resolution, min_maximum_deviation, min_maximum_area_deviation);
}

void TreeModelVolumes::precalculate(coord_t max_layer)
void TreeModelVolumes::precalculate(coord_t max_layer, TimeKeeper& time_keeper)
{
const auto t_start = std::chrono::high_resolution_clock::now();
precalculated_ = true;

// Get the config corresponding to one mesh that is in the current group. Which one has to be irrelevant.
Expand Down Expand Up @@ -264,15 +263,13 @@ void TreeModelVolumes::precalculate(coord_t max_layer)

// ### Calculate collisions without holes, build from regular collision
calculateCollisionHolefree(relevant_hole_collision_radiis);

const auto t_coll = std::chrono::high_resolution_clock::now();
auto t_acc = std::chrono::high_resolution_clock::now();
time_keeper.registerTime("Pre-calculate collision");


if (max_layer_idx_without_blocker_ < max_layer && support_rests_on_model_)
{
calculateAccumulatedPlaceable0(max_layer);
t_acc = std::chrono::high_resolution_clock::now();
time_keeper.registerTime("Pre-calculate avoidance");
}

// ### Calculate the relevant avoidances in parallel as far as possible
Expand Down Expand Up @@ -302,30 +299,16 @@ void TreeModelVolumes::precalculate(coord_t max_layer)
}
// FIXME: When nowait (parellel-for) is implemented, ensure here the following is calculated: calculateWallRestrictions.
}
const auto t_avo = std::chrono::high_resolution_clock::now();
time_keeper.registerTime("Pre-calculate accumulated Placeables");

auto t_colAvo = std::chrono::high_resolution_clock::now();
if (max_layer_idx_without_blocker_ < max_layer && support_rests_on_model_)
{
// FIXME: When nowait (parellel-for) is implemented, ensure here the following is calculated: calculateAccumulatedPlaceable0.
calculateCollisionAvoidance(relevant_avoidance_radiis);
t_colAvo = std::chrono::high_resolution_clock::now();
time_keeper.registerTime("Pre-calculate collision-avoidance");
}

precalculation_finished_ = true;
const auto dur_col = 0.001 * std::chrono::duration_cast<std::chrono::microseconds>(t_coll - t_start).count();
const auto dur_acc = 0.001 * std::chrono::duration_cast<std::chrono::microseconds>(t_acc - t_coll).count();
const auto dur_avo = 0.001 * std::chrono::duration_cast<std::chrono::microseconds>(t_avo - t_acc).count();
const auto dur_col_avo = 0.001 * std::chrono::duration_cast<std::chrono::microseconds>(t_colAvo - t_avo).count();


spdlog::info(
"Pre-calculating collision took {} ms. Pre-calculating avoidance took {} ms. Pre-calculating accumulated Placeables with radius 0 took {} ms. Pre-calculating "
"collision-avoidance took {} ms. ",
dur_col,
dur_avo,
dur_acc,
dur_col_avo);
}

const Shape& TreeModelVolumes::getCollision(coord_t radius, LayerIndex layer_idx, bool min_xy_dist)
Expand Down
Loading
Loading