]> git.mxchange.org Git - flightgear.git/blob - Airports/genapt.cxx
e9789faa0d4be99032facec56904677d8429e573
[flightgear.git] / Airports / genapt.cxx
1 //
2 // getapt.cxx -- generate airport scenery from the given definition file
3 //
4 // Written by Curtis Olson, started September 1998.
5 //
6 // Copyright (C) 1998  Curtis L. Olson  - curt@me.umn.edu
7 //
8 // This program is free software; you can redistribute it and/or
9 // modify it under the terms of the GNU General Public License as
10 // published by the Free Software Foundation; either version 2 of the
11 // License, or (at your option) any later version.
12 //
13 // This program is distributed in the hope that it will be useful, but
14 // WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16 // General Public License for more details.
17 //
18 // You should have received a copy of the GNU General Public License
19 // along with this program; if not, write to the Free Software
20 // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 //
22 // $Id$
23 // (Log is kept at end of this file)
24
25
26 #include <string>        // Standard C++ string library
27 #include <vector>
28 #include "Include/fg_stl_config.h"
29
30 #ifdef NEEDNAMESPACESTD
31 using namespace std;
32 #endif
33
34 #include <Debug/fg_debug.h>
35 // #include <Include/fg_types.h>
36 #include <Math/fg_geodesy.h>
37 #include <Math/mat3.h>
38 #include <Math/point3d.hxx>
39 #include <Math/polar3d.hxx>
40 #include <Misc/fgstream.hxx>
41 #include <Objects/material.hxx>
42
43 // #include <gpc/gpc.h>
44
45 #include "genapt.hxx"
46
47
48 typedef vector < Point3D > container;
49 typedef container::iterator iterator;
50 typedef container::const_iterator const_iterator;
51
52
53 /*
54 // Calculate distance between to Point3D's
55 static double calc_dist(const Point3D& p1, const Point3D& p2) {
56     double x, y, z;
57     x = p1.x() - p2.x();
58     y = p1.y() - p2.y();
59     z = p1.z() - p2.z();
60     return sqrt(x*x + y*y + z*z);
61 }
62 */
63
64
65 // convert a geodetic point lon(radians), lat(radians), elev(meter) to
66 // a cartesian point
67 static Point3D geod_to_cart(const Point3D& geod) {
68     Point3D cp;
69     Point3D pp;
70     double gc_lon, gc_lat, sl_radius;
71
72     // printf("A geodetic point is (%.2f, %.2f, %.2f)\n", 
73     //        geod[0], geod[1], geod[2]);
74
75     gc_lon = geod.lon();
76     fgGeodToGeoc(geod.lat(), geod.radius(), &sl_radius, &gc_lat);
77
78     // printf("A geocentric point is (%.2f, %.2f, %.2f)\n", gc_lon, 
79     //        gc_lat, sl_radius+geod[2]);
80
81     pp.setvals(gc_lon, gc_lat, sl_radius + geod.radius());
82     cp = fgPolarToCart3d(pp);
83     
84     // printf("A cart point is (%.8f, %.8f, %.8f)\n", cp.x, cp.y, cp.z);
85
86     return(cp);
87 }
88
89 #define FG_APT_BASE_TEX_CONSTANT 2000.0
90
91 #ifdef OLD_TEX_COORDS
92 // Calculate texture coordinates for a given point.
93 static fgPoint3d
94 calc_tex_coords(const fgPoint3d& p) {
95     fgPoint3d tex;
96
97     cout << "Texture coordinates = " << 
98         FG_APT_BASE_TEX_CONSTANT * p.lon << "  " << 
99         FG_APT_BASE_TEX_CONSTANT * p.lat << "\n";
100
101     tex.x = fmod(FG_APT_BASE_TEX_CONSTANT * p.lon, 10.0);
102     tex.y = fmod(FG_APT_BASE_TEX_CONSTANT * p.lat, 10.0);
103
104     if ( tex.x < 0.0 ) {
105         tex.x += 10.0;
106     }
107
108     if ( tex.y < 0.0 ) {
109         tex.y += 10.0;
110     }
111
112     cout << "Texture coordinates = " << tex.x << "  " << tex.y << "\n";
113
114     return tex;
115 }
116 #endif
117
118
119 // Calculate texture coordinates for a given point.
120 static Point3D calc_tex_coords(double *node, const Point3D& ref) {
121     Point3D cp;
122     Point3D pp;
123
124     cp.setvals( node[0] + ref.x(), node[1] + ref.y(), node[2] + ref.z() );
125
126     pp = fgCartToPolar3d(cp);
127
128     pp.setx( fmod(FG_APT_BASE_TEX_CONSTANT * pp.x(), 10.0) );
129     pp.sety( fmod(FG_APT_BASE_TEX_CONSTANT * pp.y(), 10.0) );
130
131     if ( pp.x() < 0.0 ) {
132         pp.setx( pp.x() + 10.0 );
133     }
134
135     if ( pp.y() < 0.0 ) {
136         pp.sety( pp.y() + 10.0 );
137     }
138
139     return(pp);
140 }
141
142
143 // generate the actual base area for the airport
144 static void
145 gen_base( const Point3D& average, const container& perimeter, fgTILE *t)
146 {
147     GLint display_list;
148     Point3D cart, cart_trans, tex;
149     MAT3vec normal;
150     double dist, max_dist, temp;
151     int center_num, i;
152
153     fgFRAGMENT fragment;
154
155     max_dist = 0.0;
156
157     cout << "generating airport base for size = " << perimeter.size() << "\n";
158
159     fragment.init();
160     fragment.tile_ptr = t;
161
162     // find airport base material in the properties list
163     if ( ! material_mgr.find( APT_BASE_MATERIAL, fragment.material_ptr )) {
164         fgPrintf( FG_TERRAIN, FG_ALERT, 
165                   "Ack! unknown material name = %s in fgAptGenerat()\n",
166                   APT_BASE_MATERIAL );
167     }
168
169     printf(" tile center = %.2f %.2f %.2f\n", 
170            t->center.x(), t->center.y(), t->center.z() );
171     printf(" airport center = %.2f %.2f %.2f\n", 
172            average.x(), average.y(), average.z());
173     fragment.center = average;
174
175     normal[0] = average.x();
176     normal[1] = average.y();
177     normal[2] = average.z();
178     MAT3_NORMALIZE_VEC(normal, temp);
179     
180     display_list = xglGenLists(1);
181     xglNewList(display_list, GL_COMPILE);
182     xglBegin(GL_TRIANGLE_FAN);
183
184     // first point center of fan
185     cart_trans = average - t->center;
186     t->nodes[t->ncount][0] = cart_trans.x();
187     t->nodes[t->ncount][1] = cart_trans.y();
188     t->nodes[t->ncount][2] = cart_trans.z();
189     center_num = t->ncount;
190     t->ncount++;
191
192     tex = calc_tex_coords( t->nodes[t->ncount-1], t->center );
193     xglTexCoord2f(tex.x(), tex.y());
194     xglNormal3dv(normal);
195     xglVertex3dv(t->nodes[t->ncount-1]);
196
197     // first point on perimeter
198     const_iterator current = perimeter.begin();
199     cart = geod_to_cart( *current );
200     cart_trans = cart - t->center;
201     t->nodes[t->ncount][0] = cart_trans.x();
202     t->nodes[t->ncount][1] = cart_trans.y();
203     t->nodes[t->ncount][2] = cart_trans.z();
204     t->ncount++;
205
206     i = 1;
207     tex = calc_tex_coords( t->nodes[i], t->center );
208     dist = distance3D(average, cart);
209     if ( dist > max_dist ) {
210         max_dist = dist;
211     }
212     xglTexCoord2f(tex.x(), tex.y());
213     xglVertex3dv(t->nodes[i]);
214     ++current;
215     ++i;
216
217     const_iterator last = perimeter.end();
218     for ( ; current != last; ++current ) {
219         cart = geod_to_cart( *current );
220         cart_trans = cart - t->center;
221         t->nodes[t->ncount][0] = cart_trans.x();
222         t->nodes[t->ncount][1] = cart_trans.y();
223         t->nodes[t->ncount][2] = cart_trans.z();
224         t->ncount++;
225         fragment.add_face(center_num, i - 1, i);
226
227         tex = calc_tex_coords( t->nodes[i], t->center );
228         dist = distance3D(average, cart);
229         if ( dist > max_dist ) {
230             max_dist = dist;
231         }
232         xglTexCoord2f(tex.x(), tex.y());
233         xglVertex3dv(t->nodes[i]);
234         i++;
235     }
236
237     // last point (first point in perimeter list)
238     current = perimeter.begin();
239     cart = geod_to_cart( *current );
240     cart_trans = cart - t->center;
241     fragment.add_face(center_num, i - 1, 1);
242
243     tex = calc_tex_coords( t->nodes[1], t->center );
244     xglTexCoord2f(tex.x(), tex.y());
245     xglVertex3dv(t->nodes[1]);
246
247     xglEnd();
248     xglEndList();
249
250     fragment.bounding_radius = max_dist;
251     fragment.display_list = display_list;
252
253     t->fragment_list.push_back(fragment);
254 }
255
256
257 // Load a .apt file and register the GL fragments with the
258 // corresponding tile
259 int
260 fgAptGenerate(const string& path, fgTILE *tile)
261 {
262     string token;
263     string apt_id, apt_name;
264     char c;
265     int i = 1;
266
267     // face list (this indexes into the master tile vertex list)
268     container perimeter;
269     Point3D p, average;
270     double avex = 0.0, avey = 0.0, avez = 0.0;
271     int size;
272
273     // gpc_vertex p_2d, list_2d[MAX_PERIMETER];
274     // gpc_vertex_list perimeter_2d;
275
276     fg_gzifstream in( path );
277     if ( !in ) {
278         // exit immediately assuming an airport file for this tile
279         // doesn't exist.
280         return 0;
281     }
282
283     apt_id = "";
284
285     // read in each line of the file
286     in.eat_comments();
287     while ( ! in.eof() )
288     {
289         in.stream() >> token;
290
291         if ( token == "a" ) {
292             // airport info record (start of airport)
293
294             if ( apt_id != "" ) {
295                 // we have just finished reading and airport record.
296                 // process the info
297                 gen_base(average, perimeter, tile);
298             }
299
300             cout << "Reading airport record\n";
301             in.stream() >> apt_id;
302             apt_name = "";
303             i = 1;
304             avex = avey = avez = 0.0;
305             perimeter.erase( perimeter.begin(), perimeter.end() );
306             // skip to end of line.
307             while ( in.get(c) && c != '\n' ) {
308                 apt_name += c;
309             }
310             cout << "\tID = " + apt_id + "  Name = " + apt_name + "\n";
311         } else if ( token == "p" ) {
312             // airport area bounding polygon coordinate.  These
313             // specify a convex hull that should already have been cut
314             // out of the base terrain.  The points are given in
315             // counter clockwise order and are specified in lon/lat
316             // degrees.
317             in.stream() >> p;
318             avex += tile->nodes[i][0];
319             avey += tile->nodes[i][1];
320             avez += tile->nodes[i][2];
321             perimeter.push_back(p);
322             ++i;
323         } else if ( token == "r" ) {
324             // runway record
325             // skip for now
326             while ( in.get(c) && c != '\n' );
327         }
328
329         // airports.insert(a);
330         in.eat_comments();
331     }
332
333     if ( apt_id != "" ) {
334         // we have just finished reading and airport record.
335         // process the info
336         size = perimeter.size();
337         average.setvals( avex / (double)size + tile->center.x(),
338                          avey / (double)size + tile->center.y(),
339                          avez / (double)size + tile->center.z() );
340
341         gen_base(average, perimeter, tile);
342     }
343
344     return 1;
345 }
346
347
348 // $Log$
349 // Revision 1.4  1998/10/16 00:51:46  curt
350 // Converted to Point3D class.
351 //
352 // Revision 1.3  1998/09/21 20:55:00  curt
353 // Used the cartesian form of the airport area coordinates to determine the
354 // center.
355 //
356 // Revision 1.2  1998/09/14 12:44:30  curt
357 // Don't recalculate perimeter points since it is not likely that they will match
358 // exactly with the previously calculated points, which will leave an ugly gap
359 // around the airport area.
360 //
361 // Revision 1.1  1998/09/14 02:14:01  curt
362 // Initial revision of genapt.[ch]xx for generating airport scenery.
363 //
364 //
365