Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
6ef4e96
Split up parts into top/bottom/side if the wall-count is different.
rburema Apr 30, 2025
694cb2b
Small refactor: DRY up getting top/bottom layer outline diffs.
rburema Apr 30, 2025
fd1c224
Use the previously re-split parts to get the correct wall-count.
rburema Apr 30, 2025
10d773d
Apply clang-format
rburema Apr 30, 2025
b21f96c
Make the previously 'bottom' wall line count only apply to initial.
rburema May 6, 2025
d06800f
Clean up function that was only used class-internally.
rburema May 6, 2025
0229ab2
Fix top/initial wall count issues w.r.t. sloped walls.
rburema May 6, 2025
39faff4
Apply clang-format
rburema May 6, 2025
65d65e4
Better variable/enum names (code review comments).
rburema May 7, 2025
0d0c936
Apply code-review suggestions.
rburema May 7, 2025
4dd0c87
Apply clang-format
rburema May 7, 2025
8d5e5aa
Merge branch 'main' into CURA-12446_top_bottom_wall_count_new
HellAholic May 9, 2025
86e8778
Apply roofing area extension
wawanbreton Jun 5, 2025
aed8b18
Merge branch 'main' into CURA-12446_top_bottom_wall_count_new
HellAholic Jun 19, 2025
017c433
Merge remote-tracking branch 'origin/5.11' into CURA-12446_top_bottom…
wawanbreton Oct 9, 2025
08633e2
Revert "Apply roofing area extension"
wawanbreton Oct 10, 2025
5b3d989
Apply roofing extension differently
wawanbreton Oct 10, 2025
d93c09c
Apply roofing extension only when enabled
wawanbreton Oct 10, 2025
a461db3
Apply roofing extension in a safer way
wawanbreton Oct 10, 2025
8cefcfc
Really disable small skin on surface when it is disabled
wawanbreton Oct 10, 2025
97d783f
Set proper method definition
wawanbreton Oct 10, 2025
458cd00
Avoid top surfaces to grow from the outside of the model
wawanbreton Oct 13, 2025
c04a924
Optimize function by moving fixed calculations out of the loop
wawanbreton Oct 13, 2025
2c66ce4
Add documentation image
wawanbreton Oct 13, 2025
36b5b61
Merge remote-tracking branch 'origin/main' into CURA-12446_top_bottom…
wawanbreton Jan 22, 2026
37594a1
(WIP) different approach to customizable flooring walls count
wawanbreton Jan 23, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ set(engine_SRCS # Except main.cpp.
src/Scene.cpp
src/SkeletalTrapezoidation.cpp
src/SkeletalTrapezoidationGraph.cpp
src/skin.cpp
src/SkinInfillAreaComputation.cpp
src/SkirtBrim.cpp
src/SupportInfillPart.cpp
src/Slice.cpp
Expand Down
2 changes: 2 additions & 0 deletions include/FffPolygonGenerator.h
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,8 @@ class FffPolygonGenerator : public NoCopy
*/
void processSkinsAndInfill(SliceMeshStorage& mesh, const LayerIndex layer_nr, bool process_infill);

void processSkinsInfillWalls(SliceMeshStorage& mesh, const LayerIndex layer_nr, bool process_infill);

/*!
* Generate the polygons where the draft screen should be.
*
Expand Down
34 changes: 27 additions & 7 deletions include/skin.h → include/SkinInfillAreaComputation.h
Original file line number Diff line number Diff line change
@@ -1,22 +1,40 @@
// Copyright (c) 2021 Ultimaker B.V.
// Copyright (c) 2026 Ultimaker B.V.
// CuraEngine is released under the terms of the AGPLv3 or higher.

#ifndef SKIN_H
#define SKIN_H
#ifndef SKININFILLAREACOMPUTATION_H
#define SKININFILLAREACOMPUTATION_H

#include <optional>

#include "geometry/Shape.h"
#include "settings/types/LayerIndex.h"
#include "utils/Coord_t.h"

namespace cura
{

class Shape;
class SkinPart;
class SliceLayerPart;
class SliceMeshStorage;

enum class SliceAreaType
{
Roofing,
Flooring,
Skin,
Infill
};

struct SliceArea
{
using Ptr = std::shared_ptr<SliceArea>;

SliceAreaType type{ SliceAreaType::Infill };
Shape outline;
size_t walls{ 0 };
SliceArea::Ptr inner_area; // Inner area that should be also be printed with walls
};

/*!
* Class containing all skin and infill area computation functions
*/
Expand All @@ -40,6 +58,8 @@ class SkinInfillAreaComputation
*/
void generateSkinsAndInfill();

SliceArea::Ptr generateRawAreas(SliceLayerPart& part);

/*!
* \brief Combines the infill of multiple layers for a specified mesh.
*
Expand Down Expand Up @@ -98,7 +118,7 @@ class SkinInfillAreaComputation
* above. The input is the area within the inner walls (or an empty Polygons
* object).
*/
void calculateTopSkin(const SliceLayerPart& part, Shape& upskin);
Shape calculateTopSkin(const SliceLayerPart& part, Shape& upskin, const size_t layer_count);

/*!
* \brief Calculate the basic areas which have air below.
Expand All @@ -107,7 +127,7 @@ class SkinInfillAreaComputation
* layers above. The input is the area within the inner walls (or an empty
* Polygons object).
*/
void calculateBottomSkin(const SliceLayerPart& part, Shape& downskin);
void calculateBottomSkin(const SliceLayerPart& part, Shape& downskin, const size_t layer_count);

/*!
* Apply skin expansion:
Expand Down Expand Up @@ -194,4 +214,4 @@ class SkinInfillAreaComputation

} // namespace cura

#endif // SKIN_H
#endif
20 changes: 4 additions & 16 deletions include/layerPart.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//Copyright (c) 2018 Ultimaker B.V.
//CuraEngine is released under the terms of the AGPLv3 or higher.
// Copyright (c) 2025 UltiMaker
// CuraEngine is released under the terms of the AGPLv3 or higher.

#ifndef LAYERPART_H
#define LAYERPART_H
Expand All @@ -19,28 +19,16 @@ It's also the first step that stores the result in the "data storage" so all oth
namespace cura
{

class Settings;
class SliceLayer;
class Slicer;
class SlicerLayer;
class SliceMeshStorage;

/*!
* \brief Split a layer into parts.
* \param settings The settings to get the settings from (whether to union or
* not).
* \param storageLayer Where to store the parts.
* \param layer The layer to split.
*/
void createLayerWithParts(const Settings& settings, SliceLayer& storageLayer, SlicerLayer* layer);

/*!
* \brief Split all layers into parts.
* \param mesh The mesh of which to split the layers into parts.
* \param slicer The slicer to get the layers from.
*/
void createLayerParts(SliceMeshStorage& mesh, Slicer* slicer);

}//namespace cura
} // namespace cura

#endif//LAYERPART_H
#endif // LAYERPART_H
8 changes: 8 additions & 0 deletions include/sliceDataStorage.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,14 @@ class SkinPart
class SliceLayerPart
{
public:
enum class WallExposedType
{
LAYER_0,
ROOFING,
SIDE_ONLY,
};
WallExposedType wall_exposed = WallExposedType::SIDE_ONLY;

AABB boundaryBox; //!< The boundaryBox is an axis-aligned boundary box which is used to quickly check for possible
//!< collision between different parts on different layers. It's an optimization used during
//!< skin calculations.
Expand Down
62 changes: 43 additions & 19 deletions src/FffPolygonGenerator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
#include "multiVolumes.h"
#include "PrintFeature.h"
#include "raft.h"
#include "skin.h"
#include "SkinInfillAreaComputation.h"
#include "SkirtBrim.h"
#include "Slice.h"
#include "TextureDataProvider.h"
Expand Down Expand Up @@ -452,9 +452,9 @@ void FffPolygonGenerator::processBasicWallsSkinInfill(
const std::vector<size_t>& mesh_order,
ProgressStageEstimator& inset_skin_progress_estimate)
{
size_t mesh_idx = mesh_order[mesh_order_idx];
const size_t mesh_idx = mesh_order[mesh_order_idx];
SliceMeshStorage& mesh = *storage.meshes[mesh_idx];
size_t mesh_layer_count = mesh.layers.size();
const size_t mesh_layer_count = mesh.layers.size();
if (mesh.settings.get<bool>("infill_mesh"))
{
processInfillMesh(storage, mesh_order_idx, mesh_order);
Expand Down Expand Up @@ -496,20 +496,6 @@ void FffPolygonGenerator::processBasicWallsSkinInfill(
}
} guarded_progress = { inset_skin_progress_estimate };

// walls
cura::parallel_for<size_t>(
0,
mesh_layer_count,
[&](size_t layer_number)
{
spdlog::debug("Processing insets for layer {} of {}", layer_number, mesh.layers.size());
processWalls(mesh, layer_number);
guarded_progress++;
});

ProgressEstimatorLinear* skin_estimator = new ProgressEstimatorLinear(mesh_layer_count);
mesh_inset_skin_progress_estimator->nextStage(skin_estimator);

bool process_infill = mesh.settings.get<coord_t>("infill_line_distance") > 0;
if (! process_infill)
{ // do process infill anyway if it's modified by modifier meshes
Expand All @@ -530,6 +516,7 @@ void FffPolygonGenerator::processBasicWallsSkinInfill(
}
}


// skin & infill
const Settings& mesh_group_settings = Application::getInstance().current_slice_->scene.current_mesh_group->settings;
bool magic_spiralize = mesh_group_settings.get<bool>("magic_spiralize");
Expand All @@ -539,19 +526,47 @@ void FffPolygonGenerator::processBasicWallsSkinInfill(
mesh_max_initial_bottom_layer_count = std::max(mesh_max_initial_bottom_layer_count, mesh.settings.get<size_t>("initial_bottom_layers"));
}

cura::parallel_for<size_t>(
0,
mesh_layer_count,
[&](size_t layer_number)
{
spdlog::debug("Processing skins and infill layer {} of {}", layer_number, mesh.layers.size());
if (! magic_spiralize || layer_number < mesh_max_initial_bottom_layer_count) // Only generate up/down skin and infill for the first X layers when spiralize is chosen.
{
processSkinsInfillWalls(mesh, layer_number, process_infill);
}
guarded_progress++;
});

guarded_progress.reset();
cura::parallel_for<size_t>(
0,
mesh_layer_count,
[&](size_t layer_number)
{
spdlog::debug("Processing skins and infill layer {} of {}", layer_number, mesh.layers.size());
if (! magic_spiralize || layer_number < mesh_max_initial_bottom_layer_count) // Only generate up/downskin and infill for the first X layers when spiralize is choosen.
if (! magic_spiralize || layer_number < mesh_max_initial_bottom_layer_count) // Only generate up/down skin and infill for the first X layers when spiralize is chosen.
{
processSkinsAndInfill(mesh, layer_number, process_infill);
}
guarded_progress++;
});

// walls
guarded_progress.reset();
cura::parallel_for<size_t>(
0,
mesh_layer_count,
[&](size_t layer_number)
{
spdlog::debug("Processing insets for layer {} of {}", layer_number, mesh.layers.size());
processWalls(mesh, layer_number);
guarded_progress++;
});

ProgressEstimatorLinear* skin_estimator = new ProgressEstimatorLinear(mesh_layer_count);
mesh_inset_skin_progress_estimator->nextStage(skin_estimator);
}

void FffPolygonGenerator::processInfillMesh(SliceDataStorage& storage, const size_t mesh_order_idx, const std::vector<size_t>& mesh_order)
Expand Down Expand Up @@ -822,6 +837,16 @@ void FffPolygonGenerator::removeEmptyFirstLayers(SliceDataStorage& storage, size
}
}

void FffPolygonGenerator::processSkinsInfillWalls(SliceMeshStorage& mesh, const LayerIndex layer_nr, bool process_infill)
{
SkinInfillAreaComputation skin_infill_area_computation(layer_nr, mesh, process_infill);

for (SliceLayerPart& part : mesh.layers[layer_nr].parts)
{
skin_infill_area_computation.generateRawAreas(part);
}
}

/*
* This function is executed in a parallel region based on layer_nr.
* When modifying make sure any changes does not introduce data races.
Expand Down Expand Up @@ -1200,5 +1225,4 @@ void FffPolygonGenerator::processFuzzyWalls(SliceMeshStorage& mesh)
}
}


} // namespace cura
Loading
Loading