1 %module libsumo
2 #pragma SWIG nowarn=511
3 
4 #ifdef SWIGPYTHON
5 %rename(edge) Edge;
6 %rename(inductionloop) InductionLoop;
7 %rename(junction) Junction;
8 %rename(lane) Lane;
9 %rename(lanearea) LaneArea;
10 %rename(multientryexit) MultiEntryExit;
11 %rename(person) Person;
12 %rename(poi) POI;
13 %rename(polygon) Polygon;
14 %rename(route) Route;
15 %rename(simulation) Simulation;
16 %rename(trafficlight) TrafficLight;
17 %rename(vehicle) Vehicle;
18 %rename(vehicletype) VehicleType;
19 
20 // adding dummy init and close for easier traci -> libsumo transfer
21 %pythoncode %{
22 from traci import constants, exceptions, _vehicle, _person, _trafficlight
23 
24 def isLibsumo():
25     return True
26 
27 def init(port):
28     print("Warning! To make your code usable with traci and libsumo, please use traci.start instead of traci.init.")
29 
30 def close():
31     simulation.close()
32 
33 def start(args):
34     simulation.load(args[1:])
35 
36 def simulationStep(step=0):
37     simulation.step(step)
38 %}
39 
40 /* There is currently no TraCIPosition used as input so this is only for future usage
41 %typemap(in) const libsumo::TraCIPosition& (libsumo::TraCIPosition pos) {
42     const Py_ssize_t size = PySequence_Size($input);
43     if (size == 2 || size == 3) {
44         pos.x = PyFloat_AsDouble(PySequence_GetItem($input, 0));
45         pos.y = PyFloat_AsDouble(PySequence_GetItem($input, 1));
46         pos.z = (size == 3 ? PyFloat_AsDouble(PySequence_GetItem($input, 2)) : 0.);
47     } else {
48     // TODO error handling
49     }
50     $1 = &pos;
51 }
52 */
53 
54 %typemap(in) const libsumo::TraCIPositionVector& (libsumo::TraCIPositionVector shape) {
55     const Py_ssize_t size = PySequence_Size($input);
56     for (Py_ssize_t i = 0; i < size; i++) {
57         PyObject* posTuple = PySequence_GetItem($input, i);
58         const Py_ssize_t posSize = PySequence_Size(posTuple);
59         libsumo::TraCIPosition pos;
60         if (posSize == 2 || posSize == 3) {
61             PyObject* item = PySequence_GetItem(posTuple, 0);
62             pos.x = PyFloat_Check(item) ? PyFloat_AsDouble(item) : PyLong_AsDouble(item);
63             item = PySequence_GetItem(posTuple, 1);
64             pos.y = PyFloat_Check(item) ? PyFloat_AsDouble(item) : PyLong_AsDouble(item);
65             pos.z = 0.;
66             if (posSize == 3) {
67                 item = PySequence_GetItem(posTuple, 2);
68                 pos.z = PyFloat_Check(item) ? PyFloat_AsDouble(item) : PyLong_AsDouble(item);
69             }
70         } else {
71         // TODO error handling
72         }
73         shape.push_back(pos);
74     }
75     $1 = &shape;
76 }
77 
78 %typemap(in) const libsumo::TraCIColor& (libsumo::TraCIColor col) {
79     const Py_ssize_t size = PySequence_Size($input);
80     if (size == 3 || size == 4) {
81         col.r = (unsigned char)PyLong_AsLong(PySequence_GetItem($input, 0));
82         col.g = (unsigned char)PyLong_AsLong(PySequence_GetItem($input, 1));
83         col.b = (unsigned char)PyLong_AsLong(PySequence_GetItem($input, 2));
84         col.a = (unsigned char)(size == 4 ? PyLong_AsLong(PySequence_GetItem($input, 3)) : 255);
85     } else {
86     // TODO error handling
87     }
88     $1 = &col;
89 }
90 
91 %typemap(in) const std::vector<int>& (std::vector<int> vars) {
92     const Py_ssize_t size = PySequence_Size($input);
93     for (Py_ssize_t i = 0; i < size; i++) {
94         vars.push_back(PyLong_AsLong(PySequence_GetItem($input, i)));
95     }
96     $1 = &vars;
97 }
98 
99 %typemap(typecheck, precedence=SWIG_TYPECHECK_INTEGER) const std::vector<int>& {
100     $1 = PySequence_Check($input) ? 1 : 0;
101 }
102 
103 
104 %typemap(out) std::map<int, std::shared_ptr<libsumo::TraCIResult> > {
105     $result = PyDict_New();
106     for (auto iter = $1.begin(); iter != $1.end(); ++iter) {
107         const int theKey = iter->first;
108         const libsumo::TraCIResult* const theVal = iter->second.get();
109         const libsumo::TraCIDouble* const theDouble = dynamic_cast<const libsumo::TraCIDouble*>(theVal);
110         if (theDouble != nullptr) {
111             PyDict_SetItem($result, PyInt_FromLong(theKey), PyFloat_FromDouble(theDouble->value));
112             continue;
113         }
114         const libsumo::TraCIInt* const theInt = dynamic_cast<const libsumo::TraCIInt*>(theVal);
115         if (theInt != nullptr) {
116             PyDict_SetItem($result, PyInt_FromLong(theKey), PyInt_FromLong(theInt->value));
117             continue;
118         }
119         const libsumo::TraCIString* const theString = dynamic_cast<const libsumo::TraCIString*>(theVal);
120         if (theString != nullptr) {
121             PyDict_SetItem($result, PyInt_FromLong(theKey), PyUnicode_FromString(theString->value.c_str()));
122             continue;
123         }
124         const libsumo::TraCIStringList* const theStringList = dynamic_cast<const libsumo::TraCIStringList*>(theVal);
125         if (theStringList != nullptr) {
126             const Py_ssize_t size = theStringList->value.size();
127             PyObject* tuple = PyTuple_New(size);
128             for (Py_ssize_t i = 0; i < size; i++) {
129                 PyTuple_SetItem(tuple, i, PyUnicode_FromString(theStringList->value[i].c_str()));
130             }
131             PyDict_SetItem($result, PyInt_FromLong(theKey), tuple);
132             continue;
133         }
134         const libsumo::TraCIPosition* const thePosition = dynamic_cast<const libsumo::TraCIPosition*>(theVal);
135         if (thePosition != nullptr) {
136             PyObject* tuple;
137             if (thePosition->z != libsumo::INVALID_DOUBLE_VALUE) {
138                 tuple = PyTuple_Pack(3, PyFloat_FromDouble(thePosition->x), PyFloat_FromDouble(thePosition->y), PyFloat_FromDouble(thePosition->z));
139             } else {
140                 tuple = PyTuple_Pack(2, PyFloat_FromDouble(thePosition->x), PyFloat_FromDouble(thePosition->y));
141             }
142             PyDict_SetItem($result, PyInt_FromLong(theKey), tuple);
143             continue;
144         }
145         const libsumo::TraCIRoadPosition* const theRoadPosition = dynamic_cast<const libsumo::TraCIRoadPosition*>(theVal);
146         if (theRoadPosition != nullptr) {
147             PyObject* tuple;
148             if (theRoadPosition->laneIndex != libsumo::INVALID_INT_VALUE) {
149                 tuple = PyTuple_Pack(3, PyUnicode_FromString(theRoadPosition->edgeID.c_str()), PyFloat_FromDouble(theRoadPosition->pos), PyInt_FromLong(theRoadPosition->laneIndex));
150             } else {
151                 tuple = PyTuple_Pack(2, PyUnicode_FromString(theRoadPosition->edgeID.c_str()), PyFloat_FromDouble(theRoadPosition->pos));
152             }
153             PyDict_SetItem($result, PyInt_FromLong(theKey), tuple);
154             continue;
155         }
156         PyObject *value = SWIG_NewPointerObj(SWIG_as_voidptr(theVal), SWIGTYPE_p_libsumo__TraCIResult, 0);
157         PyDict_SetItem($result, PyInt_FromLong(theKey), value);
158     }
159 };
160 
161 %typemap(out) libsumo::TraCIPosition {
162     if ($1.z != libsumo::INVALID_DOUBLE_VALUE) {
163         $result = PyTuple_Pack(3, PyFloat_FromDouble($1.x), PyFloat_FromDouble($1.y), PyFloat_FromDouble($1.z));
164     } else {
165         $result = PyTuple_Pack(2, PyFloat_FromDouble($1.x), PyFloat_FromDouble($1.y));
166     }
167 };
168 
169 %typemap(out) libsumo::TraCIPositionVector {
170     $result = PyTuple_New($1.size());
171     int index = 0;
172     for (auto iter = $1.begin(); iter != $1.end(); ++iter) {
173         PyTuple_SetItem($result, index++, PyTuple_Pack(2, PyFloat_FromDouble(iter->x), PyFloat_FromDouble(iter->y)));
174     }
175 };
176 
177 %typemap(out) libsumo::TraCIColor {
178     $result = PyTuple_Pack(4, PyLong_FromLong($1.r), PyLong_FromLong($1.g), PyLong_FromLong($1.b), PyLong_FromLong($1.a));
179 };
180 
181 %typemap(out) libsumo::TraCIRoadPosition {
182     $result = PyTuple_Pack(3, PyUnicode_FromString($1.edgeID.c_str()), PyFloat_FromDouble($1.pos), PyLong_FromLong($1.laneIndex));
183 };
184 
185 %typemap(out) std::vector<libsumo::TraCIConnection> {
186     $result = PyList_New($1.size());
187     int index = 0;
188     for (auto iter = $1.begin(); iter != $1.end(); ++iter) {
189         PyList_SetItem($result, index++, PyTuple_Pack(8, PyUnicode_FromString(iter->approachedLane.c_str()),
190                                                          PyBool_FromLong(iter->hasPrio),
191                                                          PyBool_FromLong(iter->isOpen),
192                                                          PyBool_FromLong(iter->hasFoe),
193                                                          PyUnicode_FromString(iter->approachedInternal.c_str()),
194                                                          PyUnicode_FromString(iter->state.c_str()),
195                                                          PyUnicode_FromString(iter->direction.c_str()),
196                                                          PyFloat_FromDouble(iter->length)));
197     }
198 };
199 
200 %typemap(out) std::vector<libsumo::TraCIVehicleData> {
201     $result = PyList_New($1.size());
202     int index = 0;
203     for (auto iter = $1.begin(); iter != $1.end(); ++iter) {
204         PyList_SetItem($result, index++, PyTuple_Pack(5, PyUnicode_FromString(iter->id.c_str()),
205                                                          PyFloat_FromDouble(iter->length),
206                                                          PyFloat_FromDouble(iter->entryTime),
207                                                          PyFloat_FromDouble(iter->leaveTime),
208                                                          PyUnicode_FromString(iter->typeID.c_str())));
209     }
210 };
211 
212 %typemap(out) std::vector<libsumo::TraCIBestLanesData> {
213     $result = PyTuple_New($1.size());
214     int index = 0;
215     for (auto iter = $1.begin(); iter != $1.end(); ++iter) {
216         const int size = (int)iter->continuationLanes.size();
217         auto nextLanes = PyTuple_New(size);
218         for (int i = 0; i < size; i++) {
219             PyTuple_SetItem(nextLanes, i, PyUnicode_FromString(iter->continuationLanes[i].c_str()));
220         }
221         PyTuple_SetItem($result, index++, PyTuple_Pack(6, PyUnicode_FromString(iter->laneID.c_str()),
222                                                           PyFloat_FromDouble(iter->length),
223                                                           PyFloat_FromDouble(iter->occupation),
224                                                           PyFloat_FromDouble(iter->bestLaneOffset),
225                                                           PyBool_FromLong(iter->allowsContinuation),
226                                                           nextLanes));
227     }
228 };
229 
230 %typemap(out) std::vector<libsumo::TraCINextTLSData> {
231     $result = PyTuple_New($1.size());
232     int index = 0;
233     for (auto iter = $1.begin(); iter != $1.end(); ++iter) {
234         PyTuple_SetItem($result, index++, PyTuple_Pack(4, PyUnicode_FromString(iter->id.c_str()),
235                                                           PyLong_FromLong(iter->tlIndex),
236                                                           PyFloat_FromDouble(iter->dist),
237                                                           PyUnicode_FromStringAndSize(&iter->state, 1)));
238     }
239 };
240 
241 %typemap(out) std::vector<libsumo::TraCINextStopData> {
242     $result = PyTuple_New($1.size());
243     int index = 0;
244     for (auto iter = $1.begin(); iter != $1.end(); ++iter) {
245         PyTuple_SetItem($result, index++, PyTuple_Pack(6, PyUnicode_FromString(iter->lane.c_str()),
246                                                           PyFloat_FromDouble(iter->endPos),
247                                                           PyUnicode_FromString(iter->stoppingPlaceID.c_str()),
248                                                           PyLong_FromLong(iter->stopFlags),
249                                                           PyFloat_FromDouble(iter->duration),
250                                                           PyFloat_FromDouble(iter->until)));
251     }
252 };
253 
254 %typemap(out) std::pair<int, int> {
255     $result = PyTuple_Pack(2, PyLong_FromLong($1.first), PyLong_FromLong($1.second));
256 };
257 
258 %typemap(out) std::pair<std::string, double> {
259     $result = PyTuple_Pack(2, PyUnicode_FromString($1.first.c_str()), PyFloat_FromDouble($1.second));
260 };
261 
262 %extend libsumo::TraCIStage {
263   %pythoncode %{
264     def __repr__(self):
265         return "Stage(%s)" % (", ".join(["%s=%s" % (attr, repr(getter(self))) for attr, getter in self.__swig_getmethods__.items()]))
266   %}
267 };
268 
269 %exceptionclass libsumo::TraCIException;
270 
271 #endif
272 
273 %begin %{
274 #ifdef _MSC_VER
275 // ignore constant conditional expression and unreachable code warnings
276 #pragma warning(disable:4127 4702)
277 #endif
278 %}
279 
280 
281 // replacing vector instances of standard types, see https://stackoverflow.com/questions/8469138
282 %include "std_string.i"
283 %include "std_vector.i"
284 %template(StringVector) std::vector<std::string>;
285 
286 // exception handling
287 %include "exception.i"
288 
289 // taken from here https://stackoverflow.com/questions/1394484/how-do-i-propagate-c-exceptions-to-python-in-a-swig-wrapper-library
290 %exception {
291     try {
292         $action
293     } catch (libsumo::TraCIException &e) {
294         const std::string s = std::string("Error: ") + e.what();
295 #ifdef SWIGPYTHON
296         PyErr_SetObject(SWIG_Python_ExceptionType(SWIGTYPE_p_libsumo__TraCIException), PyUnicode_FromString(s.c_str()));
297         SWIG_fail;
298 #else
299         SWIG_exception(SWIG_ValueError, s.c_str());
300 #endif
301     } catch (std::runtime_error &e) {
302         const std::string s = std::string("SUMO error: ") + e.what();
303         SWIG_exception(SWIG_RuntimeError, s.c_str());
304     } catch (...) {
305         SWIG_exception(SWIG_UnknownError, "unknown exception");
306     }
307 }
308 
309 // %feature("compactdefaultargs") libsumo::Simulation::findRoute;
310 
311 // Add necessary symbols to generated header
312 %{
313 #include <libsumo/TraCIDefs.h>
314 #include <libsumo/Edge.h>
315 #include <libsumo/InductionLoop.h>
316 #include <libsumo/Junction.h>
317 #include <libsumo/LaneArea.h>
318 #include <libsumo/Lane.h>
319 #include <libsumo/MultiEntryExit.h>
320 #include <libsumo/POI.h>
321 #include <libsumo/Polygon.h>
322 #include <libsumo/Route.h>
323 #include <libsumo/Simulation.h>
324 #include <libsumo/TrafficLight.h>
325 #include <libsumo/VehicleType.h>
326 #include <libsumo/Vehicle.h>
327 #include <libsumo/Person.h>
328 %}
329 
330 // Process symbols in header
331 %include "TraCIDefs.h"
332 %template(TraCIConnectionVector) std::vector<libsumo::TraCIConnection>;
333 %template(TraCILogicVector) std::vector<libsumo::TraCILogic>;
334 %template(TraCIStageVector) std::vector<libsumo::TraCIStage>;
335 %include "Edge.h"
336 %include "InductionLoop.h"
337 %include "Junction.h"
338 %include "LaneArea.h"
339 %include "Lane.h"
340 %include "MultiEntryExit.h"
341 %include "POI.h"
342 %include "Polygon.h"
343 %include "Route.h"
344 %include "Simulation.h"
345 %include "TraCIConstants.h"
346 %include "TrafficLight.h"
347 %include "VehicleType.h"
348 %include "Vehicle.h"
349 %include "Person.h"
350 
351 #ifdef SWIGPYTHON
352 %pythoncode %{
353 def wrapAsClassMethod(func, module):
354     def wrapper(*args, **kwargs):
355         return func(module, *args, **kwargs)
356     return wrapper
357 
358 exceptions.TraCIException = TraCIException
359 trafficlight.Phase = TraCIPhase
360 trafficlight.Logic = TraCILogic
361 vehicle.addFull = vehicle.add
362 vehicle.addLegacy = wrapAsClassMethod(_vehicle.VehicleDomain.addLegacy, vehicle)
363 vehicle.couldChangeLane = wrapAsClassMethod(_vehicle.VehicleDomain.couldChangeLane, vehicle)
364 vehicle.wantsAndCouldChangeLane = wrapAsClassMethod(_vehicle.VehicleDomain.wantsAndCouldChangeLane, vehicle)
365 vehicle.isStopped = wrapAsClassMethod(_vehicle.VehicleDomain.isStopped, vehicle)
366 vehicle.setBusStop = wrapAsClassMethod(_vehicle.VehicleDomain.setBusStop, vehicle)
367 vehicle.setParkingAreaStop = wrapAsClassMethod(_vehicle.VehicleDomain.setParkingAreaStop, vehicle)
368 person.removeStages = wrapAsClassMethod(_person.PersonDomain.removeStages, person)
369 trafficlight.setLinkState = wrapAsClassMethod(_trafficlight.TrafficLightDomain.setLinkState, trafficlight)
370 %}
371 #endif
372