From ffc9db1b829f5233ad8986599d74415ff7946c25 Mon Sep 17 00:00:00 2001 From: Peter Sadrozinski Date: Sat, 14 Jul 2012 14:32:46 -0400 Subject: [PATCH] Checkpoint 2 - fixed tile matching using add_intermediate_nodes - source code rearrangement phase 1 - remove a lot of libraries that are not used by other apps - move some of the Buildtiles libraries that are used by other apps (and libs) into terragear lib directory - debug message overhal - to show some progress. TODO - not implemented yet - caculate face nodes and save in superpoly (where the faces are stored) - calculate node normals, and store in tg_nodes (where the nodes are stored) TODO - bugs - find_intermediate_nodes isn't working for a lot of roads - still many t-juntions making visible gaps - flatten ocean nosed is also creating gaps - there's a grey poly on madeira - need to investigate --- src/Airports/GenAirports/build.cxx | 2 +- src/Airports/GenAirports850/rwy_gen.cxx | 2 +- src/BuildTiles/CMakeLists.txt | 5 +- src/BuildTiles/Clipper/.gitignore | 1 - src/BuildTiles/Clipper/CMakeLists.txt | 15 - src/BuildTiles/Clipper/clipper.cxx | 567 ------ src/BuildTiles/Clipper/clipper.hxx | 127 -- src/BuildTiles/Clipper/testclipper.cxx | 116 -- src/BuildTiles/GenOutput/CMakeLists.txt | 5 - src/BuildTiles/GenOutput/genobj.cxx | 519 ------ src/BuildTiles/GenOutput/genobj.hxx | 107 -- src/BuildTiles/Main/CMakeLists.txt | 25 +- src/BuildTiles/Main/construct.cxx | 1586 ++++++++++++++++- src/BuildTiles/Main/construct.hxx | 152 +- .../{Clipper => Main}/default_priorities.txt | 7 + src/BuildTiles/Main/main.cxx | 1456 +-------------- .../{Clipper => Main}/priorities.cxx | 0 .../{Clipper => Main}/priorities.hxx | 0 src/BuildTiles/Main/usgs.hxx | 4 +- src/BuildTiles/Match/match.cxx | 93 +- src/BuildTiles/Match/match.hxx | 14 +- src/BuildTiles/Triangulate/CMakeLists.txt | 6 - src/BuildTiles/Triangulate/triangle.cxx | 567 ------ src/BuildTiles/Triangulate/triangle.hxx | 105 -- src/BuildTiles/Triangulate/trieles.cxx | 26 - src/Lib/Geometry/poly_extra.cxx | 4 +- src/Lib/Geometry/poly_support.cxx | 2 - src/Lib/Geometry/poly_support.hxx | 2 +- src/Lib/Geometry/tg_nodes.cxx | 6 +- src/Lib/Geometry/tg_nodes.hxx | 2 +- .../Triangulate => Lib/Geometry}/trieles.hxx | 0 src/Lib/Optimize/genfans.hxx | 2 +- src/Lib/Optimize/genstrips.hxx | 2 +- src/Lib/Polygon/superpoly.cxx | 1 + src/Lib/Polygon/superpoly.hxx | 13 +- 35 files changed, 1799 insertions(+), 3742 deletions(-) delete mode 100644 src/BuildTiles/Clipper/.gitignore delete mode 100644 src/BuildTiles/Clipper/CMakeLists.txt delete mode 100644 src/BuildTiles/Clipper/clipper.cxx delete mode 100644 src/BuildTiles/Clipper/clipper.hxx delete mode 100644 src/BuildTiles/Clipper/testclipper.cxx delete mode 100644 src/BuildTiles/GenOutput/CMakeLists.txt delete mode 100644 src/BuildTiles/GenOutput/genobj.cxx delete mode 100644 src/BuildTiles/GenOutput/genobj.hxx rename src/BuildTiles/{Clipper => Main}/default_priorities.txt (94%) rename src/BuildTiles/{Clipper => Main}/priorities.cxx (100%) rename src/BuildTiles/{Clipper => Main}/priorities.hxx (100%) delete mode 100644 src/BuildTiles/Triangulate/CMakeLists.txt delete mode 100644 src/BuildTiles/Triangulate/triangle.cxx delete mode 100644 src/BuildTiles/Triangulate/triangle.hxx delete mode 100644 src/BuildTiles/Triangulate/trieles.cxx rename src/{BuildTiles/Triangulate => Lib/Geometry}/trieles.hxx (100%) diff --git a/src/Airports/GenAirports/build.cxx b/src/Airports/GenAirports/build.cxx index 4e88aa54..a79a8653 100644 --- a/src/Airports/GenAirports/build.cxx +++ b/src/Airports/GenAirports/build.cxx @@ -50,13 +50,13 @@ #include #include #include +#include #include #include #include #include #include #include -#include #include "apt_surface.hxx" #include "convex_hull.hxx" diff --git a/src/Airports/GenAirports850/rwy_gen.cxx b/src/Airports/GenAirports850/rwy_gen.cxx index 095f4546..046b1305 100644 --- a/src/Airports/GenAirports850/rwy_gen.cxx +++ b/src/Airports/GenAirports850/rwy_gen.cxx @@ -36,7 +36,7 @@ using std::string; struct sections { const char* tex; - int size; + double size; }; // UK Precision runway sections from after the designation number diff --git a/src/BuildTiles/CMakeLists.txt b/src/BuildTiles/CMakeLists.txt index 311e08ae..f49c3a24 100644 --- a/src/BuildTiles/CMakeLists.txt +++ b/src/BuildTiles/CMakeLists.txt @@ -4,9 +4,6 @@ include_directories(${PROJECT_SOURCE_DIR}/src/Lib) include_directories(${PROJECT_SOURCE_DIR}/src/BuildTiles) add_subdirectory(Osgb36) -add_subdirectory(Parallel) -add_subdirectory(Triangulate) -add_subdirectory(Clipper) -add_subdirectory(GenOutput) +add_subdirectory(Parallel) add_subdirectory(Match) add_subdirectory(Main) diff --git a/src/BuildTiles/Clipper/.gitignore b/src/BuildTiles/Clipper/.gitignore deleted file mode 100644 index 7c15631d..00000000 --- a/src/BuildTiles/Clipper/.gitignore +++ /dev/null @@ -1 +0,0 @@ -testclipper diff --git a/src/BuildTiles/Clipper/CMakeLists.txt b/src/BuildTiles/Clipper/CMakeLists.txt deleted file mode 100644 index 21803ec6..00000000 --- a/src/BuildTiles/Clipper/CMakeLists.txt +++ /dev/null @@ -1,15 +0,0 @@ - - -add_library(Clipper STATIC - clipper.cxx clipper.hxx priorities.cxx priorities.hxx -) - -add_executable(testclipper testclipper.cxx) - -target_link_libraries(testclipper - Clipper Osgb36 Triangulate Polygon Geometry - ${SIMGEAR_CORE_LIBRARIES} - ${SIMGEAR_CORE_LIBRARY_DEPENDENCIES} - ${GPC_LIBRARY}) - -INSTALL(FILES default_priorities.txt DESTINATION ${PKGDATADIR} ) \ No newline at end of file diff --git a/src/BuildTiles/Clipper/clipper.cxx b/src/BuildTiles/Clipper/clipper.cxx deleted file mode 100644 index bc39f489..00000000 --- a/src/BuildTiles/Clipper/clipper.cxx +++ /dev/null @@ -1,567 +0,0 @@ -// 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 - http://www.flightgear.org/~curt -// -// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. -// -// $Id: clipper.cxx,v 1.33 2006-11-29 22:19:33 curt Exp $ - - -#ifdef HAVE_CONFIG_H -# include -#endif - -#include -#include -#include -#include - -#include -#include - -#include "clipper.hxx" - -#include - -#include - -using std::string; - -#define MASK_CLIP 1 - - -// Constructor. -TGClipper::TGClipper(): - nudge(0.0), - m_ignore_landmass(false) -{ -} - - -// Destructor. -TGClipper::~TGClipper() { -} - - -// Initialize the clipper (empty all the polygon buckets.) -bool TGClipper::init() { - for ( int i = 0; i < TG_MAX_AREA_TYPES; ++i ) { - polys_in.superpolys[i].clear(); - } - nodes.clear(); - - return true; -} - - -// Load a polygon definition file. -bool TGClipper::load_polys(const string& path) { - bool poly3d = false; - string first_line; - string poly_name; - AreaType poly_type; - int contours, count, i, j; - int hole_flag; - double startx, starty, startz, x, y, z, lastx, lasty, lastz; - - SG_LOG( SG_CLIPPER, SG_INFO, "Loading " << path << " ..." ); - - sg_gzifstream in( path ); - - if ( !in ) { - SG_LOG( SG_CLIPPER, SG_ALERT, "Cannot open file: " << path ); - exit(-1); - } - - TGPolygon poly; - - Point3D p; - // (this could break things, why is it here) in >> skipcomment; - while ( !in.eof() ) { - in >> first_line; - if ( first_line == "#2D" ) { - poly3d = false; - in >> poly_name; - } else if ( first_line == "#3D" ) { - poly3d = true; - in >> poly_name; - } else { - // support old format (default to 2d) - poly3d = false; - poly_name = first_line; - } - SG_LOG( SG_CLIPPER, SG_INFO, "poly name = " << poly_name); - poly_type = get_area_type( poly_name ); - SG_LOG( SG_CLIPPER, SG_INFO, "poly type (int) = " << (int)poly_type); - in >> contours; - SG_LOG( SG_CLIPPER, SG_INFO, "num contours = " << contours); - - poly.erase(); - - for ( i = 0; i < contours; ++i ) { - in >> count; - - if ( count < 3 ) { - SG_LOG( SG_CLIPPER, SG_ALERT, "Polygon with less than 3 data points." ); - exit(-1); - } - - in >> hole_flag; - - in >> startx; - in >> starty; - if ( poly3d ) { - in >> startz; - } else { - startz = -9999.0; - } - p = Point3D(startx+nudge, starty+nudge, startz); - poly.add_node( i, p ); - - if ( poly3d ) { - nodes.unique_add_fixed_elevation( p ); - } else { - nodes.unique_add( p ); - } - - for ( j = 1; j < count - 1; ++j ) { - in >> x; - in >> y; - if ( poly3d ) { - in >> z; - } else { - z = -9999.0; - } - p = Point3D( x+nudge, y+nudge, z ); - poly.add_node( i, p ); - if ( poly3d ) { - nodes.unique_add_fixed_elevation( p ); - } else { - nodes.unique_add( p ); - } - } - - in >> lastx; - in >> lasty; - if ( poly3d ) { - in >> lastz; - } else { - lastz = -9999.0; - } - - if ( (fabs(startx - lastx) < SG_EPSILON) && - (fabs(starty - lasty) < SG_EPSILON) && - (fabs(startz - lastz) < SG_EPSILON) ) { - // last point same as first, discard - } else { - p = Point3D( lastx+nudge, lasty+nudge, lastz ); - poly.add_node( i, p ); - if ( poly3d ) { - nodes.unique_add_fixed_elevation( p ); - } else { - nodes.unique_add( p ); - } - } - } - - int area = (int)poly_type; - string material = get_area_name( area ); - - add_poly(area, poly, material); - - in >> skipcomment; - } - - return true; -} - - -// Load a polygon definition file containing osgb36 Eastings and Northings -// and convert them to WGS84 Latitude and Longitude -bool TGClipper::load_osgb36_polys(const string& path) { - string poly_name; - AreaType poly_type; - int contours, count, i, j; - int hole_flag; - double startx, starty, x, y, lastx, lasty; - - SG_LOG( SG_CLIPPER, SG_INFO, "Loading " << path << " ..." ); - - sg_gzifstream in( path ); - - if ( !in ) { - SG_LOG( SG_CLIPPER, SG_ALERT, "Cannot open file: " << path ); - exit(-1); - } - - TGPolygon poly; - - Point3D p; - Point3D OSRef; - in >> skipcomment; - while ( !in.eof() ) { - in >> poly_name; - SG_LOG( SG_CLIPPER, SG_INFO, "poly name = " << poly_name); - poly_type = get_area_type( poly_name ); - SG_LOG( SG_CLIPPER, SG_INFO, "poly type (int) = " << (int)poly_type); - in >> contours; - SG_LOG( SG_CLIPPER, SG_INFO, "num contours = " << contours); - - poly.erase(); - - for ( i = 0; i < contours; ++i ) { - in >> count; - - if ( count < 3 ) { - SG_LOG( SG_CLIPPER, SG_ALERT, "Polygon with less than 3 data points." ); - exit(-1); - } - - in >> hole_flag; - - in >> startx; - in >> starty; - OSRef = Point3D(startx, starty, -9999.0); - - //Convert from OSGB36 Eastings/Northings to WGS84 Lat/Lon - //Note that startx and starty themselves must not be altered since we compare them with unaltered lastx and lasty later - p = OSGB36ToWGS84(OSRef); - - poly.add_node( i, p ); - nodes.unique_add( p ); - - SG_LOG( SG_CLIPPER, SG_BULK, "0 = " << startx << ", " << starty ); - - for ( j = 1; j < count - 1; ++j ) { - in >> x; - in >> y; - OSRef = Point3D( x, y, -9999.0 ); - p = OSGB36ToWGS84(OSRef); - - poly.add_node( i, p ); - nodes.unique_add( p ); - SG_LOG( SG_CLIPPER, SG_BULK, j << " = " << x << ", " << y ); - } - - in >> lastx; - in >> lasty; - - if ( (fabs(startx - lastx) < SG_EPSILON) && - (fabs(starty - lasty) < SG_EPSILON) ) { - // last point same as first, discard - } else { - OSRef = Point3D( lastx, lasty, -9999.0 ); - p = OSGB36ToWGS84(OSRef); - - poly.add_node( i, p ); - nodes.unique_add( p ); - SG_LOG( SG_CLIPPER, SG_BULK, count - 1 << " = " << lastx << ", " << lasty ); - } - } - - int area = (int)poly_type; - string material = get_area_name( area ); - - add_poly(area, poly, material); - - in >> skipcomment; - } - - return true; -} - -// Add a polygon to the clipper. -void TGClipper::add_poly( int area, const TGPolygon &poly, string material ) -{ - TGSuperPoly sp; - - if ( area < TG_MAX_AREA_TYPES ) { - sp.set_poly( poly ); - sp.set_material( material ); - - polys_in.superpolys[area].push_back(sp); - } else { - SG_LOG( SG_CLIPPER, SG_ALERT, "Polygon type out of range = " << area); - exit(-1); - } -} - - -// Move slivers from in polygon to out polygon. -void TGClipper::move_slivers( TGPolygon& in, TGPolygon& out ) { - // traverse each contour of the polygon and attempt to identify - // likely slivers - int i; - - out.erase(); - - double angle_cutoff = 10.0 * SGD_DEGREES_TO_RADIANS; - double area_cutoff = 0.00000008; - 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 ( i = in.contours() - 1; i >= 0; --i ) { - min_angle = in.minangle_contour( i ); - area = in.area_contour( i ); - - 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 ); - } - } - } -} - - -// Attempt to merge slivers into a list of polygons. -// -// 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 TGClipper::merge_slivers( TGPolyList& clipped, TGPolygon& slivers ) { - TGPolygon poly, result, sliver; - point_list contour; - int original_contours, result_contours; - bool done; - int area, i, j; - - for ( 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 ( area = 0; area < TG_MAX_AREA_TYPES && !done; ++area ) { - - if ( is_hole_area( area ) ) { - // don't merge a non-hole sliver in with a hole - continue; - } - - // cout << " testing area = " << area << " with " - // << clipped.polys[area].size() << " polys" << endl; - for ( j = 0; j < (int)clipped.superpolys[area].size() && !done; ++j ) { - // cout << " polygon = " << j << endl; - poly = clipped.superpolys[area][j].get_poly(); - original_contours = poly.contours(); - result = tgPolygonUnion( poly, sliver ); - result_contours = result.contours(); - - if ( original_contours == result_contours ) { - // cout << " FOUND a poly to merge the sliver with" << endl; - clipped.superpolys[area][j].set_poly( result ); - done = true; - } - } - } - - if ( !done ) { - // cout << "no suitable polys found for sliver merge" << endl; - } - } -} - - -// Clip all the polygons against each other in a priority scheme based -// on order of the polygon type in the polygon type enum. -bool TGClipper::clip_all(const point2d& min, const point2d& max) { - TGPolygon accum, tmp; - TGPolygon slivers, remains; - int i, j; - Point3D p; - - SG_LOG( SG_CLIPPER, SG_INFO, "Running master clipper" ); - SG_LOG( SG_CLIPPER, SG_INFO, " (" << min.x << "," << min.y << ") (" << max.x << "," << max.y << ")" ); - - accum.erase(); - - // set up clipping tile : and remember to add the nodes! - polys_in.safety_base.erase(); - - p = Point3D(min.x, min.y, -9999.0); - polys_in.safety_base.add_node( 0, p ); - nodes.unique_add( p ); - - p = Point3D(max.x, min.y, -9999.0); - polys_in.safety_base.add_node( 0, p ); - nodes.unique_add( p ); - - p = Point3D(max.x, max.y, -9999.0); - polys_in.safety_base.add_node( 0, p ); - nodes.unique_add( p ); - - p = Point3D(min.x, max.y, -9999.0); - polys_in.safety_base.add_node( 0, p ); - nodes.unique_add( p ); - - // set up land mask, we clip most things to this since it is our - // best representation of land vs. ocean. If we have other less - // accurate data that spills out into the ocean, we want to just - // clip it. - // also set up a mask for all water and islands - TGPolygon land_mask, water_mask, island_mask; - land_mask.erase(); - water_mask.erase(); - island_mask.erase(); - for ( i = 0; i < TG_MAX_AREA_TYPES; i++ ) { - if ( is_landmass_area( i ) && !m_ignore_landmass ) { - for ( unsigned int j = 0; j < polys_in.superpolys[i].size(); ++j ) { - land_mask = tgPolygonUnion( land_mask, polys_in.superpolys[i][j].get_poly() ); - } - } else if ( is_water_area( i ) ) { - for (unsigned int j = 0; j < polys_in.superpolys[i].size(); j++) { - water_mask = tgPolygonUnion( water_mask, polys_in.superpolys[i][j].get_poly() ); - } - } else if ( is_island_area( i ) ) { - for (unsigned int j = 0; j < polys_in.superpolys[i].size(); j++) { - island_mask = tgPolygonUnion( island_mask, polys_in.superpolys[i][j].get_poly() ); - } - } - } - - // process polygons in priority order - for ( i = 0; i < TG_MAX_AREA_TYPES; ++i ) { - SG_LOG( SG_CLIPPER, SG_INFO, "num polys of type (" << i << ") = " << polys_in.superpolys[i].size() ); - for( j = 0; j < (int)polys_in.superpolys[i].size(); ++j ) { - TGPolygon current = polys_in.superpolys[i][j].get_poly(); - SG_LOG( SG_CLIPPER, SG_INFO, get_area_name( (AreaType)i ) << " = " << current.contours() ); - - tmp = current; - - // if not a hole, clip the area to the land_mask - if ( !m_ignore_landmass && !is_hole_area( i ) ) { - tmp = tgPolygonInt( tmp, land_mask ); - } - - // Airport areas are limited to existing land mass and - // never override water. - // - // 9/26/2005 - CLO: We are going to add the ability to - // manually define airport areas when the default area - // isn't sufficient. It is clear that it is impossible to - // auto-generate correct airport areas in all cases. For - // now we default to topologically continuous scenery and - // wait for people to submit manual fixes. - // - // if ( i == AirportArea ) { - // tmp = tgPolygonInt( tmp, land_mask ); - // tmp = tgPolygonDiff( tmp, water_mask ); - // } - - // if a water area, cut out potential islands - if ( is_water_area( i ) ) { - // clip against island mask - tmp = tgPolygonDiff( tmp, island_mask ); - } - - TGPolygon result_union, result_diff; - - if ( accum.contours() == 0 ) { - result_diff = tmp; - result_union = tmp; - } else { - result_diff = tgPolygonDiff( tmp, accum); - result_union = tgPolygonUnion( tmp, accum); - } - - // 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); - - // 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 ) { - TGSuperPoly sp; - string material = get_area_name( (AreaType)i ); - - sp.set_material( material ); - sp.set_poly( result_diff ); - polys_clipped.superpolys[i].push_back( sp ); - } - } - 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 = tgPolygonDiff( 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 ) { - TGSuperPoly sp; - string material = get_area_name(get_sliver_target_area_type()); - - sp.set_material( material ); - sp.set_poly( remains ); - - polys_clipped.superpolys[(int)get_sliver_target_area_type()].push_back(sp); - } - } - - SG_LOG( SG_CLIPPER, SG_INFO, " master clipper finished." ); - - return true; -} diff --git a/src/BuildTiles/Clipper/clipper.hxx b/src/BuildTiles/Clipper/clipper.hxx deleted file mode 100644 index 5fd6e3a2..00000000 --- a/src/BuildTiles/Clipper/clipper.hxx +++ /dev/null @@ -1,127 +0,0 @@ -// 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 - http://www.flightgear.org/~curt -// -// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. -// -// $Id: clipper.hxx,v 1.11 2007-08-15 14:36:52 curt Exp $ - - - -#ifndef _CLIPPER_HXX -#define _CLIPPER_HXX - - -#ifndef __cplusplus -# error This library requires C++ -#endif - - -#include - -//#include -#include -#include -#include -#include - -#include - -#define TG_MAX_AREA_TYPES 128 // FIXME also defined in - // MergerClipper/clipper.hxx -#define EXTRA_SAFETY_CLIP - - -class TGPolyList -{ -public: - superpoly_list superpolys[TG_MAX_AREA_TYPES]; - texparams_list texparams[TG_MAX_AREA_TYPES]; - TGPolygon safety_base; -}; - - - -class TGClipper -{ - -private: - - TGPolyList polys_in, polys_clipped; - //TGTriNodes fixed_elevations; - TGNodes nodes; - -public: - - // Constructor. - TGClipper (void); - - // Destructor. - ~TGClipper (void); - - // Initialize Clipper (allocate and/or connect structures.) - bool init(); - - // Load a polygon definition file - bool load_polys(const std::string& path); - - // Load an Osgb36 polygon definition file - bool load_osgb36_polys(const std::string& path); - - // Add a polygon. - void add_poly(int area, const TGPolygon &poly, std::string material); - - // Remove any slivers from in polygon and move them to out - // polygon. - void move_slivers( TGPolygon& in, TGPolygon& 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( TGPolyList& clipped, TGPolygon& slivers ); - - // Do actual clipping work. - bool clip_all(const point2d& min, const point2d& max); - - // Return output poly list - inline TGPolyList get_polys_clipped() const { return polys_clipped; } - - // Return the fixed elevation points list - inline TGNodes get_nodes() const { return nodes; } - - inline node_list get_fixed_elevations_nodes() { return nodes.get_fixed_elevation_nodes(); } - - double nudge; - - bool ignore_landmass() const { - return m_ignore_landmass; - } - - void ignore_landmass(bool b) { - m_ignore_landmass = b; - } -protected: - bool m_ignore_landmass; -}; - - -#endif // _CLIPPER_HXX - - diff --git a/src/BuildTiles/Clipper/testclipper.cxx b/src/BuildTiles/Clipper/testclipper.cxx deleted file mode 100644 index 23be6701..00000000 --- a/src/BuildTiles/Clipper/testclipper.cxx +++ /dev/null @@ -1,116 +0,0 @@ -// main.cxx -- sample use of the clipper lib -// -// Written by Curtis Olson, started February 1999. -// -// Copyright (C) 1999 Curtis L. Olson - http://www.flightgear.org/~curt -// -// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. -// -// $Id: testclipper.cxx,v 1.7 2004-11-19 22:25:49 curt Exp $ - - - -#include -#include - -#include "clipper.hxx" - -#include - -using std::cout; -using std::endl; -using std::string; - - -int main( int argc, char **argv ) { - point2d global_min, global_max; - - sglog().setLogLevels( SG_ALL, SG_DEBUG ); - - global_min.x = global_min.y = 200; - global_max.y = global_max.x = -200; - - TGClipper clipper; - clipper.init(); - - if ( argc < 2 ) { - SG_LOG( SG_CLIPPER, SG_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); - SGBucket 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 = b.get_width(); - - 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 - SG_HALF_BUCKET_SPAN; - max.y = c.y + SG_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 { - SG_LOG ( SG_GENERAL, SG_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); - - SG_LOG( SG_CLIPPER, SG_INFO, "finished main" ); - - return 0; -} - diff --git a/src/BuildTiles/GenOutput/CMakeLists.txt b/src/BuildTiles/GenOutput/CMakeLists.txt deleted file mode 100644 index ef32931c..00000000 --- a/src/BuildTiles/GenOutput/CMakeLists.txt +++ /dev/null @@ -1,5 +0,0 @@ - - -add_library(GenOutput STATIC - genobj.cxx genobj.hxx -) diff --git a/src/BuildTiles/GenOutput/genobj.cxx b/src/BuildTiles/GenOutput/genobj.cxx deleted file mode 100644 index 1e049d99..00000000 --- a/src/BuildTiles/GenOutput/genobj.cxx +++ /dev/null @@ -1,519 +0,0 @@ -// 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 - http://www.flightgear.org/~curt -// -// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. -// -// $Id: genobj.cxx,v 1.26 2004-11-19 22:25:49 curt Exp $ - - -#include - -#include -#include -#include -#include -#include - -#include -#include - -#include -#include - -#include "genobj.hxx" - -using std::cout; -using std::endl; -using std::string; - - -// calculate the global bounding sphere. Center is the center of the -// tile and zero elevation -void TGGenOutput::calc_gbs( TGConstruct& c ) { - point_list wgs84_nodes = c.get_wgs84_nodes(); - gbs_center = SGVec3d::fromGeod( c.get_bucket().get_center() ); - - double dist_squared, radius_squared = 0; - for ( unsigned int i = 0; i < wgs84_nodes.size(); ++i ) { - dist_squared = distSqr(gbs_center, wgs84_nodes[i].toSGVec3d()); - if ( dist_squared > radius_squared ) { - radius_squared = dist_squared; - } - } - gbs_radius = sqrt(radius_squared); -} - -// build the necessary output structures based on the triangulation -// data -int TGGenOutput::build_fans( TGConstruct& c ) { -// TGTriNodes trinodes = c.get_tri_nodes(); - TGNodes* nodes = c.get_nodes(); - - string tile_id = c.get_bucket().gen_index_str(); - - // copy the geodetic node list into this class - geod_nodes = nodes->get_geod_nodes(); - - // copy the triangle list into this class - tri_elements = c.get_tri_elements(); - - // build the trifan list - cout << "total triangles = " << tri_elements.size() << endl; - - TGGenFans f; - - // Sort the triangles by area type - // TODO: Need to sort on Material type - going to make the attribute an index - // into an array of texparams / material names - for ( unsigned int i = 0; i < TG_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 ( t_current->get_attribute() == i ) { - area_tris.push_back( *t_current ); - } - } - - if ( (int)area_tris.size() > 0 ) { - cout << "generating fans for area = " << i << endl; - primitives[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; - cout << "c.get_useUKGrid() = " << c.get_useUKGrid() << endl; - tex_coords.clear(); - std::vector < SGGeod > convGeodNodes; - for ( unsigned int k = 0; k < geod_nodes.size(); k++ ) { - Point3D node = geod_nodes[k]; - convGeodNodes.push_back( SGGeod::fromDegM( node.x(), node.y(), node.z() ) ); - } - - for ( unsigned int i = 0; i < TG_MAX_AREA_TYPES; ++i ) { - // cout << " area = " << i << endl; - for ( unsigned int j = 0; j < primitives[i].size(); ++j ) { - SG_LOG( SG_CLIPPER, SG_INFO, tile_id << ": Texturing " << get_area_name( (AreaType)i ) << " primitive " << j+1 << " of " << primitives[i].size() ); - - SGBucket b = c.get_bucket(); - Point3D ourPosition; - - ourPosition.setlon(b.get_chunk_lon()); - ourPosition.setlat(b.get_chunk_lat()); - - int_list ti_list; - ti_list.clear(); - - //dcl - here read the flag to check if we are building UK grid - //If so - check if the bucket is within the UK lat & lon - if( (c.get_useUKGrid()) && (isInUK(ourPosition)) ) { - point_list tp_list; - tp_list = UK_calc_tex_coords( b, geod_nodes, primitives[i][j], 1.0 ); - for ( unsigned int k = 0; k < tp_list.size(); ++k ) { - // cout << " tc = " << tp_list[k] << endl; - int index = tex_coords.simple_add( tp_list[k] ); - ti_list.push_back( index ); - } - } else { - std::vector< SGVec2f > tp_list = sgCalcTexCoords( b, convGeodNodes, primitives[i][j] ); - for ( unsigned int k = 0; k < tp_list.size(); ++k ) { - SGVec2f tc = tp_list[k]; - // SG_LOG(SG_GENERAL, SG_DEBUG, "base_tc = " << tc); - int index = tex_coords.simple_add( Point3D( tc.x(), tc.y(), 0 ) ); - 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; -} - - -static opt_list tgGenTris( const triele_list tris ) { - triele_list remaining = tris; - opt_list tri_lists; - int_list tri; - - tri_lists.clear(); - for ( unsigned int i = 0; i < tris.size(); ++i ) { - tri.clear(); - - tri.push_back( tris[i].get_n1() ); - tri.push_back( tris[i].get_n2() ); - tri.push_back( tris[i].get_n3() ); - - tri_lists.push_back( tri ); - } - - return tri_lists; -} - -int TGGenOutput::build_tris( TGConstruct& c ) { -// TGTriNodes trinodes = c.get_tri_nodes(); - TGNodes* nodes = c.get_nodes(); - - string tile_id = c.get_bucket().gen_index_str(); - - // copy the geodetic node list into this class - geod_nodes = nodes->get_geod_nodes(); - - // copy the triangle list into this class - tri_elements = c.get_tri_elements(); - - // build the trifan list - cout << "total triangles = " << tri_elements.size() << endl; - - // Sort the triangles by area type - // TODO: Need to sort on Material type - going to make the attribute an index - // into an array of texparams / material names - for ( unsigned int i = 0; i < TG_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 ( t_current->get_attribute() == i ) { - area_tris.push_back( *t_current ); - } - } - - if ( area_tris.size() > 0 ) { - cout << "generating tris for area = " << i << endl; - primitives[i] = tgGenTris( 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; - cout << "c.get_useUKGrid() = " << c.get_useUKGrid() << endl; - tex_coords.clear(); - std::vector < SGGeod > convGeodNodes; - for ( unsigned int k = 0; k < geod_nodes.size(); k++ ) { - Point3D node = geod_nodes[k]; - convGeodNodes.push_back( SGGeod::fromDegM( node.x(), node.y(), node.z() ) ); - } - - for ( unsigned int i = 0; i < TG_MAX_AREA_TYPES; ++i ) { - // cout << " area = " << i << endl; - for ( unsigned int j = 0; j < primitives[i].size(); ++j ) { - SG_LOG( SG_CLIPPER, SG_INFO, tile_id << ": Texturing " << get_area_name( (AreaType)i ) << " primitive " << j+1 << " of " << primitives[i].size() ); - - SGBucket b = c.get_bucket(); - Point3D ourPosition; - - ourPosition.setlon(b.get_chunk_lon()); - ourPosition.setlat(b.get_chunk_lat()); - - int_list ti_list; - ti_list.clear(); - - //dcl - here read the flag to check if we are building UK grid - //If so - check if the bucket is within the UK lat & lon - if( (c.get_useUKGrid()) && (isInUK(ourPosition)) ) { - point_list tp_list; - tp_list = UK_calc_tex_coords( b, geod_nodes, primitives[i][j], 1.0 ); - for ( unsigned int k = 0; k < tp_list.size(); ++k ) { - // cout << " tc = " << tp_list[k] << endl; - int index = tex_coords.simple_add( tp_list[k] ); - ti_list.push_back( index ); - } - } else { - std::vector< SGVec2f > tp_list = sgCalcTexCoords( b, convGeodNodes, primitives[i][j] ); - for ( unsigned int k = 0; k < tp_list.size(); ++k ) { - SGVec2f tc = tp_list[k]; - // SG_LOG(SG_GENERAL, SG_DEBUG, "base_tc = " << tc); - int index = tex_coords.simple_add( Point3D( tc.x(), tc.y(), 0 ) ); - 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; -} - -// calculate the bounding sphere for a list of triangle faces -void TGGenOutput::calc_group_bounding_sphere( TGConstruct& c, - const opt_list& primitives, - Point3D *center, double *radius ) -{ - cout << "calculate group bounding sphere for " << primitives.size() << " primitives." << endl; - - point_list wgs84_nodes = c.get_wgs84_nodes(); - - // generate a list of unique points from the triangle list - TGTriNodes nodes; - - const_opt_list_iterator f_current = primitives.begin(); - const_opt_list_iterator f_last = primitives.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); -} - - -// calculate the bounding sphere for the specified triangle face -void TGGenOutput::calc_bounding_sphere( TGConstruct& c, const TGTriEle& 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 (using fans) -int TGGenOutput::write_fans( TGConstruct &c ) { - // Assemble all the data into the final format - - SGBucket b = c.get_bucket(); - string base = c.get_output_base(); - string name = b.gen_index_str(); - name += ".btg"; - - std::vector< SGVec3d > wgs84_nodes; - for ( unsigned int i = 0; i < c.get_wgs84_nodes().size(); i++ ) { - Point3D node = c.get_wgs84_nodes()[i]; - wgs84_nodes.push_back( node.toSGVec3d() ); - } - std::vector< SGVec3f > normals; - for ( unsigned int i = 0; i < c.get_point_normals().size(); i++ ) { - Point3D node = c.get_point_normals()[i]; - normals.push_back( node.toSGVec3f() ); - } - cout << "dumping normals = " << normals.size() << endl; - /* for ( i = 0; i < (int)normals.size(); ++i ) { - Point3D p = normals[i]; - printf("vn %.5f %.5f %.5f\n", p.x(), p.y(), p.z()); - } */ - std::vector< SGVec2f > texcoords; - for ( unsigned int i = 0; i < tex_coords.get_node_list().size(); i++ ) { - Point3D node = tex_coords.get_node_list()[i]; - texcoords.push_back( node.toSGVec2f() ); - } - - // allocate and initialize triangle group structures - group_list tris_v; group_list tris_tc; string_list tri_materials; - tris_v.clear(); tris_tc.clear(); tri_materials.clear(); - - group_list strips_v; group_list strips_tc; string_list strip_materials; - strips_v.clear(); strips_tc.clear(); strip_materials.clear(); - - group_list fans_v; group_list fans_tc; string_list fan_materials; - fans_v.clear(); fans_tc.clear(); fan_materials.clear(); - - for ( unsigned int i = 0; i < TG_MAX_AREA_TYPES; ++i ) { - if ( primitives[i].size() > 0 ) { - cout << "creating " << primitives[i].size() << " fans of type " << i << endl; - string attr_name = get_area_name( (AreaType)i ); - - int_list vs, tcs; - for ( unsigned int j = 0; j < primitives[i].size(); ++j ) { - vs.clear(); tcs.clear(); - for ( unsigned int k = 0; k < primitives[i][j].size(); ++k ) { - vs.push_back( primitives[i][j][k] ); - tcs.push_back( textures[i][j][k] ); - } - fans_v.push_back( vs ); - fans_tc.push_back( tcs ); - fan_materials.push_back( attr_name ); - } - } - } - - SGBinObject obj; - - obj.set_gbs_center( gbs_center ); - obj.set_gbs_radius( gbs_radius ); - obj.set_wgs84_nodes( wgs84_nodes ); - obj.set_normals( normals ); - obj.set_texcoords( texcoords ); - obj.set_tris_v( tris_v ); - obj.set_tris_tc( tris_tc ); - obj.set_tri_materials( tri_materials ); - obj.set_strips_v( strips_v ); - obj.set_strips_tc( strips_tc ); - obj.set_strip_materials( strip_materials ); - obj.set_fans_v( fans_v ); - obj.set_fans_tc( fans_tc ); - obj.set_fan_materials( fan_materials ); - - obj.write_bin( base, name, b ); - - return 1; -} - -// write out the fgfs scenery file (using tris) -int TGGenOutput::write_tris( TGConstruct &c ) { - // Assemble all the data into the final format - - SGBucket b = c.get_bucket(); - string base = c.get_output_base(); - string name = b.gen_index_str(); - name += ".btg"; - - std::vector< SGVec3d > wgs84_nodes; - for ( unsigned int i = 0; i < c.get_wgs84_nodes().size(); i++ ) { - Point3D node = c.get_wgs84_nodes()[i]; - wgs84_nodes.push_back( node.toSGVec3d() ); - } - std::vector< SGVec3f > normals; - for ( unsigned int i = 0; i < c.get_point_normals().size(); i++ ) { - Point3D node = c.get_point_normals()[i]; - normals.push_back( node.toSGVec3f() ); - } - cout << "dumping normals = " << normals.size() << endl; - /* for ( i = 0; i < (int)normals.size(); ++i ) { - Point3D p = normals[i]; - printf("vn %.5f %.5f %.5f\n", p.x(), p.y(), p.z()); - } */ - std::vector< SGVec2f > texcoords; - for ( unsigned int i = 0; i < tex_coords.get_node_list().size(); i++ ) { - Point3D node = tex_coords.get_node_list()[i]; - texcoords.push_back( node.toSGVec2f() ); - } - - // allocate and initialize triangle group structures - group_list tris_v; group_list tris_tc; string_list tri_materials; - tris_v.clear(); tris_tc.clear(); tri_materials.clear(); - - group_list strips_v; group_list strips_tc; string_list strip_materials; - strips_v.clear(); strips_tc.clear(); strip_materials.clear(); - - group_list fans_v; group_list fans_tc; string_list fan_materials; - fans_v.clear(); fans_tc.clear(); fan_materials.clear(); - - for ( unsigned int i = 0; i < TG_MAX_AREA_TYPES; ++i ) { - if ( primitives[i].size() > 0 ) { - cout << "creating " << primitives[i].size() << " tris of type " << i << endl; - string attr_name = get_area_name( (AreaType)i ); - - int_list vs, tcs; - for ( unsigned int j = 0; j < primitives[i].size(); ++j ) { - vs.clear(); tcs.clear(); - for ( unsigned int k = 0; k < primitives[i][j].size(); ++k ) { - vs.push_back( primitives[i][j][k] ); - tcs.push_back( textures[i][j][k] ); - } - tris_v.push_back( vs ); - tris_tc.push_back( tcs ); - tri_materials.push_back( attr_name ); - } - } - } - - SGBinObject obj; - - obj.set_gbs_center( gbs_center ); - obj.set_gbs_radius( gbs_radius ); - obj.set_wgs84_nodes( wgs84_nodes ); - obj.set_normals( normals ); - obj.set_texcoords( texcoords ); - obj.set_tris_v( tris_v ); - obj.set_tris_tc( tris_tc ); - obj.set_tri_materials( tri_materials ); - obj.set_strips_v( strips_v ); - obj.set_strips_tc( strips_tc ); - obj.set_strip_materials( strip_materials ); - obj.set_fans_v( fans_v ); - obj.set_fans_tc( fans_tc ); - obj.set_fan_materials( fan_materials ); - - obj.write_bin( base, name, b ); - - return 1; -} diff --git a/src/BuildTiles/GenOutput/genobj.hxx b/src/BuildTiles/GenOutput/genobj.hxx deleted file mode 100644 index ab3d605b..00000000 --- a/src/BuildTiles/GenOutput/genobj.hxx +++ /dev/null @@ -1,107 +0,0 @@ -// 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 - http://www.flightgear.org/~curt -// -// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. -// -// $Id: genobj.hxx,v 1.9 2004-11-19 22:25:49 curt Exp $ - - -#ifndef _GENOBJ_HXX -#define _GENOBJ_HXX - - -#ifndef __cplusplus -# error This library requires C++ -#endif - - -#include - -#include -#include -#include -#include - -#include -#include
-#include - -typedef std::vector < int_list > tex_list; -typedef tex_list::iterator tex_list_iterator; -typedef tex_list::const_iterator const_tex_list_iterator; - -class TGGenOutput { - -private: - - // node list in geodetic coordinates - point_list geod_nodes; - - // triangles (by index into point list) - triele_list tri_elements; - - // texture coordinates - TGTriNodes tex_coords; - - // fan / triangle list - opt_list primitives[TG_MAX_AREA_TYPES]; - - // textures pointer list - tex_list textures[TG_MAX_AREA_TYPES]; - - // global bounding sphere - SGVec3d gbs_center; - double gbs_radius; - - // calculate the global bounding sphere. Center is the average of - // the points. - void calc_gbs( TGConstruct& c ); - - // caclulate the bounding sphere for a list of triangle faces - void calc_group_bounding_sphere( TGConstruct& c, const opt_list& fans, - Point3D *center, double *radius ); - - // caclulate the bounding sphere for the specified triangle face - void calc_bounding_sphere( TGConstruct& c, const TGTriEle& t, - Point3D *center, double *radius ); - - // traverse the specified fan and attempt to calculate "none - // stretching" texture coordinates - // int_list calc_tex_coords( TGConstruct& c, point_list geod_nodes, int_list fan ); - -public: - - // Constructor && Destructor - inline TGGenOutput() { } - inline ~TGGenOutput() { } - - // build the necessary output structures based on the - // triangulation data - int build_fans( TGConstruct& c ); - int build_tris( TGConstruct& c ); - - // write out the fgfs scenery file - int write_fans( TGConstruct &c ); - int write_tris( TGConstruct &c ); -}; - - -#endif // _GENOBJ_HXX - - diff --git a/src/BuildTiles/Main/CMakeLists.txt b/src/BuildTiles/Main/CMakeLists.txt index 7eba5e69..7c25b57b 100644 --- a/src/BuildTiles/Main/CMakeLists.txt +++ b/src/BuildTiles/Main/CMakeLists.txt @@ -1,18 +1,22 @@ add_executable(fgfs-construct - construct.cxx construct.hxx - usgs.cxx main.cxx) + construct.cxx + construct.hxx + priorities.cxx + priorities.hxx + usgs.cxx + main.cxx) set_target_properties(fgfs-construct PROPERTIES COMPILE_DEFINITIONS "DEFAULT_USGS_MAPFILE=\"${PKGDATADIR}/usgsmap.txt\";DEFAULT_PRIORITIES_FILE=\"${PKGDATADIR}/default_priorities.txt\"" ) target_link_libraries(fgfs-construct - Clipper GenOutput Osgb36 Triangulate + Osgb36 Match Polygon Geometry - Array Optimize Output landcover poly2tri + Array Optimize landcover poly2tri TriangleJRS ${GDAL_LIBRARY} ${SIMGEAR_CORE_LIBRARIES} @@ -20,15 +24,6 @@ target_link_libraries(fgfs-construct ${GPC_LIBRARY}) install(TARGETS fgfs-construct RUNTIME DESTINATION bin) + INSTALL(FILES usgsmap.txt DESTINATION ${PKGDATADIR} ) - - -add_executable(fgfs-master - master.cxx) - -target_link_libraries(fgfs-master - ${SIMGEAR_CORE_LIBRARIES} - ${SIMGEAR_CORE_LIBRARY_DEPENDENCIES} - ) - -install(TARGETS fgfs-master RUNTIME DESTINATION bin) +INSTALL(FILES default_priorities.txt DESTINATION ${PKGDATADIR} ) diff --git a/src/BuildTiles/Main/construct.cxx b/src/BuildTiles/Main/construct.cxx index dc3ba319..7b772128 100644 --- a/src/BuildTiles/Main/construct.cxx +++ b/src/BuildTiles/Main/construct.cxx @@ -25,8 +25,43 @@ # include #endif -#include "construct.hxx" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include "construct.hxx" +#include "usgs.hxx" + +using std::string; + +double gSnap = 0.00000001; // approx 1 mm + +static const double cover_size = 1.0 / 120.0; +static const double half_cover_size = cover_size * 0.5; + +// If we don't offset land use squares by some amount, then we can get +// land use square boundaries coinciding with tile boundaries. +// +// This can foul up our edge matching scheme because a subsequently +// generated adjacent tile might be forced to have edge nodes not +// found in the first tile and not on the shared edge. This can lead +// to gaps. If we put skirts around everything that might hide the +// problem. +static const double quarter_cover_size = cover_size * 0.25; // Constructor TGConstruct::TGConstruct(): @@ -38,3 +73,1552 @@ TGConstruct::TGConstruct(): // Destructor TGConstruct::~TGConstruct() { } + +// Load elevation data from an Array file, a regular grid of elevation +// data) and return list of fitted nodes. +bool TGConstruct::load_array() { + string base = bucket.gen_base_path(); + int i; + + for ( i = 0; i < (int)load_dirs.size(); ++i ) { + string array_path = get_work_base() + "/" + load_dirs[i] + "/" + base + "/" + bucket.gen_index_str(); + + if ( array.open(array_path) ) { + break; + } else { + SG_LOG(SG_GENERAL, SG_ALERT, "Failed to open Array file " << array_path); + } + } + + array.parse( bucket ); + array.remove_voids( ); + + return true; +} + +// Add a polygon to the clipper. +void TGConstruct::add_poly( int area, const TGPolygon &poly, string material ) { + TGSuperPoly sp; + + if ( area < TG_MAX_AREA_TYPES ) { + sp.set_poly( poly ); + sp.set_material( material ); + + polys_in.superpolys[area].push_back(sp); + } else { + SG_LOG( SG_CLIPPER, SG_ALERT, "Polygon type out of range = " << area); + exit(-1); + } +} + +// Load a polygon definition file. +bool TGConstruct::load_poly(const string& path) { + bool poly3d = false; + string first_line; + string poly_name; + AreaType poly_type; + int contours, count, i, j; + int hole_flag; + double startx, starty, startz, x, y, z, lastx, lasty, lastz; + + sg_gzifstream in( path ); + + if ( !in ) { + SG_LOG( SG_CLIPPER, SG_ALERT, "Cannot open file: " << path ); + exit(-1); + } + + TGPolygon poly; + + Point3D p; + // (this could break things, why is it here) in >> skipcomment; + while ( !in.eof() ) { + in >> first_line; + if ( first_line == "#2D" ) { + poly3d = false; + in >> poly_name; + } else if ( first_line == "#3D" ) { + poly3d = true; + in >> poly_name; + } else { + // support old format (default to 2d) + poly3d = false; + poly_name = first_line; + } + poly_type = get_area_type( poly_name ); + in >> contours; + + SG_LOG( SG_CLIPPER, SG_INFO, "Loading " << path << ":" << poly_name << "-" << poly_type << " contours = " << contours ); + + poly.erase(); + + for ( i = 0; i < contours; ++i ) { + in >> count; + + if ( count < 3 ) { + SG_LOG( SG_CLIPPER, SG_ALERT, "Polygon with less than 3 data points." ); + exit(-1); + } + + in >> hole_flag; + + in >> startx; + in >> starty; + if ( poly3d ) { + in >> startz; + } else { + startz = -9999.0; + } + + p = Point3D(startx+nudge, starty+nudge, startz); + p.snap( gSnap ); + poly.add_node( i, p ); + + if ( poly3d ) { + nodes.unique_add_fixed_elevation( p ); + } else { + nodes.unique_add( p ); + } + + for ( j = 1; j < count - 1; ++j ) { + in >> x; + in >> y; + if ( poly3d ) { + in >> z; + } else { + z = -9999.0; + } + p = Point3D( x+nudge, y+nudge, z ); + p.snap( gSnap ); + poly.add_node( i, p ); + if ( poly3d ) { + nodes.unique_add_fixed_elevation( p ); + } else { + nodes.unique_add( p ); + } + } + + in >> lastx; + in >> lasty; + if ( poly3d ) { + in >> lastz; + } else { + lastz = -9999.0; + } + + if ( (fabs(startx - lastx) < SG_EPSILON) && + (fabs(starty - lasty) < SG_EPSILON) && + (fabs(startz - lastz) < SG_EPSILON) ) { + // last point same as first, discard + } else { + p = Point3D( lastx+nudge, lasty+nudge, lastz ); + p.snap( gSnap ); + poly.add_node( i, p ); + if ( poly3d ) { + nodes.unique_add_fixed_elevation( p ); + } else { + nodes.unique_add( p ); + } + } + } + + poly = remove_dups( poly ); + + int area = (int)poly_type; + string material = get_area_name( area ); + + add_poly(area, poly, material); + + in >> skipcomment; + } + + return true; +} + + +// Load a polygon definition file containing osgb36 Eastings and Northings +// and convert them to WGS84 Latitude and Longitude +bool TGConstruct::load_osgb36_poly(const string& path) { + string poly_name; + AreaType poly_type; + int contours, count, i, j; + int hole_flag; + double startx, starty, x, y, lastx, lasty; + + SG_LOG( SG_CLIPPER, SG_INFO, "Loading " << path << " ..." ); + + sg_gzifstream in( path ); + + if ( !in ) { + SG_LOG( SG_CLIPPER, SG_ALERT, "Cannot open file: " << path ); + exit(-1); + } + + TGPolygon poly; + + Point3D p; + Point3D OSRef; + in >> skipcomment; + while ( !in.eof() ) { + in >> poly_name; + SG_LOG( SG_CLIPPER, SG_INFO, "poly name = " << poly_name); + poly_type = get_area_type( poly_name ); + SG_LOG( SG_CLIPPER, SG_INFO, "poly type (int) = " << (int)poly_type); + in >> contours; + SG_LOG( SG_CLIPPER, SG_INFO, "num contours = " << contours); + + poly.erase(); + + for ( i = 0; i < contours; ++i ) { + in >> count; + + if ( count < 3 ) { + SG_LOG( SG_CLIPPER, SG_ALERT, "Polygon with less than 3 data points." ); + exit(-1); + } + + in >> hole_flag; + + in >> startx; + in >> starty; + OSRef = Point3D(startx, starty, -9999.0); + + //Convert from OSGB36 Eastings/Northings to WGS84 Lat/Lon + //Note that startx and starty themselves must not be altered since we compare them with unaltered lastx and lasty later + p = OSGB36ToWGS84(OSRef); + + poly.add_node( i, p ); + nodes.unique_add( p ); + + SG_LOG( SG_CLIPPER, SG_BULK, "0 = " << startx << ", " << starty ); + + for ( j = 1; j < count - 1; ++j ) { + in >> x; + in >> y; + OSRef = Point3D( x, y, -9999.0 ); + p = OSGB36ToWGS84(OSRef); + + poly.add_node( i, p ); + nodes.unique_add( p ); + SG_LOG( SG_CLIPPER, SG_BULK, j << " = " << x << ", " << y ); + } + + in >> lastx; + in >> lasty; + + if ( (fabs(startx - lastx) < SG_EPSILON) && + (fabs(starty - lasty) < SG_EPSILON) ) { + // last point same as first, discard + } else { + OSRef = Point3D( lastx, lasty, -9999.0 ); + p = OSGB36ToWGS84(OSRef); + + poly.add_node( i, p ); + nodes.unique_add( p ); + SG_LOG( SG_CLIPPER, SG_BULK, count - 1 << " = " << lastx << ", " << lasty ); + } + } + + int area = (int)poly_type; + string material = get_area_name( area ); + + add_poly(area, poly, material); + + in >> skipcomment; + } + + return true; +} + +// load all 2d polygons from the specified load disk directories and +// clip against each other to resolve any overlaps +int TGConstruct::load_polys( ) { + int i; + + string base = bucket.gen_base_path(); + string poly_path; + int count = 0; + + for ( int i = 0; i < TG_MAX_AREA_TYPES; ++i ) { + polys_in.superpolys[i].clear(); + } + + // load 2D polygons from all directories provided + for ( i = 0; i < (int)load_dirs.size(); ++i ) { + poly_path = get_work_base() + "/" + load_dirs[i] + '/' + base; + SG_LOG(SG_GENERAL, SG_ALERT, "poly_path = " << poly_path); + +// count += actual_load_polys( poly_path ); + string tile_str = bucket.gen_index_str(); + + simgear::Dir d(poly_path); + if (!d.exists()) { + SG_LOG(SG_GENERAL, SG_ALERT, "directory not found:" << poly_path); + continue; + } + + simgear::PathList files = d.children(simgear::Dir::TYPE_FILE); + BOOST_FOREACH(const SGPath& p, files) { + if (p.file_base() != tile_str) { + continue; + } + + string lext = p.complete_lower_extension(); + if ((lext == "arr") || (lext == "arr.gz") || (lext == "btg.gz") || + (lext == "fit") || (lext == "fit.gz") || (lext == "ind")) + { + // skipped! + } else if (lext == "osgb36") { + SG_LOG(SG_GENERAL, SG_ALERT, "Loading osgb36 poly definition file"); + load_osgb36_poly( p.str() ); + ++count; + } else { + load_poly( p.str() ); + ++count; + } + } // of directory file children + + SG_LOG(SG_GENERAL, SG_ALERT, " loaded " << count << " total polys"); + } + + return count; +} + +// Add a polygon to a list, merging if possible. +// +// Merge a polygon with an existing one if possible, append a new one +// otherwise; this function is used by actual_load_landcover, below, +// to reduce the number of separate polygons. +void TGConstruct::add_to_polys ( TGPolygon &accum, const TGPolygon &poly) { + if ( accum.contours() > 0 ) { + accum = tgPolygonUnion( accum, poly ); + } else { + accum = poly; + } +} + +// make the area specified area, look up the land cover type, and add +// it to polys +void TGConstruct::make_area( const LandCover &cover, TGPolygon *polys, + double x1, double y1, double x2, double y2, + double half_dx, double half_dy ) +{ + const double fudge = 0.0001; // (0.0001 degrees =~ 10 meters) + + AreaType area = get_landcover_type( cover, + x1 + half_dx, y1 + half_dy, + x2 - x1, y2 - y1 ); + + if ( area != get_default_area_type() ) { + // Create a square polygon and merge it into the list. + TGPolygon poly; + poly.erase(); + poly.add_node(0, Point3D(x1 - fudge, y1 - fudge, 0.0)); + poly.add_node(0, Point3D(x1 - fudge, y2 + fudge, 0.0)); + poly.add_node(0, Point3D(x2 + fudge, y2 + fudge, 0.0)); + poly.add_node(0, Point3D(x2 + fudge, y1 - fudge, 0.0)); + + if ( measure_roughness( poly ) < 1.0 ) { + add_to_polys(polys[area], poly); + } + } +} + +// Come up with a "rough" metric for the roughness of the terrain +// coverted by a polygon +double TGConstruct::measure_roughness( TGPolygon &poly ) { + int i; + unsigned int j; + + // find the elevation range + double max_z = -9999.0; + double min_z = 9999.0; + + for ( i = 0; i < poly.contours(); ++i ) { + point_list points = poly.get_contour( i ); + for ( j = 0; j < points.size(); ++j ) { + double z; + z = array.altitude_from_grid( points[j].x() * 3600.0, + points[j].y() * 3600.0 ); + if ( z < -9000 ) { + z = array.closest_nonvoid_elev( points[j].x() * 3600.0, + points[j].y() * 3600.0 ); + } + // cout << "elevation = " << z << endl; + if ( z < min_z ) { + min_z = z; + } + if ( z > max_z ) { + max_z = z; + } + } + } + + double diff = max_z - min_z; + + // 50m difference in polygon elevation range yields a roughness + // metric of 1.0. Less than 1.0 is relatively flat. More than + // 1.0 is relatively rough. + + SG_LOG(SG_GENERAL, SG_ALERT, "roughness = " << diff / 50.0 ); + + return diff / 50.0; +} + +AreaType TGConstruct::get_landcover_type (const LandCover &cover, double xpos, double ypos, double dx, double dy) +{ + // Look up the land cover for the square + int cover_value = cover.getValue(xpos, ypos); + AreaType area = translateUSGSCover(cover_value); + + if ( area != get_default_area_type() ) { + // Non-default area is fine. + return area; + } else { + // If we're stuck with the default area, try to borrow from a + // neighbour. + for (double x = xpos - dx; x <= xpos + dx; x += dx) { + for (double y = ypos - dy; y < ypos + dx; y += dy) { + if (x != xpos || y != ypos) { + cover_value = cover.getValue(x, y); + area = translateUSGSCover(cover_value); + if (area != get_default_area_type() ) { + return area; + } + } + } + } + } + + // OK, give up and return default + return get_default_area_type(); +} + + +// Generate polygons from land-cover raster. Horizontally- or +// vertically-adjacent polygons will be merged automatically. +int TGConstruct::load_landcover() +{ + int count = 0; + + try { + + LandCover cover(get_cover()); + TGPolygon polys[TG_MAX_AREA_TYPES]; + TGPolygon poly; // working polygon + + // Get the lower left (SW) corner of the tile + double base_lon = bucket.get_center_lon() + - 0.5 * bucket.get_width() + - quarter_cover_size; + double base_lat = bucket.get_center_lat() + - 0.5 * bucket.get_height() + - quarter_cover_size; + + SG_LOG(SG_GENERAL, SG_ALERT, "raster land cover: tile at " << base_lon << ',' << base_lat); + + double max_lon = bucket.get_center_lon() + + 0.5 * bucket.get_width(); + double max_lat = bucket.get_center_lat() + + 0.5 * bucket.get_height(); + + SG_LOG(SG_GENERAL, SG_ALERT, "raster land cover: extends to " << max_lon << ',' << max_lat); + + double x1 = base_lon; + double y1 = base_lat; + double x2 = x1 + cover_size; + double y2 = y1 + cover_size; + + while ( x1 < max_lon ) { + while ( y1 < max_lat ) { + make_area( cover, polys, x1, y1, x2, y2, half_cover_size, half_cover_size ); + + y1 = y2; + y2 += cover_size; + } + + x1 = x2; + x2 += cover_size; + y1 = base_lat; + y2 = y1 + cover_size; + } + + // Now that we're finished looking up land cover, we have a list + // of lists of polygons, one (possibly-empty) list for each area + // type. Add the remaining polygons to the clipper. + for ( int i = 0; i < TG_MAX_AREA_TYPES; i++ ) { + if ( polys[i].contours() ) { + add_poly( i, polys[i], get_area_name((AreaType)i )); + count++; + } + } + } catch ( string e ) { + SG_LOG(SG_GENERAL, SG_ALERT, "Died with exception: " << e); + exit(-1); + } + + // Return the number of polygons actually read. + return count; +} + +void TGConstruct::add_intermediate_nodes( ) { + int before, after; + + // traverse each poly, and add intermediate nodes + for ( unsigned int i = 0; i < TG_MAX_AREA_TYPES; ++i ) { + for( unsigned int j = 0; j < polys_clipped.superpolys[i].size(); ++j ) { + TGPolygon current = polys_clipped.superpolys[i][j].get_poly(); + + before = current.total_size(); + current = add_tgnodes_to_poly( current, &nodes ); + after = current.total_size(); + + if (before != after) { + SG_LOG( SG_CLIPPER, SG_INFO, "Fixed t-juntions is " << get_area_name( (AreaType)i ) << ":" << j << " of " << (int)polys_clipped.superpolys[i].size() << " nodes increased from " << before << " to " << after ); + } + + /* Save it back */ + polys_clipped.superpolys[i][j].set_poly( current ); + } + } +} + +void TGConstruct::calc_gc_course_dist( const Point3D& start, const Point3D& dest, + double *course, double *dist ) +{ + SGGeoc gs = start.toSGGeoc(); + SGGeoc gd = dest.toSGGeoc(); + *course = SGGeoc::courseRad(gs, gd); + *dist = SGGeoc::distanceM(gs, gd); +} + +// calculate spherical distance between two points (lon, lat specified +// in degrees, result returned in meters) +double TGConstruct::distanceSphere( const Point3D p1, const Point3D p2 ) { + Point3D r1( p1.x() * SG_DEGREES_TO_RADIANS, + p1.y() * SG_DEGREES_TO_RADIANS, + p1.z() ); + Point3D r2( p2.x() * SG_DEGREES_TO_RADIANS, + p2.y() * SG_DEGREES_TO_RADIANS, + p2.z() ); + + double course, dist_m; + calc_gc_course_dist( r1, r2, &course, &dist_m ); + + return dist_m; +} + +// fix the elevations of the geodetic nodes +// This should be done in the nodes class itself, except for the need for the triangle type +// hopefully, this will get better when we have the area lookup via superpoly... +void TGConstruct::fix_point_heights() +{ + SG_LOG(SG_GENERAL, SG_ALERT, "fixing node heights"); + + for (int i = 0; i < (int)nodes.size(); ++i) { + TGNode node = nodes.get_node( i ); + Point3D pos = node.GetPosition(); + + if ( !node.GetFixedPosition() ) { + // set elevation as interpolated point from DEM data. + nodes.SetElevation( i, array.altitude_from_grid(pos.x() * 3600.0, pos.y() * 3600.0) ); + } + } + + // now flatten some stuuf + for (int i = 0; i < TG_MAX_AREA_TYPES; i++) { + if ( is_lake_area( (AreaType)i ) ) { + for (int j = 0; j < (int)polys_clipped.superpolys[i].size(); ++j ) { + SG_LOG( SG_CLIPPER, SG_INFO, "Flattening " << get_area_name( (AreaType)i ) << ":" << j << " of " << (int)polys_clipped.superpolys[i].size() ); + + TGPolygon tri_poly = polys_clipped.superpolys[i][j].get_tris(); + for (int k=0; k< tri_poly.contours(); k++) { + if (tri_poly.contour_size(k) != 3) { + SG_LOG(SG_GENERAL, SG_ALERT, "triangle doesnt have 3 nodes" << tri_poly.contour_size(k) ); + exit(0); + } + + double e1, e2, e3, min; + int n1, n2, n3; + + e1 = tri_poly.get_pt( k, 0 ).z(); + n1 = get_nodes()->find( tri_poly.get_pt( k, 0 ) ); + + e2 = tri_poly.get_pt( k, 1 ).z(); + n2 = get_nodes()->find( tri_poly.get_pt( k, 1 ) ); + + e3 = tri_poly.get_pt( k, 2 ).z(); + n3 = get_nodes()->find( tri_poly.get_pt( k, 2 ) ); + + min = e1; + if ( e2 < min ) { min = e2; } + if ( e3 < min ) { min = e3; } + + get_nodes()->SetElevation( n1, min ); + get_nodes()->SetElevation( n2, min ); + get_nodes()->SetElevation( n3, min ); + } + } + } + + if ( is_stream_area( (AreaType)i ) ) { + for (int j = 0; j < (int)polys_clipped.superpolys[i].size(); ++j ) { + SG_LOG( SG_CLIPPER, SG_INFO, "Flattening " << get_area_name( (AreaType)i ) << ":" << j << " of " << (int)polys_clipped.superpolys[i].size() ); + + TGPolygon tri_poly = polys_clipped.superpolys[i][j].get_tris(); + for (int k=0; k< tri_poly.contours(); k++) { + if (tri_poly.contour_size(k) != 3) { + SG_LOG(SG_GENERAL, SG_ALERT, "triangle doesnt have 3 nodes" << tri_poly.contour_size(k) ); + exit(0); + } + + point_list raw_nodes = nodes.get_geod_nodes(); + double e1, e2, e3, min; + int n1, n2, n3; + Point3D p; + + e1 = tri_poly.get_pt( k, 0 ).z(); + n1 = get_nodes()->find( tri_poly.get_pt( k, 0 ) ); + + e2 = tri_poly.get_pt( k, 1 ).z(); + n2 = get_nodes()->find( tri_poly.get_pt( k, 1 ) ); + + e3 = tri_poly.get_pt( k, 2 ).z(); + n3 = get_nodes()->find( tri_poly.get_pt( k, 2 ) ); + + 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 = distanceSphere( p, raw_nodes[n1] ); + double d2 = distanceSphere( p, raw_nodes[n2] ); + double d3 = distanceSphere( p, raw_nodes[n3] ); + + double max1 = d1 * 0.20 + min; + double max2 = d2 * 0.20 + min; + double max3 = d3 * 0.20 + min; + + if ( max1 < e1 ) { get_nodes()->SetElevation( n1, max1 ); } + if ( max2 < e2 ) { get_nodes()->SetElevation( n2, max2 ); } + if ( max3 < e3 ) { get_nodes()->SetElevation( n3, max3 ); } + } + } + } + + if ( is_road_area( (AreaType)i ) ) { + for (int j = 0; j < (int)polys_clipped.superpolys[i].size(); ++j ) { + SG_LOG( SG_CLIPPER, SG_INFO, "Flattening " << get_area_name( (AreaType)i ) << ":" << j << " of " << (int)polys_clipped.superpolys[i].size() ); + + TGPolygon tri_poly = polys_clipped.superpolys[i][j].get_tris(); + for (int k=0; k< tri_poly.contours(); k++) { + if (tri_poly.contour_size(k) != 3) { + SG_LOG(SG_GENERAL, SG_ALERT, "triangle doesnt have 3 nodes" << tri_poly.contour_size(k) ); + exit(0); + } + + point_list raw_nodes = nodes.get_geod_nodes(); + double e1, e2, e3, min; + int n1, n2, n3; + Point3D p; + + e1 = tri_poly.get_pt( k, 0 ).z(); + n1 = get_nodes()->find( tri_poly.get_pt( k, 0 ) ); + + e2 = tri_poly.get_pt( k, 1 ).z(); + n2 = get_nodes()->find( tri_poly.get_pt( k, 1 ) ); + + e3 = tri_poly.get_pt( k, 2 ).z(); + n3 = get_nodes()->find( tri_poly.get_pt( k, 2 ) ); + + 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 = distanceSphere( p, raw_nodes[n1] ); + double d2 = distanceSphere( p, raw_nodes[n2] ); + double d3 = distanceSphere( p, raw_nodes[n3] ); + + double max1 = d1 * 0.30 + min; + double max2 = d2 * 0.30 + min; + double max3 = d3 * 0.30 + min; + + if ( max1 < e1 ) { get_nodes()->SetElevation( n1, max1 ); } + if ( max2 < e2 ) { get_nodes()->SetElevation( n2, max2 ); } + if ( max3 < e3 ) { get_nodes()->SetElevation( n3, max3 ); } + } + } + } + + if ( is_ocean_area( (AreaType)i ) ) { + for (int j = 0; j < (int)polys_clipped.superpolys[i].size(); ++j ) { + TGPolygon tri_poly = polys_clipped.superpolys[i][j].get_tris(); + + SG_LOG( SG_CLIPPER, SG_INFO, "Flattening " << get_area_name( (AreaType)i ) << ":" << j << " of " << (int)polys_clipped.superpolys[i].size() ); + + for (int k=0; k< tri_poly.contours(); k++) { + if (tri_poly.contour_size(k) != 3) { + SG_LOG(SG_GENERAL, SG_ALERT, "triangle doesnt have 3 nodes" << tri_poly.contour_size(k) ); + exit(0); + } + + int n1, n2, n3; + + n1 = get_nodes()->find( tri_poly.get_pt( k, 0 ) ); + n2 = get_nodes()->find( tri_poly.get_pt( k, 1 ) ); + n3 = get_nodes()->find( tri_poly.get_pt( k, 2 ) ); + + SG_LOG(SG_GENERAL, SG_ALERT, "Set Ocean Triangle " << n1 << "," << n2 << "," << n3 << " to 0.0" ); + get_nodes()->SetElevation( n1, 0.0 ); + get_nodes()->SetElevation( n2, 0.0 ); + get_nodes()->SetElevation( n3, 0.0 ); + } + } + } + } +} + +TGPolygon TGConstruct::area_tex_coords( const TGPolygon& tri ) +{ + TGPolygon result; + result.erase(); + + // lots of conversion needed to use simgear API - perhaps we need a new simgear API? + for (int c=0; c conv_geods; + point_list tex_coords; + + for (int i = 0; i < (int)nodes.size(); ++i ) + { + SGGeod conv_geod = SGGeod::fromDegM( nodes[i].x(), nodes[i].y(), nodes[i].z() ); + SG_LOG(SG_GENERAL, SG_DEBUG, "geod pt = " << nodes[i] ); + conv_geods.push_back( conv_geod ); + } + + // now calculate texture coordinates + // generate identity interger list... + std::vector< int > node_idx; + for (int i = 0; i < (int)conv_geods.size(); i++) { + node_idx.push_back(i); + } + + std::vector< SGVec2f > tp_list = sgCalcTexCoords( bucket, conv_geods, node_idx ); + // generate a contour of texture coordinates from the tp list + for (int i = 0; i < (int)tp_list.size(); i++) + { + tex_coords.push_back( Point3D::fromSGVec2( tp_list[i] ) ); + } + result.add_contour( tex_coords, 0 ); + } + + return result; +} + +TGPolygon TGConstruct::linear_tex_coords( const TGPolygon& tri, const TGTexParams& tp ) +{ + TGPolygon result; + int i, j; + + result.erase(); + + Point3D ref = tp.get_ref(); + double width = tp.get_width(); + double length = tp.get_length(); + double heading = tp.get_heading(); + double minu = tp.get_minu(); + double maxu = tp.get_maxu(); + double minv = tp.get_minv(); + double maxv = tp.get_maxv(); + SG_LOG( SG_GENERAL, SG_DEBUG, "section ref = " << ref ); + SG_LOG( SG_GENERAL, SG_DEBUG, " width = " << width ); + SG_LOG( SG_GENERAL, SG_DEBUG, " length = " << length ); + SG_LOG( SG_GENERAL, SG_DEBUG, " heading = " << heading ); + SG_LOG( SG_GENERAL, SG_DEBUG, " minv = " << minv ); + SG_LOG( SG_GENERAL, SG_DEBUG, " maxv = " << maxv ); + SG_LOG( SG_GENERAL, SG_DEBUG, " heading = " << heading ); + + Point3D p, t; + double x, y, tx, ty; + + for ( i = 0; i < tri.contours(); ++i ) + { + for ( j = 0; j < tri.contour_size( i ); ++j ) + { + p = tri.get_pt( i, j ); + SG_LOG(SG_GENERAL, SG_DEBUG, "tex coords for contour " << i << "point " << j << ": " << p ); + + // + // 1. Calculate distance and bearing from the center of + // the feature + // + + // given alt, lat1, lon1, lat2, lon2, calculate starting + // and ending az1, az2 and distance (s). Lat, lon, and + // azimuth are in degrees. distance in meters + double az1, az2, dist; + geo_inverse_wgs_84( 0, ref.y(), ref.x(), p.y(), p.x(), + &az1, &az2, &dist ); + SG_LOG(SG_GENERAL, SG_DEBUG, "basic course from ref = " << az2); + + // + // 2. Rotate this back into a coordinate system where Y + // runs the length of the runway and X runs crossways. + // + + double course = az2 - heading; + while ( course < -360 ) { course += 360; } + while ( course > 360 ) { course -= 360; } + SG_LOG( SG_GENERAL, SG_DEBUG, + " course = " << course << " dist = " << dist ); + + // + // 3. Convert from polar to cartesian coordinates + // + + x = sin( course * SGD_DEGREES_TO_RADIANS ) * dist; + y = cos( course * SGD_DEGREES_TO_RADIANS ) * dist; + SG_LOG(SG_GENERAL, SG_DEBUG, " x = " << x << " y = " << y); + + // + // 4. Map x, y point into texture coordinates + // + double tmp; + + tmp = x / width; + tx = tmp * (maxu - minu) + minu; + + if ( tx < -1.0 ) { tx = -1.0; } + if ( tx > 1.0 ) { tx = 1.0; } + + SG_LOG(SG_GENERAL, SG_DEBUG, " (" << tx << ")"); + + ty = (y/length) + minv; + SG_LOG(SG_GENERAL, SG_DEBUG, " (" << ty << ")"); + + t = Point3D( tx, ty, 0 ); + SG_LOG(SG_GENERAL, SG_DEBUG, " (" << tx << ", " << ty << ")"); + + result.add_node( i, t ); + } + } + + return result; +} + +// collect custom objects and move to scenery area +void TGConstruct::do_custom_objects( ) { + // Create/open the output .stg file for writing + SGPath dest_d(get_output_base().c_str()); + dest_d.append(bucket.gen_base_path().c_str()); + string dest_dir = dest_d.str_native(); + SGPath dest_i(dest_d); + dest_i.append(bucket.gen_index_str()); + dest_i.concat(".stg"); + string dest_ind = dest_i.str_native(); + + FILE *fp; + if ( (fp = fopen( dest_ind.c_str(), "w" )) == NULL ) { + SG_LOG( SG_GENERAL, SG_ALERT, "ERROR: opening " << dest_ind << " for writing!" ); + exit(-1); + } + + // Start with the default custom object which is the base terrain + fprintf(fp, "OBJECT_BASE %s.btg\n", bucket.gen_index_str().c_str()); + + char line[2048]; // big enough? + char token[256]; + char name[256]; + + for ( int i = 0; i < (int)load_dirs.size(); ++i ) { + SGPath base(get_work_base().c_str()); + base.append(load_dirs[i]); + base.append( bucket.gen_base_path() ); + SGPath index(base); + index.append( bucket.gen_index_str() ); + index.concat(".ind"); + string index_file = index.str_native(); + //SG_LOG(SG_GENERAL, SG_ALERT, "Collecting custom objects from " << index_file); + + sg_gzifstream in( index_file ); + + if ( ! in.is_open() ) { + //SG_LOG(SG_GENERAL, SG_ALERT, "No custom objects"); + } else { + while ( ! in.eof() ) { + SG_LOG( SG_GENERAL, SG_INFO, "Collecting custom objects from " << index_file ); + in.getline(line, 2048); + SG_LOG( SG_GENERAL, SG_INFO, "line = " << line ); + + int result = sscanf( line, "%s %s", token, name ); + SG_LOG( SG_GENERAL, SG_INFO, "scanf scanned " << result << " tokens" ); + + if ( result > 0 ) { + SG_LOG( SG_GENERAL, SG_INFO, "token = " << token << " name = " << name ); + + if ( strcmp( token, "OBJECT" ) == 0 ) { + base.append(name); + base.concat(".gz"); + string basecom = base.str_native(); +#ifdef _MSC_VER + string command = "copy " + basecom + " " + dest_dir; +#else + string command = "cp " + basecom + " " + dest_dir; +#endif + SG_LOG( SG_GENERAL, SG_INFO, "running " << command ); + system( command.c_str() ); + + fprintf(fp, "OBJECT %s\n", name); + } else { + fprintf(fp, "%s\n", line); + } + } + } + } + } + + fclose(fp); +} + +// Move slivers from in polygon to out polygon. +void TGConstruct::move_slivers( TGPolygon& in, TGPolygon& out ) { + // traverse each contour of the polygon and attempt to identify + // likely slivers + int i; + + out.erase(); + + double angle_cutoff = 10.0 * SGD_DEGREES_TO_RADIANS; + double area_cutoff = 0.00000008; + 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 ( i = in.contours() - 1; i >= 0; --i ) { + min_angle = in.minangle_contour( i ); + area = in.area_contour( i ); + + 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 ); + } + } + } +} + + +// Attempt to merge slivers into a list of polygons. +// +// 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 TGConstruct::merge_slivers( TGPolyList& clipped, TGPolygon& slivers ) { + TGPolygon poly, result, sliver; + point_list contour; + int original_contours, result_contours; + bool done; + int area, i, j; + + for ( 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 ( area = 0; area < TG_MAX_AREA_TYPES && !done; ++area ) { + + if ( is_hole_area( area ) ) { + // don't merge a non-hole sliver in with a hole + continue; + } + + // cout << " testing area = " << area << " with " + // << clipped.polys[area].size() << " polys" << endl; + for ( j = 0; j < (int)clipped.superpolys[area].size() && !done; ++j ) { + // cout << " polygon = " << j << endl; + poly = clipped.superpolys[area][j].get_poly(); + original_contours = poly.contours(); + result = tgPolygonUnion( poly, sliver ); + result_contours = result.contours(); + + if ( original_contours == result_contours ) { + // cout << " FOUND a poly to merge the sliver with" << endl; + clipped.superpolys[area][j].set_poly( result ); + done = true; + } + } + } + + if ( !done ) { + // cout << "no suitable polys found for sliver merge" << endl; + } + } +} + +bool TGConstruct::clip_all(const point2d& min, const point2d& max) { + TGPolygon accum, tmp; + TGPolygon slivers, remains; + int i, j; + Point3D p; + + SG_LOG( SG_CLIPPER, SG_INFO, "Running master clipper" ); + SG_LOG( SG_CLIPPER, SG_INFO, " (" << min.x << "," << min.y << ") (" << max.x << "," << max.y << ")" ); + + accum.erase(); + + // set up clipping tile : and remember to add the nodes! + polys_in.safety_base.erase(); + + p = Point3D(min.x, min.y, -9999.0); + polys_in.safety_base.add_node( 0, p ); + nodes.unique_add( p ); + + p = Point3D(max.x, min.y, -9999.0); + polys_in.safety_base.add_node( 0, p ); + nodes.unique_add( p ); + + p = Point3D(max.x, max.y, -9999.0); + polys_in.safety_base.add_node( 0, p ); + nodes.unique_add( p ); + + p = Point3D(min.x, max.y, -9999.0); + polys_in.safety_base.add_node( 0, p ); + nodes.unique_add( p ); + + // set up land mask, we clip most things to this since it is our + // best representation of land vs. ocean. If we have other less + // accurate data that spills out into the ocean, we want to just + // clip it. + // also set up a mask for all water and islands + TGPolygon land_mask, water_mask, island_mask; + land_mask.erase(); + water_mask.erase(); + island_mask.erase(); + for ( i = 0; i < TG_MAX_AREA_TYPES; i++ ) { + if ( is_landmass_area( i ) && !ignoreLandmass ) { + for ( unsigned int j = 0; j < polys_in.superpolys[i].size(); ++j ) { + land_mask = tgPolygonUnion( land_mask, polys_in.superpolys[i][j].get_poly() ); + } + } else if ( is_water_area( i ) ) { + for (unsigned int j = 0; j < polys_in.superpolys[i].size(); j++) { + water_mask = tgPolygonUnion( water_mask, polys_in.superpolys[i][j].get_poly() ); + } + } else if ( is_island_area( i ) ) { + for (unsigned int j = 0; j < polys_in.superpolys[i].size(); j++) { + island_mask = tgPolygonUnion( island_mask, polys_in.superpolys[i][j].get_poly() ); + } + } + } + + // process polygons in priority order + for ( i = 0; i < TG_MAX_AREA_TYPES; ++i ) { + SG_LOG( SG_CLIPPER, SG_INFO, "num polys of type (" << i << ") = " << polys_in.superpolys[i].size() ); + for( j = 0; j < (int)polys_in.superpolys[i].size(); ++j ) { + TGPolygon current = polys_in.superpolys[i][j].get_poly(); + + SG_LOG( SG_CLIPPER, SG_INFO, "Clipping " << get_area_name( (AreaType)i ) << ":" << j << " of " << (int)polys_in.superpolys[i].size() ); + + tmp = current; + + // if not a hole, clip the area to the land_mask + if ( !ignoreLandmass && !is_hole_area( i ) ) { + tmp = tgPolygonInt( tmp, land_mask ); + } + + // Airport areas are limited to existing land mass and + // never override water. + // + // 9/26/2005 - CLO: We are going to add the ability to + // manually define airport areas when the default area + // isn't sufficient. It is clear that it is impossible to + // auto-generate correct airport areas in all cases. For + // now we default to topologically continuous scenery and + // wait for people to submit manual fixes. + // + // if ( i == AirportArea ) { + // tmp = tgPolygonInt( tmp, land_mask ); + // tmp = tgPolygonDiff( tmp, water_mask ); + // } + + // if a water area, cut out potential islands + if ( is_water_area( i ) ) { + // clip against island mask + tmp = tgPolygonDiff( tmp, island_mask ); + } + + // clean the poly before operations + // tmp = reduce_degeneracy( tmp ); + + TGPolygon result_union, result_diff; + + if ( accum.contours() == 0 ) { + result_diff = tmp; + result_union = tmp; + } else { + result_diff = tgPolygonDiff( tmp, accum); + result_union = tgPolygonUnion( tmp, accum); + } + + // 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); + + // 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 ) { + TGSuperPoly sp; + string material = get_area_name( (AreaType)i ); + + sp.set_material( material ); + sp.set_poly( result_diff ); + polys_clipped.superpolys[i].push_back( sp ); + } + } + 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 = tgPolygonDiff( 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 ) { + TGSuperPoly sp; + string material = get_area_name(get_sliver_target_area_type()); + + sp.set_material( material ); + sp.set_poly( remains ); + + polys_clipped.superpolys[(int)get_sliver_target_area_type()].push_back(sp); + } + } + + SG_LOG( SG_CLIPPER, SG_INFO, " master clipper finished." ); + + return true; +} + +// master construction routine +void TGConstruct::construct_bucket( SGBucket b ) { + bucket = b; + + SG_LOG(SG_GENERAL, SG_ALERT, "Construct tile, bucket = " << bucket ); + + // STEP 1) Load grid of elevation data (Array) + load_array(); + + // STEP 2) Clip 2D polygons against one another + if ( load_polys() == 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 the land use polygons if the --cover option was specified + if ( get_cover().size() > 0 ) { + load_landcover(); + } + + // Get clip bounds + point2d min, max; + min.x = bucket.get_center_lon() - 0.5 * bucket.get_width(); + min.y = bucket.get_center_lat() - 0.5 * bucket.get_height(); + max.x = bucket.get_center_lon() + 0.5 * bucket.get_width(); + max.y = bucket.get_center_lat() + 0.5 * bucket.get_height(); + + // do clipping + SG_LOG(SG_GENERAL, SG_ALERT, "clipping polygons"); + + clip_all(min, max); + +// SG_LOG(SG_GENERAL, SG_ALERT, "NODE LIST AFTER CLIPPING" ); +// dump_nodes( c ); + + // Make sure we have the elavation nodes in the main node database + // I'd like to do this first, but we get initial tgnodes from clipper + point_list corner_list = array.get_corner_list(); + if ( corner_list.size() == 0 ) { + SG_LOG(SG_GENERAL, SG_ALERT, "corner list is 0 " ); + // exit(0); + } + + for (unsigned int i=0; iunique_add_fixed_elevation(corner_list[i]); + get_nodes()->unique_add(corner_list[i]); + } + + point_list fit_list = array.get_fitted_list(); + for (unsigned int i=0; iunique_add_fixed_elevation(fit_list[i]); + get_nodes()->unique_add(fit_list[i]); + } + + SG_LOG(SG_GENERAL, SG_ALERT, "NODE LIST AFTER FITTING" ); + + // Step 3) Merge in Shared data (just add the nodes to the nodelist) + // When this step is complete, some nodes will have normals (from shared tiles) + // and some will not - need to indicate this in the new node class + + SG_LOG(SG_GENERAL, SG_ALERT, "number of geod nodes = before adding adding shared edges" << get_nodes()->size() ); + + TGMatch m; + m.load_neighbor_shared( bucket, work_base ); + if ( useOwnSharedEdges ) { + m.load_missing_shared( bucket, work_base ); + } + m.add_shared_nodes( this ); + +// SG_LOG(SG_GENERAL, SG_ALERT, "NODE LIST AFTER ADDING SHARED EDGES" ); +// dump_nodes( c ); + + // Step 4) Add intermediate nodes + // need to add another add intermediate nodes function that can handle the new node class + add_intermediate_nodes(); + + // After adding intermediate nodes, clean the polys + clean_clipped_polys(); + + for (int i = 0; i < TG_MAX_AREA_TYPES; i++) { + for (int j = 0; j < (int)polys_clipped.superpolys[i].size(); ++j ) { + TGPolygon poly = polys_clipped.superpolys[i][j].get_poly(); + + SG_LOG( SG_CLIPPER, SG_INFO, "Collecting nodes for " << get_area_name( (AreaType)i ) << ":" << j << " of " << (int)polys_clipped.superpolys[i].size() ); + + for (int k=0; k< poly.contours(); k++) { + for (int l = 0; l < poly.contour_size(k); l++) { + // ensure we have all nodes... + nodes.unique_add( poly.get_pt( k, l ) ); + } + } + } + } + +// SG_LOG(SG_GENERAL, SG_ALERT, "NODE LIST AFTER ADDING CLIPPED POLYS" ); +// dump_nodes( c ); + + // tesselate the polygons and prepair them for final output + point_list extra = nodes.get_geod_nodes(); + for (int i = 0; i < TG_MAX_AREA_TYPES; i++) { + for (int j = 0; j < (int)polys_clipped.superpolys[i].size(); ++j ) { + TGPolygon poly = polys_clipped.superpolys[i][j].get_poly(); + + SG_LOG( SG_CLIPPER, SG_INFO, "Tesselating " << get_area_name( (AreaType)i ) << ":" << j << " of " << (int)polys_clipped.superpolys[i].size() << " : flag = " << polys_clipped.superpolys[i][j].get_flag()); + + TGPolygon tri = polygon_tesselate_alt_with_extra( poly, extra, false ); + TGPolygon tc; + + if ( polys_clipped.superpolys[i][j].get_flag() == "textured" ) { + // SG_LOG(SG_GENERAL, SG_DEBUG, "USE TEXTURE PARAMS for tex coord calculations" ); + // tc = linear_tex_coords( tri, clipped_polys.texparams[i][j] ); + tc = area_tex_coords( tri ); + } else { + // SG_LOG(SG_GENERAL, SG_DEBUG, "USE SIMGEAR for tex coord calculations" ); + tc = area_tex_coords( tri ); + } + + polys_clipped.superpolys[i][j].set_tris( tri ); + polys_clipped.superpolys[i][j].set_texcoords( tc ); + } + } + + // Add triangulation points + for (int i = 0; i < TG_MAX_AREA_TYPES; i++) { + for (int j = 0; j < (int)polys_clipped.superpolys[i].size(); ++j ) { + TGPolygon tri_poly = polys_clipped.superpolys[i][j].get_tris(); + for (int k=0; k< tri_poly.contours(); k++) { + for (int l = 0; l < tri_poly.contour_size(k); l++) { + // ensure we have all nodes... + nodes.unique_add( tri_poly.get_pt( k, l ) ); + } + } + } + } + + // Step 7) Flatten + fix_point_heights(); + +#if 0 + + SG_LOG(SG_GENERAL, SG_ALERT, "REVERSE ELE LOOKUP "); + + // Step 9) Generate face_connected list + // build the node -> element (triangle) reverse lookup table + c.set_reverse_ele_lookup( gen_node_ele_lookup_table( c ) ); + + SG_LOG(SG_GENERAL, SG_ALERT, "FACE NORMALS "); + + // Step 10) Generate Face normals + // build the face normal list + c.set_face_normals( gen_face_normals( c ) ); + + // Step 11) Generate node normals + // calculate the normals for each point in wgs84_nodes + c.set_point_normals( gen_point_normals( c ) ); + + if ( c.get_cover().size() > 0 ) { + // Now for all the remaining "default" land cover polygons, assign + // each one it's proper type from the land use/land cover + // database. + fix_land_cover_assignments( c ); + } + + // Step 12) calculate texture coordinates for each triangle + + // Step 13) Sort the triangle list by material (optional) +#endif + + // write shared data + m.split_tile( bucket, this ); + SG_LOG(SG_GENERAL, SG_ALERT, "Tile Split"); + + if ( writeSharedEdges ) { + SG_LOG(SG_GENERAL, SG_ALERT, "write shared edges"); + + m.write_shared( bucket, this ); + } + +// dump_lat_nodes( c, 32.75 ); + +// TEMP TEMP TEMP TEMP + + TGTriNodes normals, texcoords; + normals.clear(); + texcoords.clear(); + + group_list pts_v; pts_v.clear(); + group_list pts_n; pts_n.clear(); + string_list pt_materials; pt_materials.clear(); + + group_list tris_v; tris_v.clear(); + group_list tris_n; tris_n.clear(); + group_list tris_tc; tris_tc.clear(); + string_list tri_materials; tri_materials.clear(); + + group_list strips_v; strips_v.clear(); + group_list strips_n; strips_n.clear(); + group_list strips_tc; strips_tc.clear(); + string_list strip_materials; strip_materials.clear(); + + int index; + int_list pt_v, tri_v, strip_v; + int_list pt_n, tri_n, strip_n; + int_list tri_tc, strip_tc; + + // calculate "the" normal for this tile + // temporary - generate a single normal + Point3D p; + p.setx( bucket.get_center_lon() * SGD_DEGREES_TO_RADIANS ); + p.sety( bucket.get_center_lat() * SGD_DEGREES_TO_RADIANS ); + p.setz( 0 ); + Point3D vnt = sgGeodToCart( p ); + + SGVec3d tmp( vnt.x(), vnt.y(), vnt.z() ); + tmp = normalize(tmp); + Point3D vn( tmp.x(), tmp.y(), tmp.z() ); + + SG_LOG(SG_GENERAL, SG_DEBUG, "found normal for this airport = " << tmp); + + for (int i = 0; i < TG_MAX_AREA_TYPES; i++) { + // only tesselate non holes + if ( !is_hole_area( i ) ) { + for (int j = 0; j < (int)polys_clipped.superpolys[i].size(); ++j ) { + SG_LOG( SG_CLIPPER, SG_INFO, "Ouput nodes for " << get_area_name( (AreaType)i ) << ":" << j << " of " << (int)polys_clipped.superpolys[i].size() ); + + TGPolygon tri_poly = polys_clipped.superpolys[i][j].get_tris(); + TGPolygon tri_txs = polys_clipped.superpolys[i][j].get_texcoords(); + string material = polys_clipped.superpolys[i][j].get_material(); + + for (int k = 0; k < tri_poly.contours(); ++k) + { + tri_v.clear(); + tri_n.clear(); + tri_tc.clear(); + for (int l = 0; l < tri_poly.contour_size(k); ++l) + { + p = tri_poly.get_pt( k, l ); + index = get_nodes()->find( p ); + if (index < 0) { + SG_LOG(SG_GENERAL, SG_ALERT, "NODE NOT FOUND " << p); + exit(0); + } + + tri_v.push_back( index ); + + // use 'the' normal + index = normals.unique_add( vn ); + tri_n.push_back( index ); + + Point3D tc = tri_txs.get_pt( k, l ); + index = texcoords.unique_add( tc ); + tri_tc.push_back( index ); + } + tris_v.push_back( tri_v ); + tris_n.push_back( tri_n ); + tris_tc.push_back( tri_tc ); + tri_materials.push_back( material ); + } + } + } + } + + std::vector< SGVec3d > wgs84_nodes = nodes.get_wgs84_nodes_as_SGVec3d(); + SGSphered d; + + for (int i = 0; i < (int)wgs84_nodes.size(); ++i) + { + d.expandBy(wgs84_nodes[ i ]); + } + + SGVec3d gbs_center = d.getCenter(); + double gbs_radius = d.getRadius(); + SG_LOG(SG_GENERAL, SG_DEBUG, "gbs center = " << gbs_center); + SG_LOG(SG_GENERAL, SG_DEBUG, "Done with wgs84 node mapping"); + SG_LOG(SG_GENERAL, SG_DEBUG, " center = " << gbs_center << " radius = " << gbs_radius ); + + // null structures + group_list fans_v; fans_v.clear(); + group_list fans_n; fans_n.clear(); + group_list fans_tc; fans_tc.clear(); + string_list fan_materials; fan_materials.clear(); + + string base = get_output_base(); + string binname = bucket.gen_index_str(); + binname += ".btg"; + string txtname = bucket.gen_index_str(); + txtname += ".txt"; + + std::vector< SGVec3f > normals_3f; + for (int i=0; i < (int)normals.get_node_list().size(); i++ ) + { + Point3D node = normals.get_node_list()[i]; + normals_3f.push_back( node.toSGVec3f() ); + } + + std::vector< SGVec2f > texcoords_2f; + for (int i=0; i < (int)texcoords.get_node_list().size(); i++ ) + { + Point3D node = texcoords.get_node_list()[i]; + texcoords_2f.push_back( node.toSGVec2f() ); + } + + SGBinObject obj; + + obj.set_gbs_center( gbs_center ); + obj.set_gbs_radius( gbs_radius ); + obj.set_wgs84_nodes( wgs84_nodes ); + obj.set_normals( normals_3f ); + obj.set_texcoords( texcoords_2f ); + obj.set_pts_v( pts_v ); + obj.set_pts_n( pts_n ); + obj.set_pt_materials( pt_materials ); + obj.set_tris_v( tris_v ); + obj.set_tris_n( tris_n ); + obj.set_tris_tc( tris_tc ); + obj.set_tri_materials( tri_materials ); + obj.set_strips_v( strips_v ); + obj.set_strips_n( strips_n ); + obj.set_strips_tc( strips_tc ); + obj.set_strip_materials( strip_materials ); + obj.set_fans_v( fans_v ); + obj.set_fans_n( fans_n ); + obj.set_fans_tc( fans_tc ); + obj.set_fan_materials( fan_materials ); + + bool result; + result = obj.write_bin( base, binname, bucket ); + if ( !result ) + { + throw sg_exception("error writing file. :-("); + } + result = obj.write_ascii( base, txtname, bucket ); + if ( !result ) + { + throw sg_exception("error writing file. :-("); + } + +// TEMP TEMP TEMP TEMP + +#if 0 + // Step 14) Generate the output + // generate the output + TGGenOutput output; + do_output( c, output ); +#endif + + array.close(); + + // Step 15) Adding custome objects to the .stg file + // collect custom objects and move to scenery area + do_custom_objects(); +} + +void TGConstruct::clean_clipped_polys() { + int i, j; + + // Clean the polys + for ( i = 0; i < TG_MAX_AREA_TYPES; ++i ) { + for( j = 0; j < (int)polys_clipped.superpolys[i].size(); ++j ) { + TGPolygon poly = polys_clipped.superpolys[i][j].get_poly(); + SG_LOG( SG_CLIPPER, SG_INFO, "Cleaning poly " << get_area_name( (AreaType)i ) << ":" << j << " of " << polys_clipped.superpolys[i].size() ); + + poly = snap(poly, gSnap); + poly = remove_dups( poly ); + poly = remove_bad_contours( poly ); + + polys_clipped.superpolys[i][j].set_poly( poly ); + } + } +} + diff --git a/src/BuildTiles/Main/construct.hxx b/src/BuildTiles/Main/construct.hxx index 249831ab..6ad5c2ba 100644 --- a/src/BuildTiles/Main/construct.hxx +++ b/src/BuildTiles/Main/construct.hxx @@ -31,28 +31,42 @@ #endif -// Maximum nodes per tile -#define TG_MAX_NODES 4000 - - -#include +#define TG_MAX_AREA_TYPES 128 #include #include +#include #include +#include +#include + +#include +#include +#include + +#include + +// TO REMOVE +#include #include #include -#include +// TO REMOVE -#include -#include +#include "priorities.hxx" typedef std::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 TGPolyList +{ +public: + superpoly_list superpolys[TG_MAX_AREA_TYPES]; + texparams_list texparams[TG_MAX_AREA_TYPES]; + TGPolygon safety_base; +}; class TGConstruct { @@ -65,10 +79,14 @@ private: std::string work_base; std::string output_base; + std::vector load_dirs; + // flag indicating whether to align texture coords within the UK // with the UK grid bool useUKGrid; + double nudge; + // flag indicating whether this is a rebuild and Shared edge // data should only be used for fitting, but not rewritten bool writeSharedEdges; @@ -80,39 +98,20 @@ private: // flag indicating whether to ignore the landmass bool ignoreLandmass; - // detail level constraints - int min_nodes; - int max_nodes; - // this bucket SGBucket bucket; - // clipped polygons (gpc format) - TGPolyList clipped_polys; + // Elevation data + TGArray array; - // Fixed elevations (from polygon input data with z values - // pre-specified) - node_list fixed_elevations; + // land class polygons + TGPolyList polys_in; + TGPolyList polys_clipped; - // raw node list (after triangulation) - TGTriNodes tri_nodes; + // All Nodes TGNodes 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) - TGTriSegments tri_segs; - - // for each node, a list of triangle indices that contain this node - belongs_to_list reverse_ele_lookup; - + // TODO : Add to superpoly // face normal list (for flat shading) point_list face_normals; @@ -124,6 +123,39 @@ public: // Destructor ~TGConstruct(); + void construct_bucket( SGBucket b ); + bool load_array(); + int load_polys(); + bool load_poly(const std::string& path); + bool load_osgb36_poly(const std::string& path); + void add_poly(int area, const TGPolygon &poly, std::string material); + + void move_slivers( TGPolygon& in, TGPolygon& out ); + void merge_slivers( TGPolyList& clipped, TGPolygon& slivers ); + + bool clip_all(const point2d& min, const point2d& max); + + void add_intermediate_nodes(void); + void clean_clipped_polys(void); + + void calc_gc_course_dist( const Point3D& start, const Point3D& dest, + double *course, double *dist ); + double distanceSphere( const Point3D p1, const Point3D p2 ); + void fix_point_heights(); + + TGPolygon linear_tex_coords( const TGPolygon& tri, const TGTexParams& tp ); + TGPolygon area_tex_coords( const TGPolygon& tri ); + + int load_landcover (); + void add_to_polys( TGPolygon &accum, const TGPolygon &poly); + double measure_roughness( TGPolygon &poly ); + AreaType get_landcover_type (const LandCover &cover, double xpos, double ypos, double dx, double dy); + void make_area( const LandCover &cover, TGPolygon *polys, + double x1, double y1, double x2, double y2, + double half_dx, double half_dy ); + + void do_custom_objects(void); + // land cover file inline std::string get_cover () const { return cover; } inline void set_cover (const std::string &s) { cover = s; } @@ -133,71 +165,29 @@ public: inline void set_work_base( const std::string s ) { work_base = s; } inline std::string get_output_base() const { return output_base; } inline void set_output_base( const std::string s ) { output_base = s; } + inline void set_load_dirs( const std::vector ld ) { load_dirs = ld; } // UK grid flag inline bool get_useUKGrid() const { return useUKGrid; } inline void set_useUKGrid( const bool b ) { useUKGrid = b; } + // Nudge + inline void set_nudge( double n ) { nudge = n; } + // shared edge write flag - inline bool get_write_shared_edges() const { return writeSharedEdges; } inline void set_write_shared_edges( const bool b ) { writeSharedEdges = b; } // own shared edge use flag - inline bool get_use_own_shared_edges() const { return useOwnSharedEdges; } inline void set_use_own_shared_edges( const bool b ) { useOwnSharedEdges = b; } // ignore landmass flag - inline bool get_ignore_landmass() const { return ignoreLandmass; } inline void set_ignore_landmass( const bool b) { ignoreLandmass = b; } - // 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 SGBucket get_bucket() const { return bucket; } - inline void set_bucket( const SGBucket b ) { bucket = b; } - - // clipped polygons - inline TGPolyList get_clipped_polys() const { return clipped_polys; } - inline void set_clipped_polys( TGPolyList p ) { clipped_polys = p; } - - // Fixed elevations (from polygon input data with z values pre-specified) - inline node_list get_fixed_elevations() const { return nodes.get_fixed_elevation_nodes(); } - - // node list (after triangulation) : No need - we won't add nodes.... -// inline TGTriNodes get_tri_nodes() const { return tri_nodes; } -// inline void set_tri_nodes( TGTriNodes n ) { tri_nodes = n; } - + // TODO : REMOVE inline TGNodes* get_nodes() { return &nodes; } - inline void set_nodes( TGNodes n ) { nodes = n; } - - // triangle elements (after triangulation) : No need - will be in the triangulated polygons - inline triele_list get_tri_elements() const { return tri_elements; } - inline void set_tri_elements( triele_list e ) { tri_elements = e; } - inline void set_tri_attribute( int num, AreaType a ) { tri_elements[num].set_attribute( a ); } - - // edge segments (after triangulation) : Same as above - inline TGTriSegments get_tri_segs() const { return tri_segs; } - inline void set_tri_segs( TGTriSegments s ) { tri_segs = s; } // node list in geodetic coords (with fixed elevation) inline point_list get_geod_nodes() const { return nodes.get_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 nodes.get_wgs84_nodes_as_Point3d(); } -// 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; } diff --git a/src/BuildTiles/Clipper/default_priorities.txt b/src/BuildTiles/Main/default_priorities.txt similarity index 94% rename from src/BuildTiles/Clipper/default_priorities.txt rename to src/BuildTiles/Main/default_priorities.txt index 91bbd053..109d568a 100644 --- a/src/BuildTiles/Clipper/default_priorities.txt +++ b/src/BuildTiles/Main/default_priorities.txt @@ -7,6 +7,13 @@ Hole hole # Leave area completely empty Airport other Freeway road Road road +Road-Motorway road +Road-Trunk road +Road-Residential road +Road-Primary road +Road-Secondary road +Road-Tertiary road + Railroad road Asphalt road Pond lake diff --git a/src/BuildTiles/Main/main.cxx b/src/BuildTiles/Main/main.cxx index d38de906..956e58ac 100644 --- a/src/BuildTiles/Main/main.cxx +++ b/src/BuildTiles/Main/main.cxx @@ -42,31 +42,22 @@ #include #include #include +#include #include #include #include #include #include -#include #include #include -#include #include -#include -#include -#include + #include #include -#include -#include -#include -#include -#include -#include #include #include "construct.hxx" @@ -75,552 +66,11 @@ using std::string; using std::vector; +using namespace std; + vector load_dirs; - -static const double cover_size = 1.0 / 120.0; -static const double half_cover_size = cover_size * 0.5; - -// If we don't offset land use squares by some amount, then we can get -// land use square boundaries coinciding with tile boundaries. -// -// This can foul up our edge matching scheme because a subsequently -// generated adjacent tile might be forced to have edge nodes not -// found in the first tile and not on the shared edge. This can lead -// to gaps. If we put skirts around everything that might hide the -// problem. -static const double quarter_cover_size = cover_size * 0.25; double nudge=0.0; - -// Scan a directory and load polygon files. -static int actual_load_polys( const SGPath& dir, TGConstruct& c, TGClipper& clipper ) { - int counter = 0; - string tile_str = c.get_bucket().gen_index_str(); - - simgear::Dir d(dir); - if (!d.exists()) { - SG_LOG(SG_GENERAL, SG_ALERT, "directory not found:" << dir.str()); - return 0; - } - - BOOST_FOREACH(const SGPath& p, d.children(simgear::Dir::TYPE_FILE)) { - if (p.file_base() != tile_str) { - continue; - } - - string lext = p.complete_lower_extension(); - if ((lext == "arr") || (lext == "arr.gz") || (lext == "btg.gz") || - (lext == "fit") || (lext == "fit.gz") || (lext == "ind")) - { - // skipped! - } else if (lext == "osgb36") { - SG_LOG(SG_GENERAL, SG_ALERT, "Loading osgb36 poly definition file"); - clipper.load_osgb36_polys( p.str() ); - ++counter; - } else { - SG_LOG(SG_GENERAL, SG_ALERT, "ext = '" << lext << "'"); - clipper.load_polys( p.str() ); - ++counter; - } - } // of directory file children - - return counter; -} - - -// Add a polygon to a list, merging if possible. -// -// Merge a polygon with an existing one if possible, append a new one -// otherwise; this function is used by actual_load_landcover, below, -// to reduce the number of separate polygons. -static void inline add_to_polys ( TGPolygon &accum, const TGPolygon &poly) { - if ( accum.contours() > 0 ) { - accum = tgPolygonUnion( accum, poly ); - } else { - accum = poly; - } -} - -static AreaType get_area_type (const LandCover &cover, double xpos, double ypos, double dx, double dy) -{ - // Look up the land cover for the square - int cover_value = cover.getValue(xpos, ypos); - AreaType area = translateUSGSCover(cover_value); - - if ( area != get_default_area_type() ) { - // Non-default area is fine. - return area; - } else { - // If we're stuck with the default area, try to borrow from a - // neighbour. - for (double x = xpos - dx; x <= xpos + dx; x += dx) { - for (double y = ypos - dy; y < ypos + dx; y += dy) { - if (x != xpos || y != ypos) { - cover_value = cover.getValue(x, y); - area = translateUSGSCover(cover_value); - if (area != get_default_area_type() ) { - return area; - } - } - } - } - } - - // OK, give up and return default - return get_default_area_type(); -} - - -// Come up with a "rough" metric for the roughness of the terrain -// coverted by a polygon -static double measure_roughness( const TGArray &array, TGPolygon &poly ) { - int i; - unsigned int j; - - // find the elevation range - double max_z = -9999.0; - double min_z = 9999.0; - - for ( i = 0; i < poly.contours(); ++i ) { - point_list points = poly.get_contour( i ); - for ( j = 0; j < points.size(); ++j ) { - double z; - z = array.altitude_from_grid( points[j].x() * 3600.0, - points[j].y() * 3600.0 ); - if ( z < -9000 ) { - z = array.closest_nonvoid_elev( points[j].x() * 3600.0, - points[j].y() * 3600.0 ); - } - // cout << "elevation = " << z << endl; - if ( z < min_z ) { - min_z = z; - } - if ( z > max_z ) { - max_z = z; - } - } - } - - double diff = max_z - min_z; - - // 50m difference in polygon elevation range yields a roughness - // metric of 1.0. Less than 1.0 is relatively flat. More than - // 1.0 is relatively rough. - - SG_LOG(SG_GENERAL, SG_ALERT, "roughness = " << diff / 50.0 ); - - return diff / 50.0; -} - - -// make the area specified area, look up the land cover type, and add -// it to polys -static void make_area( const LandCover &cover, const TGArray &array, TGPolygon *polys, - double x1, double y1, double x2, double y2, - double half_dx, double half_dy ) -{ - const double fudge = 0.0001; // (0.0001 degrees =~ 10 meters) - - AreaType area = get_area_type( cover, - x1 + half_dx, y1 + half_dy, - x2 - x1, y2 - y1 ); - if ( area != get_default_area_type() ) { - // Create a square polygon and merge it into the list. - TGPolygon poly; - poly.erase(); - poly.add_node(0, Point3D(x1 - fudge, y1 - fudge, 0.0)); - poly.add_node(0, Point3D(x1 - fudge, y2 + fudge, 0.0)); - poly.add_node(0, Point3D(x2 + fudge, y2 + fudge, 0.0)); - poly.add_node(0, Point3D(x2 + fudge, y1 - fudge, 0.0)); - - if ( measure_roughness( array, poly ) < 1.0 ) { - add_to_polys(polys[area], poly); - } - } -} - - -// Generate polygons from land-cover raster. Horizontally- or -// vertically-adjacent polygons will be merged automatically. -static int actual_load_landcover ( TGConstruct &c, const TGArray &array, TGClipper &clipper ) -{ - int count = 0; - - try { - - LandCover cover(c.get_cover()); - TGPolygon polys[TG_MAX_AREA_TYPES]; - TGPolygon poly; // working polygon - - // Get the lower left (SW) corner of the tile - double base_lon = c.get_bucket().get_center_lon() - - 0.5 * c.get_bucket().get_width() - - quarter_cover_size; - double base_lat = c.get_bucket().get_center_lat() - - 0.5 * c.get_bucket().get_height() - - quarter_cover_size; - - SG_LOG(SG_GENERAL, SG_ALERT, "raster land cover: tile at " << base_lon << ',' << base_lat); - - double max_lon = c.get_bucket().get_center_lon() - + 0.5 * c.get_bucket().get_width(); - double max_lat = c.get_bucket().get_center_lat() - + 0.5 * c.get_bucket().get_height(); - - SG_LOG(SG_GENERAL, SG_ALERT, "raster land cover: extends to " << max_lon << ',' << max_lat); - - double x1 = base_lon; - double y1 = base_lat; - double x2 = x1 + cover_size; - double y2 = y1 + cover_size; - - while ( x1 < max_lon ) { - while ( y1 < max_lat ) { - make_area( cover, array, polys, x1, y1, x2, y2, half_cover_size, half_cover_size ); - - y1 = y2; - y2 += cover_size; - } - - x1 = x2; - x2 += cover_size; - y1 = base_lat; - y2 = y1 + cover_size; - } - - // Now that we're finished looking up land cover, we have a list - // of lists of polygons, one (possibly-empty) list for each area - // type. Add the remaining polygons to the clipper. - for ( int i = 0; i < TG_MAX_AREA_TYPES; i++ ) { - if ( polys[i].contours() ) { - clipper.add_poly( i, polys[i], get_area_name((AreaType)i )); - count++; - } - } - } catch ( string e ) { - SG_LOG(SG_GENERAL, SG_ALERT, "Died with exception: " << e); - exit(-1); - } - - // Return the number of polygons actually read. - return count; -} - - -// load all 2d polygons from the specified load disk directories and -// clip against each other to resolve any overlaps -static int load_polys( TGConstruct& c, const TGArray &array ) { - TGClipper clipper; - int i; - - string base = c.get_bucket().gen_base_path(); - string poly_path; - int count = 0; - - clipper.nudge = nudge; - clipper.ignore_landmass( c.get_ignore_landmass() ); - - // initialize clipper - clipper.init(); - - // load 2D polygons from all directories provided - for ( i = 0; i < (int)load_dirs.size(); ++i ) { - poly_path = c.get_work_base() + "/" + load_dirs[i] + '/' + base; - SG_LOG(SG_GENERAL, SG_ALERT, "poly_path = " << poly_path); - count += actual_load_polys( poly_path, c, clipper ); - SG_LOG(SG_GENERAL, SG_ALERT, " loaded " << count << " total polys"); - } - - // Load the land use polygons if the --cover option was specified - if ( c.get_cover().size() > 0 ) { - count += actual_load_landcover (c, array, clipper); - } - - 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 - SG_LOG(SG_GENERAL, SG_ALERT, "clipping polygons"); - clipper.clip_all(min, max); - - // update main data repository - c.set_clipped_polys( clipper.get_polys_clipped() ); - // c.set_fixed_elevations( clipper.get_fixed_elevations_nodes() ); - - // really set nodes - c.set_nodes( clipper.get_nodes() ); - - return count; -} - - -// Load elevation data from an Array file, a regular grid of elevation -// data) and return list of fitted nodes. -static bool load_array( TGConstruct& c, TGArray& array) { - string base = c.get_bucket().gen_base_path(); - int i; - - for ( i = 0; i < (int)load_dirs.size(); ++i ) { - string array_path = c.get_work_base() + "/" + load_dirs[i] + "/" + base + "/" + c.get_bucket().gen_index_str(); - SG_LOG(SG_GENERAL, SG_ALERT, "array_path = " << array_path); - - if ( array.open(array_path) ) { - SG_LOG(SG_GENERAL, SG_ALERT, "Found Array file " << array_path); - break; - } else { - SG_LOG(SG_GENERAL, SG_ALERT, "Failed to open Array file " << array_path); - } - } - - SGBucket b = c.get_bucket(); - array.parse( b ); - array.remove_voids(); - - return true; -} - -#if 0 -// triangulate the data for each polygon ( first time before splitting ) -static void first_triangulate( TGConstruct& c, const TGArray& array, TGTriangle& t ) { - // first we need to consolidate the points of the Array fit list and - // all the polygons into a more "Triangle" friendly format - - point_list corner_list = array.get_corner_list(); - point_list fit_list = array.get_fitted_list(); - TGPolyList gpc_polys = c.get_clipped_polys(); - - SG_LOG(SG_GENERAL, SG_ALERT, "ready to build node list and polygons"); - t.build( corner_list, fit_list, gpc_polys ); - SG_LOG(SG_GENERAL, SG_ALERT, "done building node list and polygons"); - - SG_LOG(SG_GENERAL, SG_ALERT, "ready to do triangulation"); - t.run_triangulate( 0.0, 1 ); - SG_LOG(SG_GENERAL, SG_ALERT, "finished triangulation"); -} -#endif - -#if 0 // UNUSED -// triangulate the data for each polygon ( second time after splitting -// and reassembling ) -static void second_triangulate( TGConstruct& c, TGTriangle& t ) { - t.rebuild( c ); - - SG_LOG(SG_GENERAL, SG_ALERT, "done re building node list and polygons"); - SG_LOG(SG_GENERAL, SG_ALERT, "ready to do second triangulation"); - SG_LOG(SG_GENERAL, SG_ALERT, " (pre) nodes = " << c.get_tri_nodes().size()); - SG_LOG(SG_GENERAL, SG_ALERT, " (pre) normals = " << c.get_point_normals().size()); - - t.run_triangulate( 0.0, 2 ); - - SG_LOG(SG_GENERAL, SG_ALERT, " (post) nodes = " << t.get_out_nodes().size()); - SG_LOG(SG_GENERAL, SG_ALERT, "finished second triangulation"); -} -#endif - -inline void calc_gc_course_dist( const Point3D& start, const Point3D& dest, - double *course, double *dist ) -{ - SGGeoc gs = start.toSGGeoc(); - SGGeoc gd = dest.toSGGeoc(); - *course = SGGeoc::courseRad(gs, gd); - *dist = SGGeoc::distanceM(gs, gd); -} - -// calculate spherical distance between two points (lon, lat specified -// in degrees, result returned in meters) -static double distanceSphere( const Point3D p1, const Point3D p2 ) { - Point3D r1( p1.x() * SG_DEGREES_TO_RADIANS, - p1.y() * SG_DEGREES_TO_RADIANS, - p1.z() ); - Point3D r2( p2.x() * SG_DEGREES_TO_RADIANS, - p2.y() * SG_DEGREES_TO_RADIANS, - p2.z() ); - - double course, dist_m; - calc_gc_course_dist( r1, r2, &course, &dist_m ); - - return dist_m; -} - -// fix the elevations of the geodetic nodes -// This should be done in the nodes class itself, except for the need for the triangle type -// hopefully, this will get better when we have the area lookup via superpoly... -static void fix_point_heights( TGConstruct& c, const TGArray& array ) -{ - int i; - double z; - TGPolyList clipped_polys = c.get_clipped_polys(); - point_list raw_nodes = c.get_nodes()->get_geod_nodes(); - - SG_LOG(SG_GENERAL, SG_ALERT, "fixing node heights"); - - for ( i = 0; i < (int)raw_nodes.size(); ++i ) { - // found an elevation we want to preserve - if ( c.get_nodes()->LookupFixedElevation( raw_nodes[i], &z ) ) { - SG_LOG(SG_GENERAL, SG_ALERT, "Found Fixed elevation at " << i << ":" << raw_nodes[i] << " z is " << z ); - } else { - // interpolate point from DEM data. - z = array.altitude_from_grid( raw_nodes[i].x() * 3600.0, - raw_nodes[i].y() * 3600.0 ); - SG_LOG(SG_GENERAL, SG_ALERT, "no Fixed elevation at " << i << ":" << raw_nodes[i] << " z is " << z ); - c.get_nodes()->SetElevation( i, z ); - } - } - - // now flatten some stuuf - for (int i = 0; i < TG_MAX_AREA_TYPES; i++) { - if ( is_lake_area( (AreaType)i ) ) { - for (int j = 0; j < (int)clipped_polys.superpolys[i].size(); ++j ) { - TGPolygon tri_poly = clipped_polys.superpolys[i][j].get_tris(); - for (int k=0; k< tri_poly.contours(); k++) { - if (tri_poly.contour_size(k) != 3) { - SG_LOG(SG_GENERAL, SG_ALERT, "triangle doesnt have 3 nodes" << tri_poly.contour_size(k) ); - exit(0); - } - - double e1, e2, e3, min; - int n1, n2, n3; - - e1 = tri_poly.get_pt( k, 0 ).z(); - n1 = c.get_nodes()->find( tri_poly.get_pt( k, 0 ) ); - - e2 = tri_poly.get_pt( k, 1 ).z(); - n2 = c.get_nodes()->find( tri_poly.get_pt( k, 1 ) ); - - e3 = tri_poly.get_pt( k, 2 ).z(); - n3 = c.get_nodes()->find( tri_poly.get_pt( k, 2 ) ); - - min = e1; - if ( e2 < min ) { min = e2; } - if ( e3 < min ) { min = e3; } - - c.get_nodes()->SetElevation( n1, min ); - c.get_nodes()->SetElevation( n2, min ); - c.get_nodes()->SetElevation( n3, min ); - } - } - } - - if ( is_stream_area( (AreaType)i ) ) { - for (int j = 0; j < (int)clipped_polys.superpolys[i].size(); ++j ) { - TGPolygon tri_poly = clipped_polys.superpolys[i][j].get_tris(); - for (int k=0; k< tri_poly.contours(); k++) { - if (tri_poly.contour_size(k) != 3) { - SG_LOG(SG_GENERAL, SG_ALERT, "triangle doesnt have 3 nodes" << tri_poly.contour_size(k) ); - exit(0); - } - - double e1, e2, e3, min; - int n1, n2, n3; - Point3D p; - - e1 = tri_poly.get_pt( k, 0 ).z(); - n1 = c.get_nodes()->find( tri_poly.get_pt( k, 0 ) ); - - e2 = tri_poly.get_pt( k, 1 ).z(); - n2 = c.get_nodes()->find( tri_poly.get_pt( k, 1 ) ); - - e3 = tri_poly.get_pt( k, 2 ).z(); - n3 = c.get_nodes()->find( tri_poly.get_pt( k, 2 ) ); - - 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 = distanceSphere( p, raw_nodes[n1] ); - double d2 = distanceSphere( p, raw_nodes[n2] ); - double d3 = distanceSphere( p, raw_nodes[n3] ); - - double max1 = d1 * 0.20 + min; - double max2 = d2 * 0.20 + min; - double max3 = d3 * 0.20 + min; - - if ( max1 < e1 ) { c.get_nodes()->SetElevation( n1, max1 ); } - if ( max2 < e2 ) { c.get_nodes()->SetElevation( n2, max2 ); } - if ( max3 < e3 ) { c.get_nodes()->SetElevation( n3, max3 ); } - } - } - } - - if ( is_road_area( (AreaType)i ) ) { - for (int j = 0; j < (int)clipped_polys.superpolys[i].size(); ++j ) { - TGPolygon tri_poly = clipped_polys.superpolys[i][j].get_tris(); - for (int k=0; k< tri_poly.contours(); k++) { - if (tri_poly.contour_size(k) != 3) { - SG_LOG(SG_GENERAL, SG_ALERT, "triangle doesnt have 3 nodes" << tri_poly.contour_size(k) ); - exit(0); - } - - double e1, e2, e3, min; - int n1, n2, n3; - Point3D p; - - e1 = tri_poly.get_pt( k, 0 ).z(); - n1 = c.get_nodes()->find( tri_poly.get_pt( k, 0 ) ); - - e2 = tri_poly.get_pt( k, 1 ).z(); - n2 = c.get_nodes()->find( tri_poly.get_pt( k, 1 ) ); - - e3 = tri_poly.get_pt( k, 2 ).z(); - n3 = c.get_nodes()->find( tri_poly.get_pt( k, 2 ) ); - - 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 = distanceSphere( p, raw_nodes[n1] ); - double d2 = distanceSphere( p, raw_nodes[n2] ); - double d3 = distanceSphere( p, raw_nodes[n3] ); - - double max1 = d1 * 0.30 + min; - double max2 = d2 * 0.30 + min; - double max3 = d3 * 0.30 + min; - - if ( max1 < e1 ) { c.get_nodes()->SetElevation( n1, max1 ); } - if ( max2 < e2 ) { c.get_nodes()->SetElevation( n2, max2 ); } - if ( max3 < e3 ) { c.get_nodes()->SetElevation( n3, max3 ); } - } - } - } - - if ( is_ocean_area( (AreaType)i ) ) { - SG_LOG(SG_GENERAL, SG_ALERT, " Flatten the ocean - has " << clipped_polys.superpolys[i].size() << " polys" ); - - for (int j = 0; j < (int)clipped_polys.superpolys[i].size(); ++j ) { - TGPolygon tri_poly = clipped_polys.superpolys[i][j].get_tris(); - - SG_LOG(SG_GENERAL, SG_ALERT, " Flatten the ocean - poly " << j << " has " << tri_poly.contours() << " contours" ); - - for (int k=0; k< tri_poly.contours(); k++) { - if (tri_poly.contour_size(k) != 3) { - SG_LOG(SG_GENERAL, SG_ALERT, "triangle doesnt have 3 nodes" << tri_poly.contour_size(k) ); - exit(0); - } - - int n1, n2, n3; - - n1 = c.get_nodes()->find( tri_poly.get_pt( k, 0 ) ); - n2 = c.get_nodes()->find( tri_poly.get_pt( k, 1 ) ); - n3 = c.get_nodes()->find( tri_poly.get_pt( k, 2 ) ); - - SG_LOG(SG_GENERAL, SG_ALERT, "Set Ocean Triangle " << n1 << "," << n2 << "," << n3 << " to 0.0" ); - c.get_nodes()->SetElevation( n1, 0.0 ); - c.get_nodes()->SetElevation( n2, 0.0 ); - c.get_nodes()->SetElevation( n3, 0.0 ); - } - } - } - } -} - - #if 0 // For each triangle assigned to the "default" area type, see if we // can lookup a better land cover type from the 1km data structure. @@ -686,38 +136,7 @@ static void fix_land_cover_assignments( TGConstruct& c ) { } #endif - -#if 0 // Handled by TGNodes -// build the wgs-84 point list -static void build_wgs_84_point_list( TGConstruct& c, const TGArray& array ) { - point_list geod_nodes; - point_list wgs84_nodes; - int i; - - SG_LOG(SG_GENERAL, SG_ALERT, "generating wgs84 list"); - Point3D geod, radians, cart; - - point_list raw_nodes = c.get_tri_nodes().get_node_list(); - - for ( i = 0; i < (int)raw_nodes.size(); ++i ) { - geod = raw_nodes[i]; - - // convert to radians - radians = Point3D( geod.x() * SGD_DEGREES_TO_RADIANS, - geod.y() * SGD_DEGREES_TO_RADIANS, - geod.z() ); - - cart = sgGeodToCart(radians); - - geod_nodes.push_back(geod); - wgs84_nodes.push_back(cart); - } - - c.set_geod_nodes( geod_nodes ); - c.set_wgs84_nodes( wgs84_nodes ); -} -#endif - +#if 0 // 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. @@ -765,7 +184,7 @@ static belongs_to_list gen_node_ele_lookup_table( TGConstruct& c ) { return reverse_ele_lookup; } - +#endif // caclulate the area for the specified triangle face static double tri_ele_area( const TGConstruct& c, const TGTriEle tri ) { @@ -778,7 +197,7 @@ static double tri_ele_area( const TGConstruct& c, const TGTriEle tri ) { return triangle_area( p1, p2, p3 ); } - +#if 0 // caclulate the normal for the specified triangle face static Point3D calc_normal( TGConstruct& c, int i ) { SGVec3d v1, v2, normal; @@ -833,8 +252,9 @@ static Point3D calc_normal( TGConstruct& c, int i ) { return Point3D( normal[0], normal[1], normal[2] ); } +#endif - +#if 0 // build the face normal list static point_list gen_face_normals( TGConstruct& c ) { point_list face_normals; @@ -851,8 +271,9 @@ static point_list gen_face_normals( TGConstruct& c ) { return face_normals; } +#endif - +#if 0 // calculate the normals for each point in wgs84_nodes static point_list gen_point_normals( TGConstruct& c ) { point_list point_normals; @@ -894,829 +315,59 @@ static point_list gen_point_normals( TGConstruct& c ) { return point_normals; } +#endif + +# if 0 // generate the flight gear scenery file static void do_output( TGConstruct& c, TGGenOutput& output ) { output.build_tris( c ); output.write_tris( c ); } - -// collect custom objects and move to scenery area -static void do_custom_objects( const TGConstruct& c ) { - SGBucket b = c.get_bucket(); - - // Create/open the output .stg file for writing - SGPath dest_d(c.get_output_base().c_str()); - dest_d.append(b.gen_base_path().c_str()); - string dest_dir = dest_d.str_native(); - SGPath dest_i(dest_d); - dest_i.append(b.gen_index_str()); - dest_i.concat(".stg"); - string dest_ind = dest_i.str_native(); - - FILE *fp; - if ( (fp = fopen( dest_ind.c_str(), "w" )) == NULL ) { - SG_LOG(SG_GENERAL, SG_ALERT, "ERROR: opening " << dest_ind << " for writing!"); - exit(-1); - } - - // Start with the default custom object which is the base terrain - fprintf(fp, "OBJECT_BASE %s.btg\n", b.gen_index_str().c_str()); - - char line[2048]; // big enough? - char token[256]; - char name[256]; - - for ( int i = 0; i < (int)load_dirs.size(); ++i ) { - SGPath base(c.get_work_base().c_str()); - base.append(load_dirs[i]); - base.append( b.gen_base_path() ); - SGPath index(base); - index.append( b.gen_index_str() ); - index.concat(".ind"); - string index_file = index.str_native(); - //SG_LOG(SG_GENERAL, SG_ALERT, "collecting custom objects from " << index_file); - - sg_gzifstream in( index_file ); - - if ( ! in.is_open() ) { - //SG_LOG(SG_GENERAL, SG_ALERT, "No custom objects"); - } else { - while ( ! in.eof() ) { - SG_LOG(SG_GENERAL, SG_ALERT, "collecting custom objects from " << index_file); - in.getline(line, 2048); - SG_LOG(SG_GENERAL, SG_ALERT, "line = " << line); - - int result = sscanf( line, "%s %s", token, name ); - SG_LOG(SG_GENERAL, SG_ALERT, "scanf scanned " << result << " tokens" ); - - if ( result > 0 ) { - SG_LOG(SG_GENERAL, SG_ALERT, "token = " << token << " name = " << name ); - - if ( strcmp( token, "OBJECT" ) == 0 ) { - SGPath srcbase(base); - srcbase.append(name); - srcbase.concat(".gz"); - string basecom = srcbase.str_native(); -#ifdef _MSC_VER - string command = "copy " + basecom + " " + dest_dir; -#else - string command = "cp " + basecom + " " + dest_dir; #endif - SG_LOG( SG_GENERAL, SG_INFO, "running " << command ); - system( command.c_str() ); - fprintf(fp, "OBJECT %s\n", name); - } else { - fprintf(fp, "%s\n", line); - } - } - } - } - } - - fclose(fp); -} - -static void add_intermediate_nodes( TGConstruct& c ) { - TGPolyList polys = c.get_clipped_polys(); - TGNodes* nodes = c.get_nodes(); - - int before, after; - - // traverse each poly, and add intermediate nodes - for ( unsigned int i = 0; i < TG_MAX_AREA_TYPES; ++i ) { - SG_LOG( SG_CLIPPER, SG_INFO, "num polys of type (" << i << ") = " << polys.superpolys[i].size() ); - for( unsigned int j = 0; j < polys.superpolys[i].size(); ++j ) { - TGPolygon current = polys.superpolys[i][j].get_poly(); - SG_LOG( SG_CLIPPER, SG_INFO, get_area_name( (AreaType)i ) << " = " << current.contours() ); - - before = current.total_size(); - current = add_tgnodes_to_poly( current, nodes ); - after = current.total_size(); - - if (before != after) { - SG_LOG( SG_CLIPPER, SG_INFO, "add_tgnodes_to_poly modified poly " << j << " from " << before << " points to " << after << " points" ); - } - - /* Save it back */ - polys.superpolys[i][j].set_poly( current ); - - if (before != after) { - SG_LOG( SG_CLIPPER, SG_INFO, " VERIFY add_tgnodes_to_poly modified poly nodes is " << polys.superpolys[i][j].get_poly().total_size() ); - } - } - } - - c.set_clipped_polys(polys); - - SG_LOG( SG_CLIPPER, SG_INFO, " add intermediate nodes finished." ); -} - -static TGPolygon area_tex_coords( const TGPolygon& tri, const SGBucket &b, const TGArray &array ) +bool TGNodesSortByLon( const TGNode& n1, const TGNode& n2 ) { - TGPolygon result; - result.erase(); - - // lots of conversion needed to use simgear API - perhaps we need a new simgear API? - for (int c=0; c conv_geods; - point_list tex_coords; - - for (int i = 0; i < (int)nodes.size(); ++i ) - { - SGGeod conv_geod = SGGeod::fromDegM( nodes[i].x(), nodes[i].y(), nodes[i].z() ); - SG_LOG(SG_GENERAL, SG_DEBUG, "geod pt = " << nodes[i] ); - conv_geods.push_back( conv_geod ); - } - - // now calculate texture coordinates - // generate identity interger list... - std::vector< int > node_idx; - for (int i = 0; i < (int)conv_geods.size(); i++) { - node_idx.push_back(i); - } - - std::vector< SGVec2f > tp_list = sgCalcTexCoords( b, conv_geods, node_idx ); - // generate a contour of texture coordinates from the tp list - for (int i = 0; i < (int)tp_list.size(); i++) - { - tex_coords.push_back( Point3D::fromSGVec2( tp_list[i] ) ); - } - result.add_contour( tex_coords, 0 ); - } - - return result; + return ( n1.GetPosition().x() < n2.GetPosition().x() ); } -static TGPolygon linear_tex_coords( const TGPolygon& tri, const TGTexParams& tp ) -{ - TGPolygon result; - int i, j; - - result.erase(); - - Point3D ref = tp.get_ref(); - double width = tp.get_width(); - double length = tp.get_length(); - double heading = tp.get_heading(); - double minu = tp.get_minu(); - double maxu = tp.get_maxu(); - double minv = tp.get_minv(); - double maxv = tp.get_maxv(); - SG_LOG( SG_GENERAL, SG_DEBUG, "section ref = " << ref ); - SG_LOG( SG_GENERAL, SG_DEBUG, " width = " << width ); - SG_LOG( SG_GENERAL, SG_DEBUG, " length = " << length ); - SG_LOG( SG_GENERAL, SG_DEBUG, " heading = " << heading ); - SG_LOG( SG_GENERAL, SG_DEBUG, " minv = " << minv ); - SG_LOG( SG_GENERAL, SG_DEBUG, " maxv = " << maxv ); - SG_LOG( SG_GENERAL, SG_DEBUG, " heading = " << heading ); - - Point3D p, t; - double x, y, tx, ty; - - for ( i = 0; i < tri.contours(); ++i ) - { - for ( j = 0; j < tri.contour_size( i ); ++j ) - { - p = tri.get_pt( i, j ); - SG_LOG(SG_GENERAL, SG_DEBUG, "tex coords for contour " << i << "point " << j << ": " << p ); - - // - // 1. Calculate distance and bearing from the center of - // the feature - // - - // given alt, lat1, lon1, lat2, lon2, calculate starting - // and ending az1, az2 and distance (s). Lat, lon, and - // azimuth are in degrees. distance in meters - double az1, az2, dist; - geo_inverse_wgs_84( 0, ref.y(), ref.x(), p.y(), p.x(), - &az1, &az2, &dist ); - SG_LOG(SG_GENERAL, SG_DEBUG, "basic course from ref = " << az2); - - // - // 2. Rotate this back into a coordinate system where Y - // runs the length of the runway and X runs crossways. - // - - double course = az2 - heading; - while ( course < -360 ) { course += 360; } - while ( course > 360 ) { course -= 360; } - SG_LOG( SG_GENERAL, SG_DEBUG, - " course = " << course << " dist = " << dist ); - - // - // 3. Convert from polar to cartesian coordinates - // - - x = sin( course * SGD_DEGREES_TO_RADIANS ) * dist; - y = cos( course * SGD_DEGREES_TO_RADIANS ) * dist; - SG_LOG(SG_GENERAL, SG_DEBUG, " x = " << x << " y = " << y); - - // - // 4. Map x, y point into texture coordinates - // - double tmp; - - tmp = x / width; - tx = tmp * (maxu - minu) + minu; - - if ( tx < -1.0 ) { tx = -1.0; } - if ( tx > 1.0 ) { tx = 1.0; } - - SG_LOG(SG_GENERAL, SG_DEBUG, " (" << tx << ")"); - - ty = (y/length) + minv; - SG_LOG(SG_GENERAL, SG_DEBUG, " (" << ty << ")"); - - t = Point3D( tx, ty, 0 ); - SG_LOG(SG_GENERAL, SG_DEBUG, " (" << tx << ", " << ty << ")"); - - result.add_node( i, t ); - } - } - - return result; -} - -// fix the elevations of the geodetic nodes -// TODO : Get rid of this -#if 0 -static point_list calc_elevations( TGConstruct& c, const TGArray& array, point_list &pl ) -{ - int i; - double z; - - point_list raw_nodes1 = pl; - point_list raw_nodes2 = c.get_nodes().get_geod_nodes(); - - SG_LOG(SG_GENERAL, SG_ALERT, "rn1 " << raw_nodes1.size() << " rn2 " << raw_nodes2.size() ); - - for ( i = 0; i < (int)raw_nodes1.size(); ++i ) { - // found an elevation we want to preserve - if ( c.get_nodes().LookupFixedElevation( raw_nodes1[i], &z ) ) { - SG_LOG(SG_GENERAL, SG_ALERT, "Found Fixed elevation at " << raw_nodes1[i] << " z is " << z ); - } else { - // interpolate point from DEM data. - z = array.altitude_from_grid( raw_nodes1[i].x() * 3600.0, - raw_nodes1[i].y() * 3600.0 ); - SG_LOG(SG_GENERAL, SG_ALERT, "no Fixed elevation at " << raw_nodes1[i] << " z is " << z ); - } - - raw_nodes1[i].setz( z ); - } - - return raw_nodes1; -} -#endif - -#if 0 -static void calc_elevations( TGConstruct& c, const TGArray& array ) -{ - int i; - double z; - - point_list raw_nodes = c.get_nodes()->get_geod_nodes(); - - for ( i = 0; i < (int)raw_nodes.size(); ++i ) { - // found an elevation we want to preserve - if ( c.get_nodes()->LookupFixedElevation( raw_nodes[i], &z ) ) { - SG_LOG(SG_GENERAL, SG_ALERT, "Found Fixed elevation at " << raw_nodes[i] << " z is " << z ); - } else { - // interpolate point from DEM data. - z = array.altitude_from_grid( raw_nodes[i].x() * 3600.0, - raw_nodes[i].y() * 3600.0 ); - SG_LOG(SG_GENERAL, SG_ALERT, "no Fixed elevation at " << raw_nodes[i] << " z is " << z ); - } - - c.get_nodes()->SetElevation( i, z ); - } - - return ; -} -#endif - -// First up: -// Create new node class for the node list - -// Second up: -// -// triangulate each poly sperately, then generate a TGTriangle with the same output as global... -// (add set_out_nodes, ele_list, and segs ) -// - -#if 0 -// master construction routine -static void construct_tile( TGConstruct& c ) { - SG_LOG(SG_GENERAL, SG_ALERT, "Construct tile, bucket = " << c.get_bucket() ); - - // STEP 1) Load elevation data - - // load grid of elevation data (Array) - TGArray array; - load_array( c, array ); - - // STEP 2) Clip 2D polygons against one another - - // load and clip 2d polygon data - if ( load_polys( c, array ) == 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; - } - - // Step 3) Merge in Shared data (just add the nodes to the nodelist) - // When this step is complete, some nodes will have normals (from shared tiles) - // and some will not - need to indicate this in the new node class - - // Step 4) Add intermediate nodes - // need to add another add intermediate nodes function that can handle the new node class - - // Step 5) Triangulate (not global) - TGTriangle t; - // triangulate the data for each polygon - first_triangulate( c, array, t ); - SG_LOG(SG_GENERAL, SG_ALERT, "number of fitted nodes = " << t.get_out_nodes_size()); - - // Step 6) Generate global triangle list - // 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() ); - - // Step 7) Flatten - // calculate wgs84 (cartesian) form of node list - fix_point_heights( c, array ); - - // Step 8) Convert nodes to wgs_84 - build_wgs_84_point_list( c, array ); - - // Step 9) Generate face_connected list - // build the node -> element (triangle) reverse lookup table - c.set_reverse_ele_lookup( gen_node_ele_lookup_table( c ) ); - - // Step 10) Generate Face normals - // build the face normal list - c.set_face_normals( gen_face_normals( c ) ); - - // Step 11) Generate node normals - // 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 - TGMatch m; - m.load_neighbor_shared( c ); - if ( c.get_use_own_shared_edges() ) { - m.load_missing_shared( c ); - } - m.split_tile( c ); - if ( c.get_write_shared_edges() ) { - 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() ); - - // double check on the off chance that the triangulator was forced - // to introduce additional points - if ( c.get_tri_nodes().size() > c.get_point_normals().size() ) { - SG_LOG(SG_GENERAL, SG_ALERT, "oops, need to add normals :-("); - point_list normals = c.get_point_normals(); - int start = normals.size(); - int end = c.get_tri_nodes().size(); - for ( int i = start; i < end; ++i ) { - SG_LOG(SG_GENERAL, SG_ALERT, "adding a normal for " << c.get_tri_nodes().get_node(i)); - Point3D p = tgFakeNormal( c.get_tri_nodes().get_node(i) ); - normals.push_back( p ); - } - c.set_point_normals( normals ); - } - - if ( c.get_cover().size() > 0 ) { - // Now for all the remaining "default" land cover polygons, assign - // each one it's proper type from the land use/land cover - // database. - fix_land_cover_assignments( c ); - } - - // calculate wgs84 (cartesian) form of node list - build_wgs_84_point_list( c, array ); - - // Step 12) calculate texture coordinates for each triangle - - // Step 13) Sort the triangle list by material (optional) - - // Step 14) Generate the output - // generate the output - TGGenOutput output; - do_output( c, output ); - - array.close(); - - // Step 15) Adding custome objects to the .stg file - // collect custom objects and move to scenery area - do_custom_objects( c ); -} - -#endif - -// master construction routine -static void construct_tile( TGConstruct& c ) { - SG_LOG(SG_GENERAL, SG_ALERT, "Construct tile, bucket = " << c.get_bucket() ); - - // STEP 1) Load elevation data - - // load grid of elevation data (Array) - TGArray array; - load_array( c, array ); - - // STEP 2) Clip 2D polygons against one another - - // load and clip 2d polygon data - if ( load_polys( c, array ) == 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; - } - - // Make sure we have the elavation nodes in the main node database - // I'd like to do this first, but we get initial tgnodes from clipper - point_list corner_list = array.get_corner_list(); - if ( corner_list.size() == 0 ) { - SG_LOG(SG_GENERAL, SG_ALERT, "corner list is 0 " ); - // exit(0); - } - - for (unsigned int i=0; iunique_add_fixed_elevation(corner_list[i]); - c.get_nodes()->unique_add(corner_list[i]); - } - - point_list fit_list = array.get_fitted_list(); - for (unsigned int i=0; iunique_add_fixed_elevation(fit_list[i]); - c.get_nodes()->unique_add(fit_list[i]); - } - - // Step 3) Merge in Shared data (just add the nodes to the nodelist) - // When this step is complete, some nodes will have normals (from shared tiles) - // and some will not - need to indicate this in the new node class - - SG_LOG(SG_GENERAL, SG_ALERT, "number of geod nodes = before adding adding shared edges" << c.get_nodes()->size() ); - - TGMatch m; - m.load_neighbor_shared( c ); - if ( c.get_use_own_shared_edges() ) { - m.load_missing_shared( c ); - } - m.add_shared_nodes( c ); - - SG_LOG(SG_GENERAL, SG_ALERT, "number of geod nodes = after adding adding shared edges" << c.get_nodes()->size() ); - - // Step 4) Add intermediate nodes - // need to add another add intermediate nodes function that can handle the new node class - add_intermediate_nodes( c ); - - TGPolyList clipped_polys = c.get_clipped_polys(); - - SG_LOG(SG_GENERAL, SG_ALERT, "number of geod nodes = before adding clipping intersections" << c.get_nodes()->size() ); - - for (int i = 0; i < TG_MAX_AREA_TYPES; i++) { - for (int j = 0; j < (int)clipped_polys.superpolys[i].size(); ++j ) { - TGPolygon poly = clipped_polys.superpolys[i][j].get_poly(); - for (int k=0; k< poly.contours(); k++) { - for (int l = 0; l < poly.contour_size(k); l++) { - // ensure we have all nodes... - c.get_nodes()->unique_add( poly.get_pt( k, l ) ); - } - } - } - } - - SG_LOG(SG_GENERAL, SG_ALERT, "number of geod nodes = after adding clipping intersections" << c.get_nodes()->size() ); - - // tesselate the polygons and prepair them for final output - point_list extra = c.get_nodes()->get_geod_nodes(); - for (int i = 0; i < TG_MAX_AREA_TYPES; i++) { - for (int j = 0; j < (int)clipped_polys.superpolys[i].size(); ++j ) { - TGPolygon poly = clipped_polys.superpolys[i][j].get_poly(); - SG_LOG(SG_GENERAL, SG_INFO, "Tesselating poly " << i << ", " << j << " : material = " << clipped_polys.superpolys[i][j].get_material() << " : flag = " << clipped_polys.superpolys[i][j].get_flag()); - - TGPolygon tri = polygon_tesselate_alt_with_extra( poly, extra, false ); - TGPolygon tc; - - if ( clipped_polys.superpolys[i][j].get_flag() == "textured" ) { - // SG_LOG(SG_GENERAL, SG_DEBUG, "USE TEXTURE PARAMS for tex coord calculations" ); - // tc = linear_tex_coords( tri, clipped_polys.texparams[i][j] ); - tc = area_tex_coords( tri, c.get_bucket(), array ); - } else { - // SG_LOG(SG_GENERAL, SG_DEBUG, "USE SIMGEAR for tex coord calculations" ); - tc = area_tex_coords( tri, c.get_bucket(), array ); - } - - clipped_polys.superpolys[i][j].set_tris( tri ); - clipped_polys.superpolys[i][j].set_texcoords( tc ); - } - } - - // Add triangulation points - for (int i = 0; i < TG_MAX_AREA_TYPES; i++) { - for (int j = 0; j < (int)clipped_polys.superpolys[i].size(); ++j ) { - TGPolygon tri_poly = clipped_polys.superpolys[i][j].get_tris(); - for (int k=0; k< tri_poly.contours(); k++) { - for (int l = 0; l < tri_poly.contour_size(k); l++) { - // ensure we have all nodes... - c.get_nodes()->unique_add( tri_poly.get_pt( k, l ) ); - } - } - } - } - - SG_LOG(SG_GENERAL, SG_ALERT, "number of geod nodes = after adding triangulation nodes" << c.get_nodes()->size() ); - - c.set_clipped_polys( clipped_polys ); - -#if 0 - -//NEXT BIG STEP : TRIANGULATE EACH POLY INDEPENDENTLY - - // Step 5) Triangulate (not global) - TGTriangle t; - // triangulate the data for each polygon - first_triangulate( c, array, t ); - SG_LOG(SG_GENERAL, SG_ALERT, "number of fitted nodes = " << t.get_out_nodes_size()); - - // Step 6) Generate global triangle list - // 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() ); - -// SO WE WONT NEED TRI ELEMENTS AND TRI SEGS -// BUT: TBD : NEED FACE NORMALS - SO WE NEED NODE TO TRIANGLE LOOKUP TABLE. -// STORE TRIANGLES IN SUPERPOLY.... - -#endif - - // Step 7) Flatten - fix_point_heights( c, array ); - +static void dump_nodes( TGConstruct& c ) { for (unsigned int i=0; isize(); i++) { - SG_LOG(SG_GENERAL, SG_ALERT, "Point[" << i << "] is " << c.get_nodes()->get_geod_nodes()[i] ); - } - -#if 0 - - SG_LOG(SG_GENERAL, SG_ALERT, "REVERSE ELE LOOKUP "); - - // Step 9) Generate face_connected list - // build the node -> element (triangle) reverse lookup table - c.set_reverse_ele_lookup( gen_node_ele_lookup_table( c ) ); - - SG_LOG(SG_GENERAL, SG_ALERT, "FACE NORMALS "); - - // Step 10) Generate Face normals - // build the face normal list - c.set_face_normals( gen_face_normals( c ) ); - - // Step 11) Generate node normals - // calculate the normals for each point in wgs84_nodes - c.set_point_normals( gen_point_normals( 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() ); - - // double check on the off chance that the triangulator was forced - // to introduce additional points -#if 0 - if ( c.get_tri_nodes().size() > c.get_point_normals().size() ) { - SG_LOG(SG_GENERAL, SG_ALERT, "oops, need to add normals :-("); - point_list normals = c.get_point_normals(); - int start = normals.size(); - int end = c.get_tri_nodes().size(); - for ( int i = start; i < end; ++i ) { - SG_LOG(SG_GENERAL, SG_ALERT, "adding a normal for " << c.get_tri_nodes().get_node(i)); - Point3D p = tgFakeNormal( c.get_tri_nodes().get_node(i) ); - normals.push_back( p ); + TGNode node = c.get_nodes()->get_node( i ); + string fixed; + + if ( node.GetFixedPosition() ) { + fixed = " z is fixed elevation "; + } else { + fixed = " z is interpolated elevation "; } - c.set_point_normals( normals ); + + SG_LOG(SG_GENERAL, SG_ALERT, "Point[" << i << "] is " << node.GetPosition() << fixed ); } -#endif +} - if ( c.get_cover().size() > 0 ) { - // Now for all the remaining "default" land cover polygons, assign - // each one it's proper type from the land use/land cover - // database. - fix_land_cover_assignments( c ); - } - - // Step 12) calculate texture coordinates for each triangle - - // Step 13) Sort the triangle list by material (optional) -#endif - -#if 1 - // write shared data - m.split_tile( c ); - SG_LOG(SG_GENERAL, SG_ALERT, "Tile Split"); - - if ( c.get_write_shared_edges() ) { - SG_LOG(SG_GENERAL, SG_ALERT, "write shared edges"); - - m.write_shared( c ); - } -#endif - -// TEMP TEMP TEMP TEMP - - TGTriNodes normals, texcoords; - normals.clear(); - texcoords.clear(); - - group_list pts_v; pts_v.clear(); - group_list pts_n; pts_n.clear(); - string_list pt_materials; pt_materials.clear(); - - group_list tris_v; tris_v.clear(); - group_list tris_n; tris_n.clear(); - group_list tris_tc; tris_tc.clear(); - string_list tri_materials; tri_materials.clear(); - - group_list strips_v; strips_v.clear(); - group_list strips_n; strips_n.clear(); - group_list strips_tc; strips_tc.clear(); - string_list strip_materials; strip_materials.clear(); - - int index; - int_list pt_v, tri_v, strip_v; - int_list pt_n, tri_n, strip_n; - int_list tri_tc, strip_tc; - - // calculate "the" normal for this tile - // temporary - generate a single normal - Point3D p; - p.setx( c.get_bucket().get_center_lon() * SGD_DEGREES_TO_RADIANS ); - p.sety( c.get_bucket().get_center_lat() * SGD_DEGREES_TO_RADIANS ); - p.setz( 0 ); - Point3D vnt = sgGeodToCart( p ); - - SGVec3d tmp( vnt.x(), vnt.y(), vnt.z() ); - tmp = normalize(tmp); - Point3D vn( tmp.x(), tmp.y(), tmp.z() ); - - SG_LOG(SG_GENERAL, SG_DEBUG, "found normal for this airport = " << tmp); - - for (int i = 0; i < TG_MAX_AREA_TYPES; i++) { - // only tesselate non holes - if ( !is_hole_area( i ) ) { - for (int j = 0; j < (int)clipped_polys.superpolys[i].size(); ++j ) { - SG_LOG(SG_GENERAL, SG_INFO, "tri " << i << ", " << j); - TGPolygon tri_poly = clipped_polys.superpolys[i][j].get_tris(); - TGPolygon tri_txs = clipped_polys.superpolys[i][j].get_texcoords(); - string material = clipped_polys.superpolys[i][j].get_material(); - SG_LOG(SG_GENERAL, SG_INFO, "material = " << material); - SG_LOG(SG_GENERAL, SG_INFO, "poly size = " << tri_poly.contours()); - SG_LOG(SG_GENERAL, SG_INFO, "texs size = " << tri_txs.contours()); - for (int k = 0; k < tri_poly.contours(); ++k) - { - tri_v.clear(); - tri_n.clear(); - tri_tc.clear(); - for (int l = 0; l < tri_poly.contour_size(k); ++l) - { - p = tri_poly.get_pt( k, l ); - index = c.get_nodes()->find( p ); - if (index < 0) { - SG_LOG(SG_GENERAL, SG_ALERT, "NODE NOT FOUND " << p); - exit(0); - } - - tri_v.push_back( index ); - - // use 'the' normal - index = normals.unique_add( vn ); - tri_n.push_back( index ); - - Point3D tc = tri_txs.get_pt( k, l ); - index = texcoords.unique_add( tc ); - tri_tc.push_back( index ); - } - tris_v.push_back( tri_v ); - tris_n.push_back( tri_n ); - tris_tc.push_back( tri_tc ); - tri_materials.push_back( material ); - } - } +static void dump_lat_nodes( TGConstruct& c, double lat ) { + node_list all_nodes = c.get_nodes()->get_node_list(); + node_list sorted_nodes; + for (unsigned int i=0; i wgs84_nodes = c.get_nodes()->get_wgs84_nodes_as_SGVec3d(); - SGSphered d; - for (int i = 0; i < (int)wgs84_nodes.size(); ++i) - { - d.expandBy(wgs84_nodes[ i ]); + sort( sorted_nodes.begin(), sorted_nodes.end(), TGNodesSortByLon ); + + for (unsigned int i=0; i normals_3f; - for (int i=0; i < (int)normals.get_node_list().size(); i++ ) - { - Point3D node = normals.get_node_list()[i]; - normals_3f.push_back( node.toSGVec3f() ); - } - - std::vector< SGVec2f > texcoords_2f; - for (int i=0; i < (int)texcoords.get_node_list().size(); i++ ) - { - Point3D node = texcoords.get_node_list()[i]; - texcoords_2f.push_back( node.toSGVec2f() ); - } - - SGBinObject obj; - - obj.set_gbs_center( gbs_center ); - obj.set_gbs_radius( gbs_radius ); - obj.set_wgs84_nodes( wgs84_nodes ); - obj.set_normals( normals_3f ); - obj.set_texcoords( texcoords_2f ); - obj.set_pts_v( pts_v ); - obj.set_pts_n( pts_n ); - obj.set_pt_materials( pt_materials ); - obj.set_tris_v( tris_v ); - obj.set_tris_n( tris_n ); - obj.set_tris_tc( tris_tc ); - obj.set_tri_materials( tri_materials ); - obj.set_strips_v( strips_v ); - obj.set_strips_n( strips_n ); - obj.set_strips_tc( strips_tc ); - obj.set_strip_materials( strip_materials ); - obj.set_fans_v( fans_v ); - obj.set_fans_n( fans_n ); - obj.set_fans_tc( fans_tc ); - obj.set_fan_materials( fan_materials ); - - bool result; - result = obj.write_bin( base, binname, b ); - if ( !result ) - { - throw sg_exception("error writing file. :-("); - } - result = obj.write_ascii( base, txtname, b ); - if ( !result ) - { - throw sg_exception("error writing file. :-("); - } - -// TEMP TEMP TEMP TEMP - -#if 0 - // Step 14) Generate the output - // generate the output - TGGenOutput output; - do_output( c, output ); -#endif - - array.close(); - - // Step 15) Adding custome objects to the .stg file - // collect custom objects and move to scenery area - do_custom_objects( c ); } // display usage and exit @@ -1882,21 +533,19 @@ int main(int argc, char **argv) { c.set_cover( cover ); c.set_work_base( work_dir ); c.set_output_base( output_dir ); + c.set_load_dirs( load_dirs ); c.set_useUKGrid( useUKgrid ); c.set_write_shared_edges( writeSharedEdges ); c.set_use_own_shared_edges( useOwnSharedEdges ); c.set_ignore_landmass( ignoreLandmass ); - - c.set_min_nodes( 50 ); - c.set_max_nodes( (int)(TG_MAX_NODES * 0.8) ); + c.set_nudge( nudge ); if (tile_id == -1) { if (xdist == -1 || ydist == -1) { // construct the tile around the specified location SG_LOG(SG_GENERAL, SG_ALERT, "Building single tile at " << lat << ',' << lon); SGBucket b( lon, lat ); - c.set_bucket( b ); - construct_tile( c ); + c.construct_bucket( b ); } else { // build all the tiles in an area SG_LOG(SG_GENERAL, SG_ALERT, "Building tile(s) at " << lat << ',' << lon << " with x distance " << xdist << " and y distance " << ydist); @@ -1909,8 +558,7 @@ int main(int argc, char **argv) { bool do_tile = true; if ( b_min == b_max ) { - c.set_bucket( b_min ); - construct_tile( c ); + c.construct_bucket( b_min ); } else { SGBucket b_cur; int dx, dy, i, j; @@ -1928,8 +576,7 @@ int main(int argc, char **argv) { } if ( do_tile ) { - c.set_bucket( b_cur ); - construct_tile( c ); + c.construct_bucket( b_cur ); } else { SG_LOG(SG_GENERAL, SG_ALERT, "skipping " << b_cur); } @@ -1941,8 +588,7 @@ int main(int argc, char **argv) { // construct the specified tile SG_LOG(SG_GENERAL, SG_ALERT, "Building tile " << tile_id); SGBucket b( tile_id ); - c.set_bucket( b ); - construct_tile( c ); + c.construct_bucket( b ); } SG_LOG(SG_GENERAL, SG_ALERT, "[Finished successfully]"); diff --git a/src/BuildTiles/Clipper/priorities.cxx b/src/BuildTiles/Main/priorities.cxx similarity index 100% rename from src/BuildTiles/Clipper/priorities.cxx rename to src/BuildTiles/Main/priorities.cxx diff --git a/src/BuildTiles/Clipper/priorities.hxx b/src/BuildTiles/Main/priorities.hxx similarity index 100% rename from src/BuildTiles/Clipper/priorities.hxx rename to src/BuildTiles/Main/priorities.hxx diff --git a/src/BuildTiles/Main/usgs.hxx b/src/BuildTiles/Main/usgs.hxx index b578ddf2..87d0af3b 100644 --- a/src/BuildTiles/Main/usgs.hxx +++ b/src/BuildTiles/Main/usgs.hxx @@ -22,11 +22,11 @@ #ifndef _USGS_HXX #define _USGS_HXX -#include +#include #include -#include +#include "priorities.hxx" int load_usgs_map( const std::string& filename ); AreaType translateUSGSCover( int usgs_value ); diff --git a/src/BuildTiles/Match/match.cxx b/src/BuildTiles/Match/match.cxx index 65220b12..0a98c269 100644 --- a/src/BuildTiles/Match/match.cxx +++ b/src/BuildTiles/Match/match.cxx @@ -141,14 +141,10 @@ void TGMatch::scan_share_file( const string& dir, const SGBucket& b, // try to find info for the specified shared component -void TGMatch::load_shared( const TGConstruct& c, neighbor_type n ) { - SGBucket b = c.get_bucket(); - +void TGMatch::load_shared( SGBucket b, string base, neighbor_type n ) { double clon = b.get_center_lon(); double clat = b.get_center_lat(); - string base = c.get_work_base() + "/Shared/"; - SGBucket cb; if ( n == SW_Corner ) { @@ -205,27 +201,29 @@ void TGMatch::load_shared( const TGConstruct& c, neighbor_type n ) { // load any previously existing shared data from all neighbors (if // shared data for a component exists set that components flag to true -void TGMatch::load_neighbor_shared( TGConstruct& c ) { +void TGMatch::load_neighbor_shared( SGBucket b, string work ) { cout << "Loading existing shared data from neighbor tiles" << endl; + string base = work + "/Shared/"; + // 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 ); + load_shared( b, base, SW_Corner ); + load_shared( b, base, SE_Corner ); + load_shared( b, base, NE_Corner ); + load_shared( b, base, 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 ); + load_shared( b, base, NORTH ); + load_shared( b, base, SOUTH ); + load_shared( b, base, EAST ); + load_shared( b, base, WEST ); cout << "Shared data read in:" << endl; if ( sw_flag ) { @@ -271,13 +269,11 @@ void TGMatch::load_neighbor_shared( TGConstruct& c ) { } // try to load any missing shared data from our own shared data file -void TGMatch::load_missing_shared( TGConstruct& c ) { - SGBucket b = c.get_bucket(); - +void TGMatch::load_missing_shared( SGBucket b, string work ) { double clon = b.get_center_lon(); double clat = b.get_center_lat(); - string base = c.get_work_base() + "/Shared/"; + string base = work + "/Shared/"; if ( !nw_flag ) { scan_share_file( base, b, NW_Corner, NW_Corner ); @@ -332,7 +328,7 @@ Point3D tgFakeNormal( const Point3D& p ) { // 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 TGMatch::split_tile( TGConstruct& c ) { +void TGMatch::split_tile( SGBucket b, TGConstruct* c ) { int i; cout << "Spliting tile" << endl; @@ -340,7 +336,7 @@ void TGMatch::split_tile( TGConstruct& c ) { // calculate tile boundaries point2d min, max; - SGBucket 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(); @@ -368,8 +364,8 @@ void TGMatch::split_tile( TGConstruct& c ) { body_nodes.clear(); - point_list nodes = c.get_geod_nodes(); - point_list point_normals = c.get_point_normals(); + point_list nodes = c->get_geod_nodes(); + point_list point_normals = c->get_point_normals(); SG_LOG(SG_GENERAL, SG_ALERT, "number of geod nodes = " << nodes.size() ); SG_LOG(SG_GENERAL, SG_ALERT, "number of normals = " << point_normals.size() ); @@ -509,9 +505,8 @@ void TGMatch::split_tile( TGConstruct& c ) { // write the new shared edge points, normals, and segments for this // tile -void TGMatch::write_shared( TGConstruct& c ) { - string base = c.get_work_base(); - SGBucket b = c.get_bucket(); +void TGMatch::write_shared( SGBucket b, TGConstruct* c ) { + string base = c->get_work_base(); string dir = base + "/Shared/" + b.gen_base_path(); string file = dir + "/" + b.gen_index_str(); @@ -548,30 +543,30 @@ void TGMatch::write_shared( TGConstruct& c ) { * means that the adjacent tile already has been built. */ if ( ! sw_flag ) { - fprintf( fp, "sw_node %.6f %.6f %.6f\n", + fprintf( fp, "sw_node %.10f %.10f %.10f\n", sw_node.x(), sw_node.y(), sw_node.z() ); - fprintf( fp, "sw_normal %.6f %.6f %.6f\n", + fprintf( fp, "sw_normal %.10f %.10f %.10f\n", sw_normal.x(), sw_normal.y(), sw_normal.z() ); } if ( ! se_flag ) { - fprintf( fp, "se_node %.6f %.6f %.6f\n", + fprintf( fp, "se_node %.10f %.10f %.10f\n", se_node.x(), se_node.y(), se_node.z() ); - fprintf( fp, "se_normal %.6f %.6f %.6f\n", + fprintf( fp, "se_normal %.10f %.10f %.10f\n", se_normal.x(), se_normal.y(), se_normal.z() ); } if ( ! nw_flag ) { - fprintf( fp, "nw_node %.6f %.6f %.6f\n", + fprintf( fp, "nw_node %.10f %.10f %.10f\n", nw_node.x(), nw_node.y(), nw_node.z() ); - fprintf( fp, "nw_normal %.6f %.6f %.6f\n", + fprintf( fp, "nw_normal %.10f %.10f %.10f\n", nw_normal.x(), nw_normal.y(), nw_normal.z() ); } if ( ! ne_flag ) { - fprintf( fp, "ne_node %.6f %.6f %.6f\n", + fprintf( fp, "ne_node %.10f %.10f %.10f\n", ne_node.x(), ne_node.y(), ne_node.z() ); - fprintf( fp, "ne_normal %.6f %.6f %.6f\n", + fprintf( fp, "ne_normal %.10f %.10f %.10f\n", ne_normal.x(), ne_normal.y(), ne_normal.z() ); } @@ -580,10 +575,10 @@ void TGMatch::write_shared( TGConstruct& c ) { 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", + fprintf( fp, "n_node %.10f %.10f %.10f\n", north_nodes[i].x(), north_nodes[i].y(), north_nodes[i].z() ); - fprintf( fp, "n_normal %.6f %.6f %.6f\n", + fprintf( fp, "n_normal %.10f %.10f %.10f\n", north_normals[i].x(), north_normals[i].y(), north_normals[i].z() ); } @@ -595,10 +590,10 @@ void TGMatch::write_shared( TGConstruct& c ) { 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", + fprintf( fp, "s_node %.10f %.10f %.10f\n", south_nodes[i].x(), south_nodes[i].y(), south_nodes[i].z() ); - fprintf( fp, "s_normal %.6f %.6f %.6f\n", + fprintf( fp, "s_normal %.10f %.10f %.10f\n", south_normals[i].x(), south_normals[i].y(), south_normals[i].z() ); } @@ -610,10 +605,10 @@ void TGMatch::write_shared( TGConstruct& c ) { 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", + fprintf( fp, "e_node %.10f %.10f %.10f\n", east_nodes[i].x(), east_nodes[i].y(), east_nodes[i].z() ); - fprintf( fp, "e_normal %.6f %.6f %.6f\n", + fprintf( fp, "e_normal %.10f %.10f %.10f\n", east_normals[i].x(), east_normals[i].y(), east_normals[i].z() ); } @@ -625,10 +620,10 @@ void TGMatch::write_shared( TGConstruct& c ) { 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", + fprintf( fp, "w_node %.10f %.10f %.10f\n", west_nodes[i].x(), west_nodes[i].y(), west_nodes[i].z() ); - fprintf( fp, "w_normal %.6f %.6f %.6f\n", + fprintf( fp, "w_normal %.10f %.10f %.10f\n", west_normals[i].x(), west_normals[i].y(), west_normals[i].z() ); } @@ -642,28 +637,28 @@ void TGMatch::write_shared( TGConstruct& c ) { 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", + fprintf( fp, "n_seg %.10f %.10f %.10f %.10f\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", + fprintf( fp, "s_seg %.10f %.10f %.10f %.10f\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", + fprintf( fp, "e_seg %.10f %.10f %.10f %.10f\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", + fprintf( fp, "w_seg %.10f %.10f %.10f %.10f\n", p1.x(), p1.y(), p2.x(), p2.y() ); } #endif @@ -688,9 +683,9 @@ void insert_normal( point_list& normals, Point3D n, int i ) { } // Just add nodes and normals to the node list -void TGMatch::add_shared_nodes( TGConstruct& c ) { +void TGMatch::add_shared_nodes( TGConstruct* c ) { TGNodes* nodes; - nodes = c.get_nodes(); + nodes = c->get_nodes(); cout << " BEFORE ADDING SHARED NODES: " << nodes->size() << endl; @@ -739,7 +734,7 @@ void TGMatch::add_shared_nodes( TGConstruct& c ) { // reassemble the tile pieces (combining the shared data and our own // data) -void TGMatch::assemble_tile( TGConstruct& c ) { +void TGMatch::assemble_tile( TGConstruct* c ) { int i; TGTriNodes new_nodes; new_nodes.clear(); @@ -824,7 +819,7 @@ void TGMatch::assemble_tile( TGConstruct& c ) { // add the body segments - point_list geod_nodes = c.get_geod_nodes(); + point_list geod_nodes = c->get_geod_nodes(); TGTriSeg seg; Point3D p1, p2; diff --git a/src/BuildTiles/Match/match.hxx b/src/BuildTiles/Match/match.hxx index d8c9013d..4c8892e8 100644 --- a/src/BuildTiles/Match/match.hxx +++ b/src/BuildTiles/Match/match.hxx @@ -83,35 +83,35 @@ public: // 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( TGConstruct& c ); + void load_neighbor_shared( SGBucket b, std::string base ); // try to load any missing shared data from our own shared data file - void load_missing_shared( TGConstruct& c ); + void load_missing_shared( SGBucket b, std::string base ); // scan the specified share file for the specified information void scan_share_file( const std::string& dir, const SGBucket& b, neighbor_type search, neighbor_type dest ); // try to find info for the specified shared component - void load_shared( const TGConstruct& c, neighbor_type n ); + void load_shared( SGBucket b, std::string base, neighbor_type n ); // NEW TILE MATCHING - PRE TRIANGULATION // Just add nodes and normals to the node list - void add_shared_nodes( TGConstruct& c ); + void add_shared_nodes( TGConstruct* c ); // 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( TGConstruct& c ); + void split_tile( SGBucket b, TGConstruct* c ); // write the new shared edge points, normals, and segments for // this tile - void write_shared( TGConstruct& c ); + void write_shared( SGBucket b, TGConstruct* c ); // reassemble the tile pieces (combining the shared data and our // own data) - void assemble_tile( TGConstruct& c ); + void assemble_tile( TGConstruct* c ); }; diff --git a/src/BuildTiles/Triangulate/CMakeLists.txt b/src/BuildTiles/Triangulate/CMakeLists.txt deleted file mode 100644 index 4b99f448..00000000 --- a/src/BuildTiles/Triangulate/CMakeLists.txt +++ /dev/null @@ -1,6 +0,0 @@ - - -add_library(Triangulate STATIC - triangle.cxx triangle.hxx - trieles.cxx trieles.hxx -) diff --git a/src/BuildTiles/Triangulate/triangle.cxx b/src/BuildTiles/Triangulate/triangle.cxx deleted file mode 100644 index a4be9654..00000000 --- a/src/BuildTiles/Triangulate/triangle.cxx +++ /dev/null @@ -1,567 +0,0 @@ -// triangle.cxx -- "Triangle" interface class -// -// Written by Curtis Olson, started March 1999. -// -// Copyright (C) 1999 Curtis L. Olson - http://www.flightgear.org/~curt -// -// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. -// -// $Id: triangle.cxx,v 1.25 2005-10-31 18:45:19 curt Exp $ - -#include - -#include -#include -#include -#include - -#include "triangle.hxx" - -#include - -using std::cout; -using std::endl; -using std::string; - - -// Constructor -TGTriangle::TGTriangle( void ) { -} - - -// Destructor -TGTriangle::~TGTriangle( void ) { -} - - -// populate this class based on the specified gpc_polys list -int -TGTriangle::build( const point_list& corner_list, - const point_list& fit_list, - const TGPolyList& gpc_polys ) -{ - int debug_counter = 0; - int index; - int i; - - in_nodes.clear(); - in_segs.clear(); - - // Point3D junkp; - // int junkc = 0; - // FILE *junkfp; - - // traverse the array 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 - for ( i = 0; i < (int)corner_list.size(); ++i ) { - Point3D p = corner_list[i]; - p.setz( -9999.0 ); - index = in_nodes.unique_add( p ); - } - - // next process the polygons - TGSuperPoly sp; - TGPolygon gpc_poly; - const_superpoly_list_iterator current, last; - - // process polygons in priority order - cout << "prepairing node list and polygons" << endl; - - for ( i = 0; i < TG_MAX_AREA_TYPES; ++i ) { - polylist[i].clear(); - - cout << "area type = " << i << " polys = " << gpc_polys.superpolys[i].size() << endl; - debug_counter = 0; - current = gpc_polys.superpolys[i].begin(); - last = gpc_polys.superpolys[i].end(); - for ( ; current != last; ++current ) { - sp = *current; - gpc_poly = sp.get_poly(); - - // 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; - - /* - char junkn[256]; - sprintf(junkn, "c%d", j); - gpc_poly.write_contour( j, junkn ); - */ - - 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); - } - - /* if ( i == OceanArea ) { - cout << "temporary exit point" << endl; - exit(-1); - } */ - - // for each contour, calculate a point inside (but not - // also inside any interior contours - - // new way - - // try to make sure our polygons aren't goofy - #if 0 - // CLO 09/18/2001: if we snap polygons including holes - // will this screw up the edge matching when objects are - // inserted into their holes? - gpc_poly = snap(gpc_poly, 0.000001); - #endif - gpc_poly = remove_dups( gpc_poly ); - gpc_poly = reduce_degeneracy( gpc_poly ); - gpc_poly = reduce_degeneracy( gpc_poly ); // can happen multiple time - gpc_poly = remove_dups( gpc_poly ); - gpc_poly = remove_bad_contours( gpc_poly ); - gpc_poly = remove_cycles( gpc_poly ); - - // cout << "after sanity checks, contours = " << gpc_poly.contours() << endl; - - /* - for ( j = 0; j < gpc_poly.contours(); ++j ) { - cout << " contour " << j << " size = " - << gpc_poly.contour_size( j ) << endl; - char junkn[256]; - sprintf(junkn, "d%d", j); - gpc_poly.write_contour( j, junkn ); - } - */ - - // cout << "before calc_points_inside()" << endl; - calc_points_inside( gpc_poly ); - // cout << "after calc_points_inside()" << endl; - - #if 0 - // old way - 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 ); - } - #endif - - 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 - for ( i = 0; i < (int)fit_list.size(); ++i ) { - index = in_nodes.course_add( fit_list[i] ); - } - - for ( i = 0; i < TG_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(); - TGPolygon poly; - - for ( i = 0; i < TG_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 ( is_hole_area(i) ) { - // mark as a boundary - in_segs.unique_divide_and_add( node_list, - TGTriSeg(i1, i2, 1) ); - } else { - // non boundary - in_segs.unique_divide_and_add( node_list, - TGTriSeg(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 ( is_hole_area(i) ) { - // mark as a boundary - in_segs.unique_divide_and_add( node_list, - TGTriSeg(i1, i2, 1) ); - } else { - // non boundary - in_segs.unique_divide_and_add( node_list, - TGTriSeg(i1, i2, 0) ); - } - } - } - } - - return 0; -} - -// populate this class based on the specified gpc_polys list -int TGTriangle::rebuild( TGConstruct& c ) { - in_nodes.clear(); - in_segs.clear(); - -#if 0 - in_nodes = c.get_tri_nodes(); - in_segs = c.get_tri_segs(); -#endif - - return 0; -} - - -// 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 TGTriangle::run_triangulate( double angle, const int pass ) { - TGPolygon poly; - Point3D p; - struct triangulateio in, out, vorout; - int counter; - int i, j; - - - // point list - point_list node_list = in_nodes.get_node_list(); - - cout << "TRIANGULATE : NUMBER OF INPUT NODES: " << node_list.size() << endl; - - in.numberofpoints = node_list.size(); - in.pointlist = (REAL *) malloc(in.numberofpoints * 2 * sizeof(REAL)); - - for ( 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 ( i = 0; i < in.numberofpoints * in.numberofpointattributes; ++i) { - in.pointattributelist[i] = node_list[i].z(); - } - - in.pointmarkerlist = (int *) malloc(in.numberofpoints * sizeof(int)); - for ( 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) - poly_list_iterator h_current, h_last; - in.numberofholes = 0; - for ( i = 0; i < TG_MAX_AREA_TYPES; i++) { - if ( is_hole_area( i ) ) { - h_current = polylist[i].begin(); - h_last = polylist[i].end(); - for ( ; h_current != h_last; ++h_current ) { - poly = *h_current; - for ( j = 0; j < poly.contours(); ++j ) { - in.numberofholes++; - } - } - } - } - - in.holelist = (REAL *) malloc(in.numberofholes * 2 * sizeof(REAL)); - - counter = 0; - for ( i = 0; i < TG_MAX_AREA_TYPES; i++) { - if ( is_hole_area( i ) ) { - h_current = polylist[i].begin(); - h_last = polylist[i].end(); - for ( ; h_current != h_last; ++h_current ) { - poly = *h_current; - for ( 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 ( i = 0; i < TG_MAX_AREA_TYPES; ++i ) { - if ( ! is_hole_area( 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 ( 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 ( i = 0; i < TG_MAX_AREA_TYPES; ++i ) { - if ( ! is_hole_area( 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 ( 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_tri_data(&in); exit(1); - - // 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 0 - if ( angle < 0.00001 ) { - tri_options = "pczAen"; - } else { - char angle_str[256]; - sprintf( angle_str, "%.2f", angle ); - tri_options = "pczq"; - tri_options += angle_str; - tri_options += "Aen"; - } -#else - - // TEST TEST TEST : NO ADDING POINTS - tri_options = "pzenYYQ"; - -#endif - - // // 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 TGTriangle::run_triangulate()" << endl; - exit(-1); - } - cout << "Triangulation with options = " << tri_options << endl; - - triangulate( (char *)tri_options.c_str(), &in, &out, &vorout ); - - // TEMPORARY - // write_tri_data(&out); - - // now copy the results back into the corresponding TGTriangle - // structures - - cout << "TRIANGULATE : NUMBER OF OUTPUT NODES: " << out.numberofpoints << endl; - - // nodes - out_nodes.clear(); - for ( i = 0; i < out.numberofpoints; ++i ) { - Point3D p( out.pointlist[2*i], out.pointlist[2*i + 1], - out.pointattributelist[i] ); - out_nodes.simple_add( p ); - } - - // segments - out_segs.clear(); - for ( i = 0; i < out.numberofsegments; ++i ) { - out_segs.unique_add( TGTriSeg( out.segmentlist[2*i], - out.segmentlist[2*i+1], - out.segmentmarkerlist[i] ) ); - } - - // triangles - elelist.clear(); - int n1, n2, n3; - double attribute; - for ( 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( TGTriEle( 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; -} - diff --git a/src/BuildTiles/Triangulate/triangle.hxx b/src/BuildTiles/Triangulate/triangle.hxx deleted file mode 100644 index 3e15a419..00000000 --- a/src/BuildTiles/Triangulate/triangle.hxx +++ /dev/null @@ -1,105 +0,0 @@ -// triangle.hxx -- "Triangle" interface class -// -// Written by Curtis Olson, started March 1999. -// -// Copyright (C) 1999 Curtis L. Olson - http://www.flightgear.org/~curt -// -// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. -// -// $Id: triangle.hxx,v 1.7 2004-11-19 22:25:50 curt Exp $ - - -#ifndef _TRIANGLE_HXX -#define _TRIANGLE_HXX - - -#ifndef __cplusplus -# error This library requires C++ -#endif - - -#include -#include - -#include -#include
- -#include -#include -#include -#include - -#define REAL double -extern "C" { -#include -} - -#include "trieles.hxx" - - -class TGTriangle { - -private: - - // list of nodes - TGTriNodes in_nodes; - TGTriNodes out_nodes; - - // list of segments - TGTriSegments in_segs; - TGTriSegments out_segs; - - // polygon list - poly_list polylist[TG_MAX_AREA_TYPES]; - - // triangle list - triele_list elelist; - -public: - - // Constructor and destructor - TGTriangle( void ); - ~TGTriangle( 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 TGPolyList& gpc_polys ); - - // populate this class based on the specified gpc_polys list - int rebuild( TGConstruct& 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( double angle, const int pass ); - - inline TGTriNodes 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 TGTriSegments get_out_segs() const { return out_segs; } -}; - - -#endif // _TRIANGLE_HXX - - diff --git a/src/BuildTiles/Triangulate/trieles.cxx b/src/BuildTiles/Triangulate/trieles.cxx deleted file mode 100644 index ef20d757..00000000 --- a/src/BuildTiles/Triangulate/trieles.cxx +++ /dev/null @@ -1,26 +0,0 @@ -// trieles.cxx -- "Triangle" element management class -// -// Written by Curtis Olson, started March 1999. -// -// Copyright (C) 1999 Curtis L. Olson - http://www.flightgear.org/~curt -// -// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. -// -// $Id: trieles.cxx,v 1.2 2004-11-19 22:25:50 curt Exp $ - - -#include "trieles.hxx" - - diff --git a/src/Lib/Geometry/poly_extra.cxx b/src/Lib/Geometry/poly_extra.cxx index f1043c5b..cbdfa81e 100644 --- a/src/Lib/Geometry/poly_extra.cxx +++ b/src/Lib/Geometry/poly_extra.cxx @@ -136,7 +136,9 @@ void add_intermediate_tgnodes( int contour, const Point3D& start, add_intermediate_tgnodes( contour, start, new_pt, nodes, result ); result->add_node( contour, new_pt ); - SG_LOG(SG_GENERAL, SG_INFO, " added = " << new_pt); + SG_LOG(SG_GENERAL, SG_DEBUG, " added = " << new_pt); + + // DEBUG : Was new node shared? add_intermediate_tgnodes( contour, new_pt, end, nodes, result ); } diff --git a/src/Lib/Geometry/poly_support.cxx b/src/Lib/Geometry/poly_support.cxx index 6a0cd3ae..e8f31643 100644 --- a/src/Lib/Geometry/poly_support.cxx +++ b/src/Lib/Geometry/poly_support.cxx @@ -35,8 +35,6 @@ #include #include -#include - #include #include diff --git a/src/Lib/Geometry/poly_support.hxx b/src/Lib/Geometry/poly_support.hxx index efdb722d..58b8918d 100644 --- a/src/Lib/Geometry/poly_support.hxx +++ b/src/Lib/Geometry/poly_support.hxx @@ -35,8 +35,8 @@ #include #include -#include +#include "trieles.hxx" #include "trinodes.hxx" diff --git a/src/Lib/Geometry/tg_nodes.cxx b/src/Lib/Geometry/tg_nodes.cxx index 92c1c74e..39076c1c 100644 --- a/src/Lib/Geometry/tg_nodes.cxx +++ b/src/Lib/Geometry/tg_nodes.cxx @@ -33,7 +33,7 @@ int TGNodes::unique_add( const Point3D& p ) { last = tg_node_list.end(); for ( ; current != last; ++current ) { - if ( close_enough_3d(p, (*current).GetPosition() ) ) { + if ( close_enough_2d(p, (*current).GetPosition() ) ) { // cout << "found an existing match!" << endl; return counter; } @@ -59,7 +59,7 @@ int TGNodes::unique_add_fixed_elevation( const Point3D& p ) { last = tg_node_list.end(); for ( ; current != last; ++current ) { - if ( close_enough_3d(p, (*current).GetPosition() ) ) { + if ( close_enough_2d(p, (*current).GetPosition() ) ) { SG_LOG(SG_GENERAL, SG_ALERT, "Adding fixed elev node : node already exists at " << counter << " old position is " << (*current).GetPosition() << " new position is " << p ); // Force the match to our position, and mark as fixed @@ -168,6 +168,7 @@ point_list TGNodes::get_normals( void ) const { return points; } +#if 0 bool TGNodes::LookupFixedElevation( Point3D p, double* z ) { int index = find( p ); @@ -183,3 +184,4 @@ bool TGNodes::LookupFixedElevation( Point3D p, double* z ) return found; } +#endif diff --git a/src/Lib/Geometry/tg_nodes.hxx b/src/Lib/Geometry/tg_nodes.hxx index 77d3fb50..a8d09d86 100644 --- a/src/Lib/Geometry/tg_nodes.hxx +++ b/src/Lib/Geometry/tg_nodes.hxx @@ -108,7 +108,7 @@ public: // tolerance as unique_add(). Returns -1 if not found. int find( const Point3D& p ) const; - bool LookupFixedElevation( Point3D p, double* z ); +// bool LookupFixedElevation( Point3D p, double* z ); void SetElevation( int idx, double z ) { tg_node_list[idx].SetElevation( z ); } // return the master node list diff --git a/src/BuildTiles/Triangulate/trieles.hxx b/src/Lib/Geometry/trieles.hxx similarity index 100% rename from src/BuildTiles/Triangulate/trieles.hxx rename to src/Lib/Geometry/trieles.hxx diff --git a/src/Lib/Optimize/genfans.hxx b/src/Lib/Optimize/genfans.hxx index a542d886..5e222886 100644 --- a/src/Lib/Optimize/genfans.hxx +++ b/src/Lib/Optimize/genfans.hxx @@ -36,7 +36,7 @@ #include -#include +#include typedef std::vector < int_list > opt_list; typedef opt_list::iterator opt_list_iterator; diff --git a/src/Lib/Optimize/genstrips.hxx b/src/Lib/Optimize/genstrips.hxx index f2162192..b1df8f0d 100644 --- a/src/Lib/Optimize/genstrips.hxx +++ b/src/Lib/Optimize/genstrips.hxx @@ -37,7 +37,7 @@ #include -#include +#include typedef std::vector < int_list > opt_list; typedef opt_list::iterator opt_list_iterator; diff --git a/src/Lib/Polygon/superpoly.cxx b/src/Lib/Polygon/superpoly.cxx index f4e73fa5..0994d8db 100644 --- a/src/Lib/Polygon/superpoly.cxx +++ b/src/Lib/Polygon/superpoly.cxx @@ -45,4 +45,5 @@ void TGSuperPoly::erase() normals.erase(); texcoords.erase(); tris.erase(); + face_normals.clear(); } diff --git a/src/Lib/Polygon/superpoly.hxx b/src/Lib/Polygon/superpoly.hxx index f499d914..ff68394d 100644 --- a/src/Lib/Polygon/superpoly.hxx +++ b/src/Lib/Polygon/superpoly.hxx @@ -42,12 +42,13 @@ class TGSuperPoly { private: -std::string material; // material/texture name -TGPolygon poly; // master polygon -TGPolygon normals; // corresponding normals -TGPolygon texcoords; // corresponding texture coordinates -TGPolygon tris; // triangulation -std::string flag; // For various potential record keeping needs +std::string material; // material/texture name +TGPolygon poly; // master polygon +TGPolygon normals; // corresponding normals +TGPolygon texcoords; // corresponding texture coordinates +TGPolygon tris; // triangulation +point_list face_normals; // triangle normals +std::string flag; // For various potential record keeping needs public: