diff --git a/src/BuildTiles/Main/main.cxx b/src/BuildTiles/Main/main.cxx index 318bfc82..cf2ad9b3 100644 --- a/src/BuildTiles/Main/main.cxx +++ b/src/BuildTiles/Main/main.cxx @@ -47,6 +47,7 @@ static void usage( const string name ) { SG_LOG(SG_GENERAL, SG_ALERT, "[ --output-dir="); SG_LOG(SG_GENERAL, SG_ALERT, " --work-dir="); SG_LOG(SG_GENERAL, SG_ALERT, " --share-dir="); + SG_LOG(SG_GENERAL, SG_ALERT, " --match-dir="); SG_LOG(SG_GENERAL, SG_ALERT, " --cover="); SG_LOG(SG_GENERAL, SG_ALERT, " --tile-id="); SG_LOG(SG_GENERAL, SG_ALERT, " --min-lon="); @@ -63,10 +64,23 @@ static void usage( const string name ) { exit(-1); } +void RemoveDuplicateBuckets( std::vector& keep, std::vector& remove ) +{ + for ( unsigned int i=0; i 0 ) { SG_LOG(SG_GENERAL, SG_ALERT, "Tile id is " << tile_id); } else { @@ -166,11 +184,14 @@ int main(int argc, char **argv) { exit( -1 ); } - // tile work queue + // tile work queue + std::vector matchList; std::vector bucketList; SGLockedQueue wq; + SGMutex filelock; - // First generate the workqueue of buckets to construct + // First, check if we want to match existing scenery - + // if we do, generate a list of buckets outside of the bounding box if (tile_id == -1) { // build all the tiles in an area SG_LOG(SG_GENERAL, SG_ALERT, "Building tile(s) within given bounding box"); @@ -179,19 +200,42 @@ int main(int argc, char **argv) { SGBucket b_max( max ); if ( b_min == b_max ) { - bucketList.push_back( b_min ); + bucketList.push_back( b_min ); } else { SG_LOG(SG_GENERAL, SG_ALERT, " construction area spans tile boundaries"); - sgGetBuckets( min, max, bucketList ); + sgGetBuckets( min, max, bucketList ); + } + if ( match_dir != "" ) { + b_min = b_min.sibling(-1,-1); + b_max = b_max.sibling(1,1); + + sgGetBuckets( b_min.get_center(), b_max.get_center(), matchList ); } } else { // construct the specified tile SG_LOG(SG_GENERAL, SG_ALERT, "Building tile " << tile_id); bucketList.push_back( SGBucket( tile_id ) ); + if ( match_dir != "" ) { + SGBucket b_min( SGBucket(tile_id).sibling(-1,-1) ); + SGBucket b_max( SGBucket(tile_id).sibling( 1, 1) ); + sgGetBuckets( b_min.get_center(), b_max.get_center(), matchList ); + } } + if ( match_dir != "" ) { + RemoveDuplicateBuckets( matchList, bucketList ); + + // generate the immuatble shared files - when tile matching, we must not + // modify shared edges from an immutable file - new tile will collapse + // triangles as appropriate. + TGConstruct* construct = new TGConstruct( areas, 1, wq, &filelock ); + //construct->set_cover( cover ); + construct->set_paths( work_dir, share_dir, match_dir, output_dir, load_dirs ); + construct->CreateMatchedEdgeFiles( matchList ); + delete construct; + } + std::vector constructs; - SGMutex filelock; /* fill the workqueue */ for (unsigned int i=0; iset_cover( cover ); - construct->set_paths( work_dir, share_dir, output_dir, load_dirs ); + construct->set_paths( work_dir, share_dir, match_dir, output_dir, load_dirs ); construct->set_options( ignoreLandmass, nudge ); construct->set_debug( debug_dir, debug_area_defs, debug_shape_defs ); constructs.push_back( construct ); @@ -235,7 +279,7 @@ int main(int argc, char **argv) { for (int i=0; iset_cover( cover ); - construct->set_paths( work_dir, share_dir, output_dir, load_dirs ); + construct->set_paths( work_dir, share_dir, match_dir, output_dir, load_dirs ); construct->set_options( ignoreLandmass, nudge ); construct->set_debug( debug_dir, debug_area_defs, debug_shape_defs ); constructs.push_back( construct ); @@ -267,7 +311,7 @@ int main(int argc, char **argv) { for (int i=0; iset_cover( cover ); - construct->set_paths( work_dir, share_dir, output_dir, load_dirs ); + construct->set_paths( work_dir, share_dir, match_dir, output_dir, load_dirs ); construct->set_options( ignoreLandmass, nudge ); construct->set_debug( debug_dir, debug_area_defs, debug_shape_defs ); constructs.push_back( construct ); diff --git a/src/BuildTiles/Main/tgconstruct.cxx b/src/BuildTiles/Main/tgconstruct.cxx index 7b1f8593..8ecf346b 100644 --- a/src/BuildTiles/Main/tgconstruct.cxx +++ b/src/BuildTiles/Main/tgconstruct.cxx @@ -55,9 +55,12 @@ TGConstruct::~TGConstruct() { } // TGConstruct: Setup -void TGConstruct::set_paths( const std::string work, const std::string share, const std::string output, const std::vector load ) { +void TGConstruct::set_paths( const std::string work, const std::string share, + const std::string match, const std::string output, + const std::vector load ) { work_base = work; share_base = share; + match_base = match; output_base = output; load_dirs = load; } @@ -93,6 +96,12 @@ void TGConstruct::run() strcpy( ds_name, "" ); } + if ( stage == 1 ) { + // Matched edge data is generated from a previous scenery build - do this before we + // start the current tile - it can mark edges as immutable + LoadMatchedEdgeFiles(); + } + if ( stage > 1 ) { LoadFromIntermediateFiles( stage-1 ); LoadSharedEdgeData( stage-1 ); @@ -244,4 +253,4 @@ void TGConstruct::run() debug_shapes.clear(); debug_areas.clear(); } -} \ No newline at end of file +} diff --git a/src/BuildTiles/Main/tgconstruct.hxx b/src/BuildTiles/Main/tgconstruct.hxx index 8e0ff049..fdf6932b 100644 --- a/src/BuildTiles/Main/tgconstruct.hxx +++ b/src/BuildTiles/Main/tgconstruct.hxx @@ -83,7 +83,8 @@ public: #endif // paths - void set_paths( const std::string work, const std::string share, const std::string output, const std::vector load_dirs ); + void set_paths( const std::string work, const std::string share, const std::string match, + const std::string output, const std::vector load_dirs ); void set_options( bool ignore_lm, double n ); // TODO : REMOVE @@ -98,6 +99,8 @@ public: // Debug void set_debug( std::string path, std::vector area_defs, std::vector shape_defs ); + void CreateMatchedEdgeFiles( std::vector& bucketList ); + private: virtual void run(); @@ -107,6 +110,10 @@ private: // Load Data void LoadElevationArray( bool add_nodes ); int LoadLandclassPolys( void ); + bool CheckMatchingNode( SGGeod& node, bool road, bool fixed ); + + SGGeod GetNearestNodeLatitude( const SGGeod& node, const std::vector& selection ); + SGGeod GetNearestNodeLongitude( const SGGeod& node, const std::vector& selection ); // Clip Data bool ClipLandclassPolys( void ); @@ -118,8 +125,11 @@ private: // Shared edge Matching void SaveSharedEdgeData( int stage ); void LoadSharedEdgeData( int stage ); + void LoadMatchedEdgeFiles(); void LoadNeighboorEdgeDataStage1( SGBucket& b, std::vector& north, std::vector& south, std::vector& east, std::vector& west ); + void LoadNeighboorMatchDataStage1( SGBucket& b, std::vector& north, std::vector& south, std::vector& east, std::vector& west ); + void ReadNeighborFaces( gzFile& fp ); void WriteNeighborFaces( gzFile& fp, const SGGeod& pt ) const; TGNeighborFaces* AddNeighborFaces( const SGGeod& node ); @@ -164,14 +174,16 @@ private: SGLockedQueue& workQueue; unsigned int total_tiles; unsigned int stage; + std::vector nm_north, nm_south, nm_east, nm_west; // path to land-cover file (if any) std::string cover; // paths std::string work_base; - std::string output_base; std::string share_base; + std::string match_base; + std::string output_base; std::vector load_dirs; diff --git a/src/BuildTiles/Main/tgconstruct_clip.cxx b/src/BuildTiles/Main/tgconstruct_clip.cxx index 8b98d29d..411918c9 100644 --- a/src/BuildTiles/Main/tgconstruct_clip.cxx +++ b/src/BuildTiles/Main/tgconstruct_clip.cxx @@ -278,6 +278,7 @@ bool TGConstruct::ClipLandclassPolys( void ) { // Now make sure any newly added intersection nodes are added to the tgnodes for (unsigned int area = 0; area < area_defs.size(); area++) { + bool isRoad = area_defs.is_road_area( area ); for (unsigned int p = 0; p < polys_clipped.area_size(area); p++ ) { tgPolygon& poly = polys_clipped.get_poly( area, p ); @@ -286,8 +287,12 @@ bool TGConstruct::ClipLandclassPolys( void ) { for (unsigned int con=0; con < poly.Contours(); con++) { for (unsigned int n = 0; n < poly.ContourSize( con ); n++) { // ensure we have all nodes... - TGNode const& node = poly.GetNode( con, n ); - nodes.unique_add( node ); + SGGeod node = poly.GetNode( con, n ); + if ( CheckMatchingNode( node, isRoad, false ) ) { + poly.SetNode( con, n, node ); + } else { + poly.DelNode( con, n ); + } } } } diff --git a/src/BuildTiles/Main/tgconstruct_elevation.cxx b/src/BuildTiles/Main/tgconstruct_elevation.cxx index 80794d18..99be7bff 100644 --- a/src/BuildTiles/Main/tgconstruct_elevation.cxx +++ b/src/BuildTiles/Main/tgconstruct_elevation.cxx @@ -56,7 +56,10 @@ void TGConstruct::LoadElevationArray( bool add_nodes ) { std::vector const& fit_list = array.get_fitted_list(); for (unsigned int i=0; i= 0; k--) { + SGGeod node = poly.GetNode( j, k ); + bool isFixed = poly.GetPreserve3D(); + + if ( CheckMatchingNode( node, isRoad, isFixed ) ) { + poly.SetNode( j, k, node ); } else { - nodes.unique_add( node ); + poly.DelNode( j, k ); } } } @@ -111,6 +110,13 @@ int TGConstruct::LoadLandclassPolys( void ) { tgShapefile::FromPolygon( poly, ds_name, layer, material.c_str() ); } + + /* make sure we loaded a valid poly */ + poly = tgPolygon::RemoveBadContours(poly); + if ( poly.Contours() ) { + polys_in.add_poly( area, poly ); + total_polys_read++; + } } } @@ -124,3 +130,112 @@ int TGConstruct::LoadLandclassPolys( void ) { return total_polys_read; } + +bool TGConstruct::CheckMatchingNode( SGGeod& node, bool road, bool fixed ) +{ + bool matched = false; + bool added = false; + + if ( fixed ) { + node = nodes.unique_add_fixed_elevation( node ); + added = true; + } else { + // check mutable edge + if ( !nm_north.empty() ) { + double north_compare = bucket.get_center_lat() + 0.5 * bucket.get_height(); + if ( fabs(node.getLatitudeDeg() - north_compare) < SG_EPSILON) { + if ( !road ) { + // node is on the non_mutable northern border - get closest pt + node = GetNearestNodeLongitude( node, nm_north ); + SG_LOG(SG_GENERAL, SG_DEBUG, " AddNode: constrained on north border from " << node << " to " << node ); + added = true; + } else { + matched = true; + } + } + } + + if ( !added && !matched && !nm_south.empty() ) { + double south_compare = bucket.get_center_lat() - 0.5 * bucket.get_height(); + if ( fabs(node.getLatitudeDeg() - south_compare) < SG_EPSILON) { + if ( !road ) { + // node is on the non_mutable southern border - get closest pt + node = GetNearestNodeLongitude( node, nm_south ); + SG_LOG(SG_GENERAL, SG_DEBUG, " AddNode: constrained on south border from " << node << " to " << node ); + added = true; + } else { + matched = true; + } + } + } + + if ( !added && !matched && !nm_east.empty() ) { + double east_compare = bucket.get_center_lon() + 0.5 * bucket.get_width(); + if ( fabs(node.getLongitudeDeg() - east_compare) < SG_EPSILON) { + if ( !road ) { + // node is on the non_mutable eastern border - get closest pt + node = GetNearestNodeLatitude( node, nm_east ); + SG_LOG(SG_GENERAL, SG_DEBUG, " AddNode: constrained on east border from " << node << " to " << node ); + added = true; + } else { + matched = true; + } + } + } + + if ( !added && !matched && !nm_west.empty() ) { + double west_compare = bucket.get_center_lon() - 0.5 * bucket.get_width(); + if ( fabs(node.getLongitudeDeg() - west_compare) < SG_EPSILON) { + if ( !road ) { + // node is on the non_mutable western border - get closest pt + node = GetNearestNodeLatitude( node, nm_west ); + SG_LOG(SG_GENERAL, SG_DEBUG, " AddNode: constrained on west border from " << node << " to " << node ); + added = true; + } else { + matched = true; + } + } + } + } + + if (!added && !matched) { + node = nodes.unique_add( node ); + added = true; + } + + return added; +} + +SGGeod TGConstruct::GetNearestNodeLongitude( const SGGeod& node, const std::vector& selection ) +{ + double min_dist = std::numeric_limits::infinity(); + double cur_dist; + unsigned int min_idx = 0; + + for ( unsigned int i=0; i& selection ) +{ + double min_dist = std::numeric_limits::infinity(); + double cur_dist; + unsigned int min_idx = 0; + + for ( unsigned int i=0; i #include +#include #include #include @@ -34,6 +35,147 @@ using std::string; +void TGConstruct::CreateMatchedEdgeFiles( std::vector& bucketList ) +{ + // todo - add to work queue + for ( unsigned int i=0; i wgs84_nodes(obj.get_wgs84_nodes() ); + + string filepath; + std::vector north, south, east, west; + int nCount; + + // read in all of the .btg nodes + for ( unsigned int j=0; jlock(); + + file2.create_dir( 0755 ); + + gzFile fp; + if ( (fp = gzopen( filepath.c_str(), "wb9" )) == NULL ) { + SG_LOG( SG_GENERAL, SG_INFO, "ERROR: opening " << file.str() << " for writing!" ); + return; + } + + sgClearWriteError(); + + // north + nCount = north.size(); + SG_LOG( SG_GENERAL, SG_DEBUG, "write " << north.size() << " northern nodes to file " << filepath.c_str() ); + sgWriteInt( fp, nCount ); + for (int i=0; iunlock(); + } +} + +void TGConstruct::LoadMatchedEdgeFiles() +{ + // try to load matched edges - on successful load, the edge is marked immutable + + // we need to read just 4 buckets for stage 1 - 1 for each edge + std::vector north, south, east, west; + SGBucket nb, sb, eb, wb; + + // Read Northern tile and add its southern nodes + nb = bucket.sibling(0, 1); + LoadNeighboorMatchDataStage1( nb, north, south, east, west ); + if ( !south.empty() ) { + SG_LOG( SG_GENERAL, SG_DEBUG, "Read " << south.size() << " northern matched nodes " ); + + // Add southern nodes from northern tile + for (unsigned int i=0; i& } } +void TGConstruct::LoadNeighboorMatchDataStage1( SGBucket& b, std::vector& north, std::vector& south, std::vector& east, std::vector& west ) +{ + string dir; + string file; + gzFile fp; + SGGeod pt; + int nCount; + + dir = share_base + "/match1/" + b.gen_base_path(); + file = dir + "/" + b.gen_index_str() + "_edges"; + fp = gzopen( file.c_str(), "rb" ); + + north.clear(); + south.clear(); + east.clear(); + west.clear(); + + if (fp) { + // North + sgReadInt( fp, &nCount ); + SG_LOG( SG_CLIPPER, SG_DEBUG, "loading " << nCount << "Points on " << b.gen_index_str() << " north boundary"); + for (int i=0; i