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/RayPickInteractor.inl>
00026 #include <sofa/component/collision/RayContact.h>
00027 #include <sofa/component/collision/SphereModel.h>
00028 #include <sofa/component/collision/TriangleModel.h>
00029 #include <sofa/component/collision/TetrahedronModel.h>
00030 #include <sofa/component/collision/SphereTreeModel.h>
00031 #include <sofa/component/collision/DistanceGridCollisionModel.h>
00032 #include <sofa/component/mapping/BarycentricMapping.h>
00033 #include <sofa/component/mapping/RigidMapping.h>
00034 #include <sofa/component/mapping/SkinningMapping.h>
00035 #include <sofa/component/MechanicalObject.h>
00036 #include <sofa/core/componentmodel/behavior/MechanicalState.h>
00037 #include <sofa/helper/Factory.inl>
00038 #include <sofa/helper/system/gl.h>
00039
00040
00041 namespace sofa
00042 {
00043
00044 namespace component
00045 {
00046
00047 namespace collision
00048 {
00049
00050 using namespace sofa::defaulttype;
00051
00052 template<>
00053 void DefaultPickingManager<defaulttype::Vec3Types,forcefield::VectorSpringForceField<defaulttype::Vec3Types> >::addContact(forcefield::VectorSpringForceField<defaulttype::Vec3Types>* ff, int index1, int index2, double stiffness, double mu_v, double , const Vector3& p1, const Vector3& p2)
00054 {
00055 ff->addSpring(index1, index2, stiffness, mu_v, (p2-p1));
00056 }
00057
00058 template<>
00059 void DefaultPickingManager<defaulttype::Vec3Types,forcefield::StiffSpringForceField<defaulttype::Vec3Types> >::addContact(forcefield::StiffSpringForceField<defaulttype::Vec3Types>* ff, int index1, int index2, double stiffness, double mu_v, double length, const Vector3& , const Vector3& )
00060 {
00061 ff->addSpring(index1, index2, stiffness, mu_v, length);
00062 }
00063
00064 template class DefaultPickingManager< Vec3Types, forcefield::VectorSpringForceField<Vec3Types> >;
00065
00066 helper::Creator<BasePickingManager::PickingManagerFactory, DefaultPickingManager< Vec3Types, forcefield::VectorSpringForceField<Vec3Types> > > PickingVectorSpringVec3Class ("VectorSpringVec3d",true);
00067
00068
00069 BasePickingManager* BasePickingManager::Create(std::string name, core::objectmodel::BaseContext* context)
00070 {
00071 BasePickingManager* o = PickingManagerFactory::CreateObject(name, context);
00072 if (o != NULL)
00073 {
00074 o->setName(name);
00075 if (context != NULL)
00076 context->addObject(o);
00077 }
00078 return o;
00079 }
00080
00081 int BasePickingManager::CreateAll(std::vector<BasePickingManager*>& instances, core::objectmodel::BaseContext* context)
00082 {
00083 int n = 0;
00084 for (PickingManagerFactory::iterator it = PickingManagerFactory::getInstance()->begin(), itend = PickingManagerFactory::getInstance()->end(); it != itend; ++it)
00085 {
00086 BasePickingManager* o = it->second->createInstance(context);
00087 if (o != NULL)
00088 {
00089 o->setName(it->first);
00090 if (context != NULL)
00091 context->addObject(o);
00092 instances.push_back(o);
00093 ++n;
00094 }
00095 }
00096 return n;
00097 }
00098
00099
00100 BasePickingManager::~BasePickingManager()
00101 {
00102 }
00103
00104
00105
00106 RayPickInteractor::RayPickInteractor()
00107 : state(DISABLED), button(0)
00108 {
00109 transform.identity();
00110 this->contactStiffness.setValue(100);
00111 }
00112
00113 RayPickInteractor::~RayPickInteractor()
00114 {
00115 }
00116
00117 void RayPickInteractor::init()
00118 {
00119 this->RayModel::init();
00120 this->getContext()->get<BasePickingManager,helper::vector<BasePickingManager*> >(&pickManagers,core::objectmodel::BaseContext::SearchRoot);
00121 if (pickManagers.empty())
00122 {
00123 std::cout << "RayPickInteractor: creating default pick managers." << std::endl;
00124 BasePickingManager::CreateAll(pickManagers, this->getContext());
00125 }
00126 }
00127
00128
00129 bool RayPickInteractor::isActive()
00130 {
00131 return state==ACTIVE || state==PRESENT || state == FIRST_INPUT || state == IS_CUT;
00132 }
00133
00134 bool RayPickInteractor::isAttached()
00135 {
00136 for (unsigned int i=0; i<pickManagers.size(); i++)
00137 if (pickManagers[i]->isAttached())
00138 return true;
00139 return false;
00140 }
00141
00142 void RayPickInteractor::pickBody()
00143 {
00144 const int oldState = state;
00145
00146
00147 for (int r=0; r<getNbRay(); r++)
00148 {
00149 Ray ray = getRay(r);
00150 double dist = 0;
00151 core::componentmodel::collision::DetectionOutput* collision = findFirstCollision(ray,&dist);
00152 if (collision==NULL)
00153 continue;
00154 core::CollisionElementIterator elem1 = collision->elem.first;
00155 core::CollisionElementIterator elem2 = collision->elem.second;
00156 Vector3 p1 = collision->point[0];
00157 Vector3 p2 = collision->point[1];
00158 if (elem2.getCollisionModel() == this)
00159 {
00160 elem2 = collision->elem.first;
00161 elem1 = collision->elem.second;
00162 p2 = collision->point[0];
00163 p1 = collision->point[1];
00164 }
00165 bool processed = false;
00166 for (unsigned int i=0;!processed && i<pickManagers.size();++i)
00167 {
00168 if (pickManagers[i]->attach(button, elem1, elem2, dist, p1, p2))
00169 processed = true;
00170 }
00171 if (!processed)
00172 switch(button)
00173 {
00174 case 0:
00175 break;
00176
00177 case 1:
00178 {
00179
00180 sofa::core::componentmodel::topology::TopologyModifier* topoMod;
00181 elem2.getCollisionModel()->getContext()->get(topoMod);
00182
00183 if(topoMod){
00184
00185 topo_changeManager.removeItemsFromCollisionModel(elem2);
00186 }
00187 }
00188 break;
00189
00190 case 2:
00191 {
00192 sofa::core::componentmodel::topology::TopologyModifier* topoMod;
00193 elem2.getCollisionModel()->getContext()->get(topoMod);
00194
00195 if(topoMod){
00196
00197 bool attach = topo_changeManager.incisionCollisionModel(elem2, p2, state == FIRST_INPUT, state == IS_CUT);
00198 if(attach)
00199 state = ATTACHED;
00200 }
00201 }
00202 break;
00203 }
00204 }
00205
00206 if(oldState == FIRST_INPUT || oldState == IS_CUT)
00207 {
00208 state = SECOND_INPUT;
00209 }
00210 else if (isAttached())
00211 {
00212 state = ATTACHED;
00213 }
00214
00215 if (oldState != state)
00216 {
00217 std::cout << "Interactor State: ";
00218 switch (state)
00219 {
00220 case DISABLED:
00221 std::cout << "DISABLED";
00222 break;
00223 case PRESENT:
00224 std::cout << "PRESENT";
00225 break;
00226 case ACTIVE:
00227 std::cout << "ACTIVE";
00228 break;
00229 case ATTACHED:
00230 std::cout << "ATTACHED";
00231 break;
00232 case FIRST_INPUT:
00233 std::cout << "FIRST_INPUT";
00234 break;
00235 case SECOND_INPUT:
00236 std::cout << "SECOND_INPUT";
00237 break;
00238 case IS_CUT:
00239 std::cout << "IS_CUT";
00240 break;
00241 }
00242 std::cout << std::endl;
00243 }
00244 }
00245
00246 void RayPickInteractor::releaseBody()
00247 {
00248 for (unsigned int i=0; i<pickManagers.size(); i++)
00249 if (pickManagers[i]->isAttached())
00250 pickManagers[i]->release();
00251 }
00252
00254 void RayPickInteractor::updatePosition(double )
00255 {
00256 if (state == DISABLED && getNbRay()>0)
00257 {
00258 resize(0);
00259 }
00260 else if (state != DISABLED && getNbRay()==0)
00261 {
00262 std::cout << "ADD RAY"<<std::endl;
00263 setNbRay(1);
00264 getRay(0).l() = 10000;
00265 }
00266
00267 if ((state == ACTIVE || state == FIRST_INPUT || state == IS_CUT) && !contacts.empty())
00268 {
00269 pickBody();
00270 }
00271 else if (state != ATTACHED && isAttached())
00272 {
00273 releaseBody();
00274 }
00275
00276
00277 if (getNbRay()>=1)
00278 {
00279 Ray ray = getRay(0);
00280 ray.origin() = transform*Vec4d(0,0,0,1);
00281 ray.direction() = transform*Vec4d(0,0,1,0);
00282 ray.direction().normalize();
00283 }
00284
00285 for (unsigned int i=0; i<pickManagers.size(); i++)
00286 pickManagers[i]->update();
00287 }
00288
00290 void RayPickInteractor::newPosition(const Vector3& , const Quat& , const Mat4x4d& transformation)
00291 {
00292 transform = transformation;
00293 }
00294
00295 void RayPickInteractor::newEvent(const std::string& command)
00296 {
00297 const int oldState = state;
00298
00299 if (command == "hide")
00300 {
00301 state = DISABLED;
00302 }
00303 else
00304 {
00305 switch(oldState)
00306 {
00307 case DISABLED:
00308 if (command == "show")
00309 {
00310 state = PRESENT;
00311 }
00312 case PRESENT:
00313 if (command == "pick" || command == "pick1")
00314 {
00315 state = ACTIVE;
00316 button = 0;
00317 }
00318 else if (command == "pick2")
00319 {
00320 state = ACTIVE;
00321 button = 1;
00322 }
00323 break;
00324 case ACTIVE:
00325 case ATTACHED:
00326 if (command == "release")
00327 state = PRESENT;
00328 break;
00329 case FIRST_INPUT:
00330
00331 break;
00332 case IS_CUT:
00333
00334 break;
00335 case SECOND_INPUT:
00336 if (command == "pick3")
00337 {
00338 state = IS_CUT;
00339 button = 2;
00340 }
00341 break;
00342 }
00343 }
00344
00345 if (command == "pick3")
00346 {
00347 if (oldState!=SECOND_INPUT)
00348 {
00349 state = FIRST_INPUT;
00350 button = 2;
00351 }
00352 }
00353
00354 if (oldState != state)
00355 {
00356 std::cout << "Interactor State: ";
00357 switch (state)
00358 {
00359 case DISABLED:
00360 std::cout << "DISABLED";
00361 break;
00362 case PRESENT:
00363 std::cout << "PRESENT";
00364 break;
00365 case ACTIVE:
00366 std::cout << "ACTIVE, button = "<<button;
00367 break;
00368 case ATTACHED:
00369 std::cout << "ATTACHED";
00370 break;
00371 case FIRST_INPUT:
00372 std::cout << "FIRST_INPUT, button = "<<button;
00373 break;
00374 case SECOND_INPUT:
00375 std::cout << "SECOND_INPUT, button = "<<button;
00376 break;
00377 case IS_CUT:
00378 std::cout << "IS_CUT";
00379 break;
00380 }
00381 std::cout << std::endl;
00382 }
00383 }
00384
00385 core::componentmodel::collision::DetectionOutput* RayPickInteractor::findFirstCollision(const Ray& ray, double* dist)
00386 {
00387 core::componentmodel::collision::DetectionOutput* result = NULL;
00388 const Vector3& origin = ray.origin();
00389 const Vector3& direction = ray.direction();
00390 double l = ray.l();
00391 double mindist = 0;
00392 for (std::set<BaseRayContact*>::iterator it = contacts.begin(); it!=contacts.end(); ++it)
00393 {
00394 const sofa::helper::vector<core::componentmodel::collision::DetectionOutput*>& collisions = (*it)->getDetectionOutputs();
00395 for (unsigned int i=0;i<collisions.size();i++)
00396 {
00397 core::componentmodel::collision::DetectionOutput* collision = collisions[i];
00398 if (collision->elem.second == ray)
00399 {
00400 if (!collision->elem.first.getCollisionModel()->isSimulated())
00401 continue;
00402 double d = (collision->point[1] - origin)*direction;
00403 if (d<0.0 || d>l)
00404 continue;
00405 if (result==NULL || d<mindist)
00406 {
00407 result = collision;
00408 mindist = d;
00409 }
00410 }
00411 else
00412 if (collision->elem.first == ray)
00413 {
00414 if (!collision->elem.second.getCollisionModel()->isSimulated())
00415 continue;
00416 double d = (collision->point[0] - origin)*direction;
00417 if (d<0.0 || d>l)
00418 continue;
00419 if (result==NULL || d<mindist)
00420 {
00421 result = collision;
00422 mindist = d;
00423 }
00424 }
00425 }
00426 }
00427 if (dist!=NULL && result!=NULL)
00428 *dist = mindist;
00429 return result;
00430 }
00431
00432 void RayPickInteractor::draw()
00433 {
00434 if (getNbRay()>=1)
00435 this->RayModel::draw();
00436 if (state==PRESENT)
00437 glColor4f(0,1,0,1);
00438 else if (state==ATTACHED)
00439 glColor4f(1,1,1,1);
00440 else
00441 return;
00442 glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
00443 glLineWidth(3);
00444 for (int r = 0; r < getNbRay(); r++)
00445 {
00446 Ray ray = getRay(r);
00447 double dist = 0;
00448 core::componentmodel::collision::DetectionOutput* collision = findFirstCollision(ray,&dist);
00449 if (collision==NULL)
00450 continue;
00451 core::CollisionElementIterator elem = collision->elem.first;
00452 if (elem.getIndex() < elem.getCollisionModel()->getSize())
00453 elem.draw();
00454 }
00455 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
00456 glColor4f(1,1,1,1);
00457 glLineWidth(1);
00458 }
00459
00460 }
00461
00462 }
00463
00464 }