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

[{'answer_id': 10261, 'author': 'cmm', 'author_id': 2082, 'author_profile': 'https://3dprinting.stackexchange.com/users/2082', 'pm_score': 3, 'selected': True, 'text': '<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>\n\n<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>\n\n<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>\n'}, {'answer_id': 15670, 'author': 'Konchog', 'author_id': 26919, 'author_profile': 'https://3dprinting.stackexchange.com/users/26919', 'pm_score': 1, 'selected': False, 'text': "<p>Try voxelfuse.</p>\n<pre><code>    from voxelfuse.voxel_model import VoxelModel\n    from voxelfuse.mesh import Mesh\n    from voxelfuse.primitives import generateMaterials\n    \n    if __name__=='__main__':\n    sponge = [\n        [\n            [1, 1, 1],\n            [1, 0, 1],\n            [1, 1, 1]\n        ],\n        [\n            [1, 0, 1],\n            [0, 0, 0],\n            [1, 0, 1]\n        ],\n        [\n            [1, 1, 1],\n            [1, 0, 1],\n            [1, 1, 1]\n        ]\n    ]\n\n    model = VoxelModel(sponge, generateMaterials(4))  #4 is aluminium.\n    mesh = Mesh.fromVoxelModel(model)\n    mesh.export('mesh.stl')\n</code></pre>\n"}, {'answer_id': 16436, 'author': 'ode han', 'author_id': 28711, 'author_profile': 'https://3dprinting.stackexchange.com/users/28711', 'pm_score': 1, 'selected': False, 'text': '<p>You can try <code>mayavi.mlab</code>:</p>\n<h2>Usage</h2>\n<pre><code>from mayavi import mlab\nimport numpy as np\n\n\ndef draw3d_mayavi(array, path):\n    mlab.contour3d(array.astype(np.int32)) # a window would pop up\n    mlab.savefig(path)\n    mlab.clf() # clear the scene to generate a new one\n</code></pre>\n<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>\n<h2>Note</h2>\n<p>There are some drawbacks:</p>\n<ol>\n<li><p>A window will pop out, you have to clear it in your code if you want to make multiple models.</p>\n</li>\n<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>\n</li>\n<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>\n</li>\n</ol>\n<p>Yet, mayavi is very quick, at least compared with voxelfuse. Maybe some post-processing is needed to solve the size problem.</p>\n<h2>Doc</h2>\n<p>This function also enables setting color and opacity, etc.\nSee <a href="https://docs.enthought.com/mayavi/mayavi/auto/mlab_helper_functions.html#contour3d" rel="nofollow noreferrer">Plotting functions - contour3d</a>:</p>\n<blockquote>\n<h3>contour3d</h3>\n<pre>mayavi.mlab.<b>contour3d</b>(<i>*args, **kwargs</i>)</pre>\n<p>Plots iso-surfaces for a 3D volume of data supplied as arguments.</p>\n<p><strong>Function signatures:</strong></p>\n<p><code>contour3d(scalars, ...) contour3d(x, y, z, scalars, ...)</code>\nscalars is a 3D numpy arrays giving the data on a grid.</p>\n<p>If 4 arrays, (x, y, z, scalars) are passed, the 3 first arrays give\nthe position, and the last the scalar value. The x, y and z arrays are\nthen supposed to have been generated by <em>numpy.mgrid</em>, in other words,\nthey are 3D arrays, with positions lying on a 3D orthogonal and\nregularly spaced grid with nearest neighbor in space matching nearest\nneighbor in the array. The function builds a scalar field assuming the\npoints are regularly spaced.</p>\n<p><strong>Keyword arguments:</strong></p>\n<ul>\n<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\nto 1, eg (1, 1, 1) for white.</p>\n</li>\n<li><p><code>colormap</code> type of colormap to use.</p>\n</li>\n<li><p><code>contours</code> Integer/list specifying number/list of contours. Specifying a list of values will only give the requested contours\nasked for.</p>\n</li>\n<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>\n</li>\n<li><p><code>figure</code> Figure to populate.</p>\n</li>\n<li><p><code>line_width</code> The width of the lines, if any used. Must be a float. Default: 2.0</p>\n</li>\n<li><p><code>name</code> the name of the vtk object created.</p>\n</li>\n<li><p><code>opacity</code> The overall opacity of the vtk object. Must be a float. Default: 1.0</p>\n</li>\n<li><p><code>reset_zoom</code> Reset the zoom to accomodate the data newly added to the scene. Defaults to True.</p>\n</li>\n<li><p><code>transparent</code> make the opacity of the actor depend on the scalar.</p>\n</li>\n<li><p><code>vmax</code> vmax is used to scale the colormap. If None, the max of the data will be used</p>\n</li>\n<li><p><code>vmin</code> vmin is used to scale the colormap. If None, the min of the data will be used</p>\n</li>\n</ul>\n<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>\n<pre><code>\ndef test_contour3d():\n    x, y, z = np.ogrid[-5:5:64j, -5:5:64j, -5:5:64j]\n\n    scalars = x * x * 0.5 + y * y + z * z * 2.0\n\n    obj = contour3d(scalars, contours=4, transparent=True)\n    return obj ```\n</code></pre>\n</blockquote>\n'}]
['https://3dprinting.stackexchange.com/questions/10205', 'https://3dprinting.stackexchange.com', 'https://3dprinting.stackexchange.com/users/16705/']