]> git.mxchange.org Git - flightgear.git/blob - src/Cockpit/groundradar.cxx
Initial commit for mongoose httpd
[flightgear.git] / src / Cockpit / groundradar.cxx
1 //  groundradar.cxx - Background layer for the ATC radar.
2 //
3 //  Copyright (C) 2007 Csaba Halasz.
4 //
5 //  This program is free software; you can redistribute it and/or
6 //  modify it under the terms of the GNU General Public License as
7 //  published by the Free Software Foundation; either version 2 of the
8 //  License, or (at your option) any later version.
9 //
10 //  This program is distributed in the hope that it will be useful, but
11 //  WITHOUT ANY WARRANTY; without even the implied warranty of
12 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13 //  General Public License for more details.
14 //
15 //  You should have received a copy of the GNU General Public License
16 //  along with this program; if not, write to the Free Software
17 //  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
18
19 #ifdef HAVE_CONFIG_H
20 #  include "config.h"
21 #endif
22
23 #include <cassert>
24
25 #include <osg/Node>
26 #include <osg/Geode>
27 #include <osg/Geometry>
28 #include <osg/Camera>
29 #include <osg/Texture2D>
30 #include <osgViewer/Viewer>
31
32 #include <osgText/Text>
33 #include <osgDB/Registry>
34 #include <osgDB/ReaderWriter>
35 #include <osgUtil/Tessellator>
36
37 #include <Main/fg_props.hxx>
38 #include <Main/globals.hxx>
39 #include <Viewer/renderer.hxx>
40 #include <Cockpit/panel.hxx>
41 #include <Airports/airport.hxx>
42 #include <Airports/runways.hxx>
43 #include <Airports/pavement.hxx>
44 #include <simgear/math/sg_geodesy.hxx>
45 #include <simgear/math/beziercurve.hxx>
46
47 #include "groundradar.hxx"
48
49 static const char* airport_source_node_name = "airport-id-source";
50 static const char* default_airport_node_name = "/sim/airport/closest-airport-id";
51 static const char* texture_node_name = "texture-name";
52 static const char* default_texture_name = "Aircraft/Instruments/Textures/od_groundradar.rgb";
53 static const char* range_source_node_name = "range-source";
54 static const char* default_range_node_name = "/instrumentation/radar/range";
55
56 struct SingleFrameCallback : public osg::Camera::DrawCallback
57 {
58     virtual void operator () (const osg::Camera& camera) const
59     {
60         const_cast<osg::Camera&>(camera).setNodeMask(0);
61     }
62 };
63
64 GroundRadar::GroundRadar(SGPropertyNode *node)
65 {
66     _airport_node = fgGetNode(node->getStringValue(airport_source_node_name, default_airport_node_name), true);
67     _range_node = fgGetNode(node->getStringValue(range_source_node_name, default_range_node_name), true);
68     createTexture(node->getStringValue(texture_node_name, default_texture_name));
69     updateTexture();
70     _airport_node->addChangeListener(this);
71     _range_node->addChangeListener(this);
72 }
73
74 GroundRadar::~GroundRadar()
75 {
76     _airport_node->removeChangeListener(this);
77     _range_node->removeChangeListener(this);
78 }
79
80 void GroundRadar::update (double /* dt */)
81 {
82   
83 }
84
85 void GroundRadar::valueChanged(SGPropertyNode*)
86 {
87     updateTexture();
88 }
89
90 inline static osg::Vec3 fromPolar(double fi, double r)
91 {
92     return osg::Vec3(sin(fi * SGD_DEGREES_TO_RADIANS) * r, cos(fi * SGD_DEGREES_TO_RADIANS) * r, 0);
93 }
94
95 void GroundRadar::createTexture(const char* texture_name)
96 {
97     setSize(TextureHalfSize + TextureHalfSize);
98     allocRT();
99
100     _geode = new osg::Geode();
101     osg::StateSet* stateset = _geode->getOrCreateStateSet();
102     stateset->setMode(GL_BLEND, osg::StateAttribute::OFF);
103
104     osg::Vec4Array* taxi_color = new osg::Vec4Array;
105     taxi_color->push_back(osg::Vec4(0.0f, 0.5f, 0.0f, 1.0f));
106     osg::Vec4Array* rwy_color = new osg::Vec4Array;
107     rwy_color->push_back(osg::Vec4(0.0f, 0.5f, 0.5f, 1.0f));
108
109     osg::Geometry *taxi_geom = new osg::Geometry();
110     taxi_geom->setColorArray(taxi_color);
111     taxi_geom->setColorBinding(osg::Geometry::BIND_OVERALL);
112     taxi_geom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::QUADS, 0, 0)); // Taxiways
113     _geode->addDrawable(taxi_geom);
114
115     osg::Geometry *pvt_geom = new osg::Geometry();
116     pvt_geom->setColorArray(taxi_color);
117     pvt_geom->setColorBinding(osg::Geometry::BIND_OVERALL);
118     // no primitive set for the moment. It needs tessellation
119     _geode->addDrawable(pvt_geom);
120
121     osg::Geometry *rwy_geom = new osg::Geometry();
122     rwy_geom->setColorArray(rwy_color);
123     rwy_geom->setColorBinding(osg::Geometry::BIND_OVERALL);
124     rwy_geom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::QUADS, 0, 0)); // Runways
125     _geode->addDrawable(rwy_geom);
126
127     osg::Camera* camera = getCamera();
128     camera->setPostDrawCallback(new SingleFrameCallback());
129     camera->addChild(_geode.get());
130     camera->setNodeMask(0);
131     camera->setProjectionMatrixAsOrtho2D(0, getTexture()->getTextureWidth(), 0, getTexture()->getTextureHeight());
132
133     // Texture in the 2D panel system
134     FGTextureManager::addTexture(texture_name, getTexture());
135 }
136
137 void GroundRadar::addRunwayVertices(const FGRunwayBase* aRunway, double aTowerLat, double aTowerLon, double aScale, osg::Vec3Array* aVertices)
138 {
139   double az1, az2, dist_m;
140   geo_inverse_wgs_84(aTowerLat, aTowerLon, aRunway->latitude(), aRunway->longitude(), &az1, &az2, &dist_m);
141
142   osg::Vec3 center = fromPolar(az1, dist_m * aScale) + osg::Vec3(TextureHalfSize, TextureHalfSize, 0);
143   osg::Vec3 leftcenter = fromPolar(aRunway->headingDeg(), aRunway->lengthM() * aScale / 2) + center;
144   osg::Vec3 lefttop = fromPolar(aRunway->headingDeg() - 90, aRunway->widthM() * aScale / 2) + leftcenter;
145   osg::Vec3 leftbottom = leftcenter * 2 - lefttop;
146   osg::Vec3 rightbottom = center * 2 - lefttop;
147   osg::Vec3 righttop = center * 2 - leftbottom;
148
149   aVertices->push_back(lefttop);
150   aVertices->push_back(leftbottom);
151   aVertices->push_back(rightbottom);
152   aVertices->push_back(righttop);
153 }
154
155 osg::Geometry *GroundRadar::addPavementGeometry(const FGPavement* aPavement, double aTowerLat, double aTowerLon, double aScale)
156 {
157
158   osg::ref_ptr<osgUtil::Tessellator> tess = new osgUtil::Tessellator;
159   osg::ref_ptr<osg::Geometry> polygon = new osg::Geometry;
160   osg::ref_ptr<osg::Vec3Array> pts = new osg::Vec3Array;
161
162   double az1, az2, dist_m;
163   const FGPavement::NodeList &nodeLst = aPavement->getNodeList();
164   FGPavement::NodeList::const_iterator it = nodeLst.begin(),
165                                         loopBegin = it;
166   while ( it != nodeLst.end() )
167   {
168     bool close = (*it)->mClose;
169     geo_inverse_wgs_84(aTowerLat, aTowerLon, (*it)->mPos.getLatitudeDeg(), (*it)->mPos.getLongitudeDeg(), &az1, &az2, &dist_m);
170     osg::Vec3 p1 = fromPolar(az1, dist_m * aScale) + osg::Vec3(TextureHalfSize, TextureHalfSize, 0);
171     const FGPavement::BezierNode *bn = dynamic_cast<const FGPavement::BezierNode *>( it->ptr() );
172     if ( bn != 0 )
173     {
174       geo_inverse_wgs_84(aTowerLat, aTowerLon, bn->mControl.getLatitudeDeg(), bn->mControl.getLongitudeDeg(), &az1, &az2, &dist_m);
175       osg::Vec3 p2 = fromPolar(az1, dist_m * aScale) + osg::Vec3(TextureHalfSize, TextureHalfSize, 0),
176                 p3;
177       ++it;
178       if ( it == nodeLst.end() || close )
179       {
180         geo_inverse_wgs_84(aTowerLat, aTowerLon, (*loopBegin)->mPos.getLatitudeDeg(), (*loopBegin)->mPos.getLongitudeDeg(), &az1, &az2, &dist_m);
181       }
182       else
183       {
184         geo_inverse_wgs_84(aTowerLat, aTowerLon, (*it)->mPos.getLatitudeDeg(), (*it)->mPos.getLongitudeDeg(), &az1, &az2, &dist_m);
185       }
186       p3 = fromPolar(az1, dist_m * aScale) + osg::Vec3(TextureHalfSize, TextureHalfSize, 0);
187       simgear::BezierCurve<osg::Vec3> bCurv( p1, p2, p3 );
188       simgear::BezierCurve<osg::Vec3>::PointList &ptList = bCurv.pointList();
189       for ( simgear::BezierCurve<osg::Vec3>::PointList::iterator ii = ptList.begin(); ii != ptList.end(); ++ii )
190       {
191         pts->push_back( *ii );
192       }
193       pts->pop_back(); // Last point belongs to next segment
194     }
195     else
196     {
197       pts->push_back( p1 );
198       ++it;
199     }
200
201     if ( close ) // One loop for the moment
202       break;
203   }
204   geo_inverse_wgs_84(aTowerLat, aTowerLon, (*loopBegin)->mPos.getLatitudeDeg(), (*loopBegin)->mPos.getLongitudeDeg(), &az1, &az2, &dist_m);
205   osg::Vec3 p1 = fromPolar(az1, dist_m * aScale) + osg::Vec3(TextureHalfSize, TextureHalfSize, 0);
206   pts->push_back( p1 );
207   polygon->setVertexArray( pts.get() );
208
209   polygon->addPrimitiveSet( new osg::DrawArrays( osg::PrimitiveSet::POLYGON, 0, pts->size() ) );
210
211   tess->setTessellationType( osgUtil::Tessellator::TESS_TYPE_GEOMETRY );
212   tess->setBoundaryOnly( false );
213   tess->setWindingType( osgUtil::Tessellator::TESS_WINDING_ODD );
214   tess->retessellatePolygons( *polygon );
215   return polygon.release();
216 }
217
218 void GroundRadar::updateTexture()
219 {
220     osg::ref_ptr<osg::Vec3Array> rwy_vertices = new osg::Vec3Array;
221     osg::ref_ptr<osg::Vec3Array> taxi_vertices = new osg::Vec3Array;
222     osg::ref_ptr<osg::Vec3Array> pvt_vertices = new osg::Vec3Array;
223
224     const std::string airport_name = _airport_node->getStringValue();
225
226     const FGAirport* airport = fgFindAirportID(airport_name);
227     if (airport == 0)
228         return;
229
230     const SGGeod& tower_location = airport->getTowerLocation();
231     const double tower_lat = tower_location.getLatitudeDeg();
232     const double tower_lon = tower_location.getLongitudeDeg();
233     double scale = SG_METER_TO_NM * 200 / _range_node->getDoubleValue();
234   
235     const FGAirport* apt = fgFindAirportID(airport_name);
236     assert(apt);
237
238     for (unsigned int i=0; i<apt->numTaxiways(); ++i)
239     {
240       FGTaxiway* txwy(apt->getTaxiwayByIndex(i));
241       addRunwayVertices(txwy, tower_lat, tower_lon, scale, taxi_vertices.get());
242     }
243     osg::Geometry *taxi_geom = dynamic_cast<osg::Geometry *>(_geode->getDrawable(0));
244     taxi_geom->setVertexArray(taxi_vertices.get());
245     osg::DrawArrays* taxi = dynamic_cast<osg::DrawArrays*>(taxi_geom->getPrimitiveSet(0));
246     taxi->setCount(taxi_vertices->size());
247
248     osg::Geometry *pvt_geom = dynamic_cast<osg::Geometry *>(_geode->getDrawable(1));
249     osg::Geometry::PrimitiveSetList &pvt_prim_list = pvt_geom->getPrimitiveSetList();
250     pvt_prim_list.clear();
251     for (unsigned int i=0; i<apt->numPavements(); ++i)
252     {
253       FGPavement* pvt(apt->getPavementByIndex(i));
254       osg::ref_ptr<osg::Geometry> geom = addPavementGeometry(pvt, tower_lat, tower_lon, scale);
255       osg::Geometry::PrimitiveSetList &prim_list = geom->getPrimitiveSetList();
256       osg::Vec3Array *vertices = dynamic_cast<osg::Vec3Array *>(geom->getVertexArray());
257       size_t before = pvt_vertices->size(),
258             count = vertices->size();
259       for (size_t i = 0; i < count; ++i )
260       {
261         pvt_vertices->push_back( (*vertices)[i] );
262       }
263       for (osg::Geometry::PrimitiveSetList::iterator ii = prim_list.begin(); ii != prim_list.end(); ++ii )
264       {
265         osg::DrawArrays *da;
266         osg::DrawElementsUByte *de1;
267         osg::DrawElementsUShort *de2;
268         osg::DrawElementsUInt *de3;
269         if ((da = dynamic_cast<osg::DrawArrays *>(ii->get())) != 0)
270         {
271           osg::DrawArrays *ps = new osg::DrawArrays(*da);
272           ps->setFirst(da->getFirst() + before);
273           pvt_prim_list.push_back(ps);
274         }
275         else if ((de1 = dynamic_cast<osg::DrawElementsUByte *>(ii->get())) != 0)
276         {
277           if (before + count <= 255)
278           {
279             osg::DrawElementsUByte *ps = new osg::DrawElementsUByte(*de1);
280             for (size_t j = 0; j < ps->size(); ++j)
281             {
282               (*ps)[j] += before;
283             }
284             pvt_prim_list.push_back(ps);
285           }
286           else if (before + count <= 65535)
287           {
288             osg::DrawElementsUShort *ps = new osg::DrawElementsUShort(de1->getMode(), de1->begin(), de1->end());
289             for (size_t j = 0; j < ps->size(); ++j)
290             {
291               (*ps)[j] += before;
292             }
293             pvt_prim_list.push_back(ps);
294           }
295           else
296           {
297             osg::DrawElementsUInt *ps = new osg::DrawElementsUInt(de1->getMode(), de1->begin(), de1->end());
298             for (size_t j = 0; j < ps->size(); ++j)
299             {
300               (*ps)[j] += before;
301             }
302             pvt_prim_list.push_back(ps);
303           }
304         }
305         else if ((de2 = dynamic_cast<osg::DrawElementsUShort *>(ii->get())) != 0)
306         {
307           if (before + count <= 65535)
308           {
309             osg::DrawElementsUShort *ps = new osg::DrawElementsUShort(*de2);
310             for (size_t j = 0; j < ps->size(); ++j)
311             {
312               (*ps)[j] += before;
313             }
314             pvt_prim_list.push_back(ps);
315           }
316           else
317           {
318             osg::DrawElementsUInt *ps = new osg::DrawElementsUInt(de2->getMode(), de2->begin(), de2->end());
319             for (size_t j = 0; j < ps->size(); ++j)
320             {
321               (*ps)[j] += before;
322             }
323             pvt_prim_list.push_back(ps);
324           }
325         }
326         else if ((de3 = dynamic_cast<osg::DrawElementsUInt *>(ii->get())) != 0)
327         {
328           osg::DrawElementsUInt *ps = new osg::DrawElementsUInt(*de3);
329           for (size_t j = 0; j < ps->size(); ++j)
330           {
331             (*ps)[j] += before;
332           }
333           pvt_prim_list.push_back(ps);
334         }
335       }
336     }
337     pvt_geom->setVertexArray(pvt_vertices.get());
338
339     FGRunwayList rwys(apt->getRunwaysWithoutReciprocals());
340     for (unsigned int i=0; i<rwys.size(); ++i)
341     {
342       addRunwayVertices(rwys[i], tower_lat, tower_lon, scale, rwy_vertices.get());
343     }
344     osg::Geometry *rwy_geom = dynamic_cast<osg::Geometry *>(_geode->getDrawable(2));
345     rwy_geom->setVertexArray(rwy_vertices.get());
346     osg::DrawArrays* rwy = dynamic_cast<osg::DrawArrays*>(rwy_geom->getPrimitiveSet(0));
347     rwy->setCount(rwy_vertices->size());
348
349     getCamera()->setNodeMask(0xffffffff);
350 }
351
352 // end of GroundRadar.cxx