Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
eclipse
GitHub Repository: eclipse/sumo
Path: blob/main/src/osgview/GUIOSGBuilder.cpp
193678 views
1
/****************************************************************************/
2
// Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3
// Copyright (C) 2001-2026 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
/****************************************************************************/
14
/// @file GUIOSGBuilder.cpp
15
/// @author Daniel Krajzewicz
16
/// @author Michael Behrisch
17
/// @author Mirko Barthauer
18
/// @date 19.01.2012
19
///
20
// Builds OSG nodes from microsim objects
21
/****************************************************************************/
22
#include <config.h>
23
24
#ifdef HAVE_OSG
25
26
#include <guisim/GUIEdge.h>
27
#include <guisim/GUIJunctionWrapper.h>
28
#include <guisim/GUILane.h>
29
#include <guisim/GUINet.h>
30
#include <microsim/MSEdge.h>
31
#include <microsim/MSEdgeControl.h>
32
#include <microsim/MSJunction.h>
33
#include <microsim/MSJunctionControl.h>
34
#include <microsim/MSLane.h>
35
#include <microsim/MSNet.h>
36
#include <microsim/MSVehicleType.h>
37
#include <microsim/traffic_lights/MSTLLogicControl.h>
38
#include <microsim/traffic_lights/MSTrafficLightLogic.h>
39
#include <utils/common/MsgHandler.h>
40
#include <utils/common/SUMOVehicleClass.h>
41
#include <utils/geom/GeomHelper.h>
42
#include <utils/gui/windows/GUISUMOAbstractView.h>
43
#include <utils/shapes/ShapeContainer.h>
44
45
#include "GUIOSGView.h"
46
#include "GUIOSGBuilder.h"
47
48
//#define DEBUG_TESSEL
49
50
// ===========================================================================
51
// static member variables
52
// ===========================================================================
53
54
std::map<std::string, osg::ref_ptr<osg::Node> > GUIOSGBuilder::myCars;
55
56
// ===========================================================================
57
// member method definitions
58
// ===========================================================================
59
60
osg::Group*
61
GUIOSGBuilder::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
76
GUISUMOAbstractView::Decal d;
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) {
79
MSTLLogicControl::TLSLogicVariants& vars = net->getTLSControl().get(*i);
80
buildTrafficLightDetails(vars, tlg, tly, tlr, tlu, pole, *root);
81
82
const MSTrafficLightLogic::LaneVectorVector& lanes = vars.getActive()->getLaneVectors();
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
118
void
119
GUIOSGBuilder::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
141
void
142
GUIOSGBuilder::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
239
void
240
GUIOSGBuilder::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
274
void
275
GUIOSGBuilder::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
315
void
316
GUIOSGBuilder::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
355
void
356
GUIOSGBuilder::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) {
521
GUISUMOAbstractView::Decal d;
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
551
void
552
GUIOSGBuilder::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
597
osg::PositionAttitudeTransform*
598
GUIOSGBuilder::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
638
osg::PositionAttitudeTransform*
639
GUIOSGBuilder::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
670
void
671
GUIOSGBuilder::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
678
GUIOSGView::OSGMovable
679
GUIOSGBuilder::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
761
osg::Node*
762
GUIOSGBuilder::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
/****************************************************************************/
791
792