Fix of flood fill on edge

This commit is contained in:
Filip Sykala 2022-05-02 17:29:56 +02:00
parent d0dd074937
commit 51b103885c
3 changed files with 51 additions and 49 deletions

View File

@ -692,10 +692,10 @@ priv::CutMesh priv::to_cgal(const ExPolygons &shapes,
bool is_last = size_t(i + 2) >= indices.size();
int32_t j = is_last ? 0 : (i + 2);
auto fi1 = result.add_face(indices[i], indices[i + 1], indices[j]);
auto ei1 = find_edge(fi1, indices[i], indices[i + 1]);
auto ei2 = find_edge(fi1, indices[i + 1], indices[j]);
auto fi2 = result.add_face(indices[j], indices[i + 1], indices[j + 1]);
auto fi1 = result.add_face(indices[i], indices[j], indices[i + 1]);
auto ei1 = find_edge(fi1, indices[i + 1], indices[i]);
auto ei2 = find_edge(fi1, indices[j], indices[i + 1]);
auto fi2 = result.add_face(indices[j], indices[j + 1], indices[i + 1]);
uint32_t vertex_base = static_cast<uint32_t>(num_vertices_old);
IntersectingElement element {vertex_base, contour_index, (unsigned char)IntersectingElement::Type::undefined};
if (is_first) element.set_is_first();
@ -786,7 +786,7 @@ void priv::set_face_type(FaceTypeMap &face_type_map,
shape_mesh.point(VI(j)),
shape_mesh.point(VI(i + 1)),
shape_mesh.point(VI(j + 1)), p);
is_inside = abcp == CGAL::NEGATIVE;
is_inside = abcp == CGAL::POSITIVE;
} else if (i_from < i_to || (i_from == i_to && type_from < type_to)) {
// TODO: check that it is continous indices of contour
bool is_last = shape_from.is_first() && shape_to.is_last() &&
@ -819,17 +819,18 @@ bool priv::is_toward_projection(FI fi,
const CutMesh &mesh,
const Project &projection)
{
HI hi = mesh.halfedge(fi);
const auto &a = mesh.point(mesh.source(hi));
const auto &b = mesh.point(mesh.target(hi));
const auto &c = mesh.point(mesh.target(mesh.next(hi)));
using P3 = CGAL::Epick::Point_3;
HI hi = mesh.halfedge(fi);
const P3 &a = mesh.point(mesh.source(hi));
const P3 &b = mesh.point(mesh.target(hi));
const P3 &c = mesh.point(mesh.target(mesh.next(hi)));
Vec3f a_(a.x(), a.y(), a.z());
Vec3f p_ = projection.project(a_);
CGAL::Epick::Point_3 p{p_.x(), p_.y(), p_.z()};
P3 p{p_.x(), p_.y(), p_.z()};
return CGAL::orientation(a, b, c, p) == CGAL::NEGATIVE;
return CGAL::orientation(a, b, c, p) == CGAL::POSITIVE;
}
@ -837,15 +838,16 @@ void priv::flood_fill_inner(const CutMesh &mesh,
const Project &projection,
FaceTypeMap &face_type_map)
{
for (FI fi : mesh.faces()) {
if (face_type_map[fi] != FaceType::not_constrained) continue;
std::vector<FI> process;
// guess count of connected not constrained triangles
size_t guess_size = 128;
process.reserve(guess_size);
// check if neighbor(one of three in triangle) has type inside
bool has_inside_neighbor = false;
// check if neighbor(one of three in triangle) has type inside
auto has_inside_neighbor = [&mesh, &face_type_map](FI fi) {
HI hi = mesh.halfedge(fi);
HI hi_end = hi;
// list of other not constrained neighbors
std::queue<FI> queue;
// loop over 3 half edges of face
do {
HI hi_opposite = mesh.opposite(hi);
// open edge doesn't have opposit half edge
@ -854,22 +856,25 @@ void priv::flood_fill_inner(const CutMesh &mesh,
continue;
}
FI fi_opposite = mesh.face(hi_opposite);
FaceType side = face_type_map[fi_opposite];
if (side == FaceType::inside) {
has_inside_neighbor = true;
} else if (side == FaceType::not_constrained) {
queue.emplace(fi_opposite);
}
if (face_type_map[fi_opposite] == FaceType::inside) return true;
hi = mesh.next(hi);
} while (hi != hi_end);
return false;
};
for (FI fi : mesh.faces()) {
if (face_type_map[fi] != FaceType::not_constrained) continue;
if (!has_inside_neighbor(fi)) continue;
if (!is_toward_projection(fi, mesh, projection)) {
face_type_map[fi] = FaceType::outside;
continue;
}
assert(process.empty());
process.push_back(fi);
if (!has_inside_neighbor) continue;
face_type_map[fi] = FaceType::inside;
while (!queue.empty()) {
FI fi = queue.front();
queue.pop();
while (!process.empty()) {
FI fi = process.back();
process.pop_back();
// Do not fill twice
if (face_type_map[fi] == FaceType::inside) continue;
face_type_map[fi] = FaceType::inside;
@ -888,7 +893,7 @@ void priv::flood_fill_inner(const CutMesh &mesh,
FaceType &side = face_type_map[fi_opposite];
if (side == FaceType::not_constrained) {
if (is_toward_projection(fi_opposite, mesh, projection)) {
queue.emplace(fi_opposite);
process.push_back(fi_opposite);
} else {
// Is in opposit direction
side = FaceType::outside;
@ -1006,13 +1011,13 @@ void priv::create_reduce_map(ReductionMap &reduction_map,
const FaceTypeMap &face_type_map,
const VertexShapeMap &vert_shape_map)
{
// IMPROVE: find better way to initialize or try use std::map
// IMPROVE: find better way to initialize
// initialize reduction map
for (VI reduction_from : mesh.vertices())
reduction_map[reduction_from] = reduction_from;
// check if vertex was made by edge_2 which is diagonal of quad
auto is_reducible_vertex = [&vert_shape_map, &mesh](VI reduction_from) -> bool {
auto is_reducible_vertex = [&vert_shape_map](VI reduction_from) -> bool {
const IntersectingElement *ie = vert_shape_map[reduction_from];
if (ie == nullptr) return false;
IntersectingElement::Type type = ie->get_type();
@ -1023,9 +1028,9 @@ void priv::create_reduce_map(ReductionMap &reduction_map,
/// Append reduction or change existing one.
/// </summary>
/// <param name="hi">HalEdge between outside and inside face.
/// Target vertex will be reduced
/// Source vertex left</param>
auto add_reduction = [&reduction_map, &mesh, &is_reducible_vertex, &face_type_map]
/// Target vertex will be reduced, source vertex left</param>
/// [[maybe_unused]] &face_type_map, &is_reducible_vertex are need only in debug
auto add_reduction = [&] //&reduction_map, &mesh, &face_type_map, &is_reducible_vertex
(HI hi) {
VI erase = mesh.target(hi);
VI left = mesh.source(hi);
@ -1055,9 +1060,6 @@ void priv::create_reduce_map(ReductionMap &reduction_map,
do {
VI reduction_from = mesh.target(hi);
if (is_reducible_vertex(reduction_from)) {
// reducible vertex
VI vi_from = mesh.target(hi);
// halfedges connected with reduction_from
HI hi1 = hi;
HI hi2 = mesh.next(hi);
@ -1100,7 +1102,6 @@ SurfaceCut priv::create_index_triangle_set(const std::vector<FI> &faces,
bool exist_reduction = false;
do {
VI vi = mesh.source(hi);
VI vi_r = reduction_map[vi];
if (vi_r != vi) {
exist_reduction = true;

View File

@ -826,6 +826,7 @@ ModelVolume *GLGizmoEmboss::get_selected_volume(const Selection &selection,
return get_model_volume(vol_gl, objects);
}
// Run Job on main thread (blocking) - ONLY DEBUG
static inline void execute_job(std::shared_ptr<Job> j)
{
struct MyCtl : public Job::Ctl
@ -1005,12 +1006,12 @@ std::unique_ptr<Emboss::IProject> create_projection_for_cut(
// X .. from left to right
// Y .. from bottom to top
// Z .. from text to eye
Vec3d untransformed_direction(0., 0., -projection_size);
Vec3d untransformed_direction(0., 0., projection_size);
Vec3f project_direction =
(transformation_for_vector * untransformed_direction).cast<float>();
// Projection is in direction from far plane
tr.translate(Vec3d(0., 0., max_z));
tr.translate(Vec3d(0., 0., min_z));
tr.scale(get_shape_scale(tc.font_item.prop, ff));
// Text alignemnt to center 2D
@ -1035,7 +1036,7 @@ static std::unique_ptr<Emboss::IProject> create_emboss_projection(
SurfaceCut &cut)
{
// Offset of clossed side to model
const float surface_offset = 1e-3; // [in mm]
const float surface_offset = 1e-3f; // [in mm]
const FontProp &fp = tc.font_item.prop;
float front_move, back_move;

View File

@ -567,7 +567,7 @@ indexed_triangle_set cut_shape(const indexed_triangle_set &source,
const ExPolygon &shape,
const Emboss::IProject &projection)
{
throw std::exception("NOT implemented yet");
// NOT implemented yet
return {};
}
@ -645,8 +645,8 @@ TEST_CASE("Emboss extrude cut", "[Emboss-Cut]")
// identify glyph for intersected vertex
std::string vert_shape_map_name = "v:glyph_id";
MyMesh cgal_object = MeshBoolean::cgal2::to_cgal(cube, face_map_name);
auto& face_map = cgal_object.property_map<MyMesh::Face_index, int32_t>(face_map_name).first;
auto& vert_shape_map = cgal_object.add_property_map<MyMesh::Vertex_index, IntersectingElemnt>(vert_shape_map_name).first;
auto face_map = cgal_object.property_map<MyMesh::Face_index, int32_t>(face_map_name).first;
auto vert_shape_map = cgal_object.add_property_map<MyMesh::Vertex_index, IntersectingElemnt>(vert_shape_map_name).first;
std::string edge_shape_map_name = "e:glyph_id";
std::string face_shape_map_name = "f:glyph_id";
@ -654,8 +654,8 @@ TEST_CASE("Emboss extrude cut", "[Emboss-Cut]")
MyMesh cgal_shape = MeshBoolean::cgal2::to_cgal(shape, projection, 0, edge_shape_map_name, face_shape_map_name, glyph_contours);
auto& edge_shape_map = cgal_shape.property_map<MyMesh::Edge_index, IntersectingElemnt>(edge_shape_map_name).first;
auto& face_shape_map = cgal_shape.property_map<MyMesh::Face_index, IntersectingElemnt>(face_shape_map_name).first;
auto edge_shape_map = cgal_shape.property_map<MyMesh::Edge_index, IntersectingElemnt>(edge_shape_map_name).first;
auto face_shape_map = cgal_shape.property_map<MyMesh::Face_index, IntersectingElemnt>(face_shape_map_name).first;
// bool map for affected edge
using d_prop_bool = CGAL::dynamic_edge_property_t<bool>;
@ -835,10 +835,10 @@ TEST_CASE("Emboss extrude cut", "[Emboss-Cut]")
p);
is_inside = abcp == CGAL::POSITIVE;
} else if (i_from < i_to || (i_from == i_to && shape_from.type < shape_to.type)) {
bool is_last = i_from == 0 && (i_to + 1) == contour.size();
bool is_last = i_from == 0 && static_cast<size_t>(i_to + 1) == contour.size();
if (!is_last) is_inside = true;
} else { // i_from > i_to || (i_from == i_to && shape_from.type > shape_to.type)
bool is_last = i_to == 0 && (i_from + 1) == contour.size();
bool is_last = i_to == 0 && static_cast<size_t>(i_from + 1) == contour.size();
if (is_last) is_inside = true;
}