Last modified 25 August 2003 by jdavis@math.wisc.edu

SMKShape

Inherits from SMKResource : NSObject
Conforms to NSCoding

SMKShape describes a crude geometric model. It comprises a series of vertices that are connected to form triangles. It does not assign normals, texture coordinates, or colors to the vertices; those are left to a subclass. SMKShape follows the file location convention described in SMKResource. The archive method below will archive the SMKShape's data to this location for you.

Drawing a Shape

In most cases, all that you will ask the initialized shape to do is draw itself, either for rendering or selection. (See SMKTester for information on selection.) Before doing any drawing or selecting, you must prepare the OpenGL system using the following two class methods. In SMKShape these methods are identical, but subclasses will often override the former and not the latter. These methods issue OpenGL commands.

+ (void)configureOpenGLForDrawing

Enables material coloring and the OpenGL vertex array, and disables the normal, texture coordinate, color and edge flag arrays. (The SMea Kit uniformly assumes RGBA mode and ignores the color-index array.)

+ (void)configureOpenGLForSelection

Enables material coloring and the OpenGL vertex array, and disables the normal, texture coordinate, color and edge flag arrays. (The SMea Kit uniformly assumes RGBA mode and ignores the color-index array.)

Once OpenGL is properly configured, the following two methods are used to draw the shape. The first draws normally, while the second draws with selection names.

- (id)draw;

Draws the receiver.

- (id)select;

Draws the receiver, manipulating the name stack to identify individual triangles. The depth of the name stack temporarily increases by 1.

Inspecting Shape Geometry

Each triangle in the shape is a sequence of three vertices, listed in counter-clockwise order when viewed from outside the shape. Each vertex is listed as an integer, which determines an entry in the array of vertices, where the actual vertex coordinates lie. The following methods access the shape's geometry on this basic level.

- (BOOL)setNumberOfTriangles:(unsigned int)number;

Sets the number of triangles by reallocating the triangle index array; returns YES if and only if no error occurred. The previous triangle index data are preserved (up to the size of the new array).

- (unsigned int)numberOfTriangles;

Returns the number of triangles currently allocated.

- (unsigned short *)triangle:(unsigned int)index;

Returns the indicated triangle; treat this pointer as an array of three unsigned shorts. The pointer will be invalid after the triangle index array is resized with setNumberOfTriangles:.

- (BOOL)setNumberOfVertices:(unsigned int)number;

Sets the number of vertices by reallocating the vertex array; returns YES if and only if no error occurred. The previous vertex data are preserved (up to the size of the new array).

- (unsigned int)numberOfVertices;

Returns the number of vertices currently allocated.

- (float *)vertex:(unsigned int)index;

Returns the indicated vertex; treat this pointer as an array of three floats. The pointer will be invalid after the vertex array is resized with setNumberOfVertices:.

Here are two handy utility methods.

- (id)getNormal:(double *)normal forTriangle:(unsigned int)triangle;

Computes the outward-pointing, unit normal vector for the indicated triangle and stores the result in normal. If the triangle is degenerate, then the returned vector will have length zero instead of one.

- (id)getCenter:(double *)center ofTriangle:(unsigned int)triangle;

Computes the center of the indicated triangle and stores the result in center. The center is computed as the average of the vertices.

Modifying a Shape

The rest of SMKShape's methods exist to let you modify the shape's geometry as it resides in memory. For example, you can create an empty shape by allocating and initializing it without a coder. You can then use the methods above to allocate and modify triangles and vertices. But altering the geometry by hand can be tedious. Usually you want your shape to be a closed surface such as a sphere; this higher-level method builds you a sphere instantly.

- (BOOL)constructSphereOfRadius:(double)radius slices:(unsigned int)slices stacks:(unsigned int)stacks;

Makes the shape a sphere of the indicated radius and returns YES if and only if no error occurred. Vertices and triangles are reallocated as needed. As in gluSphere(), the slices parameter indicates the number of subdivisions around the Z-axis (meridians), and the stacks parameter indicates the number of subdivisions perpindicular to the Z-axis (parallels).

The following three methods perform various transformations on the shape.

- (id)translateByVector:(double *)vector;

Adds the indicated three-dimensional vector to all of the vertices.

- (id)scaleByFactor:(double)factor;

Scales all of the vertices by the indicated factor.

- (id)deformByMatrix:(SMKMatrix *)matrix;

Deforms the vertices by the indicated 4x4 matrix.

SMKShape stores its bounding radius, which is the radius of the smallest sphere, centered at the origin, that contains the shape. After altering the shape's geometry, you'll probably want to recompute its bounding radius.

- (id)updateBoundingRadius;

Computes and stores the bounding radius of the shape.

- (double)boundingRadius;

Returns the stored bounding radius.

SMKShape's final method lets you save your changes to the standard resource file location, as described by SMKResource.

- (BOOL)archive;

Uses an NSArchiver to store the receiver to the standard location and returns YES if and only if no error occurred. This method assumes that all necessary directories exist; it creates and overwrites only files.