{"id":39350598,"url":"https://github.com/wildmeshing/wildmeshing-toolkit","last_synced_at":"2026-01-18T02:29:52.975Z","repository":{"id":37769196,"uuid":"415044882","full_name":"wildmeshing/wildmeshing-toolkit","owner":"wildmeshing","description":"Toolkit for Meshing in the Wild","archived":false,"fork":false,"pushed_at":"2026-01-12T12:40:54.000Z","size":621534,"stargazers_count":173,"open_issues_count":84,"forks_count":20,"subscribers_count":9,"default_branch":"main","last_synced_at":"2026-01-12T13:51:57.712Z","etag":null,"topics":["remeshing","siggraph-asia-2022"],"latest_commit_sha":null,"homepage":"","language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/wildmeshing.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2021-10-08T15:50:54.000Z","updated_at":"2026-01-12T06:56:01.000Z","dependencies_parsed_at":"2023-02-18T00:02:09.760Z","dependency_job_id":"3a69ab2e-c41f-42bd-acbc-47bd2c3ffaaf","html_url":"https://github.com/wildmeshing/wildmeshing-toolkit","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/wildmeshing/wildmeshing-toolkit","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wildmeshing%2Fwildmeshing-toolkit","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wildmeshing%2Fwildmeshing-toolkit/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wildmeshing%2Fwildmeshing-toolkit/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wildmeshing%2Fwildmeshing-toolkit/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/wildmeshing","download_url":"https://codeload.github.com/wildmeshing/wildmeshing-toolkit/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wildmeshing%2Fwildmeshing-toolkit/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28526571,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-18T00:39:45.795Z","status":"online","status_checked_at":"2026-01-18T02:00:07.578Z","response_time":98,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["remeshing","siggraph-asia-2022"],"created_at":"2026-01-18T02:29:52.370Z","updated_at":"2026-01-18T02:29:52.964Z","avatar_url":"https://github.com/wildmeshing.png","language":"C++","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Wildmeshing-toolkit: Declarative Specification for Unstructured Mesh Editing Algorithms\n\n## Installation\n\n#### via CMake\n\n- Clone the repository into your local machine:\n\n```bash\ngit clone https://github.com/wildmeshing/wildmeshing-toolkit.git\n```\n\n- Compile the code using cmake\u003e3.20.0\n\n```bash\ncd wildmeshing-toolkit\nmkdir build\ncd build\ncmake -DCMAKE_BUILD_TYPE=Release ..\nmake\n```\n\nYou may need to install `gmp` before compiling the code. You can install `gmp` via [homebrew](https://brew.sh/).\n\n## Usage\nTo reproduce figures from the paper, please use the commands from [reproduce_scripts](reproduce_scripts.sh). Note that the input data are from `wmtk-data-package.zip`. (Download: https://drive.google.com/drive/folders/1jFdQ77E2_n3EJF5_bPOOMEOxF4dyctjN?usp=sharing)\n\n\n## About Us\nThis toolkit is a novel approach to describe mesh generation, mesh adaptation, and geometric modeling algorithms relying on changing mesh connectivity using a high-level abstraction. The main motivation is to enable easy customization and development of these algorithms via a declarative specification consisting of a set of per-element invariants, operation scheduling,and attribute transfer for each editing operation.\n\nMany widely used algorithms editing surfaces and volumes\ncan be compactly expressed with our abstraction, and their implementation\nwithin our framework is simple, automatically parallelizable on shared-\nmemory architectures, and with guaranteed satisfaction of the prescribed\ninvariants. These algorithms are readable and easy to customize for specific use cases.\n\nThis software library implements the abstractiona in our paper and providing automatic shared memory parallelization.\n\nWe will use the implementation of the shortest edge collapse algorithm as an example to introduce the framework and run through the basic software structures and APIs of the toolkit. All the code that is referenced below can be found under the `app` folder of the toolkit. \n\n## Basic Algorithm\nThe algorithm is after [Hoppe 1996] Progressive Meshes which performs a series of collapse operations prioritizing the shorter edges. The algorithm requires only one local operation, edge collapse. We terminate when the mesh reaches a desired number of mesh elements. For every collapsed edge, we generate a new vertex at the midpoint of the edge.\n\nWe implemented `class ShortestEdgeCollapse` as a child class of `wmtk::TriMesh`. The 3d vertex positions are stored as a field of the `VertexAttributes`.\n```\nstruct VertexAttributes\n{\n \u003e\u003e Eigen::Vector3d pos;\n    size_t partition_id = 0;\n    bool freeze = false;\n};\n```\n\n## Explicit Invariant Design\nIt is common to have a set of desiderata on\nthe mesh that needs to be satisfied, such as avoiding triangle insertions or self-intersections. The responsibility of ensuring the user-defined explicit invariants being checked after every mesh\nmodification, and after the input is loaded is assumed by the toolkit. It is much easier to ensure correctness for the user, as\nthe checks are handled transparently by the toolkit.\n\nAs an example of user-defined invariants, in our shortest edge collapse implementation, we created an envelope around the original surface and designated that any operation shall not cause any vertex to move outside of the envelop, so that during local operations we can roughly keep the shape of the input mesh and avoid self-intersection. \n\n```\nbool sec::ShortestEdgeCollapse::invariants(const std::vector\u003cTuple\u003e\u0026 new_tris)\n{\n    if (m_has_envelope) {\n        for (auto\u0026 t : new_tris) {\n            std::array\u003cEigen::Vector3d, 3\u003e tris;\n            auto vs = oriented_tri_vertices(t);\n            for (auto j = 0; j \u003c 3; j++) tris[j] = vertex_attrs[vs[j].vid(*this)].pos;\n            bool outside = m_envelope.is_outside(tris);\n            if (outside) return false;\n        }\n    }\n    return true;\n}\n```\nThe envelope development is after [Exact and Efficient Polyhedral Envelope Containment Check](https://cims.nyu.edu/gcl/papers/2020-Fast-Envelope.pdf)\n\n\n## Explicit Attribute Update \nOpposed to the common practice of attaching mesh attributes to mesh elements we enable the users to only provide the rules on how to update attributes after local operations in a high-level specifications. The actual update is handled entirely by the toolkit. \n\nThis easy-to-write user-specified update rule is examplified in our shortest edge collapse as below\n```\nbool sec::ShortestEdgeCollapse::collapse_edge_after(const TriMesh::Tuple\u0026 t)\n{\n    const Eigen::Vector3d p = (position_cache.local().v1p + position_cache.local().v2p) / 2.0;\n    auto vid = t.vid(*this);\n    vertex_attrs[vid].pos = p;\n\n    return true;\n}\n```\n\n## Operation Rollback\nIt is common to perform mesh editing to\nimprove a given energy functional, such as mesh quality or element\nsize. However, due to the discrete nature of the operations, it is\nnot possible to use standard smooth optimization techniques, and\ninstead the effect of the energy is evaluated before and after every\noperation to measure its effect on the energy. If the user desires a certain property of the mesh for each operation, the desiderata can be easily coded up as a check in the after operation. \n\nIf either the user specified invariants or the after operation check/update has failed, the toolkit will perform an operation rollback that restores the mesh configuration to before the operation. And our toolkit also handles the recovery of element attributes on this occasion. The rollback and attribute protection gurantee both topology and geometry consistency for the mesh. Users would not need to perform any manual updates were the operations to fail, thank to the rollback.\n\n## Operation Demonstration\n\nFor easier usage and customization, here we demonstrate the before and after of each operation and the vertex, edge, face, and tet (in 3d) that is reference.\n\n### 2D operations\n- **edge collapse**\n![img](img/collapse_demonstration.svg)\n\n- **edge split**\n![img](img/split_demonstration.svg)\n- **edge swap**\n![img](img/swap_demonstration.svg)\n\n- **vertex smooth**\nThis operation do not change the reference.\n\n### 3D operations\n- **edge collapse**\n![img](img/collapse3d.PNG)\n\n- **edge collapse boundary case**\n![img](img/collapseboundary3d.PNG)\n\n- **edge split**\n![img](img/split3d.PNG)\n\n- **edge swap 4-4**\n![img](img/swap44.PNG)\n\n- **edge swap 2-3 \u0026 3-2**\n![img](img/swap32.PNG)\n\n\n## Parallel Scheduling\nThe type and scheduling of local operations is crucial in mesh editing algorithms. This involves maintaining a priority queue of operations, which is updated after every local operation.\n\nWe provide a direct way of controlling the operations performed\nand how the queue is updated through our scheduler. The main purpose of the scheduler is to\nabstract the operation order and hide parallelization details from\nthe user. Our scheduler provides customizable callbacks, including, *Priority*, *Renew neighbor*, *Lock vertices*, *Stopping criterion*.  \n\nFor shortest edge collapse, we want to attempt to collapse all edges, prioritizing the shortest ones, until we reach a fixed number of vertices.\n\n```\nfor (auto\u0026 loc : get_edges()) collect_all_ops.emplace_back(\"edge_collapse\", loc);\n```\n\n  We put here the example of our shortest edge collapse implementation of the *Priority* and *Renew neighbor*, and how they are used in scheduler. \n```\n  auto renew = [](auto\u0026 m, auto op, auto\u0026 tris) {\n      auto edges = m.new_edges_after(tris);\n      auto optup = std::vector\u003cstd::pair\u003cstd::string, Tuple\u003e\u003e();\n      for (auto\u0026 e : edges) optup.emplace_back(\"edge_collapse\", e);\n      return optup;\n  };\n  auto measure_len2 = [](auto\u0026 m, auto op, const Tuple\u0026 new_e) {\n      auto len2 =\n          (m.vertex_attrs[new_e.vid(m)].pos - m.vertex_attrs[new_e.switch_vertex(m).vid(m)].pos)\n              .squaredNorm();\n      return -len2;\n  };\n  auto setup_and_execute = [\u0026](auto executor) {\n      executor.num_threads = NUM_THREADS;\n  \u003e\u003e executor.renew_neighbor_tuples = renew;\n  \u003e\u003e executor.priority = measure_len2;\n      executor.stopping_criterion_checking_frequency =\n          target_vert_number \u003e 0 ? (initial_size - target_vert_number - 1)\n                                  : std::numeric_limits\u003cint\u003e::max();\n      executor.stopping_criterion = [](auto\u0026 m) { return true; };\n      executor(*this, collect_all_ops);\n  };\n```\n\n## Command Line Executions for Example Applications\nTo showcase the generality and effectiveness of our approach, we\nimplemented five popular mesh editing algorithms in our framework. We provide the command lines and corresponding parameters for running the these applications as below:\n\n```\ncd build\n```\n\n- ### Shortest Edge Collpase : [Progressive Meshes](https://hhoppe.com/pm.pdf)\n```\nUsage:./app/sec_app input output [OPTIONS] \n\nRequired:\n  input                       Input surface mesh INPUT in .off/.obj/.stl/.ply format. \n  output                      Output tetmesh OUTPUT in .obj format. \n\nOptions:\n  -e,--envelope               Relative envelope size. enveleope_size = diag_of_bbox * e. negative to disable.\n  -j, --thread thread         Thread number.\n  -t, --target                Percentage of input vertices in output.\n```\n- ### Qslim : [Surface Simplification Using Quadric Error Metrics](https://dl.acm.org/doi/pdf/10.1145/258734.258849)\n```\nUsage:./app/qslim_app input output [OPTIONS] \n\nRequired:\n  input                       Input surface mesh INPUT in .off/.obj/.stl/.ply format. \n  output                      Output tetmesh OUTPUT in .obj format. \n\nOptions:\n  -e,--envelope               Relative envelope size. enveleope_size = diag_of_bbox * e. negative to disable.\n  -j, --thread thread         Thread number.\n  -t, --target                Percentage of input vertices in output.\n```\n- ### Isotropic Remeshing : [A Remeshing Approach to Multiresolution Modeling](https://ls7-gv.cs.tu-dortmund.de/downloads/publications/2004/sgp04.pdf)\n```\nUsage:./app/remeshing_app input output [OPTIONS] \n\nRequired:\n  input                       Input surface mesh INPUT in .off/.obj/.stl/.ply format. \n  output                      Output tetmesh OUTPUT in .obj format. \n\nOptions:\n  -e,--envelope               Relative envelope size. enveleope_size = diag_of_bbox * e negative to disable.\n  -j, --thread thread         Thread number.\n  -r, --relativelength        Relative edge length. Target edge length in output mesh is min(diag * rel_len, 5 * avg_len).\n  -a, --absolutelengt         Absolute edge length in output mesh.\n  -i, --iterations            Number of remeshing itrs.\n  -f, --freeze                To freeze the boundary, default to true.\n  --sample-envelope           use sample envelope, default to false.\n```\n- ### Harmonic Triangulations : [Harmonic Triangulations](https://dl.acm.org/doi/pdf/10.1145/3306346.3322986)\n```\nUsage:\n./app/harmonic_tet/wmtk_harmonic_tet_bin input output \n\nRequired:\n  input                       Input surface mesh INPUT in .off/.obj/.stl/.ply format. \n  output                      Output tetmesh OUTPUT in .msh format. \n\nOptions:\n  -j, --thread thread         Thread number.\n  --harmonize                 Enable to use for point cloud.\n```\n\n- ### Tetwild : [Tetrahedral Meshing in the Wild](https://cims.nyu.edu/gcl/papers/2018-TetWild.pdf)\n```\nUsage:\n./app/tetwild/tetwild -i input -o output\n\nRequired:\n  input                       Input surface mesh INPUT in .off/.obj/.stl/.ply format. \n  output                      Output tetmesh OUTPUT in .msh format. \n\nOptions:\n  -e,--epsr                   Relative envelope size. enveleope_size = diag_of_bbox * e negative to disable.\n  -j, --thread thread         Thread number.\n  --skip-simplify             Skip simplify_input.\n  --max-its                   Max # its.\n  -r, --rlen                  Relative ideal edge length wrt diag of bbox.\n  --filter-with-input         Filter with input mesh, default is tracked surface.\n  --sample-envelope           Use sample envelope for both simp and optim.\n```\n\n## License\nMIT License.\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwildmeshing%2Fwildmeshing-toolkit","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fwildmeshing%2Fwildmeshing-toolkit","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwildmeshing%2Fwildmeshing-toolkit/lists"}