Eclipse 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-2022 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>
43
44#include "GUIOSGView.h"
45#include "GUIOSGBuilder.h"
46
47//#define DEBUG_TESSEL
48
49// ===========================================================================
50// static member variables
51// ===========================================================================
52
53std::map<std::string, osg::ref_ptr<osg::Node> > GUIOSGBuilder::myCars;
54
55// ===========================================================================
56// member method definitions
57// ===========================================================================
58
59osg::Group*
60GUIOSGBuilder::buildOSGScene(osg::Node* const tlg, osg::Node* const tly, osg::Node* const tlr, osg::Node* const tlu, osg::Node* const pole) {
61 osgUtil::Tessellator tesselator;
62 osg::Group* root = new osg::Group();
63 GUINet* net = static_cast<GUINet*>(MSNet::getInstance());
64 // build edges
65 for (const MSEdge* e : net->getEdgeControl().getEdges()) {
66 if (!e->isInternal()) {
67 buildOSGEdgeGeometry(*e, *root, tesselator);
68 }
69 }
70 // build junctions
71 for (int index = 0; index < (int)net->myJunctionWrapper.size(); ++index) {
72 buildOSGJunctionGeometry(*net->myJunctionWrapper[index], *root, tesselator);
73 }
74 // build traffic lights
76 const std::vector<std::string> tlids = net->getTLSControl().getAllTLIds();
77 for (std::vector<std::string>::const_iterator i = tlids.begin(); i != tlids.end(); ++i) {
79 buildTrafficLightDetails(vars, tlg, tly, tlr, tlu, pole, *root);
80
82 const MSLane* lastLane = 0;
83 int idx = 0;
84 for (MSTrafficLightLogic::LaneVectorVector::const_iterator j = lanes.begin(); j != lanes.end(); ++j, ++idx) {
85 if ((*j).size() == 0) {
86 continue;
87 }
88 const MSLane* const lane = (*j)[0];
89 const Position pos = lane->getShape().back();
90 const double angle = osg::DegreesToRadians(lane->getShape().rotationDegreeAtOffset(-1.) + 90.);
91 d.centerZ = pos.z() + 4.;
92 if (lane == lastLane) {
93 d.centerX += 1.2 * sin(angle);
94 d.centerY += 1.2 * cos(angle);
95 } else {
96 d.centerX = pos.x() - 1.5 * sin(angle);
97 d.centerY = pos.y() - 1.5 * cos(angle);
98 }
99 osg::PositionAttitudeTransform* tlNode = getTrafficLight(d, vars, vars.getActive()->getLinksAt(idx)[0], nullptr, nullptr, nullptr, nullptr, nullptr, false, .25, -1, 1.);
100 tlNode->setName("tlLogic:" + *i);
101 root->addChild(tlNode);
102 lastLane = lane;
103 }
104 }
105 return root;
106}
107
108
109void
110GUIOSGBuilder::buildLight(const GUISUMOAbstractView::Decal& d, osg::Group& addTo) {
111 // each light must have a unique number
112 osg::Light* light = new osg::Light(d.filename[5] - '0');
113 // we set the light's position via a PositionAttitudeTransform object
114 light->setPosition(osg::Vec4(0.0, 0.0, 0.0, 1.0));
115 light->setDiffuse(osg::Vec4(1.0, 1.0, 1.0, 1.0));
116 light->setSpecular(osg::Vec4(1.0, 1.0, 1.0, 1.0));
117 light->setAmbient(osg::Vec4(1.0, 1.0, 1.0, 1.0));
118
119 osg::LightSource* lightSource = new osg::LightSource();
120 lightSource->setLight(light);
121 lightSource->setLocalStateSetModes(osg::StateAttribute::ON);
122 lightSource->setStateSetModes(*addTo.getOrCreateStateSet(), osg::StateAttribute::ON);
123
124 osg::PositionAttitudeTransform* lightTransform = new osg::PositionAttitudeTransform();
125 lightTransform->addChild(lightSource);
126 lightTransform->setPosition(osg::Vec3d(d.centerX, d.centerY, d.centerZ));
127 lightTransform->setScale(osg::Vec3d(0.1, 0.1, 0.1));
128 addTo.addChild(lightTransform);
129}
130
131
132void
133GUIOSGBuilder::buildOSGEdgeGeometry(const MSEdge& edge,
134 osg::Group& addTo,
135 osgUtil::Tessellator& tessellator) {
136 const std::vector<MSLane*>& lanes = edge.getLanes();
137 for (std::vector<MSLane*>::const_iterator j = lanes.begin(); j != lanes.end(); ++j) {
138 MSLane* l = (*j);
139 const bool extrude = edge.isWalkingArea() || isSidewalk(l->getPermissions());
140 const int geomFactor = (edge.isWalkingArea()) ? 1 : 2;
141 const PositionVector& shape = l->getShape();
142 const int originalSize = (int)shape.size();
143 osg::Geode* geode = new osg::Geode();
144 osg::Geometry* geom = new osg::Geometry();
145 geode->addDrawable(geom);
146 geode->setName("lane:" + l->getID());
147 addTo.addChild(geode);
148 dynamic_cast<GUIGlObject*>(l)->setNode(geode);
149 const int upperShapeSize = originalSize * geomFactor;
150 const int totalShapeSize = (extrude) ? originalSize * 2 * geomFactor : originalSize * geomFactor;
151 const float zOffset = (extrude) ? (edge.isCrossing()) ? 0.01f : 0.1f : 0.f;
152 osg::Vec4ubArray* osg_colors = new osg::Vec4ubArray(1);
153 (*osg_colors)[0].set(128, 128, 128, 255);
154 geom->setColorArray(osg_colors, osg::Array::BIND_OVERALL);
155 osg::Vec3Array* osg_coords = new osg::Vec3Array(totalShapeSize);
156 geom->setVertexArray(osg_coords);
157 int sizeDiff = 0;
158 if (edge.isWalkingArea()) {
159 int index = upperShapeSize - 1;
160 for (int k = 0; k < upperShapeSize; ++k, --index) {
161 (*osg_coords)[index].set((float)shape[k].x(), (float)shape[k].y(), (float)shape[k].z() + zOffset);
162 }
163 geom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::POLYGON, 0, upperShapeSize));
164 } else {
165 int index = 0;
166 PositionVector rshape = shape;
167 rshape.move2side(l->getWidth() / 2);
168 for (int k = (int)rshape.size() - 1; k >= 0; --k, ++index) {
169 (*osg_coords)[index].set((float)rshape[k].x(), (float)rshape[k].y(), (float)rshape[k].z() + zOffset);
170 }
171 PositionVector lshape = shape;
172 lshape.move2side(-l->getWidth() / 2);
173 for (int k = 0; k < (int)lshape.size(); ++k, ++index) {
174 (*osg_coords)[index].set((float)lshape[k].x(), (float)lshape[k].y(), (float)lshape[k].z() + zOffset);
175 }
176 sizeDiff = (int)rshape.size() + (int)lshape.size() - upperShapeSize;
177 int minSize = MIN2((int)rshape.size(), (int)lshape.size());
178 osg::DrawElementsUInt* surface = new osg::DrawElementsUInt(osg::PrimitiveSet::TRIANGLE_STRIP, 0);
179 for (int i = 0; i < minSize; ++i) {
180 surface->push_back(i);
181 surface->push_back(upperShapeSize + sizeDiff - 1 - i);
182 }
183 geom->addPrimitiveSet(surface);
184 }
185 if (extrude) {
186 int index = upperShapeSize;
187 for (int k = 0; k < upperShapeSize + sizeDiff; ++k, ++index) {
188 (*osg_coords)[index].set((*osg_coords)[k].x(), (*osg_coords)[k].y(), 0.);
189 }
190 // extrude edge to create the kerb
191 for (int i = 0; i < upperShapeSize + sizeDiff; ++i) {
192 osg::Vec3 surfaceVec = (*osg_coords)[i] - (*osg_coords)[(i + 1) % (upperShapeSize + sizeDiff)];
193 if (surfaceVec.length() > 0.) {
194 osg::DrawElementsUInt* kerb = new osg::DrawElementsUInt(osg::PrimitiveSet::POLYGON, 0);
195 kerb->push_back(i);
196 kerb->push_back(upperShapeSize + i);
197 kerb->push_back(upperShapeSize + (i + 1) % (upperShapeSize + sizeDiff));
198 kerb->push_back((i + 1) % (upperShapeSize + sizeDiff));
199 geom->addPrimitiveSet(kerb);
200 }
201 }
202 }
203
204 osg::ref_ptr<osg::StateSet> ss = geode->getOrCreateStateSet();
205 ss->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
206 ss->setMode(GL_BLEND, osg::StateAttribute::OVERRIDE | osg::StateAttribute::PROTECTED | osg::StateAttribute::ON);
207
208
209
210 if (shape.size() > 2) {
211 tessellator.retessellatePolygons(*geom);
212
213#ifdef DEBUG_TESSEL
214 std::cout << "l=" << l->getID() << " origPoints=" << shape.size() << " geomSize=" << geom->getVertexArray()->getNumElements() << " points=";
215 for (int i = 0; i < (int)geom->getVertexArray()->getNumElements(); i++) {
216 const osg::Vec3& p = (*((osg::Vec3Array*)geom->getVertexArray()))[i];
217 std::cout << p.x() << "," << p.y() << "," << p.z() << " ";
218 }
219 std::cout << "\n";
220#endif
221 }
222 osgUtil::SmoothingVisitor sv;
223#if OSG_MIN_VERSION_REQUIRED(3,5,4)
224 sv.setCreaseAngle(0.6 * osg::PI);
225#endif
226 geom->accept(sv);
227 static_cast<GUILane*>(l)->setGeometry(geom);
228 }
229}
230
231
232void
233GUIOSGBuilder::buildOSGJunctionGeometry(GUIJunctionWrapper& junction,
234 osg::Group& addTo,
235 osgUtil::Tessellator& tessellator) {
236 const PositionVector& shape = junction.getJunction().getShape();
237 osg::Geode* geode = new osg::Geode();
238 osg::Geometry* geom = new osg::Geometry();
239 geode->addDrawable(geom);
240 geode->setName("junction:" + junction.getMicrosimID());
241 addTo.addChild(geode);
242 dynamic_cast<GUIGlObject&>(junction).setNode(geode);
243 osg::Vec3Array* osg_coords = new osg::Vec3Array((int)shape.size());
244 geom->setVertexArray(osg_coords);
245 for (int k = 0; k < (int)shape.size(); ++k) {
246 (*osg_coords)[k].set((float)shape[k].x(), (float)shape[k].y(), (float)shape[k].z());
247 }
248 osg::Vec3Array* osg_normals = new osg::Vec3Array(1);
249 (*osg_normals)[0] = osg::Vec3(0, 0, 1);
250 geom->setNormalArray(osg_normals, osg::Array::BIND_PER_PRIMITIVE_SET);
251 osg::Vec4ubArray* osg_colors = new osg::Vec4ubArray(1);
252 (*osg_colors)[0].set(128, 128, 128, 255);
253 geom->setColorArray(osg_colors, osg::Array::BIND_OVERALL);
254 geom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::POLYGON, 0, (int)shape.size()));
255
256 osg::ref_ptr<osg::StateSet> ss = geode->getOrCreateStateSet();
257 ss->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
258 ss->setMode(GL_BLEND, osg::StateAttribute::OVERRIDE | osg::StateAttribute::PROTECTED | osg::StateAttribute::ON);
259
260 if (shape.size() > 4) {
261 tessellator.retessellatePolygons(*geom);
262 }
263 junction.setGeometry(geom);
264}
265
266
267void
268GUIOSGBuilder::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) {
269 // get the poleBase diameter for later repositioning
270 osg::ComputeBoundsVisitor bboxCalc;
271 poleBase->accept(bboxCalc);
272 const double poleDiameter = bboxCalc.getBoundingBox().yMax() - bboxCalc.getBoundingBox().yMin();
273 tlg->accept(bboxCalc);
274 const double tlWidth = bboxCalc.getBoundingBox().yMax() - bboxCalc.getBoundingBox().yMin();
275
276 // loop through lanes, collect edges, skip ped and bike infra for the time being
277 MSTrafficLightLogic* tlLogic = vars.getActive();
278 const MSTrafficLightLogic::LinkVectorVector& allLinks = tlLogic->getLinks();
279 std::set<const MSEdge*> seenEdges;
280
281 for (const MSTrafficLightLogic::LinkVector& lv : allLinks) {
282 for (const MSLink* tlLink : lv) {
283 // if not in seenEdges, create pole and reference it in the maps above
284 const MSEdge* approach = &tlLink->getLaneBefore()->getEdge();
285 if (!approach->isWalkingArea() && seenEdges.find(approach) != seenEdges.end()) {
286 continue;
287 }
288 const std::vector<MSLane*> appLanes = approach->getLanes();
289 // ref pos
290 const double poleMinHeight = 5.;
291 const double poleOffset = .5;
292 double angle = 90. - appLanes[0]->getShape().rotationDegreeAtOffset(-1.);
293 bool onlyPedCycle = isBikepath(approach->getPermissions()) || isSidewalk(approach->getPermissions());
294 Position pos = appLanes[0]->getShape().back();
295 double skipWidth = 0.;
296 int firstSignalLaneIx = 0;
297 std::vector<std::pair<osg::Group*, osg::Vec3d>> repeaters;
298 // start with local coordinate system
299 osg::PositionAttitudeTransform* appBase = new osg::PositionAttitudeTransform();
300 osg::PositionAttitudeTransform* rightPoleBase = new osg::PositionAttitudeTransform();
301 osg::PositionAttitudeTransform* rightPoleScaleNode = new osg::PositionAttitudeTransform();
302 rightPoleScaleNode->addChild(poleBase);
303 rightPoleBase->addChild(rightPoleScaleNode);
304 appBase->addChild(rightPoleBase);
305 rightPoleBase->setPosition(osg::Vec3d(pos.x(), pos.y(), pos.z()));
306 rightPoleBase->setAttitude(osg::Quat(0., osg::Vec3d(1, 0, 0),
307 0., osg::Vec3d(0, 1, 0),
308 DEG2RAD(angle), osg::Vec3d(0, 0, 1)));
309 if (onlyPedCycle) { // pedestrian / cyclist signal only
310 rightPoleScaleNode->setScale(osg::Vec3d(.12 / poleDiameter, .12 / poleDiameter, 2.8));
311 if (approach->isCrossing()) { // center VRU signal pole at crossings
312 // move pole to the other side of the road
313 osg::Vec3d offset(cos(DEG2RAD(angle)), sin(DEG2RAD(angle)), 0.);
314 appBase->setPosition(appBase->getPosition() + offset * (poleOffset + approach->getLength()));
315 appBase->setAttitude(osg::Quat(0., osg::Vec3d(1, 0, 0),
316 0., osg::Vec3d(0, 1, 0),
317 DEG2RAD(angle + 180), osg::Vec3d(0, 0, 1)));
318 } else if (approach->isWalkingArea()) { // pole for other direction > get position from crossing
319 pos = tlLink->getLane()->getShape().back();
320 angle = 90. - tlLink->getLane()->getShape().rotationDegreeAtOffset(-1.);
321 rightPoleBase->setPosition(osg::Vec3d(pos.x(), pos.y(), pos.z()) - osg::Vec3d(poleOffset * cos(DEG2RAD(angle)), poleOffset * sin(DEG2RAD(angle)), 0.));
322 rightPoleBase->setAttitude(osg::Quat(0., osg::Vec3d(1, 0, 0),
323 0., osg::Vec3d(0, 1, 0),
324 DEG2RAD(angle), osg::Vec3d(0, 0, 1)));
325 if (tlLink->getLane()->getLinkCont()[0]->getTLIndex() < 0) { // check whether the other side is not specified explicitly
326 osg::PositionAttitudeTransform* leftPoleBase = new osg::PositionAttitudeTransform();
327 osg::PositionAttitudeTransform* leftPoleScaleNode = new osg::PositionAttitudeTransform();
328 appBase->addChild(leftPoleBase);
329 leftPoleScaleNode->addChild(poleBase);
330 leftPoleScaleNode->setScale(osg::Vec3d(.12 / poleDiameter, .12 / poleDiameter, 2.8));
331 leftPoleBase->addChild(leftPoleScaleNode);
332 double otherAngle = 90. - tlLink->getLane()->getShape().rotationDegreeAtOffset(1.);
333 Position otherPosRel = tlLink->getLane()->getShape().front();
334 osg::Vec3d leftPolePos(otherPosRel.x(), otherPosRel.y(), otherPosRel.z());
335 leftPoleBase->setPosition(leftPolePos + osg::Vec3d(poleOffset * cos(DEG2RAD(otherAngle)), poleOffset * sin(DEG2RAD(otherAngle)), 0.));
336 leftPoleBase->setAttitude(osg::Quat(0., osg::Vec3d(1., 0., 0.),
337 0., osg::Vec3d(0., 1., 0.),
338 DEG2RAD(angle + 180.), osg::Vec3d(0., 0., 1.)));
339 repeaters.push_back({ leftPoleBase, osg::Vec3d(0., 0., leftPoleBase->getPosition().z())});
340 }
341 } else {
342 double laneWidth = appLanes[0]->getWidth();
343 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.);
344 rightPoleBase->setPosition(rightPoleBase->getPosition() + offset);
345 }
346 } else {
347 // skip sidewalk and bike lane if leftmost lane is for cars
348 if (!noVehicles(appLanes.back()->getPermissions())) {
349 for (MSLane* appLane : appLanes) {
350 SVCPermissions permissions = appLane->getPermissions();
351 if (isSidewalk(permissions) || isForbidden(permissions)) {
352 skipWidth += appLane->getWidth();
353 } else {
354 break;
355 }
356 firstSignalLaneIx++;
357 }
358 }
359 const double laneWidth = appLanes[0]->getWidth();
360 const double horizontalWidth = approach->getWidth() - skipWidth;
361 const int laneCount = (int)appLanes.size() - firstSignalLaneIx;
362 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.);
363 rightPoleBase->setPosition(rightPoleBase->getPosition() + offset);
364
365 if (laneCount < 3) { // cantilever
366 const double cantiWidth = horizontalWidth - .1 * appLanes.back()->getWidth() + poleOffset;
367 const double holderWidth = cantiWidth - .4 * appLanes.back()->getWidth();
368 const double holderAngle = 7.5; // degrees
369 const double extraHeight = sin(DEG2RAD(holderAngle)) * holderWidth;
370 rightPoleScaleNode->setScale(osg::Vec3d(.25 / poleDiameter, .25 / poleDiameter, poleMinHeight + extraHeight));
371 osg::PositionAttitudeTransform* cantileverBase = new osg::PositionAttitudeTransform();
372 cantileverBase->setPosition(osg::Vec3d(0., 0., poleMinHeight));
373 cantileverBase->setAttitude(osg::Quat(DEG2RAD(90.), osg::Vec3d(1, 0, 0),
374 0., osg::Vec3d(0, 1, 0),
375 0., osg::Vec3d(0, 0, 1)));
376 cantileverBase->setScale(osg::Vec3d(1., 1., cantiWidth));
377 cantileverBase->addChild(poleBase);
378 rightPoleBase->addChild(cantileverBase);
379 osg::PositionAttitudeTransform* cantileverHolderBase = new osg::PositionAttitudeTransform();
380 cantileverHolderBase->setPosition(osg::Vec3d(0., 0., poleMinHeight + extraHeight - .02));
381 cantileverHolderBase->setAttitude(osg::Quat(DEG2RAD(90. + holderAngle), osg::Vec3d(1, 0, 0),
382 0., osg::Vec3d(0, 1, 0),
383 0., osg::Vec3d(0, 0, 1)));
384 cantileverHolderBase->setScale(osg::Vec3d(.04 / poleDiameter, .04 / poleDiameter, sqrt(pow(holderWidth, 2.) + pow(extraHeight, 2.))));
385 cantileverHolderBase->addChild(poleBase);
386 rightPoleBase->addChild(cantileverHolderBase);
387 } else { // signal bridge
388 rightPoleScaleNode->setScale(osg::Vec3d(.25 / poleDiameter, .25 / poleDiameter, poleMinHeight));
389 osg::PositionAttitudeTransform* leftPoleBase = new osg::PositionAttitudeTransform();
390 leftPoleBase->addChild(poleBase);
391 leftPoleBase->setScale(osg::Vec3d(.25 / poleDiameter, .25 / poleDiameter, poleMinHeight));
392 osg::Vec3d leftPolePos = osg::Vec3d(0, -(horizontalWidth + 2. * poleOffset), 0.);
393 leftPoleBase->setPosition(leftPolePos);
394 rightPoleBase->addChild(leftPoleBase);
395 osg::PositionAttitudeTransform* bridgeBase = new osg::PositionAttitudeTransform();
396 bridgeBase->setPosition(osg::Vec3d(0., 0., poleMinHeight - .125));
397 bridgeBase->setAttitude(osg::Quat(DEG2RAD(90.), osg::Vec3d(1, 0, 0),
398 0., osg::Vec3d(0, 1, 0),
399 0., osg::Vec3d(0, 0, 1)));
400 bridgeBase->setScale(osg::Vec3d(.25 / poleDiameter, .25 / poleDiameter, leftPolePos.length()));
401 bridgeBase->addChild(poleBase);
402 rightPoleBase->addChild(bridgeBase);
403 }
404 }
405 seenEdges.insert(approach);
406
407 // Add signals and position them along the cantilever/bridge
408 double refPos = poleOffset /*- skipWidth*/;
409 std::vector<MSLane*>::const_iterator it = appLanes.begin();
410 for (std::advance(it, firstSignalLaneIx); it != appLanes.end(); it++) {
411 // get tlLinkIndices
412 const std::vector<MSLink*>& links = (*it)->getLinkCont();
413 std::set<int> tlIndices;
414 for (MSLink* link : links) {
415 if (link->getTLIndex() > -1) {
416 tlIndices.insert(link->getTLIndex());
417 }
418 }
419 std::set<int> seenTlIndices;
420 bool placeRepeaters = true;
421 for (MSLink* link : links) {
422 std::vector<std::pair<osg::Group*, osg::Vec3d>> signalTransforms = { {rightPoleBase, osg::Vec3d(0., 0., 0.)} };
423 if (placeRepeaters) {
424 signalTransforms.insert(signalTransforms.end(), repeaters.begin(), repeaters.end());
425 repeaters.clear();
426 placeRepeaters = false;
427 }
428 int tlIndex = link->getTLIndex();
429 if (tlIndex < 0 || seenTlIndices.find(tlIndex) != seenTlIndices.end()) {
430 continue;
431 }
432 for (const std::pair<osg::Group*, osg::Vec3d>& transform : signalTransforms) {
434 d.centerX = transform.second.x() + 0.15;
435 d.centerY = (onlyPedCycle) ? 0. : -(refPos + .5 * (*it)->getWidth() - ((double)tlIndices.size() / 2. - 1. + (double)seenTlIndices.size()) * 1.5 * tlWidth);
436 d.centerY += transform.second.y();
437 d.centerZ = (onlyPedCycle) ? 2.2 : 3.8;
438 d.centerZ += transform.second.z();
439 d.altitude = (onlyPedCycle) ? 0.6 : -1;
440 osg::PositionAttitudeTransform* tlNode = getTrafficLight(d, vars, links[0], tlg, tly, tlr, tlu, poleBase, false);
441 tlNode->setAttitude(osg::Quat(0., osg::Vec3d(1, 0, 0),
442 0., osg::Vec3d(0, 1, 0),
443 DEG2RAD(180.0), osg::Vec3d(0, 0, 1)));
444 transform.first->addChild(tlNode);
445 }
446 seenTlIndices.insert(tlIndex);
447 }
448 // only one signal for bike/pedestrian only edges
449 if (onlyPedCycle) {
450 break;
451 }
452 refPos += (*it)->getWidth();
453 }
454 // interaction
455 appBase->setNodeMask(1 << GUIOSGView::NODESET_TLSMODELS);
456 appBase->setName("tlLogic:" + tlLogic->getID());
457 addTo.addChild(appBase);
458 }
459 }
460}
461
462
463void
464GUIOSGBuilder::buildDecal(const GUISUMOAbstractView::Decal& d, osg::Group& addTo) {
465 osg::Node* pLoadedModel = osgDB::readNodeFile(d.filename);
466 osg::PositionAttitudeTransform* base = new osg::PositionAttitudeTransform();
467 double zOffset = 0.;
468 if (pLoadedModel == nullptr) {
469 // check for 2D image
470 osg::Image* pImage = osgDB::readImageFile(d.filename);
471 if (pImage == nullptr) {
472 base = nullptr;
473 WRITE_ERROR("Could not load '" + d.filename + "'.");
474 return;
475 }
476 osg::Texture2D* texture = new osg::Texture2D();
477 texture->setImage(pImage);
478 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.));
479 quad->getOrCreateStateSet()->setTextureAttributeAndModes(0, texture);
480 osg::Geode* const pModel = new osg::Geode();
481 pModel->addDrawable(quad);
482 base->addChild(pModel);
483 zOffset = d.layer;
484 } else {
485 osg::ShadeModel* sm = new osg::ShadeModel();
486 sm->setMode(osg::ShadeModel::FLAT);
487 pLoadedModel->getOrCreateStateSet()->setAttribute(sm);
488 base->addChild(pLoadedModel);
489 }
490 osg::ComputeBoundsVisitor bboxCalc;
491 base->accept(bboxCalc);
492 const osg::BoundingBox& bbox = bboxCalc.getBoundingBox();
493 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())) + ".");
494 double xScale = d.width > 0 ? d.width / (bbox.xMax() - bbox.xMin()) : 1.;
495 double yScale = d.height > 0 ? d.height / (bbox.yMax() - bbox.yMin()) : 1.;
496 const double zScale = d.altitude > 0 ? d.altitude / (bbox.zMax() - bbox.zMin()) : 1.;
497 if (d.width < 0 && d.height < 0 && d.altitude > 0) {
498 xScale = yScale = zScale;
499 }
500 base->setScale(osg::Vec3d(xScale, yScale, zScale));
501 base->setPosition(osg::Vec3d(d.centerX, d.centerY, d.centerZ + zOffset));
502 base->setAttitude(osg::Quat(osg::DegreesToRadians(d.roll), osg::Vec3d(1, 0, 0),
503 osg::DegreesToRadians(d.tilt), osg::Vec3d(0, 1, 0),
504 osg::DegreesToRadians(d.rot), osg::Vec3d(0, 0, 1)));
505 addTo.addChild(base);
506}
507
508
509osg::PositionAttitudeTransform*
510GUIOSGBuilder::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) {
511 osg::PositionAttitudeTransform* ret = new osg::PositionAttitudeTransform();
512 double xScale = 1., yScale = 1., zScale = 1.;
513 if (tlg != nullptr) {
514 osg::ComputeBoundsVisitor bboxCalc;
515 tlg->accept(bboxCalc);
516 const osg::BoundingBox& bbox = bboxCalc.getBoundingBox();
517 xScale = d.width > 0 ? d.width / (bbox.xMax() - bbox.xMin()) : 1.;
518 yScale = d.height > 0 ? d.height / (bbox.yMax() - bbox.yMin()) : 1.;
519 double addHeight = (withPole) ? poleHeight : 0.;
520 zScale = d.altitude > 0 ? d.altitude / (addHeight + bbox.zMax() - bbox.zMin()) : 1.;
521 }
522 if (d.width < 0 && d.height < 0 && d.altitude > 0) {
523 xScale = yScale = zScale;
524 }
525 osg::PositionAttitudeTransform* base = new osg::PositionAttitudeTransform();
526 osg::Switch* switchNode = new osg::Switch();
527 switchNode->addChild(createTrafficLightState(d, tlg, withPole, size, osg::Vec4d(0., 1., 0., transparency)));
528 switchNode->addChild(createTrafficLightState(d, tly, withPole, size, osg::Vec4d(1., 1., 0., transparency)));
529 switchNode->addChild(createTrafficLightState(d, tlr, withPole, size, osg::Vec4d(1., 0., 0., transparency)));
530 switchNode->addChild(createTrafficLightState(d, tlu, withPole, size, osg::Vec4d(1., .5, 0., transparency)));
531 base->addChild(switchNode);
532 vars.addSwitchCommand(new GUIOSGView::Command_TLSChange(link, switchNode));
533 if (withPole) {
534 base->setPosition(osg::Vec3d(0., 0., poleHeight));
535 osg::PositionAttitudeTransform* poleBase = new osg::PositionAttitudeTransform();
536 poleBase->addChild(pole);
537 poleBase->setScale(osg::Vec3d(1., 1., poleHeight));
538 ret->addChild(poleBase);
539 }
540 ret->setAttitude(osg::Quat(osg::DegreesToRadians(d.roll), osg::Vec3(1, 0, 0),
541 osg::DegreesToRadians(d.tilt), osg::Vec3(0, 1, 0),
542 osg::DegreesToRadians(d.rot), osg::Vec3(0, 0, 1)));
543 ret->setPosition(osg::Vec3d(d.centerX, d.centerY, d.centerZ));
544 ret->setScale(osg::Vec3d(xScale, yScale, zScale));
545 ret->addChild(base);
546 return ret;
547}
548
549
550osg::PositionAttitudeTransform*
551GUIOSGBuilder::createTrafficLightState(const GUISUMOAbstractView::Decal& d, osg::Node* tl, const double withPole, const double size, osg::Vec4d color) {
552 osg::PositionAttitudeTransform* ret = new osg::PositionAttitudeTransform();
553 if (tl != nullptr) {
554 ret->addChild(tl);
555 }
556 if (size > 0.) {
557 unsigned int nodeMask = (withPole) ? 1 << GUIOSGView::NodeSetGroup::NODESET_TLSDOMES : 1 << GUIOSGView::NodeSetGroup::NODESET_TLSLINKMARKERS;
558 osg::Geode* geode = new osg::Geode();
559 osg::Vec3d center = osg::Vec3d(0., 0., (withPole) ? -1.8 : 0.);
560 osg::ShapeDrawable* shape = new osg::ShapeDrawable(new osg::Sphere(center, (float)size));
561 geode->addDrawable(shape);
562 osg::ref_ptr<osg::StateSet> ss = shape->getOrCreateStateSet();
563 ss->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
564 ss->setMode(GL_BLEND, osg::StateAttribute::OVERRIDE | osg::StateAttribute::PROTECTED | osg::StateAttribute::ON);
565 shape->setColor(color);
566 osg::PositionAttitudeTransform* ellipse = new osg::PositionAttitudeTransform();
567 ellipse->addChild(geode);
568 ellipse->setPosition(center);
569 ellipse->setPivotPoint(center);
570 if (withPole) {
571 ellipse->setScale(osg::Vec3d(4., 4., 2.5 * d.altitude + 1.1));
572 } else {
573 ellipse->setScale(osg::Vec3d(4., 4., 1.1));
574 }
575 ellipse->setNodeMask(nodeMask);
576 ret->addChild(ellipse);
577 }
578 return ret;
579}
580
581
582void
583GUIOSGBuilder::setShapeState(osg::ref_ptr<osg::ShapeDrawable> shape) {
584 osg::ref_ptr<osg::StateSet> ss = shape->getOrCreateStateSet();
585 ss->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
586 ss->setMode(GL_BLEND, osg::StateAttribute::OVERRIDE | osg::StateAttribute::PROTECTED | osg::StateAttribute::ON);
587}
588
589
590GUIOSGView::OSGMovable
591GUIOSGBuilder::buildMovable(const MSVehicleType& type) {
592 GUIOSGView::OSGMovable m;
593 m.pos = new osg::PositionAttitudeTransform();
594 double enlarge = 0.;
595 const std::string& osgFile = type.getOSGFile();
596 if (myCars.find(osgFile) == myCars.end()) {
597 myCars[osgFile] = osgDB::readNodeFile(osgFile);
598 if (myCars[osgFile] == 0) {
599 WRITE_ERROR("Could not load '" + osgFile + "'. The model is replaced by a cone shape.");
600 osg::PositionAttitudeTransform* rot = new osg::PositionAttitudeTransform();
601 rot->addChild(new osg::ShapeDrawable(new osg::Cone(osg::Vec3d(0, 0, 0), 1.0f, 1.0f)));
602 rot->setAttitude(osg::Quat(osg::DegreesToRadians(90.), osg::Vec3(1, 0, 0),
603 0., osg::Vec3(0, 1, 0),
604 0., osg::Vec3(0, 0, 1)));
605 myCars[osgFile] = rot;
606 }
607 }
608 osg::Node* carNode = myCars[osgFile];
609 if (carNode != nullptr) {
610 osg::ComputeBoundsVisitor bboxCalc;
611 carNode->accept(bboxCalc);
612 const osg::BoundingBox& bbox = bboxCalc.getBoundingBox();
613 osg::PositionAttitudeTransform* base = new osg::PositionAttitudeTransform();
614 base->addChild(carNode);
615 base->setPivotPoint(osg::Vec3d((bbox.xMin() + bbox.xMax()) / 2., bbox.yMin(), bbox.zMin()));
616 base->setScale(osg::Vec3d(type.getWidth() / (bbox.xMax() - bbox.xMin()),
617 type.getLength() / (bbox.yMax() - bbox.yMin()),
618 type.getHeight() / (bbox.zMax() - bbox.zMin())));
619 m.pos->addChild(base);
620 enlarge = type.getMinGap() / 2.;
621
622 // material for coloring the vehicle body
623 m.mat = new osg::Material();
624 osg::ref_ptr<osg::StateSet> ss = base->getOrCreateStateSet();
625 ss->setAttribute(m.mat, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE | osg::StateAttribute::PROTECTED);
626 ss->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
627 ss->setMode(GL_BLEND, osg::StateAttribute::OVERRIDE | osg::StateAttribute::PROTECTED | osg::StateAttribute::ON);
628 }
629 m.lights = new osg::Switch();
630 for (double offset = -0.3; offset < 0.5; offset += 0.6) {
631 osg::Geode* geode = new osg::Geode();
632 osg::ShapeDrawable* right = new osg::ShapeDrawable(new osg::Sphere(osg::Vec3d(offset, (type.getLength() - .9) / 2., (type.getHeight() - .5) / 2.), .1f));
633 geode->addDrawable(right);
634 setShapeState(right);
635 right->setColor(osg::Vec4(1.f, .5f, 0.f, .8f));
636 osg::Sequence* seq = new osg::Sequence();
637 // Wikipedia says about 1.5Hz
638 seq->addChild(geode, .33);
639 seq->addChild(new osg::Geode(), .33);
640 // loop through all children
641 seq->setInterval(osg::Sequence::LOOP, 0, -1);
642 // real-time playback, repeat indefinitely
643 seq->setDuration(1.0f, -1);
644 // must be started explicitly
645 seq->setMode(osg::Sequence::START);
646 m.lights->addChild(seq);
647 }
648
649 osg::Geode* geode = new osg::Geode();
650 osg::CompositeShape* comp = new osg::CompositeShape();
651 comp->addChild(new osg::Sphere(osg::Vec3d(-0.3, (type.getLength() + .8) / 2., (type.getHeight() - .5) / 2.), .1f));
652 comp->addChild(new osg::Sphere(osg::Vec3d(0.3, (type.getLength() + .8) / 2., (type.getHeight() - .5) / 2.), .1f));
653 osg::ShapeDrawable* brake = new osg::ShapeDrawable(comp);
654 brake->setColor(osg::Vec4(1.f, 0.f, 0.f, .8f));
655 geode->addDrawable(brake);
656 setShapeState(brake);
657 m.lights->addChild(geode);
658
659 osg::Vec3d center(0, type.getLength() / 2., type.getHeight() / 2.);
660 osg::PositionAttitudeTransform* ellipse = new osg::PositionAttitudeTransform();
661 ellipse->addChild(geode);
662 ellipse->addChild(m.lights);
663 ellipse->setPivotPoint(center);
664 ellipse->setPosition(center);
665 ellipse->setScale(osg::Vec3d(type.getWidth() + enlarge, type.getLength() + enlarge, type.getHeight() + enlarge));
666 m.pos->addChild(ellipse);
667 m.active = true;
668 return m;
669}
670
671#endif
672
673/****************************************************************************/
#define DEG2RAD(x)
Definition: GeomHelper.h:35
#define WRITE_MESSAGE(msg)
Definition: MsgHandler.h:267
#define WRITE_ERROR(msg)
Definition: MsgHandler.h:274
bool isForbidden(SVCPermissions permissions)
Returns whether an edge with the given permission is a forbidden edge.
bool isSidewalk(SVCPermissions permissions)
Returns whether an edge with the given permission is a sidewalk.
bool noVehicles(SVCPermissions permissions)
Returns whether an edge with the given permission forbids vehicles.
bool isBikepath(SVCPermissions permissions)
Returns whether an edge with the given permission is a bicycle edge.
int SVCPermissions
bitset where each bit declares whether a certain SVC may use this edge/lane
T MIN2(T a, T b)
Definition: StdDefs.h:71
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.
Definition: GUIGlObject.h:141
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:377
const MSEdgeVector & getEdges() const
Returns loaded edges.
A road/street connecting two junctions.
Definition: MSEdge.h:77
bool isCrossing() const
return whether this edge is a pedestrian crossing
Definition: MSEdge.h:270
SVCPermissions getPermissions() const
Returns the combined permissions of all lanes of this edge.
Definition: MSEdge.h:622
bool isWalkingArea() const
return whether this edge is walking area
Definition: MSEdge.h:284
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:658
double getWidth() const
Returns the edges's width (sum over all lanes)
Definition: MSEdge.h:629
const PositionVector & getShape() const
Returns this junction's shape.
Definition: MSJunction.h:88
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:583
const PositionVector & getShape() const
Returns this lane's shape.
Definition: MSLane.h:506
double getWidth() const
Returns the lane's width.
Definition: MSLane.h:590
static MSNet * getInstance()
Returns the pointer to the unique instance of MSNet (singleton).
Definition: MSNet.cpp:183
MSTLLogicControl & getTLSControl()
Returns the tls logics control.
Definition: MSNet.h:452
MSEdgeControl & getEdgeControl()
Returns the edge control.
Definition: MSNet.h:422
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.
Definition: MSVehicleType.h:63
double getWidth() const
Get the width which vehicles of this class shall have when being drawn.
std::string getOSGFile() const
Get this vehicle type's 3D model file name.
double getMinGap() const
Get the free space in front of vehicles of this class.
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 in 2D or 3D with translation and scaling methods.
Definition: Position.h:37
double x() const
Returns the x-position.
Definition: Position.h:55
double z() const
Returns the z-position.
Definition: Position.h:65
double y() const
Returns the y-position.
Definition: Position.h:60
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 ammount
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)