# GMAC
[](https://github.com/alexlovric/gmac/actions/workflows/build&test.yml)
[](https://opensource.org/licenses/MIT)
A fast mesh manipulation and creation library made in rust, with a convenient python interface, and very few dependencies. Primary features include:
- Deform meshes using RBF and FFD
- Transform meshes (or selection just a selection of nodes)
- Large range of selection and transformation tools
- Import/export stl, obj and vtk-type files
- Convenient python interface
- Create primitives
- Great performance
Here's a demonstration of a plane tail deformed using the Free Form deformer (FFD):
| <img src="https://github.com/alexlovric/gmac/blob/main/assets/plane_tail_variationa1.png?raw=true" /> | <img src="https://github.com/alexlovric/gmac/blob/main/assets/plane_tail_variationa2.png?raw=true" /> |
## Add to your rust project
Add the following to your `Cargo.toml`:
```toml
[dependencies]
gmac = "^0.2.0"
```
This includes `rayon` by default, for those who want a lightweight dependency free version use `default-features = false`
For **Rbf** specifically, if you still need more performance try adding features `openblas` or `intel-mkl`.
Make sure you have the required dependencies installed for the features you choose. For openblas openssl is required.
## Examples in Rust
### Deforming with Free Form Deformer (FFD)
Heres a demonstration of deformation using the `FreeFormDeformer`:
```rust
use gmac::{
core::{
primitives::generate_box,
transformation::{build_transformation_matrix, transform_selected_nodes},
},
io::stl::StlFormat,
morph::{design_block::DesignBlock, ffd::FreeFormDeformer},
};
fn main() -> Result<(), Box<dyn std::error::Error>> {
// Create a simple primitive or import something else
let mut mesh = generate_box(
[2.0, 1.0, 1.0], // Lengths (x, y, z)
[0.0, 0.0, 0.0], // Center coordinates
[0.0, 0.0, 0.0], // Rotation angles (degrees)
[12, 12, 12], // Elements in each direction
)?;
// Alternative: mesh = Mesh::from_stl("path_to_stl")? or from_obj
// Create a design block (control lattice) for FFD
// This should contain the region you wish to deform
let design_block = DesignBlock::new(
[1.8, 1.2, 1.2], // Lengths (x, y, z)
[0.2, 0.0, 0.0], // Center offset
[0.0, 0.0, 0.0], // Rotation angles (degrees)
[3, 2, 2], // Control points each direction
)?;
// Select which control points will be free to move during
// deformation, the second parameter specifies the number of
// fixed layers of control points at the boundaries
let free_design_ids = design_block
.select_free_design_nodes(&mesh, Some(2))?;
// Apply the transformation to each free control point
let transform_matrix = build_transformation_matrix(
[0.25, 0.0, 0.0], // Translation vector (x, y, z)
[125.0, 0.0, 0.0], // Rotation angles (degrees)
[1.0, 1.25, 1.25], // Scaling factors (x, y, z)
);
let deformed_design_nodes = design_block.transform_subset(
&free_design_ids,
&transform_matrix,
&[0.2, 0.0, 0.0], // Pivot point
);
// Create a Free-Form Deformer with original design block
let ffd = FreeFormDeformer::new(design_block)?;
// Apply the deformation to the original geometry
mesh.nodes = ffd.deform(&mesh.nodes, &deformed_design_nodes)?;
// Save the final deformed geometry as an STL/OBJ/VTK file
mesh.write_stl(Some("deformed.stl"), Some(StlFormat::Binary))?;
Ok(())
}
```
| <img src="https://github.com/alexlovric/gmac/blob/main/assets/example_1_original.png?raw=true" /> | <img src="https://github.com/alexlovric/gmac/blob/main/assets/example_1_deformed.png?raw=true" width="99%" /> |
Note: There are many ways to achieve the same result with all the tools provided, this is just one of them.
### Deforming with Radial Basis Functions (RBF)
Using the `RbfDeformer` is very similar to using the FFD, but instead of using a design block (control lattice), you use a set of control points:
```rust
use gmac::core::{
clusters::generate_block_cluster,
primitives::generate_torus,
selection::select_nodes_in_plane_direction,
transformation::{build_transformation_matrix, transform_selected_nodes},
};
use gmac::morph::rbf::RbfDeformer;
fn main() -> Result<(), Box<dyn std::error::Error>> {
// Create a simple geometry or import one
let mut mesh = generate_torus(1.0, 0.3, [0.0, 0.0, 0.0], 64, 64)?;
// Create a set of control points
let original_control_points = generate_block_cluster(
[2.8, 1.0, 2.8], // Slightly larger than the original box
[0.0, 0.0, 0.0], // Centered at the origin
[0.0, 0.0, 0.0], // No rotation
[3, 3, 3], // Control points in each direction
)?;
// Select control points that lie in a plane defined
let target_control_point_ids = select_nodes_in_plane_direction(
&original_control_points,
[0.0, 0.0, 0.0], // A point in the plane
[1.0, 0.0, 0.0], // Normal vector (x-axis in this case)
);
// Apply transformation to the selected control points
let transform_matrix = build_transformation_matrix(
[0.0, 0.0, 0.0], // Translation
[45.0, 20.0, 0.0], // Rotation
[1.0, 1.0, 1.0], // Scale
);
let deformed_control_points = transform_selected_nodes(
&original_control_points,
&target_control_point_ids,
&transform_matrix,
&[0.0, 0.0, 0.0], // Origin/pivot point
);
// Create an RBF deformer with the control point configurations
let rbf = RbfDeformer::new(
original_control_points,
deformed_control_points,
Some("thin_plate_spline"), // Type of RBF kernel
Some(1.0), // Shape parameter
)?;
// Apply the RBF deformation to the original geometry
mesh.nodes = rbf.deform(&mesh.nodes)?;
// Save the final deformed geometry as an STL/OBJ/VTK file
mesh.write_stl(Some("deformed.stl"), None)?;
Ok(())
}
```
Here you can see the original control points and mesh, as well as the deformed control points and mesh:
| <img src="https://github.com/alexlovric/gmac/blob/main/assets/example_2_original.png?raw=true" /> | <img src="https://github.com/alexlovric/gmac/blob/main/assets/example_2_deformed.png?raw=true" width="99%"/> |
## Examples in Python
### Using GMAC to deform a box
Heres a simple demonstration of using the Free Form Deformer (FFD) to deform a generated box (or an imported STL file).
```python
import gmac as gm
# Create a simple primitive geometry or import something
mesh = gm.generate_box([2.0, 1.0, 1.0], [0.0, 0.0, 0.0], [0.0, 0.0, 0.0], [12, 12, 12])
# Alternative: mesh = gm.Mesh.from_stl("path_to_stl") or obj
# Create a design block (control lattice) for FFD
design_block = gm.morph.DesignBlock(
[1.8, 1.2, 1.2], # Dimensions of the control lattice
[0.2, 0.0, 0.0], # Center offset
[0.0, 0.0, 0.0], # Rotation angles (degrees)
[3, 2, 2], # Control points in each direction
)
# Select which control points will be free to move
free_design_ids = design_block.select_free_design_nodes(mesh, 2)
# Transform only the free control points using transformation matrix
transformation_matrix = gm.build_transformation_matrix(
[0.25, 0.0, 0.0], # Translation vector
[125.0, 0.0, 0.0], # Rotation angles
[1.0, 1.25, 1.25], # Scaling factors
)
deformed_design_nodes = gm.transform_selected_nodes(
design_block.nodes,
free_design_ids,
transformation_matrix,
[0.2, 0.0, 0.0],
)
# Save the deformed control points for visualisation
gm.io.write_vtp(deformed_design_nodes, "deformed_design_nodes.vtp")
# Create a Free-Form Deformer with the original design block
ffd = gm.morph.FreeFormDeformer(design_block)
# Apply the deformation to the original geometry
mesh.nodes = ffd.deform(mesh.nodes, deformed_design_nodes)
# Save the deformed geometry as STL/OBJ/VTK file
mesh.write_stl("deformed_geometry.stl") # binary default
```
For Radial Basis Function (RBF) deformation, see the RbfDeformer example in examples.
## Build python from source
These instructions assume that Python3 and Cargo are installed on your system. To set up this project, follow these steps:
1. Clone the repository:
```bash
git clone https://github.com/alexlovric/gmac.git
cd gmac/gmac_py
```
2. Create a virtual environment and install build system:
```bash
python3 -m venv .venv
source .venv/bin/activate python3 -m pip install -r requirements.txt
```
3. Build the release binary:
```bash
maturin develop --release
```
4. Build the python wheel:
```bash
maturin build --release
```
5. Running examples:
```bash
python3 -m pip install <path to wheel (target/wheels/*.whl)>
cd examples
python3 -m pip install -r requirements.txt
python3 *simple_ffd_deformation*.py
```
## References
The gmac_morph is heavily influenced by PyGEM (https://github.com/mathLab/PyGeM), and the following
Sieger, Menzel, Botsch. *On Shape Deformation Techniques for Simulation-based Design Optimization.* SEMA SIMAI Springer Series, 2015.
Lombardi, Parolini, Quarteroni, Rozza. *Numerical Simulation of Sailing Boats: Dynamics, FSI, and Shape Optimization.* Springer Optimization and Its Applications, 2012.
## License
MIT License - See [LICENSE](LICENSE) for details.
## Support
If you'd like to support the project consider:
- Identifying the features you'd like to see implemented or bugs you'd like to fix and open an issue.
- Contributing to the code by resolving existing issues, I'm happy to have you.
- Donating to help me continue development, [Buy Me a Coffee](https://coff.ee/alexlovric)