/*****************************************************************************1*2* Elmer, A Finite Element Software for Multiphysical Problems3*4* Copyright 1st April 1995 - , CSC - IT Center for Science Ltd., Finland5*6* This program is free software; you can redistribute it and/or7* modify it under the terms of the GNU General Public License8* as published by the Free Software Foundation; either version 29* of the License, or (at your option) any later version.10*11* This program is distributed in the hope that it will be useful,12* but WITHOUT ANY WARRANTY; without even the implied warranty of13* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the14* GNU General Public License for more details.15*16* You should have received a copy of the GNU General Public License17* along with this program (in file fem/GPL-2); if not, write to the18* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,19* Boston, MA 02110-1301, USA.20*21*****************************************************************************/2223/*******************************************************************************24*25* Object transformations26*27*******************************************************************************28*29* Author: Juha Ruokolainen30*31* Address: CSC - IT Center for Science Ltd.32* Keilaranta 14, P.O. BOX 40533* 02101 Espoo, Finland34* Tel. +358 0 457 272335* Telefax: +358 0 457 230236* EMail: [email protected]37*38* Date: 1 Oct 199539*40******************************************************************************/4142#include "../elmerpost.h"4344/*******************************************************************************45*46* Name: obj_init_matrix( matrix_t )47*48* Purpose: Set given transformation matrix to unit matrix.49* Internal only.50*51* Parameters:52*53* Input: none54*55* Output: (matrix_t) matrix to set56*57* Return value: void58*59******************************************************************************/60static void obj_init_matrix( matrix_t matrix )61{62memset( matrix,0, sizeof(matrix_t) );6364matrix[0][0] = matrix[1][1] =65matrix[2][2] = matrix[3][3] = 1.0;66}6768/*******************************************************************************69*70* Name: obj_init_transform( transform_t * )71*72* Purpose: Initialize given transform_t structure.73* Internal only.74*75* Parameters:76*77* Input: none78*79* Output: (transform_t *)80*81* Return value: void82*83******************************************************************************/84void obj_init_transform( transform_t *transform )85{86transform->RotX = transform->RotY = transform->RotZ = 0.0;87transform->TrnX = transform->TrnY = transform->TrnZ = 0.0;88transform->SclX = transform->SclY = transform->SclZ = 1.0;8990transform->TransformPriority = trn_pri_str;91transform->RotationPriority = rot_pri_xyz;9293obj_init_matrix( transform->Matrix );9495obj_init_matrix( transform->RotMatrix );96obj_init_matrix( transform->SclMatrix );97obj_init_matrix( transform->TrnMatrix );98}99100/*******************************************************************************101*102* Name: obj_get_matrix( matrix_t, object_t * )103*104* Purpose: Return objects transformation matrix given105* (object_t *) structure.106*107* Parameters:108*109* Input: (object_t *)110*111* Output: (matrix_t)112*113* Return value: void114*115******************************************************************************/116void obj_get_matrix(matrix_t matrix,object_t *object)117{118transform_t *transform = &object->Transform;119120memcpy( matrix,transform->Matrix,sizeof(matrix_t) );121}122123/*******************************************************************************124*125* Name: obj_get_matrix_transpose( matrix_t, object_t * )126*127* Purpose: Return transpose of objects transformation matrix given128* (object_t *) structure.129*130* Parameters:131*132* Input: (object_t *)133*134* Output: (matrix_t)135*136* Return value: void137*138******************************************************************************/139void obj_get_matrix_transpose( matrix_t matrix,object_t *object )140{141transform_t *transform = &object->Transform;142int i,j;143144for( i=0; i<4; i++ )145for( j=0; j<4; j++ ) matrix[j][i] = transform->Matrix[i][j];146}147148/*******************************************************************************149*150* Name: obj_copy_matrix( matrix_t A, matrix_t B)151*152* Purpose: Copy matrix A to matrix B153*154* Parameters:155*156* Input: (matrix_t)157*158* Output: (matrix_t)159*160* Return value: void161*162******************************************************************************/163static void obj_copy_matrix( matrix_t A,matrix_t B )164{165memcpy( A,B,sizeof(matrix_t) );166}167168/*******************************************************************************169*170* Name: obj_mult_matrix( matrix_t A, matrix_t B)171* obj_mult_matrix_left( matrix_t A, matrix_t B)172*173* Purpose: return A = A*B. Internal only.174*175* Parameters:176*177* Input: (matrix_t)A, (matrix_t)B178*179* Output: (matrix_t)A180*181* Return value: void182*183******************************************************************************/184#define obj_mult_matrix( A, B ) obj_mult_matrix_left( A,B )185static void obj_mult_matrix_left( matrix_t A,matrix_t B )186{187matrix_t R;188double s;189int i,j,k;190191for( i=0; i<4; i++ )192for( j=0; j<4; j++ )193{194s = 0.0;195for( k=0; k<4; k++ ) s += A[i][k]*B[k][j];196R[i][j] = s;197}198199obj_copy_matrix( A,R );200}201202/*******************************************************************************203*204* Name: obj_mult_matrix_right( matrix_t A, matrix_t B)205*206* Purpose: return A = B*A. Internal only.207*208* Parameters:209*210* Input: (matrix_t)A, (matrix_t)B211*212* Output: (matrix_t)A213*214* Return value: void215*216******************************************************************************/217static void obj_mult_matrix_right( matrix_t A,matrix_t B )218{219matrix_t R;220double s;221int i,j,k;222223for( i=0; i<4; i++ )224for( j=0; j<4; j++ )225{226s = 0.0;227for( k=0; k<4; k++ ) s += B[i][k]*A[k][j];228R[i][j] = s;229}230231obj_copy_matrix( A,R );232}233234/*******************************************************************************235*236* Name: obj_translate_matrix( matrix_t,double,double,double )237*238* Purpose: return matrix_t corresponding to translations x,y,z239* Internal only.240*241* Parameters:242*243* Input: (double,double,double) translations x,y,and z244*245* Output: (matrix_t) resulting transformation matrix246*247* Return value: void248*249******************************************************************************/250static void obj_translate_matrix( matrix_t M, double x, double y, double z )251{252int i;253254obj_init_matrix( M );255256M[0][3] = x;257M[1][3] = y;258M[2][3] = z;259/*260* for( i=0; i<4; i++ )261* {262* M[0][i] += x*M[3][i];263* M[1][i] += y*M[3][i];264* M[2][i] += z*M[3][i];265* }266*/267}268269/*******************************************************************************270*271* Name: obj_scale_matrix( matrix_t,double,double,double )272*273* Purpose: return matrix_t corresponding to scalings x,y,z274* Internal only.275*276* Parameters:277*278* Input: (double,double,double) scalings x,y,and z279*280* Output: (matrix_t) resulting transformation matrix281*282* Return value: void283*284******************************************************************************/285static void obj_scale_matrix( matrix_t M,double x, double y, double z )286{287int i;288289obj_init_matrix( M );290291M[0][0] = x;292M[1][1] = y;293M[2][2] = z;294/*295* for( i=0; i<4; i++ )296* {297* M[0][i] *= x;298* M[1][i] *= y;299* M[2][i] *= z;300* }301*/302}303304/*******************************************************************************305*306* Name: obj_internal_rotate_matrix( matrix_t,double,double,int )307*308* Purpose: return matrix_t corresponding to rotation about axis309* given, by amount given in sin(a), cos(a).310* Internal only.311*312* Parameters:313*314* Input: (double) sine of the angle to rotate315* (double) cosine of the angle to rotate316* (int) axis about which to rotate:317* x: axis = 0, y: axis = 1, z: axis = 2318*319* Output: (matrix_t) resulting transformation matrix320*321* Return value: void322*323******************************************************************************/324static void obj_internal_rotate_matrix( matrix_t M,double s, double c, int axis )325{326double t;327int i;328329switch( axis )330{331case 0: for( i=0; i<4; i++ )332{333t = M[1][i];334M[1][i] = c*t - s*M[2][i];335M[2][i] = c*M[2][i] + s*t;336}337break;338339case 1: for( i=0; i<4; i++ )340{341t = M[0][i];342M[0][i] = c*t + s*M[2][i];343M[2][i] = c*M[2][i] - s*t;344}345break;346347case 2: for( i=0; i<4; i++ )348{349t = M[0][i];350M[0][i] = c*t - s*M[1][i];351M[1][i] = c*M[1][i] + s*t;352}353break;354}355}356357/*******************************************************************************358*359* Name: obj_set_rotation_priority( object_t *,rot_pri_t )360*361* Purpose: set rotation priority for an object given362*363* Parameters:364*365* Input: (rot_pri_t) rotation priority, one of:366*367* rot_pri_xyz368* rot_pri_xzy369* rot_pri_yxz370* rot_pri_yzx371* rot_pri_zxy372* rot_pri_zyx373*374* Output: (object_t *) is modified375*376* Return value: void377*378******************************************************************************/379void obj_set_rotation_priority( object_t *object, rot_pri_t priority)380{381object->Transform.RotationPriority = priority;382}383384/*******************************************************************************385*386* Name: obj_set_transform_priority( object_t *, trn_pri_t )387*388* Purpose: set transformation priority for an object given389*390* Parameters:391*392* Input: (trn_pri_t) transformation priority, one of:393*394* trn_pri_trs395* trn_pri_tsr396* trn_pri_rts397* trn_pri_rst398* trn_pri_str399* trn_pri_srt400*401* Output: (object_t *) is modified402*403* Return value: void404*405******************************************************************************/406void obj_set_transform_priority( object_t *object, trn_pri_t priority)407{408object->Transform.TransformPriority = priority;409}410411/*******************************************************************************412*413* Name: obj_rotate_matrix( matrix_t,rot_pri_t,double,double,double )414*415* Purpose: return matrix_t corresponding to rotation about416* three axes by angles given. Internal only.417*418* Parameters:419*420* Input: (rot_pri_t) rotation priority, one of:421*422* rot_pri_xyz423* rot_pri_xzy424* rot_pri_yxz425* rot_pri_yzx426* rot_pri_zxy427* rot_pri_zyx428*429* (double) angle about 'x' - axis430* (double) angle about 'y' - axis431* (double) angle about 'z' - axis432*433* Output: (matrix_t) resulting transformation matrix434*435* Return value: void436*437******************************************************************************/438static void obj_rotate_matrix( matrix_t M,rot_pri_t rot_pri,double x,double y,double z )439{440int i,j,axis,a_ord[3];441double a;442matrix_t N,P;443444obj_init_matrix( M );445446switch( rot_pri )447{448case rot_pri_xyz: a_ord[0]=0; a_ord[1]=1; a_ord[2]=2; break;449case rot_pri_xzy: a_ord[0]=0; a_ord[1]=2; a_ord[2]=1; break;450case rot_pri_yxz: a_ord[0]=1; a_ord[1]=0; a_ord[2]=2; break;451case rot_pri_yzx: a_ord[0]=1; a_ord[1]=2; a_ord[2]=0; break;452case rot_pri_zxy: a_ord[0]=2; a_ord[1]=0; a_ord[2]=1; break;453case rot_pri_zyx: a_ord[0]=2; a_ord[1]=1; a_ord[2]=0; break;454}455456for( i=0; i<3; i++ )457{458axis = a_ord[i];459switch(axis)460{461case 0: a = x; break;462case 1: a = y; break;463case 2: a = z; break;464}465a *= PiDiv180;466467obj_init_matrix( N );468obj_internal_rotate_matrix( N,sin(a),cos(a),axis );469470obj_mult_matrix_right( M,N );471}472}473474/*******************************************************************************475*476* Name: obj_rotate_mult_matrix( transform_t *,double *,double *,double *)477*478* Purpose: return matrix_t corresponding to rotation about479* three axes by angles given multiplied by objects480* transformation matrix. Internal only.481*482* Parameters:483*484* Input: (transform_t *)485*486* (double *) angle about 'x' - axis487* (double *) angle about 'y' - axis488* (double *) angle about 'z' - axis489*490* Output: (transform_t *)->RotMatrix is modified as are the491* angles.492*493* Return value: void494*495******************************************************************************/496#define ROUND_PI(A) (180*(int)(((A)>0?(A)+90.0:(A)-90.0)/180.0))497498static void obj_rotate_mult_matrix(transform_t *transform,double *x,double *y,double *z )499{500matrix_t M;501502int i,j;503double a;504505for( i=0; i<3; i++ )506{507switch(i)508{509case 0: a = *x; break;510case 1: a = *y; break;511case 2: a = *z; break;512}513a *= PiDiv180;514515obj_init_matrix( M );516obj_internal_rotate_matrix( M,sin(a),cos(a),i );517518if ( transform->RotationPriority == rot_pri_local )519{520obj_mult_matrix_left( transform->RotMatrix,M );521} else if ( transform->RotationPriority == rot_pri_parent )522{523obj_mult_matrix_right( transform->RotMatrix,M );524}525}526527obj_copy_matrix( M,transform->RotMatrix );528529*x = atan2( M[2][1],M[2][2] ) / PiDiv180;530*y = -asin( M[2][0] )/ PiDiv180;531*z = atan2( M[1][0],M[0][0] ) / PiDiv180;532533*x += ROUND_PI( transform->RotX - *x );534*y += ROUND_PI( transform->RotY - *y );535*z += ROUND_PI( transform->RotZ - *z );536}537538/*******************************************************************************539*540* Name: obj_compute_matrix( transform_t * )541*542* Purpose: Return total transformation matrix_t given rotations,543* scaling, and translations. Internal only.544*545* Parameters:546*547* Input: (transform_t *)548*549* Output: (transform_t *)->Matrix is modified550*551* Return value: void552*553******************************************************************************/554static void obj_compute_matrix( transform_t *transform )555{556transform_list_t *child;557558matrix_t M;559560obj_init_matrix( M );561562switch( transform->TransformPriority )563{564case trn_pri_trs: obj_mult_matrix( M,transform->TrnMatrix );565obj_mult_matrix( M,transform->RotMatrix );566obj_mult_matrix( M,transform->SclMatrix );567break;568569case trn_pri_tsr: obj_mult_matrix( M,transform->TrnMatrix );570obj_mult_matrix( M,transform->SclMatrix );571obj_mult_matrix( M,transform->RotMatrix );572break;573574case trn_pri_rts: obj_mult_matrix( M,transform->RotMatrix );575obj_mult_matrix( M,transform->TrnMatrix );576obj_mult_matrix( M,transform->SclMatrix );577break;578579case trn_pri_rst: obj_mult_matrix( M,transform->RotMatrix );580obj_mult_matrix( M,transform->SclMatrix );581obj_mult_matrix( M,transform->TrnMatrix );582break;583584case trn_pri_str: obj_mult_matrix( M,transform->SclMatrix );585obj_mult_matrix( M,transform->TrnMatrix );586obj_mult_matrix( M,transform->RotMatrix );587break;588589case trn_pri_srt: obj_mult_matrix( M,transform->SclMatrix );590obj_mult_matrix( M,transform->RotMatrix );591obj_mult_matrix( M,transform->TrnMatrix );592break;593}594595if ( transform->Parent && transform->Parent != transform )596{597memcpy( transform->Matrix, transform->Parent->Matrix, sizeof(matrix_t) );598obj_mult_matrix( transform->Matrix,M );599} else600{601obj_copy_matrix( transform->Matrix,M );602}603604for( child = transform->Children; child != NULL; child = child->Next )605{606obj_compute_matrix( child->Entry );607}608}609610611/*******************************************************************************612*613* Name: obj_set_parent( object_t *obj, object_t *parent )614*615* Purpose: Set transformation parent of an object616*617* Parameters:618*619* Input: both structures are read620*621* Output: both structures are modified622*623* Return value: malloc() success624*625******************************************************************************/626int obj_set_parent( object_t *object,object_t *parent )627{628transform_t *objtrans = &object->Transform;629transform_t *partrans = &parent->Transform;630631transform_list_t *child;632633if ( object == parent ) return TRUE;634635objtrans->Parent = partrans;636637if ( !(child = (transform_list_t *)calloc(1,sizeof(transform_list_t)) ) )638{639fprintf( stderr, "obj_set_parent: FATAL: can't allocate a few bytes of memory.\n" );640return FALSE;641}642643child->Entry = objtrans;644child->Next = partrans->Children;645646partrans->Children = child;647648obj_compute_matrix( objtrans );649650return TRUE;651}652653/*******************************************************************************654*655* Name: obj_rotate( object_t *,double,double,double,int,int )656*657* Purpose: Modify object transformation matrix given rotations658*659* Parameters:660*661* Input: (object_t *)662* (double,double,double) input rotations663* (int) flag if rotations should be relative (TRUE)664* or absolute (FALSE)665*666* Output: (object->Transform_t *)->XXXMatrix are modified667*668* Return value: void669*670******************************************************************************/671void obj_rotate( object_t *object,double x,double y,double z,int which,int relative )672{673double rx,ry,rz;674675transform_t *transform = &object->Transform;676677switch( which )678{679case 'x': if ( transform->RotationPriority < rot_pri_local )680{681if ( relative ) x += transform->RotX;682y = transform->RotY;683z = transform->RotZ;684} else685{686if ( !relative )687{688x -= transform->RotX;689}690y = z = 0.0;691}692break;693694case 'y': if ( transform->RotationPriority < rot_pri_local )695{696if ( relative ) y = x + transform->RotY; else y = x;697x = transform->RotX;698z = transform->RotZ;699} else700{701if ( relative )702{703y = x;704} else705{706y = x - transform->RotY;707}708x = z = 0.0;709}710break;711712case 'z': if ( transform->RotationPriority < rot_pri_local )713{714if ( relative ) z = x + transform->RotZ; else z = x;715x = transform->RotX;716y = transform->RotY;717} else718{719if ( relative )720{721z = x;722} else723{724z = x - transform->RotZ;725}726x = y = 0.0;727}728break;729730case 'a': if ( transform->RotationPriority < rot_pri_local )731{732if ( relative )733{734x += transform->RotX;735y += transform->RotY;736z += transform->RotZ;737}738} else739{740if ( !relative ) obj_init_matrix( transform->RotMatrix );741}742break;743}744745if ( transform->RotationPriority >= rot_pri_local )746{747obj_rotate_mult_matrix( transform,&x,&y,&z );748} else749{750obj_rotate_matrix( transform->RotMatrix,transform->RotationPriority,x,y,z );751}752753transform->RotX = x;754transform->RotY = y;755transform->RotZ = z;756757obj_compute_matrix( transform );758}759760/*******************************************************************************761*762* Name: obj_scale( object_t *,double,double,double,int,int )763*764* Purpose: Modify object transformation matrix given scalings765*766* Parameters:767*768* Input: (object_t *)769* (double,double,double) input scalings770* (int) flag if scalings should be relative (TRUE)771* or absolute (FALSE)772*773* Output: (object->Transform_t *)->XXXMatrix are modified774*775* Return value: void776*777******************************************************************************/778void obj_scale( object_t *object,double x,double y,double z,int which, int relative )779{780transform_t *transform = &object->Transform;781double s;782783if ( relative )784{785switch( which )786{787case 's': s = 1+x;788x = s*transform->SclX;789y = s*transform->SclY;790z = s*transform->SclZ;791break;792793case 'x': x = (1+x)*transform->SclX; break;794case 'y': y = (1+x)*transform->SclY; break;795case 'z': z = (1+x)*transform->SclZ; break;796797case 'a': x = (1+x)*transform->SclX;798y = (1+y)*transform->SclY;799z = (1+z)*transform->SclZ;800break;801}802}803804if ( x > 0 )805{806x = MAX(x, 1.0e-6);807} else {808x = MIN(x,-1.0e-6);809}810811if ( y > 0 )812{813y = MAX(y, 1.0e-6);814} else {815y = MIN(y,-1.0e-6);816}817818if ( z > 0 )819{820z = MAX(z, 1.0e-6);821} else {822z = MIN(z,-1.0e-6);823}824825switch( which )826{827case 'a': transform->SclX = x;828transform->SclY = y;829transform->SclZ = z;830break;831832case 'x': transform->SclX = x; break;833case 'y': transform->SclY = y; break;834case 'z': transform->SclZ = z; break;835}836837obj_scale_matrix(838transform->SclMatrix,839transform->SclX, transform->SclY, transform->SclZ840);841842obj_compute_matrix( transform );843}844845/*******************************************************************************846*847* Name: obj_translate( object_t *,double,double,double,int,int )848*849* Purpose: Modify object transformation matrix given translations850*851* Parameters:852*853* Input: (object_t *)854* (double,double,double) input translations855* (int) flag if translations should be relative (TRUE)856* or absolute (FALSE)857*858* Output: (object->Transform_t *)->XXXMatrix are modified859*860* Return value: void861*862******************************************************************************/863void obj_translate( object_t *object,double x,double y,double z,int which,int relative )864{865transform_t *transform = &object->Transform;866867switch( which )868{869case 'x': transform->TrnX = (relative?transform->TrnX:0.0)+x; break;870case 'y': transform->TrnY = (relative?transform->TrnY:0.0)+x; break;871case 'z': transform->TrnZ = (relative?transform->TrnZ:0.0)+x; break;872case 'a': if ( relative )873{874transform->TrnX += x;875transform->TrnY += y;876transform->TrnZ += z;877} else878{879transform->TrnX = x;880transform->TrnY = y;881transform->TrnZ = z;882}883break;884}885886obj_translate_matrix(887transform->TrnMatrix,888transform->TrnX, transform->TrnY, transform->TrnZ889);890891obj_compute_matrix( transform );892}893894/*******************************************************************************895*896* Name: obj_set_matrix( object_t * )897*898* Purpose: Tell graphics module about transformation matrix of899* a given object900*901* Parameters:902*903* Input: (object_t *)904*905* Output: none906*907* Return value: void908*909******************************************************************************/910void obj_set_matrix( object_t *object )911{912transform_t *transform = &object->Transform;913matrix_t matrix;914915obj_get_matrix_transpose( matrix,object );916917gra_mult_matrix( matrix );918}919920921