Module voxelfuse.periodic
Functions for generating triply periodic structures.
Copyright 2020 - Cole Brauer, Dan Aukes
Expand source code
"""
Functions for generating triply periodic structures.
----
Copyright 2020 - Cole Brauer, Dan Aukes
"""
import math
import numpy as np
from typing import Tuple
from tqdm import tqdm
from voxelfuse.voxel_model import VoxelModel, generateMaterials
def gyroid(size: Tuple[int, int, int] = (15, 15, 15), scale: int = 15, coords: Tuple[int, int, int] = (0, 0, 0), material1: int = 1, material2: int = 2, resolution: float = 1):
"""
Generate a Gyroid pattern over a rectangular region.
This function will generate two models representing the "positive" and
"negative" halves of the pattern. If a thin surface is desired,
these two models can be dilated and the intersection of the results found.
However, due to the voxel-based representation, this "surface" will have
a non-zero thickness.
Args:
size: Size of rectangular region
scale: Period of the surface function in voxels
coords: Model origin coordinates
material1: Material index for negative model, corresponds to materials.py
material2: Material index for positive model, corresponds to materials.py
resolution: Number of voxels per mm
Returns:
Negative model, Positive model
"""
s = (2 * math.pi) / scale # scaling multipler
modelData = np.zeros((size[0], size[1], size[2]), dtype=np.uint16)
surface_model_inner = VoxelModel(modelData, generateMaterials(material1), coords=coords, resolution=resolution)
surface_model_outer = VoxelModel(modelData, generateMaterials(material2), coords=coords, resolution=resolution)
for x in tqdm(range(size[0]), desc='Generating Gyroid'):
for y in range(size[1]):
for z in range(size[2]):
t_calc = math.sin(x*s) * math.cos(y*s)
t_calc = math.sin(y*s) * math.cos(z*s) + t_calc
t_calc = math.sin(z*s) * math.cos(x*s) + t_calc
if t_calc < 0:
surface_model_inner.voxels[x, y, z] = 1
else:
surface_model_outer.voxels[x, y, z] = 1
return surface_model_inner, surface_model_outer
def schwarzP(size: Tuple[int, int, int] = (15, 15, 15), scale: int = 15, coords: Tuple[int, int, int] = (0, 0, 0), material1: int = 1, material2: int = 2, resolution: float = 1):
"""
Generate a Schwarz P-surface over a rectangular region.
This function will generate two models representing the "positive" and
"negative" halves of the pattern. If a thin surface is desired,
these two models can be dilated and the intersection of the results found.
However, due to the voxel-based representation, this "surface" will have
a non-zero thickness.
Args:
size: Size of rectangular region
scale: Period of the surface function in voxels
coords: Model origin coordinates
material1: Material index for negative model, corresponds to materials.py
material2: Material index for positive model, corresponds to materials.py
resolution: Number of voxels per mm
Returns:
Negative model, Positive model
"""
s = (2 * math.pi) / scale # scaling multipler
modelData = np.zeros((size[0], size[1], size[2]), dtype=np.uint16)
surface_model_inner = VoxelModel(modelData, generateMaterials(material1), coords=coords, resolution=resolution)
surface_model_outer = VoxelModel(modelData, generateMaterials(material2), coords=coords, resolution=resolution)
for x in tqdm(range(size[0]), desc='Generating Gyroid'):
for y in range(size[1]):
for z in range(size[2]):
t_calc = math.cos(x*s)
t_calc = math.cos(y*s) + t_calc
t_calc = math.cos(z*s) + t_calc
if t_calc < 0:
surface_model_inner.voxels[x, y, z] = 1
else:
surface_model_outer.voxels[x, y, z] = 1
return surface_model_inner, surface_model_outer
def schwarzD(size: Tuple[int, int, int] = (15, 15, 15), scale: int = 15, coords: Tuple[int, int, int] = (0, 0, 0), material1: int = 1, material2: int = 2, resolution: float = 1):
"""
Generate a Schwarz D-surface over a rectangular region.
This function will generate two models representing the "positive" and
"negative" halves of the pattern. If a thin surface is desired,
these two models can be dilated and the intersection of the results found.
However, due to the voxel-based representation, this "surface" will have
a non-zero thickness.
Args:
size: Size of rectangular region
scale: Period of the surface function in voxels
coords: Model origin coordinates
material1: Material index for negative model, corresponds to materials.py
material2: Material index for positive model, corresponds to materials.py
resolution: Number of voxels per mm
Returns:
Negative model, Positive model
"""
s = (2 * math.pi) / scale # scaling multipler
modelData = np.zeros((size[0], size[1], size[2]), dtype=np.uint16)
surface_model_inner = VoxelModel(modelData, generateMaterials(material1), coords=coords, resolution=resolution)
surface_model_outer = VoxelModel(modelData, generateMaterials(material2), coords=coords, resolution=resolution)
for x in tqdm(range(size[0]), desc='Generating Gyroid'):
for y in range(size[1]):
for z in range(size[2]):
t_calc = math.sin(x*s) * math.sin(y*s) * math.sin(z*s)
t_calc = math.sin(x*s) * math.cos(y*s) * math.cos(z*s) + t_calc
t_calc = math.cos(x*s) * math.sin(y*s) * math.cos(z*s) + t_calc
t_calc = math.cos(x*s) * math.cos(y*s) * math.sin(z*s) + t_calc
if t_calc < 0:
surface_model_inner.voxels[x, y, z] = 1
else:
surface_model_outer.voxels[x, y, z] = 1
return surface_model_inner, surface_model_outer
def FRD(size: Tuple[int, int, int] = (15, 15, 15), scale: int = 15, coords: Tuple[int, int, int] = (0, 0, 0), material1: int = 1, material2: int = 2, resolution: float = 1):
"""
Generate a FRD surface over a rectangular region.
This function will generate two models representing the "positive" and
"negative" halves of the pattern. If a thin surface is desired,
these two models can be dilated and the intersection of the results found.
However, due to the voxel-based representation, this "surface" will have
a non-zero thickness.
Args:
size: Size of rectangular region
scale: Period of the surface function in voxels
coords: Model origin coordinates
material1: Material index for negative model, corresponds to materials.py
material2: Material index for positive model, corresponds to materials.py
resolution: Number of voxels per mm
Returns:
Negative model, Positive model
"""
s = (2 * math.pi) / scale # scaling multipler
modelData = np.zeros((size[0], size[1], size[2]), dtype=np.uint16)
surface_model_inner = VoxelModel(modelData, generateMaterials(material1), coords=coords, resolution=resolution)
surface_model_outer = VoxelModel(modelData, generateMaterials(material2), coords=coords, resolution=resolution)
for x in tqdm(range(size[0]), desc='Generating Gyroid'):
for y in range(size[1]):
for z in range(size[2]):
t_calc = 4*(math.cos(x*s) * math.cos(y*s) * math.cos(z*s))
t_calc = -(math.cos(2*x*s) * math.cos(2*y*s)) + t_calc
t_calc = -(math.cos(2*y*s) * math.cos(2*z*s)) + t_calc
t_calc = -(math.cos(2*x*s) * math.cos(2*z*s)) + t_calc
if t_calc < 0:
surface_model_inner.voxels[x, y, z] = 1
else:
surface_model_outer.voxels[x, y, z] = 1
return surface_model_inner, surface_model_outer
Functions
def FRD(size: Tuple[int, int, int] = (15, 15, 15), scale: int = 15, coords: Tuple[int, int, int] = (0, 0, 0), material1: int = 1, material2: int = 2, resolution: float = 1)
-
Generate a FRD surface over a rectangular region.
This function will generate two models representing the "positive" and "negative" halves of the pattern. If a thin surface is desired, these two models can be dilated and the intersection of the results found. However, due to the voxel-based representation, this "surface" will have a non-zero thickness.
Args
size
- Size of rectangular region
scale
- Period of the surface function in voxels
coords
- Model origin coordinates
material1
- Material index for negative model, corresponds to materials.py
material2
- Material index for positive model, corresponds to materials.py
resolution
- Number of voxels per mm
Returns
Negative model, Positive model
Expand source code
def FRD(size: Tuple[int, int, int] = (15, 15, 15), scale: int = 15, coords: Tuple[int, int, int] = (0, 0, 0), material1: int = 1, material2: int = 2, resolution: float = 1): """ Generate a FRD surface over a rectangular region. This function will generate two models representing the "positive" and "negative" halves of the pattern. If a thin surface is desired, these two models can be dilated and the intersection of the results found. However, due to the voxel-based representation, this "surface" will have a non-zero thickness. Args: size: Size of rectangular region scale: Period of the surface function in voxels coords: Model origin coordinates material1: Material index for negative model, corresponds to materials.py material2: Material index for positive model, corresponds to materials.py resolution: Number of voxels per mm Returns: Negative model, Positive model """ s = (2 * math.pi) / scale # scaling multipler modelData = np.zeros((size[0], size[1], size[2]), dtype=np.uint16) surface_model_inner = VoxelModel(modelData, generateMaterials(material1), coords=coords, resolution=resolution) surface_model_outer = VoxelModel(modelData, generateMaterials(material2), coords=coords, resolution=resolution) for x in tqdm(range(size[0]), desc='Generating Gyroid'): for y in range(size[1]): for z in range(size[2]): t_calc = 4*(math.cos(x*s) * math.cos(y*s) * math.cos(z*s)) t_calc = -(math.cos(2*x*s) * math.cos(2*y*s)) + t_calc t_calc = -(math.cos(2*y*s) * math.cos(2*z*s)) + t_calc t_calc = -(math.cos(2*x*s) * math.cos(2*z*s)) + t_calc if t_calc < 0: surface_model_inner.voxels[x, y, z] = 1 else: surface_model_outer.voxels[x, y, z] = 1 return surface_model_inner, surface_model_outer
def gyroid(size: Tuple[int, int, int] = (15, 15, 15), scale: int = 15, coords: Tuple[int, int, int] = (0, 0, 0), material1: int = 1, material2: int = 2, resolution: float = 1)
-
Generate a Gyroid pattern over a rectangular region.
This function will generate two models representing the "positive" and "negative" halves of the pattern. If a thin surface is desired, these two models can be dilated and the intersection of the results found. However, due to the voxel-based representation, this "surface" will have a non-zero thickness.
Args
size
- Size of rectangular region
scale
- Period of the surface function in voxels
coords
- Model origin coordinates
material1
- Material index for negative model, corresponds to materials.py
material2
- Material index for positive model, corresponds to materials.py
resolution
- Number of voxels per mm
Returns
Negative model, Positive model
Expand source code
def gyroid(size: Tuple[int, int, int] = (15, 15, 15), scale: int = 15, coords: Tuple[int, int, int] = (0, 0, 0), material1: int = 1, material2: int = 2, resolution: float = 1): """ Generate a Gyroid pattern over a rectangular region. This function will generate two models representing the "positive" and "negative" halves of the pattern. If a thin surface is desired, these two models can be dilated and the intersection of the results found. However, due to the voxel-based representation, this "surface" will have a non-zero thickness. Args: size: Size of rectangular region scale: Period of the surface function in voxels coords: Model origin coordinates material1: Material index for negative model, corresponds to materials.py material2: Material index for positive model, corresponds to materials.py resolution: Number of voxels per mm Returns: Negative model, Positive model """ s = (2 * math.pi) / scale # scaling multipler modelData = np.zeros((size[0], size[1], size[2]), dtype=np.uint16) surface_model_inner = VoxelModel(modelData, generateMaterials(material1), coords=coords, resolution=resolution) surface_model_outer = VoxelModel(modelData, generateMaterials(material2), coords=coords, resolution=resolution) for x in tqdm(range(size[0]), desc='Generating Gyroid'): for y in range(size[1]): for z in range(size[2]): t_calc = math.sin(x*s) * math.cos(y*s) t_calc = math.sin(y*s) * math.cos(z*s) + t_calc t_calc = math.sin(z*s) * math.cos(x*s) + t_calc if t_calc < 0: surface_model_inner.voxels[x, y, z] = 1 else: surface_model_outer.voxels[x, y, z] = 1 return surface_model_inner, surface_model_outer
def schwarzD(size: Tuple[int, int, int] = (15, 15, 15), scale: int = 15, coords: Tuple[int, int, int] = (0, 0, 0), material1: int = 1, material2: int = 2, resolution: float = 1)
-
Generate a Schwarz D-surface over a rectangular region.
This function will generate two models representing the "positive" and "negative" halves of the pattern. If a thin surface is desired, these two models can be dilated and the intersection of the results found. However, due to the voxel-based representation, this "surface" will have a non-zero thickness.
Args
size
- Size of rectangular region
scale
- Period of the surface function in voxels
coords
- Model origin coordinates
material1
- Material index for negative model, corresponds to materials.py
material2
- Material index for positive model, corresponds to materials.py
resolution
- Number of voxels per mm
Returns
Negative model, Positive model
Expand source code
def schwarzD(size: Tuple[int, int, int] = (15, 15, 15), scale: int = 15, coords: Tuple[int, int, int] = (0, 0, 0), material1: int = 1, material2: int = 2, resolution: float = 1): """ Generate a Schwarz D-surface over a rectangular region. This function will generate two models representing the "positive" and "negative" halves of the pattern. If a thin surface is desired, these two models can be dilated and the intersection of the results found. However, due to the voxel-based representation, this "surface" will have a non-zero thickness. Args: size: Size of rectangular region scale: Period of the surface function in voxels coords: Model origin coordinates material1: Material index for negative model, corresponds to materials.py material2: Material index for positive model, corresponds to materials.py resolution: Number of voxels per mm Returns: Negative model, Positive model """ s = (2 * math.pi) / scale # scaling multipler modelData = np.zeros((size[0], size[1], size[2]), dtype=np.uint16) surface_model_inner = VoxelModel(modelData, generateMaterials(material1), coords=coords, resolution=resolution) surface_model_outer = VoxelModel(modelData, generateMaterials(material2), coords=coords, resolution=resolution) for x in tqdm(range(size[0]), desc='Generating Gyroid'): for y in range(size[1]): for z in range(size[2]): t_calc = math.sin(x*s) * math.sin(y*s) * math.sin(z*s) t_calc = math.sin(x*s) * math.cos(y*s) * math.cos(z*s) + t_calc t_calc = math.cos(x*s) * math.sin(y*s) * math.cos(z*s) + t_calc t_calc = math.cos(x*s) * math.cos(y*s) * math.sin(z*s) + t_calc if t_calc < 0: surface_model_inner.voxels[x, y, z] = 1 else: surface_model_outer.voxels[x, y, z] = 1 return surface_model_inner, surface_model_outer
def schwarzP(size: Tuple[int, int, int] = (15, 15, 15), scale: int = 15, coords: Tuple[int, int, int] = (0, 0, 0), material1: int = 1, material2: int = 2, resolution: float = 1)
-
Generate a Schwarz P-surface over a rectangular region.
This function will generate two models representing the "positive" and "negative" halves of the pattern. If a thin surface is desired, these two models can be dilated and the intersection of the results found. However, due to the voxel-based representation, this "surface" will have a non-zero thickness.
Args
size
- Size of rectangular region
scale
- Period of the surface function in voxels
coords
- Model origin coordinates
material1
- Material index for negative model, corresponds to materials.py
material2
- Material index for positive model, corresponds to materials.py
resolution
- Number of voxels per mm
Returns
Negative model, Positive model
Expand source code
def schwarzP(size: Tuple[int, int, int] = (15, 15, 15), scale: int = 15, coords: Tuple[int, int, int] = (0, 0, 0), material1: int = 1, material2: int = 2, resolution: float = 1): """ Generate a Schwarz P-surface over a rectangular region. This function will generate two models representing the "positive" and "negative" halves of the pattern. If a thin surface is desired, these two models can be dilated and the intersection of the results found. However, due to the voxel-based representation, this "surface" will have a non-zero thickness. Args: size: Size of rectangular region scale: Period of the surface function in voxels coords: Model origin coordinates material1: Material index for negative model, corresponds to materials.py material2: Material index for positive model, corresponds to materials.py resolution: Number of voxels per mm Returns: Negative model, Positive model """ s = (2 * math.pi) / scale # scaling multipler modelData = np.zeros((size[0], size[1], size[2]), dtype=np.uint16) surface_model_inner = VoxelModel(modelData, generateMaterials(material1), coords=coords, resolution=resolution) surface_model_outer = VoxelModel(modelData, generateMaterials(material2), coords=coords, resolution=resolution) for x in tqdm(range(size[0]), desc='Generating Gyroid'): for y in range(size[1]): for z in range(size[2]): t_calc = math.cos(x*s) t_calc = math.cos(y*s) + t_calc t_calc = math.cos(z*s) + t_calc if t_calc < 0: surface_model_inner.voxels[x, y, z] = 1 else: surface_model_outer.voxels[x, y, z] = 1 return surface_model_inner, surface_model_outer