PointModel.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/helper/system/config.h>
00026 #include <sofa/component/collision/proximity.h>
00027 #include <sofa/defaulttype/Mat.h>
00028 #include <sofa/defaulttype/Vec.h>
00029 #include <sofa/core/componentmodel/collision/Intersection.inl>
00030 #include <iostream>
00031 #include <algorithm>
00032
00033
00034
00035
00036 #include <sofa/component/collision/PointModel.h>
00037 #include <sofa/component/collision/CubeModel.h>
00038 #include <sofa/core/ObjectFactory.h>
00039 #include <vector>
00040 #include <sofa/helper/system/gl.h>
00041 #include <sofa/helper/gl/template.h>
00042 #include <sofa/core/componentmodel/collision/Intersection.inl>
00043
00044 #include <sofa/core/componentmodel/topology/BaseMeshTopology.h>
00045
00046 namespace sofa
00047 {
00048
00049 namespace component
00050 {
00051
00052 namespace collision
00053 {
00054
00055 using namespace sofa::defaulttype;
00056 using namespace sofa::core::componentmodel::collision;
00057 using namespace helper;
00058
00059 SOFA_DECL_CLASS(Point)
00060
00061 int PointModelClass = core::RegisterObject("Collision model which represents a set of points")
00062 .add< PointModel >()
00063 .addAlias("Point")
00064
00065 .addAlias("PointMesh")
00066 .addAlias("PointSet")
00067 ;
00068
00069 PointModel::PointModel()
00070 : mstate(NULL)
00071 , computeNormals( initData(&computeNormals, false, "computeNormals", "activate computation of normal vectors (required for some collision detection algorithms)") )
00072 {
00073 }
00074
00075 void PointModel::resize(int size)
00076 {
00077 this->core::CollisionModel::resize(size);
00078 }
00079
00080 void PointModel::init()
00081 {
00082 this->CollisionModel::init();
00083 mstate = dynamic_cast< core::componentmodel::behavior::MechanicalState<Vec3Types>* > (getContext()->getMechanicalState());
00084
00085 if (mstate==NULL)
00086 {
00087 std::cerr << "ERROR: PointModel requires a Vec3 Mechanical Model.\n";
00088 return;
00089 }
00090
00091 const int npoints = mstate->getX()->size();
00092 resize(npoints);
00093 if (computeNormals.getValue()) updateNormals();
00094 }
00095
00096 void PointModel::draw(int index)
00097 {
00098 Point t(this,index);
00099 glBegin(GL_POINTS);
00100 helper::gl::glVertexT(t.p());
00101 glEnd();
00102 if ((unsigned)index < normals.size())
00103 {
00104 glBegin(GL_LINES);
00105 helper::gl::glVertexT(t.p());
00106 helper::gl::glVertexT(t.p()+normals[index]*0.1f);
00107 glEnd();
00108 }
00109 }
00110
00111 void PointModel::draw()
00112 {
00113 if (getContext()->getShowCollisionModels())
00114 {
00115 if (getContext()->getShowWireFrame())
00116 glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
00117
00118 glDisable(GL_LIGHTING);
00119 glPointSize(3);
00120 glColor4fv(getColor4f());
00121
00122
00123 const int npoints = mstate->getX()->size();
00124 if (npoints != size)
00125 {
00126 resize(npoints);
00127 }
00128
00129 for (int i = 0; i < size; i++)
00130 {
00131 draw(i);
00132 }
00133
00134 glColor3f(1.0f, 1.0f, 1.0f);
00135 glDisable(GL_LIGHTING);
00136 glPointSize(1);
00137 if (getContext()->getShowWireFrame())
00138 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
00139 }
00140 if (getPrevious()!=NULL && getContext()->getShowBoundingCollisionModels())
00141 getPrevious()->draw();
00142 }
00143
00144 bool PointModel::canCollideWithElement(int index, CollisionModel* model2, int index2)
00145 {
00146 if (!this->bSelfCollision.getValue()) return true;
00147 if (this->getContext() != model2->getContext()) return true;
00148 if (model2 == this)
00149 {
00150
00151 return index < index2-2;
00152 }
00153 else
00154 return model2->canCollideWithElement(index2, this, index);
00155 }
00156
00157 void PointModel::computeBoundingTree(int maxDepth)
00158 {
00159 CubeModel* cubeModel = createPrevious<CubeModel>();
00160 const int npoints = mstate->getX()->size();
00161 bool updated = false;
00162 if (npoints != size)
00163 {
00164 resize(npoints);
00165 updated = true;
00166 }
00167 if (updated) cubeModel->resize(0);
00168 if (!isMoving() && !cubeModel->empty() && !updated) return;
00169
00170 if (computeNormals.getValue()) updateNormals();
00171
00172 cubeModel->resize(size);
00173 if (!empty())
00174 {
00175
00176 for (int i=0;i<size;i++)
00177 {
00178 Point p(this,i);
00179 const Vector3& pt = p.p();
00180 cubeModel->setParentOf(i, pt, pt);
00181 }
00182 cubeModel->computeBoundingTree(maxDepth);
00183 }
00184 }
00185
00186 void PointModel::computeContinuousBoundingTree(double dt, int maxDepth)
00187 {
00188 CubeModel* cubeModel = createPrevious<CubeModel>();
00189 const int npoints = mstate->getX()->size();
00190 bool updated = false;
00191 if (npoints != size)
00192 {
00193 resize(npoints);
00194 updated = true;
00195 }
00196 if (!isMoving() && !cubeModel->empty() && !updated) return;
00197
00198 if (computeNormals.getValue()) updateNormals();
00199
00200 Vector3 minElem, maxElem;
00201
00202 cubeModel->resize(size);
00203 if (!empty())
00204 {
00205
00206
00207 for (int i=0;i<size;i++)
00208 {
00209 Point p(this,i);
00210 const Vector3& pt = p.p();
00211 const Vector3 ptv = pt + p.v()*dt;
00212
00213 for (int c = 0; c < 3; c++)
00214 {
00215 minElem[c] = pt[c];
00216 maxElem[c] = pt[c];
00217 if (ptv[c] > maxElem[c]) maxElem[c] = ptv[c];
00218 else if (ptv[c] < minElem[c]) minElem[c] = ptv[c];
00219 }
00220 cubeModel->setParentOf(i, minElem, maxElem);
00221 }
00222 cubeModel->computeBoundingTree(maxDepth);
00223 }
00224 }
00225
00226 void PointModel::updateNormals()
00227 {
00228 const VecCoord& x = *mstate->getX();
00229 int n = x.size();
00230 normals.resize(n);
00231 for (int i=0;i<n;++i)
00232 {
00233 normals[i].clear();
00234 }
00235 core::componentmodel::topology::BaseMeshTopology* mesh = getContext()->getMeshTopology();
00236 if (mesh->getNbTetras()+mesh->getNbHexas() > 0)
00237 {
00238 if (mesh->getNbTetras()>0)
00239 {
00240 const core::componentmodel::topology::BaseMeshTopology::SeqTetras &elems = mesh->getTetras();
00241 for (unsigned int i=0; i < elems.size(); ++i)
00242 {
00243 const core::componentmodel::topology::BaseMeshTopology::Tetra &e = elems[i];
00244 const Coord& p1 = x[e[0]];
00245 const Coord& p2 = x[e[1]];
00246 const Coord& p3 = x[e[2]];
00247 const Coord& p4 = x[e[3]];
00248 Coord& n1 = normals[e[0]];
00249 Coord& n2 = normals[e[1]];
00250 Coord& n3 = normals[e[2]];
00251 Coord& n4 = normals[e[3]];
00252 Coord n;
00253 n = cross(p3-p1,p2-p1); n.normalize();
00254 n1 += n;
00255 n2 += n;
00256 n3 += n;
00257 n = cross(p4-p1,p3-p1); n.normalize();
00258 n1 += n;
00259 n3 += n;
00260 n4 += n;
00261 n = cross(p2-p1,p4-p1); n.normalize();
00262 n1 += n;
00263 n4 += n;
00264 n2 += n;
00265 n = cross(p3-p2,p4-p2); n.normalize();
00266 n2 += n;
00267 n4 += n;
00268 n3 += n;
00269 }
00270 }
00272 }
00273 else if (mesh->getNbTriangles()+mesh->getNbQuads() > 0)
00274 {
00275 if (mesh->getNbTriangles()>0)
00276 {
00277 const core::componentmodel::topology::BaseMeshTopology::SeqTriangles &elems = mesh->getTriangles();
00278 for (unsigned int i=0; i < elems.size(); ++i)
00279 {
00280 const core::componentmodel::topology::BaseMeshTopology::Triangle &e = elems[i];
00281 const Coord& p1 = x[e[0]];
00282 const Coord& p2 = x[e[1]];
00283 const Coord& p3 = x[e[2]];
00284 Coord& n1 = normals[e[0]];
00285 Coord& n2 = normals[e[1]];
00286 Coord& n3 = normals[e[2]];
00287 Coord n;
00288 n = cross(p2-p1,p3-p1); n.normalize();
00289 n1 += n;
00290 n2 += n;
00291 n3 += n;
00292 }
00293 }
00294 if (mesh->getNbQuads()>0)
00295 {
00296 const core::componentmodel::topology::BaseMeshTopology::SeqQuads &elems = mesh->getQuads();
00297 for (unsigned int i=0; i < elems.size(); ++i)
00298 {
00299 const core::componentmodel::topology::BaseMeshTopology::Quad &e = elems[i];
00300 const Coord& p1 = x[e[0]];
00301 const Coord& p2 = x[e[1]];
00302 const Coord& p3 = x[e[2]];
00303 const Coord& p4 = x[e[3]];
00304 Coord& n1 = normals[e[0]];
00305 Coord& n2 = normals[e[1]];
00306 Coord& n3 = normals[e[2]];
00307 Coord& n4 = normals[e[3]];
00308 Coord n;
00309 n = cross(p3-p1,p4-p2); n.normalize();
00310 n1 += n;
00311 n2 += n;
00312 n3 += n;
00313 n4 += n;
00314 }
00315 }
00316 }
00317 for (int i=0;i<n;++i)
00318 {
00319 SReal l = normals[i].norm();
00320 if (l > 1.0e-3)
00321 normals[i] *= 1/l;
00322 else
00323 normals[i].clear();
00324 }
00325 }
00326
00327
00328 bool Point::testLMD(const Vector3 &PQ, double &coneFactor, double &coneExtension)
00329 {
00330 Vector3 pt = p();
00331
00332 sofa::core::componentmodel::topology::BaseMeshTopology* mesh = model->getMeshTopology();
00333 helper::vector<Vector3> x = (*model->mstate->getX());
00334
00335 const helper::vector <unsigned int>& triangleVertexShell = mesh->getTriangleVertexShell(index);
00336 const helper::vector <unsigned int>& edgeVertexShell = mesh->getEdgeVertexShell(index);
00337
00338
00339 Vector3 nMean;
00340
00341 for (unsigned int i=0; i<triangleVertexShell.size(); i++)
00342 {
00343 unsigned int t = triangleVertexShell[i];
00344 const fixed_array<unsigned int,3>& ptr = mesh->getTriangle(t);
00345 Vector3 nCur = (x[ptr[1]]-x[ptr[0]]).cross(x[ptr[2]]-x[ptr[0]]);
00346 nCur.normalize();
00347 nMean += nCur;
00348 }
00349
00350 if (triangleVertexShell.size()==0)
00351 {
00352 for (unsigned int i=0; i<edgeVertexShell.size(); i++)
00353 {
00354 unsigned int e = edgeVertexShell[i];
00355 const fixed_array<unsigned int,2>& ped = mesh->getEdge(e);
00356 Vector3 l = (pt - x[ped[0]]) + (pt - x[ped[1]]);
00357 l.normalize();
00358 nMean += l;
00359 }
00360 }
00361
00362 if (nMean.norm()> 0.0000000001)
00363 nMean.normalize();
00364
00365
00366 for (unsigned int i=0; i<edgeVertexShell.size(); i++)
00367 {
00368 unsigned int e = edgeVertexShell[i];
00369 const fixed_array<unsigned int,2>& ped = mesh->getEdge(e);
00370 Vector3 l = (pt - x[ped[0]]) + (pt - x[ped[1]]);
00371 l.normalize();
00372 double computedAngleCone = dot(nMean , l) * coneFactor;
00373 if (computedAngleCone<0)
00374 computedAngleCone=0.0;
00375 computedAngleCone+=coneExtension;
00376 if (dot(l , PQ) < -computedAngleCone*PQ.norm())
00377 return false;
00378 }
00379 return true;
00380
00381
00382 }
00383
00384
00385
00386
00387
00388
00389
00390
00391 }
00392
00393 }
00394
00395 }
00396