Skip to content

Instantly share code, notes, and snippets.

@julesghub
Created March 16, 2017 22:07
Show Gist options
  • Save julesghub/df35115d1247f7f75f1eafa6461d2d83 to your computer and use it in GitHub Desktop.
Save julesghub/df35115d1247f7f75f1eafa6461d2d83 to your computer and use it in GitHub Desktop.
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Complex shapes in Underworld: Voxels, binvox and the Cow\n",
"\n",
"This notebook describes a possible method for importing complex geometries onto Underworld particles\n",
"\n",
"Given a supported 3D model file format (based on binvox):\n",
" VRML V2.0: almost fully supported\n",
" UG, OBJ, OFF, DXF, XGL, POV, BREP, PLY, JOT: only polygons supported\n",
"\n",
"The workflow is:\n",
" 1. Use **binvox** to convert 3D model file into a voxel binary file.\n",
" 2. Use numpy to read in the voxel file.\n",
" 3. Setup an uw particle distribution.\n",
" 4. Use scipy to interpolate (ndimage) the voxel field onto the particles"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Input 3D model: \n",
"downloaded from http://tf3dm.com/3d-model/cow-39025.html\n",
"\n",
"**Note**: We can also use 3D software like 'blender' to manipulate the model file\n",
"\n",
"Binvox \n",
"downloaded http://www.patrickmin.com/binvox/\n",
"\n",
"Run this command on the input image \n",
"`./binvox -c -t vtk <filename>.obj`\n",
"\n",
"This will output a file named `<filename>.vtk`"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"import numpy as np\n",
"from scipy import ndimage\n",
"import underworld as uw\n",
"import glucifer"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"# read in the vtk file, create a binary file from it\n",
"prefix = '/home/julian/Downloads/theCow/cleanCow'\n",
"with open(prefix+'.vtk') as fp, open(prefix+'.binary','w') as ff:\n",
" \n",
" for line in fp:\n",
" if line.startswith(\"DIMENSIONS\"):\n",
" shape = line.partition(\" \")[2].rstrip().split(\" \")\n",
" if line.startswith(\"LOOKUP_TABLE default\"):\n",
" # stop reading ascii\n",
" break\n",
" \n",
" # create new binary file\n",
" for line in fp:\n",
" ff.write(line) "
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"# size of binary voxel field\n",
"shape = [int(ii) for ii in shape]\n",
"shape"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"# read in binary information into a numpy array\n",
"wtf = np.fromfile(prefix+'.binary', dtype=np.uint8 )"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"# UW part - create particle distribution across geometry\n",
"mesh = uw.mesh.FeMesh_Cartesian(elementRes=(10,10,10), \n",
" minCoord=(0.0,0.0,0.0),\n",
" maxCoord=(150.0,260.0,150.0) )\n",
"\n",
"swarm = uw.swarm.Swarm(mesh)\n",
"colour = swarm.add_variable('double',count=1)\n",
"layout = uw.swarm.layouts.GlobalSpaceFillerLayout(swarm, particlesPerCell=50)\n",
"swarm.populate_using_layout(layout)\n",
"\n",
"colour.data[:]=0.0"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"# reshape the coordinates appropriately\n",
"cow = wtf.reshape((shape[0],shape[1],shape[2]))"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"# evaluate the cow coordinates at the particle coordinates - order is 0 but can be [0 - 5] for spline interpolation\n",
"mapping = ndimage.map_coordinates(cow, \n",
" [swarm.particleCoordinates.data[:,0].T-50,\n",
" swarm.particleCoordinates.data[:,1].T,\n",
" swarm.particleCoordinates.data[:,2].T], \n",
" order=0)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"# how many unique numbers \n",
"np.unique(mapping)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"np.histogram(mapping)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"colour.data[:]=mapping.reshape(-1,1)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"# output as xdmf file to visualise\n",
"sH = swarm.save('swarm.h5')\n",
"cH = colour.save('colour.h5')\n",
"\n",
"colour.xdmf('colour', cH, 'colour',sH,'swarm')"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 2",
"language": "python",
"name": "python2"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 2
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython2",
"version": "2.7.11+"
}
},
"nbformat": 4,
"nbformat_minor": 0
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment