2.1 Geometry Coordinates

In HOOPS, as in most graphics systems, points in space are specified with Cartesian coordinates. Coordinates in 3D space are commonly called x, y, and z. HOOPS commands always take three coordinates; thus, all points in HOOPS are 3D. If we want to specify something in 2D, we simply use a z coordinate of zero. HOOPS will notice the value and will automatically switch to using 2D routines as appropriate.

Coordinates are specified in HOOPS using single-precision floating-point numbers.

2.1.1 Points

HOOPS is inconsistent in the way that points are specified. A point is always three single-precision floating-point numbers, but points are passed to HOOPS in several different ways:

Some HOOPS commands use three separate arguments to pass the three coordinates of a point. Each argument is a floating-point number. For example,

float x, y, z; 
float x1, y1, z1, x2, y2, z2; 
HC_Insert_Text(x, y, z, "hello, world!"); 
HC_Insert_Line(x1, y1, z1, x2, y2, z2);   

Some HOOPS commands take the points themselves as arguments. These routines always expect the address of the point. For example,

HC_Insert_Circle(&point1, &point2, &point3);   

Physically, HOOPS requires you to pass it an address of three consecutive single-precision floating-point numbers, but there are several ways that you can create such a pointer. The two most common ways are as the address of an array of three floats, or as the address of a structure containing three floats. In the following code, the point p1 is an array of three floats, and p2 is a structure containing three floats.

float p1[3]; // array of three floats 

struct Point { float x, y, z; }; 
Point p2;   // structure containing three floats   

The actual declaration in HOOPS commands for a point argument (in hc.h) is a "void *". Because the memory organization of an array of three floats and that of a struct containing three floats are the same, either can be passed (as can any other data structure with the same memory organization). Unfortunately, this flexibility is purchased at the expense of type checking; later in this section, we shall describe a way to restore strong type checking to points.

If you use an array of three floats for a point, rather than a struct, then the "address of" (&) operator is optional when you pass a point to a HOOPS command, because arrays are passed as pointers in C++. The disadvantage of using an array is that the individual x, y, and z components of a point are accessed via a subscript, rather than via a name (for example, the x coordinate is p1[0], rather than p1.x), and assigning one point to another can be tricky because simply assigning one array to another does a pointer assignment.

Some HOOPS commands take an array of points as an argument (usually preceded by a count of how many points are in the array):

HC_Insert_Polygon(5, array_of_5_points); 
HC_Insert_Polyline(9, array_of_9_points);   

In this case, you can use either a 2D array or an array of point structures (or some other data structure that has the same memory organization):

float array_of_5_points[3][5]; 
Point array_of_9_points[9];  

You can tell HOOPS which kind of point you will be using, so that it can do type checking. You just define the preprocessor variable POINT to be the C++ type name that you are using:

struct Point { float x, y, z; }; 
#define HC_POINT Point 
#include <hc.h>
Program 2.1.1.a Definition of type Point to be a struct of three floats.

Note that you must define POINT before the file hc.h is included. Program 2.1.1.a changes the declarations of all the HOOPS routines that take a point argument to expect a struct of three floats. If you define a point to be a struct of three floats in this way, then you cannot use an array of three floats for a point, of course.

This guide will always define a point to be a struct of three floats. Actually, the definition of struct Point that we shall be using also has a member function to allow the coordinates of a point to be set with a single function call (as shown in Program 2.1.1.b). Note that the z coordinate defaults to 0.0 so we can use the same function to set 2D points.

class HPoint 
{ 
public:
    float       x;  // The x-coordinate of a 3-dimensional point.
    float       y;  // The y-coordinate of a 3-dimensional point.
    float       z;  // The z-coordinate of a 3-dimensional point.


    HPoint() { x=0.0f;y=0.0f;z=0.0f; };
    HPoint(float X,float Y,float Z=0.0f) { x=X;y=Y;z=Z; };
    HPoint(HPoint const *p) { x=p->x;y=p->y;z=p->z; };
    HPoint(const HPoint &p) { x=p.x;y=p.y;z=p.z; };
    
    /* Set packs an HPoint object with coordinate values.  */
    inline void Set(float X,float Y,float Z=0.0f) { x=X;y=Y;z=Z; };
    inline void Set(HPoint *p) { x=p->x;y=p->y;z=p->z; };
    inline void Set(HPoint const *p) { x=p->x;y=p->y;z=p->z; };
    inline void Set(HPoint &p) { x=p.x;y=p.y;z=p.z; };
    inline void Set(const HPoint &p) { x=p.x;y=p.y;z=p.z; };

    /* Add increases or decreases the coordinate values of an existing HPoint object.  */
    inline void Add(float X,float Y,float Z=0.0) { x+=X;y+=Y;z+=Z; };

};  
Program 2.1.1.b Definition of type HPoint.

2.1.2 Dealing with Double-Precision Data

HOOPS/3dGS includes double-precision variants of the geometry Insert and Show routines. These routines only deal with storing double-precision data in the HOOPS scene graph. The double-precision coordinates could still get truncated when casting them to float, since a single-precision float doesn't have enough bits of precision, and the result may be a loss of precision.

If you want to avoid such precision-loss, you must 'relocate' (translate) the origin for a group of data, and subtract the origin from each coordinate. This will reduce the number of bits needed for the 'fraction' portion of each coordinate, and the truncation problem should go away. To do this, you simply find the min/max for each range (for each of x, y and z), pick a value in the middle of that range, and then subtract that value from each coordinate. Then you 'remember' what that value is to 'add it back' if you want to query the original double-precision value.

For example, let's say that for x, the min is 650000 and the max is 660000. You'd take 655000 as the new 'center', and subtract that away from each of the values. Thus, your 'translated' x values would range from -5000 to 5000. Then, when querying a point, you'd just add 655000 to the point that was queried to give the original double-precision value.

Next

Previous

Index