Statistiques
| Révision :

root / MyDefaultContactManager.cpp

Historique | Voir | Annoter | Télécharger (15,15 ko)

1
/******************************************************************************
2
*       SOFA, Simulation Open-Framework Architecture, version 1.0 RC 1        *
3
*                (c) 2006-2011 MGH, INRIA, USTL, UJF, CNRS                    *
4
*                                                                             *
5
* This library is free software; you can redistribute it and/or modify it     *
6
* under the terms of the GNU Lesser General Public License as published by    *
7
* the Free Software Foundation; either version 2.1 of the License, or (at     *
8
* your option) any later version.                                             *
9
*                                                                             *
10
* This library is distributed in the hope that it will be useful, but WITHOUT *
11
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or       *
12
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License *
13
* for more details.                                                           *
14
*                                                                             *
15
* You should have received a copy of the GNU Lesser General Public License    *
16
* along with this library; if not, write to the Free Software Foundation,     *
17
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA.          *
18
*******************************************************************************
19
*                               SOFA :: Modules                               *
20
*                                                                             *
21
* Authors: The SOFA Team and external contributors (see Authors.txt)          *
22
*                                                                             *
23
* Contact information: contact@sofa-framework.org                             *
24
******************************************************************************/
25
//#include <sofa/component/collision/DefaultContactManager.h>
26

    
27
#include "MyDefaultContactManager.h"
28
#include <sofa/core/visual/VisualParams.h>
29
#include <sofa/core/ObjectFactory.h>
30
#include <sofa/core/objectmodel/Tag.h>
31

    
32

    
33
namespace sofa
34
{
35

    
36
namespace component
37
{
38

    
39
namespace collision
40
{
41

    
42
SOFA_DECL_CLASS(MyDefaultContactManager)
43

    
44
int MyDefaultContactManagerClass = core::RegisterObject("My Default class to create reactions to the collisions")
45
        .add< MyDefaultContactManager >()
46
        .addAlias("MyCollisionResponse")
47
        ;
48

    
49
MyDefaultContactManager::MyDefaultContactManager()
50
    : response(initData(&response, "response", "contact response class"))
51
    , responseParams(initData(&responseParams, "responseParams", "contact response parameters (syntax: name1=value1&name2=value2&...)"))
52
    //,deepInMeristem(0.0)
53
    ,deepInMeristem(initData(&deepInMeristem,"deepInMeristem","how deep we are in the meristem"))
54
    ,aTouche(initData(&aTouche,"aTouche","has there been a collision between the meristem and the indentor"))
55
    ,origine(initData(&origine,"origine","origine of collision between the meristem and the indentor"))
56
{
57
}
58

    
59
MyDefaultContactManager::~MyDefaultContactManager()
60
{
61
    // Contacts are now attached to the graph.
62
    // So they will be deleted by the DeleteVisitor
63
    // FIX crash on unload bug. -- J. Allard
64
    //clear();
65
}
66

    
67
sofa::helper::OptionsGroup MyDefaultContactManager::initializeResponseOptions(core::collision::Pipeline *pipeline)
68
{
69
    helper::set<std::string> listResponse;
70
    if (pipeline) listResponse=pipeline->getResponseList();
71
    else
72
    {
73
        core::collision::Contact::Factory::iterator it;
74
        for (it=core::collision::Contact::Factory::getInstance()->begin(); it!=core::collision::Contact::Factory::getInstance()->end(); ++it)
75
        {
76
            listResponse.insert(it->first);
77
        }
78
    }
79
    sofa::helper::OptionsGroup responseOptions(listResponse);
80
    if (listResponse.find("default") != listResponse.end())
81
        responseOptions.setSelectedItem("default");
82
    return responseOptions;
83
}
84

    
85
void MyDefaultContactManager::init()
86
{
87

    
88
    aTouche.setValue(false);
89

    
90
    if (response.getValue().size() == 0)
91
    {
92
        core::collision::Pipeline *pipeline=static_cast<simulation::Node*>(getContext())->collisionPipeline;
93
        response.setValue(initializeResponseOptions(pipeline));
94
    }
95
}
96

    
97
void MyDefaultContactManager::cleanup()
98
{
99
    for (sofa::helper::vector<core::collision::Contact::SPtr>::iterator it=contacts.begin(); it!=contacts.end(); ++it)
100
    {
101
        (*it)->removeResponse();
102
        (*it)->cleanup();
103
        //delete *it;
104
        it->reset();
105
    }
106
    contacts.clear();
107
    contactMap.clear();
108
}
109

    
110
void MyDefaultContactManager::createContacts(const DetectionOutputMap& outputsMap)
111
{
112
    using core::CollisionModel;
113
    using core::collision::Contact;
114

    
115
    int nbContact = 0;
116

    
117
        double origineActuelle[3];
118

    
119

    
120
        // First iterate on the collision detection outputs and look for existing or new contacts
121
        for (DetectionOutputMap::const_iterator outputsIt = outputsMap.begin(),
122
                outputsItEnd = outputsMap.end(); outputsIt != outputsItEnd ; ++outputsIt)
123
        {
124
                const helper::set<int>& myGroup_first=outputsIt->first.first->getGroups();
125
                const helper::set<int>& myGroup_second=outputsIt->first.second->getGroups();
126
        if (aTouche.getValue()){
127
                        helper::set<int>::iterator it_first=myGroup_first.begin();
128
                        helper::set<int>::iterator it_second=myGroup_second.begin();
129
                        if (*it_first == 1){
130
                                origineActuelle[0] = outputsIt->first.first->getContext()->getMechanicalState()->getPX(0);
131
                                origineActuelle[1] = outputsIt->first.first->getContext()->getMechanicalState()->getPY(0);
132
                                origineActuelle[2] = outputsIt->first.first->getContext()->getMechanicalState()->getPZ(0);
133
                deepInMeristem.setValue(std::sqrt(pow(origine.getValue()[0]-origineActuelle[0],2)+pow(origine.getValue()[1]-origineActuelle[1],2)+pow(origine.getValue()[2]-origineActuelle[2],2)));
134
                        }
135
                        else if (*it_second==1){
136
                                origineActuelle[0] = outputsIt->first.second->getContext()->getMechanicalState()->getPX(0);
137
                                origineActuelle[1] = outputsIt->first.second->getContext()->getMechanicalState()->getPY(0);
138
                                origineActuelle[2] = outputsIt->first.second->getContext()->getMechanicalState()->getPZ(0);
139
                deepInMeristem.setValue(std::sqrt(pow(origine.getValue()[0]-origineActuelle[0],2)+pow(origine.getValue()[1]-origineActuelle[1],2)+pow(origine.getValue()[2]-origineActuelle[2],2)));
140
                        }
141
        }
142

    
143

    
144

    
145
                std::pair<ContactMap::iterator,bool> contactInsert =
146
                        contactMap.insert(ContactMap::value_type(outputsIt->first,Contact::SPtr()));
147
                ContactMap::iterator contactIt = contactInsert.first;
148
                if (contactInsert.second)
149
                {
150
            // new contact
151
            //sout << "Creation new "<<contacttype<<" contact"<<sendl;
152
            CollisionModel* model1 = outputsIt->first.first;
153
            CollisionModel* model2 = outputsIt->first.second;
154
            std::string responseUsed = getContactResponse(model1, model2);
155

    
156

    
157
            if (*model1->getGroups().begin() == 1 && !aTouche.getValue()){
158
            if (!aTouche.getValue()){
159
                printf("Collision detected\n");
160
                                std::fflush(stdout);
161

    
162
                aTouche.setValue(true);
163
                sofa::helper::vector<double> actuelorigine;
164
                actuelorigine.push_back(model1->getContext()->getMechanicalState()->getPX(0));
165
                actuelorigine.push_back(model1->getContext()->getMechanicalState()->getPY(0));
166
                actuelorigine.push_back(model1->getContext()->getMechanicalState()->getPZ(0));
167
                origine.setValue(actuelorigine);
168

    
169
            }
170
                        }
171
            else if(*model2->getGroups().begin() == 1 && !aTouche.getValue()){
172
                                printf("Collision detected\n");
173
                                std::fflush(stdout);
174

    
175
                aTouche.setValue(true);
176
                sofa::helper::vector<double> actuelorigine;
177
                actuelorigine.push_back(model2->getContext()->getMechanicalState()->getPX(0));
178
                actuelorigine.push_back(model2->getContext()->getMechanicalState()->getPY(0));
179
                actuelorigine.push_back(model2->getContext()->getMechanicalState()->getPZ(0));
180
                origine.setValue(actuelorigine);
181
            }
182
                
183
                        std::fflush(stdout);
184

    
185

    
186

    
187
            // We can create rules in order to not respond to specific collisions
188
            if (!responseUsed.compare("null"))
189
            {
190
                                contactMap.erase(contactIt);
191
            }
192
                        else
193
                        {
194
                                Contact::SPtr contact = Contact::Create(responseUsed, model1, model2, intersectionMethod,
195
                                        this->f_printLog.getValue());
196

    
197
                                if (contact == NULL)
198
                                {
199
                                        std::string model1class = model1->getClassName();
200
                                        std::string model2class = model2->getClassName();
201
                                        int count = ++errorMsgCount[std::make_pair(responseUsed,
202
                                                std::make_pair(model1class, model2class))];
203
                                        if (count <= 10)
204
                                        {
205
                                                serr << "Contact " << responseUsed << " between " << model1->getClassName()
206
                                                        << " and " << model2->getClassName() << " creation failed" << sendl;
207
                                                if (count == 1)
208
                                                {
209
                                                        serr << "Supported models for contact " << responseUsed << ":" << sendl;
210
                                                        for (Contact::Factory::const_iterator it =
211
                                                                Contact::Factory::getInstance()->begin(),
212
                                                                itend = Contact::Factory::getInstance()->end(); it != itend; ++it)
213
                                                        {
214
                                                                if (it->first != responseUsed) continue;
215
                                                                serr << "   " << helper::gettypename(it->second->type()) << sendl;
216
                                                        }
217
                                                        serr << sendl;
218
                                                }
219
                                                if (count == 10) serr << "further messages suppressed" << sendl;
220
                                        }
221
                                        contactMap.erase(contactIt);
222
                                }
223
                                else
224
                                {
225
                                        contactIt->second = contact;
226
                                        contact->setName(model1->getName() + std::string("-") + model2->getName());
227
                                        setContactTags(model1, model2, contact);
228
                                        contact->f_printLog.setValue(this->f_printLog.getValue());
229
                                        contact->init();
230
                                        contact->setDetectionOutputs(outputsIt->second);
231
                                        ++nbContact;
232
                                }
233
                        }
234
                }
235
                else
236
                {
237
            // pre-existing and still active contact
238
            contactIt->second->setDetectionOutputs(outputsIt->second);
239
            ++nbContact;
240
                }
241
        }
242

    
243
        // Then look at previous contacts
244
        // and remove inactive contacts
245
        std::stack<ContactMap::iterator> deadContacts;
246
        for (ContactMap::iterator contactIt = contactMap.begin(), contactItEnd = contactMap.end();
247
                contactIt != contactItEnd;)
248
        {
249
                bool remove = false;
250
                DetectionOutputMap::const_iterator outputsIt = outputsMap.find(contactIt->first);
251
                if (outputsIt == outputsMap.end())
252
                {
253
            // inactive contact
254
            if (contactIt->second->keepAlive())
255
            {
256
                                contactIt->second->setDetectionOutputs(NULL);
257
                ++nbContact;
258
            }
259
            else
260
            {
261
                                remove = true;
262
                        }
263
                }
264
                if (remove)
265
                {
266
                        if (contactIt->second)
267
                        {
268
                contactIt->second->removeResponse();
269
                contactIt->second->cleanup();
270
                contactIt->second.reset();
271
                        }
272
                        ContactMap::iterator eraseIt = contactIt;
273
                        ++contactIt;
274
                        contactMap.erase(eraseIt);
275
                }
276
                else
277
                {
278
                        ++contactIt;
279
                }
280
        }
281

    
282
    // now update contactVec
283
    contacts.clear();
284
    contacts.reserve(nbContact);
285
    for (ContactMap::const_iterator contactIt = contactMap.begin(), contactItEnd = contactMap.end();
286
                contactIt != contactItEnd; ++contactIt)
287
    {
288
        contacts.push_back(contactIt->second);
289
    }
290

    
291
    // compute number of contacts attached to each collision model
292
    std::map< CollisionModel*, int > nbContactsMap;
293
    for (unsigned int i = 0; i < contacts.size(); ++i)
294
    {
295
        std::pair< CollisionModel*, CollisionModel* > cms = contacts[i]->getCollisionModels();
296
        nbContactsMap[cms.first]++;
297
        if (cms.second != cms.first)
298
            nbContactsMap[cms.second]++;
299
    }
300

    
301
        // TODO: this is VERY inefficient, should be replaced with a visitor
302
    helper::vector< CollisionModel* > collisionModels;
303
    simulation::Node* context = dynamic_cast< simulation::Node* >(getContext());
304
    context->getTreeObjects< CollisionModel >(&collisionModels);
305

    
306
    for (unsigned int i = 0; i < collisionModels.size(); ++i)
307
    {
308
        collisionModels[i]->setNumberOfContacts(nbContactsMap[collisionModels[i]]);
309
    }
310
}
311

    
312
std::string MyDefaultContactManager::getContactResponse(core::CollisionModel* model1, core::CollisionModel* model2)
313
{
314
    std::string responseUsed = response.getValue().getSelectedItem();
315
    std::string params = responseParams.getValue();
316
    if (!params.empty())
317
    {
318
        responseUsed += '?';
319
        responseUsed += params;
320
    }
321
    std::string response1 = model1->getContactResponse();
322
    std::string response2 = model2->getContactResponse();
323

    
324
    if (response1.empty()  &&  response2.empty()) return responseUsed;
325
    if (response1.empty()  && !response2.empty()) return response2;
326
    if (!response1.empty() &&  response2.empty()) return response1;
327

    
328
    if (response1 != response2) return responseUsed;
329
    else return response1;
330
}
331

    
332
void MyDefaultContactManager::draw(const core::visual::VisualParams* vparams)
333
{
334
    for (sofa::helper::vector<core::collision::Contact::SPtr>::iterator it = contacts.begin(); it!=contacts.end(); it++)
335
    {
336
        if ((*it)!=NULL)
337
            (*it)->draw(vparams);
338
    }
339
}
340

    
341
void MyDefaultContactManager::removeContacts(const ContactVector &c)
342
{
343
    ContactVector::const_iterator remove_it = c.begin();
344
    ContactVector::const_iterator remove_itEnd = c.end();
345

    
346
    ContactVector::iterator it;
347
    ContactVector::iterator itEnd;
348

    
349
    ContactMap::iterator map_it;
350
    ContactMap::iterator map_itEnd;
351

    
352
    while (remove_it != remove_itEnd)
353
    {
354
        // Whole scene contacts
355
        it = contacts.begin();
356
        itEnd = contacts.end();
357

    
358
        while (it != itEnd)
359
        {
360
            if (*it == *remove_it)
361
            {
362
                (*it)->removeResponse();
363
                (*it)->cleanup();
364
                it->reset();
365
                contacts.erase(it);
366
                break;
367
            }
368

    
369
            ++it;
370
        }
371

    
372
        // Stored contacts (keeping alive)
373
        map_it = contactMap.begin();
374
        map_itEnd = contactMap.end();
375

    
376
        while (map_it != map_itEnd)
377
        {
378
            if (map_it->second == *remove_it)
379
            {
380
                ContactMap::iterator erase_it = map_it;
381
                ++map_it;
382

    
383
                erase_it->second->removeResponse();
384
                erase_it->second->cleanup();
385
                erase_it->second.reset();
386
                contactMap.erase(erase_it);
387
            }
388
            else
389
            {
390
                ++map_it;
391
            }
392
        }
393

    
394
        ++remove_it;
395
    }
396
}
397

    
398
void MyDefaultContactManager::setContactTags(core::CollisionModel* model1, core::CollisionModel* model2, core::collision::Contact::SPtr contact)
399
{
400
    sofa::core::objectmodel::TagSet tagsm1 = model1->getTags();
401
    sofa::core::objectmodel::TagSet tagsm2 = model2->getTags();
402
    sofa::core::objectmodel::TagSet::iterator it;
403
    for(it=tagsm1.begin(); it != tagsm1.end(); it++)
404
        contact->addTag(*it);
405
    for(it=tagsm2.begin(); it!=tagsm2.end(); it++)
406
        contact->addTag(*it);
407
}
408

    
409
} // namespace collision
410

    
411
} // namespace component
412

    
413
} // namespace sofa