add clear of conversion map for vertex index between conversions of AOI_cuts to indexed_triangle_set
AOI_cut could share vertex and this vertex has own index in each cut.
This commit is contained in:
parent
7295c3470b
commit
49467667f8
3 changed files with 130 additions and 79 deletions
|
@ -146,6 +146,16 @@ struct IntersectingElement
|
||||||
bool is_last() const { return attr >= 16; }
|
bool is_last() const { return attr >= 16; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// set true to skip map for indicies
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="skip_indicies">Flag to convert triangle to cgal</param>
|
||||||
|
/// <param name="its">model</param>
|
||||||
|
/// <param name="projection">direction</param>
|
||||||
|
void set_skip_for_outward_projection(std::vector<bool> &skip_indicies,
|
||||||
|
const indexed_triangle_set &its,
|
||||||
|
const Emboss::IProject3f &projection);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Convert triangle mesh model to CGAL Surface_mesh
|
/// Convert triangle mesh model to CGAL Surface_mesh
|
||||||
/// Filtrate out opposite triangles
|
/// Filtrate out opposite triangles
|
||||||
|
@ -533,11 +543,15 @@ SurfaceCut Slic3r::cut_surface(const indexed_triangle_set &model,
|
||||||
priv::FaceTypeMap face_type_map = cgal_model.add_property_map<priv::FI, priv::FaceType>(face_type_map_name).first;
|
priv::FaceTypeMap face_type_map = cgal_model.add_property_map<priv::FI, priv::FaceType>(face_type_map_name).first;
|
||||||
|
|
||||||
// Select inside and outside face in model
|
// Select inside and outside face in model
|
||||||
priv::set_face_type(face_type_map, cgal_model, vert_shape_map, ecm, cgal_shape);
|
priv::set_face_type(face_type_map, cgal_model, vert_shape_map, ecm, cgal_shape);
|
||||||
priv::set_almost_parallel_type(face_type_map, cgal_model, projection);
|
|
||||||
#ifdef DEBUG_OUTPUT_DIR
|
#ifdef DEBUG_OUTPUT_DIR
|
||||||
priv::store(cgal_model, face_type_map, DEBUG_OUTPUT_DIR + "constrained.off"); // only debug
|
priv::store(cgal_model, face_type_map, DEBUG_OUTPUT_DIR + "constrained.off"); // only debug
|
||||||
#endif // DEBUG_OUTPUT_DIR
|
#endif // DEBUG_OUTPUT_DIR
|
||||||
|
|
||||||
|
priv::set_almost_parallel_type(face_type_map, cgal_model, projection);
|
||||||
|
#ifdef DEBUG_OUTPUT_DIR
|
||||||
|
priv::store(cgal_model, face_type_map, DEBUG_OUTPUT_DIR + "constrainedWithAlmostParallel.off"); // only debug
|
||||||
|
#endif // DEBUG_OUTPUT_DIR
|
||||||
|
|
||||||
priv::flood_fill_inner(cgal_model, face_type_map);
|
priv::flood_fill_inner(cgal_model, face_type_map);
|
||||||
// Seed fill the other faces inside the region.
|
// Seed fill the other faces inside the region.
|
||||||
|
@ -763,11 +777,25 @@ bool priv::is_toward_projection(const Vec3f &a,
|
||||||
CGAL::POSITIVE;
|
CGAL::POSITIVE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void priv::set_skip_for_outward_projection(std::vector<bool> &skip_indicies,
|
||||||
|
const indexed_triangle_set &its,
|
||||||
|
const Emboss::IProject3f &projection)
|
||||||
|
{
|
||||||
|
for (const auto &t : its.indices) {
|
||||||
|
size_t index = &t - &its.indices.front();
|
||||||
|
if (skip_indicies[index]) continue;
|
||||||
|
if (is_toward_projection(t, its.vertices, projection)) continue;
|
||||||
|
skip_indicies[index] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
priv::CutMesh priv::to_cgal(const indexed_triangle_set &its,
|
priv::CutMesh priv::to_cgal(const indexed_triangle_set &its,
|
||||||
const Emboss::IProject3f &projection)
|
const Emboss::IProject3f &projection)
|
||||||
{
|
{
|
||||||
CutMesh result;
|
if (its.empty()) return {};
|
||||||
if (its.empty()) return result;
|
std::vector<bool> skip_indicies(its.indices.size(), {false});
|
||||||
|
// cut out opposit triangles
|
||||||
|
set_skip_for_outward_projection(skip_indicies, its, projection);
|
||||||
|
|
||||||
const std::vector<stl_vertex> &vertices = its.vertices;
|
const std::vector<stl_vertex> &vertices = its.vertices;
|
||||||
const std::vector<stl_triangle_vertex_indices> &indices = its.indices;
|
const std::vector<stl_triangle_vertex_indices> &indices = its.indices;
|
||||||
|
@ -780,9 +808,9 @@ priv::CutMesh priv::to_cgal(const indexed_triangle_set &its,
|
||||||
size_t edges_count = 0;
|
size_t edges_count = 0;
|
||||||
|
|
||||||
for (const auto &t : indices) {
|
for (const auto &t : indices) {
|
||||||
if (!is_toward_projection(t, vertices, projection)) continue;
|
|
||||||
++faces_count;
|
|
||||||
size_t index = &t - &indices.front();
|
size_t index = &t - &indices.front();
|
||||||
|
if (skip_indicies[index]) continue;
|
||||||
|
++faces_count;
|
||||||
use_indices[index] = true;
|
use_indices[index] = true;
|
||||||
size_t count_used_vertices = 0;
|
size_t count_used_vertices = 0;
|
||||||
for (const auto vi : t) {
|
for (const auto vi : t) {
|
||||||
|
@ -804,6 +832,8 @@ priv::CutMesh priv::to_cgal(const indexed_triangle_set &its,
|
||||||
assert(vertices_count <= vertices.size());
|
assert(vertices_count <= vertices.size());
|
||||||
assert(edges_count <= (indices.size() * 3) / 2);
|
assert(edges_count <= (indices.size() * 3) / 2);
|
||||||
assert(faces_count <= indices.size());
|
assert(faces_count <= indices.size());
|
||||||
|
|
||||||
|
CutMesh result;
|
||||||
result.reserve(vertices_count, edges_count, faces_count);
|
result.reserve(vertices_count, edges_count, faces_count);
|
||||||
|
|
||||||
std::vector<size_t> to_filtrated_vertices_index(vertices.size());
|
std::vector<size_t> to_filtrated_vertices_index(vertices.size());
|
||||||
|
@ -911,79 +941,76 @@ void priv::set_face_type(FaceTypeMap &face_type_map,
|
||||||
const EcmType &ecm,
|
const EcmType &ecm,
|
||||||
const CutMesh &shape_mesh)
|
const CutMesh &shape_mesh)
|
||||||
{
|
{
|
||||||
|
auto get_face_type = [&mesh, &shape_mesh, &vertex_shape_map](HI hi) -> FaceType {
|
||||||
|
VI vi_from = mesh.source(hi);
|
||||||
|
VI vi_to = mesh.target(hi);
|
||||||
|
// This face has a constrained edge.
|
||||||
|
const IntersectingElement &shape_from = *vertex_shape_map[vi_from];
|
||||||
|
const IntersectingElement &shape_to = *vertex_shape_map[vi_to];
|
||||||
|
|
||||||
|
assert(shape_from.point_index != std::numeric_limits<uint32_t>::max());
|
||||||
|
assert(shape_from.attr != (unsigned char) IntersectingElement::Type::undefined);
|
||||||
|
assert(shape_to.point_index != std::numeric_limits<uint32_t>::max());
|
||||||
|
assert(shape_to.attr != (unsigned char) IntersectingElement::Type::undefined);
|
||||||
|
// assert mean: There is constrained between two shapes
|
||||||
|
// Filip think it can't happens.
|
||||||
|
// consider what to do?
|
||||||
|
assert(shape_from.vertex_base == shape_to.vertex_base);
|
||||||
|
|
||||||
|
bool is_inside = false;
|
||||||
|
// index into contour
|
||||||
|
uint32_t i_from = shape_from.point_index;
|
||||||
|
uint32_t i_to = shape_to.point_index;
|
||||||
|
IntersectingElement::Type type_from = shape_from.get_type();
|
||||||
|
IntersectingElement::Type type_to = shape_to.get_type();
|
||||||
|
if (i_from == i_to && type_from == type_to) {
|
||||||
|
// intersecting element must be face
|
||||||
|
assert(type_from == IntersectingElement::Type::face_1 ||
|
||||||
|
type_from == IntersectingElement::Type::face_2);
|
||||||
|
|
||||||
|
// count of vertices is twice as count of point in the contour
|
||||||
|
uint32_t i = i_from * 2;
|
||||||
|
// j is next contour point in vertices
|
||||||
|
uint32_t j = shape_from.is_last() ? 0 : i + 2;
|
||||||
|
i += shape_from.vertex_base;
|
||||||
|
j += shape_from.vertex_base;
|
||||||
|
|
||||||
|
// opposit point(in triangle face) to edge
|
||||||
|
const auto &p = mesh.point(mesh.target(mesh.next(hi)));
|
||||||
|
|
||||||
|
// abc is source triangle face
|
||||||
|
auto abcp = type_from == IntersectingElement::Type::face_1 ?
|
||||||
|
CGAL::orientation(shape_mesh.point(VI(i)),
|
||||||
|
shape_mesh.point(VI(i + 1)),
|
||||||
|
shape_mesh.point(VI(j)), p) :
|
||||||
|
// type_from == IntersectingElement::Type::face_2
|
||||||
|
CGAL::orientation(shape_mesh.point(VI(j)),
|
||||||
|
shape_mesh.point(VI(i + 1)),
|
||||||
|
shape_mesh.point(VI(j + 1)), p);
|
||||||
|
is_inside = abcp == CGAL::POSITIVE;
|
||||||
|
} else if (i_from < i_to || (i_from == i_to && type_from < type_to)) {
|
||||||
|
bool is_last = shape_to.is_last() && shape_from.is_first();
|
||||||
|
// check continuity of indicies
|
||||||
|
assert(i_from == i_to || is_last || (i_from + 1) == i_to);
|
||||||
|
if (!is_last) is_inside = true;
|
||||||
|
} else {
|
||||||
|
assert(i_from > i_to || (i_from == i_to && type_from > type_to));
|
||||||
|
bool is_last = shape_to.is_first() && shape_from.is_last();
|
||||||
|
// check continuity of indicies
|
||||||
|
assert(i_from == i_to || is_last || (i_to + 1) == i_from);
|
||||||
|
if (is_last) is_inside = true;
|
||||||
|
}
|
||||||
|
return (is_inside) ? FaceType::inside : FaceType::outside;
|
||||||
|
};
|
||||||
|
|
||||||
for (const FI& fi : mesh.faces()) {
|
for (const FI& fi : mesh.faces()) {
|
||||||
FaceType face_type = FaceType::not_constrained;
|
FaceType face_type = FaceType::not_constrained;
|
||||||
HI hi_end = mesh.halfedge(fi);
|
HI hi_end = mesh.halfedge(fi);
|
||||||
HI hi = hi_end;
|
HI hi = hi_end;
|
||||||
do {
|
do {
|
||||||
EI edge_index = mesh.edge(hi);
|
|
||||||
// is edge new created - constrained?
|
// is edge new created - constrained?
|
||||||
if (get(ecm, edge_index)) {
|
if (get(ecm, mesh.edge(hi))) {
|
||||||
VI vi_from = mesh.source(hi);
|
face_type = get_face_type(hi);
|
||||||
VI vi_to = mesh.target(hi);
|
|
||||||
// This face has a constrained edge.
|
|
||||||
const IntersectingElement& shape_from = *vertex_shape_map[vi_from];
|
|
||||||
const IntersectingElement& shape_to = *vertex_shape_map[vi_to];
|
|
||||||
|
|
||||||
assert(shape_from.point_index != std::numeric_limits<uint32_t>::max());
|
|
||||||
assert(shape_from.attr != (unsigned char)IntersectingElement::Type::undefined);
|
|
||||||
assert(shape_to.point_index != std::numeric_limits<uint32_t>::max());
|
|
||||||
assert(shape_to.attr != (unsigned char)IntersectingElement::Type::undefined);
|
|
||||||
|
|
||||||
// assert mean: There is constrained between two shapes
|
|
||||||
// Filip think it can't happens.
|
|
||||||
// consider what to do?
|
|
||||||
assert(shape_from.vertex_base == shape_to.vertex_base);
|
|
||||||
|
|
||||||
bool is_inside = false;
|
|
||||||
|
|
||||||
// index into contour
|
|
||||||
uint32_t i_from = shape_from.point_index;
|
|
||||||
uint32_t i_to = shape_to.point_index;
|
|
||||||
IntersectingElement::Type type_from = shape_from.get_type();
|
|
||||||
IntersectingElement::Type type_to = shape_to.get_type();
|
|
||||||
if (i_from == i_to && type_from == type_to) {
|
|
||||||
// intersecting element must be face
|
|
||||||
assert(type_from == IntersectingElement::Type::face_1 ||
|
|
||||||
type_from == IntersectingElement::Type::face_2);
|
|
||||||
|
|
||||||
// count of vertices is twice as count of point in the contour
|
|
||||||
uint32_t i = i_from * 2;
|
|
||||||
// j is next contour point in vertices
|
|
||||||
uint32_t j = shape_from.is_last() ? 0 : i + 2;
|
|
||||||
i += shape_from.vertex_base;
|
|
||||||
j += shape_from.vertex_base;
|
|
||||||
|
|
||||||
// opposit point(in triangle face) to edge
|
|
||||||
const auto &p = mesh.point(mesh.target(mesh.next(hi)));
|
|
||||||
|
|
||||||
// abc is source triangle face
|
|
||||||
auto abcp =
|
|
||||||
type_from == IntersectingElement::Type::face_1 ?
|
|
||||||
CGAL::orientation(
|
|
||||||
shape_mesh.point(VI(i)),
|
|
||||||
shape_mesh.point(VI(i + 1)),
|
|
||||||
shape_mesh.point(VI(j)), p) :
|
|
||||||
// type_from == IntersectingElement::Type::face_2
|
|
||||||
CGAL::orientation(
|
|
||||||
shape_mesh.point(VI(j)),
|
|
||||||
shape_mesh.point(VI(i + 1)),
|
|
||||||
shape_mesh.point(VI(j + 1)), p);
|
|
||||||
is_inside = abcp == CGAL::POSITIVE;
|
|
||||||
} else if (i_from < i_to || (i_from == i_to && type_from < type_to)) {
|
|
||||||
bool is_last = shape_to.is_last() && shape_from.is_first();
|
|
||||||
// check continuity of indicies
|
|
||||||
assert(i_from == i_to || is_last || (i_from + 1) == i_to);
|
|
||||||
if (!is_last) is_inside = true;
|
|
||||||
} else {
|
|
||||||
assert(i_from > i_to || (i_from == i_to && type_from > type_to));
|
|
||||||
bool is_last = shape_to.is_first() && shape_from.is_last();
|
|
||||||
// check continuity of indicies
|
|
||||||
assert(i_from == i_to || is_last || (i_to + 1) == i_from);
|
|
||||||
if (is_last) is_inside = true;
|
|
||||||
}
|
|
||||||
face_type = (is_inside) ? FaceType::inside :
|
|
||||||
FaceType::outside;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// next half edge index inside of face
|
// next half edge index inside of face
|
||||||
|
@ -998,9 +1025,15 @@ void priv::set_almost_parallel_type(FaceTypeMap &face_type_map,
|
||||||
const Emboss::IProject3f &projection)
|
const Emboss::IProject3f &projection)
|
||||||
{
|
{
|
||||||
for (const FI &fi : mesh.faces()) {
|
for (const FI &fi : mesh.faces()) {
|
||||||
assert(is_toward_projection(fi, mesh, projection));
|
|
||||||
auto &type = face_type_map[fi];
|
auto &type = face_type_map[fi];
|
||||||
if (type != FaceType::inside) continue;
|
if (type != FaceType::inside) continue;
|
||||||
|
//*
|
||||||
|
assert(is_toward_projection(fi, mesh, projection));
|
||||||
|
/*/
|
||||||
|
if (!is_toward_projection(fi, mesh, projection)) {
|
||||||
|
type = FaceType::outside;
|
||||||
|
}else
|
||||||
|
// */
|
||||||
if (is_almost_parallel(fi, mesh, projection))
|
if (is_almost_parallel(fi, mesh, projection))
|
||||||
// change type
|
// change type
|
||||||
type = FaceType::inside_parallel;
|
type = FaceType::inside_parallel;
|
||||||
|
@ -1248,7 +1281,7 @@ void priv::create_reduce_map(ReductionMap &reduction_map,
|
||||||
// initialize reduction map
|
// initialize reduction map
|
||||||
for (VI reduction_from : mesh.vertices())
|
for (VI reduction_from : mesh.vertices())
|
||||||
reduction_map[reduction_from] = reduction_from;
|
reduction_map[reduction_from] = reduction_from;
|
||||||
|
|
||||||
// check if vertex was made by edge_2 which is diagonal of quad
|
// check if vertex was made by edge_2 which is diagonal of quad
|
||||||
auto is_reducible_vertex = [&vert_shape_map](VI reduction_from) -> bool {
|
auto is_reducible_vertex = [&vert_shape_map](VI reduction_from) -> bool {
|
||||||
const IntersectingElement *ie = vert_shape_map[reduction_from];
|
const IntersectingElement *ie = vert_shape_map[reduction_from];
|
||||||
|
@ -1316,6 +1349,14 @@ SurfaceCut priv::create_index_triangle_set(const std::vector<FI> &faces,
|
||||||
const ReductionMap &reduction_map,
|
const ReductionMap &reduction_map,
|
||||||
ConvertMap &v2v)
|
ConvertMap &v2v)
|
||||||
{
|
{
|
||||||
|
// clear v2v
|
||||||
|
// more than one cut can share vertex and each cut need its own conversion
|
||||||
|
for (FI fi : faces) {
|
||||||
|
HI hi = mesh.halfedge(fi);
|
||||||
|
for (VI vi : {mesh.source(hi), mesh.target(hi), mesh.target(mesh.next(hi))})
|
||||||
|
v2v[vi] = std::numeric_limits<SurfaceCut::Index>::max();
|
||||||
|
}
|
||||||
|
|
||||||
// IMPROVE: use reduced count of faces and outlines
|
// IMPROVE: use reduced count of faces and outlines
|
||||||
size_t indices_size = faces.size();
|
size_t indices_size = faces.size();
|
||||||
size_t vertices_size = (indices_size * 3 - count_outlines / 2) / 2;
|
size_t vertices_size = (indices_size * 3 - count_outlines / 2) / 2;
|
||||||
|
@ -1645,7 +1686,7 @@ SurfaceCuts priv::create_surface_cuts(const CutAOIs &cuts,
|
||||||
// convert_map could be used separately for each surface cut.
|
// convert_map could be used separately for each surface cut.
|
||||||
// But it is moore faster to use one memory allocation for them all.
|
// But it is moore faster to use one memory allocation for them all.
|
||||||
SurfaceCut sc = create_index_triangle_set(faces, outlines.size(), mesh, reduction_map, convert_map);
|
SurfaceCut sc = create_index_triangle_set(faces, outlines.size(), mesh, reduction_map, convert_map);
|
||||||
|
|
||||||
// connect outlines
|
// connect outlines
|
||||||
sc.contours = create_cut(outlines, mesh, reduction_map, convert_map);
|
sc.contours = create_cut(outlines, mesh, reduction_map, convert_map);
|
||||||
result.emplace_back(std::move(sc));
|
result.emplace_back(std::move(sc));
|
||||||
|
|
|
@ -17,8 +17,8 @@ namespace Slic3r{
|
||||||
/// </summary>
|
/// </summary>
|
||||||
struct SurfaceCut : public indexed_triangle_set
|
struct SurfaceCut : public indexed_triangle_set
|
||||||
{
|
{
|
||||||
// connected cutted surface
|
// connected cutted surface --> inheritance is used
|
||||||
indexed_triangle_set mesh;
|
//indexed_triangle_set mesh;
|
||||||
|
|
||||||
// vertex indices(index to mesh vertices)
|
// vertex indices(index to mesh vertices)
|
||||||
using Index = unsigned int;
|
using Index = unsigned int;
|
||||||
|
|
|
@ -49,6 +49,14 @@ static TriangleMesh create_default_mesh();
|
||||||
/// <param name="data">Text configuration, ...</param>
|
/// <param name="data">Text configuration, ...</param>
|
||||||
static void update_volume(TriangleMesh &&mesh, const EmbossDataUpdate &data);
|
static void update_volume(TriangleMesh &&mesh, const EmbossDataUpdate &data);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// extract scale in 2d
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="fp">Property of font style</param>
|
||||||
|
/// <param name="ff">Font file for size --> unit per em</param>
|
||||||
|
/// <returns>scaling factor</returns>
|
||||||
|
static double get_shape_scale(const FontProp &fp, const Emboss::FontFile &ff);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Create projection for cut surface from mesh
|
/// Create projection for cut surface from mesh
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -335,6 +343,8 @@ void UseSurfaceJob::finalize(bool canceled, std::exception_ptr &)
|
||||||
{
|
{
|
||||||
if (canceled || m_input.cancel->load()) return;
|
if (canceled || m_input.cancel->load()) return;
|
||||||
priv::update_volume(std::move(m_result), m_input);
|
priv::update_volume(std::move(m_result), m_input);
|
||||||
|
// TODO: use fix matrix to compensate uncentered position
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////
|
////////////////////////////
|
||||||
|
@ -444,7 +454,7 @@ void priv::update_volume(TriangleMesh &&mesh,
|
||||||
canvas->reload_scene(refresh_immediately);
|
canvas->reload_scene(refresh_immediately);
|
||||||
}
|
}
|
||||||
|
|
||||||
static double get_shape_scale(const FontProp &fp, const Emboss::FontFile &ff)
|
static double priv::get_shape_scale(const FontProp &fp, const Emboss::FontFile &ff)
|
||||||
{
|
{
|
||||||
const auto &cn = fp.collection_number;
|
const auto &cn = fp.collection_number;
|
||||||
unsigned int font_index = (cn.has_value()) ? *cn : 0;
|
unsigned int font_index = (cn.has_value()) ? *cn : 0;
|
||||||
|
|
Loading…
Add table
Reference in a new issue