Skip to content
Open
Show file tree
Hide file tree
Changes from 11 commits
Commits
Show all changes
24 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
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
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 @@ -56,6 +56,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
5 changes: 4 additions & 1 deletion src/WallsComputation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,10 @@ WallsComputation::WallsComputation(const Settings& settings, const LayerIndex la
*/
void WallsComputation::generateWalls(SliceLayerPart* part, SectionType section_type)
{
size_t wall_count = settings_.get<size_t>("wall_line_count");
const std::map<SliceLayerPart::WallExposedType, std::string> wall_count_setting_names({ { SliceLayerPart::WallExposedType::LAYER_0, "wall_line_count_layer_0" },
{ SliceLayerPart::WallExposedType::ROOFING, "wall_line_count_roofing" },
{ SliceLayerPart::WallExposedType::SIDE_ONLY, "wall_line_count" } });
size_t wall_count = settings_.get<size_t>(wall_count_setting_names.at(part->wall_exposed));
if (wall_count == 0) // Early out if no walls are to be generated
{
part->print_outline = part->outline;
Expand Down
67 changes: 56 additions & 11 deletions src/layerPart.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) 2023 UltiMaker
// Copyright (c) 2025 UltiMaker
// CuraEngine is released under the terms of the AGPLv3 or higher.

#include "layerPart.h"
Expand Down Expand Up @@ -28,7 +28,16 @@ It's also the first step that stores the result in the "data storage" so all oth
namespace cura
{

void createLayerWithParts(const Settings& settings, SliceLayer& storageLayer, SlicerLayer* layer)
/*!
* \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.
* \param bottom_parts The bottom parts of the layer.
* \param top_parts The top parts of the layer.
*/
void createLayerWithParts(const Settings& settings, SliceLayer& storageLayer, SlicerLayer* layer, const Shape& bottom_parts, const Shape& top_parts)
{
OpenPolylineStitcher::stitch(layer->open_polylines_, storageLayer.open_polylines, layer->polygons_, settings.get<coord_t>("wall_line_width_0"));

Expand Down Expand Up @@ -65,20 +74,51 @@ void createLayerWithParts(const Settings& settings, SliceLayer& storageLayer, Sl
result = layer->polygons_.splitIntoParts(union_layers || union_all_remove_holes);
}

for (auto& part : result)
for (auto& main_part : result)
{
storageLayer.parts.emplace_back();
if (part.empty())
std::map<SliceLayerPart::WallExposedType, std::vector<SingleShape>> parts_by_type = {
{ SliceLayerPart::WallExposedType::LAYER_0, bottom_parts.splitIntoParts() },
{ SliceLayerPart::WallExposedType::ROOFING, top_parts.difference(bottom_parts).splitIntoParts() },
{ SliceLayerPart::WallExposedType::SIDE_ONLY, main_part.difference(bottom_parts).difference(top_parts).splitIntoParts() },
};

for (auto& [wall_exposed, parts] : parts_by_type)
{
continue;
for (auto& part : parts)
{
storageLayer.parts.emplace_back();
if (part.empty())
{
continue;
}
auto& back_part = storageLayer.parts.back();
back_part.wall_exposed = wall_exposed;
back_part.outline = part;
back_part.boundaryBox.calculate(back_part.outline);
if (back_part.outline.empty())
{
storageLayer.parts.pop_back();
}
}
}
storageLayer.parts.back().outline = part;
storageLayer.parts.back().boundaryBox.calculate(storageLayer.parts.back().outline);
if (storageLayer.parts.back().outline.empty())
}
}

Shape getTopOrBottom(int direction, const std::string& setting_name, size_t layer_nr, const std::vector<SlicerLayer>& slayers, const Settings& settings)
{
Shape result;
if (settings.get<size_t>(setting_name) != settings.get<size_t>("wall_line_count") && ! settings.get<bool>("magic_spiralize"))
{
result = slayers[layer_nr].polygons_;
const auto next_layer = layer_nr + direction;
if (next_layer >= 0 && next_layer < slayers.size())
{
storageLayer.parts.pop_back();
constexpr coord_t EPSILON = 5;
const auto wall_line_width = settings.get<coord_t>(layer_nr == 0 ? "wall_line_width_0" : "wall_line_width") - 5;
result = result.offset(-wall_line_width).difference(slayers[next_layer].polygons_).offset(wall_line_width);
}
}
return result;
}

void createLayerParts(SliceMeshStorage& mesh, Slicer* slicer)
Expand All @@ -93,7 +133,12 @@ void createLayerParts(SliceMeshStorage& mesh, Slicer* slicer)
{
SliceLayer& layer_storage = mesh.layers[layer_nr];
SlicerLayer& slice_layer = slicer->layers[layer_nr];
createLayerWithParts(mesh.settings, layer_storage, &slice_layer);
createLayerWithParts(
mesh.settings,
layer_storage,
&slice_layer,
layer_nr == 0 ? getTopOrBottom(-1, "wall_line_count_layer_0", layer_nr, slicer->layers, mesh.settings) : Shape(),
getTopOrBottom(+1, "wall_line_count_roofing", layer_nr, slicer->layers, mesh.settings));
});

for (LayerIndex layer_nr = total_layers - 1; layer_nr >= 0; layer_nr--)
Expand Down