SGI Techpubs Library

IRIX 6.5  »  Books  »  Developer  »  
OpenGL Optimizer Programmer's Guide: An Open API for Large-Model Visualization
(document number: 007-2852-002 / published: 1998-06-09)    table of contents  |  additional info  |  download
find in page

Chapter 9. Higher-Order Geometric Primitives and Discrete Meshes

OpenGL Optimizer extends the set of geometric objects available through Cosmo3D with a large set of higher-order primitives that you can include in a scene graph. “Higher-order” means objects other than sets of triangles, and typically implies an object that is defined mathematically.

Designs produced by CAD systems are defined by mathematically defined surface representations. By providing direct support for them, OpenGL Optimizer expands possible applications from simple walkthrough ability to direct interaction with the design data base. When combined with advanced rendering tools such as those discussed in “Occlusion Culling”, higher-order surface representations provide visual access to very large design data bases, with free-roaming interactivity.

OpenGL Optimizer also provides classes to define discrete curves, discrete surfaces, and meshes. Meshes associate a vector with each mesh point and are useful for scientific visualization.

The objects are discussed in the following sections:

Features and Uses of Higher-Order Geometric Primitives

Higher-order geometric primitives, called representations or simply reps, facilitate the design process by providing a library of useful curves and surfaces that ease interactive flexibility, accelerate scene-graph transformations, and reduce the memory footprint of the scene graph. Reps yield these advantages by using parameters to describe objects. Instead of a collection of vertices, which must be manipulated independently to change a surface, reps define surfaces in terms of a relatively small set of control parameters; they are more like pure mathematical objects.

Reps and the Rendering Process

OpenGL Optimizer allows you to interact with an abstract object (a representation or rep) and treat rendering as a separate operation. A simple example of a rep is a sphere, defined by a radius and a center. After defining a sphere, you can implement how it is rendered in several ways: by tessellating, by a sphere-specific draw routine, or conceivably by hardware. Member functions of geometric-primitive classes allow you to implement the most appropriate way of rendering. The fundamental rendering step of tessellating a representation is discussed in Chapter 11, “Rendering Higher-Order Primitives: Tessellators.”

Trimmed NURBS

NURBS curves and surfaces are included in the set of OpenGL Optimizer reps. OpenGL also has these, but OpenGL Optimizer NURBS have two advantages:

  • You can maintain topology, so cracks do not appear at the boundaries of adjacent tessellations when they are drawn.

  • You have better control over tessellation.

See Chapter 10, “Creating and Maintaining Surface Topology,” and “opTessNurbSurfaceAction”.

Objects Required by Reps

To use reps effectively, you have to understand the OpenGL Optimizer representations of geometric points and the transformation matrices that are used by the methods of the rep classes.

Pi

OpenGL Optimizer uses the value for π held in the variable M_PI, declared in csBasic.h: 3.14159265358979323846.

Classes for Points

The classes opVec2, opVec3, and opVec4 define two-, three-, and four-dimensional vectors, and include common operations of vector algebra such as addition, scalar multiplication, cross products, and so on. See the header file opVec.h for a list of operations defined for each vector.

The important distinction between these vector classes and csVec of Cosmo3D is that OpenGL Optimizer vectors are declared opReal and so can be single or double precision, depending on the version of the OpenGL Optimizer library you use.

Classes for Scalar Functions

The opScalar class is the base class for defining scalar functions; it allows you to conveniently read and write functions. The class provides a virtual evaluation method.

Class Declaration for opScalar

The class has the following main methods:

class opScalar : public csObject
{ public:
// Creating and destroying
opScalar();
virtual ~opScalar();
virtual opReal eval(opReal u); 
virtual csObject* clone(csNode::CloneEnum);
}; 

The class opCompositeScalar allows you to define the functional composition of two opScalars.

Class Declaration for opCompositeScalar

The class has the following main methods:

class opCompositeScalar : public opScalar
{ public:
// Creating and destroying
opCompositeScalar( );
opCompositeScalar(opScalar *outFun, opScalar *inFun);
virtual ~opCompositeScalar();

// Accessor functions
opScalar *getOutF() 
opScalar *getInF() 
void      setOutF(opScalar *outF);
void      setInF (opScalar *inF);

opReal eval(opReal t);

//Copy
virtual csObject clone(csNode::CloneEnum what);
};

Methods in opCompositeScalar

eval() 

Returns the value of outF(inF(t)).

clone(what)  

Copy constructor for Cosmo3d. Creates an instance that has the same type (classType) as “this”, and copies field values from the created instance. Each derived class should implement this function.

When what equals CLONE_SELF, data members that are pointers to csObject are not cloned, and pointers to non-csObjects are cloned. When what equals CLONE_NODES, only data members that are pointers to csNode or to non-csObjects are cloned. When what equals CLONE_ALL, all pointer data members are cloned.

Trigonometric Functions

OpenGL Optimizer provides classes for two trigonometric functions, opCosScalar and opSinScalar. The class declarations are similar to that of opScalar.

Polynomials

Polynomials of arbitrary degree are defined by the class opPolyScalar.

Class Declaration for opPolyScalar

The class has the following main methods:

class opPolyScalar : public opScalar
{
public:
    // Creating and destroying
opPolyScalar( void );
opPolyScalar( int degree, opReal* coef); 
virtual ~opPolyScalar();
    // Accessor functions
void set( int degree, opReal* coef);
int getDegree() 
opReal getCoef( int i) 
    // Evaluators
opReal eval(opReal u);
    //Copy
virtual csObject* clone ( csNode::CloneEnum what);
}:

Matrix Class: opFrame

Each geometric primitive is defined with respect to its own coordinate system. The elementary definition of an object gives a particular orientation and location with respect to the origin. This reference frame can, in turn, be manipulated by a csTransform to place it in a scene or manipulate it (see Chapter 7, “Interactive Highlighting and Manipulating”).

The base class for higher-order primitives has methods that allow you to locate and orient a primitive with respect to its own reference frame. These methods make insertion of csTransform nodes whenever you want to define the location or orientation of an object or to change the shape of an object unnecessary.

The location is defined by an opVec2 or opVec3, and the orientation is controlled by a 3 x 3 matrix, held in the class opFrame. If the matrix is not a rotation matrix, you can change the shape of an object, for example, you can distort a sphere into an ellipsoid.

Class Declaration for opFrame

The class has the following main methods:

class opFrame
{
public:
opReal m[3][3];
bool   identity;

void setIdentity()
opFrame();
};

Geometric Primitives: The Base Class opRep and the Application repTest

opRep is the base class for higher-order geometric primitives that are stored in a Cosmo 3D scene graph. An opRep is derived from a csShape and is therefore always a leaf node. Figure 9-1 shows the hierarchy of classes derived from opRep.

The following sections discuss the subclasses of opRep:

To experiment with opReps, you can use and modify the application repTest in /usr/share/Optimizer/src/apps/repTest, which provides sample instances of several geometric representations, as well as the tessellation and Cosmo3D calls that render the objects. Sample code from repTest is included with discussions of several of the classes derived from opRep.

opRep has methods to orient the object in space, so you don't have to place a csTransform node above each opRep to move it from its default position. opRep also has a virtual drawing function that you can use to define an approach to rendering other than via tessellation and a Cosmo3D draw action.

Figure 9-1. Class Hierarchy for Higher-Order Primitives

Figure 9-1 Class Hierarchy for Higher-Order Primitives

Class Declaration for opRep

The class has the following main methods:

class opRep : public csShape
{
public:
opRep( );
virtual ~opRep( );

// Accessor functions
void setOrigin( const opVec3&  org );
void setOrient( const opFrame& mat );

opVec3  getOrigin();
opFrame getOrient();

// Utility methods
virtual int getMemSize();

public: 
// Comso3d virtual functions
virtual void draw(csDrawAction* action);
virtual void isect(csIsectAction* ia);
};

Methods in opRep

setOrient()  

Sets the orientation of the representation with respect to the origin via a matrix multiplication.

For a discussion of useful matrices, see the book Computer Graphics: Principles and Practice in “Recommended Background Reading”.

setOrigin() 

Sets the location of the representation with respect to the origin. For example, supplying the vector (1,0,0) shifts the location of the object 1 unit in the direction of the positive x axis.

opRep's subclasses typically include evaluator methods to determine coordinates of points, tangents, and normals. If you do not want the values corresponding to the default position, do not call these methods before you use setOrient() and setOrigin() to locate an opRep. Thus, for example, when defining points on a circle, first set the center and the radius, then call setOrient() to set the orientation, and then evaluate points.

Planar Curves

A parametric curve in the plane can be thought of as the result of taking a piece of the real number line, twisting it, stretching it, maybe gluing the ends together, and laying it down on the plane. The base class for parametric curves that lie in the x-y plane is the class opCurve2d.

An important use of opCurve2d is to specify trim curves, which define boundaries for surfaces. Surfaces are parameterized by part of a plane, which in OpenGL Optimizer is referred to as the u-v plane. When an opCurve2d is used to define a trim curve, it is treated as a curve in the u-v plane. This topic is discussed further in the section “Parametric Surfaces”.

Another important use of opCurve2d is for specifying cross sections for swept surfaces. See “Swept Surfaces”.

OpenGL Optimizer also provides a class to create discrete curves, opDisCurve2d.

The following sections discuss planar curve classes, most of which are derived from opCurve2d:

Mathematical Description of a Planar Curve

Planar curves consist of sets of points, described by two-dimensional vectors, opVec2s. They are parameterized by the opReal variable t; as t varies, a point “moves” along the curve. t can be thought of as the amount of time that has passed as a point moves along the curve. Or, t can measure the distance traveled.

More precisely, each component of a point on the curve is a function of t, which lies in the parameter interval (t0, t1) on the real line. Points on the curve are described by a pair of functions of t: (x(t), y(t)).

Figure 9-2. Parametric Curve: Parameter Interval (0,1).

Figure 9-2 Parametric Curve: Parameter Interval (0,1).

Classes derived from opCurve2d inherit a set of evaluator functions which, for a given value of t, evaluate a point on the curve, the tangent and normal vectors at the point, and the curvature. Naturally, the base-class evaluator that locates points on the curve is a pure virtual function.

To evaluate tangent and normal vectors at a point, opCurve2d provides virtual functions that, by default, use finite-central-difference calculations. To compute the tangent to the curve at p[t], a point on the curve, the tangent evaluator function takes the vector connecting two “nearby” points on the curve, p[t+Dt] - p[t-Dt] where Δτ is “small,” and divides by 2Δτ. Similarly, a finite-central-difference calculation of the normal vector uses the difference between two nearby tangent vectors: n[t] = (t[t+Dt] -t[t-Dt])/2Δτ.

Class Declaration for opCurve2d

The class has the following main methods:

class opCurve2d : public opRep
{
public:
// Creating and destroying
opCurve2d( );
opCurve2d( opReal beginT, opReal endT  );

virtual ~opCurve2d();

// Accessor functions
void setBeginT( opReal beginT );
void setEndT(   opReal endT );

opReal getBeginT();
opReal getEndT();

opVec2 getBeginPt();
opVec2 getEndPt();

opVec2 getBeginTan();
opVec2 getEndTan();

void   setClosed( opLoop loopVal );
opLoop getClosed();

void  setClosedTol( opReal tol );
opReal getClosedTol();

// Evaluators
virtual void evalPt(    opReal t, opVec2 &pnt ) = 0;
virtual void evalTan(   opReal t, opVec2 &tan );
virtual void evalNorm(  opReal t, opVec2 &norm );
virtual void evalCurv(  opReal t, opReal &curv );
virtual void eval(      opReal t, opVec2 &pnt, 
                                  opVec2 &tan, 
                                  opReal &curv, 
                                  opVec2 &norm );
};

Methods in opCurve2d

opCurve2d(beginT, endT)  


Creates an instance of opCurve2d(). If you do not specify any arguments, then the parametric range of the curve is [0.0,1.0].

eval() 

For a given t, returns the position, tangent, curvature, and normal vectors.

evalPt() 

Is a pure virtual function to evaluate position on the curve.

evalTan(), evalCurv(), and evalNorm() 


Evaluate the curve's tangent, curvature, and normal vectors, respectively. The default methods approximate the computation using central differences taken about a small Δτ, given by (endT - beginT) * functionTol. functionTol is a static data element specified in the file opRep.H.

setBeginT() and setEndT(), getBeginPt() and getEndPt() 


Set and get the parameter range for the curve. Whenever you set one of these values, the endpoint of the curve changes. Therefore, each of these methods also recomputes the endpoint, which is cached because it is frequently used. Also, the methods recompute the Δτ used to approximate derivatives.

Note that all planar curve classes derived from opCurve2d reuse setBeginT() and setEndT() to define the extents of their curves.

setClosed() and getClosed()  


Set and get whether a curve is closed.

A closed curve is one for which the endpoints match. OpenGL Optimizer determines automatically whether curves are closed, but you can override this with setClosed().

setClosedTol() and getClosedTol() 


Set and get the mismatch between endpoints that is allowed when calculating whether curves are closed.

To specify the origin used to locate an opCurve2d, use the first two components set by the inherited method opRep::setOrigin().

Lines in the Plane

Parametric lines in the plane are defined by beginning and ending points. The parameterization is such that as t varies from t1 to t2, a point on the line “moves,” at a uniform rate, from the beginning to the ending point.

Figure 9-3. Line in the Plane Parameterization

Figure 9-3 Line in the Plane Parameterization

Class Declaration for opLine2d

The class has the following main methods:

class opLine2d : public opCurve2d
{
public:
// Creating and destroying
opLine2d();
opLine2d( opReal x1, opReal y1, opReal t1,
          opReal x2, opReal y2, opReal t2 );
virtual ~opLine2d();

// Accessor functions
void setPoint1( opReal x1, opReal y1, opReal t1 );
void setPoint2( opReal x2, opReal y2, opReal t2 );
void getPoint1( opReal *x1, opReal *y1, opReal *t1 );
void getPoint2( opReal *x2, opReal *y2, opReal *t2 );
// Evaluators
void evalPt(   opReal t, opVec2 &pnt );
//Copy
virtual csNode* clone(csNode::CloneEnum what);
};

Methods in opLine2d

opLine2d()  

Creates a parametric line with end points (0,0) and (1,0), and parameter interval (0,1).

opLine2d(x1, y1, t1, x2, y2, t2) 


Creates a parametric line starting at the point (x1, y1) and ending at (x2,y2). The line is parameterized so that t = t1 corresponds to (x1, y1) and t = t2 corresponds to (x2,y2).

evalPt()  

Is the only evaluator function defined for this object. The tangent vector is (x2-x1, y2-y1) and the curvature is zero.

setPoint*() and getPoint*() 


Set and get the end points of the line.

Circles in the Plane

Use the class opCircle2d to define a parametric circle in the plane. The parameterization is such that t is the angular displacement, in radians, in a counterclockwise direction from the x axis. Figure 9-4 illustrates the parameterization of the circle.

Figure 9-4. Circle in the Plane Parameterization

Figure 9-4 Circle in the Plane Parameterization

Class Declaration for opCircle2d

The class has the following main methods:

class opCircle2d : public opCurve2d
{
public:
    // Creating amd destroying
opCircle2d();
opCircle2d( opReal rad, opVec2 *org );
virtual ~opCircle2d();
    // Accessor functions
void   setRadius( opReal rad ) ;
opReal getRadius()             ;
    // Evaluator
void evalPt(   opReal t, opVec2 &pnt );
void evalTan(  opReal t, opVec2 &tan );
void evalCurv( opReal t, opReal &curv );
void evalNorm( opReal t, opVec2 &norm );
void eval(     opReal t, 
               opVec2 &pnt, 
               opVec2 &tan, 
               opReal &curv,
               opVec2& norm );
    //Copy
virtual csNode* clone(csNode::CloneEnum what)
};

Methods in opCircle2d

opCircle2d inherits methods to set the range of parameter values from opCurve2d.

opCircle2d(rad, org) 


Creates an instance of a two-dimensional circle with radius rad centered at org. The default circle has unit radius and origin (0,0). To change the default position, use the methods setOrigin() and setOrient() inherited from opRep.

setRadius() and getRadius() 


Set and get the circle's radius.

opCircle2d provides exact calculations for the evaluator functions inherited from opCurve2d.

Superquadric Curves: opSuperQuadCurve2d

The class opSuperQuadCurve2d provides methods to define a generalization of a circle that, when used for constructing a swept surface, is convenient for generating rounded, nearly square surfaces, or surfaces with sharp cusps (see “Swept Surfaces”). Two examples of superquadrics appear in repTest.

The position along the curve is specified by an angle from the x axis, in the same as for an opCircle2d. The shape of the curve is controlled by a second parameter.

A superquadric is the set of points (x,y) given by the following equation that clearly expresses the relationship to the equation of a circle:

The above equation can be written in a parametric form:

The family of curves generated by these equations as the quantity α varies can be described as follows (see Figure 9-5).

Four points are always on the curve for any value of a: (\ξβ1 ρ, 0) and (0, \ξβ1 ρ).

  • If α is 1, the curve is a circle of radius r.

  • As α approaches zero, the circle expands to fill a square of side 2r as if you were inflating a balloon in a box.

  • As α approaches infinity, the circle contracts towards the two diameters along the x and y axes, approaching two orthogonal lines as if you deflated a balloon with two rigid orthogonal sticks inside it.

    Figure 9-5. Superquadric Curve's Dependence on the Parameter α.

    Figure 9-5 Superquadric Curve's Dependence on the Parameter α.

Class Declaration for opSuperQuadCurve2d

The class has the following main methods:

class opSuperQuadCurve2d : public opCurve2d
{
public:
// Creating and destroying
opSuperQuadCurve2d();
opSuperQuadCurve2d( opReal radius, 
                    opVec2 *origin,
                    opReal exponent );
virtual ~opSuperQuadCurve2d();

// Accessor functions
void   setRadius( opReal _radius );
opReal getRadius();

void   setExponent( opReal _exponent );
opReal getExponent();

// Evaluator
void evalPt(   opReal t, opVec2 &pnt );

//Copy
virtual csNode* clone(csNode::CloneEnum what);
};

Methods in opSuperQuadCurve2d

The accessor functions allow you to control the radius r and exponent α of the curve. To change the default position, use the methods setOrigin() and setOrient() inherited from opRep.

Hermite-Spline Curves in the Plane

A spline is a mathematical technique for generating a single geometric object from pieces. An advantage of breaking a curve into pieces is greater flexibility when you have many points controlling the shape: changes to one piece of the curve do not have significant effects on remote pieces. To define a spline curve for a range of values for the parameter t, say from 0 to 3, you “tie” together pieces of curves defined over intervals of values for t. For example, you might assign curve pieces to the three intervals 0 to 1, 1 to 2, and 2 to 3. The four points in the set of parameters, 0, 1, 2, and 3, define the endpoints of the intervals and are called knots.

A Hermite-spline curve is a curve whose segments are cubic polynomials of the parameter t, where the coefficients of the polynomials are determined by the position and tangent to the curve at each knot point. Thus the curve passes through each of a set of specified points with a specified tangent vector. The set of knot points must be increasing values of the parameter t.

Figure 9-6. Hermite Spline Curve Parameterization

Figure 9-6 Hermite Spline Curve Parameterization

Class Declaration for opHsplineCurve2d

The class for creating Hermite spline curves is opHsplineCurve2d. The class has the following main methods:

class opHsplineCurve2d : public opCurve2d
{
public:
// Creating and destroying
opHsplineCurve2d( opReal tBegin = 0.0, opReal tEnd = 1.0 );
virtual ~opHsplineCurve2d( );

// Accessor functions  
void setPoint(   int i, opVec2 &p );
void setTangent( int i, opVec2 &tng );
void setKnot(    int i, opReal t );

int getKnotCount();
opVec2* getPoint( int i );
opVec2* getTangent( int i );
opReal  getKnot( int i );

virtual int getMemSize( );

// Evaluator
virtual void evalPt( opReal t, opVec2 &pnt );

//Copy
virtual csNode* clone(csNode::CloneEnum what);
};

NURBS Overview

The acronym NURBS stands for “nonuniform rational B-splines.” NURBS define a set of curves and surfaces that generalizes Bezier curves. Both NURBS curves and Bezier curves are “smooth” curves that are well suited for CAD design work. They are essentially determined by a set of points that controls the shape of the curves, although the points do not lie on the curves.

Because NURBS properties are not widely known, a discussion of their features precedes details of how to create instances of them. The discussion is necessarily brief and is intended to provide the minimum amount of information needed to start using OpenGL Optimizer NURBS classes.

This general discussion of NURBS is presented in the following sections:

For more information, consult the following sources, which are listed in “Recommended Background Reading”:

  • An intuitive introduction to NURBS curves and surfaces is Chapter 8 of The Inventor Mentor.

  • A more rigorous mathematical discussion appears in the book Curves and Surfaces for Computer Aided Geometric Design: A Practical Guide.

  • A discussion of NURBS also appears in Chapter 11 of the OpenGL Programming Guide.

OpenGL Optimizer NURBS Classes

The OpenGL Optimizer classes allow you to treat a NURBS object as a black box that takes a set of control parameters and generates a geometric shape. A NURBS object's essential properties are rather straightforward, although the underlying mathematics are complex. Unlike lines and circles, NURBS can represent a large set of distinct complex shapes. Because of this flexibility, developing a NURBS object is often best done interactively. For example, you could allow a user to design a curve using an interface in which control parameters are changed by clicking and dragging and by using sliders.

There are three classes:

  • The opNurbCurve2d class generates curves in the plane, the simplest NURBS object provided by OpenGL Optimizer.

  • The opNurbCurve3d class generates NURBS curves in three-dimensional space.

  • The opNurbSurface class generates NURBS surfaces, which extend the ideas underlying NURBS curves to two-dimensional objects. The principles for controlling the shapes of these objects are all essentially the same.

NURBS Elements That Determine the Control Parameters

This section provides some theoretical background information on NURBS elements. If you already understand NURBS, continue with “NURBS Curves in the Plane”)

NURBS are defined by the following elements, discussed in this chapter:

Knot Points

The knot points determine how and where the pieces of the NURBS object are joined. The knots are nondecreasing— but not necessarily uniformly spaced or distinct—values of the parameter t for the curve. The sequence of knots need not have uniform spacing in the parameter interval. In fact, the mathematics of NURBS make it possible and, perhaps, necessary to repeat knot values; that is, knots can appear with a certain multiplicity. The number of knot points is determined by counting all the knot points, including all multiplicities.

For example, although the sequence (0,0,0,0,1,1,1,1) has only two distinct knot points, the number of knot points is eight. (This example it is the set of knot points for a cubic Bezier curve defined on the interval 0 to 1). How to determine the order of a NURBS curve is discussed in “Features of NURBS and Bezier Curves”.

Control Hull

The control hull is the set of all points that determine the basic shape of NURBS object. The effect of the control hull is determined by a “B-spline.”

A B-spline is a basis spline; a set of special curves associated with a given knot sequence from which you can generate all other spline curves having the same knot sequence and control hull. For each interval described by the knot sequence, the corresponding piece of a B-spline curve is a Bezier curve.

B-spline curves are like Bezier curves in that they are defined by an algorithm that acts on a sequence of control points, the control hull, which lie in the plane or in three-dimensional space. For information on this, consult the book Curves and Surface for Computer Aided Geometric Design in “Recommended Background Reading”.

Weights for Control Points

The third set of control parameters for a NURBS curve is the set of weights associated with the control points.

A rational B-spline consists of curves that have a weight associated with each control point. The individual pieces of a NURBS curve usually are not Bezier curves but rational Bezier curves. The values of the weights have no absolute meaning; they control how “hard” an individual control point pulls on the curve relative to other control points. If the weights for all the control points of a rational Bezier curve are equal, then the curve becomes a simple Bezier curve. Weights allow construction of exact conic sections, which cannot be made with simple Bezier curves. See Curves and Surface for Computer Aided Geometric Design in “Recommended Background Reading”.

Features of NURBS and Bezier Curves

Bezier curves have the following properties:

  • They are “nice” polynomial curves whose degree is one less than the number of control points.

    For a polynomial curve, each of the components is a polynomial function of the parameter t. The number of coefficients in the polynomial, the order of the polynomial, is equal to the number of control points.

  • The control points determine the shape of the Bezier curve, but they do not lie on the curve, except the first and last control points.

NURBS curves differ in the following ways:

  • The order of the polynomial pieces that make up the NURBS curve depends on the number of control points and the number of knot points. The order of a NURBS curve is the difference between the number of knots, accounting for multiplicity, and the number of control points. That is,

    order = number of knot points - number of control points

  • The relationship between the curves and the control points is looser than for a Bezier curve. It also depends on the knot sequence and the sequence of weights.

Equation Used to Calculate a NURBS Curve

The equation that defines the NURBS curve is

Alternative Equation for a NURBS Curve

If you have a surface developed from the alternative expression for a NURBS surface:

you must change the coordinates of the control points to get the same surface from OpenGL Optimizer; you convert the coordinates of the control points from (x,y,w) to (wx,wy,w).

NURBS Curves in the Plane

The class opNurbCurve2d defines a nonuniform rational B-spline curve in the plane, the simplest NURBS object provided by OpenGL Optimizer.

Class Declaration for opNurbCurve2d

The class has the following main methods:

class opNurbCurve2d : public opCurve2d
{
public:
// Creating and destroying
opNurbCurve2d( opReal tBegin = 0.0, opReal tEnd = 1.0 );
virtual ~opNurbCurve2d( );

// Accessor functions
void setControlHull(     int i, opVec2 &p );
void setControlHull(     int i, opVec3 &p );
void setWeight(          int i, opReal w  );
void setKnot(            int i, opReal t  );
void setControlHullSize( int s            );

opVec2* getControlHull( int i );
opReal  getWeight( int i );
int     getControlHullSize( );
int     getKnotCount( );
opReal  getKnot( int i );
int     getOrder( );

void removeControlHullPnt(int i);
void removeKnot(int i);

// Evaluator
virtual void evalPt( opReal t, opVec2 &pnt );

// Memory foot print
virtual int getMemSize( );

//Copy
virtual csNode* clone(csNode::CloneEnum what);
};

Methods in opNurbCurve2d

opNurbCurve2d(tBegin, tEnd) 


Creates a NURBS curve in the plane with the specified parameter domain. The default parameter domain is 0.0 to 1.0.

evalPt() 

Is a pure virtual function inherited from opCurve2d, and produces unpredictable results until you set the control parameters.

setControlHull(i, p) and getControlHull(i) 


Set and get the two-dimensional control point with index i to the value p. If you supply opVec3 arguments, the location of the control points is set by the first two components; the last component is their weight.

setControlHullSize() 


Gives a hint about how big the control hull array is. This is not mandatory but uses time and space most efficiently.

setKnot(i, t) and getKnot(i) 


Set and get the knot point with index i and the value t.

setWeight(i, w) and getWeight(i) 


Set and get the weight of the control point with index i and weight w.

Piecewise Polynomial Curves: opPieceWisePolyCurve2d

A piecewise polynomial curve consists of an array of polynomial curves. Each polynomial curve is a polynomial mapping from t to UV plane, where the domain is a subinterval of [0,1]. The polynomial coefficients are set by setControlHull().

Notice that an opPieceWisePolyCurve2d is a subclass of opCurve2d. The domain of a opPieceWisePolyCurve2d is defined to be [0, n] where n is the number of pieces.

If reverse is 0, then for any given t in [0, n], its corresponding uv is evaluated in the following way: The index of the piece that corresponds to t is floor(t), and the polynomial of that piece is evaluated at w1 + (t-floor(t)) * (w2-w1) to get the (u,v), where [w1, w2] is the domain interval (set by setLimitParas()) of this piece.

If reverse is 1, then for any given t in [0,n], we first transform t into n-t, then perform the normal evaluation (at n-t) as described in the preceding paragraph.

Class Declaration for opPieceWisePolyCurve

The class has the following main methods:

class opPieceWisePolyCurve2d : public opCurve3d
{
public:
// Creating and destroying
opPieceWisePolyCurve2d ( );
~opPieceWisePolyCurve2d ( );

//Accessor functions
void setControlHull ( int piece, int i, const opVec2& p);
opVec2& getControlHull ( int piece, int i);
void setLimitParas ( int piece, opReal w1, opReal w2);
void setReverse ( int _reverse);
opVec2& getLimitParas ( int piece);
int getReverse ( );
int getPatchCount ( );
int getOrder ( int piece);
virtual void evalPt ( opReal t, opVec2& pnt);
virtual void evalBreakPoints ( opParaSurface* sur);

//Copy
virtual csNode* clone(csNode::CloneEnum what);
};

setControlHull(piece, i, p) defines the ith polynomial coefficient of the pieceth polynomial curve to p. p[0] is for the u coefficient and p[1] is for the v coefficient. setLimitParas() sets the domain interval.

The class opPieceWisePolyCurve3d has parallel functionality and declaration.

Discrete Curves in the Plane

The class opDisCurve2d is the base class for making a discrete curve from line segments connecting a sequence of points in the plane. Because opDisCurve2d is not derived from opCurve2d, it does not inherit that class's finite difference functions for calculating derivatives, therefore, opDisCurve2d includes member functions that calculate arc length, tangents, principal normals, and curvatures using finite central differences. Figure 9-7 illustrates the definition of the curve by a set of points.

Figure 9-7. Discrete Curve Definition

Figure 9-7 Discrete Curve Definition

Class Declaration for opDisCurve2d

The class has the following main methods:

class opDisCurve2d : public opRep
{
public:
// Creating and destroying
opDisCurve2d( void );
opDisCurve2d( int nPoints, opReal *points );

virtual ~opDisCurve2d( void );

// Accessor functions
void set (int nPoints, opReal* points);
opVec2 getBeginPt();
opVec2 getEndPt();

opLoop getClosed();
void   setClosed( opLoop c );

void setPoint( int i, const opVec2& pnt ); 
opVec2 getPoint( int i);
int getPointCount(); 
opVec2 getTangent(int i); 
opVec2 getNormal(int i); 
opReal getCurvature(int i);

// Evaluators
void computeTangents( );
void computeNormals( );
void computeCurvatures( );
void computeDerivatives( );

// Copy
virtual csNode* clone(csNode::CloneEnum::what);
};

Methods in opDisCurve2d

opDisCurve2d(nPoints, points)  


Creates a discrete curve from an array of point coordinates. The constructor assumes that the coordinates of the points are stored in pairs sequentially; thus the points array is nPoint*2 in length.

computeCurvatures()  


Computes the curvature, which is the magnitude of the normal vector.

computeDerivatives()  


Is a convenience function that calls (in order) the tangent, normal, and curvature functions.

computeNormals()  


Computes the principal normal at a point using finite central differences and stores the result in the class member opDvector n. For the point p[i], the normal vector is computed to be the difference vector between the tangents at the two neighboring points, t[i+1] - t[i-1], divided by the sum of the distances from p[i] to the two neighboring points.

computeTangents()  


Computes the arc lengths of segments and then uses finite central differences to compute the tangents. For the point p[i], the tangent vector is computed to be the vector between its two neighboring points, p[i+1] - p[i-1], divided by the sum of the distances from p[i] to the two neighboring points. The tangents are stored in the opDvector t, the arc lengths in the opDvector ds, and the total arc length in arcLength.

getCurvature()  

Returns the value of the curvature at the ith point.

getNormal() 

Returns the value of the normal at the ith point.

getPoint() 

Returns the value of the ith point.

getPointCount() 


Returns the value of the ith point.

getTangent()  

Returns the value of the tangent at the ith point.

Spatial Curves

The class opCurve3d is the base for parametric curves that lie in three-dimensional space. Among other uses, a curve in space could locate a moving viewpoint in a CAD walk-through.

The nature of these curves is essentially the same as those of opCurve2d curves, except opCurve3d curves are made of points described by opVec3s. The components of the points are assumed to be x, y, and z coordinates. Refer to the section “Planar Curves” for a discussion of the basic features of parametric curves and references to further reading.

This section parallels the discussion in “Planar Curves”, and emphasizes the (not very great) differences that distinguish spatial curves:

The class declaration for opCurve3d is in the file /usr/share/Optimizer/src/libop/opCurve3d.h. Its declaration is essentially identical to the declaration for opCurve2d. The difference is that all opVec2 variables are replaced by opVec3 variables.

Lines in Space

The base class for lines in space, opLine3d, is essentially the same as opLine2d, discussed in “Lines in the Plane”. The main differences are due to the need to manage three-dimensional vectors. Thus all vector variables are opVec3 and the constructor takes six variables to define the endpoints of the line.

The default orientation of the curve is identical to that for the planar curve opLine2d; you can translate and rotate the line in three-dimensional space with the methods setOrigin() and setOrient() inherited from opRep.

opOrientedLine3d

The class opOrientedLine3d is derived from opLine3d, and adds vectors to define a moving three-dimensional reference frame for the line. This object is useful if you want a straight-line path for an opFrenetSweptSurface (see “Swept Surfaces” and, in particular, “Class Declaration for opFrenetSweptSurface”).

The methods of opOrientedLine3d add to the description of the line an “up” vector, which you specify. The normal to the line is calculated from the direction of the line and the up vector.

Circles in Space

The class opCircle3d defines a parametric circle with an arbitrary location and orientation in space. The parameterization of the circle, before you change its location or orientation, is such that t is the angular displacement, in radians, in a counterclockwise direction from the x axis.

The class declaration for opCircle3d is identical to that for opCircle2d, discussed in “Circles in the Plane”, except for the changes from opVec2 to opVec3. The member functions perform the same operations. For more information, see the discussion in the section “Circles in the Plane”.

If the matrix you use to orient an opCircle3d does not correspond to a rotation about an axis—that is, the matrix is not orthonormal— you not only change the tilt of the plane in which the circle lies but also change the radius, and may distort the circle into an ellipse. For a discussion of useful matrices, see the book by J. D. Foley, et al., in “Recommended Background Reading”.

Superquadrics in Space

The class opSuperQuadCurve3d provides methods to define a superquadric in space (see “Superquadric Curves: opSuperQuadCurve2d”). The class declaration is identical to that for opSuperQuad2d except that position on the curve is defined by an opVec3.

The default orientation of the curve is identical to that for the planar curve opSuperQuad2d; you can translate and rotate the curve in three-dimensional space with the methods setOrigin() and setOrient() inherited from opRep.

Hermite Spline Curves in Space

The class opHsplineCurve3d provides methods to define a Hermite spline curve in space. The definition of the curve is the same as that for a Hermite spline curve in the plane, discussed in “Hermite-Spline Curves in the Plane”. The class declaration is the same as that for opHsplineCurve2d, but the position and tangent vectors are opVec3s.

NURBS Curves in Space

The basic properties of NURBS are discussed in the section “NURBS Overview”. In an effort to keep things as simple as possible, the discussion in that section has a bias toward curves in the plane. But the principles and control parameters are, with one difference, the same for NURBS curves in space.

The difference is that control points for NURBS curves in space can be anywhere in space instead of being restricted to a plane. The section “Examples of NURBS Curves” in Chapter 8 of The Inventor Mentor presents illustrations of NURBS curves in space, along with their control parameters.

The class opNurbCurve3d is the base class for NURBS curves in space. Its class declaration is practically identical to that for opNurbCurve2d but all occurrences of opVec2 are changed to opVec3. In addition, the vector argument of setControlHull() can be an opVec3, if you just want to specify control point locations, or an opVec4, if you want to append weighting information as a fourth component. See the discussion in the section “NURBS Curves in the Plane”.

Curves on Surfaces: opCompositeCurve3d

A planar curve in the u-v plane describes a curve on the surface, given a parameterized surface (see the section “Parametric Surfaces”). Each point on the curve in the parameter plane is “lifted up” to the surface. Such curves are known as composite curves because they are described mathematically as the composition of the function describing the curve and the function describing the surface. The edge of a surface defined by a trim curve is a composite curve.

opCompositeCurve3d is the base class for composite curves. This class is useful for defining trim curves and surface silhouettes in the parametric surface's coordinate system.

Class Declaration for opCompositeCurve3d

The class has the following main methods:

class opCompositeCurve3d : public opCurve3d
{
public:
// Creating and destroying
opCompositeCurve3d( );
opCompositeCurve3d( opParaSurface *sur, opCurve2d *cur );
~opCompositeCurve3d( );

// Accessor functions
void set( opParaSurface *sur, opCurve2d *cur );
opParaSurface* getParaSurface() {return s;}
opCurve2d* getCurve2d() {return c;}

// Evaluator
void evalPt( opReal u, opVec3 &pnt );
};

Methods in opCompositeCurve3d

The constructor takes two arguments: the first is the surface on which the curve lies, the second is the curve in the coordinate system of the surface. The returned object is a curve in space.

Discrete Curves in Space

The class opDisCurve3d is the base class for making a discrete curve of line segments connecting a sequence of points in space. The class declaration for opDisCurve3d is identical to that for opDisCurve2d, discussed in “Discrete Curves in the Plane”, but opVec2 changes to opVec3. The member functions perform the same operations.

Example of Using opDisCurve3d and opHsplineCurve3d

One application of an opDisCurve3d and opHsplineCurve3d is to use them to interactively specify routing for tubing. These are the operations to perform:

  1. Create a opDisCurve3d from a set of points. See “Discrete Curves in Space”.

  2. Use the points and tangents to the discrete curve to create a continuous path with an opHsplineCurve3d. See “Hermite Spline Curves in Space”

  3. Use the continuous path in an opFrenetSweptSurface with a circular cross section. See “opFrenetSweptSurface”.

Parametric Surfaces

A parametric surface can be thought of as the result of taking a piece of a plane, twisting and stretching it, maybe gluing edges of the piece together, and placing it in space.

The introductory discussion of parametric surfaces occurs in the following sections:

The subclasses of opParaSurface are discussed in the subsequent sections:

Instances of most of the opParaSurface subclasses are used in the sample application /usr/share/Optimizer/src/apps/repTest/repTest.

Mathematical Description of a Parametric Surface

To locate a point on a parametric surface, you need two parameters, referred to as u and v in OpenGL Optimizer. The set of u and v values that describe the surface are known as the parameter space, or coordinate system, of the surface (see Figure 9-8).

More precisely, the coordinates of the points in space that define a parametric surface are described by a set of three functions of two parameters: (x(u,v), y(u,v), z(u,v)).

Well-known examples of a parametric surface are a sphere or a globe. On a globe you can locate points with two parameters: latitude and longitude. The rectangular grid of latitude and longitudes is the coordinate system that describes points on the globe.

Figure 9-8. Parametric Surface: Unit-Square Coordinate System

Figure 9-8 Parametric Surface: Unit-Square Coordinate System

Defining Edges of a Parametric Surface: Trim Loops and Curves

To define the extent of a parametric curve, pick an interval. For accurate trimming of a parametric surface, you need more complex tools. You are likely to need:

  • Edges for the surface other than those defined by the limits of the coordinate system. For example, to define a pipe elbow, you might join two cylinders by a piece cut from a torus.

  • Holes in a surface, for example, to define a T-joint intersection of pipes.

OpenGL Optimizer keeps the trim loop side on the left as you look down on the u-v plane while a point moves along the curve in the direction of increasing t; you can hold on to the surface with your left hand as you go along the trim loop. Thus a clockwise loop removes a hole; a counterclockwise loop keeps the enclosed region and eliminates everything outside. Do not create a trim loop that crosses itself like a figure eight.

OpenGL Optimizer allows you to maintain curves to define the edges of a surface. These curves are opCurve2d objects defined in the u-v plane that are “lifted” to the surface by the parameterization. The main use of these curves is to eliminate a portion of the surface on one side of the curve. The name of a curve in the coordinate system that is used to define (possibly a piece of) such a surface edge is a trim curve. One or more joined trim curves form a sequence called a trim loop. To be of use, trim curves should form a closed loop or reach the edges of the coordinate system for the surface. Figure 9-9 illustrates trim loops and their effect on a surface.

Figure 9-9. Trim Loops and Trimmed Surface: Both Trim Loops Made of Four Trim Curves

Figure 9-9 Trim Loops and Trimmed Surface: Both Trim Loops Made of Four Trim Curves

Adjacency Information: opEdge

An opEdge defines a trim curve in u, v space. opEdge holds information about a surface's adjacency. Each opEdge identifies an opBoundary, which the class opTopo uses to keep track of surface connectivity, and continuous and discrete versions of the trim curve associated with the boundary. The members of an opEdge are set by the toplogy building tools; the methods of opEdge access the members. Topology building and the classes opTopo and opBoundary are discussed further in Chapter 10, “Creating and Maintaining Surface Topology.”

The information held in opEdge allows tessellators to determine whether a set of vertices has already been developed for points shared with other surfaces. You can also find other surfaces that have the same edge or trim-curve endpoint as that defined by a given trim curve.

The set*() methods are mainly used when reading surface data from a file and creating OpenGL Optimizer data structures.

Class Declaration for opEdge

The class has the following main methods:

class opEdge
{
public:
// Creating and destroying
opEdge();
~opEdge();

opCurve2d *getContCurve();
void setContCurve(opCurve2d *c);

opDisCurve2d *getDisCurve();
void setDisCurve( opDisCurve2d *d);

int getBoundary();

void setBoundaryDir( int dir );
int getBoundaryDir();

opEdge* clone( csNode::CloneEnum what);
};

Base Class for Parametric Surfaces: opParaSurface

opParaSurface is the base class for parametric surfaces in OpenGL Optimizer. As for the base classes opCurve2d and opCurve3d, opParaSurface includes a pure virtual function to evaluate points on the surface and default evaluator functions that calculate derivatives using finite central differences. The surface normal at a point is the cross product of the partial derivatives.

For parametric curves whose extent is defined by the interval of values for t, the extent of an opParaSurface is, initially, defined by all the points in its parameter space.

Class Declaration for opParaSurface

The class has the following main methods:

class opParaSurface : public opRep
{
public:
// Creating and destroying
opParaSurface();
opParaSurface( opReal _beginU = 0, opReal _endU = 1, 
               opReal _beginV = 0, opReal _endV = 1,
               int    _topoId = 0, int    _solid_id = -1 );

~opParaSurface();

// Accessor functions
void setBeginU( opReal u );
void setEndU(   opReal u );
void setBeginV( opReal v );
void setEndV(   opReal v );
void setSolidId( int solidId);
void SetTopoId( int topoId);
void setSurfaceId (int surfaceId);
opReal getBeginU()
opReal getEndU() 
opReal getBeginV()
opReal getEndV()

int     getTrimLoopCount();
opLoop  getTrimLoopClosed( int loopNum );
int     getTrimCurveCount( int loopNum );
opEdge* getTrimCurve( int loopNum, int curveNum );

int     getTopoId();
int     getSolidId();
int     getSurfaceId();
  
void setHandednessHint( bool _clockWise ) 
bool getHandednessHint()
  
void insertTrimCurve( int loopNum, opCurve2d *c, opDisCurve2d *d );

// Explicit add a trim curve to a trim loop
void addTrimCurve(int loopNum, opCurve2d *c, opDisCurve2d *d );
void setTrimLoopClosed(  int loopNum, opLoop closed );

// Surface evaluators
virtual void evalPt(   opReal u, opReal v, opVec3 &pnt ) = 0;
virtual void evalDu(   opReal u, opReal v, opVec3 &Du );
virtual void evalDv(   opReal u, opReal v, opVec3 &Dv );
virtual void evalDuu(  opReal u, opReal v, opVec3 &Duu );
virtual void evalDvv(  opReal u, opReal v, opVec3 &Dvv );
virtual void evalDuv(  opReal u, opReal v, opVec3 &Duv );
virtual void evalNorm( opReal u, opReal v, opVec3 &norm );

// Directional derivative evaluators
virtual void evalD( opReal u, opReal v, opReal theta, opVec3 &D );
virtual void evalDD( opReal u, opReal v, opReal theta, opVec3 &DD );

virtual void eval( opReal u, opReal v,
opVec3 &p,            // The point
opVec3 &Du,           // The derivative in the u direction
opVec3 &Dv,           // The derivative in the v direction
opVec3 &Duu,          // The 2nd derivative in the u direction
opVec3 &Dvv,          // The 2nd derivative in the v direction
opVec3 &Duv,          // The cross derivative
opReal &s,            // Texture coordinates
opReal &t  );

void clearTessallation();
};

Methods in opParaSurface

addTrimCurve(j, curve, discurve) 


Is a quick function for building a trim loop that assumes you know the order of trim curves. It adds curve to the end of the list of continuous trim curves for the jth trim loop, and adds discurve to the list of discrete trim curves.

For example, you could build the trim loops in Figure 9-9 by starting with one segment and successively adding segments. If the beginning of curve does not match the end of the previously added curve, use insertTrimCurve(), which finds the right place for the curve by assuming topological consistency.

eval() 

Returns the evaluator functions. The last two arguments of eval() are the same as the input coordinates u and v.

evalDu(), evalDv(), evalDuu(), evalDvv(), and evalDuv() 


Are evaluator functions that use central differences to calculate the first and second derivatives, identified by the lowercase u and v in the function names, at a point on the surface.

evalD() and evalDD() 


Calculate the first and second directional derivatives in the direction given by an angle theta from the u axis in the parameter space.

evalNorm() 

Calculates the unit normal to the surface.

evalPt() 

Is a pure virtual function that you define to specify a surface.

opParaSurface() 


Constructs a parametric surface. You can specify the topology and the surface to which the parametric surface belongs. See “Summary of Scene Graph Topology: opTopo”.

insertTrimCurve(j, curve, discurve) 


Is a slower function than addTrimCurve() for building a trim loop that attempts to guarantee all curves form a sensible trim loop sequence. It compares the ends of curve with the ends of the trim curves that are already in the jth trim loop and inserts curve at the appropriate point in the list. Similarly, addTrimCurve() inserts the discrete curve discurve. If insertTrimCurve() cannot find an endpoint match, it adds curve to the end of the list of trim curves. If you are building a trim loop by inserting trim curves end to end, then addTrimCurve() gives the same result but more quickly.

setBeginU(), setBeginV(), etc. 


Set and get the start and end values for the coordinate space of the surface. The coordinate space is a rectangle in the u-v plane. The default is the unit square; u and v both lie in the interval (0,1).

getTrimLoopCount() 


Returns the number of trim loops for the opParaSurface.

getTrimLoopClosed() and setTrimLoopClosed() 


Get and set the flag indicating whether a given trim loop is closed. OpenGL Optimizer determines this for you, so use setTrimLoopClosed() with caution; you could get a meaningless result.

getTrimCurveCount() 


Returns the number of trim curves in the specified trim loop.

getTrimCurve(i,j) 


Returns the opEdge for the trim curve with index i in the trim loop with index j.

clearTessellation() 


Removes all data that resulted from previous tessellation. This removal allows the surface to be retessellated with a different tolerance. For each trim curve, the disCurve is deleted if the contCurve is not NULL. The xyzBoundary in its boundary structure is deleted. Also, the tessellated triangles (csGeometry) are removed.

opPlane

The simplest parametric surface is a plane. The class opPlane defines a plane by two parameter intervals and three points that define the two coordinate directions. Figure 9-10 illustrates the parameterization of an opPlane.

Figure 9-10. Plane Parameterization

Figure 9-10 Plane Parameterization

Class Declaration for opPlane

The class has the following main methods:

class opPlane : public opParaSurface
{
public:
// Creating and destroying
opPlane();
opPlane( opReal x1, opReal y1, opReal z1, opReal u1, opReal v1,
         opReal x2, opReal y2, opReal z2, opReal u2,
         opReal x3, opReal y3, opReal z3, opReal v3 );
virtual ~opPlane();

// Accessor functions
void setPoint1( opReal x1, opReal y1, opReal z1, opReal u1, opReal v1);
void setPoint2( opReal x2, opReal y2, opReal z2, opReal u2 );
void setPoint3( opReal x3, opReal y3, opReal z3, opReal v3 );
 
void getPoint1( opReal *x1, opReal *y1, opReal *z1, 
                opReal *u1, opReal *v1 );
void getPoint2( opReal *x2, opReal *y2, opReal *z2, opReal *u2 );
void getPoint3( opReal *x3, opReal *y3, opReal *z3, opReal *v3 );

// Evaluators
void evalPt( opReal u, opReal v, opVec3 &pnt );
void evalDu( opReal u, opReal v, opVec3 &Du );
void evalDv( opReal u, opReal v, opVec3 &Dv );
void evalNorm( opReal u, opReal v, opVec3 &norm );

virtual csNode* clone( csNode::CloneEnum what);

Methods in opPlane

opPlane() 

When you construct the class, you can specify the plane with three points and two parameter intervals or you can use the setPoint*() methods. Those parameters have the following meanings:

  • the point (x1,y1,z1) and its parameter values, (u1,v1)

  • the point (x2,y2,z2), which defines the u direction, (x2-x1,y2-y1,z2-z1), and its parameter values (u2,v1)

  • the point (x3,y3,z3), which defines the v direction, (x3-x1,y3-y1,z3-z1) and its parameter values (u1,v3).

setPoint*() and getPoint*() 


Set and get each of the points that define the plane and their corresponding parameter values (see opPlane()).

opSphere

The surface of the sphere is parameterized by angles, in radians, for latitude and longitude; v corresponds to longitude, u to latitude. Figure 9-11 illustrates the parameterization of an opSphere.

Figure 9-11. Sphere Parameterization

Figure 9-11 Sphere Parameterization

Class Declaration for opSphere

The class has the following main methods:

class opSphere : public opParaSurface
{
public:
// Creating and destroying
opSphere( );
opSphere( opReal radius );
~opSphere( );
      
// Accessor functions
void setRadius( opReal radiusVal ) 
opReal getRadius( )              

// Evaluators
void evalPt(   opReal  u, opReal v, opVec3 &pnt );
void evalNorm( opReal  u, opReal v, opVec3 &norm );

//Copy
virtual csNode* clone(csNode::CloneEnum what);
}

Methods in opSphere

The constructor defines a sphere centered on the origin with the specified radius. The default radius is 1. The evaluator functions do not use finite-difference calculations for derivatives.

Any point on the sphere is represented as:

x = radius * cos(u) * sin(v)
y = radius * sin(u) * sin(v)
z = radius * cos(v)

opSphere Example

The following code from the sample application repTest illustrates how an instance of an opSphere of radius three would be created:

opSphere *sphere = new opSphere( 3 );

// under certain conditions, a trim curve is added that keeps only the // portion of the surface above a circle 
if ( nVersions <= 0 )
{
opCircle2d  *trimCircle2d = 
                   new opCircle2d( 1.0, new opVec2(M_PI/2.0,M_PI) );
sphere->addTrimCurve( 0, trimCircle2d );
}
setUpShape( sphere, OP_XDIST*numObject++, Y, OP_VIEWDIST );

setUpShape() locates the sphere in the scene, tessellates it, and places it in the scene graph (see src/apps/repTest/repTest.cxx). Creating an instance of any opRep is basically the same, as subsequent examples in the discussions of other opReps will show.

opCylinder

The opCylinder class provides methods for describing a cylinder. 

A cylinder can be defined geometrically as the surface in space that is swept by moving a circle along an axis that is perpendicular to the plane of the circle and passes through the center of the circle.

The parameterization of an opCylinder is as follows: u represents the position on the circle and that v represents the position along the axis.

Figure 9-12. Cylinder Parameterization

Figure 9-12 Cylinder Parameterization

Class Declaration for opCylinder

The class has the following main methods:

class opCylinder : public opParaSurface
{
public:
// Creating and destroying
opCylinder( void );
opCylinder( opReal radius, opReal height );
~opCylinder();

// Accessor functions
void setRadius( opReal radiusVal ) ;
void setHeight( opReal heightVal );

opReal getRadius( ) 
opReal getHeight( ) 

// Evaluators
void evalPt(   opReal  u, opReal v, opVec3 &pnt );
void evalNorm( opReal  u, opReal v, opVec3 &norm );

//Copy
virtual csNode* clone(csNode::CloneEnum what);
};

Methods in opCylinder

opCylinder( radius, height ) constructs a cylinder with the specified height and radius. By default, the z axis is the cylinder's axis and the cylinder is centered on the origin, extending in the positive and negative z directions for one-half the height.

For the default orientation, u measures the angle from the x-z plane in a counterclockwise direction as you look down on the x-y plane and v measures the distance along the z-axis. The default radius is 1 and the default height is 2.

opTorus

The opTorus class provides methods to describe a torus. Figure 9-13 illustrates a torus, and how it is parameterized in opTorus.

A torus can be defined geometrically as the surface in space that is swept by moving a circle, the minor circle, through space such that its center lies on a second circle, the major circle, and the planes of the two circles are always perpendicular to each other, with the plane of the minor circle aligned along radii of the major circle. The parametrization of the surface is that u represents a position on the major circle and v represents a position on the minor circle.

Figure 9-13. Torus Parameterization

Figure 9-13 Torus Parameterization

Class Declaration for opTorus

The class has the following main methods:

class opTorus : public opParaSurface
{
public:
// Creating and destroying
opTorus( );
opTorus( opReal majorRadius, opReal minorRadius );
~opTorus();
      
// Accessor functions
void setMajorRadius(  opReal majorRadiusVal )
void setMinorRadius( opReal minorRadiusVal ) 
opReal getMajorRadius( )
opReal getMinorRadius( )

// Evaluators
virtual void evalPt(   opReal  u, opReal v, opVec3 &pnt );
virtual void evalNorm( opReal  u, opReal v, opVec3 &norm );

//Copy
virtual csNode* clone(csNode::CloneEnum what);
}

Methods in opTorus

The constructor opTorus( majorRadius, minorRadius ) defines a torus with the specified radii such that the major circle is in the x-y plane and the minor circle is initially in the x-z plane. The default value for the major radius is 1; the default for the minor radius is 0.1.

opCone

You can define a cone geometrically by sweeping a circle along an axis in a way similar to the way a cylinder is defined; however, as the circle is swept along the axis, the radius changes linearly with distance.

The parameterization of a point on an opCone is that u measures the angle, in radians, of the point on the circle, and that v measures the distance along the axis from the origin. To truncate a cone, yielding a frustum, adjust the value for v.

Figure 9-14. Cone Parameterization

Figure 9-14 Cone Parameterization

Class Declaration for opCone

The class has the following main methods:

class opCone : public opParaSurface
{
public:
// Creating and destroying
opCone( void );
opCone( opReal radius, opReal height );
~opCone();
      
// Accessor functions
void setRadius( opReal radius ) ;
void setHeight( opReal height );
opReal getRadius( )              
opReal getHeight( )              

// Evaluators
void evalPt(   opReal  u, opReal v, opVec3 &pnt );
void evalNorm( opReal  u, opReal v, opVec3 &norm ); 

// Copy
virtual csNode* clone(csNode::CloneEnum what);
}

Methods in opCone

The constructor opCone( radius, height ) creates a parametric cone with the specified height and a circular base with the specified radius. By default, the base of the cone is parallel to the x-y plane and centered on the z axis and the apex of the cone is on the positive z-axis. The cone extends from the origin in the positive and negative z directions for one half the height. The default for the radius of the base is 1 and the default height is 2.

Swept Surfaces

The class opSweptSurface provides methods to describe a general swept surface. Three examples of swept surfaces have been presented: a cylinder, a torus, and a cone. In the first two cases a simple cross-section, a circle of constant radius, was swept along a path. For a cone, the radius of the circle varied according to a simple profile.

To describe a swept surface, you specify a path, a cross section, and a coordinate frame in which the graph of the cross section is drawn at each point on the path. The parameterization of the surface is that u denotes the position along the path and v denotes the position on the cross-section curve. You can also specify a profile, which adjusts the size of the cross-section curve. Thus, for example, with a simple profile method you could generate a sphere from a straight-line path and a circular cross section. Figure 9-15 illustrates the feature of a swept surface.

Figure 9-15. Swept Surface: Moving Reference Frame and Effect of Profile Function

Figure 9-15 Swept Surface: Moving Reference Frame and Effect of Profile Function

Orientation of the Cross Section

Unlike the examples of the cylinder, torus, and cone, the cross-section in an opSweptSurface generally is not necessarily perpendicular to the path. You set the orientation of the cross-section with two additional instances of opCurve3d. For a point on the path corresponding the parameter value t0, the vectors on these two additional curves that have the same parameter value define the local coordinate system used to draw the profile: one vector defines the normal to the plane of the graph, the second the x axis for the graph, and their cross product determines the direction of the y axis for the graph. For more details, see the discussion of the constructor below.

Class Declaration for opSweptSurface

The class has the following main methods:

class opSweptSurface : public opParaSurface
{
public:
// Creating and destroying
opSweptSurface( void );
opSweptSurface( opCurve3d *crossSection,
                opCurve3d *_path,
                opCurve3d *_t,
                opCurve3d *_b,
                opScalar  *_profile  );
~opSweptSurface( );

// Accessor functions
void setCrossSection( opCurve3d *_crossSection );
void setPath( opCurve3d *_path );
void setT( opCurve3d *_tng );
void setB( opCurve3d *_b );
void setProf( opScalar  *_profile );
opCurve3d *getCrossSection() ;
opCurve3d *getPath() ;
opCurve3d *getT() ;
opCurve3d *getB() ;
opScalar  *getProf();

virtual void evalPt( opReal u, opReal v, opVec3 &pnt );

virtual csNode clone(csNode::CloneEnum what);
};

Methods in opSweptSurface

opSweptSurface( crossSection, path, t, b, profile )  


Defines a swept surface with the given path, cross section, and profile. The arguments t and b are vector-valued functions of the path's parameter. They define the orientation of the profile at each point on the path.

The orientation at a particular point on the curve is determined by rendering the graph of crossSection in the coordinate plane perpendicular to t, which locally defines the z axis of an x-y-z coordinate system. The x axis is defined by the projection of b onto the plane, and the y axis forms a right-hand coordinate system with the other two axes. The cross section is plotted in the x-y plane.

If you specify a NULL value for profile, crossSection does not vary along path.

evalPt( u, v, pnt ) 


Calculates the point on the surface, pnt, as the vector sum of (a) the point on the path corresponding to the value u and (b) the point on the cross section corresponding to the value v. The vector locating the point on the cross section is scaled by the value at u of the profile function, if profile is not NULL.

opFrenetSweptSurface

As a convenience, the class opFrenetSweptSurface allows you to use the Frenet frame of the path to define the orientation vectors in a swept surface. The Frenet frame is defined by the three unit vectors derived from the tangent, the principal normal, and their cross product. This set of vectors facilitates orienting the cross section perpendicularly to the path at every point.


Note: The path for an opFrenetSweptSurface must be at least a cubic to allow for the principal normal calculation, which requires a second derivative.


Class Declaration for opFrenetSweptSurface

The class has the following main methods:

class opFrenetSweptSurface : public opSweptSurface
{
public:
// Accessor functions
opFrenetSweptSurface( void );
opFrenetSweptSurface( opCurve3d *crossSection,
                      opCurve3d *path,
                      opScalar  *profile  );
~opFrenetSweptSurface( );

// Accessor functions
void set( opCurve3d *crossSection,
          opCurve3d *path,
          opScalar  *profile  );

// Copy
virtual csNode clone(csNode::CloneEnum what);
};

Methods in opFrenetSweptSurface

The arguments of the constructor for opFrenetSweptSurface are the same as for opSweptSurface and have the same effects, except for the orientation vectors, which are set to be the tangent and principal normal to path, and so do not appear as arguments. Use the inherited method evalPt() to locate points on the surface.

Making a Modulated Torus With opFrenetSweptSurface

The following code uses an opFrenetSweptSurface to define a torus whose minor radius varies with position on the ring. Other instances of opFrenetSweptSurface appear in repTest.

// Scalar curve used by the swept surface primitive
static opReal profile( opReal t )
{
return 0.5*cos(t*5.0) + 1.25;
};
 
opCircle3d  *cross = 
                    new opCircle3d( 0.75, new opVec3( 0.0, 0.0, 0.0) );
opCircle3d  *path  = 
                    new opCircle3d( 1.75, new opVec3( 0.0, 0.0, 0.0) );
opFrenetSweptSurface *fswept = 
                      new opFrenetSweptSurface( cross, path, profile );
fswept->setHandednessHint( true );

Ruled Surfaces

A ruled surface is generated from two curves in space, both parameterized by the same variable, u. A particular value of u specifies a point on both curves. A ruled surface is defined by connecting the two points with a straight line parameterized by v. The parameterization of the resulting surface is always the unit square in the u-v plane, regardless of the parameterizations of the original curves.

Figure 9-16. Ruled Surface Parameterization

Figure 9-16 Ruled Surface Parameterization

A bilinear interpolation of four points is perhaps the simplest example of a ruled surface, one for which the “curves” that define the surface are in fact straight lines. Thus, you connect two pairs of points in space with lines and then develop the ruled surface. For a bilinear interpolation, the parameterization by u and v is such that, if one of them is held constant, a point “moves” along the connecting straight line at a uniform speed as the other parameter is varied.

Class Declaration for opRuled

The class has the following main methods:

class opRuled : public opParaSurface
{
public:
// Creating and destroying
opRuled();
opRuled( opCurve3d *c1, opCurve3d *c2 );
~opRuled();
      
// Accessor functions
void setCurve1( opCurve3d *_c1 );
void setCurve2( opCurve3d *_c2 );
opCurve3d *getCurve1( )   
opCurve3d *getCurve2( )   

// Evaluators
void evalPt(   opReal  u, opReal v, opVec3 &pnt );

//Copy
virtual csNode* clone(csNode::CloneEnum what);
};

The constructor opRuled( c1, c2 ) creates an instance of a ruled surface defined by the two curves c1 and c2.

Coons Patches

A Coons patch is arguably the simplest surface you can define from four curves whose endpoints match and form a closed loop. Think of the four curves as defining the four sides of the patch, with one pair on opposite sides of the patch defining the top and bottom curves and the other pair defining the left and right curves (see Figure 9-17). The top and bottom curves are parameterized by u, and the left and right curves by v. Thus, u is the “horizontal” coordinate and v the “vertical” coordinate.

The patch is made by

  1. Adding the points on the ruled surface defined by the top and bottom curves to the points on the ruled surface defined by the left and right curves.

  2. Subtracting the bilinear interpolation of the four corner points.

Figure 9-17 illustrates the construction. To understand the result, notice that, after you add the two ruled surfaces, each side of the boundary of the resulting surface is the sum of the original bounding curve and the straight line connecting the bounding curve's endpoints. The straight line was introduced by the construction of the ruled surface that did not include the boundary curve. Subtracting the bilinear interpolation eliminates the straight-line components of the sum, leaving just the original four curves as the boundary of the resulting surface.

Figure 9-17. Coons Patch Construction

Figure 9-17 Coons Patch Construction

Class Declaration for opCoons

The class has the following main methods:

class opCoons : public opParaSurface
{
public:
opCoons( );
opCoons( opCurve3d *right,   opCurve3d *left,
         opCurve3d *bottom,  opCurve3d *top );
~opCoons( );

// Accessor functions
void setRight(  opCurve3d *right );
void setLeft( opCurve3d *left );
void setBottom( opCurve3d *bottom );
void setTop( opCurve3d *top );

opCurve3d* getTop();
opCurve3d* getBottom();
opCurve3d* getLeft();
opCurve3d* getRight();

// Surface point evaluator
void evalPt( opReal u, opReal v, opVec3 &pnt );

//Copy
virtual csNode* clone(csNode::CloneEnum what);
};

The constructor opCoons( right, left, bottom, top ) creates an instance of a Coons patch defined by the four curves right, left, bottom, and top. The top and bottom curves are parameterized by u and the left and right curves are parameterized by v. For more details, see the book Curves and Surface for Computer Aided Geometric Design listed in “Recommended Background Reading”.

NURBS Surfaces

Just as a NURBS curve consists of Bezier curves, a NURBS surface consists of Bezier surfaces. The set of control parameters is essentially the same for the curves and surfaces: a set of knots, a control hull, and a set of weights. However, for a NURBS surface, the knots form a grid in the coordinate system of the surface; that is, in the u-v plane, and the control hull is a grid of points in space that loosely defines the surface.

Understanding a Bezier surface helps you understand and use a NURBS surface. A Bezier surface is defined essentially as the surface formed by sweeping a Bezier cross section curve through space, along a path defined by a Bezier curve. But, unlike an opSweptSurface, the shape of the cross-section can be changed.

You define a Bezier surface as follows:

  1. Start with a Bezier curve in space: the cross section parameterized by u.

  2. Define a family of Bezier curves, a set of paths all of which are parameterized by v, that start at the control points of the initial cross section.

    For each value of v, the set of control points defines a Bezier curve. As v changes, the cross-sectional curve “moves” through space, changing shape and defining a Bezier surface.

A more rigorous discussion appears in the book Curves and Surface for Computer Aided Geometric Design, listed in the section “Recommended Background Reading”.

A NURBS surface joins Bezier surfaces in a smooth way, similar to NURBS curves joining Bezier curves. The class opNurbSurface provides methods to describe a NURBS surface.

Class Declaration for opNurbSurface

The class has the following main methods:

class opNurbSurface : public opParaSurface
{
public:
// Creating and destroying
opNurbSurface( void );
~opNurbSurface( void );

// Accessor functions
void setControlHull( int iu, int iv, opVec3 &p );
void setControlHull( int iu, int iv, opVec4 &p );
void setWeight( int iu, int iv, opReal w ); 
void setUknot( int iu, opReal u );
void setVknot( int iv, opReal v );
void setControlHullUSize( int s );
void setControlHullVSize( int s );

// Get the same parameters
opVec3& getControlHull( int iu, int iv) ;
int     getControlHullUSize( void );
int     getControlHullVSize( void );
opReal  getWeight( int iu, int iv)
opReal& getUknot( int iu);
opReal& getVknot( int iv);
int     getUknotCount( void );
int     getVknotCount( void );
int     getUorder( void ) ;
int     getVorder( void ) ;
void    removeControlHullElm(int ui, int iv);
void    removeUknot(int iu);
void    removeVknow(int iv);
void    flipUV();

// Evaluator
virtual void evalPt(   opReal u, opReal v, opVec3 &pnt );
virtual void evalDu(   opReal u, opReal v, opVec3 &Du );
virtual void evalDv(   opReal u, opReal v, opVec3 &Du );
virtual void evalNorm( opReal u, opReal v, opVec3 &norm );

int getMemSize();
virtual csNode* clone(csNode::CloneEnum what);
};

Methods in opNurbSurface

The member functions are essentially the same as those for opNurbCurve3d (see “NURBS Curves in Space”), however:

  • The hull is a grid of opVec3s indexed by i and j.

  • The set of knots is defined by points on the u and v axes.

  • There are B-spline basis functions (of possibly differing orders) associated with each coordinate direction.


Note: opNurbSurface redefines the virtual evaluators inherited from opParaSurface for tangent and normal vectors; the methods use the NURBS equation rather than finite, central differences.


Indexing Knot Points and the Control Hull

Indexing of knot points in coordinate space and control hull points in three-dimensional space is illustrated in Figure 9-18. The indexing works as for gluNurbsSurface, that is, as follows:

  • iu indexes knots on the u axis. The correspondence is established by setUknot().

  • iv indexes knots on the v axis.The correspondence is established by setVknot().

  • Each (iu,iv) thus indexes a knot point in the u-v plane.

  • Each (iu,iv) also indexes a point on the control hull in three-dimensional space. The correspondence is established by setControlHull().

  • Thus, setUknot(), setVknot(), and setControlHull() establish a correspondence between an index pair (iu,iv) a knot point (uiu viv), and a point on the control hull in three-dimensional space.

    Figure 9-18. NURBS Surface Control Hull Parameterization

    Figure 9-18 NURBS Surface Control Hull Parameterization

Equation Used to Calculate a NURBS Surface

Indexing is determined by the following equation that OpenGL Optimizer uses to calculate a NURBS surface (the index i corresponds to iu in the API, and j corresponds to iv):

Alternative Equation for a NURBS Surface

A NURBS surface can also be developed from the following alternative expression:

For this case, you must change the coordinates of the control points to get the same surface from OpenGL Optimizer. You convert the coordinates of the control points from (x,y,z,w) to (wx,wy,wz,w).

Sample of a Trimmed opNurbSurface From repTest

The following code fragment form the repTest sample application illustrates an instance of an opNurbSurface. Toward the end of the example, an optional opNurbCurve2d trim curve is created.

int i, j;

opNurbSurface *nurb = new opNurbSurface;

// Control hull dimensions
#define USIZE 4
#define VSIZE 5

// Set up the control hull size because we know a priori how big
// the nurb is.  The next two lines are used for space
// efficiency but are functionally unnecessary.
nurb->setControlHullUSize(USIZE);
nurb->setControlHullVSize(VSIZE);

// Make the control hull be an oscillating grid
for ( i = 0; i < VSIZE; i++ )
{
opReal y = i/(float)(VSIZE - 1) * 2*M_PI - M_PI;
      
for ( j = 0; j < USIZE; j++ )
{
opReal x = j/(float)(USIZE - 1) * 2*M_PI - M_PI;
opReal val = 6*pow( cos(sqrt(x*x + y*y)), 2.0); 

// Make the control hull a box, j maps to u and i maps to v
nurb->setControlHull( i, j, opVec3( x, y, val));

// Add the weights
nurb->setWeight( i, j, 1.0 );
}
}

// Add the knot points
nurb->setUknot( 0,  0.0 );
nurb->setUknot( 1,  0.0 );
nurb->setUknot( 2,  0.0 );
nurb->setUknot( 3,  0.0 );
nurb->setUknot( 4,  1.0 );
nurb->setUknot( 5,  1.0 );
nurb->setUknot( 6,  1.0 );
nurb->setUknot( 7,  1.0 );

nurb->setVknot( 0,  0.0 );
nurb->setVknot( 1,  0.0 );
nurb->setVknot( 2,  0.0 );
nurb->setVknot( 3,  0.0 );
nurb->setVknot( 4,  1.0 );
nurb->setVknot( 5,  1.0 );
nurb->setVknot( 6,  1.0 );
nurb->setVknot( 7,  1.0 );

// Only trim reps in the first row
if ( nVersions <= 0 )
{
// Add a super quadric trim curve 
opSuperQuadCurve2d  *trimCircle0 = new opSuperQuadCurve2d( 0.25, new opVec2(0.25, 0.50), 2.0 );
nurb->addTrimCurve( 0, trimCircle0, NULL );

// make a 4-th order nurb trim curve
opNurbCurve2d *l = new opNurbCurve2d;

l->setKnot(0,0.0);
l->setKnot(1,0.0);
l->setKnot(2,0.0);
l->setKnot(3,0.0);
l->setKnot(4,1.0);
l->setKnot(5,1.0);
l->setKnot(6,1.0);
l->setKnot(7,1.0);
l->setControlHull(0,opVec2(0.50,0.50));
l->setControlHull(1,opVec2(0.90,0.10));
l->setControlHull(2,opVec2(0.90,0.90));
l->setControlHull(3,opVec2(0.50,0.50));

nurb->addTrimCurve( 1, l, NULL  );
}

Hermite-Spline Surfaces

Hermite-spline surfaces interpolate a grid of points; that is, they pass through the set of specified points under the constraint that you supply the tangents at each point in the u and v directions and the mixed partial derivative at each point. This surface definition is the natural generalization of Hermite-spline curves, discussed in “Hermite-Spline Curves in the Plane”.

Figure 9-19. Hermite Spline Surface With Derivatives Specified at Knot Points

Figure 9-19 Hermite Spline Surface With Derivatives Specified at Knot Points

Hermite-spline surfaces are made of Hermite patches (see Figure 9-19). A bicubic Hermite patch expands the definition of a bilinear interpolation to include specification of first derivatives and mixed partial derivatives of the surface at each of the four corners. The adjective “bicubic” in the name of the patches refers to the mathematical definition, which includes products of the cubic Hermite polynomials that define a Hermite-spline curve.

An advantage of including the derivatives to constrain the surface is that it is simple to combine the patches into a smooth composite surface, that is, into a Hermite-spline surface. A more formal discussion of these objects appears in the book Curves and Surface for Computer Aided Geometric Design listed in the section “Recommended Background Reading”.

Class Declaration for opHsplineSurface

The class has the following main methods:

class opHsplineSurface : public opParaSurface
{
public:
// Creating and destroying
opHsplineSurface();
opHsplineSurface( opReal *_p, 
                  opReal *_tu,  opReal *_tv, opReal *_tuv, 
                  opReal *_uu, opReal *_vv, 
                  int uKnotCount, int vKnotCount );
~opHsplineSurface();

// Accessor functions
opVec3& getP( int i, int j );
opVec3& getTu( int i, int j );
opVec3& getTv( int i, int j );
opVec3& getTuv( int i, int j );
opReal  getUknot( int i );
opReal  getVknot( int j );
int     getUknotCount();
int     getVknotCount();
opReal  getCylindrical();

void setAll( opReal *p, 
             opReal *tu,
             opReal *tv, 
             opReal *tuv,
             opReal *uu,
             opReal *vv,
             int uKnotCount,
             int vKnotCount );
void setCylindrical(opReal cylinderical);

// Surface point evaluator
void evalPt( opReal u, opReal v, opVec3 &pnt );
// Copy
virtual csNode* clone ( csNode::CloneEnum what);
};

Methods in opHsplineSurface

The opHsplineSurface class has two important methods, the constructor and set/getCylinderical.

The opHsplineSurface constructor has the following arguments:

_p 

Specifies the grid of points on the surface.

_tu, _tv, and _tuv 


Specify, respectively, the corresponding tangents in the u and v directions and the mixed partials.

The indexing of each of the arrays _p, _tu, _tv, and _tuv is as follows: the x, y, and z components of each vector are grouped in that order, and the sequence of points is defined so that the vKnotCount index changes more rapidly.

uKnotCount and vKnotCount 


Specify the number of points in the grid. The surface is made of (uKnotCount-1) ¥ (vKnotCount-1) Hermite patches.

_uu and _vv  

Define the knot points, the parameter values corresponding to the patch corners; thus, they have uKnotCount and vKnotCount elements, respectively.

setCylindrical() and getCylindrical() 


Control the flag for whether the coordinates and derivatives are assumed to be in cylindrical coordinates.

opCuboid

The opCuboid class defines a simple closed surface, a box with a specified height, width, and depth. It is not a parametric surface.

Class Declaration for opCuboid

The class has the following main methods:

class opCuboid : public opRep
{
public:
// Creating and destroying
opCuboid( );
opCuboid( opReal width, opReal height, opReal depth );
~opCuboid();

// Accessor functions
void setWidth( opReal widthVal);
opReal getWidth( )

void setHeight( opReal heightVal );
opReal getHeight( )

void setDepth( opReal depthVal );
opReal getDepth( );

// Copy
virtual csNode* clone(csNode::CloneEnum what);
};

Regular Meshes and Discrete Surfaces

OpenGL Optimizer provides flexible tools to describe discrete objects in space. For example, you can define a vector-valued function over a topologically regular mesh and so visualize a fluid flow field.

Discrete Surface Base Class: opDisSurface

opDisSurface is the base for the all discrete surfaces and, more generally, higher-dimensional meshes. A discrete surface is described as a set of discrete points interconnected by a specific topology. An example of such a topology is a planar grid structure. The base class provides methods only for discrete trim curves.

Making a Discrete Surface and Other Mesh Objects: opRegMesh

The opRegMesh template class describes a vector-valued function over a rectangular mesh. Thus, an opRegMesh is the natural object for visualizing many data sets or scientific modeling calculations.

The type of the template is determined by the return value of the mesh function you define. For example, you can describe a discrete surface with a two-dimensional grid and a mesh function that returns csVec3f positions of points on the surface. Thus the mesh would be of type csVec3f. A surface tiling is developed by the member function evalPt(), which interpolates values of the mesh function.

A mesh can have an arbitrary number of dimensions, although opRegMesh provides special operations for two-, three-, or four-dimensional meshes. A mesh can have regular or variable spacing in all dimensions. In general, if you specify a mesh by an array of grid points, then the argument of the mesh function must be the same data type as the grid points.

Class Declaration for opRegMesh

The class has the following main methods:

template <class T>
class opRegMesh : public opDisSurface
{
public:
opRegMesh( );
opRegMesh( int Xres, int Yres );
opRegMesh( int Xres, int Yres, int Zres );
opRegMesh( int Xres, int Yres, int Zres, int Tres );
opRegMesh( int d,    int *res );
   
~opRegMesh( );

// Set and get the dimensionality of the mesh
void setDim (int _dim)  
int  getDim (void)      

// Set and get the dimension of the mesh
void setRes( int Xres, int Yres );
void setRes( int Xres, int Yres, int Zres );
void setRes( int Xres, int Yres, int Zres, int Tres );
void setRes( int d,    int *res );

int *getRes( ) ;

// Set and get the type
void setType( opRegMeshType meshType ) 
opRegMeshType getType( )

// Set and get the origin
void setOrigin( opReal *Origin )
opReal& getOrigin( ) 
 
// Set and get the delta spacing
void setSpacing( opReal *Delta );

opReal& getSpacing( ) ;
opReal& getSpacing( int i )
opReal& getSpacing( int i, int j );
opReal& getSpacing( int i, int j, int k );
opReal& getSpacing( int i, int j, int k, int l );
   
// Arbitary indexing via an index vector
opReal& getSpacing( int *index );

// Set and get the mesh function
void  setFunction( T *function ) 
T    *getFunction( )        

// Set and get variable spacing grid 
// (memory maintained by calling program
// assumes sizeof(grid) = 
//                  ndim*sizeof(opReal) * res[0]*res[1]*...*res[ndim-1]
void     setGrid (opReal *_grid) 
opReal  *getGrid ()              

// Single index subscripting operator
T& operator[]( int i );

// One, two, three and four dimensional indexing operators
T& operator()( int i );
T& operator()( int i, int j );
T& operator()( int i, int j, int k );
T& operator()( int i, int j, int k, int l );
   
// Arbitary indexing via an index vector
T& operator()( int *index );
   
// Point interpolated evaluators
void evalPt( T& pt, opReal x, opReal y );
void evalPt( T& pt, opReal x, opReal y, opReal z );
void evalPt( T& pt, opReal x, opReal y, opReal z, opReal t );   
// Extract positional information out of grid
opReal  gridVal ( int i );
csVec2f gridVal ( int i, int j );
csVec3f gridVal ( int i, int j, int k );
csVec4f gridVal ( int i, int j, int k, int l );

// Can set extents if you know them, or compute them
void setExtents (T _min,  T _max);
void getExtents (T *_min, T *_max);
// compute min/max over all data points
bool computeExtents (bool force);
};

Methods in opRegMesh

opRegMesh() ( Xres, Yres ), ( Xres, Yres, Zres ), ( Xres, Yres, Zres, Tres ), and ( d, res )  


Create meshes of two, three, four, and d dimensions, respectively. The numbers of points in each dimension are Xres, Yres, Zres, and Tres, or are given by the elements of the integer vector, res.

If parameters are supplied to the constructor, the value of opRegMeshType is opConstant, indicating constant spacing along the axes. See the discussion of the methods setType() and getType() for more information about opRegMeshType.

computeExtents () 


Computes the maximum and minimum values of the mesh function.

evalPt(pt, x, y, ... ) 


Interpolates from neighboring mesh points the value of the mesh function. pt is the interpolated value.

gridVal (i,j,...)  

Returns the grid point corresponding to the specified set of indices.

operator[] and operator() 


Are the indexing operators that allow you to define an array of variables with the same type as the class and use the indexing operator to return values of the mesh function. For example, F(i,j,k) would give the value of the grid function F(), for the point indexed by (i,j,k).

setDim () and getDim () 


Get and set the dimension of the mesh.

setExtents() and getExtents() 


Set or get the maximum and minimum values of the mesh function. If you know these values beforehand, use setExtents() rather than the computationally more expensive computeExtents().

setFunction( function ) and getFunction() 


Set and get the mesh function. Define the mesh function before you create an instance of opRegMesh. The return value of function is the type of this template class.

setGrid ( _grid ) and getGrid() 


Get and set an array of grid points. _grid is a one-dimensional opReal array. Coordinates of points on the grid are grouped, and the offsets of the groups of coordinates are computed using the offset schemes presented in the class declaration by the indexing operators (see opRegMesh.h). The offsets take into account the number of coordinates associated with each point. Thus, for example, the first coordinate of the point (i,j,k) in a three-dimensional grid constructed by opRegMesh(Xres, Yres, Zres) is 3(i + j*Xres + k*Xres*Yres).

setRes() and getRes() 


Set and get the number of mesh points.

setSpacing() and getSpacing() 


Get and set the spacing of points for meshes with constant spacing along each axis. Although the spacing along each axis is constant, the spacings for the axes may differ. The argument for setSpacing() is an opReal array specifying spacings for each axis.

setType() and getType() 


Set and get the mesh type, which is a value of the enumerated type opRegMeshType: opConstant, opVariable, and opCurviLinear.

An opConstant opRegMesh is defined by the number of points on orthogonal axes and the spacing between the points on the axes.

An opVariable opRegMesh is defined with an explicit set of grid points. The grid points must be topologically regular; that is, they can be indexed with an integer vector that has the same dimension as the grid points. Thus, for example, points on a three-dimensional grid can be described by (i,j,k). See the discussions of setGrid() and operator[] for more information about indexing.

An opConstant opRegMesh<opReal>: Data for opviz

An elementary instance of an opRegMesh<opReal> has a three-dimensional cubic mesh of points with unit spacing in all three dimensions and a number assigned to each point. The spacing of the mesh points determines that the mesh is opConstant.

For this example, make_data_cube() is the opReal-valued function. The program computes the make_data_cube() values for the mesh points, stores them in an opReal array called data, and loads data into the opRegMesh.

make_data_cube (&data, dims);
ndim = 3;
      
...

//     Set origin and mesh spacing
opReal orig[3]  = ;
opReal delta[3] = ;

// --- Allocate opRegMesh to contain raw data
opRegMesh<opReal>  *rm = new opRegMesh<opReal>

//     Load parameters of the opRegMesh rm:
rm->setType (opConstant);
rm->setRes (ndim, dims);
rm->setDim (ndim);  
// do this after setRes because setRes(d,res) will reset dim=4
rm->setOrigin (orig);
rm->setSpacing (delta);

//     Load function values:
rm->setFunction (data);

An opVariable opRegMesh<opReal>: Data for opviz

This instance of an opRegMesh<opReal> has a mesh of three-dimensional points that the application reads from a file and loads into the opReal array grid. Thus, the mesh is opVariable.

The physical model for the real-valued mesh function is the distribution of material density in space specified by the mesh density function real_rho.

When reading the grid array, the application also determines the number of points along each grid axis and stores the values in an int array, dims. The application reads values for the opReal-valued function from a second file and loads them in the array real_rho.

densityMesh = new opRegMesh<opReal>;

densityMesh->setType (opVariable);
densityMesh->setDim (3);
densityMesh->setRes (dims[0], dims[1], dims[2]);
densityMesh->setOrigin (orig);
densityMesh->setGrid (grid);
densityMesh->setFunction (real_rho);

An opVariable opRegMesh<csVec3f>: Data for opviz

This instance of an opRegMesh has the same mesh of three-dimensional points as in the previous example, but the mesh function is vector-valued.

The physical model here is the distribution of momenta in space specified by the vector-valued mesh function momentum. The application reads values for the csVec3f-valued function from a file and loads them in the array momentum.

momentumMesh = new opRegMesh<csVec3f>;

momentumMesh->setType (opVariable);
momentumMesh->setDim (3);
momentumMesh->setRes (dims[0], dims[1], dims[2]);
momentumMesh->setOrigin (orig);
momentumMesh->setGrid (grid);
momentumMesh->setFunction (momentum);


OpenGL Optimizer Programmer's Guide: An Open API for Large-Model Visualization
(document number: 007-2852-002 / published: 1998-06-09)    table of contents  |  additional info  |  download

    Front Matter
    About This Guide
    Part I. Getting Started
    Part II. High-Level Strategic Tools for Fast Rendering
    Part III. Specific Tools for Fast Rendering
    Part IV. Managing and Rendering Higher-Order Geometric Primitives
    Part V. Traversers, Low-Level Geometry Processing, and Multiprocessing
    Part VI. Utilities and Troubleshooting
    Part VII. Appendices
    Glossary
    Index


home/search | what's new | help