diff --git a/.github/workflows/continuous.yml b/.github/workflows/continuous.yml index efe02cc3..aefedeae 100644 --- a/.github/workflows/continuous.yml +++ b/.github/workflows/continuous.yml @@ -18,27 +18,22 @@ jobs: #################### Unix: - name: ${{ matrix.name }}-${{ matrix.envelope }} (${{ matrix.config }}) - runs-on: ${{ matrix.os }} + name: ${{ matrix.os }}-${{ matrix.envelope }} (${{ matrix.config }}) + runs-on: ${{ matrix.os }}-latest strategy: fail-fast: false matrix: - os: [ubuntu-18.04, macos-latest] + os: [ubuntu, macos] config: [Debug, Release] envelope: [ON, OFF] - include: - - os: macos-latest - name: macOS - - os: ubuntu-18.04 - name: Linux steps: - name: Checkout repository - uses: actions/checkout@v1 + uses: actions/checkout@v3 with: fetch-depth: 10 - name: Dependencies (Linux) - if: runner.os == 'Linux' + if: matrix.os == 'ubuntu' run: | sudo apt-get update sudo apt-get install \ @@ -52,15 +47,15 @@ jobs: ccache - name: Dependencies (macOS) - if: runner.os == 'macOS' + if: matrix.os == 'macos' run: brew install suite-sparse ccache gmp - name: Cache Build id: cache-build - uses: actions/cache@v1 + uses: actions/cache@v3 with: path: ~/.ccache - key: ${{ runner.os }}-${{ matrix.config }}-${{ matrix.envelope }}-cache + key: ${{ matrix.os }}-${{ matrix.config }}-${{ matrix.envelope }}-cache - name: Prepare ccache run: | @@ -90,8 +85,8 @@ jobs: #################### Windows: - name: Windows-${{ matrix.envelope }} (${{ matrix.config }}) - runs-on: windows-2019 + name: windows-${{ matrix.envelope }} (${{ matrix.config }}) + runs-on: windows-latest env: CC: cl.exe CXX: cl.exe @@ -114,7 +109,7 @@ jobs: conda install -c conda-forge mpir -y - name: Checkout repository - uses: actions/checkout@v1 + uses: actions/checkout@v3 with: fetch-depth: 10 - uses: seanmiddleditch/gha-setup-ninja@master @@ -127,14 +122,15 @@ jobs: - name: Cache build id: cache-build - uses: actions/cache@v1 + uses: actions/cache@v3 with: path: ${{ env.appdata }}\Mozilla\sccache - key: ${{ runner.os }}-${{ matrix.config }}-${{ matrix.envelope }}-cache + key: ${{ matrix.os }}-${{ matrix.config }}-${{ matrix.envelope }}-cache - name: Prepare sccache run: | - Invoke-Expression (New-Object System.Net.WebClient).DownloadString('https://get.scoop.sh') + irm get.scoop.sh -outfile 'install.ps1' + .\install.ps1 -RunAsAdmin scoop install sccache --global # Scoop modifies the PATH so we make it available for the next steps of the job echo "${env:PATH}" >> ${env:GITHUB_PATH} @@ -142,7 +138,7 @@ jobs: - name: Configure and build shell: cmd run: | - call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\Common7\Tools\VsDevCmd.bat" -arch=x64 + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\Common7\Tools\VsDevCmd.bat" -arch=x64 cmake --version cmake -G Ninja ^ -DCMAKE_CXX_COMPILER_LAUNCHER=sccache ^ @@ -162,6 +158,6 @@ jobs: shell: powershell run: | cd build - cp C:\Miniconda\Library\bin\mpir.dll .\ - cp C:\Miniconda\Library\bin\gmp.dll .\ + cp C:\Miniconda\envs\__setup_conda\Library\bin\mpir.dll .\ + cp C:\Miniconda\envs\__setup_conda\Library\bin\gmp.dll .\ .\FloatTetwild_bin.exe --input ..\tests\bunny.off --level 0 --stop-energy 200 diff --git a/README.md b/README.md index b5dcafcd..f46d1f68 100644 --- a/README.md +++ b/README.md @@ -85,9 +85,9 @@ sudo apt-get install gmp conda install -c conda-forge mpir ``` -**Note Windows** The executable needs that the file `mpir.dll` is in the same directiory of `FloatTetwild_bin.exe`. Once you compliled the code, copy `mpir.dll` (e.g., `\Library\bin`) to the directoy containing `FloatTetwild_bin.exe`. +**Note Windows** The executable needs that the file `mpir.dll` is in the same directory as `FloatTetwild_bin.exe`. Once you compiled the code, copy `mpir.dll` (e.g., `\Library\bin`) to the directory containing `FloatTetwild_bin.exe`. -**Note** if cmake cannot find gmp you need to export the envirnement variable `GMP_INC` and `GMP_LIB` to the folder where you installed (e.g., `\Library\include` for `GMP_INC` and `\Library\lib` for `GMP_LIB`). +**Note** if cmake cannot find gmp you need to export the environment variable `GMP_INC` and `GMP_LIB` to the folder where you installed (e.g., `\Library\include` for `GMP_INC` and `\Library\lib` for `GMP_LIB`). - Check the installation: @@ -102,7 +102,7 @@ This command should show a list of fTetWild parameters. The inputs of our software are triangle surface meshes in `.off/.obj/.stl/.ply` format. -We support `.mesh/.msh` format output. The default output format is `.msh` with minimum dihedral angle recorded as element scalar field, which can be visualized by software [Gmsh](http://gmsh.info/). You can use `PyMesh::MshLoader` and `PyMesh::MshSaver` in `pymesh/` for read and write `.msh` meshes. +We support `.mesh/.msh` format output. The default output format is `.msh` with the elements' energy as the scalar field, which can be visualized by software [Gmsh](http://gmsh.info/). You can use `PyMesh::MshLoader` and `PyMesh::MshSaver` in `pymesh/` for read and write `.msh` meshes. ### Features @@ -134,7 +134,7 @@ Users can provide a background tetmesh in .msh format with vertex scalar field v - Smoothing open regions -Our method can fill gaps and holes but the tetmesh faces on those parts could be bumpy. We provide users an option to do Lapacian smoothing on those faces to get a smoother surface. +Our method can fill gaps and holes but the tetmesh faces on those parts could be bumpy. We provide users an option to do Laplacian smoothing on those faces to get a smoother surface. ### Command Line Switches Our software supports usage via command line or via a C++ function wrapper. Here is an overview of all command line switches: @@ -150,7 +150,7 @@ Options: --op INT Boolean operation: 0: union, 1: intersection, 2: difference. -l,--lr FLOAT ideal_edge_length = diag_of_bbox * L. (double, optional, default: 0.05) -e,--epsr FLOAT epsilon = diag_of_bbox * EPS. (double, optional, default: 1e-3) - --stop-energy FLOAT Stop optimization when max energy is lower than this. + --stop-energy FLOAT Stop optimization when max energy is lower than this. (double, optional, default: 10.0) --log TEXT Log info to given file. --level INT Log level (0 = most verbose, 6 = off). -q,--is-quiet Mute console output. (optional) diff --git a/src/Mesh.cpp b/src/Mesh.cpp index 85b171a8..4036ecf7 100644 --- a/src/Mesh.cpp +++ b/src/Mesh.cpp @@ -101,7 +101,7 @@ namespace floatTetWild { } - void Mesh::one_ring_edge_set(const std::vector> &edges, const std::vector& v_is_removed, const std::vector& f_is_removed, + void Mesh::one_ring_edge_set(const std::vector> &edges, const std::vector& v_is_removed, const std::vector& f_is_removed, const std::vector>& conn_fs, const std::vector& input_vertices, std::vector &safe_set) { // std::vector indices(edges.size()); diff --git a/src/Mesh.hpp b/src/Mesh.hpp index c121794f..744bb422 100644 --- a/src/Mesh.hpp +++ b/src/Mesh.hpp @@ -111,7 +111,7 @@ class Random is_surface_fs = {{NOT_SURFACE, NOT_SURFACE, NOT_SURFACE, NOT_SURFACE}}; is_bbox_fs = {{NOT_BBOX, NOT_BBOX, NOT_BBOX, NOT_BBOX}}; opp_t_ids = {{OPP_T_ID_UNKNOWN, OPP_T_ID_UNKNOWN, OPP_T_ID_UNKNOWN, OPP_T_ID_UNKNOWN}}; - surface_tags = {{0, 0, 0, 0}}; + surface_tags = {{NO_SURFACE_TAG, NO_SURFACE_TAG, NO_SURFACE_TAG, NO_SURFACE_TAG}}; quality = 0; scalar = 0; @@ -152,7 +152,7 @@ class Random std::array is_surface_fs = {{NOT_SURFACE, NOT_SURFACE, NOT_SURFACE, NOT_SURFACE}}; std::array is_bbox_fs = {{NOT_BBOX, NOT_BBOX, NOT_BBOX, NOT_BBOX}}; std::array opp_t_ids = {{OPP_T_ID_UNKNOWN, OPP_T_ID_UNKNOWN, OPP_T_ID_UNKNOWN, OPP_T_ID_UNKNOWN}}; - std::array surface_tags = {{0, 0, 0, 0}}; + std::array surface_tags = {{NO_SURFACE_TAG, NO_SURFACE_TAG, NO_SURFACE_TAG, NO_SURFACE_TAG}}; Scalar quality = 0; Scalar scalar = 0; @@ -189,8 +189,8 @@ class Random void partition(const int n_parts, std::vector> &tets_id) const; - static void one_ring_edge_set(const std::vector> &edges, const std::vector &v_is_removed, - const std::vector &f_is_removed, const std::vector> &conn_fs, + static void one_ring_edge_set(const std::vector> &edges, const std::vector &v_is_removed, + const std::vector &f_is_removed, const std::vector> &conn_fs, const std::vector &input_vertices, std::vector &safe_set); inline int t_empty_size() const { diff --git a/src/MeshImprovement.cpp b/src/MeshImprovement.cpp index 764844ff..ddb9d2ea 100644 --- a/src/MeshImprovement.cpp +++ b/src/MeshImprovement.cpp @@ -615,7 +615,7 @@ void floatTetWild::operation(const std::vector &input_vertices, const s bool floatTetWild::update_scaling_field(Mesh &mesh, Scalar max_energy) { // return false; - cout << "updating sclaing field ..." << endl; + cout << "updating scaling field ..." << endl; bool is_hit_min_edge_length = false; Scalar radius0 = mesh.params.ideal_edge_length * 1.8;//increasing the radius would increase the #v in output diff --git a/src/Simplification.cpp b/src/Simplification.cpp index a85753c3..7dab1d3e 100644 --- a/src/Simplification.cpp +++ b/src/Simplification.cpp @@ -31,8 +31,8 @@ void floatTetWild::simplify(std::vector& input_vertices, std::vector v_is_removed(input_vertices.size(), false); - std::vector f_is_removed(input_faces.size(), false); + std::vector v_is_removed(input_vertices.size(), false); + std::vector f_is_removed(input_faces.size(), false); std::vector> conn_fs(input_vertices.size()); for (int i = 0; i < input_faces.size(); i++) { for (int j = 0; j < 3; j++) @@ -42,11 +42,11 @@ void floatTetWild::simplify(std::vector& input_vertices, std::vector& input_vertices, std:: input_tags.push_back(old_input_tags[i]); } + logger().info("remove degenerate triangles and duplicated opposite-oriented triangles:"); + logger().info("(removing degenerate triangles might leave lone vertices that will be removed later)"); + logger().info("#v: {} -> {}", V_in.rows(), input_vertices.size()); + logger().info("#f: {} -> {}", F_in.rows(), input_faces.size()); + return true; } void floatTetWild::collapsing(std::vector& input_vertices, std::vector& input_faces, const AABBWrapper& tree, const Parameters& params, - std::vector& v_is_removed, std::vector& f_is_removed, std::vector>& conn_fs){ + std::vector& v_is_removed, std::vector& f_is_removed, std::vector>& conn_fs){ #ifdef FLOAT_TETWILD_USE_TBB std::vector> edges; @@ -357,6 +362,7 @@ void floatTetWild::collapsing(std::vector& input_vertices, std::vector< } //real update +#ifndef FLOAT_TETWILD_USE_TBB // std::unordered_set n_v_ids;//get this info before real update for later usage std::vector n_v_ids;//get this info before real update for later usage for (int f_id:new_f_ids) { @@ -366,6 +372,7 @@ void floatTetWild::collapsing(std::vector& input_vertices, std::vector< } } vector_unique(n_v_ids); +#endif v_is_removed[v1_id] = true; input_vertices[v2_id] = p; @@ -491,12 +498,12 @@ void floatTetWild::collapsing(std::vector& input_vertices, std::vector< // cout<& input_vertices, std::vector& input_faces, const AABBWrapper& tree, const Parameters& params, - std::vector& v_is_removed, std::vector& f_is_removed, std::vector>& conn_fs) { + std::vector& v_is_removed, std::vector& f_is_removed, std::vector>& conn_fs) { std::vector> edges; edges.reserve(input_faces.size() * 6); for (int i = 0; i < input_faces.size(); i++) { @@ -516,7 +523,6 @@ void floatTetWild::swapping(std::vector& input_vertices, std::vector({{e[1], e[0]}}), weight)); } int cnt = 0; @@ -551,26 +557,11 @@ void floatTetWild::swapping(std::vector& input_vertices, std::vector -0.999) {//maybe it's for avoiding numerical issue - if (old_nvs[0].dot(old_nvs[1]) < 1 - 1e-6)//not coplanar + if (cos_a0 > -0.999 and cos_a1 > -0.999) {//if any old face too degenerate, ignore coplanarity + if (old_nvs[0].dot(old_nvs[1]) < 1 - SCALAR_ZERO)//not coplanar continue; } - //check inversion - auto &old_nv = cos_a1 < cos_a0 ? old_nvs[0] : old_nvs[1]; - bool is_filp = false; - for (int f_id:n12_f_ids) { - auto &a = input_vertices[input_faces[f_id][0]]; - auto &b = input_vertices[input_faces[f_id][1]]; - auto &c = input_vertices[input_faces[f_id][2]]; - if (old_nv.dot(((b - c).cross(a - c)).normalized()) < 0) { - is_filp = true; - break; - } - } - if (is_filp) - continue; - //check quality Scalar cos_a0_new = get_angle_cos(input_vertices[v1_id], input_vertices[n_v_ids[0]], input_vertices[n_v_ids[1]]); @@ -579,31 +570,36 @@ void floatTetWild::swapping(std::vector& input_vertices, std::vector& input_vertices, std::vector& vs, const AABBW // return false; } -void floatTetWild::check_surface(std::vector& input_vertices, std::vector& input_faces, const std::vector& f_is_removed, +void floatTetWild::check_surface(std::vector& input_vertices, std::vector& input_faces, const std::vector& f_is_removed, const AABBWrapper& tree, const Parameters& params) { cout<<"checking surface"<& input_vertices, std::vector& input_faces, std::vector& input_tags, const Parameters& params); void collapsing(std::vector& input_vertices, std::vector& input_faces, const AABBWrapper& sf_tree, const Parameters& params, - std::vector& is_v_removed, std::vector& is_f_removed, std::vector>& conn_fs); + std::vector& v_is_removed, std::vector& f_is_removed, std::vector>& conn_fs); void swapping(std::vector& input_vertices, std::vector& input_faces, const AABBWrapper& sf_tree, const Parameters& params, - std::vector& is_v_removed, std::vector& is_f_removed, std::vector>& conn_fs); + std::vector& v_is_removed, std::vector& f_is_removed, std::vector>& conn_fs); void flattening(std::vector& input_vertices, std::vector& input_faces, const AABBWrapper& sf_tree, const Parameters& params); bool is_out_envelope(const std::array& vs, const AABBWrapper& tree, const Parameters& params); Scalar get_angle_cos(const Vector3& p, const Vector3& p1, const Vector3& p2); - void check_surface(std::vector& input_vertices, std::vector& input_faces, const std::vector& is_f_removed, + void check_surface(std::vector& input_vertices, std::vector& input_faces, const std::vector& f_is_removed, const AABBWrapper& tree, const Parameters& params); void output_component(const std::vector& input_vertices, const std::vector& input_faces, const std::vector& input_tags); diff --git a/src/TriangleInsertion.cpp b/src/TriangleInsertion.cpp index 4f34985f..5fc32218 100644 --- a/src/TriangleInsertion.cpp +++ b/src/TriangleInsertion.cpp @@ -1918,7 +1918,7 @@ bool floatTetWild::insert_boundary_edges(const std::vector &input_verti covered_fs_infos[f_id].push_back(std::make_pair(i, j)); } } - logger().info("time1 = {}", timer.getElapsedTime()); + logger().info("time1 = {}s", timer.getElapsedTime()); bool is_all_inserted = true; int cnt = 0; @@ -2060,11 +2060,11 @@ bool floatTetWild::insert_boundary_edges(const std::vector &input_verti } logger().info("uninsert boundary #e = {}/{}", b_edge_infos.size() - cnt, b_edge_infos.size()); - logger().info("time2 = {}", time2); - logger().info("time3 = {}", time3); - logger().info("time4 = {}", time4); - logger().info("time5 = {}", time5); - logger().info("time6 = {}", time6); + logger().info("time2 = {}s", time2); + logger().info("time3 = {}s", time3); + logger().info("time4 = {}s", time4); + logger().info("time5 = {}s", time5); + logger().info("time6 = {}s", time6); // logger().info("time_e1 = {}", time_e1); // logger().info("time_e2 = {}", time_e2); diff --git a/src/main.cpp b/src/main.cpp index f277e892..06b4d2ce 100755 --- a/src/main.cpp +++ b/src/main.cpp @@ -202,7 +202,9 @@ int main(int argc, char** argv) command_line.add_option("--max-its", params.max_its, "(for debugging usage only)"); command_line.add_option( - "--stop-energy", params.stop_energy, "Stop optimization when max energy is lower than this."); + "--stop-energy", + params.stop_energy, + "Stop optimization when max energy is lower than this. (double, optional, default: 10.0)"); command_line.add_option("--stage", params.stage, "(for debugging usage only)"); command_line.add_option("--stop-p", params.stop_p, "(for debugging usage only)");