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