Library Goals & Design Principles
There are a lot of geometry processing libraries out there, and it might be a little confusing where Lagrange stands in the current landscape. In this page, we highlight some of the goals and key design principles that go into Lagrange.
-
Do Not Reinvent The Wheel. If a library exists that already solves a particular problem (nanoflann, embree, etc.) we will use it instead of reinventing the wheel. As such, we have libigl-style wrappers around some common third-party libraries. Note that we only use external libraries that are available under commercial friendly licenses. Please consult our dedicated page for more information.
-
Powerful Mesh Data Structure. Our mesh data structure can represent any type of mesh (triangle mesh, quad-dominant, polygonal mesh, 2D, 3D, etc.). It is memory-efficient, support generic attributes, navigation, dynamic editing, etc. More information is available on our dedicated Mesh Class user guide.
-
Interoperability. Our mesh data structure is designed to allow wrapping any continuous buffers as regular mesh attributes. This allows creating a Lagrange mesh from an external buffer without copying any data, as long as memory layout is compatible. Furthermore, you can export attributes to reuse our buffers after a mesh object is destroyed. And because our attributes can be viewed as Eigen matrices, our mesh data structure is directly compatible with libigl. We are planning to implement conversion functions for other mesh processing libraries in the future.
Interoperability With Others Libraries
Name From Lagrange Mesh To Lagrange Mesh Comment cinolib geogram Planned. geometry-central Planned. libigl (no copy) (may copy) pmp-library -
Clean Build System. Lagrange has a clean and polished CMake build system. Getting started with Lagrange is incredibly simple, just add 5 lines to your CMake project (no git submodule needed):
include(FetchContent) FetchContent_Declare(lagrange GIT_REPOSITORY <lagrange-url> GIT_TAG <sha256> ) FetchContent_MakeAvailable(lagrange) target_link_libraries(my_project PUBLIC lagrange::core)
If you are not a fan of CMake, all Lagrange modules follow the same organization, so it should be easy to add them to your build system, provided you can compile the required dependencies.
-
Ease Of Use. Lagrange meshes have a clean and well-documented API. Any mesh attribute can be viewed as a Eigen matrix, ensuring compatibility with libigl functions. Combined with our simple CMake system, Lagrange is an ideal framework for prototyping C++ applications with advanced geometry processing features.
-
Modularity. Lagrange features are split into modules, based on specific features and dependencies. Module names are sensible and short. While
lagrange::core
is relatively small, bringing additional modules to your project can provide more advanced features. -
File Formats. Our IO module supports reading/writing a variety of standard file formats used in the industry. Rather than writing our own parsers, we leverage existing libraries such as tinyobj to provide IO functionalities.
Supported File Formats
Legacy Mesh IO
IO for our legacy Mesh class (will be retired in the future).
Format Read Write Comment FBX Via Assimp glTF Via Assimp HDF5 Planned OBJ Via tinyobj/libigl OFF Via libigl PLY Via tinyply/libigl USD Planned VTK Custom writer Surface Mesh IO
IO for our new polygonal mesh class.
Format Read Write Comment FBX 1 Via Assimp glTF Via tinygltf HDF5 Planned MSH Via MshIO OBJ Read via tinyobj, custom writer PLY Read via libigl, write via happly USD Planned Other 1 Via Assimp Simple Scene IO
IO for our simple scene class, supporting a list of instanced meshes.
Format Read Write Comment glTF Via tinygtlf FBX 1 Via Assimp Other 1 Via Assimp -
Performance. Lagrange functions are written with performance in mind. We use TBB for multithreading, and avoid unnecessary heap memory allocation or data copies. Lagrange should be able to process large assets that are often encountered in the industry. If you encounter any performance limitation, please reach out to us.
-
Advanced Viewer. We provide an advanced mesh viewer for building interactive applications with realistic shading. We use a modified ImGui that conforms to the Spectrum specification to provide a user experience more consistent with Adobe products.
Viewer Key Features
- Support for all lagrange mesh types
- Customizable renderer that includes PBR
- Gizmos for interactive mesh and element manipulation
- Easy to add your own UI via ImGui
- Variety of visualization options - mix and match indexing/colormapping/rendered primitive/shading.
-
Robustness/Support. Being backed by a company, Lagrange has a strong focus on correctness/being as bug free as possible. We have extensive unit testing internally, with more than 400 unit tests. Specifically, we try to ensure the following:
- Corner Cases. Special cases should not crash the program. Incorrect inputs may result in exceptions being thrown.
- Determinism. Parallel algorithms should produce the same results when called repeatedly with the same inputs.
- Regression Tests. We should have unit tests to ensure that algorithms produce the same output whenever code changes. Changes in algorithm behaviors should be documented.
- Cross-Platform. Algorithms should produce the same result on all three platforms whenever possible (macOS/Linux/Windows). This means avoiding
std::default_random_engine
and other platform-specific constructs.
- Useful Feedbacks. Being integrated into a product means we often need to provide some simple feedback mechanisms, such as logging, cancellation and progress report.
- Logger. We use spdlog to provide beautiful logging messages. The global logger is thread-safe, and can be turned off or redirected as needed by the client application.
- Cancellation. It should be possible to cancel any running function by switching a
std::atomic_bool &
flag. - Progress Report. A simple thread-safe callback mechanism can be used in certain functions to report progress. This is useful to inform the user about the advancement of certain tasks that can be slow (e.g. mesh cleanup, etc.).
- Error Mechanism. We use exception throwing as the mechanism to report an error. While returning error code has certain advantages over exceptions, third-party libraries or the STL can still throw exceptions, and thus it is the user's responsibility to catch them should they occur.
- Documentation/Code Style. Our codebase is formatted via clang-format for consistency. We aim to provide both libigl-style tutorials to get started using Lagrange, as well as detailed API documentation written in Doxygen.