Skip to main content

GMAC

Build & Test License: 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):

Variation 1 Variation 2

Add to your rust project

Add the following to your Cargo.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:

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(())
}
Original mesh & control points Deformed mesh & control points

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:

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:

Original mesh & control points Deformed mesh & control points

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).

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:
    git clone https://github.com/alexlovric/gmac.git
    cd gmac/gmac_py
    
  2. 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
    
  3. Build the release binary:
    maturin develop --release
    
  4. Build the python wheel:
    maturin build --release
    
  5. Running examples:
    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 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

Metadata

Release files for gmac 0.2.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Built distributions (wheels)

Table of built distributions (wheels) for gmac 0.2.0
File Interpreter ABI Platform
gmac-0.2.0-cp38-abi3-win_amd64.whl CPython 3.8 abi3 Windows x86-64 Details
gmac-0.2.0-cp38-abi3-manylinux_2_34_x86_64.whl CPython 3.8 abi3 Linux glibc 2.34+ x86-64 Details
gmac-0.2.0-cp38-abi3-macosx_11_0_arm64.whl CPython 3.8 abi3 macOS 11.0+ ARM64 Details

Total release size: 1.2 MB

Release files / gmac-0.2.0-cp38-abi3-win_amd64.whl

Download URL gmac-0.2.0-cp38-abi3-win_amd64.whl
Size 355.1 kB
Tags CPython 3.8 Windows x86-64 abi3
SHA-256 checksum
How to use checksums
48042453603eae8320edd82a48b82bffb1be885026ec4abf9701b14ae606f308
BLAKE2b-256 checksum
How to use checksums
0e7813b82f44cb3ec2b1d150bf31073994236cdee08a0a44f13aa7a653565f80
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via maturin/1.9.0

Release files / gmac-0.2.0-cp38-abi3-manylinux_2_34_x86_64.whl

Download URL gmac-0.2.0-cp38-abi3-manylinux_2_34_x86_64.whl
Size 452.3 kB
Tags CPython 3.8 Linux glibc 2.34+ x86-64 abi3
SHA-256 checksum
How to use checksums
c7987bbe8a1b59226816de4d4103c1c624c3c552a3bca7dd5af204fcdbbf45de
BLAKE2b-256 checksum
How to use checksums
f22bb7a956a365fa0adae08695573594ef0c6bad802121d517531760f815b27c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via maturin/1.9.0

Release files / gmac-0.2.0-cp38-abi3-macosx_11_0_arm64.whl

Download URL gmac-0.2.0-cp38-abi3-macosx_11_0_arm64.whl
Size 394.1 kB
Tags CPython 3.8 abi3 macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
c6ffc11b66de5f92f63496d40c74154d8bfa0d45302dc4537fa5b03d186395e0
BLAKE2b-256 checksum
How to use checksums
7784aba6ddf4c0a4814922ef39938d66ee7b1ba55375b476b527a6a39c12ee95
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via maturin/1.9.0

Release history Release notifications | RSS feed

This release

0.2.0 This release

3 release files

0.1.8

3 release files

0.1.7

3 release files

0.1.6

3 release files

0.1.5

4 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page