-
Notifications
You must be signed in to change notification settings - Fork 331
/
Copy pathpython_common.i
322 lines (281 loc) · 10.1 KB
/
python_common.i
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
%module(directors="1") common
#pragma SWIG nowarn=822,451,503,516,325
// 401 is "Nothing known about base class *some-class*.
// Maybe you forgot to instantiate *some-template* using %template."
// When wrapping new classes it's good to uncomment the line below to make sure
// you've wrapped your new class properly. However, SWIG generates lots of 401
// errors that are very difficult to resolve.
#pragma SWIG nowarn=401
%{
#define SWIG_FILE_WITH_INIT
#include <Bindings/OpenSimHeaders_common.h>
%}
%{
using namespace OpenSim;
using namespace SimTK;
%}
%include "python_preliminaries.i"
// Tell SWIG about the simbody module.
%import "python_simbody.i"
// Relay exceptions to the target language.
// This causes substantial code bloat and possibly hurts performance.
// Without these try-catch block, a SimTK or OpenSim exception causes the
// program to crash.
// We use SWIG_exception_fail instead of SWIG_exception due to some fluke where
// SWIG_exception isn't defined for this module (because we're importing
// another module?).
%include "exception.i"
// Delete any previous exception handlers.
%exception;
%exception {
try {
$action
} catch (const std::exception& e) {
std::string str("std::exception in '$fulldecl': ");
std::string what(e.what());
SWIG_exception_fail(SWIG_RuntimeError, (str + what).c_str());
}
}
// The following exception handling is preferred but causes too much bloat.
//%exception {
// try {
// $action
// } catch (const SimTK::Exception::IndexOutOfRange& e) {
// SWIG_exception(SWIG_IndexError, e.what());
// } catch (const SimTK::Exception::Base& e) {
// std::string str("SimTK Simbody error in '$fulldecl': ");
// std::string what(e.what());
// SWIG_exception(SWIG_RuntimeError, (str + what).c_str());
// } catch (const OpenSim::Exception& e) {
// std::string str("OpenSim error in '$fulldecl': ");
// std::string what(e.what());
// SWIG_exception(SWIG_RuntimeError, (str + what).c_str());
// } catch (const std::exception& e) {
// std::string str("std::exception in '$fulldecl': ");
// std::string what(e.what());
// SWIG_exception(SWIG_RuntimeError, (str + what).c_str());
// } catch (...) {
// SWIG_exception(SWIG_RuntimeError, "Unknown exception in '$fulldecl'.");
// }
//}
%rename(printToXML) OpenSim::Object::print(const std::string&) const;
%rename(printToXML) OpenSim::XMLDocument::print(const std::string&);
%rename(printToXML) OpenSim::XMLDocument::print();
%rename(printToFile) OpenSim::Storage::print;
// Memory management
// =================
/*
This facility will help us avoid segfaults that occur when two different
objects believe they own a pointer, and so they both try to delete it. We can
instead notify the object that something else has adopted it, and will take
care of deleting it.
*/
%extend OpenSim::Object {
%pythoncode %{
def _markAdopted(self):
if self.this and self.thisown:
self.thisown = False
%}
};
/*
The added component is not responsible for its own memory management anymore
once added to another Component. This snippet is based on the
MODEL_ADOPT_HELPER macro in python_simulation.i.
note: ## is a "glue" operator: `a ## b` --> `ab`.
*/
%pythonappend OpenSim::Component::addComponent %{
subcomponent._markAdopted()
%}
%extend OpenSim::Array<double> {
void appendVec3(SimTK::Vec3 vec3) {
for(int i=0; i<3; i++)
self->append(vec3[i]);
}
void appendVector(SimTK::Vector vec) {
for(int i=0; i<vec.size(); i++)
self->append(vec[i]);
}
SimTK::Vec3 getAsVec3() {
return SimTK::Vec3::getAs(self->get());
};
static SimTK::Vec3 createVec3(double e1, double e2, double e3) {
Array<double>* arr = new Array<double>(e1, 3);
arr->set(1, e2);
arr->set(2, e3);
return SimTK::Vec3::getAs(arr->get());
};
static SimTK::Vec3 createVec3(double e1) {
Array<double>* arr = new Array<double>(e1, 3);
return SimTK::Vec3::getAs(arr->get());
};
static SimTK::Vec3 createVec3(double es[3]) {
Array<double>* arr = new Array<double>(es[0], 3);
arr->set(1, es[1]);
arr->set(2, es[2]);
return SimTK::Vec3::getAs(arr->get());
};
SimTK::Vector_<double> getAsVector() {
return SimTK::Vector(self->getSize(), &(*self)[0]);
};
void populateFromVector(SimTK::Vector_<double> aVector) {
int sz = aVector.size();
for(int i=0; i<sz; ++i)
self->append(aVector[i]);
}
static OpenSim::Array<double> getValuesFromVec3(SimTK::Vec3 vec3) {
OpenSim::Array<double> arr(0, 3);
for (int i=0; i<3; i++) arr[i] = vec3[i];
return arr;
};
std::string toString() const {
std::stringstream stream;
for (int i=0; i< self->getSize(); i++)
stream << self->get(i) << " ";
return stream.str();
}
void setFromPyArray(double* dValues, int size) {
self->setSize(size);
for(int i=0; i< size; ++i)
self->set(i, dValues[i]);
};
};
// Load OpenSim plugins TODO
// ====================
//%include <OpenSim/Common/LoadOpenSimLibrary.h>
// %include "numpy.i"
// Pythonic operators
// ==================
// Extend the template Vec class; these methods will apply for all template
// parameters. This extend block must appear before the %template call in
// common.i.
%extend OpenSim::Set {
%pythoncode %{
class SetIterator(object):
"""
Use this object to iterate over a Set. You create an instance of
this nested class by calling Set.__iter__().
"""
def __init__(self, set_obj, index):
"""Construct an iterator for the Set `set`."""
self._set_obj = set_obj
self._index = index
def __iter__(self):
"""This iterator is also iterable."""
return self
def next(self):
if self._index < self._set_obj.getSize():
current_index = self._index
self._index += 1
return self._set_obj.get(current_index)
else:
# This is how Python knows to stop iterating.
raise StopIteration()
def __iter__(self):
"""Get an iterator for this Set, starting at index 0."""
return self.SetIterator(self, 0)
def items(self):
"""
A generator function that allows you to iterate over the key-value
pairs of this Set. You can use this in a for-loop as such::
for key, val in my_function_set.items():
# `val` is an item in the Set, and `key` is its name.
print key, val
"""
index = 0
while index < self.getSize():
yield self.get(index).getName(), self.get(index)
index += 1
%}
};
// This function tries to downcast the component; if that does not succeed,
// then it just returns a Component (or whatever the type for this specific
// ComponentList is).
%extend OpenSim::ComponentList {
%pythoncode %{
def __iter__(self):
"""Get an iterator for this ComponentList, to be used as such::
for c in model.getComponentsList():
c.getName()
"""
import sys
opensim_pkg = sys.modules[__name__.partition('.')[0]]
it = self.begin()
while it != self.end():
component = it.__deref__()
try:
ConcreteClass = getattr(opensim_pkg, component.getConcreteClassName())
concrete_component = ConcreteClass.safeDownCast(component)
yield concrete_component
except:
yield component
it.next()
%}
};
// Return concrete instances from certain methods.
// -----------------------------------------------
// http://stackoverflow.com/questions/27392602/swig-downcasting-from-base-to-derived
// "$1" holds the original return value from getConnectee() (an Object*).
// An Object with name Foo is registered with SWIG as "OpenSim::Foo *".
// If the type query fails, we just return an Object*
%typemap(out) const OpenSim::Object& OpenSim::Component::getConnectee {
swig_type_info * const outtype = SWIG_TypeQuery(
("OpenSim::" + ($1)->getConcreteClassName() + " *").c_str());
if (outtype) {
$result = SWIG_NewPointerObj(SWIG_as_voidptr($1), outtype, $owner);
} else {
swig_type_info * const outtype = SWIG_TypeQuery("OpenSim::Object *");
$result = SWIG_NewPointerObj(SWIG_as_voidptr($1), outtype, $owner);
}
}
%typemap(out) const OpenSim::Component& OpenSim::Component::getComponent {
swig_type_info * const outtype = SWIG_TypeQuery(
("OpenSim::" + ($1)->getConcreteClassName() + " *").c_str());
if (outtype) {
$result = SWIG_NewPointerObj(SWIG_as_voidptr($1), outtype, $owner);
} else {
swig_type_info * const outtype = SWIG_TypeQuery("OpenSim::Component *");
$result = SWIG_NewPointerObj(SWIG_as_voidptr($1), outtype, $owner);
}
}
%typemap(out) OpenSim::Component& OpenSim::Component::updComponent {
swig_type_info * const outtype = SWIG_TypeQuery(
("OpenSim::" + ($1)->getConcreteClassName() + " *").c_str());
if (outtype) {
$result = SWIG_NewPointerObj(SWIG_as_voidptr($1), outtype, $owner);
} else {
swig_type_info * const outtype = SWIG_TypeQuery("OpenSim::Component *");
$result = SWIG_NewPointerObj(SWIG_as_voidptr($1), outtype, $owner);
}
}
%extend OpenSim::DataTable_ {
std::string __str__() const {
return $self->toString();
}
}
%extend OpenSim::Path {
std::string __str__() const {
return $self->toString();
}
}
// ChannelPath does not inherit from Path.
%extend OpenSim::ChannelPath {
std::string __str__() const {
return $self->toString();
}
}
// Include all the OpenSim code.
// =============================
%include <Bindings/preliminaries.i>
%include <Bindings/common.i>
// Memory management
// =================
SET_ADOPT_HELPER(Scale);
// This didn't work with the macro for some reason. I got complaints about
// multiple definitions of, e.g., Function in the target language.
%extend OpenSim::FunctionSet {
%pythoncode %{
def adoptAndAppend(self, aFunction):
aFunction._markAdopted()
return super(FunctionSet, self).adoptAndAppend(aFunction)
%}
};