00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #include <sofa/component/forcefield/TriangleFEMForceField.h>
00026 #include <sofa/core/ObjectFactory.h>
00027 #include <sofa/core/componentmodel/topology/BaseMeshTopology.h>
00028 #include <sofa/helper/gl/template.h>
00029 #include <fstream>
00030 #include <iostream>
00031 #include <vector>
00032 #include <sofa/defaulttype/Vec3Types.h>
00033
00034
00035 #ifdef _WIN32
00036 #include <windows.h>
00037 #endif
00038
00039
00040
00041
00042 namespace sofa
00043 {
00044
00045 namespace component
00046 {
00047
00048 namespace forcefield
00049 {
00050
00051 using namespace sofa::defaulttype;
00052
00053 using std::cerr;
00054 using std::cout;
00055 using std::endl;
00056
00057 template <class DataTypes>
00058 TriangleFEMForceField<DataTypes>::
00059 TriangleFEMForceField()
00060 : _mesh(NULL)
00061 , _indexedElements(NULL)
00062 , _initialPoints(initData(&_initialPoints, "initialPoints", "Initial Position"))
00063 , method(LARGE)
00064 , f_method(initData(&f_method,std::string("large"),"method","large: large displacements, small: small displacements"))
00065 , f_poisson(initData(&f_poisson,(Real)0.3,"poissonRatio","Poisson ratio in Hooke's law"))
00066 , f_young(initData(&f_young,(Real)1000.,"youngModulus","Young modulus in Hooke's law"))
00067 , f_damping(initData(&f_damping,(Real)0.,"damping","Ratio damping/stiffness"))
00068 {}
00069
00070 template <class DataTypes>
00071 TriangleFEMForceField<DataTypes>::~TriangleFEMForceField()
00072 {
00073 }
00074
00075
00076 template <class DataTypes>
00077 void TriangleFEMForceField<DataTypes>::init()
00078 {
00079 this->Inherited::init();
00080 if (f_method.getValue() == "small")
00081 method = SMALL;
00082 else if (f_method.getValue() == "large")
00083 method = LARGE;
00084
00085 cerr<<"TriangleFEMForceField<DataTypes>::init(), node = "<<this->getContext()->getName()<<endl;
00086 _mesh = this->getContext()->getMeshTopology();
00087
00088 if (_mesh==NULL || (_mesh->getTriangles().empty() && _mesh->getNbQuads()<=0))
00089 {
00090 std::cerr << "ERROR(TriangleFEMForceField): object must have a triangular MeshTopology.\n";
00091 return;
00092 }
00093 if (!_mesh->getTriangles().empty())
00094 {
00095 _indexedElements = & (_mesh->getTriangles());
00096 }
00097 else
00098 {
00099 sofa::core::componentmodel::topology::BaseMeshTopology::SeqTriangles* trias = new sofa::core::componentmodel::topology::BaseMeshTopology::SeqTriangles;
00100 int nbcubes = _mesh->getNbQuads();
00101 trias->reserve(nbcubes*2);
00102 for (int i=0;i<nbcubes;i++)
00103 {
00104 sofa::core::componentmodel::topology::BaseMeshTopology::Quad q = _mesh->getQuad(i);
00105 trias->push_back(Element(q[0],q[1],q[2]));
00106 trias->push_back(Element(q[0],q[2],q[3]));
00107 }
00108 _indexedElements = trias;
00109 }
00110
00111 if (_initialPoints.getValue().size() == 0)
00112 {
00113 VecCoord& p = *this->mstate->getX();
00114 _initialPoints.setValue(p);
00115 }
00116
00117 _strainDisplacements.resize(_indexedElements->size());
00118 _rotations.resize(_indexedElements->size());
00119
00120 computeMaterialStiffnesses();
00121
00122 initSmall();
00123 initLarge();
00124 }
00125
00126
00127
00128 template <class DataTypes>
00129 void TriangleFEMForceField<DataTypes>::reinit()
00130 {
00131 if (f_method.getValue() == "small")
00132 method = SMALL;
00133 else if (f_method.getValue() == "large")
00134 method = LARGE;
00135
00136 computeMaterialStiffnesses();
00137
00138 initSmall();
00139 initLarge();
00140 }
00141
00142
00143 template <class DataTypes>
00144 void TriangleFEMForceField<DataTypes>::addForce(VecDeriv& f, const VecCoord& x, const VecDeriv& )
00145 {
00146 f.resize(x.size());
00147
00148 if(f_damping.getValue() != 0)
00149 {
00150 if(method == SMALL)
00151 {
00152 for( unsigned int i=0; i<_indexedElements->size(); i+=3 )
00153 {
00154 accumulateForceSmall( f, x, i/3, true );
00155 accumulateDampingSmall( f, i/3 );
00156 }
00157 }
00158 else
00159 {
00160 for( unsigned int i=0; i<_indexedElements->size(); i+=3 )
00161 {
00162 accumulateForceLarge( f, x, i/3, true );
00163 accumulateDampingLarge( f, i/3 );
00164 }
00165 }
00166 }
00167 else
00168 {
00169 if(method==SMALL)
00170 {
00171 typename VecElement::const_iterator it;
00172 unsigned int i(0);
00173
00174 for(it = _indexedElements->begin() ; it != _indexedElements->end() ; ++it, ++i)
00175 {
00176 accumulateForceSmall( f, x, i, true );
00177 }
00178 }
00179 else
00180 {
00181 typename VecElement::const_iterator it;
00182 unsigned int i(0);
00183
00184 for(it = _indexedElements->begin() ; it != _indexedElements->end() ; ++it, ++i)
00185 {
00186 accumulateForceLarge( f, x, i, true );
00187 }
00188 }
00189 }
00190 }
00191
00192
00193 template <class DataTypes>
00194 void TriangleFEMForceField<DataTypes>::addDForce(VecDeriv& df, const VecDeriv& dx)
00195 {
00196 Real h=1;
00197 df.resize(dx.size());
00198
00199 if (method == SMALL)
00200 {
00201 applyStiffnessSmall( df,h,dx );
00202 }
00203 else
00204 {
00205 applyStiffnessLarge( df,h,dx );
00206 }
00207 }
00208
00209 template <class DataTypes>
00210 double TriangleFEMForceField<DataTypes>::getPotentialEnergy(const VecCoord& )
00211 {
00212 cerr<<"TriangleFEMForceField::getPotentialEnergy-not-implemented !!!"<<endl;
00213 return 0;
00214 }
00215
00216 template <class DataTypes>
00217 void TriangleFEMForceField<DataTypes>::applyStiffness( VecCoord& v, Real h, const VecCoord& x )
00218 {
00219 if (method == SMALL)
00220 {
00221 applyStiffnessSmall( v,h,x );
00222 }
00223 else
00224 {
00225 applyStiffnessLarge( v,h,x );
00226 }
00227 }
00228
00229
00230 template <class DataTypes>
00231 void TriangleFEMForceField<DataTypes>::computeStrainDisplacement( StrainDisplacement &J, Coord , Coord b, Coord c )
00232 {
00233 #ifdef DEBUG_TRIANGLEFEM
00234 std::cout << "TriangleFEMForceField::computeStrainDisplacement\n";
00235 #endif
00236
00237
00238 Real determinant = b[0] * c[1];
00239
00240 J[0][0] = J[1][2] = -c[1] / determinant;
00241 J[0][2] = J[1][1] = (c[0] - b[0]) / determinant;
00242 J[2][0] = J[3][2] = c[1] / determinant;
00243 J[2][2] = J[3][1] = -c[0] / determinant;
00244 J[4][0] = J[5][2] = 0;
00245 J[4][2] = J[5][1] = b[0] / determinant;
00246 J[1][0] = J[3][0] = J[5][0] = J[0][1] = J[2][1] = J[4][1] = 0;
00247 }
00248
00249
00250 template <class DataTypes>
00251 void TriangleFEMForceField<DataTypes>::computeMaterialStiffnesses()
00252 {
00253 _materialsStiffnesses.resize(_indexedElements->size());
00254
00255 for(unsigned i = 0; i < _indexedElements->size(); ++i)
00256 {
00257 _materialsStiffnesses[i][0][0] = 1;
00258 _materialsStiffnesses[i][0][1] = f_poisson.getValue();
00259 _materialsStiffnesses[i][0][2] = 0;
00260 _materialsStiffnesses[i][1][0] = f_poisson.getValue();
00261 _materialsStiffnesses[i][1][1] = 1;
00262 _materialsStiffnesses[i][1][2] = 0;
00263 _materialsStiffnesses[i][2][0] = 0;
00264 _materialsStiffnesses[i][2][1] = 0;
00265 _materialsStiffnesses[i][2][2] = 0.5f * (1 - f_poisson.getValue());
00266
00267 _materialsStiffnesses[i] *= (f_young.getValue() / (12 * (1 - f_poisson.getValue() * f_poisson.getValue())));
00268 }
00269 }
00270
00271
00272 template <class DataTypes>
00273 void TriangleFEMForceField<DataTypes>::computeForce( Displacement &F, const Displacement &Depl, const MaterialStiffness &K, const StrainDisplacement &J )
00274 {
00275 Mat<3,6,Real> Jt;
00276 Jt.transpose( J );
00277
00278 Vec<3,Real> JtD;
00279
00280
00281
00282
00283
00284
00285
00286
00287
00288
00289
00290
00291
00292
00293
00294 JtD[0] = Jt[0][0] * Depl[0] + Jt[0][2] * Depl[2]
00295 ;
00296
00297 JtD[1] = Jt[1][1] * Depl[1] +
00298 Jt[1][3] * Depl[3] + Jt[1][5] * Depl[5];
00299
00300 JtD[2] = Jt[2][0] * Depl[0] + Jt[2][1] * Depl[1] + Jt[2][2] * Depl[2] +
00301 Jt[2][3] * Depl[3] + Jt[2][4] * Depl[4] ;
00302
00303 Vec<3,Real> KJtD;
00304
00305
00306
00307
00308
00309
00310
00311
00312
00313
00314 KJtD[0] = K[0][0] * JtD[0] + K[0][1] * JtD[1] ;
00315
00316 KJtD[1] = K[1][0] * JtD[0] + K[1][1] * JtD[1] ;
00317
00318 KJtD[2] = + K[2][2] * JtD[2];
00319
00320
00321
00322
00323
00324
00325
00326
00327
00328
00329
00330
00331
00332
00333
00334 F[0] = J[0][0] * KJtD[0] + J[0][2] * KJtD[2];
00335
00336 F[1] = J[1][1] * KJtD[1] + J[1][2] * KJtD[2];
00337
00338 F[2] = J[2][0] * KJtD[0] + J[2][2] * KJtD[2];
00339
00340 F[3] = J[3][1] * KJtD[1] + J[3][2] * KJtD[2];
00341
00342 F[4] = J[4][2] * KJtD[2];
00343
00344 F[5] = J[5][1] * KJtD[1] ;
00345 }
00346
00347
00348
00349
00350
00351
00352
00353 template <class DataTypes>
00354 void TriangleFEMForceField<DataTypes>::initSmall()
00355 {
00356
00357 #ifdef DEBUG_TRIANGLEFEM
00358 std::cout << "TriangleFEMForceField::initSmall\n";
00359 #endif
00360
00361 }
00362
00363
00364 template <class DataTypes>
00365 void TriangleFEMForceField<DataTypes>::accumulateForceSmall( VecCoord &f, const VecCoord &p, Index elementIndex, bool implicit )
00366 {
00367
00368 #ifdef DEBUG_TRIANGLEFEM
00369 std::cout << "TriangleFEMForceField::accumulateForceSmall\n";
00370 #endif
00371
00372 Index a = (*_indexedElements)[elementIndex][0];
00373 Index b = (*_indexedElements)[elementIndex][1];
00374 Index c = (*_indexedElements)[elementIndex][2];
00375
00376 Coord deforme_a, deforme_b, deforme_c;
00377 deforme_b = p[b]-p[a];
00378 deforme_c = p[c]-p[a];
00379 deforme_a = Coord(0,0,0);
00380
00381
00382 Displacement D;
00383 D[0] = 0;
00384 D[1] = 0;
00385 D[2] = (_initialPoints.getValue()[b][0]-_initialPoints.getValue()[a][0]) - deforme_b[0];
00386 D[3] = 0;
00387 D[4] = (_initialPoints.getValue()[c][0]-_initialPoints.getValue()[a][0]) - deforme_c[0];
00388 D[5] = (_initialPoints.getValue()[c][1]-_initialPoints.getValue()[a][1]) - deforme_c[1];
00389
00390
00391 StrainDisplacement J;
00392 computeStrainDisplacement(J,deforme_a,deforme_b,deforme_c);
00393 if (implicit)
00394 _strainDisplacements[elementIndex] = J;
00395
00396
00397 Displacement F;
00398 computeForce( F, D, _materialsStiffnesses[elementIndex], J );
00399
00400 f[a] += Coord( F[0], F[1], 0);
00401 f[b] += Coord( F[2], F[3], 0);
00402 f[c] += Coord( F[4], F[5], 0);
00403 }
00404
00405
00406 template <class DataTypes>
00407 void TriangleFEMForceField<DataTypes>::accumulateDampingSmall(VecCoord&, Index )
00408 {
00409
00410 #ifdef DEBUG_TRIANGLEFEM
00411 std::cout << "TriangleFEMForceField::accumulateDampingSmall\n";
00412 #endif
00413
00414 }
00415
00416
00417 template <class DataTypes>
00418 void TriangleFEMForceField<DataTypes>::applyStiffnessSmall(VecCoord &v, Real h, const VecCoord &x)
00419 {
00420
00421 #ifdef DEBUG_TRIANGLEFEM
00422 std::cout << "TriangleFEMForceField::applyStiffnessSmall\n";
00423 #endif
00424
00425 typename VecElement::const_iterator it;
00426 unsigned int i(0);
00427
00428 for(it = _indexedElements->begin() ; it != _indexedElements->end() ; ++it, ++i)
00429 {
00430 Index a = (*it)[0];
00431 Index b = (*it)[1];
00432 Index c = (*it)[2];
00433
00434 Displacement X;
00435
00436 X[0] = x[a][0];
00437 X[1] = x[a][1];
00438
00439 X[2] = x[b][0];
00440 X[3] = x[b][1];
00441
00442 X[4] = x[c][0];
00443 X[5] = x[c][1];
00444
00445 Displacement F;
00446 computeForce( F, X, _materialsStiffnesses[i], _strainDisplacements[i] );
00447
00448 v[a] += Coord(-h*F[0], -h*F[1], 0);
00449 v[b] += Coord(-h*F[2], -h*F[3], 0);
00450 v[c] += Coord(-h*F[4], -h*F[5], 0);
00451 }
00452 }
00453
00454
00455
00456
00457
00458
00459 template <class DataTypes>
00460 void TriangleFEMForceField<DataTypes>::initLarge()
00461 {
00462
00463 #ifdef DEBUG_TRIANGLEFEM
00464 std::cout << "TriangleFEMForceField::initLarge\n";
00465 #endif
00466
00467 _rotatedInitialElements.resize(_indexedElements->size());
00468
00469 typename VecElement::const_iterator it;
00470 unsigned int i(0);
00471
00472 for(it = _indexedElements->begin() ; it != _indexedElements->end() ; ++it, ++i)
00473 {
00474 Index a = (*it)[0];
00475 Index b = (*it)[1];
00476 Index c = (*it)[2];
00477
00478
00479
00480
00481
00482 Transformation R_0_1;
00483
00484 computeRotationLarge( R_0_1, _initialPoints.getValue(), a, b, c );
00485
00486 _rotatedInitialElements[i][0] = R_0_1 * _initialPoints.getValue()[a];
00487 _rotatedInitialElements[i][1] = R_0_1 * _initialPoints.getValue()[b];
00488 _rotatedInitialElements[i][2] = R_0_1 * _initialPoints.getValue()[c];
00489
00490 _rotatedInitialElements[i][1] -= _rotatedInitialElements[i][0];
00491 _rotatedInitialElements[i][2] -= _rotatedInitialElements[i][0];
00492 _rotatedInitialElements[i][0] = Coord(0,0,0);
00493 }
00494 }
00495
00496
00497 template <class DataTypes>
00498 void TriangleFEMForceField<DataTypes>::computeRotationLarge( Transformation &r, const VecCoord &p, const Index &a, const Index &b, const Index &c)
00499 {
00500
00501 #ifdef DEBUG_TRIANGLEFEM
00502 std::cout << "TriangleFEMForceField::computeRotationLarge\n";
00503 #endif
00504
00505
00506
00507
00508
00509 Coord edgex = p[b] - p[a];
00510 edgex.normalize();
00511
00512 Coord edgey = p[c] - p[a];
00513 edgey.normalize();
00514
00515 Coord edgez;
00516 edgez = cross(edgex, edgey);
00517 edgez.normalize();
00518
00519 edgey = cross(edgez, edgex);
00520 edgey.normalize();
00521
00522 r[0][0] = edgex[0];
00523 r[0][1] = edgex[1];
00524 r[0][2] = edgex[2];
00525 r[1][0] = edgey[0];
00526 r[1][1] = edgey[1];
00527 r[1][2] = edgey[2];
00528 r[2][0] = edgez[0];
00529 r[2][1] = edgez[1];
00530 r[2][2] = edgez[2];
00531 }
00532
00533
00534 template <class DataTypes>
00535 void TriangleFEMForceField<DataTypes>::accumulateForceLarge(VecCoord &f, const VecCoord &p, Index elementIndex, bool implicit )
00536 {
00537
00538 #ifdef DEBUG_TRIANGLEFEM
00539 std::cout << "TriangleFEMForceField::accumulateForceLarge\n";
00540 #endif
00541
00542 Index a = (*_indexedElements)[elementIndex][0];
00543 Index b = (*_indexedElements)[elementIndex][1];
00544 Index c = (*_indexedElements)[elementIndex][2];
00545
00546
00547 Transformation R_2_0, R_0_2;
00548 computeRotationLarge( R_0_2, p, a, b, c);
00549 R_2_0.transpose(R_0_2);
00550
00551
00552
00553 Coord deforme_a, deforme_b, deforme_c;
00554
00555
00556
00557
00558
00559
00560 deforme_b = R_0_2 * (p[b]-p[a]);
00561 deforme_c = R_0_2 * (p[c]-p[a]);
00562
00563
00564 Displacement D;
00565 D[0] = 0;
00566 D[1] = 0;
00567 D[2] = _rotatedInitialElements[elementIndex][1][0] - deforme_b[0];
00568 D[3] = 0;
00569 D[4] = _rotatedInitialElements[elementIndex][2][0] - deforme_c[0];
00570 D[5] = _rotatedInitialElements[elementIndex][2][1] - deforme_c[1];
00571
00572
00573 StrainDisplacement J;
00574 computeStrainDisplacement(J,deforme_a,deforme_b,deforme_c);
00575
00576 if(implicit)
00577 {
00578 _strainDisplacements[elementIndex] = J;
00579 _rotations[elementIndex] = R_2_0 ;
00580 }
00581
00582
00583 Displacement F;
00584 computeForce( F, D, _materialsStiffnesses[elementIndex], J );
00585
00586 f[a] += R_2_0 * Coord(F[0], F[1], 0);
00587 f[b] += R_2_0 * Coord(F[2], F[3], 0);
00588 f[c] += R_2_0 * Coord(F[4], F[5], 0);
00589 }
00590
00591
00592 template <class DataTypes>
00593 void TriangleFEMForceField<DataTypes>::accumulateDampingLarge(VecCoord &, Index )
00594 {
00595
00596 #ifdef DEBUG_TRIANGLEFEM
00597 std::cout << "TriangleFEMForceField::accumulateDampingLarge\n";
00598 #endif
00599
00600 }
00601
00602
00603 template <class DataTypes>
00604 void TriangleFEMForceField<DataTypes>::applyStiffnessLarge(VecCoord &v, Real h, const VecCoord &x)
00605 {
00606
00607 #ifdef DEBUG_TRIANGLEFEM
00608 std::cout << "TriangleFEMForceField::applyStiffnessLarge\n";
00609 #endif
00610
00611 typename VecElement::const_iterator it;
00612 unsigned int i(0);
00613
00614 for(it = _indexedElements->begin() ; it != _indexedElements->end() ; ++it, ++i)
00615 {
00616 Index a = (*it)[0];
00617 Index b = (*it)[1];
00618 Index c = (*it)[2];
00619
00620 Transformation R_0_2;
00621 R_0_2.transpose(_rotations[i]);
00622
00623 Displacement X;
00624 Coord x_2;
00625
00626 x_2 = R_0_2 * x[a];
00627 X[0] = x_2[0];
00628 X[1] = x_2[1];
00629
00630 x_2 = R_0_2 * x[b];
00631 X[2] = x_2[0];
00632 X[3] = x_2[1];
00633
00634 x_2 = R_0_2 * x[c];
00635 X[4] = x_2[0];
00636 X[5] = x_2[1];
00637
00638 Displacement F;
00639 computeForce( F, X, _materialsStiffnesses[i], _strainDisplacements[i] );
00640
00641 v[a] += _rotations[i] * Coord(-h*F[0], -h*F[1], 0);
00642 v[b] += _rotations[i] * Coord(-h*F[2], -h*F[3], 0);
00643 v[c] += _rotations[i] * Coord(-h*F[4], -h*F[5], 0);
00644 }
00645 }
00646
00647
00648 template<class DataTypes>
00649 void TriangleFEMForceField<DataTypes>::draw()
00650 {
00651 if (!getContext()->getShowForceFields())
00652 return;
00653
00654
00655
00656 if (getContext()->getShowWireFrame())
00657 glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
00658
00659 const VecCoord& x = *this->mstate->getX();
00660
00661 glDisable(GL_LIGHTING);
00662
00663 glBegin(GL_TRIANGLES);
00664 typename VecElement::const_iterator it;
00665 for(it = _indexedElements->begin() ; it != _indexedElements->end() ; ++it)
00666 {
00667 Index a = (*it)[0];
00668 Index b = (*it)[1];
00669 Index c = (*it)[2];
00670
00671 glColor4f(0,1,0,1);
00672 helper::gl::glVertexT(x[a]);
00673 glColor4f(0,0.5,0.5,1);
00674 helper::gl::glVertexT(x[b]);
00675 glColor4f(0,0,1,1);
00676 helper::gl::glVertexT(x[c]);
00677 }
00678 glEnd();
00679
00680 if (getContext()->getShowWireFrame())
00681 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
00682 }
00683
00684 SOFA_DECL_CLASS(TriangleFEMForceField)
00685
00686 using namespace sofa::defaulttype;
00687
00688
00689
00690
00691 int TriangleFEMForceFieldClass = core::RegisterObject("Triangular finite elements")
00692 #ifndef SOFA_FLOAT
00693 .add< TriangleFEMForceField<Vec3dTypes> >()
00694 #endif
00695 #ifndef SOFA_DOUBLE
00696 .add< TriangleFEMForceField<Vec3fTypes> >()
00697 #endif
00698 ;
00699
00700 #ifndef SOFA_FLOAT
00701 template class TriangleFEMForceField<Vec3dTypes>;
00702 #endif
00703 #ifndef SOFA_DOUBLE
00704 template class TriangleFEMForceField<Vec3fTypes>;
00705 #endif
00706
00707 }
00708
00709 }
00710
00711 }