]> git.mxchange.org Git - flightgear.git/blob - Airports/genapt.cxx
Used the cartesian form of the airport area coordinates to determine the
[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/polar3d.hxx>
39 #include <Misc/fgstream.hxx>
40 #include <Objects/material.hxx>
41
42 // #include <gpc/gpc.h>
43
44 #include "genapt.hxx"
45
46
47 typedef vector < fgPoint3d > container;
48 typedef container::iterator iterator;
49 typedef container::const_iterator const_iterator;
50
51
52 // Calculate distance between to fgPoint3d's
53 static double calc_dist(const fgPoint3d& p1, const fgPoint3d& p2) {
54     double x, y, z;
55     x = p1.x - p2.x;
56     y = p1.y - p2.y;
57     z = p1.z - p2.z;
58     return sqrt(x*x + y*y + z*z);
59 }
60
61
62 // convert a geodetic point lon(degrees), lat(degrees), elev(meter) to a
63 // cartesian point
64 static fgPoint3d geod_to_cart(fgPoint3d geod) {
65     fgPoint3d cart;
66     fgPoint3d geoc;
67     double sl_radius;
68
69     // printf("A geodetic point is (%.2f, %.2f, %.2f)\n", geod[0],
70     //        geod[1], geod[2]);
71
72     geoc.lon = geod.lon*DEG_TO_RAD;
73     fgGeodToGeoc(geod.lat*DEG_TO_RAD, geod.radius, &sl_radius, &geoc.lat);
74
75     // printf("A geocentric point is (%.2f, %.2f, %.2f)\n", gc_lon, 
76     //        gc_lat, sl_radius+geod[2]); */
77
78     geoc.radius = sl_radius + geod.radius;
79     cart = fgPolarToCart3d(geoc);
80     
81     // printf("A cart point is (%.8f, %.8f, %.8f)\n", cp.x, cp.y, cp.z);
82
83     return cart;
84 }
85
86
87 #define FG_APT_BASE_TEX_CONSTANT 2000.0
88
89 #ifdef OLD_TEX_COORDS
90 // Calculate texture coordinates for a given point.
91 static fgPoint3d
92 calc_tex_coords(const fgPoint3d& p) {
93     fgPoint3d tex;
94
95     cout << "Texture coordinates = " << 
96         FG_APT_BASE_TEX_CONSTANT * p.lon << "  " << 
97         FG_APT_BASE_TEX_CONSTANT * p.lat << "\n";
98
99     tex.x = fmod(FG_APT_BASE_TEX_CONSTANT * p.lon, 10.0);
100     tex.y = fmod(FG_APT_BASE_TEX_CONSTANT * p.lat, 10.0);
101
102     if ( tex.x < 0.0 ) {
103         tex.x += 10.0;
104     }
105
106     if ( tex.y < 0.0 ) {
107         tex.y += 10.0;
108     }
109
110     cout << "Texture coordinates = " << tex.x << "  " << tex.y << "\n";
111
112     return tex;
113 }
114 #endif
115
116
117 // Calculate texture coordinates for a given point.
118 static fgPoint3d calc_tex_coords(double *node, fgPoint3d *ref) {
119     fgPoint3d cp;
120     fgPoint3d pp;
121
122     cp.x = node[0] + ref->x; 
123     cp.y = node[1] + ref->y;
124     cp.z = node[2] + ref->z;
125
126     pp = fgCartToPolar3d(cp);
127
128     pp.lon = fmod(FG_APT_BASE_TEX_CONSTANT * pp.lon, 10.0);
129     pp.lat = fmod(FG_APT_BASE_TEX_CONSTANT * pp.lat, 10.0);
130
131     if ( pp.lon < 0.0 ) {
132         pp.lon += 10.0;
133     }
134
135     if ( pp.lat < 0.0 ) {
136         pp.lat += 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 fgPoint3d& average, const container& perimeter, fgTILE *t)
146 {
147     GLint display_list;
148     fgPoint3d 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.x = average.x;
174     fragment.center.y = average.y;
175     fragment.center.z = average.z;
176
177     normal[0] = average.x;
178     normal[1] = average.y;
179     normal[2] = average.z;
180     MAT3_NORMALIZE_VEC(normal, temp);
181     
182     display_list = xglGenLists(1);
183     xglNewList(display_list, GL_COMPILE);
184     xglBegin(GL_TRIANGLE_FAN);
185
186     // first point center of fan
187     cart_trans.x = average.x - t->center.x;
188     cart_trans.y = average.y - t->center.y;
189     cart_trans.z = average.z - t->center.z;
190     t->nodes[t->ncount][0] = cart_trans.x;
191     t->nodes[t->ncount][1] = cart_trans.y;
192     t->nodes[t->ncount][2] = cart_trans.z;
193     center_num = t->ncount;
194     t->ncount++;
195
196     tex = calc_tex_coords( t->nodes[t->ncount-1], &(t->center) );
197     xglTexCoord2f(tex.x, tex.y);
198     xglNormal3dv(normal);
199     xglVertex3dv(t->nodes[t->ncount-1]);
200
201     // first point on perimeter
202     iterator current = perimeter.begin();
203     cart = geod_to_cart( *current );
204     cart_trans.x = cart.x - t->center.x;
205     cart_trans.y = cart.y - t->center.y;
206     cart_trans.z = cart.z - t->center.z;
207     t->nodes[t->ncount][0] = cart_trans.x;
208     t->nodes[t->ncount][1] = cart_trans.y;
209     t->nodes[t->ncount][2] = cart_trans.z;
210     t->ncount++;
211
212     i = 1;
213     tex = calc_tex_coords( t->nodes[i], &(t->center) );
214     dist = calc_dist(average, cart);
215     if ( dist > max_dist ) {
216         max_dist = dist;
217     }
218     xglTexCoord2f(tex.x, tex.y);
219     xglVertex3dv(t->nodes[i]);
220     ++current;
221     ++i;
222
223     const_iterator last = perimeter.end();
224     for ( ; current != last; ++current ) {
225         cart = geod_to_cart( *current );
226         cart_trans.x = cart.x - t->center.x;
227         cart_trans.y = cart.y - t->center.y;
228         cart_trans.z = cart.z - t->center.z;
229         t->nodes[t->ncount][0] = cart_trans.x;
230         t->nodes[t->ncount][1] = cart_trans.y;
231         t->nodes[t->ncount][2] = cart_trans.z;
232         t->ncount++;
233         fragment.add_face(center_num, i - 1, i);
234
235         tex = calc_tex_coords( t->nodes[i], &(t->center) );
236         dist = calc_dist(average, cart);
237         if ( dist > max_dist ) {
238             max_dist = dist;
239         }
240         xglTexCoord2f(tex.x, tex.y);
241         xglVertex3dv(t->nodes[i]);
242         i++;
243     }
244
245     // last point (first point in perimeter list)
246     current = perimeter.begin();
247     cart = geod_to_cart( *current );
248     cart_trans.x = cart.x - t->center.x;
249     cart_trans.y = cart.y - t->center.y;
250     cart_trans.z = cart.z - t->center.z;
251     fragment.add_face(center_num, i - 1, 1);
252
253     tex = calc_tex_coords( t->nodes[1], &(t->center) );
254     xglTexCoord2f(tex.x, tex.y);
255     xglVertex3dv(t->nodes[1]);
256
257     xglEnd();
258     xglEndList();
259
260     fragment.bounding_radius = max_dist;
261     fragment.display_list = display_list;
262
263     t->fragment_list.push_back(fragment);
264 }
265
266
267 // Load a .apt file and register the GL fragments with the
268 // corresponding tile
269 int
270 fgAptGenerate(const string& path, fgTILE *tile)
271 {
272     string token;
273     string apt_id, apt_name;
274     char c;
275     int i = 1;
276
277     // face list (this indexes into the master tile vertex list)
278     container perimeter;
279     fgPoint3d p, average;
280     int size;
281
282     // gpc_vertex p_2d, list_2d[MAX_PERIMETER];
283     // gpc_vertex_list perimeter_2d;
284
285     fg_gzifstream in( path );
286     if ( !in ) {
287         // exit immediately assuming an airport file for this tile
288         // doesn't exist.
289         return 0;
290     }
291
292     apt_id = "";
293
294     // read in each line of the file
295     in.eat_comments();
296     while ( ! in.eof() )
297     {
298         in.stream() >> token;
299
300         if ( token == "a" ) {
301             // airport info record (start of airport)
302
303             if ( apt_id != "" ) {
304                 // we have just finished reading and airport record.
305                 // process the info
306                 gen_base(average, perimeter, tile);
307             }
308
309             cout << "Reading airport record\n";
310             in.stream() >> apt_id;
311             apt_name = "";
312             i = 1;
313             average.lon = average.lat = average.radius = 0.0;
314             perimeter.erase( perimeter.begin(), perimeter.end() );
315             // skip to end of line.
316             while ( in.get(c) && c != '\n' ) {
317                 apt_name += c;
318             }
319             cout << "\tID = " + apt_id + "  Name = " + apt_name + "\n";
320         } else if ( token == "p" ) {
321             // airport area bounding polygon coordinate.  These
322             // specify a convex hull that should already have been cut
323             // out of the base terrain.  The points are given in
324             // counter clockwise order and are specified in lon/lat
325             // degrees.
326             in.stream() >> p.lon >> p.lat >> p.radius;
327             average.x += tile->nodes[i][0];
328             average.y += tile->nodes[i][1];
329             average.z += tile->nodes[i][2];
330             perimeter.push_back(p);
331             ++i;
332         } else if ( token == "r" ) {
333             // runway record
334             // skip for now
335             while ( in.get(c) && c != '\n' );
336         }
337
338         // airports.insert(a);
339         in.eat_comments();
340     }
341
342     if ( apt_id != "" ) {
343         // we have just finished reading and airport record.
344         // process the info
345         size = perimeter.size();
346         average.x = average.x / (double)size + tile->center.x;
347         average.y = average.y / (double)size + tile->center.y;
348         average.z = average.z / (double)size + tile->center.z;
349
350         gen_base(average, perimeter, tile);
351     }
352
353     return 1;
354 }
355
356
357 // $Log$
358 // Revision 1.3  1998/09/21 20:55:00  curt
359 // Used the cartesian form of the airport area coordinates to determine the
360 // center.
361 //
362 // Revision 1.2  1998/09/14 12:44:30  curt
363 // Don't recalculate perimeter points since it is not likely that they will match
364 // exactly with the previously calculated points, which will leave an ugly gap
365 // around the airport area.
366 //
367 // Revision 1.1  1998/09/14 02:14:01  curt
368 // Initial revision of genapt.[ch]xx for generating airport scenery.
369 //
370 //
371