<p>I agree with the use of OpenSCAD, but since it is difficult to program in OpenSCAD, I would use <a href="https://github.com/SolidCode/SolidPython" rel="nofollow noreferrer">SolidPython</a>, which is a front end for OpenSCAD with the full programming capability of Python.</p>

<p>In the alternative, you could use any programming language to decode your arrays and generate the OpenSCAD code for the little network of cubes (or voxels).</p>

<p>The final possibility is to generate an STL file directly.  I've helped someone do this, but we found the rules to be a little non-intuitive.  We used mesh tools to check out results, both by looking for error messages, and by displaying the result to see if it looked as we intended it to look.</p>

CC BY-SA 4.0
2019-07-03T20:38:04.323Z
It's also possible to generate STL files in Python using [numpy-stl](https://pypi.org/project/numpy-stl/).
Anderson Green
CC BY-SA 4.0
2019-11-10T02:41:08.810Z
An OpenSCAD approach will be fine if you're going for a low-res minecraft style model with a smallish number of cubes. If the voxels are supposed to approximate a smooth surface at the printer's best resolution, then OpenSCAD will take days to render it out. There has got to be a better way to do this!
N. Virgo
CC BY-SA 4.0
2019-06-13T21:44:29.540Z
2019-06-14T20:52:53.543Z
2019-06-14T20:52:53.543Z
cmm
<p>You can try <code>mayavi.mlab</code>:</p>
<h2>Usage</h2>
<pre><code>from mayavi import mlab
import numpy as np


def draw3d_mayavi(array, path):
    mlab.contour3d(array.astype(np.int32)) # a window would pop up
    mlab.savefig(path)
    mlab.clf() # clear the scene to generate a new one
</code></pre>
<p>mayavi's recontruction is meant for generating 3D heatmap models of the array, so you have to put in a numeric one with 1s and 0s.</p>
<h2>Note</h2>
<p>There are some drawbacks:</p>
<ol>
<li><p>A window will pop out, you have to clear it in your code if you want to make multiple models.</p>
</li>
<li><p>The model reconstructed is .obj and can be very large. If you look closer at the model, you'll see that on the boder the mesh gets 3 layers. I guess the program assumes there to be some gradient.</p>
</li>
<li><p>The <code>contour3d</code> function can set <code>line_width</code>, but I don't see any sense of using it for binary data.</p>
</li>
</ol>
<p>Yet, mayavi is very quick, at least compared with voxelfuse. Maybe some post-processing is needed to solve the size problem.</p>
<h2>Doc</h2>
<p>This function also enables setting color and opacity, etc.
See <a href="https://docs.enthought.com/mayavi/mayavi/auto/mlab_helper_functions.html#contour3d" rel="nofollow noreferrer">Plotting functions - contour3d</a>:</p>
<blockquote>
<h3>contour3d</h3>
<pre>mayavi.mlab.<b>contour3d</b>(<i>*args, **kwargs</i>)</pre>
<p>Plots iso-surfaces for a 3D volume of data supplied as arguments.</p>
<p><strong>Function signatures:</strong></p>
<p><code>contour3d(scalars, ...) contour3d(x, y, z, scalars, ...)</code>
scalars is a 3D numpy arrays giving the data on a grid.</p>
<p>If 4 arrays, (x, y, z, scalars) are passed, the 3 first arrays give
the position, and the last the scalar value. The x, y and z arrays are
then supposed to have been generated by <em>numpy.mgrid</em>, in other words,
they are 3D arrays, with positions lying on a 3D orthogonal and
regularly spaced grid with nearest neighbor in space matching nearest
neighbor in the array. The function builds a scalar field assuming the
points are regularly spaced.</p>
<p><strong>Keyword arguments:</strong></p>
<ul>
<li><p><code>color</code> the color of the vtk object. Overides the colormap, if any, when specified. This is specified as a triplet of float ranging from 0
to 1, eg (1, 1, 1) for white.</p>
</li>
<li><p><code>colormap</code> type of colormap to use.</p>
</li>
<li><p><code>contours</code> Integer/list specifying number/list of contours. Specifying a list of values will only give the requested contours
asked for.</p>
</li>
<li><p><code>extent</code> [xmin, xmax, ymin, ymax, zmin, zmax] Default is the x, y, z arrays extent. Use this to change the extent of the object created.</p>
</li>
<li><p><code>figure</code> Figure to populate.</p>
</li>
<li><p><code>line_width</code> The width of the lines, if any used. Must be a float. Default: 2.0</p>
</li>
<li><p><code>name</code> the name of the vtk object created.</p>
</li>
<li><p><code>opacity</code> The overall opacity of the vtk object. Must be a float. Default: 1.0</p>
</li>
<li><p><code>reset_zoom</code> Reset the zoom to accomodate the data newly added to the scene. Defaults to True.</p>
</li>
<li><p><code>transparent</code> make the opacity of the actor depend on the scalar.</p>
</li>
<li><p><code>vmax</code> vmax is used to scale the colormap. If None, the max of the data will be used</p>
</li>
<li><p><code>vmin</code> vmin is used to scale the colormap. If None, the min of the data will be used</p>
</li>
</ul>
<p><strong>Example</strong> (run in <code>ipython --gui=qt</code>, or in the mayavi2 interactive shell, see <a href="https://docs.enthought.com/mayavi/mayavi/mlab_running_scripts.html#running-mlab-scripts" rel="nofollow noreferrer">Running mlab scripts</a> for more info):</p>
<pre><code>
def test_contour3d():
    x, y, z = np.ogrid[-5:5:64j, -5:5:64j, -5:5:64j]

    scalars = x * x * 0.5 + y * y + z * z * 2.0

    obj = contour3d(scalars, contours=4, transparent=True)
    return obj ```
</code></pre>
</blockquote>

CC BY-SA 4.0
2021-06-04T13:06:20.650Z
Welcome to 3D Printing SE and thank you for your contribution. Could you summarize the "Doc" you linked to since links can "die" over time? Also, when you get a chance, please take the [tour] to understand how the site works and how it is different than others.
agarza
CC BY-SA 4.0
2021-06-04T06:17:19.697Z
2021-06-05T01:57:00.047Z
2021-06-05T01:57:00.047Z
ode han
<p>Try voxelfuse.</p>
<pre><code>    from voxelfuse.voxel_model import VoxelModel
    from voxelfuse.mesh import Mesh
    from voxelfuse.primitives import generateMaterials
    
    if __name__=='__main__':
    sponge = [
        [
            [1, 1, 1],
            [1, 0, 1],
            [1, 1, 1]
        ],
        [
            [1, 0, 1],
            [0, 0, 0],
            [1, 0, 1]
        ],
        [
            [1, 1, 1],
            [1, 0, 1],
            [1, 1, 1]
        ]
    ]

    model = VoxelModel(sponge, generateMaterials(4))  #4 is aluminium.
    mesh = Mesh.fromVoxelModel(model)
    mesh.export('mesh.stl')
</code></pre>

CC BY-SA 4.0
2021-06-05T02:15:30.913Z
It's great that you posted an answer, with a code example, thereby expanding upon your comment. However, I can't help wondering whether a little explanation of the code would help significantly, i.e. a brief detail about each line (especially the last three lines). Just to save people having to go off and google `VoxelModel` in order to understand what is happening in the code.
Greenonline
CC BY-SA 4.0
2021-06-05T10:15:23.607Z
@greenonline, sometimes I have little time and my answers are rushed- you are correct that this was minimal. But Python is (generally) so easy to install packages, ang Google is our friend for more details, in this case I thought maybe it would help the questioner.  
I would also have offered more had I had more experience with voxelfuse - but I generally use other modules for my 3D work..
Konchog
CC BY-SA 4.0
2021-02-17T19:25:52.137Z
2021-02-17T19:25:52.137Z
Konchog
<p>Given a 3D boolean array representing voxels, how can it be converted to a 3D-printer-ready file?</p>

<p>The end-goal I would like to achieve is to print the 3D shape that the numpy array represents (<code>True</code> coding for <em>fill this voxel</em>, <code>False</code> for <em>leave it empty</em>).</p>

<p>For example, the array</p>

<pre><code>[
    [
        [T, T, T],
        [T, F, T],
        [T, T, T]
    ],
    [
        [T, F, T],
        [F, F, F],
        [T, F, T]
    ],
    [
        [T, T, T],
        [T, F, T],
        [T, T, T]
    ]
]
</code></pre>

<p>would encode a <a href="https://en.wikipedia.org/wiki/Void_Cube" rel="nofollow noreferrer">level-1 Menger sponge</a>.</p>

CC BY-SA 4.0
2019-06-09T15:03:04.597Z
Seems like OpenSCAD would be suitable for this.
T. M.
<stl><python>
Convert a 3D NumPy array of voxels to an STL file
Stephane Bersier
# Convert a 3D NumPy array of voxels to an STL file

(Asked by: username_0 on 2019-06-08)

Given a 3D boolean array representing voxels, how can it be converted to a 3D-printer-ready file?

The end-goal I would like to achieve is to print the 3D shape that the numpy array represents (`True` coding for *fill this voxel*, `False` for *leave it empty*).

For example, the array

```
[
    [
        [T, T, T],
        [T, F, T],
        [T, T, T]
    ],
    [
        [T, F, T],
        [F, F, F],
        [T, F, T]
    ],
    [
        [T, T, T],
        [T, F, T],
        [T, T, T]
    ]
]

```

would encode a [level-1 Menger sponge](https://en.wikipedia.org/wiki/Void_Cube).

**Tags:** stl, python

> **Comments:**
> **username_1**: Seems like OpenSCAD would be suitable for this.  

---

## 3 answers

### Answer by username_2 on 2019-06-13. Score: 2 | Accepted answer

I agree with the use of OpenSCAD, but since it is difficult to program in OpenSCAD, I would use [SolidPython](https://github.com/SolidCode/SolidPython), which is a front end for OpenSCAD with the full programming capability of Python.

In the alternative, you could use any programming language to decode your arrays and generate the OpenSCAD code for the little network of cubes (or voxels).

The final possibility is to generate an STL file directly. I've helped someone do this, but we found the rules to be a little non-intuitive. We used mesh tools to check out results, both by looking for error messages, and by displaying the result to see if it looked as we intended it to look.

> **Comments:**
> **username_3**: It's also possible to generate STL files in Python using [numpy-stl](https://pypi.org/project/numpy-stl/).  
> **username_4**: An OpenSCAD approach will be fine if you're going for a low-res minecraft style model with a smallish number of cubes. If the voxels are supposed to approximate a smooth surface at the printer's best resolution, then OpenSCAD will take days to render it out. There has got to be a better way to do this!  

---

### Answer by username_5 on 2021-06-04. Score: 1

You can try `mayavi.mlab`:

## Usage

```
from mayavi import mlab
import numpy as np

def draw3d_mayavi(array, path):
    mlab.contour3d(array.astype(np.int32)) # a window would pop up
    mlab.savefig(path)
    mlab.clf() # clear the scene to generate a new one

```

mayavi's recontruction is meant for generating 3D heatmap models of the array, so you have to put in a numeric one with 1s and 0s.

## Note

There are some drawbacks:

1. A window will pop out, you have to clear it in your code if you want to make multiple models.
2. The model reconstructed is .obj and can be very large. If you look closer at the model, you'll see that on the boder the mesh gets 3 layers. I guess the program assumes there to be some gradient.
3. The `contour3d` function can set `line_width`, but I don't see any sense of using it for binary data.

Yet, mayavi is very quick, at least compared with voxelfuse. Maybe some post-processing is needed to solve the size problem.

## Doc

This function also enables setting color and opacity, etc.
See [Plotting functions - contour3d](https://docs.enthought.com/mayavi/mayavi/auto/mlab_helper_functions.html#contour3d):

> ### contour3d
>
> ```
> mayavi.mlab.contour3d(*args, **kwargs)
> ```
>
> Plots iso-surfaces for a 3D volume of data supplied as arguments.
>
> **Function signatures:**
>
> `contour3d(scalars, ...) contour3d(x, y, z, scalars, ...)`
> scalars is a 3D numpy arrays giving the data on a grid.
>
> If 4 arrays, (x, y, z, scalars) are passed, the 3 first arrays give
> the position, and the last the scalar value. The x, y and z arrays are
> then supposed to have been generated by *numpy.mgrid*, in other words,
> they are 3D arrays, with positions lying on a 3D orthogonal and
> regularly spaced grid with nearest neighbor in space matching nearest
> neighbor in the array. The function builds a scalar field assuming the
> points are regularly spaced.
>
> **Keyword arguments:**
>
> * `color` the color of the vtk object. Overides the colormap, if any, when specified. This is specified as a triplet of float ranging from 0
>   to 1, eg (1, 1, 1) for white.
> * `colormap` type of colormap to use.
> * `contours` Integer/list specifying number/list of contours. Specifying a list of values will only give the requested contours
>   asked for.
> * `extent` [xmin, xmax, ymin, ymax, zmin, zmax] Default is the x, y, z arrays extent. Use this to change the extent of the object created.
> * `figure` Figure to populate.
> * `line_width` The width of the lines, if any used. Must be a float. Default: 2.0
> * `name` the name of the vtk object created.
> * `opacity` The overall opacity of the vtk object. Must be a float. Default: 1.0
> * `reset_zoom` Reset the zoom to accomodate the data newly added to the scene. Defaults to True.
> * `transparent` make the opacity of the actor depend on the scalar.
> * `vmax` vmax is used to scale the colormap. If None, the max of the data will be used
> * `vmin` vmin is used to scale the colormap. If None, the min of the data will be used
>
> **Example** (run in `ipython --gui=qt`, or in the mayavi2 interactive shell, see [Running mlab scripts](https://docs.enthought.com/mayavi/mayavi/mlab_running_scripts.html#running-mlab-scripts) for more info):
>
> ```
>
> def test_contour3d():
>     x, y, z = np.ogrid[-5:5:64j, -5:5:64j, -5:5:64j]
>
>     scalars = x * x * 0.5 + y * y + z * z * 2.0
>
>     obj = contour3d(scalars, contours=4, transparent=True)
>     return obj ```
>
> ```

> **Comments:**
> **username_6**: Welcome to 3D Printing SE and thank you for your contribution. Could you summarize the "Doc" you linked to since links can "die" over time? Also, when you get a chance, please take the [tour] to understand how the site works and how it is different than others.  

---

### Answer by username_7 on 2021-02-17. Score: 1

Try voxelfuse.

```
    from voxelfuse.voxel_model import VoxelModel
    from voxelfuse.mesh import Mesh
    from voxelfuse.primitives import generateMaterials
    
    if __name__=='__main__':
    sponge = [
        [
            [1, 1, 1],
            [1, 0, 1],
            [1, 1, 1]
        ],
        [
            [1, 0, 1],
            [0, 0, 0],
            [1, 0, 1]
        ],
        [
            [1, 1, 1],
            [1, 0, 1],
            [1, 1, 1]
        ]
    ]

    model = VoxelModel(sponge, generateMaterials(4))  #4 is aluminium.
    mesh = Mesh.fromVoxelModel(model)
    mesh.export('mesh.stl')

```

> **Comments:**
> **username_8**: It's great that you posted an answer, with a code example, thereby expanding upon your comment. However, I can't help wondering whether a little explanation of the code would help significantly, i.e. a brief detail about each line (especially the last three lines). Just to save people having to go off and google `VoxelModel` in order to understand what is happening in the code.  
> **username_7**: @username_8, sometimes I have little time and my answers are rushed- you are correct that this was minimal. But Python is (generally) so easy to install packages, ang Google is our friend for more details, in this case I thought maybe it would help the questioner.   I would also have offered more had I had more experience with voxelfuse - but I generally use other modules for my 3D work..  

---

