Fix of flood fill on edge
This commit is contained in:
parent
d0dd074937
commit
51b103885c
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user