Révision 1
MyDefaultContactManager.h (revision 1) | ||
---|---|---|
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 |
#ifndef SOFA_COMPONENT_COLLISION_MYDEFAULTCONTACTMANAGER_H |
|
26 |
#define SOFA_COMPONENT_COLLISION_MYDEFAULTCONTACTMANAGER_H |
|
27 |
|
|
28 |
#include <sofa/core/collision/ContactManager.h> |
|
29 |
#include <sofa/simulation/common/Node.h> |
|
30 |
#include <sofa/component/component.h> |
|
31 |
#include <sofa/helper/OptionsGroup.h> |
|
32 |
#include <sofa/helper/map_ptr_stable_compare.h> |
|
33 |
#include <vector> |
|
34 |
|
|
35 |
#include "initAFM_plane.h" |
|
36 |
|
|
37 |
namespace sofa |
|
38 |
{ |
|
39 |
|
|
40 |
namespace component |
|
41 |
{ |
|
42 |
|
|
43 |
namespace collision |
|
44 |
{ |
|
45 |
|
|
46 |
class SOFA_AFM_plane_API MyDefaultContactManager : public core::collision::ContactManager |
|
47 |
{ |
|
48 |
public : |
|
49 |
SOFA_CLASS(MyDefaultContactManager,sofa::core::collision::ContactManager); |
|
50 |
|
|
51 |
protected: |
|
52 |
typedef sofa::helper::map_ptr_stable_compare<std::pair<core::CollisionModel*,core::CollisionModel*>,core::collision::Contact::SPtr> ContactMap; |
|
53 |
ContactMap contactMap; |
|
54 |
//typedef struct MaProfondeur{bool aTouche; double origine[3];} Profondeur; |
|
55 |
|
|
56 |
void cleanup(); |
|
57 |
public: |
|
58 |
//typedef struct MaProfondeur{bool aTouche; double origine[3];} Profondeur; |
|
59 |
|
|
60 |
Data<double> deepInMeristem; |
|
61 |
Data<bool> aTouche; |
|
62 |
Data<sofa::helper::vector<double> > origine; |
|
63 |
Data<sofa::helper::OptionsGroup> response; |
|
64 |
Data<std::string> responseParams; |
|
65 |
protected: |
|
66 |
MyDefaultContactManager(); |
|
67 |
~MyDefaultContactManager(); |
|
68 |
void setContactTags(core::CollisionModel* model1, core::CollisionModel* model2, core::collision::Contact::SPtr contact); |
|
69 |
|
|
70 |
//double deepInMeristem; |
|
71 |
//Profondeur penetration; |
|
72 |
|
|
73 |
public: |
|
74 |
|
|
75 |
// bool CollisionDetected(){return penetration.aTouche;} |
|
76 |
// double getDepth(){return deepInMeristem;} |
|
77 |
bool CollisionDetected(){return aTouche.getValue();} |
|
78 |
double getDepth(){return deepInMeristem.getValue();} |
|
79 |
/// outputsVec fixes the reproducibility problems by storing contacts in the collision detection saved order |
|
80 |
/// if not given, it is still working but with eventual reproducibility problems |
|
81 |
void createContacts(const DetectionOutputMap& outputs); |
|
82 |
|
|
83 |
void init(); |
|
84 |
void draw(const core::visual::VisualParams* vparams); |
|
85 |
|
|
86 |
template<class T> |
|
87 |
static typename T::SPtr create(T*, core::objectmodel::BaseContext* context, core::objectmodel::BaseObjectDescription* arg) |
|
88 |
{ |
|
89 |
typename T::SPtr obj = sofa::core::objectmodel::New<T>(); |
|
90 |
|
|
91 |
if (context) |
|
92 |
{ |
|
93 |
context->addObject(obj); |
|
94 |
core::collision::Pipeline *pipeline = static_cast<simulation::Node*>(context)->collisionPipeline; |
|
95 |
sofa::helper::OptionsGroup options = initializeResponseOptions(pipeline); |
|
96 |
obj->response.setValue(options); |
|
97 |
} |
|
98 |
|
|
99 |
if (arg) |
|
100 |
obj->parse(arg); |
|
101 |
|
|
102 |
return obj; |
|
103 |
} |
|
104 |
|
|
105 |
virtual std::string getContactResponse(core::CollisionModel* model1, core::CollisionModel* model2); |
|
106 |
|
|
107 |
/// virtual methods used for cleaning the pipeline after a dynamic graph node deletion. |
|
108 |
/** |
|
109 |
* Contacts can be attached to a deleted node and their deletion is a problem for the pipeline. |
|
110 |
* @param c is the list of deleted contacts. |
|
111 |
*/ |
|
112 |
virtual void removeContacts(const ContactVector &/*c*/); |
|
113 |
void setDefaultResponseType(const std::string &responseT) |
|
114 |
{ |
|
115 |
if (response.getValue().size() == 0) |
|
116 |
{ |
|
117 |
helper::vector<std::string> listResponse(1,responseT); |
|
118 |
|
|
119 |
sofa::helper::OptionsGroup responseOptions(listResponse); |
|
120 |
response.setValue(responseOptions); |
|
121 |
} |
|
122 |
else |
|
123 |
{ |
|
124 |
sofa::helper::OptionsGroup* options = response.beginEdit(); |
|
125 |
|
|
126 |
options->setSelectedItem(responseT); |
|
127 |
response.endEdit(); |
|
128 |
} |
|
129 |
} |
|
130 |
|
|
131 |
std::string getDefaultResponseType() const { return response.getValue().getSelectedItem(); } |
|
132 |
|
|
133 |
protected: |
|
134 |
static sofa::helper::OptionsGroup initializeResponseOptions(core::collision::Pipeline *pipeline); |
|
135 |
|
|
136 |
std::map<Instance,ContactMap> storedContactMap; |
|
137 |
|
|
138 |
virtual void changeInstance(Instance inst) |
|
139 |
{ |
|
140 |
core::collision::ContactManager::changeInstance(inst); |
|
141 |
storedContactMap[instance].swap(contactMap); |
|
142 |
contactMap.swap(storedContactMap[inst]); |
|
143 |
} |
|
144 |
|
|
145 |
// count failure messages, so we don't continuously repeat them |
|
146 |
std::map<std::pair<std::string,std::pair<std::string,std::string> >, int> errorMsgCount; |
|
147 |
}; |
|
148 |
|
|
149 |
} // namespace collision |
|
150 |
|
|
151 |
} // namespace component |
|
152 |
|
|
153 |
} // namespace sofa |
|
154 |
|
|
155 |
#endif |
initAFM_plane.cpp (revision 1) | ||
---|---|---|
1 |
|
|
2 |
/****************************************************************************** |
|
3 |
* SOFA, Simulation Open-Framework Architecture, version 1.0 RC 1 * |
|
4 |
* (c) 2006-2011 MGH, INRIA, USTL, UJF, CNRS * |
|
5 |
* * |
|
6 |
* This library is free software; you can redistribute it and/or modify it * |
|
7 |
* under the terms of the GNU Lesser General Public License as published by * |
|
8 |
* the Free Software Foundation; either version 2.1 of the License, or (at * |
|
9 |
* your option) any later version. * |
|
10 |
* * |
|
11 |
* This library is distributed in the hope that it will be useful, but WITHOUT * |
|
12 |
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * |
|
13 |
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * |
|
14 |
* for more details. * |
|
15 |
* * |
|
16 |
* You should have received a copy of the GNU Lesser General Public License * |
|
17 |
* along with this library; if not, write to the Free Software Foundation, * |
|
18 |
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * |
|
19 |
******************************************************************************* |
|
20 |
* SOFA :: Plugins * |
|
21 |
* * |
|
22 |
* Authors: The SOFA Team and external contributors (see Authors.txt) * |
|
23 |
* * |
|
24 |
* Contact information: contact@sofa-framework.org * |
|
25 |
******************************************************************************/ |
|
26 |
#include "initAFM_plane.h" |
|
27 |
|
|
28 |
namespace sofa |
|
29 |
{ |
|
30 |
|
|
31 |
namespace component |
|
32 |
{ |
|
33 |
|
|
34 |
//Here are just several convenient functions to help user to know what contains the plugin |
|
35 |
|
|
36 |
extern "C" { |
|
37 |
SOFA_AFM_plane_API void initExternalModule(); |
|
38 |
SOFA_AFM_plane_API const char* getModuleName(); |
|
39 |
SOFA_AFM_plane_API const char* getModuleVersion(); |
|
40 |
SOFA_AFM_plane_API const char* getModuleLicense(); |
|
41 |
SOFA_AFM_plane_API const char* getModuleDescription(); |
|
42 |
SOFA_AFM_plane_API const char* getModuleComponentList(); |
|
43 |
} |
|
44 |
|
|
45 |
void initExternalModule() |
|
46 |
{ |
|
47 |
static bool first = true; |
|
48 |
if (first) |
|
49 |
{ |
|
50 |
first = false; |
|
51 |
} |
|
52 |
} |
|
53 |
|
|
54 |
const char* getModuleName() |
|
55 |
{ |
|
56 |
return "AFM_plane"; |
|
57 |
} |
|
58 |
|
|
59 |
const char* getModuleVersion() |
|
60 |
{ |
|
61 |
return "0.2"; |
|
62 |
} |
|
63 |
|
|
64 |
const char* getModuleLicense() |
|
65 |
{ |
|
66 |
return "LGPL"; |
|
67 |
} |
|
68 |
|
|
69 |
|
|
70 |
const char* getModuleDescription() |
|
71 |
{ |
|
72 |
return "TODO: replace this with the description of your plugin"; |
|
73 |
} |
|
74 |
|
|
75 |
const char* getModuleComponentList() |
|
76 |
{ |
|
77 |
/// string containing the names of the classes provided by the plugin |
|
78 |
return ""; |
|
79 |
//return "MyMappingPendulumInPlane, MyBehaviorModel, MyProjectiveConstraintSet"; |
|
80 |
} |
|
81 |
|
|
82 |
|
|
83 |
|
|
84 |
} |
|
85 |
|
|
86 |
} |
|
87 |
|
|
88 |
/// Use the SOFA_LINK_CLASS macro for each class, to enable linking on all platforms |
|
89 |
SOFA_LINK_CLASS(MyDefaultContactManager) |
README.txt (revision 1) | ||
---|---|---|
1 |
Author : R. Malgat, F. Faure, A. Boudaoud. |
|
2 |
|
|
3 |
This plugin works with the Software Open Framework Architecture (SOFA). |
|
4 |
It is a simulated Atomic Force Microscope acting on a plane. |
|
5 |
|
|
6 |
To get an idea of the scene, you can launch Sofa on the example examples/plane.py. The scene appearing should be like the image plane.png and gives you an overview of the scene described. |
|
7 |
Then to use the AFM and trace curves, simply install the folder as a SOFA plugin. Go to the examples folder and launch the application called AFM which should be under "YourPathToSofa/build_release/bin/AFM". You should get a resulting curve called AFM-results.txt, where, for each line, the force and the corresponding depth is written. |
|
8 |
Feel free to change the parameters : pressure, elastic modulus, poisson ratio... |
|
9 |
|
|
10 |
If Sofa does not find the path to the plugin when you launch the AFM application, you may have to change the paths in the file AFM/AFM.cpp line 112 and eventually line 129. |
initAFM_plane.h (revision 1) | ||
---|---|---|
1 |
|
|
2 |
/****************************************************************************** |
|
3 |
* SOFA, Simulation Open-Framework Architecture, version 1.0 RC 1 * |
|
4 |
* (c) 2006-2011 MGH, INRIA, USTL, UJF, CNRS * |
|
5 |
* * |
|
6 |
* This library is free software; you can redistribute it and/or modify it * |
|
7 |
* under the terms of the GNU Lesser General Public License as published by * |
|
8 |
* the Free Software Foundation; either version 2.1 of the License, or (at * |
|
9 |
* your option) any later version. * |
|
10 |
* * |
|
11 |
* This library is distributed in the hope that it will be useful, but WITHOUT * |
|
12 |
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * |
|
13 |
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * |
|
14 |
* for more details. * |
|
15 |
* * |
|
16 |
* You should have received a copy of the GNU Lesser General Public License * |
|
17 |
* along with this library; if not, write to the Free Software Foundation, * |
|
18 |
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * |
|
19 |
******************************************************************************* |
|
20 |
* SOFA :: Plugins * |
|
21 |
* * |
|
22 |
* Authors: The SOFA Team and external contributors (see Authors.txt) * |
|
23 |
* * |
|
24 |
* Contact information: contact@sofa-framework.org * |
|
25 |
******************************************************************************/ |
|
26 |
#ifndef INITAFM_plane_H |
|
27 |
#define INITAFM_plane_H |
|
28 |
|
|
29 |
|
|
30 |
#include <sofa/helper/system/config.h> |
|
31 |
|
|
32 |
#ifdef SOFA_BUILD_AFM_plane |
|
33 |
#define SOFA_AFM_plane_API SOFA_EXPORT_DYNAMIC_LIBRARY |
|
34 |
#else |
|
35 |
#define SOFA_AFM_plane_API SOFA_IMPORT_DYNAMIC_LIBRARY |
|
36 |
#endif |
|
37 |
|
|
38 |
|
|
39 |
#endif // INITAFM_plane_H |
CMakeLists.txt (revision 1) | ||
---|---|---|
1 |
include(${SOFA_CMAKE_DIR}/preProject.cmake) |
|
2 |
|
|
3 |
##plugin external dependencies |
|
4 |
#find_package( REQUIRED) |
|
5 |
#include_directories(${}) |
|
6 |
|
|
7 |
set(HEADER_FILES |
|
8 |
|
|
9 |
initAFM_plane.h |
|
10 |
MyDefaultContactManager.h |
|
11 |
) |
|
12 |
|
|
13 |
set(SOURCE_FILES |
|
14 |
|
|
15 |
initAFM_plane.cpp |
|
16 |
MyDefaultContactManager.cpp |
|
17 |
) |
|
18 |
|
|
19 |
set(README_FILES |
|
20 |
|
|
21 |
|
|
22 |
) |
|
23 |
|
|
24 |
|
|
25 |
add_library(${PROJECT_NAME} SHARED ${HEADER_FILES} ${MOC_FILES} ${SOURCE_FILES} ${README_FILES}) |
|
26 |
|
|
27 |
AddCompilerDefinitions("SOFA_BUILD_AFM-plane") |
|
28 |
AddLinkerDependencies(SofaGuiQt) |
|
29 |
|
|
30 |
include(${SOFA_CMAKE_DIR}/postProject.cmake) |
examples/AFM-results.txt (revision 1) | ||
---|---|---|
1 |
### first the force then the depth ### |
|
2 |
|
|
3 |
0.1 0.0566023 |
|
4 |
0.2 0.0629732 |
|
5 |
0.3 0.0707535 |
|
6 |
0.4 0.0788602 |
|
7 |
0.5 0.0870693 |
|
8 |
0.6 0.0951414 |
|
9 |
0.7 0.103042 |
|
10 |
0.8 0.110816 |
|
11 |
0.9 0.118506 |
|
12 |
1 0.126105 |
|
13 |
1.1 0.13365 |
|
14 |
1.2 0.141175 |
|
15 |
1.3 0.148656 |
|
16 |
1.4 0.156105 |
examples/plane.py (revision 1) | ||
---|---|---|
1 |
import Sofa |
|
2 |
|
|
3 |
poissonRatio = 0.49 |
|
4 |
youngModulus = 100 |
|
5 |
pressure = 5 |
|
6 |
|
|
7 |
indentorRadius = 0.3 |
|
8 |
|
|
9 |
def createScene(node): |
|
10 |
|
|
11 |
print 'Creation of Sofa SceneGraph' |
|
12 |
|
|
13 |
node.gravity = [0,0,0] |
|
14 |
|
|
15 |
node.createObject('RequiredPlugin', pluginName="Flexible") |
|
16 |
|
|
17 |
node.createObject('VisualStyle', displayFlags = 'showVisual hideBehavior showCollisionModels') |
|
18 |
node.createObject('DefaultPipeline', name="DefaultCollisionPipeline", verbose="0", draw="0", depth="6") |
|
19 |
node.createObject('BruteForceDetection', name="Detection") |
|
20 |
node.createObject('MinProximityIntersection', name="Proximity", alarmDistance="0.1", contactDistance="0.0") |
|
21 |
node.createObject('DefaultContactManager', name="Response", response="default", responseParams="") |
|
22 |
node.createObject('TreeCollisionGroupManager', name="Group") |
|
23 |
|
|
24 |
node.createObject('CGLinearSolver', template="GraphScattered",iterations=500,threshold=1e-10,tolerance=1e-10) |
|
25 |
node.createObject('EulerImplicitSolver', rayleighStiffness=0.5,rayleighMass=0.5) |
|
26 |
|
|
27 |
node.createObject('GridMeshCreator', name='Grid', resolution="10 10", triangulate=1) |
|
28 |
node.createObject('MeshTopology', name='Topology',src="@Grid") |
|
29 |
node.createObject('MechanicalObject', name='DOFs', template="Vec3d") |
|
30 |
node.createObject('UniformMass',name='mass', template='Vec3d') |
|
31 |
node.createObject('FixedConstraint',template="Vec3d", indices="0 9 90 99" ) |
|
32 |
|
|
33 |
## Pressure |
|
34 |
node.createObject("SurfacePressureForceField", pressure=pressure) |
|
35 |
|
|
36 |
## Deformation, Stress and Strain |
|
37 |
node.createObject('BarycentricShapeFunction', template="ShapeFunctiond") |
|
38 |
deformation = node.createChild("deformation") |
|
39 |
deformation.createObject('TopologyGaussPointSampler',name='sampler', inPosition='@../Topology.position' , showSamples="false", method="0", order="1" ) |
|
40 |
deformation.createObject('MechanicalObject', name='deform', template='F321') |
|
41 |
deformation.createObject('LinearMapping', template='Vec3d,F321') |
|
42 |
stressStrain = deformation.createChild('stressStrain') |
|
43 |
stressStrain.createObject('MechanicalObject', name='Strain',template='E321') |
|
44 |
stressStrain.createObject('CorotationalStrainMapping', template="F321,E321") |
|
45 |
stressStrain.createObject('HookeForceField', template="E321", youngModulus=youngModulus,poissonRatio=poissonRatio, viscosity=0 ) |
|
46 |
|
|
47 |
## Collision |
|
48 |
node.createObject('TriangleModel',contactStiffness=1000) |
|
49 |
node.createObject('LineModel',contactStiffness=1000) |
|
50 |
node.createObject('PointModel',contactStiffness=1000) |
|
51 |
Visu = node.createChild('Visu') |
|
52 |
Visu.createObject('OglModel') |
|
53 |
Visu.createObject('IdentityMapping', template='Vec3d,ExtVec3f') |
|
54 |
|
|
55 |
## indentor |
|
56 |
indentor = node.createChild('indentor') |
|
57 |
indentor.createObject('MechanicalObject',name='indentor', position="0.5 0.5 2") |
|
58 |
indentor.createObject('UniformMass') |
|
59 |
indentor.createObject('ConstantForceField', points=0, force="0 0 -1") |
|
60 |
indentor.createObject('TSphereModel', radius= indentorRadius, ContactStiffness=1000) |
|
61 |
indentor.createObject('ProjectToLineConstraint',endTime='-1', indices=0, origin="0.5 0.5 2", direction="0 0 1") |
|
62 |
indentor.createObject('PointConstraint', endTime=3, indices=0) |
examples/AFM-plane.py (revision 1) | ||
---|---|---|
1 |
import Sofa |
|
2 |
|
|
3 |
poissonRatio = 0.49 |
|
4 |
youngModulus = 100 |
|
5 |
pressure = 5 |
|
6 |
|
|
7 |
indentorRadius = 0.3 |
|
8 |
|
|
9 |
def createScene(node): |
|
10 |
|
|
11 |
print 'Creation of Sofa SceneGraph' |
|
12 |
|
|
13 |
node.gravity = [0,0,0] |
|
14 |
|
|
15 |
node.createObject('RequiredPlugin', pluginName="Flexible") |
|
16 |
node.createObject('RequiredPlugin', pluginName="AFM_plane") |
|
17 |
|
|
18 |
node.createObject('VisualStyle', displayFlags = 'showVisual hideBehavior showCollisionModels') |
|
19 |
node.createObject('DefaultPipeline', name="DefaultCollisionPipeline", verbose="0", draw="0", depth="6") |
|
20 |
node.createObject('BruteForceDetection', name="Detection") |
|
21 |
node.createObject('MinProximityIntersection', name="Proximity", alarmDistance="0.05", contactDistance="0.0") |
|
22 |
node.createObject('MyDefaultContactManager', name="Response", response="default", responseParams="") |
|
23 |
node.createObject('TreeCollisionGroupManager', name="Group") |
|
24 |
|
|
25 |
node.createObject('CGLinearSolver', template="GraphScattered",iterations=500,threshold=1e-10,tolerance=1e-10) |
|
26 |
node.createObject('EulerImplicitSolver', rayleighStiffness=0.5,rayleighMass=0.5) |
|
27 |
|
|
28 |
node.createObject('GridMeshCreator', name='Grid', resolution="10 10", triangulate=1) |
|
29 |
node.createObject('MeshTopology', name='Topology',src="@Grid") |
|
30 |
node.createObject('MechanicalObject', name='DOFs', template="Vec3d") |
|
31 |
node.createObject('UniformMass',name='mass', template='Vec3d') |
|
32 |
node.createObject('FixedConstraint',template="Vec3d", indices="0 9 90 99" ) |
|
33 |
|
|
34 |
## Pressure |
|
35 |
node.createObject("SurfacePressureForceField", pressure=pressure) |
|
36 |
|
|
37 |
## Deformation, Stress and Strain |
|
38 |
node.createObject('BarycentricShapeFunction', template="ShapeFunctiond") |
|
39 |
deformation = node.createChild("deformation") |
|
40 |
deformation.createObject('TopologyGaussPointSampler',name='sampler', inPosition='@../Topology.position' , showSamples="false", method="0", order="1" ) |
|
41 |
deformation.createObject('MechanicalObject', name='deform', template='F321') |
|
42 |
deformation.createObject('LinearMapping', template='Vec3d,F321') |
|
43 |
stressStrain = deformation.createChild('stressStrain') |
|
44 |
stressStrain.createObject('MechanicalObject', name='Strain',template='E321') |
|
45 |
stressStrain.createObject('CorotationalStrainMapping', template="F321,E321") |
|
46 |
stressStrain.createObject('HookeForceField', template="E321", youngModulus=youngModulus,poissonRatio=poissonRatio, viscosity=0 ) |
|
47 |
|
|
48 |
## Collision |
|
49 |
node.createObject('TriangleModel',contactStiffness=1000,group=0) |
|
50 |
node.createObject('LineModel',contactStiffness=1000,group=0) |
|
51 |
node.createObject('PointModel',contactStiffness=1000,group=0) |
|
52 |
Visu = node.createChild('Visu') |
|
53 |
Visu.createObject('OglModel') |
|
54 |
Visu.createObject('IdentityMapping', template='Vec3d,ExtVec3f') |
|
55 |
|
|
56 |
## indentor |
|
57 |
indentor = node.createChild('indentor') |
|
58 |
indentor.createObject('MechanicalObject',name='indentor', position="0.5 0.5 2") |
|
59 |
indentor.createObject('UniformMass') |
|
60 |
indentor.createObject('ConstantForceField', points=0, force="0 0 -1") |
|
61 |
indentor.createObject('TSphereModel', radius= indentorRadius, ContactStiffness=1000, group=1) |
|
62 |
indentor.createObject('ProjectToLineConstraint',endTime='-1', indices=0, origin="0.5 0.5 2", direction="0 0 1") |
|
63 |
indentor.createObject('PointConstraint', endTime=3, indices=0) |
MyDefaultContactManager.cpp (revision 1) | ||
---|---|---|
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 |
AFM/CMakeLists.txt (revision 1) | ||
---|---|---|
1 |
#cmake_minimum_required(VERSION 2.8) |
|
2 |
|
|
3 |
include(${SOFA_CMAKE_DIR}/preProject.cmake) |
|
4 |
|
|
5 |
set(HEADER_FILES |
|
6 |
|
|
7 |
) |
|
8 |
|
|
9 |
set(SOURCE_FILES |
|
10 |
|
|
11 |
AFM.cpp) |
|
12 |
|
|
13 |
if(APPLE) |
|
14 |
|
|
15 |
set(RC_FILE "runSOFA.icns") |
|
16 |
|
|
17 |
else() |
|
18 |
|
|
19 |
set(RC_FILE "sofa.rc") |
|
20 |
|
|
21 |
endif() |
|
22 |
|
|
23 |
add_executable(${PROJECT_NAME} ${HEADER_FILES} ${SOURCE_FILES} ${RC_FILES}) |
|
24 |
|
|
25 |
AddLinkerDependencies(SofaGuiMain SofaComponentMain SofaPython Flexible AFM_plane) |
|
26 |
|
|
27 |
ADD_DEFINITIONS(-DNDEBUG ) |
|
28 |
ADD_DEFINITIONS(-DBOOST_UBLAS_NDEBUG -O3) |
|
29 |
|
|
30 |
|
|
31 |
|
|
32 |
if(SOFA-LIB_SIMULATION_GRAPH_DAG) |
|
33 |
AddLinkerDependencies(SofaSimulationGraph) |
|
34 |
endif() |
|
35 |
|
|
36 |
if(UNIX) |
|
37 |
|
|
38 |
AddLinkerDependencies("dl") |
|
39 |
|
|
40 |
endif() |
|
41 |
TARGET_LINK_LIBRARIES( ${PROJECT_NAME} ${LINK_LIBRARIES} ) |
|
42 |
include(${SOFA_CMAKE_DIR}/postProject.cmake) |
|
43 |
|
AFM/AFM-results.txt (revision 1) | ||
---|---|---|
1 |
### E = 1000 ; P = 10 ; R = 0.4 = small ; mesh subsubsubdivided; first the force then the depth ### |
|
2 |
|
AFM/AFM.cpp (revision 1) | ||
---|---|---|
1 |
#include <sofa/simulation/graph/DAGSimulation.h> |
|
2 |
#include <plugins/SofaPython/SceneLoaderPY.h> |
|
3 |
#include <sofa/helper/system/PluginManager.h> |
|
4 |
#include <sofa/defaulttype/Mat.h> |
|
5 |
#include <SofaBaseLinearSolver/FullVector.h> |
|
6 |
#include <sofa/simulation/common/MechanicalVisitor.h> |
|
7 |
#include <SofaComponentMain/init.h> |
|
8 |
#include <../MyDefaultContactManager.h> |
|
9 |
#include <sofa/core/objectmodel/BaseObject.h> |
|
10 |
#include <SofaBoundaryCondition/ConstantForceField.h> |
|
11 |
#include <sofa/simulation/common/FindByTypeVisitor.h> |
|
12 |
#include <SofaBaseMechanics/MechanicalObject.h> |
|
13 |
#include <sofa/helper/accessor.h> |
|
14 |
#include <sofa/defaulttype/DataTypeInfo.h> |
|
15 |
#include <SofaBoundaryCondition/ProjectToLineConstraint.h> |
|
16 |
#include <cmath> |
|
17 |
#include <cstdlib> |
|
18 |
#include <fstream> |
|
19 |
#include <vector> |
|
20 |
|
|
21 |
using namespace sofa; |
|
22 |
using namespace simulation; |
|
23 |
|
|
24 |
typedef sofa::component::linearsolver::FullVector<double> FullVector; |
|
25 |
typedef defaulttype::Vec3dTypes::Deriv Deriv; |
|
26 |
typedef defaulttype::Vec3d myVec3d; |
|
27 |
|
|
28 |
/// return the maximum difference between corresponding entries, or the infinity if the vectors have different sizes |
|
29 |
template< typename Vector1, typename Vector2> |
|
30 |
static double vectorCompare( const Vector1& m1, const Vector2& m2 ) |
|
31 |
{ |
|
32 |
if( m1.size()!=m2.size() ) { |
|
33 |
printf("Comparison between vectors of different sizes\n"); |
|
34 |
std::fflush(stdout); |
|
35 |
return std::numeric_limits<double>::infinity(); |
|
36 |
} |
|
37 |
double result = 0; |
|
38 |
for( unsigned i=0; i<m1.size(); i++ ){ |
|
39 |
double diff = fabs(m1.element(i)-m2.element(i)); |
|
40 |
if( diff>result ) result=diff; |
|
41 |
} |
|
42 |
return result; |
|
43 |
} |
|
44 |
|
|
45 |
/** fill the vector with the positions. |
|
46 |
@param x the position vector |
|
47 |
*/ |
|
48 |
void getAssembledPositionVector( FullVector* x, unsigned xSize, |
|
49 |
std::vector<component::container::MechanicalObject<defaulttype::Vec3dTypes> *> DOFs ) |
|
50 |
{ |
|
51 |
x->resize(xSize); |
|
52 |
unsigned offset = 0; |
|
53 |
|
|
54 |
for (unsigned i = 0; i < DOFs.size(); i++){ |
|
55 |
helper::ReadAccessor< Data<defaulttype::Vec3dTypes::VecCoord> > vSrc = DOFs[i]->readPositions(); |
|
56 |
|
|
57 |
for (unsigned j=0; j < vSrc.size(); j++){ |
|
58 |
double tmp = 0.0; |
|
59 |
tmp = vSrc[j][0]; |
|
60 |
// defaulttype::Vec3dTypes::Coord getValue(vSrc[j], 0, tmp); |
|
61 |
x->set(offset + 3*j,tmp); |
|
62 |
// DataTypeInfo<defaulttype::Vec3dTypes::Coord>::getValue(vSrc[j], 1, tmp); |
|
63 |
tmp = vSrc[j][1]; |
|
64 |
x->set(offset + 3*j+1,tmp); |
|
65 |
//DataTypeInfo<defaulttype::Vec3dTypes::Coord>::getValue(vSrc[j], 2, tmp); |
|
66 |
tmp = vSrc[j][2]; |
|
67 |
x->set(offset + 3*j+2,tmp); |
|
68 |
} |
|
69 |
offset += DOFs[i]->getSize() * 3; |
|
70 |
} |
|
71 |
} |
|
72 |
|
|
73 |
/** fill the vector with the velocities. |
|
74 |
@param v the velocity vector |
|
75 |
*/ |
|
76 |
void getAssembledVelocityVector( FullVector* v, unsigned vSize, |
|
77 |
std::vector<component::container::MechanicalObject<defaulttype::Vec3dTypes> *> DOFs ) |
|
78 |
{ |
|
79 |
v->resize(vSize); |
|
80 |
unsigned offset = 0; |
|
81 |
|
|
82 |
for (unsigned i = 0; i < DOFs.size(); i++){ |
|
83 |
helper::ReadAccessor< Data<defaulttype::Vec3dTypes::VecDeriv> > vSrc = DOFs[i]->readVelocities(); |
|
84 |
for (unsigned j=0; j < vSrc.size(); j++){ |
|
85 |
double tmp = 0.0; |
|
86 |
//DataTypeInfo<defaulttype::Vec3dTypes::Deriv>::getValue(vSrc[j], 0, tmp); |
|
87 |
tmp = vSrc[j][0]; |
|
88 |
v->set(offset + 3*j,tmp); |
|
89 |
//DataTypeInfo<defaulttype::Vec3dTypes::Deriv>::getValue(vSrc[j], 1, tmp); |
|
90 |
tmp = vSrc[j][1]; |
|
91 |
v->set(offset + 3*j+1,tmp); |
|
92 |
//DataTypeInfo<defaulttype::Vec3dTypes::Deriv>::getValue(vSrc[j], 2, tmp); |
|
93 |
tmp = vSrc[j][2]; |
|
94 |
v->set(offset + 3*j+2,tmp); |
|
95 |
} |
|
96 |
offset += DOFs[i]->getSize() * 3; |
|
97 |
} |
|
98 |
|
|
99 |
} |
|
100 |
|
|
101 |
|
|
102 |
int main() |
|
103 |
{ |
|
104 |
//the file in which the resulting curve will be put |
|
105 |
std::ofstream fileResult("./AFM-results.txt"); |
|
106 |
fileResult << "### first the force then the depth ###\n\n" ; |
|
107 |
|
|
108 |
//load the required plugins |
|
109 |
std::string pluginPath = "Flexible"; |
|
110 |
std::string pluginPath1 = "AFM_plane"; |
|
111 |
|
|
112 |
sofa::helper::system::PluginRepository.addLastPath("../../../../build_release/lib/"); |
|
113 |
if (sofa::helper::system::PluginManager::getInstance().loadPlugin(pluginPath) && |
|
114 |
sofa::helper::system::PluginManager::getInstance().loadPlugin(pluginPath1)) |
|
115 |
sofa::helper::system::PluginManager::getInstance().init(); |
|
116 |
|
|
117 |
|
|
118 |
|
|
119 |
unsigned xsize; ///< size of assembled position vector, |
|
120 |
unsigned vsize; ///< size of assembled velocity vector, |
|
121 |
|
|
122 |
|
|
123 |
// loading the scene which is in the file examples/AFM-plane.py |
|
124 |
setSimulation(new simulation::graph::DAGSimulation()); |
|
125 |
sofa::component::init(); |
|
126 |
Node::SPtr root = getSimulation()->createNewGraph("root"); |
|
127 |
|
|
128 |
SceneLoaderPY LoaderPy; |
|
129 |
root = LoaderPy.load("./AFM-plane.py"); |
|
130 |
getSimulation()->init(root.get()); |
|
131 |
|
|
132 |
//we take the direction of the force |
|
133 |
sofa::component::forcefield::ConstantForceField<defaulttype::Vec3dTypes>::SPtr CFF; |
|
134 |
root->getContext()->get(CFF, sofa::core::objectmodel::BaseContext::SearchRoot); |
|
135 |
|
|
136 |
Deriv forceInit = CFF->force.getValue(); |
|
137 |
|
|
138 |
Deriv forceActu; |
|
139 |
forceActu[0] = 0; |
|
140 |
forceActu[1] = 0; |
|
141 |
forceActu[2] = 0; |
|
142 |
CFF->force = forceActu; |
|
143 |
|
|
144 |
|
|
145 |
// first find the size of the DOFs |
|
146 |
core::ExecParams* params = core::ExecParams::defaultInstance(); |
|
147 |
FindByTypeVisitor<component::container::MechanicalObject<defaulttype::Vec3dTypes> > FBTVisitor(params); |
|
148 |
root->execute(FBTVisitor); |
|
149 |
|
|
150 |
std::vector<component::container::MechanicalObject<defaulttype::Vec3dTypes> *> allPoints; |
|
151 |
allPoints = FBTVisitor.found; |
|
152 |
|
|
153 |
std::vector<component::container::MechanicalObject<defaulttype::Vec3dTypes> *> DOFs, mObject; |
|
154 |
for (unsigned i=0; i<allPoints.size();i++) |
|
155 |
if (allPoints[i]->getName() == "DOFs" || allPoints[i]->getName() == "indentor" ) |
|
156 |
DOFs.push_back(allPoints[i]); |
|
157 |
|
|
158 |
for (unsigned i=0; i<allPoints.size();i++) |
|
159 |
if (allPoints[i]->getName() == "DOFs") |
|
160 |
mObject.push_back(allPoints[i]); |
|
161 |
|
|
162 |
unsigned xInitSize = mObject[0]->getSize(); |
|
163 |
|
|
164 |
xsize = DOFs[0]->getSize() * DOFs[0]->getCoordDimension() + DOFs[1]->getSize() * DOFs[1]->getCoordDimension(); |
|
165 |
vsize = DOFs[0]->getMatrixSize() + DOFs[1]->getMatrixSize(); |
|
166 |
|
|
167 |
FullVector x0, x1, v0, v1, xinit, xend; |
|
168 |
getAssembledPositionVector(&x0, xsize, DOFs); // cerr<<"My_test, initial positions : " << x0 << endl; |
|
169 |
getAssembledVelocityVector(&v0, vsize, DOFs); // cerr<<"My_test, initial velocities: " << v0 << endl; |
|
170 |
|
|
171 |
double dx, dv; |
|
172 |
unsigned n=0; |
|
173 |
const double precision = 1.e-4; |
|
174 |
unsigned const nmax = 1000; |
|
175 |
// first loop to stabilize the plane growth under pressure |
|
176 |
|
|
177 |
do { |
|
178 |
getSimulation()->animate(root.get(),0.01); |
|
179 |
|
|
180 |
getAssembledPositionVector(&x1, xsize, DOFs); // cerr<<"My_test, new positions : " << x1 << endl; |
|
181 |
getAssembledVelocityVector(&v1, vsize, DOFs); // cerr<<"My_test, new velocities: " << v1 << endl; |
|
182 |
|
|
183 |
dx = vectorCompare(x0,x1); |
|
184 |
dv = vectorCompare(v0,v1); |
|
185 |
x0 = x1; |
|
186 |
v0 = v1; |
|
187 |
n++; |
|
188 |
|
|
189 |
} while((dx>precision || dv>precision) && n < nmax); // |
|
190 |
|
|
191 |
printf("\n %i iterations to stabilize the plane \n",n); |
|
192 |
std::fflush(stdout); |
|
193 |
|
|
194 |
getAssembledPositionVector(&xinit, xInitSize*3, mObject); |
|
195 |
|
|
196 |
//second loop : to detect a collision |
|
197 |
|
|
198 |
//we place the indentor first and calculate the force |
|
199 |
forceInit[0] = 0; |
|
200 |
forceInit[1] = 0; |
|
201 |
forceInit[2] = -0.1; |
|
202 |
|
|
203 |
|
|
204 |
|
|
205 |
//we put the position of indentor |
|
206 |
component::container::MechanicalObject<defaulttype::Vec3dTypes> *indentor = NULL ; |
|
207 |
if (DOFs[0]->getName()=="DOFs") |
|
208 |
indentor = DOFs[1]; |
|
209 |
else indentor = DOFs[0]; |
|
210 |
|
|
211 |
helper::vector<double> centerPos; |
|
212 |
|
|
213 |
centerPos.push_back(0.5); |
|
214 |
centerPos.push_back(0.5); |
|
215 |
centerPos.push_back(2); |
|
216 |
|
|
217 |
indentor->forcePointPosition(0,centerPos); |
|
218 |
|
|
219 |
myVec3d indentPos; |
|
220 |
myVec3d indentForce; |
|
221 |
indentPos.set(0.5 ,0.5, 2); |
|
222 |
indentForce.set(0,0,1); |
|
223 |
|
|
224 |
component::projectiveconstraintset::ProjectToLineConstraint<defaulttype::Vec3dTypes>::SPtr constraint; |
|
225 |
root->getContext()->get(constraint, sofa::core::objectmodel::BaseContext::SearchRoot); |
|
226 |
constraint->f_origin.setValue(indentPos); |
|
227 |
constraint->f_direction.setValue(indentForce); |
|
228 |
|
|
229 |
forceActu[2] = -0.1; |
|
230 |
|
|
231 |
CFF->force = forceActu; |
|
232 |
|
|
233 |
component::collision::MyDefaultContactManager::SPtr MDCM; |
|
234 |
root->getContext()->get(MDCM, sofa::core::objectmodel::BaseContext::SearchRoot); |
|
235 |
while (!MDCM->CollisionDetected()) |
|
236 |
{ |
|
237 |
getSimulation()->animate(root.get(),0.01); |
|
238 |
root->getContext()->get(MDCM, sofa::core::objectmodel::BaseContext::SearchRoot); |
|
239 |
} |
|
240 |
|
|
241 |
|
|
242 |
//third loop : until the end we increment the force |
|
243 |
n = 0; |
|
244 |
unsigned compteur = 0; |
|
245 |
|
|
246 |
getAssembledPositionVector(&x0, xsize, DOFs); // cerr<<"My_test, initial positions : " << x0 << endl; |
|
247 |
getAssembledVelocityVector(&v0, vsize, DOFs); // cerr<<"My_test, initial velocities: " << v0 << endl; |
|
248 |
|
|
249 |
|
|
250 |
while (forceActu.norm() < 150 && MDCM->getDepth() < 0.15 ){ |
|
251 |
n = 0; |
|
252 |
fileResult << forceActu.norm() <<" " ; |
|
253 |
printf("new force %f : ",forceActu.norm()); |
|
254 |
std::fflush(stdout); |
|
255 |
|
|
256 |
do { |
|
257 |
getSimulation()->animate(root.get(),0.01); |
|
258 |
|
|
259 |
getAssembledPositionVector(&x1, xsize, DOFs); // cerr<<"My_test, new positions : " << x1 << endl; |
|
260 |
getAssembledVelocityVector(&v1, vsize, DOFs); // cerr<<"My_test, new velocities: " << v1 << endl; |
|
261 |
|
|
262 |
dx = vectorCompare(x0,x1); |
|
263 |
dv = vectorCompare(v0,v1); |
|
264 |
x0 = x1; |
|
265 |
v0 = v1; |
|
266 |
n++; |
|
267 |
|
|
268 |
} while((dx>precision || dv>precision) && n < nmax); // |
|
269 |
|
|
270 |
printf("%i iterations, depth: %f \n",n,MDCM->getDepth()); |
|
271 |
std::fflush(stdout); |
|
272 |
|
|
273 |
compteur++; |
|
274 |
fileResult << MDCM->getDepth() << std::endl; |
|
275 |
forceActu += forceInit; |
|
276 |
CFF->force = forceActu; |
|
277 |
} |
|
278 |
|
|
279 |
|
|
280 |
|
|
281 |
//forth loop to decrement the force |
|
282 |
|
|
283 |
/*while (forceActu.norm() > 0.1){ |
|
284 |
n = 0; |
|
285 |
fileResult << forceActu.norm() <<" " ; |
|
286 |
printf("new force %f : ",forceActu.norm()); |
|
287 |
std::fflush(stdout); |
|
288 |
|
|
289 |
do { |
|
290 |
getSimulation()->animate(root.get(),0.01); |
|
291 |
|
|
292 |
getAssembledPositionVector(&x1, xsize, DOFs); // cerr<<"My_test, new positions : " << x1 << endl; |
|
293 |
getAssembledVelocityVector(&v1, vsize, DOFs); // cerr<<"My_test, new velocities: " << v1 << endl; |
|
294 |
|
|
295 |
dx = vectorCompare(x0,x1); |
|
296 |
dv = vectorCompare(v0,v1); |
|
297 |
x0 = x1; |
|
298 |
v0 = v1; |
|
299 |
n++; |
|
300 |
|
|
301 |
} while((dx>precision || dv>precision) && n < nmax); // |
|
302 |
|
|
303 |
printf("%i iterations, depth : %f \n",n,MDCM->getDepth() ); |
|
304 |
std::fflush(stdout); |
|
305 |
|
|
306 |
compteur++; |
|
307 |
fileResult << MDCM->getDepth() << std::endl; |
|
308 |
forceActu -= forceInit; |
|
309 |
CFF->force = forceActu; |
|
310 |
} |
|
311 |
*/ |
|
312 |
|
|
313 |
return 0; |
|
314 |
} |
|
315 |
|
Formats disponibles : Unified diff