Initial revision
This commit is contained in:
commit
b20be51d65
160 changed files with 61258 additions and 0 deletions
0
AUTHORS
Normal file
0
AUTHORS
Normal file
0
ChangeLog
Normal file
0
ChangeLog
Normal file
7
Makefile.am
Normal file
7
Makefile.am
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
EXTRA_DIST = README README.howto scenery_version.hxx
|
||||||
|
|
||||||
|
SUBDIRS = \
|
||||||
|
Lib \
|
||||||
|
Prep \
|
||||||
|
Construct \
|
||||||
|
Utils
|
0
NEWS
Normal file
0
NEWS
Normal file
75
README
Normal file
75
README
Normal file
|
@ -0,0 +1,75 @@
|
||||||
|
FG Scenery Tools README
|
||||||
|
=======================
|
||||||
|
|
||||||
|
Contained here-in are the FG scenery creation tools. These can be
|
||||||
|
used to convert 3 arcsec ASCII format DEM files and 30 arcsec binary
|
||||||
|
format DEM files into Flight Gear scenery.
|
||||||
|
|
||||||
|
Eventually these tools will expand to support insertion of airports,
|
||||||
|
roads, rivers, lakes, etc.
|
||||||
|
|
||||||
|
|
||||||
|
Building the Tools
|
||||||
|
==================
|
||||||
|
|
||||||
|
These tools are compiled and tested under Linux. I'm all for
|
||||||
|
portability, but I just haven't been as motivated to port these tools,
|
||||||
|
since scenery creation is less of a general need ... especially at
|
||||||
|
this stage. However, if anyone wants to work on porting to other
|
||||||
|
platforms, I will be happy to incorporate patches.
|
||||||
|
|
||||||
|
The process for building these tools is very similar to building the
|
||||||
|
main FG source code.
|
||||||
|
|
||||||
|
1. Set the FG_ROOT, FG_ROOT_SRC, and FG_ROOT_LIB environment
|
||||||
|
variables.
|
||||||
|
|
||||||
|
2. Run ``make depend''
|
||||||
|
|
||||||
|
3. Run ``make clean''
|
||||||
|
|
||||||
|
4. Run ``make''
|
||||||
|
|
||||||
|
|
||||||
|
3 Arcsec ASCII DEM files
|
||||||
|
========================
|
||||||
|
|
||||||
|
Data files for the USA are available in this format from:
|
||||||
|
|
||||||
|
http://edcwww.cr.usgs.gov/doc/edchome/ndcdb/ndcdb.html
|
||||||
|
|
||||||
|
To generate FG scenery from one of these dem files, run:
|
||||||
|
|
||||||
|
./process-dem.pl <error-tolerance-squared> dem-file-1 [ dem-file-2 ...]
|
||||||
|
|
||||||
|
You can vary the error tolerance to control the level of detail (and
|
||||||
|
size) of the resulting scenery. Note, you must specify the error
|
||||||
|
tolerance squared. So, if you wish to allow up to a 10 meter error
|
||||||
|
margin (very high level of detail) you would specify a value of 100.
|
||||||
|
If you desire an error tolerance of 200 meters (medium detail level)
|
||||||
|
you would specify a value of 40000.
|
||||||
|
|
||||||
|
The process-dem.pl script will automatically dump the resulting .obj
|
||||||
|
files in the proper directory tree.
|
||||||
|
|
||||||
|
|
||||||
|
30 Arcsec Binary DEM files
|
||||||
|
==========================
|
||||||
|
|
||||||
|
These data files have world wide coverage and are available from:
|
||||||
|
|
||||||
|
http://edcwww.cr.usgs.gov/landdaac/gtopo30/gtopo30.html
|
||||||
|
|
||||||
|
To process these data files, you must first run:
|
||||||
|
|
||||||
|
DemRaw2Ascii/raw2ascii <input_file_basename> <output_dir>
|
||||||
|
|
||||||
|
For example:
|
||||||
|
|
||||||
|
DemRaw2Ascii/raw2ascii /tmp/W020N90 asciidems/
|
||||||
|
|
||||||
|
This will create ASCII DEM files for each 1 degree x 1 degree area in
|
||||||
|
the specified output dir.
|
||||||
|
|
||||||
|
Then, you can take these ascii dem files and feed them through the
|
||||||
|
same procedure you use with the 3 arcsec dem files.
|
122
README.howto
Normal file
122
README.howto
Normal file
|
@ -0,0 +1,122 @@
|
||||||
|
Original version by Alexei Novikov <anovikov@heron.itep.ru> Sep. 3, 1999
|
||||||
|
Updates by Curtis Olson <curt@flightgear.org>
|
||||||
|
|
||||||
|
|
||||||
|
Overview
|
||||||
|
========
|
||||||
|
The scenery creation process has 3 basic steps. 1. Fetch the raw
|
||||||
|
data. 2. Preprocess this data into an intermediate form. 3.
|
||||||
|
Assemble the intermediate data into the final scenery tiles.
|
||||||
|
|
||||||
|
There are a couple basic types of data used to create scenery. 1. DEM
|
||||||
|
data which is typically a set of elevation points on a regular grid.
|
||||||
|
2. Polygonal data such as landmass outlines, lakes, urban areas,
|
||||||
|
glaciers, etc. 3. Other more specialized data such as airport
|
||||||
|
runways and taxiways, lighthouse locations, etc.
|
||||||
|
|
||||||
|
|
||||||
|
Preparation and Preprocessing
|
||||||
|
============================
|
||||||
|
1) DEM data.
|
||||||
|
|
||||||
|
As the first step you have to download DEM for the area you need. (You
|
||||||
|
can get them from USGS site). If this is a 30 arc sec DEM (which is most
|
||||||
|
probable) you need to transfer this file into ASCII format using
|
||||||
|
raw2ascii
|
||||||
|
|
||||||
|
Usage: ./raw2ascii <input_file_basename> <output_dir>
|
||||||
|
|
||||||
|
Here output dir is quite arbitrary as we will remove all the files from
|
||||||
|
it later.
|
||||||
|
Then you have to chop files that we got into the tiles used for the
|
||||||
|
scenery generation. You should use demchop for this. As we already have
|
||||||
|
a number of files I'm using the following Perl script
|
||||||
|
|
||||||
|
#--------------------------------------------------------------------------
|
||||||
|
#!/usr/bin/perl
|
||||||
|
my @files=glob("./*.dem");
|
||||||
|
my $size=@files;
|
||||||
|
for (my $i=0;$i<$size;$i++) {
|
||||||
|
system("demchop $files[$i] /home/anovikov/w020n90/Work/DEM-30");
|
||||||
|
}
|
||||||
|
#--------------------------------------------------------------------------
|
||||||
|
|
||||||
|
Here you can change /home/anovikov/w020n90 to whatever you like but keep
|
||||||
|
in mind that we will use that directory for our scenery generation.
|
||||||
|
|
||||||
|
The 3 arcsec DEMs (which are available for the USA) should go in
|
||||||
|
.../Work/DEM-3/
|
||||||
|
|
||||||
|
That's all with the DEM files. If yu want to have a blibloagraphy on
|
||||||
|
them see f.e. http://www.geo.ed.ac.uk/geoinfo/dem.send
|
||||||
|
|
||||||
|
2) Airport Data
|
||||||
|
|
||||||
|
Next thing is to generate airports data. You need to have default.apt
|
||||||
|
from the fgfs-base package and genapts compiled. Usage is genapts
|
||||||
|
/path/to/appt_file /work/dir (in our example
|
||||||
|
genapts .../RawData/AirNa/default.apt.gz .../Work/Airports/
|
||||||
|
|
||||||
|
3) Landmass Data
|
||||||
|
|
||||||
|
You can just download it from Curtis FTP site
|
||||||
|
ftp://kenai.me.umn.edu/pub/fgfs/RawData/Global-Landmass/
|
||||||
|
or generate it by yourself. If you download data from Curtis site then
|
||||||
|
you should extract it in the .../Work/Global-Landmass
|
||||||
|
|
||||||
|
If you are generating it by yourself you have to ask Curtis how he is
|
||||||
|
doing that.
|
||||||
|
|
||||||
|
4) Landuse Data. (Curtis, you asked me for this).
|
||||||
|
|
||||||
|
If you have a CD-ROM with DCW then you are lucky, if not you need to go
|
||||||
|
to ESRI WWW site (http://www.esri.com/data/online/index.html), "Select
|
||||||
|
by Geographic Area" - "Esri Thematic Data" (Go!) then
|
||||||
|
Select a Theme - Natural Landscape Zones, Select a Region - Continent
|
||||||
|
you need and download data. Please read the license agreement first.
|
||||||
|
|
||||||
|
Then comes the tricky part. (You will need to modify the code)
|
||||||
|
I included one file you have to change as an attachment . You have to
|
||||||
|
put it in /FlightGear/Tools/Lib/Polygon/ rebuild the libPolygon and
|
||||||
|
then change the shape-decode. Go to /FlightGear/Tools/Prep/ShapeFile/
|
||||||
|
open main.cxx and either comment out line # 357 or add || area ==
|
||||||
|
DefaultArea at line #279.
|
||||||
|
Then you have to rebuild the shape-decode. Now we are ready to generate
|
||||||
|
the landuse data.
|
||||||
|
./shapedecode /name/of_the_file_from_esri /work_dir/work.states
|
||||||
|
|
||||||
|
(in my case it is ./shapedecode /users/anovikov/fgfs_data/aalandsc
|
||||||
|
/home/anovikov/w020n90/work.states).
|
||||||
|
|
||||||
|
5) Hydro and Urban data.
|
||||||
|
|
||||||
|
Origianlly I was using the same ESRI web server but this is kind of very
|
||||||
|
tricky part that I will not tell you. (I was writing about the way to do
|
||||||
|
it in the mailing list)
|
||||||
|
|
||||||
|
I think that one can get data from Coastline Extractor using "Rivers
|
||||||
|
from WDBII" but I'm not 100% sure.
|
||||||
|
|
||||||
|
If you have acess to DCW then you just run shapedecode on the
|
||||||
|
corresponding files puting hydro data in the directory work.hydro and
|
||||||
|
urban data in the directory work.urban.
|
||||||
|
|
||||||
|
As Curtis changed the directory structure in the last CVS versions you
|
||||||
|
have to look in Construct/Main/main.cxx first and modify the directory
|
||||||
|
names accordingly. (FE 30 arc-sec files should be in work_base/DEM-30/
|
||||||
|
|
||||||
|
Now we finished with data preparation and we can start generating
|
||||||
|
scenery but first we need to change the resolution of the data from the
|
||||||
|
default values ( if we are working with 30 arc sec DEMs). You have to
|
||||||
|
find line
|
||||||
|
double error = 200.0 in Construct/Main/main.cxx and change initial error
|
||||||
|
to smth like 10. Then you need to rebuild everything in that directory.
|
||||||
|
|
||||||
|
I generally hate using fgfs-launch-clients and fgfs-launch-server so I'm
|
||||||
|
doing everyting (almost) by hand. So I start from Construct/Parallel
|
||||||
|
launch fgfs-tools-server on the computer with data on local disk and
|
||||||
|
then slogin to other computers ( with data mounted over nfs) and run
|
||||||
|
fgfs-tools-client in rude mode. After a while scenery is ready.
|
||||||
|
|
||||||
|
That's all folks,
|
||||||
|
Alexei.
|
1
VERSION
Normal file
1
VERSION
Normal file
|
@ -0,0 +1 @@
|
||||||
|
0.0.0
|
1
VERSION.in
Normal file
1
VERSION.in
Normal file
|
@ -0,0 +1 @@
|
||||||
|
@VERSION@
|
324
acconfig.h
Normal file
324
acconfig.h
Normal file
|
@ -0,0 +1,324 @@
|
||||||
|
/* acconfig.h
|
||||||
|
This file is in the public domain.
|
||||||
|
|
||||||
|
Descriptive text for the C preprocessor macros that
|
||||||
|
the distributed Autoconf macros can define.
|
||||||
|
No software package will use all of them; autoheader copies the ones
|
||||||
|
your configure.in uses into your configuration header file templates.
|
||||||
|
|
||||||
|
The entries are in sort -df order: alphabetical, case insensitive,
|
||||||
|
ignoring punctuation (such as underscores). Although this order
|
||||||
|
can split up related entries, it makes it easier to check whether
|
||||||
|
a given entry is in the file.
|
||||||
|
|
||||||
|
Leave the following blank line there!! Autoheader needs it. */
|
||||||
|
|
||||||
|
|
||||||
|
/* Define if on AIX 3.
|
||||||
|
System headers sometimes define this.
|
||||||
|
We just want to avoid a redefinition error message. */
|
||||||
|
#ifndef _ALL_SOURCE
|
||||||
|
#undef _ALL_SOURCE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Define if using alloca.c. */
|
||||||
|
#undef C_ALLOCA
|
||||||
|
|
||||||
|
/* Define if type char is unsigned and you are not using gcc. */
|
||||||
|
#ifndef __CHAR_UNSIGNED__
|
||||||
|
#undef __CHAR_UNSIGNED__
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Define if the closedir function returns void instead of int. */
|
||||||
|
#undef CLOSEDIR_VOID
|
||||||
|
|
||||||
|
/* Define to empty if the keyword does not work. */
|
||||||
|
#undef const
|
||||||
|
|
||||||
|
/* Define to one of _getb67, GETB67, getb67 for Cray-2 and Cray-YMP systems.
|
||||||
|
This function is required for alloca.c support on those systems. */
|
||||||
|
#undef CRAY_STACKSEG_END
|
||||||
|
|
||||||
|
/* Define for DGUX with <sys/dg_sys_info.h>. */
|
||||||
|
#undef DGUX
|
||||||
|
|
||||||
|
/* Define if you have <dirent.h>. */
|
||||||
|
#undef DIRENT
|
||||||
|
|
||||||
|
/* Define to enable audio support */
|
||||||
|
#undef ENABLE_AUDIO_SUPPORT
|
||||||
|
|
||||||
|
/* Define to enable GLUT joystick support (limited to 3 axes) */
|
||||||
|
#undef ENABLE_GLUT_JOYSTICK
|
||||||
|
|
||||||
|
/* Define to enable plib joystick support (recommended) */
|
||||||
|
#undef ENABLE_PLIB_JOYSTICK
|
||||||
|
|
||||||
|
/* Define to eliminate all trace of debugging messages such as for a
|
||||||
|
release build */
|
||||||
|
#undef FG_NDEBUG
|
||||||
|
|
||||||
|
/* Define to include Oliver's networking support */
|
||||||
|
#undef FG_NETWORK_OLK
|
||||||
|
|
||||||
|
/* Define to avoid Christian's new weather code */
|
||||||
|
#undef FG_OLD_WEATHER
|
||||||
|
|
||||||
|
/* Define if we are building FGFS (should always be defined) */
|
||||||
|
#undef FGFS
|
||||||
|
|
||||||
|
/* Define to enable 3dfx/glide render in a window hack under unix.
|
||||||
|
This probably won't work under windows. */
|
||||||
|
#undef XMESA
|
||||||
|
#undef FX
|
||||||
|
|
||||||
|
/* Define to the type of elements in the array set by `getgroups'.
|
||||||
|
Usually this is either `int' or `gid_t'. */
|
||||||
|
#undef GETGROUPS_T
|
||||||
|
|
||||||
|
/* Define if the `getloadavg' function needs to be run setuid or setgid. */
|
||||||
|
#undef GETLOADAVG_PRIVILEGED
|
||||||
|
|
||||||
|
/* Define if the `getpgrp' function takes no argument. */
|
||||||
|
#undef GETPGRP_VOID
|
||||||
|
|
||||||
|
/* Define to `int' if <sys/types.h> doesn't define. */
|
||||||
|
#undef gid_t
|
||||||
|
|
||||||
|
/* Define if you have alloca, as a function or macro. */
|
||||||
|
#undef HAVE_ALLOCA
|
||||||
|
|
||||||
|
/* Define if you have <alloca.h> and it should be used (not on Ultrix). */
|
||||||
|
#undef HAVE_ALLOCA_H
|
||||||
|
|
||||||
|
/* Define if you external variables daylight. */
|
||||||
|
#undef HAVE_DAYLIGHT
|
||||||
|
|
||||||
|
/* Define if you don't have vprintf but do have _doprnt. */
|
||||||
|
#undef HAVE_DOPRNT
|
||||||
|
|
||||||
|
/* Define if your system has a working fnmatch function. */
|
||||||
|
#undef HAVE_FNMATCH
|
||||||
|
|
||||||
|
/* Define if your system has its own `getloadavg' function. */
|
||||||
|
#undef HAVE_GETLOADAVG
|
||||||
|
|
||||||
|
/* Define if you have getrusage() */
|
||||||
|
#undef HAVE_GETRUSAGE
|
||||||
|
|
||||||
|
/* Define if you have the getmntent function. */
|
||||||
|
#undef HAVE_GETMNTENT
|
||||||
|
|
||||||
|
/* Define if you have the gpc library and headers installed. */
|
||||||
|
#undef HAVE_GPC_H
|
||||||
|
|
||||||
|
/* Define if the `long double' type works. */
|
||||||
|
#undef HAVE_LONG_DOUBLE
|
||||||
|
|
||||||
|
/* Define if you support file names longer than 14 characters. */
|
||||||
|
#undef HAVE_LONG_FILE_NAMES
|
||||||
|
|
||||||
|
/* Define if you have a working `mmap' system call. */
|
||||||
|
#undef HAVE_MMAP
|
||||||
|
|
||||||
|
/* Define if system calls automatically restart after interruption
|
||||||
|
by a signal. */
|
||||||
|
#undef HAVE_RESTARTABLE_SYSCALLS
|
||||||
|
|
||||||
|
/* Define if you have rint() which rounds to closest int but returns
|
||||||
|
result as a double data type. */
|
||||||
|
#undef HAVE_RINT
|
||||||
|
|
||||||
|
/* Define if your struct stat has st_blksize. */
|
||||||
|
#undef HAVE_ST_BLKSIZE
|
||||||
|
|
||||||
|
/* Define if your struct stat has st_blocks. */
|
||||||
|
#undef HAVE_ST_BLOCKS
|
||||||
|
|
||||||
|
/* Define if you have the strcoll function and it is properly defined. */
|
||||||
|
#undef HAVE_STRCOLL
|
||||||
|
|
||||||
|
/* Define if your struct stat has st_rdev. */
|
||||||
|
#undef HAVE_ST_RDEV
|
||||||
|
|
||||||
|
/* Define if you have the strftime function. */
|
||||||
|
#undef HAVE_STRFTIME
|
||||||
|
|
||||||
|
/* Define if you have <sys/param.h> */
|
||||||
|
#undef HAVE_SYS_PARAM_H
|
||||||
|
|
||||||
|
/* Define if you have <sys/stat.h> that is POSIX.1 compatible. */
|
||||||
|
#undef HAVE_SYS_STAT_H
|
||||||
|
|
||||||
|
/* Define if you have <sys/wait.h> that is POSIX.1 compatible. */
|
||||||
|
#undef HAVE_SYS_WAIT_H
|
||||||
|
|
||||||
|
/* Define if you have timegm() */
|
||||||
|
#undef HAVE_TIMEGM
|
||||||
|
|
||||||
|
/* Define if you external variables timezone. */
|
||||||
|
#undef HAVE_TIMEZONE
|
||||||
|
|
||||||
|
/* Define if your struct tm has tm_zone. */
|
||||||
|
#undef HAVE_TM_ZONE
|
||||||
|
|
||||||
|
/* Define if you don't have tm_zone but do have the external array
|
||||||
|
tzname. */
|
||||||
|
#undef HAVE_TZNAME
|
||||||
|
|
||||||
|
/* Define if you have <unistd.h>. */
|
||||||
|
#undef HAVE_UNISTD_H
|
||||||
|
|
||||||
|
/* Define if utime(file, NULL) sets file's timestamp to the present. */
|
||||||
|
#undef HAVE_UTIME_NULL
|
||||||
|
|
||||||
|
/* Define if you have <vfork.h>. */
|
||||||
|
#undef HAVE_VFORK_H
|
||||||
|
|
||||||
|
/* Define if you have the vprintf function. */
|
||||||
|
#undef HAVE_VPRINTF
|
||||||
|
|
||||||
|
/* Define if you have the wait3 system call. */
|
||||||
|
#undef HAVE_WAIT3
|
||||||
|
|
||||||
|
/* Define as __inline if that's what the C compiler calls it. */
|
||||||
|
#undef inline
|
||||||
|
|
||||||
|
/* Define if int is 16 bits instead of 32. */
|
||||||
|
#undef INT_16_BITS
|
||||||
|
|
||||||
|
/* Define if long int is 64 bits. */
|
||||||
|
#undef LONG_64_BITS
|
||||||
|
|
||||||
|
/* Define if major, minor, and makedev are declared in <mkdev.h>. */
|
||||||
|
#undef MAJOR_IN_MKDEV
|
||||||
|
|
||||||
|
/* Define if major, minor, and makedev are declared in <sysmacros.h>. */
|
||||||
|
#undef MAJOR_IN_SYSMACROS
|
||||||
|
|
||||||
|
/* Define if on MINIX. */
|
||||||
|
#undef _MINIX
|
||||||
|
|
||||||
|
/* Define to `int' if <sys/types.h> doesn't define. */
|
||||||
|
#undef mode_t
|
||||||
|
|
||||||
|
/* Define if you don't have <dirent.h>, but have <ndir.h>. */
|
||||||
|
#undef NDIR
|
||||||
|
|
||||||
|
/* Define if you have <memory.h>, and <string.h> doesn't declare the
|
||||||
|
mem* functions. */
|
||||||
|
#undef NEED_MEMORY_H
|
||||||
|
|
||||||
|
/* Define if your struct nlist has an n_un member. */
|
||||||
|
#undef NLIST_NAME_UNION
|
||||||
|
|
||||||
|
/* Define if you have <nlist.h>. */
|
||||||
|
#undef NLIST_STRUCT
|
||||||
|
|
||||||
|
/* Define if your C compiler doesn't accept -c and -o together. */
|
||||||
|
#undef NO_MINUS_C_MINUS_O
|
||||||
|
|
||||||
|
/* Define to `long' if <sys/types.h> doesn't define. */
|
||||||
|
#undef off_t
|
||||||
|
|
||||||
|
/* Define to package name */
|
||||||
|
#undef PACKAGE
|
||||||
|
|
||||||
|
/* Define to `int' if <sys/types.h> doesn't define. */
|
||||||
|
#undef pid_t
|
||||||
|
|
||||||
|
/* Define if the system does not provide POSIX.1 features except
|
||||||
|
with this defined. */
|
||||||
|
#undef _POSIX_1_SOURCE
|
||||||
|
|
||||||
|
/* Define if you need to in order for stat and other things to work. */
|
||||||
|
#undef _POSIX_SOURCE
|
||||||
|
|
||||||
|
/* Define as the return type of signal handlers (int or void). */
|
||||||
|
#undef RETSIGTYPE
|
||||||
|
|
||||||
|
/* Define if the `setpgrp' function takes no argument. */
|
||||||
|
#undef SETPGRP_VOID
|
||||||
|
|
||||||
|
/* Define if the setvbuf function takes the buffering type as its second
|
||||||
|
argument and the buffer pointer as the third, as on System V
|
||||||
|
before release 3. */
|
||||||
|
#undef SETVBUF_REVERSED
|
||||||
|
|
||||||
|
/* Define to `unsigned' if <sys/types.h> doesn't define. */
|
||||||
|
#undef size_t
|
||||||
|
|
||||||
|
/* If using the C implementation of alloca, define if you know the
|
||||||
|
direction of stack growth for your system; otherwise it will be
|
||||||
|
automatically deduced at run-time.
|
||||||
|
STACK_DIRECTION > 0 => grows toward higher addresses
|
||||||
|
STACK_DIRECTION < 0 => grows toward lower addresses
|
||||||
|
STACK_DIRECTION = 0 => direction of growth unknown
|
||||||
|
*/
|
||||||
|
#undef STACK_DIRECTION
|
||||||
|
|
||||||
|
/* Define if the `S_IS*' macros in <sys/stat.h> do not work properly. */
|
||||||
|
#undef STAT_MACROS_BROKEN
|
||||||
|
|
||||||
|
/* Define if you have the ANSI C header files. */
|
||||||
|
#undef STDC_HEADERS
|
||||||
|
|
||||||
|
/* Define on System V Release 4. */
|
||||||
|
#undef SVR4
|
||||||
|
|
||||||
|
/* Define if you don't have <dirent.h>, but have <sys/dir.h>. */
|
||||||
|
#undef SYSDIR
|
||||||
|
|
||||||
|
/* Define if you don't have <dirent.h>, but have <sys/ndir.h>. */
|
||||||
|
#undef SYSNDIR
|
||||||
|
|
||||||
|
/* Define if `sys_siglist' is declared by <signal.h>. */
|
||||||
|
#undef SYS_SIGLIST_DECLARED
|
||||||
|
|
||||||
|
/* Define if you can safely include both <sys/time.h> and <time.h>. */
|
||||||
|
#undef TIME_WITH_SYS_TIME
|
||||||
|
|
||||||
|
/* Define if your <sys/time.h> declares struct tm. */
|
||||||
|
#undef TM_IN_SYS_TIME
|
||||||
|
|
||||||
|
/* Define to `int' if <sys/types.h> doesn't define. */
|
||||||
|
#undef uid_t
|
||||||
|
|
||||||
|
/* Define for Encore UMAX. */
|
||||||
|
#undef UMAX
|
||||||
|
|
||||||
|
/* Define for Encore UMAX 4.3 that has <inq_status/cpustats.h>
|
||||||
|
instead of <sys/cpustats.h>. */
|
||||||
|
#undef UMAX4_3
|
||||||
|
|
||||||
|
/* Define if you do not have <strings.h>, index, bzero, etc.. */
|
||||||
|
#undef USG
|
||||||
|
|
||||||
|
/* Define to version number */
|
||||||
|
#undef VERSION
|
||||||
|
|
||||||
|
/* Define vfork as fork if vfork does not work. */
|
||||||
|
#undef vfork
|
||||||
|
|
||||||
|
/* Define if the closedir function returns void instead of int. */
|
||||||
|
#undef VOID_CLOSEDIR
|
||||||
|
|
||||||
|
/* Define if compiling on a Winbloze (95, NT, etc.) platform */
|
||||||
|
#undef WIN32
|
||||||
|
|
||||||
|
/* Define if your processor stores words with the most significant
|
||||||
|
byte first (like Motorola and SPARC, unlike Intel and VAX). */
|
||||||
|
#undef WORDS_BIGENDIAN
|
||||||
|
|
||||||
|
/* Define if the X Window System is missing or not being used. */
|
||||||
|
#undef X_DISPLAY_MISSING
|
||||||
|
|
||||||
|
/* Define if lex declares yytext as a char * by default, not a char[]. */
|
||||||
|
#undef YYTEXT_POINTER
|
||||||
|
|
||||||
|
|
||||||
|
/* Leave that blank line there!! Autoheader needs it.
|
||||||
|
If you're adding to this file, keep in mind:
|
||||||
|
The entries are in sort -df order: alphabetical, case insensitive,
|
||||||
|
ignoring punctuation (such as underscores). */
|
||||||
|
|
149
aclocal.m4
vendored
Normal file
149
aclocal.m4
vendored
Normal file
|
@ -0,0 +1,149 @@
|
||||||
|
dnl aclocal.m4 generated automatically by aclocal 1.3
|
||||||
|
|
||||||
|
dnl Copyright (C) 1994, 1995, 1996, 1997, 1998 Free Software Foundation, Inc.
|
||||||
|
dnl This Makefile.in is free software; the Free Software Foundation
|
||||||
|
dnl gives unlimited permission to copy and/or distribute it,
|
||||||
|
dnl with or without modifications, as long as this notice is preserved.
|
||||||
|
|
||||||
|
dnl This program is distributed in the hope that it will be useful,
|
||||||
|
dnl but WITHOUT ANY WARRANTY, to the extent permitted by law; without
|
||||||
|
dnl even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||||
|
dnl PARTICULAR PURPOSE.
|
||||||
|
|
||||||
|
# Do all the work for Automake. This macro actually does too much --
|
||||||
|
# some checks are only needed if your package does certain things.
|
||||||
|
# But this isn't really a big deal.
|
||||||
|
|
||||||
|
# serial 1
|
||||||
|
|
||||||
|
dnl Usage:
|
||||||
|
dnl AM_INIT_AUTOMAKE(package,version, [no-define])
|
||||||
|
|
||||||
|
AC_DEFUN(AM_INIT_AUTOMAKE,
|
||||||
|
[AC_REQUIRE([AM_PROG_INSTALL])
|
||||||
|
PACKAGE=[$1]
|
||||||
|
AC_SUBST(PACKAGE)
|
||||||
|
VERSION=[$2]
|
||||||
|
AC_SUBST(VERSION)
|
||||||
|
dnl test to see if srcdir already configured
|
||||||
|
if test "`cd $srcdir && pwd`" != "`pwd`" && test -f $srcdir/config.status; then
|
||||||
|
AC_MSG_ERROR([source directory already configured; run "make distclean" there first])
|
||||||
|
fi
|
||||||
|
ifelse([$3],,
|
||||||
|
AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE")
|
||||||
|
AC_DEFINE_UNQUOTED(VERSION, "$VERSION"))
|
||||||
|
AC_REQUIRE([AM_SANITY_CHECK])
|
||||||
|
AC_REQUIRE([AC_ARG_PROGRAM])
|
||||||
|
dnl FIXME This is truly gross.
|
||||||
|
missing_dir=`cd $ac_aux_dir && pwd`
|
||||||
|
AM_MISSING_PROG(ACLOCAL, aclocal, $missing_dir)
|
||||||
|
AM_MISSING_PROG(AUTOCONF, autoconf, $missing_dir)
|
||||||
|
AM_MISSING_PROG(AUTOMAKE, automake, $missing_dir)
|
||||||
|
AM_MISSING_PROG(AUTOHEADER, autoheader, $missing_dir)
|
||||||
|
AM_MISSING_PROG(MAKEINFO, makeinfo, $missing_dir)
|
||||||
|
AC_REQUIRE([AC_PROG_MAKE_SET])])
|
||||||
|
|
||||||
|
|
||||||
|
# serial 1
|
||||||
|
|
||||||
|
AC_DEFUN(AM_PROG_INSTALL,
|
||||||
|
[AC_REQUIRE([AC_PROG_INSTALL])
|
||||||
|
test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL_PROGRAM}'
|
||||||
|
AC_SUBST(INSTALL_SCRIPT)dnl
|
||||||
|
])
|
||||||
|
|
||||||
|
#
|
||||||
|
# Check to make sure that the build environment is sane.
|
||||||
|
#
|
||||||
|
|
||||||
|
AC_DEFUN(AM_SANITY_CHECK,
|
||||||
|
[AC_MSG_CHECKING([whether build environment is sane])
|
||||||
|
# Just in case
|
||||||
|
sleep 1
|
||||||
|
echo timestamp > conftestfile
|
||||||
|
# Do `set' in a subshell so we don't clobber the current shell's
|
||||||
|
# arguments. Must try -L first in case configure is actually a
|
||||||
|
# symlink; some systems play weird games with the mod time of symlinks
|
||||||
|
# (eg FreeBSD returns the mod time of the symlink's containing
|
||||||
|
# directory).
|
||||||
|
if (
|
||||||
|
set X `ls -Lt $srcdir/configure conftestfile 2> /dev/null`
|
||||||
|
if test "[$]*" = "X"; then
|
||||||
|
# -L didn't work.
|
||||||
|
set X `ls -t $srcdir/configure conftestfile`
|
||||||
|
fi
|
||||||
|
if test "[$]*" != "X $srcdir/configure conftestfile" \
|
||||||
|
&& test "[$]*" != "X conftestfile $srcdir/configure"; then
|
||||||
|
|
||||||
|
# If neither matched, then we have a broken ls. This can happen
|
||||||
|
# if, for instance, CONFIG_SHELL is bash and it inherits a
|
||||||
|
# broken ls alias from the environment. This has actually
|
||||||
|
# happened. Such a system could not be considered "sane".
|
||||||
|
AC_MSG_ERROR([ls -t appears to fail. Make sure there is not a broken
|
||||||
|
alias in your environment])
|
||||||
|
fi
|
||||||
|
|
||||||
|
test "[$]2" = conftestfile
|
||||||
|
)
|
||||||
|
then
|
||||||
|
# Ok.
|
||||||
|
:
|
||||||
|
else
|
||||||
|
AC_MSG_ERROR([newly created file is older than distributed files!
|
||||||
|
Check your system clock])
|
||||||
|
fi
|
||||||
|
rm -f conftest*
|
||||||
|
AC_MSG_RESULT(yes)])
|
||||||
|
|
||||||
|
dnl AM_MISSING_PROG(NAME, PROGRAM, DIRECTORY)
|
||||||
|
dnl The program must properly implement --version.
|
||||||
|
AC_DEFUN(AM_MISSING_PROG,
|
||||||
|
[AC_MSG_CHECKING(for working $2)
|
||||||
|
# Run test in a subshell; some versions of sh will print an error if
|
||||||
|
# an executable is not found, even if stderr is redirected.
|
||||||
|
# Redirect stdin to placate older versions of autoconf. Sigh.
|
||||||
|
if ($2 --version) < /dev/null > /dev/null 2>&1; then
|
||||||
|
$1=$2
|
||||||
|
AC_MSG_RESULT(found)
|
||||||
|
else
|
||||||
|
$1="$3/missing $2"
|
||||||
|
AC_MSG_RESULT(missing)
|
||||||
|
fi
|
||||||
|
AC_SUBST($1)])
|
||||||
|
|
||||||
|
# Define a conditional.
|
||||||
|
|
||||||
|
AC_DEFUN(AM_CONDITIONAL,
|
||||||
|
[AC_SUBST($1_TRUE)
|
||||||
|
AC_SUBST($1_FALSE)
|
||||||
|
if $2; then
|
||||||
|
$1_TRUE=
|
||||||
|
$1_FALSE='#'
|
||||||
|
else
|
||||||
|
$1_TRUE='#'
|
||||||
|
$1_FALSE=
|
||||||
|
fi])
|
||||||
|
|
||||||
|
# Like AC_CONFIG_HEADER, but automatically create stamp file.
|
||||||
|
|
||||||
|
AC_DEFUN(AM_CONFIG_HEADER,
|
||||||
|
[AC_PREREQ([2.12])
|
||||||
|
AC_CONFIG_HEADER([$1])
|
||||||
|
dnl When config.status generates a header, we must update the stamp-h file.
|
||||||
|
dnl This file resides in the same directory as the config header
|
||||||
|
dnl that is generated. We must strip everything past the first ":",
|
||||||
|
dnl and everything past the last "/".
|
||||||
|
AC_OUTPUT_COMMANDS(changequote(<<,>>)dnl
|
||||||
|
ifelse(patsubst(<<$1>>, <<[^ ]>>, <<>>), <<>>,
|
||||||
|
<<test -z "<<$>>CONFIG_HEADERS" || echo timestamp > patsubst(<<$1>>, <<^\([^:]*/\)?.*>>, <<\1>>)stamp-h<<>>dnl>>,
|
||||||
|
<<am_indx=1
|
||||||
|
for am_file in <<$1>>; do
|
||||||
|
case " <<$>>CONFIG_HEADERS " in
|
||||||
|
*" <<$>>am_file "*<<)>>
|
||||||
|
echo timestamp > `echo <<$>>am_file | sed -e 's%:.*%%' -e 's%[^/]*$%%'`stamp-h$am_indx
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
am_indx=`expr "<<$>>am_indx" + 1`
|
||||||
|
done<<>>dnl>>)
|
||||||
|
changequote([,]))])
|
||||||
|
|
394
acsite.m4
Normal file
394
acsite.m4
Normal file
|
@ -0,0 +1,394 @@
|
||||||
|
dnl
|
||||||
|
dnl originally from ncftp 2.3.0
|
||||||
|
dnl added wi_EXTRA_PDIR and wi_ANSI_C
|
||||||
|
dnl $Id$
|
||||||
|
dnl
|
||||||
|
AC_DEFUN(wi_EXTRA_IDIR, [
|
||||||
|
incdir="$1"
|
||||||
|
if test -r $incdir ; then
|
||||||
|
case "$CPPFLAGS" in
|
||||||
|
*-I${incdir}*)
|
||||||
|
# echo " + already had $incdir" 1>&6
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
if test "$CPPFLAGS" = "" ; then
|
||||||
|
CPPFLAGS="-I$incdir"
|
||||||
|
else
|
||||||
|
CPPFLAGS="$CPPFLAGS -I$incdir"
|
||||||
|
fi
|
||||||
|
echo " + found $incdir" 1>&6
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
])
|
||||||
|
dnl
|
||||||
|
dnl
|
||||||
|
dnl
|
||||||
|
dnl
|
||||||
|
AC_DEFUN(wi_EXTRA_LDIR, [
|
||||||
|
mylibdir="$1"
|
||||||
|
if test -r $mylibdir ; then
|
||||||
|
case "$LDFLAGS" in
|
||||||
|
*-L${mylibdir}*)
|
||||||
|
# echo " + already had $mylibdir" 1>&6
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
if test "$LDFLAGS" = "" ; then
|
||||||
|
LDFLAGS="-L$mylibdir"
|
||||||
|
else
|
||||||
|
LDFLAGS="$LDFLAGS -L$mylibdir"
|
||||||
|
fi
|
||||||
|
echo " + found $mylibdir" 1>&6
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
])
|
||||||
|
dnl
|
||||||
|
dnl __FP__
|
||||||
|
dnl
|
||||||
|
dnl
|
||||||
|
AC_DEFUN(wi_EXTRA_PDIR, [
|
||||||
|
progdir="$1"
|
||||||
|
if test -r $progdir ; then
|
||||||
|
case "$PATH" in
|
||||||
|
*:${progdir}*)
|
||||||
|
# echo " + already had $progdir" 1>&6
|
||||||
|
;;
|
||||||
|
*${progdir}:*)
|
||||||
|
# echo " + already had $progdir" 1>&6
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
if test "$PATH" = "" ; then
|
||||||
|
PATH="$progdir"
|
||||||
|
else
|
||||||
|
PATH="$PATH:$progdir"
|
||||||
|
fi
|
||||||
|
echo " + found $progdir" 1>&6
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
])
|
||||||
|
dnl
|
||||||
|
dnl
|
||||||
|
dnl If you want to also look for include and lib subdirectories in the
|
||||||
|
dnl $HOME tree, you supply "yes" as the first argument to this macro.
|
||||||
|
dnl
|
||||||
|
dnl If you want to look for subdirectories in include/lib directories,
|
||||||
|
dnl you pass the names in argument 3, otherwise pass a dash.
|
||||||
|
dnl
|
||||||
|
AC_DEFUN(wi_EXTRA_DIRS, [echo "checking for extra include and lib directories..." 1>&6
|
||||||
|
ifelse([$1], yes, [dnl
|
||||||
|
b1=`cd .. ; pwd`
|
||||||
|
b2=`cd ../.. ; pwd`
|
||||||
|
exdirs="$HOME $j $b1 $b2 $prefix $2"
|
||||||
|
],[dnl
|
||||||
|
exdirs="$prefix $2"
|
||||||
|
])
|
||||||
|
subexdirs="$3"
|
||||||
|
if test "$subexdirs" = "" ; then
|
||||||
|
subexdirs="-"
|
||||||
|
fi
|
||||||
|
for subexdir in $subexdirs ; do
|
||||||
|
if test "$subexdir" = "-" ; then
|
||||||
|
subexdir=""
|
||||||
|
else
|
||||||
|
subexdir="/$subexdir"
|
||||||
|
fi
|
||||||
|
for exdir in $exdirs ; do
|
||||||
|
if test "$exdir" != "/usr" || test "$subexdir" != ""; then
|
||||||
|
incdir="${exdir}/include${subexdir}"
|
||||||
|
wi_EXTRA_IDIR($incdir)
|
||||||
|
|
||||||
|
mylibdir="${exdir}/lib${subexdir}"
|
||||||
|
wi_EXTRA_LDIR($mylibdir)
|
||||||
|
|
||||||
|
progdir="${exdir}/bin${subexdirr}"
|
||||||
|
wi_EXTRA_PDIR($progdir)
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
done
|
||||||
|
])
|
||||||
|
dnl
|
||||||
|
dnl
|
||||||
|
dnl
|
||||||
|
AC_DEFUN(wi_HPUX_CFLAGS,
|
||||||
|
[AC_MSG_CHECKING(if HP-UX ansi C compiler flags are needed)
|
||||||
|
AC_REQUIRE([AC_PROG_CC])
|
||||||
|
os=`uname -s | tr '[A-Z]' '[a-z]'`
|
||||||
|
ac_cv_hpux_flags=no
|
||||||
|
if test "$os" = hp-ux ; then
|
||||||
|
if test "$ac_cv_prog_gcc" = yes ; then
|
||||||
|
if test "$CFLAGS" != "" ; then
|
||||||
|
# Shouldn't be in there.
|
||||||
|
CFLAGS=`echo "$CFLAGS" | sed 's/-Aa//g'`
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
# If you're not using gcc, then you better have a cc/c89
|
||||||
|
# that is usable. If you have the barebones compiler, it
|
||||||
|
# won't work. The good compiler uses -Aa for the ANSI
|
||||||
|
# compatible stuff.
|
||||||
|
x=`echo $CFLAGS | grep 'Aa' 2>/dev/null`
|
||||||
|
if test "$x" = "" ; then
|
||||||
|
CFLAGS="$CFLAGS -Aa"
|
||||||
|
fi
|
||||||
|
ac_cv_hpux_flags=yes
|
||||||
|
fi
|
||||||
|
# Also add _HPUX_SOURCE to get the extended namespace.
|
||||||
|
x=`echo $CFLAGS | grep '_HPUX_SOURCE' 2>/dev/null`
|
||||||
|
if test "$x" = "" ; then
|
||||||
|
CFLAGS="$CFLAGS -D_HPUX_SOURCE"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
AC_MSG_RESULT($ac_cv_hpux_flags)
|
||||||
|
])
|
||||||
|
dnl
|
||||||
|
dnl
|
||||||
|
dnl
|
||||||
|
AC_DEFUN(wi_CFLAGS, [AC_REQUIRE([AC_PROG_CC])
|
||||||
|
wi_HPUX_CFLAGS
|
||||||
|
if test "$CFLAGS" = "" ; then
|
||||||
|
CFLAGS="-O"
|
||||||
|
elif test "$ac_cv_prog_gcc" = "yes" ; then
|
||||||
|
case "$CFLAGS" in
|
||||||
|
*"-g -O"*)
|
||||||
|
#echo "using -g as default gcc CFLAGS" 1>&6
|
||||||
|
CFLAGS=`echo $CFLAGS | sed 's/-g\ -O/-O/'`
|
||||||
|
;;
|
||||||
|
*"-O -g"*)
|
||||||
|
# Leave the -g, but remove all -O options.
|
||||||
|
#echo "using -g as default gcc CFLAGS" 1>&6
|
||||||
|
CFLAGS=`echo $CFLAGS | sed 's/-O\ -g/-O/'`
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
])
|
||||||
|
dnl
|
||||||
|
dnl
|
||||||
|
dnl
|
||||||
|
AC_DEFUN(wi_PROTOTYPES, [
|
||||||
|
AC_MSG_CHECKING(if the compiler supports function prototypes)
|
||||||
|
AC_TRY_COMPILE(,[extern void exit(int status);],[wi_cv_prototypes=yes
|
||||||
|
AC_DEFINE(PROTOTYPES)],wi_cv_prototypes=no)
|
||||||
|
AC_MSG_RESULT($wi_cv_prototypes)
|
||||||
|
])
|
||||||
|
dnl
|
||||||
|
dnl
|
||||||
|
dnl
|
||||||
|
AC_DEFUN(wi_ANSI_C, [
|
||||||
|
AC_MSG_CHECKING(ANSI-style function definitions)
|
||||||
|
AC_TRY_COMPILE(,[int blubb(int x) { return 0; }],[wi_cv_ansi_funcs=yes
|
||||||
|
AC_DEFINE(ANSI_FUNCS)],wi_cv_ansi_funcs=no)
|
||||||
|
AC_MSG_RESULT($wi_cv_ansi_funcs)
|
||||||
|
])
|
||||||
|
dnl
|
||||||
|
dnl
|
||||||
|
dnl
|
||||||
|
AC_DEFUN(wi_HEADER_SYS_SELECT_H, [
|
||||||
|
# See if <sys/select.h> is includable after <sys/time.h>
|
||||||
|
if test "$ac_cv_header_sys_time_h" = no ; then
|
||||||
|
AC_CHECK_HEADERS(sys/time.h sys/select.h)
|
||||||
|
else
|
||||||
|
AC_CHECK_HEADERS(sys/select.h)
|
||||||
|
fi
|
||||||
|
if test "$ac_cv_header_sys_select_h" = yes ; then
|
||||||
|
AC_MSG_CHECKING([if <sys/select.h> is compatible with <sys/time.h>])
|
||||||
|
selecth=yes
|
||||||
|
if test "$ac_cv_header_sys_time_h" = yes ; then
|
||||||
|
AC_TRY_COMPILE([#include <sys/time.h>
|
||||||
|
#include <sys/select.h>],[
|
||||||
|
fd_set a;
|
||||||
|
struct timeval tmval;
|
||||||
|
|
||||||
|
tmval.tv_sec = 0;],selecth=yes,selecth=no)
|
||||||
|
|
||||||
|
if test "$selecth" = yes ; then
|
||||||
|
AC_DEFINE(CAN_USE_SYS_SELECT_H)
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
AC_MSG_RESULT($selecth)
|
||||||
|
fi
|
||||||
|
])
|
||||||
|
dnl
|
||||||
|
dnl
|
||||||
|
dnl
|
||||||
|
AC_DEFUN(wi_LIB_RESOLV, [
|
||||||
|
# See if we could access two well-known sites without help of any special
|
||||||
|
# libraries, like resolv.
|
||||||
|
|
||||||
|
AC_TRY_RUN([
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <netdb.h>
|
||||||
|
|
||||||
|
main()
|
||||||
|
{
|
||||||
|
struct hostent *hp1, *hp2;
|
||||||
|
int result;
|
||||||
|
|
||||||
|
hp1 = gethostbyname("gatekeeper.dec.com");
|
||||||
|
hp2 = gethostbyname("ftp.ncsa.uiuc.edu");
|
||||||
|
result = ((hp1 != (struct hostent *) 0) && (hp2 != (struct hostent *) 0));
|
||||||
|
exit(! result);
|
||||||
|
}],look_for_resolv=no,look_for_resolv=yes,look_for_resolv=yes)
|
||||||
|
|
||||||
|
AC_MSG_CHECKING([if we need to look for -lresolv])
|
||||||
|
AC_MSG_RESULT($look_for_resolv)
|
||||||
|
if test "$look_for_resolv" = yes ; then
|
||||||
|
AC_CHECK_LIB(resolv,main)
|
||||||
|
else
|
||||||
|
ac_cv_lib_resolv=no
|
||||||
|
fi
|
||||||
|
])
|
||||||
|
dnl
|
||||||
|
dnl
|
||||||
|
dnl
|
||||||
|
|
||||||
|
AC_DEFUN(wi_LIB_NSL, [
|
||||||
|
AC_MSG_CHECKING(if we can use -lnsl)
|
||||||
|
ac_save_LIBS="$LIBS";
|
||||||
|
LIBS="$LIBS -lnsl";
|
||||||
|
AC_CACHE_VAL(r_cv_use_libnsl, [
|
||||||
|
AC_TRY_RUN(
|
||||||
|
main() { if (getpwuid(getuid())) exit(0); exit(-1); },
|
||||||
|
nc_cv_use_libnsl=yes, nc_cv_use_libnsl=no, nc_cv_use_libnsl=no)
|
||||||
|
])
|
||||||
|
if test "$nc_cv_use_libnsl" = "no"; then LIBS="$ac_save_LIBS"; fi
|
||||||
|
AC_MSG_RESULT($nc_cv_use_libnsl)
|
||||||
|
])dnl
|
||||||
|
|
||||||
|
dnl
|
||||||
|
dnl
|
||||||
|
dnl
|
||||||
|
|
||||||
|
AC_DEFUN(nc_PATH_PROG_ZCAT, [
|
||||||
|
AC_PATH_PROG(GZCAT,gzcat)
|
||||||
|
AC_PATH_PROG(ZCAT,zcat)
|
||||||
|
if test "x$GZCAT" = x ; then
|
||||||
|
if test "x$ZCAT" != x ; then
|
||||||
|
# See if zcat is really gzcat. gzcat has a --version option, regular
|
||||||
|
# zcat does not.
|
||||||
|
AC_MSG_CHECKING(if zcat is really gzcat in disguise)
|
||||||
|
if $ZCAT --version 2> /dev/null ; then
|
||||||
|
AC_DEFINE_UNQUOTED(GZCAT, "$ZCAT")
|
||||||
|
AC_MSG_RESULT(yes)
|
||||||
|
else
|
||||||
|
AC_MSG_RESULT(no)
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
AC_DEFINE_UNQUOTED(GZCAT, "$GZCAT")
|
||||||
|
fi
|
||||||
|
|
||||||
|
if test "x$ZCAT" != x ; then
|
||||||
|
AC_DEFINE_UNQUOTED(ZCAT, "$ZCAT")
|
||||||
|
fi
|
||||||
|
])
|
||||||
|
dnl
|
||||||
|
dnl
|
||||||
|
dnl
|
||||||
|
AC_DEFUN(wi_SYSV_EXTRA_DIRS, [
|
||||||
|
# Use System V because their curses extensions are required. This must
|
||||||
|
# be done early so we use the -I and -L in the library checks also.
|
||||||
|
# This is mostly a Solaris/SunOS hack. Note that doing this will also
|
||||||
|
# use all of the other System V libraries and headers.
|
||||||
|
|
||||||
|
AC_MSG_CHECKING(for alternative System V libraries)
|
||||||
|
if test -f /usr/5include/curses.h ; then
|
||||||
|
CPPFLAGS="$CPPFLAGS -I/usr/5include"
|
||||||
|
LDFLAGS="$LDFLAGS -L/usr/5lib"
|
||||||
|
AC_MSG_RESULT(yes)
|
||||||
|
else
|
||||||
|
AC_MSG_RESULT(no)
|
||||||
|
fi
|
||||||
|
])
|
||||||
|
dnl
|
||||||
|
dnl
|
||||||
|
dnl
|
||||||
|
AC_DEFUN(wi_DEFINE_UNAME, [
|
||||||
|
# Get first 127 chars of all uname information. Some folks have
|
||||||
|
# way too much stuff there, so grab only the first 127.
|
||||||
|
unam=`uname -a 2>/dev/null | cut -c1-127`
|
||||||
|
if test "$unam" != "" ; then
|
||||||
|
AC_DEFINE_UNQUOTED(UNAME, "$unam")
|
||||||
|
fi
|
||||||
|
])
|
||||||
|
dnl
|
||||||
|
dnl
|
||||||
|
dnl
|
||||||
|
AC_DEFUN(wi_READLINE_WITH_NCURSES, [
|
||||||
|
# Readline and Ncurses could both define "backspace".
|
||||||
|
# Warn about this if we have both things in our definitions list.
|
||||||
|
|
||||||
|
if test "$ac_cv_lib_readline" = yes && test "$ac_cv_lib_ncurses" = yes ; then
|
||||||
|
|
||||||
|
AC_MSG_CHECKING(if readline and ncurses will link together)
|
||||||
|
j="$LIBS"
|
||||||
|
LIBS="-lreadline -lncurses"
|
||||||
|
AC_TRY_LINK(,[
|
||||||
|
readline("prompt");
|
||||||
|
endwin();
|
||||||
|
],k=yes,k=no)
|
||||||
|
if test "$k" = no ; then
|
||||||
|
AC_MSG_RESULT(no)
|
||||||
|
# Remove '-lreadline' from LIBS.
|
||||||
|
LIBS=`echo $j | sed s/-lreadline//g`
|
||||||
|
ac_cv_lib_readline=no
|
||||||
|
AC_WARN([The versions of GNU readline and ncurses you have installed on this system
|
||||||
|
can't be used together, because they use the same symbol, backspace. If
|
||||||
|
possible, recompile one of the libraries with -Dbackspace=back_space, then
|
||||||
|
re-run configure.])
|
||||||
|
|
||||||
|
else
|
||||||
|
AC_MSG_RESULT(yes)
|
||||||
|
LIBS="$j"
|
||||||
|
fi
|
||||||
|
|
||||||
|
fi
|
||||||
|
])
|
||||||
|
dnl
|
||||||
|
dnl
|
||||||
|
dnl
|
||||||
|
|
||||||
|
dnl AC_EXT_DAYLIGHT
|
||||||
|
dnl Check for an external variable daylight. Stolen from w3c-libwww.
|
||||||
|
AC_DEFUN(AC_EXT_DAYLIGHT,
|
||||||
|
[ AC_MSG_CHECKING(int daylight variable)
|
||||||
|
AC_TRY_COMPILE([#include <time.h>], [return daylight;],
|
||||||
|
have_daylight=yes,
|
||||||
|
have_daylight=no)
|
||||||
|
AC_MSG_RESULT($have_daylight)
|
||||||
|
])dnl
|
||||||
|
|
||||||
|
dnl AC_EXT_TIMEZONE
|
||||||
|
dnl Check for an external variable timezone. Stolen from tcl-8.0.
|
||||||
|
AC_DEFUN(AC_EXT_TIMEZONE,
|
||||||
|
[
|
||||||
|
#
|
||||||
|
# Its important to include time.h in this check, as some systems (like convex)
|
||||||
|
# have timezone functions, etc.
|
||||||
|
#
|
||||||
|
have_timezone=no
|
||||||
|
AC_MSG_CHECKING([long timezone variable])
|
||||||
|
AC_TRY_COMPILE([#include <time.h>],
|
||||||
|
[extern long timezone;
|
||||||
|
timezone += 1;
|
||||||
|
exit (0);],
|
||||||
|
[have_timezone=yes
|
||||||
|
AC_MSG_RESULT(yes)],
|
||||||
|
AC_MSG_RESULT(no))
|
||||||
|
|
||||||
|
#
|
||||||
|
# On some systems (eg IRIX 6.2), timezone is a time_t and not a long.
|
||||||
|
#
|
||||||
|
if test "$have_timezone" = no; then
|
||||||
|
AC_MSG_CHECKING([time_t timezone variable])
|
||||||
|
AC_TRY_COMPILE([#include <time.h>],
|
||||||
|
[extern time_t timezone;
|
||||||
|
timezone += 1;
|
||||||
|
exit (0);],
|
||||||
|
[have_timezone=yes
|
||||||
|
AC_MSG_RESULT(yes)],
|
||||||
|
AC_MSG_RESULT(no))
|
||||||
|
fi
|
||||||
|
])dnl
|
89
config.cache
Normal file
89
config.cache
Normal file
|
@ -0,0 +1,89 @@
|
||||||
|
# This file is a shell script that caches the results of configure
|
||||||
|
# tests run on this system so they can be shared between configure
|
||||||
|
# scripts and configure runs. It is not useful on other systems.
|
||||||
|
# If it contains results you don't want to keep, you may remove or edit it.
|
||||||
|
#
|
||||||
|
# By default, configure uses ./config.cache as the cache file,
|
||||||
|
# creating it if it does not exist already. You can give configure
|
||||||
|
# the --cache-file=FILE option to use a different cache file; that is
|
||||||
|
# what configure does when it calls configure scripts in
|
||||||
|
# subdirectories, so they share the cache.
|
||||||
|
# Giving --cache-file=/dev/null disables caching, for debugging configure.
|
||||||
|
# config.status only pays attention to the cache file if you give it the
|
||||||
|
# --recheck option to rerun configure.
|
||||||
|
#
|
||||||
|
ac_cv_c_const=${ac_cv_c_const=yes}
|
||||||
|
ac_cv_func_GetLocalTime=${ac_cv_func_GetLocalTime=no}
|
||||||
|
ac_cv_func_bcopy=${ac_cv_func_bcopy=yes}
|
||||||
|
ac_cv_func_connect=${ac_cv_func_connect=yes}
|
||||||
|
ac_cv_func_ftime=${ac_cv_func_ftime=yes}
|
||||||
|
ac_cv_func_gethostbyname=${ac_cv_func_gethostbyname=yes}
|
||||||
|
ac_cv_func_getitimer=${ac_cv_func_getitimer=yes}
|
||||||
|
ac_cv_func_getrusage=${ac_cv_func_getrusage=yes}
|
||||||
|
ac_cv_func_gettimeofday=${ac_cv_func_gettimeofday=yes}
|
||||||
|
ac_cv_func_memcpy=${ac_cv_func_memcpy=yes}
|
||||||
|
ac_cv_func_mktime=${ac_cv_func_mktime=yes}
|
||||||
|
ac_cv_func_rand=${ac_cv_func_rand=yes}
|
||||||
|
ac_cv_func_random=${ac_cv_func_random=yes}
|
||||||
|
ac_cv_func_remove=${ac_cv_func_remove=yes}
|
||||||
|
ac_cv_func_rint=${ac_cv_func_rint=yes}
|
||||||
|
ac_cv_func_setitimer=${ac_cv_func_setitimer=yes}
|
||||||
|
ac_cv_func_shmat=${ac_cv_func_shmat=yes}
|
||||||
|
ac_cv_func_signal=${ac_cv_func_signal=yes}
|
||||||
|
ac_cv_func_strstr=${ac_cv_func_strstr=yes}
|
||||||
|
ac_cv_func_timegm=${ac_cv_func_timegm=yes}
|
||||||
|
ac_cv_func_vprintf=${ac_cv_func_vprintf=yes}
|
||||||
|
ac_cv_have_x=${ac_cv_have_x='have_x=yes ac_x_includes=/usr/X11R6/include ac_x_libraries=/usr/X11R6/lib'}
|
||||||
|
ac_cv_header_fcntl_h=${ac_cv_header_fcntl_h=yes}
|
||||||
|
ac_cv_header_getopt_h=${ac_cv_header_getopt_h=yes}
|
||||||
|
ac_cv_header_gpc_h=${ac_cv_header_gpc_h=yes}
|
||||||
|
ac_cv_header_malloc_h=${ac_cv_header_malloc_h=yes}
|
||||||
|
ac_cv_header_memory_h=${ac_cv_header_memory_h=yes}
|
||||||
|
ac_cv_header_plib_pu_h=${ac_cv_header_plib_pu_h=yes}
|
||||||
|
ac_cv_header_stdc=${ac_cv_header_stdc=yes}
|
||||||
|
ac_cv_header_stdlib_h=${ac_cv_header_stdlib_h=yes}
|
||||||
|
ac_cv_header_sys_param_h=${ac_cv_header_sys_param_h=yes}
|
||||||
|
ac_cv_header_sys_stat_h=${ac_cv_header_sys_stat_h=yes}
|
||||||
|
ac_cv_header_sys_time_h=${ac_cv_header_sys_time_h=yes}
|
||||||
|
ac_cv_header_sys_timeb_h=${ac_cv_header_sys_timeb_h=yes}
|
||||||
|
ac_cv_header_time=${ac_cv_header_time=yes}
|
||||||
|
ac_cv_header_unistd_h=${ac_cv_header_unistd_h=yes}
|
||||||
|
ac_cv_header_values_h=${ac_cv_header_values_h=yes}
|
||||||
|
ac_cv_header_winbase_h=${ac_cv_header_winbase_h=no}
|
||||||
|
ac_cv_header_windows_h=${ac_cv_header_windows_h=no}
|
||||||
|
ac_cv_lib_GLU_gluLookAt=${ac_cv_lib_GLU_gluLookAt=no}
|
||||||
|
ac_cv_lib_GL_glNewList=${ac_cv_lib_GL_glNewList=yes}
|
||||||
|
ac_cv_lib_GLcore_glNewList=${ac_cv_lib_GLcore_glNewList=no}
|
||||||
|
ac_cv_lib_ICE_IceConnectionNumber=${ac_cv_lib_ICE_IceConnectionNumber=yes}
|
||||||
|
ac_cv_lib_ICE_IceOpenConnection=${ac_cv_lib_ICE_IceOpenConnection=yes}
|
||||||
|
ac_cv_lib_MesaGLU_gluLookAt=${ac_cv_lib_MesaGLU_gluLookAt=yes}
|
||||||
|
ac_cv_lib_SM_SmcOpenConnection=${ac_cv_lib_SM_SmcOpenConnection=yes}
|
||||||
|
ac_cv_lib_X11_XCreateWindow=${ac_cv_lib_X11_XCreateWindow=yes}
|
||||||
|
ac_cv_lib_Xext_XShmCreateImage=${ac_cv_lib_Xext_XShmCreateImage=yes}
|
||||||
|
ac_cv_lib_Xi_XGetExtensionVersion=${ac_cv_lib_Xi_XGetExtensionVersion=yes}
|
||||||
|
ac_cv_lib_Xmu_XmuLookupStandardColormap=${ac_cv_lib_Xmu_XmuLookupStandardColormap=yes}
|
||||||
|
ac_cv_lib_Xt_XtMalloc=${ac_cv_lib_Xt_XtMalloc=yes}
|
||||||
|
ac_cv_lib_dnet_dnet_ntoa=${ac_cv_lib_dnet_dnet_ntoa=no}
|
||||||
|
ac_cv_lib_dnet_stub_dnet_ntoa=${ac_cv_lib_dnet_stub_dnet_ntoa=no}
|
||||||
|
ac_cv_lib_glut_glutGameModeString=${ac_cv_lib_glut_glutGameModeString=yes}
|
||||||
|
ac_cv_lib_glut_glutGetModifiers=${ac_cv_lib_glut_glutGetModifiers=yes}
|
||||||
|
ac_cv_lib_m_cos=${ac_cv_lib_m_cos=yes}
|
||||||
|
ac_cv_lib_socket_socket=${ac_cv_lib_socket_socket=no}
|
||||||
|
ac_cv_path_install=${ac_cv_path_install='/usr/bin/install -c'}
|
||||||
|
ac_cv_prog_CC=${ac_cv_prog_CC=gcc}
|
||||||
|
ac_cv_prog_CPP=${ac_cv_prog_CPP='gcc -E'}
|
||||||
|
ac_cv_prog_CXX=${ac_cv_prog_CXX=c++}
|
||||||
|
ac_cv_prog_LN_S=${ac_cv_prog_LN_S='ln -s'}
|
||||||
|
ac_cv_prog_RANLIB=${ac_cv_prog_RANLIB=ranlib}
|
||||||
|
ac_cv_prog_cc_cross=${ac_cv_prog_cc_cross=no}
|
||||||
|
ac_cv_prog_cc_g=${ac_cv_prog_cc_g=yes}
|
||||||
|
ac_cv_prog_cc_works=${ac_cv_prog_cc_works=yes}
|
||||||
|
ac_cv_prog_cxx_cross=${ac_cv_prog_cxx_cross=no}
|
||||||
|
ac_cv_prog_cxx_g=${ac_cv_prog_cxx_g=yes}
|
||||||
|
ac_cv_prog_cxx_works=${ac_cv_prog_cxx_works=yes}
|
||||||
|
ac_cv_prog_gcc=${ac_cv_prog_gcc=yes}
|
||||||
|
ac_cv_prog_gxx=${ac_cv_prog_gxx=yes}
|
||||||
|
ac_cv_prog_make_make_set=${ac_cv_prog_make_make_set=yes}
|
||||||
|
ac_cv_struct_tm=${ac_cv_struct_tm=time.h}
|
||||||
|
ac_cv_type_signal=${ac_cv_type_signal=void}
|
||||||
|
ac_cv_type_size_t=${ac_cv_type_size_t=yes}
|
89
config.log
Normal file
89
config.log
Normal file
|
@ -0,0 +1,89 @@
|
||||||
|
This file contains any messages produced by compilers while
|
||||||
|
running configure, to aid debugging if configure makes a mistake.
|
||||||
|
|
||||||
|
configure:561: checking for a BSD compatible install
|
||||||
|
configure:614: checking whether build environment is sane
|
||||||
|
configure:671: checking whether make sets ${MAKE}
|
||||||
|
configure:717: checking for working aclocal
|
||||||
|
configure:730: checking for working autoconf
|
||||||
|
configure:743: checking for working automake
|
||||||
|
configure:756: checking for working autoheader
|
||||||
|
configure:769: checking for working makeinfo
|
||||||
|
configure:784: checking whether make sets ${MAKE}
|
||||||
|
configure:813: checking for gcc
|
||||||
|
configure:890: checking whether the C compiler (gcc ) works
|
||||||
|
configure:904: gcc -o conftest conftest.c 1>&5
|
||||||
|
configure:924: checking whether the C compiler (gcc ) is a cross-compiler
|
||||||
|
configure:929: checking whether we are using GNU C
|
||||||
|
configure:953: checking whether gcc accepts -g
|
||||||
|
configure:985: checking for c++
|
||||||
|
configure:1016: checking whether the C++ compiler (c++ ) works
|
||||||
|
configure:1030: c++ -o conftest conftest.C 1>&5
|
||||||
|
configure:1056: checking whether the C++ compiler (c++ ) is a cross-compiler
|
||||||
|
configure:1061: checking whether we are using GNU C++
|
||||||
|
configure:1085: checking whether c++ accepts -g
|
||||||
|
configure:1115: checking for ranlib
|
||||||
|
configure:1152: checking for a BSD compatible install
|
||||||
|
configure:1202: checking whether ln -s works
|
||||||
|
configure:1261: checking how to run the C preprocessor
|
||||||
|
configure:1323: checking for windows.h
|
||||||
|
configure:1452: checking for X
|
||||||
|
configure:1766: checking for dnet_ntoa in -ldnet
|
||||||
|
configure:1807: checking for dnet_ntoa in -ldnet_stub
|
||||||
|
configure:1855: checking for gethostbyname
|
||||||
|
configure:1953: checking for connect
|
||||||
|
configure:2045: checking for remove
|
||||||
|
configure:2137: checking for shmat
|
||||||
|
configure:2238: checking for IceConnectionNumber in -lICE
|
||||||
|
configure:2286: checking for cos in -lm
|
||||||
|
configure:2336: checking for socket in -lsocket
|
||||||
|
configure:2383: checking for XCreateWindow in -lX11
|
||||||
|
configure:2430: checking for XShmCreateImage in -lXext
|
||||||
|
configure:2477: checking for XGetExtensionVersion in -lXi
|
||||||
|
configure:2524: checking for IceOpenConnection in -lICE
|
||||||
|
configure:2571: checking for SmcOpenConnection in -lSM
|
||||||
|
configure:2618: checking for XtMalloc in -lXt
|
||||||
|
configure:2665: checking for XmuLookupStandardColormap in -lXmu
|
||||||
|
configure:2716: checking for glNewList in -lGLcore
|
||||||
|
configure:2764: checking for glNewList in -lGL
|
||||||
|
configure:2956: checking for gluLookAt in -lGLU
|
||||||
|
configure:3004: checking for gluLookAt in -lMesaGLU
|
||||||
|
configure:3053: checking for glutGetModifiers in -lglut
|
||||||
|
configure:3102: checking for glutGameModeString in -lglut
|
||||||
|
configure:3221: checking for plib/pu.h
|
||||||
|
configure:3267: checking for gpc.h
|
||||||
|
configure:3317: checking for ANSI C header files
|
||||||
|
configure:3426: checking for fcntl.h
|
||||||
|
configure:3426: checking for getopt.h
|
||||||
|
configure:3426: checking for malloc.h
|
||||||
|
configure:3426: checking for memory.h
|
||||||
|
configure:3426: checking for stdlib.h
|
||||||
|
configure:3426: checking for sys/param.h
|
||||||
|
configure:3426: checking for sys/stat.h
|
||||||
|
configure:3426: checking for sys/time.h
|
||||||
|
configure:3426: checking for sys/timeb.h
|
||||||
|
configure:3426: checking for unistd.h
|
||||||
|
configure:3426: checking for windows.h
|
||||||
|
configure:3426: checking for winbase.h
|
||||||
|
configure:3426: checking for values.h
|
||||||
|
configure:3464: checking for working const
|
||||||
|
configure:3539: checking for size_t
|
||||||
|
configure:3572: checking whether time.h and sys/time.h may both be included
|
||||||
|
configure:3607: checking whether struct tm is in sys/time.h or time.h
|
||||||
|
configure:3642: checking return type of signal handlers
|
||||||
|
configure:3683: checking for vprintf
|
||||||
|
configure:3791: checking for ftime
|
||||||
|
configure:3791: checking for gettimeofday
|
||||||
|
configure:3791: checking for timegm
|
||||||
|
configure:3791: checking for memcpy
|
||||||
|
configure:3791: checking for bcopy
|
||||||
|
configure:3791: checking for mktime
|
||||||
|
configure:3791: checking for strstr
|
||||||
|
configure:3791: checking for rand
|
||||||
|
configure:3791: checking for random
|
||||||
|
configure:3791: checking for setitimer
|
||||||
|
configure:3791: checking for getitimer
|
||||||
|
configure:3791: checking for signal
|
||||||
|
configure:3791: checking for GetLocalTime
|
||||||
|
configure:3791: checking for rint
|
||||||
|
configure:3791: checking for getrusage
|
441
config.status
Executable file
441
config.status
Executable file
|
@ -0,0 +1,441 @@
|
||||||
|
#! /bin/sh
|
||||||
|
# Generated automatically by configure.
|
||||||
|
# Run this file to recreate the current configuration.
|
||||||
|
# This directory was configured as follows,
|
||||||
|
# on host kenai:
|
||||||
|
#
|
||||||
|
# ./configure --prefix=/h/curt --bindir=/h/curt/bin/Linux
|
||||||
|
#
|
||||||
|
# Compiler output produced by configure, useful for debugging
|
||||||
|
# configure, is in ./config.log if it exists.
|
||||||
|
|
||||||
|
ac_cs_usage="Usage: ./config.status [--recheck] [--version] [--help]"
|
||||||
|
for ac_option
|
||||||
|
do
|
||||||
|
case "$ac_option" in
|
||||||
|
-recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
|
||||||
|
echo "running ${CONFIG_SHELL-/bin/sh} ./configure --prefix=/h/curt --bindir=/h/curt/bin/Linux --no-create --no-recursion"
|
||||||
|
exec ${CONFIG_SHELL-/bin/sh} ./configure --prefix=/h/curt --bindir=/h/curt/bin/Linux --no-create --no-recursion ;;
|
||||||
|
-version | --version | --versio | --versi | --vers | --ver | --ve | --v)
|
||||||
|
echo "./config.status generated by autoconf version 2.12"
|
||||||
|
exit 0 ;;
|
||||||
|
-help | --help | --hel | --he | --h)
|
||||||
|
echo "$ac_cs_usage"; exit 0 ;;
|
||||||
|
*) echo "$ac_cs_usage"; exit 1 ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
ac_given_srcdir=.
|
||||||
|
ac_given_INSTALL="/usr/bin/install -c"
|
||||||
|
|
||||||
|
trap 'rm -fr VERSION Makefile Construct/Makefile Construct/Clipper/Makefile Construct/Combine/Makefile Construct/GenOutput/Makefile Construct/Match/Makefile Construct/Triangulate/Makefile Construct/Main/Makefile Construct/Parallel/Makefile Lib/Makefile Lib/Array/Makefile Lib/Build/Makefile Lib/DEM/Makefile Lib/Polygon/Makefile Lib/poly2tri/Makefile Lib/shapelib/Makefile Lib/Triangle/Makefile Prep/Makefile Prep/DemChop/Makefile Prep/DemInfo/Makefile Prep/DemRaw2ascii/Makefile Prep/GenAirports/Makefile Prep/GSHHS/Makefile Prep/MergerClipper/Makefile Prep/ShapeFile/Makefile Utils/Makefile Include/config.h conftest*; exit 1' 1 2 15
|
||||||
|
|
||||||
|
# Protect against being on the right side of a sed subst in config.status.
|
||||||
|
sed 's/%@/@@/; s/@%/@@/; s/%g$/@g/; /@g$/s/[\\&%]/\\&/g;
|
||||||
|
s/@@/%@/; s/@@/@%/; s/@g$/%g/' > conftest.subs <<\CEOF
|
||||||
|
/^[ ]*VPATH[ ]*=[^:]*$/d
|
||||||
|
|
||||||
|
s%@CFLAGS@%-g -O2%g
|
||||||
|
s%@CPPFLAGS@%-I/usr/local/include -I/usr/X11R6/include%g
|
||||||
|
s%@CXXFLAGS@%-g -O2%g
|
||||||
|
s%@DEFS@%-DHAVE_CONFIG_H%g
|
||||||
|
s%@LDFLAGS@%-L/h/curt/lib -L/usr/local/lib -L/usr/X11R6/lib%g
|
||||||
|
s%@LIBS@%-lm %g
|
||||||
|
s%@exec_prefix@%${prefix}%g
|
||||||
|
s%@prefix@%/h/curt%g
|
||||||
|
s%@program_transform_name@%s,x,x,%g
|
||||||
|
s%@bindir@%/h/curt/bin/Linux%g
|
||||||
|
s%@sbindir@%${exec_prefix}/sbin%g
|
||||||
|
s%@libexecdir@%${exec_prefix}/libexec%g
|
||||||
|
s%@datadir@%${prefix}/share%g
|
||||||
|
s%@sysconfdir@%${prefix}/etc%g
|
||||||
|
s%@sharedstatedir@%${prefix}/com%g
|
||||||
|
s%@localstatedir@%${prefix}/var%g
|
||||||
|
s%@libdir@%${exec_prefix}/lib%g
|
||||||
|
s%@includedir@%${prefix}/include%g
|
||||||
|
s%@oldincludedir@%/usr/include%g
|
||||||
|
s%@infodir@%${prefix}/info%g
|
||||||
|
s%@mandir@%${prefix}/man%g
|
||||||
|
s%@INSTALL_PROGRAM@%${INSTALL}%g
|
||||||
|
s%@INSTALL_DATA@%${INSTALL} -m 644%g
|
||||||
|
s%@INSTALL_SCRIPT@%${INSTALL_PROGRAM}%g
|
||||||
|
s%@PACKAGE@%TerraGear%g
|
||||||
|
s%@VERSION@%0.0.0%g
|
||||||
|
s%@ACLOCAL@%aclocal%g
|
||||||
|
s%@AUTOCONF@%autoconf%g
|
||||||
|
s%@AUTOMAKE@%automake%g
|
||||||
|
s%@AUTOHEADER@%autoheader%g
|
||||||
|
s%@MAKEINFO@%/h/curt/projects/TerraGear-0.0/src/missing makeinfo%g
|
||||||
|
s%@SET_MAKE@%%g
|
||||||
|
s%@CC@%gcc%g
|
||||||
|
s%@CXX@%c++%g
|
||||||
|
s%@RANLIB@%ranlib%g
|
||||||
|
s%@LN_S@%ln -s%g
|
||||||
|
s%@CPP@%gcc -E%g
|
||||||
|
s%@X_CFLAGS@% -I/usr/X11R6/include%g
|
||||||
|
s%@X_PRE_LIBS@% -lSM -lICE%g
|
||||||
|
s%@X_LIBS@% -L/usr/X11R6/lib%g
|
||||||
|
s%@X_EXTRA_LIBS@%%g
|
||||||
|
s%@ENABLE_XMESA_FX_TRUE@%%g
|
||||||
|
s%@ENABLE_XMESA_FX_FALSE@%%g
|
||||||
|
s%@base_LIBS@%-lm %g
|
||||||
|
s%@opengl_LIBS@%-lglut -lMesaGLU -lGL -lXmu -lXt -lSM -lICE -lXi -lXext -lX11 -lm %g
|
||||||
|
s%@HAVE_XWINDOWS_TRUE@%%g
|
||||||
|
s%@HAVE_XWINDOWS_FALSE@%#%g
|
||||||
|
|
||||||
|
CEOF
|
||||||
|
|
||||||
|
# Split the substitutions into bite-sized pieces for seds with
|
||||||
|
# small command number limits, like on Digital OSF/1 and HP-UX.
|
||||||
|
ac_max_sed_cmds=90 # Maximum number of lines to put in a sed script.
|
||||||
|
ac_file=1 # Number of current file.
|
||||||
|
ac_beg=1 # First line for current file.
|
||||||
|
ac_end=$ac_max_sed_cmds # Line after last line for current file.
|
||||||
|
ac_more_lines=:
|
||||||
|
ac_sed_cmds=""
|
||||||
|
while $ac_more_lines; do
|
||||||
|
if test $ac_beg -gt 1; then
|
||||||
|
sed "1,${ac_beg}d; ${ac_end}q" conftest.subs > conftest.s$ac_file
|
||||||
|
else
|
||||||
|
sed "${ac_end}q" conftest.subs > conftest.s$ac_file
|
||||||
|
fi
|
||||||
|
if test ! -s conftest.s$ac_file; then
|
||||||
|
ac_more_lines=false
|
||||||
|
rm -f conftest.s$ac_file
|
||||||
|
else
|
||||||
|
if test -z "$ac_sed_cmds"; then
|
||||||
|
ac_sed_cmds="sed -f conftest.s$ac_file"
|
||||||
|
else
|
||||||
|
ac_sed_cmds="$ac_sed_cmds | sed -f conftest.s$ac_file"
|
||||||
|
fi
|
||||||
|
ac_file=`expr $ac_file + 1`
|
||||||
|
ac_beg=$ac_end
|
||||||
|
ac_end=`expr $ac_end + $ac_max_sed_cmds`
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
if test -z "$ac_sed_cmds"; then
|
||||||
|
ac_sed_cmds=cat
|
||||||
|
fi
|
||||||
|
|
||||||
|
CONFIG_FILES=${CONFIG_FILES-" VERSION Makefile Construct/Makefile Construct/Clipper/Makefile Construct/Combine/Makefile Construct/GenOutput/Makefile Construct/Match/Makefile Construct/Triangulate/Makefile Construct/Main/Makefile Construct/Parallel/Makefile Lib/Makefile Lib/Array/Makefile Lib/Build/Makefile Lib/DEM/Makefile Lib/Polygon/Makefile Lib/poly2tri/Makefile Lib/shapelib/Makefile Lib/Triangle/Makefile Prep/Makefile Prep/DemChop/Makefile Prep/DemInfo/Makefile Prep/DemRaw2ascii/Makefile Prep/GenAirports/Makefile Prep/GSHHS/Makefile Prep/MergerClipper/Makefile Prep/ShapeFile/Makefile Utils/Makefile "}
|
||||||
|
for ac_file in .. $CONFIG_FILES; do if test "x$ac_file" != x..; then
|
||||||
|
# Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in".
|
||||||
|
case "$ac_file" in
|
||||||
|
*:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'`
|
||||||
|
ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;;
|
||||||
|
*) ac_file_in="${ac_file}.in" ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
# Adjust a relative srcdir, top_srcdir, and INSTALL for subdirectories.
|
||||||
|
|
||||||
|
# Remove last slash and all that follows it. Not all systems have dirname.
|
||||||
|
ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'`
|
||||||
|
if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then
|
||||||
|
# The file is in a subdirectory.
|
||||||
|
test ! -d "$ac_dir" && mkdir "$ac_dir"
|
||||||
|
ac_dir_suffix="/`echo $ac_dir|sed 's%^\./%%'`"
|
||||||
|
# A "../" for each directory in $ac_dir_suffix.
|
||||||
|
ac_dots=`echo $ac_dir_suffix|sed 's%/[^/]*%../%g'`
|
||||||
|
else
|
||||||
|
ac_dir_suffix= ac_dots=
|
||||||
|
fi
|
||||||
|
|
||||||
|
case "$ac_given_srcdir" in
|
||||||
|
.) srcdir=.
|
||||||
|
if test -z "$ac_dots"; then top_srcdir=.
|
||||||
|
else top_srcdir=`echo $ac_dots|sed 's%/$%%'`; fi ;;
|
||||||
|
/*) srcdir="$ac_given_srcdir$ac_dir_suffix"; top_srcdir="$ac_given_srcdir" ;;
|
||||||
|
*) # Relative path.
|
||||||
|
srcdir="$ac_dots$ac_given_srcdir$ac_dir_suffix"
|
||||||
|
top_srcdir="$ac_dots$ac_given_srcdir" ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
case "$ac_given_INSTALL" in
|
||||||
|
[/$]*) INSTALL="$ac_given_INSTALL" ;;
|
||||||
|
*) INSTALL="$ac_dots$ac_given_INSTALL" ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
echo creating "$ac_file"
|
||||||
|
rm -f "$ac_file"
|
||||||
|
configure_input="Generated automatically from `echo $ac_file_in|sed 's%.*/%%'` by configure."
|
||||||
|
case "$ac_file" in
|
||||||
|
*Makefile*) ac_comsub="1i\\
|
||||||
|
# $configure_input" ;;
|
||||||
|
*) ac_comsub= ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"`
|
||||||
|
sed -e "$ac_comsub
|
||||||
|
s%@configure_input@%$configure_input%g
|
||||||
|
s%@srcdir@%$srcdir%g
|
||||||
|
s%@top_srcdir@%$top_srcdir%g
|
||||||
|
s%@INSTALL@%$INSTALL%g
|
||||||
|
" $ac_file_inputs | (eval "$ac_sed_cmds") > $ac_file
|
||||||
|
fi; done
|
||||||
|
rm -f conftest.s*
|
||||||
|
|
||||||
|
# These sed commands are passed to sed as "A NAME B NAME C VALUE D", where
|
||||||
|
# NAME is the cpp macro being defined and VALUE is the value it is being given.
|
||||||
|
#
|
||||||
|
# ac_d sets the value in "#define NAME VALUE" lines.
|
||||||
|
ac_dA='s%^\([ ]*\)#\([ ]*define[ ][ ]*\)'
|
||||||
|
ac_dB='\([ ][ ]*\)[^ ]*%\1#\2'
|
||||||
|
ac_dC='\3'
|
||||||
|
ac_dD='%g'
|
||||||
|
# ac_u turns "#undef NAME" with trailing blanks into "#define NAME VALUE".
|
||||||
|
ac_uA='s%^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)'
|
||||||
|
ac_uB='\([ ]\)%\1#\2define\3'
|
||||||
|
ac_uC=' '
|
||||||
|
ac_uD='\4%g'
|
||||||
|
# ac_e turns "#undef NAME" without trailing blanks into "#define NAME VALUE".
|
||||||
|
ac_eA='s%^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)'
|
||||||
|
ac_eB='$%\1#\2define\3'
|
||||||
|
ac_eC=' '
|
||||||
|
ac_eD='%g'
|
||||||
|
|
||||||
|
if test "${CONFIG_HEADERS+set}" != set; then
|
||||||
|
CONFIG_HEADERS="Include/config.h"
|
||||||
|
fi
|
||||||
|
for ac_file in .. $CONFIG_HEADERS; do if test "x$ac_file" != x..; then
|
||||||
|
# Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in".
|
||||||
|
case "$ac_file" in
|
||||||
|
*:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'`
|
||||||
|
ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;;
|
||||||
|
*) ac_file_in="${ac_file}.in" ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
echo creating $ac_file
|
||||||
|
|
||||||
|
rm -f conftest.frag conftest.in conftest.out
|
||||||
|
ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"`
|
||||||
|
cat $ac_file_inputs > conftest.in
|
||||||
|
|
||||||
|
cat > conftest.frag <<CEOF
|
||||||
|
${ac_dA}PACKAGE${ac_dB}PACKAGE${ac_dC}"TerraGear"${ac_dD}
|
||||||
|
${ac_uA}PACKAGE${ac_uB}PACKAGE${ac_uC}"TerraGear"${ac_uD}
|
||||||
|
${ac_eA}PACKAGE${ac_eB}PACKAGE${ac_eC}"TerraGear"${ac_eD}
|
||||||
|
${ac_dA}VERSION${ac_dB}VERSION${ac_dC}"0.0.0"${ac_dD}
|
||||||
|
${ac_uA}VERSION${ac_uB}VERSION${ac_uC}"0.0.0"${ac_uD}
|
||||||
|
${ac_eA}VERSION${ac_eB}VERSION${ac_eC}"0.0.0"${ac_eD}
|
||||||
|
${ac_dA}HAVE_LIBM${ac_dB}HAVE_LIBM${ac_dC}1${ac_dD}
|
||||||
|
${ac_uA}HAVE_LIBM${ac_uB}HAVE_LIBM${ac_uC}1${ac_uD}
|
||||||
|
${ac_eA}HAVE_LIBM${ac_eB}HAVE_LIBM${ac_eC}1${ac_eD}
|
||||||
|
${ac_dA}HAVE_LIBX11${ac_dB}HAVE_LIBX11${ac_dC}1${ac_dD}
|
||||||
|
${ac_uA}HAVE_LIBX11${ac_uB}HAVE_LIBX11${ac_uC}1${ac_uD}
|
||||||
|
${ac_eA}HAVE_LIBX11${ac_eB}HAVE_LIBX11${ac_eC}1${ac_eD}
|
||||||
|
CEOF
|
||||||
|
sed -f conftest.frag conftest.in > conftest.out
|
||||||
|
rm -f conftest.in
|
||||||
|
mv conftest.out conftest.in
|
||||||
|
|
||||||
|
cat > conftest.frag <<CEOF
|
||||||
|
${ac_dA}HAVE_LIBXEXT${ac_dB}HAVE_LIBXEXT${ac_dC}1${ac_dD}
|
||||||
|
${ac_uA}HAVE_LIBXEXT${ac_uB}HAVE_LIBXEXT${ac_uC}1${ac_uD}
|
||||||
|
${ac_eA}HAVE_LIBXEXT${ac_eB}HAVE_LIBXEXT${ac_eC}1${ac_eD}
|
||||||
|
${ac_dA}HAVE_LIBXI${ac_dB}HAVE_LIBXI${ac_dC}1${ac_dD}
|
||||||
|
${ac_uA}HAVE_LIBXI${ac_uB}HAVE_LIBXI${ac_uC}1${ac_uD}
|
||||||
|
${ac_eA}HAVE_LIBXI${ac_eB}HAVE_LIBXI${ac_eC}1${ac_eD}
|
||||||
|
${ac_dA}HAVE_LIBICE${ac_dB}HAVE_LIBICE${ac_dC}1${ac_dD}
|
||||||
|
${ac_uA}HAVE_LIBICE${ac_uB}HAVE_LIBICE${ac_uC}1${ac_uD}
|
||||||
|
${ac_eA}HAVE_LIBICE${ac_eB}HAVE_LIBICE${ac_eC}1${ac_eD}
|
||||||
|
${ac_dA}HAVE_LIBSM${ac_dB}HAVE_LIBSM${ac_dC}1${ac_dD}
|
||||||
|
${ac_uA}HAVE_LIBSM${ac_uB}HAVE_LIBSM${ac_uC}1${ac_uD}
|
||||||
|
${ac_eA}HAVE_LIBSM${ac_eB}HAVE_LIBSM${ac_eC}1${ac_eD}
|
||||||
|
CEOF
|
||||||
|
sed -f conftest.frag conftest.in > conftest.out
|
||||||
|
rm -f conftest.in
|
||||||
|
mv conftest.out conftest.in
|
||||||
|
|
||||||
|
cat > conftest.frag <<CEOF
|
||||||
|
${ac_dA}HAVE_LIBXT${ac_dB}HAVE_LIBXT${ac_dC}1${ac_dD}
|
||||||
|
${ac_uA}HAVE_LIBXT${ac_uB}HAVE_LIBXT${ac_uC}1${ac_uD}
|
||||||
|
${ac_eA}HAVE_LIBXT${ac_eB}HAVE_LIBXT${ac_eC}1${ac_eD}
|
||||||
|
${ac_dA}HAVE_LIBXMU${ac_dB}HAVE_LIBXMU${ac_dC}1${ac_dD}
|
||||||
|
${ac_uA}HAVE_LIBXMU${ac_uB}HAVE_LIBXMU${ac_uC}1${ac_uD}
|
||||||
|
${ac_eA}HAVE_LIBXMU${ac_eB}HAVE_LIBXMU${ac_eC}1${ac_eD}
|
||||||
|
${ac_dA}HAVE_LIBGL${ac_dB}HAVE_LIBGL${ac_dC}1${ac_dD}
|
||||||
|
${ac_uA}HAVE_LIBGL${ac_uB}HAVE_LIBGL${ac_uC}1${ac_uD}
|
||||||
|
${ac_eA}HAVE_LIBGL${ac_eB}HAVE_LIBGL${ac_eC}1${ac_eD}
|
||||||
|
${ac_dA}HAVE_LIBMESAGLU${ac_dB}HAVE_LIBMESAGLU${ac_dC}1${ac_dD}
|
||||||
|
${ac_uA}HAVE_LIBMESAGLU${ac_uB}HAVE_LIBMESAGLU${ac_uC}1${ac_uD}
|
||||||
|
${ac_eA}HAVE_LIBMESAGLU${ac_eB}HAVE_LIBMESAGLU${ac_eC}1${ac_eD}
|
||||||
|
CEOF
|
||||||
|
sed -f conftest.frag conftest.in > conftest.out
|
||||||
|
rm -f conftest.in
|
||||||
|
mv conftest.out conftest.in
|
||||||
|
|
||||||
|
cat > conftest.frag <<CEOF
|
||||||
|
${ac_dA}HAVE_LIBGLUT${ac_dB}HAVE_LIBGLUT${ac_dC}1${ac_dD}
|
||||||
|
${ac_uA}HAVE_LIBGLUT${ac_uB}HAVE_LIBGLUT${ac_uC}1${ac_uD}
|
||||||
|
${ac_eA}HAVE_LIBGLUT${ac_eB}HAVE_LIBGLUT${ac_eC}1${ac_eD}
|
||||||
|
${ac_dA}HAVE_LIBGLUT${ac_dB}HAVE_LIBGLUT${ac_dC}1${ac_dD}
|
||||||
|
${ac_uA}HAVE_LIBGLUT${ac_uB}HAVE_LIBGLUT${ac_uC}1${ac_uD}
|
||||||
|
${ac_eA}HAVE_LIBGLUT${ac_eB}HAVE_LIBGLUT${ac_eC}1${ac_eD}
|
||||||
|
${ac_dA}HAVE_GPC_H${ac_dB}HAVE_GPC_H${ac_dC}1${ac_dD}
|
||||||
|
${ac_uA}HAVE_GPC_H${ac_uB}HAVE_GPC_H${ac_uC}1${ac_uD}
|
||||||
|
${ac_eA}HAVE_GPC_H${ac_eB}HAVE_GPC_H${ac_eC}1${ac_eD}
|
||||||
|
${ac_dA}STDC_HEADERS${ac_dB}STDC_HEADERS${ac_dC}1${ac_dD}
|
||||||
|
${ac_uA}STDC_HEADERS${ac_uB}STDC_HEADERS${ac_uC}1${ac_uD}
|
||||||
|
${ac_eA}STDC_HEADERS${ac_eB}STDC_HEADERS${ac_eC}1${ac_eD}
|
||||||
|
CEOF
|
||||||
|
sed -f conftest.frag conftest.in > conftest.out
|
||||||
|
rm -f conftest.in
|
||||||
|
mv conftest.out conftest.in
|
||||||
|
|
||||||
|
cat > conftest.frag <<CEOF
|
||||||
|
${ac_dA}HAVE_FCNTL_H${ac_dB}HAVE_FCNTL_H${ac_dC}1${ac_dD}
|
||||||
|
${ac_uA}HAVE_FCNTL_H${ac_uB}HAVE_FCNTL_H${ac_uC}1${ac_uD}
|
||||||
|
${ac_eA}HAVE_FCNTL_H${ac_eB}HAVE_FCNTL_H${ac_eC}1${ac_eD}
|
||||||
|
${ac_dA}HAVE_GETOPT_H${ac_dB}HAVE_GETOPT_H${ac_dC}1${ac_dD}
|
||||||
|
${ac_uA}HAVE_GETOPT_H${ac_uB}HAVE_GETOPT_H${ac_uC}1${ac_uD}
|
||||||
|
${ac_eA}HAVE_GETOPT_H${ac_eB}HAVE_GETOPT_H${ac_eC}1${ac_eD}
|
||||||
|
${ac_dA}HAVE_MALLOC_H${ac_dB}HAVE_MALLOC_H${ac_dC}1${ac_dD}
|
||||||
|
${ac_uA}HAVE_MALLOC_H${ac_uB}HAVE_MALLOC_H${ac_uC}1${ac_uD}
|
||||||
|
${ac_eA}HAVE_MALLOC_H${ac_eB}HAVE_MALLOC_H${ac_eC}1${ac_eD}
|
||||||
|
${ac_dA}HAVE_MEMORY_H${ac_dB}HAVE_MEMORY_H${ac_dC}1${ac_dD}
|
||||||
|
${ac_uA}HAVE_MEMORY_H${ac_uB}HAVE_MEMORY_H${ac_uC}1${ac_uD}
|
||||||
|
${ac_eA}HAVE_MEMORY_H${ac_eB}HAVE_MEMORY_H${ac_eC}1${ac_eD}
|
||||||
|
CEOF
|
||||||
|
sed -f conftest.frag conftest.in > conftest.out
|
||||||
|
rm -f conftest.in
|
||||||
|
mv conftest.out conftest.in
|
||||||
|
|
||||||
|
cat > conftest.frag <<CEOF
|
||||||
|
${ac_dA}HAVE_STDLIB_H${ac_dB}HAVE_STDLIB_H${ac_dC}1${ac_dD}
|
||||||
|
${ac_uA}HAVE_STDLIB_H${ac_uB}HAVE_STDLIB_H${ac_uC}1${ac_uD}
|
||||||
|
${ac_eA}HAVE_STDLIB_H${ac_eB}HAVE_STDLIB_H${ac_eC}1${ac_eD}
|
||||||
|
${ac_dA}HAVE_SYS_PARAM_H${ac_dB}HAVE_SYS_PARAM_H${ac_dC}1${ac_dD}
|
||||||
|
${ac_uA}HAVE_SYS_PARAM_H${ac_uB}HAVE_SYS_PARAM_H${ac_uC}1${ac_uD}
|
||||||
|
${ac_eA}HAVE_SYS_PARAM_H${ac_eB}HAVE_SYS_PARAM_H${ac_eC}1${ac_eD}
|
||||||
|
${ac_dA}HAVE_SYS_STAT_H${ac_dB}HAVE_SYS_STAT_H${ac_dC}1${ac_dD}
|
||||||
|
${ac_uA}HAVE_SYS_STAT_H${ac_uB}HAVE_SYS_STAT_H${ac_uC}1${ac_uD}
|
||||||
|
${ac_eA}HAVE_SYS_STAT_H${ac_eB}HAVE_SYS_STAT_H${ac_eC}1${ac_eD}
|
||||||
|
${ac_dA}HAVE_SYS_TIME_H${ac_dB}HAVE_SYS_TIME_H${ac_dC}1${ac_dD}
|
||||||
|
${ac_uA}HAVE_SYS_TIME_H${ac_uB}HAVE_SYS_TIME_H${ac_uC}1${ac_uD}
|
||||||
|
${ac_eA}HAVE_SYS_TIME_H${ac_eB}HAVE_SYS_TIME_H${ac_eC}1${ac_eD}
|
||||||
|
CEOF
|
||||||
|
sed -f conftest.frag conftest.in > conftest.out
|
||||||
|
rm -f conftest.in
|
||||||
|
mv conftest.out conftest.in
|
||||||
|
|
||||||
|
cat > conftest.frag <<CEOF
|
||||||
|
${ac_dA}HAVE_SYS_TIMEB_H${ac_dB}HAVE_SYS_TIMEB_H${ac_dC}1${ac_dD}
|
||||||
|
${ac_uA}HAVE_SYS_TIMEB_H${ac_uB}HAVE_SYS_TIMEB_H${ac_uC}1${ac_uD}
|
||||||
|
${ac_eA}HAVE_SYS_TIMEB_H${ac_eB}HAVE_SYS_TIMEB_H${ac_eC}1${ac_eD}
|
||||||
|
${ac_dA}HAVE_UNISTD_H${ac_dB}HAVE_UNISTD_H${ac_dC}1${ac_dD}
|
||||||
|
${ac_uA}HAVE_UNISTD_H${ac_uB}HAVE_UNISTD_H${ac_uC}1${ac_uD}
|
||||||
|
${ac_eA}HAVE_UNISTD_H${ac_eB}HAVE_UNISTD_H${ac_eC}1${ac_eD}
|
||||||
|
${ac_dA}HAVE_VALUES_H${ac_dB}HAVE_VALUES_H${ac_dC}1${ac_dD}
|
||||||
|
${ac_uA}HAVE_VALUES_H${ac_uB}HAVE_VALUES_H${ac_uC}1${ac_uD}
|
||||||
|
${ac_eA}HAVE_VALUES_H${ac_eB}HAVE_VALUES_H${ac_eC}1${ac_eD}
|
||||||
|
${ac_dA}TIME_WITH_SYS_TIME${ac_dB}TIME_WITH_SYS_TIME${ac_dC}1${ac_dD}
|
||||||
|
${ac_uA}TIME_WITH_SYS_TIME${ac_uB}TIME_WITH_SYS_TIME${ac_uC}1${ac_uD}
|
||||||
|
${ac_eA}TIME_WITH_SYS_TIME${ac_eB}TIME_WITH_SYS_TIME${ac_eC}1${ac_eD}
|
||||||
|
CEOF
|
||||||
|
sed -f conftest.frag conftest.in > conftest.out
|
||||||
|
rm -f conftest.in
|
||||||
|
mv conftest.out conftest.in
|
||||||
|
|
||||||
|
cat > conftest.frag <<CEOF
|
||||||
|
${ac_dA}RETSIGTYPE${ac_dB}RETSIGTYPE${ac_dC}void${ac_dD}
|
||||||
|
${ac_uA}RETSIGTYPE${ac_uB}RETSIGTYPE${ac_uC}void${ac_uD}
|
||||||
|
${ac_eA}RETSIGTYPE${ac_eB}RETSIGTYPE${ac_eC}void${ac_eD}
|
||||||
|
${ac_dA}HAVE_VPRINTF${ac_dB}HAVE_VPRINTF${ac_dC}1${ac_dD}
|
||||||
|
${ac_uA}HAVE_VPRINTF${ac_uB}HAVE_VPRINTF${ac_uC}1${ac_uD}
|
||||||
|
${ac_eA}HAVE_VPRINTF${ac_eB}HAVE_VPRINTF${ac_eC}1${ac_eD}
|
||||||
|
${ac_dA}HAVE_FTIME${ac_dB}HAVE_FTIME${ac_dC}1${ac_dD}
|
||||||
|
${ac_uA}HAVE_FTIME${ac_uB}HAVE_FTIME${ac_uC}1${ac_uD}
|
||||||
|
${ac_eA}HAVE_FTIME${ac_eB}HAVE_FTIME${ac_eC}1${ac_eD}
|
||||||
|
${ac_dA}HAVE_GETTIMEOFDAY${ac_dB}HAVE_GETTIMEOFDAY${ac_dC}1${ac_dD}
|
||||||
|
${ac_uA}HAVE_GETTIMEOFDAY${ac_uB}HAVE_GETTIMEOFDAY${ac_uC}1${ac_uD}
|
||||||
|
${ac_eA}HAVE_GETTIMEOFDAY${ac_eB}HAVE_GETTIMEOFDAY${ac_eC}1${ac_eD}
|
||||||
|
CEOF
|
||||||
|
sed -f conftest.frag conftest.in > conftest.out
|
||||||
|
rm -f conftest.in
|
||||||
|
mv conftest.out conftest.in
|
||||||
|
|
||||||
|
cat > conftest.frag <<CEOF
|
||||||
|
${ac_dA}HAVE_TIMEGM${ac_dB}HAVE_TIMEGM${ac_dC}1${ac_dD}
|
||||||
|
${ac_uA}HAVE_TIMEGM${ac_uB}HAVE_TIMEGM${ac_uC}1${ac_uD}
|
||||||
|
${ac_eA}HAVE_TIMEGM${ac_eB}HAVE_TIMEGM${ac_eC}1${ac_eD}
|
||||||
|
${ac_dA}HAVE_MEMCPY${ac_dB}HAVE_MEMCPY${ac_dC}1${ac_dD}
|
||||||
|
${ac_uA}HAVE_MEMCPY${ac_uB}HAVE_MEMCPY${ac_uC}1${ac_uD}
|
||||||
|
${ac_eA}HAVE_MEMCPY${ac_eB}HAVE_MEMCPY${ac_eC}1${ac_eD}
|
||||||
|
${ac_dA}HAVE_BCOPY${ac_dB}HAVE_BCOPY${ac_dC}1${ac_dD}
|
||||||
|
${ac_uA}HAVE_BCOPY${ac_uB}HAVE_BCOPY${ac_uC}1${ac_uD}
|
||||||
|
${ac_eA}HAVE_BCOPY${ac_eB}HAVE_BCOPY${ac_eC}1${ac_eD}
|
||||||
|
${ac_dA}HAVE_MKTIME${ac_dB}HAVE_MKTIME${ac_dC}1${ac_dD}
|
||||||
|
${ac_uA}HAVE_MKTIME${ac_uB}HAVE_MKTIME${ac_uC}1${ac_uD}
|
||||||
|
${ac_eA}HAVE_MKTIME${ac_eB}HAVE_MKTIME${ac_eC}1${ac_eD}
|
||||||
|
CEOF
|
||||||
|
sed -f conftest.frag conftest.in > conftest.out
|
||||||
|
rm -f conftest.in
|
||||||
|
mv conftest.out conftest.in
|
||||||
|
|
||||||
|
cat > conftest.frag <<CEOF
|
||||||
|
${ac_dA}HAVE_STRSTR${ac_dB}HAVE_STRSTR${ac_dC}1${ac_dD}
|
||||||
|
${ac_uA}HAVE_STRSTR${ac_uB}HAVE_STRSTR${ac_uC}1${ac_uD}
|
||||||
|
${ac_eA}HAVE_STRSTR${ac_eB}HAVE_STRSTR${ac_eC}1${ac_eD}
|
||||||
|
${ac_dA}HAVE_RAND${ac_dB}HAVE_RAND${ac_dC}1${ac_dD}
|
||||||
|
${ac_uA}HAVE_RAND${ac_uB}HAVE_RAND${ac_uC}1${ac_uD}
|
||||||
|
${ac_eA}HAVE_RAND${ac_eB}HAVE_RAND${ac_eC}1${ac_eD}
|
||||||
|
${ac_dA}HAVE_RANDOM${ac_dB}HAVE_RANDOM${ac_dC}1${ac_dD}
|
||||||
|
${ac_uA}HAVE_RANDOM${ac_uB}HAVE_RANDOM${ac_uC}1${ac_uD}
|
||||||
|
${ac_eA}HAVE_RANDOM${ac_eB}HAVE_RANDOM${ac_eC}1${ac_eD}
|
||||||
|
${ac_dA}HAVE_SETITIMER${ac_dB}HAVE_SETITIMER${ac_dC}1${ac_dD}
|
||||||
|
${ac_uA}HAVE_SETITIMER${ac_uB}HAVE_SETITIMER${ac_uC}1${ac_uD}
|
||||||
|
${ac_eA}HAVE_SETITIMER${ac_eB}HAVE_SETITIMER${ac_eC}1${ac_eD}
|
||||||
|
CEOF
|
||||||
|
sed -f conftest.frag conftest.in > conftest.out
|
||||||
|
rm -f conftest.in
|
||||||
|
mv conftest.out conftest.in
|
||||||
|
|
||||||
|
cat > conftest.frag <<CEOF
|
||||||
|
${ac_dA}HAVE_GETITIMER${ac_dB}HAVE_GETITIMER${ac_dC}1${ac_dD}
|
||||||
|
${ac_uA}HAVE_GETITIMER${ac_uB}HAVE_GETITIMER${ac_uC}1${ac_uD}
|
||||||
|
${ac_eA}HAVE_GETITIMER${ac_eB}HAVE_GETITIMER${ac_eC}1${ac_eD}
|
||||||
|
${ac_dA}HAVE_SIGNAL${ac_dB}HAVE_SIGNAL${ac_dC}1${ac_dD}
|
||||||
|
${ac_uA}HAVE_SIGNAL${ac_uB}HAVE_SIGNAL${ac_uC}1${ac_uD}
|
||||||
|
${ac_eA}HAVE_SIGNAL${ac_eB}HAVE_SIGNAL${ac_eC}1${ac_eD}
|
||||||
|
${ac_dA}HAVE_RINT${ac_dB}HAVE_RINT${ac_dC}1${ac_dD}
|
||||||
|
${ac_uA}HAVE_RINT${ac_uB}HAVE_RINT${ac_uC}1${ac_uD}
|
||||||
|
${ac_eA}HAVE_RINT${ac_eB}HAVE_RINT${ac_eC}1${ac_eD}
|
||||||
|
${ac_dA}HAVE_GETRUSAGE${ac_dB}HAVE_GETRUSAGE${ac_dC}1${ac_dD}
|
||||||
|
${ac_uA}HAVE_GETRUSAGE${ac_uB}HAVE_GETRUSAGE${ac_uC}1${ac_uD}
|
||||||
|
${ac_eA}HAVE_GETRUSAGE${ac_eB}HAVE_GETRUSAGE${ac_eC}1${ac_eD}
|
||||||
|
CEOF
|
||||||
|
sed -f conftest.frag conftest.in > conftest.out
|
||||||
|
rm -f conftest.in
|
||||||
|
mv conftest.out conftest.in
|
||||||
|
|
||||||
|
cat > conftest.frag <<CEOF
|
||||||
|
s%^[ ]*#[ ]*undef[ ][ ]*[a-zA-Z_][a-zA-Z_0-9]*%/* & */%
|
||||||
|
CEOF
|
||||||
|
sed -f conftest.frag conftest.in > conftest.out
|
||||||
|
rm -f conftest.in
|
||||||
|
mv conftest.out conftest.in
|
||||||
|
|
||||||
|
rm -f conftest.frag conftest.h
|
||||||
|
echo "/* $ac_file. Generated automatically by configure. */" > conftest.h
|
||||||
|
cat conftest.in >> conftest.h
|
||||||
|
rm -f conftest.in
|
||||||
|
if cmp -s $ac_file conftest.h 2>/dev/null; then
|
||||||
|
echo "$ac_file is unchanged"
|
||||||
|
rm -f conftest.h
|
||||||
|
else
|
||||||
|
# Remove last slash and all that follows it. Not all systems have dirname.
|
||||||
|
ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'`
|
||||||
|
if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then
|
||||||
|
# The file is in a subdirectory.
|
||||||
|
test ! -d "$ac_dir" && mkdir "$ac_dir"
|
||||||
|
fi
|
||||||
|
rm -f $ac_file
|
||||||
|
mv conftest.h $ac_file
|
||||||
|
fi
|
||||||
|
fi; done
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
test -z "$CONFIG_HEADERS" || echo timestamp > Include/stamp-h
|
||||||
|
|
||||||
|
exit 0
|
275
configure.in
Normal file
275
configure.in
Normal file
|
@ -0,0 +1,275 @@
|
||||||
|
dnl Process this file with aclocal ; automake -a ; autoconf to produce a
|
||||||
|
dnl working configure script.
|
||||||
|
dnl
|
||||||
|
dnl $Id$
|
||||||
|
|
||||||
|
AC_INIT(Lib/DEM/dem.cxx)
|
||||||
|
|
||||||
|
dnl Initialize the automake stuff
|
||||||
|
AM_INIT_AUTOMAKE(TerraGear, 0.0.0)
|
||||||
|
|
||||||
|
dnl Checks for programs.
|
||||||
|
AC_PROG_MAKE_SET
|
||||||
|
AC_PROG_CC
|
||||||
|
AC_PROG_CXX
|
||||||
|
AC_PROG_RANLIB
|
||||||
|
AC_PROG_INSTALL
|
||||||
|
AC_PROG_LN_S
|
||||||
|
|
||||||
|
dnl Specify if we want logging (testing build) or not (release build)
|
||||||
|
# set logging default value
|
||||||
|
# with_logging=yes
|
||||||
|
AC_ARG_WITH(logging, [ --with-logging Include logging output (default)])
|
||||||
|
if test "x$with_logging" = "xno" ; then
|
||||||
|
AC_DEFINE(FG_NDEBUG)
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
dnl specify if we are building with "checker"
|
||||||
|
AC_ARG_WITH(efence, [ --with-efence Specify if we are building with "electric-fence"])
|
||||||
|
|
||||||
|
if test "x$with_efence" = "xyes" ; then
|
||||||
|
echo "Building with efence"
|
||||||
|
LIBS= "$LIBS -lefence"
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
dnl Let the Win32 user specify if they want to build with the SGI
|
||||||
|
dnl opengl.dll as opposed to the more standard openg32.dll
|
||||||
|
AC_ARG_WITH(sgi-opengl, [ --with-sgi-opengl Build against SGI's opengl.dll glu.dll and glut.dll])
|
||||||
|
|
||||||
|
|
||||||
|
dnl Check for MS Windows environment
|
||||||
|
AC_CHECK_HEADER(windows.h)
|
||||||
|
|
||||||
|
dnl extra library and include directories
|
||||||
|
EXTRA_DIRS="/usr/local /usr/local/plib /usr/X11R6"
|
||||||
|
|
||||||
|
if test -d /opt/X11R6 ; then
|
||||||
|
EXTRA_DIRS="$EXTRA_DIRS /opt/X11R6"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if test "x$ac_cv_header_windows_h" = "xyes" ; then
|
||||||
|
EXTRA_DIRS="${EXTRA_DIRS} `pwd`/Win32"
|
||||||
|
fi
|
||||||
|
wi_EXTRA_DIRS(no, ${EXTRA_DIRS})
|
||||||
|
|
||||||
|
dnl Using AM_CONDITIONAL is a step out of the protected little
|
||||||
|
dnl automake fold so it is potentially dangerous. But, we are
|
||||||
|
dnl beginning to run into cases where the standard checks are not
|
||||||
|
dnl enough. AM_CONDITIONALS are then referenced to conditionally
|
||||||
|
dnl build a Makefile.in from a Makefile.am which lets us define custom
|
||||||
|
dnl includes, compile alternative source files, etc.
|
||||||
|
|
||||||
|
dnl Check for X11 (fancy)
|
||||||
|
AC_PATH_XTRA
|
||||||
|
|
||||||
|
dnl Checks for libraries.
|
||||||
|
|
||||||
|
null_LIBS="$LIBS"
|
||||||
|
|
||||||
|
AC_CHECK_LIB(m, cos)
|
||||||
|
|
||||||
|
base_LIBS="$LIBS"
|
||||||
|
|
||||||
|
AC_CHECK_LIB(socket, socket)
|
||||||
|
AC_CHECK_LIB(X11, XCreateWindow)
|
||||||
|
AC_CHECK_LIB(Xext, XShmCreateImage)
|
||||||
|
AC_CHECK_LIB(Xi, XGetExtensionVersion)
|
||||||
|
AC_CHECK_LIB(ICE, IceOpenConnection)
|
||||||
|
AC_CHECK_LIB(SM, SmcOpenConnection)
|
||||||
|
AC_CHECK_LIB(Xt, XtMalloc)
|
||||||
|
AC_CHECK_LIB(Xmu, XmuLookupStandardColormap)
|
||||||
|
|
||||||
|
dnl check for OpenGL related libraries
|
||||||
|
|
||||||
|
if test "x$ac_cv_header_windows_h" != "xyes" ; then
|
||||||
|
dnl Reasonable stuff for non-windoze variants ... :-)
|
||||||
|
|
||||||
|
AC_CHECK_LIB(GLcore, glNewList)
|
||||||
|
if test "x$ac_cv_lib_GLcore_glNewList" = "xno" ; then
|
||||||
|
dnl if no GLcore, check for GL
|
||||||
|
AC_CHECK_LIB(GL, glNewList)
|
||||||
|
if test "x$ac_cv_lib_GL_glNewList" = "xno" ; then
|
||||||
|
dnl if no GL, check for MesaGL
|
||||||
|
AC_CHECK_LIB(MesaGL, glNewList)
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
dnl if GLcore found, then also check for GL
|
||||||
|
AC_CHECK_LIB(GL, glXCreateContext)
|
||||||
|
fi
|
||||||
|
|
||||||
|
dnl if using mesa, check for xmesa.h
|
||||||
|
if test "x$ac_cv_lib_MesaGL_glNewList" = "xyes" ; then
|
||||||
|
AC_CHECK_HEADER(GL/xmesa.h)
|
||||||
|
if test "x$ac_cv_header_GL_xmesa_h" = "xyes"; then
|
||||||
|
AC_DEFINE( XMESA )
|
||||||
|
AC_DEFINE( FX )
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
AC_CHECK_LIB(GLU, gluLookAt)
|
||||||
|
if test "x$ac_cv_lib_GLU_gluLookAt" = "xno" ; then
|
||||||
|
dnl if no GLU, check for MesaGLU
|
||||||
|
AC_CHECK_LIB(MesaGLU, gluLookAt)
|
||||||
|
fi
|
||||||
|
|
||||||
|
dnl check for glut
|
||||||
|
AC_CHECK_LIB(glut, glutGetModifiers)
|
||||||
|
|
||||||
|
dnl test for glutGameModeString, but avoid adding glut a second time into
|
||||||
|
dnl the list of libraries
|
||||||
|
save_LIBS="$LIBS"
|
||||||
|
AC_CHECK_LIB(glut, glutGameModeString)
|
||||||
|
LIBS="$save_LIBS"
|
||||||
|
else
|
||||||
|
dnl Win32 is a little wierd because it has to try to handle the various
|
||||||
|
dnl winbloze-isms. We'll just do this manually for now.
|
||||||
|
|
||||||
|
echo Win32 specific hacks...
|
||||||
|
AC_DEFINE(WIN32)
|
||||||
|
|
||||||
|
dnl force a failed check since we will be building under windoze
|
||||||
|
AM_CONDITIONAL(ENABLE_XMESA_FX, test "no" = "yes")
|
||||||
|
|
||||||
|
dnl just define these to true and hope for the best
|
||||||
|
ac_cv_lib_glut_glutGetModifiers="yes"
|
||||||
|
ac_cv_lib_glut_glutGameModeString="yes"
|
||||||
|
|
||||||
|
if test "x$with_sgi_opengl" = "xyes" ; then
|
||||||
|
echo "Building with glut.dll, glu.dll, and opengl.dll"
|
||||||
|
WIN32_GLUT=glut
|
||||||
|
WIN32_GLU=glu
|
||||||
|
WIN32_OPENGL=opengl
|
||||||
|
else
|
||||||
|
echo "Building with glut32.dll, glu32.dll, and opengl32.dll"
|
||||||
|
WIN32_GLUT=glut32
|
||||||
|
WIN32_GLU=glu32
|
||||||
|
WIN32_OPENGL=opengl32
|
||||||
|
fi
|
||||||
|
|
||||||
|
LIBS="$LIBS -l${WIN32_GLUT} -l${WIN32_GLU} -l${WIN32_OPENGL}"
|
||||||
|
LIBS="$LIBS -luser32 -lgdi32"
|
||||||
|
echo "Will link apps with $LIBS"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if test "x$ac_cv_lib_glut_glutGetModifiers" = "xno"; then
|
||||||
|
echo
|
||||||
|
echo "Unable to find the necessary OpenGL or GLUT libraries."
|
||||||
|
echo "See config.log for automated test details and results ..."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if test "x$ac_cv_lib_glut_glutGameModeString" = "xno"; then
|
||||||
|
echo
|
||||||
|
echo "Your version of glut doesn't support game mode."
|
||||||
|
echo "You need to fetch and install the latest version of glut from:"
|
||||||
|
echo
|
||||||
|
echo " http://reality.sgi.com/opengl/glut3/glut3.html"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
opengl_LIBS="$LIBS"
|
||||||
|
LIBS="$base_LIBS"
|
||||||
|
|
||||||
|
AC_SUBST(base_LIBS)
|
||||||
|
AC_SUBST(opengl_LIBS)
|
||||||
|
|
||||||
|
AM_CONDITIONAL(HAVE_XWINDOWS, test "x$ac_cv_lib_X11_XCreateWindow" = "xyes" )
|
||||||
|
|
||||||
|
dnl Check for "plib" without which we cannot go on
|
||||||
|
AC_CHECK_HEADER(plib/pu.h)
|
||||||
|
if test "x$ac_cv_header_plib_pu_h" != "xyes"; then
|
||||||
|
echo
|
||||||
|
echo "You *must* have the plib library installed on your system to build"
|
||||||
|
echo "the FGFS simulator!"
|
||||||
|
echo
|
||||||
|
echo "Please see README.plib for more details."
|
||||||
|
echo
|
||||||
|
echo "configure aborted."
|
||||||
|
exit
|
||||||
|
fi
|
||||||
|
|
||||||
|
dnl Check if Generic Polygon Clipping library is installed
|
||||||
|
dnl (from http://www.cs.man.ac.uk/aig/staff/alan/software/)
|
||||||
|
AC_CHECK_HEADERS( gpc.h )
|
||||||
|
if test "x$ac_cv_header_gpc_h" != "xyes"; then
|
||||||
|
echo
|
||||||
|
echo "You need to have the GPC library installed on your system to"
|
||||||
|
echo "build some of the scenery generation tools, otherwise you won't"
|
||||||
|
echo "be able to create scenery."
|
||||||
|
echo
|
||||||
|
echo "Please see README.gpc for more details."
|
||||||
|
echo
|
||||||
|
echo "(pausing 5 seconds)"
|
||||||
|
sleep 5
|
||||||
|
echo
|
||||||
|
fi
|
||||||
|
|
||||||
|
dnl Checks for header files.
|
||||||
|
AC_HEADER_STDC
|
||||||
|
AC_CHECK_HEADERS( \
|
||||||
|
fcntl.h getopt.h malloc.h memory.h stdlib.h sys/param.h sys/stat.h \
|
||||||
|
sys/time.h sys/timeb.h unistd.h windows.h winbase.h values.h )
|
||||||
|
|
||||||
|
dnl Checks for typedefs, structures, and compiler characteristics.
|
||||||
|
AC_C_CONST
|
||||||
|
AC_TYPE_SIZE_T
|
||||||
|
AC_HEADER_TIME
|
||||||
|
AC_STRUCT_TM
|
||||||
|
|
||||||
|
dnl Checks for library functions.
|
||||||
|
AC_TYPE_SIGNAL
|
||||||
|
AC_FUNC_VPRINTF
|
||||||
|
AC_CHECK_FUNCS( ftime gettimeofday timegm memcpy bcopy mktime strstr rand \
|
||||||
|
random setitimer getitimer signal GetLocalTime rint getrusage )
|
||||||
|
|
||||||
|
AM_CONFIG_HEADER(Include/config.h)
|
||||||
|
|
||||||
|
AC_OUTPUT( \
|
||||||
|
VERSION \
|
||||||
|
Makefile \
|
||||||
|
Construct/Makefile \
|
||||||
|
Construct/Clipper/Makefile \
|
||||||
|
Construct/Combine/Makefile \
|
||||||
|
Construct/GenOutput/Makefile \
|
||||||
|
Construct/Match/Makefile \
|
||||||
|
Construct/Triangulate/Makefile \
|
||||||
|
Construct/Main/Makefile \
|
||||||
|
Construct/Parallel/Makefile \
|
||||||
|
Lib/Makefile \
|
||||||
|
Lib/Array/Makefile \
|
||||||
|
Lib/Build/Makefile \
|
||||||
|
Lib/DEM/Makefile \
|
||||||
|
Lib/Polygon/Makefile \
|
||||||
|
Lib/poly2tri/Makefile \
|
||||||
|
Lib/shapelib/Makefile \
|
||||||
|
Lib/Triangle/Makefile \
|
||||||
|
Prep/Makefile \
|
||||||
|
Prep/DemChop/Makefile \
|
||||||
|
Prep/DemInfo/Makefile \
|
||||||
|
Prep/DemRaw2ascii/Makefile \
|
||||||
|
Prep/GenAirports/Makefile \
|
||||||
|
Prep/GSHHS/Makefile \
|
||||||
|
Prep/MergerClipper/Makefile \
|
||||||
|
Prep/ShapeFile/Makefile \
|
||||||
|
Utils/Makefile \
|
||||||
|
)
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "Configure Summary"
|
||||||
|
echo "================="
|
||||||
|
|
||||||
|
echo "Prefix: $prefix"
|
||||||
|
|
||||||
|
if test "x$with_logging" != "x"; then
|
||||||
|
echo "Debug messages: $with_logging"
|
||||||
|
else
|
||||||
|
echo "Debug messages: yes"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if test "x$with_efence" != "x"; then
|
||||||
|
echo "Electric fence: $with_efence"
|
||||||
|
else
|
||||||
|
echo "Electric fence: no"
|
||||||
|
fi
|
183
detect.c
Normal file
183
detect.c
Normal file
|
@ -0,0 +1,183 @@
|
||||||
|
#include "plugin.h"
|
||||||
|
// Triangle-stripdetection made simple. By Joost Bloemen, Copyright Vimana BV
|
||||||
|
// If you can improve the algorithm, be sure to let me know you can reach me
|
||||||
|
// at research@3dtop.com
|
||||||
|
|
||||||
|
struct BMF_SURFACE{
|
||||||
|
USHORT p0, p1, p2;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Hit{
|
||||||
|
USHORT hits;
|
||||||
|
USHORT t[3];
|
||||||
|
UCHAR mask[3];
|
||||||
|
BMF_SURFACE p[3];
|
||||||
|
BOOL Stripped;
|
||||||
|
}* HitList;
|
||||||
|
|
||||||
|
// INPUT:
|
||||||
|
//ilist is the list with indices of the original triangles, will be broken down to
|
||||||
|
// only the triangles that can 't be stripped, at the end.
|
||||||
|
//length is the number of triangles in ilist.
|
||||||
|
// OUTPUT:
|
||||||
|
//nr-strips is the number of strips we detected, they have a minimum of two triangles
|
||||||
|
//strips_length contains an array[nr_strips] of strip-lengths, strip1, strip2 strip3 etc...
|
||||||
|
//nr_indices is the total number of vertice-indices we have in the array "stripindex":
|
||||||
|
//stripindex is a long list of strip1-indices, strip2-indices, strip3-indices etc...
|
||||||
|
//return-value is the new number of seperate triangles in ilist.
|
||||||
|
USHORT DetectStrips(BMF_SURFACE * ilist, USHORT length,
|
||||||
|
USHORT * nr_strips, USHORT * strip_length,
|
||||||
|
USHORT * nr_indices, USHORT * stripindex)
|
||||||
|
{
|
||||||
|
USHORT lastp0,lastp1,lastp2;
|
||||||
|
USHORT n,nr,trynr;
|
||||||
|
USHORT p0,p1,p2;
|
||||||
|
USHORT i,k,next,p;
|
||||||
|
UCHAR mask;
|
||||||
|
BMF_SURFACE * temp, * tempEnd;
|
||||||
|
struct Hit * tempHitList;
|
||||||
|
// First part makes a hitlist per triangle, how many sides(hits) a triangle has shared,
|
||||||
|
// the indexes of the hits, up to 3 masks that define wich points the triangles each share
|
||||||
|
// and the points of each shared triangle.
|
||||||
|
HitList=(struct Hit *)GlobalAlloc(GMEM_FIXED|GMEM_ZEROINIT,length*sizeof(struct Hit));
|
||||||
|
tempHitList=HitList;
|
||||||
|
for(n=0;n<length;n++,tempHitList++)
|
||||||
|
{
|
||||||
|
p0=ilist[n].p0;
|
||||||
|
p1=ilist[n].p1;
|
||||||
|
p2=ilist[n].p2;
|
||||||
|
temp=ilist;
|
||||||
|
tempEnd=ilist+length;
|
||||||
|
while(temp<tempEnd)
|
||||||
|
{USHORT p;
|
||||||
|
// The following piece of code accounts for 99% of the time when converting large models
|
||||||
|
nr=2; // count-down, we only want the ones with two points the same
|
||||||
|
mask=0;
|
||||||
|
if ((p=temp->p0)==p0){mask|=0x11;nr--;}
|
||||||
|
else {if (p==p1){mask|=0x12;nr--;}
|
||||||
|
else {if (p==p2){mask|=0x14;nr--;}}
|
||||||
|
}
|
||||||
|
if ((p=temp->p1)==p0){mask|=0x21;nr--;}
|
||||||
|
else {if (p==p1){mask|=0x22;nr--;}
|
||||||
|
else {if (p==p2){mask|=0x24;nr--;}}
|
||||||
|
}
|
||||||
|
if ((p=temp->p2)==p0){mask|=0x41;nr--;}
|
||||||
|
else {if (p==p1){mask|=0x42;nr--;}
|
||||||
|
else {if (p==p2){mask|=0x44;nr--;}}
|
||||||
|
}
|
||||||
|
|
||||||
|
// That's it
|
||||||
|
if(!nr) //this doesn't happen very often
|
||||||
|
{USHORT nrs=tempHitList->hits;
|
||||||
|
//Rotate and save points so that p0 and p1 point to points that are the same.
|
||||||
|
// to check later, if we can make a strip of this
|
||||||
|
switch (mask>>4){
|
||||||
|
case 5:
|
||||||
|
tempHitList->p[nrs].p1=temp->p0;
|
||||||
|
tempHitList->p[nrs].p0=temp->p2;
|
||||||
|
tempHitList->p[nrs].p2=temp->p1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 6:
|
||||||
|
tempHitList->p[nrs].p0=temp->p1;
|
||||||
|
tempHitList->p[nrs].p1=temp->p2;
|
||||||
|
tempHitList->p[nrs].p2=temp->p0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 3:
|
||||||
|
tempHitList->p[nrs].p0=temp->p0;
|
||||||
|
tempHitList->p[nrs].p1=temp->p1;
|
||||||
|
tempHitList->p[nrs].p2=temp->p2;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
tempHitList->t[nrs]=temp-ilist; // (temp-ilist) is actually the triangle-number
|
||||||
|
tempHitList->mask[nrs]=mask; // mask is for later
|
||||||
|
if(++tempHitList->hits==3)temp=tempEnd; // break while-loop if we have 3 hits
|
||||||
|
}
|
||||||
|
temp++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Next:
|
||||||
|
// Start with trying to make a strip of all triangles with 1 hit as a starting point,
|
||||||
|
// then 2 , finally 3.
|
||||||
|
// That's all.
|
||||||
|
for(trynr=1;trynr<=3;trynr++)
|
||||||
|
{
|
||||||
|
for(p=0;p<length;p++)
|
||||||
|
{
|
||||||
|
if(HitList[p].hits==trynr&&!HitList[p].Stripped)
|
||||||
|
{
|
||||||
|
n=p; // n is first triangle of possible strip
|
||||||
|
i=0; // i is triangle-counter of this possible strip
|
||||||
|
k=10; // found a matching triangle
|
||||||
|
while(k>=10) // while found a triangle
|
||||||
|
{for (k=0;k<trynr;k++) // try all possible triangles
|
||||||
|
{next=HitList[n].t[k]; // possible triangle
|
||||||
|
if(!HitList[next].Stripped) // not included yet ?
|
||||||
|
{if(!i) // if testing with first triangle, it must be rotated so that
|
||||||
|
// points that are the same as next triangle are p1 and p2
|
||||||
|
{switch (HitList[n].mask[k]&0x0f){
|
||||||
|
case 6:
|
||||||
|
lastp0=ilist[p].p0; // lastp0-p2 is first triangle of strip
|
||||||
|
lastp1=ilist[p].p1; // is a local triangle that defines the last
|
||||||
|
lastp2=ilist[p].p2; // triangle added to the strip
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 3:
|
||||||
|
lastp1=ilist[p].p0;
|
||||||
|
lastp2=ilist[p].p1;
|
||||||
|
lastp0=ilist[p].p2;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 5:
|
||||||
|
lastp0=ilist[p].p1;
|
||||||
|
lastp1=ilist[p].p2;
|
||||||
|
lastp2=ilist[p].p0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
stripindex[*nr_indices]=lastp0; //save
|
||||||
|
stripindex[(*nr_indices)+1]=lastp1;
|
||||||
|
stripindex[(*nr_indices)+2]=lastp2;
|
||||||
|
}
|
||||||
|
if(i&1) // odd or even, makes a difference, see OpenGL
|
||||||
|
{if (HitList[n].p[k].p0==lastp0&&HitList[n].p[k].p1==lastp2) //new one fits ?
|
||||||
|
{lastp0=HitList[n].p[k].p0; // update last triangle used
|
||||||
|
lastp1=HitList[n].p[k].p1;
|
||||||
|
lastp2=HitList[n].p[k].p2;
|
||||||
|
HitList[next].Stripped=TRUE; //this one is done
|
||||||
|
stripindex[(*nr_indices)++]=lastp2; //save, p2 defines this triangle
|
||||||
|
n=next; //use this one as next source
|
||||||
|
k=10; // break for-loop with k, found one
|
||||||
|
i++;
|
||||||
|
} }
|
||||||
|
else
|
||||||
|
{if (HitList[n].p[k].p0==lastp2&&HitList[n].p[k].p1==lastp1) //new one fits ?
|
||||||
|
{lastp0=HitList[n].p[k].p0; // update last triangle used
|
||||||
|
lastp1=HitList[n].p[k].p1;
|
||||||
|
lastp2=HitList[n].p[k].p2;
|
||||||
|
HitList[next].Stripped=TRUE; //this one is done
|
||||||
|
if(!i++)
|
||||||
|
{
|
||||||
|
(*nr_indices)+=3; //first triangle had 3 indices and keep it
|
||||||
|
HitList[n].Stripped=TRUE; //and is done also
|
||||||
|
}
|
||||||
|
stripindex[(*nr_indices)++]=lastp2; // save, p2 defines this triangle
|
||||||
|
n=next; //use this one as next source
|
||||||
|
k=10; // break for-loop with k, found one
|
||||||
|
} } } } }
|
||||||
|
i++; //actual number of triangles in strip is one more
|
||||||
|
if(i>1)strip_length[(*nr_strips)++]=i+2; //actual strip-length (in indices) is traingles +2
|
||||||
|
} } }
|
||||||
|
// Done.
|
||||||
|
// Now keep all triangles that aren't stripped in original triangle-list and return
|
||||||
|
// remaining number of triangles in original triangle-list.
|
||||||
|
i=0;
|
||||||
|
for(p=0;p<length;p++)
|
||||||
|
{if(!HitList[p].Stripped)
|
||||||
|
{
|
||||||
|
ilist[i++]=ilist[p];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
GlobalFree(HitList);
|
||||||
|
return(i);
|
||||||
|
}
|
26
scenery_version.hxx
Normal file
26
scenery_version.hxx
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
// scenery_version.hxx -- Scenery file format version
|
||||||
|
//
|
||||||
|
// Written by Curtis Olson, started March 1999.
|
||||||
|
//
|
||||||
|
// Copyright (C) 1999 Curtis L. Olson - curt@flightgear.org
|
||||||
|
//
|
||||||
|
// This program is free software; you can redistribute it and/or
|
||||||
|
// modify it under the terms of the GNU General Public License as
|
||||||
|
// published by the Free Software Foundation; either version 2 of the
|
||||||
|
// License, or (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful, but
|
||||||
|
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
// General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
//
|
||||||
|
// $Id$
|
||||||
|
|
||||||
|
|
||||||
|
#define FG_SCENERY_FILE_FORMAT "0.4"
|
||||||
|
|
||||||
|
|
47
src/Airports/GenAirports/Makefile.am
Normal file
47
src/Airports/GenAirports/Makefile.am
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
# Makefile
|
||||||
|
#
|
||||||
|
# Written by Curtis Olson, started January 1998.
|
||||||
|
#
|
||||||
|
# Copyright (C) 1998 Curtis L. Olson - curt@me.umn.edu
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation; either version 2 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program; if not, write to the Free Software
|
||||||
|
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
#
|
||||||
|
# $Id$
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
bin_PROGRAMS = genapts
|
||||||
|
|
||||||
|
genapts_SOURCES = \
|
||||||
|
build.cxx build.hxx \
|
||||||
|
convex_hull.cxx convex_hull.hxx \
|
||||||
|
main.cxx \
|
||||||
|
point2d.cxx point2d.hxx \
|
||||||
|
runway.cxx runway.hxx
|
||||||
|
|
||||||
|
genapts_LDADD = \
|
||||||
|
$(top_builddir)/Lib/Array/libArray.a \
|
||||||
|
$(top_builddir)/Lib/Polygon/libPolygon.a \
|
||||||
|
$(top_builddir)/Lib/poly2tri/libpoly2tri.a \
|
||||||
|
$(top_builddir)/Lib/Build/libBuild.a \
|
||||||
|
-lsgbucket -lsgdebug -lsgmath -lsgmisc -lz -lgpc \
|
||||||
|
$(base_LIBS)
|
||||||
|
|
||||||
|
INCLUDES += \
|
||||||
|
-I$(top_builddir) \
|
||||||
|
-I$(top_builddir)/Tools \
|
||||||
|
-I$(top_builddir)/Lib \
|
||||||
|
-I$(top_builddir)/Tools/Lib
|
1120
src/Airports/GenAirports/build.cxx
Normal file
1120
src/Airports/GenAirports/build.cxx
Normal file
File diff suppressed because it is too large
Load diff
43
src/Airports/GenAirports/build.hxx
Normal file
43
src/Airports/GenAirports/build.hxx
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
// build.hxx -- routines to build polygon model of an airport from the runway
|
||||||
|
// definition
|
||||||
|
//
|
||||||
|
// Written by Curtis Olson, started September 1999.
|
||||||
|
//
|
||||||
|
// Copyright (C) 1999 Curtis L. Olson - curt@flightgear.org
|
||||||
|
//
|
||||||
|
// This program is free software; you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation; either version 2 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
//
|
||||||
|
// $Id$
|
||||||
|
//
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef _BUILD_HXX
|
||||||
|
#define _BUILD_HXX
|
||||||
|
|
||||||
|
|
||||||
|
#include <list>
|
||||||
|
|
||||||
|
#include "point2d.hxx"
|
||||||
|
|
||||||
|
|
||||||
|
// build 3d airport
|
||||||
|
void build_airport( string airport, string_list& runways_raw,
|
||||||
|
const string& root );
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#endif // _BUILD_HXX
|
||||||
|
|
||||||
|
|
247
src/Airports/GenAirports/convex_hull.cxx
Normal file
247
src/Airports/GenAirports/convex_hull.cxx
Normal file
|
@ -0,0 +1,247 @@
|
||||||
|
// convex_hull.cxx -- calculate the convex hull of a set of points
|
||||||
|
//
|
||||||
|
// Written by Curtis Olson, started September 1998.
|
||||||
|
//
|
||||||
|
// Copyright (C) 1998 Curtis L. Olson - curt@me.umn.edu
|
||||||
|
//
|
||||||
|
// This program is free software; you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation; either version 2 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
//
|
||||||
|
// $Id$
|
||||||
|
//
|
||||||
|
|
||||||
|
|
||||||
|
#include <math.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
|
||||||
|
#ifdef NEEDNAMESPACESTD
|
||||||
|
using namespace std;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <simgear/constants.h>
|
||||||
|
|
||||||
|
#include "convex_hull.hxx"
|
||||||
|
#include "point2d.hxx"
|
||||||
|
|
||||||
|
|
||||||
|
// stl map typedefs
|
||||||
|
typedef map < double, double, less<double> > map_container;
|
||||||
|
typedef map_container::iterator map_iterator;
|
||||||
|
|
||||||
|
|
||||||
|
// Calculate theta of angle (a, b, c)
|
||||||
|
double calc_angle(Point3D a, Point3D b, Point3D c) {
|
||||||
|
Point3D u, v;
|
||||||
|
double udist, vdist, uv_dot, tmp;
|
||||||
|
|
||||||
|
// u . v = ||u|| * ||v|| * cos(theta)
|
||||||
|
|
||||||
|
u.setx( b.x() - a.x() );
|
||||||
|
u.sety( b.y() - a.y() );
|
||||||
|
udist = sqrt( u.x() * u.x() + u.y() * u.y() );
|
||||||
|
// printf("udist = %.6f\n", udist);
|
||||||
|
|
||||||
|
v.setx( b.x() - c.x() );
|
||||||
|
v.sety( b.y() - c.y() );
|
||||||
|
vdist = sqrt( v.x() * v.x() + v.y() * v.y() );
|
||||||
|
// printf("vdist = %.6f\n", vdist);
|
||||||
|
|
||||||
|
uv_dot = u.x() * v.x() + u.y() * v.y();
|
||||||
|
// printf("uv_dot = %.6f\n", uv_dot);
|
||||||
|
|
||||||
|
tmp = uv_dot / (udist * vdist);
|
||||||
|
// printf("tmp = %.6f\n", tmp);
|
||||||
|
|
||||||
|
return acos(tmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Test to see if angle(Pa, Pb, Pc) < 180 degrees
|
||||||
|
bool test_point(Point3D Pa, Point3D Pb, Point3D Pc) {
|
||||||
|
double a1, a2;
|
||||||
|
|
||||||
|
Point3D origin( 0.0 );
|
||||||
|
|
||||||
|
Point3D a( cos(Pa.y()) * Pa.x(),
|
||||||
|
sin(Pa.y()) * Pa.x(), 0 );
|
||||||
|
|
||||||
|
Point3D b( cos(Pb.y()) * Pb.x(),
|
||||||
|
sin(Pb.y()) * Pb.x(), 0 );
|
||||||
|
|
||||||
|
Point3D c( cos(Pc.y()) * Pc.x(),
|
||||||
|
sin(Pc.y()) * Pc.x(), 0 );
|
||||||
|
|
||||||
|
// printf("a is %.6f %.6f\n", a.x, a.y);
|
||||||
|
// printf("b is %.6f %.6f\n", b.x, b.y);
|
||||||
|
// printf("c is %.6f %.6f\n", c.x, c.y);
|
||||||
|
|
||||||
|
a1 = calc_angle(a, b, origin);
|
||||||
|
a2 = calc_angle(origin, b, c);
|
||||||
|
|
||||||
|
// printf("a1 = %.2f a2 = %.2f\n", a1 * RAD_TO_DEG, a2 * RAD_TO_DEG);
|
||||||
|
|
||||||
|
return ( (a1 + a2) < FG_PI );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// calculate the convex hull of a set of points, return as a list of
|
||||||
|
// point2d. The algorithm description can be found at:
|
||||||
|
// http://riot.ieor.berkeley.edu/riot/Applications/ConvexHull/CHDetails.html
|
||||||
|
FGPolygon convex_hull( const point_list& input_list ) {
|
||||||
|
map_iterator map_current, map_next, map_next_next, map_last;
|
||||||
|
|
||||||
|
// list of translated points
|
||||||
|
point_list trans_list;
|
||||||
|
|
||||||
|
// points sorted by radian degrees
|
||||||
|
map_container radians_map;
|
||||||
|
|
||||||
|
// will contain the convex hull
|
||||||
|
FGPolygon con_hull;
|
||||||
|
|
||||||
|
Point3D p, Pa, Pb, Pc, result;
|
||||||
|
double sum_x, sum_y;
|
||||||
|
int in_count, last_size;
|
||||||
|
|
||||||
|
// STEP ONE: Find an average midpoint of the input set of points
|
||||||
|
in_count = input_list.size();
|
||||||
|
sum_x = sum_y = 0.0;
|
||||||
|
|
||||||
|
for ( int i = 0; i < in_count; ++i ) {
|
||||||
|
sum_x += input_list[i].x();
|
||||||
|
sum_y += input_list[i].y();
|
||||||
|
}
|
||||||
|
|
||||||
|
Point3D average( sum_x / in_count, sum_y / in_count, 0 );
|
||||||
|
|
||||||
|
// printf("Average center point is %.4f %.4f\n", average.x, average.y);
|
||||||
|
|
||||||
|
// STEP TWO: Translate input points so average is at origin
|
||||||
|
trans_list.clear();
|
||||||
|
|
||||||
|
for ( int i = 0; i < in_count; ++i ) {
|
||||||
|
p = Point3D( input_list[i].x() - average.x(),
|
||||||
|
input_list[i].y() - average.y(), 0 );
|
||||||
|
// printf("%.6f %.6f\n", p.x, p.y);
|
||||||
|
trans_list.push_back( p );
|
||||||
|
}
|
||||||
|
|
||||||
|
// STEP THREE: convert to radians and sort by theta
|
||||||
|
radians_map.clear();
|
||||||
|
|
||||||
|
for ( int i = 0; i < in_count; ++i ) {
|
||||||
|
p = cart_to_polar_2d( trans_list[i] );
|
||||||
|
if ( p.x() > radians_map[p.y()] ) {
|
||||||
|
radians_map[p.y()] = p.x();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
// printf("Sorted list\n");
|
||||||
|
map_current = radians_map.begin();
|
||||||
|
map_last = radians_map.end();
|
||||||
|
for ( ; map_current != map_last ; ++map_current ) {
|
||||||
|
p.setx( (*map_current).first );
|
||||||
|
p.sety( (*map_current).second );
|
||||||
|
|
||||||
|
printf("p is %.6f %.6f\n", p.x(), p.y());
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
// STEP FOUR: traverse the sorted list and eliminate everything
|
||||||
|
// not on the perimeter.
|
||||||
|
// printf("Traversing list\n");
|
||||||
|
|
||||||
|
// double check list size ... this should never fail because a
|
||||||
|
// single runway will always generate four points.
|
||||||
|
if ( radians_map.size() < 3 ) {
|
||||||
|
cout << "convex hull not possible with < 3 points" << endl;
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ensure that we run the while loop at least once
|
||||||
|
last_size = radians_map.size() + 1;
|
||||||
|
|
||||||
|
while ( last_size > (int)radians_map.size() ) {
|
||||||
|
// printf("Running an iteration of the graham scan algorithm\n");
|
||||||
|
last_size = radians_map.size();
|
||||||
|
|
||||||
|
map_current = radians_map.begin();
|
||||||
|
while ( map_current != radians_map.end() ) {
|
||||||
|
// get first element
|
||||||
|
Pa.sety( (*map_current).first );
|
||||||
|
Pa.setx( (*map_current).second );
|
||||||
|
|
||||||
|
// get second element
|
||||||
|
map_next = map_current;
|
||||||
|
++map_next;
|
||||||
|
if ( map_next == radians_map.end() ) {
|
||||||
|
map_next = radians_map.begin();
|
||||||
|
}
|
||||||
|
Pb.sety( (*map_next).first );
|
||||||
|
Pb.setx( (*map_next).second );
|
||||||
|
|
||||||
|
// get third element
|
||||||
|
map_next_next = map_next;
|
||||||
|
++map_next_next;
|
||||||
|
if ( map_next_next == radians_map.end() ) {
|
||||||
|
map_next_next = radians_map.begin();
|
||||||
|
}
|
||||||
|
Pc.sety( (*map_next_next).first );
|
||||||
|
Pc.setx( (*map_next_next).second );
|
||||||
|
|
||||||
|
// printf("Pa is %.6f %.6f\n", Pa.y(), Pa.x());
|
||||||
|
// printf("Pb is %.6f %.6f\n", Pb.y(), Pb.x());
|
||||||
|
// printf("Pc is %.6f %.6f\n", Pc.y(), Pc.x());
|
||||||
|
|
||||||
|
if ( test_point(Pa, Pb, Pc) ) {
|
||||||
|
// printf("Accepted a point\n");
|
||||||
|
// accept point, advance Pa, Pb, and Pc.
|
||||||
|
++map_current;
|
||||||
|
} else {
|
||||||
|
// printf("REJECTED A POINT\n");
|
||||||
|
// reject point, delete it and advance only Pb and Pc
|
||||||
|
map_next = map_current;
|
||||||
|
++map_next;
|
||||||
|
if ( map_next == radians_map.end() ) {
|
||||||
|
map_next = radians_map.begin();
|
||||||
|
}
|
||||||
|
radians_map.erase( map_next );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// translate back to correct lon/lat
|
||||||
|
// printf("Final sorted convex hull\n");
|
||||||
|
con_hull.erase();
|
||||||
|
map_current = radians_map.begin();
|
||||||
|
map_last = radians_map.end();
|
||||||
|
for ( ; map_current != map_last ; ++map_current ) {
|
||||||
|
p.sety( (*map_current).first );
|
||||||
|
p.setx( (*map_current).second );
|
||||||
|
|
||||||
|
result.setx( cos(p.y()) * p.x() + average.x() );
|
||||||
|
result.sety( sin(p.y()) * p.x() + average.y() );
|
||||||
|
|
||||||
|
// printf("%.6f %.6f\n", result.x, result.y);
|
||||||
|
|
||||||
|
con_hull.add_node(0, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
return con_hull;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
51
src/Airports/GenAirports/convex_hull.hxx
Normal file
51
src/Airports/GenAirports/convex_hull.hxx
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
// convex_hull.hxx -- calculate the convex hull of a set of points
|
||||||
|
//
|
||||||
|
// Written by Curtis Olson, started September 1998.
|
||||||
|
//
|
||||||
|
// Copyright (C) 1998 Curtis L. Olson - curt@me.umn.edu
|
||||||
|
//
|
||||||
|
// This program is free software; you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation; either version 2 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
//
|
||||||
|
// $Id$
|
||||||
|
//
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef _CONVEX_HULL_HXX
|
||||||
|
#define _CONVEX_HULL_HXX
|
||||||
|
|
||||||
|
|
||||||
|
#include <list>
|
||||||
|
|
||||||
|
#ifdef NEEDNAMESPACESTD
|
||||||
|
using namespace std;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <simgear/fg_types.hxx>
|
||||||
|
|
||||||
|
#include <Polygon/polygon.hxx>
|
||||||
|
|
||||||
|
#include "point2d.hxx"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// calculate the convex hull of a set of points, return as a list of
|
||||||
|
// point2d. The algorithm description can be found at:
|
||||||
|
// http://riot.ieor.berkeley.edu/riot/Applications/ConvexHull/CHDetails.html
|
||||||
|
FGPolygon convex_hull( const point_list& input_list );
|
||||||
|
|
||||||
|
|
||||||
|
#endif // _CONVEX_HULL_HXX
|
||||||
|
|
||||||
|
|
351
src/Airports/GenAirports/main.cxx
Normal file
351
src/Airports/GenAirports/main.cxx
Normal file
|
@ -0,0 +1,351 @@
|
||||||
|
// main.cxx -- main loop
|
||||||
|
//
|
||||||
|
// Written by Curtis Olson, started March 1998.
|
||||||
|
//
|
||||||
|
// Copyright (C) 1998 Curtis L. Olson - curt@me.umn.edu
|
||||||
|
//
|
||||||
|
// This program is free software; you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation; either version 2 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
//
|
||||||
|
// $Id$
|
||||||
|
//
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include <config.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <simgear/compiler.h>
|
||||||
|
|
||||||
|
#ifdef HAVE_STDLIB_H
|
||||||
|
#include <stdlib.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <list>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include STL_STRING
|
||||||
|
|
||||||
|
#include <simgear/newbucket.hxx>
|
||||||
|
#include <simgear/logstream.hxx>
|
||||||
|
#include <simgear/constants.h>
|
||||||
|
#include <simgear/fgstream.hxx>
|
||||||
|
|
||||||
|
#include <Polygon/index.hxx>
|
||||||
|
|
||||||
|
#include "build.hxx"
|
||||||
|
#include "convex_hull.hxx"
|
||||||
|
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
// write out airport data
|
||||||
|
void write_airport( long int p_index, const FGPolygon& hull_list, FGBucket b,
|
||||||
|
const string& root, const bool cut_and_keep ) {
|
||||||
|
char tile_name[256], poly_index[256];
|
||||||
|
|
||||||
|
string base = b.gen_base_path();
|
||||||
|
string path = root + "/" + base;
|
||||||
|
string command = "mkdir -p " + path;
|
||||||
|
system( command.c_str() );
|
||||||
|
|
||||||
|
long int b_index = b.gen_index();
|
||||||
|
sprintf(tile_name, "%ld", b_index);
|
||||||
|
string aptfile = path + "/" + tile_name;
|
||||||
|
|
||||||
|
sprintf( poly_index, "%ld", p_index );
|
||||||
|
aptfile += ".";
|
||||||
|
aptfile += poly_index;
|
||||||
|
cout << "apt file = " << aptfile << endl;
|
||||||
|
|
||||||
|
FILE *fd;
|
||||||
|
if ( (fd = fopen(aptfile.c_str(), "a")) == NULL ) {
|
||||||
|
cout << "Cannot open file: " << aptfile << endl;
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// polygon type
|
||||||
|
if ( cut_and_keep ) {
|
||||||
|
fprintf( fd, "AirportKeep\n" );
|
||||||
|
} else {
|
||||||
|
fprintf( fd, "AirportIgnore\n" );
|
||||||
|
}
|
||||||
|
|
||||||
|
// number of contours
|
||||||
|
fprintf( fd, "1\n" );
|
||||||
|
|
||||||
|
// size of first contour
|
||||||
|
fprintf( fd, "%d\n", hull_list.contour_size(0) );
|
||||||
|
|
||||||
|
// hole flag
|
||||||
|
fprintf( fd, "%d\n", 0 ); // not a hole
|
||||||
|
|
||||||
|
// write contour (polygon) points
|
||||||
|
for ( int i = 0; i < hull_list.contour_size(0); ++i ) {
|
||||||
|
fprintf( fd, "%.7f %.7f\n",
|
||||||
|
hull_list.get_pt(0,i).x(),
|
||||||
|
hull_list.get_pt(0,i).y() );
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// process and airport + runway list
|
||||||
|
void process_airport( string airport, list < string > & runways_list,
|
||||||
|
const string& root ) {
|
||||||
|
FGPolygon rwy_list, hull;
|
||||||
|
point_list apt_list;
|
||||||
|
|
||||||
|
// parse main airport information
|
||||||
|
int elev;
|
||||||
|
|
||||||
|
cout << airport << endl;
|
||||||
|
string apt_type = airport.substr(0, 1);
|
||||||
|
string apt_code = airport.substr(2, 4); my_chomp(apt_code);
|
||||||
|
string apt_lat = airport.substr(7, 10);
|
||||||
|
string apt_lon = airport.substr(18, 11);
|
||||||
|
string apt_elev = airport.substr(30, 5);
|
||||||
|
sscanf( apt_elev.c_str(), "%d", &elev );
|
||||||
|
string apt_use = airport.substr(36, 1);
|
||||||
|
string apt_twr = airport.substr(37, 1);
|
||||||
|
string apt_bldg = airport.substr(38, 1);
|
||||||
|
string apt_name = airport.substr(40);
|
||||||
|
|
||||||
|
/*
|
||||||
|
cout << " type = " << apt_type << endl;
|
||||||
|
cout << " code = " << apt_code << endl;
|
||||||
|
cout << " lat = " << apt_lat << endl;
|
||||||
|
cout << " lon = " << apt_lon << endl;
|
||||||
|
cout << " elev = " << apt_elev << " " << elev << endl;
|
||||||
|
cout << " use = " << apt_use << endl;
|
||||||
|
cout << " twr = " << apt_twr << endl;
|
||||||
|
cout << " bldg = " << apt_bldg << endl;
|
||||||
|
cout << " name = " << apt_name << endl;
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Ignore any seaplane bases
|
||||||
|
if ( apt_type == "S" ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// parse runways and generate the vertex list
|
||||||
|
string rwy_str;
|
||||||
|
double lon, lat, hdg;
|
||||||
|
int len, width;
|
||||||
|
|
||||||
|
list < string >::iterator last_runway = runways_list.end();
|
||||||
|
for ( list < string >::iterator current_runway = runways_list.begin();
|
||||||
|
current_runway != last_runway ; ++current_runway ) {
|
||||||
|
rwy_str = (*current_runway);
|
||||||
|
|
||||||
|
cout << rwy_str << endl;
|
||||||
|
string rwy_no = rwy_str.substr(2, 4);
|
||||||
|
string rwy_lat = rwy_str.substr(6, 10);
|
||||||
|
sscanf( rwy_lat.c_str(), "%lf", &lat);
|
||||||
|
string rwy_lon = rwy_str.substr(17, 11);
|
||||||
|
sscanf( rwy_lon.c_str(), "%lf", &lon);
|
||||||
|
string rwy_hdg = rwy_str.substr(29, 7);
|
||||||
|
sscanf( rwy_hdg.c_str(), "%lf", &hdg);
|
||||||
|
string rwy_len = rwy_str.substr(36, 7);
|
||||||
|
sscanf( rwy_len.c_str(), "%d", &len);
|
||||||
|
string rwy_width = rwy_str.substr(43, 4);
|
||||||
|
sscanf( rwy_width.c_str(), "%d", &width);
|
||||||
|
string rwy_sfc = rwy_str.substr(47, 4);
|
||||||
|
string rwy_end1 = rwy_str.substr(52, 8);
|
||||||
|
string rwy_end2 = rwy_str.substr(61, 8);
|
||||||
|
|
||||||
|
/*
|
||||||
|
cout << " no = " << rwy_no << endl;
|
||||||
|
cout << " lat = " << rwy_lat << " " << lat << endl;
|
||||||
|
cout << " lon = " << rwy_lon << " " << lon << endl;
|
||||||
|
cout << " hdg = " << rwy_hdg << " " << hdg << endl;
|
||||||
|
cout << " len = " << rwy_len << " " << len << endl;
|
||||||
|
cout << " width = " << rwy_width << " " << width << endl;
|
||||||
|
cout << " sfc = " << rwy_sfc << endl;
|
||||||
|
cout << " end1 = " << rwy_end1 << endl;
|
||||||
|
cout << " end2 = " << rwy_end2 << endl;
|
||||||
|
*/
|
||||||
|
|
||||||
|
rwy_list = gen_runway_area( lon, lat, hdg * DEG_TO_RAD,
|
||||||
|
(double)len * FEET_TO_METER,
|
||||||
|
(double)width * FEET_TO_METER );
|
||||||
|
|
||||||
|
// add rwy_list to apt_list
|
||||||
|
for (int i = 0; i < (int)rwy_list.contour_size(0); ++i ) {
|
||||||
|
apt_list.push_back( rwy_list.get_pt(0,i) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( apt_list.size() == 0 ) {
|
||||||
|
cout << "no runway points generated" << endl;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// printf("Runway points in degrees\n");
|
||||||
|
// current = apt_list.begin();
|
||||||
|
// last = apt_list.end();
|
||||||
|
// for ( ; current != last; ++current ) {
|
||||||
|
// printf( "%.5f %.5f\n", current->lon, current->lat );
|
||||||
|
// }
|
||||||
|
// printf("\n");
|
||||||
|
|
||||||
|
// generate convex hull
|
||||||
|
hull = convex_hull(apt_list);
|
||||||
|
|
||||||
|
// get next polygon index
|
||||||
|
long int index = poly_index_next();
|
||||||
|
|
||||||
|
// find average center, min, and max point of convex hull
|
||||||
|
Point3D min(200.0), max(-200.0);
|
||||||
|
double sum_x, sum_y;
|
||||||
|
int count = hull.contour_size(0);
|
||||||
|
sum_x = sum_y = 0.0;
|
||||||
|
for ( int i = 0; i < count; ++i ) {
|
||||||
|
// printf("return = %.6f %.6f\n", (*current).x, (*current).y);
|
||||||
|
Point3D p = hull.get_pt( 0, i );
|
||||||
|
sum_x += p.x();
|
||||||
|
sum_y += p.y();
|
||||||
|
|
||||||
|
if ( p.x() < min.x() ) { min.setx( p.x() ); }
|
||||||
|
if ( p.y() < min.y() ) { min.sety( p.y() ); }
|
||||||
|
if ( p.x() > max.x() ) { max.setx( p.x() ); }
|
||||||
|
if ( p.y() > max.y() ) { max.sety( p.y() ); }
|
||||||
|
}
|
||||||
|
Point3D average( sum_x / count, sum_y / count, 0 );
|
||||||
|
|
||||||
|
// find buckets for center, min, and max points of convex hull.
|
||||||
|
// note to self: self, you should think about checking for runways
|
||||||
|
// that span the data line
|
||||||
|
FGBucket b(average.x(), average.y());
|
||||||
|
FGBucket b_min(min.x(), min.y());
|
||||||
|
FGBucket b_max(max.x(), max.y());
|
||||||
|
cout << "Bucket center = " << b << endl;
|
||||||
|
cout << "Bucket min = " << b_min << endl;
|
||||||
|
cout << "Bucket max = " << b_max << endl;
|
||||||
|
|
||||||
|
if ( b_min == b_max ) {
|
||||||
|
write_airport( index, hull, b, root, true );
|
||||||
|
} else {
|
||||||
|
FGBucket b_cur;
|
||||||
|
int dx, dy, i, j;
|
||||||
|
|
||||||
|
fgBucketDiff(b_min, b_max, &dx, &dy);
|
||||||
|
cout << "airport spans tile boundaries" << endl;
|
||||||
|
cout << " dx = " << dx << " dy = " << dy << endl;
|
||||||
|
|
||||||
|
if ( (dx > 2) || (dy > 2) ) {
|
||||||
|
cout << "somethings really wrong!!!!" << endl;
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
for ( j = 0; j <= dy; j++ ) {
|
||||||
|
for ( i = 0; i <= dx; i++ ) {
|
||||||
|
b_cur = fgBucketOffset(min.x(), min.y(), i, j);
|
||||||
|
if ( b_cur == b ) {
|
||||||
|
write_airport( index, hull, b_cur, root, true );
|
||||||
|
} else {
|
||||||
|
write_airport( index, hull, b_cur, root, true );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// string answer; cin >> answer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
// reads the apt_full file and extracts and processes the individual
|
||||||
|
// airport records
|
||||||
|
int main( int argc, char **argv ) {
|
||||||
|
string_list runways_list;
|
||||||
|
string airport, last_airport;
|
||||||
|
string line;
|
||||||
|
char tmp[256];
|
||||||
|
|
||||||
|
fglog().setLogLevels( FG_ALL, FG_DEBUG );
|
||||||
|
|
||||||
|
if ( argc != 3 ) {
|
||||||
|
FG_LOG( FG_GENERAL, FG_ALERT,
|
||||||
|
"Usage " << argv[0] << " <apt_file> <work_dir>" );
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// make work directory
|
||||||
|
string work_dir = argv[2];
|
||||||
|
string command = "mkdir -p " + work_dir;
|
||||||
|
system( command.c_str() );
|
||||||
|
|
||||||
|
// initialize persistant polygon counter
|
||||||
|
string counter_file = work_dir + "/poly_counter";
|
||||||
|
poly_index_init( counter_file );
|
||||||
|
|
||||||
|
fg_gzifstream in( argv[1] );
|
||||||
|
if ( !in ) {
|
||||||
|
FG_LOG( FG_GENERAL, FG_ALERT, "Cannot open file: " << argv[1] );
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// throw away the first 3 lines
|
||||||
|
in.getline(tmp, 256);
|
||||||
|
in.getline(tmp, 256);
|
||||||
|
in.getline(tmp, 256);
|
||||||
|
|
||||||
|
last_airport = "";
|
||||||
|
|
||||||
|
while ( ! in.eof() ) {
|
||||||
|
in.getline(tmp, 256);
|
||||||
|
line = tmp;
|
||||||
|
// cout << line << endl;
|
||||||
|
|
||||||
|
if ( line.length() == 0 ) {
|
||||||
|
// empty, skip
|
||||||
|
} else if ( line[0] == '#' ) {
|
||||||
|
// comment, skip
|
||||||
|
} else if ( (line[0] == 'A') || (line[0] == 'S') ) {
|
||||||
|
// start of airport record
|
||||||
|
airport = line;
|
||||||
|
|
||||||
|
if ( last_airport.length() ) {
|
||||||
|
// process previous record
|
||||||
|
// process_airport(last_airport, runways_list, argv[2]);
|
||||||
|
build_airport(last_airport, runways_list, argv[2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// clear runway list for start of next airport
|
||||||
|
runways_list.clear();
|
||||||
|
|
||||||
|
last_airport = airport;
|
||||||
|
} else if ( line[0] == 'R' ) {
|
||||||
|
// runway entry
|
||||||
|
runways_list.push_back(line);
|
||||||
|
} else if ( line == "[End]" ) {
|
||||||
|
// end of file
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
FG_LOG( FG_GENERAL, FG_ALERT,
|
||||||
|
"Unknown line in file" << endl << line );
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( last_airport.length() ) {
|
||||||
|
// process previous record
|
||||||
|
// process_airport(last_airport, runways_list, argv[2]);
|
||||||
|
build_airport(last_airport, runways_list, argv[2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
38
src/Airports/GenAirports/point2d.cxx
Normal file
38
src/Airports/GenAirports/point2d.cxx
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
// point2d.cxx -- 2d coordinate routines
|
||||||
|
//
|
||||||
|
// Written by Curtis Olson, started September 1998.
|
||||||
|
//
|
||||||
|
// Copyright (C) 1998 Curtis L. Olson - curt@me.umn.edu
|
||||||
|
//
|
||||||
|
// This program is free software; you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation; either version 2 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
//
|
||||||
|
// $Id$
|
||||||
|
//
|
||||||
|
|
||||||
|
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
|
#include "point2d.hxx"
|
||||||
|
|
||||||
|
|
||||||
|
// convert a point from cartesian to polar coordinates
|
||||||
|
Point3D cart_to_polar_2d(const Point3D& in) {
|
||||||
|
Point3D result( sqrt(in.x() * in.x() + in.y() * in.y()),
|
||||||
|
atan2(in.y(), in.x()),
|
||||||
|
0 );
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
39
src/Airports/GenAirports/point2d.hxx
Normal file
39
src/Airports/GenAirports/point2d.hxx
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
// point2d.hxx -- define a 2d point class
|
||||||
|
//
|
||||||
|
// Written by Curtis Olson, started February 1998.
|
||||||
|
//
|
||||||
|
// Copyright (C) 1998 Curtis L. Olson - curt@me.umn.edu
|
||||||
|
//
|
||||||
|
// This program is free software; you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation; either version 2 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
//
|
||||||
|
// $Id$
|
||||||
|
//
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef _POINT2D_HXX
|
||||||
|
#define _POINT2D_HXX
|
||||||
|
|
||||||
|
|
||||||
|
#include <simgear/fg_types.hxx>
|
||||||
|
#include <simgear/point3d.hxx>
|
||||||
|
|
||||||
|
|
||||||
|
// convert a point from cartesian to polar coordinates
|
||||||
|
Point3D cart_to_polar_2d(const Point3D& in);
|
||||||
|
|
||||||
|
|
||||||
|
#endif // _POINT2D_HXX
|
||||||
|
|
||||||
|
|
201
src/Airports/GenAirports/runway.cxx
Normal file
201
src/Airports/GenAirports/runway.cxx
Normal file
|
@ -0,0 +1,201 @@
|
||||||
|
// area.c -- routines to assist with inserting "areas" into FG terrain
|
||||||
|
//
|
||||||
|
// Written by Curtis Olson, started March 1998.
|
||||||
|
//
|
||||||
|
// Copyright (C) 1998 Curtis L. Olson - curt@me.umn.edu
|
||||||
|
//
|
||||||
|
// This program is free software; you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation; either version 2 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
//
|
||||||
|
// $Id$
|
||||||
|
//
|
||||||
|
|
||||||
|
|
||||||
|
#include <math.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include <simgear/constants.h>
|
||||||
|
#include <simgear/fg_types.hxx>
|
||||||
|
#include <simgear/fg_geodesy.hxx>
|
||||||
|
|
||||||
|
#include "runway.hxx"
|
||||||
|
#include "point2d.hxx"
|
||||||
|
|
||||||
|
|
||||||
|
// calc new x, y for a rotation
|
||||||
|
double rot_x(double x, double y, double theta) {
|
||||||
|
return ( x * cos(theta) + y * sin(theta) );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// calc new x, y for a rotation
|
||||||
|
double rot_y(double x, double y, double theta) {
|
||||||
|
return ( -x * sin(theta) + y * cos(theta) );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
FGPolygon batch_cart_to_polar_2d( const FGPolygon& in_list ) {
|
||||||
|
FGPolygon out_list;
|
||||||
|
Point3D p;
|
||||||
|
|
||||||
|
out_list.erase();
|
||||||
|
for ( int i = 0; i < (int)in_list.contour_size( 0 ); ++i ) {
|
||||||
|
p = cart_to_polar_2d( in_list.get_pt( 0, i ) );
|
||||||
|
out_list.add_node( 0, p );
|
||||||
|
}
|
||||||
|
|
||||||
|
return out_list;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// given a set of 2d coordinates relative to a center point, and the
|
||||||
|
// lon, lat of that center point (specified in degrees), as well as a
|
||||||
|
// potential orientation angle, generate the corresponding lon and lat
|
||||||
|
// of the original 2d verticies.
|
||||||
|
FGPolygon gen_area(Point3D origin, double angle, const FGPolygon& cart_list) {
|
||||||
|
FGPolygon rad_list;
|
||||||
|
FGPolygon result_list;
|
||||||
|
Point3D p;
|
||||||
|
|
||||||
|
// convert to polar coordinates
|
||||||
|
rad_list = batch_cart_to_polar_2d(cart_list);
|
||||||
|
|
||||||
|
// display points
|
||||||
|
// cout << "converted to polar" << endl;
|
||||||
|
// for ( int i = 0; i < rad_list.contour_size( 0 ); ++i ) {
|
||||||
|
// cout << " " << rad_list.get_pt(0, i) << endl;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// rotate by specified angle
|
||||||
|
// cout << "Rotating points by " << angle << endl;
|
||||||
|
for ( int i = 0; i < rad_list.contour_size( 0 ); ++i) {
|
||||||
|
p = rad_list.get_pt( 0, i );
|
||||||
|
double theta = p.y() - angle;
|
||||||
|
while ( theta < FG_2PI ) {
|
||||||
|
theta += FG_2PI;
|
||||||
|
}
|
||||||
|
p.sety( theta );
|
||||||
|
rad_list.set_pt( 0, i, p );
|
||||||
|
// cout << " " << p << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
// find actual lon,lat of coordinates
|
||||||
|
// cout << "convert to lon, lat relative to " << origin << endl;
|
||||||
|
for ( int i = 0; i < (int)rad_list.contour_size( 0 ); ++i ) {
|
||||||
|
// p = calc_lon_lat(origin_rad, rad_list.get_pt(0, i) );
|
||||||
|
|
||||||
|
double lat2, lon2, az2;
|
||||||
|
geo_direct_wgs_84 ( 0, origin.y(), origin.x(),
|
||||||
|
rad_list.get_pt(0, i).y() * RAD_TO_DEG,
|
||||||
|
rad_list.get_pt(0, i).x(),
|
||||||
|
&lat2, &lon2, &az2 );
|
||||||
|
|
||||||
|
// convert from radians to degress
|
||||||
|
p.setx( lon2 );
|
||||||
|
p.sety( lat2 );
|
||||||
|
// cout << " " << p << endl;
|
||||||
|
result_list.add_node( 0, p );
|
||||||
|
}
|
||||||
|
|
||||||
|
return result_list;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// generate an area for a runway
|
||||||
|
FGPolygon gen_runway_area( const FGRunway& runway,
|
||||||
|
double len_scale = 1.0,
|
||||||
|
double width_scale = 1.0 ) {
|
||||||
|
|
||||||
|
FGPolygon result_list;
|
||||||
|
FGPolygon tmp_list;
|
||||||
|
|
||||||
|
double l, w;
|
||||||
|
|
||||||
|
/*
|
||||||
|
printf("runway: lon = %.2f lat = %.2f hdg = %.2f len = %.2f width = %.2f\n",
|
||||||
|
lon, lat, heading, length, width);
|
||||||
|
*/
|
||||||
|
|
||||||
|
Point3D origin(runway.lon, runway.lat, 0);
|
||||||
|
l = runway.length * len_scale * FEET_TO_METER / 2.0;
|
||||||
|
w = runway.width * width_scale * FEET_TO_METER / 2.0;
|
||||||
|
|
||||||
|
// generate untransformed runway area vertices
|
||||||
|
tmp_list.add_node( 0, Point3D( l, w, 0 ) );
|
||||||
|
tmp_list.add_node( 0, Point3D( l, -w, 0 ) );
|
||||||
|
tmp_list.add_node( 0, Point3D( -l, -w, 0 ) );
|
||||||
|
tmp_list.add_node( 0, Point3D( -l, w, 0 ) );
|
||||||
|
|
||||||
|
// display points
|
||||||
|
// cout << "Untransformed, unrotated runway" << endl;
|
||||||
|
// for ( int i = 0; i < tmp_list.contour_size( 0 ); ++i ) {
|
||||||
|
// cout << " " << tmp_list.get_pt(0, i) << endl;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// rotate, transform, and convert points to lon, lat in degrees
|
||||||
|
result_list = gen_area(origin, runway.heading * DEG_TO_RAD, tmp_list);
|
||||||
|
|
||||||
|
// display points
|
||||||
|
// cout << "Results in radians." << endl;
|
||||||
|
// for ( int i = 0; i < result_list.contour_size( 0 ); ++i ) {
|
||||||
|
// cout << " " << result_list.get_pt(0, i) << endl;
|
||||||
|
// }
|
||||||
|
|
||||||
|
return result_list;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// generate an area for a runway and include midpoints
|
||||||
|
FGPolygon gen_runway_w_mid( const FGRunway& runway,
|
||||||
|
double len_scale = 1.0,
|
||||||
|
double width_scale = 1.0 ) {
|
||||||
|
FGPolygon result_list;
|
||||||
|
FGPolygon tmp_list;
|
||||||
|
|
||||||
|
double l, w;
|
||||||
|
|
||||||
|
/*
|
||||||
|
printf("runway: lon = %.2f lat = %.2f hdg = %.2f len = %.2f width = %.2f\n",
|
||||||
|
lon, lat, heading, length, width);
|
||||||
|
*/
|
||||||
|
|
||||||
|
Point3D origin(runway.lon, runway.lat, 0);
|
||||||
|
l = runway.length * len_scale * FEET_TO_METER / 2.0;
|
||||||
|
w = runway.width * width_scale * FEET_TO_METER / 2.0;
|
||||||
|
|
||||||
|
// generate untransformed runway area vertices
|
||||||
|
tmp_list.add_node( 0, Point3D( l, w, 0 ) );
|
||||||
|
tmp_list.add_node( 0, Point3D( l, -w, 0 ) );
|
||||||
|
tmp_list.add_node( 0, Point3D( 0, -w, 0 ) );
|
||||||
|
tmp_list.add_node( 0, Point3D( -l, -w, 0 ) );
|
||||||
|
tmp_list.add_node( 0, Point3D( -l, w, 0 ) );
|
||||||
|
tmp_list.add_node( 0, Point3D( 0, w, 0 ) );
|
||||||
|
|
||||||
|
// display points
|
||||||
|
// cout << "Untransformed, unrotated runway" << endl;
|
||||||
|
// for ( int i = 0; i < tmp_list.contour_size( 0 ); ++i ) {
|
||||||
|
// cout << " " << tmp_list.get_pt(0, i) << endl;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// rotate, transform, and convert points to lon, lat in degrees
|
||||||
|
result_list = gen_area(origin, runway.heading * DEG_TO_RAD, tmp_list);
|
||||||
|
|
||||||
|
// display points
|
||||||
|
// cout << "Results in radians." << endl;
|
||||||
|
// for ( int i = 0; i < result_list.contour_size( 0 ); ++i ) {
|
||||||
|
// cout << " " << result_list.get_pt(0, i) << endl;
|
||||||
|
// }
|
||||||
|
|
||||||
|
return result_list;
|
||||||
|
}
|
68
src/Airports/GenAirports/runway.hxx
Normal file
68
src/Airports/GenAirports/runway.hxx
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
// runway.hxx -- class to store runway info
|
||||||
|
//
|
||||||
|
// Written by Curtis Olson, started November 1999.
|
||||||
|
//
|
||||||
|
// Copyright (C) 1999 Curtis L. Olson - curt@flightgear.org
|
||||||
|
//
|
||||||
|
// This program is free software; you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation; either version 2 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
//
|
||||||
|
// $Id$
|
||||||
|
//
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef _RUNWAY_HXX
|
||||||
|
#define _RUNWAY_HXX
|
||||||
|
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include <simgear/point3d.hxx>
|
||||||
|
|
||||||
|
#include <Polygon/polygon.hxx>
|
||||||
|
|
||||||
|
|
||||||
|
struct FGRunway {
|
||||||
|
string rwy_no;
|
||||||
|
|
||||||
|
double lon;
|
||||||
|
double lat;
|
||||||
|
double heading;
|
||||||
|
double length;
|
||||||
|
double width;
|
||||||
|
|
||||||
|
string surface_flags;
|
||||||
|
string end1_flags;
|
||||||
|
string end2_flags;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
typedef vector < FGRunway > runway_list;
|
||||||
|
typedef runway_list::iterator runway_list_iterator;
|
||||||
|
typedef runway_list::const_iterator const_runway_list_iterator;
|
||||||
|
|
||||||
|
|
||||||
|
// generate an area for a runway (return result points in degrees)
|
||||||
|
FGPolygon gen_runway_area( const FGRunway& runway,
|
||||||
|
double len_scale = 1.0,
|
||||||
|
double width_scale = 1.0 );
|
||||||
|
|
||||||
|
// generate an area for half a runway
|
||||||
|
FGPolygon gen_runway_w_mid( const FGRunway& runway,
|
||||||
|
double len_scale = 1.0,
|
||||||
|
double width_scale = 1.0 );
|
||||||
|
|
||||||
|
|
||||||
|
#endif // _RUNWAY_HXX
|
17
src/BuildTiles/Clipper/Makefile.am
Normal file
17
src/BuildTiles/Clipper/Makefile.am
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
noinst_LIBRARIES = libClipper.a
|
||||||
|
|
||||||
|
libClipper_a_SOURCES = clipper.cxx clipper.hxx
|
||||||
|
|
||||||
|
noinst_PROGRAMS = testclipper
|
||||||
|
|
||||||
|
testclipper_SOURCES = testclipper.cxx
|
||||||
|
|
||||||
|
testclipper_LDADD = \
|
||||||
|
$(top_builddir)/Construct/Clipper/libClipper.a \
|
||||||
|
$(top_builddir)/Construct/Triangulate/libTriangulate.a \
|
||||||
|
$(top_builddir)/Lib/Polygon/libPolygon.a \
|
||||||
|
$(top_builddir)/Lib/poly2tri/libpoly2tri.a \
|
||||||
|
-lsgdebug -lsgmisc -lz -lgpc
|
||||||
|
|
||||||
|
INCLUDES += -I$(top_builddir) \
|
||||||
|
-I$(top_builddir)/Lib
|
440
src/BuildTiles/Clipper/clipper.cxx
Normal file
440
src/BuildTiles/Clipper/clipper.cxx
Normal file
|
@ -0,0 +1,440 @@
|
||||||
|
// clipper.cxx -- top level routines to take a series of arbitrary areas and
|
||||||
|
// produce a tight fitting puzzle pieces that combine to make a
|
||||||
|
// tile
|
||||||
|
//
|
||||||
|
// Written by Curtis Olson, started February 1999.
|
||||||
|
//
|
||||||
|
// Copyright (C) 1999 Curtis L. Olson - curt@flightgear.org
|
||||||
|
//
|
||||||
|
// This program is free software; you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation; either version 2 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
//
|
||||||
|
// $Id$
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#include <simgear/logstream.hxx>
|
||||||
|
#include <simgear/constants.h>
|
||||||
|
#include <simgear/fgstream.hxx>
|
||||||
|
|
||||||
|
#include <Polygon/names.hxx>
|
||||||
|
|
||||||
|
#include "clipper.hxx"
|
||||||
|
|
||||||
|
|
||||||
|
// Constructor
|
||||||
|
FGClipper::FGClipper( void ) {
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Destructor
|
||||||
|
FGClipper::~FGClipper( void ) {
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Initialize Clipper (allocate and/or connect structures)
|
||||||
|
bool FGClipper::init() {
|
||||||
|
// v_list.num_vertices = 0;
|
||||||
|
// v_list.vertex = new gpc_vertex[FG_MAX_VERTICES];;
|
||||||
|
|
||||||
|
for ( int i = 0; i < FG_MAX_AREA_TYPES; ++i ) {
|
||||||
|
polys_in.polys[i].clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Load a polygon definition file
|
||||||
|
bool FGClipper::load_polys(const string& path) {
|
||||||
|
string poly_name;
|
||||||
|
AreaType poly_type = DefaultArea;
|
||||||
|
int contours, count, i, j;
|
||||||
|
int hole_flag;
|
||||||
|
double startx, starty, x, y, lastx, lasty;
|
||||||
|
|
||||||
|
FG_LOG( FG_CLIPPER, FG_INFO, "Loading " << path << " ..." );
|
||||||
|
|
||||||
|
fg_gzifstream in( path );
|
||||||
|
|
||||||
|
if ( !in ) {
|
||||||
|
FG_LOG( FG_CLIPPER, FG_ALERT, "Cannot open file: " << path );
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// gpc_polygon *poly = new gpc_polygon;
|
||||||
|
// poly->num_contours = 0;
|
||||||
|
// poly->contour = NULL;
|
||||||
|
FGPolygon poly;
|
||||||
|
|
||||||
|
Point3D p;
|
||||||
|
in >> skipcomment;
|
||||||
|
while ( !in.eof() ) {
|
||||||
|
in >> poly_name;
|
||||||
|
cout << "poly name = " << poly_name << endl;
|
||||||
|
poly_type = get_area_type( poly_name );
|
||||||
|
cout << "poly type (int) = " << (int)poly_type << endl;
|
||||||
|
in >> contours;
|
||||||
|
cout << "num contours = " << contours << endl;
|
||||||
|
|
||||||
|
poly.erase();
|
||||||
|
|
||||||
|
for ( i = 0; i < contours; ++i ) {
|
||||||
|
in >> count;
|
||||||
|
|
||||||
|
if ( count < 3 ) {
|
||||||
|
FG_LOG( FG_CLIPPER, FG_ALERT,
|
||||||
|
"Polygon with less than 3 data points." );
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
in >> hole_flag;
|
||||||
|
|
||||||
|
in >> startx;
|
||||||
|
in >> starty;
|
||||||
|
p = Point3D(startx, starty, 0.0);
|
||||||
|
poly.add_node( i, p );
|
||||||
|
FG_LOG( FG_CLIPPER, FG_BULK, "0 = "
|
||||||
|
<< startx << ", " << starty );
|
||||||
|
|
||||||
|
for ( j = 1; j < count - 1; ++j ) {
|
||||||
|
in >> x;
|
||||||
|
in >> y;
|
||||||
|
p = Point3D( x, y, 0.0 );
|
||||||
|
poly.add_node( i, p );
|
||||||
|
FG_LOG( FG_CLIPPER, FG_BULK, j << " = " << x << ", " << y );
|
||||||
|
}
|
||||||
|
|
||||||
|
in >> lastx;
|
||||||
|
in >> lasty;
|
||||||
|
|
||||||
|
if ( (fabs(startx - lastx) < FG_EPSILON)
|
||||||
|
&& (fabs(starty - lasty) < FG_EPSILON) ) {
|
||||||
|
// last point same as first, discard
|
||||||
|
} else {
|
||||||
|
p = Point3D( lastx, lasty, 0.0 );
|
||||||
|
poly.add_node( i, p );
|
||||||
|
FG_LOG( FG_CLIPPER, FG_BULK, count - 1 << " = "
|
||||||
|
<< lastx << ", " << lasty );
|
||||||
|
}
|
||||||
|
|
||||||
|
// gpc_add_contour( poly, &v_list, hole_flag );
|
||||||
|
}
|
||||||
|
|
||||||
|
in >> skipcomment;
|
||||||
|
}
|
||||||
|
|
||||||
|
int area = (int)poly_type;
|
||||||
|
|
||||||
|
// if ( area == OceanArea ) {
|
||||||
|
// TEST - Ignore
|
||||||
|
// } else
|
||||||
|
|
||||||
|
if ( area < FG_MAX_AREA_TYPES ) {
|
||||||
|
polys_in.polys[area].push_back(poly);
|
||||||
|
} else {
|
||||||
|
FG_LOG( FG_CLIPPER, FG_ALERT, "Polygon type out of range = "
|
||||||
|
<< (int)poly_type);
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// FILE *ofp= fopen("outfile", "w");
|
||||||
|
// gpc_write_polygon(ofp, &polys.landuse);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// remove any slivers from in polygon and move them to out polygon.
|
||||||
|
void FGClipper::move_slivers( FGPolygon& in, FGPolygon& out ) {
|
||||||
|
cout << "Begin move slivers" << endl;
|
||||||
|
// traverse each contour of the polygon and attempt to identify
|
||||||
|
// likely slivers
|
||||||
|
|
||||||
|
out.erase();
|
||||||
|
|
||||||
|
double angle_cutoff = 10.0 * DEG_TO_RAD;
|
||||||
|
double area_cutoff = 0.000008;
|
||||||
|
double min_angle;
|
||||||
|
double area;
|
||||||
|
|
||||||
|
point_list contour;
|
||||||
|
int hole_flag;
|
||||||
|
|
||||||
|
// process contours in reverse order so deleting a contour doesn't
|
||||||
|
// foul up our sequence
|
||||||
|
for ( int i = in.contours() - 1; i >= 0; --i ) {
|
||||||
|
cout << "contour " << i << endl;
|
||||||
|
|
||||||
|
min_angle = in.minangle_contour( i );
|
||||||
|
area = in.area_contour( i );
|
||||||
|
|
||||||
|
cout << " min_angle (rad) = "
|
||||||
|
<< min_angle << endl;
|
||||||
|
cout << " min_angle (deg) = "
|
||||||
|
<< min_angle * 180.0 / FG_PI << endl;
|
||||||
|
cout << " area = " << area << endl;
|
||||||
|
|
||||||
|
if ( ((min_angle < angle_cutoff) && (area < area_cutoff)) ||
|
||||||
|
( area < area_cutoff / 10.0) )
|
||||||
|
{
|
||||||
|
cout << " WE THINK IT'S A SLIVER!" << endl;
|
||||||
|
|
||||||
|
// check if this is a hole
|
||||||
|
hole_flag = in.get_hole_flag( i );
|
||||||
|
|
||||||
|
if ( hole_flag ) {
|
||||||
|
// just delete/eliminate/remove sliver holes
|
||||||
|
cout << "just deleting a sliver hole" << endl;
|
||||||
|
in.delete_contour( i );
|
||||||
|
} else {
|
||||||
|
// move sliver contour to out polygon
|
||||||
|
contour = in.get_contour( i );
|
||||||
|
in.delete_contour( i );
|
||||||
|
out.add_contour( contour, hole_flag );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// for each sliver contour, see if a union with another polygon yields
|
||||||
|
// a polygon with no increased contours (i.e. the sliver is adjacent
|
||||||
|
// and can be merged.) If so, replace the clipped polygon with the
|
||||||
|
// new polygon that has the sliver merged in.
|
||||||
|
void FGClipper::merge_slivers( FGPolyList& clipped, FGPolygon& slivers ) {
|
||||||
|
FGPolygon poly, result, sliver;
|
||||||
|
point_list contour;
|
||||||
|
int original_contours, result_contours;
|
||||||
|
bool done;
|
||||||
|
|
||||||
|
for ( int i = 0; i < slivers.contours(); ++i ) {
|
||||||
|
cout << "Merging sliver = " << i << endl;
|
||||||
|
|
||||||
|
// make the sliver polygon
|
||||||
|
contour = slivers.get_contour( i );
|
||||||
|
sliver.erase();
|
||||||
|
sliver.add_contour( contour, 0 );
|
||||||
|
done = false;
|
||||||
|
|
||||||
|
for ( int area = 0; area < FG_MAX_AREA_TYPES && !done; ++area ) {
|
||||||
|
cout << " testing area = " << area << " with "
|
||||||
|
<< clipped.polys[area].size() << " polys" << endl;
|
||||||
|
for ( int j = 0;
|
||||||
|
j < (int)clipped.polys[area].size() && !done;
|
||||||
|
++j )
|
||||||
|
{
|
||||||
|
cout << " polygon = " << j << endl;
|
||||||
|
|
||||||
|
poly = clipped.polys[area][j];
|
||||||
|
original_contours = poly.contours();
|
||||||
|
result = polygon_union( poly, sliver );
|
||||||
|
result_contours = result.contours();
|
||||||
|
|
||||||
|
if ( original_contours == result_contours ) {
|
||||||
|
cout << " FOUND a poly to merge the sliver with" << endl;
|
||||||
|
clipped.polys[area][j] = result;
|
||||||
|
done = true;
|
||||||
|
// poly.write("orig");
|
||||||
|
// sliver.write("sliver");
|
||||||
|
// result.write("result");
|
||||||
|
// cout << "press return: ";
|
||||||
|
// string input;
|
||||||
|
// cin >> input;
|
||||||
|
} else {
|
||||||
|
cout << " poly not a match" << endl;
|
||||||
|
cout << " original = " << original_contours
|
||||||
|
<< " result = " << result_contours << endl;
|
||||||
|
cout << " sliver = " << endl;
|
||||||
|
for ( int k = 0; k < (int)contour.size(); ++k ) {
|
||||||
|
cout << " " << contour[k].x() << ", "
|
||||||
|
<< contour[k].y() << endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ( !done ) {
|
||||||
|
cout << "no suitable polys found for sliver merge" << endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Do actually clipping work
|
||||||
|
bool FGClipper::clip_all(const point2d& min, const point2d& max) {
|
||||||
|
FGPolygon accum, result_union, tmp;
|
||||||
|
FGPolygon result_diff, slivers, remains;
|
||||||
|
// gpcpoly_iterator current, last;
|
||||||
|
|
||||||
|
FG_LOG( FG_CLIPPER, FG_INFO, "Running master clipper" );
|
||||||
|
|
||||||
|
accum.erase();
|
||||||
|
|
||||||
|
cout << " (" << min.x << "," << min.y << ") ("
|
||||||
|
<< max.x << "," << max.y << ")" << endl;
|
||||||
|
|
||||||
|
// set up clipping tile
|
||||||
|
polys_in.safety_base.erase();
|
||||||
|
polys_in.safety_base.add_node( 0, Point3D(min.x, min.y, 0.0) );
|
||||||
|
polys_in.safety_base.add_node( 0, Point3D(max.x, min.y, 0.0) );
|
||||||
|
polys_in.safety_base.add_node( 0, Point3D(max.x, max.y, 0.0) );
|
||||||
|
polys_in.safety_base.add_node( 0, Point3D(min.x, max.y, 0.0) );
|
||||||
|
|
||||||
|
// int count = 0;
|
||||||
|
// process polygons in priority order
|
||||||
|
for ( int i = 0; i < FG_MAX_AREA_TYPES; ++i ) {
|
||||||
|
cout << "num polys of type (" << i << ") = "
|
||||||
|
<< polys_in.polys[i].size() << endl;
|
||||||
|
// current = polys_in.polys[i].begin();
|
||||||
|
// last = polys_in.polys[i].end();
|
||||||
|
// for ( ; current != last; ++current ) {
|
||||||
|
for( int j = 0; j < (int)polys_in.polys[i].size(); ++j ) {
|
||||||
|
FGPolygon current = polys_in.polys[i][j];
|
||||||
|
FG_LOG( FG_CLIPPER, FG_DEBUG, get_area_name( (AreaType)i )
|
||||||
|
<< " = " << current.contours() );
|
||||||
|
|
||||||
|
#ifdef EXTRA_SAFETY_CLIP
|
||||||
|
// clip to base tile
|
||||||
|
tmp = polygon_int( current, polys_in.safety_base );
|
||||||
|
#else
|
||||||
|
tmp = current;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// clip current polygon against previous higher priority
|
||||||
|
// stuff
|
||||||
|
|
||||||
|
// result_diff = new gpc_polygon;
|
||||||
|
// result_diff->num_contours = 0;
|
||||||
|
// result_diff->contour = NULL;
|
||||||
|
|
||||||
|
if ( accum.contours() == 0 ) {
|
||||||
|
result_diff = tmp;
|
||||||
|
result_union = tmp;
|
||||||
|
} else {
|
||||||
|
// cout << "DIFF: tmp.num_contours = " << tmp.num_contours
|
||||||
|
// << " accum.num_contours = " << accum.num_contours
|
||||||
|
// << endl;
|
||||||
|
// tmp output accum
|
||||||
|
|
||||||
|
// FILE *ofp= fopen("tmp-debug", "w");
|
||||||
|
// gpc_write_polygon(ofp, 1, &tmp);
|
||||||
|
// fclose(ofp);
|
||||||
|
|
||||||
|
// ofp= fopen("accum-debug", "w");
|
||||||
|
// gpc_write_polygon(ofp, 1, &accum);
|
||||||
|
// fclose(ofp);
|
||||||
|
|
||||||
|
result_diff = polygon_diff( tmp, accum);
|
||||||
|
result_union = polygon_union( tmp, accum);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
cout << "original contours = " << tmp.num_contours << endl;
|
||||||
|
|
||||||
|
for ( int j = 0; j < tmp.num_contours; j++ ) {
|
||||||
|
for (int k = 0;k < tmp.contour[j].num_vertices;k++ ) {
|
||||||
|
cout << tmp.contour[j].vertex[k].x << ","
|
||||||
|
<< tmp.contour[j].vertex[k].y << endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cout << "clipped contours = " << result_diff->num_contours << endl;
|
||||||
|
|
||||||
|
for ( int j = 0; j < result_diff->num_contours; j++ ) {
|
||||||
|
for (int k = 0;k < result_diff->contour[j].num_vertices;k++ ) {
|
||||||
|
cout << result_diff->contour[j].vertex[k].x << ","
|
||||||
|
<< result_diff->contour[j].vertex[k].y << endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
// only add to output list if the clip left us with a polygon
|
||||||
|
if ( result_diff.contours() > 0 ) {
|
||||||
|
// move slivers from result_diff polygon to slivers polygon
|
||||||
|
move_slivers(result_diff, slivers);
|
||||||
|
cout << " After sliver move:" << endl;
|
||||||
|
cout << " result_diff = " << result_diff.contours() << endl;
|
||||||
|
cout << " slivers = " << slivers.contours() << endl;
|
||||||
|
|
||||||
|
// merge any slivers with previously clipped
|
||||||
|
// neighboring polygons
|
||||||
|
if ( slivers.contours() > 0 ) {
|
||||||
|
merge_slivers(polys_clipped, slivers);
|
||||||
|
}
|
||||||
|
|
||||||
|
// add the sliverless result polygon (from after the
|
||||||
|
// move_slivers) to the clipped polys list
|
||||||
|
if ( result_diff.contours() > 0 ) {
|
||||||
|
polys_clipped.polys[i].push_back(result_diff);
|
||||||
|
}
|
||||||
|
|
||||||
|
// char filename[256];
|
||||||
|
// sprintf(filename, "next-result-%02d", count++);
|
||||||
|
// FILE *tmpfp= fopen(filename, "w");
|
||||||
|
// gpc_write_polygon(tmpfp, 1, result_diff);
|
||||||
|
// fclose(tmpfp);
|
||||||
|
}
|
||||||
|
accum = result_union;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// finally, what ever is left over goes to ocean
|
||||||
|
|
||||||
|
// clip to accum against original base tile
|
||||||
|
// remains = new gpc_polygon;
|
||||||
|
// remains->num_contours = 0;
|
||||||
|
// remains->contour = NULL;
|
||||||
|
remains = polygon_diff( polys_in.safety_base, accum );
|
||||||
|
|
||||||
|
if ( remains.contours() > 0 ) {
|
||||||
|
cout << "remains contours = " << remains.contours() << endl;
|
||||||
|
// move slivers from remains polygon to slivers polygon
|
||||||
|
move_slivers(remains, slivers);
|
||||||
|
cout << " After sliver move:" << endl;
|
||||||
|
cout << " remains = " << remains.contours() << endl;
|
||||||
|
cout << " slivers = " << slivers.contours() << endl;
|
||||||
|
|
||||||
|
// merge any slivers with previously clipped
|
||||||
|
// neighboring polygons
|
||||||
|
if ( slivers.contours() > 0 ) {
|
||||||
|
merge_slivers(polys_clipped, slivers);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( remains.contours() > 0 ) {
|
||||||
|
polys_clipped.polys[(int)OceanArea].push_back(remains);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
FILE *ofp;
|
||||||
|
|
||||||
|
// tmp output accum
|
||||||
|
if ( accum.num_contours ) {
|
||||||
|
ofp = fopen("accum", "w");
|
||||||
|
gpc_write_polygon(ofp, 1, &accum);
|
||||||
|
fclose(ofp);
|
||||||
|
}
|
||||||
|
|
||||||
|
// tmp output safety_base
|
||||||
|
if ( remains->num_contours ) {
|
||||||
|
ofp= fopen("remains", "w");
|
||||||
|
gpc_write_polygon(ofp, 1, remains);
|
||||||
|
fclose(ofp);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
107
src/BuildTiles/Clipper/clipper.hxx
Normal file
107
src/BuildTiles/Clipper/clipper.hxx
Normal file
|
@ -0,0 +1,107 @@
|
||||||
|
// clipper.hxx -- top level routines to take a series of arbitrary areas and
|
||||||
|
// produce a tight fitting puzzle pieces that combine to make a
|
||||||
|
// tile
|
||||||
|
//
|
||||||
|
// Written by Curtis Olson, started February 1999.
|
||||||
|
//
|
||||||
|
// Copyright (C) 1999 Curtis L. Olson - curt@flightgear.org
|
||||||
|
//
|
||||||
|
// This program is free software; you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation; either version 2 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
//
|
||||||
|
// $Id$
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef _CLIPPER_HXX
|
||||||
|
#define _CLIPPER_HXX
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef __cplusplus
|
||||||
|
# error This library requires C++
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#include <simgear/compiler.h>
|
||||||
|
#include <simgear/fg_types.hxx>
|
||||||
|
|
||||||
|
#include <Polygon/polygon.hxx>
|
||||||
|
|
||||||
|
#include STL_STRING
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
FG_USING_STD(string);
|
||||||
|
FG_USING_STD(vector);
|
||||||
|
|
||||||
|
|
||||||
|
// typedef vector < gpc_polygon * > gpcpoly_container;
|
||||||
|
// typedef gpcpoly_container::iterator gpcpoly_iterator;
|
||||||
|
// typedef gpcpoly_container::const_iterator const_gpcpoly_iterator;
|
||||||
|
|
||||||
|
|
||||||
|
#define FG_MAX_AREA_TYPES 20
|
||||||
|
#define EXTRA_SAFETY_CLIP
|
||||||
|
// #define FG_MAX_VERTICES 100000
|
||||||
|
|
||||||
|
|
||||||
|
class FGPolyList {
|
||||||
|
public:
|
||||||
|
poly_list polys[FG_MAX_AREA_TYPES];
|
||||||
|
FGPolygon safety_base;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class FGClipper {
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
// gpc_vertex_list v_list;
|
||||||
|
// static gpc_polygon poly;
|
||||||
|
FGPolyList polys_in, polys_clipped;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
// Constructor
|
||||||
|
FGClipper( void );
|
||||||
|
|
||||||
|
// Destructor
|
||||||
|
~FGClipper( void );
|
||||||
|
|
||||||
|
// Initialize Clipper (allocate and/or connect structures)
|
||||||
|
bool init();
|
||||||
|
|
||||||
|
// Load a polygon definition file
|
||||||
|
bool load_polys(const string& path);
|
||||||
|
|
||||||
|
// remove any slivers from in polygon and move them to out
|
||||||
|
// polygon.
|
||||||
|
void move_slivers( FGPolygon& in, FGPolygon& out );
|
||||||
|
|
||||||
|
// for each sliver contour, see if a union with another polygon
|
||||||
|
// yields a polygon with no increased contours (i.e. the sliver is
|
||||||
|
// adjacent and can be merged.) If so, replace the clipped
|
||||||
|
// polygon with the new polygon that has the sliver merged in.
|
||||||
|
void merge_slivers( FGPolyList& clipped, FGPolygon& slivers );
|
||||||
|
|
||||||
|
// Do actually clipping work
|
||||||
|
bool clip_all(const point2d& min, const point2d& max);
|
||||||
|
|
||||||
|
// return output poly list
|
||||||
|
inline FGPolyList get_polys_clipped() const { return polys_clipped; }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // _CLIPPER_HXX
|
||||||
|
|
||||||
|
|
110
src/BuildTiles/Clipper/testclipper.cxx
Normal file
110
src/BuildTiles/Clipper/testclipper.cxx
Normal file
|
@ -0,0 +1,110 @@
|
||||||
|
// main.cxx -- sample use of the clipper lib
|
||||||
|
//
|
||||||
|
// Written by Curtis Olson, started February 1999.
|
||||||
|
//
|
||||||
|
// Copyright (C) 1999 Curtis L. Olson - curt@flightgear.org
|
||||||
|
//
|
||||||
|
// This program is free software; you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation; either version 2 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
//
|
||||||
|
// $Id$
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#include <simgear/logstream.hxx>
|
||||||
|
#include <simgear/newbucket.hxx>
|
||||||
|
|
||||||
|
#include "clipper.hxx"
|
||||||
|
|
||||||
|
|
||||||
|
int main( int argc, char **argv ) {
|
||||||
|
point2d global_min, global_max;
|
||||||
|
|
||||||
|
fglog().setLogLevels( FG_ALL, FG_DEBUG );
|
||||||
|
|
||||||
|
global_min.x = global_min.y = 200;
|
||||||
|
global_max.y = global_max.x = -200;
|
||||||
|
|
||||||
|
FGClipper clipper;
|
||||||
|
clipper.init();
|
||||||
|
|
||||||
|
if ( argc < 2 ) {
|
||||||
|
FG_LOG( FG_CLIPPER, FG_ALERT, "Usage: " << argv[0]
|
||||||
|
<< " file1 file2 ..." );
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// process all specified polygon files
|
||||||
|
for ( int i = 1; i < argc; i++ ) {
|
||||||
|
string full_path = argv[i];
|
||||||
|
|
||||||
|
// determine bucket for this polygon
|
||||||
|
int pos = full_path.rfind("/");
|
||||||
|
string file_name = full_path.substr(pos + 1);
|
||||||
|
cout << "file name = " << file_name << endl;
|
||||||
|
|
||||||
|
pos = file_name.find(".");
|
||||||
|
string base_name = file_name.substr(0, pos);
|
||||||
|
cout << "base_name = " << base_name << endl;
|
||||||
|
|
||||||
|
long int index;
|
||||||
|
sscanf( base_name.c_str(), "%ld", &index);
|
||||||
|
FGBucket b(index);
|
||||||
|
cout << "bucket = " << b << endl;
|
||||||
|
|
||||||
|
// calculate bucket dimensions
|
||||||
|
point2d c, min, max;
|
||||||
|
|
||||||
|
c.x = b.get_center_lon();
|
||||||
|
c.y = b.get_center_lat();
|
||||||
|
double span = bucket_span(c.y);
|
||||||
|
|
||||||
|
if ( (c.y >= -89.0) && (c.y < 89.0) ) {
|
||||||
|
min.x = c.x - span / 2.0;
|
||||||
|
max.x = c.x + span / 2.0;
|
||||||
|
min.y = c.y - FG_HALF_BUCKET_SPAN;
|
||||||
|
max.y = c.y + FG_HALF_BUCKET_SPAN;
|
||||||
|
} else if ( c.y < -89.0) {
|
||||||
|
min.x = -90.0;
|
||||||
|
max.x = -89.0;
|
||||||
|
min.y = -180.0;
|
||||||
|
max.y = 180.0;
|
||||||
|
} else if ( c.y >= 89.0) {
|
||||||
|
min.x = 89.0;
|
||||||
|
max.x = 90.0;
|
||||||
|
min.y = -180.0;
|
||||||
|
max.y = 180.0;
|
||||||
|
} else {
|
||||||
|
FG_LOG ( FG_GENERAL, FG_ALERT,
|
||||||
|
"Out of range latitude in clip_and_write_poly() = "
|
||||||
|
<< c.y );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( min.x < global_min.x ) global_min.x = min.x;
|
||||||
|
if ( min.y < global_min.y ) global_min.y = min.y;
|
||||||
|
if ( max.x > global_max.x ) global_max.x = max.x;
|
||||||
|
if ( max.y > global_max.y ) global_max.y = max.y;
|
||||||
|
|
||||||
|
// finally, load the polygon(s) from this file
|
||||||
|
clipper.load_polys( full_path );
|
||||||
|
}
|
||||||
|
|
||||||
|
// do the clipping
|
||||||
|
clipper.clip_all(global_min, global_max);
|
||||||
|
|
||||||
|
FG_LOG( FG_CLIPPER, FG_INFO, "finished main" );
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
8
src/BuildTiles/GenOutput/Makefile.am
Normal file
8
src/BuildTiles/GenOutput/Makefile.am
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
noinst_LIBRARIES = libGenOutput.a
|
||||||
|
|
||||||
|
libGenOutput_a_SOURCES = genobj.cxx genobj.hxx
|
||||||
|
|
||||||
|
INCLUDES += \
|
||||||
|
-I$(top_builddir) \
|
||||||
|
-I$(top_builddir)/Lib \
|
||||||
|
-I$(top_builddir)/Construct
|
410
src/BuildTiles/GenOutput/genobj.cxx
Normal file
410
src/BuildTiles/GenOutput/genobj.cxx
Normal file
|
@ -0,0 +1,410 @@
|
||||||
|
// genobj.hxx -- Generate the flight gear "obj" file format from the
|
||||||
|
// triangle output
|
||||||
|
//
|
||||||
|
// Written by Curtis Olson, started March 1999.
|
||||||
|
//
|
||||||
|
// Copyright (C) 1999 Curtis L. Olson - curt@flightgear.org
|
||||||
|
//
|
||||||
|
// This program is free software; you can redistribute it and/or
|
||||||
|
// modify it under the terms of the GNU General Public License as
|
||||||
|
// published by the Free Software Foundation; either version 2 of the
|
||||||
|
// License, or (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful, but
|
||||||
|
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
// General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
//
|
||||||
|
// $Id$
|
||||||
|
|
||||||
|
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
#include <simgear/texcoord.hxx>
|
||||||
|
|
||||||
|
#include <Polygon/names.hxx>
|
||||||
|
#include "scenery_version.hxx"
|
||||||
|
|
||||||
|
#include "genobj.hxx"
|
||||||
|
|
||||||
|
|
||||||
|
// calculate the global bounding sphere. Center is the center of the
|
||||||
|
// tile and zero elevation
|
||||||
|
void FGGenOutput::calc_gbs( FGConstruct& c ) {
|
||||||
|
double dist_squared;
|
||||||
|
double radius_squared = 0;
|
||||||
|
|
||||||
|
FGBucket b = c.get_bucket();
|
||||||
|
|
||||||
|
Point3D p( b.get_center_lon() * DEG_TO_RAD,
|
||||||
|
b.get_center_lat() * DEG_TO_RAD,
|
||||||
|
0 );
|
||||||
|
|
||||||
|
gbs_center = fgGeodToCart(p);
|
||||||
|
|
||||||
|
point_list wgs84_nodes = c.get_wgs84_nodes();
|
||||||
|
const_point_list_iterator current = wgs84_nodes.begin();
|
||||||
|
const_point_list_iterator last = wgs84_nodes.end();
|
||||||
|
for ( ; current != last; ++current ) {
|
||||||
|
dist_squared = gbs_center.distance3Dsquared(*current);
|
||||||
|
if ( dist_squared > radius_squared ) {
|
||||||
|
radius_squared = dist_squared;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
gbs_radius = sqrt(radius_squared);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
#define FG_STANDARD_TEXTURE_DIMENSION 1000.0 // meters
|
||||||
|
|
||||||
|
// traverse the specified fan and attempt to calculate "none
|
||||||
|
// stretching" texture coordinates
|
||||||
|
int_list FGGenOutput::calc_tex_coords( FGConstruct& c, point_list geod_nodes,
|
||||||
|
int_list fan )
|
||||||
|
{
|
||||||
|
// cout << "calculating texture coordinates for a specific fan of size = "
|
||||||
|
// << fan.size() << endl;
|
||||||
|
|
||||||
|
FGBucket b = c.get_bucket();
|
||||||
|
double clat = b.get_center_lat();
|
||||||
|
double clat_rad = clat * DEG_TO_RAD;
|
||||||
|
double cos_lat = cos( clat_rad );
|
||||||
|
double local_radius = cos_lat * EQUATORIAL_RADIUS_M;
|
||||||
|
double local_perimeter = 2.0 * local_radius * FG_PI;
|
||||||
|
double degree_width = local_perimeter / 360.0;
|
||||||
|
|
||||||
|
// cout << "clat = " << clat << endl;
|
||||||
|
// cout << "clat (radians) = " << clat_rad << endl;
|
||||||
|
// cout << "cos(lat) = " << cos_lat << endl;
|
||||||
|
// cout << "local_radius = " << local_radius << endl;
|
||||||
|
// cout << "local_perimeter = " << local_perimeter << endl;
|
||||||
|
// cout << "degree_width = " << degree_width << endl;
|
||||||
|
|
||||||
|
double perimeter = 2.0 * EQUATORIAL_RADIUS_M * FG_PI;
|
||||||
|
double degree_height = perimeter / 360.0;
|
||||||
|
// cout << "degree_height = " << degree_height << endl;
|
||||||
|
|
||||||
|
// find min/max of fan
|
||||||
|
Point3D min, max, p, t;
|
||||||
|
bool first = true;
|
||||||
|
|
||||||
|
for ( int i = 0; i < (int)fan.size(); ++i ) {
|
||||||
|
p = geod_nodes[ fan[i] ];
|
||||||
|
t.setx( p.x() * ( degree_width / FG_STANDARD_TEXTURE_DIMENSION ) );
|
||||||
|
t.sety( p.y() * ( degree_height / FG_STANDARD_TEXTURE_DIMENSION ) );
|
||||||
|
|
||||||
|
if ( first ) {
|
||||||
|
min = max = t;
|
||||||
|
first = false;
|
||||||
|
} else {
|
||||||
|
if ( t.x() < min.x() ) {
|
||||||
|
min.setx( t.x() );
|
||||||
|
}
|
||||||
|
if ( t.y() < min.y() ) {
|
||||||
|
min.sety( t.y() );
|
||||||
|
}
|
||||||
|
if ( t.x() > max.x() ) {
|
||||||
|
max.setx( t.x() );
|
||||||
|
}
|
||||||
|
if ( t.y() > max.y() ) {
|
||||||
|
max.sety( t.y() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
min.setx( (double)( (int)min.x() - 1 ) );
|
||||||
|
min.sety( (double)( (int)min.y() - 1 ) );
|
||||||
|
// cout << "found min = " << min << endl;
|
||||||
|
|
||||||
|
// generate tex_list
|
||||||
|
Point3D shifted_t;
|
||||||
|
int index;
|
||||||
|
int_list tex;
|
||||||
|
tex.clear();
|
||||||
|
for ( int i = 0; i < (int)fan.size(); ++i ) {
|
||||||
|
p = geod_nodes[ fan[i] ];
|
||||||
|
t.setx( p.x() * ( degree_width / FG_STANDARD_TEXTURE_DIMENSION ) );
|
||||||
|
t.sety( p.y() * ( degree_height / FG_STANDARD_TEXTURE_DIMENSION ) );
|
||||||
|
shifted_t = t - min;
|
||||||
|
if ( shifted_t.x() < FG_EPSILON ) {
|
||||||
|
shifted_t.setx( 0.0 );
|
||||||
|
}
|
||||||
|
if ( shifted_t.y() < FG_EPSILON ) {
|
||||||
|
shifted_t.sety( 0.0 );
|
||||||
|
}
|
||||||
|
shifted_t.setz( 0.0 );
|
||||||
|
// cout << "shifted_t = " << shifted_t << endl;
|
||||||
|
index = tex_coords.unique_add( shifted_t );
|
||||||
|
tex.push_back( index );
|
||||||
|
}
|
||||||
|
|
||||||
|
return tex;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
// build the necessary output structures based on the triangulation
|
||||||
|
// data
|
||||||
|
int FGGenOutput::build( FGConstruct& c ) {
|
||||||
|
FGTriNodes trinodes = c.get_tri_nodes();
|
||||||
|
|
||||||
|
// copy the geodetic node list into this class
|
||||||
|
geod_nodes = trinodes.get_node_list();
|
||||||
|
|
||||||
|
// copy the triangle list into this class
|
||||||
|
tri_elements = c.get_tri_elements();
|
||||||
|
|
||||||
|
// build the trifan list
|
||||||
|
cout << "total triangles = " << tri_elements.size() << endl;
|
||||||
|
FGGenFans f;
|
||||||
|
for ( int i = 0; i < FG_MAX_AREA_TYPES; ++i ) {
|
||||||
|
triele_list area_tris;
|
||||||
|
area_tris.erase( area_tris.begin(), area_tris.end() );
|
||||||
|
|
||||||
|
const_triele_list_iterator t_current = tri_elements.begin();
|
||||||
|
const_triele_list_iterator t_last = tri_elements.end();
|
||||||
|
for ( ; t_current != t_last; ++t_current ) {
|
||||||
|
if ( (int)t_current->get_attribute() == i ) {
|
||||||
|
area_tris.push_back( *t_current );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( (int)area_tris.size() > 0 ) {
|
||||||
|
cout << "generating fans for area = " << i << endl;
|
||||||
|
fans[i] = f.greedy_build( area_tris );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// build the texture coordinate list and make a parallel structure
|
||||||
|
// to the fan list for pointers into the texture list
|
||||||
|
cout << "calculating texture coordinates" << endl;
|
||||||
|
tex_coords.clear();
|
||||||
|
|
||||||
|
for ( int i = 0; i < FG_MAX_AREA_TYPES; ++i ) {
|
||||||
|
for ( int j = 0; j < (int)fans[i].size(); ++j ) {
|
||||||
|
// int_list t_list = calc_tex_coords( c, geod_nodes, fans[i][j] );
|
||||||
|
// cout << fans[i][j].size() << " === "
|
||||||
|
// << t_list.size() << endl;
|
||||||
|
point_list tp_list = calc_tex_coords( c.get_bucket(),
|
||||||
|
geod_nodes, fans[i][j] );
|
||||||
|
int_list ti_list;
|
||||||
|
ti_list.clear();
|
||||||
|
for ( int k = 0; k < (int)tp_list.size(); ++k ) {
|
||||||
|
int index = tex_coords.simple_add( tp_list[k] );
|
||||||
|
ti_list.push_back( index );
|
||||||
|
}
|
||||||
|
textures[i].push_back( ti_list );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// calculate the global bounding sphere
|
||||||
|
calc_gbs( c );
|
||||||
|
cout << "center = " << gbs_center << " radius = " << gbs_radius << endl;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// caclulate the bounding sphere for a list of triangle faces
|
||||||
|
void FGGenOutput::calc_group_bounding_sphere( FGConstruct& c,
|
||||||
|
const fan_list& fans,
|
||||||
|
Point3D *center, double *radius )
|
||||||
|
{
|
||||||
|
cout << "calculate group bounding sphere for " << fans.size() << " fans."
|
||||||
|
<< endl;
|
||||||
|
|
||||||
|
point_list wgs84_nodes = c.get_wgs84_nodes();
|
||||||
|
|
||||||
|
// generate a list of unique points from the triangle list
|
||||||
|
FGTriNodes nodes;
|
||||||
|
|
||||||
|
const_fan_list_iterator f_current = fans.begin();
|
||||||
|
const_fan_list_iterator f_last = fans.end();
|
||||||
|
for ( ; f_current != f_last; ++f_current ) {
|
||||||
|
const_int_list_iterator i_current = f_current->begin();
|
||||||
|
const_int_list_iterator i_last = f_current->end();
|
||||||
|
for ( ; i_current != i_last; ++i_current ) {
|
||||||
|
Point3D p1 = wgs84_nodes[ *i_current ];
|
||||||
|
nodes.unique_add(p1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// find average of point list
|
||||||
|
*center = Point3D( 0.0 );
|
||||||
|
point_list points = nodes.get_node_list();
|
||||||
|
// cout << "found " << points.size() << " unique nodes" << endl;
|
||||||
|
point_list_iterator p_current = points.begin();
|
||||||
|
point_list_iterator p_last = points.end();
|
||||||
|
for ( ; p_current != p_last; ++p_current ) {
|
||||||
|
*center += *p_current;
|
||||||
|
}
|
||||||
|
*center /= points.size();
|
||||||
|
|
||||||
|
// find max radius
|
||||||
|
double dist_squared;
|
||||||
|
double max_squared = 0;
|
||||||
|
|
||||||
|
p_current = points.begin();
|
||||||
|
p_last = points.end();
|
||||||
|
for ( ; p_current != p_last; ++p_current ) {
|
||||||
|
dist_squared = (*center).distance3Dsquared(*p_current);
|
||||||
|
if ( dist_squared > max_squared ) {
|
||||||
|
max_squared = dist_squared;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*radius = sqrt(max_squared);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// caclulate the bounding sphere for the specified triangle face
|
||||||
|
void FGGenOutput::calc_bounding_sphere( FGConstruct& c, const FGTriEle& t,
|
||||||
|
Point3D *center, double *radius )
|
||||||
|
{
|
||||||
|
point_list wgs84_nodes = c.get_wgs84_nodes();
|
||||||
|
|
||||||
|
*center = Point3D( 0.0 );
|
||||||
|
|
||||||
|
Point3D p1 = wgs84_nodes[ t.get_n1() ];
|
||||||
|
Point3D p2 = wgs84_nodes[ t.get_n2() ];
|
||||||
|
Point3D p3 = wgs84_nodes[ t.get_n3() ];
|
||||||
|
|
||||||
|
*center = p1 + p2 + p3;
|
||||||
|
*center /= 3;
|
||||||
|
|
||||||
|
double dist_squared;
|
||||||
|
double max_squared = 0;
|
||||||
|
|
||||||
|
dist_squared = (*center).distance3Dsquared(p1);
|
||||||
|
if ( dist_squared > max_squared ) {
|
||||||
|
max_squared = dist_squared;
|
||||||
|
}
|
||||||
|
|
||||||
|
dist_squared = (*center).distance3Dsquared(p2);
|
||||||
|
if ( dist_squared > max_squared ) {
|
||||||
|
max_squared = dist_squared;
|
||||||
|
}
|
||||||
|
|
||||||
|
dist_squared = (*center).distance3Dsquared(p3);
|
||||||
|
if ( dist_squared > max_squared ) {
|
||||||
|
max_squared = dist_squared;
|
||||||
|
}
|
||||||
|
|
||||||
|
*radius = sqrt(max_squared);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// write out the fgfs scenery file
|
||||||
|
int FGGenOutput::write( FGConstruct &c ) {
|
||||||
|
Point3D p;
|
||||||
|
|
||||||
|
string base = c.get_output_base();
|
||||||
|
FGBucket b = c.get_bucket();
|
||||||
|
|
||||||
|
string dir = base + "/Scenery/" + b.gen_base_path();
|
||||||
|
string command = "mkdir -p " + dir;
|
||||||
|
system(command.c_str());
|
||||||
|
|
||||||
|
string file = dir + "/" + b.gen_index_str();
|
||||||
|
cout << "Output file = " << file << endl;
|
||||||
|
|
||||||
|
FILE *fp;
|
||||||
|
if ( (fp = fopen( file.c_str(), "w" )) == NULL ) {
|
||||||
|
cout << "ERROR: opening " << file << " for writing!" << endl;
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// write headers
|
||||||
|
fprintf(fp, "# FGFS Scenery\n");
|
||||||
|
fprintf(fp, "# Version %s\n", FG_SCENERY_FILE_FORMAT);
|
||||||
|
|
||||||
|
time_t calendar_time = time(NULL);
|
||||||
|
struct tm *local_tm;
|
||||||
|
local_tm = localtime( &calendar_time );
|
||||||
|
char time_str[256];
|
||||||
|
strftime( time_str, 256, "%a %b %d %H:%M:%S %Z %Y", local_tm);
|
||||||
|
fprintf(fp, "# Created %s\n", time_str );
|
||||||
|
fprintf(fp, "\n");
|
||||||
|
|
||||||
|
// write global bounding sphere
|
||||||
|
fprintf(fp, "# gbs %.5f %.5f %.5f %.2f\n",
|
||||||
|
gbs_center.x(), gbs_center.y(), gbs_center.z(), gbs_radius);
|
||||||
|
fprintf(fp, "\n");
|
||||||
|
|
||||||
|
// write nodes
|
||||||
|
point_list wgs84_nodes = c.get_wgs84_nodes();
|
||||||
|
fprintf(fp, "# vertex list\n");
|
||||||
|
const_point_list_iterator w_current = wgs84_nodes.begin();
|
||||||
|
const_point_list_iterator w_last = wgs84_nodes.end();
|
||||||
|
for ( ; w_current != w_last; ++w_current ) {
|
||||||
|
p = *w_current - gbs_center;
|
||||||
|
fprintf(fp, "v %.5f %.5f %.5f\n", p.x(), p.y(), p.z());
|
||||||
|
}
|
||||||
|
fprintf(fp, "\n");
|
||||||
|
|
||||||
|
// write vertex normals
|
||||||
|
point_list point_normals = c.get_point_normals();
|
||||||
|
fprintf(fp, "# vertex normal list\n");
|
||||||
|
const_point_list_iterator n_current = point_normals.begin();
|
||||||
|
const_point_list_iterator n_last = point_normals.end();
|
||||||
|
for ( ; n_current != n_last; ++n_current ) {
|
||||||
|
p = *n_current;
|
||||||
|
fprintf(fp, "vn %.5f %.5f %.5f\n", p.x(), p.y(), p.z());
|
||||||
|
}
|
||||||
|
fprintf(fp, "\n");
|
||||||
|
|
||||||
|
// write texture coordinates
|
||||||
|
point_list tex_coord_list = tex_coords.get_node_list();
|
||||||
|
fprintf(fp, "# texture coordinate list\n");
|
||||||
|
for ( int i = 0; i < (int)tex_coord_list.size(); ++i ) {
|
||||||
|
p = tex_coord_list[i];
|
||||||
|
fprintf(fp, "vt %.5f %.5f\n", p.x(), p.y());
|
||||||
|
}
|
||||||
|
fprintf(fp, "\n");
|
||||||
|
|
||||||
|
// write triangles (grouped by type for now)
|
||||||
|
Point3D center;
|
||||||
|
double radius;
|
||||||
|
fprintf(fp, "# triangle groups\n");
|
||||||
|
fprintf(fp, "\n");
|
||||||
|
|
||||||
|
int total_tris = 0;
|
||||||
|
for ( int i = 0; i < FG_MAX_AREA_TYPES; ++i ) {
|
||||||
|
if ( (int)fans[i].size() > 0 ) {
|
||||||
|
string attr_name = get_area_name( (AreaType)i );
|
||||||
|
calc_group_bounding_sphere( c, fans[i], ¢er, &radius );
|
||||||
|
cout << "writing " << (int)fans[i].size() << " fans for "
|
||||||
|
<< attr_name << endl;
|
||||||
|
|
||||||
|
fprintf(fp, "# usemtl %s\n", attr_name.c_str() );
|
||||||
|
fprintf(fp, "# bs %.4f %.4f %.4f %.2f\n",
|
||||||
|
center.x(), center.y(), center.z(), radius);
|
||||||
|
|
||||||
|
for ( int j = 0; j < (int)fans[i].size(); ++j ) {
|
||||||
|
fprintf( fp, "tf" );
|
||||||
|
total_tris += fans[i][j].size() - 2;
|
||||||
|
for ( int k = 0; k < (int)fans[i][j].size(); ++k ) {
|
||||||
|
fprintf( fp, " %d/%d", fans[i][j][k], textures[i][j][k] );
|
||||||
|
}
|
||||||
|
fprintf( fp, "\n" );
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf( fp, "\n" );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cout << "wrote " << total_tris << " tris to output file" << endl;
|
||||||
|
|
||||||
|
fclose(fp);
|
||||||
|
|
||||||
|
command = "gzip --force --best " + file;
|
||||||
|
system(command.c_str());
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
111
src/BuildTiles/GenOutput/genobj.hxx
Normal file
111
src/BuildTiles/GenOutput/genobj.hxx
Normal file
|
@ -0,0 +1,111 @@
|
||||||
|
// genobj.hxx -- Generate the flight gear "obj" file format from the
|
||||||
|
// triangle output
|
||||||
|
//
|
||||||
|
// Written by Curtis Olson, started March 1999.
|
||||||
|
//
|
||||||
|
// Copyright (C) 1999 Curtis L. Olson - curt@flightgear.org
|
||||||
|
//
|
||||||
|
// This program is free software; you can redistribute it and/or
|
||||||
|
// modify it under the terms of the GNU General Public License as
|
||||||
|
// published by the Free Software Foundation; either version 2 of the
|
||||||
|
// License, or (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful, but
|
||||||
|
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
// General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
//
|
||||||
|
// $Id$
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef _GENOBJ_HXX
|
||||||
|
#define _GENOBJ_HXX
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef __cplusplus
|
||||||
|
# error This library requires C++
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#include <simgear/compiler.h>
|
||||||
|
|
||||||
|
#include STL_STRING
|
||||||
|
|
||||||
|
#include <simgear/fg_types.hxx>
|
||||||
|
#include <simgear/newbucket.hxx>
|
||||||
|
#include <simgear/fg_geodesy.hxx>
|
||||||
|
#include <simgear/point3d.hxx>
|
||||||
|
|
||||||
|
#include <Combine/genfans.hxx>
|
||||||
|
#include <Main/construct.hxx>
|
||||||
|
#include <Triangulate/triangle.hxx>
|
||||||
|
|
||||||
|
FG_USING_STD(string);
|
||||||
|
FG_USING_STD(vector);
|
||||||
|
|
||||||
|
|
||||||
|
typedef vector < int_list > tex_list;
|
||||||
|
typedef tex_list::iterator tex_list_iterator;
|
||||||
|
typedef tex_list::const_iterator const_tex_list_iterator;
|
||||||
|
|
||||||
|
class FGGenOutput {
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
// node list in geodetic coordinates
|
||||||
|
point_list geod_nodes;
|
||||||
|
|
||||||
|
// triangles (by index into point list)
|
||||||
|
triele_list tri_elements;
|
||||||
|
|
||||||
|
// texture coordinates
|
||||||
|
FGTriNodes tex_coords;
|
||||||
|
|
||||||
|
// fan list
|
||||||
|
fan_list fans[FG_MAX_AREA_TYPES];
|
||||||
|
|
||||||
|
// textures pointer list
|
||||||
|
tex_list textures[FG_MAX_AREA_TYPES];
|
||||||
|
|
||||||
|
// global bounding sphere
|
||||||
|
Point3D gbs_center;
|
||||||
|
double gbs_radius;
|
||||||
|
|
||||||
|
// calculate the global bounding sphere. Center is the average of
|
||||||
|
// the points.
|
||||||
|
void calc_gbs( FGConstruct& c );
|
||||||
|
|
||||||
|
// caclulate the bounding sphere for a list of triangle faces
|
||||||
|
void calc_group_bounding_sphere( FGConstruct& c, const fan_list& fans,
|
||||||
|
Point3D *center, double *radius );
|
||||||
|
|
||||||
|
// caclulate the bounding sphere for the specified triangle face
|
||||||
|
void calc_bounding_sphere( FGConstruct& c, const FGTriEle& t,
|
||||||
|
Point3D *center, double *radius );
|
||||||
|
|
||||||
|
// traverse the specified fan and attempt to calculate "none
|
||||||
|
// stretching" texture coordinates
|
||||||
|
// int_list calc_tex_coords( FGConstruct& c, point_list geod_nodes, int_list fan );
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
// Constructor && Destructor
|
||||||
|
inline FGGenOutput() { }
|
||||||
|
inline ~FGGenOutput() { }
|
||||||
|
|
||||||
|
// build the necessary output structures based on the
|
||||||
|
// triangulation data
|
||||||
|
int build( FGConstruct& c );
|
||||||
|
|
||||||
|
// write out the fgfs scenery file
|
||||||
|
int write( FGConstruct &c );
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // _GENOBJ_HXX
|
||||||
|
|
||||||
|
|
27
src/BuildTiles/Main/Makefile.am
Normal file
27
src/BuildTiles/Main/Makefile.am
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
bin_PROGRAMS = fgfs-construct fgfs-master
|
||||||
|
|
||||||
|
fgfs_construct_SOURCES = \
|
||||||
|
construct.cxx construct.hxx \
|
||||||
|
main.cxx
|
||||||
|
|
||||||
|
fgfs_construct_LDADD = \
|
||||||
|
$(top_builddir)/Construct/Clipper/libClipper.a \
|
||||||
|
$(top_builddir)/Construct/GenOutput/libGenOutput.a \
|
||||||
|
$(top_builddir)/Construct/Combine/libCombine.a \
|
||||||
|
$(top_builddir)/Construct/Match/libMatch.a \
|
||||||
|
$(top_builddir)/Construct/Triangulate/libTriangulate.a \
|
||||||
|
$(top_builddir)/Lib/Array/libArray.a \
|
||||||
|
$(top_builddir)/Lib/Build/libBuild.a \
|
||||||
|
$(top_builddir)/Lib/Polygon/libPolygon.a \
|
||||||
|
$(top_builddir)/Lib/poly2tri/libpoly2tri.a \
|
||||||
|
$(top_builddir)/Lib/Triangle/libTriangle.a \
|
||||||
|
-lsgbucket -lsgmath -lsgmisc -lsgdebug -lz -lgpc
|
||||||
|
|
||||||
|
fgfs_master_SOURCES = master.cxx
|
||||||
|
|
||||||
|
fgfs_master_LDADD = -lsgbucket -lsgmisc
|
||||||
|
|
||||||
|
INCLUDES += \
|
||||||
|
-I$(top_builddir) \
|
||||||
|
-I$(top_builddir)/Lib \
|
||||||
|
-I$(top_builddir)/Construct
|
33
src/BuildTiles/Main/construct.cxx
Normal file
33
src/BuildTiles/Main/construct.cxx
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
// construct.cxx -- Class to manage the primary data used in the
|
||||||
|
// construction process
|
||||||
|
//
|
||||||
|
// Written by Curtis Olson, started May 1999.
|
||||||
|
//
|
||||||
|
// Copyright (C) 1999 Curtis L. Olson - curt@flightgear.org
|
||||||
|
//
|
||||||
|
// This program is free software; you can redistribute it and/or
|
||||||
|
// modify it under the terms of the GNU General Public License as
|
||||||
|
// published by the Free Software Foundation; either version 2 of the
|
||||||
|
// License, or (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful, but
|
||||||
|
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
// General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
//
|
||||||
|
// $Id$
|
||||||
|
|
||||||
|
|
||||||
|
#include "construct.hxx"
|
||||||
|
|
||||||
|
|
||||||
|
// Constructor
|
||||||
|
FGConstruct::FGConstruct() { }
|
||||||
|
|
||||||
|
|
||||||
|
// Destructor
|
||||||
|
FGConstruct::~FGConstruct() { }
|
175
src/BuildTiles/Main/construct.hxx
Normal file
175
src/BuildTiles/Main/construct.hxx
Normal file
|
@ -0,0 +1,175 @@
|
||||||
|
// construct.hxx -- Class to manage the primary data used in the
|
||||||
|
// construction process
|
||||||
|
//
|
||||||
|
// Written by Curtis Olson, started May 1999.
|
||||||
|
//
|
||||||
|
// Copyright (C) 1999 Curtis L. Olson - curt@flightgear.org
|
||||||
|
//
|
||||||
|
// This program is free software; you can redistribute it and/or
|
||||||
|
// modify it under the terms of the GNU General Public License as
|
||||||
|
// published by the Free Software Foundation; either version 2 of the
|
||||||
|
// License, or (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful, but
|
||||||
|
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
// General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
//
|
||||||
|
// $Id$
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef _CONSTRUCT_HXX
|
||||||
|
#define _CONSTRUCT_HXX
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef __cplusplus
|
||||||
|
# error This library requires C++
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
// Maximum nodes per tile
|
||||||
|
#define FG_MAX_NODES 2000
|
||||||
|
|
||||||
|
|
||||||
|
#include <simgear/compiler.h>
|
||||||
|
|
||||||
|
#include STL_STRING
|
||||||
|
|
||||||
|
#include <simgear/newbucket.hxx>
|
||||||
|
|
||||||
|
#include <Build/trinodes.hxx>
|
||||||
|
#include <Build/trisegs.hxx>
|
||||||
|
|
||||||
|
#include <Clipper/clipper.hxx>
|
||||||
|
#include <Triangulate/trieles.hxx>
|
||||||
|
|
||||||
|
FG_USING_STD(string);
|
||||||
|
|
||||||
|
|
||||||
|
typedef vector < int_list > belongs_to_list;
|
||||||
|
typedef belongs_to_list::iterator belongs_to_list_iterator;
|
||||||
|
typedef belongs_to_list::const_iterator belongs_to_list_tripoly_iterator;
|
||||||
|
|
||||||
|
|
||||||
|
class FGConstruct {
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
// minimum interior angle for triangulation
|
||||||
|
string angle;
|
||||||
|
|
||||||
|
// paths
|
||||||
|
string work_base;
|
||||||
|
string output_base;
|
||||||
|
|
||||||
|
// detail level constraints
|
||||||
|
int min_nodes;
|
||||||
|
int max_nodes;
|
||||||
|
|
||||||
|
// this bucket
|
||||||
|
FGBucket bucket;
|
||||||
|
|
||||||
|
// clipped polygons (gpc format)
|
||||||
|
FGPolyList clipped_polys;
|
||||||
|
|
||||||
|
// raw node list (after triangulation)
|
||||||
|
FGTriNodes tri_nodes;
|
||||||
|
|
||||||
|
// node list in geodetic coords (with fixed elevation)
|
||||||
|
point_list geod_nodes;
|
||||||
|
|
||||||
|
// node list in cartesian coords (wgs84 model)
|
||||||
|
point_list wgs84_nodes;
|
||||||
|
|
||||||
|
// triangle elements (after triangulation)
|
||||||
|
triele_list tri_elements;
|
||||||
|
|
||||||
|
// edge segments (after triangulation)
|
||||||
|
FGTriSegments tri_segs;
|
||||||
|
|
||||||
|
// for each node, a list of triangle indices that contain this node
|
||||||
|
belongs_to_list reverse_ele_lookup;
|
||||||
|
|
||||||
|
// face normal list (for flat shading)
|
||||||
|
point_list face_normals;
|
||||||
|
|
||||||
|
// normal list (for each point) in cart coords (for smooth
|
||||||
|
// shading)
|
||||||
|
point_list point_normals;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
// Constructor
|
||||||
|
FGConstruct();
|
||||||
|
|
||||||
|
// Destructor
|
||||||
|
~FGConstruct();
|
||||||
|
|
||||||
|
// minimum interior angle for triangulation
|
||||||
|
inline string get_angle() const { return angle; }
|
||||||
|
inline void set_angle( const string s ) { angle = s; }
|
||||||
|
|
||||||
|
// paths
|
||||||
|
inline string get_work_base() const { return work_base; }
|
||||||
|
inline void set_work_base( const string s ) { work_base = s; }
|
||||||
|
inline string get_output_base() const { return output_base; }
|
||||||
|
inline void set_output_base( const string s ) { output_base = s; }
|
||||||
|
|
||||||
|
// detail level constraints
|
||||||
|
inline int get_min_nodes() const { return min_nodes; }
|
||||||
|
inline void set_min_nodes( const int n ) { min_nodes = n; }
|
||||||
|
inline int get_max_nodes() const { return max_nodes; }
|
||||||
|
inline void set_max_nodes( const int n ) { max_nodes = n; }
|
||||||
|
|
||||||
|
// this bucket
|
||||||
|
inline FGBucket get_bucket() const { return bucket; }
|
||||||
|
inline void set_bucket( const FGBucket b ) { bucket = b; }
|
||||||
|
|
||||||
|
// clipped polygons
|
||||||
|
inline FGPolyList get_clipped_polys() const { return clipped_polys; }
|
||||||
|
inline void set_clipped_polys( FGPolyList p ) { clipped_polys = p; }
|
||||||
|
|
||||||
|
// node list (after triangulation)
|
||||||
|
inline FGTriNodes get_tri_nodes() const { return tri_nodes; }
|
||||||
|
inline void set_tri_nodes( FGTriNodes n ) { tri_nodes = n; }
|
||||||
|
|
||||||
|
// triangle elements (after triangulation)
|
||||||
|
inline triele_list get_tri_elements() const { return tri_elements; }
|
||||||
|
inline void set_tri_elements( triele_list e ) { tri_elements = e; }
|
||||||
|
|
||||||
|
// edge segments (after triangulation)
|
||||||
|
inline FGTriSegments get_tri_segs() const { return tri_segs; }
|
||||||
|
inline void set_tri_segs( FGTriSegments s ) { tri_segs = s; }
|
||||||
|
|
||||||
|
// node list in geodetic coords (with fixed elevation)
|
||||||
|
inline point_list get_geod_nodes() const { return geod_nodes; }
|
||||||
|
inline void set_geod_nodes( point_list n ) { geod_nodes = n; }
|
||||||
|
|
||||||
|
// node list in cartesian coords (wgs84 model)
|
||||||
|
inline point_list get_wgs84_nodes() const { return wgs84_nodes; }
|
||||||
|
inline void set_wgs84_nodes( point_list n ) { wgs84_nodes = n; }
|
||||||
|
|
||||||
|
// for each node, a list of triangle indices that contain this node
|
||||||
|
inline belongs_to_list get_reverse_ele_lookup() const {
|
||||||
|
return reverse_ele_lookup;
|
||||||
|
}
|
||||||
|
inline void set_reverse_ele_lookup( belongs_to_list r ) {
|
||||||
|
reverse_ele_lookup = r;
|
||||||
|
}
|
||||||
|
|
||||||
|
// face normal list (for flat shading)
|
||||||
|
inline point_list get_face_normals() const { return face_normals; }
|
||||||
|
inline void set_face_normals( point_list n ) { face_normals = n; }
|
||||||
|
|
||||||
|
// normal list (for each point) in cart coords (for smooth
|
||||||
|
// shading)
|
||||||
|
inline point_list get_point_normals() const { return point_normals; }
|
||||||
|
inline void set_point_normals( point_list n ) { point_normals = n; }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // _CONSTRUCT_HXX
|
794
src/BuildTiles/Main/main.cxx
Normal file
794
src/BuildTiles/Main/main.cxx
Normal file
|
@ -0,0 +1,794 @@
|
||||||
|
// main.cxx -- top level construction routines
|
||||||
|
//
|
||||||
|
// Written by Curtis Olson, started March 1999.
|
||||||
|
//
|
||||||
|
// Copyright (C) 1999 Curtis L. Olson - curt@flightgear.org
|
||||||
|
//
|
||||||
|
// This program is free software; you can redistribute it and/or
|
||||||
|
// modify it under the terms of the GNU General Public License as
|
||||||
|
// published by the Free Software Foundation; either version 2 of the
|
||||||
|
// License, or (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful, but
|
||||||
|
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
// General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
//
|
||||||
|
// $Id$
|
||||||
|
|
||||||
|
|
||||||
|
#include <sys/types.h> // for directory reading
|
||||||
|
#include <dirent.h> // for directory reading
|
||||||
|
|
||||||
|
#include <sys/time.h> // set mem allocation limit
|
||||||
|
#include <sys/resource.h> // set mem allocation limit
|
||||||
|
#include <unistd.h> // set mem allocation limit
|
||||||
|
|
||||||
|
#include <simgear/newbucket.hxx>
|
||||||
|
#include <simgear/constants.h>
|
||||||
|
#include <simgear/mat3.h>
|
||||||
|
#include <simgear/logstream.hxx>
|
||||||
|
|
||||||
|
#include <Array/array.hxx>
|
||||||
|
#include <Clipper/clipper.hxx>
|
||||||
|
#include <GenOutput/genobj.hxx>
|
||||||
|
#include <Match/match.hxx>
|
||||||
|
#include <Triangulate/triangle.hxx>
|
||||||
|
|
||||||
|
#include "construct.hxx"
|
||||||
|
|
||||||
|
|
||||||
|
// do actual scan of directory and loading of files
|
||||||
|
int actual_load_polys( const string& dir, FGConstruct& c, FGClipper& clipper ) {
|
||||||
|
int counter = 0;
|
||||||
|
string base = c.get_bucket().gen_base_path();
|
||||||
|
string tile_str = c.get_bucket().gen_index_str();
|
||||||
|
string ext;
|
||||||
|
|
||||||
|
DIR *d;
|
||||||
|
struct dirent *de;
|
||||||
|
|
||||||
|
if ( (d = opendir( dir.c_str() )) == NULL ) {
|
||||||
|
cout << "cannot open directory " << dir << "\n";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// load all matching polygon files
|
||||||
|
string file, f_index, full_path;
|
||||||
|
int pos;
|
||||||
|
while ( (de = readdir(d)) != NULL ) {
|
||||||
|
file = de->d_name;
|
||||||
|
pos = file.find(".");
|
||||||
|
f_index = file.substr(0, pos);
|
||||||
|
|
||||||
|
if ( tile_str == f_index ) {
|
||||||
|
ext = file.substr(pos + 1);
|
||||||
|
cout << file << " " << f_index << " '" << ext << "'" << endl;
|
||||||
|
full_path = dir + "/" + file;
|
||||||
|
if ( (ext == "dem") || (ext == "dem.gz") ) {
|
||||||
|
// skip
|
||||||
|
} else {
|
||||||
|
cout << "ext = '" << ext << "'" << endl;
|
||||||
|
clipper.load_polys( full_path );
|
||||||
|
++counter;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
closedir(d);
|
||||||
|
|
||||||
|
return counter;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// load all 2d polygons matching the specified base path and clip
|
||||||
|
// against each other to resolve any overlaps
|
||||||
|
int load_polys( FGConstruct& c ) {
|
||||||
|
FGClipper clipper;
|
||||||
|
|
||||||
|
string base = c.get_bucket().gen_base_path();
|
||||||
|
string poly_path;
|
||||||
|
int count = 0;
|
||||||
|
|
||||||
|
// initialize clipper
|
||||||
|
clipper.init();
|
||||||
|
|
||||||
|
// load airports
|
||||||
|
poly_path = c.get_work_base() + "/AirportArea/" + base;
|
||||||
|
cout << "poly_path = " << poly_path << endl;
|
||||||
|
count += actual_load_polys( poly_path, c, clipper );
|
||||||
|
cout << " loaded " << count << " total polys" << endl;
|
||||||
|
|
||||||
|
// load hydro
|
||||||
|
poly_path = c.get_work_base() + "/USA-Hydro/" + base;
|
||||||
|
cout << "poly_path = " << poly_path << endl;
|
||||||
|
count += actual_load_polys( poly_path, c, clipper );
|
||||||
|
cout << " loaded " << count << " total polys" << endl;
|
||||||
|
|
||||||
|
// load land masses
|
||||||
|
poly_path = c.get_work_base() + "/Global-LandMass/" + base;
|
||||||
|
cout << "poly_path = " << poly_path << endl;
|
||||||
|
count += actual_load_polys( poly_path, c, clipper );
|
||||||
|
cout << " loaded " << count << " total polys" << endl;
|
||||||
|
|
||||||
|
// load urban areas
|
||||||
|
poly_path = c.get_work_base() + "/USA-Urban/" + base;
|
||||||
|
cout << "poly_path = " << poly_path << endl;
|
||||||
|
count += actual_load_polys( poly_path, c, clipper );
|
||||||
|
cout << " loaded " << count << " total polys" << endl;
|
||||||
|
|
||||||
|
point2d min, max;
|
||||||
|
min.x = c.get_bucket().get_center_lon() - 0.5 * c.get_bucket().get_width();
|
||||||
|
min.y = c.get_bucket().get_center_lat() - 0.5 * c.get_bucket().get_height();
|
||||||
|
max.x = c.get_bucket().get_center_lon() + 0.5 * c.get_bucket().get_width();
|
||||||
|
max.y = c.get_bucket().get_center_lat() + 0.5 * c.get_bucket().get_height();
|
||||||
|
|
||||||
|
// do clipping
|
||||||
|
cout << "clipping polygons" << endl;
|
||||||
|
clipper.clip_all(min, max);
|
||||||
|
|
||||||
|
// update main data repository
|
||||||
|
c.set_clipped_polys( clipper.get_polys_clipped() );
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// load regular grid of elevation data (dem based), return list of
|
||||||
|
// fitted nodes
|
||||||
|
int load_dem( FGConstruct& c, FGArray& array) {
|
||||||
|
point_list result;
|
||||||
|
string base = c.get_bucket().gen_base_path();
|
||||||
|
|
||||||
|
// try 3 arcsec dems first
|
||||||
|
string dem_path = c.get_work_base() + "/DEM-3/" + base
|
||||||
|
+ "/" + c.get_bucket().gen_index_str() + ".dem";
|
||||||
|
cout << "dem_path = " << dem_path << endl;
|
||||||
|
|
||||||
|
if ( ! array.open(dem_path) ) {
|
||||||
|
cout << "ERROR: cannot open 3 arcsec file " << dem_path << endl;
|
||||||
|
cout << "trying 30 arcsec file" << endl;
|
||||||
|
|
||||||
|
// try 30 arcsec dem
|
||||||
|
dem_path = c.get_work_base() + "/DEM-30/" + base
|
||||||
|
+ "/" + c.get_bucket().gen_index_str() + ".dem";
|
||||||
|
cout << "dem_path = " << dem_path << endl;
|
||||||
|
if ( ! array.open(dem_path) ) {
|
||||||
|
cout << "ERROR: cannot open 3 arcsec file " << dem_path << endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FGBucket b = c.get_bucket();
|
||||||
|
array.parse( b );
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// fit dem nodes, return number of fitted nodes
|
||||||
|
int fit_dem(FGArray& array, int error) {
|
||||||
|
return array.fit( error );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// triangulate the data for each polygon ( first time before splitting )
|
||||||
|
void first_triangulate( FGConstruct& c, const FGArray& array,
|
||||||
|
FGTriangle& t ) {
|
||||||
|
// first we need to consolidate the points of the DEM fit list and
|
||||||
|
// all the polygons into a more "Triangle" friendly format
|
||||||
|
|
||||||
|
point_list corner_list = array.get_corner_node_list();
|
||||||
|
point_list fit_list = array.get_fit_node_list();
|
||||||
|
FGPolyList gpc_polys = c.get_clipped_polys();
|
||||||
|
|
||||||
|
cout << "ready to build node list and polygons" << endl;
|
||||||
|
t.build( corner_list, fit_list, gpc_polys );
|
||||||
|
cout << "done building node list and polygons" << endl;
|
||||||
|
|
||||||
|
cout << "ready to do triangulation" << endl;
|
||||||
|
t.run_triangulate( c.get_angle(), 1 );
|
||||||
|
cout << "finished triangulation" << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// triangulate the data for each polygon ( second time after splitting
|
||||||
|
// and reassembling )
|
||||||
|
void second_triangulate( FGConstruct& c, FGTriangle& t ) {
|
||||||
|
t.rebuild( c );
|
||||||
|
cout << "done re building node list and polygons" << endl;
|
||||||
|
|
||||||
|
cout << "ready to do second triangulation" << endl;
|
||||||
|
t.run_triangulate( c.get_angle(), 2 );
|
||||||
|
cout << "finished second triangulation" << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// calculate distance based on x,y only
|
||||||
|
static double distance2D( const Point3D p1, const Point3D p2 ) {
|
||||||
|
double dx = p1.x() - p2.x();
|
||||||
|
double dy = p1.y() - p2.y();
|
||||||
|
return sqrt( dx*dx + dy*dy );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// fix the elevations of the geodetic nodes
|
||||||
|
static void fix_point_heights( FGConstruct& c, const FGArray& array ) {
|
||||||
|
double z;
|
||||||
|
|
||||||
|
cout << "fixing node heights" << endl;
|
||||||
|
|
||||||
|
point_list raw_nodes = c.get_tri_nodes().get_node_list();
|
||||||
|
|
||||||
|
for ( int i = 0; i < (int)raw_nodes.size(); ++i ) {
|
||||||
|
z = array.interpolate_altitude( raw_nodes[i].x() * 3600.0,
|
||||||
|
raw_nodes[i].y() * 3600.0 );
|
||||||
|
cout << " old z = " << raw_nodes[i].z() << " new z = " << z << endl;
|
||||||
|
if ( raw_nodes[i].z() != z ) {
|
||||||
|
cout << " DIFFERENT" << endl;
|
||||||
|
}
|
||||||
|
raw_nodes[i].setz( z );
|
||||||
|
}
|
||||||
|
|
||||||
|
cout << "flattening ocean connected nodes" << endl;
|
||||||
|
|
||||||
|
triele_list tris = c.get_tri_elements();
|
||||||
|
FGTriEle t;
|
||||||
|
Point3D p;
|
||||||
|
AreaType a;
|
||||||
|
int n1, n2, n3;
|
||||||
|
|
||||||
|
for ( int count = 0; count < 3; ++count ) {
|
||||||
|
for ( int i = 0; i < (int)tris.size(); ++i ) {
|
||||||
|
double e1, e2, e3, ave, min;
|
||||||
|
|
||||||
|
t = tris[i];
|
||||||
|
n1 = t.get_n1();
|
||||||
|
n2 = t.get_n2();
|
||||||
|
n3 = t.get_n3();
|
||||||
|
a = (AreaType)((int)(t.get_attribute()));
|
||||||
|
|
||||||
|
// scale elevation of all water nodes based on the average
|
||||||
|
// of the elevations of the nodes of the triangle of which
|
||||||
|
// they are a member. This could really suck for certain
|
||||||
|
// cases, but it is my first stab at something reasonable.
|
||||||
|
// It might be better to eventually iterate, and allow
|
||||||
|
// some flexibility in elevations to handle rivers and
|
||||||
|
// things like that.
|
||||||
|
if ( (a == LakeArea) || (a == ReservoirArea) ) {
|
||||||
|
e1 = raw_nodes[n1].z();
|
||||||
|
e2 = raw_nodes[n2].z();
|
||||||
|
e3 = raw_nodes[n3].z();
|
||||||
|
|
||||||
|
min = e1; p = raw_nodes[n1];
|
||||||
|
if ( e2 < min ) { min = e2; p = raw_nodes[n2]; }
|
||||||
|
if ( e3 < min ) { min = e3; p = raw_nodes[n3]; }
|
||||||
|
ave = (e1 + e2 + e3) / 3.0;
|
||||||
|
|
||||||
|
raw_nodes[n1].setz( min );
|
||||||
|
raw_nodes[n2].setz( min );
|
||||||
|
raw_nodes[n3].setz( min );
|
||||||
|
} else if ( (a == StreamArea) || (a == CanalArea) ) {
|
||||||
|
e1 = raw_nodes[n1].z();
|
||||||
|
e2 = raw_nodes[n2].z();
|
||||||
|
e3 = raw_nodes[n3].z();
|
||||||
|
|
||||||
|
min = e1; p = raw_nodes[n1];
|
||||||
|
if ( e2 < min ) { min = e2; p = raw_nodes[n2]; }
|
||||||
|
if ( e3 < min ) { min = e3; p = raw_nodes[n3]; }
|
||||||
|
|
||||||
|
double d1 = distance2D( p, raw_nodes[n1] );
|
||||||
|
double d2 = distance2D( p, raw_nodes[n2] );
|
||||||
|
double d3 = distance2D( p, raw_nodes[n3] );
|
||||||
|
|
||||||
|
double max1 = 1000.0 * d1 + min;
|
||||||
|
double max2 = 1000.0 * d2 + min;
|
||||||
|
double max3 = 1000.0 * d3 + min;
|
||||||
|
|
||||||
|
if ( max1 < e1 ) { raw_nodes[n1].setz( max1 ); }
|
||||||
|
if ( max2 < e2 ) { raw_nodes[n2].setz( max2 ); }
|
||||||
|
if ( max3 < e3 ) { raw_nodes[n3].setz( max3 ); }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for ( int i = 0; i < (int)tris.size(); ++i ) {
|
||||||
|
// set all ocean nodes to 0.0
|
||||||
|
t = tris[i];
|
||||||
|
n1 = t.get_n1();
|
||||||
|
n2 = t.get_n2();
|
||||||
|
n3 = t.get_n3();
|
||||||
|
a = (AreaType)((int)(t.get_attribute()));
|
||||||
|
|
||||||
|
if ( a == OceanArea ) {
|
||||||
|
raw_nodes[n1].setz( 0.0 );
|
||||||
|
raw_nodes[n2].setz( 0.0 );
|
||||||
|
raw_nodes[n3].setz( 0.0 );
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
FGTriNodes tmp;
|
||||||
|
tmp.set_node_list( raw_nodes );
|
||||||
|
c.set_tri_nodes( tmp );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// build the wgs-84 point list
|
||||||
|
static void build_wgs_84_point_list( FGConstruct& c, const FGArray& array ) {
|
||||||
|
point_list geod_nodes;
|
||||||
|
point_list wgs84_nodes;
|
||||||
|
|
||||||
|
cout << "generating wgs84 list" << endl;
|
||||||
|
Point3D geod, radians, cart;
|
||||||
|
|
||||||
|
point_list raw_nodes = c.get_tri_nodes().get_node_list();
|
||||||
|
|
||||||
|
for ( int i = 0; i < (int)raw_nodes.size(); ++i ) {
|
||||||
|
geod = raw_nodes[i];
|
||||||
|
|
||||||
|
// convert to radians
|
||||||
|
radians = Point3D( geod.x() * DEG_TO_RAD,
|
||||||
|
geod.y() * DEG_TO_RAD,
|
||||||
|
geod.z() );
|
||||||
|
|
||||||
|
cart = fgGeodToCart(radians);
|
||||||
|
// cout << cart << endl;
|
||||||
|
|
||||||
|
geod_nodes.push_back(geod);
|
||||||
|
wgs84_nodes.push_back(cart);
|
||||||
|
}
|
||||||
|
|
||||||
|
c.set_geod_nodes( geod_nodes );
|
||||||
|
c.set_wgs84_nodes( wgs84_nodes );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// build the node -> element (triangle) reverse lookup table. there
|
||||||
|
// is an entry for each point containing a list of all the triangles
|
||||||
|
// that share that point.
|
||||||
|
static belongs_to_list gen_node_ele_lookup_table( FGConstruct& c ) {
|
||||||
|
belongs_to_list reverse_ele_lookup;
|
||||||
|
reverse_ele_lookup.clear();
|
||||||
|
|
||||||
|
int_list ele_list;
|
||||||
|
ele_list.clear();
|
||||||
|
|
||||||
|
// initialize reverse_ele_lookup structure by creating an empty
|
||||||
|
// list for each point
|
||||||
|
point_list wgs84_nodes = c.get_wgs84_nodes();
|
||||||
|
const_point_list_iterator w_current = wgs84_nodes.begin();
|
||||||
|
const_point_list_iterator w_last = wgs84_nodes.end();
|
||||||
|
for ( ; w_current != w_last; ++w_current ) {
|
||||||
|
reverse_ele_lookup.push_back( ele_list );
|
||||||
|
}
|
||||||
|
|
||||||
|
// traverse triangle structure building reverse lookup table
|
||||||
|
triele_list tri_elements = c.get_tri_elements();
|
||||||
|
const_triele_list_iterator current = tri_elements.begin();
|
||||||
|
const_triele_list_iterator last = tri_elements.end();
|
||||||
|
int counter = 0;
|
||||||
|
for ( ; current != last; ++current ) {
|
||||||
|
reverse_ele_lookup[ current->get_n1() ].push_back( counter );
|
||||||
|
reverse_ele_lookup[ current->get_n2() ].push_back( counter );
|
||||||
|
reverse_ele_lookup[ current->get_n3() ].push_back( counter );
|
||||||
|
++counter;
|
||||||
|
}
|
||||||
|
|
||||||
|
return reverse_ele_lookup;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// caclulate the normal for the specified triangle face
|
||||||
|
static Point3D calc_normal( FGConstruct& c, int i ) {
|
||||||
|
double v1[3], v2[3], normal[3];
|
||||||
|
double temp;
|
||||||
|
|
||||||
|
point_list wgs84_nodes = c.get_wgs84_nodes();
|
||||||
|
triele_list tri_elements = c.get_tri_elements();
|
||||||
|
|
||||||
|
Point3D p1 = wgs84_nodes[ tri_elements[i].get_n1() ];
|
||||||
|
Point3D p2 = wgs84_nodes[ tri_elements[i].get_n2() ];
|
||||||
|
Point3D p3 = wgs84_nodes[ tri_elements[i].get_n3() ];
|
||||||
|
|
||||||
|
v1[0] = p2.x() - p1.x(); v1[1] = p2.y() - p1.y(); v1[2] = p2.z() - p1.z();
|
||||||
|
v2[0] = p3.x() - p1.x(); v2[1] = p3.y() - p1.y(); v2[2] = p3.z() - p1.z();
|
||||||
|
|
||||||
|
MAT3cross_product(normal, v1, v2);
|
||||||
|
MAT3_NORMALIZE_VEC(normal,temp);
|
||||||
|
|
||||||
|
return Point3D( normal[0], normal[1], normal[2] );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// build the face normal list
|
||||||
|
static point_list gen_face_normals( FGConstruct& c ) {
|
||||||
|
point_list face_normals;
|
||||||
|
|
||||||
|
// traverse triangle structure building the face normal table
|
||||||
|
|
||||||
|
cout << "calculating face normals" << endl;
|
||||||
|
|
||||||
|
triele_list tri_elements = c.get_tri_elements();
|
||||||
|
for ( int i = 0; i < (int)tri_elements.size(); i++ ) {
|
||||||
|
// cout << calc_normal( i ) << endl;
|
||||||
|
face_normals.push_back( calc_normal( c, i ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
return face_normals;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// calculate the normals for each point in wgs84_nodes
|
||||||
|
static point_list gen_point_normals( FGConstruct& c ) {
|
||||||
|
point_list point_normals;
|
||||||
|
|
||||||
|
Point3D normal;
|
||||||
|
cout << "caculating node normals" << endl;
|
||||||
|
|
||||||
|
point_list wgs84_nodes = c.get_wgs84_nodes();
|
||||||
|
belongs_to_list reverse_ele_lookup = c.get_reverse_ele_lookup();
|
||||||
|
point_list face_normals = c.get_face_normals();
|
||||||
|
|
||||||
|
// for each node
|
||||||
|
for ( int i = 0; i < (int)wgs84_nodes.size(); ++i ) {
|
||||||
|
int_list tri_list = reverse_ele_lookup[i];
|
||||||
|
|
||||||
|
int_list_iterator current = tri_list.begin();
|
||||||
|
int_list_iterator last = tri_list.end();
|
||||||
|
|
||||||
|
Point3D average( 0.0 );
|
||||||
|
|
||||||
|
// for each triangle that shares this node
|
||||||
|
for ( ; current != last; ++current ) {
|
||||||
|
normal = face_normals[ *current ];
|
||||||
|
average += normal;
|
||||||
|
// cout << normal << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
average /= tri_list.size();
|
||||||
|
// cout << "average = " << average << endl;
|
||||||
|
|
||||||
|
point_normals.push_back( average );
|
||||||
|
}
|
||||||
|
|
||||||
|
cout << "1st" << endl;
|
||||||
|
cout << "wgs84 node list size = " << wgs84_nodes.size() << endl;
|
||||||
|
cout << "normal list size = " << point_normals.size() << endl;
|
||||||
|
|
||||||
|
return point_normals;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// generate the flight gear scenery file
|
||||||
|
void do_output( FGConstruct& c, FGGenOutput& output ) {
|
||||||
|
output.build( c );
|
||||||
|
output.write( c );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// collect custom objects and move to scenery area
|
||||||
|
void do_custom_objects( const FGConstruct& c ) {
|
||||||
|
FGBucket b = c.get_bucket();
|
||||||
|
|
||||||
|
string work_base = c.get_work_base();
|
||||||
|
string src_dir = work_base + "/AirportObj/" + b.gen_base_path();
|
||||||
|
string index_file = src_dir + "/" + b.gen_index_str() + ".ind";
|
||||||
|
|
||||||
|
cout << "collecting custom objects from " << index_file << endl;
|
||||||
|
|
||||||
|
string output_base = c.get_output_base();
|
||||||
|
string dest_dir = output_base + "/Scenery/" + b.gen_base_path();
|
||||||
|
string dest_ind = dest_dir + "/" + b.gen_index_str() + ".ind";
|
||||||
|
|
||||||
|
fg_gzifstream in( index_file );
|
||||||
|
|
||||||
|
if ( ! in.is_open() ) {
|
||||||
|
cout << "No custom objects" << endl;
|
||||||
|
} else {
|
||||||
|
FILE *fp;
|
||||||
|
if ( (fp = fopen( dest_ind.c_str(), "w" )) == NULL ) {
|
||||||
|
cout << "ERROR: opening " << dest_ind << " for writing!" << endl;
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
string token, name;
|
||||||
|
|
||||||
|
while ( ! in.eof() ) {
|
||||||
|
in >> token;
|
||||||
|
in >> name;
|
||||||
|
in >> skipws;
|
||||||
|
|
||||||
|
cout << "token = " << token << " name = " << name << endl;
|
||||||
|
string command = "cp " + src_dir + "/" + name + ".gz " + dest_dir;
|
||||||
|
cout << "running " << command << endl;
|
||||||
|
system( command.c_str() );
|
||||||
|
|
||||||
|
fprintf(fp, "OBJECT %s\n", name.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(fp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// master construction routine
|
||||||
|
void construct_tile( FGConstruct& c ) {
|
||||||
|
cout << "Construct tile, bucket = " << c.get_bucket() << endl;
|
||||||
|
|
||||||
|
// fit with ever increasing error tolerance until we produce <=
|
||||||
|
// 80% of max nodes. We should really have the sim end handle
|
||||||
|
// arbitrarily complex tiles.
|
||||||
|
|
||||||
|
bool acceptable = false;
|
||||||
|
bool growing = false;
|
||||||
|
bool shrinking = false;
|
||||||
|
|
||||||
|
double error = 200.0;
|
||||||
|
int count = 0;
|
||||||
|
|
||||||
|
// load and clip 2d polygon data
|
||||||
|
if ( load_polys( c ) == 0 ) {
|
||||||
|
// don't build the tile if there is no 2d data ... it *must*
|
||||||
|
// be ocean and the sim can build the tile on the fly.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// load grid of elevation data (dem)
|
||||||
|
FGArray array;
|
||||||
|
load_dem( c, array );
|
||||||
|
|
||||||
|
FGTriangle t;
|
||||||
|
|
||||||
|
while ( ! acceptable ) {
|
||||||
|
// do a least squares fit of the (dem) data with the given
|
||||||
|
// error tolerance
|
||||||
|
array.fit( error );
|
||||||
|
|
||||||
|
// triangulate the data for each polygon
|
||||||
|
first_triangulate( c, array, t );
|
||||||
|
|
||||||
|
acceptable = true;
|
||||||
|
|
||||||
|
count = t.get_out_nodes_size();
|
||||||
|
|
||||||
|
if ( (count < c.get_min_nodes()) && (error >= 25.0) ) {
|
||||||
|
// reduce error tolerance until number of points exceeds the
|
||||||
|
// minimum threshold
|
||||||
|
cout << "produced too few nodes ..." << endl;
|
||||||
|
|
||||||
|
acceptable = false;
|
||||||
|
growing = true;
|
||||||
|
|
||||||
|
if ( shrinking ) {
|
||||||
|
error /= 1.25;
|
||||||
|
shrinking = false;
|
||||||
|
} else {
|
||||||
|
error /= 1.5;
|
||||||
|
}
|
||||||
|
cout << "Setting error to " << error << " and retrying fit."
|
||||||
|
<< endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( count > c.get_max_nodes() ) {
|
||||||
|
if ( error <= 1000.0 ) {
|
||||||
|
// increase error tolerance until number of points drops below
|
||||||
|
// the maximum threshold
|
||||||
|
cout << "produced too many nodes ..." << endl;
|
||||||
|
|
||||||
|
acceptable = false;
|
||||||
|
shrinking = true;
|
||||||
|
|
||||||
|
if ( growing ) {
|
||||||
|
error *= 1.25;
|
||||||
|
growing = false;
|
||||||
|
} else {
|
||||||
|
error *= 1.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
cout << "Setting error to " << error << " and retrying fit."
|
||||||
|
<< endl;
|
||||||
|
} else {
|
||||||
|
// we tried, but can't seem to get down to a
|
||||||
|
// reasonable number of points even with a huge error
|
||||||
|
// tolerance. This could be related to the triangle()
|
||||||
|
// call which might be having trouble with our input
|
||||||
|
// set. Let's just die hope that our parent can try
|
||||||
|
// again with a smaller interior triangle angle.
|
||||||
|
cout << "Error: Too many nodes." << endl;
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cout << "finished fit with error = " << error << " node count = "
|
||||||
|
<< count << endl;
|
||||||
|
|
||||||
|
// save the results of the triangulation
|
||||||
|
c.set_tri_nodes( t.get_out_nodes() );
|
||||||
|
c.set_tri_elements( t.get_elelist() );
|
||||||
|
c.set_tri_segs( t.get_out_segs() );
|
||||||
|
|
||||||
|
// calculate wgs84 (cartesian) form of node list
|
||||||
|
fix_point_heights( c, array );
|
||||||
|
build_wgs_84_point_list( c, array );
|
||||||
|
|
||||||
|
// build the node -> element (triangle) reverse lookup table
|
||||||
|
c.set_reverse_ele_lookup( gen_node_ele_lookup_table( c ) );
|
||||||
|
|
||||||
|
// build the face normal list
|
||||||
|
c.set_face_normals( gen_face_normals( c ) );
|
||||||
|
|
||||||
|
// calculate the normals for each point in wgs84_nodes
|
||||||
|
c.set_point_normals( gen_point_normals( c ) );
|
||||||
|
|
||||||
|
// match tile edges with any neighbor tiles that have already been
|
||||||
|
// generated
|
||||||
|
FGMatch m;
|
||||||
|
m.load_neighbor_shared( c );
|
||||||
|
m.split_tile( c );
|
||||||
|
m.write_shared( c );
|
||||||
|
m.assemble_tile( c );
|
||||||
|
|
||||||
|
// now we must retriangulate the pasted together tile points
|
||||||
|
second_triangulate( c, t );
|
||||||
|
|
||||||
|
// save the results of the triangulation
|
||||||
|
c.set_tri_nodes( t.get_out_nodes() );
|
||||||
|
c.set_tri_elements( t.get_elelist() );
|
||||||
|
c.set_tri_segs( t.get_out_segs() );
|
||||||
|
|
||||||
|
// calculate wgs84 (cartesian) form of node list
|
||||||
|
build_wgs_84_point_list( c, array );
|
||||||
|
|
||||||
|
// generate the output
|
||||||
|
FGGenOutput output;
|
||||||
|
do_output( c, output );
|
||||||
|
|
||||||
|
array.close();
|
||||||
|
|
||||||
|
// collect custom objects and move to scenery area
|
||||||
|
do_custom_objects( c );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// display usage and exit
|
||||||
|
void usage( const string name ) {
|
||||||
|
cout << "Usage: " << name
|
||||||
|
<< " <min_tri_angle> <work_base> <output_base> tile_id" << endl;
|
||||||
|
cout << "Usage: " << name
|
||||||
|
<< " <min_tri_angle> <work_base> <output_base> center_lon center_lat xdist ydist"
|
||||||
|
<< endl;
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
main(int argc, char **argv) {
|
||||||
|
double lon, lat;
|
||||||
|
|
||||||
|
fglog().setLogLevels( FG_ALL, FG_DEBUG );
|
||||||
|
|
||||||
|
if ( argc < 4 ) {
|
||||||
|
usage( argv[0] );
|
||||||
|
}
|
||||||
|
|
||||||
|
// set mem allocation limit. Reason: occasionally the triangle()
|
||||||
|
// routine can blow up and allocate memory forever. We'd like
|
||||||
|
// this process to die before things get out of hand so we can try
|
||||||
|
// again with a smaller interior angle limit.
|
||||||
|
int result;
|
||||||
|
struct rlimit limit;
|
||||||
|
limit.rlim_cur = 20000000;
|
||||||
|
limit.rlim_max = 20000000;
|
||||||
|
result = setrlimit( RLIMIT_DATA, &limit );
|
||||||
|
cout << "result of setting mem limit = " << result << endl;
|
||||||
|
result = setrlimit( RLIMIT_STACK, &limit );
|
||||||
|
cout << "result of setting mem limit = " << result << endl;
|
||||||
|
result = setrlimit( RLIMIT_CORE, &limit );
|
||||||
|
cout << "result of setting mem limit = " << result << endl;
|
||||||
|
result = setrlimit( RLIMIT_RSS, &limit );
|
||||||
|
cout << "result of setting mem limit = " << result << endl;
|
||||||
|
|
||||||
|
// cpu time limit since occassionally the triangulator can go into
|
||||||
|
// and infinite loop.
|
||||||
|
limit.rlim_cur = 120;
|
||||||
|
limit.rlim_max = 120;
|
||||||
|
result = setrlimit( RLIMIT_CPU, &limit );
|
||||||
|
cout << "result of setting mem limit = " << result << endl;
|
||||||
|
|
||||||
|
// main construction data management class
|
||||||
|
FGConstruct c;
|
||||||
|
|
||||||
|
c.set_angle( argv[1] );
|
||||||
|
c.set_work_base( argv[2] );
|
||||||
|
c.set_output_base( argv[3] );
|
||||||
|
|
||||||
|
c.set_min_nodes( 50 );
|
||||||
|
c.set_max_nodes( (int)(FG_MAX_NODES * 0.8) );
|
||||||
|
|
||||||
|
// lon = -146.248360; lat = 61.133950; // PAVD (Valdez, AK)
|
||||||
|
// lon = -110.664244; lat = 33.352890; // P13
|
||||||
|
// lon = -93.211389; lat = 45.145000; // KANE
|
||||||
|
// lon = -92.486188; lat = 44.590190; // KRGK
|
||||||
|
// lon = -89.7446823; lat= 29.314495;
|
||||||
|
// lon = -122.488090; lat = 42.743183; // 64S
|
||||||
|
// lon = -114.861097; lat = 35.947480; // 61B
|
||||||
|
// lon = -112.012175; lat = 41.195944; // KOGD
|
||||||
|
// lon = -90.757128; lat = 46.790212; // WI32
|
||||||
|
// lon = -122.220717; lat = 37.721291; // KOAK
|
||||||
|
// lon = -111.721477; lat = 40.215641; // KPVU
|
||||||
|
// lon = -122.309313; lat = 47.448982; // KSEA
|
||||||
|
lon = -121.534; lat = 47.0131; // 6WA8
|
||||||
|
// lon = -148.798131; lat = 63.645099; // AK06 (Danali, AK)
|
||||||
|
// lon = -92.5; lat = 47.5; // Marsh test (northern MN)
|
||||||
|
// lon = -111.977773; lat = 40.788388; // KSLC
|
||||||
|
// lon = -121.914; lat = 42.5655; // TEST (Oregon SW of Crater)
|
||||||
|
// lon = -76.201239; lat = 36.894606; // KORF (Norfolk, Virginia)
|
||||||
|
// lon = -147.166; lat = 60.9925; // Hale-bop test
|
||||||
|
|
||||||
|
if ( argc == 4 ) {
|
||||||
|
// construct the default tile and exit
|
||||||
|
|
||||||
|
FGBucket b( lon, lat );
|
||||||
|
c.set_bucket( b );
|
||||||
|
construct_tile( c );
|
||||||
|
} else if ( argc == 5 ) {
|
||||||
|
// construct a specific tile and exit
|
||||||
|
|
||||||
|
long index = atoi( argv[4] );
|
||||||
|
FGBucket b( index );
|
||||||
|
c.set_bucket( b );
|
||||||
|
construct_tile( c );
|
||||||
|
} else if ( argc == 8 ) {
|
||||||
|
// build all the tiles in an area
|
||||||
|
|
||||||
|
lon = atof( argv[4] );
|
||||||
|
lat = atof( argv[5] );
|
||||||
|
double xdist = atof( argv[6] );
|
||||||
|
double ydist = atof( argv[7] );
|
||||||
|
|
||||||
|
double min_x = lon - xdist;
|
||||||
|
double min_y = lat - ydist;
|
||||||
|
FGBucket b_min( min_x, min_y );
|
||||||
|
FGBucket b_max( lon + xdist, lat + ydist );
|
||||||
|
|
||||||
|
FGBucket b_start(550401L);
|
||||||
|
bool do_tile = true;
|
||||||
|
|
||||||
|
if ( b_min == b_max ) {
|
||||||
|
c.set_bucket( b_min );
|
||||||
|
construct_tile( c );
|
||||||
|
} else {
|
||||||
|
FGBucket b_cur;
|
||||||
|
int dx, dy, i, j;
|
||||||
|
|
||||||
|
fgBucketDiff(b_min, b_max, &dx, &dy);
|
||||||
|
cout << " construction area spans tile boundaries" << endl;
|
||||||
|
cout << " dx = " << dx << " dy = " << dy << endl;
|
||||||
|
|
||||||
|
for ( j = 0; j <= dy; j++ ) {
|
||||||
|
for ( i = 0; i <= dx; i++ ) {
|
||||||
|
b_cur = fgBucketOffset(min_x, min_y, i, j);
|
||||||
|
|
||||||
|
if ( b_cur == b_start ) {
|
||||||
|
do_tile = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( do_tile ) {
|
||||||
|
c.set_bucket( b_cur );
|
||||||
|
construct_tile( c );
|
||||||
|
} else {
|
||||||
|
cout << "skipping " << b_cur << endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// string answer; cin >> answer;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
usage( argv[0] );
|
||||||
|
}
|
||||||
|
|
||||||
|
cout << "[Finished successfully]" << endl;
|
||||||
|
}
|
153
src/BuildTiles/Main/master.cxx
Normal file
153
src/BuildTiles/Main/master.cxx
Normal file
|
@ -0,0 +1,153 @@
|
||||||
|
// master.cxx -- top level construction routines
|
||||||
|
//
|
||||||
|
// Written by Curtis Olson, started May 1999.
|
||||||
|
//
|
||||||
|
// Copyright (C) 1999 Curtis L. Olson - curt@flightgear.org
|
||||||
|
//
|
||||||
|
// This program is free software; you can redistribute it and/or
|
||||||
|
// modify it under the terms of the GNU General Public License as
|
||||||
|
// published by the Free Software Foundation; either version 2 of the
|
||||||
|
// License, or (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful, but
|
||||||
|
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
// General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
//
|
||||||
|
// $Id$
|
||||||
|
|
||||||
|
|
||||||
|
#include <stdlib.h> // for system()
|
||||||
|
#include <sys/stat.h> // for stat()
|
||||||
|
#include <unistd.h> // for stat()
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include <simgear/newbucket.hxx>
|
||||||
|
|
||||||
|
// #include <Include/fg_constants.h>
|
||||||
|
// #include <Math/mat3.h>
|
||||||
|
|
||||||
|
// #include <Debug/logstream.hxx>
|
||||||
|
// #include <Array/array.hxx>
|
||||||
|
// #include <Clipper/clipper.hxx>
|
||||||
|
// #include <GenOutput/genobj.hxx>
|
||||||
|
// #include <Match/match.hxx>
|
||||||
|
// #include <Triangulate/triangle.hxx>
|
||||||
|
|
||||||
|
|
||||||
|
// return true if file exists
|
||||||
|
static bool file_exists( const string& file ) {
|
||||||
|
struct stat buf;
|
||||||
|
|
||||||
|
if ( stat( file.c_str(), &buf ) == 0 ) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// check if the specified tile has data defined for it
|
||||||
|
static bool has_data( const string& path, const FGBucket& b ) {
|
||||||
|
string dem_file = path + "DEM-3/" + b.gen_base_path()
|
||||||
|
+ "/" + b.gen_index_str() + ".dem";
|
||||||
|
if ( file_exists( dem_file ) ) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
dem_file += ".gz";
|
||||||
|
if ( file_exists( dem_file ) ) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// build the tile and check for success
|
||||||
|
bool build_tile( const string& work_base, const string& output_base,
|
||||||
|
const FGBucket& b ) {
|
||||||
|
string result_file = "result";
|
||||||
|
|
||||||
|
string command = "./construct " + work_base + " " + output_base + " "
|
||||||
|
+ b.gen_index_str() + " > " + result_file + " 2>&1";
|
||||||
|
cout << command << endl;
|
||||||
|
|
||||||
|
system( command.c_str() );
|
||||||
|
|
||||||
|
FILE *fp = fopen( result_file.c_str(), "r" );
|
||||||
|
char line[256];
|
||||||
|
while ( fgets( line, 256, fp ) != NULL ) {
|
||||||
|
string line_str = line;
|
||||||
|
line_str = line_str.substr(0, line_str.length() - 1);
|
||||||
|
cout << line_str << endl;
|
||||||
|
if ( line_str == "[Finished successfully]" ) {
|
||||||
|
fclose(fp);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(fp);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// display usage and exit
|
||||||
|
void usage( const string name ) {
|
||||||
|
cout << "Usage: " << name << " <work_base> <output_base>" << endl;
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
main(int argc, char **argv) {
|
||||||
|
double lon, lat;
|
||||||
|
|
||||||
|
if ( argc < 3 ) {
|
||||||
|
usage( argv[0] );
|
||||||
|
}
|
||||||
|
|
||||||
|
string work_base = argv[1];
|
||||||
|
string output_base = argv[2];
|
||||||
|
|
||||||
|
FGBucket tmp1( 0.0, 0.0 );
|
||||||
|
|
||||||
|
double dy = tmp1.get_height();
|
||||||
|
lat = 68.75 + dy * 0.5;
|
||||||
|
|
||||||
|
bool start_lon = true;
|
||||||
|
lon = -152.9 /* + (1.0/16.0) */;
|
||||||
|
|
||||||
|
while ( lat <= 90.0 ) {
|
||||||
|
FGBucket tmp2( 0.0, lat );
|
||||||
|
double dx = tmp2.get_width();
|
||||||
|
|
||||||
|
if ( ! start_lon ) {
|
||||||
|
lon = -180 + dx * 0.5;
|
||||||
|
} else {
|
||||||
|
start_lon = false;
|
||||||
|
}
|
||||||
|
while ( lon <= 180.0 ) {
|
||||||
|
FGBucket b( lon, lat );
|
||||||
|
cout << "Bucket = " << b << endl;
|
||||||
|
|
||||||
|
if ( has_data( work_base, b ) ) {
|
||||||
|
if ( ! build_tile( work_base, output_base, b ) ) {
|
||||||
|
cout << "error building last tile" << endl;
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lon += dx;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
lat += dy;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
9
src/BuildTiles/Makefile.am
Normal file
9
src/BuildTiles/Makefile.am
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
SUBDIRS = \
|
||||||
|
Triangulate \
|
||||||
|
Clipper \
|
||||||
|
Combine \
|
||||||
|
GenOutput \
|
||||||
|
Match \
|
||||||
|
Parallel \
|
||||||
|
Main
|
||||||
|
|
8
src/BuildTiles/Match/Makefile.am
Normal file
8
src/BuildTiles/Match/Makefile.am
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
noinst_LIBRARIES = libMatch.a
|
||||||
|
|
||||||
|
libMatch_a_SOURCES = match.cxx match.hxx
|
||||||
|
|
||||||
|
INCLUDES += \
|
||||||
|
-I$(top_builddir) \
|
||||||
|
-I$(top_builddir)/Lib \
|
||||||
|
-I$(top_builddir)/Construct
|
721
src/BuildTiles/Match/match.cxx
Normal file
721
src/BuildTiles/Match/match.cxx
Normal file
|
@ -0,0 +1,721 @@
|
||||||
|
// array.cxx -- Array management class
|
||||||
|
//
|
||||||
|
// Written by Curtis Olson, started March 1998.
|
||||||
|
//
|
||||||
|
// Copyright (C) 1998 - 1999 Curtis L. Olson - curt@flightgear.org
|
||||||
|
//
|
||||||
|
// This program is free software; you can redistribute it and/or
|
||||||
|
// modify it under the terms of the GNU General Public License as
|
||||||
|
// published by the Free Software Foundation; either version 2 of the
|
||||||
|
// License, or (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful, but
|
||||||
|
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
// General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
//
|
||||||
|
// $Id$
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
# include <config.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <simgear/fg_geodesy.hxx>
|
||||||
|
#include <simgear/point3d.hxx>
|
||||||
|
#include <simgear/fgstream.hxx>
|
||||||
|
|
||||||
|
#include "match.hxx"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
FGMatch::FGMatch( void ) {
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
FGMatch::~FGMatch( void ) {
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// scan the specified share file for the specified information
|
||||||
|
void FGMatch::scan_share_file( const string& dir, const FGBucket& b,
|
||||||
|
neighbor_type search, neighbor_type dest )
|
||||||
|
{
|
||||||
|
string file = dir + "/" + b.gen_base_path() + "/" + b.gen_index_str();
|
||||||
|
|
||||||
|
fg_gzifstream in( file );
|
||||||
|
if ( !in.is_open() ) {
|
||||||
|
cout << "Cannot open file: " << file << endl;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// cout << "reading shared data from " << file << endl;
|
||||||
|
|
||||||
|
string target;
|
||||||
|
if ( search == SW_Corner ) {
|
||||||
|
target = "sw_node";
|
||||||
|
} else if ( search == SE_Corner ) {
|
||||||
|
target = "se_node";
|
||||||
|
} else if ( search == NE_Corner ) {
|
||||||
|
target = "ne_node";
|
||||||
|
} else if ( search == NW_Corner ) {
|
||||||
|
target = "nw_node";
|
||||||
|
} else if ( search == NORTH ) {
|
||||||
|
target = "n_node";
|
||||||
|
} else if ( search == SOUTH ) {
|
||||||
|
target = "s_node";
|
||||||
|
} else if ( search == EAST ) {
|
||||||
|
target = "e_node";
|
||||||
|
} else if ( search == WEST ) {
|
||||||
|
target = "w_node";
|
||||||
|
}
|
||||||
|
|
||||||
|
string key;
|
||||||
|
Point3D node, normal;
|
||||||
|
while ( in ) {
|
||||||
|
in >> key;
|
||||||
|
in >> node;
|
||||||
|
if ( key == target ) {
|
||||||
|
// cout << key << " " << node << endl;
|
||||||
|
in >> key;
|
||||||
|
in >> normal;
|
||||||
|
|
||||||
|
if ( dest == SW_Corner ) {
|
||||||
|
sw_node = node;
|
||||||
|
sw_normal = normal;
|
||||||
|
sw_flag = true;
|
||||||
|
} else if ( dest == SE_Corner ) {
|
||||||
|
se_node = node;
|
||||||
|
se_normal = normal;
|
||||||
|
se_flag = true;
|
||||||
|
} else if ( dest == NE_Corner ) {
|
||||||
|
ne_node = node;
|
||||||
|
ne_normal = normal;
|
||||||
|
ne_flag = true;
|
||||||
|
} else if ( dest == NW_Corner ) {
|
||||||
|
nw_node = node;
|
||||||
|
nw_normal = normal;
|
||||||
|
nw_flag = true;
|
||||||
|
} else if ( dest == NORTH ) {
|
||||||
|
north_nodes.push_back(node);
|
||||||
|
north_normals.push_back(normal);
|
||||||
|
north_flag = true;
|
||||||
|
} else if ( dest == SOUTH ) {
|
||||||
|
south_nodes.push_back(node);
|
||||||
|
south_normals.push_back(normal);
|
||||||
|
south_flag = true;
|
||||||
|
} else if ( dest == EAST ) {
|
||||||
|
east_nodes.push_back(node);
|
||||||
|
east_normals.push_back(normal);
|
||||||
|
east_flag = true;
|
||||||
|
} else if ( dest == WEST ) {
|
||||||
|
west_nodes.push_back(node);
|
||||||
|
west_normals.push_back(normal);
|
||||||
|
west_flag = true;
|
||||||
|
}
|
||||||
|
} else if ( (target == "n_node") && (key == "n_null") ) {
|
||||||
|
south_flag = true;
|
||||||
|
} else if ( (target == "s_node") && (key == "s_null") ) {
|
||||||
|
north_flag = true;
|
||||||
|
} else if ( (target == "e_node") && (key == "e_null") ) {
|
||||||
|
west_flag = true;
|
||||||
|
} else if ( (target == "w_node") && (key == "w_null") ) {
|
||||||
|
east_flag = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// try to find info for the specified shared component
|
||||||
|
void FGMatch::load_shared( const FGConstruct& c, neighbor_type n ) {
|
||||||
|
FGBucket b = c.get_bucket();
|
||||||
|
|
||||||
|
double clon = b.get_center_lon();
|
||||||
|
double clat = b.get_center_lat();
|
||||||
|
|
||||||
|
string base = c.get_work_base() + "/Shared/";
|
||||||
|
|
||||||
|
FGBucket cb;
|
||||||
|
|
||||||
|
if ( n == SW_Corner ) {
|
||||||
|
// cout << "searching for SW corner data" << endl;
|
||||||
|
cb = fgBucketOffset(clon, clat, -1, 0);
|
||||||
|
scan_share_file( base, cb, SE_Corner, n );
|
||||||
|
cb = fgBucketOffset(clon, clat, -1, -1);
|
||||||
|
scan_share_file( base, cb, NE_Corner, n );
|
||||||
|
cb = fgBucketOffset(clon, clat, 0, -1);
|
||||||
|
scan_share_file( base, cb, NW_Corner, n );
|
||||||
|
} else if ( n == SE_Corner ) {
|
||||||
|
// cout << "searching for SE corner data" << endl;
|
||||||
|
cb = fgBucketOffset(clon, clat, 0, -1);
|
||||||
|
scan_share_file( base, cb, NE_Corner, n );
|
||||||
|
cb = fgBucketOffset(clon, clat, 1, -1);
|
||||||
|
scan_share_file( base, cb, NW_Corner, n );
|
||||||
|
cb = fgBucketOffset(clon, clat, 1, 0);
|
||||||
|
scan_share_file( base, cb, SW_Corner, n );
|
||||||
|
} else if ( n == NE_Corner ) {
|
||||||
|
// cout << "searching for NE corner data" << endl;
|
||||||
|
cb = fgBucketOffset(clon, clat, 1, 0);
|
||||||
|
scan_share_file( base, cb, NW_Corner, n );
|
||||||
|
cb = fgBucketOffset(clon, clat, 1, 1);
|
||||||
|
scan_share_file( base, cb, SW_Corner, n );
|
||||||
|
cb = fgBucketOffset(clon, clat, 0, 1);
|
||||||
|
scan_share_file( base, cb, SE_Corner, n );
|
||||||
|
} else if ( n == NW_Corner ) {
|
||||||
|
// cout << "searching for NW corner data" << endl;
|
||||||
|
cb = fgBucketOffset(clon, clat, 0, 1);
|
||||||
|
scan_share_file( base, cb, SW_Corner, n );
|
||||||
|
cb = fgBucketOffset(clon, clat, -1, 1);
|
||||||
|
scan_share_file( base, cb, SE_Corner, n );
|
||||||
|
cb = fgBucketOffset(clon, clat, -1, 0);
|
||||||
|
scan_share_file( base, cb, NE_Corner, n );
|
||||||
|
} else if ( n == NORTH ) {
|
||||||
|
// cout << "searching for NORTH edge data" << endl;
|
||||||
|
cb = fgBucketOffset(clon, clat, 0, 1);
|
||||||
|
scan_share_file( base, cb, SOUTH, n );
|
||||||
|
} else if ( n == SOUTH ) {
|
||||||
|
// cout << "searching for SOUTH edge data" << endl;
|
||||||
|
cb = fgBucketOffset(clon, clat, 0, -1);
|
||||||
|
scan_share_file( base, cb, NORTH, n );
|
||||||
|
} else if ( n == EAST ) {
|
||||||
|
// cout << "searching for EAST edge data" << endl;
|
||||||
|
cb = fgBucketOffset(clon, clat, 1, 0);
|
||||||
|
scan_share_file( base, cb, WEST, n );
|
||||||
|
} else if ( n == WEST ) {
|
||||||
|
// cout << "searching for WEST edge data" << endl;
|
||||||
|
cb = fgBucketOffset(clon, clat, -1, 0);
|
||||||
|
scan_share_file( base, cb, EAST, n );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// load any previously existing shared data from all neighbors (if
|
||||||
|
// shared data for a component exists set that components flag to true
|
||||||
|
void FGMatch::load_neighbor_shared( FGConstruct& c ) {
|
||||||
|
cout << "Loading existing shared data from neighbor tiles" << endl;
|
||||||
|
|
||||||
|
// start with all flags false
|
||||||
|
sw_flag = se_flag = ne_flag = nw_flag = false;
|
||||||
|
north_flag = south_flag = east_flag = west_flag = false;
|
||||||
|
|
||||||
|
load_shared( c, SW_Corner );
|
||||||
|
load_shared( c, SE_Corner );
|
||||||
|
load_shared( c, NE_Corner );
|
||||||
|
load_shared( c, NW_Corner );
|
||||||
|
|
||||||
|
north_nodes.clear();
|
||||||
|
south_nodes.clear();
|
||||||
|
east_nodes.clear();
|
||||||
|
west_nodes.clear();
|
||||||
|
|
||||||
|
load_shared( c, NORTH );
|
||||||
|
load_shared( c, SOUTH );
|
||||||
|
load_shared( c, EAST );
|
||||||
|
load_shared( c, WEST );
|
||||||
|
|
||||||
|
cout << "Shared data read in:" << endl;
|
||||||
|
if ( sw_flag ) { cout << " sw corner = " << sw_node << endl; }
|
||||||
|
if ( se_flag ) { cout << " se corner = " << se_node << endl; }
|
||||||
|
if ( ne_flag ) { cout << " ne corner = " << ne_node << endl; }
|
||||||
|
if ( nw_flag ) { cout << " nw corner = " << nw_node << endl; }
|
||||||
|
if ( north_flag ) {
|
||||||
|
cout << " north nodes = " << north_nodes.size() << endl;
|
||||||
|
for ( int i = 0; i < (int)north_nodes.size(); ++i ) {
|
||||||
|
cout << " " << north_nodes[i] << endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ( south_flag ) {
|
||||||
|
cout << " south nodes = " << south_nodes.size() << endl;
|
||||||
|
for ( int i = 0; i < (int)south_nodes.size(); ++i ) {
|
||||||
|
cout << " " << south_nodes[i] << endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ( east_flag ) {
|
||||||
|
cout << " east nodes = " << east_nodes.size() << endl;
|
||||||
|
for ( int i = 0; i < (int)east_nodes.size(); ++i ) {
|
||||||
|
cout << " " << east_nodes[i] << endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ( west_flag ) {
|
||||||
|
cout << " west nodes = " << west_nodes.size() << endl;
|
||||||
|
for ( int i = 0; i < (int)west_nodes.size(); ++i ) {
|
||||||
|
cout << " " << west_nodes[i] << endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// split up the tile between the shared edge points, normals, and
|
||||||
|
// segments and the body. This must be done after calling
|
||||||
|
// load_neighbor_data() and will ignore any shared data from the
|
||||||
|
// current tile that already exists from a neighbor.
|
||||||
|
void FGMatch::split_tile( FGConstruct& c ) {
|
||||||
|
cout << "Spliting tile" << endl;
|
||||||
|
cout << " extracting (shared) edge nodes and normals" << endl;
|
||||||
|
|
||||||
|
// calculate tile boundaries
|
||||||
|
point2d min, max;
|
||||||
|
FGBucket b = c.get_bucket();
|
||||||
|
min.x = b.get_center_lon() - 0.5 * b.get_width();
|
||||||
|
min.y = b.get_center_lat() - 0.5 * b.get_height();
|
||||||
|
max.x = b.get_center_lon() + 0.5 * b.get_width();
|
||||||
|
max.y = b.get_center_lat() + 0.5 * b.get_height();
|
||||||
|
|
||||||
|
// separate nodes and normals into components
|
||||||
|
|
||||||
|
body_nodes.clear();
|
||||||
|
|
||||||
|
point_list nodes = c.get_geod_nodes();
|
||||||
|
point_list point_normals = c.get_point_normals();
|
||||||
|
|
||||||
|
for ( int i = 0; i < (int)nodes.size(); ++i ) {
|
||||||
|
Point3D node = nodes[i];
|
||||||
|
Point3D normal = point_normals[i];
|
||||||
|
|
||||||
|
if ( (fabs(node.y() - min.y) < FG_EPSILON) &&
|
||||||
|
(fabs(node.x() - min.x) < FG_EPSILON) ) {
|
||||||
|
if ( ! sw_flag ) {
|
||||||
|
sw_node = node;
|
||||||
|
sw_normal = normal;
|
||||||
|
}
|
||||||
|
} else if ( (fabs(node.y() - min.y) < FG_EPSILON) &&
|
||||||
|
(fabs(node.x() - max.x) < FG_EPSILON) ) {
|
||||||
|
if ( ! se_flag ) {
|
||||||
|
se_node = node;
|
||||||
|
se_normal = normal;
|
||||||
|
}
|
||||||
|
} else if ( (fabs(node.y() - max.y) < FG_EPSILON) &&
|
||||||
|
(fabs(node.x() - max.x) < FG_EPSILON)) {
|
||||||
|
if ( ! ne_flag ) {
|
||||||
|
ne_node = node;
|
||||||
|
ne_normal = normal;
|
||||||
|
}
|
||||||
|
} else if ( (fabs(node.y() - max.y) < FG_EPSILON) &&
|
||||||
|
(fabs(node.x() - min.x) < FG_EPSILON) ) {
|
||||||
|
if ( ! nw_flag ) {
|
||||||
|
nw_node = node;
|
||||||
|
nw_normal = normal;
|
||||||
|
}
|
||||||
|
} else if ( fabs(node.x() - min.x) < FG_EPSILON ) {
|
||||||
|
if ( ! west_flag ) {
|
||||||
|
west_nodes.push_back( node );
|
||||||
|
west_normals.push_back( normal );
|
||||||
|
}
|
||||||
|
} else if ( fabs(node.x() - max.x) < FG_EPSILON ) {
|
||||||
|
if ( ! east_flag ) {
|
||||||
|
east_nodes.push_back( node );
|
||||||
|
east_normals.push_back( normal );
|
||||||
|
}
|
||||||
|
} else if ( fabs(node.y() - min.y) < FG_EPSILON ) {
|
||||||
|
if ( ! south_flag ) {
|
||||||
|
south_nodes.push_back( node );
|
||||||
|
south_normals.push_back( normal );
|
||||||
|
}
|
||||||
|
} else if ( fabs(node.y() - max.y) < FG_EPSILON ) {
|
||||||
|
if ( ! north_flag ) {
|
||||||
|
north_nodes.push_back( node );
|
||||||
|
north_normals.push_back( normal );
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
body_nodes.push_back( node );
|
||||||
|
body_normals.push_back( normal );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// separate area edge segment into components
|
||||||
|
cout << " extracting (shared) area edge segments" << endl;
|
||||||
|
|
||||||
|
FGTriSeg seg;
|
||||||
|
Point3D p1, p2;
|
||||||
|
triseg_list seg_list = c.get_tri_segs().get_seg_list();
|
||||||
|
triseg_list_iterator current = seg_list.begin();
|
||||||
|
triseg_list_iterator last = seg_list.end();
|
||||||
|
|
||||||
|
for ( ; current != last; ++current ) {
|
||||||
|
seg = *current;
|
||||||
|
p1 = nodes[ seg.get_n1() ];
|
||||||
|
p2 = nodes[ seg.get_n2() ];
|
||||||
|
|
||||||
|
if ( fabs(p1.y() - p2.y()) < FG_EPSILON ) {
|
||||||
|
// check if horizontal
|
||||||
|
if ( fabs(p1.y() - max.y) < FG_EPSILON ) {
|
||||||
|
north_segs.push_back( seg );
|
||||||
|
} else if ( fabs(p1.y() - min.y) < FG_EPSILON ) {
|
||||||
|
south_segs.push_back( seg );
|
||||||
|
} else {
|
||||||
|
body_segs.push_back( seg );
|
||||||
|
}
|
||||||
|
} else if ( fabs(p1.x() - p2.x()) < FG_EPSILON ) {
|
||||||
|
// check if vertical
|
||||||
|
if ( fabs(p1.x() - max.x) < FG_EPSILON ) {
|
||||||
|
east_segs.push_back( seg );
|
||||||
|
} else if ( fabs(p1.x() - min.x) < FG_EPSILON ) {
|
||||||
|
west_segs.push_back( seg );
|
||||||
|
} else {
|
||||||
|
body_segs.push_back( seg );
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
body_segs.push_back( seg );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( !sw_flag ) { cout << " sw corner = " << sw_node << endl; }
|
||||||
|
if ( !se_flag ) { cout << " se corner = " << se_node << endl; }
|
||||||
|
if ( !ne_flag ) { cout << " ne corner = " << ne_node << endl; }
|
||||||
|
if ( !nw_flag ) { cout << " nw corner = " << nw_node << endl; }
|
||||||
|
if ( !north_flag ) {
|
||||||
|
cout << " north nodes = " << north_nodes.size() << endl;
|
||||||
|
for ( int i = 0; i < (int)north_nodes.size(); ++i ) {
|
||||||
|
cout << " " << north_nodes[i] << endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ( !south_flag ) {
|
||||||
|
cout << " south nodes = " << south_nodes.size() << endl;
|
||||||
|
for ( int i = 0; i < (int)south_nodes.size(); ++i ) {
|
||||||
|
cout << " " << south_nodes[i] << endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ( !east_flag ) {
|
||||||
|
cout << " east nodes = " << east_nodes.size() << endl;
|
||||||
|
for ( int i = 0; i < (int)east_nodes.size(); ++i ) {
|
||||||
|
cout << " " << east_nodes[i] << endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ( !west_flag ) {
|
||||||
|
cout << " west nodes = " << west_nodes.size() << endl;
|
||||||
|
for ( int i = 0; i < (int)west_nodes.size(); ++i ) {
|
||||||
|
cout << " " << west_nodes[i] << endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cout << " body nodes = " << body_nodes.size() << endl;
|
||||||
|
for ( int i = 0; i < (int)body_nodes.size(); ++i ) {
|
||||||
|
cout << " " << body_nodes[i] << endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// write the new shared edge points, normals, and segments for this
|
||||||
|
// tile
|
||||||
|
void FGMatch::write_shared( FGConstruct& c ) {
|
||||||
|
string base = c.get_work_base();
|
||||||
|
FGBucket b = c.get_bucket();
|
||||||
|
|
||||||
|
string dir = base + "/Shared/" + b.gen_base_path();
|
||||||
|
string command = "mkdir -p " + dir;
|
||||||
|
string file = dir + "/" + b.gen_index_str();
|
||||||
|
cout << "shared data will be written to " << file << endl;
|
||||||
|
|
||||||
|
system(command.c_str());
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
cout << "FLAGS" << endl;
|
||||||
|
cout << "=====" << endl;
|
||||||
|
cout << "sw_flag = " << sw_flag << endl;
|
||||||
|
cout << "se_flag = " << se_flag << endl;
|
||||||
|
cout << "ne_flag = " << ne_flag << endl;
|
||||||
|
cout << "nw_flag = " << nw_flag << endl;
|
||||||
|
cout << "north_flag = " << north_flag << endl;
|
||||||
|
cout << "south_flag = " << south_flag << endl;
|
||||||
|
cout << "east_flag = " << east_flag << endl;
|
||||||
|
cout << "west_flag = " << west_flag << endl;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
FILE *fp;
|
||||||
|
if ( (fp = fopen( file.c_str(), "w" )) == NULL ) {
|
||||||
|
cout << "ERROR: opening " << file << " for writing!" << endl;
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ! sw_flag ) {
|
||||||
|
fprintf( fp, "sw_node %.6f %.6f %.6f\n",
|
||||||
|
sw_node.x(), sw_node.y(), sw_node.z() );
|
||||||
|
fprintf( fp, "sw_normal %.6f %.6f %.6f\n",
|
||||||
|
sw_normal.x(), sw_normal.y(), sw_normal.z() );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ! se_flag ) {
|
||||||
|
fprintf( fp, "se_node %.6f %.6f %.6f\n",
|
||||||
|
se_node.x(), se_node.y(), se_node.z() );
|
||||||
|
fprintf( fp, "se_normal %.6f %.6f %.6f\n",
|
||||||
|
se_normal.x(), se_normal.y(), se_normal.z() );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ! nw_flag ) {
|
||||||
|
fprintf( fp, "nw_node %.6f %.6f %.6f\n",
|
||||||
|
nw_node.x(), nw_node.y(), nw_node.z() );
|
||||||
|
fprintf( fp, "nw_normal %.6f %.6f %.6f\n",
|
||||||
|
nw_normal.x(), nw_normal.y(), nw_normal.z() );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ! ne_flag ) {
|
||||||
|
fprintf( fp, "ne_node %.6f %.6f %.6f\n",
|
||||||
|
ne_node.x(), ne_node.y(), ne_node.z() );
|
||||||
|
fprintf( fp, "ne_normal %.6f %.6f %.6f\n",
|
||||||
|
ne_normal.x(), ne_normal.y(), ne_normal.z() );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ! north_flag ) {
|
||||||
|
if ( (int)north_nodes.size() == 0 ) {
|
||||||
|
fprintf( fp, "n_null -999.0 -999.0 -999.0\n" );
|
||||||
|
} else {
|
||||||
|
for ( int i = 0; i < (int)north_nodes.size(); ++i ) {
|
||||||
|
fprintf( fp, "n_node %.6f %.6f %.6f\n",
|
||||||
|
north_nodes[i].x(), north_nodes[i].y(),
|
||||||
|
north_nodes[i].z() );
|
||||||
|
fprintf( fp, "n_normal %.6f %.6f %.6f\n",
|
||||||
|
north_normals[i].x(), north_normals[i].y(),
|
||||||
|
north_normals[i].z() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ! south_flag ) {
|
||||||
|
if ( (int)south_nodes.size() == 0 ) {
|
||||||
|
fprintf( fp, "s_null -999.0 -999.0 -999.0\n" );
|
||||||
|
} else {
|
||||||
|
for ( int i = 0; i < (int)south_nodes.size(); ++i ) {
|
||||||
|
fprintf( fp, "s_node %.6f %.6f %.6f\n",
|
||||||
|
south_nodes[i].x(), south_nodes[i].y(),
|
||||||
|
south_nodes[i].z() );
|
||||||
|
fprintf( fp, "s_normal %.6f %.6f %.6f\n",
|
||||||
|
south_normals[i].x(), south_normals[i].y(),
|
||||||
|
south_normals[i].z() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ! east_flag ) {
|
||||||
|
if ( (int)east_nodes.size() == 0 ) {
|
||||||
|
fprintf( fp, "e_null -999.0 -999.0 -999.0\n" );
|
||||||
|
} else {
|
||||||
|
for ( int i = 0; i < (int)east_nodes.size(); ++i ) {
|
||||||
|
fprintf( fp, "e_node %.6f %.6f %.6f\n",
|
||||||
|
east_nodes[i].x(), east_nodes[i].y(),
|
||||||
|
east_nodes[i].z() );
|
||||||
|
fprintf( fp, "e_normal %.6f %.6f %.6f\n",
|
||||||
|
east_normals[i].x(), east_normals[i].y(),
|
||||||
|
east_normals[i].z() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ! west_flag ) {
|
||||||
|
if ( (int)west_nodes.size() == 0 ) {
|
||||||
|
fprintf( fp, "w_null -999.0 -999.0 -999.0\n" );
|
||||||
|
} else {
|
||||||
|
for ( int i = 0; i < (int)west_nodes.size(); ++i ) {
|
||||||
|
fprintf( fp, "w_node %.6f %.6f %.6f\n",
|
||||||
|
west_nodes[i].x(), west_nodes[i].y(),
|
||||||
|
west_nodes[i].z() );
|
||||||
|
fprintf( fp, "w_normal %.6f %.6f %.6f\n",
|
||||||
|
west_normals[i].x(), west_normals[i].y(),
|
||||||
|
west_normals[i].z() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0 // not needed
|
||||||
|
point_list nodes = c.get_geod_nodes();
|
||||||
|
Point3D p1, p2;
|
||||||
|
|
||||||
|
for ( int i = 0; i < (int)north_segs.size(); ++i ) {
|
||||||
|
p1 = nodes[ north_segs[i].get_n1() ];
|
||||||
|
p2 = nodes[ north_segs[i].get_n2() ];
|
||||||
|
fprintf( fp, "n_seg %.6f %.6f %.6f %.6f\n",
|
||||||
|
p1.x(), p1.y(), p2.x(), p2.y() );
|
||||||
|
}
|
||||||
|
|
||||||
|
for ( int i = 0; i < (int)south_segs.size(); ++i ) {
|
||||||
|
p1 = nodes[ south_segs[i].get_n1() ];
|
||||||
|
p2 = nodes[ south_segs[i].get_n2() ];
|
||||||
|
fprintf( fp, "s_seg %.6f %.6f %.6f %.6f\n",
|
||||||
|
p1.x(), p1.y(), p2.x(), p2.y() );
|
||||||
|
}
|
||||||
|
|
||||||
|
for ( int i = 0; i < (int)east_segs.size(); ++i ) {
|
||||||
|
p1 = nodes[ east_segs[i].get_n1() ];
|
||||||
|
p2 = nodes[ east_segs[i].get_n2() ];
|
||||||
|
fprintf( fp, "e_seg %.6f %.6f %.6f %.6f\n",
|
||||||
|
p1.x(), p1.y(), p2.x(), p2.y() );
|
||||||
|
}
|
||||||
|
|
||||||
|
for ( int i = 0; i < (int)west_segs.size(); ++i ) {
|
||||||
|
p1 = nodes[ west_segs[i].get_n1() ];
|
||||||
|
p2 = nodes[ west_segs[i].get_n2() ];
|
||||||
|
fprintf( fp, "w_seg %.6f %.6f %.6f %.6f\n",
|
||||||
|
p1.x(), p1.y(), p2.x(), p2.y() );
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
fclose( fp );
|
||||||
|
|
||||||
|
command = "gzip --force --best " + file;
|
||||||
|
system(command.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// insert normal into vector, extending it first if needed
|
||||||
|
void insert_normal( point_list& normals, Point3D n, int i ) {
|
||||||
|
Point3D empty( 0.0 );
|
||||||
|
|
||||||
|
// extend vector if needed
|
||||||
|
while ( i >= (int)normals.size() ) {
|
||||||
|
normals.push_back( empty );
|
||||||
|
}
|
||||||
|
|
||||||
|
normals[i] = n;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// fake a normal for a point which is basically straight up
|
||||||
|
static Point3D fake_normal( const Point3D& p ) {
|
||||||
|
Point3D radians = Point3D( p.x() * DEG_TO_RAD,
|
||||||
|
p.y() * DEG_TO_RAD,
|
||||||
|
p.z() );
|
||||||
|
Point3D cart = fgGeodToCart(radians);
|
||||||
|
double len = Point3D(0.0).distance3D(cart);
|
||||||
|
cout << "len = " << len << endl;
|
||||||
|
cart /= len;
|
||||||
|
cout << "fake normal = " << cart << endl;
|
||||||
|
|
||||||
|
return cart;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// reassemble the tile pieces (combining the shared data and our own
|
||||||
|
// data)
|
||||||
|
void FGMatch::assemble_tile( FGConstruct& c ) {
|
||||||
|
FGTriNodes new_nodes;
|
||||||
|
new_nodes.clear();
|
||||||
|
|
||||||
|
point_list new_normals;
|
||||||
|
new_normals.clear();
|
||||||
|
|
||||||
|
FGTriSegments new_segs;
|
||||||
|
new_segs.clear();
|
||||||
|
|
||||||
|
// add the corner points
|
||||||
|
int sw_index = new_nodes.unique_add( sw_node );
|
||||||
|
insert_normal( new_normals, sw_normal, sw_index );
|
||||||
|
|
||||||
|
int se_index = new_nodes.unique_add( se_node );
|
||||||
|
insert_normal( new_normals, se_normal, se_index );
|
||||||
|
|
||||||
|
int ne_index = new_nodes.unique_add( ne_node );
|
||||||
|
insert_normal( new_normals, ne_normal, ne_index );
|
||||||
|
|
||||||
|
int nw_index = new_nodes.unique_add( nw_node );
|
||||||
|
insert_normal( new_normals, nw_normal, nw_index );
|
||||||
|
|
||||||
|
cout << "after adding corners:" << endl;
|
||||||
|
cout << " new_nodes = " << new_nodes.size() << endl;
|
||||||
|
cout << " new normals = " << new_normals.size() << endl;
|
||||||
|
|
||||||
|
// add the edge points
|
||||||
|
|
||||||
|
int index;
|
||||||
|
|
||||||
|
for ( int i = 0; i < (int)north_nodes.size(); ++i ) {
|
||||||
|
index = new_nodes.unique_add( north_nodes[i] );
|
||||||
|
insert_normal( new_normals, north_normals[i], index );
|
||||||
|
}
|
||||||
|
|
||||||
|
for ( int i = 0; i < (int)south_nodes.size(); ++i ) {
|
||||||
|
index = new_nodes.unique_add( south_nodes[i] );
|
||||||
|
insert_normal( new_normals, south_normals[i], index );
|
||||||
|
}
|
||||||
|
|
||||||
|
for ( int i = 0; i < (int)east_nodes.size(); ++i ) {
|
||||||
|
index = new_nodes.unique_add( east_nodes[i] );
|
||||||
|
insert_normal( new_normals, east_normals[i], index );
|
||||||
|
}
|
||||||
|
|
||||||
|
// cout << "Total west nodes = " << west_nodes.size() << endl;
|
||||||
|
for ( int i = 0; i < (int)west_nodes.size(); ++i ) {
|
||||||
|
// cout << "adding west node " << west_nodes[i] << endl;
|
||||||
|
index = new_nodes.unique_add( west_nodes[i] );
|
||||||
|
insert_normal( new_normals, west_normals[i], index );
|
||||||
|
}
|
||||||
|
|
||||||
|
cout << "after adding edges:" << endl;
|
||||||
|
cout << " new_nodes = " << new_nodes.size() << endl;
|
||||||
|
cout << " new normals = " << new_normals.size() << endl;
|
||||||
|
|
||||||
|
// add the body points
|
||||||
|
for ( int i = 0; i < (int)body_nodes.size(); ++i ) {
|
||||||
|
index = new_nodes.unique_add( body_nodes[i] );
|
||||||
|
insert_normal( new_normals, body_normals[i], index );
|
||||||
|
}
|
||||||
|
|
||||||
|
cout << "after adding body points:" << endl;
|
||||||
|
cout << " new_nodes = " << new_nodes.size() << endl;
|
||||||
|
cout << " new normals = " << new_normals.size() << endl;
|
||||||
|
|
||||||
|
// add the edge segments
|
||||||
|
new_segs.unique_divide_and_add( new_nodes.get_node_list(),
|
||||||
|
FGTriSeg(sw_index, se_index, 1) );
|
||||||
|
new_segs.unique_divide_and_add( new_nodes.get_node_list(),
|
||||||
|
FGTriSeg(se_index, ne_index, 1) );
|
||||||
|
new_segs.unique_divide_and_add( new_nodes.get_node_list(),
|
||||||
|
FGTriSeg(ne_index, nw_index, 1) );
|
||||||
|
new_segs.unique_divide_and_add( new_nodes.get_node_list(),
|
||||||
|
FGTriSeg(nw_index, sw_index, 1) );
|
||||||
|
cout << "after adding edge segments:" << endl;
|
||||||
|
cout << " new_nodes = " << new_nodes.size() << endl;
|
||||||
|
cout << " new normals = " << new_normals.size() << endl;
|
||||||
|
|
||||||
|
// add the body segments
|
||||||
|
|
||||||
|
point_list geod_nodes = c.get_geod_nodes();
|
||||||
|
|
||||||
|
FGTriSeg seg;
|
||||||
|
Point3D p1, p2;
|
||||||
|
int n1, n2, marker;
|
||||||
|
|
||||||
|
triseg_list_iterator current = body_segs.begin();
|
||||||
|
triseg_list_iterator last = body_segs.end();
|
||||||
|
|
||||||
|
for ( ; current != last; ++current ) {
|
||||||
|
seg = *current;
|
||||||
|
|
||||||
|
// get the original points (x,y,z)
|
||||||
|
p1 = geod_nodes[ seg.get_n1() ];
|
||||||
|
p2 = geod_nodes[ seg.get_n2() ];
|
||||||
|
marker = seg.get_boundary_marker();
|
||||||
|
|
||||||
|
// make sure these points are in the new node list (and get
|
||||||
|
// their new index)
|
||||||
|
n1 = new_nodes.unique_add( p1 );
|
||||||
|
if ( n1 >= (int)new_normals.size() ) {
|
||||||
|
cout << "Adding a segment resulted in a new node, faking a normal"
|
||||||
|
<< endl;
|
||||||
|
Point3D fake = fake_normal( p1 );
|
||||||
|
insert_normal( new_normals, fake, n1 );
|
||||||
|
}
|
||||||
|
|
||||||
|
n2 = new_nodes.unique_add( p2 );
|
||||||
|
if ( n2 >= (int)new_normals.size() ) {
|
||||||
|
cout << "Adding a segment resulted in a new node, faking a normal"
|
||||||
|
<< endl;
|
||||||
|
Point3D fake = fake_normal( p2 );
|
||||||
|
insert_normal( new_normals, fake, n2 );
|
||||||
|
}
|
||||||
|
|
||||||
|
// add the segment using the new indices
|
||||||
|
new_segs.unique_divide_and_add( new_nodes.get_node_list(),
|
||||||
|
FGTriSeg(n1, n2, marker) );
|
||||||
|
}
|
||||||
|
|
||||||
|
c.set_tri_nodes( new_nodes );
|
||||||
|
c.set_point_normals( new_normals );
|
||||||
|
c.set_tri_segs( new_segs );
|
||||||
|
|
||||||
|
cout << "after adding all segments (should be the same):" << endl;
|
||||||
|
cout << " new_nodes = " << new_nodes.size() << endl;
|
||||||
|
cout << " new normals = " << new_normals.size() << endl;
|
||||||
|
|
||||||
|
}
|
109
src/BuildTiles/Match/match.hxx
Normal file
109
src/BuildTiles/Match/match.hxx
Normal file
|
@ -0,0 +1,109 @@
|
||||||
|
// match.hxx -- Class to help match up tile edges
|
||||||
|
//
|
||||||
|
// Written by Curtis Olson, started April 1999.
|
||||||
|
//
|
||||||
|
// Copyright (C) 1998 - 1999 Curtis L. Olson - curt@flightgear.org
|
||||||
|
//
|
||||||
|
// This program is free software; you can redistribute it and/or
|
||||||
|
// modify it under the terms of the GNU General Public License as
|
||||||
|
// published by the Free Software Foundation; either version 2 of the
|
||||||
|
// License, or (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful, but
|
||||||
|
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
// General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
//
|
||||||
|
// $Id$
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef _MATCH_HXX
|
||||||
|
#define _MATCH_HXX
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef __cplusplus
|
||||||
|
# error This library requires C++
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#include <simgear/compiler.h>
|
||||||
|
#include <simgear/fg_types.hxx>
|
||||||
|
#include <simgear/newbucket.hxx>
|
||||||
|
|
||||||
|
#include <Main/construct.hxx>
|
||||||
|
|
||||||
|
|
||||||
|
class FGMatch {
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
// nodes breakdown
|
||||||
|
Point3D sw_node, se_node, ne_node, nw_node;
|
||||||
|
point_list north_nodes, south_nodes, east_nodes, west_nodes;
|
||||||
|
point_list body_nodes;
|
||||||
|
|
||||||
|
// normals breakdown
|
||||||
|
Point3D sw_normal, se_normal, ne_normal, nw_normal;
|
||||||
|
point_list north_normals, south_normals, east_normals, west_normals;
|
||||||
|
point_list body_normals;
|
||||||
|
|
||||||
|
// flags
|
||||||
|
bool sw_flag, se_flag, ne_flag, nw_flag;
|
||||||
|
bool north_flag, south_flag, east_flag, west_flag;
|
||||||
|
|
||||||
|
// segment breakdown
|
||||||
|
triseg_list north_segs, south_segs, east_segs, west_segs;
|
||||||
|
triseg_list body_segs;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
enum neighbor_type {
|
||||||
|
SW_Corner = 1,
|
||||||
|
SE_Corner = 2,
|
||||||
|
NE_Corner = 3,
|
||||||
|
NW_Corner = 4,
|
||||||
|
NORTH = 5,
|
||||||
|
SOUTH = 6,
|
||||||
|
EAST = 7,
|
||||||
|
WEST = 8
|
||||||
|
};
|
||||||
|
|
||||||
|
// Constructor
|
||||||
|
FGMatch( void );
|
||||||
|
|
||||||
|
// Destructor
|
||||||
|
~FGMatch( void );
|
||||||
|
|
||||||
|
// load any previously existing shared data from all neighbors (if
|
||||||
|
// shared data for a component exists set that components flag to
|
||||||
|
// true
|
||||||
|
void load_neighbor_shared( FGConstruct& c );
|
||||||
|
|
||||||
|
// scan the specified share file for the specified information
|
||||||
|
void scan_share_file( const string& dir, const FGBucket& b,
|
||||||
|
neighbor_type search, neighbor_type dest );
|
||||||
|
|
||||||
|
// try to find info for the specified shared component
|
||||||
|
void load_shared( const FGConstruct& c, neighbor_type n );
|
||||||
|
|
||||||
|
// split up the tile between the shared edge points, normals, and
|
||||||
|
// segments and the body. This must be done after calling
|
||||||
|
// load_neighbor_data() and will ignore any shared data from the
|
||||||
|
// current tile that already exists from a neighbor.
|
||||||
|
void split_tile( FGConstruct& c );
|
||||||
|
|
||||||
|
// write the new shared edge points, normals, and segments for
|
||||||
|
// this tile
|
||||||
|
void write_shared( FGConstruct& c );
|
||||||
|
|
||||||
|
// reassemble the tile pieces (combining the shared data and our
|
||||||
|
// own data)
|
||||||
|
void assemble_tile( FGConstruct& c );
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // _MATCH_HXX
|
14
src/BuildTiles/Parallel/Makefile.am
Normal file
14
src/BuildTiles/Parallel/Makefile.am
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
bin_PROGRAMS = fgfs-tools-server fgfs-tools-client
|
||||||
|
|
||||||
|
fgfs_tools_server_SOURCES = server.cxx
|
||||||
|
|
||||||
|
fgfs_tools_server_LDADD = -lsgbucket -lsgmisc
|
||||||
|
|
||||||
|
fgfs_tools_client_SOURCES = client.cxx
|
||||||
|
|
||||||
|
fgfs_tools_client_LDADD = -lsgbucket -lsgmisc
|
||||||
|
|
||||||
|
INCLUDES += \
|
||||||
|
-I$(top_builddir) \
|
||||||
|
-I$(top_builddir)/Lib \
|
||||||
|
-I$(top_builddir)/Construct
|
283
src/BuildTiles/Parallel/client.cxx
Normal file
283
src/BuildTiles/Parallel/client.cxx
Normal file
|
@ -0,0 +1,283 @@
|
||||||
|
/* remote_exec.c -- Written by Curtis Olson */
|
||||||
|
/* -- for CSci 5502 */
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
# include <Include/config.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef HAVE_SYS_PARAM_H
|
||||||
|
# include <sys/param.h> // BSD macro definitions
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <sys/time.h> // FD_ISSET(), etc.
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <netdb.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
|
||||||
|
#include <utmp.h>
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h> // atoi()
|
||||||
|
#include <string.h> // bcopy()
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include <simgear/newbucket.hxx>
|
||||||
|
|
||||||
|
|
||||||
|
#define MAXBUF 1024
|
||||||
|
#define BUSY_WAIT_TIME 30
|
||||||
|
|
||||||
|
|
||||||
|
string work_base = "";
|
||||||
|
string output_base = "";
|
||||||
|
|
||||||
|
|
||||||
|
// check if it is ok to run
|
||||||
|
void check_master_switch() {
|
||||||
|
string file = work_base + "/Status/MASTER_ON";
|
||||||
|
|
||||||
|
FILE *fp = fopen( file.c_str(), "r" );
|
||||||
|
if ( fp == NULL ) {
|
||||||
|
cout << "MASTER_ON file, " << file << " not found ... exiting." << endl;
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose( fp );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// check if the host system is free of interactive users
|
||||||
|
int system_free() {
|
||||||
|
|
||||||
|
#ifndef BSD
|
||||||
|
struct utmp *uptr;
|
||||||
|
|
||||||
|
setutent();
|
||||||
|
|
||||||
|
while ( (uptr = getutent()) != NULL ) {
|
||||||
|
// cout << "NULL = " << NULL << " uptr = " << uptr << endl;
|
||||||
|
// cout << "user = ut_user = " << uptr->ut_user << endl;
|
||||||
|
// cout << "user = ut_type = " << uptr->ut_type << endl;
|
||||||
|
if (uptr->ut_type == USER_PROCESS) {
|
||||||
|
// found someone
|
||||||
|
endutent();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
endutent();
|
||||||
|
#else
|
||||||
|
# warning Port me
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int make_socket (char *host, unsigned short int port) {
|
||||||
|
int sock;
|
||||||
|
struct sockaddr_in name;
|
||||||
|
struct hostent *hp;
|
||||||
|
|
||||||
|
// Create the socket.
|
||||||
|
sock = socket (PF_INET, SOCK_STREAM, 0);
|
||||||
|
if (sock < 0) {
|
||||||
|
perror ("socket");
|
||||||
|
exit (EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
// specify address family
|
||||||
|
name.sin_family = AF_INET;
|
||||||
|
|
||||||
|
// get the hosts official name/info
|
||||||
|
hp = gethostbyname(host);
|
||||||
|
|
||||||
|
// Connect this socket to the host and the port specified on the
|
||||||
|
// command line
|
||||||
|
bcopy(hp->h_addr, &(name.sin_addr.s_addr), hp->h_length);
|
||||||
|
name.sin_port = htons(port);
|
||||||
|
|
||||||
|
if ( connect(sock, (struct sockaddr *) &name,
|
||||||
|
sizeof(struct sockaddr_in)) < 0 )
|
||||||
|
{
|
||||||
|
close(sock);
|
||||||
|
perror("Cannot connect to stream socket");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return sock;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// connect to the server and get the next task
|
||||||
|
long int get_next_task( const string& host, int port, long int last_tile ) {
|
||||||
|
long int tile;
|
||||||
|
int sock, len;
|
||||||
|
fd_set ready;
|
||||||
|
char message[256];
|
||||||
|
|
||||||
|
// loop till we get a socket connection
|
||||||
|
while ( (sock = make_socket( (char *)host.c_str(), port )) < 0 ) {
|
||||||
|
// check if the master switch is on
|
||||||
|
check_master_switch();
|
||||||
|
|
||||||
|
sleep(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// build a command string from the argv[]'s
|
||||||
|
sprintf(message, "%ld", last_tile);
|
||||||
|
|
||||||
|
// send command and arguments to remote server
|
||||||
|
if ( write(sock, message, sizeof(message)) < 0 ) {
|
||||||
|
perror("Cannot write to stream socket");
|
||||||
|
}
|
||||||
|
|
||||||
|
// loop until remote program finishes
|
||||||
|
cout << "querying server for next task ..." << endl;
|
||||||
|
|
||||||
|
FD_ZERO(&ready);
|
||||||
|
FD_SET(sock, &ready);
|
||||||
|
|
||||||
|
// block until input from sock
|
||||||
|
select(32, &ready, 0, 0, NULL);
|
||||||
|
cout << " received reply" << endl;
|
||||||
|
|
||||||
|
if ( FD_ISSET(sock, &ready) ) {
|
||||||
|
/* input coming from socket */
|
||||||
|
if ( (len = read(sock, message, 1024)) > 0 ) {
|
||||||
|
message[len] = '\0';
|
||||||
|
tile = atoi(message);
|
||||||
|
cout << " tile to construct = " << tile << endl;
|
||||||
|
close(sock);
|
||||||
|
return tile;
|
||||||
|
} else {
|
||||||
|
close(sock);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
close(sock);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// build the specified tile, return true if contruction completed
|
||||||
|
// successfully
|
||||||
|
bool construct_tile( const FGBucket& b, const string& result_file ) {
|
||||||
|
double angle = 10.0;
|
||||||
|
bool still_trying = true;
|
||||||
|
|
||||||
|
while ( still_trying ) {
|
||||||
|
still_trying = false;
|
||||||
|
char angle_str[256];
|
||||||
|
sprintf(angle_str, "%.0f", angle);
|
||||||
|
string command = "fgfs-construct ";
|
||||||
|
command += angle_str;
|
||||||
|
command += " " + work_base + " " + output_base + " "
|
||||||
|
+ b.gen_index_str() + " > " + result_file + " 2>&1";
|
||||||
|
cout << command << endl;
|
||||||
|
|
||||||
|
system( command.c_str() );
|
||||||
|
|
||||||
|
FILE *fp = fopen( result_file.c_str(), "r" );
|
||||||
|
char line[256];
|
||||||
|
while ( fgets( line, 256, fp ) != NULL ) {
|
||||||
|
string line_str = line;
|
||||||
|
line_str = line_str.substr(0, line_str.length() - 1);
|
||||||
|
// cout << line_str << endl;
|
||||||
|
if ( line_str == "[Finished successfully]" ) {
|
||||||
|
fclose(fp);
|
||||||
|
return true;
|
||||||
|
} else if
|
||||||
|
( (line_str.substr(0, 31) == "Error: Ran out of precision at")
|
||||||
|
|| (line_str.substr(0, 22) == "Error: Out of memory.")
|
||||||
|
|| (line_str.substr(0, 23) == "Error: Too many nodes.") ) {
|
||||||
|
if ( angle > 9.0 ) {
|
||||||
|
angle = 5.0;
|
||||||
|
still_trying = true;
|
||||||
|
} else if ( angle > 4.0 ) {
|
||||||
|
angle = 0.0;
|
||||||
|
still_trying = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
fclose(fp);
|
||||||
|
|
||||||
|
if ( !still_trying && ( angle > 0.0 ) ) {
|
||||||
|
// build died for some reason ... lets try one last time
|
||||||
|
// with an interior angle restriction of 0
|
||||||
|
angle = 0.0;
|
||||||
|
still_trying = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
main(int argc, char *argv[]) {
|
||||||
|
long int tile, last_tile;
|
||||||
|
bool rude = false;
|
||||||
|
bool result;
|
||||||
|
|
||||||
|
// Check usage
|
||||||
|
if ( argc < 5 ) {
|
||||||
|
printf("Usage: %s remote_machine port work_base output_base [ -r ]\n",
|
||||||
|
argv[0]);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
string host = argv[1];
|
||||||
|
int port = atoi( argv[2] );
|
||||||
|
work_base = argv[3];
|
||||||
|
output_base = argv[4];
|
||||||
|
|
||||||
|
if ( argc == 6 ) {
|
||||||
|
string option = argv[5];
|
||||||
|
if ( option == "-r" ) {
|
||||||
|
cout << "Running in RUDE mode!" << endl;
|
||||||
|
rude = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// get hostname and pid
|
||||||
|
char hostname[MAXBUF];
|
||||||
|
gethostname( hostname, MAXBUF );
|
||||||
|
pid_t pid = getpid();
|
||||||
|
|
||||||
|
char tmp[MAXBUF];
|
||||||
|
sprintf(tmp, "/tmp/result.%s.%d", hostname, pid);
|
||||||
|
string result_file = tmp;
|
||||||
|
|
||||||
|
last_tile = 0;
|
||||||
|
|
||||||
|
// check if the master switch is on
|
||||||
|
check_master_switch();
|
||||||
|
|
||||||
|
while ( (tile = get_next_task( host, port, last_tile )) >= 0 ) {
|
||||||
|
result = construct_tile( FGBucket(tile), result_file );
|
||||||
|
if ( result ) {
|
||||||
|
last_tile = tile;
|
||||||
|
} else {
|
||||||
|
last_tile = -tile;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if the master switch is on
|
||||||
|
check_master_switch();
|
||||||
|
|
||||||
|
// niceness policy: This whole process should run niced. But
|
||||||
|
// additionally, if there is interactive use, we will sleep
|
||||||
|
// for 60 seconds between each tile to stagger out the load
|
||||||
|
// and impose less of an impact on the machine.
|
||||||
|
if ( !system_free() && !rude) {
|
||||||
|
cout << "System has interactive use, sleeping for "
|
||||||
|
<< BUSY_WAIT_TIME << " seconds..." << endl;
|
||||||
|
sleep( BUSY_WAIT_TIME );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
406
src/BuildTiles/Parallel/server.cxx
Normal file
406
src/BuildTiles/Parallel/server.cxx
Normal file
|
@ -0,0 +1,406 @@
|
||||||
|
// remote_server.c -- Written by Curtis Olson
|
||||||
|
// -- for CSci 5502
|
||||||
|
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <sys/time.h> // FD_ISSET(), etc.
|
||||||
|
#include <sys/stat.h> // for stat()
|
||||||
|
#include <time.h> // for time();
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include <sys/socket.h> // bind
|
||||||
|
#include <netinet/in.h>
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include <simgear/newbucket.hxx>
|
||||||
|
|
||||||
|
|
||||||
|
#if defined (sun)
|
||||||
|
# define WAIT_ANY (pid_t)-1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define MAXBUF 1024
|
||||||
|
|
||||||
|
|
||||||
|
static double start_lon, start_lat;
|
||||||
|
static double lat = 0.0;
|
||||||
|
static double lon = 0.0;
|
||||||
|
static double dy = 0.0;
|
||||||
|
static int pass = 0;
|
||||||
|
|
||||||
|
|
||||||
|
int make_socket (unsigned short int* port) {
|
||||||
|
int sock;
|
||||||
|
struct sockaddr_in name;
|
||||||
|
socklen_t length;
|
||||||
|
|
||||||
|
// Create the socket.
|
||||||
|
sock = socket (PF_INET, SOCK_STREAM, 0);
|
||||||
|
if (sock < 0) {
|
||||||
|
perror ("socket");
|
||||||
|
exit (EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Give the socket a name.
|
||||||
|
name.sin_family = AF_INET;
|
||||||
|
name.sin_addr.s_addr = INADDR_ANY;
|
||||||
|
name.sin_port = 0 /* htons (port) */;
|
||||||
|
name.sin_addr.s_addr = htonl (INADDR_ANY);
|
||||||
|
if (bind (sock, (struct sockaddr *) &name, sizeof (name)) < 0) {
|
||||||
|
perror ("bind");
|
||||||
|
exit (EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find the assigned port number
|
||||||
|
length = sizeof(struct sockaddr_in);
|
||||||
|
if ( getsockname(sock, (struct sockaddr *) &name, &length) ) {
|
||||||
|
perror("Cannot get socket's port number");
|
||||||
|
}
|
||||||
|
*port = ntohs(name.sin_port);
|
||||||
|
|
||||||
|
return sock;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
// let's keep these two around for a while in case we need to revive
|
||||||
|
// them
|
||||||
|
|
||||||
|
// return true if file exists
|
||||||
|
static bool file_exists( const string& file ) {
|
||||||
|
struct stat buf;
|
||||||
|
|
||||||
|
if ( stat( file.c_str(), &buf ) == 0 ) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// check if the specified tile has data defined for it [ depricated ]
|
||||||
|
static bool has_data( const string& path, const FGBucket& b ) {
|
||||||
|
string dem_file = path + ".dem" + "/" + b.gen_base_path()
|
||||||
|
+ "/" + b.gen_index_str() + ".dem";
|
||||||
|
if ( file_exists( dem_file ) ) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
dem_file += ".gz";
|
||||||
|
if ( file_exists( dem_file ) ) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
// initialize the tile counting system
|
||||||
|
void init_tile_count( const string& chunk ) {
|
||||||
|
// pre-pass
|
||||||
|
pass = 0;
|
||||||
|
|
||||||
|
// initial bogus value
|
||||||
|
lat = 100;
|
||||||
|
|
||||||
|
// determine tile height
|
||||||
|
FGBucket tmp1( 0.0, 0.0 );
|
||||||
|
dy = tmp1.get_height();
|
||||||
|
|
||||||
|
string lons = chunk.substr(0, 4);
|
||||||
|
string lats = chunk.substr(4, 3);
|
||||||
|
cout << "lons = " << lons << " lats = " << lats << endl;
|
||||||
|
|
||||||
|
string horz = lons.substr(0, 1);
|
||||||
|
start_lon = atof( lons.substr(1,3).c_str() );
|
||||||
|
if ( horz == "w" ) { start_lon *= -1; }
|
||||||
|
|
||||||
|
string vert = lats.substr(0, 1);
|
||||||
|
start_lat = atof( lats.substr(1,2).c_str() );
|
||||||
|
if ( vert == "s" ) { start_lat *= -1; }
|
||||||
|
|
||||||
|
cout << "start_lon = " << start_lon << " start_lat = " << start_lat
|
||||||
|
<< endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// return the next tile
|
||||||
|
long int get_next_tile() {
|
||||||
|
FGBucket b;
|
||||||
|
static double shift_over = 0.0;
|
||||||
|
static double shift_up = 0.0;
|
||||||
|
static bool first_time = true;
|
||||||
|
static time_t start_seconds, seconds;
|
||||||
|
static int counter;
|
||||||
|
static int global_counter;
|
||||||
|
|
||||||
|
// first time this routine is called, init counters
|
||||||
|
if ( first_time ) {
|
||||||
|
first_time = false;
|
||||||
|
start_seconds = seconds = time(NULL);
|
||||||
|
counter = global_counter = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// cout << "lon = " << lon << " lat = " << lat << endl;
|
||||||
|
// cout << "start_lat = " << start_lat << endl;
|
||||||
|
|
||||||
|
if ( lon > start_lon + 10.0 ) {
|
||||||
|
// increment to next row
|
||||||
|
// skip every other row (to avoid two clients working on
|
||||||
|
// adjacent tiles)
|
||||||
|
lat += 2.0 * dy;
|
||||||
|
|
||||||
|
FGBucket tmp( 0.0, lat );
|
||||||
|
double dx = tmp.get_width();
|
||||||
|
lon = start_lon + (shift_over*dx) + (dx*0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( lat > start_lat + 10.0 ) {
|
||||||
|
++pass;
|
||||||
|
if ( pass == 1 ) {
|
||||||
|
shift_over = 0.0;
|
||||||
|
shift_up = 0.0;
|
||||||
|
} else if ( pass == 2 ) {
|
||||||
|
shift_over = 1.0;
|
||||||
|
shift_up = 0.0;
|
||||||
|
} else if ( pass == 3 ) {
|
||||||
|
shift_over = 0.0;
|
||||||
|
shift_up = 1.0;
|
||||||
|
} else if ( pass == 4 ) {
|
||||||
|
shift_over = 1.0;
|
||||||
|
shift_up = 1.0;
|
||||||
|
} else {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// reset lat
|
||||||
|
// lat = -89.0 + (shift_up*dy) - (dy*0.5);
|
||||||
|
// lat = 27.0 + (0*dy) + (dy*0.5);
|
||||||
|
lat = start_lat + (shift_up*dy) + (dy*0.5);
|
||||||
|
|
||||||
|
// reset lon
|
||||||
|
FGBucket tmp( 0.0, lat );
|
||||||
|
double dx = tmp.get_width();
|
||||||
|
// lon = -82 + (shift_over*dx) + (dx*0.5);
|
||||||
|
lon = start_lon + (shift_over*dx) + (dx*0.5);
|
||||||
|
|
||||||
|
cout << "starting pass = " << pass
|
||||||
|
<< " with lat = " << lat << " lon = " << lon << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if ( ! start_lon ) {
|
||||||
|
// lon = -180 + dx * 0.5;
|
||||||
|
// } else {
|
||||||
|
// start_lon = false;
|
||||||
|
// }
|
||||||
|
|
||||||
|
b = FGBucket( lon, lat );
|
||||||
|
|
||||||
|
// increment to next tile
|
||||||
|
FGBucket tmp( 0.0, lat );
|
||||||
|
double dx = tmp.get_width();
|
||||||
|
|
||||||
|
// skip every other column (to avoid two clients working on
|
||||||
|
// adjacent tiles)
|
||||||
|
lon += 2.0 * dx;
|
||||||
|
|
||||||
|
++global_counter;
|
||||||
|
++counter;
|
||||||
|
|
||||||
|
time_t tmp_time = time(NULL);
|
||||||
|
if ( tmp_time != seconds ) {
|
||||||
|
seconds = tmp_time;
|
||||||
|
cout << "Current tile per second rate = " << counter << endl;
|
||||||
|
cout << "Overall tile per second rate = "
|
||||||
|
<< global_counter / ( seconds - start_seconds ) << endl;
|
||||||
|
counter = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return b.gen_index();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// log a pending tile (has been given out as a taks for some client)
|
||||||
|
void log_pending_tile( const string& path, long int tile ) {
|
||||||
|
FGBucket b(tile);
|
||||||
|
|
||||||
|
string pending_file = path + "/" + b.gen_index_str() + ".pending";
|
||||||
|
|
||||||
|
string command = "touch " + pending_file;
|
||||||
|
system( command.c_str() );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// a tile is finished (removed the .pending file)
|
||||||
|
void log_finished_tile( const string& path, long int tile ) {
|
||||||
|
FGBucket b(tile);
|
||||||
|
|
||||||
|
string finished_file = path + "/" + b.gen_index_str() + ".pending";
|
||||||
|
// cout << "unlinking " << finished_file << endl;
|
||||||
|
unlink( finished_file.c_str() );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// make note of a failed tile
|
||||||
|
void log_failed_tile( const string& path, long int tile ) {
|
||||||
|
FGBucket b(tile);
|
||||||
|
|
||||||
|
string failed_file = path + "/" + b.gen_index_str() + ".failed";
|
||||||
|
|
||||||
|
string command = "touch " + failed_file;
|
||||||
|
system( command.c_str() );
|
||||||
|
|
||||||
|
cout << "logged bad tile = " << tile << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// display usage and exit
|
||||||
|
void usage( const string name ) {
|
||||||
|
cout << "Usage: " << name << " <work_base> <output_base> chunk1 chunk2 ..."
|
||||||
|
<< endl;
|
||||||
|
cout << "\twhere chunk represent the south west corner of a 10x10 degree"
|
||||||
|
<< endl;
|
||||||
|
cout << "\tsquare and is of the form [we]xxx[ns]yy. For example:"
|
||||||
|
<< endl;
|
||||||
|
cout << "\tw020n10 e150s70" << endl;
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int main( int argc, char **argv ) {
|
||||||
|
int arg_counter;
|
||||||
|
long int next_tile;
|
||||||
|
int sock, msgsock, length, pid;
|
||||||
|
fd_set ready;
|
||||||
|
short unsigned int port;
|
||||||
|
|
||||||
|
// quick argument sanity check
|
||||||
|
if ( argc < 4 ) {
|
||||||
|
usage( argv[0] );
|
||||||
|
}
|
||||||
|
|
||||||
|
string work_base = argv[1];
|
||||||
|
string output_base = argv[2];
|
||||||
|
|
||||||
|
arg_counter = 3;
|
||||||
|
|
||||||
|
// initialize tile counter / incrementer
|
||||||
|
init_tile_count( argv[arg_counter++] );
|
||||||
|
|
||||||
|
// temp test
|
||||||
|
// while ( (next_tile = get_next_tile()) != -1 ) {
|
||||||
|
// cout << next_tile << " " << FGBucket(next_tile) << endl;
|
||||||
|
// }
|
||||||
|
// cout << "done" << endl;
|
||||||
|
// exit(0);
|
||||||
|
|
||||||
|
// create the status directory
|
||||||
|
string status_dir = work_base + "/Status";
|
||||||
|
string command = "mkdir -p " + status_dir;
|
||||||
|
system( command.c_str() );
|
||||||
|
|
||||||
|
// setup socket to listen on
|
||||||
|
sock = make_socket( &port );
|
||||||
|
cout << "socket is connected to port = " << port << endl;
|
||||||
|
|
||||||
|
// Specify the maximum length of the connection queue
|
||||||
|
listen(sock, 10);
|
||||||
|
|
||||||
|
for ( ;; ) {
|
||||||
|
FD_ZERO(&ready);
|
||||||
|
FD_SET(sock, &ready);
|
||||||
|
|
||||||
|
// block until we get some input on sock
|
||||||
|
select(32, &ready, 0, 0, NULL);
|
||||||
|
|
||||||
|
if ( FD_ISSET(sock, &ready) ) {
|
||||||
|
// printf("%d %d Incomming message --> ", getpid(), pid);
|
||||||
|
|
||||||
|
// get the next tile to work on
|
||||||
|
next_tile = get_next_tile();
|
||||||
|
|
||||||
|
if ( next_tile == -1 ) {
|
||||||
|
// end of chunk see if there are more chunks
|
||||||
|
if ( arg_counter < argc ) {
|
||||||
|
// still more chunks to process
|
||||||
|
init_tile_count( argv[arg_counter++] );
|
||||||
|
next_tile = get_next_tile();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cout << "Bucket = " << FGBucket(next_tile)
|
||||||
|
<< " (" << pass << ")" << endl;
|
||||||
|
|
||||||
|
log_pending_tile( status_dir, next_tile );
|
||||||
|
// cout << "next tile = " << next_tile << endl;;
|
||||||
|
|
||||||
|
msgsock = accept(sock, 0, 0);
|
||||||
|
// cout << "msgsock = " << msgsock << endl;
|
||||||
|
|
||||||
|
// spawn a child
|
||||||
|
pid = fork();
|
||||||
|
|
||||||
|
if ( pid < 0 ) {
|
||||||
|
// error
|
||||||
|
perror("Cannot fork child process");
|
||||||
|
exit(-1);
|
||||||
|
} else if ( pid > 0 ) {
|
||||||
|
// This is the parent
|
||||||
|
close(msgsock);
|
||||||
|
|
||||||
|
// clean up all of our zombie children
|
||||||
|
int status;
|
||||||
|
while ( (pid = waitpid( WAIT_ANY, &status, WNOHANG )) > 0 ) {
|
||||||
|
// cout << "waitpid(): pid = " << pid
|
||||||
|
// << " status = " << status << endl;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// This is the child
|
||||||
|
|
||||||
|
// cout << "new process started to handle new connection for "
|
||||||
|
// << next_tile << endl;
|
||||||
|
|
||||||
|
// Read client's message (which is the status of the
|
||||||
|
// last scenery creation task.)
|
||||||
|
char buf[MAXBUF];
|
||||||
|
if ( (length = read(msgsock, buf, MAXBUF)) < 0) {
|
||||||
|
perror("Cannot read command");
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
buf[length] = '\0';
|
||||||
|
long int returned_tile = atoi(buf);
|
||||||
|
cout << "client returned = " << returned_tile << endl;
|
||||||
|
|
||||||
|
// record status
|
||||||
|
if ( returned_tile < 0 ) {
|
||||||
|
// failure
|
||||||
|
log_failed_tile( status_dir, -returned_tile );
|
||||||
|
log_finished_tile( status_dir, -returned_tile );
|
||||||
|
} else {
|
||||||
|
// success
|
||||||
|
log_finished_tile( status_dir, returned_tile );
|
||||||
|
}
|
||||||
|
|
||||||
|
// reply to the client
|
||||||
|
char message[MAXBUF];
|
||||||
|
sprintf(message, "%ld", next_tile);
|
||||||
|
length = strlen(message);
|
||||||
|
if ( write(msgsock, message, length) < 0 ) {
|
||||||
|
perror("Cannot write to stream socket");
|
||||||
|
}
|
||||||
|
close(msgsock);
|
||||||
|
// cout << "process for " << next_tile << " ended" << endl;
|
||||||
|
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
10
src/BuildTiles/Triangulate/Makefile.am
Normal file
10
src/BuildTiles/Triangulate/Makefile.am
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
noinst_LIBRARIES = libTriangulate.a
|
||||||
|
|
||||||
|
libTriangulate_a_SOURCES = \
|
||||||
|
triangle.cxx triangle.hxx \
|
||||||
|
trieles.cxx trieles.hxx
|
||||||
|
|
||||||
|
INCLUDES += \
|
||||||
|
-I$(top_builddir) \
|
||||||
|
-I$(top_builddir)/Lib \
|
||||||
|
-I$(top_builddir)/Construct
|
529
src/BuildTiles/Triangulate/triangle.cxx
Normal file
529
src/BuildTiles/Triangulate/triangle.cxx
Normal file
|
@ -0,0 +1,529 @@
|
||||||
|
// triangle.cxx -- "Triangle" interface class
|
||||||
|
//
|
||||||
|
// Written by Curtis Olson, started March 1999.
|
||||||
|
//
|
||||||
|
// Copyright (C) 1999 Curtis L. Olson - curt@flightgear.org
|
||||||
|
//
|
||||||
|
// This program is free software; you can redistribute it and/or
|
||||||
|
// modify it under the terms of the GNU General Public License as
|
||||||
|
// published by the Free Software Foundation; either version 2 of the
|
||||||
|
// License, or (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful, but
|
||||||
|
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
// General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
//
|
||||||
|
// $Id$
|
||||||
|
|
||||||
|
|
||||||
|
#include <Build/poly_support.hxx>
|
||||||
|
#include <Polygon/polygon.hxx>
|
||||||
|
|
||||||
|
#include "triangle.hxx"
|
||||||
|
|
||||||
|
|
||||||
|
// Constructor
|
||||||
|
FGTriangle::FGTriangle( void ) {
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Destructor
|
||||||
|
FGTriangle::~FGTriangle( void ) {
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// populate this class based on the specified gpc_polys list
|
||||||
|
int
|
||||||
|
FGTriangle::build( const point_list& corner_list,
|
||||||
|
const point_list& fit_list,
|
||||||
|
const FGPolyList& gpc_polys )
|
||||||
|
{
|
||||||
|
int debug_counter = 0;
|
||||||
|
int index;
|
||||||
|
|
||||||
|
in_nodes.clear();
|
||||||
|
in_segs.clear();
|
||||||
|
|
||||||
|
// Point3D junkp;
|
||||||
|
// int junkc = 0;
|
||||||
|
// char junkn[256];
|
||||||
|
// FILE *junkfp;
|
||||||
|
|
||||||
|
// traverse the dem corner and fit lists and gpc_polys building a
|
||||||
|
// unified node list and converting the polygons so that they
|
||||||
|
// reference the node list by index (starting at zero) rather than
|
||||||
|
// listing the points explicitely
|
||||||
|
|
||||||
|
// first the corners since these are important
|
||||||
|
const_point_list_iterator f_current, f_last;
|
||||||
|
f_current = corner_list.begin();
|
||||||
|
f_last = corner_list.end();
|
||||||
|
for ( ; f_current != f_last; ++f_current ) {
|
||||||
|
index = in_nodes.unique_add( *f_current );
|
||||||
|
}
|
||||||
|
|
||||||
|
// next process the polygons
|
||||||
|
FGPolygon gpc_poly;
|
||||||
|
const_poly_list_iterator current, last;
|
||||||
|
|
||||||
|
// process polygons in priority order
|
||||||
|
cout << "prepairing node list and polygons" << endl;
|
||||||
|
|
||||||
|
for ( int i = 0; i < FG_MAX_AREA_TYPES; ++i ) {
|
||||||
|
polylist[i].clear();
|
||||||
|
|
||||||
|
cout << "area type = " << i << endl;
|
||||||
|
debug_counter = 0;
|
||||||
|
current = gpc_polys.polys[i].begin();
|
||||||
|
last = gpc_polys.polys[i].end();
|
||||||
|
for ( ; current != last; ++current ) {
|
||||||
|
gpc_poly = *current;
|
||||||
|
|
||||||
|
cout << "processing a polygon, contours = "
|
||||||
|
<< gpc_poly.contours() << endl;
|
||||||
|
|
||||||
|
if (gpc_poly.contours() <= 0 ) {
|
||||||
|
cout << "FATAL ERROR! no contours in this polygon" << endl;
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
int j;
|
||||||
|
for ( j = 0; j < gpc_poly.contours(); ++j ) {
|
||||||
|
cout << " processing contour = " << j << ", nodes = "
|
||||||
|
<< gpc_poly.contour_size( j ) << ", hole = "
|
||||||
|
<< gpc_poly.get_hole_flag( j ) << endl;
|
||||||
|
|
||||||
|
// sprintf(junkn, "g.%d", junkc++);
|
||||||
|
// junkfp = fopen(junkn, "w");
|
||||||
|
|
||||||
|
for ( int k = 0; k < gpc_poly.contour_size( j ); k++ ) {
|
||||||
|
Point3D p = gpc_poly.get_pt( j, k );
|
||||||
|
index = in_nodes.unique_add( p );
|
||||||
|
// junkp = in_nodes.get_node( index );
|
||||||
|
// fprintf(junkfp, "%.4f %.4f\n", junkp.x(), junkp.y());
|
||||||
|
// cout << " - " << index << endl;
|
||||||
|
}
|
||||||
|
// fprintf(junkfp, "%.4f %.4f\n",
|
||||||
|
// gpc_poly->contour[j].vertex[0].x,
|
||||||
|
// gpc_poly->contour[j].vertex[0].y);
|
||||||
|
// fclose(junkfp);
|
||||||
|
}
|
||||||
|
|
||||||
|
Point3D inside_pt;
|
||||||
|
for ( j = 0; j < gpc_poly.contours(); ++j ) {
|
||||||
|
inside_pt = calc_point_inside( gpc_poly, j, in_nodes );
|
||||||
|
gpc_poly.set_point_inside( j, inside_pt );
|
||||||
|
}
|
||||||
|
|
||||||
|
polylist[i].push_back( gpc_poly );
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
// temporary ... write out hole/polygon info for debugging
|
||||||
|
for ( j = 0; j < (int)gpc_poly.contours(); ++j ) {
|
||||||
|
char pname[256];
|
||||||
|
sprintf(pname, "poly%02d-%02d-%02d", i, debug_counter, j);
|
||||||
|
cout << "writing to " << pname << endl;
|
||||||
|
FILE *fp = fopen( pname, "w" );
|
||||||
|
Point3D point;
|
||||||
|
for ( int k = 0; k < gpc_poly.contour_size( j ); ++k ) {
|
||||||
|
point = gpc_poly.get_pt( j, k );
|
||||||
|
fprintf( fp, "%.6f %.6f\n", point.x(), point.y() );
|
||||||
|
}
|
||||||
|
point = gpc_poly.get_pt( j, 0 );
|
||||||
|
fprintf( fp, "%.6f %.6f\n", point.x(), point.y() );
|
||||||
|
fclose(fp);
|
||||||
|
|
||||||
|
char hname[256];
|
||||||
|
sprintf(hname, "hole%02d-%02d-%02d", i, debug_counter, j);
|
||||||
|
FILE *fh = fopen( hname, "w" );
|
||||||
|
point = gpc_poly.get_point_inside( j );
|
||||||
|
fprintf( fh, "%.6f %.6f\n", point.x(), point.y() );
|
||||||
|
fclose(fh);
|
||||||
|
}
|
||||||
|
|
||||||
|
// cout << "type a letter + enter to continue: ";
|
||||||
|
// string input;
|
||||||
|
// cin >> input;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
++debug_counter;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// last, do the rest of the height nodes
|
||||||
|
f_current = fit_list.begin();
|
||||||
|
f_last = fit_list.end();
|
||||||
|
for ( ; f_current != f_last; ++f_current ) {
|
||||||
|
index = in_nodes.course_add( *f_current );
|
||||||
|
}
|
||||||
|
|
||||||
|
for ( int i = 0; i < FG_MAX_AREA_TYPES; ++i ) {
|
||||||
|
if ( polylist[i].size() ) {
|
||||||
|
cout << get_area_name((AreaType)i) << " = "
|
||||||
|
<< polylist[i].size() << endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// traverse the polygon lists and build the segment (edge) list
|
||||||
|
// that is used by the "Triangle" lib.
|
||||||
|
|
||||||
|
cout << "building segment list" << endl;
|
||||||
|
int i1, i2;
|
||||||
|
Point3D p1, p2;
|
||||||
|
point_list node_list = in_nodes.get_node_list();
|
||||||
|
FGPolygon poly;
|
||||||
|
|
||||||
|
for ( int i = 0; i < FG_MAX_AREA_TYPES; ++i ) {
|
||||||
|
cout << "area type = " << i << endl;
|
||||||
|
poly_list_iterator tp_current, tp_last;
|
||||||
|
tp_current = polylist[i].begin();
|
||||||
|
tp_last = polylist[i].end();
|
||||||
|
|
||||||
|
// process each polygon in list
|
||||||
|
for ( ; tp_current != tp_last; ++tp_current ) {
|
||||||
|
poly = *tp_current;
|
||||||
|
cout << " processing a polygon with contours = "
|
||||||
|
<< poly.contours() << endl;
|
||||||
|
for ( int j = 0; j < (int)poly.contours(); ++j) {
|
||||||
|
for ( int k = 0; k < (int)(poly.contour_size(j) - 1); ++k ) {
|
||||||
|
p1 = poly.get_pt( j, k );
|
||||||
|
p2 = poly.get_pt( j, k + 1 );
|
||||||
|
i1 = in_nodes.find( p1 );
|
||||||
|
i2 = in_nodes.find( p2 );
|
||||||
|
// calc_line_params(i1, i2, &m, &b);
|
||||||
|
if ( i == (int)HoleArea ) {
|
||||||
|
// mark as a boundary
|
||||||
|
in_segs.unique_divide_and_add( node_list,
|
||||||
|
FGTriSeg(i1, i2, 1) );
|
||||||
|
} else {
|
||||||
|
// non boundary
|
||||||
|
in_segs.unique_divide_and_add( node_list,
|
||||||
|
FGTriSeg(i1, i2, 0) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
p1 = poly.get_pt( j, 0 );
|
||||||
|
p2 = poly.get_pt( j, poly.contour_size(j) - 1 );
|
||||||
|
i1 = in_nodes.find( p1 );
|
||||||
|
i2 = in_nodes.find( p2 );
|
||||||
|
// calc_line_params(i1, i2, &m, &b);
|
||||||
|
if ( i == (int)HoleArea ) {
|
||||||
|
// mark as a boundary
|
||||||
|
in_segs.unique_divide_and_add( node_list,
|
||||||
|
FGTriSeg(i1, i2, 1) );
|
||||||
|
} else {
|
||||||
|
// non boundary
|
||||||
|
in_segs.unique_divide_and_add( node_list,
|
||||||
|
FGTriSeg(i1, i2, 0) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// populate this class based on the specified gpc_polys list
|
||||||
|
int FGTriangle::rebuild( FGConstruct& c ) {
|
||||||
|
in_nodes.clear();
|
||||||
|
in_segs.clear();
|
||||||
|
|
||||||
|
in_nodes = c.get_tri_nodes();
|
||||||
|
in_segs = c.get_tri_segs();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void write_out_data(struct triangulateio *out) {
|
||||||
|
FILE *node = fopen("tile.node", "w");
|
||||||
|
fprintf(node, "%d 2 %d 0\n",
|
||||||
|
out->numberofpoints, out->numberofpointattributes);
|
||||||
|
for (int i = 0; i < out->numberofpoints; ++i) {
|
||||||
|
fprintf(node, "%d %.6f %.6f %.2f\n",
|
||||||
|
i, out->pointlist[2*i], out->pointlist[2*i + 1], 0.0);
|
||||||
|
}
|
||||||
|
fclose(node);
|
||||||
|
|
||||||
|
FILE *ele = fopen("tile.ele", "w");
|
||||||
|
fprintf(ele, "%d 3 0\n", out->numberoftriangles);
|
||||||
|
for (int i = 0; i < out->numberoftriangles; ++i) {
|
||||||
|
fprintf(ele, "%d ", i);
|
||||||
|
for (int j = 0; j < out->numberofcorners; ++j) {
|
||||||
|
fprintf(ele, "%d ", out->trianglelist[i * out->numberofcorners + j]);
|
||||||
|
}
|
||||||
|
for (int j = 0; j < out->numberoftriangleattributes; ++j) {
|
||||||
|
fprintf(ele, "%.6f ",
|
||||||
|
out->triangleattributelist[i
|
||||||
|
* out->numberoftriangleattributes
|
||||||
|
+ j]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
fprintf(ele, "\n");
|
||||||
|
}
|
||||||
|
fclose(ele);
|
||||||
|
|
||||||
|
FILE *fp = fopen("tile.poly", "w");
|
||||||
|
fprintf(fp, "0 2 1 0\n");
|
||||||
|
fprintf(fp, "%d 1\n", out->numberofsegments);
|
||||||
|
for (int i = 0; i < out->numberofsegments; ++i) {
|
||||||
|
fprintf(fp, "%d %d %d %d\n",
|
||||||
|
i, out->segmentlist[2*i], out->segmentlist[2*i + 1],
|
||||||
|
out->segmentmarkerlist[i] );
|
||||||
|
}
|
||||||
|
fprintf(fp, "%d\n", out->numberofholes);
|
||||||
|
for (int i = 0; i < out->numberofholes; ++i) {
|
||||||
|
fprintf(fp, "%d %.6f %.6f\n",
|
||||||
|
i, out->holelist[2*i], out->holelist[2*i + 1]);
|
||||||
|
}
|
||||||
|
fprintf(fp, "%d\n", out->numberofregions);
|
||||||
|
for (int i = 0; i < out->numberofregions; ++i) {
|
||||||
|
fprintf(fp, "%d %.6f %.6f %.6f\n",
|
||||||
|
i, out->regionlist[4*i], out->regionlist[4*i + 1],
|
||||||
|
out->regionlist[4*i + 2]);
|
||||||
|
}
|
||||||
|
fclose(fp);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Front end triangulator for polygon list. Allocates and builds up
|
||||||
|
// all the needed structures for the triangulator, runs it, copies the
|
||||||
|
// results, and frees all the data structures used by the
|
||||||
|
// triangulator. "pass" can be 1 or 2. 1 = first pass which
|
||||||
|
// generates extra nodes for a better triangulation. 2 = second pass
|
||||||
|
// after split/reassem where we don't want any extra nodes generated.
|
||||||
|
|
||||||
|
int FGTriangle::run_triangulate( const string& angle, const int pass ) {
|
||||||
|
FGPolygon poly;
|
||||||
|
Point3D p;
|
||||||
|
struct triangulateio in, out, vorout;
|
||||||
|
int counter;
|
||||||
|
|
||||||
|
// point list
|
||||||
|
point_list node_list = in_nodes.get_node_list();
|
||||||
|
in.numberofpoints = node_list.size();
|
||||||
|
in.pointlist = (REAL *) malloc(in.numberofpoints * 2 * sizeof(REAL));
|
||||||
|
|
||||||
|
for ( int i = 0; i < in.numberofpoints; ++i ) {
|
||||||
|
in.pointlist[2*i] = node_list[i].x();
|
||||||
|
in.pointlist[2*i + 1] = node_list[i].y();
|
||||||
|
}
|
||||||
|
|
||||||
|
in.numberofpointattributes = 1;
|
||||||
|
in.pointattributelist = (REAL *) malloc(in.numberofpoints *
|
||||||
|
in.numberofpointattributes *
|
||||||
|
sizeof(REAL));
|
||||||
|
for ( int i = 0; i < in.numberofpoints * in.numberofpointattributes; ++i) {
|
||||||
|
in.pointattributelist[i] = node_list[i].z();
|
||||||
|
}
|
||||||
|
|
||||||
|
in.pointmarkerlist = (int *) malloc(in.numberofpoints * sizeof(int));
|
||||||
|
for ( int i = 0; i < in.numberofpoints; ++i) {
|
||||||
|
in.pointmarkerlist[i] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// triangle list
|
||||||
|
in.numberoftriangles = 0;
|
||||||
|
|
||||||
|
// segment list
|
||||||
|
triseg_list seg_list = in_segs.get_seg_list();
|
||||||
|
in.numberofsegments = seg_list.size();
|
||||||
|
in.segmentlist = (int *) malloc(in.numberofsegments * 2 * sizeof(int));
|
||||||
|
in.segmentmarkerlist = (int *) malloc(in.numberofsegments * sizeof(int));
|
||||||
|
|
||||||
|
triseg_list_iterator s_current, s_last;
|
||||||
|
s_current = seg_list.begin();
|
||||||
|
s_last = seg_list.end();
|
||||||
|
counter = 0;
|
||||||
|
for ( ; s_current != s_last; ++s_current ) {
|
||||||
|
in.segmentlist[counter++] = s_current->get_n1();
|
||||||
|
in.segmentlist[counter++] = s_current->get_n2();
|
||||||
|
}
|
||||||
|
s_current = seg_list.begin();
|
||||||
|
s_last = seg_list.end();
|
||||||
|
counter = 0;
|
||||||
|
for ( ; s_current != s_last; ++s_current ) {
|
||||||
|
in.segmentmarkerlist[counter++] = s_current->get_boundary_marker();
|
||||||
|
}
|
||||||
|
|
||||||
|
// hole list (make holes for airport ignore areas)
|
||||||
|
in.numberofholes = polylist[(int)HoleArea].size();
|
||||||
|
in.holelist = (REAL *) malloc(in.numberofholes * 2 * sizeof(REAL));
|
||||||
|
|
||||||
|
poly_list_iterator h_current, h_last;
|
||||||
|
h_current = polylist[(int)HoleArea].begin();
|
||||||
|
h_last = polylist[(int)HoleArea].end();
|
||||||
|
counter = 0;
|
||||||
|
for ( ; h_current != h_last; ++h_current ) {
|
||||||
|
poly = *h_current;
|
||||||
|
for ( int j = 0; j < poly.contours(); ++j ) {
|
||||||
|
p = poly.get_point_inside( j );
|
||||||
|
in.holelist[counter++] = p.x();
|
||||||
|
in.holelist[counter++] = p.y();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// region list
|
||||||
|
in.numberofregions = 0;
|
||||||
|
for ( int i = 0; i < FG_MAX_AREA_TYPES; ++i ) {
|
||||||
|
poly_list_iterator h_current, h_last;
|
||||||
|
h_current = polylist[i].begin();
|
||||||
|
h_last = polylist[i].end();
|
||||||
|
for ( ; h_current != h_last; ++h_current ) {
|
||||||
|
poly = *h_current;
|
||||||
|
for ( int j = 0; j < poly.contours(); ++j ) {
|
||||||
|
if ( ! poly.get_hole_flag( j ) ) {
|
||||||
|
++in.numberofregions;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
in.regionlist = (REAL *) malloc(in.numberofregions * 4 * sizeof(REAL));
|
||||||
|
counter = 0;
|
||||||
|
for ( int i = 0; i < FG_MAX_AREA_TYPES; ++i ) {
|
||||||
|
poly_list_iterator h_current, h_last;
|
||||||
|
h_current = polylist[(int)i].begin();
|
||||||
|
h_last = polylist[(int)i].end();
|
||||||
|
for ( ; h_current != h_last; ++h_current ) {
|
||||||
|
poly = *h_current;
|
||||||
|
for ( int j = 0; j < poly.contours(); ++j ) {
|
||||||
|
if ( ! poly.get_hole_flag( j ) ) {
|
||||||
|
p = poly.get_point_inside( j );
|
||||||
|
cout << "Region point = " << p << endl;
|
||||||
|
in.regionlist[counter++] = p.x(); // x coord
|
||||||
|
in.regionlist[counter++] = p.y(); // y coord
|
||||||
|
in.regionlist[counter++] = i; // region attribute
|
||||||
|
in.regionlist[counter++] = -1.0; // area constraint
|
||||||
|
// (unused)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// prep the output structures
|
||||||
|
out.pointlist = (REAL *) NULL; // Not needed if -N switch used.
|
||||||
|
// Not needed if -N switch used or number of point attributes is zero:
|
||||||
|
out.pointattributelist = (REAL *) NULL;
|
||||||
|
out.pointmarkerlist = (int *) NULL; // Not needed if -N or -B switch used.
|
||||||
|
out.trianglelist = (int *) NULL; // Not needed if -E switch used.
|
||||||
|
// Not needed if -E switch used or number of triangle attributes is zero:
|
||||||
|
out.triangleattributelist = (REAL *) NULL;
|
||||||
|
out.neighborlist = (int *) NULL; // Needed only if -n switch used.
|
||||||
|
// Needed only if segments are output (-p or -c) and -P not used:
|
||||||
|
out.segmentlist = (int *) NULL;
|
||||||
|
// Needed only if segments are output (-p or -c) and -P and -B not used:
|
||||||
|
out.segmentmarkerlist = (int *) NULL;
|
||||||
|
out.edgelist = (int *) NULL; // Needed only if -e switch used.
|
||||||
|
out.edgemarkerlist = (int *) NULL; // Needed if -e used and -B not used.
|
||||||
|
|
||||||
|
vorout.pointlist = (REAL *) NULL; // Needed only if -v switch used.
|
||||||
|
// Needed only if -v switch used and number of attributes is not zero:
|
||||||
|
vorout.pointattributelist = (REAL *) NULL;
|
||||||
|
vorout.edgelist = (int *) NULL; // Needed only if -v switch used.
|
||||||
|
vorout.normlist = (REAL *) NULL; // Needed only if -v switch used.
|
||||||
|
|
||||||
|
// TEMPORARY
|
||||||
|
write_out_data(&in);
|
||||||
|
|
||||||
|
// Triangulate the points. Switches are chosen to read and write
|
||||||
|
// a PSLG (p), preserve the convex hull (c), number everything
|
||||||
|
// from zero (z), assign a regional attribute to each element (A),
|
||||||
|
// and produce an edge list (e), and a triangle neighbor list (n).
|
||||||
|
|
||||||
|
string tri_options;
|
||||||
|
if ( pass == 1 ) {
|
||||||
|
// use a quality value of 10 (q10) meaning no interior
|
||||||
|
// triangle angles less than 10 degrees
|
||||||
|
// tri_options = "pczAen";
|
||||||
|
if ( angle == "0" ) {
|
||||||
|
tri_options = "pczAen";
|
||||||
|
} else {
|
||||||
|
tri_options = "pczq" + angle + "Aen";
|
||||||
|
}
|
||||||
|
// // string tri_options = "pzAen";
|
||||||
|
// // string tri_options = "pczq15S400Aen";
|
||||||
|
} else if ( pass == 2 ) {
|
||||||
|
// no new points on boundary (Y), no internal segment
|
||||||
|
// splitting (YY), no quality refinement (q)
|
||||||
|
tri_options = "pczYYAen";
|
||||||
|
} else {
|
||||||
|
cout << "unknown pass number = " << pass
|
||||||
|
<< " in FGTriangle::run_triangulate()" << endl;
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
cout << "Triangulation with options = " << tri_options << endl;
|
||||||
|
|
||||||
|
triangulate( (char *)tri_options.c_str(), &in, &out, &vorout );
|
||||||
|
|
||||||
|
// TEMPORARY
|
||||||
|
// write_out_data(&out);
|
||||||
|
|
||||||
|
// now copy the results back into the corresponding FGTriangle
|
||||||
|
// structures
|
||||||
|
|
||||||
|
// nodes
|
||||||
|
out_nodes.clear();
|
||||||
|
for ( int i = 0; i < out.numberofpoints; ++i ) {
|
||||||
|
Point3D p( out.pointlist[2*i], out.pointlist[2*i + 1],
|
||||||
|
out.pointattributelist[i] );
|
||||||
|
// cout << "point = " << p << endl;
|
||||||
|
out_nodes.simple_add( p );
|
||||||
|
}
|
||||||
|
|
||||||
|
// segments
|
||||||
|
out_segs.clear();
|
||||||
|
for ( int i = 0; i < out.numberofsegments; ++i ) {
|
||||||
|
out_segs.unique_add( FGTriSeg( out.segmentlist[2*i],
|
||||||
|
out.segmentlist[2*i+1],
|
||||||
|
out.segmentmarkerlist[i] ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
// triangles
|
||||||
|
elelist.clear();
|
||||||
|
int n1, n2, n3;
|
||||||
|
double attribute;
|
||||||
|
for ( int i = 0; i < out.numberoftriangles; ++i ) {
|
||||||
|
n1 = out.trianglelist[i * 3];
|
||||||
|
n2 = out.trianglelist[i * 3 + 1];
|
||||||
|
n3 = out.trianglelist[i * 3 + 2];
|
||||||
|
if ( out.numberoftriangleattributes > 0 ) {
|
||||||
|
attribute = out.triangleattributelist[i];
|
||||||
|
} else {
|
||||||
|
attribute = 0.0;
|
||||||
|
}
|
||||||
|
// cout << "triangle = " << n1 << " " << n2 << " " << n3 << endl;
|
||||||
|
|
||||||
|
elelist.push_back( FGTriEle( n1, n2, n3, attribute ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
// free mem allocated to the "Triangle" structures
|
||||||
|
free(in.pointlist);
|
||||||
|
free(in.pointattributelist);
|
||||||
|
free(in.pointmarkerlist);
|
||||||
|
free(in.regionlist);
|
||||||
|
free(out.pointlist);
|
||||||
|
free(out.pointattributelist);
|
||||||
|
free(out.pointmarkerlist);
|
||||||
|
free(out.trianglelist);
|
||||||
|
free(out.triangleattributelist);
|
||||||
|
// free(out.trianglearealist);
|
||||||
|
free(out.neighborlist);
|
||||||
|
free(out.segmentlist);
|
||||||
|
free(out.segmentmarkerlist);
|
||||||
|
free(out.edgelist);
|
||||||
|
free(out.edgemarkerlist);
|
||||||
|
free(vorout.pointlist);
|
||||||
|
free(vorout.pointattributelist);
|
||||||
|
free(vorout.edgelist);
|
||||||
|
free(vorout.normlist);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
106
src/BuildTiles/Triangulate/triangle.hxx
Normal file
106
src/BuildTiles/Triangulate/triangle.hxx
Normal file
|
@ -0,0 +1,106 @@
|
||||||
|
// triangle.hxx -- "Triangle" interface class
|
||||||
|
//
|
||||||
|
// Written by Curtis Olson, started March 1999.
|
||||||
|
//
|
||||||
|
// Copyright (C) 1999 Curtis L. Olson - curt@flightgear.org
|
||||||
|
//
|
||||||
|
// This program is free software; you can redistribute it and/or
|
||||||
|
// modify it under the terms of the GNU General Public License as
|
||||||
|
// published by the Free Software Foundation; either version 2 of the
|
||||||
|
// License, or (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful, but
|
||||||
|
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
// General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
//
|
||||||
|
// $Id$
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef _TRIANGLE_HXX
|
||||||
|
#define _TRIANGLE_HXX
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef __cplusplus
|
||||||
|
# error This library requires C++
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#include <simgear/compiler.h>
|
||||||
|
#include <simgear/point3d.hxx>
|
||||||
|
|
||||||
|
#include <Array/array.hxx>
|
||||||
|
#include <Clipper/clipper.hxx>
|
||||||
|
#include <Main/construct.hxx>
|
||||||
|
|
||||||
|
#include <Build/trinodes.hxx>
|
||||||
|
#include <Build/trisegs.hxx>
|
||||||
|
#include <Polygon/names.hxx>
|
||||||
|
#include <Polygon/polygon.hxx>
|
||||||
|
|
||||||
|
#define REAL double
|
||||||
|
extern "C" {
|
||||||
|
#include <Triangle/triangle.h>
|
||||||
|
}
|
||||||
|
|
||||||
|
#include "trieles.hxx"
|
||||||
|
|
||||||
|
|
||||||
|
class FGTriangle {
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
// list of nodes
|
||||||
|
FGTriNodes in_nodes;
|
||||||
|
FGTriNodes out_nodes;
|
||||||
|
|
||||||
|
// list of segments
|
||||||
|
FGTriSegments in_segs;
|
||||||
|
FGTriSegments out_segs;
|
||||||
|
|
||||||
|
// polygon list
|
||||||
|
poly_list polylist[FG_MAX_AREA_TYPES];
|
||||||
|
|
||||||
|
// triangle list
|
||||||
|
triele_list elelist;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
// Constructor and destructor
|
||||||
|
FGTriangle( void );
|
||||||
|
~FGTriangle( void );
|
||||||
|
|
||||||
|
// add nodes from the dem fit
|
||||||
|
int add_nodes();
|
||||||
|
|
||||||
|
// populate this class based on the specified gpc_polys list
|
||||||
|
int build( const point_list& corner_list,
|
||||||
|
const point_list& fit_list,
|
||||||
|
const FGPolyList& gpc_polys );
|
||||||
|
|
||||||
|
// populate this class based on the specified gpc_polys list
|
||||||
|
int rebuild( FGConstruct& c );
|
||||||
|
|
||||||
|
// Front end triangulator for polygon list. Allocates and builds
|
||||||
|
// up all the needed structures for the triangulator, runs it,
|
||||||
|
// copies the results, and frees all the data structures used by
|
||||||
|
// the triangulator. "pass" can be 1 or 2. 1 = first pass which
|
||||||
|
// generates extra nodes for a better triangulation. 2 = second
|
||||||
|
// pass after split/reassem where we don't want any extra nodes
|
||||||
|
// generated.
|
||||||
|
int run_triangulate( const string& angle, const int pass );
|
||||||
|
|
||||||
|
inline FGTriNodes get_out_nodes() const { return out_nodes; }
|
||||||
|
inline size_t get_out_nodes_size() const { return out_nodes.size(); }
|
||||||
|
inline triele_list get_elelist() const { return elelist; }
|
||||||
|
inline FGTriSegments get_out_segs() const { return out_segs; }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // _TRIANGLE_HXX
|
||||||
|
|
||||||
|
|
26
src/BuildTiles/Triangulate/trieles.cxx
Normal file
26
src/BuildTiles/Triangulate/trieles.cxx
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
// trieles.cxx -- "Triangle" element management class
|
||||||
|
//
|
||||||
|
// Written by Curtis Olson, started March 1999.
|
||||||
|
//
|
||||||
|
// Copyright (C) 1999 Curtis L. Olson - curt@flightgear.org
|
||||||
|
//
|
||||||
|
// This program is free software; you can redistribute it and/or
|
||||||
|
// modify it under the terms of the GNU General Public License as
|
||||||
|
// published by the Free Software Foundation; either version 2 of the
|
||||||
|
// License, or (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful, but
|
||||||
|
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
// General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
//
|
||||||
|
// $Id$
|
||||||
|
|
||||||
|
|
||||||
|
#include "trieles.hxx"
|
||||||
|
|
||||||
|
|
75
src/BuildTiles/Triangulate/trieles.hxx
Normal file
75
src/BuildTiles/Triangulate/trieles.hxx
Normal file
|
@ -0,0 +1,75 @@
|
||||||
|
// trieles.hxx -- "Triangle" element management class
|
||||||
|
//
|
||||||
|
// Written by Curtis Olson, started March 1999.
|
||||||
|
//
|
||||||
|
// Copyright (C) 1999 Curtis L. Olson - curt@flightgear.org
|
||||||
|
//
|
||||||
|
// This program is free software; you can redistribute it and/or
|
||||||
|
// modify it under the terms of the GNU General Public License as
|
||||||
|
// published by the Free Software Foundation; either version 2 of the
|
||||||
|
// License, or (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful, but
|
||||||
|
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
// General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
//
|
||||||
|
// $Id$
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef _TRIELES_HXX
|
||||||
|
#define _TRIELES_HXX
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef __cplusplus
|
||||||
|
# error This library requires C++
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#include <simgear/compiler.h>
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
FG_USING_STD(vector);
|
||||||
|
|
||||||
|
|
||||||
|
// a segment is two integer pointers into the node list
|
||||||
|
class FGTriEle {
|
||||||
|
int n1, n2, n3;
|
||||||
|
|
||||||
|
double attribute;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
// Constructor and destructor
|
||||||
|
inline FGTriEle( void ) { };
|
||||||
|
inline FGTriEle( int i1, int i2, int i3, double a ) {
|
||||||
|
n1 = i1; n2 = i2; n3 = i3; attribute = a;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline ~FGTriEle( void ) { };
|
||||||
|
|
||||||
|
inline int get_n1() const { return n1; }
|
||||||
|
inline void set_n1( int i ) { n1 = i; }
|
||||||
|
inline int get_n2() const { return n2; }
|
||||||
|
inline void set_n2( int i ) { n2 = i; }
|
||||||
|
inline int get_n3() const { return n3; }
|
||||||
|
inline void set_n3( int i ) { n3 = i; }
|
||||||
|
|
||||||
|
inline double get_attribute() const { return attribute; }
|
||||||
|
inline void set_attribute( double a ) { attribute = a; }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
typedef vector < FGTriEle > triele_list;
|
||||||
|
typedef triele_list::iterator triele_list_iterator;
|
||||||
|
typedef triele_list::const_iterator const_triele_list_iterator;
|
||||||
|
|
||||||
|
|
||||||
|
#endif // _TRIELES_HXX
|
||||||
|
|
||||||
|
|
208
src/Include/config.h
Normal file
208
src/Include/config.h
Normal file
|
@ -0,0 +1,208 @@
|
||||||
|
/* Include/config.h. Generated automatically by configure. */
|
||||||
|
/* Include/config.h.in. Generated automatically from configure.in by autoheader. */
|
||||||
|
|
||||||
|
/* Define to empty if the keyword does not work. */
|
||||||
|
/* #undef const */
|
||||||
|
|
||||||
|
/* Define if you don't have vprintf but do have _doprnt. */
|
||||||
|
/* #undef HAVE_DOPRNT */
|
||||||
|
|
||||||
|
/* Define if you have the vprintf function. */
|
||||||
|
#define HAVE_VPRINTF 1
|
||||||
|
|
||||||
|
/* Define as the return type of signal handlers (int or void). */
|
||||||
|
#define RETSIGTYPE void
|
||||||
|
|
||||||
|
/* Define to `unsigned' if <sys/types.h> doesn't define. */
|
||||||
|
/* #undef size_t */
|
||||||
|
|
||||||
|
/* Define if you have the ANSI C header files. */
|
||||||
|
#define STDC_HEADERS 1
|
||||||
|
|
||||||
|
/* Define if you can safely include both <sys/time.h> and <time.h>. */
|
||||||
|
#define TIME_WITH_SYS_TIME 1
|
||||||
|
|
||||||
|
/* Define if your <sys/time.h> declares struct tm. */
|
||||||
|
/* #undef TM_IN_SYS_TIME */
|
||||||
|
|
||||||
|
/* Define if the X Window System is missing or not being used. */
|
||||||
|
/* #undef X_DISPLAY_MISSING */
|
||||||
|
|
||||||
|
/* Define to empty if the keyword does not work. */
|
||||||
|
/* #undef const */
|
||||||
|
|
||||||
|
|
||||||
|
/* Define to eliminate all trace of debugging messages such as for a
|
||||||
|
release build */
|
||||||
|
/* #undef FG_NDEBUG */
|
||||||
|
|
||||||
|
|
||||||
|
/* Define to enable 3dfx/glide render in a window hack under unix.
|
||||||
|
This probably won't work under windows. */
|
||||||
|
/* #undef XMESA */
|
||||||
|
/* #undef FX */
|
||||||
|
|
||||||
|
/* Define if you don't have vprintf but do have _doprnt. */
|
||||||
|
/* #undef HAVE_DOPRNT */
|
||||||
|
|
||||||
|
/* Define if you have the vprintf function. */
|
||||||
|
#define HAVE_VPRINTF 1
|
||||||
|
|
||||||
|
/* Define to package name */
|
||||||
|
#define PACKAGE "TerraGear"
|
||||||
|
|
||||||
|
/* Define as the return type of signal handlers (int or void). */
|
||||||
|
#define RETSIGTYPE void
|
||||||
|
|
||||||
|
/* Define to `unsigned' if <sys/types.h> doesn't define. */
|
||||||
|
/* #undef size_t */
|
||||||
|
|
||||||
|
/* Define if you have the ANSI C header files. */
|
||||||
|
#define STDC_HEADERS 1
|
||||||
|
|
||||||
|
/* Define if you can safely include both <sys/time.h> and <time.h>. */
|
||||||
|
#define TIME_WITH_SYS_TIME 1
|
||||||
|
|
||||||
|
/* Define if your <sys/time.h> declares struct tm. */
|
||||||
|
/* #undef TM_IN_SYS_TIME */
|
||||||
|
|
||||||
|
/* Define to version number */
|
||||||
|
#define VERSION "0.0.0"
|
||||||
|
|
||||||
|
/* Define if compiling on a Winbloze (95, NT, etc.) platform */
|
||||||
|
/* #undef WIN32 */
|
||||||
|
|
||||||
|
/* Define if the X Window System is missing or not being used. */
|
||||||
|
/* #undef X_DISPLAY_MISSING */
|
||||||
|
|
||||||
|
/* Define if you have the GetLocalTime function. */
|
||||||
|
/* #undef HAVE_GETLOCALTIME */
|
||||||
|
|
||||||
|
/* Define if you have the bcopy function. */
|
||||||
|
#define HAVE_BCOPY 1
|
||||||
|
|
||||||
|
/* Define if you have the ftime function. */
|
||||||
|
#define HAVE_FTIME 1
|
||||||
|
|
||||||
|
/* Define if you have the getitimer function. */
|
||||||
|
#define HAVE_GETITIMER 1
|
||||||
|
|
||||||
|
/* Define if you have the getrusage function. */
|
||||||
|
#define HAVE_GETRUSAGE 1
|
||||||
|
|
||||||
|
/* Define if you have the gettimeofday function. */
|
||||||
|
#define HAVE_GETTIMEOFDAY 1
|
||||||
|
|
||||||
|
/* Define if you have the memcpy function. */
|
||||||
|
#define HAVE_MEMCPY 1
|
||||||
|
|
||||||
|
/* Define if you have the mktime function. */
|
||||||
|
#define HAVE_MKTIME 1
|
||||||
|
|
||||||
|
/* Define if you have the rand function. */
|
||||||
|
#define HAVE_RAND 1
|
||||||
|
|
||||||
|
/* Define if you have the random function. */
|
||||||
|
#define HAVE_RANDOM 1
|
||||||
|
|
||||||
|
/* Define if you have the rint function. */
|
||||||
|
#define HAVE_RINT 1
|
||||||
|
|
||||||
|
/* Define if you have the setitimer function. */
|
||||||
|
#define HAVE_SETITIMER 1
|
||||||
|
|
||||||
|
/* Define if you have the signal function. */
|
||||||
|
#define HAVE_SIGNAL 1
|
||||||
|
|
||||||
|
/* Define if you have the strstr function. */
|
||||||
|
#define HAVE_STRSTR 1
|
||||||
|
|
||||||
|
/* Define if you have the timegm function. */
|
||||||
|
#define HAVE_TIMEGM 1
|
||||||
|
|
||||||
|
/* Define if you have the <fcntl.h> header file. */
|
||||||
|
#define HAVE_FCNTL_H 1
|
||||||
|
|
||||||
|
/* Define if you have the <getopt.h> header file. */
|
||||||
|
#define HAVE_GETOPT_H 1
|
||||||
|
|
||||||
|
/* Define if you have the <gpc.h> header file. */
|
||||||
|
#define HAVE_GPC_H 1
|
||||||
|
|
||||||
|
/* Define if you have the <malloc.h> header file. */
|
||||||
|
#define HAVE_MALLOC_H 1
|
||||||
|
|
||||||
|
/* Define if you have the <memory.h> header file. */
|
||||||
|
#define HAVE_MEMORY_H 1
|
||||||
|
|
||||||
|
/* Define if you have the <stdlib.h> header file. */
|
||||||
|
#define HAVE_STDLIB_H 1
|
||||||
|
|
||||||
|
/* Define if you have the <sys/param.h> header file. */
|
||||||
|
#define HAVE_SYS_PARAM_H 1
|
||||||
|
|
||||||
|
/* Define if you have the <sys/stat.h> header file. */
|
||||||
|
#define HAVE_SYS_STAT_H 1
|
||||||
|
|
||||||
|
/* Define if you have the <sys/time.h> header file. */
|
||||||
|
#define HAVE_SYS_TIME_H 1
|
||||||
|
|
||||||
|
/* Define if you have the <sys/timeb.h> header file. */
|
||||||
|
#define HAVE_SYS_TIMEB_H 1
|
||||||
|
|
||||||
|
/* Define if you have the <unistd.h> header file. */
|
||||||
|
#define HAVE_UNISTD_H 1
|
||||||
|
|
||||||
|
/* Define if you have the <values.h> header file. */
|
||||||
|
#define HAVE_VALUES_H 1
|
||||||
|
|
||||||
|
/* Define if you have the <winbase.h> header file. */
|
||||||
|
/* #undef HAVE_WINBASE_H */
|
||||||
|
|
||||||
|
/* Define if you have the <windows.h> header file. */
|
||||||
|
/* #undef HAVE_WINDOWS_H */
|
||||||
|
|
||||||
|
/* Define if you have the GL library (-lGL). */
|
||||||
|
#define HAVE_LIBGL 1
|
||||||
|
|
||||||
|
/* Define if you have the GLU library (-lGLU). */
|
||||||
|
/* #undef HAVE_LIBGLU */
|
||||||
|
|
||||||
|
/* Define if you have the GLcore library (-lGLcore). */
|
||||||
|
/* #undef HAVE_LIBGLCORE */
|
||||||
|
|
||||||
|
/* Define if you have the ICE library (-lICE). */
|
||||||
|
#define HAVE_LIBICE 1
|
||||||
|
|
||||||
|
/* Define if you have the MesaGL library (-lMesaGL). */
|
||||||
|
/* #undef HAVE_LIBMESAGL */
|
||||||
|
|
||||||
|
/* Define if you have the MesaGLU library (-lMesaGLU). */
|
||||||
|
#define HAVE_LIBMESAGLU 1
|
||||||
|
|
||||||
|
/* Define if you have the SM library (-lSM). */
|
||||||
|
#define HAVE_LIBSM 1
|
||||||
|
|
||||||
|
/* Define if you have the X11 library (-lX11). */
|
||||||
|
#define HAVE_LIBX11 1
|
||||||
|
|
||||||
|
/* Define if you have the Xext library (-lXext). */
|
||||||
|
#define HAVE_LIBXEXT 1
|
||||||
|
|
||||||
|
/* Define if you have the Xi library (-lXi). */
|
||||||
|
#define HAVE_LIBXI 1
|
||||||
|
|
||||||
|
/* Define if you have the Xmu library (-lXmu). */
|
||||||
|
#define HAVE_LIBXMU 1
|
||||||
|
|
||||||
|
/* Define if you have the Xt library (-lXt). */
|
||||||
|
#define HAVE_LIBXT 1
|
||||||
|
|
||||||
|
/* Define if you have the glut library (-lglut). */
|
||||||
|
#define HAVE_LIBGLUT 1
|
||||||
|
|
||||||
|
/* Define if you have the m library (-lm). */
|
||||||
|
#define HAVE_LIBM 1
|
||||||
|
|
||||||
|
/* Define if you have the socket library (-lsocket). */
|
||||||
|
/* #undef HAVE_LIBSOCKET */
|
207
src/Include/config.h.in
Normal file
207
src/Include/config.h.in
Normal file
|
@ -0,0 +1,207 @@
|
||||||
|
/* Include/config.h.in. Generated automatically from configure.in by autoheader. */
|
||||||
|
|
||||||
|
/* Define to empty if the keyword does not work. */
|
||||||
|
#undef const
|
||||||
|
|
||||||
|
/* Define if you don't have vprintf but do have _doprnt. */
|
||||||
|
#undef HAVE_DOPRNT
|
||||||
|
|
||||||
|
/* Define if you have the vprintf function. */
|
||||||
|
#undef HAVE_VPRINTF
|
||||||
|
|
||||||
|
/* Define as the return type of signal handlers (int or void). */
|
||||||
|
#undef RETSIGTYPE
|
||||||
|
|
||||||
|
/* Define to `unsigned' if <sys/types.h> doesn't define. */
|
||||||
|
#undef size_t
|
||||||
|
|
||||||
|
/* Define if you have the ANSI C header files. */
|
||||||
|
#undef STDC_HEADERS
|
||||||
|
|
||||||
|
/* Define if you can safely include both <sys/time.h> and <time.h>. */
|
||||||
|
#undef TIME_WITH_SYS_TIME
|
||||||
|
|
||||||
|
/* Define if your <sys/time.h> declares struct tm. */
|
||||||
|
#undef TM_IN_SYS_TIME
|
||||||
|
|
||||||
|
/* Define if the X Window System is missing or not being used. */
|
||||||
|
#undef X_DISPLAY_MISSING
|
||||||
|
|
||||||
|
/* Define to empty if the keyword does not work. */
|
||||||
|
#undef const
|
||||||
|
|
||||||
|
|
||||||
|
/* Define to eliminate all trace of debugging messages such as for a
|
||||||
|
release build */
|
||||||
|
#undef FG_NDEBUG
|
||||||
|
|
||||||
|
|
||||||
|
/* Define to enable 3dfx/glide render in a window hack under unix.
|
||||||
|
This probably won't work under windows. */
|
||||||
|
#undef XMESA
|
||||||
|
#undef FX
|
||||||
|
|
||||||
|
/* Define if you don't have vprintf but do have _doprnt. */
|
||||||
|
#undef HAVE_DOPRNT
|
||||||
|
|
||||||
|
/* Define if you have the vprintf function. */
|
||||||
|
#undef HAVE_VPRINTF
|
||||||
|
|
||||||
|
/* Define to package name */
|
||||||
|
#undef PACKAGE
|
||||||
|
|
||||||
|
/* Define as the return type of signal handlers (int or void). */
|
||||||
|
#undef RETSIGTYPE
|
||||||
|
|
||||||
|
/* Define to `unsigned' if <sys/types.h> doesn't define. */
|
||||||
|
#undef size_t
|
||||||
|
|
||||||
|
/* Define if you have the ANSI C header files. */
|
||||||
|
#undef STDC_HEADERS
|
||||||
|
|
||||||
|
/* Define if you can safely include both <sys/time.h> and <time.h>. */
|
||||||
|
#undef TIME_WITH_SYS_TIME
|
||||||
|
|
||||||
|
/* Define if your <sys/time.h> declares struct tm. */
|
||||||
|
#undef TM_IN_SYS_TIME
|
||||||
|
|
||||||
|
/* Define to version number */
|
||||||
|
#undef VERSION
|
||||||
|
|
||||||
|
/* Define if compiling on a Winbloze (95, NT, etc.) platform */
|
||||||
|
#undef WIN32
|
||||||
|
|
||||||
|
/* Define if the X Window System is missing or not being used. */
|
||||||
|
#undef X_DISPLAY_MISSING
|
||||||
|
|
||||||
|
/* Define if you have the GetLocalTime function. */
|
||||||
|
#undef HAVE_GETLOCALTIME
|
||||||
|
|
||||||
|
/* Define if you have the bcopy function. */
|
||||||
|
#undef HAVE_BCOPY
|
||||||
|
|
||||||
|
/* Define if you have the ftime function. */
|
||||||
|
#undef HAVE_FTIME
|
||||||
|
|
||||||
|
/* Define if you have the getitimer function. */
|
||||||
|
#undef HAVE_GETITIMER
|
||||||
|
|
||||||
|
/* Define if you have the getrusage function. */
|
||||||
|
#undef HAVE_GETRUSAGE
|
||||||
|
|
||||||
|
/* Define if you have the gettimeofday function. */
|
||||||
|
#undef HAVE_GETTIMEOFDAY
|
||||||
|
|
||||||
|
/* Define if you have the memcpy function. */
|
||||||
|
#undef HAVE_MEMCPY
|
||||||
|
|
||||||
|
/* Define if you have the mktime function. */
|
||||||
|
#undef HAVE_MKTIME
|
||||||
|
|
||||||
|
/* Define if you have the rand function. */
|
||||||
|
#undef HAVE_RAND
|
||||||
|
|
||||||
|
/* Define if you have the random function. */
|
||||||
|
#undef HAVE_RANDOM
|
||||||
|
|
||||||
|
/* Define if you have the rint function. */
|
||||||
|
#undef HAVE_RINT
|
||||||
|
|
||||||
|
/* Define if you have the setitimer function. */
|
||||||
|
#undef HAVE_SETITIMER
|
||||||
|
|
||||||
|
/* Define if you have the signal function. */
|
||||||
|
#undef HAVE_SIGNAL
|
||||||
|
|
||||||
|
/* Define if you have the strstr function. */
|
||||||
|
#undef HAVE_STRSTR
|
||||||
|
|
||||||
|
/* Define if you have the timegm function. */
|
||||||
|
#undef HAVE_TIMEGM
|
||||||
|
|
||||||
|
/* Define if you have the <fcntl.h> header file. */
|
||||||
|
#undef HAVE_FCNTL_H
|
||||||
|
|
||||||
|
/* Define if you have the <getopt.h> header file. */
|
||||||
|
#undef HAVE_GETOPT_H
|
||||||
|
|
||||||
|
/* Define if you have the <gpc.h> header file. */
|
||||||
|
#undef HAVE_GPC_H
|
||||||
|
|
||||||
|
/* Define if you have the <malloc.h> header file. */
|
||||||
|
#undef HAVE_MALLOC_H
|
||||||
|
|
||||||
|
/* Define if you have the <memory.h> header file. */
|
||||||
|
#undef HAVE_MEMORY_H
|
||||||
|
|
||||||
|
/* Define if you have the <stdlib.h> header file. */
|
||||||
|
#undef HAVE_STDLIB_H
|
||||||
|
|
||||||
|
/* Define if you have the <sys/param.h> header file. */
|
||||||
|
#undef HAVE_SYS_PARAM_H
|
||||||
|
|
||||||
|
/* Define if you have the <sys/stat.h> header file. */
|
||||||
|
#undef HAVE_SYS_STAT_H
|
||||||
|
|
||||||
|
/* Define if you have the <sys/time.h> header file. */
|
||||||
|
#undef HAVE_SYS_TIME_H
|
||||||
|
|
||||||
|
/* Define if you have the <sys/timeb.h> header file. */
|
||||||
|
#undef HAVE_SYS_TIMEB_H
|
||||||
|
|
||||||
|
/* Define if you have the <unistd.h> header file. */
|
||||||
|
#undef HAVE_UNISTD_H
|
||||||
|
|
||||||
|
/* Define if you have the <values.h> header file. */
|
||||||
|
#undef HAVE_VALUES_H
|
||||||
|
|
||||||
|
/* Define if you have the <winbase.h> header file. */
|
||||||
|
#undef HAVE_WINBASE_H
|
||||||
|
|
||||||
|
/* Define if you have the <windows.h> header file. */
|
||||||
|
#undef HAVE_WINDOWS_H
|
||||||
|
|
||||||
|
/* Define if you have the GL library (-lGL). */
|
||||||
|
#undef HAVE_LIBGL
|
||||||
|
|
||||||
|
/* Define if you have the GLU library (-lGLU). */
|
||||||
|
#undef HAVE_LIBGLU
|
||||||
|
|
||||||
|
/* Define if you have the GLcore library (-lGLcore). */
|
||||||
|
#undef HAVE_LIBGLCORE
|
||||||
|
|
||||||
|
/* Define if you have the ICE library (-lICE). */
|
||||||
|
#undef HAVE_LIBICE
|
||||||
|
|
||||||
|
/* Define if you have the MesaGL library (-lMesaGL). */
|
||||||
|
#undef HAVE_LIBMESAGL
|
||||||
|
|
||||||
|
/* Define if you have the MesaGLU library (-lMesaGLU). */
|
||||||
|
#undef HAVE_LIBMESAGLU
|
||||||
|
|
||||||
|
/* Define if you have the SM library (-lSM). */
|
||||||
|
#undef HAVE_LIBSM
|
||||||
|
|
||||||
|
/* Define if you have the X11 library (-lX11). */
|
||||||
|
#undef HAVE_LIBX11
|
||||||
|
|
||||||
|
/* Define if you have the Xext library (-lXext). */
|
||||||
|
#undef HAVE_LIBXEXT
|
||||||
|
|
||||||
|
/* Define if you have the Xi library (-lXi). */
|
||||||
|
#undef HAVE_LIBXI
|
||||||
|
|
||||||
|
/* Define if you have the Xmu library (-lXmu). */
|
||||||
|
#undef HAVE_LIBXMU
|
||||||
|
|
||||||
|
/* Define if you have the Xt library (-lXt). */
|
||||||
|
#undef HAVE_LIBXT
|
||||||
|
|
||||||
|
/* Define if you have the glut library (-lglut). */
|
||||||
|
#undef HAVE_LIBGLUT
|
||||||
|
|
||||||
|
/* Define if you have the m library (-lm). */
|
||||||
|
#undef HAVE_LIBM
|
||||||
|
|
||||||
|
/* Define if you have the socket library (-lsocket). */
|
||||||
|
#undef HAVE_LIBSOCKET
|
1
src/Include/stamp-h
Normal file
1
src/Include/stamp-h
Normal file
|
@ -0,0 +1 @@
|
||||||
|
timestamp
|
17
src/Lib/Array/Makefile.am
Normal file
17
src/Lib/Array/Makefile.am
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
noinst_LIBRARIES = libArray.a
|
||||||
|
|
||||||
|
libArray_a_SOURCES = array.cxx array.hxx
|
||||||
|
|
||||||
|
noinst_PROGRAMS = testarray
|
||||||
|
|
||||||
|
testarray_SOURCES = testarray.cxx
|
||||||
|
|
||||||
|
testarray_LDADD = \
|
||||||
|
$(top_builddir)/Lib/Array/libArray.a \
|
||||||
|
-lsgbucket -lsgmath -lsgmisc -lz
|
||||||
|
|
||||||
|
INCLUDES += \
|
||||||
|
-I$(top_builddir) \
|
||||||
|
-I$(top_builddir)/Lib \
|
||||||
|
-I$(top_builddir)/Tools/Lib \
|
||||||
|
-I$(top_builddir)/Tools/Construct
|
577
src/Lib/Array/array.cxx
Normal file
577
src/Lib/Array/array.cxx
Normal file
|
@ -0,0 +1,577 @@
|
||||||
|
// array.cxx -- Array management class
|
||||||
|
//
|
||||||
|
// Written by Curtis Olson, started March 1998.
|
||||||
|
//
|
||||||
|
// Copyright (C) 1998 - 1999 Curtis L. Olson - curt@flightgear.org
|
||||||
|
//
|
||||||
|
// This program is free software; you can redistribute it and/or
|
||||||
|
// modify it under the terms of the GNU General Public License as
|
||||||
|
// published by the Free Software Foundation; either version 2 of the
|
||||||
|
// License, or (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful, but
|
||||||
|
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
// General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
//
|
||||||
|
// $Id$
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
# include <config.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <simgear/compiler.h>
|
||||||
|
|
||||||
|
// #include <ctype.h> // isspace()
|
||||||
|
// #include <stdlib.h> // atoi()
|
||||||
|
// #include <math.h> // rint()
|
||||||
|
// #include <stdio.h>
|
||||||
|
// #include <string.h>
|
||||||
|
// #ifdef HAVE_SYS_STAT_H
|
||||||
|
// # include <sys/stat.h> // stat()
|
||||||
|
// #endif
|
||||||
|
// #ifdef FG_HAVE_STD_INCLUDES
|
||||||
|
// # include <cerrno>
|
||||||
|
// #else
|
||||||
|
// # include <errno.h>
|
||||||
|
// #endif
|
||||||
|
// #ifdef HAVE_UNISTD_H
|
||||||
|
// # include <unistd.h> // stat()
|
||||||
|
// #endif
|
||||||
|
|
||||||
|
#include STL_STRING
|
||||||
|
|
||||||
|
#include <simgear/constants.h>
|
||||||
|
#include <simgear/fgstream.hxx>
|
||||||
|
#include <simgear/strutils.hxx>
|
||||||
|
#include <simgear/leastsqs.hxx>
|
||||||
|
|
||||||
|
#include "array.hxx"
|
||||||
|
|
||||||
|
FG_USING_STD(string);
|
||||||
|
|
||||||
|
|
||||||
|
FGArray::FGArray( void ) {
|
||||||
|
// cout << "class FGArray CONstructor called." << endl;
|
||||||
|
in_data = new float[ARRAY_SIZE_1][ARRAY_SIZE_1];
|
||||||
|
// out_data = new float[ARRAY_SIZE_1][ARRAY_SIZE_1];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
FGArray::FGArray( const string &file ) {
|
||||||
|
// cout << "class FGArray CONstructor called." << endl;
|
||||||
|
in_data = new float[ARRAY_SIZE_1][ARRAY_SIZE_1];
|
||||||
|
// out_data = new float[ARRAY_SIZE_1][ARRAY_SIZE_1];
|
||||||
|
|
||||||
|
FGArray::open(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// open an Array file
|
||||||
|
int
|
||||||
|
FGArray::open( const string& file ) {
|
||||||
|
// open input file (or read from stdin)
|
||||||
|
if ( file == "-" ) {
|
||||||
|
cout << " Opening array data pipe from stdin" << endl;
|
||||||
|
// fd = stdin;
|
||||||
|
// fd = gzdopen(STDIN_FILENO, "r");
|
||||||
|
cout << " Not yet ported ..." << endl;
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
in = new fg_gzifstream( file );
|
||||||
|
if ( ! in->is_open() ) {
|
||||||
|
cout << " Cannot open " << file << endl;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
cout << " Opening array data file: " << file << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// close an Array file
|
||||||
|
int
|
||||||
|
FGArray::close() {
|
||||||
|
// the fg_gzifstream doesn't seem to have a close()
|
||||||
|
|
||||||
|
delete in;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// parse Array file, pass in the bucket so we can make up values when
|
||||||
|
// the file wasn't found.
|
||||||
|
int
|
||||||
|
FGArray::parse( FGBucket& b ) {
|
||||||
|
if ( in->is_open() ) {
|
||||||
|
// file open, parse
|
||||||
|
*in >> originx >> originy;
|
||||||
|
*in >> cols >> col_step;
|
||||||
|
*in >> rows >> row_step;
|
||||||
|
|
||||||
|
cout << " origin = " << originx << " " << originy << endl;
|
||||||
|
cout << " cols = " << cols << " rows = " << rows << endl;
|
||||||
|
cout << " col_step = " << col_step
|
||||||
|
<< " row_step = " << row_step <<endl;
|
||||||
|
|
||||||
|
for ( int i = 0; i < cols; i++ ) {
|
||||||
|
for ( int j = 0; j < rows; j++ ) {
|
||||||
|
*in >> in_data[i][j];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cout << " Done parsing\n";
|
||||||
|
} else {
|
||||||
|
// file not open (not found?), fill with zero'd data
|
||||||
|
|
||||||
|
originx = ( b.get_center_lon() - 0.5 * b.get_width() ) * 3600.0;
|
||||||
|
originy = ( b.get_center_lat() - 0.5 * b.get_height() ) * 3600.0;
|
||||||
|
|
||||||
|
double max_x = ( b.get_center_lon() + 0.5 * b.get_width() ) * 3600.0;
|
||||||
|
double max_y = ( b.get_center_lat() + 0.5 * b.get_height() ) * 3600.0;
|
||||||
|
|
||||||
|
cols = 3;
|
||||||
|
col_step = (max_x - originx) / (cols - 1);
|
||||||
|
rows = 3;
|
||||||
|
row_step = (max_y - originy) / (rows - 1);
|
||||||
|
|
||||||
|
cout << " origin = " << originx << " " << originy << endl;
|
||||||
|
cout << " cols = " << cols << " rows = " << rows << endl;
|
||||||
|
cout << " col_step = " << col_step
|
||||||
|
<< " row_step = " << row_step <<endl;
|
||||||
|
|
||||||
|
for ( int i = 0; i < cols; i++ ) {
|
||||||
|
for ( int j = 0; j < rows; j++ ) {
|
||||||
|
in_data[i][j] = 0.0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cout << " File not open, so using zero'd data" << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// add a node to the output corner node list
|
||||||
|
void FGArray::add_corner_node( int i, int j, double val ) {
|
||||||
|
|
||||||
|
double x = (originx + i * col_step) / 3600.0;
|
||||||
|
double y = (originy + j * row_step) / 3600.0;
|
||||||
|
// cout << "originx = " << originx << " originy = " << originy << endl;
|
||||||
|
cout << "corner = " << Point3D(x, y, val) << endl;
|
||||||
|
corner_list.push_back( Point3D(x, y, val) );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// add a node to the output fitted node list
|
||||||
|
void FGArray::add_fit_node( int i, int j, double val ) {
|
||||||
|
double x = (originx + i * col_step) / 3600.0;
|
||||||
|
double y = (originy + j * row_step) / 3600.0;
|
||||||
|
// cout << Point3D(x, y, val) << endl;
|
||||||
|
node_list.push_back( Point3D(x, y, val) );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Use least squares to fit a simpler data set to dem data. Return
|
||||||
|
// the number of fitted nodes
|
||||||
|
int FGArray::fit( double error ) {
|
||||||
|
double x[ARRAY_SIZE_1], y[ARRAY_SIZE_1];
|
||||||
|
double m, b, max_error, error_sq;
|
||||||
|
double x1, y1;
|
||||||
|
// double ave_error;
|
||||||
|
double cury, lasty;
|
||||||
|
int n, row, start, end;
|
||||||
|
int colmin, colmax, rowmin, rowmax;
|
||||||
|
bool good_fit;
|
||||||
|
// FILE *dem, *fit, *fit1;
|
||||||
|
|
||||||
|
error_sq = error * error;
|
||||||
|
|
||||||
|
cout << " Initializing fitted node list" << endl;
|
||||||
|
corner_list.clear();
|
||||||
|
node_list.clear();
|
||||||
|
|
||||||
|
// determine dimensions
|
||||||
|
colmin = 0;
|
||||||
|
colmax = cols;
|
||||||
|
rowmin = 0;
|
||||||
|
rowmax = rows;
|
||||||
|
cout << " Fitting region = " << colmin << "," << rowmin << " to "
|
||||||
|
<< colmax << "," << rowmax << endl;;
|
||||||
|
|
||||||
|
// generate corners list
|
||||||
|
add_corner_node( colmin, rowmin, in_data[colmin][rowmin] );
|
||||||
|
add_corner_node( colmin, rowmax-1, in_data[colmin][rowmax] );
|
||||||
|
add_corner_node( colmax-1, rowmin, in_data[colmax][rowmin] );
|
||||||
|
add_corner_node( colmax-1, rowmax-1, in_data[colmax][rowmax] );
|
||||||
|
|
||||||
|
cout << " Beginning best fit procedure" << endl;
|
||||||
|
lasty = 0;
|
||||||
|
|
||||||
|
for ( row = rowmin; row < rowmax; row++ ) {
|
||||||
|
// fit = fopen("fit.dat", "w");
|
||||||
|
// fit1 = fopen("fit1.dat", "w");
|
||||||
|
|
||||||
|
start = colmin;
|
||||||
|
|
||||||
|
// cout << " fitting row = " << row << endl;
|
||||||
|
|
||||||
|
while ( start < colmax - 1 ) {
|
||||||
|
end = start + 1;
|
||||||
|
good_fit = true;
|
||||||
|
|
||||||
|
x[0] = start * col_step;
|
||||||
|
y[0] = in_data[start][row];
|
||||||
|
|
||||||
|
x[1] = end * col_step;
|
||||||
|
y[1] = in_data[end][row];
|
||||||
|
|
||||||
|
n = 2;
|
||||||
|
|
||||||
|
// cout << "Least square of first 2 points" << endl;
|
||||||
|
least_squares(x, y, n, &m, &b);
|
||||||
|
|
||||||
|
end++;
|
||||||
|
|
||||||
|
while ( (end < colmax) && good_fit ) {
|
||||||
|
++n;
|
||||||
|
// cout << "Least square of first " << n << " points" << endl;
|
||||||
|
x[n-1] = x1 = end * col_step;
|
||||||
|
y[n-1] = y1 = in_data[end][row];
|
||||||
|
least_squares_update(x1, y1, &m, &b);
|
||||||
|
// ave_error = least_squares_error(x, y, n, m, b);
|
||||||
|
max_error = least_squares_max_error(x, y, n, m, b);
|
||||||
|
|
||||||
|
/*
|
||||||
|
printf("%d - %d ave error = %.2f max error = %.2f y = %.2f*x + %.2f\n",
|
||||||
|
start, end, ave_error, max_error, m, b);
|
||||||
|
|
||||||
|
f = fopen("gnuplot.dat", "w");
|
||||||
|
for ( j = 0; j <= end; j++) {
|
||||||
|
fprintf(f, "%.2f %.2f\n", 0.0 + ( j * col_step ),
|
||||||
|
in_data[row][j]);
|
||||||
|
}
|
||||||
|
for ( j = start; j <= end; j++) {
|
||||||
|
fprintf(f, "%.2f %.2f\n", 0.0 + ( j * col_step ),
|
||||||
|
in_data[row][j]);
|
||||||
|
}
|
||||||
|
fclose(f);
|
||||||
|
|
||||||
|
printf("Please hit return: "); gets(junk);
|
||||||
|
*/
|
||||||
|
|
||||||
|
if ( max_error > error_sq ) {
|
||||||
|
good_fit = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
end++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( !good_fit ) {
|
||||||
|
// error exceeded the threshold, back up
|
||||||
|
end -= 2; // back "end" up to the last good enough fit
|
||||||
|
n--; // back "n" up appropriately too
|
||||||
|
} else {
|
||||||
|
// we popped out of the above loop while still within
|
||||||
|
// the error threshold, so we must be at the end of
|
||||||
|
// the data set
|
||||||
|
end--;
|
||||||
|
}
|
||||||
|
|
||||||
|
least_squares(x, y, n, &m, &b);
|
||||||
|
// ave_error = least_squares_error(x, y, n, m, b);
|
||||||
|
max_error = least_squares_max_error(x, y, n, m, b);
|
||||||
|
|
||||||
|
/*
|
||||||
|
printf("\n");
|
||||||
|
printf("%d - %d ave error = %.2f max error = %.2f y = %.2f*x + %.2f\n",
|
||||||
|
start, end, ave_error, max_error, m, b);
|
||||||
|
printf("\n");
|
||||||
|
|
||||||
|
fprintf(fit1, "%.2f %.2f\n", x[0], m * x[0] + b);
|
||||||
|
fprintf(fit1, "%.2f %.2f\n", x[end-start], m * x[end-start] + b);
|
||||||
|
*/
|
||||||
|
|
||||||
|
if ( start > colmin ) {
|
||||||
|
// skip this for the first line segment
|
||||||
|
cury = m * x[0] + b;
|
||||||
|
add_fit_node( start, row, (lasty + cury) / 2 );
|
||||||
|
// fprintf(fit, "%.2f %.2f\n", x[0], (lasty + cury) / 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
lasty = m * x[end-start] + b;
|
||||||
|
start = end;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
fclose(fit);
|
||||||
|
fclose(fit1);
|
||||||
|
|
||||||
|
dem = fopen("gnuplot.dat", "w");
|
||||||
|
for ( j = 0; j < ARRAY_SIZE_1; j++) {
|
||||||
|
fprintf(dem, "%.2f %.2f\n", 0.0 + ( j * col_step ),
|
||||||
|
in_data[j][row]);
|
||||||
|
}
|
||||||
|
fclose(dem);
|
||||||
|
*/
|
||||||
|
|
||||||
|
// NOTICE, this is for testing only. This instance of
|
||||||
|
// output_nodes should be removed. It should be called only
|
||||||
|
// once at the end once all the nodes have been generated.
|
||||||
|
// newmesh_output_nodes(&nm, "mesh.node");
|
||||||
|
// printf("Please hit return: "); gets(junk);
|
||||||
|
}
|
||||||
|
|
||||||
|
// outputmesh_output_nodes(fg_root, p);
|
||||||
|
|
||||||
|
// return fit nodes + 4 corners
|
||||||
|
return node_list.size() + 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// return the current altitude based on grid data. We should rewrite
|
||||||
|
// this to interpolate exact values, but for now this is good enough
|
||||||
|
double FGArray::interpolate_altitude( double lon, double lat ) const {
|
||||||
|
// we expect incoming (lon,lat) to be in arcsec for now
|
||||||
|
|
||||||
|
double xlocal, ylocal, dx, dy, zA, zB, elev;
|
||||||
|
int x1, x2, x3, y1, y2, y3;
|
||||||
|
float z1, z2, z3;
|
||||||
|
int xindex, yindex;
|
||||||
|
|
||||||
|
/* determine if we are in the lower triangle or the upper triangle
|
||||||
|
______
|
||||||
|
| /|
|
||||||
|
| / |
|
||||||
|
| / |
|
||||||
|
|/ |
|
||||||
|
------
|
||||||
|
|
||||||
|
then calculate our end points
|
||||||
|
*/
|
||||||
|
|
||||||
|
xlocal = (lon - originx) / col_step;
|
||||||
|
ylocal = (lat - originy) / row_step;
|
||||||
|
|
||||||
|
xindex = (int)(xlocal);
|
||||||
|
yindex = (int)(ylocal);
|
||||||
|
|
||||||
|
// printf("xindex = %d yindex = %d\n", xindex, yindex);
|
||||||
|
|
||||||
|
if ( xindex + 1 == cols ) {
|
||||||
|
xindex--;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( yindex + 1 == rows ) {
|
||||||
|
yindex--;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( (xindex < 0) || (xindex + 1 >= cols) ||
|
||||||
|
(yindex < 0) || (yindex + 1 >= rows) ) {
|
||||||
|
cout << "WARNING: Attempt to interpolate value outside of array!!!"
|
||||||
|
<< endl;
|
||||||
|
return -9999;
|
||||||
|
}
|
||||||
|
|
||||||
|
dx = xlocal - xindex;
|
||||||
|
dy = ylocal - yindex;
|
||||||
|
|
||||||
|
if ( dx > dy ) {
|
||||||
|
// lower triangle
|
||||||
|
// printf(" Lower triangle\n");
|
||||||
|
|
||||||
|
x1 = xindex;
|
||||||
|
y1 = yindex;
|
||||||
|
z1 = in_data[x1][y1];
|
||||||
|
|
||||||
|
x2 = xindex + 1;
|
||||||
|
y2 = yindex;
|
||||||
|
z2 = in_data[x2][y2];
|
||||||
|
|
||||||
|
x3 = xindex + 1;
|
||||||
|
y3 = yindex + 1;
|
||||||
|
z3 = in_data[x3][y3];
|
||||||
|
|
||||||
|
// printf(" dx = %.2f dy = %.2f\n", dx, dy);
|
||||||
|
// printf(" (x1,y1,z1) = (%d,%d,%d)\n", x1, y1, z1);
|
||||||
|
// printf(" (x2,y2,z2) = (%d,%d,%d)\n", x2, y2, z2);
|
||||||
|
// printf(" (x3,y3,z3) = (%d,%d,%d)\n", x3, y3, z3);
|
||||||
|
|
||||||
|
zA = dx * (z2 - z1) + z1;
|
||||||
|
zB = dx * (z3 - z1) + z1;
|
||||||
|
|
||||||
|
// printf(" zA = %.2f zB = %.2f\n", zA, zB);
|
||||||
|
|
||||||
|
if ( dx > FG_EPSILON ) {
|
||||||
|
elev = dy * (zB - zA) / dx + zA;
|
||||||
|
} else {
|
||||||
|
elev = zA;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// upper triangle
|
||||||
|
// printf(" Upper triangle\n");
|
||||||
|
|
||||||
|
x1 = xindex;
|
||||||
|
y1 = yindex;
|
||||||
|
z1 = in_data[x1][y1];
|
||||||
|
|
||||||
|
x2 = xindex;
|
||||||
|
y2 = yindex + 1;
|
||||||
|
z2 = in_data[x2][y2];
|
||||||
|
|
||||||
|
x3 = xindex + 1;
|
||||||
|
y3 = yindex + 1;
|
||||||
|
z3 = in_data[x3][y3];
|
||||||
|
|
||||||
|
// printf(" dx = %.2f dy = %.2f\n", dx, dy);
|
||||||
|
// printf(" (x1,y1,z1) = (%d,%d,%d)\n", x1, y1, z1);
|
||||||
|
// printf(" (x2,y2,z2) = (%d,%d,%d)\n", x2, y2, z2);
|
||||||
|
// printf(" (x3,y3,z3) = (%d,%d,%d)\n", x3, y3, z3);
|
||||||
|
|
||||||
|
zA = dy * (z2 - z1) + z1;
|
||||||
|
zB = dy * (z3 - z1) + z1;
|
||||||
|
|
||||||
|
// printf(" zA = %.2f zB = %.2f\n", zA, zB );
|
||||||
|
// printf(" xB - xA = %.2f\n", col_step * dy / row_step);
|
||||||
|
|
||||||
|
if ( dy > FG_EPSILON ) {
|
||||||
|
elev = dx * (zB - zA) / dy + zA;
|
||||||
|
} else {
|
||||||
|
elev = zA;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return(elev);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
// Write out a node file that can be used by the "triangle" program.
|
||||||
|
// Check for an optional "index.node.ex" file in case there is a .poly
|
||||||
|
// file to go along with this node file. Include these nodes first
|
||||||
|
// since they are referenced by position from the .poly file.
|
||||||
|
void FGArray::outputmesh_output_nodes( const string& fg_root, FGBucket& p )
|
||||||
|
{
|
||||||
|
double exnodes[MAX_EX_NODES][3];
|
||||||
|
struct stat stat_buf;
|
||||||
|
string dir, file;
|
||||||
|
char exfile[256];
|
||||||
|
#ifdef WIN32
|
||||||
|
char tmp_path[256];
|
||||||
|
#endif
|
||||||
|
string command;
|
||||||
|
FILE *fd;
|
||||||
|
int colmin, colmax, rowmin, rowmax;
|
||||||
|
int i, j, count, excount, result;
|
||||||
|
|
||||||
|
// determine dimensions
|
||||||
|
colmin = p.get_x() * ( (cols - 1) / 8);
|
||||||
|
colmax = colmin + ( (cols - 1) / 8);
|
||||||
|
rowmin = p.get_y() * ( (rows - 1) / 8);
|
||||||
|
rowmax = rowmin + ( (rows - 1) / 8);
|
||||||
|
cout << " dumping region = " << colmin << "," << rowmin << " to " <<
|
||||||
|
colmax << "," << rowmax << "\n";
|
||||||
|
|
||||||
|
// generate the base directory
|
||||||
|
string base_path = p.gen_base_path();
|
||||||
|
cout << " fg_root = " << fg_root << " Base Path = " << base_path << endl;
|
||||||
|
dir = fg_root + "/" + base_path;
|
||||||
|
cout << " Dir = " << dir << endl;
|
||||||
|
|
||||||
|
// stat() directory and create if needed
|
||||||
|
errno = 0;
|
||||||
|
result = stat(dir.c_str(), &stat_buf);
|
||||||
|
if ( result != 0 && errno == ENOENT ) {
|
||||||
|
cout << " Creating directory\n";
|
||||||
|
|
||||||
|
command = "mkdir -p " + dir + "\n";
|
||||||
|
system( command.c_str() );
|
||||||
|
} else {
|
||||||
|
// assume directory exists
|
||||||
|
}
|
||||||
|
|
||||||
|
// get index and generate output file name
|
||||||
|
file = dir + "/" + p.gen_index_str() + ".node";
|
||||||
|
|
||||||
|
// get (optional) extra node file name (in case there is matching
|
||||||
|
// .poly file.
|
||||||
|
exfile = file + ".ex";
|
||||||
|
|
||||||
|
// load extra nodes if they exist
|
||||||
|
excount = 0;
|
||||||
|
if ( (fd = fopen(exfile, "r")) != NULL ) {
|
||||||
|
int junki;
|
||||||
|
fscanf(fd, "%d %d %d %d", &excount, &junki, &junki, &junki);
|
||||||
|
|
||||||
|
if ( excount > MAX_EX_NODES - 1 ) {
|
||||||
|
printf("Error, too many 'extra' nodes, increase array size\n");
|
||||||
|
exit(-1);
|
||||||
|
} else {
|
||||||
|
printf(" Expecting %d 'extra' nodes\n", excount);
|
||||||
|
}
|
||||||
|
|
||||||
|
for ( i = 1; i <= excount; i++ ) {
|
||||||
|
fscanf(fd, "%d %lf %lf %lf\n", &junki,
|
||||||
|
&exnodes[i][0], &exnodes[i][1], &exnodes[i][2]);
|
||||||
|
printf("(extra) %d %.2f %.2f %.2f\n",
|
||||||
|
i, exnodes[i][0], exnodes[i][1], exnodes[i][2]);
|
||||||
|
}
|
||||||
|
fclose(fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("Creating node file: %s\n", file);
|
||||||
|
fd = fopen(file, "w");
|
||||||
|
|
||||||
|
// first count regular nodes to generate header
|
||||||
|
count = 0;
|
||||||
|
for ( j = rowmin; j <= rowmax; j++ ) {
|
||||||
|
for ( i = colmin; i <= colmax; i++ ) {
|
||||||
|
if ( out_data[i][j] > -9000.0 ) {
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// printf(" count = %d\n", count);
|
||||||
|
}
|
||||||
|
fprintf(fd, "%d 2 1 0\n", count + excount);
|
||||||
|
|
||||||
|
// now write out extra node data
|
||||||
|
for ( i = 1; i <= excount; i++ ) {
|
||||||
|
fprintf(fd, "%d %.2f %.2f %.2f\n",
|
||||||
|
i, exnodes[i][0], exnodes[i][1], exnodes[i][2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// write out actual node data
|
||||||
|
count = excount + 1;
|
||||||
|
for ( j = rowmin; j <= rowmax; j++ ) {
|
||||||
|
for ( i = colmin; i <= colmax; i++ ) {
|
||||||
|
if ( out_data[i][j] > -9000.0 ) {
|
||||||
|
fprintf(fd, "%d %.2f %.2f %.2f\n",
|
||||||
|
count++,
|
||||||
|
originx + (double)i * col_step,
|
||||||
|
originy + (double)j * row_step,
|
||||||
|
out_data[i][j]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// printf(" count = %d\n", count);
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(fd);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
FGArray::~FGArray( void ) {
|
||||||
|
// printf("class FGArray DEstructor called.\n");
|
||||||
|
delete [] in_data;
|
||||||
|
// delete [] out_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
124
src/Lib/Array/array.hxx
Normal file
124
src/Lib/Array/array.hxx
Normal file
|
@ -0,0 +1,124 @@
|
||||||
|
// array.hxx -- Array management class
|
||||||
|
//
|
||||||
|
// Written by Curtis Olson, started March 1998.
|
||||||
|
//
|
||||||
|
// Copyright (C) 1998 - 1999 Curtis L. Olson - curt@flightgear.org
|
||||||
|
//
|
||||||
|
// This program is free software; you can redistribute it and/or
|
||||||
|
// modify it under the terms of the GNU General Public License as
|
||||||
|
// published by the Free Software Foundation; either version 2 of the
|
||||||
|
// License, or (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful, but
|
||||||
|
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
// General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
//
|
||||||
|
// $Id$
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef _ARRAY_HXX
|
||||||
|
#define _ARRAY_HXX
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef __cplusplus
|
||||||
|
# error This library requires C++
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#include <simgear/compiler.h>
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include <simgear/fg_types.hxx>
|
||||||
|
|
||||||
|
#include <simgear/newbucket.hxx>
|
||||||
|
#include <simgear/point3d.hxx>
|
||||||
|
#include <simgear/fgstream.hxx>
|
||||||
|
|
||||||
|
|
||||||
|
FG_USING_STD(vector);
|
||||||
|
|
||||||
|
|
||||||
|
#define ARRAY_SIZE 1200
|
||||||
|
#define ARRAY_SIZE_1 1201
|
||||||
|
|
||||||
|
|
||||||
|
class FGArray {
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
// file pointer for input
|
||||||
|
// gzFile fd;
|
||||||
|
fg_gzifstream *in;
|
||||||
|
|
||||||
|
// coordinates (in arc seconds) of south west corner
|
||||||
|
double originx, originy;
|
||||||
|
|
||||||
|
// number of columns and rows
|
||||||
|
int cols, rows;
|
||||||
|
|
||||||
|
// Distance between column and row data points (in arc seconds)
|
||||||
|
double col_step, row_step;
|
||||||
|
|
||||||
|
// pointers to the actual grid data allocated here
|
||||||
|
float (*in_data)[ARRAY_SIZE_1];
|
||||||
|
// float (*out_data)[ARRAY_SIZE_1];
|
||||||
|
|
||||||
|
// output nodes
|
||||||
|
point_list corner_list;
|
||||||
|
point_list node_list;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
// Constructor
|
||||||
|
FGArray( void );
|
||||||
|
FGArray( const string& file );
|
||||||
|
|
||||||
|
// Destructor
|
||||||
|
~FGArray( void );
|
||||||
|
|
||||||
|
// open an Array file (use "-" if input is coming from stdin)
|
||||||
|
int open ( const string& file );
|
||||||
|
|
||||||
|
// close a Array file
|
||||||
|
int close();
|
||||||
|
|
||||||
|
// parse a Array file
|
||||||
|
int parse( FGBucket& b );
|
||||||
|
|
||||||
|
// Use least squares to fit a simpler data set to dem data.
|
||||||
|
// Return the number of fitted nodes
|
||||||
|
int fit( double error );
|
||||||
|
|
||||||
|
// add a node to the output corner node list
|
||||||
|
void add_corner_node( int i, int j, double val );
|
||||||
|
|
||||||
|
// add a node to the output fitted node list
|
||||||
|
void add_fit_node( int i, int j, double val );
|
||||||
|
|
||||||
|
// return the current altitude based on grid data. We should
|
||||||
|
// rewrite this to interpolate exact values, but for now this is
|
||||||
|
// good enough
|
||||||
|
double interpolate_altitude( double lon, double lat ) const;
|
||||||
|
|
||||||
|
// Informational methods
|
||||||
|
inline double get_originx() const { return originx; }
|
||||||
|
inline double get_originy() const { return originy; }
|
||||||
|
inline int get_cols() const { return cols; }
|
||||||
|
inline int get_rows() const { return rows; }
|
||||||
|
inline double get_col_step() const { return col_step; }
|
||||||
|
inline double get_row_step() const { return row_step; }
|
||||||
|
|
||||||
|
inline point_list get_corner_node_list() const { return corner_list; }
|
||||||
|
inline point_list get_fit_node_list() const { return node_list; }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // _ARRAY_HXX
|
||||||
|
|
||||||
|
|
33
src/Lib/Array/testarray.cxx
Normal file
33
src/Lib/Array/testarray.cxx
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
#include <simgear/newbucket.hxx>
|
||||||
|
|
||||||
|
#include "array.hxx"
|
||||||
|
|
||||||
|
main(int argc, char **argv) {
|
||||||
|
double lon, lat;
|
||||||
|
|
||||||
|
if ( argc != 2 ) {
|
||||||
|
cout << "Usage: " << argv[0] << " work_dir" << endl;
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
string work_dir = argv[1];
|
||||||
|
|
||||||
|
lon = -146.248360; lat = 61.133950; // PAVD (Valdez, AK)
|
||||||
|
lon = -110.664244; lat = 33.352890; // P13
|
||||||
|
|
||||||
|
FGBucket b( lon, lat );
|
||||||
|
string base = b.gen_base_path();
|
||||||
|
string path = work_dir + "/" + base;
|
||||||
|
|
||||||
|
string arrayfile = path + "/" + b.gen_index_str() + ".dem";
|
||||||
|
cout << "arrayfile = " << arrayfile << endl;
|
||||||
|
|
||||||
|
FGArray a(arrayfile);
|
||||||
|
a.parse( b );
|
||||||
|
|
||||||
|
lon *= 3600;
|
||||||
|
lat *= 3600;
|
||||||
|
cout << " " << a.interpolate_altitude(lon, lat) << endl;
|
||||||
|
|
||||||
|
a.fit( 100 );
|
||||||
|
}
|
11
src/Lib/DEM/Makefile.am
Normal file
11
src/Lib/DEM/Makefile.am
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
noinst_LIBRARIES = libDEM.a
|
||||||
|
|
||||||
|
libDEM_a_SOURCES = dem.cxx dem.hxx
|
||||||
|
|
||||||
|
INCLUDES += -I$(top_builddir) -I$(top_builddir)/Lib
|
||||||
|
|
||||||
|
# We can't build this with "-O2" (optimization) since this causes a seg fault
|
||||||
|
# I haven't found a way to strip this out of the CXXFLAGS, so I'm just
|
||||||
|
# setting it to "-g"
|
||||||
|
# CXXFLAGS = -g
|
||||||
|
|
871
src/Lib/DEM/dem.cxx
Normal file
871
src/Lib/DEM/dem.cxx
Normal file
|
@ -0,0 +1,871 @@
|
||||||
|
// dem.cxx -- DEM management class
|
||||||
|
//
|
||||||
|
// Written by Curtis Olson, started March 1998.
|
||||||
|
//
|
||||||
|
// Copyright (C) 1998 Curtis L. Olson - curt@flightgear.org
|
||||||
|
//
|
||||||
|
// This program is free software; you can redistribute it and/or
|
||||||
|
// modify it under the terms of the GNU General Public License as
|
||||||
|
// published by the Free Software Foundation; either version 2 of the
|
||||||
|
// License, or (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful, but
|
||||||
|
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
// General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
//
|
||||||
|
// $Id$
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
# include <config.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <simgear/compiler.h>
|
||||||
|
|
||||||
|
#include <ctype.h> // isspace()
|
||||||
|
#include <stdlib.h> // atoi()
|
||||||
|
#include <math.h> // rint()
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#ifdef HAVE_SYS_STAT_H
|
||||||
|
# include <sys/stat.h> // stat()
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef FG_HAVE_STD_INCLUDES
|
||||||
|
# include <cerrno>
|
||||||
|
#else
|
||||||
|
# include <errno.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef HAVE_UNISTD_H
|
||||||
|
# include <unistd.h> // stat()
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <simgear/fgstream.hxx>
|
||||||
|
#include <simgear/strutils.hxx>
|
||||||
|
#include <simgear/constants.h>
|
||||||
|
|
||||||
|
#include "dem.hxx"
|
||||||
|
|
||||||
|
|
||||||
|
#define MAX_EX_NODES 10000
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
#ifdef WIN32
|
||||||
|
# ifdef __BORLANDC__
|
||||||
|
# include <dir.h>
|
||||||
|
# define MKDIR(a) mkdir(a)
|
||||||
|
# else
|
||||||
|
# define MKDIR(a) mkdir(a,S_IRWXU) // I am just guessing at this flag (NHV)
|
||||||
|
# endif // __BORLANDC__
|
||||||
|
#endif // WIN32
|
||||||
|
#endif //0
|
||||||
|
|
||||||
|
|
||||||
|
FGDem::FGDem( void ) {
|
||||||
|
// cout << "class FGDem CONstructor called." << endl;
|
||||||
|
dem_data = new float[DEM_SIZE_1][DEM_SIZE_1];
|
||||||
|
output_data = new float[DEM_SIZE_1][DEM_SIZE_1];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
FGDem::FGDem( const string &file ) {
|
||||||
|
// cout << "class FGDem CONstructor called." << endl;
|
||||||
|
dem_data = new float[DEM_SIZE_1][DEM_SIZE_1];
|
||||||
|
output_data = new float[DEM_SIZE_1][DEM_SIZE_1];
|
||||||
|
|
||||||
|
FGDem::open(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// open a DEM file
|
||||||
|
int
|
||||||
|
FGDem::open ( const string& file ) {
|
||||||
|
// open input file (or read from stdin)
|
||||||
|
if ( file == "-" ) {
|
||||||
|
printf("Loading DEM data file: stdin\n");
|
||||||
|
// fd = stdin;
|
||||||
|
// fd = gzdopen(STDIN_FILENO, "r");
|
||||||
|
printf("Not yet ported ...\n");
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
in = new fg_gzifstream( file );
|
||||||
|
if ( !(*in) ) {
|
||||||
|
cout << "Cannot open " << file << endl;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
cout << "Loading DEM data file: " << file << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// close a DEM file
|
||||||
|
int
|
||||||
|
FGDem::close () {
|
||||||
|
// the fg_gzifstream doesn't seem to have a close()
|
||||||
|
|
||||||
|
delete in;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// return next token from input stream
|
||||||
|
string
|
||||||
|
FGDem::next_token() {
|
||||||
|
string token;
|
||||||
|
|
||||||
|
*in >> token;
|
||||||
|
|
||||||
|
// cout << " returning " + token + "\n";
|
||||||
|
|
||||||
|
return token;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// return next integer from input stream
|
||||||
|
int
|
||||||
|
FGDem::next_int() {
|
||||||
|
int result;
|
||||||
|
|
||||||
|
*in >> result;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// return next double from input stream
|
||||||
|
double
|
||||||
|
FGDem::next_double() {
|
||||||
|
double result;
|
||||||
|
|
||||||
|
*in >> result;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// return next exponential num from input stream
|
||||||
|
double
|
||||||
|
FGDem::next_exp() {
|
||||||
|
string token;
|
||||||
|
|
||||||
|
token = next_token();
|
||||||
|
|
||||||
|
const char* p = token.c_str();
|
||||||
|
char buf[64];
|
||||||
|
char* bp = buf;
|
||||||
|
|
||||||
|
for ( ; *p != 0; ++p )
|
||||||
|
{
|
||||||
|
if ( *p == 'D' )
|
||||||
|
*bp++ = 'E';
|
||||||
|
else
|
||||||
|
*bp++ = *p;
|
||||||
|
}
|
||||||
|
*bp = 0;
|
||||||
|
return ::atof( buf );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// read and parse DEM "A" record
|
||||||
|
int
|
||||||
|
FGDem::read_a_record() {
|
||||||
|
int i, inum;
|
||||||
|
double dnum;
|
||||||
|
string name, token;
|
||||||
|
char c;
|
||||||
|
|
||||||
|
// get the name field (144 characters)
|
||||||
|
for ( i = 0; i < 144; i++ ) {
|
||||||
|
in->get(c);
|
||||||
|
name += c;
|
||||||
|
}
|
||||||
|
|
||||||
|
// clean off the trailing whitespace
|
||||||
|
name = trim(name);
|
||||||
|
cout << " Quad name field: " << name << endl;
|
||||||
|
|
||||||
|
// DEM level code, 3 reflects processing by DMA
|
||||||
|
inum = next_int();
|
||||||
|
cout << " DEM level code = " << inum << "\n";
|
||||||
|
|
||||||
|
if ( inum > 3 ) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pattern code, 1 indicates a regular elevation pattern
|
||||||
|
inum = next_int();
|
||||||
|
cout << " Pattern code = " << inum << "\n";
|
||||||
|
|
||||||
|
// Planimetric reference system code, 0 indicates geographic
|
||||||
|
// coordinate system.
|
||||||
|
inum = next_int();
|
||||||
|
cout << " Planimetric reference code = " << inum << "\n";
|
||||||
|
|
||||||
|
// Zone code
|
||||||
|
inum = next_int();
|
||||||
|
cout << " Zone code = " << inum << "\n";
|
||||||
|
|
||||||
|
// Map projection parameters (ignored)
|
||||||
|
for ( i = 0; i < 15; i++ ) {
|
||||||
|
dnum = next_exp();
|
||||||
|
// printf("%d: %f\n",i,dnum);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Units code, 3 represents arc-seconds as the unit of measure for
|
||||||
|
// ground planimetric coordinates throughout the file.
|
||||||
|
inum = next_int();
|
||||||
|
if ( inum != 3 ) {
|
||||||
|
cout << " Unknown (X,Y) units code = " << inum << "!\n";
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Units code; 2 represents meters as the unit of measure for
|
||||||
|
// elevation coordinates throughout the file.
|
||||||
|
inum = next_int();
|
||||||
|
if ( inum != 2 ) {
|
||||||
|
cout << " Unknown (Z) units code = " << inum << "!\n";
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Number (n) of sides in the polygon which defines the coverage of
|
||||||
|
// the DEM file (usually equal to 4).
|
||||||
|
inum = next_int();
|
||||||
|
if ( inum != 4 ) {
|
||||||
|
cout << " Unknown polygon dimension = " << inum << "!\n";
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ground coordinates of bounding box in arc-seconds
|
||||||
|
dem_x1 = originx = next_exp();
|
||||||
|
dem_y1 = originy = next_exp();
|
||||||
|
cout << " Origin = (" << originx << "," << originy << ")\n";
|
||||||
|
|
||||||
|
dem_x2 = next_exp();
|
||||||
|
dem_y2 = next_exp();
|
||||||
|
|
||||||
|
dem_x3 = next_exp();
|
||||||
|
dem_y3 = next_exp();
|
||||||
|
|
||||||
|
dem_x4 = next_exp();
|
||||||
|
dem_y4 = next_exp();
|
||||||
|
|
||||||
|
// Minimum/maximum elevations in meters
|
||||||
|
dem_z1 = next_exp();
|
||||||
|
dem_z2 = next_exp();
|
||||||
|
cout << " Elevation range " << dem_z1 << " to " << dem_z2 << "\n";
|
||||||
|
|
||||||
|
// Counterclockwise angle from the primary axis of ground
|
||||||
|
// planimetric referenced to the primary axis of the DEM local
|
||||||
|
// reference system.
|
||||||
|
token = next_token();
|
||||||
|
|
||||||
|
// Accuracy code; 0 indicates that a record of accuracy does not
|
||||||
|
// exist and that no record type C will follow.
|
||||||
|
|
||||||
|
// DEM spacial resolution. Usually (3,3,1) (3,6,1) or (3,9,1)
|
||||||
|
// depending on latitude
|
||||||
|
|
||||||
|
// I will eventually have to do something with this for data at
|
||||||
|
// higher latitudes */
|
||||||
|
token = next_token();
|
||||||
|
cout << " accuracy & spacial resolution string = " << token << endl;
|
||||||
|
i = token.length();
|
||||||
|
cout << " length = " << i << "\n";
|
||||||
|
|
||||||
|
inum = atoi( token.substr( 0, i - 36 ) );
|
||||||
|
row_step = atof( token.substr( i - 24, 12 ) );
|
||||||
|
col_step = atof( token.substr( i - 36, 12 ) );
|
||||||
|
cout << " Accuracy code = " << inum << "\n";
|
||||||
|
cout << " column step = " << col_step <<
|
||||||
|
" row step = " << row_step << "\n";
|
||||||
|
|
||||||
|
// dimension of arrays to follow (1)
|
||||||
|
token = next_token();
|
||||||
|
|
||||||
|
// number of profiles
|
||||||
|
dem_num_profiles = cols = next_int();
|
||||||
|
cout << " Expecting " << dem_num_profiles << " profiles\n";
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// read and parse DEM "B" record
|
||||||
|
void
|
||||||
|
FGDem::read_b_record( ) {
|
||||||
|
string token;
|
||||||
|
int i;
|
||||||
|
int last;
|
||||||
|
|
||||||
|
// row / column id of this profile
|
||||||
|
prof_row = next_int();
|
||||||
|
prof_col = next_int();
|
||||||
|
// printf("col id = %d row id = %d\n", prof_col, prof_row);
|
||||||
|
|
||||||
|
// Number of columns and rows (elevations) in this profile
|
||||||
|
prof_num_rows = rows = next_int();
|
||||||
|
prof_num_cols = next_int();
|
||||||
|
// printf(" profile num rows = %d\n", prof_num_rows);
|
||||||
|
|
||||||
|
// Ground planimetric coordinates (arc-seconds) of the first
|
||||||
|
// elevation in the profile
|
||||||
|
prof_x1 = next_exp();
|
||||||
|
prof_y1 = next_exp();
|
||||||
|
// printf(" Starting at %.2f %.2f\n", prof_x1, prof_y1);
|
||||||
|
|
||||||
|
// Elevation of local datum for the profile. Always zero for
|
||||||
|
// 1-degree DEM, the reference is mean sea level.
|
||||||
|
token = next_token();
|
||||||
|
|
||||||
|
// Minimum and maximum elevations for the profile.
|
||||||
|
token = next_token();
|
||||||
|
token = next_token();
|
||||||
|
|
||||||
|
// One (usually) dimensional array (prof_num_cols,1) of elevations
|
||||||
|
last = 0;
|
||||||
|
for ( i = 0; i < prof_num_rows; i++ ) {
|
||||||
|
prof_data = next_int();
|
||||||
|
|
||||||
|
// a bit of sanity checking that is unfortunately necessary
|
||||||
|
if ( prof_data > 10000 ) { // meters
|
||||||
|
prof_data = last;
|
||||||
|
}
|
||||||
|
|
||||||
|
dem_data[cur_col][i] = (float)prof_data;
|
||||||
|
last = prof_data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// parse dem file
|
||||||
|
int
|
||||||
|
FGDem::parse( ) {
|
||||||
|
int i;
|
||||||
|
|
||||||
|
cur_col = 0;
|
||||||
|
|
||||||
|
if ( !read_a_record() ) {
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
for ( i = 0; i < dem_num_profiles; i++ ) {
|
||||||
|
// printf("Ready to read next b record\n");
|
||||||
|
read_b_record();
|
||||||
|
cur_col++;
|
||||||
|
|
||||||
|
if ( cur_col % 100 == 0 ) {
|
||||||
|
cout << " loaded " << cur_col << " profiles of data\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cout << " Done parsing\n";
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// write out the area of data covered by the specified bucket. Data
|
||||||
|
// is written out column by column starting at the lower left hand
|
||||||
|
// corner.
|
||||||
|
int
|
||||||
|
FGDem::write_area( const string& root, FGBucket& b, bool compress ) {
|
||||||
|
// calculate some boundaries
|
||||||
|
double min_x = ( b.get_center_lon() - 0.5 * b.get_width() ) * 3600.0;
|
||||||
|
double max_x = ( b.get_center_lon() + 0.5 * b.get_width() ) * 3600.0;
|
||||||
|
|
||||||
|
double min_y = ( b.get_center_lat() - 0.5 * b.get_height() ) * 3600.0;
|
||||||
|
double max_y = ( b.get_center_lat() + 0.5 * b.get_height() ) * 3600.0;
|
||||||
|
|
||||||
|
cout << b << endl;
|
||||||
|
cout << "width = " << b.get_width() << " height = " << b.get_height()
|
||||||
|
<< endl;
|
||||||
|
|
||||||
|
int start_x = (int)((min_x - originx) / col_step);
|
||||||
|
int span_x = (int)(b.get_width() * 3600.0 / col_step);
|
||||||
|
|
||||||
|
int start_y = (int)((min_y - originy) / row_step);
|
||||||
|
int span_y = (int)(b.get_height() * 3600.0 / row_step);
|
||||||
|
|
||||||
|
cout << "start_x = " << start_x << " span_x = " << span_x << endl;
|
||||||
|
cout << "start_y = " << start_y << " span_y = " << span_y << endl;
|
||||||
|
|
||||||
|
// Do a simple sanity checking. But, please, please be nice to
|
||||||
|
// this write_area() routine and feed it buckets that coincide
|
||||||
|
// well with the underlying grid structure and spacing.
|
||||||
|
|
||||||
|
if ( ( min_x < originx )
|
||||||
|
|| ( max_x > originx + cols * col_step )
|
||||||
|
|| ( min_y < originy )
|
||||||
|
|| ( max_y > originy + rows * row_step ) ) {
|
||||||
|
cout << " ERROR: bucket at least partially outside DEM data range!" <<
|
||||||
|
endl;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// generate output file name
|
||||||
|
string base = b.gen_base_path();
|
||||||
|
string path = root + "/" + base;
|
||||||
|
string command = "mkdir -p " + path;
|
||||||
|
system( command.c_str() );
|
||||||
|
|
||||||
|
string demfile = path + "/" + b.gen_index_str() + ".dem";
|
||||||
|
cout << "demfile = " << demfile << endl;
|
||||||
|
|
||||||
|
// write the file
|
||||||
|
FILE *fp;
|
||||||
|
if ( (fp = fopen(demfile.c_str(), "w")) == NULL ) {
|
||||||
|
cout << "cannot open " << demfile << " for writing!" << endl;
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf( fp, "%d %d\n", (int)min_x, (int)min_y );
|
||||||
|
fprintf( fp, "%d %d %d %d\n", span_x + 1, (int)col_step,
|
||||||
|
span_y + 1, (int)row_step );
|
||||||
|
for ( int i = start_x; i <= start_x + span_x; ++i ) {
|
||||||
|
for ( int j = start_y; j <= start_y + span_y; ++j ) {
|
||||||
|
fprintf( fp, "%d ", (int)dem_data[i][j] );
|
||||||
|
}
|
||||||
|
fprintf( fp, "\n" );
|
||||||
|
}
|
||||||
|
fclose(fp);
|
||||||
|
|
||||||
|
if ( compress ) {
|
||||||
|
string command = "gzip --best -f " + demfile;
|
||||||
|
system( command.c_str() );
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
|
||||||
|
// return the current altitude based on grid data. We should rewrite
|
||||||
|
// this to interpolate exact values, but for now this is good enough
|
||||||
|
double FGDem::interpolate_altitude( double lon, double lat ) {
|
||||||
|
// we expect incoming (lon,lat) to be in arcsec for now
|
||||||
|
|
||||||
|
double xlocal, ylocal, dx, dy, zA, zB, elev;
|
||||||
|
int x1, x2, x3, y1, y2, y3;
|
||||||
|
float z1, z2, z3;
|
||||||
|
int xindex, yindex;
|
||||||
|
|
||||||
|
/* determine if we are in the lower triangle or the upper triangle
|
||||||
|
______
|
||||||
|
| /|
|
||||||
|
| / |
|
||||||
|
| / |
|
||||||
|
|/ |
|
||||||
|
------
|
||||||
|
|
||||||
|
then calculate our end points
|
||||||
|
*/
|
||||||
|
|
||||||
|
xlocal = (lon - originx) / col_step;
|
||||||
|
ylocal = (lat - originy) / row_step;
|
||||||
|
|
||||||
|
xindex = (int)(xlocal);
|
||||||
|
yindex = (int)(ylocal);
|
||||||
|
|
||||||
|
// printf("xindex = %d yindex = %d\n", xindex, yindex);
|
||||||
|
|
||||||
|
if ( xindex + 1 == cols ) {
|
||||||
|
xindex--;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( yindex + 1 == rows ) {
|
||||||
|
yindex--;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( (xindex < 0) || (xindex + 1 >= cols) ||
|
||||||
|
(yindex < 0) || (yindex + 1 >= rows) ) {
|
||||||
|
return(-9999);
|
||||||
|
}
|
||||||
|
|
||||||
|
dx = xlocal - xindex;
|
||||||
|
dy = ylocal - yindex;
|
||||||
|
|
||||||
|
if ( dx > dy ) {
|
||||||
|
// lower triangle
|
||||||
|
// printf(" Lower triangle\n");
|
||||||
|
|
||||||
|
x1 = xindex;
|
||||||
|
y1 = yindex;
|
||||||
|
z1 = dem_data[x1][y1];
|
||||||
|
|
||||||
|
x2 = xindex + 1;
|
||||||
|
y2 = yindex;
|
||||||
|
z2 = dem_data[x2][y2];
|
||||||
|
|
||||||
|
x3 = xindex + 1;
|
||||||
|
y3 = yindex + 1;
|
||||||
|
z3 = dem_data[x3][y3];
|
||||||
|
|
||||||
|
// printf(" dx = %.2f dy = %.2f\n", dx, dy);
|
||||||
|
// printf(" (x1,y1,z1) = (%d,%d,%d)\n", x1, y1, z1);
|
||||||
|
// printf(" (x2,y2,z2) = (%d,%d,%d)\n", x2, y2, z2);
|
||||||
|
// printf(" (x3,y3,z3) = (%d,%d,%d)\n", x3, y3, z3);
|
||||||
|
|
||||||
|
zA = dx * (z2 - z1) + z1;
|
||||||
|
zB = dx * (z3 - z1) + z1;
|
||||||
|
|
||||||
|
// printf(" zA = %.2f zB = %.2f\n", zA, zB);
|
||||||
|
|
||||||
|
if ( dx > FG_EPSILON ) {
|
||||||
|
elev = dy * (zB - zA) / dx + zA;
|
||||||
|
} else {
|
||||||
|
elev = zA;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// upper triangle
|
||||||
|
// printf(" Upper triangle\n");
|
||||||
|
|
||||||
|
x1 = xindex;
|
||||||
|
y1 = yindex;
|
||||||
|
z1 = dem_data[x1][y1];
|
||||||
|
|
||||||
|
x2 = xindex;
|
||||||
|
y2 = yindex + 1;
|
||||||
|
z2 = dem_data[x2][y2];
|
||||||
|
|
||||||
|
x3 = xindex + 1;
|
||||||
|
y3 = yindex + 1;
|
||||||
|
z3 = dem_data[x3][y3];
|
||||||
|
|
||||||
|
// printf(" dx = %.2f dy = %.2f\n", dx, dy);
|
||||||
|
// printf(" (x1,y1,z1) = (%d,%d,%d)\n", x1, y1, z1);
|
||||||
|
// printf(" (x2,y2,z2) = (%d,%d,%d)\n", x2, y2, z2);
|
||||||
|
// printf(" (x3,y3,z3) = (%d,%d,%d)\n", x3, y3, z3);
|
||||||
|
|
||||||
|
zA = dy * (z2 - z1) + z1;
|
||||||
|
zB = dy * (z3 - z1) + z1;
|
||||||
|
|
||||||
|
// printf(" zA = %.2f zB = %.2f\n", zA, zB );
|
||||||
|
// printf(" xB - xA = %.2f\n", col_step * dy / row_step);
|
||||||
|
|
||||||
|
if ( dy > FG_EPSILON ) {
|
||||||
|
elev = dx * (zB - zA) / dy + zA;
|
||||||
|
} else {
|
||||||
|
elev = zA;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return(elev);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Use least squares to fit a simpler data set to dem data
|
||||||
|
void FGDem::fit( double error, FGBucket& p ) {
|
||||||
|
double x[DEM_SIZE_1], y[DEM_SIZE_1];
|
||||||
|
double m, b, ave_error, max_error;
|
||||||
|
double cury, lasty;
|
||||||
|
int n, row, start, end;
|
||||||
|
int colmin, colmax, rowmin, rowmax;
|
||||||
|
bool good_fit;
|
||||||
|
// FILE *dem, *fit, *fit1;
|
||||||
|
|
||||||
|
printf("Initializing output mesh structure\n");
|
||||||
|
outputmesh_init();
|
||||||
|
|
||||||
|
// determine dimensions
|
||||||
|
colmin = p.get_x() * ( (cols - 1) / 8);
|
||||||
|
colmax = colmin + ( (cols - 1) / 8);
|
||||||
|
rowmin = p.get_y() * ( (rows - 1) / 8);
|
||||||
|
rowmax = rowmin + ( (rows - 1) / 8);
|
||||||
|
printf("Fitting region = %d,%d to %d,%d\n", colmin, rowmin, colmax, rowmax);
|
||||||
|
|
||||||
|
// include the corners explicitly
|
||||||
|
outputmesh_set_pt(colmin, rowmin, dem_data[colmin][rowmin]);
|
||||||
|
outputmesh_set_pt(colmin, rowmax, dem_data[colmin][rowmax]);
|
||||||
|
outputmesh_set_pt(colmax, rowmax, dem_data[colmax][rowmax]);
|
||||||
|
outputmesh_set_pt(colmax, rowmin, dem_data[colmax][rowmin]);
|
||||||
|
|
||||||
|
printf("Beginning best fit procedure\n");
|
||||||
|
|
||||||
|
for ( row = rowmin; row <= rowmax; row++ ) {
|
||||||
|
// fit = fopen("fit.dat", "w");
|
||||||
|
// fit1 = fopen("fit1.dat", "w");
|
||||||
|
|
||||||
|
start = colmin;
|
||||||
|
|
||||||
|
// printf(" fitting row = %d\n", row);
|
||||||
|
|
||||||
|
while ( start < colmax ) {
|
||||||
|
end = start + 1;
|
||||||
|
good_fit = true;
|
||||||
|
|
||||||
|
x[(end - start) - 1] = 0.0 + ( start * col_step );
|
||||||
|
y[(end - start) - 1] = dem_data[start][row];
|
||||||
|
|
||||||
|
while ( (end <= colmax) && good_fit ) {
|
||||||
|
n = (end - start) + 1;
|
||||||
|
// printf("Least square of first %d points\n", n);
|
||||||
|
x[end - start] = 0.0 + ( end * col_step );
|
||||||
|
y[end - start] = dem_data[end][row];
|
||||||
|
least_squares(x, y, n, &m, &b);
|
||||||
|
ave_error = least_squares_error(x, y, n, m, b);
|
||||||
|
max_error = least_squares_max_error(x, y, n, m, b);
|
||||||
|
|
||||||
|
/*
|
||||||
|
printf("%d - %d ave error = %.2f max error = %.2f y = %.2f*x + %.2f\n",
|
||||||
|
start, end, ave_error, max_error, m, b);
|
||||||
|
|
||||||
|
f = fopen("gnuplot.dat", "w");
|
||||||
|
for ( j = 0; j <= end; j++) {
|
||||||
|
fprintf(f, "%.2f %.2f\n", 0.0 + ( j * col_step ),
|
||||||
|
dem_data[row][j]);
|
||||||
|
}
|
||||||
|
for ( j = start; j <= end; j++) {
|
||||||
|
fprintf(f, "%.2f %.2f\n", 0.0 + ( j * col_step ),
|
||||||
|
dem_data[row][j]);
|
||||||
|
}
|
||||||
|
fclose(f);
|
||||||
|
|
||||||
|
printf("Please hit return: "); gets(junk);
|
||||||
|
*/
|
||||||
|
|
||||||
|
if ( max_error > error ) {
|
||||||
|
good_fit = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
end++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( !good_fit ) {
|
||||||
|
// error exceeded the threshold, back up
|
||||||
|
end -= 2; // back "end" up to the last good enough fit
|
||||||
|
n--; // back "n" up appropriately too
|
||||||
|
} else {
|
||||||
|
// we popped out of the above loop while still within
|
||||||
|
// the error threshold, so we must be at the end of
|
||||||
|
// the data set
|
||||||
|
end--;
|
||||||
|
}
|
||||||
|
|
||||||
|
least_squares(x, y, n, &m, &b);
|
||||||
|
ave_error = least_squares_error(x, y, n, m, b);
|
||||||
|
max_error = least_squares_max_error(x, y, n, m, b);
|
||||||
|
|
||||||
|
/*
|
||||||
|
printf("\n");
|
||||||
|
printf("%d - %d ave error = %.2f max error = %.2f y = %.2f*x + %.2f\n",
|
||||||
|
start, end, ave_error, max_error, m, b);
|
||||||
|
printf("\n");
|
||||||
|
|
||||||
|
fprintf(fit1, "%.2f %.2f\n", x[0], m * x[0] + b);
|
||||||
|
fprintf(fit1, "%.2f %.2f\n", x[end-start], m * x[end-start] + b);
|
||||||
|
*/
|
||||||
|
|
||||||
|
if ( start > colmin ) {
|
||||||
|
// skip this for the first line segment
|
||||||
|
cury = m * x[0] + b;
|
||||||
|
outputmesh_set_pt(start, row, (lasty + cury) / 2);
|
||||||
|
// fprintf(fit, "%.2f %.2f\n", x[0], (lasty + cury) / 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
lasty = m * x[end-start] + b;
|
||||||
|
start = end;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
fclose(fit);
|
||||||
|
fclose(fit1);
|
||||||
|
|
||||||
|
dem = fopen("gnuplot.dat", "w");
|
||||||
|
for ( j = 0; j < DEM_SIZE_1; j++) {
|
||||||
|
fprintf(dem, "%.2f %.2f\n", 0.0 + ( j * col_step ),
|
||||||
|
dem_data[j][row]);
|
||||||
|
}
|
||||||
|
fclose(dem);
|
||||||
|
*/
|
||||||
|
|
||||||
|
// NOTICE, this is for testing only. This instance of
|
||||||
|
// output_nodes should be removed. It should be called only
|
||||||
|
// once at the end once all the nodes have been generated.
|
||||||
|
// newmesh_output_nodes(&nm, "mesh.node");
|
||||||
|
// printf("Please hit return: "); gets(junk);
|
||||||
|
}
|
||||||
|
|
||||||
|
// outputmesh_output_nodes(fg_root, p);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Initialize output mesh structure
|
||||||
|
void FGDem::outputmesh_init( void ) {
|
||||||
|
int i, j;
|
||||||
|
|
||||||
|
for ( j = 0; j < DEM_SIZE_1; j++ ) {
|
||||||
|
for ( i = 0; i < DEM_SIZE_1; i++ ) {
|
||||||
|
output_data[i][j] = -9999.0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Get the value of a mesh node
|
||||||
|
double FGDem::outputmesh_get_pt( int i, int j ) {
|
||||||
|
return ( output_data[i][j] );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Set the value of a mesh node
|
||||||
|
void FGDem::outputmesh_set_pt( int i, int j, double value ) {
|
||||||
|
// printf("Setting data[%d][%d] = %.2f\n", i, j, value);
|
||||||
|
output_data[i][j] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Write out a node file that can be used by the "triangle" program.
|
||||||
|
// Check for an optional "index.node.ex" file in case there is a .poly
|
||||||
|
// file to go along with this node file. Include these nodes first
|
||||||
|
// since they are referenced by position from the .poly file.
|
||||||
|
void FGDem::outputmesh_output_nodes( const string& fg_root, FGBucket& p )
|
||||||
|
{
|
||||||
|
double exnodes[MAX_EX_NODES][3];
|
||||||
|
struct stat stat_buf;
|
||||||
|
string dir;
|
||||||
|
char file[256], exfile[256];
|
||||||
|
#ifdef WIN32
|
||||||
|
char tmp_path[256];
|
||||||
|
#endif
|
||||||
|
string command;
|
||||||
|
FILE *fd;
|
||||||
|
long int index;
|
||||||
|
int colmin, colmax, rowmin, rowmax;
|
||||||
|
int i, j, count, excount, result;
|
||||||
|
|
||||||
|
// determine dimensions
|
||||||
|
colmin = p.get_x() * ( (cols - 1) / 8);
|
||||||
|
colmax = colmin + ( (cols - 1) / 8);
|
||||||
|
rowmin = p.get_y() * ( (rows - 1) / 8);
|
||||||
|
rowmax = rowmin + ( (rows - 1) / 8);
|
||||||
|
cout << " dumping region = " << colmin << "," << rowmin << " to " <<
|
||||||
|
colmax << "," << rowmax << "\n";
|
||||||
|
|
||||||
|
// generate the base directory
|
||||||
|
string base_path = p.gen_base_path();
|
||||||
|
cout << "fg_root = " << fg_root << " Base Path = " << base_path << endl;
|
||||||
|
dir = fg_root + "/" + base_path;
|
||||||
|
cout << "Dir = " << dir << endl;
|
||||||
|
|
||||||
|
// stat() directory and create if needed
|
||||||
|
errno = 0;
|
||||||
|
result = stat(dir.c_str(), &stat_buf);
|
||||||
|
if ( result != 0 && errno == ENOENT ) {
|
||||||
|
cout << "Creating directory\n";
|
||||||
|
|
||||||
|
// #ifndef WIN32
|
||||||
|
|
||||||
|
command = "mkdir -p " + dir + "\n";
|
||||||
|
system( command.c_str() );
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
// #else // WIN32
|
||||||
|
|
||||||
|
// Cygwin crashes when trying to output to node file
|
||||||
|
// explicitly making directory structure seems OK on Win95
|
||||||
|
|
||||||
|
extract_path (base_path, tmp_path);
|
||||||
|
|
||||||
|
dir = fg_root + "/" + tmp_path;
|
||||||
|
if (my_mkdir ( dir.c_str() )) { exit (-1); }
|
||||||
|
|
||||||
|
dir = fg_root + "/" + base_path;
|
||||||
|
if (my_mkdir ( dir.c_str() )) { exit (-1); }
|
||||||
|
|
||||||
|
// #endif // WIN32
|
||||||
|
#endif //0
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// assume directory exists
|
||||||
|
}
|
||||||
|
|
||||||
|
// get index and generate output file name
|
||||||
|
index = p.gen_index();
|
||||||
|
sprintf(file, "%s/%ld.node", dir.c_str(), index);
|
||||||
|
|
||||||
|
// get (optional) extra node file name (in case there is matching
|
||||||
|
// .poly file.
|
||||||
|
strcpy(exfile, file);
|
||||||
|
strcat(exfile, ".ex");
|
||||||
|
|
||||||
|
// load extra nodes if they exist
|
||||||
|
excount = 0;
|
||||||
|
if ( (fd = fopen(exfile, "r")) != NULL ) {
|
||||||
|
int junki;
|
||||||
|
fscanf(fd, "%d %d %d %d", &excount, &junki, &junki, &junki);
|
||||||
|
|
||||||
|
if ( excount > MAX_EX_NODES - 1 ) {
|
||||||
|
printf("Error, too many 'extra' nodes, increase array size\n");
|
||||||
|
exit(-1);
|
||||||
|
} else {
|
||||||
|
printf(" Expecting %d 'extra' nodes\n", excount);
|
||||||
|
}
|
||||||
|
|
||||||
|
for ( i = 1; i <= excount; i++ ) {
|
||||||
|
fscanf(fd, "%d %lf %lf %lf\n", &junki,
|
||||||
|
&exnodes[i][0], &exnodes[i][1], &exnodes[i][2]);
|
||||||
|
printf("(extra) %d %.2f %.2f %.2f\n",
|
||||||
|
i, exnodes[i][0], exnodes[i][1], exnodes[i][2]);
|
||||||
|
}
|
||||||
|
fclose(fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("Creating node file: %s\n", file);
|
||||||
|
fd = fopen(file, "w");
|
||||||
|
|
||||||
|
// first count regular nodes to generate header
|
||||||
|
count = 0;
|
||||||
|
for ( j = rowmin; j <= rowmax; j++ ) {
|
||||||
|
for ( i = colmin; i <= colmax; i++ ) {
|
||||||
|
if ( output_data[i][j] > -9000.0 ) {
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// printf(" count = %d\n", count);
|
||||||
|
}
|
||||||
|
fprintf(fd, "%d 2 1 0\n", count + excount);
|
||||||
|
|
||||||
|
// now write out extra node data
|
||||||
|
for ( i = 1; i <= excount; i++ ) {
|
||||||
|
fprintf(fd, "%d %.2f %.2f %.2f\n",
|
||||||
|
i, exnodes[i][0], exnodes[i][1], exnodes[i][2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// write out actual node data
|
||||||
|
count = excount + 1;
|
||||||
|
for ( j = rowmin; j <= rowmax; j++ ) {
|
||||||
|
for ( i = colmin; i <= colmax; i++ ) {
|
||||||
|
if ( output_data[i][j] > -9000.0 ) {
|
||||||
|
fprintf(fd, "%d %.2f %.2f %.2f\n",
|
||||||
|
count++,
|
||||||
|
originx + (double)i * col_step,
|
||||||
|
originy + (double)j * row_step,
|
||||||
|
output_data[i][j]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// printf(" count = %d\n", count);
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(fd);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
FGDem::~FGDem( void ) {
|
||||||
|
// printf("class FGDem DEstructor called.\n");
|
||||||
|
delete [] dem_data;
|
||||||
|
delete [] output_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
154
src/Lib/DEM/dem.hxx
Normal file
154
src/Lib/DEM/dem.hxx
Normal file
|
@ -0,0 +1,154 @@
|
||||||
|
// dem.hxx -- DEM management class
|
||||||
|
//
|
||||||
|
// Written by Curtis Olson, started March 1998.
|
||||||
|
//
|
||||||
|
// Copyright (C) 1998 Curtis L. Olson - curt@flightgear.org
|
||||||
|
//
|
||||||
|
// This program is free software; you can redistribute it and/or
|
||||||
|
// modify it under the terms of the GNU General Public License as
|
||||||
|
// published by the Free Software Foundation; either version 2 of the
|
||||||
|
// License, or (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful, but
|
||||||
|
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
// General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
//
|
||||||
|
// $Id$
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef _DEM_HXX
|
||||||
|
#define _DEM_HXX
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef __cplusplus
|
||||||
|
# error This library requires C++
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#include <simgear/newbucket.hxx>
|
||||||
|
#include <simgear/fgstream.hxx>
|
||||||
|
|
||||||
|
|
||||||
|
#define DEM_SIZE 1200
|
||||||
|
#define DEM_SIZE_1 1201
|
||||||
|
|
||||||
|
|
||||||
|
class FGDem {
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
// file pointer for input
|
||||||
|
// gzFile fd;
|
||||||
|
fg_gzifstream *in;
|
||||||
|
|
||||||
|
// coordinates (in arc seconds) of south west corner
|
||||||
|
double originx, originy;
|
||||||
|
|
||||||
|
// number of columns and rows
|
||||||
|
int cols, rows;
|
||||||
|
|
||||||
|
// Distance between column and row data points (in arc seconds)
|
||||||
|
double col_step, row_step;
|
||||||
|
|
||||||
|
// pointers to the actual grid data allocated here
|
||||||
|
float (*dem_data)[DEM_SIZE_1];
|
||||||
|
float (*output_data)[DEM_SIZE_1];
|
||||||
|
|
||||||
|
// Current "A" Record Information
|
||||||
|
char dem_description[80], dem_quadrangle[80];
|
||||||
|
double dem_x1, dem_y1, dem_x2, dem_y2, dem_x3, dem_y3, dem_x4, dem_y4;
|
||||||
|
double dem_z1, dem_z2;
|
||||||
|
int dem_resolution, dem_num_profiles;
|
||||||
|
|
||||||
|
// Current "B" Record Information
|
||||||
|
int prof_col, prof_row;
|
||||||
|
int prof_num_cols, prof_num_rows;
|
||||||
|
double prof_x1, prof_y1;
|
||||||
|
int prof_data;
|
||||||
|
|
||||||
|
// temporary values for the class to use
|
||||||
|
char option_name[32];
|
||||||
|
int do_data;
|
||||||
|
int cur_col, cur_row;
|
||||||
|
|
||||||
|
// return next token from input stream
|
||||||
|
string next_token();
|
||||||
|
|
||||||
|
// return next integer from input stream
|
||||||
|
int next_int();
|
||||||
|
|
||||||
|
// return next double from input stream
|
||||||
|
double next_double();
|
||||||
|
|
||||||
|
// return next exponential num from input stream
|
||||||
|
double next_exp();
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
// Constructor
|
||||||
|
FGDem( void );
|
||||||
|
FGDem( const string& file );
|
||||||
|
|
||||||
|
// Destructor
|
||||||
|
~FGDem( void );
|
||||||
|
|
||||||
|
// open a DEM file (use "-" if input is coming from stdin)
|
||||||
|
int open ( const string& file );
|
||||||
|
|
||||||
|
// close a DEM file
|
||||||
|
int close();
|
||||||
|
|
||||||
|
// parse a DEM file
|
||||||
|
int parse();
|
||||||
|
|
||||||
|
// read and parse DEM "A" record
|
||||||
|
int read_a_record();
|
||||||
|
|
||||||
|
// read and parse DEM "B" record
|
||||||
|
void read_b_record();
|
||||||
|
|
||||||
|
// write out the area of data covered by the specified bucket.
|
||||||
|
// Data is written out column by column starting at the lower left
|
||||||
|
// hand corner.
|
||||||
|
int write_area( const string& root, FGBucket& b, bool compress );
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
// return the current altitude based on grid data. We should
|
||||||
|
// rewrite this to interpolate exact values, but for now this is
|
||||||
|
// good enough
|
||||||
|
double interpolate_altitude( double lon, double lat );
|
||||||
|
|
||||||
|
// Use least squares to fit a simpler data set to dem data
|
||||||
|
void fit( double error, FGBucket& p );
|
||||||
|
|
||||||
|
// Initialize output mesh structure
|
||||||
|
void outputmesh_init( void );
|
||||||
|
|
||||||
|
// Get the value of a mesh node
|
||||||
|
double outputmesh_get_pt( int i, int j );
|
||||||
|
|
||||||
|
// Set the value of a mesh node
|
||||||
|
void outputmesh_set_pt( int i, int j, double value );
|
||||||
|
|
||||||
|
// Write out a node file that can be used by the "triangle" program
|
||||||
|
void outputmesh_output_nodes( const string& fg_root, FGBucket& p );
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Informational methods
|
||||||
|
inline double get_originx() const { return originx; }
|
||||||
|
inline double get_originy() const { return originy; }
|
||||||
|
inline int get_cols() const { return cols; }
|
||||||
|
inline int get_rows() const { return rows; }
|
||||||
|
inline double get_col_step() const { return col_step; }
|
||||||
|
inline double get_row_step() const { return row_step; }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // _DEM_HXX
|
||||||
|
|
||||||
|
|
8
src/Lib/Geometry/Makefile.am
Normal file
8
src/Lib/Geometry/Makefile.am
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
noinst_LIBRARIES = libBuild.a
|
||||||
|
|
||||||
|
libBuild_a_SOURCES = \
|
||||||
|
poly_support.cxx poly_support.hxx \
|
||||||
|
trinodes.cxx trinodes.hxx \
|
||||||
|
trisegs.cxx trisegs.hxx
|
||||||
|
|
||||||
|
INCLUDES += -I$(top_builddir) -I$(top_builddir)/Lib -I$(top_builddir)/Tools/Lib
|
229
src/Lib/Geometry/poly_support.cxx
Normal file
229
src/Lib/Geometry/poly_support.cxx
Normal file
|
@ -0,0 +1,229 @@
|
||||||
|
// poly_support.cxx -- additional supporting routines for the FGPolygon class
|
||||||
|
// specific to the object building process.
|
||||||
|
//
|
||||||
|
// Written by Curtis Olson, started October 1999.
|
||||||
|
//
|
||||||
|
// Copyright (C) 1999 Curtis L. Olson - curt@flightgear.org
|
||||||
|
//
|
||||||
|
// This program is free software; you can redistribute it and/or
|
||||||
|
// modify it under the terms of the GNU General Public License as
|
||||||
|
// published by the Free Software Foundation; either version 2 of the
|
||||||
|
// License, or (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful, but
|
||||||
|
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
// General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
//
|
||||||
|
// $Id$
|
||||||
|
|
||||||
|
|
||||||
|
#include <simgear/compiler.h>
|
||||||
|
#include <simgear/fg_types.hxx>
|
||||||
|
|
||||||
|
#include <Polygon/polygon.hxx>
|
||||||
|
|
||||||
|
#include "trinodes.hxx"
|
||||||
|
|
||||||
|
|
||||||
|
// calculate some "arbitrary" point inside the specified contour for
|
||||||
|
// assigning attribute areas. This requires data structures outside
|
||||||
|
// of "FGPolygon" which is why it is living over here in "Lib/Build"
|
||||||
|
|
||||||
|
void calc_point_inside( const int contour, const FGTriNodes& trinodes );
|
||||||
|
|
||||||
|
|
||||||
|
#include <simgear/constants.h>
|
||||||
|
#include <simgear/point3d.hxx>
|
||||||
|
|
||||||
|
#include <Build/trisegs.hxx>
|
||||||
|
|
||||||
|
|
||||||
|
// Given a line segment specified by two endpoints p1 and p2, return
|
||||||
|
// the slope of the line.
|
||||||
|
static double slope( const Point3D& p0, const Point3D& p1 ) {
|
||||||
|
if ( fabs(p0.x() - p1.x()) > FG_EPSILON ) {
|
||||||
|
return (p0.y() - p1.y()) / (p0.x() - p1.x());
|
||||||
|
} else {
|
||||||
|
return 1.0e+999; // really big number
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Given a line segment specified by two endpoints p1 and p2, return
|
||||||
|
// the y value of a point on the line that intersects with the
|
||||||
|
// verticle line through x. Return true if an intersection is found,
|
||||||
|
// false otherwise.
|
||||||
|
static bool intersects( Point3D p0, Point3D p1, double x, Point3D *result ) {
|
||||||
|
// sort the end points
|
||||||
|
if ( p0.x() > p1.x() ) {
|
||||||
|
Point3D tmp = p0;
|
||||||
|
p0 = p1;
|
||||||
|
p1 = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( (x < p0.x()) || (x > p1.x()) ) {
|
||||||
|
// out of range of line segment, bail right away
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// equation of a line through (x0,y0) and (x1,y1):
|
||||||
|
//
|
||||||
|
// y = y1 + (x - x1) * (y0 - y1) / (x0 - x1)
|
||||||
|
|
||||||
|
double y;
|
||||||
|
|
||||||
|
if ( fabs(p0.x() - p1.x()) > FG_EPSILON ) {
|
||||||
|
y = p1.y() + (x - p1.x()) * (p0.y() - p1.y()) / (p0.x() - p1.x());
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
result->setx(x);
|
||||||
|
result->sety(y);
|
||||||
|
|
||||||
|
if ( p0.y() <= p1.y() ) {
|
||||||
|
if ( (p0.y() <= y) && (y <= p1.y()) ) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if ( (p0.y() >= y) && (y >= p1.y()) ) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// calculate some "arbitrary" point inside the specified contour for
|
||||||
|
// assigning attribute areas
|
||||||
|
Point3D calc_point_inside( const FGPolygon& p, const int contour,
|
||||||
|
const FGTriNodes& trinodes ) {
|
||||||
|
Point3D tmp, min, ln, p1, p2, p3, m, result, inside_pt;
|
||||||
|
int min_node_index = 0;
|
||||||
|
int min_index = 0;
|
||||||
|
int p1_index = 0;
|
||||||
|
int p2_index = 0;
|
||||||
|
int ln_index = 0;
|
||||||
|
|
||||||
|
// 1. find a point on the specified contour, min, with smallest y
|
||||||
|
|
||||||
|
// min.y() starts greater than the biggest possible lat (degrees)
|
||||||
|
min.sety( 100.0 );
|
||||||
|
|
||||||
|
point_list c = p.get_contour(contour);
|
||||||
|
point_list_iterator current, last;
|
||||||
|
current = c.begin();
|
||||||
|
last = c.end();
|
||||||
|
|
||||||
|
for ( int i = 0; i < p.contour_size( contour ); ++i ) {
|
||||||
|
tmp = p.get_pt( contour, i );
|
||||||
|
if ( tmp.y() < min.y() ) {
|
||||||
|
min = tmp;
|
||||||
|
min_index = trinodes.find( min );
|
||||||
|
min_node_index = i;
|
||||||
|
|
||||||
|
// cout << "min index = " << *current
|
||||||
|
// << " value = " << min_y << endl;
|
||||||
|
} else {
|
||||||
|
// cout << " index = " << *current << endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cout << "min node index = " << min_node_index << endl;
|
||||||
|
cout << "min index = " << min_index
|
||||||
|
<< " value = " << trinodes.get_node( min_index )
|
||||||
|
<< " == " << min << endl;
|
||||||
|
|
||||||
|
// 2. take midpoint, m, of min with neighbor having lowest
|
||||||
|
// fabs(slope)
|
||||||
|
|
||||||
|
if ( min_node_index == 0 ) {
|
||||||
|
p1 = c[1];
|
||||||
|
p2 = c[c.size() - 1];
|
||||||
|
} else if ( min_node_index == (int)(c.size()) - 1 ) {
|
||||||
|
p1 = c[0];
|
||||||
|
p2 = c[c.size() - 2];
|
||||||
|
} else {
|
||||||
|
p1 = c[min_node_index - 1];
|
||||||
|
p2 = c[min_node_index + 1];
|
||||||
|
}
|
||||||
|
p1_index = trinodes.find( p1 );
|
||||||
|
p2_index = trinodes.find( p2 );
|
||||||
|
|
||||||
|
double s1 = fabs( slope(min, p1) );
|
||||||
|
double s2 = fabs( slope(min, p2) );
|
||||||
|
if ( s1 < s2 ) {
|
||||||
|
ln_index = p1_index;
|
||||||
|
ln = p1;
|
||||||
|
} else {
|
||||||
|
ln_index = p2_index;
|
||||||
|
ln = p2;
|
||||||
|
}
|
||||||
|
|
||||||
|
FGTriSeg base_leg( min_index, ln_index, 0 );
|
||||||
|
|
||||||
|
m.setx( (min.x() + ln.x()) / 2.0 );
|
||||||
|
m.sety( (min.y() + ln.y()) / 2.0 );
|
||||||
|
cout << "low mid point = " << m << endl;
|
||||||
|
|
||||||
|
// 3. intersect vertical line through m and all other segments of
|
||||||
|
// all other contours of this polygon. save point, p3, with
|
||||||
|
// smallest y > m.y
|
||||||
|
|
||||||
|
p3.sety(100);
|
||||||
|
|
||||||
|
for ( int i = 0; i < (int)p.contours(); ++i ) {
|
||||||
|
cout << "contour = " << i << " size = " << p.contour_size( i ) << endl;
|
||||||
|
for ( int j = 0; j < (int)(p.contour_size( i ) - 1); ++j ) {
|
||||||
|
// cout << " p1 = " << poly[i][j] << " p2 = "
|
||||||
|
// << poly[i][j+1] << endl;
|
||||||
|
p1 = p.get_pt( i, j );
|
||||||
|
p2 = p.get_pt( i, j+1 );
|
||||||
|
p1_index = trinodes.find( p1 );
|
||||||
|
p2_index = trinodes.find( p2 );
|
||||||
|
|
||||||
|
if ( intersects(p1, p2, m.x(), &result) ) {
|
||||||
|
cout << "intersection = " << result << endl;
|
||||||
|
if ( ( result.y() < p3.y() ) &&
|
||||||
|
( result.y() > m.y() ) &&
|
||||||
|
( base_leg != FGTriSeg(p1_index, p2_index, 0) ) ) {
|
||||||
|
p3 = result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// cout << " p1 = " << poly[i][0] << " p2 = "
|
||||||
|
// << poly[i][poly[i].size() - 1] << endl;
|
||||||
|
p1 = p.get_pt( i, 0 );
|
||||||
|
p2 = p.get_pt( i, p.contour_size( i ) - 1 );
|
||||||
|
p1_index = trinodes.find( p1 );
|
||||||
|
p2_index = trinodes.find( p2 );
|
||||||
|
if ( intersects(p1, p2, m.x(), &result) ) {
|
||||||
|
cout << "intersection = " << result << endl;
|
||||||
|
if ( ( result.y() < p3.y() ) &&
|
||||||
|
( result.y() > m.y() ) &&
|
||||||
|
( base_leg != FGTriSeg(p1_index, p2_index, 0) ) ) {
|
||||||
|
p3 = result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ( p3.y() < 100 ) {
|
||||||
|
cout << "low intersection of other segment = " << p3 << endl;
|
||||||
|
inside_pt = Point3D( (m.x() + p3.x()) / 2.0,
|
||||||
|
(m.y() + p3.y()) / 2.0,
|
||||||
|
0.0 );
|
||||||
|
} else {
|
||||||
|
cout << "Error: Failed to find a point inside :-(" << endl;
|
||||||
|
inside_pt = p3;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. take midpoint of p2 && m as an arbitrary point inside polygon
|
||||||
|
|
||||||
|
cout << "inside point = " << inside_pt << endl;
|
||||||
|
|
||||||
|
return inside_pt;
|
||||||
|
}
|
52
src/Lib/Geometry/poly_support.hxx
Normal file
52
src/Lib/Geometry/poly_support.hxx
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
// poly_support.hxx -- additional supporting routines for the FGPolygon class
|
||||||
|
// specific to the object building process.
|
||||||
|
//
|
||||||
|
// Written by Curtis Olson, started October 1999.
|
||||||
|
//
|
||||||
|
// Copyright (C) 1999 Curtis L. Olson - curt@flightgear.org
|
||||||
|
//
|
||||||
|
// This program is free software; you can redistribute it and/or
|
||||||
|
// modify it under the terms of the GNU General Public License as
|
||||||
|
// published by the Free Software Foundation; either version 2 of the
|
||||||
|
// License, or (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful, but
|
||||||
|
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
// General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
//
|
||||||
|
// $Id$
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef _POLY_SUPPORT_HXX
|
||||||
|
#define _POLY_SUPPORT_HXX
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef __cplusplus
|
||||||
|
# error This library requires C++
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#include <simgear/compiler.h>
|
||||||
|
#include <simgear/fg_types.hxx>
|
||||||
|
|
||||||
|
#include <Polygon/polygon.hxx>
|
||||||
|
|
||||||
|
#include "trinodes.hxx"
|
||||||
|
|
||||||
|
|
||||||
|
// calculate some "arbitrary" point inside the specified contour for
|
||||||
|
// assigning attribute areas. This requires data structures outside
|
||||||
|
// of "FGPolygon" which is why it is living over here in "Lib/Build"
|
||||||
|
|
||||||
|
Point3D calc_point_inside( const FGPolygon& p, const int contour,
|
||||||
|
const FGTriNodes& trinodes );
|
||||||
|
|
||||||
|
|
||||||
|
#endif // _POLY_SUPPORT_HXX
|
||||||
|
|
||||||
|
|
123
src/Lib/Geometry/trinodes.cxx
Normal file
123
src/Lib/Geometry/trinodes.cxx
Normal file
|
@ -0,0 +1,123 @@
|
||||||
|
// trinodes.cxx -- "Triangle" nodes management class
|
||||||
|
//
|
||||||
|
// Written by Curtis Olson, started March 1999.
|
||||||
|
//
|
||||||
|
// Copyright (C) 1999 Curtis L. Olson - curt@flightgear.org
|
||||||
|
//
|
||||||
|
// This program is free software; you can redistribute it and/or
|
||||||
|
// modify it under the terms of the GNU General Public License as
|
||||||
|
// published by the Free Software Foundation; either version 2 of the
|
||||||
|
// License, or (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful, but
|
||||||
|
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
// General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
//
|
||||||
|
// $Id$
|
||||||
|
|
||||||
|
|
||||||
|
#include "trinodes.hxx"
|
||||||
|
|
||||||
|
|
||||||
|
// Constructor
|
||||||
|
FGTriNodes::FGTriNodes( void ) {
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Destructor
|
||||||
|
FGTriNodes::~FGTriNodes( void ) {
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Add a point to the point list if it doesn't already exist. Returns
|
||||||
|
// the index (starting at zero) of the point in the list.
|
||||||
|
int FGTriNodes::unique_add( const Point3D& p ) {
|
||||||
|
point_list_iterator current, last;
|
||||||
|
int counter = 0;
|
||||||
|
|
||||||
|
// cout << p.x() << "," << p.y() << endl;
|
||||||
|
|
||||||
|
// see if point already exists
|
||||||
|
current = node_list.begin();
|
||||||
|
last = node_list.end();
|
||||||
|
for ( ; current != last; ++current ) {
|
||||||
|
if ( close_enough(p, *current) ) {
|
||||||
|
// cout << "found an existing match!" << endl;
|
||||||
|
return counter;
|
||||||
|
}
|
||||||
|
|
||||||
|
++counter;
|
||||||
|
}
|
||||||
|
|
||||||
|
// add to list
|
||||||
|
node_list.push_back( p );
|
||||||
|
|
||||||
|
return counter;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Add the point with no uniqueness checking
|
||||||
|
int FGTriNodes::simple_add( const Point3D& p ) {
|
||||||
|
node_list.push_back( p );
|
||||||
|
|
||||||
|
return node_list.size() - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Add a point to the point list if it doesn't already exist. Returns
|
||||||
|
// the index (starting at zero) of the point in the list. Use a
|
||||||
|
// course proximity check
|
||||||
|
int FGTriNodes::course_add( const Point3D& p ) {
|
||||||
|
point_list_iterator current, last;
|
||||||
|
int counter = 0;
|
||||||
|
|
||||||
|
// cout << p.x() << "," << p.y() << endl;
|
||||||
|
|
||||||
|
// see if point already exists
|
||||||
|
current = node_list.begin();
|
||||||
|
last = node_list.end();
|
||||||
|
for ( ; current != last; ++current ) {
|
||||||
|
if ( course_close_enough(p, *current) ) {
|
||||||
|
// cout << "found an existing match!" << endl;
|
||||||
|
return counter;
|
||||||
|
}
|
||||||
|
|
||||||
|
++counter;
|
||||||
|
}
|
||||||
|
|
||||||
|
// add to list
|
||||||
|
node_list.push_back( p );
|
||||||
|
|
||||||
|
return counter;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Find the index of the specified point (compair to the same
|
||||||
|
// tolerance as unique_add(). Returns -1 if not found.
|
||||||
|
int FGTriNodes::find( const Point3D& p ) const {
|
||||||
|
const_point_list_iterator current, last;
|
||||||
|
int counter = 0;
|
||||||
|
|
||||||
|
// cout << p.x() << "," << p.y() << endl;
|
||||||
|
|
||||||
|
// see if point already exists
|
||||||
|
current = node_list.begin();
|
||||||
|
last = node_list.end();
|
||||||
|
for ( ; current != last; ++current ) {
|
||||||
|
if ( close_enough(p, *current) ) {
|
||||||
|
// cout << "found an existing match!" << endl;
|
||||||
|
return counter;
|
||||||
|
}
|
||||||
|
|
||||||
|
++counter;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
124
src/Lib/Geometry/trinodes.hxx
Normal file
124
src/Lib/Geometry/trinodes.hxx
Normal file
|
@ -0,0 +1,124 @@
|
||||||
|
// trinodes.hxx -- "Triangle" nodes management class
|
||||||
|
//
|
||||||
|
// Written by Curtis Olson, started March 1999.
|
||||||
|
//
|
||||||
|
// Copyright (C) 1999 Curtis L. Olson - curt@flightgear.org
|
||||||
|
//
|
||||||
|
// This program is free software; you can redistribute it and/or
|
||||||
|
// modify it under the terms of the GNU General Public License as
|
||||||
|
// published by the Free Software Foundation; either version 2 of the
|
||||||
|
// License, or (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful, but
|
||||||
|
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
// General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
//
|
||||||
|
// $Id$
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef _TRINODES_HXX
|
||||||
|
#define _TRINODES_HXX
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef __cplusplus
|
||||||
|
# error This library requires C++
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#include <simgear/compiler.h>
|
||||||
|
#include <simgear/fg_types.hxx>
|
||||||
|
#include <simgear/point3d.hxx>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#define FG_PROXIMITY_EPSILON 0.000001
|
||||||
|
#define FG_COURSE_EPSILON 0.0003
|
||||||
|
|
||||||
|
|
||||||
|
class FGTriNodes {
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
point_list node_list;
|
||||||
|
|
||||||
|
// return true of the two points are "close enough" as defined by
|
||||||
|
// FG_PROXIMITY_EPSILON
|
||||||
|
bool close_enough( const Point3D& p, const Point3D& p ) const;
|
||||||
|
|
||||||
|
// return true of the two points are "close enough" as defined by
|
||||||
|
// FG_COURSE_EPSILON
|
||||||
|
bool course_close_enough( const Point3D& p1, const Point3D& p2 );
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
// Constructor and destructor
|
||||||
|
FGTriNodes( void );
|
||||||
|
~FGTriNodes( void );
|
||||||
|
|
||||||
|
// delete all the data out of node_list
|
||||||
|
inline void clear() { node_list.clear(); }
|
||||||
|
|
||||||
|
// Add a point to the point list if it doesn't already exist.
|
||||||
|
// Returns the index (starting at zero) of the point in the list.
|
||||||
|
int unique_add( const Point3D& p );
|
||||||
|
|
||||||
|
// Add the point with no uniqueness checking
|
||||||
|
int simple_add( const Point3D& p );
|
||||||
|
|
||||||
|
// Add a point to the point list if it doesn't already exist.
|
||||||
|
// Returns the index (starting at zero) of the point in the list.
|
||||||
|
// Use a course proximity check
|
||||||
|
int course_add( const Point3D& p );
|
||||||
|
|
||||||
|
// Find the index of the specified point (compair to the same
|
||||||
|
// tolerance as unique_add(). Returns -1 if not found.
|
||||||
|
int find( const Point3D& p ) const;
|
||||||
|
|
||||||
|
// return the master node list
|
||||||
|
inline point_list get_node_list() const { return node_list; }
|
||||||
|
inline void set_node_list( point_list pl ) { node_list = pl; }
|
||||||
|
|
||||||
|
// return the ith point
|
||||||
|
inline Point3D get_node( int i ) const { return node_list[i]; }
|
||||||
|
|
||||||
|
// return the size of the node list
|
||||||
|
inline size_t size() const { return node_list.size(); }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// return true of the two points are "close enough" as defined by
|
||||||
|
// FG_PROXIMITY_EPSILON
|
||||||
|
inline bool FGTriNodes::close_enough( const Point3D& p1, const Point3D& p2 )
|
||||||
|
const
|
||||||
|
{
|
||||||
|
if ( ( fabs(p1.x() - p2.x()) < FG_PROXIMITY_EPSILON ) &&
|
||||||
|
( fabs(p1.y() - p2.y()) < FG_PROXIMITY_EPSILON ) ) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// return true of the two points are "close enough" as defined by
|
||||||
|
// FG_COURSE_EPSILON
|
||||||
|
inline bool FGTriNodes::course_close_enough( const Point3D& p1,
|
||||||
|
const Point3D& p2 )
|
||||||
|
{
|
||||||
|
if ( ( fabs(p1.x() - p2.x()) < FG_COURSE_EPSILON ) &&
|
||||||
|
( fabs(p1.y() - p2.y()) < FG_COURSE_EPSILON ) ) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif // _TRINODES_HXX
|
||||||
|
|
||||||
|
|
210
src/Lib/Geometry/trisegs.cxx
Normal file
210
src/Lib/Geometry/trisegs.cxx
Normal file
|
@ -0,0 +1,210 @@
|
||||||
|
// trisegs.cxx -- "Triangle" segment management class
|
||||||
|
//
|
||||||
|
// Written by Curtis Olson, started March 1999.
|
||||||
|
//
|
||||||
|
// Copyright (C) 1999 Curtis L. Olson - curt@flightgear.org
|
||||||
|
//
|
||||||
|
// This program is free software; you can redistribute it and/or
|
||||||
|
// modify it under the terms of the GNU General Public License as
|
||||||
|
// published by the Free Software Foundation; either version 2 of the
|
||||||
|
// License, or (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful, but
|
||||||
|
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
// General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
//
|
||||||
|
// $Id$
|
||||||
|
|
||||||
|
|
||||||
|
#include <simgear/constants.h>
|
||||||
|
#include <simgear/point3d.hxx>
|
||||||
|
|
||||||
|
#include "trinodes.hxx"
|
||||||
|
|
||||||
|
#include "trisegs.hxx"
|
||||||
|
|
||||||
|
|
||||||
|
// Constructor
|
||||||
|
FGTriSegments::FGTriSegments( void ) {
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Destructor
|
||||||
|
FGTriSegments::~FGTriSegments( void ) {
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Add a segment to the segment list if it doesn't already exist.
|
||||||
|
// Returns the index (starting at zero) of the segment in the list.
|
||||||
|
int FGTriSegments::unique_add( const FGTriSeg& s )
|
||||||
|
{
|
||||||
|
triseg_list_iterator current, last;
|
||||||
|
int counter = 0;
|
||||||
|
|
||||||
|
// cout << s.get_n1() << "," << s.get_n2() << endl;
|
||||||
|
|
||||||
|
// check if segment has duplicated endpoints
|
||||||
|
if ( s.get_n1() == s.get_n2() ) {
|
||||||
|
cout << "WARNING: ignoring null segment with the same "
|
||||||
|
<< "point for both endpoints" << endl;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if segment already exists
|
||||||
|
current = seg_list.begin();
|
||||||
|
last = seg_list.end();
|
||||||
|
for ( ; current != last; ++current ) {
|
||||||
|
if ( s == *current ) {
|
||||||
|
// cout << "found an existing segment match" << endl;
|
||||||
|
return counter;
|
||||||
|
}
|
||||||
|
|
||||||
|
++counter;
|
||||||
|
}
|
||||||
|
|
||||||
|
// add to list
|
||||||
|
seg_list.push_back( s );
|
||||||
|
|
||||||
|
return counter;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Divide segment if there are other points on it, return the divided
|
||||||
|
// list of segments
|
||||||
|
void FGTriSegments::unique_divide_and_add( const point_list& nodes,
|
||||||
|
const FGTriSeg& s )
|
||||||
|
{
|
||||||
|
Point3D p0 = nodes[ s.get_n1() ];
|
||||||
|
Point3D p1 = nodes[ s.get_n2() ];
|
||||||
|
|
||||||
|
bool found_extra = false;
|
||||||
|
int extra_index = 0;
|
||||||
|
int counter;
|
||||||
|
double m, m1, b, b1, y_err, x_err, y_err_min, x_err_min;
|
||||||
|
const_point_list_iterator current, last;
|
||||||
|
|
||||||
|
// bool temp = false;
|
||||||
|
// if ( s == FGTriSeg( 170, 206 ) ) {
|
||||||
|
// cout << "this is it!" << endl;
|
||||||
|
// temp = true;
|
||||||
|
// }
|
||||||
|
|
||||||
|
double xdist = fabs(p0.x() - p1.x());
|
||||||
|
double ydist = fabs(p0.y() - p1.y());
|
||||||
|
x_err_min = xdist + 1.0;
|
||||||
|
y_err_min = ydist + 1.0;
|
||||||
|
|
||||||
|
if ( xdist > ydist ) {
|
||||||
|
// use y = mx + b
|
||||||
|
|
||||||
|
// sort these in a sensible order
|
||||||
|
if ( p0.x() > p1.x() ) {
|
||||||
|
Point3D tmp = p0;
|
||||||
|
p0 = p1;
|
||||||
|
p1 = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
m = (p0.y() - p1.y()) / (p0.x() - p1.x());
|
||||||
|
b = p1.y() - m * p1.x();
|
||||||
|
|
||||||
|
// if ( temp ) {
|
||||||
|
// cout << "m = " << m << " b = " << b << endl;
|
||||||
|
// }
|
||||||
|
|
||||||
|
current = nodes.begin();
|
||||||
|
last = nodes.end();
|
||||||
|
counter = 0;
|
||||||
|
for ( ; current != last; ++current ) {
|
||||||
|
if ( (current->x() > (p0.x() + FG_EPSILON))
|
||||||
|
&& (current->x() < (p1.x() - FG_EPSILON)) ) {
|
||||||
|
|
||||||
|
// if ( temp ) {
|
||||||
|
// cout << counter << endl;
|
||||||
|
// }
|
||||||
|
|
||||||
|
y_err = fabs(current->y() - (m * current->x() + b));
|
||||||
|
|
||||||
|
if ( y_err < FG_PROXIMITY_EPSILON ) {
|
||||||
|
cout << "FOUND EXTRA SEGMENT NODE (Y)" << endl;
|
||||||
|
cout << p0 << " < " << *current << " < "
|
||||||
|
<< p1 << endl;
|
||||||
|
found_extra = true;
|
||||||
|
if ( y_err < y_err_min ) {
|
||||||
|
extra_index = counter;
|
||||||
|
y_err_min = y_err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
++counter;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// use x = m1 * y + b1
|
||||||
|
|
||||||
|
// sort these in a sensible order
|
||||||
|
if ( p0.y() > p1.y() ) {
|
||||||
|
Point3D tmp = p0;
|
||||||
|
p0 = p1;
|
||||||
|
p1 = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
m1 = (p0.x() - p1.x()) / (p0.y() - p1.y());
|
||||||
|
b1 = p1.x() - m1 * p1.y();
|
||||||
|
|
||||||
|
// bool temp = true;
|
||||||
|
// if ( temp ) {
|
||||||
|
// cout << "xdist = " << xdist << " ydist = " << ydist << endl;
|
||||||
|
// cout << " p0 = " << p0 << " p1 = " << p1 << endl;
|
||||||
|
// cout << " m1 = " << m1 << " b1 = " << b1 << endl;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// cout << " should = 0 = " << fabs(p0.x() - (m1 * p0.y() + b1)) << endl;;
|
||||||
|
// cout << " should = 0 = " << fabs(p1.x() - (m1 * p1.y() + b1)) << endl;;
|
||||||
|
|
||||||
|
current = nodes.begin();
|
||||||
|
last = nodes.end();
|
||||||
|
counter = 0;
|
||||||
|
for ( ; current != last; ++current ) {
|
||||||
|
if ( (current->y() > (p0.y() + FG_EPSILON))
|
||||||
|
&& (current->y() < (p1.y() - FG_EPSILON)) ) {
|
||||||
|
|
||||||
|
x_err = fabs(current->x() - (m1 * current->y() + b1));
|
||||||
|
|
||||||
|
// if ( temp ) {
|
||||||
|
// cout << " (" << counter << ") x_err = " << x_err << endl;
|
||||||
|
// }
|
||||||
|
|
||||||
|
if ( x_err < FG_PROXIMITY_EPSILON ) {
|
||||||
|
cout << "FOUND EXTRA SEGMENT NODE (X)" << endl;
|
||||||
|
cout << p0 << " < " << *current << " < "
|
||||||
|
<< p1 << endl;
|
||||||
|
found_extra = true;
|
||||||
|
if ( x_err < x_err_min ) {
|
||||||
|
extra_index = counter;
|
||||||
|
x_err_min = x_err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
++counter;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( found_extra ) {
|
||||||
|
// recurse with two sub segments
|
||||||
|
cout << "dividing " << s.get_n1() << " " << extra_index
|
||||||
|
<< " " << s.get_n2() << endl;
|
||||||
|
unique_divide_and_add( nodes, FGTriSeg( s.get_n1(), extra_index,
|
||||||
|
s.get_boundary_marker() ) );
|
||||||
|
unique_divide_and_add( nodes, FGTriSeg( extra_index, s.get_n2(),
|
||||||
|
s.get_boundary_marker() ) );
|
||||||
|
} else {
|
||||||
|
// this segment does not need to be divided, lets add it
|
||||||
|
unique_add( s );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
123
src/Lib/Geometry/trisegs.hxx
Normal file
123
src/Lib/Geometry/trisegs.hxx
Normal file
|
@ -0,0 +1,123 @@
|
||||||
|
// trisegs.hxx -- "Triangle" segment management class
|
||||||
|
//
|
||||||
|
// Written by Curtis Olson, started March 1999.
|
||||||
|
//
|
||||||
|
// Copyright (C) 1999 Curtis L. Olson - curt@flightgear.org
|
||||||
|
//
|
||||||
|
// This program is free software; you can redistribute it and/or
|
||||||
|
// modify it under the terms of the GNU General Public License as
|
||||||
|
// published by the Free Software Foundation; either version 2 of the
|
||||||
|
// License, or (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful, but
|
||||||
|
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
// General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
//
|
||||||
|
// $Id$
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef _TRISEGS_HXX
|
||||||
|
#define _TRISEGS_HXX
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef __cplusplus
|
||||||
|
# error This library requires C++
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#include <simgear/compiler.h>
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "trinodes.hxx"
|
||||||
|
|
||||||
|
FG_USING_STD(vector);
|
||||||
|
|
||||||
|
|
||||||
|
// a segment is two integer pointers into the node list
|
||||||
|
class FGTriSeg {
|
||||||
|
int n1, n2; // indices into point list
|
||||||
|
int boundary_marker; // flag if segment is a boundary
|
||||||
|
// (i.e. shouldn't get split)
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
// Constructor and destructor
|
||||||
|
inline FGTriSeg( void ) { };
|
||||||
|
inline FGTriSeg( int i1, int i2, int b ) {
|
||||||
|
n1 = i1;
|
||||||
|
n2 = i2;
|
||||||
|
boundary_marker = b;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline ~FGTriSeg( void ) { };
|
||||||
|
|
||||||
|
inline int get_n1() const { return n1; }
|
||||||
|
inline void set_n1( int i ) { n1 = i; }
|
||||||
|
inline int get_n2() const { return n2; }
|
||||||
|
inline void set_n2( int i ) { n2 = i; }
|
||||||
|
inline int get_boundary_marker() const { return boundary_marker; }
|
||||||
|
inline void set_boundary_marker( int b ) { boundary_marker = b; }
|
||||||
|
|
||||||
|
friend bool operator == (const FGTriSeg& a, const FGTriSeg& b);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
inline bool operator == (const FGTriSeg& a, const FGTriSeg& b)
|
||||||
|
{
|
||||||
|
return ((a.n1 == b.n1) && (a.n2 == b.n2))
|
||||||
|
|| ((a.n1 == b.n2) && (a.n2 == b.n1));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
typedef vector < FGTriSeg > triseg_list;
|
||||||
|
typedef triseg_list::iterator triseg_list_iterator;
|
||||||
|
typedef triseg_list::const_iterator const_triseg_list_iterator;
|
||||||
|
|
||||||
|
|
||||||
|
class FGTriSegments {
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
triseg_list seg_list;
|
||||||
|
|
||||||
|
// Divide segment if there are other points on it, return the
|
||||||
|
// divided list of segments
|
||||||
|
triseg_list divide_segment( const point_list& nodes,
|
||||||
|
const FGTriSeg& s );
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
// Constructor and destructor
|
||||||
|
FGTriSegments( void );
|
||||||
|
~FGTriSegments( void );
|
||||||
|
|
||||||
|
// delete all the data out of seg_list
|
||||||
|
inline void clear() { seg_list.clear(); }
|
||||||
|
|
||||||
|
// Add a segment to the segment list if it doesn't already exist.
|
||||||
|
// Returns the index (starting at zero) of the segment in the
|
||||||
|
// list.
|
||||||
|
int unique_add( const FGTriSeg& s );
|
||||||
|
|
||||||
|
// Add a segment to the segment list if it doesn't already exist.
|
||||||
|
// Returns the index (starting at zero) of the segment in the list.
|
||||||
|
void unique_divide_and_add( const point_list& node_list,
|
||||||
|
const FGTriSeg& s );
|
||||||
|
|
||||||
|
// return the master segment list
|
||||||
|
inline triseg_list get_seg_list() const { return seg_list; }
|
||||||
|
|
||||||
|
// return the ith segment
|
||||||
|
inline FGTriSeg get_seg( int i ) const { return seg_list[i]; }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // _TRISEGS_HXX
|
||||||
|
|
||||||
|
|
8
src/Lib/Makefile.am
Normal file
8
src/Lib/Makefile.am
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
SUBDIRS = \
|
||||||
|
Array \
|
||||||
|
Build \
|
||||||
|
DEM \
|
||||||
|
Polygon \
|
||||||
|
poly2tri \
|
||||||
|
shapelib \
|
||||||
|
Triangle
|
8
src/Lib/Optimize/Makefile.am
Normal file
8
src/Lib/Optimize/Makefile.am
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
noinst_LIBRARIES = libCombine.a
|
||||||
|
|
||||||
|
libCombine_a_SOURCES = genfans.cxx genfans.hxx
|
||||||
|
|
||||||
|
INCLUDES += \
|
||||||
|
-I$(top_builddir) \
|
||||||
|
-I$(top_builddir)/Lib \
|
||||||
|
-I$(top_builddir)/Construct
|
244
src/Lib/Optimize/genfans.cxx
Normal file
244
src/Lib/Optimize/genfans.cxx
Normal file
|
@ -0,0 +1,244 @@
|
||||||
|
// genfans.cxx -- Combine individual triangles into more optimal fans.
|
||||||
|
//
|
||||||
|
// Written by Curtis Olson, started March 1999.
|
||||||
|
//
|
||||||
|
// Copyright (C) 1999 Curtis L. Olson - curt@flightgear.org
|
||||||
|
//
|
||||||
|
// This program is free software; you can redistribute it and/or
|
||||||
|
// modify it under the terms of the GNU General Public License as
|
||||||
|
// published by the Free Software Foundation; either version 2 of the
|
||||||
|
// License, or (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful, but
|
||||||
|
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
// General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
//
|
||||||
|
// $Id$
|
||||||
|
|
||||||
|
|
||||||
|
#include "genfans.hxx"
|
||||||
|
|
||||||
|
|
||||||
|
// make sure the list is expanded at least to hold "n" and then push
|
||||||
|
// "i" onto the back of the "n" list.
|
||||||
|
void FGGenFans::add_and_expand( reverse_list& by_node, int n, int i ) {
|
||||||
|
int_list empty;
|
||||||
|
|
||||||
|
int size = (int)by_node.size();
|
||||||
|
if ( size > n ) {
|
||||||
|
// ok
|
||||||
|
} else {
|
||||||
|
// cout << "capacity = " << by_node.capacity() << endl;
|
||||||
|
// cout << "size = " << size << " n = " << n
|
||||||
|
// << " need to push = " << n - size + 1 << endl;
|
||||||
|
for ( int i = 0; i < n - size + 1; ++i ) {
|
||||||
|
by_node.push_back(empty);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
by_node[n].push_back(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// given an input triangle, shuffle nodes so that "center" is the
|
||||||
|
// first node, but maintain winding order.
|
||||||
|
static FGTriEle canonify( const FGTriEle& t, int center ) {
|
||||||
|
if ( t.get_n1() == center ) {
|
||||||
|
// already ok
|
||||||
|
return t;
|
||||||
|
} else if ( t.get_n2() == center ) {
|
||||||
|
return FGTriEle( t.get_n2(), t.get_n3(), t.get_n1(), 0.0 );
|
||||||
|
} else if ( t.get_n3() == center ) {
|
||||||
|
return FGTriEle( t.get_n3(), t.get_n1(), t.get_n2(), 0.0 );
|
||||||
|
} else {
|
||||||
|
cout << "ERROR, index doesn't refer to this triangle!!!" << endl;
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// returns a list of triangle indices
|
||||||
|
static int_list make_best_fan( const triele_list& master_tris,
|
||||||
|
const int center, const int_list& local_tris )
|
||||||
|
{
|
||||||
|
int_list best_result;
|
||||||
|
|
||||||
|
// try starting with each of local_tris to find the best fan
|
||||||
|
// arrangement
|
||||||
|
for ( int start = 0; start < (int)local_tris.size(); ++start ) {
|
||||||
|
// cout << "trying with first triangle = " << local_tris[start] << endl;
|
||||||
|
|
||||||
|
int_list tmp_result;
|
||||||
|
tmp_result.clear();
|
||||||
|
|
||||||
|
FGTriEle current_tri;
|
||||||
|
FGTriEle test;
|
||||||
|
current_tri = canonify( master_tris[local_tris[start]], center );
|
||||||
|
tmp_result.push_back( local_tris[start] );
|
||||||
|
|
||||||
|
// follow the ring
|
||||||
|
int next = -1;
|
||||||
|
bool matches = true;
|
||||||
|
while ( (next != start) && matches ) {
|
||||||
|
// find next triangle in ring
|
||||||
|
matches = false;
|
||||||
|
for ( int i = 0; i < (int)local_tris.size(); ++i ) {
|
||||||
|
test = canonify( master_tris[local_tris[i]], center );
|
||||||
|
if ( current_tri.get_n3() == test.get_n2() ) {
|
||||||
|
if ( i != start ) {
|
||||||
|
// cout << " next triangle = " << local_tris[i] << endl;
|
||||||
|
current_tri = test;
|
||||||
|
tmp_result.push_back( local_tris[i] );
|
||||||
|
matches = true;
|
||||||
|
next = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( tmp_result.size() == local_tris.size() ) {
|
||||||
|
// we found a complete usage, no need to go on
|
||||||
|
// cout << "we found a complete usage, no need to go on" << endl;
|
||||||
|
best_result = tmp_result;
|
||||||
|
break;
|
||||||
|
} else if ( tmp_result.size() > best_result.size() ) {
|
||||||
|
// we found a better way to fan
|
||||||
|
// cout << "we found a better fan arrangement" << endl;
|
||||||
|
best_result = tmp_result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return best_result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static bool in_fan(int index, const int_list& fan ) {
|
||||||
|
const_int_list_iterator current = fan.begin();
|
||||||
|
const_int_list_iterator last = fan.end();
|
||||||
|
|
||||||
|
for ( ; current != last; ++current ) {
|
||||||
|
if ( index == *current ) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// recursive build fans from triangle list
|
||||||
|
fan_list FGGenFans::greedy_build( triele_list tris ) {
|
||||||
|
cout << "starting greedy build of fans" << endl;
|
||||||
|
|
||||||
|
fans.clear();
|
||||||
|
|
||||||
|
while ( ! tris.empty() ) {
|
||||||
|
// cout << "building reverse_list" << endl;
|
||||||
|
reverse_list by_node;
|
||||||
|
by_node.clear();
|
||||||
|
|
||||||
|
// traverse the triangle list and for each node, build a list of
|
||||||
|
// triangles that attach to it.
|
||||||
|
|
||||||
|
for ( int i = 0; i < (int)tris.size(); ++i ) {
|
||||||
|
int n1 = tris[i].get_n1();
|
||||||
|
int n2 = tris[i].get_n2();
|
||||||
|
int n3 = tris[i].get_n3();
|
||||||
|
|
||||||
|
add_and_expand( by_node, n1, i );
|
||||||
|
add_and_expand( by_node, n2, i );
|
||||||
|
add_and_expand( by_node, n3, i );
|
||||||
|
}
|
||||||
|
|
||||||
|
// find the node in the tris list that attaches to the most
|
||||||
|
// triangles
|
||||||
|
|
||||||
|
// cout << "find most connected node" << endl;
|
||||||
|
|
||||||
|
int_list biggest_group;
|
||||||
|
reverse_list_iterator r_current = by_node.begin();
|
||||||
|
reverse_list_iterator r_last = by_node.end();
|
||||||
|
int index = 0;
|
||||||
|
int counter = 0;
|
||||||
|
for ( ; r_current != r_last; ++r_current ) {
|
||||||
|
if ( r_current->size() > biggest_group.size() ) {
|
||||||
|
biggest_group = *r_current;
|
||||||
|
index = counter;
|
||||||
|
}
|
||||||
|
++counter;
|
||||||
|
}
|
||||||
|
// cout << "triangle pool = " << tris.size() << endl;
|
||||||
|
// cout << "biggest_group = " << biggest_group.size() << endl;
|
||||||
|
// cout << "center node = " << index << endl;
|
||||||
|
|
||||||
|
// make the best fan we can out of this group
|
||||||
|
// cout << "before make_best_fan()" << endl;
|
||||||
|
int_list best_fan = make_best_fan( tris, index, biggest_group );
|
||||||
|
// cout << "after make_best_fan()" << endl;
|
||||||
|
|
||||||
|
// generate point form of best_fan
|
||||||
|
int_list node_list;
|
||||||
|
node_list.clear();
|
||||||
|
|
||||||
|
int_list_iterator i_start = best_fan.begin();
|
||||||
|
int_list_iterator i_current = i_start;
|
||||||
|
int_list_iterator i_last = best_fan.end();
|
||||||
|
for ( ; i_current != i_last; ++i_current ) {
|
||||||
|
FGTriEle t = canonify( tris[*i_current], index );
|
||||||
|
if ( i_start == i_current ) {
|
||||||
|
node_list.push_back( t.get_n1() );
|
||||||
|
node_list.push_back( t.get_n2() );
|
||||||
|
}
|
||||||
|
node_list.push_back( t.get_n3() );
|
||||||
|
}
|
||||||
|
// cout << "best list size = " << node_list.size() << endl;
|
||||||
|
|
||||||
|
// add this fan to the fan list
|
||||||
|
fans.push_back( node_list );
|
||||||
|
|
||||||
|
// delete the triangles in best_fan out of tris and repeat
|
||||||
|
triele_list_iterator t_current = tris.begin();
|
||||||
|
triele_list_iterator t_last = tris.end();
|
||||||
|
counter = 0;
|
||||||
|
while ( t_current != t_last ) {
|
||||||
|
if ( in_fan(counter, best_fan) ) {
|
||||||
|
// cout << "erasing "
|
||||||
|
// << t_current->get_n1() << ","
|
||||||
|
// << t_current->get_n2() << ","
|
||||||
|
// << t_current->get_n3()
|
||||||
|
// << " from master tri pool"
|
||||||
|
// << endl;
|
||||||
|
tris.erase( t_current );
|
||||||
|
} else {
|
||||||
|
++t_current;
|
||||||
|
}
|
||||||
|
++counter;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cout << "end of greedy build of fans" << endl;
|
||||||
|
cout << "average fan size = " << ave_size() << endl;
|
||||||
|
|
||||||
|
return fans;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// report average fan size
|
||||||
|
double FGGenFans::ave_size() {
|
||||||
|
double sum = 0.0;
|
||||||
|
|
||||||
|
fan_list_iterator current = fans.begin();
|
||||||
|
fan_list_iterator last = fans.end();
|
||||||
|
for ( ; current != last; ++current ) {
|
||||||
|
sum += current->size();
|
||||||
|
}
|
||||||
|
|
||||||
|
return sum / (double)fans.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
81
src/Lib/Optimize/genfans.hxx
Normal file
81
src/Lib/Optimize/genfans.hxx
Normal file
|
@ -0,0 +1,81 @@
|
||||||
|
// genfans.hxx -- Combine individual triangles into more optimal fans.
|
||||||
|
//
|
||||||
|
// Written by Curtis Olson, started March 1999.
|
||||||
|
//
|
||||||
|
// Copyright (C) 1999 Curtis L. Olson - curt@flightgear.org
|
||||||
|
//
|
||||||
|
// This program is free software; you can redistribute it and/or
|
||||||
|
// modify it under the terms of the GNU General Public License as
|
||||||
|
// published by the Free Software Foundation; either version 2 of the
|
||||||
|
// License, or (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful, but
|
||||||
|
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
// General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
//
|
||||||
|
// $Id$
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef _GENFANS_HXX
|
||||||
|
#define _GENFANS_HXX
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef __cplusplus
|
||||||
|
# error This library requires C++
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#include <simgear/compiler.h>
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include <simgear/fg_types.hxx>
|
||||||
|
|
||||||
|
#include <Triangulate/trieles.hxx>
|
||||||
|
|
||||||
|
FG_USING_STD(vector);
|
||||||
|
|
||||||
|
|
||||||
|
typedef vector < int_list > fan_list;
|
||||||
|
typedef fan_list::iterator fan_list_iterator;
|
||||||
|
typedef fan_list::const_iterator const_fan_list_iterator;
|
||||||
|
|
||||||
|
typedef vector < int_list > reverse_list;
|
||||||
|
typedef reverse_list::iterator reverse_list_iterator;
|
||||||
|
typedef reverse_list::const_iterator const_reverse_list_iterator;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class FGGenFans {
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
fan_list fans;
|
||||||
|
|
||||||
|
// make sure the list is expanded at least to hold "n" and then
|
||||||
|
// push "i" onto the back of the "n" list.
|
||||||
|
void add_and_expand( reverse_list& by_node, int n, int i );
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
// Constructor && Destructor
|
||||||
|
inline FGGenFans() { }
|
||||||
|
inline ~FGGenFans() { }
|
||||||
|
|
||||||
|
// recursive build fans from triangle list
|
||||||
|
// fan_list greedy_build( triele_list tris );
|
||||||
|
fan_list greedy_build( triele_list tris );
|
||||||
|
|
||||||
|
// report average fan size
|
||||||
|
double ave_size();
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // _GENFANS_HXX
|
||||||
|
|
||||||
|
|
9
src/Lib/Polygon/Makefile.am
Normal file
9
src/Lib/Polygon/Makefile.am
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
noinst_LIBRARIES = libPolygon.a
|
||||||
|
|
||||||
|
libPolygon_a_SOURCES = \
|
||||||
|
index.cxx index.hxx \
|
||||||
|
names.cxx names.hxx \
|
||||||
|
polygon.cxx polygon.hxx \
|
||||||
|
split.cxx split.hxx
|
||||||
|
|
||||||
|
INCLUDES += -I$(top_builddir) -I$(top_builddir)/Lib -I$(top_builddir)/Tools/Lib
|
71
src/Lib/Polygon/index.cxx
Normal file
71
src/Lib/Polygon/index.cxx
Normal file
|
@ -0,0 +1,71 @@
|
||||||
|
// index.cxx -- routines to handle a unique/persistant integer polygon index
|
||||||
|
//
|
||||||
|
// Written by Curtis Olson, started February 1999.
|
||||||
|
//
|
||||||
|
// Copyright (C) 1999 Curtis L. Olson - curt@flightgear.org
|
||||||
|
//
|
||||||
|
// This program is free software; you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation; either version 2 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
//
|
||||||
|
// $Id$
|
||||||
|
|
||||||
|
#include <simgear/compiler.h>
|
||||||
|
|
||||||
|
#include STL_STRING
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include "index.hxx"
|
||||||
|
|
||||||
|
|
||||||
|
static long int poly_index;
|
||||||
|
static string poly_path;
|
||||||
|
|
||||||
|
|
||||||
|
// initialize the unique polygon index counter stored in path
|
||||||
|
bool poly_index_init( string path ) {
|
||||||
|
poly_path = path;
|
||||||
|
|
||||||
|
FILE *fp = fopen( poly_path.c_str(), "r" );
|
||||||
|
|
||||||
|
if ( fp == NULL ) {
|
||||||
|
cout << "Error cannot open " << poly_path << endl;
|
||||||
|
poly_index = 0;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
fscanf( fp, "%ld", &poly_index );
|
||||||
|
|
||||||
|
fclose( fp );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// increment the persistant counter and return the next poly_index
|
||||||
|
long int poly_index_next() {
|
||||||
|
++poly_index;
|
||||||
|
|
||||||
|
FILE *fp = fopen( poly_path.c_str(), "w" );
|
||||||
|
|
||||||
|
if ( fp == NULL ) {
|
||||||
|
cout << "Error cannot open " << poly_path << " for writing" << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf( fp, "%ld\n", poly_index );
|
||||||
|
|
||||||
|
fclose( fp );
|
||||||
|
|
||||||
|
return poly_index;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
43
src/Lib/Polygon/index.hxx
Normal file
43
src/Lib/Polygon/index.hxx
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
// index.cxx -- routines to handle a unique/persistant integer polygon index
|
||||||
|
//
|
||||||
|
// Written by Curtis Olson, started February 1999.
|
||||||
|
//
|
||||||
|
// Copyright (C) 1999 Curtis L. Olson - curt@flightgear.org
|
||||||
|
//
|
||||||
|
// This program is free software; you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation; either version 2 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
//
|
||||||
|
// $Id$
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef _INDEX_HXX
|
||||||
|
#define _INDEX_HXX
|
||||||
|
|
||||||
|
|
||||||
|
#include <simgear/compiler.h>
|
||||||
|
|
||||||
|
#include STL_STRING
|
||||||
|
|
||||||
|
|
||||||
|
// initialize the unique polygon index counter stored in path
|
||||||
|
bool poly_index_init( string path );
|
||||||
|
|
||||||
|
// increment the persistant counter and return the next poly_index
|
||||||
|
long int poly_index_next();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#endif // _INDEX_HXX
|
||||||
|
|
||||||
|
|
118
src/Lib/Polygon/names.cxx
Normal file
118
src/Lib/Polygon/names.cxx
Normal file
|
@ -0,0 +1,118 @@
|
||||||
|
// names.cxx -- process shapefiles names
|
||||||
|
//
|
||||||
|
// Written by Curtis Olson, started February 1999.
|
||||||
|
//
|
||||||
|
// Copyright (C) 1999 Curtis L. Olson - curt@flightgear.org
|
||||||
|
//
|
||||||
|
// This program is free software; you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation; either version 2 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
//
|
||||||
|
// $Id$
|
||||||
|
|
||||||
|
#include <simgear/compiler.h>
|
||||||
|
|
||||||
|
#include STL_STRING
|
||||||
|
|
||||||
|
#include "names.hxx"
|
||||||
|
|
||||||
|
|
||||||
|
// return area type from text name
|
||||||
|
AreaType get_area_type( string area ) {
|
||||||
|
if ( area == "SomeSort" ) {
|
||||||
|
return SomeSortOfArea;
|
||||||
|
} else if ( area == "Hole" ) {
|
||||||
|
return HoleArea;
|
||||||
|
} else if ( (area == "Swamp or Marsh")
|
||||||
|
|| (area == "Marsh") ) {
|
||||||
|
return MarshArea;
|
||||||
|
} else if ( area == "Lake" ) {
|
||||||
|
return LakeArea;
|
||||||
|
} else if ( (area == "Lake Dry")
|
||||||
|
|| (area == "DryLake") ) {
|
||||||
|
return DryLakeArea;
|
||||||
|
} else if ( (area == "Lake Intermittent")
|
||||||
|
|| (area == "IntermittentLake") ) {
|
||||||
|
return IntLakeArea;
|
||||||
|
} else if ( area == "Reservoir" ) {
|
||||||
|
return ReservoirArea;
|
||||||
|
} else if ( (area == "Reservoir Intermittent")
|
||||||
|
|| (area == "IntermittentReservoir") ) {
|
||||||
|
return IntReservoirArea;
|
||||||
|
} else if ( area == "Stream" ) {
|
||||||
|
return StreamArea;
|
||||||
|
} else if ( area == "Canal" ) {
|
||||||
|
return CanalArea;
|
||||||
|
} else if ( area == "Glacier" ) {
|
||||||
|
return GlacierArea;
|
||||||
|
} else if ( area == "Urban" ) {
|
||||||
|
return UrbanArea;
|
||||||
|
} else if ( area == "Default" ) {
|
||||||
|
return DefaultArea;
|
||||||
|
} else if ( (area == "Bay Estuary or Ocean")
|
||||||
|
|| (area == "Ocean") ) {
|
||||||
|
return OceanArea;
|
||||||
|
} else if ( area == "Void Area" ) {
|
||||||
|
return VoidArea;
|
||||||
|
} else if ( area == "Null" ) {
|
||||||
|
return NullArea;
|
||||||
|
} else {
|
||||||
|
cout << "unknown area = '" << area << "'" << endl;
|
||||||
|
// cout << "area = " << area << endl;
|
||||||
|
// for ( int i = 0; i < area.length(); i++ ) {
|
||||||
|
// cout << i << ") " << (int)area[i] << endl;
|
||||||
|
// }
|
||||||
|
return UnknownArea;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// return text from of area name
|
||||||
|
string get_area_name( AreaType area ) {
|
||||||
|
if ( area == DefaultArea ) {
|
||||||
|
return "Default";
|
||||||
|
} else if ( area == HoleArea ) {
|
||||||
|
return "Hole";
|
||||||
|
} else if ( area == MarshArea ) {
|
||||||
|
return "Marsh";
|
||||||
|
} else if ( area == LakeArea ) {
|
||||||
|
return "Lake";
|
||||||
|
} else if ( area == DryLakeArea ) {
|
||||||
|
return "DryLake";
|
||||||
|
} else if ( area == IntLakeArea ) {
|
||||||
|
return "IntermittentLake";
|
||||||
|
} else if ( area == ReservoirArea ) {
|
||||||
|
return "Reservoir";
|
||||||
|
} else if ( area == IntReservoirArea ) {
|
||||||
|
return "IntermittentReservoir";
|
||||||
|
} else if ( area == StreamArea ) {
|
||||||
|
return "Stream";
|
||||||
|
} else if ( area == CanalArea ) {
|
||||||
|
return "Canal";
|
||||||
|
} else if ( area == GlacierArea ) {
|
||||||
|
return "Glacier";
|
||||||
|
} else if ( area == UrbanArea ) {
|
||||||
|
return "Urban";
|
||||||
|
} else if ( area == OceanArea ) {
|
||||||
|
return "Ocean";
|
||||||
|
} else if ( area == VoidArea ) {
|
||||||
|
return "VoidArea";
|
||||||
|
} else if ( area == NullArea ) {
|
||||||
|
return "Null";
|
||||||
|
} else {
|
||||||
|
cout << "unknown area code = " << (int)area << endl;
|
||||||
|
return "Unknown";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
68
src/Lib/Polygon/names.hxx
Normal file
68
src/Lib/Polygon/names.hxx
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
// names.hxx -- process shapefiles names
|
||||||
|
//
|
||||||
|
// Written by Curtis Olson, started February 1999.
|
||||||
|
//
|
||||||
|
// Copyright (C) 1999 Curtis L. Olson - curt@flightgear.org
|
||||||
|
//
|
||||||
|
// This program is free software; you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation; either version 2 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
//
|
||||||
|
// $Id$
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef _NAMES_HXX
|
||||||
|
#define _NAMES_HXX
|
||||||
|
|
||||||
|
|
||||||
|
#include <simgear/compiler.h>
|
||||||
|
|
||||||
|
#include STL_STRING
|
||||||
|
|
||||||
|
FG_USING_STD(string);
|
||||||
|
|
||||||
|
|
||||||
|
// Posible shape file types. Note the order of these is important and
|
||||||
|
// defines the priority of these shapes if they should intersect. The
|
||||||
|
// smaller the number, the higher the priority.
|
||||||
|
enum AreaType {
|
||||||
|
SomeSortOfArea = 0,
|
||||||
|
HoleArea = 1,
|
||||||
|
LakeArea = 2,
|
||||||
|
DryLakeArea = 3,
|
||||||
|
IntLakeArea = 4,
|
||||||
|
ReservoirArea = 5,
|
||||||
|
IntReservoirArea = 6,
|
||||||
|
StreamArea = 7,
|
||||||
|
CanalArea = 8,
|
||||||
|
GlacierArea = 9,
|
||||||
|
OceanArea = 10,
|
||||||
|
UrbanArea = 11,
|
||||||
|
MarshArea = 12,
|
||||||
|
DefaultArea = 13,
|
||||||
|
VoidArea = 9997,
|
||||||
|
NullArea = 9998,
|
||||||
|
UnknownArea = 9999
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// return area type from text name
|
||||||
|
AreaType get_area_type( string area );
|
||||||
|
|
||||||
|
// return text form of area name
|
||||||
|
string get_area_name( AreaType area );
|
||||||
|
|
||||||
|
|
||||||
|
#endif // _NAMES_HXX
|
||||||
|
|
||||||
|
|
493
src/Lib/Polygon/polygon.cxx
Normal file
493
src/Lib/Polygon/polygon.cxx
Normal file
|
@ -0,0 +1,493 @@
|
||||||
|
// polygon.cxx -- polygon (with holes) management class
|
||||||
|
//
|
||||||
|
// Written by Curtis Olson, started March 1999.
|
||||||
|
//
|
||||||
|
// Copyright (C) 1999 Curtis L. Olson - curt@flightgear.org
|
||||||
|
//
|
||||||
|
// This program is free software; you can redistribute it and/or
|
||||||
|
// modify it under the terms of the GNU General Public License as
|
||||||
|
// published by the Free Software Foundation; either version 2 of the
|
||||||
|
// License, or (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful, but
|
||||||
|
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
// General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
//
|
||||||
|
// $Id$
|
||||||
|
|
||||||
|
|
||||||
|
// include Generic Polygon Clipping Library
|
||||||
|
//
|
||||||
|
// http://www.cs.man.ac.uk/aig/staff/alan/software/
|
||||||
|
//
|
||||||
|
extern "C" {
|
||||||
|
#include <gpc.h>
|
||||||
|
}
|
||||||
|
|
||||||
|
#include <simgear/constants.h>
|
||||||
|
#include <simgear/point3d.hxx>
|
||||||
|
|
||||||
|
#include <poly2tri/interface.h>
|
||||||
|
|
||||||
|
#include "polygon.hxx"
|
||||||
|
|
||||||
|
|
||||||
|
// Constructor
|
||||||
|
FGPolygon::FGPolygon( void ) {
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Destructor
|
||||||
|
FGPolygon::~FGPolygon( void ) {
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Calculate theta of angle (a, b, c)
|
||||||
|
static double calc_angle(point2d a, point2d b, point2d c) {
|
||||||
|
point2d u, v;
|
||||||
|
double udist, vdist, uv_dot, tmp;
|
||||||
|
|
||||||
|
// u . v = ||u|| * ||v|| * cos(theta)
|
||||||
|
|
||||||
|
u.x = b.x - a.x;
|
||||||
|
u.y = b.y - a.y;
|
||||||
|
udist = sqrt( u.x * u.x + u.y * u.y );
|
||||||
|
// printf("udist = %.6f\n", udist);
|
||||||
|
|
||||||
|
v.x = b.x - c.x;
|
||||||
|
v.y = b.y - c.y;
|
||||||
|
vdist = sqrt( v.x * v.x + v.y * v.y );
|
||||||
|
// printf("vdist = %.6f\n", vdist);
|
||||||
|
|
||||||
|
uv_dot = u.x * v.x + u.y * v.y;
|
||||||
|
// printf("uv_dot = %.6f\n", uv_dot);
|
||||||
|
|
||||||
|
tmp = uv_dot / (udist * vdist);
|
||||||
|
// printf("tmp = %.6f\n", tmp);
|
||||||
|
|
||||||
|
return acos(tmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// return the perimeter of a contour (assumes simple polygons,
|
||||||
|
// i.e. non-self intersecting.)
|
||||||
|
//
|
||||||
|
// negative areas indicate counter clockwise winding
|
||||||
|
// postitive areas indicate clockwise winding.
|
||||||
|
|
||||||
|
double FGPolygon::area_contour( const int contour ) const {
|
||||||
|
// area = 1/2 * sum[i = 0 to k-1][x(i)*y(i+1) - x(i+1)*y(i)]
|
||||||
|
// where k is defined as 0
|
||||||
|
|
||||||
|
point_list c = poly[contour];
|
||||||
|
int size = c.size();
|
||||||
|
double sum = 0.0;
|
||||||
|
|
||||||
|
for ( int i = 0; i < size; ++i ) {
|
||||||
|
sum += c[(i+1)%size].x() * c[i].y() - c[i].x() * c[(i+1)%size].y();
|
||||||
|
}
|
||||||
|
|
||||||
|
// area can be negative or positive depending on the polygon
|
||||||
|
// winding order
|
||||||
|
return fabs(sum / 2.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// return the smallest interior angle of the polygon
|
||||||
|
double FGPolygon::minangle_contour( const int contour ) {
|
||||||
|
point_list c = poly[contour];
|
||||||
|
int size = c.size();
|
||||||
|
int p1_index, p2_index, p3_index;
|
||||||
|
point2d p1, p2, p3;
|
||||||
|
double angle;
|
||||||
|
double min_angle = 2.0 * FG_PI;
|
||||||
|
|
||||||
|
for ( int i = 0; i < size; ++i ) {
|
||||||
|
p1_index = i - 1;
|
||||||
|
if ( p1_index < 0 ) {
|
||||||
|
p1_index += size;
|
||||||
|
}
|
||||||
|
|
||||||
|
p2_index = i;
|
||||||
|
|
||||||
|
p3_index = i + 1;
|
||||||
|
if ( p3_index >= size ) {
|
||||||
|
p3_index -= size;
|
||||||
|
}
|
||||||
|
|
||||||
|
p1.x = c[p1_index].x();
|
||||||
|
p1.y = c[p1_index].y();
|
||||||
|
|
||||||
|
p2.x = c[p2_index].x();
|
||||||
|
p2.y = c[p2_index].y();
|
||||||
|
|
||||||
|
p3.x = c[p3_index].x();
|
||||||
|
p3.y = c[p3_index].y();
|
||||||
|
|
||||||
|
angle = calc_angle( p1, p2, p3 );
|
||||||
|
|
||||||
|
if ( angle < min_angle ) {
|
||||||
|
min_angle = angle;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return min_angle;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// shift every point in the polygon by lon, lat
|
||||||
|
void FGPolygon::shift( double lon, double lat ) {
|
||||||
|
for ( int i = 0; i < (int)poly.size(); ++i ) {
|
||||||
|
for ( int j = 0; j < (int)poly[i].size(); ++j ) {
|
||||||
|
poly[i][j].setx( poly[i][j].x() + lon );
|
||||||
|
poly[i][j].sety( poly[i][j].y() + lat );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// output
|
||||||
|
void FGPolygon::write( const string& file ) {
|
||||||
|
FILE *fp = fopen( file.c_str(), "w" );
|
||||||
|
|
||||||
|
for ( int i = 0; i < (int)poly.size(); ++i ) {
|
||||||
|
for ( int j = 0; j < (int)poly[i].size(); ++j ) {
|
||||||
|
fprintf(fp, "%.6f %.6f\n", poly[i][j].x(), poly[i][j].y());
|
||||||
|
}
|
||||||
|
fprintf(fp, "%.6f %.6f\n", poly[i][0].x(), poly[i][0].y());
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(fp);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// wrapper functions for gpc polygon clip routines
|
||||||
|
//
|
||||||
|
|
||||||
|
// Make a gpc_poly from an FGPolygon
|
||||||
|
void make_gpc_poly( const FGPolygon& in, gpc_polygon *out ) {
|
||||||
|
gpc_vertex_list v_list;
|
||||||
|
v_list.num_vertices = 0;
|
||||||
|
v_list.vertex = new gpc_vertex[FG_MAX_VERTICES];
|
||||||
|
|
||||||
|
// cout << "making a gpc_poly" << endl;
|
||||||
|
// cout << " input contours = " << in.contours() << endl;
|
||||||
|
|
||||||
|
Point3D p;
|
||||||
|
// build the gpc_polygon structures
|
||||||
|
for ( int i = 0; i < in.contours(); ++i ) {
|
||||||
|
// cout << " contour " << i << " = " << in.contour_size( i ) << endl;
|
||||||
|
if ( in.contour_size( i ) > FG_MAX_VERTICES ) {
|
||||||
|
cout << "Polygon too large, need to increase FG_MAX_VERTICES to at "
|
||||||
|
<< "least " << in.contour_size( i ) << endl;
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
for ( int j = 0; j < in.contour_size( i ); ++j ) {
|
||||||
|
p = in.get_pt( i, j );
|
||||||
|
v_list.vertex[j].x = p.x();
|
||||||
|
v_list.vertex[j].y = p.y();
|
||||||
|
}
|
||||||
|
v_list.num_vertices = in.contour_size( i );
|
||||||
|
gpc_add_contour( out, &v_list, in.get_hole_flag( i ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
// free alocated memory
|
||||||
|
delete v_list.vertex;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Set operation type
|
||||||
|
typedef enum {
|
||||||
|
POLY_DIFF, // Difference
|
||||||
|
POLY_INT, // Intersection
|
||||||
|
POLY_XOR, // Exclusive or
|
||||||
|
POLY_UNION // Union
|
||||||
|
} clip_op;
|
||||||
|
|
||||||
|
|
||||||
|
// Generic clipping routine
|
||||||
|
FGPolygon polygon_clip( clip_op poly_op, const FGPolygon& subject,
|
||||||
|
const FGPolygon& clip )
|
||||||
|
{
|
||||||
|
FGPolygon result;
|
||||||
|
|
||||||
|
gpc_polygon *gpc_subject = new gpc_polygon;
|
||||||
|
gpc_subject->num_contours = 0;
|
||||||
|
gpc_subject->contour = NULL;
|
||||||
|
gpc_subject->hole = NULL;
|
||||||
|
make_gpc_poly( subject, gpc_subject );
|
||||||
|
|
||||||
|
gpc_polygon *gpc_clip = new gpc_polygon;
|
||||||
|
gpc_clip->num_contours = 0;
|
||||||
|
gpc_clip->contour = NULL;
|
||||||
|
gpc_clip->hole = NULL;
|
||||||
|
make_gpc_poly( clip, gpc_clip );
|
||||||
|
|
||||||
|
gpc_polygon *gpc_result = new gpc_polygon;
|
||||||
|
gpc_result->num_contours = 0;
|
||||||
|
gpc_result->contour = NULL;
|
||||||
|
gpc_result->hole = NULL;
|
||||||
|
|
||||||
|
gpc_op op;
|
||||||
|
if ( poly_op == POLY_DIFF ) {
|
||||||
|
op = GPC_DIFF;
|
||||||
|
} else if ( poly_op == POLY_INT ) {
|
||||||
|
op = GPC_INT;
|
||||||
|
} else if ( poly_op == POLY_XOR ) {
|
||||||
|
op = GPC_XOR;
|
||||||
|
} else if ( poly_op == POLY_UNION ) {
|
||||||
|
op = GPC_UNION;
|
||||||
|
} else {
|
||||||
|
cout << "Unknown polygon op, exiting." << endl;
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
gpc_polygon_clip( op, gpc_subject, gpc_clip, gpc_result );
|
||||||
|
|
||||||
|
for ( int i = 0; i < gpc_result->num_contours; ++i ) {
|
||||||
|
// cout << " processing contour = " << i << ", nodes = "
|
||||||
|
// << gpc_result->contour[i].num_vertices << ", hole = "
|
||||||
|
// << gpc_result->hole[i] << endl;
|
||||||
|
|
||||||
|
// sprintf(junkn, "g.%d", junkc++);
|
||||||
|
// junkfp = fopen(junkn, "w");
|
||||||
|
|
||||||
|
for ( int j = 0; j < gpc_result->contour[i].num_vertices; j++ ) {
|
||||||
|
Point3D p( gpc_result->contour[i].vertex[j].x,
|
||||||
|
gpc_result->contour[i].vertex[j].y,
|
||||||
|
0 );
|
||||||
|
// junkp = in_nodes.get_node( index );
|
||||||
|
// fprintf(junkfp, "%.4f %.4f\n", junkp.x(), junkp.y());
|
||||||
|
result.add_node(i, p);
|
||||||
|
// cout << " - " << index << endl;
|
||||||
|
}
|
||||||
|
// fprintf(junkfp, "%.4f %.4f\n",
|
||||||
|
// gpc_result->contour[i].vertex[0].x,
|
||||||
|
// gpc_result->contour[i].vertex[0].y);
|
||||||
|
// fclose(junkfp);
|
||||||
|
|
||||||
|
result.set_hole_flag( i, gpc_result->hole[i] );
|
||||||
|
}
|
||||||
|
|
||||||
|
// free allocated memory
|
||||||
|
gpc_free_polygon( gpc_subject );
|
||||||
|
gpc_free_polygon( gpc_clip );
|
||||||
|
gpc_free_polygon( gpc_result );
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Difference
|
||||||
|
FGPolygon polygon_diff( const FGPolygon& subject, const FGPolygon& clip ) {
|
||||||
|
return polygon_clip( POLY_DIFF, subject, clip );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Intersection
|
||||||
|
FGPolygon polygon_int( const FGPolygon& subject, const FGPolygon& clip ) {
|
||||||
|
return polygon_clip( POLY_INT, subject, clip );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Exclusive or
|
||||||
|
FGPolygon polygon_xor( const FGPolygon& subject, const FGPolygon& clip ) {
|
||||||
|
return polygon_clip( POLY_XOR, subject, clip );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Union
|
||||||
|
FGPolygon polygon_union( const FGPolygon& subject, const FGPolygon& clip ) {
|
||||||
|
return polygon_clip( POLY_UNION, subject, clip );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// canonify the polygon winding, outer contour must be anti-clockwise,
|
||||||
|
// all inner contours must be clockwise.
|
||||||
|
FGPolygon polygon_canonify( const FGPolygon& in_poly ) {
|
||||||
|
FGPolygon result;
|
||||||
|
result.erase();
|
||||||
|
|
||||||
|
// Negative areas indicate counter clockwise winding. Postitive
|
||||||
|
// areas indicate clockwise winding.
|
||||||
|
|
||||||
|
int non_hole_count = 0;
|
||||||
|
|
||||||
|
for ( int i = 0; i < in_poly.contours(); ++i ) {
|
||||||
|
point_list contour = in_poly.get_contour( i );
|
||||||
|
int hole_flag = in_poly.get_hole_flag( i );
|
||||||
|
if ( !hole_flag ) {
|
||||||
|
non_hole_count++;
|
||||||
|
if ( non_hole_count > 1 ) {
|
||||||
|
cout << "ERROR: polygon with more than one enclosing" << endl;
|
||||||
|
cout << " contour. I bet you don't handle that!" << endl;
|
||||||
|
cout << " dying!!!" << endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
double area = in_poly.area_contour( i );
|
||||||
|
if ( hole_flag && (area < 0) ) {
|
||||||
|
// reverse contour
|
||||||
|
point_list rcontour;
|
||||||
|
rcontour.clear();
|
||||||
|
for ( int j = (int)contour.size() - 1; j >= 0; --j ) {
|
||||||
|
rcontour.push_back( contour[j] );
|
||||||
|
}
|
||||||
|
result.add_contour( rcontour, hole_flag );
|
||||||
|
} else if ( !hole_flag && (area > 0) ) {
|
||||||
|
// reverse contour
|
||||||
|
point_list rcontour;
|
||||||
|
rcontour.clear();
|
||||||
|
for ( int j = (int)contour.size() - 1; j >= 0; --j ) {
|
||||||
|
rcontour.push_back( contour[j] );
|
||||||
|
}
|
||||||
|
result.add_contour( rcontour, hole_flag );
|
||||||
|
} else {
|
||||||
|
result.add_contour( contour, hole_flag );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Wrapper for the fast Polygon Triangulation based on Seidel's
|
||||||
|
// Algorithm by Atul Narkhede and Dinesh Manocha
|
||||||
|
// http://www.cs.unc.edu/~dm/CODE/GEM/chapter.html
|
||||||
|
|
||||||
|
// I make this oversize because given an n sided concave polygon with
|
||||||
|
// m, n, o, ... sided holes, I have no idea how many triangles would
|
||||||
|
// result and I don't have time right now to see if an upper bound can
|
||||||
|
// be determined easily.
|
||||||
|
#define FG_MAX_TRIANGLES 100000
|
||||||
|
|
||||||
|
FGPolygon polygon_to_tristrip( const FGPolygon& in_poly ) {
|
||||||
|
|
||||||
|
// canonify the polygon winding, outer contour must be
|
||||||
|
// anti-clockwise, all inner contours must be clockwise.
|
||||||
|
FGPolygon canon_poly = polygon_canonify( in_poly );
|
||||||
|
|
||||||
|
// create and fill in the required structures
|
||||||
|
int ncontours = canon_poly.contours();
|
||||||
|
int cntr[ncontours];
|
||||||
|
int vsize = 1;
|
||||||
|
for ( int i = 0; i < canon_poly.contours(); ++i ) {
|
||||||
|
cntr[i] = canon_poly.contour_size( i );
|
||||||
|
vsize += cntr[i];
|
||||||
|
}
|
||||||
|
double vertices[vsize][2];
|
||||||
|
int counter = 1;
|
||||||
|
Point3D p;
|
||||||
|
for ( int i = 0; i < canon_poly.contours(); ++i ) {
|
||||||
|
for ( int j = 0; j < canon_poly.contour_size( i ); ++j ) {
|
||||||
|
p = canon_poly.get_pt( i, j );
|
||||||
|
vertices[counter][0] = p.x();
|
||||||
|
vertices[counter][1] = p.y();
|
||||||
|
counter++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
int triangles[FG_MAX_TRIANGLES][3];
|
||||||
|
|
||||||
|
// do the triangulation
|
||||||
|
int ntriangles = triangulate_polygon(ncontours, cntr, vertices, triangles);
|
||||||
|
|
||||||
|
/*
|
||||||
|
gpc_polygon *tmp_poly = new gpc_polygon;
|
||||||
|
tmp_poly->num_contours = 0;
|
||||||
|
tmp_poly->contour = NULL;
|
||||||
|
tmp_poly->hole = NULL;
|
||||||
|
make_gpc_poly( in_poly, tmp_poly );
|
||||||
|
|
||||||
|
gpc_tristrip *tmp_tristrip = new gpc_tristrip;
|
||||||
|
tmp_tristrip->num_strips = 0;
|
||||||
|
tmp_tristrip->strip = NULL;
|
||||||
|
|
||||||
|
gpc_polygon_to_tristrip( tmp_poly, tmp_tristrip );
|
||||||
|
|
||||||
|
FGPolygon result;
|
||||||
|
|
||||||
|
for ( int i = 0; i < tmp_tristrip->num_strips; ++i ) {
|
||||||
|
cout << " processing strip = " << i << ", nodes = "
|
||||||
|
<< tmp_tristrip->strip[i].num_vertices << endl;
|
||||||
|
|
||||||
|
// sprintf(junkn, "g.%d", junkc++);
|
||||||
|
// junkfp = fopen(junkn, "w");
|
||||||
|
|
||||||
|
for ( int j = 0; j < tmp_tristrip->strip[i].num_vertices; j++ ) {
|
||||||
|
Point3D p( tmp_tristrip->strip[i].vertex[j].x,
|
||||||
|
tmp_tristrip->strip[i].vertex[j].y,
|
||||||
|
0 );
|
||||||
|
// junkp = in_nodes.get_node( index );
|
||||||
|
// fprintf(junkfp, "%.4f %.4f\n", junkp.x(), junkp.y());
|
||||||
|
result.add_node(i, p);
|
||||||
|
// cout << " - " << index << endl;
|
||||||
|
}
|
||||||
|
// fprintf(junkfp, "%.4f %.4f\n",
|
||||||
|
// gpc_result->contour[i].vertex[0].x,
|
||||||
|
// gpc_result->contour[i].vertex[0].y);
|
||||||
|
// fclose(junkfp);
|
||||||
|
}
|
||||||
|
|
||||||
|
// free allocated memory
|
||||||
|
gpc_free_polygon( tmp_poly );
|
||||||
|
gpc_free_tristrip( tmp_tristrip );
|
||||||
|
*/
|
||||||
|
|
||||||
|
// return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
//
|
||||||
|
// wrapper functions for gpc polygon to tristrip routine
|
||||||
|
//
|
||||||
|
|
||||||
|
FGPolygon polygon_to_tristrip_old( const FGPolygon& in_poly ) {
|
||||||
|
gpc_polygon *tmp_poly = new gpc_polygon;
|
||||||
|
tmp_poly->num_contours = 0;
|
||||||
|
tmp_poly->contour = NULL;
|
||||||
|
tmp_poly->hole = NULL;
|
||||||
|
make_gpc_poly( in_poly, tmp_poly );
|
||||||
|
|
||||||
|
gpc_tristrip *tmp_tristrip = new gpc_tristrip;
|
||||||
|
tmp_tristrip->num_strips = 0;
|
||||||
|
tmp_tristrip->strip = NULL;
|
||||||
|
|
||||||
|
gpc_polygon_to_tristrip( tmp_poly, tmp_tristrip );
|
||||||
|
|
||||||
|
FGPolygon result;
|
||||||
|
|
||||||
|
for ( int i = 0; i < tmp_tristrip->num_strips; ++i ) {
|
||||||
|
cout << " processing strip = " << i << ", nodes = "
|
||||||
|
<< tmp_tristrip->strip[i].num_vertices << endl;
|
||||||
|
|
||||||
|
// sprintf(junkn, "g.%d", junkc++);
|
||||||
|
// junkfp = fopen(junkn, "w");
|
||||||
|
|
||||||
|
for ( int j = 0; j < tmp_tristrip->strip[i].num_vertices; j++ ) {
|
||||||
|
Point3D p( tmp_tristrip->strip[i].vertex[j].x,
|
||||||
|
tmp_tristrip->strip[i].vertex[j].y,
|
||||||
|
0 );
|
||||||
|
// junkp = in_nodes.get_node( index );
|
||||||
|
// fprintf(junkfp, "%.4f %.4f\n", junkp.x(), junkp.y());
|
||||||
|
result.add_node(i, p);
|
||||||
|
// cout << " - " << index << endl;
|
||||||
|
}
|
||||||
|
// fprintf(junkfp, "%.4f %.4f\n",
|
||||||
|
// gpc_result->contour[i].vertex[0].x,
|
||||||
|
// gpc_result->contour[i].vertex[0].y);
|
||||||
|
// fclose(junkfp);
|
||||||
|
}
|
||||||
|
|
||||||
|
// free allocated memory
|
||||||
|
gpc_free_polygon( tmp_poly );
|
||||||
|
gpc_free_tristrip( tmp_tristrip );
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
#endif
|
189
src/Lib/Polygon/polygon.hxx
Normal file
189
src/Lib/Polygon/polygon.hxx
Normal file
|
@ -0,0 +1,189 @@
|
||||||
|
// polygon.hxx -- polygon (with holes) management class
|
||||||
|
//
|
||||||
|
// Written by Curtis Olson, started March 1999.
|
||||||
|
//
|
||||||
|
// Copyright (C) 1999 Curtis L. Olson - curt@flightgear.org
|
||||||
|
//
|
||||||
|
// This program is free software; you can redistribute it and/or
|
||||||
|
// modify it under the terms of the GNU General Public License as
|
||||||
|
// published by the Free Software Foundation; either version 2 of the
|
||||||
|
// License, or (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful, but
|
||||||
|
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
// General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
//
|
||||||
|
// $Id$
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef _POLYGON_HXX
|
||||||
|
#define _POLYGON_HXX
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef __cplusplus
|
||||||
|
# error This library requires C++
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#include <simgear/compiler.h>
|
||||||
|
#include <simgear/fg_types.hxx>
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
FG_USING_STD(string);
|
||||||
|
FG_USING_STD(vector);
|
||||||
|
|
||||||
|
|
||||||
|
#define FG_MAX_VERTICES 1500000
|
||||||
|
|
||||||
|
|
||||||
|
typedef vector < point_list > polytype;
|
||||||
|
typedef polytype::iterator polytype_iterator;
|
||||||
|
typedef polytype::const_iterator const_polytype_iterator;
|
||||||
|
|
||||||
|
|
||||||
|
class FGPolygon {
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
polytype poly; // polygons
|
||||||
|
point_list inside_list; // point inside list
|
||||||
|
int_list hole_list; // hole flag list
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
// Constructor and destructor
|
||||||
|
FGPolygon( void );
|
||||||
|
~FGPolygon( void );
|
||||||
|
|
||||||
|
// Add a contour
|
||||||
|
inline void add_contour( const point_list contour, const int hole_flag ) {
|
||||||
|
poly.push_back( contour );
|
||||||
|
hole_list.push_back( hole_flag );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get a contour
|
||||||
|
inline point_list get_contour( const int i ) const {
|
||||||
|
return poly[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete a contour
|
||||||
|
inline void delete_contour( const int i ) {
|
||||||
|
polytype_iterator start_poly = poly.begin();
|
||||||
|
poly.erase( start_poly + i );
|
||||||
|
|
||||||
|
int_list_iterator start_hole = hole_list.begin();
|
||||||
|
hole_list.erase( start_hole + i );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the specified node (index) to the polygon
|
||||||
|
inline void add_node( int contour, Point3D p ) {
|
||||||
|
if ( contour >= (int)poly.size() ) {
|
||||||
|
// extend polygon
|
||||||
|
point_list empty_contour;
|
||||||
|
empty_contour.clear();
|
||||||
|
for ( int i = 0; i < contour - (int)poly.size() + 1; ++i ) {
|
||||||
|
poly.push_back( empty_contour );
|
||||||
|
inside_list.push_back( Point3D(0.0) );
|
||||||
|
hole_list.push_back( 0 );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
poly[contour].push_back( p );
|
||||||
|
}
|
||||||
|
|
||||||
|
// return size
|
||||||
|
inline int contours() const { return poly.size(); }
|
||||||
|
inline int contour_size( int contour ) const {
|
||||||
|
return poly[contour].size();
|
||||||
|
}
|
||||||
|
|
||||||
|
// return the ith polygon point index from the specified contour
|
||||||
|
inline Point3D get_pt( int contour, int i ) const {
|
||||||
|
return poly[contour][i];
|
||||||
|
}
|
||||||
|
|
||||||
|
// update the value of a point
|
||||||
|
inline void set_pt( int contour, int i, const Point3D& p ) {
|
||||||
|
poly[contour][i] = p;
|
||||||
|
}
|
||||||
|
|
||||||
|
// get and set an arbitrary point inside the specified polygon contour
|
||||||
|
inline Point3D get_point_inside( const int contour ) const {
|
||||||
|
return inside_list[contour];
|
||||||
|
}
|
||||||
|
inline void set_point_inside( int contour, const Point3D& p ) {
|
||||||
|
inside_list[contour] = p;
|
||||||
|
}
|
||||||
|
|
||||||
|
// get and set hole flag
|
||||||
|
inline int get_hole_flag( const int contour ) const {
|
||||||
|
return hole_list[contour];
|
||||||
|
}
|
||||||
|
inline void set_hole_flag( const int contour, const int flag ) {
|
||||||
|
hole_list[contour] = flag;
|
||||||
|
}
|
||||||
|
|
||||||
|
// shift every point in the polygon by lon, lat
|
||||||
|
void shift( double lon, double lat );
|
||||||
|
|
||||||
|
// erase
|
||||||
|
inline void erase() { poly.clear(); }
|
||||||
|
|
||||||
|
// informational
|
||||||
|
|
||||||
|
// return the area of a contour (assumes simple polygons,
|
||||||
|
// i.e. non-self intersecting.)
|
||||||
|
//
|
||||||
|
// negative areas indicate counter clockwise winding
|
||||||
|
// postitive areas indicate clockwise winding.
|
||||||
|
double area_contour( const int contour ) const;
|
||||||
|
|
||||||
|
// return the smallest interior angle of the polygon
|
||||||
|
double minangle_contour( const int contour );
|
||||||
|
|
||||||
|
// output
|
||||||
|
void write( const string& file );
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
typedef vector < FGPolygon > poly_list;
|
||||||
|
typedef poly_list::iterator poly_list_iterator;
|
||||||
|
typedef poly_list::const_iterator const_poly_list_iterator;
|
||||||
|
|
||||||
|
|
||||||
|
// canonify the polygon winding, outer contour must be anti-clockwise,
|
||||||
|
// all inner contours must be clockwise.
|
||||||
|
FGPolygon polygon_canonify( const FGPolygon& in_poly );
|
||||||
|
|
||||||
|
|
||||||
|
// Wrapper for the fast Polygon Triangulation based on Seidel's
|
||||||
|
// Algorithm by Atul Narkhede and Dinesh Manocha
|
||||||
|
// http://www.cs.unc.edu/~dm/CODE/GEM/chapter.html
|
||||||
|
|
||||||
|
FGPolygon polygon_to_tristrip( const FGPolygon& poly );
|
||||||
|
|
||||||
|
|
||||||
|
// wrapper functions for gpc polygon clip routines
|
||||||
|
|
||||||
|
// Difference
|
||||||
|
FGPolygon polygon_diff( const FGPolygon& subject, const FGPolygon& clip );
|
||||||
|
|
||||||
|
// Intersection
|
||||||
|
FGPolygon polygon_int( const FGPolygon& subject, const FGPolygon& clip );
|
||||||
|
|
||||||
|
// Exclusive or
|
||||||
|
FGPolygon polygon_xor( const FGPolygon& subject, const FGPolygon& clip );
|
||||||
|
|
||||||
|
// Union
|
||||||
|
FGPolygon polygon_union( const FGPolygon& subject, const FGPolygon& clip );
|
||||||
|
|
||||||
|
|
||||||
|
#endif // _POLYGON_HXX
|
||||||
|
|
||||||
|
|
233
src/Lib/Polygon/split.cxx
Normal file
233
src/Lib/Polygon/split.cxx
Normal file
|
@ -0,0 +1,233 @@
|
||||||
|
// split.cxx -- polygon splitting utils
|
||||||
|
//
|
||||||
|
// Written by Curtis Olson, started February 1999.
|
||||||
|
//
|
||||||
|
// Copyright (C) 1999 Curtis L. Olson - curt@flightgear.org
|
||||||
|
//
|
||||||
|
// This program is free software; you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation; either version 2 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
//
|
||||||
|
// $Id$
|
||||||
|
|
||||||
|
|
||||||
|
#include <simgear/compiler.h>
|
||||||
|
|
||||||
|
#include STL_STRING
|
||||||
|
|
||||||
|
#include <simgear/newbucket.hxx>
|
||||||
|
#include <simgear/logstream.hxx>
|
||||||
|
|
||||||
|
#include "index.hxx"
|
||||||
|
#include "names.hxx"
|
||||||
|
#include "split.hxx"
|
||||||
|
|
||||||
|
|
||||||
|
static void clip_and_write_poly( string root, long int p_index, AreaType area,
|
||||||
|
FGBucket b, const FGPolygon& shape ) {
|
||||||
|
Point3D c, min, max, p;
|
||||||
|
c = Point3D( b.get_center_lon(), b.get_center_lat(), 0 );
|
||||||
|
double span = bucket_span( c.y() );
|
||||||
|
FGPolygon base, result;
|
||||||
|
char tile_name[256], poly_index[256];
|
||||||
|
|
||||||
|
// calculate bucket dimensions
|
||||||
|
if ( (c.y() >= -89.0) && (c.y() < 89.0) ) {
|
||||||
|
min.setx( c.x() - span / 2.0 );
|
||||||
|
max.setx( c.x() + span / 2.0 );
|
||||||
|
min.sety( c.y() - FG_HALF_BUCKET_SPAN );
|
||||||
|
max.sety( c.y() + FG_HALF_BUCKET_SPAN );
|
||||||
|
} else if ( c.y() < -89.0) {
|
||||||
|
min.setx( -90.0 );
|
||||||
|
max.setx( -89.0 );
|
||||||
|
min.sety( -180.0 );
|
||||||
|
max.sety( 180.0 );
|
||||||
|
} else if ( c.y() >= 89.0) {
|
||||||
|
min.setx( 89.0 );
|
||||||
|
max.setx( 90.0 );
|
||||||
|
min.sety( -180.0 );
|
||||||
|
max.sety( 180.0 );
|
||||||
|
} else {
|
||||||
|
FG_LOG ( FG_GENERAL, FG_ALERT,
|
||||||
|
"Out of range latitude in clip_and_write_poly() = " << c.y() );
|
||||||
|
}
|
||||||
|
|
||||||
|
FG_LOG( FG_GENERAL, FG_DEBUG, " (" << min << ") (" << max << ")" );
|
||||||
|
|
||||||
|
// set up clipping tile
|
||||||
|
base.add_node( 0, Point3D(min.x(), min.y(), 0) );
|
||||||
|
base.add_node( 0, Point3D(max.x(), min.y(), 0) );
|
||||||
|
base.add_node( 0, Point3D(max.x(), max.y(), 0) );
|
||||||
|
base.add_node( 0, Point3D(min.x(), max.y(), 0) );
|
||||||
|
|
||||||
|
// FG_LOG( FG_GENERAL, FG_DEBUG, "base = 4 vertices" );
|
||||||
|
|
||||||
|
/*
|
||||||
|
FILE *bfp= fopen("base", "w");
|
||||||
|
gpc_write_polygon(bfp, &base);
|
||||||
|
fclose(bfp);
|
||||||
|
*/
|
||||||
|
|
||||||
|
result = polygon_int( base, shape );
|
||||||
|
|
||||||
|
if ( result.contours() > 0 ) {
|
||||||
|
long int t_index = b.gen_index();
|
||||||
|
string path = root + "/" + b.gen_base_path();
|
||||||
|
string command = "mkdir -p " + path;
|
||||||
|
system( command.c_str() );
|
||||||
|
|
||||||
|
sprintf( tile_name, "%ld", t_index );
|
||||||
|
string polyfile = path + "/" + tile_name;
|
||||||
|
|
||||||
|
sprintf( poly_index, "%ld", p_index );
|
||||||
|
polyfile += ".";
|
||||||
|
polyfile += poly_index;
|
||||||
|
|
||||||
|
string poly_type = get_area_name( area );
|
||||||
|
if ( poly_type == "Unknown" ) {
|
||||||
|
cout << "unknown area type in clip_and_write_poly()!" << endl;
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
FILE *rfp= fopen( polyfile.c_str(), "w" );
|
||||||
|
fprintf( rfp, "%s\n", poly_type.c_str() );
|
||||||
|
|
||||||
|
fprintf( rfp, "%d\n", result.contours() );
|
||||||
|
for ( int i = 0; i < result.contours(); ++i ) {
|
||||||
|
fprintf( rfp, "%d\n", result.contour_size(i) );
|
||||||
|
fprintf( rfp, "%d\n", result.get_hole_flag(i) );
|
||||||
|
for ( int j = 0; j < result.contour_size(i); ++j ) {
|
||||||
|
p = result.get_pt( i, j );
|
||||||
|
fprintf( rfp, "%.15f %.15f\n", p.x(), p.y() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fclose( rfp );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// process shape (write polygon to all intersecting tiles)
|
||||||
|
void split_polygon(const string& path, AreaType area, const FGPolygon& shape) {
|
||||||
|
Point3D min, max, p;
|
||||||
|
// point2d min, max;
|
||||||
|
long int index;
|
||||||
|
int i, j;
|
||||||
|
|
||||||
|
// bail out immediately if polygon is empty
|
||||||
|
if ( shape.contours() == 0 ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
min = Point3D( 200.0 );
|
||||||
|
max = Point3D( -200.0 );
|
||||||
|
|
||||||
|
// find min/max of polygon
|
||||||
|
for ( i = 0; i < shape.contours(); i++ ) {
|
||||||
|
for ( j = 0; j < shape.contour_size(i); j++ ) {
|
||||||
|
p = shape.get_pt( i, j );
|
||||||
|
|
||||||
|
if ( p.x() < min.x() ) { min.setx( p.x() ); }
|
||||||
|
if ( p.y() < min.y() ) { min.sety( p.y() ); }
|
||||||
|
if ( p.x() > max.x() ) { max.setx( p.x() ); }
|
||||||
|
if ( p.y() > max.y() ) { max.sety( p.y() ); }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// get next polygon index
|
||||||
|
index = poly_index_next();
|
||||||
|
|
||||||
|
FG_LOG( FG_GENERAL, FG_INFO, " min = " << min << " max = " << max );
|
||||||
|
|
||||||
|
// find buckets for min, and max points of convex hull.
|
||||||
|
// note to self: self, you should think about checking for
|
||||||
|
// polygons that span the date line
|
||||||
|
FGBucket b_min( min.x(), min.y() );
|
||||||
|
FGBucket b_max( max.x(), max.y() );
|
||||||
|
FG_LOG( FG_GENERAL, FG_INFO, " Bucket min = " << b_min );
|
||||||
|
FG_LOG( FG_GENERAL, FG_INFO, " Bucket max = " << b_max );
|
||||||
|
|
||||||
|
if ( b_min == b_max ) {
|
||||||
|
clip_and_write_poly( path, index, area, b_min, shape );
|
||||||
|
} else {
|
||||||
|
FGBucket b_cur;
|
||||||
|
int dx, dy, i, j;
|
||||||
|
|
||||||
|
fgBucketDiff(b_min, b_max, &dx, &dy);
|
||||||
|
FG_LOG( FG_GENERAL, FG_INFO,
|
||||||
|
" polygon spans tile boundaries" );
|
||||||
|
FG_LOG( FG_GENERAL, FG_INFO, " dx = " << dx
|
||||||
|
<< " dy = " << dy );
|
||||||
|
|
||||||
|
if ( (dx > 2880) || (dy > 1440) ) {
|
||||||
|
FG_LOG( FG_GENERAL, FG_ALERT,
|
||||||
|
"somethings really wrong!!!!" );
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
for ( j = 0; j <= dy; j++ ) {
|
||||||
|
// for performance reasons, we'll clip out just this
|
||||||
|
// horizontal row, and clip all the tiles in this row
|
||||||
|
// against the smaller shape
|
||||||
|
|
||||||
|
FG_LOG ( FG_GENERAL, FG_INFO,
|
||||||
|
"Generating clip row " << j << " of " << dy );
|
||||||
|
|
||||||
|
FGBucket b_clip = fgBucketOffset(min.x(), min.y(), 0, j);
|
||||||
|
FGPolygon row, clip_row;
|
||||||
|
Point3D c, clip_max, clip_min;
|
||||||
|
c = Point3D( b_clip.get_center_lon(), b_clip.get_center_lat(), 0 );
|
||||||
|
|
||||||
|
row.erase();
|
||||||
|
clip_row.erase();
|
||||||
|
|
||||||
|
// calculate bucket clip_min.y and clip_max.y
|
||||||
|
if ( (c.y() >= -89.0) && (c.y() < 89.0) ) {
|
||||||
|
clip_min.sety( c.y() - FG_HALF_BUCKET_SPAN );
|
||||||
|
clip_max.sety( c.y() + FG_HALF_BUCKET_SPAN );
|
||||||
|
} else if ( c.y() < -89.0) {
|
||||||
|
clip_min.sety( -90.0 );
|
||||||
|
clip_max.sety( -89.0 );
|
||||||
|
} else if ( c.y() >= 89.0) {
|
||||||
|
clip_min.sety( 89.0 );
|
||||||
|
clip_max.sety( 90.0 );
|
||||||
|
} else {
|
||||||
|
FG_LOG ( FG_GENERAL, FG_ALERT,
|
||||||
|
"Out of range latitude in clip_and_write_poly() = "
|
||||||
|
<< c.y() );
|
||||||
|
}
|
||||||
|
clip_min.setx( -180.0 );
|
||||||
|
clip_max.setx( 180.0 );
|
||||||
|
|
||||||
|
// set up clipping tile
|
||||||
|
row.add_node( 0, Point3D(clip_min.x(), clip_min.y(), 0) );
|
||||||
|
row.add_node( 0, Point3D(clip_max.x(), clip_min.y(), 0) );
|
||||||
|
row.add_node( 0, Point3D(clip_max.x(), clip_max.y(), 0) );
|
||||||
|
row.add_node( 0, Point3D(clip_min.x(), clip_max.y(), 0) );
|
||||||
|
|
||||||
|
clip_row = polygon_int( row, shape );
|
||||||
|
|
||||||
|
/* FILE *sfp = fopen("shape", "w");
|
||||||
|
gpc_write_polygon(sfp, 0, shape);
|
||||||
|
fclose(sfp);
|
||||||
|
sfp = fopen("clip_row", "w");
|
||||||
|
gpc_write_polygon(sfp, 0, &clip_row);
|
||||||
|
fclose(sfp); */
|
||||||
|
|
||||||
|
for ( i = 0; i <= dx; i++ ) {
|
||||||
|
b_cur = fgBucketOffset(min.x(), min.y(), i, j);
|
||||||
|
clip_and_write_poly( path, index, area, b_cur, clip_row );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// string answer; cin >> answer;
|
||||||
|
}
|
||||||
|
}
|
38
src/Lib/Polygon/split.hxx
Normal file
38
src/Lib/Polygon/split.hxx
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
// split.hxx -- polygon splitting utils
|
||||||
|
//
|
||||||
|
// Written by Curtis Olson, started February 1999.
|
||||||
|
//
|
||||||
|
// Copyright (C) 1999 Curtis L. Olson - curt@flightgear.org
|
||||||
|
//
|
||||||
|
// This program is free software; you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation; either version 2 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
//
|
||||||
|
// $Id$
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef _SPLIT_HXX
|
||||||
|
#define _SPLIT_HXX
|
||||||
|
|
||||||
|
|
||||||
|
#include "names.hxx"
|
||||||
|
#include "polygon.hxx"
|
||||||
|
|
||||||
|
|
||||||
|
// process shape (write polygon to all intersecting tiles)
|
||||||
|
void split_polygon(const string& path, AreaType area, const FGPolygon& shape);
|
||||||
|
|
||||||
|
|
||||||
|
#endif // _SPLIT_HXX
|
||||||
|
|
||||||
|
|
24
src/Lib/TriangleJRS/Makefile.am
Normal file
24
src/Lib/TriangleJRS/Makefile.am
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
# CPPFLAGS is a list of definitions used to compile an object code version
|
||||||
|
# of Triangle (triangle.o) to be called by another program. The file
|
||||||
|
# "triangle.h" contains detailed information on how to call triangle.o.
|
||||||
|
#
|
||||||
|
# The -DTRILIBRARY should always be used when compiling Triangle into an
|
||||||
|
# object file.
|
||||||
|
#
|
||||||
|
# An example DEFS line is:
|
||||||
|
#
|
||||||
|
# CPPFLAGS = -DTRILIBRARY -DREDUCED -DCDT_ONLY
|
||||||
|
|
||||||
|
CPPFLAGS += -DTRILIBRARY
|
||||||
|
|
||||||
|
noinst_LIBRARIES = libTriangle.a
|
||||||
|
|
||||||
|
libTriangle_a_SOURCES = triangle.c triangle.h
|
||||||
|
|
||||||
|
if HAVE_XWINDOWS
|
||||||
|
|
||||||
|
bin_PROGRAMS = showme
|
||||||
|
showme_SOURCES = showme.c
|
||||||
|
showme_LDADD = -lX11
|
||||||
|
|
||||||
|
endif
|
181
src/Lib/TriangleJRS/README
Normal file
181
src/Lib/TriangleJRS/README
Normal file
|
@ -0,0 +1,181 @@
|
||||||
|
Triangle
|
||||||
|
A Two-Dimensional Quality Mesh Generator and Delaunay Triangulator.
|
||||||
|
Version 1.3
|
||||||
|
|
||||||
|
Show Me
|
||||||
|
A Display Program for Meshes and More.
|
||||||
|
Version 1.3
|
||||||
|
|
||||||
|
Copyright 1996 Jonathan Richard Shewchuk
|
||||||
|
School of Computer Science
|
||||||
|
Carnegie Mellon University
|
||||||
|
5000 Forbes Avenue
|
||||||
|
Pittsburgh, Pennsylvania 15213-3891
|
||||||
|
Please send bugs and comments to jrs@cs.cmu.edu
|
||||||
|
|
||||||
|
Created as part of the Archimedes project (tools for parallel FEM).
|
||||||
|
Supported in part by NSF Grant CMS-9318163 and an NSERC 1967 Scholarship.
|
||||||
|
There is no warranty whatsoever. Use at your own risk.
|
||||||
|
|
||||||
|
|
||||||
|
Triangle generates exact Delaunay triangulations, constrained Delaunay
|
||||||
|
triangulations, and quality conforming Delaunay triangulations. The
|
||||||
|
latter can be generated with no small angles, and are thus suitable for
|
||||||
|
finite element analysis. Show Me graphically displays the contents of
|
||||||
|
the geometric files used by Triangle. Show Me can also write images in
|
||||||
|
PostScript form.
|
||||||
|
|
||||||
|
Information on the algorithms used by Triangle, including complete
|
||||||
|
references, can be found in the comments at the beginning of the triangle.c
|
||||||
|
source file. Another listing of these references, with PostScript copies
|
||||||
|
of some of the papers, is available from the Web page
|
||||||
|
|
||||||
|
http://www.cs.cmu.edu/~quake/triangle.research.html
|
||||||
|
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
These programs may be freely redistributed under the condition that the
|
||||||
|
copyright notices (including the copy of this notice in the code comments
|
||||||
|
and the copyright notice printed when the `-h' switch is selected) are
|
||||||
|
not removed, and no compensation is received. Private, research, and
|
||||||
|
institutional use is free. You may distribute modified versions of this
|
||||||
|
code UNDER THE CONDITION THAT THIS CODE AND ANY MODIFICATIONS MADE TO IT
|
||||||
|
IN THE SAME FILE REMAIN UNDER COPYRIGHT OF THE ORIGINAL AUTHOR, BOTH
|
||||||
|
SOURCE AND OBJECT CODE ARE MADE FREELY AVAILABLE WITHOUT CHARGE, AND
|
||||||
|
CLEAR NOTICE IS GIVEN OF THE MODIFICATIONS. Distribution of this code as
|
||||||
|
part of a commercial system is permissible ONLY BY DIRECT ARRANGEMENT
|
||||||
|
WITH THE AUTHOR. (If you are not directly supplying this code to a
|
||||||
|
customer, and you are instead telling them how they can obtain it for
|
||||||
|
free, then you are not required to make any arrangement with me.)
|
||||||
|
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
The files included in this distribution are:
|
||||||
|
|
||||||
|
README The file you're reading now.
|
||||||
|
triangle.c Complete C source code for Triangle.
|
||||||
|
showme.c Complete C source code for Show Me.
|
||||||
|
triangle.h Include file for calling Triangle from another program.
|
||||||
|
tricall.c Sample program that calls Triangle.
|
||||||
|
makefile Makefile for compiling Triangle and Show Me.
|
||||||
|
A.poly A sample data file.
|
||||||
|
|
||||||
|
Triangle and Show Me are each a single portable C file. The easiest way to
|
||||||
|
compile them is to edit and use the included makefile. Before compiling,
|
||||||
|
read the makefile, which describes your options, and edit it accordingly.
|
||||||
|
You should specify:
|
||||||
|
|
||||||
|
The source and binary directories.
|
||||||
|
|
||||||
|
The C compiler and level of optimization.
|
||||||
|
|
||||||
|
Do you want single precision or double? Do you want to leave out some of
|
||||||
|
Triangle's features to reduce the size of the executable file?
|
||||||
|
|
||||||
|
The "correct" directories for include files (especially X include files),
|
||||||
|
if necessary.
|
||||||
|
|
||||||
|
Once you've done this, type "make" to compile the programs. Alternatively,
|
||||||
|
the files are usually easy to compile without a makefile:
|
||||||
|
|
||||||
|
cc -O -o triangle triangle.c -lm
|
||||||
|
cc -O -o showme showme.c -lX11
|
||||||
|
|
||||||
|
On some systems, the C compiler won't be able to find the X include files
|
||||||
|
or libraries, and you'll need to specify an include path or library path:
|
||||||
|
|
||||||
|
cc -O -I/usr/local/include -o showme showme.c -L/usr/local/lib -lX11
|
||||||
|
|
||||||
|
However, on other systems (like my workstation), the latter incantation
|
||||||
|
will cause the wrong files to be read, and the Show Me mouse buttons won't
|
||||||
|
work properly in the main window. Hence, try the "-I" and "-L" switches
|
||||||
|
ONLY if the compiler fails without it. (If you're using the makefile, you
|
||||||
|
may edit it to add this switch.)
|
||||||
|
|
||||||
|
Some processors, possibly including Intel x86 family and Motorola 68xxx
|
||||||
|
family chips, are IEEE conformant but have extended length internal
|
||||||
|
floating-point registers that may defeat Triangle's exact arithmetic
|
||||||
|
routines by failing to cause enough roundoff error! Typically, there is
|
||||||
|
a way to set these internal registers so that they are rounded off to
|
||||||
|
IEEE single or double precision format. If you have such a processor,
|
||||||
|
you should check your C compiler or system manuals to find out how to
|
||||||
|
configure these internal registers to the precision you are using.
|
||||||
|
Otherwise, the exact arithmetic routines won't be exact at all.
|
||||||
|
Unfortunately, I don't have access to any such systems, and can't give
|
||||||
|
advice on how to configure them. These problems don't occur on any
|
||||||
|
workstations I am aware of. However, Triangle's exact arithmetic hasn't
|
||||||
|
a hope of working on machines like the Cray C90 or Y-MP, which are not
|
||||||
|
IEEE conformant and have inaccurate rounding.
|
||||||
|
|
||||||
|
Triangle and Show Me both produce their own documentation. Complete
|
||||||
|
instructions are printed by invoking each program with the `-h' switch:
|
||||||
|
|
||||||
|
triangle -h
|
||||||
|
showme -h
|
||||||
|
|
||||||
|
The instructions are long; you'll probably want to pipe the output to
|
||||||
|
`more' or `lpr' or redirect it to a file. Both programs give a short list
|
||||||
|
of command line options if they are invoked without arguments (that is,
|
||||||
|
just type `triangle' or `showme'). Alternatively, you may want to read
|
||||||
|
the instructions on the World Wide Web. The appropriate URLs are:
|
||||||
|
|
||||||
|
http://www.cs.cmu.edu/~quake/triangle.html
|
||||||
|
http://www.cs.cmu.edu/~quake/showme.html
|
||||||
|
|
||||||
|
Try out Triangle on the enclosed sample file, A.poly:
|
||||||
|
|
||||||
|
triangle -p A
|
||||||
|
showme A.poly &
|
||||||
|
|
||||||
|
Triangle will read the Planar Straight Line Graph defined by A.poly, and
|
||||||
|
write its constrained Delaunay triangulation to A.1.node and A.1.ele.
|
||||||
|
Show Me will display the figure defined by A.poly. There are two buttons
|
||||||
|
marked "ele" in the Show Me window; click on the top one. This will cause
|
||||||
|
Show Me to load and display the triangulation.
|
||||||
|
|
||||||
|
For contrast, try running
|
||||||
|
|
||||||
|
triangle -pq A
|
||||||
|
|
||||||
|
Now, click on the same "ele" button. A new triangulation will be loaded;
|
||||||
|
this one having no angles smaller than 20 degrees.
|
||||||
|
|
||||||
|
To see a Voronoi diagram, try this:
|
||||||
|
|
||||||
|
cp A.poly A.node
|
||||||
|
triangle -v A
|
||||||
|
|
||||||
|
Click the "ele" button again. You will see the Delaunay triangulation of
|
||||||
|
the points in A.poly, without the segments. Now click the top "voro" button.
|
||||||
|
You will see the Voronoi diagram corresponding to that Delaunay triangulation.
|
||||||
|
Click the "Reset" button to see the full extent of the diagram.
|
||||||
|
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
If you wish to call Triangle from another program, instructions for doing
|
||||||
|
so are contained in the file `triangle.h' (but read Triangle's regular
|
||||||
|
instructions first!). Also look at `tricall.c', which provides an example.
|
||||||
|
|
||||||
|
Type "make trilibrary" to create triangle.o, a callable object file.
|
||||||
|
Alternatively, the object file is usually easy to compile without a
|
||||||
|
makefile:
|
||||||
|
|
||||||
|
cc -DTRILIBRARY -O -c triangle.c
|
||||||
|
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
If you use Triangle, and especially if you use it to accomplish real
|
||||||
|
work, I would like very much to hear from you. A short letter or email
|
||||||
|
(to jrs@cs.cmu.edu) describing how you use Triangle will mean a lot to
|
||||||
|
me. The more people I know are using this program, the more easily I can
|
||||||
|
justify spending time on improvements and on the three-dimensional
|
||||||
|
successor to Triangle, which in turn will benefit you. Also, I can put
|
||||||
|
you on a list to receive email whenever a new version of Triangle is
|
||||||
|
available.
|
||||||
|
|
||||||
|
If you use a mesh generated by Triangle or plotted by Show Me in a
|
||||||
|
publication, please include an acknowledgment as well.
|
||||||
|
|
||||||
|
|
||||||
|
Jonathan Richard Shewchuk
|
||||||
|
July 20, 1996
|
3384
src/Lib/TriangleJRS/showme.c
Normal file
3384
src/Lib/TriangleJRS/showme.c
Normal file
File diff suppressed because it is too large
Load diff
13241
src/Lib/TriangleJRS/triangle.c
Normal file
13241
src/Lib/TriangleJRS/triangle.c
Normal file
File diff suppressed because it is too large
Load diff
289
src/Lib/TriangleJRS/triangle.h
Normal file
289
src/Lib/TriangleJRS/triangle.h
Normal file
|
@ -0,0 +1,289 @@
|
||||||
|
/*****************************************************************************/
|
||||||
|
/* */
|
||||||
|
/* (triangle.h) */
|
||||||
|
/* */
|
||||||
|
/* Include file for programs that call Triangle. */
|
||||||
|
/* */
|
||||||
|
/* Accompanies Triangle Version 1.3 */
|
||||||
|
/* July 19, 1996 */
|
||||||
|
/* */
|
||||||
|
/* Copyright 1996 */
|
||||||
|
/* Jonathan Richard Shewchuk */
|
||||||
|
/* School of Computer Science */
|
||||||
|
/* Carnegie Mellon University */
|
||||||
|
/* 5000 Forbes Avenue */
|
||||||
|
/* Pittsburgh, Pennsylvania 15213-3891 */
|
||||||
|
/* jrs@cs.cmu.edu */
|
||||||
|
/* */
|
||||||
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/* */
|
||||||
|
/* How to call Triangle from another program */
|
||||||
|
/* */
|
||||||
|
/* */
|
||||||
|
/* If you haven't read Triangle's instructions (run "triangle -h" to read */
|
||||||
|
/* them), you won't understand what follows. */
|
||||||
|
/* */
|
||||||
|
/* Triangle must be compiled into an object file (triangle.o) with the */
|
||||||
|
/* TRILIBRARY symbol defined (preferably by using the -DTRILIBRARY compiler */
|
||||||
|
/* switch). The makefile included with Triangle will do this for you if */
|
||||||
|
/* you run "make trilibrary". The resulting object file can be called via */
|
||||||
|
/* the procedure triangulate(). */
|
||||||
|
/* */
|
||||||
|
/* If the size of the object file is important to you, you may wish to */
|
||||||
|
/* generate a reduced version of triangle.o. The REDUCED symbol gets rid */
|
||||||
|
/* of all features that are primarily of research interest. Specifically, */
|
||||||
|
/* the -DREDUCED switch eliminates Triangle's -i, -F, -s, and -C switches. */
|
||||||
|
/* The CDT_ONLY symbol gets rid of all meshing algorithms above and beyond */
|
||||||
|
/* constrained Delaunay triangulation. Specifically, the -DCDT_ONLY switch */
|
||||||
|
/* eliminates Triangle's -r, -q, -a, -S, and -s switches. */
|
||||||
|
/* */
|
||||||
|
/* IMPORTANT: These definitions (TRILIBRARY, REDUCED, CDT_ONLY) must be */
|
||||||
|
/* made in the makefile or in triangle.c itself. Putting these definitions */
|
||||||
|
/* in this file will not create the desired effect. */
|
||||||
|
/* */
|
||||||
|
/* */
|
||||||
|
/* The calling convention for triangulate() follows. */
|
||||||
|
/* */
|
||||||
|
/* void triangulate(triswitches, in, out, vorout) */
|
||||||
|
/* char *triswitches; */
|
||||||
|
/* struct triangulateio *in; */
|
||||||
|
/* struct triangulateio *out; */
|
||||||
|
/* struct triangulateio *vorout; */
|
||||||
|
/* */
|
||||||
|
/* `triswitches' is a string containing the command line switches you wish */
|
||||||
|
/* to invoke. No initial dash is required. Some suggestions: */
|
||||||
|
/* */
|
||||||
|
/* - You'll probably find it convenient to use the `z' switch so that */
|
||||||
|
/* points (and other items) are numbered from zero. This simplifies */
|
||||||
|
/* indexing, because the first item of any type always starts at index */
|
||||||
|
/* [0] of the corresponding array, whether that item's number is zero or */
|
||||||
|
/* one. */
|
||||||
|
/* - You'll probably want to use the `Q' (quiet) switch in your final code, */
|
||||||
|
/* but you can take advantage of Triangle's printed output (including the */
|
||||||
|
/* `V' switch) while debugging. */
|
||||||
|
/* - If you are not using the `q' or `a' switches, then the output points */
|
||||||
|
/* will be identical to the input points, except possibly for the */
|
||||||
|
/* boundary markers. If you don't need the boundary markers, you should */
|
||||||
|
/* use the `N' (no nodes output) switch to save memory. (If you do need */
|
||||||
|
/* boundary markers, but need to save memory, a good nasty trick is to */
|
||||||
|
/* set out->pointlist equal to in->pointlist before calling triangulate(),*/
|
||||||
|
/* so that Triangle overwrites the input points with identical copies.) */
|
||||||
|
/* - The `I' (no iteration numbers) and `g' (.off file output) switches */
|
||||||
|
/* have no effect when Triangle is compiled with TRILIBRARY defined. */
|
||||||
|
/* */
|
||||||
|
/* `in', `out', and `vorout' are descriptions of the input, the output, */
|
||||||
|
/* and the Voronoi output. If the `v' (Voronoi output) switch is not used, */
|
||||||
|
/* `vorout' may be NULL. `in' and `out' may never be NULL. */
|
||||||
|
/* */
|
||||||
|
/* Certain fields of the input and output structures must be initialized, */
|
||||||
|
/* as described below. */
|
||||||
|
/* */
|
||||||
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/* */
|
||||||
|
/* The `triangulateio' structure. */
|
||||||
|
/* */
|
||||||
|
/* Used to pass data into and out of the triangulate() procedure. */
|
||||||
|
/* */
|
||||||
|
/* */
|
||||||
|
/* Arrays are used to store points, triangles, markers, and so forth. In */
|
||||||
|
/* all cases, the first item in any array is stored starting at index [0]. */
|
||||||
|
/* However, that item is item number `1' unless the `z' switch is used, in */
|
||||||
|
/* which case it is item number `0'. Hence, you may find it easier to */
|
||||||
|
/* index points (and triangles in the neighbor list) if you use the `z' */
|
||||||
|
/* switch. Unless, of course, you're calling Triangle from a Fortran */
|
||||||
|
/* program. */
|
||||||
|
/* */
|
||||||
|
/* Description of fields (except the `numberof' fields, which are obvious): */
|
||||||
|
/* */
|
||||||
|
/* `pointlist': An array of point coordinates. The first point's x */
|
||||||
|
/* coordinate is at index [0] and its y coordinate at index [1], followed */
|
||||||
|
/* by the coordinates of the remaining points. Each point occupies two */
|
||||||
|
/* REALs. */
|
||||||
|
/* `pointattributelist': An array of point attributes. Each point's */
|
||||||
|
/* attributes occupy `numberofpointattributes' REALs. */
|
||||||
|
/* `pointmarkerlist': An array of point markers; one int per point. */
|
||||||
|
/* */
|
||||||
|
/* `trianglelist': An array of triangle corners. The first triangle's */
|
||||||
|
/* first corner is at index [0], followed by its other two corners in */
|
||||||
|
/* counterclockwise order, followed by any other nodes if the triangle */
|
||||||
|
/* represents a nonlinear element. Each triangle occupies */
|
||||||
|
/* `numberofcorners' ints. */
|
||||||
|
/* `triangleattributelist': An array of triangle attributes. Each */
|
||||||
|
/* triangle's attributes occupy `numberoftriangleattributes' REALs. */
|
||||||
|
/* `trianglearealist': An array of triangle area constraints; one REAL per */
|
||||||
|
/* triangle. Input only. */
|
||||||
|
/* `neighborlist': An array of triangle neighbors; three ints per */
|
||||||
|
/* triangle. Output only. */
|
||||||
|
/* */
|
||||||
|
/* `segmentlist': An array of segment endpoints. The first segment's */
|
||||||
|
/* endpoints are at indices [0] and [1], followed by the remaining */
|
||||||
|
/* segments. Two ints per segment. */
|
||||||
|
/* `segmentmarkerlist': An array of segment markers; one int per segment. */
|
||||||
|
/* */
|
||||||
|
/* `holelist': An array of holes. The first hole's x and y coordinates */
|
||||||
|
/* are at indices [0] and [1], followed by the remaining holes. Two */
|
||||||
|
/* REALs per hole. Input only, although the pointer is copied to the */
|
||||||
|
/* output structure for your convenience. */
|
||||||
|
/* */
|
||||||
|
/* `regionlist': An array of regional attributes and area constraints. */
|
||||||
|
/* The first constraint's x and y coordinates are at indices [0] and [1], */
|
||||||
|
/* followed by the regional attribute and index [2], followed by the */
|
||||||
|
/* maximum area at index [3], followed by the remaining area constraints. */
|
||||||
|
/* Four REALs per area constraint. Note that each regional attribute is */
|
||||||
|
/* used only if you select the `A' switch, and each area constraint is */
|
||||||
|
/* used only if you select the `a' switch (with no number following), but */
|
||||||
|
/* omitting one of these switches does not change the memory layout. */
|
||||||
|
/* Input only, although the pointer is copied to the output structure for */
|
||||||
|
/* your convenience. */
|
||||||
|
/* */
|
||||||
|
/* `edgelist': An array of edge endpoints. The first edge's endpoints are */
|
||||||
|
/* at indices [0] and [1], followed by the remaining edges. Two ints per */
|
||||||
|
/* edge. Output only. */
|
||||||
|
/* `edgemarkerlist': An array of edge markers; one int per edge. Output */
|
||||||
|
/* only. */
|
||||||
|
/* `normlist': An array of normal vectors, used for infinite rays in */
|
||||||
|
/* Voronoi diagrams. The first normal vector's x and y magnitudes are */
|
||||||
|
/* at indices [0] and [1], followed by the remaining vectors. For each */
|
||||||
|
/* finite edge in a Voronoi diagram, the normal vector written is the */
|
||||||
|
/* zero vector. Two REALs per edge. Output only. */
|
||||||
|
/* */
|
||||||
|
/* */
|
||||||
|
/* Any input fields that Triangle will examine must be initialized. */
|
||||||
|
/* Furthermore, for each output array that Triangle will write to, you */
|
||||||
|
/* must either provide space by setting the appropriate pointer to point */
|
||||||
|
/* to the space you want the data written to, or you must initialize the */
|
||||||
|
/* pointer to NULL, which tells Triangle to allocate space for the results. */
|
||||||
|
/* The latter option is preferable, because Triangle always knows exactly */
|
||||||
|
/* how much space to allocate. The former option is provided mainly for */
|
||||||
|
/* people who need to call Triangle from Fortran code, though it also makes */
|
||||||
|
/* possible some nasty space-saving tricks, like writing the output to the */
|
||||||
|
/* same arrays as the input. */
|
||||||
|
/* */
|
||||||
|
/* Triangle will not free() any input or output arrays, including those it */
|
||||||
|
/* allocates itself; that's up to you. */
|
||||||
|
/* */
|
||||||
|
/* Here's a guide to help you decide which fields you must initialize */
|
||||||
|
/* before you call triangulate(). */
|
||||||
|
/* */
|
||||||
|
/* `in': */
|
||||||
|
/* */
|
||||||
|
/* - `pointlist' must always point to a list of points; `numberofpoints' */
|
||||||
|
/* and `numberofpointattributes' must be properly set. */
|
||||||
|
/* `pointmarkerlist' must either be set to NULL (in which case all */
|
||||||
|
/* markers default to zero), or must point to a list of markers. If */
|
||||||
|
/* `numberofpointattributes' is not zero, `pointattributelist' must */
|
||||||
|
/* point to a list of point attributes. */
|
||||||
|
/* - If the `r' switch is used, `trianglelist' must point to a list of */
|
||||||
|
/* triangles, and `numberoftriangles', `numberofcorners', and */
|
||||||
|
/* `numberoftriangleattributes' must be properly set. If */
|
||||||
|
/* `numberoftriangleattributes' is not zero, `triangleattributelist' */
|
||||||
|
/* must point to a list of triangle attributes. If the `a' switch is */
|
||||||
|
/* used (with no number following), `trianglearealist' must point to a */
|
||||||
|
/* list of triangle area constraints. `neighborlist' may be ignored. */
|
||||||
|
/* - If the `p' switch is used, `segmentlist' must point to a list of */
|
||||||
|
/* segments, `numberofsegments' must be properly set, and */
|
||||||
|
/* `segmentmarkerlist' must either be set to NULL (in which case all */
|
||||||
|
/* markers default to zero), or must point to a list of markers. */
|
||||||
|
/* - If the `p' switch is used without the `r' switch, then */
|
||||||
|
/* `numberofholes' and `numberofregions' must be properly set. If */
|
||||||
|
/* `numberofholes' is not zero, `holelist' must point to a list of */
|
||||||
|
/* holes. If `numberofregions' is not zero, `regionlist' must point to */
|
||||||
|
/* a list of region constraints. */
|
||||||
|
/* - If the `p' switch is used, `holelist', `numberofholes', */
|
||||||
|
/* `regionlist', and `numberofregions' is copied to `out'. (You can */
|
||||||
|
/* nonetheless get away with not initializing them if the `r' switch is */
|
||||||
|
/* used.) */
|
||||||
|
/* - `edgelist', `edgemarkerlist', `normlist', and `numberofedges' may be */
|
||||||
|
/* ignored. */
|
||||||
|
/* */
|
||||||
|
/* `out': */
|
||||||
|
/* */
|
||||||
|
/* - `pointlist' must be initialized (NULL or pointing to memory) unless */
|
||||||
|
/* the `N' switch is used. `pointmarkerlist' must be initialized */
|
||||||
|
/* unless the `N' or `B' switch is used. If `N' is not used and */
|
||||||
|
/* `in->numberofpointattributes' is not zero, `pointattributelist' must */
|
||||||
|
/* be initialized. */
|
||||||
|
/* - `trianglelist' must be initialized unless the `E' switch is used. */
|
||||||
|
/* `neighborlist' must be initialized if the `n' switch is used. If */
|
||||||
|
/* the `E' switch is not used and (`in->numberofelementattributes' is */
|
||||||
|
/* not zero or the `A' switch is used), `elementattributelist' must be */
|
||||||
|
/* initialized. `trianglearealist' may be ignored. */
|
||||||
|
/* - `segmentlist' must be initialized if the `p' or `c' switch is used, */
|
||||||
|
/* and the `P' switch is not used. `segmentmarkerlist' must also be */
|
||||||
|
/* initialized under these circumstances unless the `B' switch is used. */
|
||||||
|
/* - `edgelist' must be initialized if the `e' switch is used. */
|
||||||
|
/* `edgemarkerlist' must be initialized if the `e' switch is used and */
|
||||||
|
/* the `B' switch is not. */
|
||||||
|
/* - `holelist', `regionlist', `normlist', and all scalars may be ignored.*/
|
||||||
|
/* */
|
||||||
|
/* `vorout' (only needed if `v' switch is used): */
|
||||||
|
/* */
|
||||||
|
/* - `pointlist' must be initialized. If `in->numberofpointattributes' */
|
||||||
|
/* is not zero, `pointattributelist' must be initialized. */
|
||||||
|
/* `pointmarkerlist' may be ignored. */
|
||||||
|
/* - `edgelist' and `normlist' must both be initialized. */
|
||||||
|
/* `edgemarkerlist' may be ignored. */
|
||||||
|
/* - Everything else may be ignored. */
|
||||||
|
/* */
|
||||||
|
/* After a call to triangulate(), the valid fields of `out' and `vorout' */
|
||||||
|
/* will depend, in an obvious way, on the choice of switches used. Note */
|
||||||
|
/* that when the `p' switch is used, the pointers `holelist' and */
|
||||||
|
/* `regionlist' are copied from `in' to `out', but no new space is */
|
||||||
|
/* allocated; be careful that you don't free() the same array twice. On */
|
||||||
|
/* the other hand, Triangle will never copy the `pointlist' pointer (or any */
|
||||||
|
/* others); new space is allocated for `out->pointlist', or if the `N' */
|
||||||
|
/* switch is used, `out->pointlist' remains uninitialized. */
|
||||||
|
/* */
|
||||||
|
/* All of the meaningful `numberof' fields will be properly set; for */
|
||||||
|
/* instance, `numberofedges' will represent the number of edges in the */
|
||||||
|
/* triangulation whether or not the edges were written. If segments are */
|
||||||
|
/* not used, `numberofsegments' will indicate the number of boundary edges. */
|
||||||
|
/* */
|
||||||
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
/* CLO: 3/21/99 - this could be done as a compile flag, but I always want
|
||||||
|
this defined and I don't want to sprinkle extra stuff throughout the
|
||||||
|
Makefile system if I don't have to. */
|
||||||
|
#define ANSI_DECLARATORS 1
|
||||||
|
|
||||||
|
struct triangulateio {
|
||||||
|
REAL *pointlist; /* In / out */
|
||||||
|
REAL *pointattributelist; /* In / out */
|
||||||
|
int *pointmarkerlist; /* In / out */
|
||||||
|
int numberofpoints; /* In / out */
|
||||||
|
int numberofpointattributes; /* In / out */
|
||||||
|
|
||||||
|
int *trianglelist; /* In / out */
|
||||||
|
REAL *triangleattributelist; /* In / out */
|
||||||
|
REAL *trianglearealist; /* In only */
|
||||||
|
int *neighborlist; /* Out only */
|
||||||
|
int numberoftriangles; /* In / out */
|
||||||
|
int numberofcorners; /* In / out */
|
||||||
|
int numberoftriangleattributes; /* In / out */
|
||||||
|
|
||||||
|
int *segmentlist; /* In / out */
|
||||||
|
int *segmentmarkerlist; /* In / out */
|
||||||
|
int numberofsegments; /* In / out */
|
||||||
|
|
||||||
|
REAL *holelist; /* In / pointer to array copied out */
|
||||||
|
int numberofholes; /* In / copied out */
|
||||||
|
|
||||||
|
REAL *regionlist; /* In / pointer to array copied out */
|
||||||
|
int numberofregions; /* In / copied out */
|
||||||
|
|
||||||
|
int *edgelist; /* Out only */
|
||||||
|
int *edgemarkerlist; /* Not used with Voronoi diagram; out only */
|
||||||
|
REAL *normlist; /* Used only with Voronoi diagram; out only */
|
||||||
|
int numberofedges; /* Out only */
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef ANSI_DECLARATORS
|
||||||
|
void triangulate(char *, struct triangulateio *, struct triangulateio *,
|
||||||
|
struct triangulateio *);
|
||||||
|
#else /* not ANSI_DECLARATORS */
|
||||||
|
void triangulate();
|
||||||
|
#endif /* not ANSI_DECLARATORS */
|
19
src/Lib/poly2tri/Makefile.am
Normal file
19
src/Lib/poly2tri/Makefile.am
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
EXTRA_DIST = README makefile.orig data_1
|
||||||
|
|
||||||
|
# if OLD_AUTOMAKE
|
||||||
|
# CFLAGS += -DSTANDALONE
|
||||||
|
# else
|
||||||
|
# AM_CFLAGS = -DSTANDALONE
|
||||||
|
# endif
|
||||||
|
|
||||||
|
noinst_LIBRARIES = libpoly2tri.a
|
||||||
|
|
||||||
|
libpoly2tri_a_SOURCES = \
|
||||||
|
construct.c \
|
||||||
|
interface.h \
|
||||||
|
misc.c \
|
||||||
|
monotone.c \
|
||||||
|
tri.c \
|
||||||
|
triangulate.h
|
||||||
|
|
||||||
|
# INCLUDES += -I$(top_builddir) -I$(top_builddir)/Lib
|
96
src/Lib/poly2tri/README
Normal file
96
src/Lib/poly2tri/README
Normal file
|
@ -0,0 +1,96 @@
|
||||||
|
This program is an implementation of a fast polygon
|
||||||
|
triangulation algorithm based on the paper "A simple and fast
|
||||||
|
incremental randomized algorithm for computing trapezoidal
|
||||||
|
decompositions and for triangulating polygons" by Raimund Seidel.
|
||||||
|
|
||||||
|
(A copy of the implementation report is available as
|
||||||
|
http://www.cs.unc.edu/~manocha/CODE/GEM/chapter.html)
|
||||||
|
|
||||||
|
The algorithm handles simple polygons with holes. The input is
|
||||||
|
specified as contours. The outermost contour is anti-clockwise, while
|
||||||
|
all the inner contours must be clockwise. No point should be repeated
|
||||||
|
in the input. A sample input file 'data_1' is provided.
|
||||||
|
|
||||||
|
|
||||||
|
The output is a list of triangles. Each triangle gives a pair
|
||||||
|
(i, j, k) where i, j, and k are indices of the vertices specified in
|
||||||
|
the input array. (The index numbering starts from 1, since the first
|
||||||
|
location v[0] in the input array of vertices is unused). The number of
|
||||||
|
output triangles produced for a polygon with n points is,
|
||||||
|
(n - 2) + 2*(#holes)
|
||||||
|
|
||||||
|
|
||||||
|
The algorithm also generates a qyery structure which can be
|
||||||
|
used to answer point-location queries very fast.
|
||||||
|
|
||||||
|
int triangulate_polygon(...)
|
||||||
|
Time for triangulation: O(n log*n)
|
||||||
|
|
||||||
|
int is_point_inside_polygon(...)
|
||||||
|
Time for query : O(log n)
|
||||||
|
|
||||||
|
Both the routines are defined in 'tri.c'. See that file for
|
||||||
|
interfacing details. If not used stand_alone, include the header file
|
||||||
|
"interface.h" which contains the declarations for these
|
||||||
|
functions. Inclusion of "triangulation.h" is not necessary.
|
||||||
|
|
||||||
|
|
||||||
|
The implementation uses statically allocated arrays. Choose
|
||||||
|
appropriate value for SEGSIZE /* in triangulate.h */ depending on
|
||||||
|
input size.
|
||||||
|
|
||||||
|
|
||||||
|
There sould not be any compilation problem. If log2() is not
|
||||||
|
defined in your math library, you will have to supply the definition.
|
||||||
|
|
||||||
|
|
||||||
|
USAGE:
|
||||||
|
triangulate <filename> /* For standalone */
|
||||||
|
|
||||||
|
|
||||||
|
------------------------------------------------------------------
|
||||||
|
Bibliography:
|
||||||
|
|
||||||
|
|
||||||
|
@article{Sei91,
|
||||||
|
AUTHOR = "R. Seidel",
|
||||||
|
TITLE = "A simple and Fast Randomized Algorithm for Computing Trapezoidal Decompositions and for Triangulating Polygons",
|
||||||
|
JOURNAL = "Computational Geometry Theory \& Applications",
|
||||||
|
PAGES = "51-64",
|
||||||
|
NUMBER = 1,
|
||||||
|
YEAR = 1991,
|
||||||
|
VOLUME = 1 }
|
||||||
|
|
||||||
|
|
||||||
|
@book{o-cgc-94
|
||||||
|
, author = "J. O'Rourke"
|
||||||
|
, title = "Computational Geometry in {C}"
|
||||||
|
, publisher = "Cambridge University Press"
|
||||||
|
, year = 1994
|
||||||
|
, note = "ISBN 0-521-44592-2/Pb \$24.95,
|
||||||
|
ISBN 0-521-44034-3/Hc \$49.95.
|
||||||
|
Cambridge University Press
|
||||||
|
40 West 20th Street
|
||||||
|
New York, NY 10011-4211
|
||||||
|
1-800-872-7423
|
||||||
|
346+xi pages, 228 exercises, 200 figures, 219 references"
|
||||||
|
, update = "94.05 orourke, 94.01 orourke"
|
||||||
|
, annote = "Textbook"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Implementation report: Narkhede A. and Manocha D., Fast polygon
|
||||||
|
triangulation algorithm based on Seidel's Algorithm, UNC-CH, 1994.
|
||||||
|
|
||||||
|
-------------------------------------------------------------------
|
||||||
|
|
||||||
|
UNC-CH GIVES NO WARRANTY, EXPRESSED OR IMPLIED, FOR THE SOFTWARE
|
||||||
|
AND/OR DOCUMENTATION PROVIDED, INCLUDING, WITHOUT LIMITATION, WARRANTY
|
||||||
|
OF MERCHANTABILITY AND WARRANTY OF FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
|
||||||
|
This software is for non-commercial use only.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
- Atul Narkhede (narkhede@cs.unc.edu)
|
1055
src/Lib/poly2tri/construct.c
Normal file
1055
src/Lib/poly2tri/construct.c
Normal file
File diff suppressed because it is too large
Load diff
24
src/Lib/poly2tri/data_1
Normal file
24
src/Lib/poly2tri/data_1
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
4
|
||||||
|
|
||||||
|
4
|
||||||
|
0.0 0.0
|
||||||
|
6.0 0.0
|
||||||
|
6.0 6.0
|
||||||
|
0.0 6.0
|
||||||
|
|
||||||
|
3
|
||||||
|
0.5 1.0
|
||||||
|
1.0 2.0
|
||||||
|
2.0 1.5
|
||||||
|
|
||||||
|
3
|
||||||
|
0.5 4.0
|
||||||
|
1.0 5.0
|
||||||
|
2.0 4.5
|
||||||
|
|
||||||
|
3
|
||||||
|
3.0 3.0
|
||||||
|
5.0 3.5
|
||||||
|
5.0 2.5
|
||||||
|
|
||||||
|
|
18
src/Lib/poly2tri/interface.h
Normal file
18
src/Lib/poly2tri/interface.h
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
#ifndef __interface_h
|
||||||
|
#define __interface_h
|
||||||
|
|
||||||
|
#define TRUE 1
|
||||||
|
#define FALSE 0
|
||||||
|
|
||||||
|
#if defined ( __cplusplus )
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
extern int triangulate_polygon(int, int *, double (*)[2], int (*)[3]);
|
||||||
|
extern int is_point_inside_polygon(double *);
|
||||||
|
|
||||||
|
#if defined ( __cplusplus )
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* __interface_h */
|
157
src/Lib/poly2tri/misc.c
Normal file
157
src/Lib/poly2tri/misc.c
Normal file
|
@ -0,0 +1,157 @@
|
||||||
|
#include <triangulate.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
|
#ifdef __STDC__
|
||||||
|
extern double log2(double);
|
||||||
|
#else
|
||||||
|
extern double log2();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static int choose_idx;
|
||||||
|
static int permute[SEGSIZE];
|
||||||
|
|
||||||
|
|
||||||
|
/* Generate a random permutation of the segments 1..n */
|
||||||
|
int generate_random_ordering(n)
|
||||||
|
int n;
|
||||||
|
{
|
||||||
|
struct timeval tval;
|
||||||
|
struct timezone tzone;
|
||||||
|
register int i;
|
||||||
|
int m, st[SEGSIZE], *p;
|
||||||
|
|
||||||
|
choose_idx = 1;
|
||||||
|
gettimeofday(&tval, &tzone);
|
||||||
|
srand48(tval.tv_sec);
|
||||||
|
|
||||||
|
for (i = 0; i <= n; i++)
|
||||||
|
st[i] = i;
|
||||||
|
|
||||||
|
p = st;
|
||||||
|
for (i = 1; i <= n; i++, p++)
|
||||||
|
{
|
||||||
|
m = lrand48() % (n + 1 - i) + 1;
|
||||||
|
permute[i] = p[m];
|
||||||
|
if (m != 1)
|
||||||
|
p[m] = p[1];
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Return the next segment in the generated random ordering of all the */
|
||||||
|
/* segments in S */
|
||||||
|
int choose_segment()
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
fprintf(stderr, "choose_segment: %d\n", permute[choose_idx]);
|
||||||
|
#endif
|
||||||
|
return permute[choose_idx++];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef STANDALONE
|
||||||
|
|
||||||
|
/* Read in the list of vertices from infile */
|
||||||
|
int read_segments(filename, genus)
|
||||||
|
char *filename;
|
||||||
|
int *genus;
|
||||||
|
{
|
||||||
|
FILE *infile;
|
||||||
|
int ccount;
|
||||||
|
register int i;
|
||||||
|
int ncontours, npoints, first, last;
|
||||||
|
|
||||||
|
if ((infile = fopen(filename, "r")) == NULL)
|
||||||
|
{
|
||||||
|
perror(filename);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fscanf(infile, "%d", &ncontours);
|
||||||
|
if (ncontours <= 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
/* For every contour, read in all the points for the contour. The */
|
||||||
|
/* outer-most contour is read in first (points specified in */
|
||||||
|
/* anti-clockwise order). Next, the inner contours are input in */
|
||||||
|
/* clockwise order */
|
||||||
|
|
||||||
|
ccount = 0;
|
||||||
|
i = 1;
|
||||||
|
|
||||||
|
while (ccount < ncontours)
|
||||||
|
{
|
||||||
|
int j;
|
||||||
|
|
||||||
|
fscanf(infile, "%d", &npoints);
|
||||||
|
first = i;
|
||||||
|
last = first + npoints - 1;
|
||||||
|
for (j = 0; j < npoints; j++, i++)
|
||||||
|
{
|
||||||
|
fscanf(infile, "%lf%lf", &seg[i].v0.x, &seg[i].v0.y);
|
||||||
|
if (i == last)
|
||||||
|
{
|
||||||
|
seg[i].next = first;
|
||||||
|
seg[i].prev = i-1;
|
||||||
|
seg[i-1].v1 = seg[i].v0;
|
||||||
|
}
|
||||||
|
else if (i == first)
|
||||||
|
{
|
||||||
|
seg[i].next = i+1;
|
||||||
|
seg[i].prev = last;
|
||||||
|
seg[last].v1 = seg[i].v0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
seg[i].prev = i-1;
|
||||||
|
seg[i].next = i+1;
|
||||||
|
seg[i-1].v1 = seg[i].v0;
|
||||||
|
}
|
||||||
|
|
||||||
|
seg[i].is_inserted = FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
ccount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
*genus = ncontours - 1;
|
||||||
|
return i-1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/* Get log*n for given n */
|
||||||
|
int math_logstar_n(n)
|
||||||
|
int n;
|
||||||
|
{
|
||||||
|
register int i;
|
||||||
|
double v;
|
||||||
|
|
||||||
|
for (i = 0, v = (double) n; v >= 1; i++) {
|
||||||
|
/* v = log2(v); */
|
||||||
|
v = log(v) / log(2.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (i - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int math_N(n, h)
|
||||||
|
int n;
|
||||||
|
int h;
|
||||||
|
{
|
||||||
|
register int i;
|
||||||
|
double v;
|
||||||
|
|
||||||
|
for (i = 0, v = (int) n; i < h; i++) {
|
||||||
|
/* v = log2(v); */
|
||||||
|
v = log(v) / log(2.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (int) ceil((double) 1.0*n/v);
|
||||||
|
}
|
737
src/Lib/poly2tri/monotone.c
Normal file
737
src/Lib/poly2tri/monotone.c
Normal file
|
@ -0,0 +1,737 @@
|
||||||
|
#include <triangulate.h>
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
|
#define CROSS_SINE(v0, v1) ((v0).x * (v1).y - (v1).x * (v0).y)
|
||||||
|
#define LENGTH(v0) (sqrt((v0).x * (v0).x + (v0).y * (v0).y))
|
||||||
|
|
||||||
|
static monchain_t mchain[TRSIZE]; /* Table to hold all the monotone */
|
||||||
|
/* polygons . Each monotone polygon */
|
||||||
|
/* is a circularly linked list */
|
||||||
|
|
||||||
|
static vertexchain_t vert[SEGSIZE]; /* chain init. information. This */
|
||||||
|
/* is used to decide which */
|
||||||
|
/* monotone polygon to split if */
|
||||||
|
/* there are several other */
|
||||||
|
/* polygons touching at the same */
|
||||||
|
/* vertex */
|
||||||
|
|
||||||
|
static int mon[SEGSIZE]; /* contains position of any vertex in */
|
||||||
|
/* the monotone chain for the polygon */
|
||||||
|
static int visited[TRSIZE];
|
||||||
|
static int chain_idx, op_idx, mon_idx;
|
||||||
|
|
||||||
|
|
||||||
|
static int triangulate_single_polygon(int, int, int, int (*)[3]);
|
||||||
|
static int traverse_polygon(int, int, int, int);
|
||||||
|
|
||||||
|
/* Function returns TRUE if the trapezoid lies inside the polygon */
|
||||||
|
static int inside_polygon(t)
|
||||||
|
trap_t *t;
|
||||||
|
{
|
||||||
|
int rseg = t->rseg;
|
||||||
|
|
||||||
|
if (t->state == ST_INVALID)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if ((t->lseg <= 0) || (t->rseg <= 0))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (((t->u0 <= 0) && (t->u1 <= 0)) ||
|
||||||
|
((t->d0 <= 0) && (t->d1 <= 0))) /* triangle */
|
||||||
|
return (_greater_than(&seg[rseg].v1, &seg[rseg].v0));
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* return a new mon structure from the table */
|
||||||
|
static int newmon()
|
||||||
|
{
|
||||||
|
return ++mon_idx;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* return a new chain element from the table */
|
||||||
|
static int new_chain_element()
|
||||||
|
{
|
||||||
|
return ++chain_idx;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static double get_angle(vp0, vpnext, vp1)
|
||||||
|
point_t *vp0;
|
||||||
|
point_t *vpnext;
|
||||||
|
point_t *vp1;
|
||||||
|
{
|
||||||
|
point_t v0, v1;
|
||||||
|
|
||||||
|
v0.x = vpnext->x - vp0->x;
|
||||||
|
v0.y = vpnext->y - vp0->y;
|
||||||
|
|
||||||
|
v1.x = vp1->x - vp0->x;
|
||||||
|
v1.y = vp1->y - vp0->y;
|
||||||
|
|
||||||
|
if (CROSS_SINE(v0, v1) >= 0) /* sine is positive */
|
||||||
|
return DOT(v0, v1)/LENGTH(v0)/LENGTH(v1);
|
||||||
|
else
|
||||||
|
return (-1.0 * DOT(v0, v1)/LENGTH(v0)/LENGTH(v1) - 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* (v0, v1) is the new diagonal to be added to the polygon. Find which */
|
||||||
|
/* chain to use and return the positions of v0 and v1 in p and q */
|
||||||
|
static int get_vertex_positions(v0, v1, ip, iq)
|
||||||
|
int v0;
|
||||||
|
int v1;
|
||||||
|
int *ip;
|
||||||
|
int *iq;
|
||||||
|
{
|
||||||
|
vertexchain_t *vp0, *vp1;
|
||||||
|
register int i;
|
||||||
|
double angle, temp;
|
||||||
|
int tp, tq;
|
||||||
|
|
||||||
|
vp0 = &vert[v0];
|
||||||
|
vp1 = &vert[v1];
|
||||||
|
|
||||||
|
/* p is identified as follows. Scan from (v0, v1) rightwards till */
|
||||||
|
/* you hit the first segment starting from v0. That chain is the */
|
||||||
|
/* chain of our interest */
|
||||||
|
|
||||||
|
angle = -4.0;
|
||||||
|
for (i = 0; i < 4; i++)
|
||||||
|
{
|
||||||
|
if (vp0->vnext[i] <= 0)
|
||||||
|
continue;
|
||||||
|
if ((temp = get_angle(&vp0->pt, &(vert[vp0->vnext[i]].pt),
|
||||||
|
&vp1->pt)) > angle)
|
||||||
|
{
|
||||||
|
angle = temp;
|
||||||
|
tp = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*ip = tp;
|
||||||
|
|
||||||
|
/* Do similar actions for q */
|
||||||
|
|
||||||
|
angle = -4.0;
|
||||||
|
for (i = 0; i < 4; i++)
|
||||||
|
{
|
||||||
|
if (vp1->vnext[i] <= 0)
|
||||||
|
continue;
|
||||||
|
if ((temp = get_angle(&vp1->pt, &(vert[vp1->vnext[i]].pt),
|
||||||
|
&vp0->pt)) > angle)
|
||||||
|
{
|
||||||
|
angle = temp;
|
||||||
|
tq = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*iq = tq;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* v0 and v1 are specified in anti-clockwise order with respect to
|
||||||
|
* the current monotone polygon mcur. Split the current polygon into
|
||||||
|
* two polygons using the diagonal (v0, v1)
|
||||||
|
*/
|
||||||
|
static int make_new_monotone_poly(mcur, v0, v1)
|
||||||
|
int mcur;
|
||||||
|
int v0;
|
||||||
|
int v1;
|
||||||
|
{
|
||||||
|
int p, q, ip, iq;
|
||||||
|
int mnew = newmon();
|
||||||
|
int i, j, nf0, nf1;
|
||||||
|
vertexchain_t *vp0, *vp1;
|
||||||
|
|
||||||
|
vp0 = &vert[v0];
|
||||||
|
vp1 = &vert[v1];
|
||||||
|
|
||||||
|
get_vertex_positions(v0, v1, &ip, &iq);
|
||||||
|
|
||||||
|
p = vp0->vpos[ip];
|
||||||
|
q = vp1->vpos[iq];
|
||||||
|
|
||||||
|
/* At this stage, we have got the positions of v0 and v1 in the */
|
||||||
|
/* desired chain. Now modify the linked lists */
|
||||||
|
|
||||||
|
i = new_chain_element(); /* for the new list */
|
||||||
|
j = new_chain_element();
|
||||||
|
|
||||||
|
mchain[i].vnum = v0;
|
||||||
|
mchain[j].vnum = v1;
|
||||||
|
|
||||||
|
mchain[i].next = mchain[p].next;
|
||||||
|
mchain[mchain[p].next].prev = i;
|
||||||
|
mchain[i].prev = j;
|
||||||
|
mchain[j].next = i;
|
||||||
|
mchain[j].prev = mchain[q].prev;
|
||||||
|
mchain[mchain[q].prev].next = j;
|
||||||
|
|
||||||
|
mchain[p].next = q;
|
||||||
|
mchain[q].prev = p;
|
||||||
|
|
||||||
|
nf0 = vp0->nextfree;
|
||||||
|
nf1 = vp1->nextfree;
|
||||||
|
|
||||||
|
vp0->vnext[ip] = v1;
|
||||||
|
|
||||||
|
vp0->vpos[nf0] = i;
|
||||||
|
vp0->vnext[nf0] = mchain[mchain[i].next].vnum;
|
||||||
|
vp1->vpos[nf1] = j;
|
||||||
|
vp1->vnext[nf1] = v0;
|
||||||
|
|
||||||
|
vp0->nextfree++;
|
||||||
|
vp1->nextfree++;
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
fprintf(stderr, "make_poly: mcur = %d, (v0, v1) = (%d, %d)\n",
|
||||||
|
mcur, v0, v1);
|
||||||
|
fprintf(stderr, "next posns = (p, q) = (%d, %d)\n", p, q);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
mon[mcur] = p;
|
||||||
|
mon[mnew] = i;
|
||||||
|
return mnew;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Main routine to get monotone polygons from the trapezoidation of
|
||||||
|
* the polygon.
|
||||||
|
*/
|
||||||
|
|
||||||
|
int monotonate_trapezoids(n)
|
||||||
|
int n;
|
||||||
|
{
|
||||||
|
register int i;
|
||||||
|
int tr_start;
|
||||||
|
|
||||||
|
memset((void *)vert, 0, sizeof(vert));
|
||||||
|
memset((void *)visited, 0, sizeof(visited));
|
||||||
|
memset((void *)mchain, 0, sizeof(mchain));
|
||||||
|
memset((void *)mon, 0, sizeof(mon));
|
||||||
|
|
||||||
|
/* First locate a trapezoid which lies inside the polygon */
|
||||||
|
/* and which is triangular */
|
||||||
|
for (i = 0; i < TRSIZE; i++)
|
||||||
|
if (inside_polygon(&tr[i]))
|
||||||
|
break;
|
||||||
|
tr_start = i;
|
||||||
|
|
||||||
|
/* Initialise the mon data-structure and start spanning all the */
|
||||||
|
/* trapezoids within the polygon */
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
for (i = 1; i <= n; i++)
|
||||||
|
{
|
||||||
|
mchain[i].prev = i - 1;
|
||||||
|
mchain[i].next = i + 1;
|
||||||
|
mchain[i].vnum = i;
|
||||||
|
vert[i].pt = seg[i].v0;
|
||||||
|
vert[i].vnext[0] = i + 1; /* next vertex */
|
||||||
|
vert[i].vpos[0] = i; /* locn. of next vertex */
|
||||||
|
vert[i].nextfree = 1;
|
||||||
|
}
|
||||||
|
mchain[1].prev = n;
|
||||||
|
mchain[n].next = 1;
|
||||||
|
vert[n].vnext[0] = 1;
|
||||||
|
vert[n].vpos[0] = n;
|
||||||
|
chain_idx = n;
|
||||||
|
mon_idx = 0;
|
||||||
|
mon[0] = 1; /* position of any vertex in the first */
|
||||||
|
/* chain */
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
for (i = 1; i <= n; i++)
|
||||||
|
{
|
||||||
|
mchain[i].prev = seg[i].prev;
|
||||||
|
mchain[i].next = seg[i].next;
|
||||||
|
mchain[i].vnum = i;
|
||||||
|
vert[i].pt = seg[i].v0;
|
||||||
|
vert[i].vnext[0] = seg[i].next; /* next vertex */
|
||||||
|
vert[i].vpos[0] = i; /* locn. of next vertex */
|
||||||
|
vert[i].nextfree = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
chain_idx = n;
|
||||||
|
mon_idx = 0;
|
||||||
|
mon[0] = 1; /* position of any vertex in the first */
|
||||||
|
/* chain */
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* traverse the polygon */
|
||||||
|
if (tr[tr_start].u0 > 0)
|
||||||
|
traverse_polygon(0, tr_start, tr[tr_start].u0, TR_FROM_UP);
|
||||||
|
else if (tr[tr_start].d0 > 0)
|
||||||
|
traverse_polygon(0, tr_start, tr[tr_start].d0, TR_FROM_DN);
|
||||||
|
|
||||||
|
/* return the number of polygons created */
|
||||||
|
return newmon();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* recursively visit all the trapezoids */
|
||||||
|
static int traverse_polygon(mcur, trnum, from, dir)
|
||||||
|
int mcur;
|
||||||
|
int trnum;
|
||||||
|
int from;
|
||||||
|
int dir;
|
||||||
|
{
|
||||||
|
trap_t *t = &tr[trnum];
|
||||||
|
int howsplit, mnew;
|
||||||
|
int v0, v1, v0next, v1next;
|
||||||
|
int retval, tmp;
|
||||||
|
int do_switch = FALSE;
|
||||||
|
|
||||||
|
if ((trnum <= 0) || visited[trnum])
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
visited[trnum] = TRUE;
|
||||||
|
|
||||||
|
/* We have much more information available here. */
|
||||||
|
/* rseg: goes upwards */
|
||||||
|
/* lseg: goes downwards */
|
||||||
|
|
||||||
|
/* Initially assume that dir = TR_FROM_DN (from the left) */
|
||||||
|
/* Switch v0 and v1 if necessary afterwards */
|
||||||
|
|
||||||
|
|
||||||
|
/* special cases for triangles with cusps at the opposite ends. */
|
||||||
|
/* take care of this first */
|
||||||
|
if ((t->u0 <= 0) && (t->u1 <= 0))
|
||||||
|
{
|
||||||
|
if ((t->d0 > 0) && (t->d1 > 0)) /* downward opening triangle */
|
||||||
|
{
|
||||||
|
v0 = tr[t->d1].lseg;
|
||||||
|
v1 = t->lseg;
|
||||||
|
if (from == t->d1)
|
||||||
|
{
|
||||||
|
do_switch = TRUE;
|
||||||
|
mnew = make_new_monotone_poly(mcur, v1, v0);
|
||||||
|
traverse_polygon(mcur, t->d1, trnum, TR_FROM_UP);
|
||||||
|
traverse_polygon(mnew, t->d0, trnum, TR_FROM_UP);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mnew = make_new_monotone_poly(mcur, v0, v1);
|
||||||
|
traverse_polygon(mcur, t->d0, trnum, TR_FROM_UP);
|
||||||
|
traverse_polygon(mnew, t->d1, trnum, TR_FROM_UP);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
retval = SP_NOSPLIT; /* Just traverse all neighbours */
|
||||||
|
traverse_polygon(mcur, t->u0, trnum, TR_FROM_DN);
|
||||||
|
traverse_polygon(mcur, t->u1, trnum, TR_FROM_DN);
|
||||||
|
traverse_polygon(mcur, t->d0, trnum, TR_FROM_UP);
|
||||||
|
traverse_polygon(mcur, t->d1, trnum, TR_FROM_UP);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
else if ((t->d0 <= 0) && (t->d1 <= 0))
|
||||||
|
{
|
||||||
|
if ((t->u0 > 0) && (t->u1 > 0)) /* upward opening triangle */
|
||||||
|
{
|
||||||
|
v0 = t->rseg;
|
||||||
|
v1 = tr[t->u0].rseg;
|
||||||
|
if (from == t->u1)
|
||||||
|
{
|
||||||
|
do_switch = TRUE;
|
||||||
|
mnew = make_new_monotone_poly(mcur, v1, v0);
|
||||||
|
traverse_polygon(mcur, t->u1, trnum, TR_FROM_DN);
|
||||||
|
traverse_polygon(mnew, t->u0, trnum, TR_FROM_DN);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mnew = make_new_monotone_poly(mcur, v0, v1);
|
||||||
|
traverse_polygon(mcur, t->u0, trnum, TR_FROM_DN);
|
||||||
|
traverse_polygon(mnew, t->u1, trnum, TR_FROM_DN);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
retval = SP_NOSPLIT; /* Just traverse all neighbours */
|
||||||
|
traverse_polygon(mcur, t->u0, trnum, TR_FROM_DN);
|
||||||
|
traverse_polygon(mcur, t->u1, trnum, TR_FROM_DN);
|
||||||
|
traverse_polygon(mcur, t->d0, trnum, TR_FROM_UP);
|
||||||
|
traverse_polygon(mcur, t->d1, trnum, TR_FROM_UP);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
else if ((t->u0 > 0) && (t->u1 > 0))
|
||||||
|
{
|
||||||
|
if ((t->d0 > 0) && (t->d1 > 0)) /* downward + upward cusps */
|
||||||
|
{
|
||||||
|
v0 = tr[t->d1].lseg;
|
||||||
|
v1 = tr[t->u0].rseg;
|
||||||
|
retval = SP_2UP_2DN;
|
||||||
|
if (((dir == TR_FROM_DN) && (t->d1 == from)) ||
|
||||||
|
((dir == TR_FROM_UP) && (t->u1 == from)))
|
||||||
|
{
|
||||||
|
do_switch = TRUE;
|
||||||
|
mnew = make_new_monotone_poly(mcur, v1, v0);
|
||||||
|
traverse_polygon(mcur, t->u1, trnum, TR_FROM_DN);
|
||||||
|
traverse_polygon(mcur, t->d1, trnum, TR_FROM_UP);
|
||||||
|
traverse_polygon(mnew, t->u0, trnum, TR_FROM_DN);
|
||||||
|
traverse_polygon(mnew, t->d0, trnum, TR_FROM_UP);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mnew = make_new_monotone_poly(mcur, v0, v1);
|
||||||
|
traverse_polygon(mcur, t->u0, trnum, TR_FROM_DN);
|
||||||
|
traverse_polygon(mcur, t->d0, trnum, TR_FROM_UP);
|
||||||
|
traverse_polygon(mnew, t->u1, trnum, TR_FROM_DN);
|
||||||
|
traverse_polygon(mnew, t->d1, trnum, TR_FROM_UP);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else /* only downward cusp */
|
||||||
|
{
|
||||||
|
if (_equal_to(&t->lo, &seg[t->lseg].v1))
|
||||||
|
{
|
||||||
|
v0 = tr[t->u0].rseg;
|
||||||
|
v1 = seg[t->lseg].next;
|
||||||
|
|
||||||
|
retval = SP_2UP_LEFT;
|
||||||
|
if ((dir == TR_FROM_UP) && (t->u0 == from))
|
||||||
|
{
|
||||||
|
do_switch = TRUE;
|
||||||
|
mnew = make_new_monotone_poly(mcur, v1, v0);
|
||||||
|
traverse_polygon(mcur, t->u0, trnum, TR_FROM_DN);
|
||||||
|
traverse_polygon(mnew, t->d0, trnum, TR_FROM_UP);
|
||||||
|
traverse_polygon(mnew, t->u1, trnum, TR_FROM_DN);
|
||||||
|
traverse_polygon(mnew, t->d1, trnum, TR_FROM_UP);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mnew = make_new_monotone_poly(mcur, v0, v1);
|
||||||
|
traverse_polygon(mcur, t->u1, trnum, TR_FROM_DN);
|
||||||
|
traverse_polygon(mcur, t->d0, trnum, TR_FROM_UP);
|
||||||
|
traverse_polygon(mcur, t->d1, trnum, TR_FROM_UP);
|
||||||
|
traverse_polygon(mnew, t->u0, trnum, TR_FROM_DN);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
v0 = t->rseg;
|
||||||
|
v1 = tr[t->u0].rseg;
|
||||||
|
retval = SP_2UP_RIGHT;
|
||||||
|
if ((dir == TR_FROM_UP) && (t->u1 == from))
|
||||||
|
{
|
||||||
|
do_switch = TRUE;
|
||||||
|
mnew = make_new_monotone_poly(mcur, v1, v0);
|
||||||
|
traverse_polygon(mcur, t->u1, trnum, TR_FROM_DN);
|
||||||
|
traverse_polygon(mnew, t->d1, trnum, TR_FROM_UP);
|
||||||
|
traverse_polygon(mnew, t->d0, trnum, TR_FROM_UP);
|
||||||
|
traverse_polygon(mnew, t->u0, trnum, TR_FROM_DN);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mnew = make_new_monotone_poly(mcur, v0, v1);
|
||||||
|
traverse_polygon(mcur, t->u0, trnum, TR_FROM_DN);
|
||||||
|
traverse_polygon(mcur, t->d0, trnum, TR_FROM_UP);
|
||||||
|
traverse_polygon(mcur, t->d1, trnum, TR_FROM_UP);
|
||||||
|
traverse_polygon(mnew, t->u1, trnum, TR_FROM_DN);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ((t->u0 > 0) || (t->u1 > 0)) /* no downward cusp */
|
||||||
|
{
|
||||||
|
if ((t->d0 > 0) && (t->d1 > 0)) /* only upward cusp */
|
||||||
|
{
|
||||||
|
if (_equal_to(&t->hi, &seg[t->lseg].v0))
|
||||||
|
{
|
||||||
|
v0 = tr[t->d1].lseg;
|
||||||
|
v1 = t->lseg;
|
||||||
|
retval = SP_2DN_LEFT;
|
||||||
|
if (!((dir == TR_FROM_DN) && (t->d0 == from)))
|
||||||
|
{
|
||||||
|
do_switch = TRUE;
|
||||||
|
mnew = make_new_monotone_poly(mcur, v1, v0);
|
||||||
|
traverse_polygon(mcur, t->u1, trnum, TR_FROM_DN);
|
||||||
|
traverse_polygon(mcur, t->d1, trnum, TR_FROM_UP);
|
||||||
|
traverse_polygon(mcur, t->u0, trnum, TR_FROM_DN);
|
||||||
|
traverse_polygon(mnew, t->d0, trnum, TR_FROM_UP);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mnew = make_new_monotone_poly(mcur, v0, v1);
|
||||||
|
traverse_polygon(mcur, t->d0, trnum, TR_FROM_UP);
|
||||||
|
traverse_polygon(mnew, t->u0, trnum, TR_FROM_DN);
|
||||||
|
traverse_polygon(mnew, t->u1, trnum, TR_FROM_DN);
|
||||||
|
traverse_polygon(mnew, t->d1, trnum, TR_FROM_UP);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
v0 = tr[t->d1].lseg;
|
||||||
|
v1 = seg[t->rseg].next;
|
||||||
|
|
||||||
|
retval = SP_2DN_RIGHT;
|
||||||
|
if ((dir == TR_FROM_DN) && (t->d1 == from))
|
||||||
|
{
|
||||||
|
do_switch = TRUE;
|
||||||
|
mnew = make_new_monotone_poly(mcur, v1, v0);
|
||||||
|
traverse_polygon(mcur, t->d1, trnum, TR_FROM_UP);
|
||||||
|
traverse_polygon(mnew, t->u1, trnum, TR_FROM_DN);
|
||||||
|
traverse_polygon(mnew, t->u0, trnum, TR_FROM_DN);
|
||||||
|
traverse_polygon(mnew, t->d0, trnum, TR_FROM_UP);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mnew = make_new_monotone_poly(mcur, v0, v1);
|
||||||
|
traverse_polygon(mcur, t->u0, trnum, TR_FROM_DN);
|
||||||
|
traverse_polygon(mcur, t->d0, trnum, TR_FROM_UP);
|
||||||
|
traverse_polygon(mcur, t->u1, trnum, TR_FROM_DN);
|
||||||
|
traverse_polygon(mnew, t->d1, trnum, TR_FROM_UP);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else /* no cusp */
|
||||||
|
{
|
||||||
|
if (_equal_to(&t->hi, &seg[t->lseg].v0) &&
|
||||||
|
_equal_to(&t->lo, &seg[t->rseg].v0))
|
||||||
|
{
|
||||||
|
v0 = t->rseg;
|
||||||
|
v1 = t->lseg;
|
||||||
|
retval = SP_SIMPLE_LRDN;
|
||||||
|
if (dir == TR_FROM_UP)
|
||||||
|
{
|
||||||
|
do_switch = TRUE;
|
||||||
|
mnew = make_new_monotone_poly(mcur, v1, v0);
|
||||||
|
traverse_polygon(mcur, t->u0, trnum, TR_FROM_DN);
|
||||||
|
traverse_polygon(mcur, t->u1, trnum, TR_FROM_DN);
|
||||||
|
traverse_polygon(mnew, t->d1, trnum, TR_FROM_UP);
|
||||||
|
traverse_polygon(mnew, t->d0, trnum, TR_FROM_UP);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mnew = make_new_monotone_poly(mcur, v0, v1);
|
||||||
|
traverse_polygon(mcur, t->d1, trnum, TR_FROM_UP);
|
||||||
|
traverse_polygon(mcur, t->d0, trnum, TR_FROM_UP);
|
||||||
|
traverse_polygon(mnew, t->u0, trnum, TR_FROM_DN);
|
||||||
|
traverse_polygon(mnew, t->u1, trnum, TR_FROM_DN);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (_equal_to(&t->hi, &seg[t->rseg].v1) &&
|
||||||
|
_equal_to(&t->lo, &seg[t->lseg].v1))
|
||||||
|
{
|
||||||
|
v0 = seg[t->rseg].next;
|
||||||
|
v1 = seg[t->lseg].next;
|
||||||
|
|
||||||
|
retval = SP_SIMPLE_LRUP;
|
||||||
|
if (dir == TR_FROM_UP)
|
||||||
|
{
|
||||||
|
do_switch = TRUE;
|
||||||
|
mnew = make_new_monotone_poly(mcur, v1, v0);
|
||||||
|
traverse_polygon(mcur, t->u0, trnum, TR_FROM_DN);
|
||||||
|
traverse_polygon(mcur, t->u1, trnum, TR_FROM_DN);
|
||||||
|
traverse_polygon(mnew, t->d1, trnum, TR_FROM_UP);
|
||||||
|
traverse_polygon(mnew, t->d0, trnum, TR_FROM_UP);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mnew = make_new_monotone_poly(mcur, v0, v1);
|
||||||
|
traverse_polygon(mcur, t->d1, trnum, TR_FROM_UP);
|
||||||
|
traverse_polygon(mcur, t->d0, trnum, TR_FROM_UP);
|
||||||
|
traverse_polygon(mnew, t->u0, trnum, TR_FROM_DN);
|
||||||
|
traverse_polygon(mnew, t->u1, trnum, TR_FROM_DN);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else /* no split possible */
|
||||||
|
{
|
||||||
|
retval = SP_NOSPLIT;
|
||||||
|
traverse_polygon(mcur, t->u0, trnum, TR_FROM_DN);
|
||||||
|
traverse_polygon(mcur, t->d0, trnum, TR_FROM_UP);
|
||||||
|
traverse_polygon(mcur, t->u1, trnum, TR_FROM_DN);
|
||||||
|
traverse_polygon(mcur, t->d1, trnum, TR_FROM_UP);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* For each monotone polygon, find the ymax and ymin (to determine the */
|
||||||
|
/* two y-monotone chains) and pass on this monotone polygon for greedy */
|
||||||
|
/* triangulation. */
|
||||||
|
/* Take care not to triangulate duplicate monotone polygons */
|
||||||
|
|
||||||
|
int triangulate_monotone_polygons(nvert, nmonpoly, op)
|
||||||
|
int nvert;
|
||||||
|
int nmonpoly;
|
||||||
|
int op[][3];
|
||||||
|
{
|
||||||
|
register int i;
|
||||||
|
point_t ymax, ymin;
|
||||||
|
int p, vfirst, posmax, posmin, v;
|
||||||
|
int vcount, processed;
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
for (i = 0; i < nmonpoly; i++)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "\n\nPolygon %d: ", i);
|
||||||
|
vfirst = mchain[mon[i]].vnum;
|
||||||
|
p = mchain[mon[i]].next;
|
||||||
|
fprintf (stderr, "%d ", mchain[mon[i]].vnum);
|
||||||
|
while (mchain[p].vnum != vfirst)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "%d ", mchain[p].vnum);
|
||||||
|
p = mchain[p].next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fprintf(stderr, "\n");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
op_idx = 0;
|
||||||
|
for (i = 0; i < nmonpoly; i++)
|
||||||
|
{
|
||||||
|
vcount = 1;
|
||||||
|
processed = FALSE;
|
||||||
|
vfirst = mchain[mon[i]].vnum;
|
||||||
|
ymax = ymin = vert[vfirst].pt;
|
||||||
|
posmax = posmin = mon[i];
|
||||||
|
mchain[mon[i]].marked = TRUE;
|
||||||
|
p = mchain[mon[i]].next;
|
||||||
|
while ((v = mchain[p].vnum) != vfirst)
|
||||||
|
{
|
||||||
|
if (mchain[p].marked)
|
||||||
|
{
|
||||||
|
processed = TRUE;
|
||||||
|
break; /* break from while */
|
||||||
|
}
|
||||||
|
else
|
||||||
|
mchain[p].marked = TRUE;
|
||||||
|
|
||||||
|
if (_greater_than(&vert[v].pt, &ymax))
|
||||||
|
{
|
||||||
|
ymax = vert[v].pt;
|
||||||
|
posmax = p;
|
||||||
|
}
|
||||||
|
if (_less_than(&vert[v].pt, &ymin))
|
||||||
|
{
|
||||||
|
ymin = vert[v].pt;
|
||||||
|
posmin = p;
|
||||||
|
}
|
||||||
|
p = mchain[p].next;
|
||||||
|
vcount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (processed) /* Go to next polygon */
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (vcount == 3) /* already a triangle */
|
||||||
|
{
|
||||||
|
op[op_idx][0] = mchain[p].vnum;
|
||||||
|
op[op_idx][1] = mchain[mchain[p].next].vnum;
|
||||||
|
op[op_idx][2] = mchain[mchain[p].prev].vnum;
|
||||||
|
op_idx++;
|
||||||
|
}
|
||||||
|
else /* triangulate the polygon */
|
||||||
|
{
|
||||||
|
v = mchain[mchain[posmax].next].vnum;
|
||||||
|
if (_equal_to(&vert[v].pt, &ymin))
|
||||||
|
{ /* LHS is a single line */
|
||||||
|
triangulate_single_polygon(nvert, posmax, TRI_LHS, op);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
triangulate_single_polygon(nvert, posmax, TRI_RHS, op);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
for (i = 0; i < op_idx; i++)
|
||||||
|
fprintf(stderr, "tri #%d: (%d, %d, %d)\n", i, op[i][0], op[i][1],
|
||||||
|
op[i][2]);
|
||||||
|
#endif
|
||||||
|
return op_idx;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* A greedy corner-cutting algorithm to triangulate a y-monotone
|
||||||
|
* polygon in O(n) time.
|
||||||
|
* Joseph O-Rourke, Computational Geometry in C.
|
||||||
|
*/
|
||||||
|
static int triangulate_single_polygon(nvert, posmax, side, op)
|
||||||
|
int nvert;
|
||||||
|
int posmax;
|
||||||
|
int side;
|
||||||
|
int op[][3];
|
||||||
|
{
|
||||||
|
register int v;
|
||||||
|
int rc[SEGSIZE], ri = 0; /* reflex chain */
|
||||||
|
int endv, tmp, vpos;
|
||||||
|
|
||||||
|
if (side == TRI_RHS) /* RHS segment is a single segment */
|
||||||
|
{
|
||||||
|
rc[0] = mchain[posmax].vnum;
|
||||||
|
tmp = mchain[posmax].next;
|
||||||
|
rc[1] = mchain[tmp].vnum;
|
||||||
|
ri = 1;
|
||||||
|
|
||||||
|
vpos = mchain[tmp].next;
|
||||||
|
v = mchain[vpos].vnum;
|
||||||
|
|
||||||
|
if ((endv = mchain[mchain[posmax].prev].vnum) == 0)
|
||||||
|
endv = nvert;
|
||||||
|
}
|
||||||
|
else /* LHS is a single segment */
|
||||||
|
{
|
||||||
|
tmp = mchain[posmax].next;
|
||||||
|
rc[0] = mchain[tmp].vnum;
|
||||||
|
tmp = mchain[tmp].next;
|
||||||
|
rc[1] = mchain[tmp].vnum;
|
||||||
|
ri = 1;
|
||||||
|
|
||||||
|
vpos = mchain[tmp].next;
|
||||||
|
v = mchain[vpos].vnum;
|
||||||
|
|
||||||
|
endv = mchain[posmax].vnum;
|
||||||
|
}
|
||||||
|
|
||||||
|
while ((v != endv) || (ri > 1))
|
||||||
|
{
|
||||||
|
if (ri > 0) /* reflex chain is non-empty */
|
||||||
|
{
|
||||||
|
if (CROSS(vert[v].pt, vert[rc[ri - 1]].pt,
|
||||||
|
vert[rc[ri]].pt) > 0)
|
||||||
|
{ /* convex corner: cut if off */
|
||||||
|
op[op_idx][0] = rc[ri - 1];
|
||||||
|
op[op_idx][1] = rc[ri];
|
||||||
|
op[op_idx][2] = v;
|
||||||
|
op_idx++;
|
||||||
|
ri--;
|
||||||
|
}
|
||||||
|
else /* non-convex */
|
||||||
|
{ /* add v to the chain */
|
||||||
|
ri++;
|
||||||
|
rc[ri] = v;
|
||||||
|
vpos = mchain[vpos].next;
|
||||||
|
v = mchain[vpos].vnum;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else /* reflex-chain empty: add v to the */
|
||||||
|
{ /* reflex chain and advance it */
|
||||||
|
rc[++ri] = v;
|
||||||
|
vpos = mchain[vpos].next;
|
||||||
|
v = mchain[vpos].vnum;
|
||||||
|
}
|
||||||
|
} /* end-while */
|
||||||
|
|
||||||
|
/* reached the bottom vertex. Add in the triangle formed */
|
||||||
|
op[op_idx][0] = rc[ri - 1];
|
||||||
|
op[op_idx][1] = rc[ri];
|
||||||
|
op[op_idx][2] = v;
|
||||||
|
op_idx++;
|
||||||
|
ri--;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
167
src/Lib/poly2tri/tri.c
Normal file
167
src/Lib/poly2tri/tri.c
Normal file
|
@ -0,0 +1,167 @@
|
||||||
|
#include <triangulate.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
|
||||||
|
|
||||||
|
static int initialise(n)
|
||||||
|
int n;
|
||||||
|
{
|
||||||
|
register int i;
|
||||||
|
|
||||||
|
for (i = 1; i <= n; i++)
|
||||||
|
seg[i].is_inserted = FALSE;
|
||||||
|
|
||||||
|
generate_random_ordering(n);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef STANDALONE
|
||||||
|
|
||||||
|
int main(argc, argv)
|
||||||
|
int argc;
|
||||||
|
char *argv[];
|
||||||
|
{
|
||||||
|
int n, nmonpoly, genus;
|
||||||
|
int op[SEGSIZE][3], i, ntriangles;
|
||||||
|
|
||||||
|
if ((argc < 2) || ((n = read_segments(argv[1], &genus)) < 0))
|
||||||
|
{
|
||||||
|
fprintf(stderr, "usage: triangulate <filename>\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
initialise(n);
|
||||||
|
construct_trapezoids(n);
|
||||||
|
nmonpoly = monotonate_trapezoids(n);
|
||||||
|
ntriangles = triangulate_monotone_polygons(n, nmonpoly, op);
|
||||||
|
|
||||||
|
for (i = 0; i < ntriangles; i++)
|
||||||
|
printf("triangle #%d: %d %d %d\n", i,
|
||||||
|
op[i][0], op[i][1], op[i][2]);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#else /* Not standalone. Use this as an interface routine */
|
||||||
|
|
||||||
|
|
||||||
|
/* Input specified as contours.
|
||||||
|
* Outer contour must be anti-clockwise.
|
||||||
|
* All inner contours must be clockwise.
|
||||||
|
*
|
||||||
|
* Every contour is specified by giving all its points in order. No
|
||||||
|
* point shoud be repeated. i.e. if the outer contour is a square,
|
||||||
|
* only the four distinct endpoints shopudl be specified in order.
|
||||||
|
*
|
||||||
|
* ncontours: #contours
|
||||||
|
* cntr: An array describing the number of points in each
|
||||||
|
* contour. Thus, cntr[i] = #points in the i'th contour.
|
||||||
|
* vertices: Input array of vertices. Vertices for each contour
|
||||||
|
* immediately follow those for previous one. Array location
|
||||||
|
* vertices[0] must NOT be used (i.e. i/p starts from
|
||||||
|
* vertices[1] instead. The output triangles are
|
||||||
|
* specified w.r.t. the indices of these vertices.
|
||||||
|
* triangles: Output array to hold triangles.
|
||||||
|
*
|
||||||
|
* Enough space must be allocated for all the arrays before calling
|
||||||
|
* this routine
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
int triangulate_polygon(ncontours, cntr, vertices, triangles)
|
||||||
|
int ncontours;
|
||||||
|
int cntr[];
|
||||||
|
double (*vertices)[2];
|
||||||
|
int (*triangles)[3];
|
||||||
|
{
|
||||||
|
register int i;
|
||||||
|
int nmonpoly, ccount, npoints, genus;
|
||||||
|
int n, ntriangles;
|
||||||
|
|
||||||
|
memset((void *)seg, 0, sizeof(seg));
|
||||||
|
ccount = 0;
|
||||||
|
i = 1;
|
||||||
|
|
||||||
|
while (ccount < ncontours)
|
||||||
|
{
|
||||||
|
int j;
|
||||||
|
int first, last;
|
||||||
|
|
||||||
|
npoints = cntr[ccount];
|
||||||
|
first = i;
|
||||||
|
last = first + npoints - 1;
|
||||||
|
for (j = 0; j < npoints; j++, i++)
|
||||||
|
{
|
||||||
|
seg[i].v0.x = vertices[i][0];
|
||||||
|
seg[i].v0.y = vertices[i][1];
|
||||||
|
|
||||||
|
if (i == last)
|
||||||
|
{
|
||||||
|
seg[i].next = first;
|
||||||
|
seg[i].prev = i-1;
|
||||||
|
seg[i-1].v1 = seg[i].v0;
|
||||||
|
}
|
||||||
|
else if (i == first)
|
||||||
|
{
|
||||||
|
seg[i].next = i+1;
|
||||||
|
seg[i].prev = last;
|
||||||
|
seg[last].v1 = seg[i].v0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
seg[i].prev = i-1;
|
||||||
|
seg[i].next = i+1;
|
||||||
|
seg[i-1].v1 = seg[i].v0;
|
||||||
|
}
|
||||||
|
|
||||||
|
seg[i].is_inserted = FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
ccount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
genus = ncontours - 1;
|
||||||
|
n = i-1;
|
||||||
|
|
||||||
|
initialise(n);
|
||||||
|
construct_trapezoids(n);
|
||||||
|
nmonpoly = monotonate_trapezoids(n);
|
||||||
|
ntriangles = triangulate_monotone_polygons(n, nmonpoly, triangles);
|
||||||
|
|
||||||
|
return ntriangles;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* This function returns TRUE or FALSE depending upon whether the
|
||||||
|
* vertex is inside the polygon or not. The polygon must already have
|
||||||
|
* been triangulated before this routine is called.
|
||||||
|
* This routine will always detect all the points belonging to the
|
||||||
|
* set (polygon-area - polygon-boundary). The return value for points
|
||||||
|
* on the boundary is not consistent!!!
|
||||||
|
*/
|
||||||
|
|
||||||
|
int is_point_inside_polygon(vertex)
|
||||||
|
double vertex[2];
|
||||||
|
{
|
||||||
|
point_t v;
|
||||||
|
int trnum, rseg;
|
||||||
|
trap_t *t;
|
||||||
|
|
||||||
|
v.x = vertex[0];
|
||||||
|
v.y = vertex[1];
|
||||||
|
|
||||||
|
trnum = locate_endpoint(&v, &v, 1);
|
||||||
|
t = &tr[trnum];
|
||||||
|
|
||||||
|
if (t->state == ST_INVALID)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
if ((t->lseg <= 0) || (t->rseg <= 0))
|
||||||
|
return FALSE;
|
||||||
|
rseg = t->rseg;
|
||||||
|
return _greater_than_equal_to(&seg[rseg].v1, &seg[rseg].v0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* STANDALONE */
|
159
src/Lib/poly2tri/triangulate.h
Normal file
159
src/Lib/poly2tri/triangulate.h
Normal file
|
@ -0,0 +1,159 @@
|
||||||
|
#ifndef _triangulate_h
|
||||||
|
#define _triangulate_h
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
double x, y;
|
||||||
|
} point_t, vector_t;
|
||||||
|
|
||||||
|
|
||||||
|
/* Segment attributes */
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
point_t v0, v1; /* two endpoints */
|
||||||
|
int is_inserted; /* inserted in trapezoidation yet ? */
|
||||||
|
int root0, root1; /* root nodes in Q */
|
||||||
|
int next; /* Next logical segment */
|
||||||
|
int prev; /* Previous segment */
|
||||||
|
} segment_t;
|
||||||
|
|
||||||
|
|
||||||
|
/* Trapezoid attributes */
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int lseg, rseg; /* two adjoining segments */
|
||||||
|
point_t hi, lo; /* max/min y-values */
|
||||||
|
int u0, u1;
|
||||||
|
int d0, d1;
|
||||||
|
int sink; /* pointer to corresponding in Q */
|
||||||
|
int usave, uside; /* I forgot what this means */
|
||||||
|
int state;
|
||||||
|
} trap_t;
|
||||||
|
|
||||||
|
|
||||||
|
/* Node attributes for every node in the query structure */
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int nodetype; /* Y-node or S-node */
|
||||||
|
int segnum;
|
||||||
|
point_t yval;
|
||||||
|
int trnum;
|
||||||
|
int parent; /* doubly linked DAG */
|
||||||
|
int left, right; /* children */
|
||||||
|
} node_t;
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int vnum;
|
||||||
|
int next; /* Circularly linked list */
|
||||||
|
int prev; /* describing the monotone */
|
||||||
|
int marked; /* polygon */
|
||||||
|
} monchain_t;
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
point_t pt;
|
||||||
|
int vnext[4]; /* next vertices for the 4 chains */
|
||||||
|
int vpos[4]; /* position of v in the 4 chains */
|
||||||
|
int nextfree;
|
||||||
|
} vertexchain_t;
|
||||||
|
|
||||||
|
|
||||||
|
/* Node types */
|
||||||
|
|
||||||
|
#define T_X 1
|
||||||
|
#define T_Y 2
|
||||||
|
#define T_SINK 3
|
||||||
|
|
||||||
|
|
||||||
|
#define SEGSIZE 200 /* max# of segments. Determines how */
|
||||||
|
/* many points can be specified as */
|
||||||
|
/* input. If your datasets have large */
|
||||||
|
/* number of points, increase this */
|
||||||
|
/* value accordingly. */
|
||||||
|
|
||||||
|
#define QSIZE 8*SEGSIZE /* maximum table sizes */
|
||||||
|
#define TRSIZE 4*SEGSIZE /* max# trapezoids */
|
||||||
|
|
||||||
|
|
||||||
|
#define TRUE 1
|
||||||
|
#define FALSE 0
|
||||||
|
|
||||||
|
|
||||||
|
#define FIRSTPT 1 /* checking whether pt. is inserted */
|
||||||
|
#define LASTPT 2
|
||||||
|
|
||||||
|
|
||||||
|
#define INFINITY 1<<30
|
||||||
|
#define C_EPS 1.0e-7 /* tolerance value: Used for making */
|
||||||
|
/* all decisions about collinearity or */
|
||||||
|
/* left/right of segment. Decrease */
|
||||||
|
/* this value if the input points are */
|
||||||
|
/* spaced very close together */
|
||||||
|
|
||||||
|
|
||||||
|
#define S_LEFT 1 /* for merge-direction */
|
||||||
|
#define S_RIGHT 2
|
||||||
|
|
||||||
|
|
||||||
|
#define ST_VALID 1 /* for trapezium state */
|
||||||
|
#define ST_INVALID 2
|
||||||
|
|
||||||
|
|
||||||
|
#define SP_SIMPLE_LRUP 1 /* for splitting trapezoids */
|
||||||
|
#define SP_SIMPLE_LRDN 2
|
||||||
|
#define SP_2UP_2DN 3
|
||||||
|
#define SP_2UP_LEFT 4
|
||||||
|
#define SP_2UP_RIGHT 5
|
||||||
|
#define SP_2DN_LEFT 6
|
||||||
|
#define SP_2DN_RIGHT 7
|
||||||
|
#define SP_NOSPLIT -1
|
||||||
|
|
||||||
|
#define TR_FROM_UP 1 /* for traverse-direction */
|
||||||
|
#define TR_FROM_DN 2
|
||||||
|
|
||||||
|
#define TRI_LHS 1
|
||||||
|
#define TRI_RHS 2
|
||||||
|
|
||||||
|
|
||||||
|
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
|
||||||
|
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
|
||||||
|
|
||||||
|
#define CROSS(v0, v1, v2) (((v1).x - (v0).x)*((v2).y - (v0).y) - \
|
||||||
|
((v1).y - (v0).y)*((v2).x - (v0).x))
|
||||||
|
|
||||||
|
#define DOT(v0, v1) ((v0).x * (v1).x + (v0).y * (v1).y)
|
||||||
|
|
||||||
|
#define FP_EQUAL(s, t) (fabs(s - t) <= C_EPS)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* Global variables */
|
||||||
|
|
||||||
|
extern node_t qs[QSIZE]; /* Query structure */
|
||||||
|
extern trap_t tr[TRSIZE]; /* Trapezoid structure */
|
||||||
|
extern segment_t seg[SEGSIZE]; /* Segment table */
|
||||||
|
|
||||||
|
|
||||||
|
/* Functions */
|
||||||
|
|
||||||
|
extern int monotonate_trapezoids(int);
|
||||||
|
extern int triangulate_monotone_polygons(int, int, int (*)[3]);
|
||||||
|
|
||||||
|
extern int _greater_than(point_t *, point_t *);
|
||||||
|
extern int _equal_to(point_t *, point_t *);
|
||||||
|
extern int _greater_than_equal_to(point_t *, point_t *);
|
||||||
|
extern int _less_than(point_t *, point_t *);
|
||||||
|
extern int locate_endpoint(point_t *, point_t *, int);
|
||||||
|
extern int construct_trapezoids(int);
|
||||||
|
|
||||||
|
extern int generate_random_ordering(int);
|
||||||
|
extern int choose_segment(void);
|
||||||
|
extern int read_segments(char *, int *);
|
||||||
|
extern int math_logstar_n(int);
|
||||||
|
extern int math_N(int, int);
|
||||||
|
|
||||||
|
#endif /* triangulate_h */
|
BIN
src/Lib/shapelib-1.2.5.tar.gz
Normal file
BIN
src/Lib/shapelib-1.2.5.tar.gz
Normal file
Binary file not shown.
6
src/Lib/shapelib/ChangeLog
Normal file
6
src/Lib/shapelib/ChangeLog
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
Tue May 4 11:04:31 1999 Frank Warmerdam <warmerda@gdal.velocet.ca>
|
||||||
|
|
||||||
|
* Prepare 1.2.5 release.
|
||||||
|
|
||||||
|
* Added support for 'F' fields.
|
||||||
|
|
37
src/Lib/shapelib/Makefile.am
Normal file
37
src/Lib/shapelib/Makefile.am
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
EXTRA_DIST = ChangeLog dbf_api.html makeshape.sh shape.errata \
|
||||||
|
shapelib.html shp_api.html stream1.sh stream2.sh
|
||||||
|
|
||||||
|
noinst_LIBRARIES = libshape.a
|
||||||
|
|
||||||
|
libshape_a_SOURCES = \
|
||||||
|
dbfopen.c shpopen.c shapefil.h
|
||||||
|
|
||||||
|
noinst_PROGRAMS = shpcreate shpadd shpdump \
|
||||||
|
dbfcreate dbfadd dbfdump \
|
||||||
|
shptest shputils
|
||||||
|
|
||||||
|
shpcreate_SOURCES = shpcreate.c
|
||||||
|
shpcreate_LDADD = libshape.a
|
||||||
|
|
||||||
|
shpadd_SOURCES = shpadd.c
|
||||||
|
shpadd_LDADD = libshape.a
|
||||||
|
|
||||||
|
shpdump_SOURCES = shpdump.c
|
||||||
|
shpdump_LDADD = libshape.a
|
||||||
|
|
||||||
|
dbfcreate_SOURCES = dbfcreate.c
|
||||||
|
dbfcreate_LDADD = libshape.a
|
||||||
|
|
||||||
|
dbfadd_SOURCES = dbfadd.c
|
||||||
|
dbfadd_LDADD = libshape.a
|
||||||
|
|
||||||
|
dbfdump_SOURCES = dbfdump.c
|
||||||
|
dbfdump_LDADD = libshape.a
|
||||||
|
|
||||||
|
shptest_SOURCES = shptest.c
|
||||||
|
shptest_LDADD = libshape.a
|
||||||
|
|
||||||
|
shputils_SOURCES = shputils.c
|
||||||
|
shputils_LDADD = libshape.a
|
||||||
|
|
||||||
|
INCLUDES += -I$(top_builddir) -I$(top_builddir)/Lib
|
322
src/Lib/shapelib/dbf_api.html
Normal file
322
src/Lib/shapelib/dbf_api.html
Normal file
|
@ -0,0 +1,322 @@
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Attribute (.DBF) API</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>Attribute (.DBF) API</h1>
|
||||||
|
|
||||||
|
The Attribute (DBF) API uses DBFHandle to represent a handle for access
|
||||||
|
to one .dbf file. The contents of the DBFHandle are visible (see shapefil.h)
|
||||||
|
but should be ignored by the application. It is intended that all information
|
||||||
|
be accessed by API functions. Note that there should be exactly one record
|
||||||
|
in the .dbf file for each shape in the .shp/.shx files. This constraint
|
||||||
|
must be maintained by the application.<p>
|
||||||
|
|
||||||
|
<!-------------------------------------------------------------------------->
|
||||||
|
|
||||||
|
<h2>DBFOpen()</h2>
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
DBFHandle DBFOpen( const char * pszDBFFile, const char * pszAccess );
|
||||||
|
|
||||||
|
pszDBFFile: The name of the xBase (.dbf) file to access.
|
||||||
|
|
||||||
|
pszAccess: The fopen() style access string. At this time only
|
||||||
|
"rb" (read-only binary) and "rb+" (read/write binary)
|
||||||
|
should be used.
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
The DBFOpen() function should be used to establish access to an existing
|
||||||
|
xBase format table file. The returned DBFHandle is passed to other
|
||||||
|
access functions, and DBFClose() should be invoked to recover resources, and
|
||||||
|
flush changes to disk when complete. The DBFCreate() function should
|
||||||
|
called to create new xBase files. As a convenience, DBFOpen() can be
|
||||||
|
called with the name of a .shp or .shx file, and it will figure out the
|
||||||
|
name of the related .dbf file.<p>
|
||||||
|
|
||||||
|
<!-------------------------------------------------------------------------->
|
||||||
|
|
||||||
|
<h2>DBFCreate()</h2>
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
DBFHandle DBFCreate( const char * pszDBFFile );
|
||||||
|
|
||||||
|
pszDBFFile: The name of the xBase (.dbf) file to create.
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
The DBFCreate() function creates a new xBase format file with the given
|
||||||
|
name, and returns an access handle that can be used with other DBF functions.
|
||||||
|
The newly created file will have no fields, and no records. Fields should
|
||||||
|
be added with DBFAddField() before any records add written.
|
||||||
|
|
||||||
|
<!-------------------------------------------------------------------------->
|
||||||
|
|
||||||
|
<h2>DBFGetFieldCount()</h2>
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
int DBFGetFieldCount( DBFHandle hDBF );
|
||||||
|
|
||||||
|
hDBF: The access handle for the file to be queried, as returned
|
||||||
|
by DBFOpen(), or DBFCreate().
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
The DBFGetFieldCount() function returns the number of fields currently
|
||||||
|
defined for the indicated xBase file.
|
||||||
|
|
||||||
|
<!-------------------------------------------------------------------------->
|
||||||
|
|
||||||
|
<h2>DBFGetRecordCount()</h2>
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
int DBFGetRecordCount( DBFHandle hDBF );
|
||||||
|
|
||||||
|
hDBF: The access handle for the file to be queried, as returned by
|
||||||
|
DBFOpen(), or DBFCreate().
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
The DBFGetRecordCount() function returns the number of records that
|
||||||
|
exist on the xBase file currently. Note that with shape files one xBase
|
||||||
|
record exists for each shape in the .shp/.shx files.<p>
|
||||||
|
|
||||||
|
<!-------------------------------------------------------------------------->
|
||||||
|
|
||||||
|
<h2>DBFGetFieldInfo()</h2>
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
DBFFieldType DBFGetFieldInfo( DBFHandle hDBF, int iField, char * pszFieldName,
|
||||||
|
int * pnWidth, int * pnDecimals );
|
||||||
|
|
||||||
|
hDBF: The access handle for the file to be queried, as returned by
|
||||||
|
DBFOpen(), or DBFCreate().
|
||||||
|
|
||||||
|
iField: The field to be queried. This should be a number between
|
||||||
|
0 and n-1, where n is the number fields on the file, as
|
||||||
|
returned by DBFGetFieldCount().
|
||||||
|
|
||||||
|
pszFieldName: If this pointer is not NULL the name of the requested field
|
||||||
|
will be written to this location. The pszFieldName buffer
|
||||||
|
should be at least 12 character is size in order to hold
|
||||||
|
the longest possible field name of 11 characters plus a
|
||||||
|
terminating zero character.
|
||||||
|
|
||||||
|
pnWidth: If this pointer is not NULL, the width of the requested field
|
||||||
|
will be returned in the int pointed to by pnWidth. This is
|
||||||
|
the width in characters.
|
||||||
|
|
||||||
|
pnDecimals: If this pointer is not NULL, the number of decimal places
|
||||||
|
precision defined for the field will be returned. This is
|
||||||
|
zero for integer fields, or non-numeric fields.
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
The DBFGetFieldInfo() returns the type of the requested field, which is
|
||||||
|
one of the DBFFieldType enumerated values. As well, the field name, and
|
||||||
|
field width information can optionally be returned. The field type returned
|
||||||
|
does not correspond one to one with the xBase field types. For instance
|
||||||
|
the xBase field type for Date will just be returned as being FTInteger. <p>
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
typedef enum {
|
||||||
|
FTString, /* fixed length string field */
|
||||||
|
FTInteger, /* numeric field with no decimals */
|
||||||
|
FTDouble, /* numeric field with decimals */
|
||||||
|
FTInvalid /* not a recognised field type */
|
||||||
|
} DBFFieldType;
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
<!-------------------------------------------------------------------------->
|
||||||
|
|
||||||
|
<h2>DBFAddField()</h2>
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
int DBFAddField( DBFHandle hDBF, const char * pszFieldName,
|
||||||
|
DBFFieldType eType, int nWidth, int nDecimals );
|
||||||
|
|
||||||
|
hDBF: The access handle for the file to be updated, as returned by
|
||||||
|
DBFOpen(), or DBFCreate().
|
||||||
|
|
||||||
|
pszFieldName: The name of the new field. At most 11 character will be used.
|
||||||
|
In order to use the xBase file in some packages it may be
|
||||||
|
necessary to avoid some special characters in the field names
|
||||||
|
such as spaces, or arithmetic operators.
|
||||||
|
|
||||||
|
eType: One of FTString, FTInteger or FTDouble in order to establish
|
||||||
|
the type of the new field. Note that some valid xBase field
|
||||||
|
types cannot be created such as date fields.
|
||||||
|
|
||||||
|
nWidth: The width of the field to be created. For FTString fields this
|
||||||
|
establishes the maximum length of string that can be stored.
|
||||||
|
For FTInteger this establishes the largest number that can
|
||||||
|
be represented. For FTDouble fields this in combination
|
||||||
|
with the nDecimals value establish the size, and precision
|
||||||
|
of the created field.
|
||||||
|
|
||||||
|
nDecimals: The number of decimal places to reserve for FTDouble fields.
|
||||||
|
For all other field types this should be zero. For instance
|
||||||
|
with nWidth=7, and nDecimals=3 numbers would be formatted
|
||||||
|
similarly to `123.456'.
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
The DBFAddField() function is used to add new fields to an existing xBase
|
||||||
|
file opened with DBFOpen(), or created with DBFCreate(). Note that fields
|
||||||
|
can only be added to xBase files with no records, though this is limitation
|
||||||
|
of this API, not of the file format.<p>
|
||||||
|
|
||||||
|
The DBFAddField() return value is the field number of the new field, or
|
||||||
|
-1 if the addition of the field failed.<p>
|
||||||
|
|
||||||
|
<!-------------------------------------------------------------------------->
|
||||||
|
|
||||||
|
<h2>DBFReadIntegerAttribute()</h2>
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
int DBFReadIntegerAttribute( DBFHandle hDBF, int iShape, int iField );
|
||||||
|
|
||||||
|
hDBF: The access handle for the file to be queried, as returned by
|
||||||
|
DBFOpen(), or DBFCreate().
|
||||||
|
|
||||||
|
iShape: The record number (shape number) from which the field value
|
||||||
|
should be read.
|
||||||
|
|
||||||
|
iField: The field within the selected record that should be read.
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
The DBFReadIntegerAttribute() will read the value of one field and return
|
||||||
|
it as an integer. This can be used even with FTString fields, though the
|
||||||
|
returned value will be zero if not interpretable as a number.<p>
|
||||||
|
|
||||||
|
<!-------------------------------------------------------------------------->
|
||||||
|
|
||||||
|
<h2>DBFReadDoubleAttribute()</h2>
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
double DBFReadDoubleAttribute( DBFHandle hDBF, int iShape, int iField );
|
||||||
|
|
||||||
|
hDBF: The access handle for the file to be queried, as returned by
|
||||||
|
DBFOpen(), or DBFCreate().
|
||||||
|
|
||||||
|
iShape: The record number (shape number) from which the field value
|
||||||
|
should be read.
|
||||||
|
|
||||||
|
iField: The field within the selected record that should be read.
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
The DBFReadDoubleAttribute() will read the value of one field and return
|
||||||
|
it as a double. This can be used even with FTString fields, though the
|
||||||
|
returned value will be zero if not interpretable as a number.<p>
|
||||||
|
|
||||||
|
<!-------------------------------------------------------------------------->
|
||||||
|
|
||||||
|
<h2>DBFReadStringAttribute()</h2>
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
const char *DBFReadStringAttribute( DBFHandle hDBF, int iShape, int iField );
|
||||||
|
|
||||||
|
hDBF: The access handle for the file to be queried, as returned by
|
||||||
|
DBFOpen(), or DBFCreate().
|
||||||
|
|
||||||
|
iShape: The record number (shape number) from which the field value
|
||||||
|
should be read.
|
||||||
|
|
||||||
|
iField: The field within the selected record that should be read.
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
The DBFReadStringAttribute() will read the value of one field and return
|
||||||
|
it as a string. This function may be used on any field type (including
|
||||||
|
FTInteger and FTDouble) and will return the string representation stored
|
||||||
|
in the .dbf file. The returned pointer is to an internal buffer
|
||||||
|
which is only valid untill the next DBF function call. It's contents may
|
||||||
|
be copied with normal string functions such as strcpy(), or strdup(). If
|
||||||
|
the TRIM_DBF_WHITESPACE macro is defined in shapefil.h (it is by default)
|
||||||
|
then all leading and trailing space (ASCII 32) characters will be stripped
|
||||||
|
before the string is returned.<p>
|
||||||
|
|
||||||
|
<!-------------------------------------------------------------------------->
|
||||||
|
|
||||||
|
<h2>DBFWriteIntegerAttribute</h2>
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
int DBFWriteIntegerAttribute( DBFHandle hDBF, int iShape, int iField,
|
||||||
|
int nFieldValue );
|
||||||
|
|
||||||
|
hDBF: The access handle for the file to be written, as returned by
|
||||||
|
DBFOpen(), or DBFCreate().
|
||||||
|
|
||||||
|
iShape: The record number (shape number) to which the field value
|
||||||
|
should be written.
|
||||||
|
|
||||||
|
iField: The field within the selected record that should be written.
|
||||||
|
|
||||||
|
nFieldValue: The integer value that should be written.
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
The DBFWriteIntegerAttribute() function is used to write a value to a numeric
|
||||||
|
field (FTInteger, or FTDouble). If the write succeeds the value TRUE will
|
||||||
|
be returned, otherwise FALSE will be returned. The value may be truncated
|
||||||
|
without warning if written to a field to narrow to represent the value.<p>
|
||||||
|
|
||||||
|
<!-------------------------------------------------------------------------->
|
||||||
|
|
||||||
|
<h2>DBFWriteDoubleAttribute()</h2>
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
int DBFWriteDoubleAttribute( DBFHandle hDBF, int iShape, int iField,
|
||||||
|
double dFieldValue );
|
||||||
|
|
||||||
|
hDBF: The access handle for the file to be written, as returned by
|
||||||
|
DBFOpen(), or DBFCreate().
|
||||||
|
|
||||||
|
iShape: The record number (shape number) to which the field value
|
||||||
|
should be written.
|
||||||
|
|
||||||
|
iField: The field within the selected record that should be written.
|
||||||
|
|
||||||
|
dFieldValue: The floating point value that should be written.
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
The DBFWriteDoubleAttribute() function is used to write a value to a numeric
|
||||||
|
field (FTInteger, or FTDouble). If the write succeeds the value TRUE will
|
||||||
|
be returned, otherwise FALSE will be returned. The value may be truncated
|
||||||
|
without warning if written to a field to narrow to represent the value.<p>
|
||||||
|
|
||||||
|
<!-------------------------------------------------------------------------->
|
||||||
|
|
||||||
|
<h2>DBFWriteStringAttribute()</h2>
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
int DBFWriteStringAttribute( DBFHandle hDBF, int iShape, int iField,
|
||||||
|
const char * pszFieldValue );
|
||||||
|
|
||||||
|
hDBF: The access handle for the file to be written, as returned by
|
||||||
|
DBFOpen(), or DBFCreate().
|
||||||
|
|
||||||
|
iShape: The record number (shape number) to which the field value
|
||||||
|
should be written.
|
||||||
|
|
||||||
|
iField: The field within the selected record that should be written.
|
||||||
|
|
||||||
|
pszFieldValue: The string to be written to the field.
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
The DBFWriteStringAttribute() function is used to write a value to a string
|
||||||
|
field (FString). If the write succeeds the value TRUE willbe returned,
|
||||||
|
otherwise FALSE will be returned. The value may be truncated
|
||||||
|
without warning if written to a field to narrow to hold the string.<p>
|
||||||
|
|
||||||
|
<!-------------------------------------------------------------------------->
|
||||||
|
|
||||||
|
<h2>DBFClose()</h2>
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
void DBFClose( DBFHandle hDBF );
|
||||||
|
|
||||||
|
hDBF: The access handle for the file to be closed.
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
The DBFClose() function will close the indicated xBase file (opened with
|
||||||
|
DBFOpen(), or DBFCreate()), flushing out all information to the file on
|
||||||
|
disk, and recovering any resources associated with having the file open.
|
||||||
|
The file handle (hDBF) should not be used again with the DBF API after
|
||||||
|
calling DBFClose().<p>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue