Eclipse SUMO - Simulation of Urban MObility
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
GUIOSGBuilder.cpp
Go to the documentation of this file.
1/****************************************************************************/
2// Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3// Copyright (C) 2001-2025 German Aerospace Center (DLR) and others.
4// This program and the accompanying materials are made available under the
5// terms of the Eclipse Public License 2.0 which is available at
6// https://www.eclipse.org/legal/epl-2.0/
7// This Source Code may also be made available under the following Secondary
8// Licenses when the conditions for such availability set forth in the Eclipse
9// Public License 2.0 are satisfied: GNU General Public License, version 2
10// or later which is available at
11// https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
12// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
13/****************************************************************************/
20// Builds OSG nodes from microsim objects
21/****************************************************************************/
22#include <config.h>
23
24#ifdef HAVE_OSG
25
26#include <guisim/GUIEdge.h>
28#include <guisim/GUILane.h>
29#include <guisim/GUINet.h>
30#include <microsim/MSEdge.h>
32#include <microsim/MSJunction.h>
34#include <microsim/MSLane.h>
35#include <microsim/MSNet.h>
44
45#include "GUIOSGView.h"
46#include "GUIOSGBuilder.h"
47
48//#define DEBUG_TESSEL
49
50// ===========================================================================
51// static member variables
52// ===========================================================================
53
54std::map<std::string, osg::ref_ptr<osg::Node> > GUIOSGBuilder::myCars;
55
56// ===========================================================================
57// member method definitions
58// ===========================================================================
59
60osg::Group*
61GUIOSGBuilder::buildOSGScene(osg::Node* const tlg, osg::Node* const tly, osg::Node* const tlr, osg::Node* const tlu, osg::Node* const pole) {
62 osgUtil::Tessellator tesselator;
63 osg::Group* root = new osg::Group();
64 GUINet* net = static_cast<GUINet*>(MSNet::getInstance());
65 // build edges
66 for (const MSEdge* e : net->getEdgeControl().getEdges()) {
67 if (!e->isInternal()) {
68 buildOSGEdgeGeometry(*e, *root, tesselator);
69 }
70 }
71 // build junctions
72 for (int index = 0; index < (int)net->myJunctionWrapper.size(); ++index) {
73 buildOSGJunctionGeometry(*net->myJunctionWrapper[index], *root, tesselator);
74 }
75 // build traffic lights
77 const std::vector<std::string> tlids = net->getTLSControl().getAllTLIds();
78 for (std::vector<std::string>::const_iterator i = tlids.begin(); i != tlids.end(); ++i) {
80 buildTrafficLightDetails(vars, tlg, tly, tlr, tlu, pole, *root);
81
83 const MSLane* lastLane = 0;
84 int idx = 0;
85 for (MSTrafficLightLogic::LaneVectorVector::const_iterator j = lanes.begin(); j != lanes.end(); ++j, ++idx) {
86 if ((*j).size() == 0) {
87 continue;
88 }
89 const MSLane* const lane = (*j)[0];
90 const Position pos = lane->getShape().back();
91 const double angle = osg::DegreesToRadians(lane->getShape().rotationDegreeAtOffset(-1.) + 90.);
92 d.centerZ = pos.z() + 4.;
93 if (lane == lastLane) {
94 d.centerX += 1.2 * sin(angle);
95 d.centerY += 1.2 * cos(angle);
96 } else {
97 d.centerX = pos.x() - 1.5 * sin(angle);
98 d.centerY = pos.y() - 1.5 * cos(angle);
99 }
100 osg::PositionAttitudeTransform* tlNode = getTrafficLight(d, vars, vars.getActive()->getLinksAt(idx)[0], nullptr, nullptr, nullptr, nullptr, nullptr, false, .25, -1, 1.);
101 tlNode->setName("tlLogic:" + *i);
102 root->addChild(tlNode);
103 lastLane = lane;
104 }
105 }
106
107 // build PoI and polygons
108 for (const auto& entry : net->getShapeContainer().getPolygons()) {
109 buildPolygonGeometry(*entry.second, *root, tesselator);
110 }
111 for (const auto& entry : net->getShapeContainer().getPOIs()) {
112 buildPoIGeometry(*entry.second, *root, tesselator);
113 }
114 return root;
115}
116
117
118void
119GUIOSGBuilder::buildLight(const GUISUMOAbstractView::Decal& d, osg::Group& addTo) {
120 // each light must have a unique number
121 osg::Light* light = new osg::Light(d.filename[5] - '0');
122 // we set the light's position via a PositionAttitudeTransform object
123 light->setPosition(osg::Vec4(0.0, 0.0, 0.0, 1.0));
124 light->setDiffuse(osg::Vec4(1.0, 1.0, 1.0, 1.0));
125 light->setSpecular(osg::Vec4(1.0, 1.0, 1.0, 1.0));
126 light->setAmbient(osg::Vec4(1.0, 1.0, 1.0, 1.0));
127
128 osg::LightSource* lightSource = new osg::LightSource();
129 lightSource->setLight(light);
130 lightSource->setLocalStateSetModes(osg::StateAttribute::ON);
131 lightSource->setStateSetModes(*addTo.getOrCreateStateSet(), osg::StateAttribute::ON);
132
133 osg::PositionAttitudeTransform* lightTransform = new osg::PositionAttitudeTransform();
134 lightTransform->addChild(lightSource);
135 lightTransform->setPosition(osg::Vec3d(d.centerX, d.centerY, d.centerZ));
136 lightTransform->setScale(osg::Vec3d(0.1, 0.1, 0.1));
137 addTo.addChild(lightTransform);
138}
139
140
141void
142GUIOSGBuilder::buildOSGEdgeGeometry(const MSEdge& edge,
143 osg::Group& addTo,
144 osgUtil::Tessellator& tessellator) {
145 const std::vector<MSLane*>& lanes = edge.getLanes();
146 for (std::vector<MSLane*>::const_iterator j = lanes.begin(); j != lanes.end(); ++j) {
147 MSLane* l = (*j);
148 const bool extrude = edge.isWalkingArea() || isSidewalk(l->getPermissions());
149 const int geomFactor = (edge.isWalkingArea()) ? 1 : 2;
150 const PositionVector& shape = l->getShape();
151 const int originalSize = (int)shape.size();
152 osg::Geode* geode = new osg::Geode();
153 osg::Geometry* geom = new osg::Geometry();
154 geode->addDrawable(geom);
155 geode->setName("lane:" + l->getID());
156 addTo.addChild(geode);
157 dynamic_cast<GUIGlObject*>(l)->setNode(geode);
158 const int upperShapeSize = originalSize * geomFactor;
159 const int totalShapeSize = (extrude) ? originalSize * 2 * geomFactor : originalSize * geomFactor;
160 const float zOffset = (extrude) ? (edge.isCrossing()) ? 0.01f : 0.1f : 0.f;
161 osg::Vec4ubArray* osg_colors = new osg::Vec4ubArray(1);
162 (*osg_colors)[0].set(128, 128, 128, 255);
163 geom->setColorArray(osg_colors, osg::Array::BIND_OVERALL);
164 osg::Vec3Array* osg_coords = new osg::Vec3Array(totalShapeSize);
165 geom->setVertexArray(osg_coords);
166 int sizeDiff = 0;
167 if (edge.isWalkingArea()) {
168 int index = upperShapeSize - 1;
169 for (int k = 0; k < upperShapeSize; ++k, --index) {
170 (*osg_coords)[index].set((float)shape[k].x(), (float)shape[k].y(), (float)shape[k].z() + zOffset);
171 }
172 geom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::POLYGON, 0, upperShapeSize));
173 } else {
174 int index = 0;
175 PositionVector rshape = shape;
176 rshape.move2side(l->getWidth() / 2);
177 for (int k = (int)rshape.size() - 1; k >= 0; --k, ++index) {
178 (*osg_coords)[index].set((float)rshape[k].x(), (float)rshape[k].y(), (float)rshape[k].z() + zOffset);
179 }
180 PositionVector lshape = shape;
181 lshape.move2side(-l->getWidth() / 2);
182 for (int k = 0; k < (int)lshape.size(); ++k, ++index) {
183 (*osg_coords)[index].set((float)lshape[k].x(), (float)lshape[k].y(), (float)lshape[k].z() + zOffset);
184 }
185 sizeDiff = (int)rshape.size() + (int)lshape.size() - upperShapeSize;
186 int minSize = MIN2((int)rshape.size(), (int)lshape.size());
187 osg::DrawElementsUInt* surface = new osg::DrawElementsUInt(osg::PrimitiveSet::TRIANGLE_STRIP, 0);
188 for (int i = 0; i < minSize; ++i) {
189 surface->push_back(i);
190 surface->push_back(upperShapeSize + sizeDiff - 1 - i);
191 }
192 geom->addPrimitiveSet(surface);
193 }
194 if (extrude) {
195 int index = upperShapeSize;
196 for (int k = 0; k < upperShapeSize + sizeDiff; ++k, ++index) {
197 (*osg_coords)[index].set((*osg_coords)[k].x(), (*osg_coords)[k].y(), (*osg_coords)[k].z() - zOffset);
198 }
199 // extrude edge to create the kerb
200 for (int i = 0; i < upperShapeSize + sizeDiff; ++i) {
201 osg::Vec3 surfaceVec = (*osg_coords)[i] - (*osg_coords)[(i + 1) % (upperShapeSize + sizeDiff)];
202 if (surfaceVec.length() > 0.) {
203 osg::DrawElementsUInt* kerb = new osg::DrawElementsUInt(osg::PrimitiveSet::POLYGON, 0);
204 kerb->push_back(i);
205 kerb->push_back(upperShapeSize + i);
206 kerb->push_back(upperShapeSize + (i + 1) % (upperShapeSize + sizeDiff));
207 kerb->push_back((i + 1) % (upperShapeSize + sizeDiff));
208 geom->addPrimitiveSet(kerb);
209 }
210 }
211 }
212
213 osg::ref_ptr<osg::StateSet> ss = geode->getOrCreateStateSet();
214 ss->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
215 ss->setMode(GL_BLEND, osg::StateAttribute::OVERRIDE | osg::StateAttribute::PROTECTED | osg::StateAttribute::ON);
216
217 if (shape.size() > 2) {
218 tessellator.retessellatePolygons(*geom);
219
220#ifdef DEBUG_TESSEL
221 std::cout << "l=" << l->getID() << " origPoints=" << shape.size() << " geomSize=" << geom->getVertexArray()->getNumElements() << " points=";
222 for (int i = 0; i < (int)geom->getVertexArray()->getNumElements(); i++) {
223 const osg::Vec3& p = (*((osg::Vec3Array*)geom->getVertexArray()))[i];
224 std::cout << p.x() << "," << p.y() << "," << p.z() << " ";
225 }
226 std::cout << "\n";
227#endif
228 }
229 osgUtil::SmoothingVisitor sv;
230#if OSG_MIN_VERSION_REQUIRED(3,5,4)
231 sv.setCreaseAngle(0.6 * osg::PI);
232#endif
233 geom->accept(sv);
234 static_cast<GUILane*>(l)->setGeometry(geom);
235 }
236}
237
238
239void
240GUIOSGBuilder::buildOSGJunctionGeometry(GUIJunctionWrapper& junction,
241 osg::Group& addTo,
242 osgUtil::Tessellator& tessellator) {
243 const PositionVector& shape = junction.getJunction().getShape();
244 osg::Geode* geode = new osg::Geode();
245 osg::Geometry* geom = new osg::Geometry();
246 geode->addDrawable(geom);
247 geode->setName("junction:" + junction.getMicrosimID());
248 addTo.addChild(geode);
249 dynamic_cast<GUIGlObject&>(junction).setNode(geode);
250 osg::Vec3Array* osg_coords = new osg::Vec3Array((int)shape.size()); // OSG needs float coordinates here
251 geom->setVertexArray(osg_coords);
252 for (int k = 0; k < (int)shape.size(); ++k) {
253 (*osg_coords)[k].set((float)shape[k].x(), (float)shape[k].y(), (float)shape[k].z());
254 }
255 osg::Vec3Array* osg_normals = new osg::Vec3Array(1);
256 (*osg_normals)[0] = osg::Vec3(0, 0, 1); // OSG needs float coordinates here
257 geom->setNormalArray(osg_normals, osg::Array::BIND_PER_PRIMITIVE_SET);
258 osg::Vec4ubArray* osg_colors = new osg::Vec4ubArray(1);
259 (*osg_colors)[0].set(128, 128, 128, 255);
260 geom->setColorArray(osg_colors, osg::Array::BIND_OVERALL);
261 geom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::POLYGON, 0, (int)shape.size()));
262
263 osg::ref_ptr<osg::StateSet> ss = geode->getOrCreateStateSet();
264 ss->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
265 ss->setMode(GL_BLEND, osg::StateAttribute::OVERRIDE | osg::StateAttribute::PROTECTED | osg::StateAttribute::ON);
266
267 if (shape.size() > 4) {
268 tessellator.retessellatePolygons(*geom);
269 }
270 junction.setGeometry(geom);
271}
272
273
274void
275GUIOSGBuilder::buildPolygonGeometry(const SUMOPolygon& poly, osg::Group& addTo, osgUtil::Tessellator& tessellator) {
276 const PositionVector& shape = poly.getShape();
277 const std::vector<PositionVector>& holes = poly.getHoles();
278 //const bool isFilled = poly.getFill();
279 //const double lineWidth = poly.getLineWidth();
280
281 osg::Geode* geode = new osg::Geode();
282 osg::Geometry* geom = new osg::Geometry();
283 geode->addDrawable(geom);
284 geode->setName("polygon:" + poly.getID());
285 addTo.addChild(geode);
286 osg::Vec3Array* osg_coords = new osg::Vec3Array((int)shape.size()); // OSG needs float coordinates here
287 geom->setVertexArray(osg_coords);
288 for (int k = 0; k < (int)shape.size(); ++k) {
289 (*osg_coords)[k].set((float)shape[k].x(), (float)shape[k].y(), 0.1f);
290 }
291 // TODO: how to draw holes? Don't worry for the moment, just don't
292 if (holes.size() > 0) {
293 }
294
295 osg::Vec3Array* osg_normals = new osg::Vec3Array(1);
296 (*osg_normals)[0] = osg::Vec3(0, 0, 1); // OSG needs float coordinates here
297 geom->setNormalArray(osg_normals, osg::Array::BIND_PER_PRIMITIVE_SET);
298 osg::Vec4ubArray* osg_colors = new osg::Vec4ubArray(1);
299 const RGBColor col = poly.getShapeColor();
300 (*osg_colors)[0].set(col.red(), col.green(), col.blue(), 255);
301 geom->setColorArray(osg_colors, osg::Array::BIND_OVERALL);
302 geom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::POLYGON, 0, (int)shape.size()));
303
304 osg::ref_ptr<osg::StateSet> ss = geode->getOrCreateStateSet();
305 ss->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
306 ss->setMode(GL_BLEND, osg::StateAttribute::OVERRIDE | osg::StateAttribute::PROTECTED | osg::StateAttribute::ON);
307
308 if (shape.size() > 4) {
309 tessellator.retessellatePolygons(*geom);
310 }
311}
312
313
314void
315GUIOSGBuilder::buildPoIGeometry(const PointOfInterest& poi, osg::Group& addTo, osgUtil::Tessellator& tessellator) {
316 osg::Geode* geode = new osg::Geode();
317 osg::Geometry* geom = new osg::Geometry();
318 geode->addDrawable(geom);
319 geode->setName("poi:" + poi.getID());
320 addTo.addChild(geode);
321 osg::Vec3Array* osg_coords = new osg::Vec3Array(4); // OSG needs float coordinates here
322 geom->setVertexArray(osg_coords);
323 // make a square
324 const Position& center = poi.getCenter();
325 const double width = poi.getWidth();
326 const double height = poi.getHeight();
327 PositionVector shape;
328 shape.push_back(Position(center.x() - 0.5 * width, center.y() + 0.5 * height));
329 shape.push_back(Position(center.x() + 0.5 * width, center.y() + 0.5 * height));
330 shape.push_back(Position(center.x() + 0.5 * width, center.y() - 0.5 * height));
331 shape.push_back(Position(center.x() - 0.5 * width, center.y() - 0.5 * height));
332 for (unsigned int k = 0; k < shape.size(); ++k) {
333 (*osg_coords)[k].set((float)shape[k].x(), (float)shape[k].y(), 0.2f);
334 }
335 osg::Vec3Array* osg_normals = new osg::Vec3Array(1);
336 (*osg_normals)[0] = osg::Vec3(0, 0, 1); // OSG needs float coordinates here
337 geom->setNormalArray(osg_normals, osg::Array::BIND_PER_PRIMITIVE_SET);
338 osg::Vec4ubArray* osg_colors = new osg::Vec4ubArray(1);
339 const RGBColor col = poi.getShapeColor();
340 (*osg_colors)[0].set(col.red(), col.green(), col.blue(), 255);
341 geom->setColorArray(osg_colors, osg::Array::BIND_OVERALL);
342 geom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::POLYGON, 0, (int)shape.size()));
343
344 osg::ref_ptr<osg::StateSet> ss = geode->getOrCreateStateSet();
345 ss->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
346 ss->setMode(GL_BLEND, osg::StateAttribute::OVERRIDE | osg::StateAttribute::PROTECTED | osg::StateAttribute::ON);
347
348 if (shape.size() > 4) {
349 tessellator.retessellatePolygons(*geom);
350 }
351}
352
353
354void
355GUIOSGBuilder::buildTrafficLightDetails(MSTLLogicControl::TLSLogicVariants& vars, osg::Node* const tlg, osg::Node* const tly, osg::Node* const tlr, osg::Node* const tlu, osg::Node* poleBase, osg::Group& addTo) {
356 // get the poleBase diameter for later repositioning
357 osg::ComputeBoundsVisitor bboxCalc;
358 poleBase->accept(bboxCalc);
359 const double poleDiameter = bboxCalc.getBoundingBox().yMax() - bboxCalc.getBoundingBox().yMin();
360 tlg->accept(bboxCalc);
361 const double tlWidth = bboxCalc.getBoundingBox().yMax() - bboxCalc.getBoundingBox().yMin();
362
363 // loop through lanes, collect edges, skip ped and bike infra for the time being
364 MSTrafficLightLogic* tlLogic = vars.getActive();
365 const MSTrafficLightLogic::LinkVectorVector& allLinks = tlLogic->getLinks();
366 std::set<const MSEdge*> seenEdges;
367
368 for (const MSTrafficLightLogic::LinkVector& lv : allLinks) {
369 for (const MSLink* tlLink : lv) {
370 // if not in seenEdges, create pole and reference it in the maps above
371 const MSEdge* approach = &tlLink->getLaneBefore()->getEdge();
372 if (!approach->isWalkingArea() && seenEdges.find(approach) != seenEdges.end()) {
373 continue;
374 }
375 const std::vector<MSLane*> appLanes = approach->getLanes();
376 // ref pos
377 const double poleMinHeight = 5.;
378 const double poleOffset = .5;
379 double angle = 90. - appLanes[0]->getShape().rotationDegreeAtOffset(-1.);
380 bool onlyPedCycle = isBikepath(approach->getPermissions()) || isSidewalk(approach->getPermissions());
381 Position pos = appLanes[0]->getShape().back();
382 double skipWidth = 0.;
383 int firstSignalLaneIx = 0;
384 std::vector<std::pair<osg::Group*, osg::Vec3d>> repeaters;
385 // start with local coordinate system
386 osg::PositionAttitudeTransform* appBase = new osg::PositionAttitudeTransform();
387 osg::PositionAttitudeTransform* rightPoleBase = new osg::PositionAttitudeTransform();
388 osg::PositionAttitudeTransform* rightPoleScaleNode = new osg::PositionAttitudeTransform();
389 rightPoleScaleNode->addChild(poleBase);
390 rightPoleBase->addChild(rightPoleScaleNode);
391 appBase->addChild(rightPoleBase);
392 rightPoleBase->setPosition(osg::Vec3d(pos.x(), pos.y(), pos.z()));
393 rightPoleBase->setAttitude(osg::Quat(0., osg::Vec3d(1, 0, 0),
394 0., osg::Vec3d(0, 1, 0),
395 DEG2RAD(angle), osg::Vec3d(0, 0, 1)));
396 if (onlyPedCycle) { // pedestrian / cyclist signal only
397 rightPoleScaleNode->setScale(osg::Vec3d(.12 / poleDiameter, .12 / poleDiameter, 2.8));
398 if (approach->isCrossing()) { // center VRU signal pole at crossings
399 // move pole to the other side of the road
400 osg::Vec3d offset(cos(DEG2RAD(angle)), sin(DEG2RAD(angle)), 0.);
401 appBase->setPosition(appBase->getPosition() + offset * (poleOffset + approach->getLength()));
402 appBase->setAttitude(osg::Quat(0., osg::Vec3d(1, 0, 0),
403 0., osg::Vec3d(0, 1, 0),
404 DEG2RAD(angle + 180), osg::Vec3d(0, 0, 1)));
405 } else if (approach->isWalkingArea()) { // pole for other direction > get position from crossing
406 pos = tlLink->getLane()->getShape().back();
407 angle = 90. - tlLink->getLane()->getShape().rotationDegreeAtOffset(-1.);
408 rightPoleBase->setPosition(osg::Vec3d(pos.x(), pos.y(), pos.z()) - osg::Vec3d(poleOffset * cos(DEG2RAD(angle)), poleOffset * sin(DEG2RAD(angle)), 0.));
409 rightPoleBase->setAttitude(osg::Quat(0., osg::Vec3d(1, 0, 0),
410 0., osg::Vec3d(0, 1, 0),
411 DEG2RAD(angle), osg::Vec3d(0, 0, 1)));
412 if (tlLink->getLane()->getLinkCont()[0]->getTLIndex() < 0) { // check whether the other side is not specified explicitly
413 osg::PositionAttitudeTransform* leftPoleBase = new osg::PositionAttitudeTransform();
414 osg::PositionAttitudeTransform* leftPoleScaleNode = new osg::PositionAttitudeTransform();
415 appBase->addChild(leftPoleBase);
416 leftPoleScaleNode->addChild(poleBase);
417 leftPoleScaleNode->setScale(osg::Vec3d(.12 / poleDiameter, .12 / poleDiameter, 2.8));
418 leftPoleBase->addChild(leftPoleScaleNode);
419 double otherAngle = 90. - tlLink->getLane()->getShape().rotationDegreeAtOffset(1.);
420 Position otherPosRel = tlLink->getLane()->getShape().front();
421 osg::Vec3d leftPolePos(otherPosRel.x(), otherPosRel.y(), otherPosRel.z());
422 leftPoleBase->setPosition(leftPolePos + osg::Vec3d(poleOffset * cos(DEG2RAD(otherAngle)), poleOffset * sin(DEG2RAD(otherAngle)), 0.));
423 leftPoleBase->setAttitude(osg::Quat(0., osg::Vec3d(1., 0., 0.),
424 0., osg::Vec3d(0., 1., 0.),
425 DEG2RAD(angle + 180.), osg::Vec3d(0., 0., 1.)));
426 repeaters.push_back({ leftPoleBase, osg::Vec3d(0., 0., leftPoleBase->getPosition().z())});
427 }
428 } else {
429 double laneWidth = appLanes[0]->getWidth();
430 osg::Vec3d offset(-poleOffset * cos(DEG2RAD(angle)) - (.5 * laneWidth - skipWidth + poleOffset) * sin(DEG2RAD(angle)), poleOffset * sin(DEG2RAD(angle)) + (.5 * laneWidth - skipWidth + poleOffset) * cos(DEG2RAD(angle)), 0.);
431 rightPoleBase->setPosition(rightPoleBase->getPosition() + offset);
432 }
433 } else {
434 // skip sidewalk and bike lane if leftmost lane is for cars
435 if (!noVehicles(appLanes.back()->getPermissions())) {
436 for (MSLane* appLane : appLanes) {
437 SVCPermissions permissions = appLane->getPermissions();
438 if (isSidewalk(permissions) || isForbidden(permissions)) {
439 skipWidth += appLane->getWidth();
440 } else {
441 break;
442 }
443 firstSignalLaneIx++;
444 }
445 }
446 const double laneWidth = appLanes[0]->getWidth();
447 const double horizontalWidth = approach->getWidth() - skipWidth;
448 const int laneCount = (int)appLanes.size() - firstSignalLaneIx;
449 osg::Vec3d offset(-poleOffset * cos(DEG2RAD(angle)) - (.5 * laneWidth - skipWidth + poleOffset) * sin(DEG2RAD(angle)), -poleOffset * sin(DEG2RAD(angle)) + (.5 * laneWidth - skipWidth + poleOffset) * cos(DEG2RAD(angle)), 0.);
450 rightPoleBase->setPosition(rightPoleBase->getPosition() + offset);
451
452 if (laneCount < 3) { // cantilever
453 const double cantiWidth = horizontalWidth - .1 * appLanes.back()->getWidth() + poleOffset;
454 const double holderWidth = cantiWidth - .4 * appLanes.back()->getWidth();
455 const double holderAngle = 7.5; // degrees
456 const double extraHeight = sin(DEG2RAD(holderAngle)) * holderWidth;
457 rightPoleScaleNode->setScale(osg::Vec3d(.25 / poleDiameter, .25 / poleDiameter, poleMinHeight + extraHeight));
458 osg::PositionAttitudeTransform* cantileverBase = new osg::PositionAttitudeTransform();
459 cantileverBase->setPosition(osg::Vec3d(0., 0., poleMinHeight));
460 cantileverBase->setAttitude(osg::Quat(DEG2RAD(90.), osg::Vec3d(1, 0, 0),
461 0., osg::Vec3d(0, 1, 0),
462 0., osg::Vec3d(0, 0, 1)));
463 cantileverBase->setScale(osg::Vec3d(1., 1., cantiWidth));
464 cantileverBase->addChild(poleBase);
465 rightPoleBase->addChild(cantileverBase);
466 osg::PositionAttitudeTransform* cantileverHolderBase = new osg::PositionAttitudeTransform();
467 cantileverHolderBase->setPosition(osg::Vec3d(0., 0., poleMinHeight + extraHeight - .02));
468 cantileverHolderBase->setAttitude(osg::Quat(DEG2RAD(90. + holderAngle), osg::Vec3d(1, 0, 0),
469 0., osg::Vec3d(0, 1, 0),
470 0., osg::Vec3d(0, 0, 1)));
471 cantileverHolderBase->setScale(osg::Vec3d(.04 / poleDiameter, .04 / poleDiameter, sqrt(pow(holderWidth, 2.) + pow(extraHeight, 2.))));
472 cantileverHolderBase->addChild(poleBase);
473 rightPoleBase->addChild(cantileverHolderBase);
474 } else { // signal bridge
475 rightPoleScaleNode->setScale(osg::Vec3d(.25 / poleDiameter, .25 / poleDiameter, poleMinHeight));
476 osg::PositionAttitudeTransform* leftPoleBase = new osg::PositionAttitudeTransform();
477 leftPoleBase->addChild(poleBase);
478 leftPoleBase->setScale(osg::Vec3d(.25 / poleDiameter, .25 / poleDiameter, poleMinHeight));
479 osg::Vec3d leftPolePos = osg::Vec3d(0, -(horizontalWidth + 2. * poleOffset), 0.);
480 leftPoleBase->setPosition(leftPolePos);
481 rightPoleBase->addChild(leftPoleBase);
482 osg::PositionAttitudeTransform* bridgeBase = new osg::PositionAttitudeTransform();
483 bridgeBase->setPosition(osg::Vec3d(0., 0., poleMinHeight - .125));
484 bridgeBase->setAttitude(osg::Quat(DEG2RAD(90.), osg::Vec3d(1, 0, 0),
485 0., osg::Vec3d(0, 1, 0),
486 0., osg::Vec3d(0, 0, 1)));
487 bridgeBase->setScale(osg::Vec3d(.25 / poleDiameter, .25 / poleDiameter, leftPolePos.length()));
488 bridgeBase->addChild(poleBase);
489 rightPoleBase->addChild(bridgeBase);
490 }
491 }
492 seenEdges.insert(approach);
493
494 // Add signals and position them along the cantilever/bridge
495 double refPos = poleOffset /*- skipWidth*/;
496 std::vector<MSLane*>::const_iterator it = appLanes.begin();
497 for (std::advance(it, firstSignalLaneIx); it != appLanes.end(); it++) {
498 // get tlLinkIndices
499 const std::vector<MSLink*>& links = (*it)->getLinkCont();
500 std::set<int> tlIndices;
501 for (MSLink* link : links) {
502 if (link->getTLIndex() > -1) {
503 tlIndices.insert(link->getTLIndex());
504 }
505 }
506 std::set<int> seenTlIndices;
507 bool placeRepeaters = true;
508 for (MSLink* link : links) {
509 std::vector<std::pair<osg::Group*, osg::Vec3d>> signalTransforms = { {rightPoleBase, osg::Vec3d(0., 0., 0.)} };
510 if (placeRepeaters) {
511 signalTransforms.insert(signalTransforms.end(), repeaters.begin(), repeaters.end());
512 repeaters.clear();
513 placeRepeaters = false;
514 }
515 int tlIndex = link->getTLIndex();
516 if (tlIndex < 0 || seenTlIndices.find(tlIndex) != seenTlIndices.end()) {
517 continue;
518 }
519 for (const std::pair<osg::Group*, osg::Vec3d>& transform : signalTransforms) {
521 d.centerX = transform.second.x() + 0.15;
522 d.centerY = (onlyPedCycle) ? 0. : -(refPos + .5 * (*it)->getWidth() - ((double)tlIndices.size() / 2. - 1. + (double)seenTlIndices.size()) * 1.5 * tlWidth);
523 d.centerY += transform.second.y();
524 d.centerZ = (onlyPedCycle) ? 2.2 : 3.8;
525 d.centerZ += transform.second.z();
526 d.altitude = (onlyPedCycle) ? 0.6 : -1;
527 osg::PositionAttitudeTransform* tlNode = getTrafficLight(d, vars, links[0], tlg, tly, tlr, tlu, poleBase, false);
528 tlNode->setAttitude(osg::Quat(0., osg::Vec3d(1, 0, 0),
529 0., osg::Vec3d(0, 1, 0),
530 DEG2RAD(180.0), osg::Vec3d(0, 0, 1)));
531 transform.first->addChild(tlNode);
532 }
533 seenTlIndices.insert(tlIndex);
534 }
535 // only one signal for bike/pedestrian only edges
536 if (onlyPedCycle) {
537 break;
538 }
539 refPos += (*it)->getWidth();
540 }
541 // interaction
542 appBase->setNodeMask(GUIOSGView::NODESET_TLSMODELS);
543 appBase->setName("tlLogic:" + tlLogic->getID());
544 addTo.addChild(appBase);
545 }
546 }
547}
548
549
550void
551GUIOSGBuilder::buildDecal(const GUISUMOAbstractView::Decal& d, osg::Group& addTo) {
552 osg::Node* pLoadedModel = osgDB::readNodeFile(d.filename);
553 osg::PositionAttitudeTransform* base = new osg::PositionAttitudeTransform();
554 double zOffset = 0.;
555 if (pLoadedModel == nullptr) {
556 // check for 2D image
557 osg::Image* pImage = osgDB::readImageFile(d.filename);
558 if (pImage == nullptr) {
559 base = nullptr;
560 WRITE_ERRORF(TL("Could not load '%'."), d.filename);
561 return;
562 }
563 osg::Texture2D* texture = new osg::Texture2D();
564 texture->setImage(pImage);
565 osg::Geometry* quad = osg::createTexturedQuadGeometry(osg::Vec3d(-0.5 * d.width, -0.5 * d.height, 0.), osg::Vec3d(d.width, 0., 0.), osg::Vec3d(0., d.height, 0.));
566 quad->getOrCreateStateSet()->setTextureAttributeAndModes(0, texture);
567 osg::Geode* const pModel = new osg::Geode();
568 pModel->addDrawable(quad);
569 base->addChild(pModel);
570 zOffset = d.layer;
571 } else {
572 osg::ShadeModel* sm = new osg::ShadeModel();
573 sm->setMode(osg::ShadeModel::FLAT);
574 pLoadedModel->getOrCreateStateSet()->setAttribute(sm);
575 base->addChild(pLoadedModel);
576 }
577 osg::ComputeBoundsVisitor bboxCalc;
578 base->accept(bboxCalc);
579 const osg::BoundingBox& bbox = bboxCalc.getBoundingBox();
580 WRITE_MESSAGEF(TL("Loaded decal '%' with bounding box % %."), d.filename, toString(Position(bbox.xMin(), bbox.yMin(), bbox.zMin())), toString(Position(bbox.xMax(), bbox.yMax(), bbox.zMax())));
581 double xScale = d.width > 0 ? d.width / (bbox.xMax() - bbox.xMin()) : 1.;
582 double yScale = d.height > 0 ? d.height / (bbox.yMax() - bbox.yMin()) : 1.;
583 const double zScale = d.altitude > 0 ? d.altitude / (bbox.zMax() - bbox.zMin()) : 1.;
584 if (d.width < 0 && d.height < 0 && d.altitude > 0) {
585 xScale = yScale = zScale;
586 }
587 base->setScale(osg::Vec3d(xScale, yScale, zScale));
588 base->setPosition(osg::Vec3d(d.centerX, d.centerY, d.centerZ + zOffset));
589 base->setAttitude(osg::Quat(osg::DegreesToRadians(d.roll), osg::Vec3d(1, 0, 0),
590 osg::DegreesToRadians(d.tilt), osg::Vec3d(0, 1, 0),
591 osg::DegreesToRadians(d.rot), osg::Vec3d(0, 0, 1)));
592 addTo.addChild(base);
593}
594
595
596osg::PositionAttitudeTransform*
597GUIOSGBuilder::getTrafficLight(const GUISUMOAbstractView::Decal& d, MSTLLogicControl::TLSLogicVariants& vars, const MSLink* link, osg::Node* const tlg, osg::Node* const tly, osg::Node* const tlr, osg::Node* const tlu, osg::Node* const pole, const bool withPole, const double size, double poleHeight, double transparency) {
598 osg::PositionAttitudeTransform* ret = new osg::PositionAttitudeTransform();
599 double xScale = 1., yScale = 1., zScale = 1.;
600 if (tlg != nullptr) {
601 osg::ComputeBoundsVisitor bboxCalc;
602 tlg->accept(bboxCalc);
603 const osg::BoundingBox& bbox = bboxCalc.getBoundingBox();
604 xScale = d.width > 0 ? d.width / (bbox.xMax() - bbox.xMin()) : 1.;
605 yScale = d.height > 0 ? d.height / (bbox.yMax() - bbox.yMin()) : 1.;
606 double addHeight = (withPole) ? poleHeight : 0.;
607 zScale = d.altitude > 0 ? d.altitude / (addHeight + bbox.zMax() - bbox.zMin()) : 1.;
608 }
609 if (d.width < 0 && d.height < 0 && d.altitude > 0) {
610 xScale = yScale = zScale;
611 }
612 osg::PositionAttitudeTransform* base = new osg::PositionAttitudeTransform();
613 osg::Switch* switchNode = new osg::Switch();
614 switchNode->addChild(createTrafficLightState(d, tlg, withPole, size, osg::Vec4d(0., 1., 0., transparency)));
615 switchNode->addChild(createTrafficLightState(d, tly, withPole, size, osg::Vec4d(1., 1., 0., transparency)));
616 switchNode->addChild(createTrafficLightState(d, tlr, withPole, size, osg::Vec4d(1., 0., 0., transparency)));
617 switchNode->addChild(createTrafficLightState(d, tlu, withPole, size, osg::Vec4d(1., .5, 0., transparency)));
618 base->addChild(switchNode);
619 vars.addSwitchCommand(new GUIOSGView::Command_TLSChange(link, switchNode));
620 if (withPole) {
621 base->setPosition(osg::Vec3d(0., 0., poleHeight));
622 osg::PositionAttitudeTransform* poleBase = new osg::PositionAttitudeTransform();
623 poleBase->addChild(pole);
624 poleBase->setScale(osg::Vec3d(1., 1., poleHeight));
625 ret->addChild(poleBase);
626 }
627 ret->setAttitude(osg::Quat(osg::DegreesToRadians(d.roll), osg::Vec3(1, 0, 0),
628 osg::DegreesToRadians(d.tilt), osg::Vec3(0, 1, 0),
629 osg::DegreesToRadians(d.rot), osg::Vec3(0, 0, 1)));
630 ret->setPosition(osg::Vec3d(d.centerX, d.centerY, d.centerZ));
631 ret->setScale(osg::Vec3d(xScale, yScale, zScale));
632 ret->addChild(base);
633 return ret;
634}
635
636
637osg::PositionAttitudeTransform*
638GUIOSGBuilder::createTrafficLightState(const GUISUMOAbstractView::Decal& d, osg::Node* tl, const double withPole, const double size, osg::Vec4d color) {
639 osg::PositionAttitudeTransform* ret = new osg::PositionAttitudeTransform();
640 if (tl != nullptr) {
641 ret->addChild(tl);
642 }
643 if (size > 0.) {
644 unsigned int nodeMask = (withPole) ? GUIOSGView::NodeSetGroup::NODESET_TLSDOMES : GUIOSGView::NodeSetGroup::NODESET_TLSLINKMARKERS;
645 osg::Geode* geode = new osg::Geode();
646 osg::Vec3d center = osg::Vec3d(0., 0., (withPole) ? -1.8 : 0.);
647 osg::ShapeDrawable* shape = new osg::ShapeDrawable(new osg::Sphere(center, (float)size));
648 geode->addDrawable(shape);
649 osg::ref_ptr<osg::StateSet> ss = shape->getOrCreateStateSet();
650 ss->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
651 ss->setMode(GL_BLEND, osg::StateAttribute::OVERRIDE | osg::StateAttribute::PROTECTED | osg::StateAttribute::ON);
652 shape->setColor(color);
653 osg::PositionAttitudeTransform* ellipse = new osg::PositionAttitudeTransform();
654 ellipse->addChild(geode);
655 ellipse->setPosition(center);
656 ellipse->setPivotPoint(center);
657 if (withPole) {
658 ellipse->setScale(osg::Vec3d(4., 4., 2.5 * d.altitude + 1.1));
659 } else {
660 ellipse->setScale(osg::Vec3d(4., 4., 1.1));
661 }
662 ellipse->setNodeMask(nodeMask);
663 ret->addChild(ellipse);
664 }
665 return ret;
666}
667
668
669void
670GUIOSGBuilder::setShapeState(osg::ref_ptr<osg::ShapeDrawable> shape) {
671 osg::ref_ptr<osg::StateSet> ss = shape->getOrCreateStateSet();
672 ss->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
673 ss->setMode(GL_BLEND, osg::StateAttribute::OVERRIDE | osg::StateAttribute::PROTECTED | osg::StateAttribute::ON);
674}
675
676
677GUIOSGView::OSGMovable
678GUIOSGBuilder::buildMovable(const MSVehicleType& type) {
679 GUIOSGView::OSGMovable m;
680 m.pos = new osg::PositionAttitudeTransform();
681 double enlarge = 0.05;
682 const std::string& osgFile = type.getOSGFile();
683 if (myCars.find(osgFile) == myCars.end()) {
684 myCars[osgFile] = osgDB::readNodeFile(osgFile);
685 if (myCars[osgFile] == 0) {
686 WRITE_ERRORF(TL("Could not load '%'. The model is replaced by a cone shape."), osgFile);
687 osg::PositionAttitudeTransform* rot = new osg::PositionAttitudeTransform();
688 rot->addChild(new osg::ShapeDrawable(new osg::Cone(osg::Vec3d(0, 0, 0), 1.0f, 1.0f)));
689 rot->setAttitude(osg::Quat(osg::DegreesToRadians(90.), osg::Vec3(1, 0, 0),
690 0., osg::Vec3(0, 1, 0),
691 0., osg::Vec3(0, 0, 1)));
692 myCars[osgFile] = rot;
693 }
694 }
695 osg::Node* carNode = myCars[osgFile];
696 if (carNode != nullptr) {
697 osg::ComputeBoundsVisitor bboxCalc;
698 carNode->accept(bboxCalc);
699 const osg::BoundingBox& bbox = bboxCalc.getBoundingBox();
700 osg::PositionAttitudeTransform* base = new osg::PositionAttitudeTransform();
701 base->addChild(carNode);
702 base->setPivotPoint(osg::Vec3d((bbox.xMin() + bbox.xMax()) / 2., bbox.yMin(), bbox.zMin()));
703 base->setScale(osg::Vec3d(type.getWidth() / (bbox.xMax() - bbox.xMin()),
704 type.getLength() / (bbox.yMax() - bbox.yMin()),
705 type.getHeight() / (bbox.zMax() - bbox.zMin())));
706 m.body = base;
707 m.pos->addChild(base);
708
709 // material for coloring the person or vehicle body
710 m.mat = new osg::Material();
711 osg::ref_ptr<osg::StateSet> ss = base->getOrCreateStateSet();
712 ss->setAttribute(m.mat, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE | osg::StateAttribute::PROTECTED);
713 ss->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
714 ss->setMode(GL_BLEND, osg::StateAttribute::OVERRIDE | osg::StateAttribute::PROTECTED | osg::StateAttribute::ON);
715 }
716 if (type.getVehicleClass() != SVC_PEDESTRIAN) {
717 m.lights = new osg::Switch();
718 for (double sideFactor = -1.; sideFactor < 2.5; sideFactor += 2.) {
719 osg::Geode* geode = new osg::Geode();
720 osg::ShapeDrawable* right = new osg::ShapeDrawable(new osg::Sphere(osg::Vec3d((type.getWidth() / 2. + enlarge)*sideFactor, 0., type.getHeight() / 2.), 0.2f));
721 geode->addDrawable(right);
722 //pat->addChild(geode);
723 setShapeState(right);
724 right->setColor(osg::Vec4(1.f, .5f, 0.f, .8f));
725 osg::Sequence* seq = new osg::Sequence();
726 // Wikipedia says about 1.5Hz
727 seq->addChild(geode, .33);
728 seq->addChild(new osg::Geode(), .33);
729 // loop through all children
730 seq->setInterval(osg::Sequence::LOOP, 0, -1);
731 // real-time playback, repeat indefinitely
732 seq->setDuration(1.0f, -1);
733 // must be started explicitly
734 seq->setMode(osg::Sequence::START);
735 m.lights->addChild(seq);
736 }
737 osg::Geode* geode = new osg::Geode();
738 osg::CompositeShape* comp = new osg::CompositeShape();
739 comp->addChild(new osg::Sphere(osg::Vec3d(-(type.getWidth() / 2. + enlarge), type.getLength() + enlarge, type.getHeight() / 2.), .2f));
740 comp->addChild(new osg::Sphere(osg::Vec3d(type.getWidth() / 2. + enlarge, type.getLength() + enlarge, type.getHeight() / 2.), .2f));
741 osg::ShapeDrawable* brake = new osg::ShapeDrawable(comp);
742 brake->setColor(osg::Vec4(1.f, 0.f, 0.f, .8f));
743 geode->addDrawable(brake);
744 setShapeState(brake);
745 m.lights->addChild(geode);
746
747 osg::Vec3d center(0, -type.getLength() / 2., 0.);
748 osg::PositionAttitudeTransform* ellipse = new osg::PositionAttitudeTransform();
749 ellipse->addChild(geode);
750 ellipse->addChild(m.lights);
751 ellipse->setPivotPoint(center);
752 ellipse->setPosition(center);
753 m.pos->addChild(ellipse);
754 }
755 m.active = true;
756 return m;
757}
758
759
760osg::Node*
761GUIOSGBuilder::buildPlane(const float length) {
762 osg::Geode* geode = new osg::Geode();
763 osg::Geometry* geom = new osg::Geometry;
764 geode->addDrawable(geom);
765 osg::Vec3Array* coords = new osg::Vec3Array(4); // OSG needs float coordinates here
766 geom->setVertexArray(coords);
767 (*coords)[0].set(.5f * length, .5f * length, -0.1f);
768 (*coords)[1].set(.5f * length, -.5f * length, -0.1f);
769 (*coords)[2].set(-.5f * length, -.5f * length, -0.1f);
770 (*coords)[3].set(-.5f * length, .5f * length, -0.1f);
771 osg::Vec3Array* normals = new osg::Vec3Array(1); // OSG needs float coordinates here
772 (*normals)[0].set(0, 0, 1);
773 geom->setNormalArray(normals, osg::Array::BIND_PER_PRIMITIVE_SET);
774 osg::Vec4ubArray* colors = new osg::Vec4ubArray(1);
775 (*colors)[0].set(0, 255, 0, 255);
776 geom->setColorArray(colors, osg::Array::BIND_OVERALL);
777 geom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::POLYGON, 0, 4));
778
779 osg::ref_ptr<osg::StateSet> ss = geode->getOrCreateStateSet();
780 ss->setRenderingHint(osg::StateSet::OPAQUE_BIN);
781 ss->setMode(GL_BLEND, osg::StateAttribute::OVERRIDE | osg::StateAttribute::PROTECTED | osg::StateAttribute::ON);
782
783 return geode;
784}
785
786
787#endif
788
789/****************************************************************************/
#define DEG2RAD(x)
Definition GeomHelper.h:35
#define WRITE_MESSAGEF(...)
Definition MsgHandler.h:290
#define WRITE_ERRORF(...)
Definition MsgHandler.h:297
#define TL(string)
Definition MsgHandler.h:305
bool isForbidden(SVCPermissions permissions)
Returns whether an edge with the given permissions is a forbidden edge.
bool isSidewalk(SVCPermissions permissions)
Returns whether an edge with the given permissions is a sidewalk.
bool noVehicles(SVCPermissions permissions)
Returns whether an edge with the given permissions forbids vehicles.
bool isBikepath(SVCPermissions permissions)
Returns whether an edge with the given permissions is a bicycle edge.
long long int SVCPermissions
bitset where each bit declares whether a certain SVC may use this edge/lane
@ SVC_PEDESTRIAN
pedestrian
T MIN2(T a, T b)
Definition StdDefs.h:76
std::string toString(const T &t, std::streamsize accuracy=gPrecision)
Definition ToString.h:46
const std::string & getMicrosimID() const
Returns the id of the object as known to microsim.
const MSJunction & getJunction() const
Returns the represented junction.
Representation of a lane in the micro simulation (gui-version)
Definition GUILane.h:60
A MSNet extended by some values for usage within the gui.
Definition GUINet.h:82
std::vector< GUIJunctionWrapper * > myJunctionWrapper
Wrapped MS-junctions.
Definition GUINet.h:387
A road/street connecting two junctions.
Definition MSEdge.h:77
bool isCrossing() const
return whether this edge is a pedestrian crossing
Definition MSEdge.h:273
SVCPermissions getPermissions() const
Returns the combined permissions of all lanes of this edge.
Definition MSEdge.h:649
bool isWalkingArea() const
return whether this edge is walking area
Definition MSEdge.h:287
const std::vector< MSLane * > & getLanes() const
Returns this edge's lanes.
Definition MSEdge.h:168
double getLength() const
return the length of the edge
Definition MSEdge.h:685
double getWidth() const
Returns the edges's width (sum over all lanes)
Definition MSEdge.h:656
const PositionVector & getShape() const
Returns this junction's shape.
Definition MSJunction.h:91
Representation of a lane in the micro simulation.
Definition MSLane.h:84
SVCPermissions getPermissions() const
Returns the vehicle class permissions for this lane.
Definition MSLane.h:619
virtual const PositionVector & getShape(bool) const
Definition MSLane.h:294
double getWidth() const
Returns the lane's width.
Definition MSLane.h:640
static MSNet * getInstance()
Returns the pointer to the unique instance of MSNet (singleton).
Definition MSNet.cpp:186
MSTLLogicControl & getTLSControl()
Returns the tls logics control.
Definition MSNet.h:457
Storage for all programs of a single tls.
void addSwitchCommand(OnSwitchAction *c)
MSTrafficLightLogic * getActive() const
std::vector< std::string > getAllTLIds() const
TLSLogicVariants & get(const std::string &id) const
Returns the variants of a named tls.
The parent class for traffic light logics.
const LinkVectorVector & getLinks() const
Returns the list of lists of all affected links.
std::vector< LaneVector > LaneVectorVector
Definition of a list that holds lists of lanes that do have the same attribute.
const LaneVectorVector & getLaneVectors() const
Returns the list of lists of all lanes controlled by this tls.
const LinkVector & getLinksAt(int i) const
Returns the list of links that are controlled by the signals at the given position.
std::vector< LinkVector > LinkVectorVector
Definition of a list that holds lists of links that do have the same attribute.
std::vector< MSLink * > LinkVector
Definition of the list of links that are subjected to this tls.
The car-following model and parameter.
double getWidth() const
Get the width which vehicles of this class shall have when being drawn.
SUMOVehicleClass getVehicleClass() const
Get this vehicle type's vehicle class.
std::string getOSGFile() const
Get this vehicle type's 3D model file name.
double getHeight() const
Get the height which vehicles of this class shall have when being drawn.
double getLength() const
Get vehicle's length [m].
const std::string & getID() const
Returns the id.
Definition Named.h:74
A point-of-interest.
Position getCenter() const
Returns the image center of the POI.
double getHeight() const
Returns the image height of the POI.
double getWidth() const
Returns the image width of the POI.
A point in 2D or 3D with translation and scaling methods.
Definition Position.h:37
double x() const
Returns the x-position.
Definition Position.h:52
double z() const
Returns the z-position.
Definition Position.h:62
double y() const
Returns the y-position.
Definition Position.h:57
A list of positions.
double rotationDegreeAtOffset(double pos) const
Returns the rotation at the given length.
void move2side(double amount, double maxExtension=100)
move position vector to side using certain amount
unsigned char red() const
Returns the red-amount of the color.
Definition RGBColor.cpp:74
unsigned char green() const
Returns the green-amount of the color.
Definition RGBColor.cpp:80
unsigned char blue() const
Returns the blue-amount of the color.
Definition RGBColor.cpp:86
void set(unsigned char r, unsigned char g, unsigned char b, unsigned char a)
assigns new values
Definition RGBColor.cpp:98
const PositionVector & getShape() const
Returns the shape of the polygon.
const std::vector< PositionVector > & getHoles() const
Returns the holers of the polygon.
const RGBColor & getShapeColor() const
Returns the color of the Shape.
Definition Shape.h:82
A decal (an image) that can be shown.
double tilt
The tilt of the image to the ground plane (in degrees)
double centerX
The center of the image in x-direction (net coordinates, in m)
double height
The height of the image (net coordinates in y-direction, in m)
double width
The width of the image (net coordinates in x-direction, in m)
double rot
The rotation of the image in the ground plane (in degrees)
double layer
The layer of the image.
double altitude
The altitude of the image (net coordinates in z-direction, in m)
double centerY
The center of the image in y-direction (net coordinates, in m)
double centerZ
The center of the image in z-direction (net coordinates, in m)
std::string filename
The path to the file the image is located at.
double roll
The roll of the image to the ground plane (in degrees)