summaryrefslogtreecommitdiff
path: root/make.py
diff options
context:
space:
mode:
authorAnthony LaTorre <tlatorre9@gmail.com>2011-08-16 17:07:52 -0400
committerAnthony LaTorre <tlatorre9@gmail.com>2011-08-16 17:07:52 -0400
commit54d7d1efe215337d121813e27cd4909b9a76e912 (patch)
tree7865db28adf2f9328fb9dcbbca8f8f125ecad40c /make.py
parentfd2e841c4c40f9e46258ac8d11c32c2204cddd5b (diff)
downloadchroma-54d7d1efe215337d121813e27cd4909b9a76e912.tar.gz
chroma-54d7d1efe215337d121813e27cd4909b9a76e912.tar.bz2
chroma-54d7d1efe215337d121813e27cd4909b9a76e912.zip
add linear_extrude() function to make.py. rotate_extrude() now takes the number of rotational steps to extrude instead of the angle step size. updated documention in make.py.
Diffstat (limited to 'make.py')
-rw-r--r--make.py144
1 files changed, 93 insertions, 51 deletions
diff --git a/make.py b/make.py
index ed02cb1..1da5d0e 100644
--- a/make.py
+++ b/make.py
@@ -1,67 +1,109 @@
import numpy as np
from geometry import Mesh
from transform import rotate
+from itertoolset import *
-def rotate_extrude(x, y, theta=np.pi/32, remove_duplicate_vertices=True):
- x, y, = np.asarray(x), np.asarray(y)
+def mesh_grid(grid):
+ return np.vstack(zip(grid[:-1].flatten(),grid[1:].flatten(),np.roll(grid[1:],-1,1).flatten()) + zip(grid[:-1].flatten(),np.roll(grid[1:],-1,1).flatten(),np.roll(grid[:-1],-1,1).flatten()))
- if len(x.shape) != 1 or len(y.shape) != 1 or x.size != y.size:
- raise ValueError('shape mismatch')
+def linear_extrude(x1, y1, height, x2=None, y2=None):
+ """
+ Return the solid mesh formed by linearly extruding the polygon formed by
+ the x and y points `x1` and `y1` by a distance `height`. If `x2` and `y2`
+ are given extrude by connecting the points `x1` and `y1` to `x2` and `y2`;
+ this allows the creation of tapered solids.
- points = np.zeros((len(x),3), dtype=np.float32)
- points[:,0] = x
- points[:,1] = y
+ .. note::
+ The path traced by the points `x` and `y` should go counter-clockwise,
+ otherwise the mesh will be inside out.
- angles = np.arange(0, 2*np.pi, theta)
+ Example:
+ >>> # create a hexagon prism
+ >>> angles = np.linspace(0, 2*np.pi, 6, endpoint=False)
+ >>> m = linear_extrude(np.cos(angles), np.sin(angles), 5.0)
+ """
+ if len(x1) != len(y1):
+ raise Exception('`x` and `y` arrays must have the same length.')
- vertices = np.empty((len(points)*len(angles), 3), dtype=np.float32)
- triangles = np.zeros((len(angles)*(len(points)-1)*2, 3), dtype=np.int32)
+ if x2 is None:
+ x2 = x1
- step = len(points) - 1
+ if y2 is None:
+ y2 = y1
- for i, angle in enumerate(angles):
- this_slice = i*len(points)
- vertices[this_slice:this_slice+len(points)] = rotate(points, angle, (0,-1,0))
+ if len(x2) != len(y2) or len(x2) != len(x1):
+ raise Exception('`x` and `y` arrays must have the same length.')
- start = 2*i*step
- next_slice = ((i+1) % len(angles))*len(points)
+ n = len(x1)
- triangles[start:start+step,0] = np.arange(this_slice, this_slice+len(points)-1)
- triangles[start:start+step,1] = np.arange(next_slice, next_slice+len(points)-1)
- triangles[start:start+step,2] = np.arange(this_slice+1, this_slice+len(points))
+ vertex_iterators = [izip(repeat(0,n),repeat(0,n),repeat(-height/2.0,n)),izip(x1,y1,repeat(-height/2.0,n)),izip(x2,y2,repeat(height/2.0,n)),izip(repeat(0,n),repeat(0,n),repeat(height/2.0,n))]
- triangles[start+step:start+2*step,0] = np.arange(next_slice, next_slice+len(points)-1)
- triangles[start+step:start+2*step,2] = np.arange(this_slice+1, this_slice+len(points))
- triangles[start+step:start+2*step,1] = np.arange(next_slice+1, next_slice+len(points))
+ vertices = np.fromiter(flatten(roundrobin(*vertex_iterators)), float)
+ vertices = vertices.reshape((len(vertices)//3,3))
- return Mesh(vertices, triangles, remove_duplicate_vertices=remove_duplicate_vertices)
+ triangles = mesh_grid(np.arange(len(vertices)).reshape((len(x1),len(vertices)//len(x1))).transpose()[::-1])
+
+ return Mesh(vertices, triangles, remove_duplicate_vertices=True)
+
+def rotate_extrude(x, y, nsteps=64):
+ """
+ Return the solid mesh formed by extruding the profile defined by the x and
+ y points `x` and `y` around the y axis.
+
+ .. note::
+ The path traced by the points `x` and `y` should go counter-clockwise,
+ otherwise the mesh will be inside out.
+ """
+ if len(x) != len(y):
+ raise Exception('`x` and `y` arrays must have the same length.')
+
+ points = np.array([x,y,np.zeros(len(x))]).transpose()
+
+ steps = np.linspace(0, 2*np.pi, nsteps, endpoint=False)
+ vertices = np.vstack([rotate(points,angle,(0,-1,0)) for angle in steps])
+ triangles = mesh_grid(np.arange(len(vertices)).reshape((len(steps),len(points))).transpose()[::-1])
+
+ return Mesh(vertices, triangles, remove_duplicate_vertices=True)
def cube(size=1):
- a = np.sqrt(size**2/2.0)
- x = [0,a,a,0]
- y = [-size/2.0,-size/2.0,size/2.0,size/2.0]
- return rotate_extrude(x, y, np.pi/2)
-
-def cylinder(radius1=1, radius2=1, height=2, theta=np.pi/32):
- x = [0,radius1,radius2,0]
- y = [-height/2.0, -height/2.0, height/2.0, height/2.0]
- return rotate_extrude(x, y, theta)
-
-def segmented_cylinder(radius, height=2, theta=np.pi/32, n=50):
- x = np.concatenate((np.linspace(0, radius, n, endpoint=False),
- [radius] * n,
- np.linspace(radius, 0, n, endpoint=False),
- [0.0]))
- y = np.concatenate(([-height/2.0] * n,
- np.linspace(-height/2.0, height/2.0, n, endpoint=False),
- [height/2.0] * (n+1)))
- return rotate_extrude(x, y, theta)
-
-def sphere(radius=1, theta=np.pi/32):
- profile_angles = np.arange(-np.pi/2, np.pi/2+theta, theta)
- return rotate_extrude(radius*np.cos(profile_angles), radius*np.sin(profile_angles), theta)
-
-def torus(radius=1, offset=3, phi=np.pi/32, theta=np.pi/32):
- profile_angles = np.arange(0, 2*np.pi+phi, phi)
- x, y = np.cos(profile_angles), np.sin(profile_angles)
- return rotate_extrude(x + offset, y)
+ "Return a cube mesh whose sides have length `size`."
+ return linear_extrude([-size/2.0,size/2.0,size/2.0,-size/2.0],[-size/2.0,-size/2.0,size/2.0,size/2.0], height=size)
+
+def cylinder(radius=1, height=2, radius2=None, nsteps=64):
+ """
+ Return a cylinder mesh with a radius of length `radius`, and a height of
+ length `height`. If `radius2` is specified, return a cone shaped cylinder
+ with bottom radius `radius`, and top radius `radius2`.
+ """
+ if radius2 is None:
+ radius2 = radius
+
+ return rotate_extrude([0,radius,radius2,0], [-height/2.0, -height/2.0, height/2.0, height/2.0], nsteps)
+
+def segmented_cylinder(radius, height=2, nsteps=64, nsegments=100):
+ """
+ Return a cylinder mesh segmented into `nsegments` points along its profile.
+ """
+ nsegments_radius = int((nsegments*radius/(2*radius+height))/2)
+ nsegments_height = int((nsegments*height/(2*radius+height))/2)
+ x = np.concatenate([np.linspace(0,radius,nsegments_radius,endpoint=False),[radius]*nsegments_height,np.linspace(radius,0,nsegments_radius,endpoint=False),[0]])
+ y = np.concatenate([[-height/2.0]*nsegments_radius,np.linspace(-height/2.0,height/2.0,nsegments_height,endpoint=False),[height/2.0]*(nsegments_radius+1)])
+ return rotate_extrude(x, y, nsteps)
+
+def sphere(radius=1, nsteps=64):
+ "Return a sphere mesh."
+ profile_angles = np.linspace(-np.pi/2, np.pi/2, nsteps)
+ return rotate_extrude(radius*np.cos(profile_angles), radius*np.sin(profile_angles), nsteps)
+
+def torus(radius=1, offset=3, nsteps=64, circle_steps=None):
+ """
+ Return a torus mesh. `offset` is the distance from the center of the torus
+ to the center of the torus barrel. `radius` is the radius of the torus
+ barrel. `nsteps` is the number of steps in the rotational extrusion of the
+ circle. `circle_steps` if specified is the number of steps around the
+ circumference of the torus barrel, else it defaults to `nsteps`.
+ """
+ if circle_steps is None:
+ circle_steps = nsteps
+ profile_angles = np.linspace(0, 2*np.pi, circle_steps)
+ return rotate_extrude(np.cos(profile_angles) + offset, np.sin(profile_angles), nsteps)