2 // genapt.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
35 # define exception c_exception
39 #include <Debug/logstream.hxx>
40 // #include <Include/fg_types.h>
41 #include <Math/fg_geodesy.hxx>
42 #include <Math/mat3.h>
43 #include <Math/point3d.hxx>
44 #include <Math/polar3d.hxx>
45 #include <Misc/fgstream.hxx>
46 #include <Objects/material.hxx>
48 // #include <gpc/gpc.h>
53 typedef vector < Point3D > container;
54 typedef container::iterator iterator;
55 typedef container::const_iterator const_iterator;
58 #define FG_APT_BASE_TEX_CONSTANT 2000.0
60 // Calculate texture coordinates for a given point.
61 static Point3D calc_tex_coords(double *node, const Point3D& ref) {
65 cp = Point3D( node[0] + ref.x(), node[1] + ref.y(), node[2] + ref.z() );
67 pp = fgCartToPolar3d(cp);
69 pp.setx( fmod(FG_APT_BASE_TEX_CONSTANT * pp.x(), 10.0) );
70 pp.sety( fmod(FG_APT_BASE_TEX_CONSTANT * pp.y(), 10.0) );
73 pp.setx( pp.x() + 10.0 );
77 pp.sety( pp.y() + 10.0 );
84 // generate the actual base area for the airport
86 gen_base( const Point3D& average, const container& perimeter, fgTILE *t)
89 Point3D cart, cart_trans, tex;
91 double dist, max_dist, temp;
98 FG_LOG( FG_TERRAIN, FG_INFO,
99 "generating airport base for size = " << perimeter.size() );
102 fragment.tile_ptr = t;
104 // find airport base material in the properties list
105 if ( ! material_mgr.find( APT_BASE_MATERIAL, fragment.material_ptr )) {
106 FG_LOG( FG_TERRAIN, FG_ALERT,
107 "Ack! unknown material name = " << APT_BASE_MATERIAL
108 << " in fgAptGenerat()" );
111 FG_LOG( FG_TERRAIN, FG_INFO,
113 << t->center.x() << " " << t->center.y() << " " << t->center.z() );
114 FG_LOG( FG_TERRAIN, FG_INFO,
116 << average.x() << " " << average.y() << " " << average.z() );
117 fragment.center = average;
119 normal[0] = average.x();
120 normal[1] = average.y();
121 normal[2] = average.z();
122 MAT3_NORMALIZE_VEC(normal, temp);
124 display_list = xglGenLists(1);
125 xglNewList(display_list, GL_COMPILE);
126 xglBegin(GL_TRIANGLE_FAN);
128 // first point center of fan
129 cart_trans = average - t->center;
130 t->nodes[t->ncount][0] = cart_trans.x();
131 t->nodes[t->ncount][1] = cart_trans.y();
132 t->nodes[t->ncount][2] = cart_trans.z();
133 center_num = t->ncount;
136 tex = calc_tex_coords( t->nodes[t->ncount-1], t->center );
137 xglTexCoord2f(tex.x(), tex.y());
138 xglNormal3dv(normal);
139 xglVertex3dv(t->nodes[t->ncount-1]);
141 // first point on perimeter
142 const_iterator current = perimeter.begin();
143 cart = fgGeodToCart( *current );
144 cart_trans = cart - t->center;
145 t->nodes[t->ncount][0] = cart_trans.x();
146 t->nodes[t->ncount][1] = cart_trans.y();
147 t->nodes[t->ncount][2] = cart_trans.z();
151 tex = calc_tex_coords( t->nodes[i], t->center );
152 dist = cart.distance3Dsquared(average);
153 if ( dist > max_dist ) {
156 xglTexCoord2f(tex.x(), tex.y());
157 xglVertex3dv(t->nodes[i]);
161 const_iterator last = perimeter.end();
162 for ( ; current != last; ++current ) {
163 cart = fgGeodToCart( *current );
164 cart_trans = cart - t->center;
165 t->nodes[t->ncount][0] = cart_trans.x();
166 t->nodes[t->ncount][1] = cart_trans.y();
167 t->nodes[t->ncount][2] = cart_trans.z();
169 fragment.add_face(center_num, i - 1, i);
171 tex = calc_tex_coords( t->nodes[i], t->center );
172 dist = cart.distance3Dsquared(average);
173 if ( dist > max_dist ) {
176 xglTexCoord2f(tex.x(), tex.y());
177 xglVertex3dv(t->nodes[i]);
181 // last point (first point in perimeter list)
182 current = perimeter.begin();
183 cart = fgGeodToCart( *current );
184 cart_trans = cart - t->center;
185 fragment.add_face(center_num, i - 1, 1);
187 tex = calc_tex_coords( t->nodes[1], t->center );
188 xglTexCoord2f(tex.x(), tex.y());
189 xglVertex3dv(t->nodes[1]);
194 fragment.bounding_radius = sqrt(max_dist);
195 fragment.display_list = display_list;
197 t->fragment_list.push_back(fragment);
201 // Load a .apt file and register the GL fragments with the
202 // corresponding tile
204 fgAptGenerate(const string& path, fgTILE *tile)
207 string apt_id, apt_name;
211 // face list (this indexes into the master tile vertex list)
214 double avex = 0.0, avey = 0.0, avez = 0.0;
217 // gpc_vertex p_2d, list_2d[MAX_PERIMETER];
218 // gpc_vertex_list perimeter_2d;
220 fg_gzifstream in( path );
222 // exit immediately assuming an airport file for this tile
229 // read in each line of the file
235 if ( token == "a" ) {
236 // airport info record (start of airport)
238 if ( apt_id != "" ) {
239 // we have just finished reading and airport record.
241 gen_base(average, perimeter, tile);
244 FG_LOG( FG_TERRAIN, FG_INFO, "Reading airport record" );
248 avex = avey = avez = 0.0;
249 perimeter.erase( perimeter.begin(), perimeter.end() );
250 // skip to end of line.
251 while ( in.get(c) && c != '\n' ) {
254 FG_LOG( FG_TERRAIN, FG_INFO,
255 "\tID = " << apt_id << " Name = " << apt_name );
256 } else if ( token == "p" ) {
257 // airport area bounding polygon coordinate. These
258 // specify a convex hull that should already have been cut
259 // out of the base terrain. The points are given in
260 // counter clockwise order and are specified in lon/lat
263 avex += tile->nodes[i][0];
264 avey += tile->nodes[i][1];
265 avez += tile->nodes[i][2];
266 perimeter.push_back(p);
268 } else if ( token == "r" ) {
271 while ( in.get(c) && c != '\n' );
277 if ( apt_id != "" ) {
278 // we have just finished reading and airport record.
280 size = perimeter.size();
281 average = Point3D( avex / (double)size + tile->center.x(),
282 avey / (double)size + tile->center.y(),
283 avez / (double)size + tile->center.z() );
285 gen_base(average, perimeter, tile);
293 // Revision 1.12 1999/02/01 21:08:33 curt
294 // Optimizations from Norman Vine.
296 // Revision 1.11 1998/11/23 21:48:09 curt
297 // Borland portability tweaks.
299 // Revision 1.10 1998/11/07 19:07:06 curt
300 // Enable release builds using the --without-logging option to the configure
301 // script. Also a couple log message cleanups, plus some C to C++ comment
304 // Revision 1.9 1998/11/06 21:17:32 curt
305 // Converted to new logstream debugging facility. This allows release
306 // builds with no messages at all (and no performance impact) by using
307 // the -DFG_NDEBUG flag.
309 // Revision 1.8 1998/11/06 14:46:59 curt
310 // Changes to track Bernie's updates to fgstream.
312 // Revision 1.7 1998/10/20 18:26:06 curt
313 // Updates to point3d.hxx
315 // Revision 1.6 1998/10/18 01:17:16 curt
318 // Revision 1.5 1998/10/16 23:27:14 curt
321 // Revision 1.4 1998/10/16 00:51:46 curt
322 // Converted to Point3D class.
324 // Revision 1.3 1998/09/21 20:55:00 curt
325 // Used the cartesian form of the airport area coordinates to determine the
328 // Revision 1.2 1998/09/14 12:44:30 curt
329 // Don't recalculate perimeter points since it is not likely that they will match
330 // exactly with the previously calculated points, which will leave an ugly gap
331 // around the airport area.
333 // Revision 1.1 1998/09/14 02:14:01 curt
334 // Initial revision of genapt.[ch]xx for generating airport scenery.