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;