Documentation


SFVec3fCellConstrained.cpp

Go to the documentation of this file.
00001 
00002 #include "SFVec3fCellConstrained.h"
00003 #include "assertions.h"
00004 #include "ConstrainedVertex.h"
00005 
00006 
00007 
00008 namespace animal
00009 {
00010 namespace octree
00011 {
00012 
00018  Vec3d getNewParametersInCell( Vec3d vParams, Vec3d originalParams, unsigned int diffDepth )
00019  {
00020     FloatingPointType scale = 1.0;
00021     if( diffDepth != 0 )
00022     {
00023         scale /= 2<<(diffDepth-1);
00024     }
00025     return vParams + originalParams*scale;
00026  }
00027  
00032 Vec3d getParametersInFrame( Vec3d params, unsigned short vId )
00033 {
00034     return Vec3d( LINEARFACTORALPHA(vId,params[0]), LINEARFACTORBETA(vId,params[1]), LINEARFACTORGAMMA(vId,params[2]) );
00035 }
00036 
00037 
00038 
00039 
00040 
00041 
00042 
00043 
00044 SFVec3fCellConstrained::SFVec3fCellConstrained( X3DTK::SFVec3f *q, Cell* cell, int vertexID, X3DTK::SFVec3f normal ) :
00045     _vec(q), _cell(cell), _vertexID(vertexID)
00046 {
00047     computeParameters();
00048     
00049     _normal = Vec3d( normal[0], normal[1], normal[2] );
00050     
00051     _alphaNormal = _alpha + normal[0] / 100.0;
00052     _betaNormal = _beta + normal[1] / 100.0;
00053     _gammaNormal = _gamma + normal[2] / 100.0;
00054     
00055     for( unsigned short i=0 ; i<8 ; ++i )
00056     {
00057         // Set the parameters in each of our depending vertex, the 8 vertices of the cell
00058         Vec3d w = getParameters(i);
00059         setRelativeWeight( _cell->vertex(i), computeWeight( w, LINEAR ) );
00060         setRelativePosition( _cell->vertex(i), w );
00061     }
00062 }
00063 
00064 SFVec3fCellConstrained::SFVec3fCellConstrained( X3DTK::SFVec3f *q, Cell* cell, Vec3d params, int vertexID, Vec3d normal ) :
00065     _vec(q), _cell(cell), _normal(normal), _vertexID(vertexID)
00066 {
00067     _alpha = params[0];
00068     _beta = params[1];
00069     _gamma = params[2];
00070     
00071     _alphaNormal = _alpha + normal[0] / 100.0;
00072     _betaNormal = _beta + normal[1] / 100.0;
00073     _gammaNormal = _gamma + normal[2] / 100.0;  
00074 }
00075     
00076 SFVec3fCellConstrained::~SFVec3fCellConstrained( )
00077 {
00078 }
00079 
00080 void SFVec3fCellConstrained::setParams( const Vec3d params )
00081 {
00082     _alpha = params[0];
00083     _beta= params[1];
00084     _gamma = params[2];
00085 }
00086 
00087 FloatingPointType SFVec3fCellConstrained::computeWeight( Vec3d w, int method )
00088 {
00089     switch( method )
00090     {
00091         case LINEAR:
00092             return (1.0-w[0]) * (1.0-w[1]) * (1.0-w[2]);
00093         case LOCAL_SKINNING:
00094             return hf.compute(w[0]) * hf.compute(w[1]) * hf.compute(w[2]);
00095         default:
00096             std::cerr << "SFVec3fCellConstrained::computeWeight() : Unknown method\n";
00097             return 0.0;
00098     }
00099 }
00100 
00101 
00102 void SFVec3fCellConstrained::updatePosition( int method )
00103 {
00104     Vec3d v = computePosition(method);
00105                         
00106     _vec->x = v[0];
00107     _vec->y = v[1];
00108     _vec->z = v[2];
00109 }
00110 
00111 
00112 
00113 void SFVec3fCellConstrained::computeParameters()
00114 {
00115     
00116     Vec3d q(_vec->x,_vec->y,_vec->z);
00117     Vec3d v = q - _cell->vertex(0)->getPosition();
00118 
00119     Vec3d va = _cell->vertex(1)->getPosition() - _cell->vertex(0)->getPosition();
00120     Vec3d vb = _cell->vertex(2)->getPosition() - _cell->vertex(0)->getPosition();
00121     Vec3d vc = _cell->vertex(4)->getPosition() - _cell->vertex(0)->getPosition();
00122     
00123     _alpha = (v*va) / (va.norm()*va.norm());
00124     _beta  = (v*vb) / (vb.norm()*vb.norm());
00125     _gamma = (v*vc) / (vc.norm()*vc.norm());
00126 }   
00127     
00128     
00129     
00130     
00131     
00132     /*
00133         std::deque<unsigned int> SFVec3fCellConstrained::getAlphaFactors( Cell *cell, unsigned int faceId, unsigned int depthLeft )
00134     {
00135         //std::cerr << "Faceid is " << faceId << " and fatherpos is " << cell->fatherPos() << "\n";
00136         Require( !cell->isRoot() );
00137         
00138         if( depthLeft == 0 )
00139         {
00140             return std::deque<unsigned int>(0);
00141         }
00142         else
00143         {
00144             std::deque<unsigned int> parents = getAlphaFactors( cell->father(), faceId, depthLeft-1 );
00145             
00146             unsigned int myId = cell->fatherPos();
00147             if( (myId%2) == 0 )
00148                 // This is a bottom cell, return 0
00149                 parents.push_back(0);
00150             else
00151                 parents.push_back(1);
00152                 
00153             return parents;
00154         }
00155     }
00156     
00157     std::deque<unsigned int> SFVec3fCellConstrained::getBetaFactors( Cell *cell, unsigned int faceId, unsigned int depthLeft )
00158     {
00159         //std::cerr << "Faceid is " << faceId << " and fatherpos is " << cell->fatherPos() << "\n";
00160         Require( !cell->isRoot() );
00161         
00162         if( depthLeft == 0 )
00163         {
00164             return std::deque<unsigned int>(0);
00165         }
00166         else
00167         {
00168             std::deque<unsigned int> parents = getBetaFactors( cell->father(), faceId, depthLeft-1 );
00169             
00170             unsigned int myId = cell->fatherPos();
00171             if( (myId%4) <= 1 )
00172                 // This is a bottom cell, return 0
00173                 parents.push_back(0);
00174             else
00175                 parents.push_back(1);
00176                 
00177             return parents;
00178         }
00179     }
00180 
00181     std::deque<unsigned int> SFVec3fCellConstrained::getGammaFactors( Cell *cell, unsigned int faceId, unsigned int depthLeft )
00182     {
00183         if( depthLeft == 0 )
00184         {
00185             return std::deque<unsigned int>(0);
00186         }
00187         else
00188         {
00189             std::deque<unsigned int> parents = getGammaFactors( cell->father(), faceId, depthLeft-1 );
00190             
00191             unsigned int myId = cell->fatherPos();
00192             if( myId <= 3 )
00193                 // This is a bottom cell, return 0
00194                 parents.push_back(0);
00195             else
00196                 parents.push_back(1);
00197                 
00198             return parents;
00199         }
00200     }
00201 
00202     
00203     
00204     
00205     
00206     
00207 TempOctree::Vertex*  SFVec3fCellConstrained::getSmallestCellsFreeVertexSharingFaceForVertex( Cell *neighbour, unsigned int face, unsigned int vertex )
00208 {
00209     Require( !neighbour->isLeaf() );
00210     
00211     unsigned int direction;
00212     if( face <= 1 )
00213         direction = 0; //x
00214     else if( face >= 4 )
00215         direction = 2; //z
00216     else
00217         direction = 1; //y
00218     
00219     unsigned int childPos = Cell::connectedVertices[vertex][direction];
00220 //  unsigned int vId = childPos;
00221     
00222     Cell *prec = NULL;
00223     Cell* res = neighbour;
00224     while( !res->isLeaf() && res->vertex(vertex)->isFree() )
00225     {
00226         prec = res;
00227         res = res->child(childPos);
00228     }
00229     
00230     if( !res->vertex(vertex)->isFree() )
00231     {
00232         Require( prec != NULL );
00233         return prec->vertex(vertex);
00234     }
00235     else
00236         return res->vertex(vertex);
00237 }
00238 */
00239     
00240     
00241     
00242     
00243         /*
00244      * Compute a point position giving the cell and alpha beta and gamma and method
00245      */
00246 Vec3d SFVec3fCellConstrained::computePosition( int method ) const
00247 {
00248         Vec3d vRes;
00249 
00250 
00251                         
00252         switch( method )
00253         {
00254             case LINEAR :
00255             {
00256             vRes =
00257                 (1.0-_gamma)*(
00258                     (1.0-_beta)*( (1-_alpha)*_cell->vertex(0)->getPosition() + _alpha*_cell->vertex(1)->getPosition() )
00259                     +
00260                     _beta      *( (1-_alpha)*_cell->vertex(2)->getPosition() + _alpha*_cell->vertex(3)->getPosition() ) )
00261                 +
00262                 _gamma*(
00263                     (1.0-_beta)*( (1-_alpha)*_cell->vertex(4)->getPosition() + _alpha*_cell->vertex(5)->getPosition() )
00264                     +
00265                     _beta      *( (1-_alpha)*_cell->vertex(6)->getPosition() + _alpha*_cell->vertex(7)->getPosition() )
00266                 );
00267                 
00268                 return vRes;
00269             }
00270 
00271             case LOCAL_SKINNING:
00272             {
00273 
00274                 CellInfluenceData & cid = _cell->getData()._influence;
00275 
00276                 FloatingPointType wSum = 0.0;
00277                 FloatingPointType w;
00278                 for( unsigned int i=0 ; i<cid.vertices.size() ; ++i )
00279                 {
00280 //                  w = getRelativeWeight( cid.vertices[i] ) / (pow(4.0,cid.vertices[i]->getDepth()));
00281                     w = getRelativeWeight( cid.vertices[i] );
00282                     Frame &f = cid.vertices[i]->getFrame();
00283                     Vec3d relPos = getRelativePosition(cid.vertices[i]);
00284 //                  Vec3d initSize(0.5,0.5,0.5);
00285                     Vec3d initSize(1.0,1.0,1.0);
00286 //                      Vec3d initSize = ((Cell*)cid.parents[i])->getData()._initialSize;
00287 //                  Frame f2( f.getOrigin(), (f[0]/f[0].norm()), (f[1]/f[1].norm()), (f[2]/f[2].norm()) );
00288 
00289                     
00290 //                  vRes += w * f2.computePosition( relPos, initSize );
00291                     vRes += w * f.computePosition( relPos, initSize );
00292 //                  vRes += w * cid.vertices[i]->getFrame().computePosition( getRelativePosition(cid.vertices[i]), ((Cell*)cid.parents[i])->getData()._initialSize );
00293                     wSum += w;
00294                 }
00295 
00296                 vRes /= wSum;
00297 
00298                 return vRes;
00299             }
00300             
00301             default:
00302             {
00303                 std::cerr << "SFVec3fCellConstrained::computePosition() : unknown method\n";
00304                 return Vec3d(0.0,0.0,0.0);
00305             }
00306     }
00307 }
00308 
00309 
00310 std::vector<Vec3d> SFVec3fCellConstrained::computeDerivative( ) const
00311 {
00312     std::vector<Vec3d> res(3);
00313     
00314     static const FloatingPointType d = 10e-5;
00315     
00316      SFVec3fCellConstrained tmpVec = *this;
00317      Vec3d posT, posB;
00318 
00319          
00320      tmpVec.setParams( this->getLocalParams() + Vec3d(d,0.0,0.0) );
00321      tmpVec.updateSkinningInformations( _cell->getData()._influence );
00322      posT = tmpVec.computePosition( LOCAL_SKINNING );
00323      tmpVec.setParams( this->getLocalParams() + Vec3d(-d,0.0,0.0) );
00324      tmpVec.updateSkinningInformations( _cell->getData()._influence );
00325      posB = tmpVec.computePosition( LOCAL_SKINNING );
00326      res[0] = (posT-posB)/(2.0*d);
00327 
00328      tmpVec.setParams( this->getLocalParams() + Vec3d(0.0,+d,0.0) );
00329      tmpVec.updateSkinningInformations( _cell->getData()._influence );
00330      posT = tmpVec.computePosition( LOCAL_SKINNING );
00331      tmpVec.setParams( this->getLocalParams() + Vec3d(0.0,-d,0.0) );
00332      tmpVec.updateSkinningInformations( _cell->getData()._influence );
00333      posB = tmpVec.computePosition( LOCAL_SKINNING );
00334      res[1] = (posT-posB)/(2.0*d);
00335 
00336      tmpVec.setParams( this->getLocalParams() + Vec3d(0.0,0.0,+d) );
00337      tmpVec.updateSkinningInformations( _cell->getData()._influence );
00338      posT = tmpVec.computePosition( LOCAL_SKINNING );
00339      tmpVec.setParams( this->getLocalParams() + Vec3d(0.0,0.0,-d) );
00340      tmpVec.updateSkinningInformations( _cell->getData()._influence );
00341      posB = tmpVec.computePosition( LOCAL_SKINNING );
00342      res[2] = (posT-posB)/(2.0*d);
00343     
00344      return res;
00345 //  std::vector<Vec3d> res(3);
00346 //  
00347 //  CellInfluenceData & cid = _cell->getData()._influence;
00348 // 
00349 //  FloatingPointType w;
00350 // 
00351 //  FloatingPointType kiSum = 0.0;  // sum_i k_i
00352 //  Vec3d kiDerSum;         // sum_i \frac{ \partial k_i }{ \partial \alpha }
00353 //  
00354 //  std::vector<FloatingPointType> ki(cid.vertices.size()); // k_i 
00355 //  std::vector<Vec3d> kiDer(cid.vertices.size());  // \frac{ \partial k_i }{ \partial x_j }
00356 //  
00357 //  FloatingPointType sign = 0.0;
00358 //  for( unsigned int i=0 ; i<cid.vertices.size() ; ++i )
00359 //  {
00360 //      Vec3d relPos = getRelativePosition(cid.vertices[i]);
00361 //      
00362 //      kiSum += getRelativeWeight( cid.vertices[i] );
00363 //      
00364 //      Vec3d paramSum;
00365 //      for( unsigned int v=0 ; v<8 ; ++v )
00366 //      {
00367 //          FloatingPointType w = computeWeight( getParameters(v), LINEAR );
00368 //          paramSum += w * cid.influenceMaps[i][_cell->vertex(v)]; 
00369 //      }
00370 //      ki[i] = computeWeight( paramSum, LOCAL_SKINNING );
00371 //      // Should be the same as getRelativeWeight( cid.vertices[i] )
00372 // 
00373 //      std::vector<Vec3d> wjDers(8);
00374 //      Vec3d wjDerSum;
00375 //      for( unsigned int v=0 ; v<8 ; ++v )
00376 //      {
00377 //          Vec3d signs;
00378 //          if( (v%2) == 0 ) { signs[0] = +1.0;} else { signs[0] = -1.0; }
00379 //          if( (v%4) <= 1 ) { signs[1] = +1.0;} else { signs[1] = -1.0; }
00380 //          if( v < 4 ) { signs[2] = +1.0;} else { signs[2] = -1.0; }
00381 //          
00382 //          Vec3d paramsj = getParameters(v);
00383 //          Vec3d wjDer;
00384 //          wjDers[v][0] = - signs[0] * (1.0-paramsj[1]) * (1.0-paramsj[2]);
00385 //          wjDers[v][1] = - signs[1] * (1.0-paramsj[0]) * (1.0-paramsj[2]);
00386 //          wjDers[v][2] = - signs[2] * (1.0-paramsj[0]) * (1.0-paramsj[1]);
00387 //          
00388 //          wjDerSum += wjDers[v];
00389 //          
00390 //          Vec3d infj = cid.influenceMaps[i][_cell->vertex(v)];
00391 //          
00392 //          kiDer[i] += wjDers[v]*infj[0] * hf.computeDerivative( paramSum[0] ) * hf.compute( paramSum[1] ) * hf.compute( paramSum[2] );
00393 //          kiDer[i] += wjDers[v]*infj[1] * hf.compute( paramSum[0] ) * hf.computeDerivative( paramSum[1] ) * hf.compute( paramSum[2] );
00394 //          kiDer[i] += wjDers[v]*infj[2] * hf.compute( paramSum[0] ) * hf.compute( paramSum[1] ) * hf.computeDerivative( paramSum[2] );
00395 //      }
00396 //      
00397 //      kiDerSum += kiDer[i];
00398 //  }
00399 //  
00400 //  for( unsigned int i=0 ; i<cid.vertices.size() ; ++i )
00401 //  {
00402 //      Frame &f = cid.vertices[i]->getFrame();
00403 //      Vec3d relPos = getRelativePosition(cid.vertices[i]);
00404 //      
00405 //      Vec3d myPos = f.computePosition( relPos, Vec3d(1,1,1) );
00406 //      
00407 //      w = getRelativeWeight( cid.vertices[i] ) / kiSum;
00408 //      
00409 //      FloatingPointType wDer;
00410 //      
00411 //      // on alpha
00412 //      // First : (+/-) ki * Ui
00413 //      if( (cid.verticesId[i]%2) == 0 ) { sign = +1.0;} else { sign = -1.0; }
00414 //      res[0] += w * f.getVector( 0 );
00415 //      // Second : (+/-) f'(alpha) f(beta) Qi
00416 //      wDer = (kiDer[i][0] * kiSum - ki[i] * kiDerSum[0]) / (kiSum*kiSum);
00417 // //       wDer = hf.computeDerivative( relPos[0] ) * hf.compute( relPos[1] ) * hf.compute( relPos[2] ) * wSum;
00418 // //       wDer -= w * wDerSum[0];
00419 // //       wDer /= wSum*wSum;
00420 //      
00421 //      res[0] += wDer * myPos;
00422 //      
00423 //      // on beta now
00424 //      if( (cid.verticesId[i]%4) <= 1 ) { sign = +1.0;} else { sign = -1.0; }
00425 //      res[1] += w * f.getVector( 1 );
00426 //      wDer = (kiDer[i][1] * kiSum - ki[i] * kiDerSum[1]) / (kiSum*kiSum);
00427 // //       wDer = hf.compute( relPos[0] ) * hf.computeDerivative( relPos[1] ) * hf.compute( relPos[2] ) * kiSum;
00428 // //       wDer -= w * kiDerSum[1];
00429 // //       wDer /= kiSum*kiSum;
00430 //      
00431 //      res[1] += wDer * myPos;
00432 //      
00433 //      // on gamma now
00434 //      if( cid.verticesId[i] < 4 ) { sign = +1.0;} else { sign = -1.0; }
00435 //      res[2] += w * f.getVector( 2 );
00436 //      wDer = (kiDer[i][2] * kiSum - ki[i] * kiDerSum[2]) / (kiSum*kiSum);
00437 // //       wDer = hf.compute( relPos[0] ) * hf.compute( relPos[1] ) * hf.computeDerivative( relPos[2] ) * kiSum;
00438 // //       wDer -= w * kiDerSum[2];
00439 // //       wDer /= kiSum*kiSum;
00440 //      res[2] += wDer * myPos;
00441 //      
00442 //  }
00443 //  
00444 //  return res;
00445     
00446 }
00447     
00448 
00449     Vec3d SFVec3fCellConstrained::getParameters( unsigned short vId ) const
00450     {
00451         Require( vId < 8 );
00452         return Vec3d(LINEARFACTORALPHA(vId,_alpha),LINEARFACTORBETA(vId,_beta),LINEARFACTORGAMMA(vId,_gamma));
00453     }
00454     
00455     
00456     void SFVec3fCellConstrained::updateSkinningInformations( CellInfluenceData & influence )
00457     {
00458         this->clearRelativePositions(  );
00459         this->clearRelativeWeights(  );
00460         
00461         // For every depending vertex given by "influence"
00462         // find the local coordinates in each frame and find the associated weight
00463         for( unsigned short vId=0 ; vId < influence.vertices.size() ; ++vId )
00464         {
00465             /*
00466             X3DTK::SFVec3f * QSF = getSFVec3f();
00467             Vec3d Q( QSF->x, QSF->y, QSF->z );
00468             
00469             Frame f = influence.vertices[vId]->getFrame();
00470             this->setRelativePosition( influence.vertices[vId], f.getLocalCoordinates( Q ) );
00471             */
00472             Vec3d params = translateParameters( this->getCell(), this->getLocalParams(), (Cell*)influence.parents[vId], influence.verticesId[vId] );
00473             this->setRelativePosition( influence.vertices[vId], params );
00474             
00475             Vec3d paramW;
00476             for( unsigned short i=0 ; i<8 ; ++i )
00477             {
00478                 FloatingPointType w = computeWeight( getParameters(i), LINEAR );
00479                 paramW += w * influence.influenceMaps[vId][_cell->vertex(i)];
00480             }           
00481             FloatingPointType w = computeWeight( paramW, LOCAL_SKINNING );
00482             this->setRelativeWeight( influence.vertices[vId], w );
00483         }       
00484     }
00485 
00486     
00487     
00488     
00489     
00490     
00491 void SFVec3fCellConstrained::globalLinearUpdatePositions( Cell *cStart )
00492 {
00493     for( Cell::vertex_width_iterator it(cStart) ; !it.empty() ; )
00494     {
00495         ConstrainedVertex* v = ++it;
00496         
00497         if( v->isFree() )
00498         {
00499             Vec3d delta = v->getDelta();
00500             X3DTK::SFVec3f sfDelta(delta[0],delta[1],delta[2]);
00501 
00502             for( unsigned int i=0 ; i<v->nConnectedCells() ; ++i )
00503             {
00504                 Cell *cell = v->connectedCell(i);
00505 
00506                 if( cell->getData()._depth == v->getDepth() )
00507                 {
00508                     unsigned int vId;
00509                     for( vId=0 ; vId<8 ; ++vId )
00510                     {
00511                         if( cell->vertex(vId) == v )
00512                         {
00513                             break;
00514                         }
00515                     }
00516 
00517                     OctreeDataPoints *points = &(cell->getData()._points);
00518                     for( OctreeDataPoints::iterator it = points->begin() ; it != points->end() ; ++it )
00519                     {
00520                         X3DTK::SFVec3f *vec = (*it)->getSFVec3f();
00521                         FloatingPointType weight = hf.compute(LINEARFACTORALPHA(vId,(*it)->getAlpha())) * hf.compute(LINEARFACTORBETA(vId,(*it)->getBeta())) * hf.compute(LINEARFACTORGAMMA(vId,(*it)->getGamma()));
00522                         weight /= ((FloatingPointType) v->getDepth() + 1.0);
00523                         *vec += weight*sfDelta;
00524                     }
00525                 }
00526             }
00527         }
00528 
00529         v->setDelta( Vec3d(0,0,0) );
00530     }
00531 }
00532 
00533 Vec3d SFVec3fCellConstrained::getInitNormalParameters( unsigned short vId ) const
00534 {
00535     Require( vId < 8 );
00536     return Vec3d(LINEARFACTORALPHA(vId,_alphaNormal),LINEARFACTORBETA(vId,_betaNormal),LINEARFACTORGAMMA(vId,_gammaNormal));
00537 }
00538 
00539 
00547 Vec3d SFVec3fCellConstrained::translateParameters( Cell *cStart, Vec3d params, Cell *cDest, unsigned short vId )
00548 {
00549     //std::cerr << "SFVec3fCellConstrained::translateParameters" << *cStart << "\n";
00550     
00551     Vec3d result = params;
00552     
00553     Cell *cell = cStart;
00554     
00555     while( cell != cDest )
00556     {
00557         if( (cell->fatherPos()%2) == 0 )
00558         {
00559             result[0] /= 2.0;
00560         }
00561         else
00562         {
00563             result[0] = (result[0]+1.0)/2.0;
00564         }
00565         if( (cell->fatherPos()%4) <= 1 )
00566         {
00567             result[1] /= 2.0;
00568         }
00569         else
00570         {
00571             result[1] = (result[1]+1.0)/2.0;
00572         }
00573         if( cell->fatherPos() <= 3 )
00574         {
00575             result[2] /= 2.0;
00576         }
00577         else
00578         {
00579             result[2] = (result[2]+1.0)/2.0;
00580         }   
00581         //std::cerr << "\t" << *cell << " : params were " << params << " and now : " << result << "\n";     
00582         cell = cell->father();
00583     }
00584     
00585     // Now translate this in the vID vertex' frame
00586     result = Vec3d( LINEARFACTORALPHA(vId,result[0]), LINEARFACTORBETA(vId,result[1]), LINEARFACTORGAMMA(vId,result[2]) );
00587     if( (vId%2) == 1 )
00588     {
00589         result[0] *= -1;
00590     }
00591     if( (vId%4) >= 2 )
00592     {
00593         result[1] *= -1;
00594     }
00595     if( vId >= 4 )
00596     {
00597         result[2] *= -1;
00598     }
00599     
00600     return result;
00601 }
00602 
00603 
00604 }
00605 }
00606 

Generated on Thu Dec 23 13:52:27 2004 by doxygen 1.3.6