Eclipse SUMO - Simulation of Urban MObility
Loading...
Searching...
No Matches
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 useZ = shape.hasElevation();
279 //const bool isFilled = poly.getFill();
280 //const double lineWidth = poly.getLineWidth();
281
282 osg::Geode* geode = new osg::Geode();
283 osg::Geometry* geom = new osg::Geometry();
284 geode->addDrawable(geom);
285 geode->setName("polygon:" + poly.getID());
286 addTo.addChild(geode);
287 osg::Vec3Array* osg_coords = new osg::Vec3Array((int)shape.size()); // OSG needs float coordinates here
288 geom->setVertexArray(osg_coords);
289 for (int k = 0; k < (int)shape.size(); ++k) {
290 (*osg_coords)[k].set((float)shape[k].x(), (float)shape[k].y(), (useZ)? (float)shape[k].z() : 0.1f);
291 }
292 // TODO: how to draw holes? Don't worry for the moment, just don't
293 if (holes.size() > 0) {
294 }
295
296 osg::Vec3Array* osg_normals = new osg::Vec3Array(1);
297 (*osg_normals)[0] = osg::Vec3(0, 0, 1); // OSG needs float coordinates here
298 geom->setNormalArray(osg_normals, osg::Array::BIND_PER_PRIMITIVE_SET);
299 osg::Vec4ubArray* osg_colors = new osg::Vec4ubArray(1);
300 const RGBColor col = poly.getShapeColor();
301 (*osg_colors)[0].set(col.red(), col.green(), col.blue(), 255);
302 geom->setColorArray(osg_colors, osg::Array::BIND_OVERALL);
303 geom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::POLYGON, 0, (int)shape.size()));
304
305 osg::ref_ptr<osg::StateSet> ss = geode->getOrCreateStateSet();
306 ss->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
307 ss->setMode(GL_BLEND, osg::StateAttribute::OVERRIDE | osg::StateAttribute::PROTECTED | osg::StateAttribute::ON);
308
309 if (shape.size() > 4) {
310 tessellator.retessellatePolygons(*geom);
311 }
312}
313
314
315void
316GUIOSGBuilder::buildPoIGeometry(const PointOfInterest& poi, osg::Group& addTo, osgUtil::Tessellator& tessellator) {
317 osg::Geode* geode = new osg::Geode();
318 osg::Geometry* geom = new osg::Geometry();
319 geode->addDrawable(geom);
320 geode->setName("poi:" + poi.getID());
321 addTo.addChild(geode);
322 osg::Vec3Array* osg_coords = new osg::Vec3Array(4); // OSG needs float coordinates here
323 geom->setVertexArray(osg_coords);
324 // make a square
325 const Position& center = poi.getCenter();
326 const double width = poi.getWidth();
327 const double height = poi.getHeight();
328 PositionVector shape;
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 shape.push_back(Position(center.x() - 0.5 * width, center.y() - 0.5 * height));
333 for (unsigned int k = 0; k < shape.size(); ++k) {
334 (*osg_coords)[k].set((float)shape[k].x(), (float)shape[k].y(), 0.2f);
335 }
336 osg::Vec3Array* osg_normals = new osg::Vec3Array(1);
337 (*osg_normals)[0] = osg::Vec3(0, 0, 1); // OSG needs float coordinates here
338 geom->setNormalArray(osg_normals, osg::Array::BIND_PER_PRIMITIVE_SET);
339 osg::Vec4ubArray* osg_colors = new osg::Vec4ubArray(1);
340 const RGBColor col = poi.getShapeColor();
341 (*osg_colors)[0].set(col.red(), col.green(), col.blue(), 255);
342 geom->setColorArray(osg_colors, osg::Array::BIND_OVERALL);
343 geom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::POLYGON, 0, (int)shape.size()));
344
345 osg::ref_ptr<osg::StateSet> ss = geode->getOrCreateStateSet();
346 ss->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
347 ss->setMode(GL_BLEND, osg::StateAttribute::OVERRIDE | osg::StateAttribute::PROTECTED | osg::StateAttribute::ON);
348
349 if (shape.size() > 4) {
350 tessellator.retessellatePolygons(*geom);
351 }
352}
353
354
355void
356GUIOSGBuilder::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) {
357 // get the poleBase diameter for later repositioning
358 osg::ComputeBoundsVisitor bboxCalc;
359 poleBase->accept(bboxCalc);
360 const double poleDiameter = bboxCalc.getBoundingBox().yMax() - bboxCalc.getBoundingBox().yMin();
361 tlg->accept(bboxCalc);
362 const double tlWidth = bboxCalc.getBoundingBox().yMax() - bboxCalc.getBoundingBox().yMin();
363
364 // loop through lanes, collect edges, skip ped and bike infra for the time being
365 MSTrafficLightLogic* tlLogic = vars.getActive();
366 const MSTrafficLightLogic::LinkVectorVector& allLinks = tlLogic->getLinks();
367 std::set<const MSEdge*> seenEdges;
368
369 for (const MSTrafficLightLogic::LinkVector& lv : allLinks) {
370 for (const MSLink* tlLink : lv) {
371 // if not in seenEdges, create pole and reference it in the maps above
372 const MSEdge* approach = &tlLink->getLaneBefore()->getEdge();
373 if (!approach->isWalkingArea() && seenEdges.find(approach) != seenEdges.end()) {
374 continue;
375 }
376 const std::vector<MSLane*> appLanes = approach->getLanes();
377 // ref pos
378 const double poleMinHeight = 5.;
379 const double poleOffset = .5;
380 double angle = 90. - appLanes[0]->getShape().rotationDegreeAtOffset(-1.);
381 bool onlyPedCycle = isBikepath(approach->getPermissions()) || isSidewalk(approach->getPermissions());
382 Position pos = appLanes[0]->getShape().back();
383 double skipWidth = 0.;
384 int firstSignalLaneIx = 0;
385 std::vector<std::pair<osg::Group*, osg::Vec3d>> repeaters;
386 // start with local coordinate system
387 osg::PositionAttitudeTransform* appBase = new osg::PositionAttitudeTransform();
388 osg::PositionAttitudeTransform* rightPoleBase = new osg::PositionAttitudeTransform();
389 osg::PositionAttitudeTransform* rightPoleScaleNode = new osg::PositionAttitudeTransform();
390 rightPoleScaleNode->addChild(poleBase);
391 rightPoleBase->addChild(rightPoleScaleNode);
392 appBase->addChild(rightPoleBase);
393 rightPoleBase->setPosition(osg::Vec3d(pos.x(), pos.y(), pos.z()));
394 rightPoleBase->setAttitude(osg::Quat(0., osg::Vec3d(1, 0, 0),
395 0., osg::Vec3d(0, 1, 0),
396 DEG2RAD(angle), osg::Vec3d(0, 0, 1)));
397 if (onlyPedCycle) { // pedestrian / cyclist signal only
398 rightPoleScaleNode->setScale(osg::Vec3d(.12 / poleDiameter, .12 / poleDiameter, 2.8));
399 if (approach->isCrossing()) { // center VRU signal pole at crossings
400 // move pole to the other side of the road
401 osg::Vec3d offset(cos(DEG2RAD(angle)), sin(DEG2RAD(angle)), 0.);
402 appBase->setPosition(appBase->getPosition() + offset * (poleOffset + approach->getLength()));
403 appBase->setAttitude(osg::Quat(0., osg::Vec3d(1, 0, 0),
404 0., osg::Vec3d(0, 1, 0),
405 DEG2RAD(angle + 180), osg::Vec3d(0, 0, 1)));
406 } else if (approach->isWalkingArea()) { // pole for other direction > get position from crossing
407 pos = tlLink->getLane()->getShape().back();
408 angle = 90. - tlLink->getLane()->getShape().rotationDegreeAtOffset(-1.);
409 rightPoleBase->setPosition(osg::Vec3d(pos.x(), pos.y(), pos.z()) - osg::Vec3d(poleOffset * cos(DEG2RAD(angle)), poleOffset * sin(DEG2RAD(angle)), 0.));
410 rightPoleBase->setAttitude(osg::Quat(0., osg::Vec3d(1, 0, 0),
411 0., osg::Vec3d(0, 1, 0),
412 DEG2RAD(angle), osg::Vec3d(0, 0, 1)));
413 if (tlLink->getLane()->getLinkCont()[0]->getTLIndex() < 0) { // check whether the other side is not specified explicitly
414 osg::PositionAttitudeTransform* leftPoleBase = new osg::PositionAttitudeTransform();
415 osg::PositionAttitudeTransform* leftPoleScaleNode = new osg::PositionAttitudeTransform();
416 appBase->addChild(leftPoleBase);
417 leftPoleScaleNode->addChild(poleBase);
418 leftPoleScaleNode->setScale(osg::Vec3d(.12 / poleDiameter, .12 / poleDiameter, 2.8));
419 leftPoleBase->addChild(leftPoleScaleNode);
420 double otherAngle = 90. - tlLink->getLane()->getShape().rotationDegreeAtOffset(1.);
421 Position otherPosRel = tlLink->getLane()->getShape().front();
422 osg::Vec3d leftPolePos(otherPosRel.x(), otherPosRel.y(), otherPosRel.z());
423 leftPoleBase->setPosition(leftPolePos + osg::Vec3d(poleOffset * cos(DEG2RAD(otherAngle)), poleOffset * sin(DEG2RAD(otherAngle)), 0.));
424 leftPoleBase->setAttitude(osg::Quat(0., osg::Vec3d(1., 0., 0.),
425 0., osg::Vec3d(0., 1., 0.),
426 DEG2RAD(angle + 180.), osg::Vec3d(0., 0., 1.)));
427 repeaters.push_back({ leftPoleBase, osg::Vec3d(0., 0., leftPoleBase->getPosition().z())});
428 }
429 } else {
430 double laneWidth = appLanes[0]->getWidth();
431 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.);
432 rightPoleBase->setPosition(rightPoleBase->getPosition() + offset);
433 }
434 } else {
435 // skip sidewalk and bike lane if leftmost lane is for cars
436 if (!noVehicles(appLanes.back()->getPermissions())) {
437 for (MSLane* appLane : appLanes) {
438 SVCPermissions permissions = appLane->getPermissions();
439 if (isSidewalk(permissions) || isForbidden(permissions)) {
440 skipWidth += appLane->getWidth();
441 } else {
442 break;
443 }
444 firstSignalLaneIx++;
445 }
446 }
447 const double laneWidth = appLanes[0]->getWidth();
448 const double horizontalWidth = approach->getWidth() - skipWidth;
449 const int laneCount = (int)appLanes.size() - firstSignalLaneIx;
450 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.);
451 rightPoleBase->setPosition(rightPoleBase->getPosition() + offset);
452
453 if (laneCount < 3) { // cantilever
454 const double cantiWidth = horizontalWidth - .1 * appLanes.back()->getWidth() + poleOffset;
455 const double holderWidth = cantiWidth - .4 * appLanes.back()->getWidth();
456 const double holderAngle = 7.5; // degrees
457 const double extraHeight = sin(DEG2RAD(holderAngle)) * holderWidth;
458 rightPoleScaleNode->setScale(osg::Vec3d(.25 / poleDiameter, .25 / poleDiameter, poleMinHeight + extraHeight));
459 osg::PositionAttitudeTransform* cantileverBase = new osg::PositionAttitudeTransform();
460 cantileverBase->setPosition(osg::Vec3d(0., 0., poleMinHeight));
461 cantileverBase->setAttitude(osg::Quat(DEG2RAD(90.), osg::Vec3d(1, 0, 0),
462 0., osg::Vec3d(0, 1, 0),
463 0., osg::Vec3d(0, 0, 1)));
464 cantileverBase->setScale(osg::Vec3d(1., 1., cantiWidth));
465 cantileverBase->addChild(poleBase);
466 rightPoleBase->addChild(cantileverBase);
467 osg::PositionAttitudeTransform* cantileverHolderBase = new osg::PositionAttitudeTransform();
468 cantileverHolderBase->setPosition(osg::Vec3d(0., 0., poleMinHeight + extraHeight - .02));
469 cantileverHolderBase->setAttitude(osg::Quat(DEG2RAD(90. + holderAngle), osg::Vec3d(1, 0, 0),
470 0., osg::Vec3d(0, 1, 0),
471 0., osg::Vec3d(0, 0, 1)));
472 cantileverHolderBase->setScale(osg::Vec3d(.04 / poleDiameter, .04 / poleDiameter, sqrt(pow(holderWidth, 2.) + pow(extraHeight, 2.))));
473 cantileverHolderBase->addChild(poleBase);
474 rightPoleBase->addChild(cantileverHolderBase);
475 } else { // signal bridge
476 rightPoleScaleNode->setScale(osg::Vec3d(.25 / poleDiameter, .25 / poleDiameter, poleMinHeight));
477 osg::PositionAttitudeTransform* leftPoleBase = new osg::PositionAttitudeTransform();
478 leftPoleBase->addChild(poleBase);
479 leftPoleBase->setScale(osg::Vec3d(.25 / poleDiameter, .25 / poleDiameter, poleMinHeight));
480 osg::Vec3d leftPolePos = osg::Vec3d(0, -(horizontalWidth + 2. * poleOffset), 0.);
481 leftPoleBase->setPosition(leftPolePos);
482 rightPoleBase->addChild(leftPoleBase);
483 osg::PositionAttitudeTransform* bridgeBase = new osg::PositionAttitudeTransform();
484 bridgeBase->setPosition(osg::Vec3d(0., 0., poleMinHeight - .125));
485 bridgeBase->setAttitude(osg::Quat(DEG2RAD(90.), osg::Vec3d(1, 0, 0),
486 0., osg::Vec3d(0, 1, 0),
487 0., osg::Vec3d(0, 0, 1)));
488 bridgeBase->setScale(osg::Vec3d(.25 / poleDiameter, .25 / poleDiameter, leftPolePos.length()));
489 bridgeBase->addChild(poleBase);
490 rightPoleBase->addChild(bridgeBase);
491 }
492 }
493 seenEdges.insert(approach);
494
495 // Add signals and position them along the cantilever/bridge
496 double refPos = poleOffset /*- skipWidth*/;
497 std::vector<MSLane*>::const_iterator it = appLanes.begin();
498 for (std::advance(it, firstSignalLaneIx); it != appLanes.end(); it++) {
499 // get tlLinkIndices
500 const std::vector<MSLink*>& links = (*it)->getLinkCont();
501 std::set<int> tlIndices;
502 for (MSLink* link : links) {
503 if (link->getTLIndex() > -1) {
504 tlIndices.insert(link->getTLIndex());
505 }
506 }
507 std::set<int> seenTlIndices;
508 bool placeRepeaters = true;
509 for (MSLink* link : links) {
510 std::vector<std::pair<osg::Group*, osg::Vec3d>> signalTransforms = { {rightPoleBase, osg::Vec3d(0., 0., 0.)} };
511 if (placeRepeaters) {
512 signalTransforms.insert(signalTransforms.end(), repeaters.begin(), repeaters.end());
513 repeaters.clear();
514 placeRepeaters = false;
515 }
516 int tlIndex = link->getTLIndex();
517 if (tlIndex < 0 || seenTlIndices.find(tlIndex) != seenTlIndices.end()) {
518 continue;
519 }
520 for (const std::pair<osg::Group*, osg::Vec3d>& transform : signalTransforms) {
522 d.centerX = transform.second.x() + 0.15;
523 d.centerY = (onlyPedCycle) ? 0. : -(refPos + .5 * (*it)->getWidth() - ((double)tlIndices.size() / 2. - 1. + (double)seenTlIndices.size()) * 1.5 * tlWidth);
524 d.centerY += transform.second.y();
525 d.centerZ = (onlyPedCycle) ? 2.2 : 3.8;
526 d.centerZ += transform.second.z();
527 d.altitude = (onlyPedCycle) ? 0.6 : -1;
528 osg::PositionAttitudeTransform* tlNode = getTrafficLight(d, vars, links[0], tlg, tly, tlr, tlu, poleBase, false);
529 tlNode->setAttitude(osg::Quat(0., osg::Vec3d(1, 0, 0),
530 0., osg::Vec3d(0, 1, 0),
531 DEG2RAD(180.0), osg::Vec3d(0, 0, 1)));
532 transform.first->addChild(tlNode);
533 }
534 seenTlIndices.insert(tlIndex);
535 }
536 // only one signal for bike/pedestrian only edges
537 if (onlyPedCycle) {
538 break;
539 }
540 refPos += (*it)->getWidth();
541 }
542 // interaction
543 appBase->setNodeMask(GUIOSGView::NODESET_TLSMODELS);
544 appBase->setName("tlLogic:" + tlLogic->getID());
545 addTo.addChild(appBase);
546 }
547 }
548}
549
550
551void
552GUIOSGBuilder::buildDecal(const GUISUMOAbstractView::Decal& d, osg::Group& addTo) {
553 osg::Node* pLoadedModel = osgDB::readNodeFile(d.filename);
554 osg::PositionAttitudeTransform* base = new osg::PositionAttitudeTransform();
555 double zOffset = 0.;
556 if (pLoadedModel == nullptr) {
557 // check for 2D image
558 osg::Image* pImage = osgDB::readImageFile(d.filename);
559 if (pImage == nullptr) {
560 base = nullptr;
561 WRITE_ERRORF(TL("Could not load '%'."), d.filename);
562 return;
563 }
564 osg::Texture2D* texture = new osg::Texture2D();
565 texture->setImage(pImage);
566 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.));
567 quad->getOrCreateStateSet()->setTextureAttributeAndModes(0, texture);
568 osg::Geode* const pModel = new osg::Geode();
569 pModel->addDrawable(quad);
570 base->addChild(pModel);
571 zOffset = d.layer;
572 } else {
573 osg::ShadeModel* sm = new osg::ShadeModel();
574 sm->setMode(osg::ShadeModel::FLAT);
575 pLoadedModel->getOrCreateStateSet()->setAttribute(sm);
576 base->addChild(pLoadedModel);
577 }
578 osg::ComputeBoundsVisitor bboxCalc;
579 base->accept(bboxCalc);
580 const osg::BoundingBox& bbox = bboxCalc.getBoundingBox();
581 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())));
582 double xScale = d.width > 0 ? d.width / (bbox.xMax() - bbox.xMin()) : 1.;
583 double yScale = d.height > 0 ? d.height / (bbox.yMax() - bbox.yMin()) : 1.;
584 const double zScale = d.altitude > 0 ? d.altitude / (bbox.zMax() - bbox.zMin()) : 1.;
585 if (d.width < 0 && d.height < 0 && d.altitude > 0) {
586 xScale = yScale = zScale;
587 }
588 base->setScale(osg::Vec3d(xScale, yScale, zScale));
589 base->setPosition(osg::Vec3d(d.centerX, d.centerY, d.centerZ + zOffset));
590 base->setAttitude(osg::Quat(osg::DegreesToRadians(d.roll), osg::Vec3d(1, 0, 0),
591 osg::DegreesToRadians(d.tilt), osg::Vec3d(0, 1, 0),
592 osg::DegreesToRadians(d.rot), osg::Vec3d(0, 0, 1)));
593 addTo.addChild(base);
594}
595
596
597osg::PositionAttitudeTransform*
598GUIOSGBuilder::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) {
599 osg::PositionAttitudeTransform* ret = new osg::PositionAttitudeTransform();
600 double xScale = 1., yScale = 1., zScale = 1.;
601 if (tlg != nullptr) {
602 osg::ComputeBoundsVisitor bboxCalc;
603 tlg->accept(bboxCalc);
604 const osg::BoundingBox& bbox = bboxCalc.getBoundingBox();
605 xScale = d.width > 0 ? d.width / (bbox.xMax() - bbox.xMin()) : 1.;
606 yScale = d.height > 0 ? d.height / (bbox.yMax() - bbox.yMin()) : 1.;
607 double addHeight = (withPole) ? poleHeight : 0.;
608 zScale = d.altitude > 0 ? d.altitude / (addHeight + bbox.zMax() - bbox.zMin()) : 1.;
609 }
610 if (d.width < 0 && d.height < 0 && d.altitude > 0) {
611 xScale = yScale = zScale;
612 }
613 osg::PositionAttitudeTransform* base = new osg::PositionAttitudeTransform();
614 osg::Switch* switchNode = new osg::Switch();
615 switchNode->addChild(createTrafficLightState(d, tlg, withPole, size, osg::Vec4d(0., 1., 0., transparency)));
616 switchNode->addChild(createTrafficLightState(d, tly, withPole, size, osg::Vec4d(1., 1., 0., transparency)));
617 switchNode->addChild(createTrafficLightState(d, tlr, withPole, size, osg::Vec4d(1., 0., 0., transparency)));
618 switchNode->addChild(createTrafficLightState(d, tlu, withPole, size, osg::Vec4d(1., .5, 0., transparency)));
619 base->addChild(switchNode);
620 vars.addSwitchCommand(new GUIOSGView::Command_TLSChange(link, switchNode));
621 if (withPole) {
622 base->setPosition(osg::Vec3d(0., 0., poleHeight));
623 osg::PositionAttitudeTransform* poleBase = new osg::PositionAttitudeTransform();
624 poleBase->addChild(pole);
625 poleBase->setScale(osg::Vec3d(1., 1., poleHeight));
626 ret->addChild(poleBase);
627 }
628 ret->setAttitude(osg::Quat(osg::DegreesToRadians(d.roll), osg::Vec3(1, 0, 0),
629 osg::DegreesToRadians(d.tilt), osg::Vec3(0, 1, 0),
630 osg::DegreesToRadians(d.rot), osg::Vec3(0, 0, 1)));
631 ret->setPosition(osg::Vec3d(d.centerX, d.centerY, d.centerZ));
632 ret->setScale(osg::Vec3d(xScale, yScale, zScale));
633 ret->addChild(base);
634 return ret;
635}
636
637
638osg::PositionAttitudeTransform*
639GUIOSGBuilder::createTrafficLightState(const GUISUMOAbstractView::Decal& d, osg::Node* tl, const double withPole, const double size, osg::Vec4d color) {
640 osg::PositionAttitudeTransform* ret = new osg::PositionAttitudeTransform();
641 if (tl != nullptr) {
642 ret->addChild(tl);
643 }
644 if (size > 0.) {
645 unsigned int nodeMask = (withPole) ? GUIOSGView::NodeSetGroup::NODESET_TLSDOMES : GUIOSGView::NodeSetGroup::NODESET_TLSLINKMARKERS;
646 osg::Geode* geode = new osg::Geode();
647 osg::Vec3d center = osg::Vec3d(0., 0., (withPole) ? -1.8 : 0.);
648 osg::ShapeDrawable* shape = new osg::ShapeDrawable(new osg::Sphere(center, (float)size));
649 geode->addDrawable(shape);
650 osg::ref_ptr<osg::StateSet> ss = shape->getOrCreateStateSet();
651 ss->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
652 ss->setMode(GL_BLEND, osg::StateAttribute::OVERRIDE | osg::StateAttribute::PROTECTED | osg::StateAttribute::ON);
653 shape->setColor(color);
654 osg::PositionAttitudeTransform* ellipse = new osg::PositionAttitudeTransform();
655 ellipse->addChild(geode);
656 ellipse->setPosition(center);
657 ellipse->setPivotPoint(center);
658 if (withPole) {
659 ellipse->setScale(osg::Vec3d(4., 4., 2.5 * d.altitude + 1.1));
660 } else {
661 ellipse->setScale(osg::Vec3d(4., 4., 1.1));
662 }
663 ellipse->setNodeMask(nodeMask);
664 ret->addChild(ellipse);
665 }
666 return ret;
667}
668
669
670void
671GUIOSGBuilder::setShapeState(osg::ref_ptr<osg::ShapeDrawable> shape) {
672 osg::ref_ptr<osg::StateSet> ss = shape->getOrCreateStateSet();
673 ss->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
674 ss->setMode(GL_BLEND, osg::StateAttribute::OVERRIDE | osg::StateAttribute::PROTECTED | osg::StateAttribute::ON);
675}
676
677
678GUIOSGView::OSGMovable
679GUIOSGBuilder::buildMovable(const MSVehicleType& type) {
680 GUIOSGView::OSGMovable m;
681 m.pos = new osg::PositionAttitudeTransform();
682 double enlarge = 0.05;
683 const std::string& osgFile = type.getOSGFile();
684 if (myCars.find(osgFile) == myCars.end()) {
685 myCars[osgFile] = osgDB::readNodeFile(osgFile);
686 if (myCars[osgFile] == 0) {
687 WRITE_ERRORF(TL("Could not load '%'. The model is replaced by a cone shape."), osgFile);
688 osg::PositionAttitudeTransform* rot = new osg::PositionAttitudeTransform();
689 rot->addChild(new osg::ShapeDrawable(new osg::Cone(osg::Vec3d(0, 0, 0), 1.0f, 1.0f)));
690 rot->setAttitude(osg::Quat(osg::DegreesToRadians(90.), osg::Vec3(1, 0, 0),
691 0., osg::Vec3(0, 1, 0),
692 0., osg::Vec3(0, 0, 1)));
693 myCars[osgFile] = rot;
694 }
695 }
696 osg::Node* carNode = myCars[osgFile];
697 if (carNode != nullptr) {
698 osg::ComputeBoundsVisitor bboxCalc;
699 carNode->accept(bboxCalc);
700 const osg::BoundingBox& bbox = bboxCalc.getBoundingBox();
701 osg::PositionAttitudeTransform* base = new osg::PositionAttitudeTransform();
702 base->addChild(carNode);
703 base->setPivotPoint(osg::Vec3d((bbox.xMin() + bbox.xMax()) / 2., bbox.yMin(), bbox.zMin()));
704 base->setScale(osg::Vec3d(type.getWidth() / (bbox.xMax() - bbox.xMin()),
705 type.getLength() / (bbox.yMax() - bbox.yMin()),
706 type.getHeight() / (bbox.zMax() - bbox.zMin())));
707 m.body = base;
708 m.pos->addChild(base);
709
710 // material for coloring the person or vehicle body
711 m.mat = new osg::Material();
712 osg::ref_ptr<osg::StateSet> ss = base->getOrCreateStateSet();
713 ss->setAttribute(m.mat, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE | osg::StateAttribute::PROTECTED);
714 ss->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
715 ss->setMode(GL_BLEND, osg::StateAttribute::OVERRIDE | osg::StateAttribute::PROTECTED | osg::StateAttribute::ON);
716 }
717 if (type.getVehicleClass() != SVC_PEDESTRIAN) {
718 m.lights = new osg::Switch();
719 for (double sideFactor = -1.; sideFactor < 2.5; sideFactor += 2.) {
720 osg::Geode* geode = new osg::Geode();
721 osg::ShapeDrawable* right = new osg::ShapeDrawable(new osg::Sphere(osg::Vec3d((type.getWidth() / 2. + enlarge)*sideFactor, 0., type.getHeight() / 2.), 0.2f));
722 geode->addDrawable(right);
723 //pat->addChild(geode);
724 setShapeState(right);
725 right->setColor(osg::Vec4(1.f, .5f, 0.f, .8f));
726 osg::Sequence* seq = new osg::Sequence();
727 // Wikipedia says about 1.5Hz
728 seq->addChild(geode, .33);
729 seq->addChild(new osg::Geode(), .33);
730 // loop through all children
731 seq->setInterval(osg::Sequence::LOOP, 0, -1);
732 // real-time playback, repeat indefinitely
733 seq->setDuration(1.0f, -1);
734 // must be started explicitly
735 seq->setMode(osg::Sequence::START);
736 m.lights->addChild(seq);
737 }
738 osg::Geode* geode = new osg::Geode();
739 osg::CompositeShape* comp = new osg::CompositeShape();
740 comp->addChild(new osg::Sphere(osg::Vec3d(-(type.getWidth() / 2. + enlarge), type.getLength() + enlarge, type.getHeight() / 2.), .2f));
741 comp->addChild(new osg::Sphere(osg::Vec3d(type.getWidth() / 2. + enlarge, type.getLength() + enlarge, type.getHeight() / 2.), .2f));
742 osg::ShapeDrawable* brake = new osg::ShapeDrawable(comp);
743 brake->setColor(osg::Vec4(1.f, 0.f, 0.f, .8f));
744 geode->addDrawable(brake);
745 setShapeState(brake);
746 m.lights->addChild(geode);
747
748 osg::Vec3d center(0, -type.getLength() / 2., 0.);
749 osg::PositionAttitudeTransform* ellipse = new osg::PositionAttitudeTransform();
750 ellipse->addChild(geode);
751 ellipse->addChild(m.lights);
752 ellipse->setPivotPoint(center);
753 ellipse->setPosition(center);
754 m.pos->addChild(ellipse);
755 }
756 m.active = true;
757 return m;
758}
759
760
761osg::Node*
762GUIOSGBuilder::buildPlane(const float length) {
763 osg::Geode* geode = new osg::Geode();
764 osg::Geometry* geom = new osg::Geometry;
765 geode->addDrawable(geom);
766 osg::Vec3Array* coords = new osg::Vec3Array(4); // OSG needs float coordinates here
767 geom->setVertexArray(coords);
768 (*coords)[0].set(.5f * length, .5f * length, -0.1f);
769 (*coords)[1].set(.5f * length, -.5f * length, -0.1f);
770 (*coords)[2].set(-.5f * length, -.5f * length, -0.1f);
771 (*coords)[3].set(-.5f * length, .5f * length, -0.1f);
772 osg::Vec3Array* normals = new osg::Vec3Array(1); // OSG needs float coordinates here
773 (*normals)[0].set(0, 0, 1);
774 geom->setNormalArray(normals, osg::Array::BIND_PER_PRIMITIVE_SET);
775 osg::Vec4ubArray* colors = new osg::Vec4ubArray(1);
776 (*colors)[0].set(0, 255, 0, 255);
777 geom->setColorArray(colors, osg::Array::BIND_OVERALL);
778 geom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::POLYGON, 0, 4));
779
780 osg::ref_ptr<osg::StateSet> ss = geode->getOrCreateStateSet();
781 ss->setRenderingHint(osg::StateSet::OPAQUE_BIN);
782 ss->setMode(GL_BLEND, osg::StateAttribute::OVERRIDE | osg::StateAttribute::PROTECTED | osg::StateAttribute::ON);
783
784 return geode;
785}
786
787
788#endif
789
790/****************************************************************************/
#define DEG2RAD(x)
Definition GeomHelper.h:35
#define WRITE_MESSAGEF(...)
Definition MsgHandler.h:289
#define WRITE_ERRORF(...)
Definition MsgHandler.h:296
#define TL(string)
Definition MsgHandler.h:304
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:80
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:389
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:657
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:693
double getWidth() const
Returns the edges's width (sum over all lanes)
Definition MSEdge.h:664
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:465
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
bool hasElevation() const
return whether two positions differ in z-coordinate
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.cpp:109
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)