Add option to keep existing painting while mapping new paintings to it

This commit is contained in:
Noisyfox
2026-05-09 21:47:40 +08:00
parent b3a513eab9
commit e6b3f6ccef
4 changed files with 18 additions and 7 deletions

View File

@@ -1995,7 +1995,7 @@ std::optional<TriangleSelector::SavedPainting> ModelVolume::save_painting() cons
return {};
}
void ModelVolume::restore_painting(const std::optional<TriangleSelector::SavedPainting>& saved)
void ModelVolume::restore_painting(const std::optional<TriangleSelector::SavedPainting>& saved, const bool keep_existing_paint)
{
if (!saved) {
return;
@@ -2005,9 +2005,13 @@ void ModelVolume::restore_painting(const std::optional<TriangleSelector::SavedPa
FacetsAnnotation& target_facets) {
if (src_data.bitstream.empty())
return;
auto result = TriangleSelector::remap_painting(saved->mesh.its, src_data, mesh().its, Geometry::translation_transform(mesh().get_init_shift()));
auto result =
TriangleSelector::remap_painting(saved->mesh.its, src_data, mesh().its, Geometry::translation_transform(mesh().get_init_shift()),
keep_existing_paint ?
std::optional<std::reference_wrapper<const TriangleSelector::TriangleSplittingData>>{std::ref(target_facets.get_data())} :
std::optional<std::reference_wrapper<const TriangleSelector::TriangleSplittingData>>{});
if (!result.bitstream.empty())
target_facets.set_data(result);
target_facets.set_data(std::move(result));
};
remap_one(saved->supported, supported_facets);
remap_one(saved->seam, seam_facets);

View File

@@ -731,7 +731,7 @@ public:
void assign(const FacetsAnnotation &rhs) { if (! this->timestamp_matches(rhs)) { m_data = rhs.m_data; this->copy_timestamp(rhs); } }
void assign(FacetsAnnotation &&rhs) { if (! this->timestamp_matches(rhs)) { m_data = std::move(rhs.m_data); this->copy_timestamp(rhs); } }
const TriangleSelector::TriangleSplittingData &get_data() const noexcept { return m_data; }
void set_data(const TriangleSelector::TriangleSplittingData &data) { m_data = data; this->touch(); }
void set_data(TriangleSelector::TriangleSplittingData &&data) { m_data = std::move(data); this->touch(); }
bool set(const TriangleSelector& selector);
indexed_triangle_set get_facets(const ModelVolume& mv, EnforcerBlockerType type) const;
// BBS
@@ -884,7 +884,7 @@ public:
std::optional<TriangleSelector::SavedPainting> save_painting() const;
// Remap painting data from previous saved source to this mesh
void restore_painting(const std::optional<TriangleSelector::SavedPainting>& saved);
void restore_painting(const std::optional<TriangleSelector::SavedPainting>& saved, bool keep_existing_paint = false);
// BBS: quick access for volume extruders, 1 based
mutable std::vector<int> mmuseg_extruders;

View File

@@ -2407,7 +2407,8 @@ TriangleSelector::TriangleSplittingData TriangleSelector::remap_painting(
const indexed_triangle_set& source_its,
const TriangleSplittingData& source_painting,
const indexed_triangle_set& target_its,
const Transform3d& target_transform)
const Transform3d& target_transform,
const std::optional<std::reference_wrapper<const TriangleSplittingData>>& existing_painting)
{
TriangleSelector::TriangleSplittingData result;
if (source_painting.bitstream.empty())
@@ -2477,6 +2478,10 @@ TriangleSelector::TriangleSplittingData TriangleSelector::remap_painting(
// 4. For each painted face, we find the nearest target face, and apply the TriangleCursor to paint it
TriangleSelector target_selector(target_mesh);
if (existing_painting) {
// Restore existing painting first, if given
target_selector.deserialize(existing_painting->get(), false);
}
for (auto tri_ref : painted_triangles) {
const Triangle& tri = tri_ref.get();
const Vec3f& pv0 = source_selector.m_vertices[tri.verts_idxs[0]].v;

View File

@@ -383,11 +383,13 @@ public:
// Remap painting data from source mesh to target mesh using spatial mapping.
// `target_transform` should transform the target mesh into source's coordinate space.
// If `existing_painting` is present, the result will be a combine of `existing_painting` and remapped `source_painting`.
static TriangleSplittingData remap_painting(
const indexed_triangle_set& source_its,
const TriangleSplittingData& source_painting,
const indexed_triangle_set& target_its,
const Transform3d& target_transform);
const Transform3d& target_transform,
const std::optional<std::reference_wrapper<const TriangleSplittingData>>& existing_painting);
protected:
// Triangle and info about how it's split.