2 // getapt.cxx -- generate airport scenery from the given definition file
4 // Written by Curtis Olson, started September 1998.
6 // Copyright (C) 1998 Curtis L. Olson - curt@me.umn.edu
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.
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.
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.
23 // (Log is kept at end of this file)
26 #include <string> // Standard C++ string library
28 #include "Include/fg_stl_config.h"
30 #ifdef NEEDNAMESPACESTD
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>
42 // #include <gpc/gpc.h>
47 typedef vector < fgPoint3d > container;
48 typedef container::iterator iterator;
49 typedef container::const_iterator const_iterator;
52 // Calculate distance between to fgPoint3d's
53 static double calc_dist(const fgPoint3d& p1, const fgPoint3d& p2) {
58 return sqrt(x*x + y*y + z*z);
62 // convert a geodetic point lon(degrees), lat(degrees), elev(meter) to a
64 static fgPoint3d geod_to_cart(fgPoint3d geod) {
69 // printf("A geodetic point is (%.2f, %.2f, %.2f)\n", geod[0],
72 geoc.lon = geod.lon*DEG_TO_RAD;
73 fgGeodToGeoc(geod.lat*DEG_TO_RAD, geod.radius, &sl_radius, &geoc.lat);
75 // printf("A geocentric point is (%.2f, %.2f, %.2f)\n", gc_lon,
76 // gc_lat, sl_radius+geod[2]); */
78 geoc.radius = sl_radius + geod.radius;
79 cart = fgPolarToCart3d(geoc);
81 // printf("A cart point is (%.8f, %.8f, %.8f)\n", cp.x, cp.y, cp.z);
87 #define FG_APT_BASE_TEX_CONSTANT 2000.0
90 // Calculate texture coordinates for a given point.
92 calc_tex_coords(const fgPoint3d& p) {
95 cout << "Texture coordinates = " <<
96 FG_APT_BASE_TEX_CONSTANT * p.lon << " " <<
97 FG_APT_BASE_TEX_CONSTANT * p.lat << "\n";
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);
110 cout << "Texture coordinates = " << tex.x << " " << tex.y << "\n";
117 // Calculate texture coordinates for a given point.
118 static fgPoint3d calc_tex_coords(double *node, fgPoint3d *ref) {
122 cp.x = node[0] + ref->x;
123 cp.y = node[1] + ref->y;
124 cp.z = node[2] + ref->z;
126 pp = fgCartToPolar3d(cp);
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);
131 if ( pp.lon < 0.0 ) {
135 if ( pp.lat < 0.0 ) {
143 // generate the actual base area for the airport
145 gen_base( const fgPoint3d& average, const container& perimeter, fgTILE *t)
148 fgPoint3d ave_cart, cart, cart_trans, tex;
150 double dist, max_dist, temp;
157 cout << "generating airport base for size = " << perimeter.size() << "\n";
160 fragment.tile_ptr = t;
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",
169 ave_cart = geod_to_cart( average );
170 printf(" tile center = %.2f %.2f %.2f\n",
171 t->center.x, t->center.y, t->center.z);
172 printf(" airport center = %.2f %.2f %.2f\n",
173 average.x, average.y, average.z);
174 printf(" airport center = %.2f %.2f %.2f\n",
175 ave_cart.x, ave_cart.y, ave_cart.z);
176 fragment.center.x = ave_cart.x;
177 fragment.center.y = ave_cart.y;
178 fragment.center.z = ave_cart.z;
180 normal[0] = ave_cart.x;
181 normal[1] = ave_cart.y;
182 normal[2] = ave_cart.z;
183 MAT3_NORMALIZE_VEC(normal, temp);
185 display_list = xglGenLists(1);
186 xglNewList(display_list, GL_COMPILE);
187 xglBegin(GL_TRIANGLE_FAN);
189 // first point center of fan
190 cart_trans.x = ave_cart.x - t->center.x;
191 cart_trans.y = ave_cart.y - t->center.y;
192 cart_trans.z = ave_cart.z - t->center.z;
193 t->nodes[t->ncount][0] = cart_trans.x;
194 t->nodes[t->ncount][1] = cart_trans.y;
195 t->nodes[t->ncount][2] = cart_trans.z;
196 center_num = t->ncount;
199 tex = calc_tex_coords( t->nodes[t->ncount-1], &(t->center) );
200 xglTexCoord2f(tex.x, tex.y);
201 xglNormal3dv(normal);
202 xglVertex3dv(t->nodes[t->ncount-1]);
204 // first point on perimeter
205 iterator current = perimeter.begin();
206 cart = geod_to_cart( *current );
207 cart_trans.x = cart.x - t->center.x;
208 cart_trans.y = cart.y - t->center.y;
209 cart_trans.z = cart.z - t->center.z;
210 t->nodes[t->ncount][0] = cart_trans.x;
211 t->nodes[t->ncount][1] = cart_trans.y;
212 t->nodes[t->ncount][2] = cart_trans.z;
216 tex = calc_tex_coords( t->nodes[i], &(t->center) );
217 dist = calc_dist(ave_cart, cart);
218 if ( dist > max_dist ) {
221 xglTexCoord2f(tex.x, tex.y);
222 xglVertex3dv(t->nodes[i]);
226 const_iterator last = perimeter.end();
227 for ( ; current != last; ++current ) {
228 cart = geod_to_cart( *current );
229 cart_trans.x = cart.x - t->center.x;
230 cart_trans.y = cart.y - t->center.y;
231 cart_trans.z = cart.z - t->center.z;
232 t->nodes[t->ncount][0] = cart_trans.x;
233 t->nodes[t->ncount][1] = cart_trans.y;
234 t->nodes[t->ncount][2] = cart_trans.z;
236 fragment.add_face(center_num, i - 1, i);
238 tex = calc_tex_coords( t->nodes[i], &(t->center) );
239 dist = calc_dist(ave_cart, cart);
240 if ( dist > max_dist ) {
243 xglTexCoord2f(tex.x, tex.y);
244 xglVertex3dv(t->nodes[i]);
248 // last point (first point in perimeter list)
249 current = perimeter.begin();
250 cart = geod_to_cart( *current );
251 cart_trans.x = cart.x - t->center.x;
252 cart_trans.y = cart.y - t->center.y;
253 cart_trans.z = cart.z - t->center.z;
254 fragment.add_face(center_num, i - 1, 1);
256 tex = calc_tex_coords( t->nodes[1], &(t->center) );
257 xglTexCoord2f(tex.x, tex.y);
258 xglVertex3dv(t->nodes[1]);
263 fragment.bounding_radius = max_dist;
264 fragment.display_list = display_list;
266 t->fragment_list.push_back(fragment);
270 // Load a .apt file and register the GL fragments with the
271 // corresponding tile
273 fgAptGenerate(const string& path, fgTILE *tile)
276 string apt_id, apt_name;
279 // face list (this indexes into the master tile vertex list)
281 fgPoint3d p, average;
284 // gpc_vertex p_2d, list_2d[MAX_PERIMETER];
285 // gpc_vertex_list perimeter_2d;
287 fg_gzifstream in( path );
289 // exit immediately assuming an airport file for this tile
296 // read in each line of the file
300 in.stream() >> token;
302 if ( token == "a" ) {
303 // airport info record (start of airport)
305 if ( apt_id != "" ) {
306 // we have just finished reading and airport record.
308 gen_base(average, perimeter, tile);
311 cout << "Reading airport record\n";
312 in.stream() >> apt_id;
314 average.lon = average.lat = average.radius = 0.0;
315 perimeter.erase( perimeter.begin(), perimeter.end() );
316 // skip to end of line.
317 while ( in.get(c) && c != '\n' ) {
320 cout << "\tID = " + apt_id + " Name = " + apt_name + "\n";
321 } else if ( token == "p" ) {
322 // airport area bounding polygon coordinate. These
323 // specify a convex hull that should already have been cut
324 // out of the base terrain. The points are given in
325 // counter clockwise order and are specified in lon/lat
327 in.stream() >> p.lon >> p.lat >> p.radius;
328 average.lon += p.lon;
329 average.lat += p.lat;
330 average.radius += p.radius;
331 perimeter.push_back(p);
332 } else if ( token == "r" ) {
335 while ( in.get(c) && c != '\n' );
338 // airports.insert(a);
342 if ( apt_id != "" ) {
343 // we have just finished reading and airport record.
345 size = perimeter.size();
346 average.lon /= (double)size;
347 average.lat /= (double)size;
348 average.radius /= (double)size;
350 gen_base(average, perimeter, tile);
358 // Revision 1.2 1998/09/14 12:44:30 curt
359 // Don't recalculate perimeter points since it is not likely that they will match
360 // exactly with the previously calculated points, which will leave an ugly gap
361 // around the airport area.
363 // Revision 1.1 1998/09/14 02:14:01 curt
364 // Initial revision of genapt.[ch]xx for generating airport scenery.