t_CS BaseCS(void); t_V3d RotAxisCS(t_CS cs); double RotAngleCS(t_CS cs); t_V3d TransVectCS(t_CS cs); t_CS TransCS(t_CS cs, t_V3d trans); t_CS RotCS(t_CS cs, t_V3d axis, double angle ); t_CS TransRotCS(t_CS cs, t_V3d v, t_V3d axis, float angle); t_CS AlignZCS(t_CS cs, t_V3d dir); t_CS AlignXCS(t_CS cs, t_V3d dir); t_CS AlignYCS(t_CS cs, t_V3d dir); t_CS ChainCS(t_CS cs, t_CS cs2); t_CS InverseCS(t_CS cs1); t_CS RelativeCS(t_CS cs, t_CS cs2); int IsValidCS(t_CS cs); int IsInvalidCS(t_CS cs); int IsEqualCS(t_CS cs1, t_CS cs2); t_CS InvalidCS(void); void PrintCS(t_CS cs); void FprintCS(t_CS cs, FILE *f); t_CS ScanCS(void); t_CS FscanCS(FILE * f); void SetPrintFormatCS(char *); void PrintQuatCS(t_CS cs); void FprintQuatCS(t_CS cs, FILE * f); t_CS ScanQuatCS(void); t_CS FscanQuatCS(FILE * f); t_LLSet ConsGFSetCS(char * setName); void InsInGFSetCS(t_CS cs, t_LLSet set); void SetXAxisLengthCS(double len); void SetYAxisLengthCS(double len); void SetZAxisLengthCS(double len);
The library defines a base (world ) coordinate system which is obtained by calling the BaseCS function. New coordinate systems (c-systems) are defined by translating (shifting) and/or rotating an existing c-system; The first user-defined c-system is a translation/rotation of the base system, eg.:
t_CS cs1 = TransCS(BaseCS(),ConsV3d(1,1,0));
which creates a new coordinate system, translated in the xy-plane by (1,1). The axes of the system are parallel to base c-system's axes. From now-on new c-system can be defined relative to the 'cs1' c-systems:
t_CS cs2 = TransCS(cs1,ConsV3d(0,0,2)); t_CS cs3 = TransCS(BaseCS(),ConsV3d(1,1,2));
Taking into account the definition of 'cs1', 'cs2' and 'cs3' define identical c-systems (such identities are tested by a call to IsEqualCS).
Translations and rotations are always defined in the c-system that is being transformed. In the example above we do not have to worry about this distinction because axes of 'cs1' and the base cs are parallel. After any rotation care must be taken:
t_CS cs1 = RotCS(BaseCS(),ConsV3d(0,0,1), 45.0/180*V3PI); t_CS cs1 = TransCS(cs1,ConsV3d(1,0,0);Rotation is defined by an axis of rotation an angle of rotation; the first command defines 'cs1' as rotated by 45 degrees (anti-clockwise) around z-axis (vector 0,0,1). The translation along the x-axis of 'cs1' corresponds to translation (sqrt(2)/2, sqrt(2)/2, 0) of the base c-system.
TransCS(cs,v) creates a new coordinate system translated by 'v' with respect to 'cs'. RotCS(cs,axis,a) creates a new coordinate system by rotating 'cs' about 'axis' by angle 'a' in radians. If the angle is not zero 'axis' must not be (close to) (0,0,0). In this case RotCS returns the 'invalid c-system' (see Error Handling section below). Both translation and rotation can be performed by a single call to TransRotCS(cs,v,axis,a) which is identical to peforming the translation and rotation sequentially.
The three functions AlignXCS(cs,dir), AlignYCS(cs,dir) and AlignZCS(cs,dir) specify rotations in the following way: The returned rotated 'cs_out' system has its x-axis (in the case of AlignXCS) aligned with direction 'dir' of 'cs'. The operation is implemented by rotating 'cs' around an axis of rotation perpendicular to both 'dir' and the axis that is being aligned.
MagnV3d(DiffV3d(TransVectCS(cs1),TransVectCS(cs2)));
Functions RotAxisCS(cs) and RotAngleCS(cs) determine the axis and angle of rotation that the base cs must undergo to become cs.
cs2 == RelativeCS(cs,ChainsSC(cs,cs2);
where the '==' should be read as 'equal up to the precision of floationg point calculations'. In example 'exCircle', RelavtiveCS() is part of the calculation to point an axis of a c-system towards the origin of another c-system.
IsEqualCS(cs1,cs2) test whether two coordinate system are identical. Note that two c-systems that can by shown algebraicly to be identical may fail this test due to finite precision of floating point numbers. The problem can be avoided by computing the transformation between the two sytems using the RelativeCS() function and then testing the magnitude of the translation vector and the rotation angle.
CS as trans: 1 2 3 axis: 1 -2 1 angle: 0.7775
Fprint(cs,f) writes c-system 'cs' to file 'f'. Print(cs) writes
to standard output. Fscanf(f) returns a c-system object read from
file f. Scanf() returns a c-system object read from standard input.
Fscanf and Scanf return the 'invalid' c-system on failure, ie. when the
file does not contain correctly formatted data, was not opened for reading
etc. The .cs file can contain:
- blank lines - comment lines starting with '#' - lines with c-system definitions.
Lines with c-system definitions can contain arbitrary text after c-system specification. Whitespace characters are ignored, but the 'CS as trans:', axis:', 'angle:' must be present as shown in the examples (the scanning fucntions are case-sensitive). An example '.cs' file may look like:
#----- Marker position for BoX_1 # all c-system are relative to base # orientations express surface normals at the marker # date: 1-Feb CS as trans: 1.2 3.1 3 axis: 0 0 1 angle: 1.57 # top CS as trans: 2 2.1 4 axis: 1 0 0 angle: 0.23 # white spot
A '.cs' file is read in as follows:
while(IsValidCS(cs=ScanCS()))
{ /* fails if a/ nothing else on input
/* b/ incorrect format of CS data
/*-------- process cs here ---------- */
}
Functions PrintQuatCS(cs), FPrintQuatCS(cs, f), ScanQuatCS(), FscanQuatCS(f) work analogically to their conterparts for manipulation of '.cs' files but the output is stored as a quaternion pair. These functions should be used for debugging purposes or when the output of the library is intented for use with a similar packages requiring quaternion input.
The '.gf' representation of c-system can be analysed by the 3D visualisation package 'Xmgf'. A '.gf' file is created in the 'cs2gf' example. In general we recommend programs output information about c-systems in the '.cs' format and then use the 'cs2gf' tool to covnvert the output into the .gf format.
Rotations (RotCS) fail if axis of rotation is incorrectly specified. Input and output operations may fail for a number of reasons. Functions IsValidCS(cs) and IsInvalidCS(cs) should be used to test return values, as shown in an example in the 'External Representation' section.
The 'invalid c-system' is obtained by a call to InvalidCS(). Users may therefore write functions returning c-system objects and indicate errors encountered during computation using error-handling mechanism of the library, eg. :
if(some_error_occured) return InvalidCS();
/*--------------------------------------------------------------------------*/
/* Author: George (Jiri) Matas g.matas@ee.surrey.ac.uk
Pavel Andris, utrrandr@savba.sk */
/*--------------------------------------------------------------------------*/
static char sccsid[]="@(#)exCircle.c 1.4 95/02/06 g.matas@ee.surrey.ac.uk";
typedef char _s_foo[sizeof(sccsid)];/*stop gcc warning: unused var sccsid*/
/*--------------------------------------------------------------------------*/
/* Description:
generates a number of coordinate systems on circle. Each of the
c-systems points with its Z-axis towards the same 'look point'.
Most parametrs, eg. number of points on the circle, center and
radius of the circle, the 'look point' etc. can be defined on
the command line.
The c-system are output to .cs file.
More generally, the example shows how to place c-system (eg. associated
with a camera) along an arbitrary trajectory with it Z-axis
(optical axis in the case of camera) pointing to a fixed 'look point'
*/
/*--------------------------------------------------------------------------*/
#include "coordSys.h"
#include "optionGM.h"
#include <math.h>
int main(int argc, char **argv)
{
OptionInit(argv,&argc); /* see optionGM man page */
{
t_V3d cenT = ConsV3d(0,0,0);
/* default: circle center = base c-system origin */
t_V3d look; /* look point */
char * out_file = OptionStr("o","-", ".gf file (output)");
double radius = OptionDouble("r",1.0, "radius of the circle");
int pts = OptionInt("pts",8, "num. of points on circle");
OptionDoubleArr("cen",(double*)&cenT,3,"circle center");
look = cenT; /* default: look at the circle center */
OptionDoubleArr("lp",(double*)&look,3,"look point for cs's on circle");
OptionCheck();
{
FILE * f = (out_file[0]=='-') ? stdout : fopen(out_file,"w");
/* open .cs file, "-" is stdout */
t_CS cenCS = TransCS(BaseCS(),cenT); /* c-sytem of the circle center */
t_CS lookCS = TransCS(BaseCS(),look); /* c-sytem of the loop point */
int i;
if(NULL == f)
{fprintf(stderr,"can't open file: %s!\n",out_file);exit(1);}
cenCS = AlignZCS(cenCS,ScalV3d(cenT,-1));
/* Point the Z-axis of circle center c-system at the origin */
/* the circle is generated in a plane perpendicular */
/* to this direction */
for(i=0;i<pts;i++)
{
double c = cos(i/(double)pts * 2*V3PI);
double s = sin(i/(double)pts * 2*V3PI);
t_CS viewCS = TransCS(cenCS,ConsV3d(radius*c,radius*s,0));
/* generate point on circle */
/* change these lines if different trajectory required */
t_CS toLook = RelativeCS(viewCS,lookCS);
viewCS = AlignZCS(viewCS,TransVectCS(toLook));
/* to make sure that an arbitrary point lies on a Z-axis */
/* of 'viewCS' c-system we must get the point position in the */
/* c-system. RelativeCS does just that. */
/* Then align the Z-axis using point posit. as direction for */
/* the AlignZCS function */
FprintCS(viewCS,f); /* save to file */
}
}
}
return 0;
}
/*--------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------*/
/* Author: George (Jiri) Matas g.matas@ee.surrey.ac.uk */
/*--------------------------------------------------------------------------*/
static char sccsid[]="@(#)exTraject.c 1.1 95/02/06 g.matas@ee.surrey.ac.uk";
typedef char _s_foo[sizeof(sccsid)]; /*stop gcc warning: unused var sccsid*/
#include "coordSys.h"
#include "optionGM.h"
#include <math.h>
/*
Description: move a c-system along a trajectory specified in a file.
Keep looking with Z-axis at the look point (see option).
For more, see exCircle.c
*/
int main(int argc, char **argv)
{
OptionInit(argv,&argc); /* see optionGM man page */
{
t_V3d look = ConsV3d(0,0,0); /* look point */
char * in_file = OptionStr("i",NULL, "file with trajectory");
char * out_file = OptionStr("o","-", ".cs file (output)");
OptionDoubleArr("lp",(double*)&look,3,"look point for cs's on circle");
OptionCompulsory("i");
OptionCheck();
{
t_V3d view; /* viewpoint */
t_CS lookCS = TransCS(BaseCS(),look); /* c-sytem of the loop point */
FILE * f = (out_file[0]=='-') ? stdout : fopen(out_file,"w");
FILE * fi= ( in_file[0]=='-') ? stdin : fopen(in_file,"r");
if(NULL==f ) {fprintf(stderr,"can't open file: %s!\n",out_file);exit(1);}
if(NULL==fi) {fprintf(stderr,"can't open file: %s!\n", in_file);exit(1);}
while(3 == fscanf(fi,"%lf %lf %lf",&view.x,&view.y,&view.z))
{
t_CS viewCS = TransCS(BaseCS(),view);
t_CS toLook = RelativeCS(viewCS,lookCS);
viewCS = AlignZCS(viewCS,TransVectCS(toLook));
FprintCS(viewCS,f);
}
}
}
return 0;
}
/*--------------------------------------------------------------------------*/
/*------------------------------------------------------------------------- */
/* author: George (Jiri) Matas g.matas@ee.surrey.ac.uk */
/*--------------------------------------------------------------------------*/
static char sccsid[]="@(#)cs2gf.c 2.2 95/02/05 g.matas@ee.surrey.ac.uk";
typedef char _s_foo[sizeof(sccsid)];/*stop gcc warning: unused var sccsid*/
#include "gfLL.h"
#include "coordSys.h"
#include "optionGM.h"
int main(int argc, char **argv)
{
OptionInit(argv,&argc);
{
char * inp_file = OptionStr("i",NULL,".cs file (input)");
char * out_file = OptionStr("o","-", ".gf file (output)");
char * set_name = OptionStr("s","CoordSys", "gf set name ");
double xLen = OptionDouble("x",1.0, "length of x-axis");
double yLen = OptionDouble("y",1.0, "length of y-axis");
double zLen = OptionDouble("z",1.0, "length of z-axis");
OptionCompulsory("i");
OptionCheck();
{
t_LLSet gfSet = ConsGFSetCS(set_name);
t_CS cs;
FILE * f = (inp_file[0]=='-') ? stdin : fopen(inp_file,"r");
if(NULL == f)
{fprintf(stderr,"can't open file: %s!\n",inp_file);exit(1);}
SetXAxisLengthCS(xLen);
SetYAxisLengthCS(yLen);
SetZAxisLengthCS(zLen);
while(IsValidCS(cs = FscanCS(f)))
InsInGFSetCS(cs,gfSet);
WriteLLSet(out_file,gfSet);
}
}
return 0;
}
At present linking (attachment) of c-systems is not supported. For example, if a number of c-systems is used to describ various locations on a complex object and the object is moved, all the c-systems must be subjected to the appropriate transformation. This is easily accomplished by the ChainCS function, but nevertheless the programmer must not forget take care of the task. Implementation of c-system linking (attachment) would require that father c-systems are not destroyed before sons in the dependency tree. Such is system can be conveniently implemented in C++.
In the current implementation, every transformation creates a new c-system. In our opinion, the efficiency penalty incurred is justified. First, one can overwrite a c-system variable only by epxlicit assignment; accidental overwrite is threfore very unlikely. Calls do not need to take addresses of variables using the '&' operator which is inconvenient and easily forgotten. Last but not least the implentation is in the spirit of other UoS libs like vector2 and vector3, which is used in the implementation of this library.
Warning. The libstrGM.a string library used in the '.gf' manipulation routines requires standard C function 'sprintf' to behave as defined by ANSI C strandard, ie. returning the number of successfully converted arguments. On some UNIX systems, eg. SUN OS 4.x, the C standard lib contains K&R implementation of spprintf which returns its first argument. Under SUN OS, the ANSI compatible lib is in /usr/5lib.