Skip to content

Commit 2c9f857

Browse files
authored
CURA-12810 Make the multi-material progress reporting aware of multiple meshes (#2260)
2 parents 7db5119 + cb20b67 commit 2c9f857

File tree

3 files changed

+112
-43
lines changed

3 files changed

+112
-43
lines changed

include/MeshMaterialSplitter.h

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,9 @@ namespace MeshMaterialSplitter
1515

1616
/*!
1717
* Generate a modifier mesh for every extruder other than 0, that has some user-painted texture data
18-
* @param mesh The mesh being sliced
19-
* @param meshgroup The group to add the modifier meshes to
18+
* @param meshgroup The group to take the sliced meshes from and add the modifier meshes to
2019
*/
21-
void makeMaterialModifierMeshes(const Mesh& mesh, MeshGroup* meshgroup);
20+
void makeMaterialModifierMeshes(MeshGroup* meshgroup);
2221

2322
} // namespace MeshMaterialSplitter
2423

src/FffPolygonGenerator.cpp

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -62,11 +62,7 @@ namespace cura
6262

6363
bool FffPolygonGenerator::generateAreas(SliceDataStorage& storage, MeshGroup* meshgroup, TimeKeeper& timeKeeper)
6464
{
65-
std::vector<Mesh> initial_meshes = meshgroup->meshes; // Make a copy, because splitting is going to insert new meshes
66-
for (const Mesh& mesh : initial_meshes)
67-
{
68-
MeshMaterialSplitter::makeMaterialModifierMeshes(mesh, meshgroup);
69-
}
65+
MeshMaterialSplitter::makeMaterialModifierMeshes(meshgroup);
7066

7167
if (! sliceModel(meshgroup, timeKeeper, storage))
7268
{

src/MeshMaterialSplitter.cpp

Lines changed: 109 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
#include <boost/unordered/concurrent_flat_map.hpp>
88
#include <boost/unordered/concurrent_flat_set.hpp>
9+
#include <range/v3/numeric/accumulate.hpp>
910
#include <range/v3/view/map.hpp>
1011
#include <spdlog/spdlog.h>
1112
#include <spdlog/stopwatch.h>
@@ -33,6 +34,18 @@
3334
namespace cura::MeshMaterialSplitter
3435
{
3536

37+
/*!
38+
* Utility structure that contains pre-calculated data to generate the multi-material modifiers of a mesh
39+
*/
40+
struct MeshGeneratorData
41+
{
42+
const Mesh& mesh; //!< The mesh for which a material modifier is to be generated
43+
AABB3D bounding_box; //!< The bounding box of the mesh
44+
size_t estimated_iterations; //!< The roughly estimated number of voxels-propagation iterations (for progress reporting)
45+
coord_t depth; //!< The propagation depth retrieved from the mesh settings
46+
coord_t resolution; //!< The points cloud resolution retrieved from the mesh settings
47+
};
48+
3649
/*!
3750
* Utility structure to store values in a map that are grouped by unique z-height and extruder number combinations
3851
*/
@@ -525,21 +538,25 @@ void findBoundaryVoxels(boost::concurrent_flat_set<VoxelGrid::LocalCoordinates>&
525538
* @param texture_data The lookup containing the rasterized texture data
526539
* @param depth_squared The maximum propagation depth, squared
527540
* @param mesh_extruder_nr The main mesh extruder number
541+
* @param delta_iterations The number of already processed iterations over the total, for progress reporting
542+
* @param total_estimated_iterations The total number of iterations to be processed, for progress reporting
528543
*/
529544
void propagateVoxels(
530545
VoxelGrid& voxel_grid,
531546
boost::concurrent_flat_set<VoxelGrid::LocalCoordinates>& evaluated_voxels,
532-
const coord_t estimated_iterations,
547+
const size_t estimated_iterations,
533548
const std::vector<Shape>& sliced_mesh,
534549
const SpatialLookup& texture_data,
535550
const coord_t depth_squared,
536-
const uint8_t mesh_extruder_nr)
551+
const uint8_t mesh_extruder_nr,
552+
const size_t delta_iterations,
553+
const size_t total_estimated_iterations)
537554
{
538-
uint32_t iteration = 0;
555+
size_t iteration = 0;
539556

540557
while (! evaluated_voxels.empty())
541558
{
542-
Progress::messageProgress(Progress::Stage::SPLIT_MULTIMATERIAL, iteration, estimated_iterations);
559+
Progress::messageProgress(Progress::Stage::SPLIT_MULTIMATERIAL, std::min(iteration, estimated_iterations) + delta_iterations, total_estimated_iterations);
543560

544561
// Make the list of new voxels to be evaluated, based on which were evaluated before
545562
spdlog::debug("Finding voxels around {} voxels for iteration {}", evaluated_voxels.size(), iteration);
@@ -560,29 +577,30 @@ void propagateVoxels(
560577

561578
/*!
562579
* Generate a modifier mesh for every extruder other than 0, that has some user-painted texture data
563-
* @param mesh The mesh being sliced
580+
* @param mesh_data The generation data for the mesh to be processed
564581
* @param texture_data_provider The provider containing the texture painted data
582+
* @param delta_iterations The number of already processed iterations over the total, for progress reporting
583+
* @param total_estimated_iterations The total number of iterations to be processed, for progress reporting
565584
* @return A list of modifier meshes to be added to the slicing process
566585
*/
567-
std::vector<Mesh> makeModifierMeshes(const Mesh& mesh, const std::shared_ptr<TextureDataProvider>& texture_data_provider)
586+
std::vector<Mesh> makeModifierMeshes(
587+
const MeshGeneratorData& mesh_data,
588+
const std::shared_ptr<TextureDataProvider>& texture_data_provider,
589+
const size_t delta_iterations,
590+
const size_t total_estimated_iterations)
568591
{
569-
const Settings& settings = mesh.settings_;
592+
const Settings& settings = mesh_data.mesh.settings_;
570593
const uint8_t mesh_extruder_nr = static_cast<uint8_t>(settings.get<size_t>("extruder_nr"));
571594

572595
// 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
573596
// to assign any point in 3D space just by finding the closest outside point and see what extruder it is assigned to.
574597
spdlog::debug("Fill original voxels based on texture data");
575-
auto resolution = settings.get<coord_t>("multi_material_paint_resolution");
576-
AABB3D bounding_box;
577-
for (const MeshVertex& vertex : mesh.vertices_)
578-
{
579-
bounding_box.include(vertex.p_);
580-
}
581-
bounding_box.expand(resolution * 8);
598+
AABB3D bounding_box = mesh_data.bounding_box;
599+
bounding_box.expand(mesh_data.resolution * 8);
582600

583601
// Create the voxel grid and initially fill it with the rasterized mesh triangles, which will be used as spatial reference for the texture data
584-
VoxelGrid voxel_grid(bounding_box, resolution);
585-
if (! makeVoxelGridFromTexture(mesh, texture_data_provider, voxel_grid, mesh_extruder_nr))
602+
VoxelGrid voxel_grid(bounding_box, mesh_data.resolution);
603+
if (! makeVoxelGridFromTexture(mesh_data.mesh, texture_data_provider, voxel_grid, mesh_extruder_nr))
586604
{
587605
// Texture is filled with the main extruder, don't bother doing anything
588606
return {};
@@ -591,11 +609,10 @@ std::vector<Mesh> makeModifierMeshes(const Mesh& mesh, const std::shared_ptr<Tex
591609
spdlog::debug("Prepare spatial lookup for texture data");
592610
const SpatialLookup texture_data = SpatialLookup::makeSpatialLookupFromVoxelGrid(voxel_grid);
593611

594-
const auto depth = settings.get<coord_t>("multi_material_paint_depth");
595-
const coord_t depth_squared = depth * depth;
612+
const coord_t depth_squared = mesh_data.depth * mesh_data.depth;
596613

597614
// Create a slice of the mesh so that we can quickly check for points insideness
598-
const std::vector<Shape> sliced_mesh = sliceMesh(mesh, voxel_grid);
615+
const std::vector<Shape> sliced_mesh = sliceMesh(mesh_data.mesh, voxel_grid);
599616

600617
spdlog::debug("Get initially filled voxels");
601618
boost::concurrent_flat_set<VoxelGrid::LocalCoordinates> previously_evaluated_voxels;
@@ -608,35 +625,92 @@ std::vector<Mesh> makeModifierMeshes(const Mesh& mesh, const std::shared_ptr<Tex
608625
};
609626
});
610627

611-
// Make a rough estimation of the max number of iterations, by calculating how deep we may propagate inside the mesh
612-
const double bounding_box_max_depth = std::max({ bounding_box.spanX() / 2.0, bounding_box.spanY() / 2.0, bounding_box.spanZ() / 2.0 });
613-
const double estimated_min_depth = std::min(static_cast<double>(depth), bounding_box_max_depth);
614-
const coord_t estimated_iterations = estimated_min_depth / resolution;
615-
spdlog::debug("Estimated {} iterations", estimated_iterations);
616-
617-
propagateVoxels(voxel_grid, previously_evaluated_voxels, estimated_iterations, sliced_mesh, texture_data, depth_squared, mesh_extruder_nr);
628+
propagateVoxels(
629+
voxel_grid,
630+
previously_evaluated_voxels,
631+
mesh_data.estimated_iterations,
632+
sliced_mesh,
633+
texture_data,
634+
depth_squared,
635+
mesh_extruder_nr,
636+
delta_iterations,
637+
total_estimated_iterations);
618638

619639
return makeMeshesFromVoxelsGrid(voxel_grid, mesh_extruder_nr);
620640
}
621641

622-
void makeMaterialModifierMeshes(const Mesh& mesh, MeshGroup* meshgroup)
642+
/*!
643+
* Pre-calculate multi-material mesh generation data for the meshes in the given group
644+
* @param meshgroup The group containing the meshes to be processed
645+
* @return The list of mesh generation data for meshes that contain relevant information
646+
*/
647+
std::vector<MeshGeneratorData> makeInitialMeshesGenerationData(const MeshGroup* meshgroup)
623648
{
624-
if (mesh.texture_ == nullptr || mesh.texture_data_mapping_ == nullptr || ! mesh.texture_data_mapping_->contains("extruder"))
649+
std::vector<MeshGeneratorData> result;
650+
651+
for (const Mesh& mesh : meshgroup->meshes)
625652
{
626-
return;
653+
if (mesh.texture_ == nullptr || mesh.texture_data_mapping_ == nullptr || ! mesh.texture_data_mapping_->contains("extruder"))
654+
{
655+
continue;
656+
}
657+
658+
const Settings& settings = mesh.settings_;
659+
MeshGeneratorData mesh_data{ .mesh = mesh,
660+
.depth = settings.get<coord_t>("multi_material_paint_depth"),
661+
.resolution = settings.get<coord_t>("multi_material_paint_resolution") };
662+
663+
for (const MeshVertex& vertex : mesh.vertices_)
664+
{
665+
mesh_data.bounding_box.include(vertex.p_);
666+
}
667+
668+
// Make a rough estimation of the max number of iterations, by calculating how deep we may propagate inside the mesh
669+
const double bounding_box_max_depth = std::max({ mesh_data.bounding_box.spanX() / 2.0, mesh_data.bounding_box.spanY() / 2.0, mesh_data.bounding_box.spanZ() / 2.0 });
670+
const double estimated_min_depth = std::min(static_cast<double>(mesh_data.depth), bounding_box_max_depth);
671+
mesh_data.estimated_iterations = estimated_min_depth / mesh_data.resolution;
672+
spdlog::debug("Estimated {} iterations for {}", mesh_data.estimated_iterations, mesh.mesh_name_);
673+
674+
result.push_back(mesh_data);
627675
}
628676

629-
const spdlog::stopwatch timer;
630-
spdlog::info("Start multi-material mesh generation");
677+
return result;
678+
}
631679

632-
const auto texture_data_provider = std::make_shared<TextureDataProvider>(nullptr, mesh.texture_, mesh.texture_data_mapping_);
680+
void makeMaterialModifierMeshes(MeshGroup* meshgroup)
681+
{
682+
const std::vector<MeshGeneratorData> mesh_generation_data = makeInitialMeshesGenerationData(meshgroup);
683+
size_t delta_iterations = 0;
684+
const size_t total_estimated_iterations = ranges::accumulate(
685+
mesh_generation_data,
686+
0,
687+
[](const size_t total_iterations, const MeshGeneratorData& mesh_data)
688+
{
689+
return total_iterations + mesh_data.estimated_iterations;
690+
});
633691

634-
for (const Mesh& modifier_mesh : makeModifierMeshes(mesh, texture_data_provider))
692+
std::vector<Mesh> modifier_meshes;
693+
for (const MeshGeneratorData& mesh_data : mesh_generation_data)
635694
{
636-
meshgroup->meshes.push_back(modifier_mesh);
695+
const Mesh& mesh = mesh_data.mesh;
696+
const spdlog::stopwatch timer;
697+
spdlog::info("Start multi-material mesh generation for {}", mesh.mesh_name_);
698+
699+
const auto texture_data_provider = std::make_shared<TextureDataProvider>(nullptr, mesh.texture_, mesh.texture_data_mapping_);
700+
for (const Mesh& modifier_mesh : makeModifierMeshes(mesh_data, texture_data_provider, delta_iterations, total_estimated_iterations))
701+
{
702+
modifier_meshes.push_back(std::move(modifier_mesh));
703+
}
704+
705+
delta_iterations += mesh_data.estimated_iterations;
706+
spdlog::info("Multi-material mesh generation for {} took {} seconds", mesh.mesh_name_, timer.elapsed().count());
637707
}
638708

639-
spdlog::info("Multi-material mesh generation took {} seconds", timer.elapsed().count());
709+
// Add meshes to group afterwards to avoid re-allocating the meshes in the vector
710+
for (Mesh& modifier_mesh : modifier_meshes)
711+
{
712+
meshgroup->meshes.push_back(std::move(modifier_mesh));
713+
}
640714
}
641715

642716
} // namespace cura::MeshMaterialSplitter

0 commit comments

Comments
 (0)