TriangularFEMForceField.cpp

Go to the documentation of this file.
00001 /******************************************************************************
00002 *       SOFA, Simulation Open-Framework Architecture, version 1.0 beta 3      *
00003 *                (c) 2006-2008 MGH, INRIA, USTL, UJF, CNRS                    *
00004 *                                                                             *
00005 * This library is free software; you can redistribute it and/or modify it     *
00006 * under the terms of the GNU Lesser General Public License as published by    *
00007 * the Free Software Foundation; either version 2.1 of the License, or (at     *
00008 * your option) any later version.                                             *
00009 *                                                                             *
00010 * This library is distributed in the hope that it will be useful, but WITHOUT *
00011 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or       *
00012 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License *
00013 * for more details.                                                           *
00014 *                                                                             *
00015 * You should have received a copy of the GNU Lesser General Public License    *
00016 * along with this library; if not, write to the Free Software Foundation,     *
00017 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA.          *
00018 *******************************************************************************
00019 *                               SOFA :: Modules                               *
00020 *                                                                             *
00021 * Authors: The SOFA Team and external contributors (see Authors.txt)          *
00022 *                                                                             *
00023 * Contact information: contact@sofa-framework.org                             *
00024 ******************************************************************************/
00025 #include <sofa/component/forcefield/TriangularFEMForceField.h>
00026 #include <sofa/core/ObjectFactory.h>
00027 #include <sofa/helper/gl/template.h>
00028 #include <sofa/component/topology/TriangleData.inl>
00029 #include <sofa/component/topology/EdgeData.inl>
00030 #include <sofa/component/topology/PointData.inl>
00031 #include <sofa/helper/system/gl.h>
00032 #include <fstream> // for reading the file
00033 #include <iostream> //for debugging
00034 #include <vector>
00035 #include <algorithm>
00036 #include <sofa/defaulttype/Vec3Types.h>
00037 #include <assert.h>
00038 
00039 #ifdef _WIN32
00040 #include <windows.h>
00041 #endif
00042 
00043 
00044 // #define DEBUG_TRIANGLEFEM
00045 
00046 namespace sofa
00047 {
00048 
00049 namespace component
00050 {
00051 
00052 namespace forcefield
00053 {
00054 
00055 using namespace sofa::defaulttype;
00056 using namespace sofa::component::topology;
00057 using namespace core::componentmodel::topology;
00058 
00059 using std::cerr;
00060 using std::cout;
00061 using std::endl;
00062 
00063 template< class DataTypes>
00064 void TriangularFEMForceField<DataTypes>::TRQSTriangleCreationFunction ( int triangleIndex, void* param, 
00065                                     TriangleInformation &/*tinfo*/,
00066                                                                         const Triangle& t, 
00067                                                                         const sofa::helper::vector< unsigned int > &,
00068                                                                         const sofa::helper::vector< double >&)
00069 {
00070     TriangularFEMForceField<DataTypes> *ff= (TriangularFEMForceField<DataTypes> *)param;
00071     if (ff) {
00072         Index a = t[0];
00073         Index b = t[1];
00074         Index c = t[2];
00075 
00076         switch(ff->method)
00077         {
00078         case SMALL :
00079             ff->computeMaterialStiffness(triangleIndex,a,b,c);
00080             ff->initSmall();
00081 
00082             break;
00083         case LARGE :
00084             ff->computeMaterialStiffness(triangleIndex,a,b,c);
00085             ff->initLarge(triangleIndex,a,b,c);
00086             break;
00087         }
00088     }
00089 
00090 }
00091 /*
00092 template< class DataTypes>
00093 void TriangularFEMForceField<DataTypes>::TRQSEdgeCreationFunction(int edgeIndex, void* param, EdgeInformation &ei,
00094                                          const Edge& ,  const sofa::helper::vector< unsigned int > &,
00095                                          const sofa::helper::vector< double >&)
00096 {
00097     ei.fracturable = false;
00098 }
00099 */
00100 
00101 
00102 template <class DataTypes>
00103 TriangularFEMForceField<DataTypes>::TriangularFEMForceField()
00104 : method(LARGE)
00105 , f_method(initData(&f_method,std::string("large"),"method","large: large displacements, small: small displacements"))
00106 , f_poisson(initData(&f_poisson,(Real)0.3,"poissonRatio","Poisson ratio in Hooke's law"))
00107 , f_young(initData(&f_young,(Real)1000.,"youngModulus","Young modulus in Hooke's law"))
00108 , f_damping(initData(&f_damping,(Real)0.,"damping","Ratio damping/stiffness"))
00109 , f_fracturable(initData(&f_fracturable,false,"fracturable","the forcefield computes the next fracturable Edge"))
00110 , showStressValue(initData(&showStressValue,false,"showStressValue","Flag activating rendering of stress values as a color in each triangle"))
00111 , showStressVector(initData(&showStressVector,false,"showStressVector","Flag activating rendering of stress directions within each triangle"))
00112 {
00113 }
00114 
00115 
00116 template <class DataTypes> void TriangularFEMForceField<DataTypes>::handleTopologyChange()
00117 {
00118     std::list<const TopologyChange *>::const_iterator itBegin=_topology->firstChange();
00119     std::list<const TopologyChange *>::const_iterator itEnd=_topology->lastChange();
00120 
00121     triangleInfo.handleTopologyEvents(itBegin,itEnd);
00122     edgeInfo.handleTopologyEvents(itBegin,itEnd);
00123     vertexInfo.handleTopologyEvents(itBegin,itEnd);
00124 }
00125 
00126 template <class DataTypes>
00127 TriangularFEMForceField<DataTypes>::~TriangularFEMForceField()
00128 {
00129 }
00130 
00131 template <class DataTypes>
00132 void TriangularFEMForceField<DataTypes>::init()
00133 {
00134     std::cerr << "initializing TriangularFEMForceField" << std::endl;
00135     this->Inherited::init();
00136 
00137     _topology = getContext()->getMeshTopology();
00138 
00139     if (f_method.getValue() == "small")
00140         method = SMALL;
00141     else if (f_method.getValue() == "large")
00142         method = LARGE;
00143     
00144     if (_topology->getNbTriangles()==0)
00145     {
00146         std::cerr << "ERROR(TriangularFEMForceField): object must have a Triangular Set Topology.\n";
00147         return;
00148     }
00149     
00150     lastFracturedEdgeIndex = -1;
00151     
00152     reinit();
00153 }
00154     
00155 
00156 template <class DataTypes>void TriangularFEMForceField<DataTypes>::reinit()
00157     {
00158         if (f_method.getValue() == "small")
00159             method = SMALL;
00160         else if (f_method.getValue() == "large")
00161             method = LARGE;     
00162         
00164         triangleInfo.resize(_topology->getNbTriangles());
00166         edgeInfo.resize(_topology->getNbEdges());       
00167         unsigned int nbPoints=_topology->getNbPoints();
00168         
00169         vertexInfo.resize(nbPoints);
00170         
00171         //if (_initialPoints.getValue().size() == 0)
00172         //{
00173         //  VecCoord& p = *this->mstate->getX(); //getX0(); ???
00174         //  _initialPoints.setValue(p);
00175         //}
00176         _initialPoints = this->mstate->getX0();
00177             
00178         for (int i=0;i<_topology->getNbTriangles();++i) 
00179         {
00180             TRQSTriangleCreationFunction(i, (void*) this, triangleInfo[i],
00181                                          _topology->getTriangle(i),  (const sofa::helper::vector< unsigned int > )0,
00182                                          (const sofa::helper::vector< double >)0);
00183         }       
00184         
00185         triangleInfo.setCreateFunction(TRQSTriangleCreationFunction);
00186         triangleInfo.setCreateParameter( (void *) this );
00187         triangleInfo.setDestroyParameter( (void *) this );
00188 }
00189 
00190 
00191 template <class DataTypes>
00192     void TriangularFEMForceField<DataTypes>::addForce(VecDeriv& f, const VecCoord& x, const VecDeriv& /*v*/)
00193 {
00194     int nbTriangles=_topology->getNbTriangles();
00195 
00196     //TriangleInformation *tinfo;
00197 
00198     //EdgeInformation *einfo;
00199 
00200     f.resize(x.size());
00201 
00202     if(f_damping.getValue() != 0)
00203     {
00204         if(method == SMALL)
00205         {
00206             for( int i=0; i<nbTriangles; i+=3 ) //unsigned int i=0; i<_indexedElements->size(); i+=3
00207             {
00208                 accumulateForceSmall( f, x, i/3, true );
00209                 accumulateDampingSmall( f, i/3 );
00210             }
00211         }
00212         else
00213         {
00214             for( int i=0; i<nbTriangles; i+=3 )
00215             {
00216                 accumulateForceLarge( f, x, i/3, true );
00217                 accumulateDampingLarge( f, i/3 );
00218             }
00219         }
00220     }
00221     else
00222     {
00223         if(method==SMALL)
00224         {
00225             //typename VecElement::const_iterator it;
00226             //unsigned int i(0);
00227 
00228             for(int i=0; i<nbTriangles; i+=1) //it = _indexedElements->begin() ; it != _indexedElements->end() ; ++it, ++i
00229             {
00230                 accumulateForceSmall( f, x, i, true );
00231             }
00232         }
00233         else
00234         {
00235             //typename VecElement::const_iterator it;
00236             //unsigned int i(0);
00237 
00238             for( int i=0; i<nbTriangles; i+=1) //it = _indexedElements->begin() ; it != _indexedElements->end() ; ++it, ++i
00239             {
00240                 accumulateForceLarge( f, x, i, true );
00241             }
00242         }
00243     }
00244 
00245     if (f_fracturable.getValue())
00246     {
00247         // First Pass - Vertices Pass       
00248         unsigned int nbPoints=_topology->getNbPoints();
00249 
00250         for( unsigned int i=0; i<nbPoints; i++ )
00251         {
00252             const sofa::helper::vector< unsigned int >& triangleNeighbors = _topology->getTriangleVertexShell(i);
00253 
00254             sofa::helper::vector< unsigned int >::const_iterator it = triangleNeighbors.begin();
00255             sofa::helper::vector< unsigned int >::const_iterator itEnd = triangleNeighbors.end();
00256             Coord meanStrainDirection, refStrainDirection;
00257             meanStrainDirection.clear();
00258             refStrainDirection.clear();
00259             vertexInfo[i].sumEigenValues = 0.0;
00260 
00261             bool b(true);
00262 
00263             while (it != itEnd)
00264             {
00265                 if (b)
00266                 {
00267                     refStrainDirection = triangleInfo[*it].principalStrainDirection;
00268                     if (refStrainDirection.norm() != 0.0)
00269                         b=false;
00270                 }
00271 
00272                 (triangleInfo[*it].principalStrainDirection * refStrainDirection < 0)?
00273                     meanStrainDirection -= triangleInfo[*it].principalStrainDirection : meanStrainDirection += triangleInfo[*it].principalStrainDirection;
00274 
00275                 vertexInfo[i].sumEigenValues += triangleInfo[*it].eigenValue;
00276 
00277                 ++it;
00278             }
00279             
00280             //meanStrainDirection.normalize();
00281             
00282             vertexInfo[i].meanStrainDirection = meanStrainDirection / (double)triangleNeighbors.size();
00283             vertexInfo[i].sumEigenValues = (double)vertexInfo[i].sumEigenValues / (double)triangleNeighbors.size();
00284         }
00285 
00286 
00287         // Second Pass - Edges Pass             
00288 
00289         for(int i=0; i<_topology->getNbEdges(); i++ )
00290             edgeInfo[i].fracturable = false;
00291 
00292         if (nbPoints > 0)
00293         {           
00294             double max = 0; //vertexInfo[0].sumEigenValues;
00295             int mostDeformableVertexIndex = -1; //0;
00296 
00297             for( unsigned int i=0; i<nbPoints; i++ )
00298             {
00299                 bool vertexOnBorder = _topology->getTriangleVertexShell(i).size() < _topology->getEdgeVertexShell(i).size() && _topology->getTriangleVertexShell(i).size() > 1;
00300 
00301                 if (vertexOnBorder && vertexInfo[i].sumEigenValues > max)
00302                 {
00303                     mostDeformableVertexIndex = i;
00304                     max = vertexInfo[i].sumEigenValues;
00305                 }
00306             }
00307 /*          
00308             std::vector< std::pair< double, unsigned int > > mostDeformableVertexIndexA(nbPoints);
00309 
00310             for( unsigned int i=0; i<nbPoints; i++ )
00311             {
00312                 mostDeformableVertexIndexA[i].first = vertexInfo[i].sumEigenValues;
00313                 mostDeformableVertexIndexA[i].second = i;
00314             }
00315 
00316             std::sort( mostDeformableVertexIndexA.begin(), mostDeformableVertexIndexA.end() ); 
00317 */
00318             /*
00319             for( unsigned int i=0; i<nbPoints; i++ )
00320             {
00321                 std::cout << mostDeformableVertexIndexA[i].first << " ";
00322             }
00323             std::cout << "\n";
00324             */
00325 /*
00326             bool vertexOnBorder(false);
00327             int curIndex = nbPoints-1;
00328 
00329             while ((!vertexOnBorder)&&(curIndex>=0))
00330             {
00331                 mostDeformableVertexIndex = mostDeformableVertexIndexA[curIndex].second;
00332                 max=mostDeformableVertexIndexA[curIndex].first;
00333                 // Check if the Vertex is on the border
00334                 curIndex--;
00335             }
00336 */
00337             // if (vertexOnBorder && (max > 0.05))
00338 
00339             const double THRESHOLD = 0.2;
00340 
00341             if ((mostDeformableVertexIndex!=-1) && (max > THRESHOLD))
00342             {
00343                 std::cout << "max=" << max << std::endl;
00344                 double minDotProduct = 1000.0;
00345                 unsigned int fracturableIndex = 0;
00346                 bool fracture(false);
00347 
00348                 const sofa::helper::vector< unsigned int >& edgeNeighbors = _topology->getEdgeVertexShell(mostDeformableVertexIndex);
00349 
00350                 sofa::helper::vector< unsigned int >::const_iterator it = edgeNeighbors.begin();
00351                 sofa::helper::vector< unsigned int >::const_iterator itEnd = edgeNeighbors.end();
00352 
00353                 Index a;
00354                 Index b;
00355                             
00356                 Coord n = vertexInfo[mostDeformableVertexIndex].meanStrainDirection;
00357                 n.normalize();
00358 
00359                 while (it != itEnd)
00360                 {
00361                     a = _topology->getEdge(*it)[0];
00362                     b = _topology->getEdge(*it)[1];
00363 
00364                     if (vertexInfo[mostDeformableVertexIndex].meanStrainDirection.norm() != 0.0)
00365                     {
00366                         Coord d = x[b]-x[a];
00367                         d.normalize();
00368                         if (fabs(n * d) < minDotProduct)
00369                         {
00370                             sofa::helper::vector< unsigned int > triangleEdgeShell = _topology->getTriangleEdgeShell(*it);
00371                             if (triangleEdgeShell.size() != 1)
00372                             {
00373                                 /*
00374                                 bool bb(false);
00375                                 sofa::helper::vector< unsigned int >::iterator _it = triangleEdgeShell.begin();
00376                                 sofa::helper::vector< unsigned int >::iterator _itEnd = triangleEdgeShell.end();
00377                                 while (_it != _itEnd)
00378                                 {
00379                                     helper::fixed_array<unsigned int,3> edges = _topology->getTriangleEdge(*_it);
00380 
00381                                     int cptTest=0;
00382                                     for (int i=0; i<3; i++)
00383                                     {
00384                                         if (_topology->getTriangleEdgeShell(edges[i]).size() < 2)
00385                                         {
00386                                             cptTest++;
00387                                         }
00388                                     }
00389 
00390                                     if (cptTest > 2)
00391                                     {
00392                                         if (max < 5 * THRESHOLD)
00393                                         {
00394                                             bb = true;
00395                                             break;
00396                                         }
00397                                     }
00398                                     
00399                                     ++_it;
00400                                 }
00401 
00402                                 if (!bb)
00403                                 */
00404                                 {
00405                                     minDotProduct = fabs(n * d);
00406                                     fracturableIndex = *it;
00407                                     fracture = true;
00408                                 }
00409                             }
00410                         }
00411                     }
00412 
00413                     ++it;
00414                 }
00415             
00416                 if (fracture) {
00417                     std::cout << "fracture at edge "<<fracturableIndex<<std::endl;
00418                     edgeInfo[fracturableIndex].fracturable = true;
00419                     lastFracturedEdgeIndex = fracturableIndex;
00420                 }
00421             }
00422         }
00423     }
00424 
00425 //  std::cout << "EOF AddForce\n";
00426 }
00427 
00428 
00429 template <class DataTypes>
00430     void TriangularFEMForceField<DataTypes>::addDForce(VecDeriv& df, const VecDeriv& dx)
00431 {
00432     Real h=1;
00433     df.resize(dx.size());
00434 
00435     if (method == SMALL)
00436     {
00437         applyStiffnessSmall( df,h,dx );
00438     }
00439     else
00440     {
00441         applyStiffnessLarge( df,h,dx );
00442     }
00443 }
00444 
00445 template <class DataTypes>
00446     double TriangularFEMForceField<DataTypes>::getPotentialEnergy(const VecCoord& /*x*/)
00447 {
00448     cerr<<"TriangularFEMForceField::getPotentialEnergy-not-implemented !!!"<<endl;
00449     return 0;
00450 }
00451 
00452 template <class DataTypes>
00453 void TriangularFEMForceField<DataTypes>::applyStiffness( VecCoord& v, Real h, const VecCoord& x )
00454 {
00455     if (method == SMALL)
00456     {
00457         applyStiffnessSmall( v,h,x );
00458     }
00459     else
00460     {
00461         applyStiffnessLarge( v,h,x );
00462     }
00463 }
00464 
00465 
00466 template <class DataTypes>
00467 void TriangularFEMForceField<DataTypes>::computeStrainDisplacement( StrainDisplacement &J, Coord /*a*/, Coord b, Coord c )
00468 {
00469 #ifdef DEBUG_TRIANGLEFEM
00470     std::cout << "TriangularFEMForceField::computeStrainDisplacement\n";
00471 #endif
00472 
00473     //Coord ab_cross_ac = cross(b, c);
00474     Real determinant = b[0] * c[1]; // Surface
00475 
00476     J[0][0] = J[1][2] = -c[1] / determinant;
00477     J[0][2] = J[1][1] = (c[0] - b[0]) / determinant;
00478     J[2][0] = J[3][2] = c[1] / determinant;
00479     J[2][2] = J[3][1] = -c[0] / determinant;
00480     J[4][0] = J[5][2] = 0;
00481     J[4][2] = J[5][1] = b[0] / determinant;
00482     J[1][0] = J[3][0] = J[5][0] = J[0][1] = J[2][1] = J[4][1] = 0;
00483 }
00484 
00485 template <class DataTypes>
00486 void TriangularFEMForceField<DataTypes>::computeEigenStrain( Coord &v, StrainDisplacement &J, Displacement &Depl, double &maxEigenValue )
00487 {
00488     Mat<3,6,Real> Jt;
00489     Jt.transpose( J );
00490     Vec<3,Real> JtD;   // JtD = Jt * Depl;
00491 
00492     JtD[0] = Jt[0][0] * Depl[0] + /* Jt[0][1] * Depl[1] + */ Jt[0][2] * Depl[2]
00493              /* + Jt[0][3] * Depl[3] + Jt[0][4] * Depl[4] + Jt[0][5] * Depl[5] */ ;
00494 
00495     JtD[1] = /* Jt[1][0] * Depl[0] + */ Jt[1][1] * Depl[1] + /* Jt[1][2] * Depl[2] + */
00496              Jt[1][3] * Depl[3] + /* Jt[1][4] * Depl[4] + */ Jt[1][5] * Depl[5];
00497 
00498     JtD[2] = Jt[2][0] * Depl[0] + Jt[2][1] * Depl[1] + Jt[2][2] * Depl[2] +
00499              Jt[2][3] * Depl[3] + Jt[2][4] * Depl[4] /* + Jt[2][5] * Depl[5] */ ;
00500     
00501     NEWMAT::SymmetricMatrix e(2);
00502     e = 0.0;
00503     
00504     NEWMAT::DiagonalMatrix D(2);
00505     D = 0.0;
00506 
00507     NEWMAT::Matrix V(2,2);
00508     V = 0.0;
00509     
00510     e(1,1) = JtD[0];
00511     e(1,2) = JtD[2];
00512     e(2,1) = JtD[2];
00513     e(2,2) = JtD[1];
00514             
00515     NEWMAT::Jacobi(e, D, V); 
00516     
00517     v[0] = (Real)V(1,1);
00518     v[1] = (Real)V(2,1);
00519     v[2] = 0.0;
00520 
00521     v.normalize();
00522     
00523     maxEigenValue = D(1,1);
00524 
00525 //  std::cout << "D = " << D(1,1) << ", " << D(2,2) << std::endl; // eigenvalues
00526 }
00527 
00528 
00529 template <class DataTypes>
00530 void TriangularFEMForceField<DataTypes>::computeMaterialStiffness(int i, Index &/*a*/, Index &/*b*/, Index &/*c*/)
00531 {
00532     //_materialsStiffnesses.resize(_indexedElements->size());
00533     
00534     TriangleInformation *tinfo = &triangleInfo[i];
00535 
00536     tinfo->materialMatrix[0][0] = 1;
00537     tinfo->materialMatrix[0][1] = f_poisson.getValue();
00538     tinfo->materialMatrix[0][2] = 0;
00539     tinfo->materialMatrix[1][0] = f_poisson.getValue();
00540     tinfo->materialMatrix[1][1] = 1;
00541     tinfo->materialMatrix[1][2] = 0;
00542     tinfo->materialMatrix[2][0] = 0;
00543     tinfo->materialMatrix[2][1] = 0;
00544     tinfo->materialMatrix[2][2] = 0.5f * (1 - f_poisson.getValue());
00545     
00546     tinfo->materialMatrix *= (f_young.getValue() / (12 * (1 - f_poisson.getValue() * f_poisson.getValue())));
00547     
00548 }
00549 
00550 
00551 template <class DataTypes>
00552 void TriangularFEMForceField<DataTypes>::computeForce( Displacement &F, const Displacement &Depl, const MaterialStiffness &K, const StrainDisplacement &J )
00553 {
00554     Mat<3,6,Real> Jt;
00555     Jt.transpose( J );
00556 
00557     Vec<3,Real> JtD;
00558 
00559     // Optimisations: The following values are 0 (per computeStrainDisplacement )
00560 
00561     // Jt[0][1]
00562     // Jt[0][3]
00563     // Jt[0][4]
00564     // Jt[0][5]
00565     // Jt[1][0]
00566     // Jt[1][2]
00567     // Jt[1][4]
00568     // Jt[2][5]
00569 
00570 
00571     //  JtD = Jt * Depl;
00572 
00573     JtD[0] = Jt[0][0] * Depl[0] + /* Jt[0][1] * Depl[1] + */ Jt[0][2] * Depl[2]
00574              /* + Jt[0][3] * Depl[3] + Jt[0][4] * Depl[4] + Jt[0][5] * Depl[5] */ ;
00575 
00576     JtD[1] = /* Jt[1][0] * Depl[0] + */ Jt[1][1] * Depl[1] + /* Jt[1][2] * Depl[2] + */
00577              Jt[1][3] * Depl[3] + /* Jt[1][4] * Depl[4] + */ Jt[1][5] * Depl[5];
00578 
00579     JtD[2] = Jt[2][0] * Depl[0] + Jt[2][1] * Depl[1] + Jt[2][2] * Depl[2] +
00580              Jt[2][3] * Depl[3] + Jt[2][4] * Depl[4] /* + Jt[2][5] * Depl[5] */ ;
00581 
00582     Vec<3,Real> KJtD;
00583 
00584     //  KJtD = K * JtD;
00585 
00586     // Optimisations: The following values are 0 (per computeMaterialStiffnesses )
00587 
00588     // K[0][2]
00589     // K[1][2]
00590     // K[2][0]
00591     // K[2][1]
00592 
00593     KJtD[0] = K[0][0] * JtD[0] + K[0][1] * JtD[1] /* + K[0][2] * JtD[2] */;
00594 
00595     KJtD[1] = K[1][0] * JtD[0] + K[1][1] * JtD[1] /* + K[1][2] * JtD[2] */;
00596 
00597     KJtD[2] = /* K[2][0] * JtD[0] + K[2][1] * JtD[1] */ + K[2][2] * JtD[2];
00598 
00599     //  F = J * KJtD;
00600 
00601 
00602     // Optimisations: The following values are 0 (per computeStrainDisplacement )
00603 
00604     // J[0][1]
00605     // J[1][0]
00606     // J[2][1]
00607     // J[3][0]
00608     // J[4][0]
00609     // J[4][1]
00610     // J[5][0]
00611     // J[5][2]
00612 
00613     F[0] = J[0][0] * KJtD[0] + /* J[0][1] * KJtD[1] + */ J[0][2] * KJtD[2];
00614 
00615     F[1] = /* J[1][0] * KJtD[0] + */ J[1][1] * KJtD[1] + J[1][2] * KJtD[2];
00616 
00617     F[2] = J[2][0] * KJtD[0] + /* J[2][1] * KJtD[1] + */ J[2][2] * KJtD[2];
00618 
00619     F[3] = /* J[3][0] * KJtD[0] + */ J[3][1] * KJtD[1] + J[3][2] * KJtD[2];
00620 
00621     F[4] = /* J[4][0] * KJtD[0] + J[4][1] * KJtD[1] + */ J[4][2] * KJtD[2];
00622 
00623     F[5] = /* J[5][0] * KJtD[0] + */ J[5][1] * KJtD[1] /* + J[5][2] * KJtD[2] */ ;
00624 }
00625 
00626 
00627 /*
00628 ** SMALL DEFORMATION METHODS
00629 */
00630 
00631 
00632 template <class DataTypes>
00633 void TriangularFEMForceField<DataTypes>::initSmall()
00634 {
00635 
00636 #ifdef DEBUG_TRIANGLEFEM
00637     std::cout << "TriangularFEMForceField::initSmall\n";
00638 #endif
00639 
00640 }
00641 
00642 
00643 template <class DataTypes>
00644 void TriangularFEMForceField<DataTypes>::accumulateForceSmall( VecCoord &f, const VecCoord &p, Index elementIndex, bool implicit )
00645 {
00646 
00647 #ifdef DEBUG_TRIANGLEFEM
00648     std::cout << "TriangularFEMForceField::accumulateForceSmall\n";
00649 #endif
00650 
00651     Index a = _topology->getTriangle(elementIndex)[0]; //(*_indexedElements)
00652     Index b = _topology->getTriangle(elementIndex)[1];
00653     Index c = _topology->getTriangle(elementIndex)[2];
00654 
00655     Coord deforme_a, deforme_b, deforme_c;
00656     deforme_b = p[b]-p[a];
00657     deforme_c = p[c]-p[a];
00658     deforme_a = Coord(0,0,0);
00659 
00660     // displacements
00661     Displacement D;
00662     D[0] = 0;
00663     D[1] = 0;
00664     D[2] = ((*_initialPoints)[b][0]-(*_initialPoints)[a][0]) - deforme_b[0];
00665     D[3] = 0;
00666     D[4] = ((*_initialPoints)[c][0]-(*_initialPoints)[a][0]) - deforme_c[0];
00667     D[5] = ((*_initialPoints)[c][1]-(*_initialPoints)[a][1]) - deforme_c[1];
00668 
00669 
00670     StrainDisplacement J;
00671     computeStrainDisplacement(J,deforme_a,deforme_b,deforme_c);
00672     if (implicit)
00673         triangleInfo[elementIndex].strainDisplacementMatrix = J;
00674 
00675     // compute force on element
00676     Displacement F;
00677     computeForce( F, D, triangleInfo[elementIndex].materialMatrix, J );
00678 
00679     f[a] += Coord( F[0], F[1], 0);
00680     f[b] += Coord( F[2], F[3], 0);
00681     f[c] += Coord( F[4], F[5], 0);
00682 }
00683 
00684 
00685 template <class DataTypes>
00686 void TriangularFEMForceField<DataTypes>::accumulateDampingSmall(VecCoord&, Index )
00687 {
00688 
00689 #ifdef DEBUG_TRIANGLEFEM
00690     std::cout << "TriangularFEMForceField::accumulateDampingSmall\n";
00691 #endif
00692 
00693 }
00694 
00695 
00696 template <class DataTypes>
00697 void TriangularFEMForceField<DataTypes>::applyStiffnessSmall(VecCoord &v, Real h, const VecCoord &x)
00698 {
00699 
00700 #ifdef DEBUG_TRIANGLEFEM
00701     std::cout << "TriangularFEMForceField::applyStiffnessSmall\n";
00702 #endif
00703 
00704     int nbTriangles=_topology->getNbTriangles();    
00705 
00706     //typename VecElement::const_iterator it;
00707     //unsigned int i(0);
00708 
00709     for( int i=0; i<nbTriangles; i+=1) //it = _indexedElements->begin() ; it != _indexedElements->end() ; ++it, ++i
00710     {
00711         Index a = _topology->getTriangle(i)[0]; //(*it)[0];
00712         Index b = _topology->getTriangle(i)[1];
00713         Index c = _topology->getTriangle(i)[2];
00714 
00715         Displacement X;
00716 
00717         X[0] = x[a][0];
00718         X[1] = x[a][1];
00719 
00720         X[2] = x[b][0];
00721         X[3] = x[b][1];
00722 
00723         X[4] = x[c][0];
00724         X[5] = x[c][1];
00725 
00726         Displacement F;
00727         computeForce( F, X, triangleInfo[i].materialMatrix, triangleInfo[i].strainDisplacementMatrix );
00728 
00729         v[a] += Coord(-h*F[0], -h*F[1], 0);
00730         v[b] += Coord(-h*F[2], -h*F[3], 0);
00731         v[c] += Coord(-h*F[4], -h*F[5], 0);
00732     }
00733 }
00734 
00735 
00736 /*
00737 ** LARGE DEFORMATION METHODS
00738 */
00739 
00740 template <class DataTypes>
00741 void TriangularFEMForceField<DataTypes>::initLarge(int i, Index&a, Index&b, Index&c)
00742 {
00743 
00744 #ifdef DEBUG_TRIANGLEFEM
00745     std::cout << "TriangularFEMForceField::initLarge\n";
00746 #endif  
00747 
00748     //_rotatedInitialElements.resize(_indexedElements->size());
00749 
00750     //typename VecElement::const_iterator it;
00751     //unsigned int i(0);
00752 
00753     TriangleInformation *tinfo = &triangleInfo[i];
00754 
00755     // Rotation matrix (initial triangle/world)
00756     // first vector on first edge
00757     // second vector in the plane of the two first edges
00758     // third vector orthogonal to first and second
00759     Transformation R_0_1;
00760     
00761     //cerr<<"TriangularFEMForceField<DataTypes>::initLarge(), x.size() = "<<_object->getX()->size()<<", (*_initialPoints).size() = "<<(*_initialPoints).size()<<endl;
00762     computeRotationLarge( R_0_1, (*_initialPoints), a, b, c );
00763     
00764     tinfo->rotatedInitialElements[0] = R_0_1 * (*_initialPoints)[a]; //_rotatedInitialElements ... (*_initialPoints)
00765     tinfo->rotatedInitialElements[1] = R_0_1 * (*_initialPoints)[b];
00766     tinfo->rotatedInitialElements[2] = R_0_1 * (*_initialPoints)[c];
00767     
00768     tinfo->rotatedInitialElements[1] -= tinfo->rotatedInitialElements[0];
00769     tinfo->rotatedInitialElements[2] -= tinfo->rotatedInitialElements[0];
00770     tinfo->rotatedInitialElements[0] = Coord(0,0,0);
00771 }
00772 
00773 
00774 template <class DataTypes>
00775 void TriangularFEMForceField<DataTypes>::computeRotationLarge( Transformation &r, const VecCoord &p, const Index &a, const Index &b, const Index &c)
00776 {
00777 
00778 #ifdef DEBUG_TRIANGLEFEM
00779     std::cout << "TriangularFEMForceField::computeRotationLarge\n";
00780 #endif
00781 
00782     // first vector on first edge
00783     // second vector in the plane of the two first edges
00784     // third vector orthogonal to first and second
00785 
00786     Coord edgex = p[b] - p[a];
00787     edgex.normalize();
00788 
00789     Coord edgey = p[c] - p[a];
00790     edgey.normalize();
00791 
00792     Coord edgez;
00793     edgez = cross(edgex, edgey);
00794     edgez.normalize();
00795 
00796     edgey = cross(edgez, edgex);
00797     edgey.normalize();
00798 
00799     r[0][0] = edgex[0];
00800     r[0][1] = edgex[1];
00801     r[0][2] = edgex[2];
00802     r[1][0] = edgey[0];
00803     r[1][1] = edgey[1];
00804     r[1][2] = edgey[2];
00805     r[2][0] = edgez[0];
00806     r[2][1] = edgez[1];
00807     r[2][2] = edgez[2];
00808 }
00809 
00810 
00811 template <class DataTypes>
00812 void TriangularFEMForceField<DataTypes>::accumulateForceLarge(VecCoord &f, const VecCoord &p, Index elementIndex, bool implicit )
00813 {
00814 
00815 #ifdef DEBUG_TRIANGLEFEM
00816     std::cout << "TriangularFEMForceField::accumulateForceLarge\n";
00817 #endif
00818 
00819 //  std::cout << "Triangle " << elementIndex << std::endl;
00820 
00821     Index a = _topology->getTriangle(elementIndex)[0];
00822     Index b = _topology->getTriangle(elementIndex)[1];
00823     Index c = _topology->getTriangle(elementIndex)[2];
00824 
00825     // Rotation matrix (deformed and displaced Triangle/world)
00826     Transformation R_2_0, R_0_2;
00827     computeRotationLarge( R_0_2, p, a, b, c);
00828     R_2_0.transpose(R_0_2);
00829 
00830 
00831     // positions of the deformed and displaced Tetrahedre in its frame
00832     Coord deforme_a, deforme_b, deforme_c;
00833     //deforme_a = R_0_2 * p[a];
00834     //deforme_b = R_0_2 * p[b];
00835     //deforme_c = R_0_2 * p[c];
00836     //deforme_b -= deforme_a;
00837     //deforme_c -= deforme_a;
00838     //deforme_a = Coord(0,0,0);
00839     deforme_b = R_0_2 * (p[b]-p[a]);
00840     deforme_c = R_0_2 * (p[c]-p[a]);
00841 
00842     // displacements
00843     Displacement D;
00844     D[0] = 0;
00845     D[1] = 0;
00846     D[2] = triangleInfo[elementIndex].rotatedInitialElements[1][0] - deforme_b[0];
00847     D[3] = 0;
00848     D[4] = triangleInfo[elementIndex].rotatedInitialElements[2][0] - deforme_c[0];
00849     D[5] = triangleInfo[elementIndex].rotatedInitialElements[2][1] - deforme_c[1];
00850 
00851     // shape functions matrix
00852     StrainDisplacement J;
00853     computeStrainDisplacement(J,deforme_a,deforme_b,deforme_c);
00854 
00855     if(implicit)
00856     {
00857         triangleInfo[elementIndex].strainDisplacementMatrix = J;
00858         triangleInfo[elementIndex].rotation = R_2_0 ;
00859     }
00860 
00861     // compute force on element
00862     Displacement F;
00863     computeForce( F, D, triangleInfo[elementIndex].materialMatrix, J );
00864 
00865     f[a] += R_2_0 * Coord(F[0], F[1], 0);
00866     f[b] += R_2_0 * Coord(F[2], F[3], 0);
00867     f[c] += R_2_0 * Coord(F[4], F[5], 0);
00868     
00869     if (f_fracturable.getValue())
00870     {
00871         Coord v, Rv;
00872         double maxEigenValue;
00873         computeEigenStrain(v, J, D, maxEigenValue);
00874 
00875     //  if (fabs(maxEigenValue) > 0.1)
00876     //  {
00877             triangleInfo[elementIndex].eigenValue = fabs(maxEigenValue);
00878     //  }
00879     /*  else
00880         {
00881             v[0] = 0.0;
00882             v[1] = 0.0;
00883             v[2] = 0.0;
00884             triangleInfo[elementIndex].eigenValue = 0.0;
00885         }
00886     */
00887         //Rv = R_2_0 * v;
00888         Rv = (p[b]-p[a]) * v[0] + (p[c]-p[a]) * v[1];
00889         
00890         triangleInfo[elementIndex].principalStrainDirection = Rv;
00891 
00892         //std::cout << "Rv = " << Rv << std::endl; // eigenvectors = columns of V
00893     }
00894 }
00895 
00896 
00897 template <class DataTypes>
00898 void TriangularFEMForceField<DataTypes>::accumulateDampingLarge(VecCoord &, Index )
00899 {
00900 
00901 #ifdef DEBUG_TRIANGLEFEM
00902     std::cout << "TriangularFEMForceField::accumulateDampingLarge\n";
00903 #endif
00904 
00905 }
00906 
00907 
00908 template <class DataTypes>
00909 void TriangularFEMForceField<DataTypes>::applyStiffnessLarge(VecCoord &v, Real h, const VecCoord &x)
00910 {
00911 
00912 #ifdef DEBUG_TRIANGLEFEM
00913     std::cout << "TriangularFEMForceField::applyStiffnessLarge\n";
00914 #endif
00915 
00916     int nbTriangles=_topology->getNbTriangles();    
00917 
00918     //typename VecElement::const_iterator it;
00919     //unsigned int i(0);
00920 
00921     for(int i=0; i<nbTriangles; i+=1) //it = _indexedElements->begin() ; it != _indexedElements->end() ; ++it, ++i
00922     {
00923         Index a = _topology->getTriangle(i)[0];
00924         Index b = _topology->getTriangle(i)[1];
00925         Index c = _topology->getTriangle(i)[2];
00926 
00927         Transformation R_0_2;
00928         R_0_2.transpose(triangleInfo[i].rotation);
00929 
00930         Displacement X;
00931         Coord x_2;
00932 
00933         x_2 = R_0_2 * x[a];
00934         X[0] = x_2[0];
00935         X[1] = x_2[1];
00936 
00937         x_2 = R_0_2 * x[b];
00938         X[2] = x_2[0];
00939         X[3] = x_2[1];
00940 
00941         x_2 = R_0_2 * x[c];
00942         X[4] = x_2[0];
00943         X[5] = x_2[1];
00944 
00945         Displacement F;
00946         computeForce( F, X, triangleInfo[i].materialMatrix, triangleInfo[i].strainDisplacementMatrix );
00947 
00948         v[a] += triangleInfo[i].rotation * Coord(-h*F[0], -h*F[1], 0);
00949         v[b] += triangleInfo[i].rotation * Coord(-h*F[2], -h*F[3], 0);
00950         v[c] += triangleInfo[i].rotation * Coord(-h*F[4], -h*F[5], 0);
00951     }
00952 }
00953 
00954 static Vec3d ColorMap[64] = {
00955         Vec3d( 0.0,        0.0,       0.5625 ),
00956         Vec3d( 0.0,        0.0,       0.625  ), 
00957         Vec3d( 0.0,        0.0,       0.6875 ),
00958         Vec3d( 0.0,        0.0,         0.75 ),
00959         Vec3d( 0.0,        0.0,       0.8125 ),
00960         Vec3d( 0.0,        0.0,        0.875 ),
00961         Vec3d( 0.0,        0.0,       0.9375 ),
00962         Vec3d( 0.0,        0.0,          1.0 ),
00963         Vec3d( 0.0,     0.0625,          1.0 ),
00964         Vec3d( 0.0,      0.125,          1.0 ),
00965         Vec3d( 0.0,     0.1875,          1.0 ),
00966         Vec3d( 0.0,       0.25,          1.0 ),
00967         Vec3d( 0.0,     0.3125,          1.0 ),
00968         Vec3d( 0.0,      0.375,          1.0 ),
00969         Vec3d( 0.0,     0.4375,          1.0 ),
00970         Vec3d( 0.0,        0.5,          1.0 ),
00971         Vec3d( 0.0,     0.5625,          1.0 ),
00972         Vec3d( 0.0,      0.625,          1.0 ),
00973         Vec3d( 0.0,     0.6875,          1.0 ),
00974         Vec3d( 0.0,       0.75,          1.0 ),
00975         Vec3d( 0.0,     0.8125,          1.0 ),
00976         Vec3d( 0.0,     0.875,           1.0 ),
00977         Vec3d( 0.0,     0.9375,          1.0 ),
00978         Vec3d( 0.0,        1.0,          1.0 ),
00979         Vec3d( 0.0625,     1.0,          1.0 ),
00980         Vec3d( 0.125,      1.0,       0.9375 ),
00981         Vec3d( 0.1875,     1.0,        0.875 ),
00982         Vec3d( 0.25,       1.0,       0.8125 ),
00983         Vec3d( 0.3125,     1.0,         0.75 ),
00984         Vec3d( 0.375,      1.0,       0.6875 ),
00985         Vec3d( 0.4375,     1.0,        0.625 ),
00986         Vec3d( 0.5,        1.0,       0.5625 ),
00987         Vec3d( 0.5625,     1.0,          0.5 ),
00988         Vec3d( 0.625,      1.0,       0.4375 ),
00989         Vec3d( 0.6875,     1.0,        0.375 ),
00990         Vec3d( 0.75,       1.0,       0.3125 ),
00991         Vec3d( 0.8125,     1.0,         0.25 ),
00992         Vec3d( 0.875,      1.0,       0.1875 ),
00993         Vec3d( 0.9375,     1.0,        0.125 ),
00994         Vec3d( 1.0,        1.0,       0.0625 ),
00995         Vec3d( 1.0,        1.0,          0.0 ),
00996         Vec3d( 1.0,       0.9375,        0.0 ),
00997         Vec3d( 1.0,        0.875,        0.0 ),
00998         Vec3d( 1.0,       0.8125,        0.0 ),
00999         Vec3d( 1.0,         0.75,        0.0 ),
01000         Vec3d( 1.0,       0.6875,        0.0 ),
01001         Vec3d( 1.0,        0.625,        0.0 ),
01002         Vec3d( 1.0,       0.5625,        0.0 ),
01003         Vec3d( 1.0,          0.5,        0.0 ),
01004         Vec3d( 1.0,       0.4375,        0.0 ),
01005         Vec3d( 1.0,        0.375,        0.0 ),
01006         Vec3d( 1.0,       0.3125,        0.0 ),
01007         Vec3d( 1.0,         0.25,        0.0 ),
01008         Vec3d( 1.0,       0.1875,        0.0 ),
01009         Vec3d( 1.0,        0.125,        0.0 ),
01010         Vec3d( 1.0,       0.0625,        0.0 ),
01011         Vec3d( 1.0,          0.0,        0.0 ),
01012         Vec3d( 0.9375,       0.0,        0.0 ),
01013         Vec3d( 0.875,        0.0,        0.0 ),
01014         Vec3d( 0.8125,       0.0,        0.0 ),
01015         Vec3d( 0.75,         0.0,        0.0 ),
01016         Vec3d( 0.6875,       0.0,        0.0 ),
01017         Vec3d( 0.625,        0.0,        0.0 ),
01018         Vec3d( 0.5625,       0.0,        0.0 ) }; 
01019 
01020 
01021 template<class DataTypes>
01022 int TriangularFEMForceField<DataTypes>::getFracturedEdge()
01023 {
01024     if (f_fracturable.getValue())
01025     {
01026         int nbEdges = _topology->getNbEdges();
01027 
01028         for( int i=0; i<nbEdges; i++ )
01029         {
01030             if (edgeInfo[i].fracturable)
01031             {
01032                 return i;
01033             }
01034         }
01035     }
01036     
01037     return -1;
01038 }
01039     
01040 
01041 template<class DataTypes>
01042 void TriangularFEMForceField<DataTypes>::draw()
01043 {
01044     if (!getContext()->getShowForceFields())
01045         return;
01046 //     if (!this->_object)
01047 //         return;
01048 
01049     if (getContext()->getShowWireFrame())
01050         glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
01051 
01052     const VecCoord& x = *this->mstate->getX();
01053     unsigned int nbTriangles=_topology->getNbTriangles();
01054 
01055     glDisable(GL_LIGHTING);
01056     if (!f_fracturable.getValue())
01057     {
01058 
01059     glBegin(GL_TRIANGLES);
01060     //typename VecElement::const_iterator it;
01061     for(unsigned int i=0;i<nbTriangles; ++i) //it = _indexedElements->begin() ; it != _indexedElements->end() ; ++it
01062     {
01063         Index a = _topology->getTriangle(i)[0];//(*it)[0];
01064         Index b = _topology->getTriangle(i)[1];//(*it)[1];
01065         Index c = _topology->getTriangle(i)[2];//(*it)[2];
01066 
01067         glColor4f(0,1,0,1);
01068         helper::gl::glVertexT(x[a]);
01069         glColor4f(0,0.5,0.5,1);
01070         helper::gl::glVertexT(x[b]);
01071         glColor4f(0,0,1,1);
01072         helper::gl::glVertexT(x[c]);
01073     }
01074     glEnd();
01075     }
01076     if (f_fracturable.getValue())
01077     {
01078       if (showStressValue.getValue())
01079         {       
01080         unsigned int nbPoints = _topology->getNbPoints();
01081 
01082         double totalSumEigenValues = vertexInfo[0].sumEigenValues;
01083         double max = vertexInfo[0].sumEigenValues;
01084 
01085         for( unsigned int i=1; i<nbPoints; i++ )
01086         {
01087             totalSumEigenValues += vertexInfo[i].sumEigenValues;
01088             if (vertexInfo[i].sumEigenValues > max)
01089                 max = vertexInfo[i].sumEigenValues;
01090         }
01091 
01092         glBegin(GL_TRIANGLES);
01093         //typename VecElement::const_iterator it;
01094         for(unsigned int i=0;i<nbTriangles; ++i) //it = _indexedElements->begin() ; it != _indexedElements->end() ; ++it
01095 
01096         {
01097             Index a = _topology->getTriangle(i)[0];//(*it)[0];
01098             Index b = _topology->getTriangle(i)[1];//(*it)[1];
01099             Index c = _topology->getTriangle(i)[2];//(*it)[2];
01100 
01101             float v = (float)((vertexInfo[a].sumEigenValues + vertexInfo[b].sumEigenValues + vertexInfo[c].sumEigenValues) / 3.0);
01102             v /= (float)max;
01103             
01104             Vec3d color = ColorMap[(int)(v*63)];
01105             glColor3dv(color.ptr());
01106             //glColor4f((float)(meanEV / max), (float)(1- meanEV / max), 0.0f, 1.0f);
01107             helper::gl::glVertexT(x[a]);
01108             helper::gl::glVertexT(x[b]);
01109             helper::gl::glVertexT(x[c]);
01110         }
01111         glEnd();
01112 
01113 /*
01114         if (nbPoints > 0)
01115         {
01116             double max = vertexInfo[0].sumEigenValues;
01117             unsigned int mostDeformableVertexIndex = 0;
01118             for( unsigned int i=1; i<nbPoints; i++ )
01119             {
01120                 if (vertexInfo[i].sumEigenValues > max)
01121                 {
01122                     mostDeformableVertexIndex = i;
01123                     max = vertexInfo[i].sumEigenValues;
01124                 }
01125             }
01126  
01127             glPointSize(8);
01128             glBegin(GL_POINTS);
01129             glColor4f(1,1,1,1);
01130             helper::gl::glVertexT(x[mostDeformableVertexIndex]);
01131             glEnd();
01132             glPointSize(1);
01133         }
01134         
01135 */
01136 /*
01137             glBegin(GL_LINES);
01138         for( unsigned int i=0; i<nbPoints; i++ )
01139         {
01140             glColor4f(1,0,1,1);
01141             helper::gl::glVertexT(x[i]-vertexInfo[i].meanStrainDirection);
01142             helper::gl::glVertexT(x[i]+vertexInfo[i].meanStrainDirection);
01143             //helper::gl::glVertexT(x[i]-vertexInfo[i].meanStrainDirection * 2.5);
01144             //helper::gl::glVertexT(x[i]+vertexInfo[i].meanStrainDirection * 2.5);
01145         }
01146             glEnd();
01147 */
01148         }
01149       if (showStressVector.getValue())
01150         {
01151         //const VecCoord& x = *this->mstate->getX();
01152         //int nbTriangles=_topology->getNbTriangles();      
01153         glColor4f(1,0,1,1);
01154         glBegin(GL_LINES);
01155         //typename VecElement::const_iterator it;
01156         for(unsigned int i=0;i<nbTriangles; ++i) //it = _indexedElements->begin() ; it != _indexedElements->end() ; ++it
01157         {
01158             Index a = _topology->getTriangle(i)[0];
01159             Index b = _topology->getTriangle(i)[1];
01160             Index c = _topology->getTriangle(i)[2];
01161             Coord center = (x[a]+x[b]+x[c])/3;
01162             Coord d = triangleInfo[i].principalStrainDirection*0.4;
01163             helper::gl::glVertexT(center-d);
01164             helper::gl::glVertexT(center+d);
01165         }
01166         glEnd();
01167         }
01168 /*      
01169         
01170         int nbEdges = _topology->getNbEdges();
01171 
01172         for( unsigned int i=0; i<nbEdges; i++ )
01173         {
01174             if (edgeInfo[i].fracturable)
01175             {
01176                 glLineWidth(7);
01177                 glBegin(GL_LINES);
01178                 glColor4f(1,0.5,0.25,1);
01179                 helper::gl::glVertexT(x[_topology->getEdge(i)[0]]);
01180                 helper::gl::glVertexT(x[_topology->getEdge(i)[1]]);
01181                 glEnd();
01182                 glLineWidth(1);
01183             }
01184         }
01185 */
01186     }
01187     
01188     if (getContext()->getShowWireFrame())
01189         glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
01190 }
01191 
01192 
01193 SOFA_DECL_CLASS(TriangularFEMForceField)
01194 
01195 
01196 // Register in the Factory
01197 int TriangularFEMForceFieldClass = core::RegisterObject("Triangular finite elements")
01198 #ifndef SOFA_FLOAT
01199 .add< TriangularFEMForceField<Vec3dTypes> >()
01200 #endif
01201 #ifndef SOFA_DOUBLE
01202 .add< TriangularFEMForceField<Vec3fTypes> >()
01203 #endif
01204 ;
01205 
01206 #ifndef SOFA_FLOAT
01207 template class TriangularFEMForceField<Vec3dTypes>;
01208 #endif
01209 #ifndef SOFA_DOUBLE
01210 template class TriangularFEMForceField<Vec3fTypes>;
01211 #endif
01212 
01213     
01214 } // namespace forcefield
01215 
01216 } // namespace component
01217 
01218 } // namespace sofa

Generated on Sun Nov 23 03:18:25 2008 for Sofa by  doxygen 1.5.7.1