Overview

The RoseXform class wraps a double[16] array of transformation matrix data with inline member functions for simple access and update. The C++ compiler provides copy operatiors and temp object creation, so you can use this to pass transforms back from your functions. The RoseXform2D class wraps a double[9] for 2D transform matrices.

It is defined in the rose_xform.h header file.

Everything is public so you can use the class with an array function by just passing the ".m" member. All calculations are done in separate C-style functions, although we usually provide overloads that take an array or a reference to a wrapper class.

There are no virtual fuctions, so the memory layout of the class is identical to the array. This lets you use a reinterpret cast to view an existing array as a class reference if needed.

double foo[16] = ROSE_XFORM_IDENTITY;

// view the foo array as a class
RoseXform& as_a_class = *((RoseXform*)(foo));

// an actual instance of the class, initialized to
// a 90-degree rotation about Y-axis
RoseXform actual_class (0, 0, -1,  0, 1, 0,  1, 0, 0);

Array Member

public:
	double m[16];

The class has a public array member with the coordinates. You can access the data directly whenever you want. The member functions are strictly for clearer code and better compiler checking.

RoseXform xf;

// completely equivalent
printf ("My ydir is %g, %g, %g\n", xf.m[4], xf.m[5], xf.m[6]);
printf ("My ydir is %g, %g, %g\n", xf.ydir().i(), xf.ydir().j(), xf.ydir().k());

Constructor

RoseXform();
RoseXform(const double src[16]);
RoseXform(
	double xi, double xj, double xk, 
	double yi, double yj, double yk, 
	double zi, double zj, double zk, 
	double x=0, double y=0, double z=0
	);

The RoseXform() default constructor initializes the transform to the identity matrix, while the other initialize the components from either an array or separate parameters.

// rotate 90 degrees around x-axis at (10, 20, 30)
double foo[16] = { 1, 0, 0,  0, 0, -1,	 0, 1, 0,   10, 20, 30 };

// default ctor initializes as identity matrix
RoseXform i_am_identity;

// initialized with explicit arguments
RoseXform xf1 (
	   1, 0, 0,  0, 0, -1,	 0, 1, 0,   10, 20, 30
	   );

// initialized by copying contents of foo
RoseXform xf2 (foo);
RoseXform xf3 = foo;	// same

// initialized by copying another RoseXform
RoseXform xf4 = xf3;

origin()

const RosePoint& origin() const;
RosePoint& origin();

void origin (const RosePoint& val);
void origin (const double val[3]);
void origin (double x,double y,double z);
void origin (ListOfDouble * lst);

The origin() function works with the x, y, z coordinates for the origin of a transform. The access functions return a reference to a RosePoint, and you can call the update function with a RosePoint, a three-element array, or three separate numbers. The update functions are equivalent to calling rose_xform_put_origin() on the transform array.

RoseXform xf;

// get the coordinate values by name
printf ("origin is at %g, %g, %g\n",
       xf.origin().x(), 
       xf.origin().y(), 
       xf.origin().z());

// get the coordinate values by array index
for (i=0; i<3; i++)
    printf ("coord %g\n", xf.origin().m[i]);



double pt1[3] = { 100, 100, 0 };
RosePoint pt2 (100, 100, 0);

xf.origin (pt1);	// set origin from array
xf.origin (pt2);	// set origin from RosePoint

// set origin directly from arguments
xf.origin (100, 100, 0);

put_alldirs()

void put_alldirs(const RoseXform& src);

The put_alldirs() function copies all three xdir(), ydir(), and zdir() axis directions from a transform. It is equivalent to calling rose_xform_put_alldirs() on the transform array.

RoseXform xf;
RoseXform other;

// copy direction portion
xf.put_alldirs (other);	     

// same, but assign each direction
xf.xdir (other.xdir());	     
xf.ydir (other.ydir());	     
xf.zdir (other.zdir());	     

// same, but work on arrays directly
rose_xform_put_alldirs(xf.m,other.m);	   

put_cto()

void put_cto(
	const RoseDirection& xax,
	const RoseDirection& yax,
	const RoseDirection& zax,
	const RosePoint& loc,
	double scale = 1
	);

The put_cto() function initializes from a cartesian transform operator, which is a generalized transform that can do rotation, translation, uniform scaling, and mirroring (by giving a left handed set of direction vectors). This function is equivalent to calling rose_xform_put_cto() on the transform array.

The function expects direction vectors for the X-axis, Y-axis, Z-axis, a location vector, and an optional scale factor. Any of the vectors can be null or zero vectors. As with put_dirs(), This function follows the STEP and IFC Part 42 EXPRESS logic for building the axes when they are missing.

put_dirs()

void put_dirs(
	const RoseDirection& zaxis,
	const RoseDirection& xaxis
	);

The put_dirs() function takes Z and X axis directions, computes a Y axis direction, makes sure that the resulting three axis directions are normalized and orthogonal, and sets xdir(), ydir(), and zdir(). You can completely initialize a transfrorm by calling this function followed by origin().

This way of describing a rotation transform is used by STEP and IFC axis2_placement3d objects and the function will handle zero direction vectors (0,0,0) correctly by choosing the appropriate defaults. This function is equivalent to calling rose_xform_put_dirs() on the transform array.

RoseXform xf;
RoseDirection minux_xaxis (-1, 0, 0);
RoseDirection zaxis (0, 0, 1);

// Set rotation to 180deg counterclockwise about the Z axis.
// The Y direction will be (0, -1, 0)	Finish by setting the
// translation portion to (10, 20, 30)

xf.put_dirs(zaxis, minux_xaxis);      
xf.origin(10, 20, 30);

// Same thing with axis vectors that are not normalized.   The 
// final result will have X, Y, and Z directions scaled to unit
// vectors, so you will get the same matrix as above.

RoseXform xf2;
RoseDirection denorm_minux_xaxis (-50, 0, 0);
RoseDirection denorm_zaxis (0, 0, 234);

xf2.put_dirs(denorm_zaxis, denorm_minux_xaxis);	     
xf2.origin(10, 20, 30);	     


if (rose_xform_is_equal(xf, xf2))
   printf("See!	 Same result!\n");

put_identity()

void put_identity();

The put_identity() function sets the contents of the transform to the identity matrix. It is equivalent to calling rose_xform_put_identity() on the transform array.

RoseXform xf;  // default ctor initializes to identity matrix

// set to identity matrix again
xf.put_identity();

// same thing, but work on the array directly
rose_xform_put_identity(xf.m);

// more verbose way to set the identity matrix
xf.xdir (1, 0, 0)
xf.ydir (0, 1, 0);
xf.zdir (0, 0, 1);
xf.origin (0, 0, 0);

put_rotation()

void put_rotation(
	const RoseDirection& axis,
	double angle,
	RoseUnit angle_unit = roseunit_rad
	);

The put_rotation() function replaces the rotation part of the matrix with a transform that rotates by a certain angle along the given axis. Use rose_xform_compose_rotation() if you want to rotate an existing matrix by some angle.

The direction of rotation is given by the right-hand rule with your thumb aligned along the given axis. By default, the angle is expected in radians, but you can use degrees by giving an extra unit parameter. This is equivalent to calling rose_xform_put_rotation() on the transform array.

RoseXform rot;
RoseDirection axis(0,0,1);
RoseDirection src(1,0,0);
RoseDirection dst;

// rotate 90deg counterclockwise around the Z axis
rot.put_rotation(axis, 90, roseunit_deg);

// apply to a src vec that points along X
rose_xform_apply_dir (dst, rot, src);

// dst vec now points along Y (0, 1, 0)

xdir()

const RoseDirection& xdir() const;
RoseDirection& xdir();

void xdir (const RoseDirection& val);
void xdir (const double val[3]);
void xdir (double i,double j,double k);
void xdir (ListOfDouble * lst);

The xdir() function works with the i, j, k components for the X-axis direction portion of a transform. The access functions return a reference to a RoseDirection, and you can call the update function with a RoseDirection, a three-element array, or three separate numbers. The update functions are equivalent to calling rose_xform_put_xdir() on the transform array.

The ydir() and zdir() functions work with the other axis directions.

RoseXform xf;

// get the coordinate values by name
printf ("xdir is %g, %g, %g\n",
       xf.xdir().i(), 
       xf.xdir().j(), 
       xf.xdir().k());

// get the direction values by array index
for (i=0; i<3; i++)
    printf ("dir %g\n", xf.xdir().m[i]);


double pt1[3] = { 0, 0, 1 };
RoseDirection pt2 (1/ROSE_SQRT_2, 1/ROSE_SQRT_2, 0);

xf.xdir (pt1);	// set x axis direction from array
xf.xdir (pt2);	// set x axis direction from RoseDirection

// set all axis directions and origin directly from arguments
xf.xdir (1, 0, 0)
xf.ydir (0, 0, -1);
xf.zdir (0, 1, 0);
xf.origin (10, 20, 30);

ydir()

const RoseDirection& ydir() const;
RoseDirection& ydir();

void ydir (const RoseDirection& val);
void ydir (const double val[3]);
void ydir (double i,double j,double k);
void ydir (ListOfDouble * lst);

The ydir() function works with the i, j, k components for the Y-axis direction portion of a transform. The access functions return a reference to a RoseDirection, and you can call the update function with a RoseDirection, a three-element array, or three separate numbers. The update functions are equivalent to calling rose_xform_put_ydir() on the transform array.

See xdir() for code examples.

zdir()

const RoseDirection& zdir() const;
RoseDirection& zdir();

void zdir (const RoseDirection& val);
void zdir (const double val[3]);
void zdir (double i,double j,double k);
void zdir (ListOfDouble * lst);

The zdir() function works with the i, j, k components for the Z-axis direction portion of a transform. The access functions return a reference to a RoseDirection, and you can call the update function with a RoseDirection, a three-element array, or three separate numbers. The update functions are equivalent to calling rose_xform_put_zdir() on the transform array.

See xdir() for code examples.