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 : /****************************************************************************/
|