LineModel.cpp
Go to the documentation of this file.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/LineModel.h>
00026 #include <sofa/component/collision/CubeModel.h>
00027 #include <sofa/component/collision/Line.h>
00028 #include <sofa/core/CollisionElement.h>
00029 #include <sofa/core/ObjectFactory.h>
00030 #include <vector>
00031 #include <sofa/helper/gl/template.h>
00032 #include <sofa/simulation/tree/GNode.h>
00033 #include <sofa/component/topology/PointSetTopologyChange.h>
00034 #include <sofa/component/topology/EdgeSetTopologyChange.h>
00035
00036 namespace sofa
00037 {
00038
00039 namespace component
00040 {
00041
00042 namespace collision
00043 {
00044
00045 SOFA_DECL_CLASS(Line)
00046
00047 int LineModelClass = core::RegisterObject("collision model using a linear mesh, as described in MeshTopology")
00048 .add< LineModel >()
00049 .addAlias("Line")
00050 .addAlias("LineMeshModel")
00051 .addAlias("LineSetModel")
00052 .addAlias("LineMesh")
00053 .addAlias("LineSet")
00054 ;
00055
00056 using core::componentmodel::topology::BaseMeshTopology;
00057
00058
00059
00060
00061
00062 LineModel::LineModel()
00063 : mstate(NULL), topology(NULL), meshRevision(-1)
00064 {
00065 }
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077 void LineModel::resize(int size)
00078 {
00079 this->core::CollisionModel::resize(size);
00080 elems.resize(size);
00081 }
00082
00083 void LineModel::init()
00084 {
00085 this->CollisionModel::init();
00086 mstate = dynamic_cast< core::componentmodel::behavior::MechanicalState<Vec3Types>* > (getContext()->getMechanicalState());
00087 mpoints = getContext()->get<PointModel>();
00088
00089 if (mstate==NULL)
00090 {
00091 std::cerr << "ERROR: LineModel requires a Vec3 Mechanical Model.\n";
00092 return;
00093 }
00094
00095 core::componentmodel::topology::BaseMeshTopology *bmt = getContext()->getMeshTopology();
00096 if (!bmt) {
00097 std::cerr << "ERROR: LineModel requires a MeshTopology.\n";
00098 return;
00099 }
00100
00101 resize( bmt->getNbEdges() );
00102
00103 for(int i = 0; i < bmt->getNbEdges(); i++)
00104 {
00105 elems[i].i1 = bmt->getEdge(i)[0];
00106 elems[i].i2 = bmt->getEdge(i)[1];
00107 }
00108
00109 updateFromTopology();
00110 }
00111
00112
00113 void LineModel::handleTopologyChange()
00114 {
00115
00116
00117
00118
00119 core::componentmodel::topology::BaseMeshTopology *bmt = getContext()->getMeshTopology();
00120 if (bmt)
00121 {
00122 resize(bmt->getNbEdges());
00123
00124 for(int i = 0; i < bmt->getNbEdges(); i++)
00125 {
00126 elems[i].i1 = bmt->getEdge(i)[0];
00127 elems[i].i2 = bmt->getEdge(i)[1];
00128 }
00129
00130 needsUpdate = true;
00131 }
00132
00133
00134
00135
00136 if (bmt)
00137 {
00138 std::list<const sofa::core::componentmodel::topology::TopologyChange *>::const_iterator itBegin = bmt->firstChange();
00139 std::list<const sofa::core::componentmodel::topology::TopologyChange *>::const_iterator itEnd = bmt->lastChange();
00140
00141 while( itBegin != itEnd )
00142 {
00143 core::componentmodel::topology::TopologyChangeType changeType = (*itBegin)->getChangeType();
00144
00145 switch( changeType )
00146 {
00147 case core::componentmodel::topology::ENDING_EVENT :
00148 {
00149
00150 needsUpdate = true;
00151 break;
00152 }
00153
00154
00155 case core::componentmodel::topology::EDGESADDED :
00156 {
00157
00158 const sofa::component::topology::EdgesAdded *ta = static_cast< const sofa::component::topology::EdgesAdded * >( *itBegin );
00159
00160 for (unsigned int i = 0; i < ta->getNbAddedEdges(); ++i)
00161 {
00162 elems[elems.size() - ta->getNbAddedEdges() + i].i1 = (ta->edgeArray[i])[0];
00163 elems[elems.size() - ta->getNbAddedEdges() + i].i2 = (ta->edgeArray[i])[1];
00164 }
00165
00166 resize( elems.size() );
00167 needsUpdate = true;
00168
00169 break;
00170 }
00171
00172 case core::componentmodel::topology::EDGESREMOVED :
00173 {
00174
00175 unsigned int last;
00176 unsigned int ind_last;
00177
00178 if (bmt)
00179 {
00180 last = bmt->getNbEdges() - 1;
00181 }
00182 else
00183 {
00184 last = elems.size() -1;
00185 }
00186
00187 const sofa::helper::vector< unsigned int > &tab = ( static_cast< const sofa::component::topology::EdgesRemoved *>( *itBegin ) )->getArray();
00188
00189 LineData tmp;
00190
00191
00192 for (unsigned int i = 0; i < tab.size(); ++i)
00193 {
00194 unsigned int ind_k = tab[i];
00195
00196 tmp = elems[ind_k];
00197 elems[ind_k] = elems[last];
00198 elems[last] = tmp;
00199
00200
00201
00202
00203
00204
00205
00206
00207
00208 ind_last = elems.size() - 1;
00209
00210 if(last != ind_last)
00211 {
00212 tmp = elems[last];
00213 elems[last] = elems[ind_last];
00214 elems[ind_last] = tmp;
00215
00216
00217
00218
00219 }
00220
00221
00222 resize( elems.size() - 1 );
00223
00224 --last;
00225 }
00226
00227 needsUpdate=true;
00228
00229 break;
00230 }
00231
00232 case core::componentmodel::topology::POINTSREMOVED :
00233 {
00234
00235 if (bmt)
00236 {
00237 unsigned int last = bmt->getNbPoints() - 1;
00238
00239 unsigned int i,j;
00240 const sofa::helper::vector<unsigned int> tab = ( static_cast< const sofa::component::topology::PointsRemoved * >( *itBegin ) )->getArray();
00241
00242 sofa::helper::vector<unsigned int> lastIndexVec;
00243 for(unsigned int i_init = 0; i_init < tab.size(); ++i_init)
00244 {
00245 lastIndexVec.push_back(last - i_init);
00246 }
00247
00248 for ( i = 0; i < tab.size(); ++i)
00249 {
00250 unsigned int i_next = i;
00251 bool is_reached = false;
00252 while( (!is_reached) && (i_next < lastIndexVec.size() - 1))
00253 {
00254 i_next += 1 ;
00255 is_reached = is_reached || (lastIndexVec[i_next] == tab[i]);
00256 }
00257
00258 if(is_reached)
00259 {
00260 lastIndexVec[i_next] = lastIndexVec[i];
00261 }
00262
00263 const sofa::helper::vector<unsigned int> &shell = bmt->getEdgeVertexShell(lastIndexVec[i]);
00264
00265 for (j = 0; j < shell.size(); ++j)
00266 {
00267 unsigned int ind_j = shell[j];
00268
00269 if ((unsigned)elems[ind_j].i1 == last)
00270 {
00271 elems[ind_j].i1 = tab[i];
00272 }
00273 else if ((unsigned)elems[ind_j].i2 == last)
00274 {
00275 elems[ind_j].i2 = tab[i];
00276 }
00277 }
00278
00279 --last;
00280 }
00281 }
00282
00283 needsUpdate=true;
00284
00285 break;
00286 }
00287
00288 case core::componentmodel::topology::POINTSRENUMBERING:
00289 {
00290
00291 if (bmt)
00292 {
00293 unsigned int i;
00294
00295 const sofa::helper::vector<unsigned int> tab = ( static_cast< const sofa::component::topology::PointsRenumbering * >( *itBegin ) )->getinv_IndexArray();
00296
00297 for ( i = 0; i < elems.size(); ++i)
00298 {
00299 elems[i].i1 = tab[elems[i].i1];
00300 elems[i].i2 = tab[elems[i].i2];
00301 }
00302 }
00303
00304 break;
00305 }
00306
00307 default:
00308
00309 break;
00310 };
00311
00312 resize( elems.size() );
00313
00314 ++itBegin;
00315 }
00316 }
00317 }
00318
00319 void LineModel::updateFromTopology()
00320 {
00321 core::componentmodel::topology::BaseMeshTopology *bmt = getContext()->getMeshTopology();
00322 if (bmt)
00323 {
00324 int revision = bmt->getRevision();
00325 if (revision == meshRevision)
00326 return;
00327
00328 needsUpdate = true;
00329
00330 const unsigned int nbPoints = mstate->getX()->size();
00331 const unsigned int nbLines = bmt->getNbEdges();
00332
00333 resize( nbLines );
00334 int index = 0;
00335
00336 for (unsigned int i = 0; i < nbLines; i++)
00337 {
00338 topology::BaseMeshTopology::Line idx = bmt->getEdge(i);
00339
00340 if (idx[0] >= nbPoints || idx[1] >= nbPoints)
00341 {
00342 std::cerr << "ERROR: Out of range index in Line " << i << ": " << idx[0] << " " << idx[1] << " ( total points = " << nbPoints << " )\n";
00343 continue;
00344 }
00345
00346 elems[index].i1 = idx[0];
00347 elems[index].i2 = idx[1];
00348 ++index;
00349 }
00350
00351 meshRevision = revision;
00352 }
00353 }
00354
00355 void LineModel::draw(int index)
00356 {
00357 Line t(this,index);
00358 glBegin(GL_LINES);
00359 helper::gl::glVertexT(t.p1());
00360 helper::gl::glVertexT(t.p2());
00361 glEnd();
00362 }
00363
00364 void LineModel::draw()
00365 {
00366 if (getContext()->getShowCollisionModels())
00367 {
00368 if (getContext()->getShowWireFrame())
00369 glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
00370
00371 glDisable(GL_LIGHTING);
00372 glColor4fv(getColor4f());
00373
00374 for (int i=0;i<size;i++)
00375 {
00376 if (elems[i].i1 < elems[i].i2)
00377 draw(i);
00378 }
00379
00380 glColor3f(1.0f, 1.0f, 1.0f);
00381 glDisable(GL_LIGHTING);
00382 if (getContext()->getShowWireFrame())
00383 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
00384 }
00385 if (getPrevious()!=NULL && getContext()->getShowBoundingCollisionModels())
00386 getPrevious()->draw();
00387 }
00388
00389 bool LineModel::canCollideWithElement(int index, CollisionModel* model2, int index2)
00390 {
00391 if (!this->bSelfCollision.getValue()) return true;
00392 if (this->getContext() != model2->getContext()) return true;
00393 if (model2 == this)
00394 {
00395
00396 return index < index2-2;
00397 }
00398 else if (model2 == mpoints)
00399 {
00400
00401 return index2 < elems[index].i1-1 || index2 > elems[index].i2+1;
00402 }
00403 else
00404 return model2->canCollideWithElement(index2, this, index);
00405 }
00406
00407 void LineModel::computeBoundingTree(int maxDepth)
00408 {
00409 CubeModel* cubeModel = createPrevious<CubeModel>();
00410 updateFromTopology();
00411 if (needsUpdate) cubeModel->resize(0);
00412 if (!isMoving() && !cubeModel->empty() && !needsUpdate) return;
00413
00414 needsUpdate = false;
00415 Vector3 minElem, maxElem;
00416
00417 cubeModel->resize(size);
00418 if (!empty())
00419 {
00420 for (int i=0;i<size;i++)
00421 {
00422 Vector3 minElem, maxElem;
00423 Line l(this,i);
00424 const Vector3& pt1 = l.p1();
00425 const Vector3& pt2 = l.p2();
00426
00427 for (int c = 0; c < 3; c++)
00428 {
00429 minElem[c] = pt1[c];
00430 maxElem[c] = pt1[c];
00431 if (pt2[c] > maxElem[c]) maxElem[c] = pt2[c];
00432 else if (pt2[c] < minElem[c]) minElem[c] = pt2[c];
00433 }
00434
00435 cubeModel->setParentOf(i, minElem, maxElem);
00436 }
00437 cubeModel->computeBoundingTree(maxDepth);
00438 }
00439 }
00440
00441 void LineModel::computeContinuousBoundingTree(double dt, int maxDepth)
00442 {
00443 CubeModel* cubeModel = createPrevious<CubeModel>();
00444 updateFromTopology();
00445 if (needsUpdate) cubeModel->resize(0);
00446 if (!isMoving() && !cubeModel->empty() && !needsUpdate) return;
00447
00448 needsUpdate=false;
00449 Vector3 minElem, maxElem;
00450
00451 cubeModel->resize(size);
00452 if (!empty())
00453 {
00454 for (int i=0;i<size;i++)
00455 {
00456 Line t(this,i);
00457 const Vector3& pt1 = t.p1();
00458 const Vector3& pt2 = t.p2();
00459 const Vector3 pt1v = pt1 + t.v1()*dt;
00460 const Vector3 pt2v = pt2 + t.v2()*dt;
00461
00462 for (int c = 0; c < 3; c++)
00463 {
00464 minElem[c] = pt1[c];
00465 maxElem[c] = pt1[c];
00466 if (pt2[c] > maxElem[c]) maxElem[c] = pt2[c];
00467 else if (pt2[c] < minElem[c]) minElem[c] = pt2[c];
00468
00469 if (pt1v[c] > maxElem[c]) maxElem[c] = pt1v[c];
00470 else if (pt1v[c] < minElem[c]) minElem[c] = pt1v[c];
00471 if (pt2v[c] > maxElem[c]) maxElem[c] = pt2v[c];
00472 else if (pt2v[c] < minElem[c]) minElem[c] = pt2v[c];
00473 }
00474 cubeModel->setParentOf(i, minElem, maxElem);
00475 }
00476 cubeModel->computeBoundingTree(maxDepth);
00477 }
00478 }
00479
00480 }
00481
00482 }
00483
00484 }
00485