From e5bf946008a40bfedbfe86106deed27df56163da Mon Sep 17 00:00:00 2001
From: Filip Sykala <filip.sykala@prusa3d.cz>
Date: Tue, 3 May 2022 13:05:58 +0200
Subject: [PATCH] Fix filtering order of AOIs

---
 src/libslic3r/CutSurface.cpp    | 127 ++++++++++++++++++++++++++++----
 tests/libslic3r/test_emboss.cpp |  12 +--
 2 files changed, 119 insertions(+), 20 deletions(-)

diff --git a/src/libslic3r/CutSurface.cpp b/src/libslic3r/CutSurface.cpp
index b236a2ae1..6c00ed33d 100644
--- a/src/libslic3r/CutSurface.cpp
+++ b/src/libslic3r/CutSurface.cpp
@@ -1,5 +1,18 @@
 #include "CutSurface.hpp"
 
+/// model.off - CGAL model created from index_triangle_set
+/// shape.off - CGAL model created from shapes
+/// constrained.off - Visualization of inside and outside triangles
+///    Green - not along constrained edge
+///    Red - sure that are inside
+///    Purple - sure that are outside
+/// filled.off - flood fill green triangles inside of red area
+///            - Same meaning of color as constrained
+/// reduction.off - Visualization of reduced and non-reduced Vertices
+/// aois/cutAOI{N}.obj - Cuted Area of interest from corefined model
+/// cuts/cut{N}.obj - Filtered surface cuts + Reduced vertices made by e2 (text_edge_2)
+//#define DEBUG_OUTPUT_DIR std::string("C:/data/temp/")
+
 using namespace Slic3r;
 
 void Slic3r::append(SurfaceCut &sc, SurfaceCut &&sc_add)
@@ -401,6 +414,10 @@ SurfaceCut::CutContour create_cut(const std::vector<HI> &outlines,
                                const ReductionMap &reduction_map,
                                const ConvertMap      &v2v);
 
+#ifdef DEBUG_OUTPUT_DIR
+indexed_triangle_set create_indexed_triangle_set(const std::vector<FI> &faces,
+                                                 const CutMesh         &mesh);
+
 /// <summary>
 /// Debug purpose store of mesh with colored face by face type
 /// </summary>
@@ -410,20 +427,30 @@ SurfaceCut::CutContour create_cut(const std::vector<HI> &outlines,
 /// <param name="file">File to store</param>
 void store(CutMesh &mesh, const FaceTypeMap &face_type_map, const std::string &file);
 void store(CutMesh &mesh, const ReductionMap &reduction_map, const std::string &file);
-void store(const SurfaceCuts &cut, const std::string &file_prefix);
+void store(const CutAOIs &aois, const CutMesh &mesh, const std::string &dir);
+void store(const SurfaceCuts &cut, const std::string &dir);
+#endif // DEBUG_OUTPUT_DIR
+
 } // namespace privat
 
+
 SurfaceCuts Slic3r::cut_surface(const indexed_triangle_set &model,
                                 const ExPolygons           &shapes,
                                 const Emboss::IProject     &projection)
 {
     priv::CutMesh cgal_model = priv::to_cgal(model);
-    CGAL::IO::write_OFF("C:/data/temp/model.off", cgal_model); // only debug
+
+#ifdef DEBUG_OUTPUT_DIR
+    CGAL::IO::write_OFF(DEBUG_OUTPUT_DIR + "model.off", cgal_model); // only debug
+#endif // DEBUG_OUTPUT_DIR
 
     std::string edge_shape_map_name = "e:IntersectingElement";
     std::string face_shape_map_name = "f:IntersectingElement";
-    priv::CutMesh cgal_shape = priv::to_cgal(shapes, projection, edge_shape_map_name, face_shape_map_name);   
-    CGAL::IO::write_OFF("C:/data/temp/shape.off", cgal_shape); // only debug
+    priv::CutMesh cgal_shape = priv::to_cgal(shapes, projection, edge_shape_map_name, face_shape_map_name);
+
+#ifdef DEBUG_OUTPUT_DIR
+    CGAL::IO::write_OFF(DEBUG_OUTPUT_DIR + "shape.off", cgal_shape); // only debug
+#endif // DEBUG_OUTPUT_DIR
 
     auto edge_shape_map = cgal_shape.property_map<priv::EI, priv::IntersectingElement>(edge_shape_map_name).first;    
     auto face_shape_map = cgal_shape.property_map<priv::FI, priv::IntersectingElement>(face_shape_map_name).first;
@@ -453,19 +480,32 @@ SurfaceCuts Slic3r::cut_surface(const indexed_triangle_set &model,
 
     // Select inside and outside face in model
     priv::set_face_type(face_type_map, cgal_model, vert_shape_map, ecm, projection, cgal_shape);
-    priv::store(cgal_model, face_type_map, "C:/data/temp/constrained.off"); // only debug
+
+#ifdef DEBUG_OUTPUT_DIR
+    priv::store(cgal_model, face_type_map, DEBUG_OUTPUT_DIR + "constrained.off"); // only debug
+#endif // DEBUG_OUTPUT_DIR
     
     // Seed fill the other faces inside the region.
     priv::flood_fill_inner(cgal_model, projection, face_type_map);
-    priv::store(cgal_model, face_type_map, "C:/data/temp/filled.off"); // only debug
+
+#ifdef DEBUG_OUTPUT_DIR
+    priv::store(cgal_model, face_type_map, DEBUG_OUTPUT_DIR + "filled.off"); // only debug
+#endif // DEBUG_OUTPUT_DIR
 
     std::string vertex_reduction_map_name = "v:reduction";
     priv::ReductionMap vertex_reduction_map = cgal_model.add_property_map<priv::VI, priv::VI>(vertex_reduction_map_name).first;
     priv::create_reduce_map(vertex_reduction_map, cgal_model, face_type_map, vert_shape_map);
-    priv::store(cgal_model, vertex_reduction_map, "C:/data/temp/reduction.off"); // only debug
+
+#ifdef DEBUG_OUTPUT_DIR
+    priv::store(cgal_model, vertex_reduction_map, DEBUG_OUTPUT_DIR + "reduction.off"); // only debug
+#endif // DEBUG_OUTPUT_DIR
 
     priv::CutAOIs cutAOIs = create_cut_area_of_interests(cgal_model, shapes, face_type_map);
 
+#ifdef DEBUG_OUTPUT_DIR
+    priv::store(cutAOIs, cgal_model, DEBUG_OUTPUT_DIR + "aois/"); // only debug
+#endif // DEBUG_OUTPUT_DIR
+
     // Filter out NO top one cuts
     priv::filter_cuts(cutAOIs, cgal_model, shapes, projection, vert_shape_map);
 
@@ -474,8 +514,10 @@ SurfaceCuts Slic3r::cut_surface(const indexed_triangle_set &model,
     std::string vertec_convert_map_name = "v:convert";
     priv::ConvertMap vertex_convert_map = cgal_model.add_property_map<priv::VI, SurfaceCut::Index>(vertec_convert_map_name).first;    
     SurfaceCuts result = priv::create_surface_cuts(cutAOIs, cgal_model, vertex_reduction_map, vertex_convert_map);
-        
-    priv::store(result, "C:/data/temp/cut"); // only debug
+    
+#ifdef DEBUG_OUTPUT_DIR
+    priv::store(result, DEBUG_OUTPUT_DIR + "cuts/"); // only debug
+#endif // DEBUG_OUTPUT_DIR
     
     // TODO: Filter surfaceCuts to only the top most.
     return result;
@@ -1355,7 +1397,7 @@ void priv::filter_cuts(CutAOIs              &cuts,
         Vec3f act_point(act.x(), act.y(), act.z());
         float act_sq_norm = (source_point - act_point).squaredNorm();
         
-        if (act_sq_norm > prev_sq_norm) {
+        if (act_sq_norm < prev_sq_norm) {
             del_cuts[cut_index] = true;
             return true;
         }
@@ -1412,7 +1454,7 @@ SurfaceCuts priv::create_surface_cuts(const CutAOIs      &cuts,
     return result;
 }
 
-// only for debug
+#ifdef DEBUG_OUTPUT_DIR
 void priv::store(CutMesh &mesh, const FaceTypeMap &face_type_map, const std::string& file)
 {
     auto face_colors = mesh.add_property_map<priv::FI, CGAL::Color>("f:color").first;    
@@ -1448,10 +1490,67 @@ void priv::store(CutMesh &mesh, const ReductionMap &reduction_map, const std::st
     mesh.remove_property_map(vertex_colors);
 }
 
-void priv::store(const SurfaceCuts &cut, const std::string &file_prefix) {
-    for (auto &c : cut) {
+indexed_triangle_set priv::create_indexed_triangle_set(
+    const std::vector<FI> &faces, const CutMesh &mesh)
+{
+    std::vector<VI> vertices;
+    vertices.reserve(faces.size() * 2);
+
+    indexed_triangle_set its;
+    its.indices.reserve(faces.size());
+    for (FI fi : faces) {
+        HI hi     = mesh.halfedge(fi);
+        HI hi_end = hi;
+
+        int   ti = 0;
+        Vec3i t;
+
+        do {
+            VI   vi  = mesh.source(hi);
+            auto res = std::find(vertices.begin(), vertices.end(), vi);
+            t[ti++]  = res - vertices.begin();
+            if (res == vertices.end()) vertices.push_back(vi);
+            hi = mesh.next(hi);
+        } while (hi != hi_end);
+
+        its.indices.push_back(t);
+    }
+
+    its.vertices.reserve(vertices.size());
+    for (VI vi : vertices) {
+        const auto &p = mesh.point(vi);
+        its.vertices.emplace_back(p.x(), p.y(), p.z());
+    }
+    return its;
+}
+
+#include <filesystem>
+static void prepare_dir(const std::string &dir) {
+    namespace fs = std::filesystem;
+    if (fs::exists(dir)) {
+        for (auto &path : fs::directory_iterator(dir))
+            fs::remove_all(path);
+    } else {
+        fs::create_directories(dir);
+    }
+}
+
+void priv::store(const CutAOIs &aois, const CutMesh &mesh, const std::string &dir) {
+    prepare_dir(dir);
+    for (const auto &aoi : aois) {
+        size_t      index = &aoi - &aois.front();
+        std::string file  = dir + "aoi" + std::to_string(index) + ".obj";
+        indexed_triangle_set its = create_indexed_triangle_set(aoi.first, mesh);
+        its_write_obj(its, file.c_str());
+        // TODO: Store outline from half edge somehow
+    }
+}
+
+void priv::store(const SurfaceCuts &cut, const std::string &dir) {
+    for (const auto &c : cut) {
         size_t index = &c - &cut.front();
-        std::string file  = file_prefix + std::to_string(index) + ".obj";
+        std::string file  = dir + "cut" + std::to_string(index) + ".obj";
         its_write_obj(c, file.c_str());  
     }
 }
+#endif // DEBUG_OUTPUT_DIR
diff --git a/tests/libslic3r/test_emboss.cpp b/tests/libslic3r/test_emboss.cpp
index a794c6e83..5ea785565 100644
--- a/tests/libslic3r/test_emboss.cpp
+++ b/tests/libslic3r/test_emboss.cpp
@@ -316,26 +316,26 @@ TEST_CASE("Cut surface", "[]")
     REQUIRE(!shape.empty());
 
     Transform3d tr = Transform3d::Identity();
-    tr.translate(Vec3d(0., 0., z_depth));
+    tr.translate(Vec3d(0., 0., -z_depth));
     tr.scale(Emboss::SHAPE_SCALE);
-    Emboss::OrthoProject cut_projection(tr, Vec3f(0.f, 0.f, -50));
+    Emboss::OrthoProject cut_projection(tr, Vec3f(0.f, 0.f, z_depth));
 
     auto object = its_make_cube(782 - 49 + 50, 724 + 10 + 50, 5);
-    its_translate(object, Vec3f(49 - 25, -10 - 25, 2.5));
+    its_translate(object, Vec3f(49 - 25, -10 - 25, -40));
     auto cube2 = object; // copy
-    its_translate(cube2, Vec3f(100, -40, 40));
+    its_translate(cube2, Vec3f(100, -40, 7.5));
     its_merge(object, std::move(cube2));
 
     auto surfaces = cut_surface(object, shape, cut_projection);
     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));
     for (auto &surface : surfaces)
         its_translate(surface, Vec3f(0.f, 0.f, 10));
 
     indexed_triangle_set its = cuts2model(surfaces, projection);
     CHECK(!its.empty());
-    its_write_obj(its, "C:/data/temp/projected.obj");
+    //its_write_obj(its, "C:/data/temp/projected.obj");
 }