SUMO - Simulation of Urban MObility
GUIOSGBuilder.cpp
Go to the documentation of this file.
1 /****************************************************************************/
2 // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.org/sumo
3 // Copyright (C) 2001-2017 German Aerospace Center (DLR) and others.
4 /****************************************************************************/
5 //
6 // This program and the accompanying materials
7 // are made available under the terms of the Eclipse Public License v2.0
8 // which accompanies this distribution, and is available at
9 // http://www.eclipse.org/legal/epl-v20.html
10 //
11 /****************************************************************************/
18 // Builds OSG nodes from microsim objects
19 /****************************************************************************/
20 
21 
22 // ===========================================================================
23 // included modules
24 // ===========================================================================
25 #ifdef _MSC_VER
26 #include <windows_config.h>
27 #else
28 #include <config.h>
29 #endif
30 
31 #ifdef HAVE_OSG
32 
33 #ifdef _MSC_VER
34 #pragma warning(push)
35 #pragma warning(disable: 4127) // do not warn about constant conditional expression
36 #endif
37 #include <osg/Version>
38 #include <osgViewer/ViewerEventHandlers>
39 #include <osgGA/TrackballManipulator>
40 #include <osgDB/ReadFile>
41 #include <osgDB/WriteFile>
42 #include <osg/ShapeDrawable>
43 #include <osg/Node>
44 #include <osg/Group>
45 #include <osg/Geode>
46 #include <osg/Geometry>
47 #include <osg/Sequence>
48 #include <osg/Texture2D>
49 #include <osgViewer/Viewer>
50 #include <osgUtil/Tessellator>
51 #include <osg/PositionAttitudeTransform>
52 #include <osg/ShadeModel>
53 #include <osg/Light>
54 #include <osg/LightSource>
55 #ifdef _MSC_VER
56 #pragma warning(pop)
57 #endif
58 
59 #include <microsim/MSNet.h>
60 #include <microsim/MSEdge.h>
61 #include <microsim/MSLane.h>
62 #include <microsim/MSEdgeControl.h>
64 #include <microsim/MSJunction.h>
65 #include <microsim/MSVehicleType.h>
69 #include <guisim/GUINet.h>
70 #include <guisim/GUIEdge.h>
71 #include <guisim/GUILane.h>
75 #include "GUIOSGView.h"
76 #include "GUIOSGBuilder.h"
77 
78 
79 // ===========================================================================
80 // static member variables
81 // ===========================================================================
82 std::map<std::string, osg::ref_ptr<osg::Node> > GUIOSGBuilder::myCars;
83 
84 
85 // ===========================================================================
86 // member method definitions
87 // ===========================================================================
88 osg::Group*
89 GUIOSGBuilder::buildOSGScene(osg::Node* const tlg, osg::Node* const tly, osg::Node* const tlr, osg::Node* const tlu) {
90  osgUtil::Tessellator tesselator;
91  osg::Group* root = new osg::Group();
92  GUINet* net = static_cast<GUINet*>(MSNet::getInstance());
93  // build edges
94  const MSEdgeVector& edges = net->getEdgeControl().getEdges();
95  for (MSEdgeVector::const_iterator i = edges.begin(); i != edges.end(); ++i) {
96  if (!(*i)->isInternal()) {
97  buildOSGEdgeGeometry(**i, *root, tesselator);
98  }
99  }
100  // build junctions
101  for (int index = 0; index < (int)net->myJunctionWrapper.size(); ++index) {
102  buildOSGJunctionGeometry(*net->myJunctionWrapper[index], *root, tesselator);
103  }
104  // build traffic lights
106  const std::vector<std::string> tlids = net->getTLSControl().getAllTLIds();
107  for (std::vector<std::string>::const_iterator i = tlids.begin(); i != tlids.end(); ++i) {
110  const MSLane* lastLane = 0;
111  int idx = 0;
112  for (MSTrafficLightLogic::LaneVectorVector::const_iterator j = lanes.begin(); j != lanes.end(); ++j, ++idx) {
113  const MSLane* const lane = (*j)[0];
114  const Position pos = lane->getShape().back();
115  const double angle = osg::DegreesToRadians(lane->getShape().rotationDegreeAtOffset(-1.) + 90.);
116  d.centerZ = pos.z() + 4.;
117  if (lane == lastLane) {
118  d.centerX += 1.2 * sin(angle);
119  d.centerY += 1.2 * cos(angle);
120  } else {
121  d.centerX = pos.x() - 1.5 * sin(angle);
122  d.centerY = pos.y() - 1.5 * cos(angle);
123  }
124  osg::Switch* switchNode = new osg::Switch();
125  switchNode->addChild(getTrafficLight(d, tlg, osg::Vec4d(0.1, 0.5, 0.1, 1.0), .25), false);
126  switchNode->addChild(getTrafficLight(d, tly, osg::Vec4d(0.5, 0.5, 0.1, 1.0), .25), false);
127  switchNode->addChild(getTrafficLight(d, tlr, osg::Vec4d(0.5, 0.1, 0.1, 1.0), .25), false);
128  switchNode->addChild(getTrafficLight(d, tlu, osg::Vec4d(0.8, 0.4, 0.0, 1.0), .25), false);
129  root->addChild(switchNode);
130  const MSLink* const l = vars.getActive()->getLinksAt(idx)[0];
131  vars.addSwitchCommand(new GUIOSGView::Command_TLSChange(l, switchNode));
132  lastLane = lane;
133  }
134  }
135  return root;
136 }
137 
138 
139 void
140 GUIOSGBuilder::buildLight(const GUISUMOAbstractView::Decal& d, osg::Group& addTo) {
141  // each light must have a unique number
142  osg::Light* light = new osg::Light(d.filename[5] - '0');
143  // we set the light's position via a PositionAttitudeTransform object
144  light->setPosition(osg::Vec4(0.0, 0.0, 0.0, 1.0));
145  light->setDiffuse(osg::Vec4(1.0, 1.0, 1.0, 1.0));
146  light->setSpecular(osg::Vec4(1.0, 1.0, 1.0, 1.0));
147  light->setAmbient(osg::Vec4(1.0, 1.0, 1.0, 1.0));
148 
149  osg::LightSource* lightSource = new osg::LightSource();
150  lightSource->setLight(light);
151  lightSource->setLocalStateSetModes(osg::StateAttribute::ON);
152  lightSource->setStateSetModes(*addTo.getOrCreateStateSet(), osg::StateAttribute::ON);
153 
154  osg::PositionAttitudeTransform* lightTransform = new osg::PositionAttitudeTransform();
155  lightTransform->addChild(lightSource);
156  lightTransform->setPosition(osg::Vec3d(d.centerX, d.centerY, d.centerZ));
157  lightTransform->setScale(osg::Vec3d(0.1, 0.1, 0.1));
158  addTo.addChild(lightTransform);
159 }
160 
161 
162 void
163 GUIOSGBuilder::buildOSGEdgeGeometry(const MSEdge& edge,
164  osg::Group& addTo,
165  osgUtil::Tessellator& tessellator) {
166  const std::vector<MSLane*>& lanes = edge.getLanes();
167  for (std::vector<MSLane*>::const_iterator j = lanes.begin(); j != lanes.end(); ++j) {
168  MSLane* l = (*j);
169  const PositionVector& shape = l->getShape();
170  osg::Geode* geode = new osg::Geode();
171  osg::Geometry* geom = new osg::Geometry();
172  geode->addDrawable(geom);
173  addTo.addChild(geode);
174  osg::Vec3dArray* osg_coords = new osg::Vec3dArray((int)shape.size() * 2);
175  geom->setVertexArray(osg_coords);
176  PositionVector rshape = shape;
178  int index = 0;
179  for (int k = 0; k < (int)rshape.size(); ++k, ++index) {
180  (*osg_coords)[index].set(rshape[k].x(), rshape[k].y(), rshape[k].z());
181  }
182  PositionVector lshape = shape;
184  for (int k = (int) lshape.size() - 1; k >= 0; --k, ++index) {
185  (*osg_coords)[index].set(lshape[k].x(), lshape[k].y(), lshape[k].z());
186  }
187  osg::Vec3Array* osg_normals = new osg::Vec3Array(1);
188  (*osg_normals)[0] = osg::Vec3(0, 0, 1);
189 #if OSG_MIN_VERSION_REQUIRED(3,2,0)
190  geom->setNormalArray(osg_normals, osg::Array::BIND_PER_PRIMITIVE_SET);
191 #else
192  geom->setNormalArray(osg_normals);
193  geom->setNormalBinding(osg::Geometry::BIND_PER_PRIMITIVE);
194 #endif
195  osg::Vec4ubArray* osg_colors = new osg::Vec4ubArray(1);
196  (*osg_colors)[0].set(128, 128, 128, 255);
197 #if OSG_MIN_VERSION_REQUIRED(3,2,0)
198  geom->setColorArray(osg_colors, osg::Array::BIND_OVERALL);
199 #else
200  geom->setColorArray(osg_colors);
201  geom->setColorBinding(osg::Geometry::BIND_OVERALL);
202 #endif
203  geom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::POLYGON, 0, (int)shape.size() * 2));
204 
205  osg::ref_ptr<osg::StateSet> ss = geode->getOrCreateStateSet();
206  ss->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
207  ss->setMode(GL_BLEND, osg::StateAttribute::OVERRIDE | osg::StateAttribute::PROTECTED | osg::StateAttribute::ON);
208 
209  if (shape.size() > 2) {
210  tessellator.retessellatePolygons(*geom);
211  }
212  static_cast<GUILane*>(l)->setGeometry(geom);
213  }
214 }
215 
216 
217 void
218 GUIOSGBuilder::buildOSGJunctionGeometry(GUIJunctionWrapper& junction,
219  osg::Group& addTo,
220  osgUtil::Tessellator& tessellator) {
221  const PositionVector& shape = junction.getJunction().getShape();
222  osg::Geode* geode = new osg::Geode();
223  osg::Geometry* geom = new osg::Geometry();
224  geode->addDrawable(geom);
225  addTo.addChild(geode);
226  osg::Vec3dArray* osg_coords = new osg::Vec3dArray((int)shape.size());
227  geom->setVertexArray(osg_coords);
228  for (int k = 0; k < (int)shape.size(); ++k) {
229  (*osg_coords)[k].set(shape[k].x(), shape[k].y(), shape[k].z());
230  }
231  osg::Vec3dArray* osg_normals = new osg::Vec3dArray(1);
232  (*osg_normals)[0] = osg::Vec3(0, 0, 1);
233 #if OSG_MIN_VERSION_REQUIRED(3,2,0)
234  geom->setNormalArray(osg_normals, osg::Array::BIND_PER_PRIMITIVE_SET);
235 #else
236  geom->setNormalArray(osg_normals);
237  geom->setNormalBinding(osg::Geometry::BIND_PER_PRIMITIVE);
238 #endif
239  osg::Vec4ubArray* osg_colors = new osg::Vec4ubArray(1);
240  (*osg_colors)[0].set(128, 128, 128, 255);
241 #if OSG_MIN_VERSION_REQUIRED(3,2,0)
242  geom->setColorArray(osg_colors, osg::Array::BIND_OVERALL);
243 #else
244  geom->setColorArray(osg_colors);
245  geom->setColorBinding(osg::Geometry::BIND_OVERALL);
246 #endif
247  geom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::POLYGON, 0, (int)shape.size()));
248 
249  osg::ref_ptr<osg::StateSet> ss = geode->getOrCreateStateSet();
250  ss->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
251  ss->setMode(GL_BLEND, osg::StateAttribute::OVERRIDE | osg::StateAttribute::PROTECTED | osg::StateAttribute::ON);
252 
253  if (shape.size() > 4) {
254  tessellator.retessellatePolygons(*geom);
255  }
256  junction.setGeometry(geom);
257 }
258 
259 
260 void
261 GUIOSGBuilder::buildDecal(const GUISUMOAbstractView::Decal& d, osg::Group& addTo) {
262  osg::Node* pLoadedModel = osgDB::readNodeFile(d.filename);
263  if (pLoadedModel == 0) {
264  WRITE_ERROR("Could not load '" + d.filename + "'.");
265  return;
266  }
267  osg::ShadeModel* sm = new osg::ShadeModel();
268  sm->setMode(osg::ShadeModel::FLAT);
269  pLoadedModel->getOrCreateStateSet()->setAttribute(sm);
270  osg::PositionAttitudeTransform* base = new osg::PositionAttitudeTransform();
271  base->addChild(pLoadedModel);
272  GUIOSGBoundingBoxCalculator bboxCalc;
273  pLoadedModel->accept(bboxCalc);
274  const osg::BoundingBox& bbox = bboxCalc.getBoundingBox();
275  WRITE_MESSAGE("Loaded decal '" + d.filename + "' with bounding box " + toString(Position(bbox.xMin(), bbox.yMin(), bbox.zMin())) + " " + toString(Position(bbox.xMax(), bbox.yMax(), bbox.zMax())) + ".");
276  double xScale = d.width > 0 ? d.width / (bbox.xMax() - bbox.xMin()) : 1.;
277  double yScale = d.height > 0 ? d.height / (bbox.yMax() - bbox.yMin()) : 1.;
278  const double zScale = d.altitude > 0 ? d.altitude / (bbox.zMax() - bbox.zMin()) : 1.;
279  if (d.width < 0 && d.height < 0 && d.altitude > 0) {
280  xScale = yScale = zScale;
281  }
282  base->setScale(osg::Vec3d(xScale, yScale, zScale));
283  base->setPosition(osg::Vec3d(d.centerX, d.centerY, d.centerZ));
284  base->setAttitude(osg::Quat(osg::DegreesToRadians(d.roll), osg::Vec3d(1, 0, 0),
285  osg::DegreesToRadians(d.tilt), osg::Vec3d(0, 1, 0),
286  osg::DegreesToRadians(d.rot), osg::Vec3d(0, 0, 1)));
287  addTo.addChild(base);
288 }
289 
290 
291 osg::PositionAttitudeTransform*
292 GUIOSGBuilder::getTrafficLight(const GUISUMOAbstractView::Decal& d, osg::Node* tl, const osg::Vec4& color, const double size) {
293  osg::PositionAttitudeTransform* ret = new osg::PositionAttitudeTransform();
294  if (tl != 0) {
295  osg::PositionAttitudeTransform* base = new osg::PositionAttitudeTransform();
296  base->addChild(tl);
297  GUIOSGBoundingBoxCalculator bboxCalc;
298  tl->accept(bboxCalc);
299  const osg::BoundingBox& bbox = bboxCalc.getBoundingBox();
300  double xScale = d.width > 0 ? d.width / (bbox.xMax() - bbox.xMin()) : 1.;
301  double yScale = d.height > 0 ? d.height / (bbox.yMax() - bbox.yMin()) : 1.;
302  const double zScale = d.altitude > 0 ? d.altitude / (bbox.zMax() - bbox.zMin()) : 1.;
303  if (d.width < 0 && d.height < 0 && d.altitude > 0) {
304  xScale = yScale = zScale;
305  }
306  base->setScale(osg::Vec3d(xScale, yScale, zScale));
307  base->setPosition(osg::Vec3d(d.centerX, d.centerY, d.centerZ));
308  base->setAttitude(osg::Quat(osg::DegreesToRadians(d.roll), osg::Vec3(1, 0, 0),
309  osg::DegreesToRadians(d.tilt), osg::Vec3(0, 1, 0),
310  osg::DegreesToRadians(d.rot), osg::Vec3(0, 0, 1)));
311  ret->addChild(base);
312  }
313  osg::Geode* geode = new osg::Geode();
314  osg::Vec3d center(d.centerX, d.centerY, d.centerZ);
315  osg::ShapeDrawable* shape = new osg::ShapeDrawable(new osg::Sphere(center, (float)size));
316  geode->addDrawable(shape);
317  osg::ref_ptr<osg::StateSet> ss = shape->getOrCreateStateSet();
318  ss->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
319  ss->setMode(GL_BLEND, osg::StateAttribute::OVERRIDE | osg::StateAttribute::PROTECTED | osg::StateAttribute::ON);
320  osg::PositionAttitudeTransform* ellipse = new osg::PositionAttitudeTransform();
321  ellipse->addChild(geode);
322  ellipse->setPivotPoint(center);
323  ellipse->setPosition(center);
324  ellipse->setScale(osg::Vec3d(4., 4., 2.5 * d.altitude + 1.1));
325  shape->setColor(color);
326  ret->addChild(ellipse);
327  return ret;
328 }
329 
330 
331 void
332 GUIOSGBuilder::setShapeState(osg::ref_ptr<osg::ShapeDrawable> shape) {
333  osg::ref_ptr<osg::StateSet> ss = shape->getOrCreateStateSet();
334  ss->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
335  ss->setMode(GL_BLEND, osg::StateAttribute::OVERRIDE | osg::StateAttribute::PROTECTED | osg::StateAttribute::ON);
336 }
337 
338 
339 GUIOSGView::OSGMovable
340 GUIOSGBuilder::buildMovable(const MSVehicleType& type) {
341  GUIOSGView::OSGMovable m;
342  m.pos = new osg::PositionAttitudeTransform();
343  double enlarge = 0.;
344  const std::string& osgFile = type.getOSGFile();
345  if (myCars.find(osgFile) == myCars.end()) {
346  myCars[osgFile] = osgDB::readNodeFile(osgFile);
347  if (myCars[osgFile] == 0) {
348  WRITE_ERROR("Could not load '" + osgFile + "'.");
349  }
350  }
351  osg::Node* carNode = myCars[osgFile];
352  if (carNode != 0) {
353  GUIOSGBoundingBoxCalculator bboxCalc;
354  carNode->accept(bboxCalc);
355  const osg::BoundingBox& bbox = bboxCalc.getBoundingBox();
356  osg::PositionAttitudeTransform* base = new osg::PositionAttitudeTransform();
357  base->addChild(carNode);
358  base->setPivotPoint(osg::Vec3d((bbox.xMin() + bbox.xMax()) / 2., bbox.yMin(), bbox.zMin()));
359  base->setScale(osg::Vec3d(type.getWidth() / (bbox.xMax() - bbox.xMin()),
360  type.getLength() / (bbox.yMax() - bbox.yMin()),
361  type.getHeight() / (bbox.zMax() - bbox.zMin())));
362  m.pos->addChild(base);
363  enlarge = type.getMinGap() / 2.;
364  }
365  m.lights = new osg::Switch();
366  for (double offset = -0.3; offset < 0.5; offset += 0.6) {
367  osg::Geode* geode = new osg::Geode();
368  osg::ShapeDrawable* right = new osg::ShapeDrawable(new osg::Sphere(osg::Vec3d(offset, (type.getLength() - .9) / 2., (type.getHeight() - .5) / 2.), .1f));
369  geode->addDrawable(right);
370  setShapeState(right);
371  right->setColor(osg::Vec4(1.f, .5f, 0.f, .8f));
372  osg::Sequence* seq = new osg::Sequence();
373  // Wikipedia says about 1.5Hz
374  seq->addChild(geode, .33);
375  seq->addChild(new osg::Geode(), .33);
376  // loop through all children
377  seq->setInterval(osg::Sequence::LOOP, 0, -1);
378  // real-time playback, repeat indefinitely
379  seq->setDuration(1.0f, -1);
380  // must be started explicitly
381  seq->setMode(osg::Sequence::START);
382  m.lights->addChild(seq);
383  }
384 
385  osg::Geode* geode = new osg::Geode();
386  osg::CompositeShape* comp = new osg::CompositeShape();
387  comp->addChild(new osg::Sphere(osg::Vec3d(-0.3, (type.getLength() + .8) / 2., (type.getHeight() - .5) / 2.), .1f));
388  comp->addChild(new osg::Sphere(osg::Vec3d(0.3, (type.getLength() + .8) / 2., (type.getHeight() - .5) / 2.), .1f));
389  osg::ShapeDrawable* brake = new osg::ShapeDrawable(comp);
390  brake->setColor(osg::Vec4(1.f, 0.f, 0.f, .8f));
391  geode->addDrawable(brake);
392  setShapeState(brake);
393  m.lights->addChild(geode);
394 
395  geode = new osg::Geode();
396  osg::Vec3d center(0, type.getLength() / 2., type.getHeight() / 2.);
397  m.geom = new osg::ShapeDrawable(new osg::Sphere(center, .5f));
398  geode->addDrawable(m.geom);
399  setShapeState(m.geom);
400  osg::PositionAttitudeTransform* ellipse = new osg::PositionAttitudeTransform();
401  ellipse->addChild(geode);
402  ellipse->addChild(m.lights);
403  ellipse->setPivotPoint(center);
404  ellipse->setPosition(center);
405  ellipse->setScale(osg::Vec3d(type.getWidth() + enlarge, type.getLength() + enlarge, type.getHeight() + enlarge));
406  m.pos->addChild(ellipse);
407  return m;
408 }
409 
410 #endif
411 
412 
413 /****************************************************************************/
414 
A decal (an image) that can be shown.
double altitude
The altitude of the image (net coordinates in z-direction, in m)
double rotationDegreeAtOffset(double pos) const
Returns the rotation at the given length.
Storage for all programs of a single tls.
std::vector< GUIJunctionWrapper * > myJunctionWrapper
Wrapped MS-junctions.
Definition: GUINet.h:351
double z() const
Returns the z-position.
Definition: Position.h:72
double y() const
Returns the y-position.
Definition: Position.h:67
const LaneVectorVector & getLaneVectors() const
Returns the list of lists of all lanes controlled by this tls.
double x() const
Returns the x-position.
Definition: Position.h:62
double centerX
The center of the image in x-direction (net coordinates, in m)
const std::vector< MSLane * > & getLanes() const
Returns this edge&#39;s lanes.
Definition: MSEdge.h:167
static MSNet * getInstance()
Returns the pointer to the unique instance of MSNet (singleton).
Definition: MSNet.cpp:167
const PositionVector & getShape() const
Returns this lane&#39;s shape.
Definition: MSLane.h:439
const LinkVector & getLinksAt(int i) const
Returns the list of links that are controlled by the signals at the given position.
double height
The height of the image (net coordinates in y-direction, in m)
The car-following model and parameter.
Definition: MSVehicleType.h:72
Representation of a lane in the micro simulation (gui-version)
Definition: GUILane.h:69
double roll
The roll of the image to the ground plane (in degrees)
A road/street connecting two junctions.
Definition: MSEdge.h:80
void addSwitchCommand(OnSwitchAction *c)
std::string toString(const T &t, std::streamsize accuracy=gPrecision)
Definition: ToString.h:55
const double SUMO_const_halfLaneWidth
Definition: StdDefs.h:50
A point in 2D or 3D with translation and scaling methods.
Definition: Position.h:45
MSTLLogicControl & getTLSControl()
Returns the tls logics control.
Definition: MSNet.h:379
A list of positions.
double rot
The rotation of the image in the ground plane (in degrees)
double centerY
The center of the image in y-direction (net coordinates, in m)
double getMinGap() const
Get the free space in front of vehicles of this class.
std::string filename
The path to the file the image is located at.
void move2side(double amount)
move position vector to side using certain ammount
double width
The width of the image (net coordinates in x-direction, in m)
#define WRITE_ERROR(msg)
Definition: MsgHandler.h:205
double getWidth() const
Get the width which vehicles of this class shall have when being drawn.
double getHeight() const
Get the height which vehicles of this class shall have when being drawn.
std::vector< LaneVector > LaneVectorVector
Definition of a list that holds lists of lanes that do have the same attribute.
A MSNet extended by some values for usage within the gui.
Definition: GUINet.h:88
const MSJunction & getJunction() const
Returns the represented junction.
double centerZ
The center of the image in z-direction (net coordinates, in m)
double getLength() const
Get vehicle&#39;s length [m].
const MSEdgeVector & getEdges() const
Returns loaded edges.
double tilt
The tilt of the image to the ground plane (in degrees)
MSEdgeControl & getEdgeControl()
Returns the edge control.
Definition: MSNet.h:349
std::string getOSGFile() const
Get this vehicle type&#39;s 3D model file name.
TLSLogicVariants & get(const std::string &id) const
Returns the variants of a named tls.
std::vector< MSEdge * > MSEdgeVector
Definition: MSEdge.h:77
MSTrafficLightLogic * getActive() const
std::vector< std::string > getAllTLIds() const
#define WRITE_MESSAGE(msg)
Definition: MsgHandler.h:200
Representation of a lane in the micro simulation.
Definition: MSLane.h:77
const PositionVector & getShape() const
Returns this junction&#39;s shape.
Definition: MSJunction.h:93