The Mathematica Journal
Download This Issue
Feature Articles
Graphics Gallery
Tricks of the Trade
In and Out
The Mathematica Programmer
New Products
New Publications
News Bulletins
Editor's Pick
Write Us
About the Journal
Staff and Contributors
Back Issues


With the above background and data structures, we will now build up the zonohedrification procedures in a bottom-up manner. First, a standard 3-space cross product produces a 3-vector orthogonal to two given vectors.


Closely related is the next procedure, which tests if two vectors are collinear. Ideally, collinear vectors have a cross product of [Graphics:../Images/index_gr_74.gif], but I have included a small leeway of 0.000001 in the zero test here, because the Graphics`Polyhedra` database gives floating point values. (This should be modified to an exact test of zero if one starts with exact vertex coordinates.)


We will build the star by choosing vertices one by one from the set of vertices of the given polyhedron. Only nonzero vertices not collinear with any vertices already selected are chosen. The following routine makes this selection then prints out the number of zonal directions. It is convenient to use a global variable gStar in many of the routines below because the star remains constant in a single zonohedrification. The last line of this routine sets this global variable, so it need not be continuously passed from one routine to the next. (The elements of gStar are halved because the distance from [Graphics:../Images/index_gr_76.gif] to [Graphics:../Images/index_gr_77.gif] in p-representations is 2.)


The number of zonal directions is often half the number of vertices of the original polyhedron because in centrally symmetric polyhedra (unlike the tetrahedron for example) vertices come in diametrically opposed pairs, and one from each pair suffices. For example, although a cube has eight vertices, it is centrally symmetric, so there are only four noncollinear directions, and [Graphics:../Images/index_gr_79.gif]. Thus, setStar[vertices[builtInPoly[Cube]]] prints out 4 zonal directions.

We will need a function for converting a vertex from our [Graphics:../Images/index_gr_80.gif]-representation to [Graphics:../Images/index_gr_81.gif] coordinates (i.e., projecting from [Graphics:../Images/index_gr_82.gif]-space), treating the star as a transformation matrix. Given a vertex [Graphics:../Images/index_gr_83.gif], this adds or subtracts the vectors in the star, according to whether the components of [Graphics:../Images/index_gr_84.gif] are [Graphics:../Images/index_gr_85.gif] or [Graphics:../Images/index_gr_86.gif].


We also need a function to compute a vector normal to the plane of a face. Because a face spans at least two zones (more if it has more than four sides), its [Graphics:../Images/index_gr_88.gif] contains at least two zeros. We find the zeros with Position and use subscripting to unpack the first two indexes. The cross product of the corresponding elements in the star gives the normal vector.


The next function determines the two endpoints of a given edge. We assume the argument has a single 0 and replace it once with [Graphics:../Images/index_gr_90.gif] and once with [Graphics:../Images/index_gr_91.gif].


Because each of a zonohedron's faces are defined by two (or more) of the [Graphics:../Images/index_gr_93.gif] vectors in its star, we will find it useful to have a function which creates a list of all pairs [Graphics:../Images/index_gr_94.gif] where [Graphics:../Images/index_gr_95.gif]. For example, allPairs[4] returns {{1,2},{1,3},{1,4},{2,3},{2,4},{3,4}}.


To make a face parallel to the [Graphics:../Images/index_gr_97.gif]th and [Graphics:../Images/index_gr_98.gif]th star vector, the convexity of the zonohedron is implicitly used. The following routine first determines a normal vector to a plane containing those edge directions. Then it checks the vectors of the star to see on which side of this plane they point. That is accomplished by examining the dot product of the normal with each vector of the star. The dot product of a vector and the normal to the plane is zero for vectors in the plane, positive for vectors pointing across the plane one way, and negative for vectors pointing across the plane the other way. At least two must be zero (because the [Graphics:../Images/index_gr_99.gif]th and [Graphics:../Images/index_gr_100.gif]th lie in the plane), but others may also be if the zonohedron contains larger zonogons. Again a tolerance is used in the zero test, because we can not expect exact planarity from floating point vertex coordinates.


Applying makeFace to all of the pairs [Graphics:../Images/index_gr_102.gif] with [Graphics:../Images/index_gr_103.gif] produces a list of half the faces. The other half (i.e., the [Graphics:../Images/index_gr_104.gif]), are geometrically opposite, so we save a little time by generating them as [Graphics:../Images/index_gr_105.gif] for every [Graphics:../Images/index_gr_106.gif] in the first half. The following function allFaces thereby generates a list of the [Graphics:../Images/index_gr_107.gif]-representations of all the faces. The Union operation is required to eliminate duplicate entries, which result when a face is generated by three (or more) coplanar entries (e.g., [Graphics:../Images/index_gr_108.gif], [Graphics:../Images/index_gr_109.gif], and [Graphics:../Images/index_gr_110.gif]).


Given this list of all faces, we need to find the edges that bound each. The procedures are analogous, because a zonogon face is a two-dimensional zonotope. (A zonotope is an arbitrary-dimension generalization of the 3D zonohedron.) Three differences are (1) that normal directions for each edge are chosen to lie in the plane of the face, (2) we do not test every component of the star, just the ones which lie in the face, and (3) after finding half the edges, the other half are chosen to lie geometrically opposite (not across the entire solid, but opposite within the face) using the [Graphics:../Images/index_gr_112.gif] formula discussed above. The first function below takes an argument, [Graphics:../Images/index_gr_113.gif], which is the index of one of the zeros in [Graphics:../Images/index_gr_114.gif], and returns the edge of the face that has a zero at that position. The second function applies this to all the edge directions of a given face.


With the above routines, we have the components required to generate a line drawing of the edges of any zonohedron. The following first finds the edges for each face, and then flattens them into a list of all edges. Next each edge in [Graphics:../Images/index_gr_116.gif] form is converted to a Line with two endpoints in [Graphics:../Images/index_gr_117.gif] format.


Line-drawing graphics output is illustrated in Figure 4. However, to generate our polyhedron format and solid Graphics3D output, we need a further step to create a polygon for each face, consisting of its vertices sorted into a correct cyclic order. The following function does this by creating a list of edges and vertices that are parts of a given face. It applies the cycleSort routine described below to the vertices.


The cycleSort routine arranges the vertices in a cyclic order by using a two-argument arctangent function to compute an angle for each vertex as seen from the centroid. A general-purpose sortBy function sorts any list according to a given numeric function of its elements. The sorting Function[{x,y}, N[x[[1]]]<N[y[[1]]]] explicitly converts the arctangents to numerical form to avoid the problem of Mathematica's built-in Sort function putting 0 before both _ and -_.


Putting everything together, the following takes a polyhedron, makes a star from its vertices, and outputs the zonohedrification.


Converted by Mathematica      September 30, 1999

[Prev Page][Next Page]