A fast geometry manipulation and creation library written in Rust, wrapped in python
Project description
GMAC
A fast geometry manipulation and creation library made in rust, with a convenient python interface, and very few dependencies. Primary features include:
- Create primitives
- Transform geometries (or selection just a selection of nodes)
- Large range of selection and transformation tools
- Deform geometries using RBF and FFD
- Convenient python interface (gmac_py)
- Fast and memory efficient
Here's a demonstration of a plane tail deformed using the Free Form deformer (FFD):
| Variation 1 | Variation 2 |
|---|---|
Both plane tail variations were created using the Gmac Free Form deformer (FFD).
Contributing
Build python from source
These instructions assume that Python3 and Cargo are installed on your system. To set up this project, follow these steps:
- Clone the repository:
git clone https://github.com/alexlovric/gmac.git cd gmac/gmac_py
- Create a virtual environment and install build system:
python3 -m venv .venv source .venv/bin/activate # In windows /Scripts/activate python3 -m pip install -r requirements.txt
- Build the release binary:
maturin develop --release
- Build the python wheel:
maturin build --release
Examples in Python
Using GMAC to deform a box
Heres a simple demonstration where we deform a box mesh using RbfDeformer from the gmac_morph library.
Firstly lets import the required modules and create a box mesh that we intend to deform using the generate_box function:
import gmac
import gmac.morph as morph
import gmac.io as io
import numpy as np
box = gmac.generate_box(
length=[1.0, 1.0, 1.0], centre=[0.0, 0.0, 0.0], resolution=[5, 5, 5]
)
io.write_stl(nodes=box.nodes, cells=box.cells, filename="original_box.stl")
Now lets define some control points to use in the training of our RBF deformer. We use generate_block_cluster to create a grid of 3D points:
original_control_points = np.array(
gmac.generate_block_cluster(
length=[1.2, 1.2, 1.2], centre=[0.0, 0.0, 0.0], resolution=[2, 2, 2]
)
)
io.write_vtp(original_control_points, "original_control_points.vtp")
Now before we define the deformed control points we want to use as the output training data for our RBF deformer, lets select nodes that we want to change from the original control points. GMAC has various selection tools to allow you to select nodes of the mesh, in this case we utilise select_nodes_in_plane_direction to select the nodes in the direction of a plane:
target_control_point_ids = gmac.select_nodes_in_plane_direction(
nodes=original_control_points, origin=[0.3, 0.0, 0.0], normal=[1.0, 0.0, 0.0]
)
io.write_vtp(nodes=original_control_points[target_control_point_ids], filename="target_points.vtp")
We will define our deformed control points by transforming the target points of the original control points. To do this we will utilise one of GMACs various transformation tools, in this case transform_points. We define our transformation using a transformation matrix, in this case we will translate, rotate and scale the target points:
deformed_control_points = original_control_points.copy()
deformed_control_points[target_control_point_ids] = gmac.transform_nodes(
nodes=deformed_control_points[target_control_point_ids],
transformation_matrix=gmac.build_transformation_matrix(
translation=[1.0, 0.0, 0.0],
rotation=[45.0, 0.0, 0.0],
scaling=[1.0, 0.75, 0.75],
),
origin=[0.0, 0.0, 0.0],
)
io.write_vtp(nodes=deformed_control_points, filename="deformed_control_points.vtp")
Now we can set up the RbfDeformer using these original and deformed control points as well as some other parameters specific to the the RBF interpolator. Using this deformer we can deform the original box:
rbf = morph.RbfDeformer(
original_control_points=original_control_points,
deformed_control_points=deformed_control_points,
kernel="gaussian",
epsilon=1.0,
)
box.nodes = rbf.deform(points=box.nodes)
io.write_stl(nodes=box.nodes, cells=box.cells, filename="deformed_box.stl")
Here you can see the original control points and mesh, as well as the deformed control points and mesh:
| Original control points | Deformed control points |
|---|---|
Similarly the Free Form Deformer can be used. This gives more control over the deformation process and can be used for deforming specific parts of the mesh without affecting the rest of the mesh. Starting from the same geometry as before, we can define a design block (the specific region we want to deform) and deform the geometry as follows:
design_block = morph.DesignBlock([0.8, 1.2, 1.2], [0.2, 0.0, 0.0], [0.0, 0.0, 0.0], [2, 2, 2])
free_design_ids = design_block.select_free_design_nodes(geometry, 2)
transformation_matrix = gmac.build_transformation_matrix([0.25, 0.0, 0.0], [45.0, 0.0, 0.0], [1.0, 1.5, 1.5])
deformed_design_nodes = np.array(design_block.nodes)
deformed_design_nodes[free_design_ids] = gmac.transform_nodes(
deformed_design_nodes[free_design_ids],
transformation_matrix,
[0.2, 0., 0.],
)
ffd = morph.FreeFormDeformer(design_block)
geometry.nodes = ffd.deform(geometry.nodes, deformed_design_nodes)
io.write_stl(geometry.nodes, geometry.cells, "deformed_geometry.stl")
| Original control points | Deformed control points |
|---|---|
Examples in Rust
Using GMAC to deform a box
Using the gmac_morph library a box can be deformed using both RBF and FFD tools. In this case we will demonstrate the FFD process. Firstly lets import the modules required and create a box:
use gmac_core::primitives::generate_box;
use gmac_morph::{ffd::FreeFormDeformer, design_block::DesignBlock};
use gmac_core::transformation::{build_transformation_matrix, transform_node};
use gmac_io::vtk::{write_vtu, write_vtp};
fn main() {
let mut geometry =
generate_box([1.0, 1.0, 1.0], [0.0, 0.0, 0.0], [0.0, 0.0, 0.0], [5, 5, 5]);
...
}
Now lets specify the design block that we want to use to map our deformation:
...
let design_block =
DesignBlock::new([0.8, 1.2, 1.2], [0.2, 0.0, 0.0], [0.0, 0.0, 0.0], [2, 2, 2]);
We will now deform the design block nodes so that the deformation can be mapped to the box. First we will clone the nodes. Then select the last layer of the nodes and transform it:
...
let free_design_ids = design_block.select_free_design_nodes(&geometry, Some(2)).unwrap();
let mut deformed_design_nodes = design_block.nodes.clone();
let transformation_matrix =
build_transformation_matrix([0.25, 0.0, 0.0], [45.0, 0.0, 0.0], [1.0, 1.5, 1.5]);
free_design_ids.iter().for_each(|&id| {
transform_node(&mut deformed_design_nodes[id], &transformation_matrix, &[0.2, 0., 0.])
});
...
Lets create the free form deformer and deform the target nodes:
...
let ffd = FreeFormDeformer::new(design_block);
geometry.nodes = ffd.deform(&target_nodes, &deformed_design_nodes).unwrap();
write_vtu(&geometry.nodes, &geometry.cells, Some("target/deformed.vtu")).unwrap();
write_stl(&geometry.nodes, &geometry.cells, Some("target/deformed.stl")).unwrap();
...
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.
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distributions
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file gmac-0.1.5.tar.gz.
File metadata
- Download URL: gmac-0.1.5.tar.gz
- Upload date:
- Size: 57.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: maturin/1.9.0
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
aeb77796224d442968deb8f31ca019ee1db676efd14ae82a38f3bb41955c5669
|
|
| MD5 |
3cc18a437a89b681124338453f8c73cb
|
|
| BLAKE2b-256 |
bb558d4846a7d08f09e2b9720317d9d9dbcc755d45712ff93b1df1bb2df7c963
|
File details
Details for the file gmac-0.1.5-cp38-abi3-win_amd64.whl.
File metadata
- Download URL: gmac-0.1.5-cp38-abi3-win_amd64.whl
- Upload date:
- Size: 249.2 kB
- Tags: CPython 3.8+, Windows x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: maturin/1.9.0
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
2f221dedc55bf7ce12b73a403359b2b8d78b089d4d48b29d57676c2ccf51dedf
|
|
| MD5 |
5f339ed34c41a2eeab0502b83d1806ea
|
|
| BLAKE2b-256 |
30625f5facbdc66d0244f4018ed3df8d356503acbd89693e560f7a6a00899a90
|
File details
Details for the file gmac-0.1.5-cp38-abi3-manylinux_2_34_x86_64.whl.
File metadata
- Download URL: gmac-0.1.5-cp38-abi3-manylinux_2_34_x86_64.whl
- Upload date:
- Size: 2.3 MB
- Tags: CPython 3.8+, manylinux: glibc 2.34+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: maturin/1.9.0
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c0e5088a7157f77a3d308950a447fbd317af8aa2e4b2b81a6b6dfa706b0c3e0b
|
|
| MD5 |
e1d96c31603f4203207495b25e2fccd2
|
|
| BLAKE2b-256 |
ab7d4e3ebb85df2a89a62a4b1415e3b4195014d0357282bdb677508b35d1dbcb
|
File details
Details for the file gmac-0.1.5-cp38-abi3-macosx_11_0_arm64.whl.
File metadata
- Download URL: gmac-0.1.5-cp38-abi3-macosx_11_0_arm64.whl
- Upload date:
- Size: 304.5 kB
- Tags: CPython 3.8+, macOS 11.0+ ARM64
- Uploaded using Trusted Publishing? No
- Uploaded via: maturin/1.9.0
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ec989a167628f8dd113cb8c482a28d1722bb0520a8b2a0d000e627cfcdd885d0
|
|
| MD5 |
c49b54ed30b1880a1eab108e1000416e
|
|
| BLAKE2b-256 |
119a4f0a46f3e720fdabb9796559f5a31ab414773c4cbcfe4924fcb44b9ea226
|