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-2024 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(), (*osg_coords)[k].z() - zOffset);
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 if (shape.size() > 2) {
209 tessellator.retessellatePolygons(*geom);
210
211#ifdef DEBUG_TESSEL
212 std::cout << "l=" << l->getID() << " origPoints=" << shape.size() << " geomSize=" << geom->getVertexArray()->getNumElements() << " points=";
213 for (int i = 0; i < (int)geom->getVertexArray()->getNumElements(); i++) {
214 const osg::Vec3& p = (*((osg::Vec3Array*)geom->getVertexArray()))[i];
215 std::cout << p.x() << "," << p.y() << "," << p.z() << " ";
216 }
217 std::cout << "\n";
218#endif
219 }
220 osgUtil::SmoothingVisitor sv;
221#if OSG_MIN_VERSION_REQUIRED(3,5,4)
222 sv.setCreaseAngle(0.6 * osg::PI);
223#endif
224 geom->accept(sv);
225 static_cast<GUILane*>(l)->setGeometry(geom);
226 }
227}
228
229
230void
231GUIOSGBuilder::buildOSGJunctionGeometry(GUIJunctionWrapper& junction,
232 osg::Group& addTo,
233 osgUtil::Tessellator& tessellator) {
234 const PositionVector& shape = junction.getJunction().getShape();
235 osg::Geode* geode = new osg::Geode();
236 osg::Geometry* geom = new osg::Geometry();
237 geode->addDrawable(geom);
238 geode->setName("junction:" + junction.getMicrosimID());
239 addTo.addChild(geode);
240 dynamic_cast<GUIGlObject&>(junction).setNode(geode);
241 osg::Vec3Array* osg_coords = new osg::Vec3Array((int)shape.size()); // OSG needs float coordinates here
242 geom->setVertexArray(osg_coords);
243 for (int k = 0; k < (int)shape.size(); ++k) {
244 (*osg_coords)[k].set((float)shape[k].x(), (float)shape[k].y(), (float)shape[k].z());
245 }
246 osg::Vec3Array* osg_normals = new osg::Vec3Array(1);
247 (*osg_normals)[0] = osg::Vec3(0, 0, 1); // OSG needs float coordinates here
248 geom->setNormalArray(osg_normals, osg::Array::BIND_PER_PRIMITIVE_SET);
249 osg::Vec4ubArray* osg_colors = new osg::Vec4ubArray(1);
250 (*osg_colors)[0].set(128, 128, 128, 255);
251 geom->setColorArray(osg_colors, osg::Array::BIND_OVERALL);
252 geom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::POLYGON, 0, (int)shape.size()));
253
254 osg::ref_ptr<osg::StateSet> ss = geode->getOrCreateStateSet();
255 ss->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
256 ss->setMode(GL_BLEND, osg::StateAttribute::OVERRIDE | osg::StateAttribute::PROTECTED | osg::StateAttribute::ON);
257
258 if (shape.size() > 4) {
259 tessellator.retessellatePolygons(*geom);
260 }
261 junction.setGeometry(geom);
262}
263
264
265void
266GUIOSGBuilder::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) {
267 // get the poleBase diameter for later repositioning
268 osg::ComputeBoundsVisitor bboxCalc;
269 poleBase->accept(bboxCalc);
270 const double poleDiameter = bboxCalc.getBoundingBox().yMax() - bboxCalc.getBoundingBox().yMin();
271 tlg->accept(bboxCalc);
272 const double tlWidth = bboxCalc.getBoundingBox().yMax() - bboxCalc.getBoundingBox().yMin();
273
274 // loop through lanes, collect edges, skip ped and bike infra for the time being
275 MSTrafficLightLogic* tlLogic = vars.getActive();
276 const MSTrafficLightLogic::LinkVectorVector& allLinks = tlLogic->getLinks();
277 std::set<const MSEdge*> seenEdges;
278
279 for (const MSTrafficLightLogic::LinkVector& lv : allLinks) {
280 for (const MSLink* tlLink : lv) {
281 // if not in seenEdges, create pole and reference it in the maps above
282 const MSEdge* approach = &tlLink->getLaneBefore()->getEdge();
283 if (!approach->isWalkingArea() && seenEdges.find(approach) != seenEdges.end()) {
284 continue;
285 }
286 const std::vector<MSLane*> appLanes = approach->getLanes();
287 // ref pos
288 const double poleMinHeight = 5.;
289 const double poleOffset = .5;
290 double angle = 90. - appLanes[0]->getShape().rotationDegreeAtOffset(-1.);
291 bool onlyPedCycle = isBikepath(approach->getPermissions()) || isSidewalk(approach->getPermissions());
292 Position pos = appLanes[0]->getShape().back();
293 double skipWidth = 0.;
294 int firstSignalLaneIx = 0;
295 std::vector<std::pair<osg::Group*, osg::Vec3d>> repeaters;
296 // start with local coordinate system
297 osg::PositionAttitudeTransform* appBase = new osg::PositionAttitudeTransform();
298 osg::PositionAttitudeTransform* rightPoleBase = new osg::PositionAttitudeTransform();
299 osg::PositionAttitudeTransform* rightPoleScaleNode = new osg::PositionAttitudeTransform();
300 rightPoleScaleNode->addChild(poleBase);
301 rightPoleBase->addChild(rightPoleScaleNode);
302 appBase->addChild(rightPoleBase);
303 rightPoleBase->setPosition(osg::Vec3d(pos.x(), pos.y(), pos.z()));
304 rightPoleBase->setAttitude(osg::Quat(0., osg::Vec3d(1, 0, 0),
305 0., osg::Vec3d(0, 1, 0),
306 DEG2RAD(angle), osg::Vec3d(0, 0, 1)));
307 if (onlyPedCycle) { // pedestrian / cyclist signal only
308 rightPoleScaleNode->setScale(osg::Vec3d(.12 / poleDiameter, .12 / poleDiameter, 2.8));
309 if (approach->isCrossing()) { // center VRU signal pole at crossings
310 // move pole to the other side of the road
311 osg::Vec3d offset(cos(DEG2RAD(angle)), sin(DEG2RAD(angle)), 0.);
312 appBase->setPosition(appBase->getPosition() + offset * (poleOffset + approach->getLength()));
313 appBase->setAttitude(osg::Quat(0., osg::Vec3d(1, 0, 0),
314 0., osg::Vec3d(0, 1, 0),
315 DEG2RAD(angle + 180), osg::Vec3d(0, 0, 1)));
316 } else if (approach->isWalkingArea()) { // pole for other direction > get position from crossing
317 pos = tlLink->getLane()->getShape().back();
318 angle = 90. - tlLink->getLane()->getShape().rotationDegreeAtOffset(-1.);
319 rightPoleBase->setPosition(osg::Vec3d(pos.x(), pos.y(), pos.z()) - osg::Vec3d(poleOffset * cos(DEG2RAD(angle)), poleOffset * sin(DEG2RAD(angle)), 0.));
320 rightPoleBase->setAttitude(osg::Quat(0., osg::Vec3d(1, 0, 0),
321 0., osg::Vec3d(0, 1, 0),
322 DEG2RAD(angle), osg::Vec3d(0, 0, 1)));
323 if (tlLink->getLane()->getLinkCont()[0]->getTLIndex() < 0) { // check whether the other side is not specified explicitly
324 osg::PositionAttitudeTransform* leftPoleBase = new osg::PositionAttitudeTransform();
325 osg::PositionAttitudeTransform* leftPoleScaleNode = new osg::PositionAttitudeTransform();
326 appBase->addChild(leftPoleBase);
327 leftPoleScaleNode->addChild(poleBase);
328 leftPoleScaleNode->setScale(osg::Vec3d(.12 / poleDiameter, .12 / poleDiameter, 2.8));
329 leftPoleBase->addChild(leftPoleScaleNode);
330 double otherAngle = 90. - tlLink->getLane()->getShape().rotationDegreeAtOffset(1.);
331 Position otherPosRel = tlLink->getLane()->getShape().front();
332 osg::Vec3d leftPolePos(otherPosRel.x(), otherPosRel.y(), otherPosRel.z());
333 leftPoleBase->setPosition(leftPolePos + osg::Vec3d(poleOffset * cos(DEG2RAD(otherAngle)), poleOffset * sin(DEG2RAD(otherAngle)), 0.));
334 leftPoleBase->setAttitude(osg::Quat(0., osg::Vec3d(1., 0., 0.),
335 0., osg::Vec3d(0., 1., 0.),
336 DEG2RAD(angle + 180.), osg::Vec3d(0., 0., 1.)));
337 repeaters.push_back({ leftPoleBase, osg::Vec3d(0., 0., leftPoleBase->getPosition().z())});
338 }
339 } else {
340 double laneWidth = appLanes[0]->getWidth();
341 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.);
342 rightPoleBase->setPosition(rightPoleBase->getPosition() + offset);
343 }
344 } else {
345 // skip sidewalk and bike lane if leftmost lane is for cars
346 if (!noVehicles(appLanes.back()->getPermissions())) {
347 for (MSLane* appLane : appLanes) {
348 SVCPermissions permissions = appLane->getPermissions();
349 if (isSidewalk(permissions) || isForbidden(permissions)) {
350 skipWidth += appLane->getWidth();
351 } else {
352 break;
353 }
354 firstSignalLaneIx++;
355 }
356 }
357 const double laneWidth = appLanes[0]->getWidth();
358 const double horizontalWidth = approach->getWidth() - skipWidth;
359 const int laneCount = (int)appLanes.size() - firstSignalLaneIx;
360 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.);
361 rightPoleBase->setPosition(rightPoleBase->getPosition() + offset);
362
363 if (laneCount < 3) { // cantilever
364 const double cantiWidth = horizontalWidth - .1 * appLanes.back()->getWidth() + poleOffset;
365 const double holderWidth = cantiWidth - .4 * appLanes.back()->getWidth();
366 const double holderAngle = 7.5; // degrees
367 const double extraHeight = sin(DEG2RAD(holderAngle)) * holderWidth;
368 rightPoleScaleNode->setScale(osg::Vec3d(.25 / poleDiameter, .25 / poleDiameter, poleMinHeight + extraHeight));
369 osg::PositionAttitudeTransform* cantileverBase = new osg::PositionAttitudeTransform();
370 cantileverBase->setPosition(osg::Vec3d(0., 0., poleMinHeight));
371 cantileverBase->setAttitude(osg::Quat(DEG2RAD(90.), osg::Vec3d(1, 0, 0),
372 0., osg::Vec3d(0, 1, 0),
373 0., osg::Vec3d(0, 0, 1)));
374 cantileverBase->setScale(osg::Vec3d(1., 1., cantiWidth));
375 cantileverBase->addChild(poleBase);
376 rightPoleBase->addChild(cantileverBase);
377 osg::PositionAttitudeTransform* cantileverHolderBase = new osg::PositionAttitudeTransform();
378 cantileverHolderBase->setPosition(osg::Vec3d(0., 0., poleMinHeight + extraHeight - .02));
379 cantileverHolderBase->setAttitude(osg::Quat(DEG2RAD(90. + holderAngle), osg::Vec3d(1, 0, 0),
380 0., osg::Vec3d(0, 1, 0),
381 0., osg::Vec3d(0, 0, 1)));
382 cantileverHolderBase->setScale(osg::Vec3d(.04 / poleDiameter, .04 / poleDiameter, sqrt(pow(holderWidth, 2.) + pow(extraHeight, 2.))));
383 cantileverHolderBase->addChild(poleBase);
384 rightPoleBase->addChild(cantileverHolderBase);
385 } else { // signal bridge
386 rightPoleScaleNode->setScale(osg::Vec3d(.25 / poleDiameter, .25 / poleDiameter, poleMinHeight));
387 osg::PositionAttitudeTransform* leftPoleBase = new osg::PositionAttitudeTransform();
388 leftPoleBase->addChild(poleBase);
389 leftPoleBase->setScale(osg::Vec3d(.25 / poleDiameter, .25 / poleDiameter, poleMinHeight));
390 osg::Vec3d leftPolePos = osg::Vec3d(0, -(horizontalWidth + 2. * poleOffset), 0.);
391 leftPoleBase->setPosition(leftPolePos);
392 rightPoleBase->addChild(leftPoleBase);
393 osg::PositionAttitudeTransform* bridgeBase = new osg::PositionAttitudeTransform();
394 bridgeBase->setPosition(osg::Vec3d(0., 0., poleMinHeight - .125));
395 bridgeBase->setAttitude(osg::Quat(DEG2RAD(90.), osg::Vec3d(1, 0, 0),
396 0., osg::Vec3d(0, 1, 0),
397 0., osg::Vec3d(0, 0, 1)));
398 bridgeBase->setScale(osg::Vec3d(.25 / poleDiameter, .25 / poleDiameter, leftPolePos.length()));
399 bridgeBase->addChild(poleBase);
400 rightPoleBase->addChild(bridgeBase);
401 }
402 }
403 seenEdges.insert(approach);
404
405 // Add signals and position them along the cantilever/bridge
406 double refPos = poleOffset /*- skipWidth*/;
407 std::vector<MSLane*>::const_iterator it = appLanes.begin();
408 for (std::advance(it, firstSignalLaneIx); it != appLanes.end(); it++) {
409 // get tlLinkIndices
410 const std::vector<MSLink*>& links = (*it)->getLinkCont();
411 std::set<int> tlIndices;
412 for (MSLink* link : links) {
413 if (link->getTLIndex() > -1) {
414 tlIndices.insert(link->getTLIndex());
415 }
416 }
417 std::set<int> seenTlIndices;
418 bool placeRepeaters = true;
419 for (MSLink* link : links) {
420 std::vector<std::pair<osg::Group*, osg::Vec3d>> signalTransforms = { {rightPoleBase, osg::Vec3d(0., 0., 0.)} };
421 if (placeRepeaters) {
422 signalTransforms.insert(signalTransforms.end(), repeaters.begin(), repeaters.end());
423 repeaters.clear();
424 placeRepeaters = false;
425 }
426 int tlIndex = link->getTLIndex();
427 if (tlIndex < 0 || seenTlIndices.find(tlIndex) != seenTlIndices.end()) {
428 continue;
429 }
430 for (const std::pair<osg::Group*, osg::Vec3d>& transform : signalTransforms) {
432 d.centerX = transform.second.x() + 0.15;
433 d.centerY = (onlyPedCycle) ? 0. : -(refPos + .5 * (*it)->getWidth() - ((double)tlIndices.size() / 2. - 1. + (double)seenTlIndices.size()) * 1.5 * tlWidth);
434 d.centerY += transform.second.y();
435 d.centerZ = (onlyPedCycle) ? 2.2 : 3.8;
436 d.centerZ += transform.second.z();
437 d.altitude = (onlyPedCycle) ? 0.6 : -1;
438 osg::PositionAttitudeTransform* tlNode = getTrafficLight(d, vars, links[0], tlg, tly, tlr, tlu, poleBase, false);
439 tlNode->setAttitude(osg::Quat(0., osg::Vec3d(1, 0, 0),
440 0., osg::Vec3d(0, 1, 0),
441 DEG2RAD(180.0), osg::Vec3d(0, 0, 1)));
442 transform.first->addChild(tlNode);
443 }
444 seenTlIndices.insert(tlIndex);
445 }
446 // only one signal for bike/pedestrian only edges
447 if (onlyPedCycle) {
448 break;
449 }
450 refPos += (*it)->getWidth();
451 }
452 // interaction
453 appBase->setNodeMask(GUIOSGView::NODESET_TLSMODELS);
454 appBase->setName("tlLogic:" + tlLogic->getID());
455 addTo.addChild(appBase);
456 }
457 }
458}
459
460
461void
462GUIOSGBuilder::buildDecal(const GUISUMOAbstractView::Decal& d, osg::Group& addTo) {
463 osg::Node* pLoadedModel = osgDB::readNodeFile(d.filename);
464 osg::PositionAttitudeTransform* base = new osg::PositionAttitudeTransform();
465 double zOffset = 0.;
466 if (pLoadedModel == nullptr) {
467 // check for 2D image
468 osg::Image* pImage = osgDB::readImageFile(d.filename);
469 if (pImage == nullptr) {
470 base = nullptr;
471 WRITE_ERRORF(TL("Could not load '%'."), d.filename);
472 return;
473 }
474 osg::Texture2D* texture = new osg::Texture2D();
475 texture->setImage(pImage);
476 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.));
477 quad->getOrCreateStateSet()->setTextureAttributeAndModes(0, texture);
478 osg::Geode* const pModel = new osg::Geode();
479 pModel->addDrawable(quad);
480 base->addChild(pModel);
481 zOffset = d.layer;
482 } else {
483 osg::ShadeModel* sm = new osg::ShadeModel();
484 sm->setMode(osg::ShadeModel::FLAT);
485 pLoadedModel->getOrCreateStateSet()->setAttribute(sm);
486 base->addChild(pLoadedModel);
487 }
488 osg::ComputeBoundsVisitor bboxCalc;
489 base->accept(bboxCalc);
490 const osg::BoundingBox& bbox = bboxCalc.getBoundingBox();
491 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())));
492 double xScale = d.width > 0 ? d.width / (bbox.xMax() - bbox.xMin()) : 1.;
493 double yScale = d.height > 0 ? d.height / (bbox.yMax() - bbox.yMin()) : 1.;
494 const double zScale = d.altitude > 0 ? d.altitude / (bbox.zMax() - bbox.zMin()) : 1.;
495 if (d.width < 0 && d.height < 0 && d.altitude > 0) {
496 xScale = yScale = zScale;
497 }
498 base->setScale(osg::Vec3d(xScale, yScale, zScale));
499 base->setPosition(osg::Vec3d(d.centerX, d.centerY, d.centerZ + zOffset));
500 base->setAttitude(osg::Quat(osg::DegreesToRadians(d.roll), osg::Vec3d(1, 0, 0),
501 osg::DegreesToRadians(d.tilt), osg::Vec3d(0, 1, 0),
502 osg::DegreesToRadians(d.rot), osg::Vec3d(0, 0, 1)));
503 addTo.addChild(base);
504}
505
506
507osg::PositionAttitudeTransform*
508GUIOSGBuilder::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) {
509 osg::PositionAttitudeTransform* ret = new osg::PositionAttitudeTransform();
510 double xScale = 1., yScale = 1., zScale = 1.;
511 if (tlg != nullptr) {
512 osg::ComputeBoundsVisitor bboxCalc;
513 tlg->accept(bboxCalc);
514 const osg::BoundingBox& bbox = bboxCalc.getBoundingBox();
515 xScale = d.width > 0 ? d.width / (bbox.xMax() - bbox.xMin()) : 1.;
516 yScale = d.height > 0 ? d.height / (bbox.yMax() - bbox.yMin()) : 1.;
517 double addHeight = (withPole) ? poleHeight : 0.;
518 zScale = d.altitude > 0 ? d.altitude / (addHeight + bbox.zMax() - bbox.zMin()) : 1.;
519 }
520 if (d.width < 0 && d.height < 0 && d.altitude > 0) {
521 xScale = yScale = zScale;
522 }
523 osg::PositionAttitudeTransform* base = new osg::PositionAttitudeTransform();
524 osg::Switch* switchNode = new osg::Switch();
525 switchNode->addChild(createTrafficLightState(d, tlg, withPole, size, osg::Vec4d(0., 1., 0., transparency)));
526 switchNode->addChild(createTrafficLightState(d, tly, withPole, size, osg::Vec4d(1., 1., 0., transparency)));
527 switchNode->addChild(createTrafficLightState(d, tlr, withPole, size, osg::Vec4d(1., 0., 0., transparency)));
528 switchNode->addChild(createTrafficLightState(d, tlu, withPole, size, osg::Vec4d(1., .5, 0., transparency)));
529 base->addChild(switchNode);
530 vars.addSwitchCommand(new GUIOSGView::Command_TLSChange(link, switchNode));
531 if (withPole) {
532 base->setPosition(osg::Vec3d(0., 0., poleHeight));
533 osg::PositionAttitudeTransform* poleBase = new osg::PositionAttitudeTransform();
534 poleBase->addChild(pole);
535 poleBase->setScale(osg::Vec3d(1., 1., poleHeight));
536 ret->addChild(poleBase);
537 }
538 ret->setAttitude(osg::Quat(osg::DegreesToRadians(d.roll), osg::Vec3(1, 0, 0),
539 osg::DegreesToRadians(d.tilt), osg::Vec3(0, 1, 0),
540 osg::DegreesToRadians(d.rot), osg::Vec3(0, 0, 1)));
541 ret->setPosition(osg::Vec3d(d.centerX, d.centerY, d.centerZ));
542 ret->setScale(osg::Vec3d(xScale, yScale, zScale));
543 ret->addChild(base);
544 return ret;
545}
546
547
548osg::PositionAttitudeTransform*
549GUIOSGBuilder::createTrafficLightState(const GUISUMOAbstractView::Decal& d, osg::Node* tl, const double withPole, const double size, osg::Vec4d color) {
550 osg::PositionAttitudeTransform* ret = new osg::PositionAttitudeTransform();
551 if (tl != nullptr) {
552 ret->addChild(tl);
553 }
554 if (size > 0.) {
555 unsigned int nodeMask = (withPole) ? GUIOSGView::NodeSetGroup::NODESET_TLSDOMES : GUIOSGView::NodeSetGroup::NODESET_TLSLINKMARKERS;
556 osg::Geode* geode = new osg::Geode();
557 osg::Vec3d center = osg::Vec3d(0., 0., (withPole) ? -1.8 : 0.);
558 osg::ShapeDrawable* shape = new osg::ShapeDrawable(new osg::Sphere(center, (float)size));
559 geode->addDrawable(shape);
560 osg::ref_ptr<osg::StateSet> ss = shape->getOrCreateStateSet();
561 ss->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
562 ss->setMode(GL_BLEND, osg::StateAttribute::OVERRIDE | osg::StateAttribute::PROTECTED | osg::StateAttribute::ON);
563 shape->setColor(color);
564 osg::PositionAttitudeTransform* ellipse = new osg::PositionAttitudeTransform();
565 ellipse->addChild(geode);
566 ellipse->setPosition(center);
567 ellipse->setPivotPoint(center);
568 if (withPole) {
569 ellipse->setScale(osg::Vec3d(4., 4., 2.5 * d.altitude + 1.1));
570 } else {
571 ellipse->setScale(osg::Vec3d(4., 4., 1.1));
572 }
573 ellipse->setNodeMask(nodeMask);
574 ret->addChild(ellipse);
575 }
576 return ret;
577}
578
579
580void
581GUIOSGBuilder::setShapeState(osg::ref_ptr<osg::ShapeDrawable> shape) {
582 osg::ref_ptr<osg::StateSet> ss = shape->getOrCreateStateSet();
583 ss->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
584 ss->setMode(GL_BLEND, osg::StateAttribute::OVERRIDE | osg::StateAttribute::PROTECTED | osg::StateAttribute::ON);
585}
586
587
588GUIOSGView::OSGMovable
589GUIOSGBuilder::buildMovable(const MSVehicleType& type) {
590 GUIOSGView::OSGMovable m;
591 m.pos = new osg::PositionAttitudeTransform();
592 double enlarge = 0.05;
593 const std::string& osgFile = type.getOSGFile();
594 if (myCars.find(osgFile) == myCars.end()) {
595 myCars[osgFile] = osgDB::readNodeFile(osgFile);
596 if (myCars[osgFile] == 0) {
597 WRITE_ERRORF(TL("Could not load '%'. The model is replaced by a cone shape."), osgFile);
598 osg::PositionAttitudeTransform* rot = new osg::PositionAttitudeTransform();
599 rot->addChild(new osg::ShapeDrawable(new osg::Cone(osg::Vec3d(0, 0, 0), 1.0f, 1.0f)));
600 rot->setAttitude(osg::Quat(osg::DegreesToRadians(90.), osg::Vec3(1, 0, 0),
601 0., osg::Vec3(0, 1, 0),
602 0., osg::Vec3(0, 0, 1)));
603 myCars[osgFile] = rot;
604 }
605 }
606 osg::Node* carNode = myCars[osgFile];
607 if (carNode != nullptr) {
608 osg::ComputeBoundsVisitor bboxCalc;
609 carNode->accept(bboxCalc);
610 const osg::BoundingBox& bbox = bboxCalc.getBoundingBox();
611 osg::PositionAttitudeTransform* base = new osg::PositionAttitudeTransform();
612 base->addChild(carNode);
613 base->setPivotPoint(osg::Vec3d((bbox.xMin() + bbox.xMax()) / 2., bbox.yMin(), bbox.zMin()));
614 base->setScale(osg::Vec3d(type.getWidth() / (bbox.xMax() - bbox.xMin()),
615 type.getLength() / (bbox.yMax() - bbox.yMin()),
616 type.getHeight() / (bbox.zMax() - bbox.zMin())));
617 m.pos->addChild(base);
618
619 // material for coloring the person or vehicle body
620 m.mat = new osg::Material();
621 osg::ref_ptr<osg::StateSet> ss = base->getOrCreateStateSet();
622 ss->setAttribute(m.mat, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE | osg::StateAttribute::PROTECTED);
623 ss->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
624 ss->setMode(GL_BLEND, osg::StateAttribute::OVERRIDE | osg::StateAttribute::PROTECTED | osg::StateAttribute::ON);
625 }
626 if (type.getVehicleClass() != SVC_PEDESTRIAN) {
627 m.lights = new osg::Switch();
628 for (double sideFactor = -1.; sideFactor < 2.5; sideFactor += 2.) {
629 osg::Geode* geode = new osg::Geode();
630 osg::ShapeDrawable* right = new osg::ShapeDrawable(new osg::Sphere(osg::Vec3d((type.getWidth() / 2. + enlarge)*sideFactor, 0., type.getHeight() / 2.), 0.2f));
631 geode->addDrawable(right);
632 //pat->addChild(geode);
633 setShapeState(right);
634 right->setColor(osg::Vec4(1.f, .5f, 0.f, .8f));
635 osg::Sequence* seq = new osg::Sequence();
636 // Wikipedia says about 1.5Hz
637 seq->addChild(geode, .33);
638 seq->addChild(new osg::Geode(), .33);
639 // loop through all children
640 seq->setInterval(osg::Sequence::LOOP, 0, -1);
641 // real-time playback, repeat indefinitely
642 seq->setDuration(1.0f, -1);
643 // must be started explicitly
644 seq->setMode(osg::Sequence::START);
645 m.lights->addChild(seq);
646 }
647 osg::Geode* geode = new osg::Geode();
648 osg::CompositeShape* comp = new osg::CompositeShape();
649 comp->addChild(new osg::Sphere(osg::Vec3d(-(type.getWidth() / 2. + enlarge), type.getLength() + enlarge, type.getHeight() / 2.), .2f));
650 comp->addChild(new osg::Sphere(osg::Vec3d(type.getWidth() / 2. + enlarge, type.getLength() + enlarge, type.getHeight() / 2.), .2f));
651 osg::ShapeDrawable* brake = new osg::ShapeDrawable(comp);
652 brake->setColor(osg::Vec4(1.f, 0.f, 0.f, .8f));
653 geode->addDrawable(brake);
654 setShapeState(brake);
655 m.lights->addChild(geode);
656
657 osg::Vec3d center(0, -type.getLength() / 2., 0.);
658 osg::PositionAttitudeTransform* ellipse = new osg::PositionAttitudeTransform();
659 ellipse->addChild(geode);
660 ellipse->addChild(m.lights);
661 ellipse->setPivotPoint(center);
662 ellipse->setPosition(center);
663 m.pos->addChild(ellipse);
664 }
665 m.active = true;
666 return m;
667}
668
669
670osg::Node*
671GUIOSGBuilder::buildPlane(const float length) {
672 osg::Geode* geode = new osg::Geode();
673 osg::Geometry* geom = new osg::Geometry;
674 geode->addDrawable(geom);
675 osg::Vec3Array* coords = new osg::Vec3Array(4); // OSG needs float coordinates here
676 geom->setVertexArray(coords);
677 (*coords)[0].set(.5f * length, .5f * length, -0.1f);
678 (*coords)[1].set(.5f * length, -.5f * length, -0.1f);
679 (*coords)[2].set(-.5f * length, -.5f * length, -0.1f);
680 (*coords)[3].set(-.5f * length, .5f * length, -0.1f);
681 osg::Vec3Array* normals = new osg::Vec3Array(1); // OSG needs float coordinates here
682 (*normals)[0].set(0, 0, 1);
683 geom->setNormalArray(normals, osg::Array::BIND_PER_PRIMITIVE_SET);
684 osg::Vec4ubArray* colors = new osg::Vec4ubArray(1);
685 (*colors)[0].set(0, 255, 0, 255);
686 geom->setColorArray(colors, osg::Array::BIND_OVERALL);
687 geom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::POLYGON, 0, 4));
688
689 osg::ref_ptr<osg::StateSet> ss = geode->getOrCreateStateSet();
690 ss->setRenderingHint(osg::StateSet::OPAQUE_BIN);
691 ss->setMode(GL_BLEND, osg::StateAttribute::OVERRIDE | osg::StateAttribute::PROTECTED | osg::StateAttribute::ON);
692
693 return geode;
694}
695
696
697#endif
698
699/****************************************************************************/
#define DEG2RAD(x)
Definition GeomHelper.h:35
#define WRITE_MESSAGEF(...)
Definition MsgHandler.h:298
#define WRITE_ERRORF(...)
Definition MsgHandler.h:305
#define TL(string)
Definition MsgHandler.h:315
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:614
virtual const PositionVector & getShape(bool) const
Definition MSLane.h:294
double getWidth() const
Returns the lane's width.
Definition MSLane.h:635
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:451
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 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 amount
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)