Partial difference for multiple volume cuts
This commit is contained in:
parent
b059d3a57c
commit
ab3148538a
5 changed files with 876 additions and 602 deletions
src
tests/libslic3r
File diff suppressed because it is too large
Load diff
|
@ -53,23 +53,22 @@ bool merge_intersection(SurfaceCut &sc1, const SurfaceCut &sc2);
|
||||||
SurfaceCut merge(SurfaceCuts&& cuts);
|
SurfaceCut merge(SurfaceCuts&& cuts);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Cut surface shape from model.
|
/// Cut surface shape from models.
|
||||||
/// IMPROVE1: It is possible to prefiltrate model triangles befor cut.(AABB)
|
|
||||||
/// IMPROVE2: Make a cut by quad. Two triangles are possible slower but it is question for profiler.
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="model">Mesh to cut</param>
|
|
||||||
/// <param name="shapes">Multiple shape to cut from model</param>
|
/// <param name="shapes">Multiple shape to cut from model</param>
|
||||||
/// <param name="projection">Define transformation from 2d coordinate of shape to 3d</param>
|
/// <param name="models">Multi mesh to cut, need to be in same coordinate system</param>
|
||||||
|
/// <param name="projection">Define transformation 2d shape into 3d</param>
|
||||||
/// <param name="projection_ratio">Define ideal ratio between front and back projection to cut
|
/// <param name="projection_ratio">Define ideal ratio between front and back projection to cut
|
||||||
/// 0 .. means use closest to front projection
|
/// 0 .. means use closest to front projection
|
||||||
/// 1 .. means use closest to back projection
|
/// 1 .. means use closest to back projection
|
||||||
/// value from <0, 1>
|
/// value from <0, 1>
|
||||||
/// </param>
|
/// </param>
|
||||||
/// <returns>Cutted surface from model</returns>
|
/// <returns>Cutted surface from model</returns>
|
||||||
SurfaceCut cut_surface(const indexed_triangle_set &model,
|
SurfaceCut cut_surface(const ExPolygons &shapes,
|
||||||
const ExPolygons &shapes,
|
const std::vector<indexed_triangle_set> &models,
|
||||||
const Emboss::IProjection &projection,
|
const Emboss::IProjection &projection,
|
||||||
float projection_ratio = 0);
|
float projection_ratio);
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Create model from surface cuts by projection
|
/// Create model from surface cuts by projection
|
||||||
|
|
|
@ -83,13 +83,11 @@ static ModelVolume *get_volume(ModelObjectPtrs &objects,
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="tr">Volume transformation in object</param>
|
/// <param name="tr">Volume transformation in object</param>
|
||||||
/// <param name="shape_scale">Convert shape to milimeters</param>
|
/// <param name="shape_scale">Convert shape to milimeters</param>
|
||||||
/// <param name="shape_bb">Bounding box 2d of shape to center result</param>
|
|
||||||
/// <param name="z_range">Bounding box 3d of model volume for projection ranges</param>
|
/// <param name="z_range">Bounding box 3d of model volume for projection ranges</param>
|
||||||
/// <returns>Orthogonal cut_projection</returns>
|
/// <returns>Orthogonal cut_projection</returns>
|
||||||
static Emboss::OrthoProject create_projection_for_cut(
|
static Emboss::OrthoProject create_projection_for_cut(
|
||||||
Transform3d tr,
|
Transform3d tr,
|
||||||
double shape_scale,
|
double shape_scale,
|
||||||
const BoundingBox &shape_bb,
|
|
||||||
const std::pair<float, float> &z_range);
|
const std::pair<float, float> &z_range);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -407,7 +405,6 @@ void UseSurfaceJob::process(Ctl &ctl) {
|
||||||
|
|
||||||
if (was_canceled()) return;
|
if (was_canceled()) return;
|
||||||
|
|
||||||
BoundingBox bb = get_extents(shapes);
|
|
||||||
const UseSurfaceData::ModelSource &source = UseSurfaceData::merge(m_input.sources);
|
const UseSurfaceData::ModelSource &source = UseSurfaceData::merge(m_input.sources);
|
||||||
|
|
||||||
Transform3d mesh_tr_inv = source.tr.inverse();
|
Transform3d mesh_tr_inv = source.tr.inverse();
|
||||||
|
@ -419,11 +416,20 @@ void UseSurfaceJob::process(Ctl &ctl) {
|
||||||
const Emboss::FontFile &ff = *m_input.font_file.font_file;
|
const Emboss::FontFile &ff = *m_input.font_file.font_file;
|
||||||
double shape_scale = Emboss::get_shape_scale(fp, ff);
|
double shape_scale = Emboss::get_shape_scale(fp, ff);
|
||||||
Emboss::OrthoProject cut_projection = priv::create_projection_for_cut(
|
Emboss::OrthoProject cut_projection = priv::create_projection_for_cut(
|
||||||
cut_projection_tr, shape_scale, bb, z_range);
|
cut_projection_tr, shape_scale, z_range);
|
||||||
float projection_ratio = (-z_range.first + priv::safe_extension) /
|
float projection_ratio = (-z_range.first + priv::safe_extension) /
|
||||||
(z_range.second - z_range.first + 2 * priv::safe_extension);
|
(z_range.second - z_range.first + 2 * priv::safe_extension);
|
||||||
|
|
||||||
|
// Define alignment of text - left, right, center, top bottom, ....
|
||||||
|
BoundingBox bb = get_extents(shapes);
|
||||||
|
Point projection_center = bb.center();
|
||||||
|
for (ExPolygon &shape : shapes)
|
||||||
|
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(source.its, shapes, cut_projection, projection_ratio);
|
SurfaceCut cut = cut_surface(shapes, {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());
|
||||||
|
@ -650,7 +656,6 @@ ModelVolume *priv::get_volume(ModelObjectPtrs &objects,
|
||||||
Emboss::OrthoProject priv::create_projection_for_cut(
|
Emboss::OrthoProject priv::create_projection_for_cut(
|
||||||
Transform3d tr,
|
Transform3d tr,
|
||||||
double shape_scale,
|
double shape_scale,
|
||||||
const BoundingBox &shape_bb,
|
|
||||||
const std::pair<float, float> &z_range)
|
const std::pair<float, float> &z_range)
|
||||||
{
|
{
|
||||||
float min_z = z_range.first - priv::safe_extension;
|
float min_z = z_range.first - priv::safe_extension;
|
||||||
|
@ -670,12 +675,7 @@ Emboss::OrthoProject priv::create_projection_for_cut(
|
||||||
|
|
||||||
// Projection is in direction from far plane
|
// Projection is in direction from far plane
|
||||||
tr.translate(Vec3d(0., 0., min_z));
|
tr.translate(Vec3d(0., 0., min_z));
|
||||||
|
|
||||||
tr.scale(shape_scale);
|
tr.scale(shape_scale);
|
||||||
// Text alignemnt to center 2D
|
|
||||||
Vec2d move = -(shape_bb.max + shape_bb.min).cast<double>() / 2.;
|
|
||||||
//Vec2d move = -shape_bb.center().cast<double>(); // not precisse
|
|
||||||
tr.translate(Vec3d(move.x(), move.y(), 0.));
|
|
||||||
return Emboss::OrthoProject(tr, project_direction);
|
return Emboss::OrthoProject(tr, project_direction);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -33,7 +33,7 @@ TEST_CASE("Cut character from surface", "[]")
|
||||||
its_merge(object, std::move(cube2));
|
its_merge(object, std::move(cube2));
|
||||||
|
|
||||||
// Call core function for cut surface
|
// Call core function for cut surface
|
||||||
auto surfaces = cut_surface(object, shape, cut_projection);
|
auto surfaces = cut_surface(shape, {object}, cut_projection, 0);
|
||||||
CHECK(!surfaces.empty());
|
CHECK(!surfaces.empty());
|
||||||
|
|
||||||
Emboss::OrthoProject projection(Transform3d::Identity(),
|
Emboss::OrthoProject projection(Transform3d::Identity(),
|
||||||
|
@ -45,15 +45,17 @@ TEST_CASE("Cut character from surface", "[]")
|
||||||
// its_write_obj(its, "C:/data/temp/projected.obj");
|
// its_write_obj(its, "C:/data/temp/projected.obj");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define DEBUG_3MF
|
||||||
#ifdef DEBUG_3MF
|
#ifdef DEBUG_3MF
|
||||||
|
|
||||||
// Test load of 3mf
|
// Test load of 3mf
|
||||||
#include "libslic3r/Format/3mf.hpp"
|
#include "libslic3r/Format/3mf.hpp"
|
||||||
#include "libslic3r/Model.hpp"
|
#include "libslic3r/Model.hpp"
|
||||||
|
|
||||||
static indexed_triangle_set merge_object(ModelVolume *mv) {
|
static std::vector<indexed_triangle_set> transform_volumes(ModelVolume *mv) {
|
||||||
const auto &volumes = mv->get_object()->volumes;
|
const auto &volumes = mv->get_object()->volumes;
|
||||||
indexed_triangle_set result;
|
std::vector<indexed_triangle_set> results;
|
||||||
|
results.reserve(volumes.size());
|
||||||
|
|
||||||
// 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
|
||||||
|
@ -63,11 +65,11 @@ static indexed_triangle_set merge_object(ModelVolume *mv) {
|
||||||
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;
|
||||||
indexed_triangle_set its = tm.its;
|
results.push_back(tm.its); // copy: indexed_triangle_set
|
||||||
|
indexed_triangle_set& its = results.back();
|
||||||
its_transform(its,v->get_matrix());
|
its_transform(its,v->get_matrix());
|
||||||
its_merge(result, std::move(its));
|
|
||||||
}
|
}
|
||||||
return result;
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
static Emboss::OrthoProject create_projection_for_cut(
|
static Emboss::OrthoProject create_projection_for_cut(
|
||||||
|
@ -137,12 +139,13 @@ TEST_CASE("CutSurface in 3mf", "[Emboss]")
|
||||||
Emboss::FontFileWithCache ff(Emboss::create_font_file(font_path.c_str()));
|
Emboss::FontFileWithCache ff(Emboss::create_font_file(font_path.c_str()));
|
||||||
// */ // end use fake font
|
// */ // end use fake font
|
||||||
CHECK(ff.has_value());
|
CHECK(ff.has_value());
|
||||||
|
std::vector<indexed_triangle_set> its = transform_volumes(mv_text);
|
||||||
indexed_triangle_set its = merge_object(mv_text);
|
BoundingBoxf3 bb;
|
||||||
BoundingBoxf3 bb = Slic3r::bounding_box(its);
|
for (auto &i : its) bb.merge(Slic3r::bounding_box(i));
|
||||||
Transform3d cut_projection_tr = mv_text->get_matrix()*tc.fix_3mf_tr->inverse();
|
|
||||||
Transform3d emboss_tr = cut_projection_tr.inverse();
|
Transform3d cut_projection_tr = mv_text->get_matrix() * tc.fix_3mf_tr->inverse();
|
||||||
BoundingBoxf3 mesh_bb_tr = bb.transformed(emboss_tr);
|
Transform3d emboss_tr = cut_projection_tr.inverse();
|
||||||
|
BoundingBoxf3 mesh_bb_tr = 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()};
|
||||||
|
|
||||||
|
@ -154,11 +157,24 @@ TEST_CASE("CutSurface in 3mf", "[Emboss]")
|
||||||
cut_projection_tr, shape_scale, get_extents(shapes), z_range);
|
cut_projection_tr, shape_scale, get_extents(shapes), z_range);
|
||||||
|
|
||||||
float projection_ratio = -z_range.first / (z_range.second - z_range.first);
|
float projection_ratio = -z_range.first / (z_range.second - z_range.first);
|
||||||
SurfaceCut cut = cut_surface(its, shapes, projection, projection_ratio);
|
SurfaceCut cut = cut_surface(shapes, its, projection, projection_ratio);
|
||||||
its_write_obj(cut, "C:/data/temp/cutSurface/result_cut.obj");
|
its_write_obj(cut, "C:/data/temp/cutSurface/result_cut.obj");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#include "libslic3r/Format/OBJ.hpp"
|
||||||
TEST_CASE("Merge Cuts", "[Emboss]") {
|
TEST_CASE("Merge Cuts", "[Emboss]") {
|
||||||
Slic3r::merge_intersection();
|
std::string dir = "C:/data/temp/";
|
||||||
|
TriangleMesh tm1, tm2;
|
||||||
|
load_obj((dir + "aoi3.obj").c_str(), &tm1);
|
||||||
|
load_obj((dir + "aoi6.obj").c_str(), &tm2);
|
||||||
|
auto create_sc = [](TriangleMesh &tm) -> SurfaceCut {
|
||||||
|
SurfaceCut sc;
|
||||||
|
sc.vertices = std::move(tm.its.vertices);
|
||||||
|
sc.indices = std::move(tm.its.indices);
|
||||||
|
// sc.contours = ???
|
||||||
|
return sc;
|
||||||
|
};
|
||||||
|
SurfaceCut sc1 = create_sc(tm1), sc2 = create_sc(tm2);
|
||||||
|
assert(merge_intersection(sc1, sc2));
|
||||||
}
|
}
|
||||||
#endif // DEBUG_3MF
|
#endif // DEBUG_3MF
|
||||||
|
|
|
@ -299,17 +299,19 @@ TEST_CASE("Italic check", "[Emboss]")
|
||||||
#include "libslic3r/CutSurface.hpp"
|
#include "libslic3r/CutSurface.hpp"
|
||||||
TEST_CASE("Cut surface", "[]")
|
TEST_CASE("Cut surface", "[]")
|
||||||
{
|
{
|
||||||
std::string font_path = get_font_filepath();
|
std::string font_path = get_font_filepath();
|
||||||
char letter = '%';
|
char letter = '%';
|
||||||
float flatness = 2.;
|
float flatness = 2.;
|
||||||
unsigned int font_index = 0; // collection
|
unsigned int font_index = 0; // collection
|
||||||
float z_depth = 50.f; // projection size
|
float z_depth = 50.f; // projection size
|
||||||
|
|
||||||
auto font = Emboss::create_font_file(font_path.c_str());
|
auto font = Emboss::create_font_file(font_path.c_str());
|
||||||
REQUIRE(font != nullptr);
|
REQUIRE(font != nullptr);
|
||||||
|
|
||||||
std::optional<Emboss::Glyph> glyph =
|
std::optional<Emboss::Glyph> glyph = Emboss::letter2glyph(*font,
|
||||||
Emboss::letter2glyph(*font, font_index, letter, flatness);
|
font_index,
|
||||||
|
letter,
|
||||||
|
flatness);
|
||||||
REQUIRE(glyph.has_value());
|
REQUIRE(glyph.has_value());
|
||||||
|
|
||||||
ExPolygons shape = glyph->shape;
|
ExPolygons shape = glyph->shape;
|
||||||
|
@ -326,7 +328,7 @@ TEST_CASE("Cut surface", "[]")
|
||||||
its_translate(cube2, Vec3f(100, -40, 7.5));
|
its_translate(cube2, Vec3f(100, -40, 7.5));
|
||||||
its_merge(object, std::move(cube2));
|
its_merge(object, std::move(cube2));
|
||||||
|
|
||||||
auto surfaces = cut_surface(object, shape, cut_projection);
|
auto surfaces = cut_surface(shape, {object}, cut_projection, 0);
|
||||||
CHECK(!surfaces.empty());
|
CHECK(!surfaces.empty());
|
||||||
|
|
||||||
Emboss::OrthoProject projection(Transform3d::Identity(), Vec3f(0.f, 0.f, 10.f));
|
Emboss::OrthoProject projection(Transform3d::Identity(), Vec3f(0.f, 0.f, 10.f));
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue