Prepare multi volume source for cut surface job
This commit is contained in:
parent
6f1bcd2469
commit
e90c2c8e9a
@ -940,8 +940,8 @@ bool GLGizmoEmboss::process()
|
|||||||
const TextConfiguration &tc = data.text_configuration;
|
const TextConfiguration &tc = data.text_configuration;
|
||||||
if (tc.font_item.prop.use_surface) {
|
if (tc.font_item.prop.use_surface) {
|
||||||
// Model to cut surface from.
|
// Model to cut surface from.
|
||||||
auto sources = UseSurfaceData::get_sources_to_cut_surface_from(m_volume);
|
UseSurfaceData::ModelSource source = UseSurfaceData::create_source(m_volume);
|
||||||
if (sources.empty()) return false;
|
if (source.its.empty()) return false;
|
||||||
|
|
||||||
Transform3d text_tr = m_volume->get_matrix();
|
Transform3d text_tr = m_volume->get_matrix();
|
||||||
auto& fix_3mf = m_volume->text_configuration->fix_3mf_tr;
|
auto& fix_3mf = m_volume->text_configuration->fix_3mf_tr;
|
||||||
@ -953,7 +953,7 @@ bool GLGizmoEmboss::process()
|
|||||||
assert(is_outside || m_volume->is_negative_volume() ||
|
assert(is_outside || m_volume->is_negative_volume() ||
|
||||||
m_volume->is_modifier());
|
m_volume->is_modifier());
|
||||||
UseSurfaceData surface_data{std::move(data), text_tr, is_outside,
|
UseSurfaceData surface_data{std::move(data), text_tr, is_outside,
|
||||||
std::move(sources)};
|
std::move(source)};
|
||||||
job = std::make_unique<UseSurfaceJob>(std::move(surface_data));
|
job = std::make_unique<UseSurfaceJob>(std::move(surface_data));
|
||||||
} else {
|
} else {
|
||||||
job = std::make_unique<EmbossUpdateJob>(std::move(data));
|
job = std::make_unique<EmbossUpdateJob>(std::move(data));
|
||||||
|
@ -318,62 +318,63 @@ void EmbossUpdateJob::finalize(bool canceled, std::exception_ptr &eptr)
|
|||||||
priv::update_volume(std::move(m_result), m_input);
|
priv::update_volume(std::move(m_result), m_input);
|
||||||
}
|
}
|
||||||
|
|
||||||
UseSurfaceData::ModelSources UseSurfaceData::get_sources_to_cut_surface_from(
|
UseSurfaceData::ModelSource UseSurfaceData::create_source(
|
||||||
const ModelVolume *text_volume)
|
const ModelVolume *text_volume)
|
||||||
{
|
{
|
||||||
if (text_volume == nullptr) return {};
|
if (text_volume == nullptr) return {};
|
||||||
if (!text_volume->text_configuration.has_value()) return {};
|
if (!text_volume->text_configuration.has_value()) return {};
|
||||||
const auto &volumes = text_volume->get_object()->volumes;
|
const ModelVolumePtrs &volumes = text_volume->get_object()->volumes;
|
||||||
// no other volume in object
|
// no other volume in object
|
||||||
if (volumes.size() <= 1) return {};
|
if (volumes.size() <= 1) return {};
|
||||||
|
|
||||||
|
// One volume transformation is used for transform others
|
||||||
|
// Most common cut is into one volume so it is cheaper to do not transform this volume
|
||||||
|
// NOTE: Preparation is made on Main thred!
|
||||||
|
auto find_biggest = [&text_volume]
|
||||||
|
(const ModelVolumePtrs& volumes, const ObjectID& text_volume_id)->const ModelVolume * {
|
||||||
|
const ModelVolume *biggest = nullptr;
|
||||||
|
size_t biggest_size = 0;
|
||||||
|
for (const ModelVolume *v: volumes) {
|
||||||
|
if (v->id() == text_volume_id) continue;
|
||||||
|
if (!v->is_model_part()) continue;
|
||||||
|
const TriangleMesh &tm = v->mesh();
|
||||||
|
if (tm.empty()) continue;
|
||||||
|
if (tm.its.empty()) continue;
|
||||||
|
if (biggest_size > tm.its.indices.size()) continue;
|
||||||
|
biggest_size = tm.its.indices.size();
|
||||||
|
biggest = v;
|
||||||
|
}
|
||||||
|
assert(biggest != nullptr);
|
||||||
|
return biggest;
|
||||||
|
};
|
||||||
|
|
||||||
UseSurfaceData::ModelSources result;
|
const ModelVolume *biggest_volume = find_biggest(volumes, text_volume->id());
|
||||||
|
const TriangleMesh &biggest_tm = biggest_volume->mesh();
|
||||||
|
|
||||||
|
// IMPROVE: Copy only AOI by shapes and projection
|
||||||
|
// NOTE: copy of source mesh tringles and it slows down on big meshes
|
||||||
|
ModelSource result{
|
||||||
|
{biggest_tm.its}, // copy !!!
|
||||||
|
biggest_volume->get_transformation().get_matrix(),
|
||||||
|
biggest_tm.bounding_box()
|
||||||
|
};
|
||||||
|
|
||||||
|
Transform3d tr_inv = result.tr.inverse();
|
||||||
// Improve create object from part or use gl_volume
|
// Improve create object from part or use gl_volume
|
||||||
// Get first model part in object
|
// Get first model part in object
|
||||||
for (const ModelVolume *v : volumes) {
|
for (const ModelVolume *v : volumes) {
|
||||||
if (v->id() == text_volume->id()) continue;
|
if (v->id() == text_volume->id()) continue;
|
||||||
|
if (v->id() == biggest_volume->id()) continue;
|
||||||
if (!v->is_model_part()) continue;
|
if (!v->is_model_part()) continue;
|
||||||
const TriangleMesh &tm = v->mesh();
|
const TriangleMesh &tm = v->mesh();
|
||||||
if (tm.empty()) continue;
|
if (tm.empty()) continue;
|
||||||
if (tm.its.empty()) continue;
|
if (tm.its.empty()) continue;
|
||||||
UseSurfaceData::ModelSource ms = {tm.its,
|
|
||||||
v->get_transformation().get_matrix(),
|
|
||||||
tm.bounding_box()};
|
|
||||||
result.push_back(std::move(ms));
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
UseSurfaceData::ModelSource UseSurfaceData::merge(ModelSources &sources)
|
Transform3d tr = v->get_matrix() * tr_inv;
|
||||||
{
|
indexed_triangle_set its = tm.its; // copy !!!
|
||||||
if (sources.size() == 1) return sources.front();
|
its_transform(its, tr);
|
||||||
// find biggest its
|
result.its.emplace_back(std::move(its));
|
||||||
size_t max_index = 0;
|
|
||||||
size_t max_vertices = 0;
|
|
||||||
// calc sum of counts for resize
|
|
||||||
size_t count_vertices = 0;
|
|
||||||
size_t count_indices = 0;
|
|
||||||
for (const ModelSource &source : sources) {
|
|
||||||
count_vertices += source.its.vertices.size();
|
|
||||||
count_indices += source.its.indices.size();
|
|
||||||
if (max_vertices < source.its.vertices.size()) {
|
|
||||||
max_vertices = source.its.vertices.size();
|
|
||||||
max_index = &source - &sources.front();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ModelSource &result = sources[max_index];
|
|
||||||
result.its.vertices.reserve(count_vertices);
|
|
||||||
result.its.indices.reserve(count_indices);
|
|
||||||
Transform3d result_tr_inv = result.tr.inverse();
|
|
||||||
for (size_t i = 0; i < sources.size(); i++) {
|
|
||||||
if (i == max_index) continue;
|
|
||||||
ModelSource &source = sources[i];
|
|
||||||
Transform3d tr = source.tr * result_tr_inv;
|
|
||||||
its_transform(source.its, tr);
|
|
||||||
its_merge(result.its, std::move(source.its));
|
|
||||||
}
|
|
||||||
result.bb = bounding_box(result.its);
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -405,12 +406,10 @@ void UseSurfaceJob::process(Ctl &ctl) {
|
|||||||
|
|
||||||
if (was_canceled()) return;
|
if (was_canceled()) return;
|
||||||
|
|
||||||
const UseSurfaceData::ModelSource &source = UseSurfaceData::merge(m_input.sources);
|
Transform3d mesh_tr_inv = m_input.source.tr.inverse();
|
||||||
|
|
||||||
Transform3d mesh_tr_inv = source.tr.inverse();
|
|
||||||
Transform3d cut_projection_tr = mesh_tr_inv * m_input.text_tr;
|
Transform3d cut_projection_tr = mesh_tr_inv * m_input.text_tr;
|
||||||
Transform3d emboss_tr = cut_projection_tr.inverse();
|
Transform3d emboss_tr = cut_projection_tr.inverse();
|
||||||
BoundingBoxf3 mesh_bb_tr = source.bb.transformed(emboss_tr);
|
BoundingBoxf3 mesh_bb_tr = m_input.source.bb.transformed(emboss_tr);
|
||||||
std::pair<float, float> z_range{mesh_bb_tr.min.z(), mesh_bb_tr.max.z()};
|
std::pair<float, float> z_range{mesh_bb_tr.min.z(), mesh_bb_tr.max.z()};
|
||||||
|
|
||||||
const Emboss::FontFile &ff = *m_input.font_file.font_file;
|
const Emboss::FontFile &ff = *m_input.font_file.font_file;
|
||||||
@ -426,10 +425,9 @@ void UseSurfaceJob::process(Ctl &ctl) {
|
|||||||
for (ExPolygon &shape : shapes)
|
for (ExPolygon &shape : shapes)
|
||||||
shape.translate(-projection_center);
|
shape.translate(-projection_center);
|
||||||
|
|
||||||
// TODO: prepare multi model -> source.its
|
|
||||||
|
|
||||||
// Use CGAL to cut surface from triangle mesh
|
// Use CGAL to cut surface from triangle mesh
|
||||||
SurfaceCut cut = cut_surface(shapes, {source.its}, cut_projection, projection_ratio);
|
SurfaceCut cut = cut_surface(shapes, m_input.source.its,
|
||||||
|
cut_projection, projection_ratio);
|
||||||
if (cut.empty())
|
if (cut.empty())
|
||||||
throw priv::EmbossJobException(
|
throw priv::EmbossJobException(
|
||||||
_u8L("There is no valid surface for text projection.").c_str());
|
_u8L("There is no valid surface for text projection.").c_str());
|
||||||
@ -514,8 +512,8 @@ bool priv::check(const EmbossDataUpdate &input, bool is_main_thread){
|
|||||||
}
|
}
|
||||||
bool priv::check(const UseSurfaceData &input, bool is_main_thread){
|
bool priv::check(const UseSurfaceData &input, bool is_main_thread){
|
||||||
bool res = check((EmbossDataUpdate) input, is_main_thread);
|
bool res = check((EmbossDataUpdate) input, is_main_thread);
|
||||||
assert(!input.sources.empty());
|
assert(!input.source.its.empty());
|
||||||
res &= !input.sources.empty();
|
res &= !input.source.its.empty();
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -161,32 +161,22 @@ struct UseSurfaceData : public EmbossDataUpdate
|
|||||||
|
|
||||||
struct ModelSource
|
struct ModelSource
|
||||||
{
|
{
|
||||||
// IMPROVE: copy of source mesh tringles
|
// IMPROVE: Copy only AOI by shapes and projection
|
||||||
// copy could slow down on big meshes
|
// NOTE: copy of source mesh tringles and it slows down on big meshes
|
||||||
// but proccessing on thread need it
|
std::vector<indexed_triangle_set> its;
|
||||||
indexed_triangle_set its;
|
|
||||||
// Transformation of volume inside of object
|
// Transformation of volume inside of object
|
||||||
Transform3d tr;
|
Transform3d tr;
|
||||||
// extract bounds for projection
|
// extract bounds for projection
|
||||||
BoundingBoxf3 bb;
|
BoundingBoxf3 bb;
|
||||||
};
|
};
|
||||||
using ModelSources = std::vector<ModelSource>;
|
ModelSource source;
|
||||||
ModelSources sources;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Copied triangles from object to be able create mesh for cut surface
|
/// Copied triangles from object to be able create mesh for cut surface from
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="text_volume">Define text in object</param>
|
/// <param name="text_volume">Define text in object</param>
|
||||||
/// <returns>Source data for cut surface from</returns>
|
/// <returns>Source data for cut surface from</returns>
|
||||||
static ModelSources get_sources_to_cut_surface_from(
|
static ModelSource create_source(const ModelVolume *text_volume);
|
||||||
const ModelVolume *text_volume);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Merging of source together
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="sources">Define input by multiple triangle models</param>
|
|
||||||
/// <returns>Create one Source</returns>
|
|
||||||
static ModelSource merge(ModelSources& sources);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -202,6 +192,8 @@ public:
|
|||||||
UseSurfaceJob(UseSurfaceData &&input);
|
UseSurfaceJob(UseSurfaceData &&input);
|
||||||
void process(Ctl &ctl) override;
|
void process(Ctl &ctl) override;
|
||||||
void finalize(bool canceled, std::exception_ptr &eptr) override;
|
void finalize(bool canceled, std::exception_ptr &eptr) override;
|
||||||
|
// prepare multi volume input
|
||||||
|
static std::vector<indexed_triangle_set> transform_volumes(ModelVolume *mv);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Slic3r::GUI
|
} // namespace Slic3r::GUI
|
||||||
|
Loading…
Reference in New Issue
Block a user