LCOV - code coverage report
Current view: top level - src/osgview - GUIOSGBuilder.cpp (source / functions) Coverage Total Hit
Test: lcov.info Lines: 73.9 % 472 349
Test Date: 2025-11-13 15:38:19 Functions: 69.2 % 13 9

            Line data    Source code
       1              : /****************************************************************************/
       2              : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
       3              : // Copyright (C) 2001-2025 German Aerospace Center (DLR) and others.
       4              : // This program and the accompanying materials are made available under the
       5              : // terms of the Eclipse Public License 2.0 which is available at
       6              : // https://www.eclipse.org/legal/epl-2.0/
       7              : // This Source Code may also be made available under the following Secondary
       8              : // Licenses when the conditions for such availability set forth in the Eclipse
       9              : // Public License 2.0 are satisfied: GNU General Public License, version 2
      10              : // or later which is available at
      11              : // https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
      12              : // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
      13              : /****************************************************************************/
      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          436 : GUIOSGBuilder::buildOSGScene(osg::Node* const tlg, osg::Node* const tly, osg::Node* const tlr, osg::Node* const tlu, osg::Node* const pole) {
      62          436 :     osgUtil::Tessellator tesselator;
      63          436 :     osg::Group* root = new osg::Group();
      64          436 :     GUINet* net = static_cast<GUINet*>(MSNet::getInstance());
      65              :     // build edges
      66        12093 :     for (const MSEdge* e : net->getEdgeControl().getEdges()) {
      67        11657 :         if (!e->isInternal()) {
      68         4195 :             buildOSGEdgeGeometry(*e, *root, tesselator);
      69              :         }
      70              :     }
      71              :     // build junctions
      72         5068 :     for (int index = 0; index < (int)net->myJunctionWrapper.size(); ++index) {
      73         4632 :         buildOSGJunctionGeometry(*net->myJunctionWrapper[index], *root, tesselator);
      74              :     }
      75              :     // build traffic lights
      76              :     GUISUMOAbstractView::Decal d;
      77          436 :     const std::vector<std::string> tlids = net->getTLSControl().getAllTLIds();
      78          547 :     for (std::vector<std::string>::const_iterator i = tlids.begin(); i != tlids.end(); ++i) {
      79          111 :         MSTLLogicControl::TLSLogicVariants& vars = net->getTLSControl().get(*i);
      80          111 :         buildTrafficLightDetails(vars, tlg, tly, tlr, tlu, pole, *root);
      81              : 
      82          111 :         const MSTrafficLightLogic::LaneVectorVector& lanes = vars.getActive()->getLaneVectors();
      83              :         const MSLane* lastLane = 0;
      84              :         int idx = 0;
      85         1796 :         for (MSTrafficLightLogic::LaneVectorVector::const_iterator j = lanes.begin(); j != lanes.end(); ++j, ++idx) {
      86         1685 :             if ((*j).size() == 0) {
      87            0 :                 continue;
      88              :             }
      89         1685 :             const MSLane* const lane = (*j)[0];
      90         1685 :             const Position pos = lane->getShape().back();
      91         1685 :             const double angle = osg::DegreesToRadians(lane->getShape().rotationDegreeAtOffset(-1.) + 90.);
      92         1685 :             d.centerZ = pos.z() + 4.;
      93         1685 :             if (lane == lastLane) {
      94          937 :                 d.centerX += 1.2 * sin(angle);
      95          937 :                 d.centerY += 1.2 * cos(angle);
      96              :             } else {
      97          748 :                 d.centerX = pos.x() - 1.5 * sin(angle);
      98          748 :                 d.centerY = pos.y() - 1.5 * cos(angle);
      99              :             }
     100         1685 :             osg::PositionAttitudeTransform* tlNode = getTrafficLight(d, vars, vars.getActive()->getLinksAt(idx)[0], nullptr, nullptr, nullptr, nullptr, nullptr, false, .25, -1, 1.);
     101         1685 :             tlNode->setName("tlLogic:" + *i);
     102         1685 :             root->addChild(tlNode);
     103              :             lastLane = lane;
     104              :         }
     105              :     }
     106              : 
     107              :     // build PoI and polygons
     108          436 :     for (const auto& entry : net->getShapeContainer().getPolygons()) {
     109            0 :         buildPolygonGeometry(*entry.second, *root, tesselator);
     110              :     }
     111          436 :     for (const auto& entry : net->getShapeContainer().getPOIs()) {
     112            0 :         buildPoIGeometry(*entry.second, *root, tesselator);
     113              :     }
     114          436 :     return root;
     115          872 : }
     116              : 
     117              : 
     118              : void
     119            0 : GUIOSGBuilder::buildLight(const GUISUMOAbstractView::Decal& d, osg::Group& addTo) {
     120              :     // each light must have a unique number
     121            0 :     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            0 :     osg::LightSource* lightSource = new osg::LightSource();
     129            0 :     lightSource->setLight(light);
     130            0 :     lightSource->setLocalStateSetModes(osg::StateAttribute::ON);
     131            0 :     lightSource->setStateSetModes(*addTo.getOrCreateStateSet(), osg::StateAttribute::ON);
     132              : 
     133            0 :     osg::PositionAttitudeTransform* lightTransform = new osg::PositionAttitudeTransform();
     134            0 :     lightTransform->addChild(lightSource);
     135            0 :     lightTransform->setPosition(osg::Vec3d(d.centerX, d.centerY, d.centerZ));
     136              :     lightTransform->setScale(osg::Vec3d(0.1, 0.1, 0.1));
     137            0 :     addTo.addChild(lightTransform);
     138            0 : }
     139              : 
     140              : 
     141              : void
     142         4195 : GUIOSGBuilder::buildOSGEdgeGeometry(const MSEdge& edge,
     143              :                                     osg::Group& addTo,
     144              :                                     osgUtil::Tessellator& tessellator) {
     145              :     const std::vector<MSLane*>& lanes = edge.getLanes();
     146        10103 :     for (std::vector<MSLane*>::const_iterator j = lanes.begin(); j != lanes.end(); ++j) {
     147         5908 :         MSLane* l = (*j);
     148         5908 :         const bool extrude = edge.isWalkingArea() || isSidewalk(l->getPermissions());
     149         5908 :         const int geomFactor = (edge.isWalkingArea()) ? 1 : 2;
     150              :         const PositionVector& shape = l->getShape();
     151         5908 :         const int originalSize = (int)shape.size();
     152         5908 :         osg::Geode* geode = new osg::Geode();
     153         5908 :         osg::Geometry* geom = new osg::Geometry();
     154         5908 :         geode->addDrawable(geom);
     155         5908 :         geode->setName("lane:" + l->getID());
     156         5908 :         addTo.addChild(geode);
     157         5908 :         dynamic_cast<GUIGlObject*>(l)->setNode(geode);
     158         5908 :         const int upperShapeSize = originalSize * geomFactor;
     159         5908 :         const int totalShapeSize = (extrude) ? originalSize * 2 * geomFactor : originalSize * geomFactor;
     160         5908 :         const float zOffset = (extrude) ? (edge.isCrossing()) ? 0.01f : 0.1f : 0.f;
     161         5908 :         osg::Vec4ubArray* osg_colors = new osg::Vec4ubArray(1);
     162              :         (*osg_colors)[0].set(128, 128, 128, 255);
     163         5908 :         geom->setColorArray(osg_colors, osg::Array::BIND_OVERALL);
     164         5908 :         osg::Vec3Array* osg_coords = new osg::Vec3Array(totalShapeSize);
     165         5908 :         geom->setVertexArray(osg_coords);
     166              :         int sizeDiff = 0;
     167         5908 :         if (edge.isWalkingArea()) {
     168          185 :             int index = upperShapeSize - 1;
     169         1266 :             for (int k = 0; k < upperShapeSize; ++k, --index) {
     170         1081 :                 (*osg_coords)[index].set((float)shape[k].x(), (float)shape[k].y(), (float)shape[k].z() + zOffset);
     171              :             }
     172          370 :             geom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::POLYGON, 0, upperShapeSize));
     173              :         } else {
     174              :             int index = 0;
     175              :             PositionVector rshape = shape;
     176         5723 :             rshape.move2side(l->getWidth() / 2);
     177        17595 :             for (int k = (int)rshape.size() - 1; k >= 0; --k, ++index) {
     178        11872 :                 (*osg_coords)[index].set((float)rshape[k].x(), (float)rshape[k].y(), (float)rshape[k].z() + zOffset);
     179              :             }
     180              :             PositionVector lshape = shape;
     181         5723 :             lshape.move2side(-l->getWidth() / 2);
     182        17595 :             for (int k = 0; k < (int)lshape.size(); ++k, ++index) {
     183        11872 :                 (*osg_coords)[index].set((float)lshape[k].x(), (float)lshape[k].y(), (float)lshape[k].z() + zOffset);
     184              :             }
     185         5723 :             sizeDiff = (int)rshape.size() + (int)lshape.size() - upperShapeSize;
     186              :             int minSize = MIN2((int)rshape.size(), (int)lshape.size());
     187         5723 :             osg::DrawElementsUInt* surface = new osg::DrawElementsUInt(osg::PrimitiveSet::TRIANGLE_STRIP, 0);
     188        17595 :             for (int i = 0; i < minSize; ++i) {
     189        11872 :                 surface->push_back(i);
     190        11872 :                 surface->push_back(upperShapeSize + sizeDiff - 1 - i);
     191              :             }
     192         5723 :             geom->addPrimitiveSet(surface);
     193         5723 :         }
     194         5908 :         if (extrude) {
     195              :             int index = upperShapeSize;
     196         2692 :             for (int k = 0; k < upperShapeSize + sizeDiff; ++k, ++index) {
     197         2225 :                 (*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         2692 :             for (int i = 0; i < upperShapeSize + sizeDiff; ++i) {
     201         2225 :                 osg::Vec3 surfaceVec = (*osg_coords)[i] - (*osg_coords)[(i + 1) % (upperShapeSize + sizeDiff)];
     202         2225 :                 if (surfaceVec.length() > 0.) {
     203         2218 :                     osg::DrawElementsUInt* kerb = new osg::DrawElementsUInt(osg::PrimitiveSet::POLYGON, 0);
     204         2218 :                     kerb->push_back(i);
     205         2218 :                     kerb->push_back(upperShapeSize + i);
     206         2218 :                     kerb->push_back(upperShapeSize + (i + 1) % (upperShapeSize + sizeDiff));
     207         2218 :                     kerb->push_back((i + 1) % (upperShapeSize + sizeDiff));
     208         2218 :                     geom->addPrimitiveSet(kerb);
     209              :                 }
     210              :             }
     211              :         }
     212              : 
     213         5908 :         osg::ref_ptr<osg::StateSet> ss = geode->getOrCreateStateSet();
     214         5908 :         ss->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
     215         5908 :         ss->setMode(GL_BLEND, osg::StateAttribute::OVERRIDE | osg::StateAttribute::PROTECTED | osg::StateAttribute::ON);
     216              : 
     217         5908 :         if (shape.size() > 2) {
     218          350 :             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         5908 :         osgUtil::SmoothingVisitor sv;
     230              : #if OSG_MIN_VERSION_REQUIRED(3,5,4)
     231              :         sv.setCreaseAngle(0.6 * osg::PI);
     232              : #endif
     233         5908 :         geom->accept(sv);
     234              :         static_cast<GUILane*>(l)->setGeometry(geom);
     235         5908 :     }
     236         4195 : }
     237              : 
     238              : 
     239              : void
     240         4632 : GUIOSGBuilder::buildOSGJunctionGeometry(GUIJunctionWrapper& junction,
     241              :                                         osg::Group& addTo,
     242              :                                         osgUtil::Tessellator& tessellator) {
     243              :     const PositionVector& shape = junction.getJunction().getShape();
     244         4632 :     osg::Geode* geode = new osg::Geode();
     245         4632 :     osg::Geometry* geom = new osg::Geometry();
     246         4632 :     geode->addDrawable(geom);
     247         4632 :     geode->setName("junction:" + junction.getMicrosimID());
     248         4632 :     addTo.addChild(geode);
     249         4632 :     dynamic_cast<GUIGlObject&>(junction).setNode(geode);
     250         4632 :     osg::Vec3Array* osg_coords = new osg::Vec3Array((int)shape.size()); // OSG needs float coordinates here
     251         4632 :     geom->setVertexArray(osg_coords);
     252        18214 :     for (int k = 0; k < (int)shape.size(); ++k) {
     253        13582 :         (*osg_coords)[k].set((float)shape[k].x(), (float)shape[k].y(), (float)shape[k].z());
     254              :     }
     255         4632 :     osg::Vec3Array* osg_normals = new osg::Vec3Array(1);
     256         4632 :     (*osg_normals)[0] = osg::Vec3(0, 0, 1); // OSG needs float coordinates here
     257         4632 :     geom->setNormalArray(osg_normals, osg::Array::BIND_PER_PRIMITIVE_SET);
     258         4632 :     osg::Vec4ubArray* osg_colors = new osg::Vec4ubArray(1);
     259              :     (*osg_colors)[0].set(128, 128, 128, 255);
     260         4632 :     geom->setColorArray(osg_colors, osg::Array::BIND_OVERALL);
     261         4632 :     geom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::POLYGON, 0, (int)shape.size()));
     262              : 
     263         4632 :     osg::ref_ptr<osg::StateSet> ss = geode->getOrCreateStateSet();
     264         4632 :     ss->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
     265         4632 :     ss->setMode(GL_BLEND, osg::StateAttribute::OVERRIDE | osg::StateAttribute::PROTECTED | osg::StateAttribute::ON);
     266              : 
     267         4632 :     if (shape.size() > 4) {
     268          939 :         tessellator.retessellatePolygons(*geom);
     269              :     }
     270              :     junction.setGeometry(geom);
     271         4632 : }
     272              : 
     273              : 
     274              : void
     275            0 : GUIOSGBuilder::buildPolygonGeometry(const SUMOPolygon& poly, osg::Group& addTo, osgUtil::Tessellator& tessellator) {
     276            0 :     const PositionVector& shape = poly.getShape();
     277            0 :     const std::vector<PositionVector>& holes = poly.getHoles();
     278            0 :     const bool useZ = shape.hasElevation();
     279              :     //const bool isFilled = poly.getFill();
     280              :     //const double lineWidth = poly.getLineWidth();
     281              : 
     282            0 :     osg::Geode* geode = new osg::Geode();
     283            0 :     osg::Geometry* geom = new osg::Geometry();
     284            0 :     geode->addDrawable(geom);
     285            0 :     geode->setName("polygon:" + poly.getID());
     286            0 :     addTo.addChild(geode);
     287            0 :     osg::Vec3Array* osg_coords = new osg::Vec3Array((int)shape.size()); // OSG needs float coordinates here
     288            0 :     geom->setVertexArray(osg_coords);
     289            0 :     for (int k = 0; k < (int)shape.size(); ++k) {
     290            0 :         (*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            0 :     osg::Vec3Array* osg_normals = new osg::Vec3Array(1);
     297            0 :     (*osg_normals)[0] = osg::Vec3(0, 0, 1); // OSG needs float coordinates here
     298            0 :     geom->setNormalArray(osg_normals, osg::Array::BIND_PER_PRIMITIVE_SET);
     299            0 :     osg::Vec4ubArray* osg_colors = new osg::Vec4ubArray(1);
     300            0 :     const RGBColor col = poly.getShapeColor();
     301            0 :     (*osg_colors)[0].set(col.red(), col.green(), col.blue(), 255);
     302            0 :     geom->setColorArray(osg_colors, osg::Array::BIND_OVERALL);
     303            0 :     geom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::POLYGON, 0, (int)shape.size()));
     304              : 
     305            0 :     osg::ref_ptr<osg::StateSet> ss = geode->getOrCreateStateSet();
     306            0 :     ss->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
     307            0 :     ss->setMode(GL_BLEND, osg::StateAttribute::OVERRIDE | osg::StateAttribute::PROTECTED | osg::StateAttribute::ON);
     308              : 
     309            0 :     if (shape.size() > 4) {
     310            0 :         tessellator.retessellatePolygons(*geom);
     311              :     }
     312            0 : }
     313              : 
     314              : 
     315              : void
     316            0 : GUIOSGBuilder::buildPoIGeometry(const PointOfInterest& poi, osg::Group& addTo, osgUtil::Tessellator& tessellator) {
     317            0 :     osg::Geode* geode = new osg::Geode();
     318            0 :     osg::Geometry* geom = new osg::Geometry();
     319            0 :     geode->addDrawable(geom);
     320            0 :     geode->setName("poi:" + poi.getID());
     321            0 :     addTo.addChild(geode);
     322            0 :     osg::Vec3Array* osg_coords = new osg::Vec3Array(4); // OSG needs float coordinates here
     323            0 :     geom->setVertexArray(osg_coords);
     324              :     // make a square
     325            0 :     const Position& center = poi.getCenter();
     326            0 :     const double width = poi.getWidth();
     327            0 :     const double height = poi.getHeight();
     328            0 :     PositionVector shape;
     329            0 :     shape.push_back(Position(center.x() - 0.5 * width, center.y() + 0.5 * height));
     330            0 :     shape.push_back(Position(center.x() + 0.5 * width, center.y() + 0.5 * height));
     331            0 :     shape.push_back(Position(center.x() + 0.5 * width, center.y() - 0.5 * height));
     332            0 :     shape.push_back(Position(center.x() - 0.5 * width, center.y() - 0.5 * height));
     333            0 :     for (unsigned int k = 0; k < shape.size(); ++k) {
     334            0 :         (*osg_coords)[k].set((float)shape[k].x(), (float)shape[k].y(), 0.2f);
     335              :     }
     336            0 :     osg::Vec3Array* osg_normals = new osg::Vec3Array(1);
     337            0 :     (*osg_normals)[0] = osg::Vec3(0, 0, 1); // OSG needs float coordinates here
     338            0 :     geom->setNormalArray(osg_normals, osg::Array::BIND_PER_PRIMITIVE_SET);
     339            0 :     osg::Vec4ubArray* osg_colors = new osg::Vec4ubArray(1);
     340            0 :     const RGBColor col = poi.getShapeColor();
     341            0 :     (*osg_colors)[0].set(col.red(), col.green(), col.blue(), 255);
     342            0 :     geom->setColorArray(osg_colors, osg::Array::BIND_OVERALL);
     343            0 :     geom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::POLYGON, 0, (int)shape.size()));
     344              : 
     345            0 :     osg::ref_ptr<osg::StateSet> ss = geode->getOrCreateStateSet();
     346            0 :     ss->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
     347            0 :     ss->setMode(GL_BLEND, osg::StateAttribute::OVERRIDE | osg::StateAttribute::PROTECTED | osg::StateAttribute::ON);
     348              : 
     349            0 :     if (shape.size() > 4) {
     350            0 :         tessellator.retessellatePolygons(*geom);
     351              :     }
     352            0 : }
     353              : 
     354              : 
     355              : void
     356          111 : 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          111 :     osg::ComputeBoundsVisitor bboxCalc;
     359          111 :     poleBase->accept(bboxCalc);
     360          111 :     const double poleDiameter = bboxCalc.getBoundingBox().yMax() - bboxCalc.getBoundingBox().yMin();
     361          111 :     tlg->accept(bboxCalc);
     362          111 :     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          111 :     MSTrafficLightLogic* tlLogic = vars.getActive();
     366              :     const MSTrafficLightLogic::LinkVectorVector& allLinks = tlLogic->getLinks();
     367              :     std::set<const MSEdge*> seenEdges;
     368              : 
     369         1796 :     for (const MSTrafficLightLogic::LinkVector& lv : allLinks) {
     370         3370 :         for (const MSLink* tlLink : lv) {
     371              :             // if not in seenEdges, create pole and reference it in the maps above
     372         1685 :             const MSEdge* approach = &tlLink->getLaneBefore()->getEdge();
     373         3290 :             if (!approach->isWalkingArea() && seenEdges.find(approach) != seenEdges.end()) {
     374         1224 :                 continue;
     375              :             }
     376          461 :             const std::vector<MSLane*> appLanes = approach->getLanes();
     377              :             // ref pos
     378              :             const double poleMinHeight = 5.;
     379              :             const double poleOffset = .5;
     380          461 :             double angle = 90. - appLanes[0]->getShape().rotationDegreeAtOffset(-1.);
     381          461 :             bool onlyPedCycle = isBikepath(approach->getPermissions()) || isSidewalk(approach->getPermissions());
     382          461 :             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          461 :             osg::PositionAttitudeTransform* appBase = new osg::PositionAttitudeTransform();
     388          461 :             osg::PositionAttitudeTransform* rightPoleBase = new osg::PositionAttitudeTransform();
     389          461 :             osg::PositionAttitudeTransform* rightPoleScaleNode = new osg::PositionAttitudeTransform();
     390          461 :             rightPoleScaleNode->addChild(poleBase);
     391          461 :             rightPoleBase->addChild(rightPoleScaleNode);
     392          461 :             appBase->addChild(rightPoleBase);
     393              :             rightPoleBase->setPosition(osg::Vec3d(pos.x(), pos.y(), pos.z()));
     394          922 :             rightPoleBase->setAttitude(osg::Quat(0., osg::Vec3d(1, 0, 0),
     395          461 :                                                  0., osg::Vec3d(0, 1, 0),
     396          461 :                                                  DEG2RAD(angle), osg::Vec3d(0, 0, 1)));
     397          461 :             if (onlyPedCycle) { // pedestrian / cyclist signal only
     398           82 :                 rightPoleScaleNode->setScale(osg::Vec3d(.12 / poleDiameter, .12 / poleDiameter, 2.8));
     399           82 :                 if (approach->isCrossing()) { // center VRU signal pole at crossings
     400              :                     // move pole to the other side of the road
     401            0 :                     osg::Vec3d offset(cos(DEG2RAD(angle)), sin(DEG2RAD(angle)), 0.);
     402            0 :                     appBase->setPosition(appBase->getPosition() + offset * (poleOffset + approach->getLength()));
     403            0 :                     appBase->setAttitude(osg::Quat(0., osg::Vec3d(1, 0, 0),
     404            0 :                                                    0., osg::Vec3d(0, 1, 0),
     405            0 :                                                    DEG2RAD(angle + 180), osg::Vec3d(0, 0, 1)));
     406           82 :                 } else if (approach->isWalkingArea()) { // pole for other direction > get position from crossing
     407           80 :                     pos = tlLink->getLane()->getShape().back();
     408           80 :                     angle = 90. - tlLink->getLane()->getShape().rotationDegreeAtOffset(-1.);
     409           80 :                     rightPoleBase->setPosition(osg::Vec3d(pos.x(), pos.y(), pos.z()) - osg::Vec3d(poleOffset * cos(DEG2RAD(angle)), poleOffset * sin(DEG2RAD(angle)), 0.));
     410           80 :                     rightPoleBase->setAttitude(osg::Quat(0., osg::Vec3d(1, 0, 0),
     411           80 :                                                          0., osg::Vec3d(0, 1, 0),
     412           80 :                                                          DEG2RAD(angle), osg::Vec3d(0, 0, 1)));
     413           80 :                     if (tlLink->getLane()->getLinkCont()[0]->getTLIndex() < 0) { // check whether the other side is not specified explicitly
     414           80 :                         osg::PositionAttitudeTransform* leftPoleBase = new osg::PositionAttitudeTransform();
     415           80 :                         osg::PositionAttitudeTransform* leftPoleScaleNode = new osg::PositionAttitudeTransform();
     416           80 :                         appBase->addChild(leftPoleBase);
     417           80 :                         leftPoleScaleNode->addChild(poleBase);
     418              :                         leftPoleScaleNode->setScale(osg::Vec3d(.12 / poleDiameter, .12 / poleDiameter, 2.8));
     419           80 :                         leftPoleBase->addChild(leftPoleScaleNode);
     420           80 :                         double otherAngle = 90. - tlLink->getLane()->getShape().rotationDegreeAtOffset(1.);
     421           80 :                         Position otherPosRel = tlLink->getLane()->getShape().front();
     422              :                         osg::Vec3d leftPolePos(otherPosRel.x(), otherPosRel.y(), otherPosRel.z());
     423           80 :                         leftPoleBase->setPosition(leftPolePos + osg::Vec3d(poleOffset * cos(DEG2RAD(otherAngle)), poleOffset * sin(DEG2RAD(otherAngle)), 0.));
     424          160 :                         leftPoleBase->setAttitude(osg::Quat(0., osg::Vec3d(1., 0., 0.),
     425           80 :                                                             0., osg::Vec3d(0., 1., 0.),
     426          160 :                                                             DEG2RAD(angle + 180.), osg::Vec3d(0., 0., 1.)));
     427           80 :                         repeaters.push_back({ leftPoleBase, osg::Vec3d(0., 0., leftPoleBase->getPosition().z())});
     428              :                     }
     429              :                 } else {
     430            2 :                     double laneWidth = appLanes[0]->getWidth();
     431            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.);
     432              :                     rightPoleBase->setPosition(rightPoleBase->getPosition() + offset);
     433              :                 }
     434              :             } else {
     435              :                 // skip sidewalk and bike lane if leftmost lane is for cars
     436          379 :                 if (!noVehicles(appLanes.back()->getPermissions())) {
     437          543 :                     for (MSLane* appLane : appLanes) {
     438              :                         SVCPermissions permissions = appLane->getPermissions();
     439          543 :                         if (isSidewalk(permissions) || isForbidden(permissions)) {
     440          164 :                             skipWidth += appLane->getWidth();
     441              :                         } else {
     442              :                             break;
     443              :                         }
     444          164 :                         firstSignalLaneIx++;
     445              :                     }
     446              :                 }
     447          379 :                 const double laneWidth = appLanes[0]->getWidth();
     448          379 :                 const double horizontalWidth = approach->getWidth() - skipWidth;
     449          379 :                 const int laneCount = (int)appLanes.size() - firstSignalLaneIx;
     450          379 :                 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          379 :                 if (laneCount < 3) { // cantilever
     454          295 :                     const double cantiWidth = horizontalWidth - .1 * appLanes.back()->getWidth() + poleOffset;
     455          295 :                     const double holderWidth = cantiWidth - .4 * appLanes.back()->getWidth();
     456              :                     const double holderAngle = 7.5; // degrees
     457          295 :                     const double extraHeight = sin(DEG2RAD(holderAngle)) * holderWidth;
     458          295 :                     rightPoleScaleNode->setScale(osg::Vec3d(.25 / poleDiameter, .25 / poleDiameter, poleMinHeight + extraHeight));
     459          295 :                     osg::PositionAttitudeTransform* cantileverBase = new osg::PositionAttitudeTransform();
     460              :                     cantileverBase->setPosition(osg::Vec3d(0., 0., poleMinHeight));
     461          295 :                     cantileverBase->setAttitude(osg::Quat(DEG2RAD(90.), osg::Vec3d(1, 0, 0),
     462          295 :                                                           0., osg::Vec3d(0, 1, 0),
     463          295 :                                                           0., osg::Vec3d(0, 0, 1)));
     464              :                     cantileverBase->setScale(osg::Vec3d(1., 1., cantiWidth));
     465          295 :                     cantileverBase->addChild(poleBase);
     466          295 :                     rightPoleBase->addChild(cantileverBase);
     467          295 :                     osg::PositionAttitudeTransform* cantileverHolderBase = new osg::PositionAttitudeTransform();
     468          295 :                     cantileverHolderBase->setPosition(osg::Vec3d(0., 0., poleMinHeight + extraHeight - .02));
     469          295 :                     cantileverHolderBase->setAttitude(osg::Quat(DEG2RAD(90. + holderAngle), osg::Vec3d(1, 0, 0),
     470          295 :                                                       0., osg::Vec3d(0, 1, 0),
     471          295 :                                                       0., osg::Vec3d(0, 0, 1)));
     472          295 :                     cantileverHolderBase->setScale(osg::Vec3d(.04 / poleDiameter, .04 / poleDiameter, sqrt(pow(holderWidth, 2.) + pow(extraHeight, 2.))));
     473          295 :                     cantileverHolderBase->addChild(poleBase);
     474          295 :                     rightPoleBase->addChild(cantileverHolderBase);
     475              :                 } else { // signal bridge
     476           84 :                     rightPoleScaleNode->setScale(osg::Vec3d(.25 / poleDiameter, .25 / poleDiameter, poleMinHeight));
     477           84 :                     osg::PositionAttitudeTransform* leftPoleBase = new osg::PositionAttitudeTransform();
     478           84 :                     leftPoleBase->addChild(poleBase);
     479              :                     leftPoleBase->setScale(osg::Vec3d(.25 / poleDiameter, .25 / poleDiameter, poleMinHeight));
     480           84 :                     osg::Vec3d leftPolePos = osg::Vec3d(0, -(horizontalWidth + 2. * poleOffset), 0.);
     481              :                     leftPoleBase->setPosition(leftPolePos);
     482           84 :                     rightPoleBase->addChild(leftPoleBase);
     483           84 :                     osg::PositionAttitudeTransform* bridgeBase = new osg::PositionAttitudeTransform();
     484              :                     bridgeBase->setPosition(osg::Vec3d(0., 0., poleMinHeight - .125));
     485           84 :                     bridgeBase->setAttitude(osg::Quat(DEG2RAD(90.), osg::Vec3d(1, 0, 0),
     486           84 :                                                       0., osg::Vec3d(0, 1, 0),
     487           84 :                                                       0., osg::Vec3d(0, 0, 1)));
     488              :                     bridgeBase->setScale(osg::Vec3d(.25 / poleDiameter, .25 / poleDiameter, leftPolePos.length()));
     489           84 :                     bridgeBase->addChild(poleBase);
     490           84 :                     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         1126 :             for (std::advance(it, firstSignalLaneIx); it != appLanes.end(); it++) {
     499              :                 // get tlLinkIndices
     500          747 :                 const std::vector<MSLink*>& links = (*it)->getLinkCont();
     501              :                 std::set<int> tlIndices;
     502         2512 :                 for (MSLink* link : links) {
     503         1765 :                     if (link->getTLIndex() > -1) {
     504         1685 :                         tlIndices.insert(link->getTLIndex());
     505              :                     }
     506              :                 }
     507              :                 std::set<int> seenTlIndices;
     508              :                 bool placeRepeaters = true;
     509         2512 :                 for (MSLink* link : links) {
     510         1765 :                     std::vector<std::pair<osg::Group*, osg::Vec3d>> signalTransforms = { {rightPoleBase, osg::Vec3d(0., 0., 0.)} };
     511         1765 :                     if (placeRepeaters) {
     512          747 :                         signalTransforms.insert(signalTransforms.end(), repeaters.begin(), repeaters.end());
     513              :                         repeaters.clear();
     514              :                         placeRepeaters = false;
     515              :                     }
     516         1765 :                     int tlIndex = link->getTLIndex();
     517         3450 :                     if (tlIndex < 0 || seenTlIndices.find(tlIndex) != seenTlIndices.end()) {
     518              :                         continue;
     519              :                     }
     520         3450 :                     for (const std::pair<osg::Group*, osg::Vec3d>& transform : signalTransforms) {
     521              :                         GUISUMOAbstractView::Decal d;
     522         1765 :                         d.centerX = transform.second.x() + 0.15;
     523         1765 :                         d.centerY = (onlyPedCycle) ? 0. : -(refPos + .5 * (*it)->getWidth() - ((double)tlIndices.size() / 2. - 1. + (double)seenTlIndices.size()) * 1.5 * tlWidth);
     524         1765 :                         d.centerY += transform.second.y();
     525         3368 :                         d.centerZ = (onlyPedCycle) ? 2.2 : 3.8;
     526         1765 :                         d.centerZ += transform.second.z();
     527         3368 :                         d.altitude = (onlyPedCycle) ? 0.6 : -1;
     528         1765 :                         osg::PositionAttitudeTransform* tlNode = getTrafficLight(d, vars, links[0], tlg, tly, tlr, tlu, poleBase, false);
     529         1765 :                         tlNode->setAttitude(osg::Quat(0., osg::Vec3d(1, 0, 0),
     530         1765 :                                                       0., osg::Vec3d(0, 1, 0),
     531            0 :                                                       DEG2RAD(180.0), osg::Vec3d(0, 0, 1)));
     532         1765 :                         transform.first->addChild(tlNode);
     533              :                     }
     534              :                     seenTlIndices.insert(tlIndex);
     535         1765 :                 }
     536              :                 // only one signal for bike/pedestrian only edges
     537          747 :                 if (onlyPedCycle) {
     538              :                     break;
     539              :                 }
     540          665 :                 refPos += (*it)->getWidth();
     541              :             }
     542              :             // interaction
     543              :             appBase->setNodeMask(GUIOSGView::NODESET_TLSMODELS);
     544          461 :             appBase->setName("tlLogic:" + tlLogic->getID());
     545          461 :             addTo.addChild(appBase);
     546          461 :         }
     547              :     }
     548          111 : }
     549              : 
     550              : 
     551              : void
     552            0 : GUIOSGBuilder::buildDecal(const GUISUMOAbstractView::Decal& d, osg::Group& addTo) {
     553            0 :     osg::Node* pLoadedModel = osgDB::readNodeFile(d.filename);
     554            0 :     osg::PositionAttitudeTransform* base = new osg::PositionAttitudeTransform();
     555              :     double zOffset = 0.;
     556            0 :     if (pLoadedModel == nullptr) {
     557              :         // check for 2D image
     558            0 :         osg::Image* pImage = osgDB::readImageFile(d.filename);
     559            0 :         if (pImage == nullptr) {
     560              :             base = nullptr;
     561            0 :             WRITE_ERRORF(TL("Could not load '%'."), d.filename);
     562            0 :             return;
     563              :         }
     564            0 :         osg::Texture2D* texture = new osg::Texture2D();
     565            0 :         texture->setImage(pImage);
     566            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.));
     567            0 :         quad->getOrCreateStateSet()->setTextureAttributeAndModes(0, texture);
     568            0 :         osg::Geode* const pModel = new osg::Geode();
     569            0 :         pModel->addDrawable(quad);
     570            0 :         base->addChild(pModel);
     571            0 :         zOffset = d.layer;
     572              :     } else {
     573            0 :         osg::ShadeModel* sm = new osg::ShadeModel();
     574              :         sm->setMode(osg::ShadeModel::FLAT);
     575            0 :         pLoadedModel->getOrCreateStateSet()->setAttribute(sm);
     576            0 :         base->addChild(pLoadedModel);
     577              :     }
     578            0 :     osg::ComputeBoundsVisitor bboxCalc;
     579            0 :     base->accept(bboxCalc);
     580              :     const osg::BoundingBox& bbox = bboxCalc.getBoundingBox();
     581            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())));
     582            0 :     double xScale = d.width > 0 ? d.width / (bbox.xMax() - bbox.xMin()) : 1.;
     583            0 :     double yScale = d.height > 0 ? d.height / (bbox.yMax() - bbox.yMin()) : 1.;
     584            0 :     const double zScale = d.altitude > 0 ? d.altitude / (bbox.zMax() - bbox.zMin()) : 1.;
     585            0 :     if (d.width < 0 && d.height < 0 && d.altitude > 0) {
     586              :         xScale = yScale = zScale;
     587              :     }
     588              :     base->setScale(osg::Vec3d(xScale, yScale, zScale));
     589            0 :     base->setPosition(osg::Vec3d(d.centerX, d.centerY, d.centerZ + zOffset));
     590            0 :     base->setAttitude(osg::Quat(osg::DegreesToRadians(d.roll), osg::Vec3d(1, 0, 0),
     591            0 :                                 osg::DegreesToRadians(d.tilt), osg::Vec3d(0, 1, 0),
     592            0 :                                 osg::DegreesToRadians(d.rot), osg::Vec3d(0, 0, 1)));
     593            0 :     addTo.addChild(base);
     594            0 : }
     595              : 
     596              : 
     597              : osg::PositionAttitudeTransform*
     598         3450 : 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         3450 :     osg::PositionAttitudeTransform* ret = new osg::PositionAttitudeTransform();
     600              :     double xScale = 1., yScale = 1., zScale = 1.;
     601         3450 :     if (tlg != nullptr) {
     602         1765 :         osg::ComputeBoundsVisitor bboxCalc;
     603         1765 :         tlg->accept(bboxCalc);
     604              :         const osg::BoundingBox& bbox = bboxCalc.getBoundingBox();
     605         1765 :         xScale = d.width > 0 ? d.width / (bbox.xMax() - bbox.xMin()) : 1.;
     606         1765 :         yScale = d.height > 0 ? d.height / (bbox.yMax() - bbox.yMin()) : 1.;
     607         1765 :         double addHeight = (withPole) ? poleHeight : 0.;
     608         1765 :         zScale = d.altitude > 0 ? d.altitude / (addHeight + bbox.zMax() - bbox.zMin()) : 1.;
     609         1765 :     }
     610         3450 :     if (d.width < 0 && d.height < 0 && d.altitude > 0) {
     611              :         xScale = yScale = zScale;
     612              :     }
     613         3450 :     osg::PositionAttitudeTransform* base = new osg::PositionAttitudeTransform();
     614         3450 :     osg::Switch* switchNode = new osg::Switch();
     615         3450 :     switchNode->addChild(createTrafficLightState(d, tlg, withPole, size, osg::Vec4d(0., 1., 0., transparency)));
     616         3450 :     switchNode->addChild(createTrafficLightState(d, tly, withPole, size, osg::Vec4d(1., 1., 0., transparency)));
     617         3450 :     switchNode->addChild(createTrafficLightState(d, tlr, withPole, size, osg::Vec4d(1., 0., 0., transparency)));
     618         3450 :     switchNode->addChild(createTrafficLightState(d, tlu, withPole, size, osg::Vec4d(1., .5, 0., transparency)));
     619         3450 :     base->addChild(switchNode);
     620         3450 :     vars.addSwitchCommand(new GUIOSGView::Command_TLSChange(link, switchNode));
     621         3450 :     if (withPole) {
     622              :         base->setPosition(osg::Vec3d(0., 0., poleHeight));
     623            0 :         osg::PositionAttitudeTransform* poleBase = new osg::PositionAttitudeTransform();
     624            0 :         poleBase->addChild(pole);
     625              :         poleBase->setScale(osg::Vec3d(1., 1., poleHeight));
     626            0 :         ret->addChild(poleBase);
     627              :     }
     628         6900 :     ret->setAttitude(osg::Quat(osg::DegreesToRadians(d.roll), osg::Vec3(1, 0, 0),
     629         3450 :                                osg::DegreesToRadians(d.tilt), osg::Vec3(0, 1, 0),
     630         3450 :                                osg::DegreesToRadians(d.rot), osg::Vec3(0, 0, 1)));
     631         3450 :     ret->setPosition(osg::Vec3d(d.centerX, d.centerY, d.centerZ));
     632              :     ret->setScale(osg::Vec3d(xScale, yScale, zScale));
     633         3450 :     ret->addChild(base);
     634         3450 :     return ret;
     635              : }
     636              : 
     637              : 
     638              : osg::PositionAttitudeTransform*
     639        13800 : GUIOSGBuilder::createTrafficLightState(const GUISUMOAbstractView::Decal& d, osg::Node* tl, const double withPole, const double size, osg::Vec4d color) {
     640        13800 :     osg::PositionAttitudeTransform* ret = new osg::PositionAttitudeTransform();
     641        13800 :     if (tl != nullptr) {
     642         7060 :         ret->addChild(tl);
     643              :     }
     644        13800 :     if (size > 0.) {
     645         6740 :         unsigned int nodeMask = (withPole) ? GUIOSGView::NodeSetGroup::NODESET_TLSDOMES : GUIOSGView::NodeSetGroup::NODESET_TLSLINKMARKERS;
     646         6740 :         osg::Geode* geode = new osg::Geode();
     647         6740 :         osg::Vec3d center = osg::Vec3d(0., 0., (withPole) ? -1.8 : 0.);
     648         6740 :         osg::ShapeDrawable* shape = new osg::ShapeDrawable(new osg::Sphere(center, (float)size));
     649         6740 :         geode->addDrawable(shape);
     650         6740 :         osg::ref_ptr<osg::StateSet> ss = shape->getOrCreateStateSet();
     651         6740 :         ss->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
     652         6740 :         ss->setMode(GL_BLEND, osg::StateAttribute::OVERRIDE | osg::StateAttribute::PROTECTED | osg::StateAttribute::ON);
     653         6740 :         shape->setColor(color);
     654         6740 :         osg::PositionAttitudeTransform* ellipse = new osg::PositionAttitudeTransform();
     655         6740 :         ellipse->addChild(geode);
     656              :         ellipse->setPosition(center);
     657              :         ellipse->setPivotPoint(center);
     658         6740 :         if (withPole) {
     659            0 :             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         6740 :         ret->addChild(ellipse);
     665              :     }
     666        13800 :     return ret;
     667              : }
     668              : 
     669              : 
     670              : void
     671       100176 : GUIOSGBuilder::setShapeState(osg::ref_ptr<osg::ShapeDrawable> shape) {
     672       100176 :     osg::ref_ptr<osg::StateSet> ss = shape->getOrCreateStateSet();
     673       100176 :     ss->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
     674       100176 :     ss->setMode(GL_BLEND, osg::StateAttribute::OVERRIDE | osg::StateAttribute::PROTECTED | osg::StateAttribute::ON);
     675       100176 : }
     676              : 
     677              : 
     678              : GUIOSGView::OSGMovable
     679        33796 : GUIOSGBuilder::buildMovable(const MSVehicleType& type) {
     680              :     GUIOSGView::OSGMovable m;
     681        33796 :     m.pos = new osg::PositionAttitudeTransform();
     682              :     double enlarge = 0.05;
     683              :     const std::string& osgFile = type.getOSGFile();
     684        33796 :     if (myCars.find(osgFile) == myCars.end()) {
     685          378 :         myCars[osgFile] = osgDB::readNodeFile(osgFile);
     686          378 :         if (myCars[osgFile] == 0) {
     687            0 :             WRITE_ERRORF(TL("Could not load '%'. The model is replaced by a cone shape."), osgFile);
     688            0 :             osg::PositionAttitudeTransform* rot = new osg::PositionAttitudeTransform();
     689            0 :             rot->addChild(new osg::ShapeDrawable(new osg::Cone(osg::Vec3d(0, 0, 0), 1.0f, 1.0f)));
     690            0 :             rot->setAttitude(osg::Quat(osg::DegreesToRadians(90.), osg::Vec3(1, 0, 0),
     691            0 :                                        0., osg::Vec3(0, 1, 0),
     692            0 :                                        0., osg::Vec3(0, 0, 1)));
     693            0 :             myCars[osgFile] = rot;
     694              :         }
     695              :     }
     696        33796 :     osg::Node* carNode = myCars[osgFile];
     697        33796 :     if (carNode != nullptr) {
     698        33796 :         osg::ComputeBoundsVisitor bboxCalc;
     699        33796 :         carNode->accept(bboxCalc);
     700              :         const osg::BoundingBox& bbox = bboxCalc.getBoundingBox();
     701        33796 :         osg::PositionAttitudeTransform* base = new osg::PositionAttitudeTransform();
     702        33796 :         base->addChild(carNode);
     703        33796 :         base->setPivotPoint(osg::Vec3d((bbox.xMin() + bbox.xMax()) / 2., bbox.yMin(), bbox.zMin()));
     704        33796 :         base->setScale(osg::Vec3d(type.getWidth() / (bbox.xMax() - bbox.xMin()),
     705        33796 :                                   type.getLength() / (bbox.yMax() - bbox.yMin()),
     706        33796 :                                   type.getHeight() / (bbox.zMax() - bbox.zMin())));
     707        33796 :         m.body = base;
     708        33796 :         m.pos->addChild(base);
     709              : 
     710              :         // material for coloring the person or vehicle body
     711        33796 :         m.mat = new osg::Material();
     712        33796 :         osg::ref_ptr<osg::StateSet> ss = base->getOrCreateStateSet();
     713              :         ss->setAttribute(m.mat, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE | osg::StateAttribute::PROTECTED);
     714        33796 :         ss->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
     715        33796 :         ss->setMode(GL_BLEND, osg::StateAttribute::OVERRIDE | osg::StateAttribute::PROTECTED | osg::StateAttribute::ON);
     716        33796 :     }
     717        33796 :     if (type.getVehicleClass() != SVC_PEDESTRIAN) {
     718        33392 :         m.lights = new osg::Switch();
     719       100176 :         for (double sideFactor = -1.; sideFactor < 2.5; sideFactor += 2.) {
     720        66784 :             osg::Geode* geode = new osg::Geode();
     721        66784 :             osg::ShapeDrawable* right = new osg::ShapeDrawable(new osg::Sphere(osg::Vec3d((type.getWidth() / 2. + enlarge)*sideFactor, 0., type.getHeight() / 2.), 0.2f));
     722        66784 :             geode->addDrawable(right);
     723              :             //pat->addChild(geode);
     724       133568 :             setShapeState(right);
     725        66784 :             right->setColor(osg::Vec4(1.f, .5f, 0.f, .8f));
     726        66784 :             osg::Sequence* seq = new osg::Sequence();
     727              :             // Wikipedia says about 1.5Hz
     728        66784 :             seq->addChild(geode, .33);
     729        66784 :             seq->addChild(new osg::Geode(), .33);
     730              :             // loop through all children
     731        66784 :             seq->setInterval(osg::Sequence::LOOP, 0, -1);
     732              :             // real-time playback, repeat indefinitely
     733        66784 :             seq->setDuration(1.0f, -1);
     734              :             // must be started explicitly
     735        66784 :             seq->setMode(osg::Sequence::START);
     736        66784 :             m.lights->addChild(seq);
     737              :         }
     738        33392 :         osg::Geode* geode = new osg::Geode();
     739        33392 :         osg::CompositeShape* comp = new osg::CompositeShape();
     740        33392 :         comp->addChild(new osg::Sphere(osg::Vec3d(-(type.getWidth() / 2. + enlarge), type.getLength() + enlarge, type.getHeight() / 2.), .2f));
     741        33392 :         comp->addChild(new osg::Sphere(osg::Vec3d(type.getWidth() / 2. + enlarge, type.getLength() + enlarge, type.getHeight() / 2.), .2f));
     742        33392 :         osg::ShapeDrawable* brake = new osg::ShapeDrawable(comp);
     743        33392 :         brake->setColor(osg::Vec4(1.f, 0.f, 0.f, .8f));
     744        33392 :         geode->addDrawable(brake);
     745        66784 :         setShapeState(brake);
     746        33392 :         m.lights->addChild(geode);
     747              : 
     748        33392 :         osg::Vec3d center(0, -type.getLength() / 2., 0.);
     749        33392 :         osg::PositionAttitudeTransform* ellipse = new osg::PositionAttitudeTransform();
     750        33392 :         ellipse->addChild(geode);
     751              :         ellipse->addChild(m.lights);
     752              :         ellipse->setPivotPoint(center);
     753              :         ellipse->setPosition(center);
     754        33392 :         m.pos->addChild(ellipse);
     755              :     }
     756        33796 :     m.active = true;
     757        33796 :     return m;
     758            0 : }
     759              : 
     760              : 
     761              : osg::Node*
     762          436 : GUIOSGBuilder::buildPlane(const float length) {
     763          436 :     osg::Geode* geode = new osg::Geode();
     764          436 :     osg::Geometry* geom = new osg::Geometry;
     765          436 :     geode->addDrawable(geom);
     766          436 :     osg::Vec3Array* coords = new osg::Vec3Array(4); // OSG needs float coordinates here
     767          436 :     geom->setVertexArray(coords);
     768          436 :     (*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          436 :     osg::Vec3Array* normals = new osg::Vec3Array(1); // OSG needs float coordinates here
     773              :     (*normals)[0].set(0, 0, 1);
     774          436 :     geom->setNormalArray(normals, osg::Array::BIND_PER_PRIMITIVE_SET);
     775          436 :     osg::Vec4ubArray* colors = new osg::Vec4ubArray(1);
     776              :     (*colors)[0].set(0, 255, 0, 255);
     777          436 :     geom->setColorArray(colors, osg::Array::BIND_OVERALL);
     778          872 :     geom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::POLYGON, 0, 4));
     779              : 
     780          436 :     osg::ref_ptr<osg::StateSet> ss = geode->getOrCreateStateSet();
     781          436 :     ss->setRenderingHint(osg::StateSet::OPAQUE_BIN);
     782          436 :     ss->setMode(GL_BLEND, osg::StateAttribute::OVERRIDE | osg::StateAttribute::PROTECTED | osg::StateAttribute::ON);
     783              : 
     784          436 :     return geode;
     785              : }
     786              : 
     787              : 
     788              : #endif
     789              : 
     790              : /****************************************************************************/
        

Generated by: LCOV version 2.0-1