Usage
This guide provides instructions and examples on how to use the brickalize library to convert 3D models into LEGO-like brick structures.
See also
For installation instructions, please refer to the Installation guide.
Core Workflow Example
The most common use case involves loading an STL file, converting it to a voxel representation, building a brick model from those voxels, optionally generating support structures, and finally visualizing or saving the result.
The following script demonstrates this entire process:
Note
You will need an STL file (e.g., named model.stl in the script’s directory) for this example to run. Replace 'model.stl' with the actual path to your file. You might also need to create the output directories (e.g., images/) beforehand, or add os.makedirs('images', exist_ok=True) to the script.
1# examples/basic_usage.py
2from brickalize import (
3 Brick,
4 BrickSet,
5 BrickModel, # Import BrickModel if needed directly in example
6 BrickModelVisualizer,
7 Brickalizer
8)
9import numpy as np
10
11# Initialize variables
12stl_file = 'model.stl'
13output_dir = 'images'
14grid_voxel_count = 20
15grid_direction = "z"
16brick_set = BrickSet([Brick(1, 2), Brick(1, 4), Brick(2, 2), Brick(1, 1), Brick(1, 3), Brick(2, 4), Brick(1, 6), Brick(1, 1, True), Brick(1, 2, True)])
17
18# Voxelize the model
19brick_array = Brickalizer.voxelize_stl(stl_file, grid_voxel_count, grid_direction, fast_mode=True)
20
21# Only keep the shell of the model, making it hollow
22boundary_array = Brickalizer.extract_shell_from_3d_array(brick_array)
23
24# Convert to a brickmodel
25brick_model = Brickalizer.array_to_brick_model(boundary_array, brick_set)
26
27# Generate support
28support_array = Brickalizer.generate_support(brick_model, boundary_array)
29
30# Add support to the brick model
31brick_model = Brickalizer.array_to_brick_model(support_array, brick_set, brick_model, is_support=True)
32
33# Check if all voxels that should be occupied are occupied
34test_array = Brickalizer.brick_model_to_array(brick_model)
35assert np.array_equal(boundary_array, test_array), "The original and converted arrays are not the same!"
36
37# Normalize the brick model to ensure it starts at (0,0,0)
38# Can be helpful in situations where the brick_model is used in a different program
39brick_model.normalize()
40
41# Create a 3D mesh
42mesh_list = BrickModelVisualizer.draw_model(brick_array, support_array) # Optimized for only visible faces
43
44# Create a 3D mesh for each brick
45mesh_brick_list = BrickModelVisualizer.draw_model_individual_bricks(brick_model) # Non-optimized, drawing all faces
46
47# Save the model as mesh or images of each layer
48BrickModelVisualizer.save_model(mesh_list, file_path="brick_model.stl")
49import os
50os.makedirs(output_dir, exist_ok=True)
51BrickModelVisualizer.save_as_images(brick_model, dir_path=output_dir)
52
53# Visualize/show the model
54BrickModelVisualizer.show_model(mesh_list)
Workflow Explanation
Let’s break down the steps shown in the example script:
Import necessary components: Import the required classes from the
brickalizelibrary. The example uses: Import classes likeBrick,BrickSet,Brickalizer, andBrickModelVisualizer.- Configuration:
Define the path to your input
stl_file.Set
grid_voxel_countandgrid_directionto control the resolution and orientation of the voxelization process.Create a
BrickSetcontaining all theBricksizes (including optional support bricks) available for building the model.
Voxelization: Use
Brickalizer.voxelize_stlto convert the geometry from the STL file into a 3D NumPy boolean array (brick_array), whereTrueindicates occupied space. Parameters likefast_modecan be used for quicker, less precise results.Shell Extraction (Optional):
Brickalizer.extract_shell_from_3d_arraycan be used on thebrick_arrayto make the resulting model hollow, keeping only the outer surfaces. The example uses thisboundary_array.Convert Voxels to Bricks:
Brickalizer.array_to_brick_modeltakes the target voxel array (e.g.,boundary_array) and theBrickSet, and populates aBrickModelobject by intelligently placing the largest possible bricks from the set to fill the occupied voxels.Generate Support:
Brickalizer.generate_supportanalyzes the placed building bricks in thebrick_modelagainst the original solid shape (boundary_arrayin this case) to identify overhangs. It returns a new 3D boolean array (support_array) indicating where support pillars are required.Add Support Bricks: If
support_arraycontainsTruevalues (meaning support is needed) and theBrickSetincludes support bricks, callBrickalizer.array_to_brick_modelagain. This time, pass thesupport_array, the existingbrick_model(to add to it), and setis_support=True.Verification (Optional): The example includes an assertion using
Brickalizer.brick_model_to_arrayto check if the array generated from the finalbrick_modelmatches the target array (boundary_array). This helps confirm the conversion integrity.Normalization (Optional): Calling
brick_model.normalize()modifies the brick positions within theBrickModelso that the model’s minimum corner sits at coordinate (0, 0, 0). This can be useful for consistent positioning or exporting.- Create Visualization Meshes:
BrickModelVisualizer.draw_modelgenerates optimized meshes suitable for rendering the overall model shape (using the originalbrick_arrayandsupport_array).BrickModelVisualizer.draw_model_individual_bricksgenerates a separate mesh for each individual brick in thebrick_model. This is less performant for viewing but represents the actual brick structure precisely.
- Save Output:
BrickModelVisualizer.save_modelsaves one of the generated mesh lists (typically the combined one) to an STL file.BrickModelVisualizer.save_as_imagesrenders thebrick_modellayer by layer into PNG images, useful for building instructions.
Display Model:
BrickModelVisualizer.show_modelopens an interactive 3D window to display one of the generated mesh lists.
Key Components
Understanding the main classes helps in customizing the process:
Brick Definition (Brick and BrickSet)
A
Brickobject represents a single type of brick, defined by its dimensions (e.g., length, width) and whether it’s a support brick. Height is a class property.A
BrickSetholds a collection of uniqueBrickobjects that theBrickalizercan use during the conversion process. You must provide at least one non-support brick.
from brickalize import Brick, BrickSet
# Define available building bricks
building_bricks = [
Brick(1, 1), Brick(1, 2), Brick(1, 4),
Brick(2, 2), Brick(2, 3), Brick(2, 4)
]
# Define available support bricks (optional)
support_bricks = [
Brick(1, 1, is_support=True),
Brick(2, 2, is_support=True)
]
# Combine them into a set
my_brick_set = BrickSet(building_bricks + support_bricks)
print(f"Support available: {my_brick_set.has_support}")
Conversion Logic (Brickalizer)
This class contains static methods that perform the core conversion steps.
voxelize_stl(): Converts STL to a 3D boolean NumPy array. Key parameters: *grid_voxel_count,grid_direction: Control resolution. *aspect_ratio: Sets the relative height of voxels (default matchesBrick.height). *fast_mode: Uses only voxel centers for occupancy checks (faster, less accurate). *threshold: Whenfast_mode=False, determines the fraction of voxel corners that must be inside the mesh (0.0 to 1.0).extract_shell_from_3d_array(): Takes a voxel array and returns a new array containing only the outer layer of voxels (hollows the model).array_to_brick_model(): The core algorithm that places bricks from aBrickSetonto aBrickModelaccording to a target voxel array. Can add building or support bricks.generate_support(): Calculates where support structures are needed based on aBrickModeland a reference voxel array.brick_model_to_array(): Converts aBrickModelback into a 3D boolean NumPy array.
Model Representation (BrickModel)
Stores the final bricked structure.
It’s essentially a dictionary where keys are layer indices (Z-height), and values are lists of dictionaries, each representing a placed brick (size, position, support status).
Provides properties like
layers,size,min,maxand methods likenormalize().
Output and Visualization (BrickModelVisualizer)
This class provides static methods to visualize and save the results.
draw_model(): Creates efficient combined meshes from voxel arrays (good for quick visualization).draw_model_individual_bricks(): Creates a mesh list where each element corresponds to a single brick in theBrickModel(accurate structure, slower rendering).save_model(): Saves a mesh list (from eitherdraw_method) to an STL file.save_as_images(): Creates layer-by-layer PNG images. Key parameters: *brick_color,support_color: Customize colors (BGR format). *add_lego_overlay: Adds stud shadow effect. *show_ghost_layer: Displays the layer below semi-transparently. *pixels_per_stud: Controls image resolution.show_model(): Opens an interactiveopen3dwindow to view a mesh list.
Customization and Examples
Voxelization Control
You can adjust the voxelization result significantly:
# Higher resolution along Y axis
hires_array = Brickalizer.voxelize_stl(stl_file, grid_voxel_count=50, grid_direction="y")
# More accurate (but slower) voxel check
accurate_array = Brickalizer.voxelize_stl(stl_file, grid_voxel_count=20, fast_mode=False, threshold=0.6)
# Different aspect ratio (e.g., for plate-like bricks)
plate_array = Brickalizer.voxelize_stl(stl_file, grid_voxel_count=10, aspect_ratio=0.4) # Standard height is 1.2
Using Different Brick Sets
The choice of bricks dramatically affects the output structure and piece count.
from brickalize import Brick, BrickSet, Brickalizer
# ... (assuming voxel_array exists) ...
simple_set = BrickSet([Brick(2, 2), Brick(2, 4)]) # Only 2x2 and 2x4 bricks
simple_model = Brickalizer.array_to_brick_model(voxel_array, simple_set)
# ... (visualize or process simple_model) ...
Customizing Image Output
Tailor the look of the layer images:
BrickModelVisualizer.save_as_images(
brick_model,
dir_path="custom_images",
brick_color=(255, 0, 0), # Blue bricks
support_color=(0, 255, 0), # Green supports
add_lego_overlay=False, # No stud shadows
show_ghost_layer=False, # Don't show layer below
pixels_per_stud=30 # Higher resolution
)
Visualizing Individual Bricks
To see the model composed of its actual constituent bricks (instead of an optimized surface mesh):
# Generate list of meshes, one per brick
mesh_brick_list = BrickModelVisualizer.draw_model_individual_bricks(brick_model)
# Show these individual meshes
BrickModelVisualizer.show_model(mesh_brick_list)