Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix some minor typos, bugs and the GitHub CI workflows #58

Open
wants to merge 11 commits into
base: master
Choose a base branch
from
40 changes: 18 additions & 22 deletions .github/workflows/continuous.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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 \
Expand All @@ -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: |
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand All @@ -127,22 +122,23 @@ 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}

- 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 ^
Expand All @@ -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
10 changes: 5 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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., `<conda_dir>\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., `<conda_dir>\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., `<conda_dir>\Library\include` for `GMP_INC` and `<conda_dir>\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., `<conda_dir>\Library\include` for `GMP_INC` and `<conda_dir>\Library\lib` for `GMP_LIB`).

- Check the installation:

Expand All @@ -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
Expand Down Expand Up @@ -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:
Expand All @@ -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)
Expand Down
2 changes: 1 addition & 1 deletion src/Mesh.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ namespace floatTetWild {
}


void Mesh::one_ring_edge_set(const std::vector<std::array<int, 2>> &edges, const std::vector<bool>& v_is_removed, const std::vector<bool>& f_is_removed,
void Mesh::one_ring_edge_set(const std::vector<std::array<int, 2>> &edges, const std::vector<char>& v_is_removed, const std::vector<char>& f_is_removed,
const std::vector<std::unordered_set<int>>& conn_fs, const std::vector<Vector3>& input_vertices, std::vector<int> &safe_set)
{
// std::vector<int> indices(edges.size());
Expand Down
8 changes: 4 additions & 4 deletions src/Mesh.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -152,7 +152,7 @@ class Random
std::array<char, 4> is_surface_fs = {{NOT_SURFACE, NOT_SURFACE, NOT_SURFACE, NOT_SURFACE}};
std::array<char, 4> is_bbox_fs = {{NOT_BBOX, NOT_BBOX, NOT_BBOX, NOT_BBOX}};
std::array<int, 4> opp_t_ids = {{OPP_T_ID_UNKNOWN, OPP_T_ID_UNKNOWN, OPP_T_ID_UNKNOWN, OPP_T_ID_UNKNOWN}};
std::array<char, 4> surface_tags = {{0, 0, 0, 0}};
std::array<char, 4> surface_tags = {{NO_SURFACE_TAG, NO_SURFACE_TAG, NO_SURFACE_TAG, NO_SURFACE_TAG}};

Scalar quality = 0;
Scalar scalar = 0;
Expand Down Expand Up @@ -189,8 +189,8 @@ class Random

void partition(const int n_parts, std::vector<std::vector<int>> &tets_id) const;

static void one_ring_edge_set(const std::vector<std::array<int, 2>> &edges, const std::vector<bool> &v_is_removed,
const std::vector<bool> &f_is_removed, const std::vector<std::unordered_set<int>> &conn_fs,
static void one_ring_edge_set(const std::vector<std::array<int, 2>> &edges, const std::vector<char> &v_is_removed,
const std::vector<char> &f_is_removed, const std::vector<std::unordered_set<int>> &conn_fs,
const std::vector<Vector3> &input_vertices, std::vector<int> &safe_set);

inline int t_empty_size() const {
Expand Down
2 changes: 1 addition & 1 deletion src/MeshImprovement.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -615,7 +615,7 @@ void floatTetWild::operation(const std::vector<Vector3> &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
Expand Down
88 changes: 42 additions & 46 deletions src/Simplification.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ void floatTetWild::simplify(std::vector<Vector3>& input_vertices, std::vector<Ve
if (skip_simplify)
return;

std::vector<bool> v_is_removed(input_vertices.size(), false);
std::vector<bool> f_is_removed(input_faces.size(), false);
std::vector<char> v_is_removed(input_vertices.size(), false);
std::vector<char> f_is_removed(input_faces.size(), false);
std::vector<std::unordered_set<int>> conn_fs(input_vertices.size());
for (int i = 0; i < input_faces.size(); i++) {
for (int j = 0; j < 3; j++)
Expand All @@ -42,11 +42,11 @@ void floatTetWild::simplify(std::vector<Vector3>& input_vertices, std::vector<Ve
igl::Timer timer;
timer.start();
collapsing(input_vertices, input_faces, tree, params, v_is_removed, f_is_removed, conn_fs);
std::cout<<"collapsing "<<timer.getElapsedTime()<<std::endl;
std::cout<<"collapsing "<<timer.getElapsedTime()<<"s"<<std::endl;

timer.start();
swapping(input_vertices, input_faces, tree, params, v_is_removed, f_is_removed, conn_fs);
std::cout<<"swapping "<<timer.getElapsedTime()<<std::endl;
std::cout<<"swapping "<<timer.getElapsedTime()<<"s"<<std::endl;

//clean up vs, fs
//v
Expand Down Expand Up @@ -204,12 +204,17 @@ bool floatTetWild::remove_duplicates(std::vector<Vector3>& 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<Vector3>& input_vertices, std::vector<Vector3i>& input_faces,
const AABBWrapper& tree, const Parameters& params,
std::vector<bool>& v_is_removed, std::vector<bool>& f_is_removed, std::vector<std::unordered_set<int>>& conn_fs){
std::vector<char>& v_is_removed, std::vector<char>& f_is_removed, std::vector<std::unordered_set<int>>& conn_fs){

#ifdef FLOAT_TETWILD_USE_TBB
std::vector<std::array<int, 2>> edges;
Expand Down Expand Up @@ -357,6 +362,7 @@ void floatTetWild::collapsing(std::vector<Vector3>& input_vertices, std::vector<
}

//real update
#ifndef FLOAT_TETWILD_USE_TBB
// std::unordered_set<int> n_v_ids;//get this info before real update for later usage
std::vector<int> n_v_ids;//get this info before real update for later usage
for (int f_id:new_f_ids) {
Expand All @@ -366,6 +372,7 @@ void floatTetWild::collapsing(std::vector<Vector3>& input_vertices, std::vector<
}
}
vector_unique(n_v_ids);
#endif

v_is_removed[v1_id] = true;
input_vertices[v2_id] = p;
Expand Down Expand Up @@ -491,12 +498,12 @@ void floatTetWild::collapsing(std::vector<Vector3>& input_vertices, std::vector<
// cout<<fail_flip<<endl;
// cout<<fail_env<<endl;
// std::cout<<"#v: "<<build_time<<std::endl;
logger().debug("{} faces are collapsed!!", cnt_suc);
logger().debug("{} edges ({} faces) were collapsed!!", cnt_suc, 2*cnt_suc);
}

void floatTetWild::swapping(std::vector<Vector3>& input_vertices, std::vector<Vector3i>& input_faces,
const AABBWrapper& tree, const Parameters& params,
std::vector<bool>& v_is_removed, std::vector<bool>& f_is_removed, std::vector<std::unordered_set<int>>& conn_fs) {
std::vector<char>& v_is_removed, std::vector<char>& f_is_removed, std::vector<std::unordered_set<int>>& conn_fs) {
std::vector<std::array<int, 2>> edges;
edges.reserve(input_faces.size() * 6);
for (int i = 0; i < input_faces.size(); i++) {
Expand All @@ -516,7 +523,6 @@ void floatTetWild::swapping(std::vector<Vector3>& input_vertices, std::vector<Ve
for (auto &e: edges) {
Scalar weight = (input_vertices[e[0]] - input_vertices[e[1]]).squaredNorm();
sm_queue.push(ElementInQueue(e, weight));
sm_queue.push(ElementInQueue(std::array<int, 2>({{e[1], e[0]}}), weight));
}

int cnt = 0;
Expand Down Expand Up @@ -551,26 +557,11 @@ void floatTetWild::swapping(std::vector<Vector3>& input_vertices, std::vector<Ve
auto &c = input_vertices[input_faces[n12_f_ids[f]][2]];
old_nvs[f] = ((b - c).cross(a - c)).normalized();
}
if (cos_a0 > -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]]);
Expand All @@ -579,31 +570,36 @@ void floatTetWild::swapping(std::vector<Vector3>& input_vertices, std::vector<Ve
if (std::min(cos_a0_new, cos_a1_new) <= std::min(cos_a0, cos_a1))
continue;

//check envelope
// bool is_valid = true;
// for(int v_id: n_v_ids) {
// if (is_out_envelope({{input_vertices[v_id], input_vertices[v1_id], input_vertices[v2_id]}},
// tree, params)) {
// is_valid = false;
// break;
// }
// }
// if(!is_valid)
// continue;
if (is_out_envelope({{input_vertices[v1_id], input_vertices[n_v_ids[0]], input_vertices[n_v_ids[1]]}}, tree,
params)
|| is_out_envelope({{input_vertices[v2_id], input_vertices[n_v_ids[0]], input_vertices[n_v_ids[1]]}}, tree,
params)) {
continue;
}

// real update
//update (possibly temporarily) the two faces' vertices
auto f1_old = input_faces[n12_f_ids[0]];
auto f2_old = input_faces[n12_f_ids[1]];
for (int j = 0; j < 3; j++) {
if (input_faces[n12_f_ids[0]][j] == v2_id)
input_faces[n12_f_ids[0]][j] = n_v_ids[1];
if (input_faces[n12_f_ids[1]][j] == v1_id)
input_faces[n12_f_ids[1]][j] = n_v_ids[0];
}

//check inversion and envelope
auto &old_nv = cos_a1 < cos_a0 ? old_nvs[0] : old_nvs[1];
bool is_flipped_or_outside = 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 or
is_out_envelope({{a, b, c}}, tree, params)) {
is_flipped_or_outside = true;
break;
}
}
if (is_flipped_or_outside) {
input_faces[n12_f_ids[0]] = f1_old;
input_faces[n12_f_ids[1]] = f2_old;
continue;
}

// real update
conn_fs[v1_id].erase(n12_f_ids[1]);
conn_fs[v2_id].erase(n12_f_ids[0]);
conn_fs[n_v_ids[0]].insert(n12_f_ids[1]);
Expand All @@ -615,7 +611,7 @@ void floatTetWild::swapping(std::vector<Vector3>& input_vertices, std::vector<Ve
// check_surface(input_vertices, input_faces, f_is_removed, tree, params);
}

logger().debug("{} faces are swapped!!", cnt);
logger().debug("{} edges/faces were swapped!!", cnt);
return;

///////////////////
Expand Down Expand Up @@ -923,7 +919,7 @@ bool floatTetWild::is_out_envelope(const std::array<Vector3, 3>& vs, const AABBW
// return false;
}

void floatTetWild::check_surface(std::vector<Vector3>& input_vertices, std::vector<Vector3i>& input_faces, const std::vector<bool>& f_is_removed,
void floatTetWild::check_surface(std::vector<Vector3>& input_vertices, std::vector<Vector3i>& input_faces, const std::vector<char>& f_is_removed,
const AABBWrapper& tree, const Parameters& params) {
cout<<"checking surface"<<endl;
bool is_valid = true;
Expand Down
Loading