/***********************************************************************/ /* Open Visualization Data Explorer */ /* (C) Copyright IBM Corp. 1989,1999 */ /* ALL RIGHTS RESERVED */ /* This code licensed under the */ /* "IBM PUBLIC LICENSE - Open Visualization Data Explorer" */ /***********************************************************************/ #include #include "dx/dx.h" #include #include #include #include #define MAX_PARAMS 21 #define MAX_RANK 16 #define NO 0 #define YES 1 static FILE *fp=NULL; static int text_as_string = NO; static char *tab[] = {""," "," "," "," "," "," ", " "," "," "}; static char *fontstyle=NULL; Error _dxfExportVRML(Object dxobject, char *filename); Error parse_dx(Object dxobject,int *index,Matrix *mat,char *name,Point *box); Error write_solid(Object dxobject,int triangle); static Error write_positions(Object dxobject,int itab,int pos_dim); static Error write_connections(Object dxobject,int triangle,int itab); static Error write_colors(Object dxobject,int itab,RGBColor **rgb,float *op); static Error write_normals(Object dxobject, int itab); static Error write_elevation(Object dxobject); static void write_appearence(RGBColor *rgb, float op,int lines, int itab); static int write_transform(Matrix mat, int *trans_two); Error SetViewPoint(Object dxobject); static Error write_caption(Object o,Point *box); static Error write_text(Object dxobject); static void DGetRotationOfMatrix(Matrix mat, Vector rotvec, float *sinhrot); Error _dxfExportVRML(Object dxobject, char *filename) { char wrlname[256]; int i=0, index = 0; Matrix default_mat = {1,0,0,0,1,0,0,0,1,0,0,0}; char *cp; int texture; int number = 0, tiffcount = 0; Point box[8]; char *string; /* open the vrml file */ if (((cp=strrchr(filename, '.'))!=NULL) && !strcmp(cp,".wrl") ) strcpy(wrlname,filename); else{ strcpy(wrlname,filename); strcat(wrlname,".wrl"); } fp = fopen(wrlname,"w"); if (!fp){ DXSetError(ERROR_INTERNAL, "unable to open output file base on %s", filename); goto error; } /* Write out the parameters */ fprintf(fp,"%s\n","#VRML V2.0 utf8"); /* set Navigation default */ fprintf(fp,"%s\n","NavigationInfo {"); if (DXGetStringAttribute((Object)dxobject,"VRML Set NavigationInfo type",&string)) fprintf(fp," type [%s]\n",string); else fprintf(fp,"%s\n"," type [\"EXAMINE\",\"WALK\",\"FLY\"] "); fprintf(fp,"%s\n","}"); fprintf(fp,"%s\n","Group {"); fprintf(fp,"%s\n"," children ["); /* add first child node ? */ if (DXGetStringAttribute((Object)dxobject,"VRML Insert First Child Node",&string)) fprintf(fp," %s\n",string); /* Calculate the Bounding Box of whole object so can position */ /* Caption is exists */ DXBoundingBox(dxobject,box); /* do we export strings are geometry? */ if (!DXGetIntegerAttribute((Object)dxobject,"VRML text as string", &text_as_string)) text_as_string = NO; /* if there a fontstyle */ if (!DXGetStringAttribute((Object)dxobject,"VRML FontStyle",&fontstyle)) fontstyle=NULL; /* now export object */ if (!parse_dx(dxobject,&index,NULL,NULL,box)) goto error; /* find the initial viewpoint based on bounding box of object */ /* and a 45 degree field of view */ SetViewPoint(dxobject); fprintf(fp,"%s\n","]"); fprintf(fp,"%s\n","}"); fclose(fp); return OK; error: if (fp) fclose(fp); return ERROR; } /* if group recurse through the objects in a group */ Error parse_dx(Object dxobject, int *index,Matrix *mat,char *name,Point *box) { Object o,o1; int i; Array a; Matrix default_mat = {1,0,0,0,1,0,0,0,1,0,0,0}; Matrix tempmat,newmat; char *string; int simple_transform,screen_pos,trans_two=0; ModuleInput modin[2]; ModuleOutput modout[1]; switch(DXGetObjectClass((Object)dxobject)){ case CLASS_GROUP: case CLASS_MULTIGRID: for (i=0; (o = DXGetEnumeratedMember((Group)dxobject,i,&name)); i++){ if (!parse_dx(o,index,mat,name,box)) goto error; } break; case CLASS_XFORM: /* use Apply transform for any transformed object this can be changed to use write_transform if I could figure out how to break the matrix into individual translations, rotations, and scales correctly */ DXGetXformInfo((Xform)dxobject,&o,&tempmat); simple_transform = write_transform(tempmat,&trans_two); if (simple_transform == 1) { if (!parse_dx(o,index,&tempmat,name,box)) goto error; if (trans_two == 0) { fprintf(fp,"%s\n"," ]"); fprintf(fp,"%s\n","}"); } if (trans_two == 1) { fprintf(fp,"%s\n"," ]"); fprintf(fp,"%s\n","}"); fprintf(fp,"%s\n"," ]"); fprintf(fp,"%s\n","}"); } } else { o = DXApplyTransform((Object)dxobject,NULL); if (!o) goto error; if (!parse_dx(o,index,&tempmat,name,box)) goto error; } break; case CLASS_SCREEN: if (DXGetAttribute((Object)dxobject,"Caption string")) { if (!write_caption(dxobject,box)) goto error; break; } DXGetScreenInfo((Screen)dxobject,&o,&screen_pos,NULL); /* Autoglyph text */ if (screen_pos == SCREEN_WORLD) { if (DXGetXformInfo((Xform)o,&o1,&tempmat) && DXGetAttribute((Object)o1,"Text string")) { /* make these Billboard objects */ fprintf(fp,"%s\n","Billboard {"); fprintf(fp,"%s\n"," axisOfRotation 0.0 0.0 0.0"); fprintf(fp,"%s\n"," children ["); if (text_as_string == YES) { if (!write_text(o1)) goto error; } else { if (!parse_dx(o1,index,mat,name,box)) goto error; } fprintf(fp,"%s\n"," ]"); fprintf(fp,"%s\n","}"); } else if (DXGetAttribute((Object)o,"Text string")) { if (!write_text(o)) goto error; } } else DXWarning("This screen objects are ignored"); break; case CLASS_FIELD: if (!DXGetComponentValue((Field)dxobject,"positions")) { DXWarning("Field does not contain positions, skipping"); break; } /* is this text ? */ if (text_as_string == YES) { if (DXGetStringAttribute((Object)dxobject,"Text string",&string)){ if (!write_text(dxobject)) goto error; break; } } /* check connections component to get type of output */ /* surface, lines, or points ? */ if (!(a = (Array)DXGetComponentValue((Field)dxobject,"connections"))){ if (!write_solid(dxobject,0)) goto error; break; } else { /* check element type and call solid with correct index */ if (!DXGetStringAttribute((Object)a,"element type",&string)) goto error; if (!strcmp("lines",string)){ if (!write_solid(dxobject,1)) goto error; } else if (!strcmp("quads",string)){ if (!write_solid(dxobject,3)) goto error; } else if (!strcmp("triangles",string)){ if (!write_solid(dxobject,2)) goto error; } else { /* not quad,triangle,lines, must be volume */ /* call showboundary first */ DXWarning("volume data is converted to boundary"); DXModSetObjectInput(&modin[0],"input",dxobject); DXModSetIntegerInput(&modin[1],"validity",1); DXModSetObjectOutput(&modout[0],NULL,&o); if (!DXCallModule("ShowBoundary",2,modin,1,modout)) goto error; if (!parse_dx(o,index,mat,name,box)) goto error; } break; } default: DXSetError(ERROR_INVALID_DATA,"not recognized type class"); goto error; } return OK; error: return ERROR; } /* write out each solid object */ Error write_solid(Object dxobject,int triangle) { int i; Type type; int rank,shape[MAX_RANK]; Array a; int np; float *f; int *d; char *string; float angle; int sided; int itab=1; float op; /* constant color and opacity */ RGBColor *rgb; int pos_dim=3; float deltas[4]; rgb =NULL; op = -1; /* get positions array and check dimensionality */ a = (Array)DXGetComponentValue((Field)dxobject,"positions"); if (!DXGetArrayInfo(a,&np,&type,NULL,&rank,shape)) goto error; if (rank != 1 || shape[0] < 2){ DXSetError(ERROR_INVALID_DATA,"positions must be 3-d or 2-d\n"); goto error; } if (shape[0]==2){ pos_dim = 2; /* regular orthogonal 2-d grid use ElevationGrid node */ if (DXQueryGridPositions(a,NULL,NULL,NULL,deltas)){ if ((deltas[0]==0 || deltas[1]==0) || (deltas[2]==0 || deltas[3]==0)) return (write_elevation(dxobject)); } } /* what type of shape is it ? */ /* PointSet - no connections */ /* IndexedFaceSet - connections of quads or triangles */ /* IndexedLineSet - connections of lines */ fprintf(fp,"%s%s\n",tab[itab++],"Shape {"); if (triangle == 0) fprintf(fp,"%s%s \n",tab[itab++],"geometry PointSet {"); else if (triangle == 1) fprintf(fp,"%s%s \n",tab[itab++],"geometry IndexedLineSet {"); else{ fprintf(fp,"%s%s \n",tab[itab++],"geometry IndexedFaceSet {"); fprintf(fp,"%s%s \n",tab[itab],"solid FALSE"); if (triangle == 3) /* quads don't have counterclockwise connect */ fprintf(fp,"%s%s \n",tab[itab],"ccw FALSE"); } /* Write out the positions */ if (!write_positions(dxobject,itab,pos_dim)) goto error; /* Write out the connections */ if (triangle > 0 ){ if (!write_connections(dxobject,triangle,itab)) goto error; } /* Get colors and opacity info */ if (!write_colors(dxobject,itab,&rgb,&op)) goto error; /* Write out normals (normals should be unit length) */ if (triangle > 1 && !write_normals(dxobject,itab)) goto error; fprintf(fp,"%s}\n",tab[--itab]); /* geometry */ /* always write appearance node to get default lighting */ write_appearence(rgb,op,triangle,itab); fprintf(fp,"%s}\n",tab[--itab]); /* Shape */ done: return OK; error: return ERROR; } /* Write out the positions */ static Error write_positions(Object dxobject,int itab,int pos_dim) { int i; Array a; int np,rank,shape[MAX_RANK]; Type type; float *f; a = (Array)DXGetComponentValue((Field)dxobject,"positions"); if (!DXGetArrayInfo(a,&np,&type,NULL,&rank,shape)) goto error; fprintf(fp,"%s%s\n",tab[itab++],"coord Coordinate{ "); fprintf(fp,"%s%s\n",tab[itab++],"point [ "); f = (float *)DXGetArrayData(a); if (pos_dim == 2){ for (i=0; i opaque, 1.0-> transparent */ if ((a = (Array)DXGetComponentValue((Field)dxobject,"opacities"))){ if (DXGetArrayClass(a) != CLASS_CONSTANTARRAY){ if (!DXStatistics(dxobject,"opacities",NULL,NULL,op_avg,NULL)) goto error; *op_avg = 1.0 - *op_avg; } else{ op = (float *)DXGetConstantArrayData(a); *op_avg = 1.0 - op[0]; } } return OK; error: return ERROR; } /* Write out normals (normals should be unit length) */ static Error write_normals(Object dxobject, int itab) { Array a; int i; int np,rank,shape[MAX_RANK]; Type type; float *f; char *string; if ((a = (Array)DXGetComponentValue((Field)dxobject,"normals")) != NULL) { if (!DXGetArrayInfo(a,&np,&type,NULL,&rank,shape)) goto error; f = (float *)DXGetArrayData(a); fprintf(fp,"%s%s\n",tab[itab++],"normal Normal {"); fprintf(fp,"%s%s\n",tab[itab++],"vector ["); for (i=0; ir,rgb->g,rgb->b); if (lines == 1) { /* lines connections */ if (rgb) fprintf(fp,"%s%s %f %f %f\n",tab[itab],"emissiveColor",rgb->r,rgb->g,rgb->b); else fprintf(fp,"%s%s ",tab[itab],"emissiveColor 1 1 1"); } if (op >=0.0) fprintf(fp,"%s%s %f\n",tab[itab],"transparency",op); fprintf(fp,"%s}\n",tab[--itab]); /* Material */ fprintf(fp,"%s}\n",tab[--itab]); /* Appearance */ } /* find the initial viewpoint based on bounding box of object */ /* and a 45 degree field of view */ Error SetViewPoint(Object dxobject) { Point center; Point box[8]; double d,distance; if (DXBoundingBox(dxobject,box)) { d = DXLength(DXSub(box[3],box[4])); distance = 1.12 * .5*d/tan(.5*.785398); center.x = (box[4].x +box[3].x)/2; center.y = (box[4].y +box[3].y)/2; center.z = (box[4].z +box[3].z)/2; fprintf(fp,"%s\n","Viewpoint {"); fprintf(fp,"%s %g %g %g\n"," position",center.x,center.y,center.z+distance); fprintf(fp,"%s\n","}"); } return OK; } /* write out transformation matrix */ static int write_transform(Matrix mat,int *trans_two) { float angle,angle2; float sinhrot; Vector rotvec; Matrix mat_zx = {0,0,1,1,0,0,0,1,0}; Matrix mat_zy = {0,1,0,0,0,1,1,0,0}; /* what kind of transformation is it */ if (mat.A[0][1]==0 && mat.A[0][2]==0 && mat.A[1][0]==0 && mat.A[1][2]==0 && mat.A[2][0]==0 && mat.A[2][1]==0){ if (mat.b[0]==0 && mat.b[1]==0 && mat.b[2]==0){ if (mat.A[0][0]!=1 || mat.A[1][1]!=1 || mat.A[2][2]!=1){ /* scale */ fprintf(fp,"%s\n","Transform {"); fprintf(fp,"%s %f %f %f\n","scale",mat.A[0][0],mat.A[1][1],mat.A[2][2]); } else { /* identity */ *trans_two = -1; return 1; } } else { /* translation */ fprintf(fp,"%s\n","Transform {"); fprintf(fp,"%s %f %f %f\n","translation",mat.b[0],mat.b[1],mat.b[2]); } } else{ /* rotation */ DGetRotationOfMatrix(mat, rotvec, &sinhrot); fprintf(fp,"%s %g %g %g %g\n","# rot angle ",rotvec.x,rotvec.y,rotvec.z, 2.*asin((double)sinhrot)); if (mat.A[0][0]==1) { /* about the x-axis */ /* angle = acos(mat.A[1][1]); */ angle = asin(mat.A[1][2]); if (mat.A[1][1] >= 0) angle = angle; else { angle = 3.14159 - angle; fprintf(fp,"%s %g\n","# cos sin ",angle); } fprintf(fp,"%s\n","Transform {"); fprintf(fp,"%s %f\n","rotation 1 0 0",angle); } else if (mat.A[1][1]==1) { /* about the y-axis */ /* angle = acos(mat.A[0][0]); */ angle = -asin(mat.A[0][2]); if (mat.A[0][0] >= 0) angle = angle; else { angle = 3.14159 - angle; fprintf(fp,"%s %g\n","# cos sin ",angle); } fprintf(fp,"%s\n","Transform {"); fprintf(fp,"%s %f\n","rotation 0 1 0",angle); } else if (mat.A[2][2]==1) { /* about the z-axis */ /* angle = acos(mat.A[0][0]); */ angle = asin(mat.A[0][1]); if (mat.A[0][0] >= 0) angle = angle; else { angle = 3.14159 - angle; fprintf(fp,"%s %g\n","# cos sin ",angle); } fprintf(fp,"%s\n","Transform {"); fprintf(fp,"%s %f\n","rotation 0 0 1",angle); } else { /* special case check for permutations (AutoAxes uses these) */ if(mat.A[0][1] == 1){ if (mat.A[1][2]==1 && mat.A[2][0]==1 && mat.A[0][0]==0 && mat.A[0][2]==0 && mat.A[1][0]==0 && mat.A[1][1]==0 && mat.A[2][1]==0 && mat.A[2][2]==0){ fprintf(fp,"%s\n","Transform {"); fprintf(fp,"%s\n","rotation 0 1 0 1.57"); fprintf(fp,"%s\n"," children["); fprintf(fp,"%s\n","Transform {"); fprintf(fp,"%s\n","rotation 0 0 1 1.57"); *trans_two=1; } else return 0; } else if (mat.A[0][2]==1){ if (mat.A[1][0]==1 && mat.A[2][1]==1 && mat.A[0][0]==0 && mat.A[0][1]==0 && mat.A[1][1]==0 && mat.A[1][2]==0 && mat.A[2][0]==0 && mat.A[2][2]==0){ fprintf(fp,"%s\n","Transform {"); fprintf(fp,"%s\n","rotation 1 0 0 -1.57"); fprintf(fp,"%s\n"," children["); fprintf(fp,"%s\n","Transform {"); fprintf(fp,"%s\n","rotation 0 0 1 -1.57"); *trans_two=1; } else return 0; } else return 0; /* not a simple translation,rotation,scale */ } } fprintf(fp,"%s\n"," children ["); /* check for translation */ /* if (mat.b[0]==0 && mat.b[1]==0 && mat.b[2]==0){ fprintf(fp,"%s\n","Transform {"); fprintf(fp,"%s %f %f %f\n","translation",mat.b[0],mat.b[1],mat.b[2]); fprintf(fp,"%s\n"," children ["); *trans_two = 1; } */ return 1; } /* Use the Text Node and ProximitySensor to create a caption that */ /* is fixed in the screen */ static Error write_caption(Object dxobject,Point *box) { int i=0,itab=1; Point center; float *pos; char *string; Object o,o1; float *rgb; /* constant color */ Array a; rgb = NULL; /* is there a colors component (if so is always a constant array) */ if (!DXGetScreenInfo((Screen)dxobject,&o,NULL,NULL)) goto error; if (!DXGetXformInfo((Xform)o,&o1,NULL)) goto error; if ((o=DXGetEnumeratedMember((Group)o1,0,NULL))==NULL) goto error; if (!DXGetScreenInfo((Screen)o,&o1,NULL,NULL)) goto error; if (!DXGetXformInfo((Xform)o1,&o,NULL)) goto error; if ((a = (Array)DXGetComponentValue((Field)o,"colors"))) rgb = (float *)DXGetConstantArrayData(a); if (DXGetIntegerAttribute((Object)dxobject,"Caption flag",&i) && i != 0){ DXWarning("VRML export can only have captions that are viewport relative"); pos[0] = 0.5; pos[1] = 0.05; } o = DXGetAttribute((Object)dxobject,"Caption position"); pos = (float *)DXGetArrayData((Array)o); o = DXGetAttribute((Object)dxobject,"Caption string"); /* Calculate the Transformation needed to place the caption at position */ /* I have fixed the translation in z so size of caption is done by */ /* font size parameter */ center.x = pos[0] * 0.2 -0.1; center.y = pos[1] * 0.12 -0.06; center.z = -0.15; fprintf(fp,"%s%s\n",tab[itab++],"DEF HudGroup Collision {"); fprintf(fp,"%s%s\n",tab[itab],"collide FALSE"); fprintf(fp,"%s%s\n",tab[itab++],"children ["); fprintf(fp,"%s%s\n",tab[itab++],"DEF HudProx ProximitySensor {"); fprintf(fp,"%s%s\n",tab[itab],"center 0 20 0"); fprintf(fp,"%s%s\n",tab[itab],"size 500 500 500"); fprintf(fp,"%s%s\n",tab[--itab],"}"); fprintf(fp,"%s%s\n",tab[itab++],"DEF HudXform Transform {"); fprintf(fp,"%s%s\n",tab[itab++],"children ["); fprintf(fp,"%s%s\n",tab[itab++],"Transform {"); fprintf(fp,"%s%s %g %g %g\n",tab[itab],"translation",center.x,center.y,center.z); fprintf(fp,"%s%s\n",tab[itab++],"children ["); fprintf(fp,"%s%s\n",tab[itab++],"Shape {"); fprintf(fp,"%s%s\n",tab[itab++],"geometry Text {"); fprintf(fp,"%s%s", tab[itab],"string ["); while (DXExtractNthString(o,i++,&string)) fprintf(fp,"\"%s\"",string); fprintf(fp,"%s\n","]"); if (DXGetStringAttribute((Object)dxobject,"VRML FontStyle",&string)) fprintf(fp,"%s%s%s%s\n",tab[itab],"fontStyle FontStyle {",string," }"); else { fprintf(fp,"%s%s\n",tab[itab],"fontStyle FontStyle {size .01"); fprintf(fp,"%s%s\n",tab[itab], "justify [\"MIDDLE\" \"MIDDLE\"] }"); } fprintf(fp,"%s%s\n",tab[--itab],"}"); /* Text */ fprintf(fp,"%s%s\n",tab[itab++],"appearance Appearance {"); fprintf(fp,"%s%s\n",tab[itab],"material Material {"); if (rgb){ fprintf(fp,"%s%s %g %g %g\n",tab[itab],"diffuseColor",rgb[0],rgb[1],rgb[2]); fprintf(fp,"%s%s %g %g %g\n",tab[itab],"emissiveColor",rgb[0],rgb[1],rgb[2]); } else fprintf(fp,"%s%s\n",tab[itab],"emissiveColor 1 1 1"); fprintf(fp,"%s%s\n",tab[itab],"}"); /* Material */ fprintf(fp,"%s%s\n",tab[--itab],"}"); /* Appearance */ fprintf(fp,"%s%s\n",tab[--itab],"}"); /* Shape */ fprintf(fp,"%s%s\n",tab[itab],"]"); /* children */ fprintf(fp,"%s%s\n",tab[--itab],"}"); /* Transform */ fprintf(fp,"%s%s\n",tab[--itab],"]"); /* children */ fprintf(fp,"%s%s\n",tab[--itab],"}"); /* Transform */ fprintf(fp,"%s%s\n",tab[--itab],"]"); /* children */ fprintf(fp,"%s%s\n",tab[itab],"ROUTE HudProx.orientation_changed TO HudXform.rotation"); fprintf(fp,"%s%s\n",tab[itab],"ROUTE HudProx.position_changed TO HudXform.translation"); fprintf(fp,"%s%s\n",tab[--itab],"}"); /* collision */ return OK; error: return ERROR; } static Error write_text(Object dxobject) { char *string; float *rgb; Array a; int itab = 1; Point box[8]; Point center; /* Use bounding box to get position of Text */ /* DXBoundingBox(dxobject,box); center.x = (box[4].x +box[3].x)/2; center.y = (box[4].y +box[3].y)/2; center.z = (box[4].z +box[3].z)/2; fprintf(fp,"%s%s\n",tab[itab++],"Transform {"); fprintf(fp,"%s%s %g %g %g\n",tab[itab],"translation",center.x,center.y,center.z); fprintf(fp,"%s%s\n",tab[itab++],"children ["); */ fprintf(fp,"%s%s\n",tab[itab++],"Shape {"); fprintf(fp,"%s%s\n",tab[itab++],"geometry Text {"); fprintf(fp,"%s%s", tab[itab],"string ["); DXGetStringAttribute((Object)dxobject,"Text string",&string); fprintf(fp,"\"%s\"",string); fprintf(fp,"%s\n","]"); if (DXGetStringAttribute((Object)dxobject,"VRML FontStyle",&string)) fprintf(fp,"%s%s%s%s\n",tab[itab],"fontStyle FontStyle {",string," }"); else if (&fontstyle != NULL) fprintf(fp,"%s%s%s%s\n",tab[itab],"fontStyle FontStyle {",fontstyle," }"); else fprintf(fp,"%s%s\n",tab[itab],"fontStyle FontStyle {size 1.25}"); fprintf(fp,"%s%s\n",tab[--itab],"}"); /* Text */ fprintf(fp,"%s%s\n",tab[itab++],"appearance Appearance {"); fprintf(fp,"%s%s\n",tab[itab],"material Material {"); if ((a = (Array)DXGetComponentValue((Field)dxobject,"colors"))){ rgb = (float *)DXGetArrayData(a); fprintf(fp,"%s%s %g %g %g\n",tab[itab],"diffuseColor",rgb[0],rgb[1],rgb[2]); fprintf(fp,"%s%s %g %g %g\n",tab[itab],"emissiveColor",rgb[0],rgb[1],rgb[2]); } else fprintf(fp,"%s%s\n",tab[itab],"emissiveColor 1 1 1"); fprintf(fp,"%s%s\n",tab[itab],"}"); /* Material */ fprintf(fp,"%s%s\n",tab[--itab],"}"); /* Appearance */ fprintf(fp,"%s%s\n",tab[--itab],"}"); /* Shape */ /* fprintf(fp,"%s%s\n",tab[--itab],"]"); fprintf(fp,"%s%s\n",tab[--itab],"}"); */ return OK; } void DGetRotationOfMatrix(Matrix mat, Vector rotvec, float *sinhrot) { /* Double precision version of GetRotationOfMatrix. */ /* Input: pointer to mat = rotation/transl (no scaling) matrix */ /* Output: pointer to rotvec = rotation unit vector */ /* pointer to sinhrot = sine of rotation half-angle */ int i, j, imax1, imax2; float rows[3][3],rowmag[3]; Vector tanvec, cenvec, sensvec, maxaxis; float maxmag, minmag; Vector row_max,row_med,mat_max; /* Find the row of (mat - identity) whose magnitude is maximum, and */ /* similarly for minimum. The latter is to get the median row by */ /* the process of elimination. */ for(i = 0; i < 3; i++) { float amag = (float)sqrt(mat.A[i][0]*mat.A[i][0] + mat.A[i][1]*mat.A[i][1] + mat.A[i][2]*mat.A[i][2]); rowmag[i] = 0.; for(j = 0; j < 3; j++) { rows[i][j] = mat.A[i][j]/amag - (float)(i == j); rowmag[i] += rows[i][j]*rows[i][j]; } rowmag[i] = (float)sqrt(rowmag[i]); if(!i || rowmag[i] > maxmag) { maxmag = rowmag[i]; imax1 = i; } if(!i || rowmag[i] < minmag) { minmag = rowmag[i]; imax2 = i; } } /* If all changes are the same, complement one of the indices. */ if(imax1 == imax2) imax2 = 2 - imax1; if(maxmag < 1.e-14) { /* There is no rotation. Return a vector along z with zero */ /* rotation (sine = 0). */ rotvec.x = rotvec.y = *sinhrot = 0.; rotvec.z = 1.; return; } /* With min and max rows in hand, median row is only one left. */ /* Find it from the fact that the sum of indices = 3. */ imax2 = 3 - imax1 - imax2; row_max.x = rows[imax1][0]; row_max.y = rows[imax1][1]; row_max.z = rows[imax1][2]; row_med.x = rows[imax2][0]; row_med.y = rows[imax2][1]; row_med.z = rows[imax2][2]; mat_max.x = mat.A[imax1][0]; mat_max.y = mat.A[imax1][1]; mat_max.z = mat.A[imax1][2]; /* Cross the max row with the second max row and unitize to get the */ /* rotation unit vector. */ rotvec = DXNormalize(DXCross(row_max,row_med)); /* Determine which direction it should point (backward or not) */ /* by forcing it to lie in the same hemisphere as the cross product */ /* of the axis vector corresponding to max row and its change. */ /* That product establishes the right-handedness of the rotation. */ sensvec = DXCross(mat_max, row_max); if(DXDot(rotvec, sensvec) < 0.) rotvec = DXNeg(rotvec); /* Cross rotation vector into axis vector corresponding to max */ /* row, and unitize to get direction of axis tip motion at */ /* beginning of rotation (i. e. initial tangent). */ maxaxis.x=maxaxis.y=maxaxis.z=0.; if (imax1 == 0) maxaxis.x=1.; else if (imax1 == 1) maxaxis.y=1.; else maxaxis.z=1.; tanvec = DXNormalize(DXCross(rotvec, maxaxis)); /* Cross rotation unit vector into that initial tangent vector */ /* to get corresponding centripetal vector. */ cenvec = DXCross(rotvec, tanvec); /* The centripetal component (dot product with centripetal unit */ /* of unitized max row is sine of half-rotation angle. */ row_max = DXNormalize(row_max); *sinhrot = DXDot(row_max, cenvec); }