Skip to content

Commit aec02ee

Browse files
authored
CURA-12740 properly handle material painting when object is set to extruder != 1 (#2249)
2 parents 9bf38bc + 9e65bde commit aec02ee

File tree

1 file changed

+49
-37
lines changed

1 file changed

+49
-37
lines changed

src/MeshMaterialSplitter.cpp

Lines changed: 49 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -62,11 +62,11 @@ bool operator==(const ContourKey& key1, const ContourKey& key2)
6262
* @param mesh The mesh to fill the voxels grid with
6363
* @param texture_data_provider The provider containing the painted texture data
6464
* @param voxel_grid The voxels grid to be filled with mesh data
65-
* @param main_extruder The main extruder of the mesh, to be used when we find a texture part that uses a disabled/inexisting extruder
65+
* @param mesh_extruder_nr The main mesh extruder number
6666
* @return True if this generated relevant data for multi-extruder, otherwise this means the mesh is completely filled with only extruder 0 and there is no need to go further on
6767
* trying to calculate the modified meshes.
6868
*/
69-
bool makeVoxelGridFromTexture(const Mesh& mesh, const std::shared_ptr<TextureDataProvider>& texture_data_provider, VoxelGrid& voxel_grid, const size_t main_extruder)
69+
bool makeVoxelGridFromTexture(const Mesh& mesh, const std::shared_ptr<TextureDataProvider>& texture_data_provider, VoxelGrid& voxel_grid, const uint8_t mesh_extruder_nr)
7070
{
7171
boost::concurrent_flat_set<uint8_t> found_extruders;
7272
std::unordered_set<size_t> active_extruders;
@@ -112,7 +112,7 @@ bool makeVoxelGridFromTexture(const Mesh& mesh, const std::shared_ptr<TextureDat
112112
std::optional<uint32_t> extruder_nr = texture_data_provider->getValue(std::get<0>(pixel), std::get<1>(pixel), "extruder");
113113
if (! extruder_nr.has_value() || ! active_extruders.contains(extruder_nr.value()))
114114
{
115-
extruder_nr = main_extruder;
115+
extruder_nr = mesh_extruder_nr;
116116
}
117117

118118
voxel_grid.setOrUpdateOccupation(traversed_voxel, extruder_nr.value());
@@ -122,14 +122,14 @@ bool makeVoxelGridFromTexture(const Mesh& mesh, const std::shared_ptr<TextureDat
122122

123123
if (found_extruders.size() == 1)
124124
{
125-
// We have found only one extruder in the texture, so return true only if this extruder is not 0, otherwise the rest is useless
126-
bool is_non_zero = true;
125+
// We have found only one extruder in the texture, so return true only if this extruder is not the mesh extruder, otherwise the rest is useless
126+
bool is_specific_extruder = true;
127127
found_extruders.visit_all(
128-
[&is_non_zero](const uint8_t extruder_nr)
128+
[&is_specific_extruder, &mesh_extruder_nr](const uint8_t extruder_nr)
129129
{
130-
is_non_zero = extruder_nr != 0;
130+
is_specific_extruder = extruder_nr != mesh_extruder_nr;
131131
});
132-
return is_non_zero;
132+
return is_specific_extruder;
133133
}
134134

135135
return true;
@@ -138,22 +138,23 @@ bool makeVoxelGridFromTexture(const Mesh& mesh, const std::shared_ptr<TextureDat
138138
/*!
139139
* Create modifier meshes from the given voxels grid, filled with the contours of the areas that should be processed by the different extruders.
140140
* @param voxel_grid The voxels grid containing the extruder occupations
141+
* @param mesh_extruder_nr The main mesh extruder number
141142
* @return A list of modifier meshes to be registered
142143
*
143144
* This function works by treating each horizontal plane separately of the voxels grid. For each plane, we apply a marching squares algorithm in order to generate 2D polygons.
144145
* Then we just have to extrude those polygons vertically. The final mesh has no horizontal face, thus it is not watertight at all. However, since it will subsequently
145146
* be re-sliced on XY planes, this is good enough.
146147
*/
147-
std::vector<Mesh> makeMeshesFromVoxelsGrid(const VoxelGrid& voxel_grid)
148+
std::vector<Mesh> makeMeshesFromVoxelsGrid(const VoxelGrid& voxel_grid, const uint8_t mesh_extruder_nr)
148149
{
149150
spdlog::debug("Make modifier meshes from voxels grid");
150151

151-
// First, gather all positions that should be considered for the marching square, e.g. all that have a non-null extruder and around them
152+
// First, gather all positions that should be considered for the marching square, e.g. all that have a specific extruder and around them
152153
boost::concurrent_flat_set<VoxelGrid::LocalCoordinates> marching_squares;
153154
voxel_grid.visitOccupiedVoxels(
154-
[&marching_squares](const auto& occupied_voxel)
155+
[&marching_squares, &mesh_extruder_nr](const auto& occupied_voxel)
155156
{
156-
if (occupied_voxel.second > 0)
157+
if (occupied_voxel.second != mesh_extruder_nr)
157158
{
158159
marching_squares.insert(occupied_voxel.first);
159160
if (occupied_voxel.first.position.x > 0)
@@ -206,25 +207,28 @@ std::vector<Mesh> makeMeshesFromVoxelsGrid(const VoxelGrid& voxel_grid)
206207
#ifdef __cpp_lib_execution
207208
std::execution::par,
208209
#endif
209-
[&voxel_grid, &raw_contours, &position_delta_center, &marching_segments](const VoxelGrid::LocalCoordinates square_start)
210+
[&voxel_grid, &raw_contours, &position_delta_center, &marching_segments, &mesh_extruder_nr](const VoxelGrid::LocalCoordinates square_start)
210211
{
211212
const int32_t x_plus1 = static_cast<int32_t>(square_start.position.x) + 1;
212213
const bool x_plus1_valid = x_plus1 <= std::numeric_limits<uint16_t>::max();
213214
const int32_t y_plus1 = static_cast<int32_t>(square_start.position.y) + 1;
214215
const bool y_plus1_valid = y_plus1 <= std::numeric_limits<uint16_t>::max();
215216

216-
const uint8_t occupation_bit0
217-
= x_plus1_valid && y_plus1_valid ? voxel_grid.getOccupation(VoxelGrid::LocalCoordinates(x_plus1, y_plus1, square_start.position.z)).value_or(0) : 0;
217+
const uint8_t occupation_bit0 = x_plus1_valid && y_plus1_valid
218+
? voxel_grid.getOccupation(VoxelGrid::LocalCoordinates(x_plus1, y_plus1, square_start.position.z)).value_or(mesh_extruder_nr)
219+
: mesh_extruder_nr;
218220
const uint8_t occupation_bit1
219-
= y_plus1_valid ? voxel_grid.getOccupation(VoxelGrid::LocalCoordinates(square_start.position.x, y_plus1, square_start.position.z)).value_or(0) : 0;
221+
= y_plus1_valid ? voxel_grid.getOccupation(VoxelGrid::LocalCoordinates(square_start.position.x, y_plus1, square_start.position.z)).value_or(mesh_extruder_nr)
222+
: mesh_extruder_nr;
220223
const uint8_t occupation_bit2
221-
= x_plus1_valid ? voxel_grid.getOccupation(VoxelGrid::LocalCoordinates(x_plus1, square_start.position.y, square_start.position.z)).value_or(0) : 0;
222-
const uint8_t occupation_bit3 = voxel_grid.getOccupation(square_start).value_or(0);
224+
= x_plus1_valid ? voxel_grid.getOccupation(VoxelGrid::LocalCoordinates(x_plus1, square_start.position.y, square_start.position.z)).value_or(mesh_extruder_nr)
225+
: mesh_extruder_nr;
226+
const uint8_t occupation_bit3 = voxel_grid.getOccupation(square_start).value_or(mesh_extruder_nr);
223227

224228
const std::unordered_set<uint8_t> extruders = { occupation_bit0, occupation_bit1, occupation_bit2, occupation_bit3 };
225229
for (const uint8_t extruder : extruders)
226230
{
227-
if (extruder == 0)
231+
if (extruder == mesh_extruder_nr)
228232
{
229233
continue;
230234
}
@@ -391,10 +395,14 @@ bool isInside(const VoxelGrid& voxel_grid, const VoxelGrid::LocalCoordinates& po
391395
* @param voxel_grid The current voxel grid to be checked. Some voxels may also be directly filled.
392396
* @param previously_evaluated_voxels The list of voxels that were just evaluated
393397
* @param sliced_mesh The pre-sliced mesh, used to check for points insideness
398+
* @param mesh_extruder_nr The main mesh extruder number
394399
* @return The list of new voxels to be evaluated
395400
*/
396-
boost::concurrent_flat_set<VoxelGrid::LocalCoordinates>
397-
findVoxelsToEvaluate(VoxelGrid& voxel_grid, const boost::concurrent_flat_set<VoxelGrid::LocalCoordinates>& previously_evaluated_voxels, const std::vector<Shape>& sliced_mesh)
401+
boost::concurrent_flat_set<VoxelGrid::LocalCoordinates> findVoxelsToEvaluate(
402+
VoxelGrid& voxel_grid,
403+
const boost::concurrent_flat_set<VoxelGrid::LocalCoordinates>& previously_evaluated_voxels,
404+
const std::vector<Shape>& sliced_mesh,
405+
const uint8_t mesh_extruder_nr)
398406
{
399407
boost::concurrent_flat_set<VoxelGrid::LocalCoordinates> voxels_to_evaluate;
400408

@@ -421,7 +429,7 @@ boost::concurrent_flat_set<VoxelGrid::LocalCoordinates>
421429

422430
if (! isInside(voxel_grid, voxel_around, sliced_mesh))
423431
{
424-
voxel_grid.setOccupation(voxel_around, 0);
432+
voxel_grid.setOccupation(voxel_around, mesh_extruder_nr);
425433
}
426434
else
427435
{
@@ -439,18 +447,20 @@ boost::concurrent_flat_set<VoxelGrid::LocalCoordinates>
439447
* @param voxels_to_evaluate The voxels to be evaluated
440448
* @param texture_data The lookup containing the rasterized texture data
441449
* @param deepness_squared The maximum deepness, squared
450+
* @param mesh_extruder_nr The main mesh extruder number
442451
*/
443452
void evaluateVoxels(
444453
VoxelGrid& voxel_grid,
445454
const boost::concurrent_flat_set<VoxelGrid::LocalCoordinates>& voxels_to_evaluate,
446455
const SpatialLookup& texture_data,
447-
const coord_t deepness_squared)
456+
const coord_t deepness_squared,
457+
const uint8_t mesh_extruder_nr)
448458
{
449459
voxels_to_evaluate.visit_all(
450460
#ifdef __cpp_lib_execution
451461
std::execution::par,
452462
#endif
453-
[&voxel_grid, &texture_data, &deepness_squared](const VoxelGrid::LocalCoordinates& voxel_to_evaluate)
463+
[&voxel_grid, &texture_data, &deepness_squared, &mesh_extruder_nr](const VoxelGrid::LocalCoordinates& voxel_to_evaluate)
454464
{
455465
const Point3D position = voxel_grid.toGlobalCoordinates(voxel_to_evaluate);
456466

@@ -460,12 +470,12 @@ void evaluateVoxels(
460470
if (nearest_occupation.has_value())
461471
{
462472
const Point3D diff = position - nearest_occupation.value().position;
463-
const uint8_t new_occupation = diff.vSize2() <= deepness_squared ? nearest_occupation.value().occupation : 0;
473+
const uint8_t new_occupation = diff.vSize2() <= deepness_squared ? nearest_occupation.value().occupation : mesh_extruder_nr;
464474
voxel_grid.setOccupation(voxel_to_evaluate, new_occupation);
465475
}
466476
else
467477
{
468-
voxel_grid.setOccupation(voxel_to_evaluate, 0);
478+
voxel_grid.setOccupation(voxel_to_evaluate, mesh_extruder_nr);
469479
}
470480
});
471481
}
@@ -502,14 +512,16 @@ void findBoundaryVoxels(boost::concurrent_flat_set<VoxelGrid::LocalCoordinates>&
502512
* @param sliced_mesh The pre-sliced mesh matching the voxel grid
503513
* @param texture_data The lookup containing the rasterized texture data
504514
* @param deepness_squared The maximum propagation deepness, squared
515+
* @param mesh_extruder_nr The main mesh extruder number
505516
*/
506517
void propagateVoxels(
507518
VoxelGrid& voxel_grid,
508519
boost::concurrent_flat_set<VoxelGrid::LocalCoordinates>& evaluated_voxels,
509520
const coord_t estimated_iterations,
510521
const std::vector<Shape>& sliced_mesh,
511522
const SpatialLookup& texture_data,
512-
const coord_t deepness_squared)
523+
const coord_t deepness_squared,
524+
const uint8_t mesh_extruder_nr)
513525
{
514526
uint32_t iteration = 0;
515527

@@ -519,11 +531,11 @@ void propagateVoxels(
519531

520532
// Make the list of new voxels to be evaluated, based on which were evaluated before
521533
spdlog::debug("Finding voxels around {} voxels for iteration {}", evaluated_voxels.size(), iteration);
522-
evaluated_voxels = findVoxelsToEvaluate(voxel_grid, evaluated_voxels, sliced_mesh);
534+
evaluated_voxels = findVoxelsToEvaluate(voxel_grid, evaluated_voxels, sliced_mesh, mesh_extruder_nr);
523535

524536
// Now actually evaluate the candidate voxels, i.e. find their closest outside point and set the according occupation
525537
spdlog::debug("Evaluating {} voxels", evaluated_voxels.size());
526-
evaluateVoxels(voxel_grid, evaluated_voxels, texture_data, deepness_squared);
538+
evaluateVoxels(voxel_grid, evaluated_voxels, texture_data, deepness_squared, mesh_extruder_nr);
527539

528540
// Now we have evaluated the candidates, check which of them are to be processed next. We skip all the voxels that have only voxels with similar occupations around
529541
// them, because they are obviously not part of the boundaries we are looking for. This avoids filling the inside of the points clouds and speeds up calculation a lot.
@@ -542,8 +554,8 @@ void propagateVoxels(
542554
*/
543555
std::vector<Mesh> makeModifierMeshes(const Mesh& mesh, const std::shared_ptr<TextureDataProvider>& texture_data_provider)
544556
{
545-
const Settings& settings = mesh.settings_;
546-
const size_t main_extruder = settings.get<size_t>("extruder_nr");
557+
const Settings& settings = Application::getInstance().current_slice_->scene.settings;
558+
const uint8_t mesh_extruder_nr = static_cast<uint8_t>(mesh.settings_.get<size_t>("extruder_nr"));
547559

548560
// Fill a first voxel grid by rasterizing the triangles of the mesh in 3D, and assign the extruders according to the texture. This way we can later evaluate which extruder
549561
// to assign any point in 3D space just by finding the closest outside point and see what extruder it is assigned to.
@@ -558,9 +570,9 @@ std::vector<Mesh> makeModifierMeshes(const Mesh& mesh, const std::shared_ptr<Tex
558570

559571
// Create the voxel grid and initially fill it with the rasterized mesh triangles, which will be used as spatial reference for the texture data
560572
VoxelGrid voxel_grid(bounding_box, resolution);
561-
if (! makeVoxelGridFromTexture(mesh, texture_data_provider, voxel_grid, main_extruder))
573+
if (! makeVoxelGridFromTexture(mesh, texture_data_provider, voxel_grid, mesh_extruder_nr))
562574
{
563-
// Texture is filled with 0s, don't bother doing anything
575+
// Texture is filled with the main extruder, don't bother doing anything
564576
return {};
565577
}
566578

@@ -576,9 +588,9 @@ std::vector<Mesh> makeModifierMeshes(const Mesh& mesh, const std::shared_ptr<Tex
576588
spdlog::debug("Get initially filled voxels");
577589
boost::concurrent_flat_set<VoxelGrid::LocalCoordinates> previously_evaluated_voxels;
578590
voxel_grid.visitOccupiedVoxels(
579-
[&previously_evaluated_voxels](const auto& voxel)
591+
[&previously_evaluated_voxels, &mesh_extruder_nr](const auto& voxel)
580592
{
581-
if (voxel.second > 0)
593+
if (voxel.second != mesh_extruder_nr)
582594
{
583595
previously_evaluated_voxels.insert(voxel.first);
584596
};
@@ -590,9 +602,9 @@ std::vector<Mesh> makeModifierMeshes(const Mesh& mesh, const std::shared_ptr<Tex
590602
const coord_t estimated_iterations = estimated_min_deepness / resolution;
591603
spdlog::debug("Estimated {} iterations", estimated_iterations);
592604

593-
propagateVoxels(voxel_grid, previously_evaluated_voxels, estimated_iterations, sliced_mesh, texture_data, deepness_squared);
605+
propagateVoxels(voxel_grid, previously_evaluated_voxels, estimated_iterations, sliced_mesh, texture_data, deepness_squared, mesh_extruder_nr);
594606

595-
return makeMeshesFromVoxelsGrid(voxel_grid);
607+
return makeMeshesFromVoxelsGrid(voxel_grid, mesh_extruder_nr);
596608
}
597609

598610
void makeMaterialModifierMeshes(const Mesh& mesh, MeshGroup* meshgroup)

0 commit comments

Comments
 (0)