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/collision/TriangleModel.h>
00026 #include <sofa/component/collision/CubeModel.h>
00027 #include <sofa/component/collision/Triangle.h>
00028 #include <sofa/simulation/tree/GNode.h>
00029 #include <sofa/component/topology/RegularGridTopology.h>
00030 #include <sofa/core/CollisionElement.h>
00031 #include <sofa/core/ObjectFactory.h>
00032 #include <vector>
00033 #include <sofa/helper/gl/template.h>
00034 #include <iostream>
00035
00036 #include <sofa/component/topology/PointSetTopologyChange.h>
00037 #include <sofa/component/topology/TriangleSetTopologyChange.h>
00038
00039
00040 using std::cerr;
00041 using std::endl;
00042
00043 namespace sofa
00044 {
00045
00046 namespace component
00047 {
00048
00049 namespace collision
00050 {
00051
00052 SOFA_DECL_CLASS(Triangle)
00053
00054 int TriangleModelClass = core::RegisterObject("collision model using a triangular mesh, as described in BaseMeshTopology")
00055 .add< TriangleModel >()
00056 .addAlias("TriangleMeshModel")
00057 .addAlias("TriangleSetModel")
00058 .addAlias("TriangleMesh")
00059 .addAlias("TriangleSet")
00060 .addAlias("Triangle")
00061 ;
00062
00063 TriangleModel::TriangleModel()
00064 : mstate(NULL)
00065 , computeNormals(initData(&computeNormals, true, "computeNormals", "set to false to disable computation of triangles normal"))
00066 , meshRevision(-1)
00067 {
00068 triangles = &mytriangles;
00069 }
00070
00071 void TriangleModel::resize(int size)
00072 {
00073 this->core::CollisionModel::resize(size);
00074 elems.resize(size);
00075 }
00076
00077 void TriangleModel::init()
00078 {
00079 _topology = this->getContext()->getMeshTopology();
00080
00081 this->CollisionModel::init();
00082 mstate = dynamic_cast< core::componentmodel::behavior::MechanicalState<Vec3Types>* > (getContext()->getMechanicalState());
00083
00084 if (mstate==NULL)
00085 {
00086 std::cerr << "ERROR: TriangleModel requires a Vec3 Mechanical Model.\n";
00087 return;
00088 }
00089
00090 if (!_topology) {
00091 std::cerr << "ERROR: TriangleModel requires a BaseMeshTopology.\n";
00092 return;
00093 }
00094
00095
00096 triangles = &_topology->getTriangles();
00097 resize(_topology->getNbTriangles());
00098
00099 updateFromTopology();
00100 updateNormals();
00101 }
00102
00103 void TriangleModel::updateNormals()
00104 {
00105 for (int i=0;i<size;i++)
00106 {
00107 Triangle t(this,i);
00108 const Vector3& pt1 = t.p1();
00109 const Vector3& pt2 = t.p2();
00110 const Vector3& pt3 = t.p3();
00111
00112 t.n() = cross(pt2-pt1,pt3-pt1);
00113 t.n().normalize();
00114 }
00115 }
00116
00117 void TriangleModel::updateFromTopology()
00118 {
00119
00120 const unsigned npoints = mstate->getX()->size();
00121 const unsigned ntris = _topology->getNbTriangles();
00122 const unsigned nquads = _topology->getNbQuads();
00123 const unsigned newsize = ntris+2*nquads;
00124
00125 int revision = _topology->getRevision();
00126 if (revision == meshRevision && newsize==(unsigned)size) {
00127 return;
00128 }
00129 needsUpdate=true;
00130
00131 resize(newsize);
00132
00133 if (newsize == ntris)
00134 {
00135 triangles = & _topology->getTriangles();
00136 }
00137 else
00138 {
00139 triangles = &mytriangles;
00140 mytriangles.resize(newsize);
00141 int index = 0;
00142 for (unsigned i=0; i<ntris; i++)
00143 {
00144 topology::BaseMeshTopology::Triangle idx = _topology->getTriangle(i);
00145 if (idx[0] >= npoints || idx[1] >= npoints || idx[2] >= npoints)
00146 {
00147 std::cerr << "ERROR: Out of range index in triangle "<<i<<": "<<idx[0]<<" "<<idx[1]<<" "<<idx[2]<<" ( total points="<<npoints<<")\n";
00148 if (idx[0] >= npoints) idx[0] = npoints-1;
00149 if (idx[1] >= npoints) idx[1] = npoints-1;
00150 if (idx[2] >= npoints) idx[2] = npoints-1;
00151 }
00152 mytriangles[index] = idx;
00153 ++index;
00154 }
00155 for (unsigned i=0; i<nquads; i++)
00156 {
00157 topology::BaseMeshTopology::Quad idx = _topology->getQuad(i);
00158 if (idx[0] >= npoints || idx[1] >= npoints || idx[2] >= npoints || idx[3] >= npoints)
00159 {
00160 std::cerr << "ERROR: Out of range index in quad "<<i<<": "<<idx[0]<<" "<<idx[1]<<" "<<idx[2]<<" "<<idx[3]<<" ( total points="<<npoints<<")\n";
00161 if (idx[0] >= npoints) idx[0] = npoints-1;
00162 if (idx[1] >= npoints) idx[1] = npoints-1;
00163 if (idx[2] >= npoints) idx[2] = npoints-1;
00164 if (idx[3] >= npoints) idx[3] = npoints-1;
00165 }
00166 mytriangles[index][0] = idx[1];
00167 mytriangles[index][1] = idx[2];
00168 mytriangles[index][2] = idx[0];
00169 ++index;
00170 mytriangles[index][0] = idx[3];
00171 mytriangles[index][1] = idx[0];
00172 mytriangles[index][2] = idx[2];
00173 ++index;
00174 }
00175 }
00176 updateFlags();
00177 meshRevision = revision;
00178 }
00179
00180 void TriangleModel::updateFlags(int ntri)
00181 {
00182 if (ntri < 0) ntri = triangles->size();
00183
00184
00185 vector<bool> pflags(mstate->getSize());
00186 std::set<std::pair<int,int> > eflags;
00187 for (unsigned i=0; i<triangles->size(); i++)
00188 {
00189 int f = 0;
00190 topology::Triangle t = (*triangles)[i];
00191 if (!pflags[t[0]])
00192 {
00193 f |= FLAG_P1;
00194 pflags[t[0]] = true;
00195 }
00196 if (!pflags[t[1]])
00197 {
00198 f |= FLAG_P2;
00199 pflags[t[1]] = true;
00200 }
00201 if (!pflags[t[2]])
00202 {
00203 f |= FLAG_P3;
00204 pflags[t[2]] = true;
00205 }
00206 if (eflags.insert( (t[0]<t[1])?std::make_pair(t[0],t[1]):std::make_pair(t[1],t[0]) ).second)
00207 {
00208 f |= FLAG_E12;
00209 }
00210 if (i < (unsigned)ntri && eflags.insert( (t[1]<t[2])?std::make_pair(t[1],t[2]):std::make_pair(t[2],t[1]) ).second)
00211 {
00212 f |= FLAG_E23;
00213 }
00214 if (eflags.insert( (t[2]<t[0])?std::make_pair(t[2],t[0]):std::make_pair(t[0],t[2]) ).second)
00215 {
00216 f |= FLAG_E31;
00217 }
00218 elems[i].flags = f;
00219 }
00220 }
00221
00222 void TriangleModel::handleTopologyChange()
00223 {
00224 bool debug_mode = false;
00225
00226 if (triangles != &mytriangles)
00227 {
00228
00229 resize(_topology->getNbTriangles());
00230 needsUpdate = true;
00231 updateFlags();
00232 updateNormals();
00233
00234 return;
00235 }
00236
00237 sofa::core::componentmodel::topology::TopologyModifier* topoMod;
00238 this->getContext()->get(topoMod);
00239
00240 if (topoMod) {
00241
00242 std::list<const sofa::core::componentmodel::topology::TopologyChange *>::const_iterator itBegin=_topology->firstChange();
00243 std::list<const sofa::core::componentmodel::topology::TopologyChange *>::const_iterator itEnd=_topology->lastChange();
00244
00245
00246 while( itBegin != itEnd )
00247 {
00248 core::componentmodel::topology::TopologyChangeType changeType = (*itBegin)->getChangeType();
00249
00250 switch( changeType ) {
00251
00252
00253 case core::componentmodel::topology::ENDING_EVENT:
00254 {
00255
00256 needsUpdate=true;
00257 break;
00258 }
00259
00260
00261 case core::componentmodel::topology::TRIANGLESADDED:
00262 {
00263
00264 TriangleInfo t;
00265 const sofa::component::topology::TrianglesAdded *ta=static_cast< const sofa::component::topology::TrianglesAdded * >( *itBegin );
00266 for (unsigned int i=0;i<ta->getNbAddedTriangles();++i) {
00267 mytriangles.push_back(ta->triangleArray[i]);
00268 }
00269 resize( mytriangles.size());
00270 needsUpdate=true;
00271
00272 break;
00273 }
00274
00275 case core::componentmodel::topology::TRIANGLESREMOVED:
00276 {
00277
00278 unsigned int last;
00279 unsigned int ind_last;
00280
00281 last= _topology->getNbPoints() - 1;
00282
00283 const sofa::helper::vector<unsigned int> &tab = ( static_cast< const sofa::component::topology::TrianglesRemoved *>( *itBegin ) )->getArray();
00284
00285 TriangleInfo tmp;
00286 topology::Triangle tmp2;
00287
00288 for (unsigned int i = 0; i <tab.size(); ++i)
00289 {
00290
00291 unsigned int ind_k = tab[i];
00292
00293 tmp = elems[ind_k];
00294 elems[ind_k] = elems[last];
00295 elems[last] = tmp;
00296
00297 tmp2 = mytriangles[ind_k];
00298 mytriangles[ind_k] = mytriangles[last];
00299 mytriangles[last] = tmp2;
00300
00301 ind_last = elems.size() - 1;
00302
00303 if(last != ind_last){
00304
00305 tmp = elems[last];
00306 elems[last] = elems[ind_last];
00307 elems[ind_last] = tmp;
00308
00309 tmp2 = mytriangles[last];
00310 mytriangles[last] = mytriangles[ind_last];
00311 mytriangles[ind_last] = tmp2;
00312 }
00313
00314 mytriangles.resize( elems.size() - 1 );
00315 resize( elems.size() - 1 );
00316
00317 --last;
00318 }
00319
00320 needsUpdate=true;
00321
00322 break;
00323 }
00324
00325
00326 case core::componentmodel::topology::POINTSREMOVED:
00327 {
00328
00329 if (_topology->getNbTriangles()>0) {
00330
00331 unsigned int last = _topology->getNbPoints() -1;
00332
00333 unsigned int i,j;
00334 const sofa::helper::vector<unsigned int> tab = ( static_cast< const sofa::component::topology::PointsRemoved * >( *itBegin ) )->getArray();
00335
00336 sofa::helper::vector<unsigned int> lastIndexVec;
00337 for(unsigned int i_init = 0; i_init < tab.size(); ++i_init){
00338
00339 lastIndexVec.push_back(last - i_init);
00340 }
00341
00342 for ( i = 0; i < tab.size(); ++i)
00343 {
00344 unsigned int i_next = i;
00345 bool is_reached = false;
00346 while( (!is_reached) && (i_next < lastIndexVec.size() - 1)){
00347
00348 i_next += 1 ;
00349 is_reached = is_reached || (lastIndexVec[i_next] == tab[i]);
00350 }
00351
00352 if(is_reached){
00353
00354 lastIndexVec[i_next] = lastIndexVec[i];
00355
00356 }
00357
00358 const sofa::helper::vector<unsigned int> &shell=_topology->getTriangleVertexShell(lastIndexVec[i]);
00359 for (j=0;j<shell.size();++j) {
00360
00361 unsigned int ind_j =shell[j];
00362
00363 if ((unsigned)mytriangles[ind_j][0]==last)
00364 mytriangles[ind_j][0]=tab[i];
00365 else if ((unsigned)mytriangles[ind_j][1]==last)
00366 mytriangles[ind_j][1]=tab[i];
00367 else if ((unsigned)mytriangles[ind_j][2]==last)
00368 mytriangles[ind_j][2]=tab[i];
00369 }
00370
00371 if (debug_mode) {
00372
00373 for (unsigned int j_loc=0;j_loc<mytriangles.size();++j_loc) {
00374
00375 bool is_forgotten = false;
00376 if ((unsigned)mytriangles[j_loc][0]==last){
00377 mytriangles[j_loc][0]=tab[i];
00378 is_forgotten=true;
00379
00380 }else{
00381 if ((unsigned)mytriangles[j_loc][1]==last){
00382 mytriangles[j_loc][1]=tab[i];
00383 is_forgotten=true;
00384
00385 }else{
00386 if ((unsigned)mytriangles[j_loc][2]==last){
00387 mytriangles[j_loc][2]=tab[i];
00388 is_forgotten=true;
00389 }
00390 }
00391
00392 }
00393
00394 if(is_forgotten){
00395
00396 unsigned int ind_forgotten = j;
00397
00398 bool is_in_shell = false;
00399 for (unsigned int j_glob=0;j_glob<shell.size();++j_glob) {
00400 is_in_shell = is_in_shell || (shell[j_glob] == ind_forgotten);
00401 }
00402
00403 if(!is_in_shell) {
00404 std::cout << "INFO_print : Col - triangle is forgotten in SHELL !!! global index = " << ind_forgotten << std::endl;
00405 }
00406
00407 }
00408
00409 }
00410 }
00411
00412 --last;
00413 }
00414
00415 }
00416
00417 needsUpdate=true;
00418
00419 break;
00420 }
00421
00422
00423
00424 case core::componentmodel::topology::POINTSRENUMBERING:
00425 {
00426
00427
00428 if (_topology->getNbTriangles()>0) {
00429
00430 unsigned int i;
00431
00432 const sofa::helper::vector<unsigned int> tab = ( static_cast< const sofa::component::topology::PointsRenumbering * >( *itBegin ) )->getinv_IndexArray();
00433
00434 for ( i = 0; i < mytriangles.size(); ++i)
00435 {
00436 mytriangles[i][0] = tab[mytriangles[i][0]];
00437 mytriangles[i][1] = tab[mytriangles[i][1]];
00438 mytriangles[i][2] = tab[mytriangles[i][2]];
00439 }
00440
00441 }
00442
00443
00444
00445 break;
00446
00447 }
00448
00449 default:
00450
00451 break;
00452 };
00453
00454 mytriangles.resize( elems.size() );
00455 resize( elems.size() );
00456
00457 ++itBegin;
00458 }
00459 }
00460 if (needsUpdate){
00461 updateFlags();
00462 }
00463 }
00464
00465 void TriangleModel::draw(int index)
00466 {
00467 Triangle t(this,index);
00468 glBegin(GL_TRIANGLES);
00469 helper::gl::glNormalT(t.n());
00470 helper::gl::glVertexT(t.p1());
00471 helper::gl::glVertexT(t.p2());
00472 helper::gl::glVertexT(t.p3());
00473 glEnd();
00474 }
00475
00476 void TriangleModel::draw()
00477 {
00478 if (getContext()->getShowCollisionModels())
00479 {
00480 if (getContext()->getShowWireFrame())
00481 glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
00482
00483 glEnable(GL_LIGHTING);
00484
00485
00486
00487 glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, getColor4f());
00488 static const float emissive[4] = { 0.0f, 0.0f, 0.0f, 0.0f};
00489 static const float specular[4] = { 1.0f, 1.0f, 1.0f, 1.0f};
00490 glMaterialfv (GL_FRONT_AND_BACK, GL_EMISSION, emissive);
00491 glMaterialfv (GL_FRONT_AND_BACK, GL_SPECULAR, specular);
00492 glMaterialf (GL_FRONT_AND_BACK, GL_SHININESS, 20);
00493
00494 for (int i=0;i<size;i++)
00495 {
00496 draw(i);
00497 }
00498
00499 glColor3f(1.0f, 1.0f, 1.0f);
00500 glDisable(GL_LIGHTING);
00501 if (getContext()->getShowWireFrame())
00502 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
00503 }
00504 if (getPrevious()!=NULL && getContext()->getShowBoundingCollisionModels())
00505 getPrevious()->draw();
00506 }
00507
00508 void TriangleModel::computeBoundingTree(int maxDepth)
00509 {
00510 CubeModel* cubeModel = createPrevious<CubeModel>();
00511 updateFromTopology();
00512 if (needsUpdate && !cubeModel->empty()) cubeModel->resize(0);
00513 if (!isMoving() && !cubeModel->empty() && !needsUpdate) return;
00514
00515 needsUpdate=false;
00516 Vector3 minElem, maxElem;
00517 const VecCoord& x = *this->mstate->getX();
00518
00519 const bool calcNormals = computeNormals.getValue();
00520
00521 if (maxDepth == 0)
00522 {
00523 if (empty())
00524 cubeModel->resize(0);
00525 else
00526 {
00527 cubeModel->resize(1);
00528 minElem = x[0];
00529 maxElem = x[0];
00530 for (unsigned i=1;i<x.size();i++)
00531 {
00532 const Vector3& pt1 = x[i];
00533 if (pt1[0] > maxElem[0]) maxElem[0] = pt1[0];
00534 else if (pt1[0] < minElem[0]) minElem[0] = pt1[0];
00535 if (pt1[1] > maxElem[1]) maxElem[1] = pt1[1];
00536 else if (pt1[1] < minElem[1]) minElem[1] = pt1[1];
00537 if (pt1[2] > maxElem[2]) maxElem[2] = pt1[2];
00538 else if (pt1[2] < minElem[2]) minElem[2] = pt1[2];
00539 }
00540 if (calcNormals)
00541 for (int i=0;i<size;i++)
00542 {
00543 Triangle t(this,i);
00544 const Vector3& pt1 = x[t.p1Index()];
00545 const Vector3& pt2 = x[t.p2Index()];
00546 const Vector3& pt3 = x[t.p3Index()];
00547
00548
00549
00550
00551
00552
00553
00554
00555
00556
00557
00558
00559
00560
00561
00562
00563
00564
00565
00566
00567 t.n() = cross(pt2-pt1,pt3-pt1);
00568 t.n().normalize();
00569
00570 }
00571 cubeModel->setLeafCube(0, std::make_pair(this->begin(),this->end()), minElem, maxElem);
00572 }
00573 }
00574 else
00575 {
00576
00577 cubeModel->resize(size);
00578 if (!empty())
00579 {
00580 for (int i=0;i<size;i++)
00581 {
00582 Triangle t(this,i);
00583 const Vector3& pt1 = x[t.p1Index()];
00584 const Vector3& pt2 = x[t.p2Index()];
00585 const Vector3& pt3 = x[t.p3Index()];
00586
00587 for (int c = 0; c < 3; c++)
00588 {
00589 minElem[c] = pt1[c];
00590 maxElem[c] = pt1[c];
00591 if (pt2[c] > maxElem[c]) maxElem[c] = pt2[c];
00592 else if (pt2[c] < minElem[c]) minElem[c] = pt2[c];
00593 if (pt3[c] > maxElem[c]) maxElem[c] = pt3[c];
00594 else if (pt3[c] < minElem[c]) minElem[c] = pt3[c];
00595 }
00596 if (calcNormals)
00597 {
00598
00599 t.n() = cross(pt2-pt1,pt3-pt1);
00600 t.n().normalize();
00601 }
00602 cubeModel->setParentOf(i, minElem, maxElem);
00603 }
00604 cubeModel->computeBoundingTree(maxDepth);
00605 }
00606 }
00607 }
00608
00609 void TriangleModel::computeContinuousBoundingTree(double dt, int maxDepth)
00610 { CubeModel* cubeModel = createPrevious<CubeModel>();
00611 updateFromTopology();
00612 if (needsUpdate) cubeModel->resize(0);
00613 if (!isMoving() && !cubeModel->empty() && !needsUpdate) return;
00614
00615 needsUpdate=false;
00616 Vector3 minElem, maxElem;
00617
00618 cubeModel->resize(size);
00619 if (!empty())
00620 {
00621 for (int i=0;i<size;i++)
00622 {
00623 Triangle t(this,i);
00624 const Vector3& pt1 = t.p1();
00625 const Vector3& pt2 = t.p2();
00626 const Vector3& pt3 = t.p3();
00627 const Vector3 pt1v = pt1 + t.v1()*dt;
00628 const Vector3 pt2v = pt2 + t.v2()*dt;
00629 const Vector3 pt3v = pt3 + t.v3()*dt;
00630
00631 for (int c = 0; c < 3; c++)
00632 {
00633 minElem[c] = pt1[c];
00634 maxElem[c] = pt1[c];
00635 if (pt2[c] > maxElem[c]) maxElem[c] = pt2[c];
00636 else if (pt2[c] < minElem[c]) minElem[c] = pt2[c];
00637 if (pt3[c] > maxElem[c]) maxElem[c] = pt3[c];
00638 else if (pt3[c] < minElem[c]) minElem[c] = pt3[c];
00639
00640 if (pt1v[c] > maxElem[c]) maxElem[c] = pt1v[c];
00641 else if (pt1v[c] < minElem[c]) minElem[c] = pt1v[c];
00642 if (pt2v[c] > maxElem[c]) maxElem[c] = pt2v[c];
00643 else if (pt2v[c] < minElem[c]) minElem[c] = pt2v[c];
00644 if (pt3v[c] > maxElem[c]) maxElem[c] = pt3v[c];
00645 else if (pt3v[c] < minElem[c]) minElem[c] = pt3v[c];
00646 }
00647
00648
00649 t.n() = cross(pt2-pt1,pt3-pt1);
00650 t.n().normalize();
00651
00652 cubeModel->setParentOf(i, minElem, maxElem);
00653 }
00654 cubeModel->computeBoundingTree(maxDepth);
00655 }
00656 }
00657
00658
00659 void TriangleModel::buildOctree(){
00660
00661
00662
00663
00664
00665
00666
00667
00668
00669
00670
00671
00672
00673
00674
00675
00676 }
00677
00678 }
00679
00680 }
00681
00682 }
00683