diff --git a/src/BuildTiles/Clipper/clipper.cxx b/src/BuildTiles/Clipper/clipper.cxx index f667454c..bc39f489 100644 --- a/src/BuildTiles/Clipper/clipper.cxx +++ b/src/BuildTiles/Clipper/clipper.cxx @@ -41,11 +41,8 @@ #include -using std::cout; -using std::endl; using std::string; - #define MASK_CLIP 1 @@ -65,9 +62,9 @@ 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.polys[i].clear(); + polys_in.superpolys[i].clear(); } - fixed_elevations.clear(); + nodes.clear(); return true; } @@ -89,7 +86,7 @@ bool TGClipper::load_polys(const string& path) { if ( !in ) { SG_LOG( SG_CLIPPER, SG_ALERT, "Cannot open file: " << path ); - exit(-1); + exit(-1); } TGPolygon poly; @@ -109,83 +106,86 @@ bool TGClipper::load_polys(const string& path) { poly3d = false; poly_name = first_line; } - cout << "poly name = " << poly_name << endl; - poly_type = get_area_type( poly_name ); - cout << "poly type (int) = " << (int)poly_type << endl; - in >> contours; - cout << "num contours = " << contours << endl; + 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(); + poly.erase(); - for ( i = 0; i < contours; ++i ) { - in >> count; - // cout << "Contour = " << i << " size = " << count << endl; + 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); - } + if ( count < 3 ) { + SG_LOG( SG_CLIPPER, SG_ALERT, "Polygon with less than 3 data points." ); + exit(-1); + } - in >> hole_flag; + in >> hole_flag; - in >> startx; - in >> starty; + in >> startx; + in >> starty; if ( poly3d ) { in >> startz; } else { startz = -9999.0; } - p = Point3D(startx+nudge, starty+nudge, startz); - poly.add_node( i, p ); + p = Point3D(startx+nudge, starty+nudge, startz); + poly.add_node( i, p ); + if ( poly3d ) { - fixed_elevations.unique_add( p ); + nodes.unique_add_fixed_elevation( p ); + } else { + nodes.unique_add( p ); } - for ( j = 1; j < count - 1; ++j ) { - in >> x; - in >> y; + 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 ); + p = Point3D( x+nudge, y+nudge, z ); + poly.add_node( i, p ); if ( poly3d ) { - fixed_elevations.unique_add( p ); + nodes.unique_add_fixed_elevation( p ); + } else { + nodes.unique_add( p ); } - } + } - in >> lastx; - in >> lasty; + 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 ( (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 ) { - fixed_elevations.unique_add( p ); + 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); - - // FILE *ofp= fopen("outfile", "w"); - // gpc_write_polygon(ofp, &polys.landuse); - - in >> skipcomment; + add_poly(area, poly, material); + + in >> skipcomment; } return true; @@ -195,7 +195,6 @@ bool TGClipper::load_polys(const string& path) { // 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) { -// cout << "Loading osgb36 poly\n"; string poly_name; AreaType poly_type; int contours, count, i, j; @@ -208,100 +207,98 @@ bool TGClipper::load_osgb36_polys(const string& path) { if ( !in ) { SG_LOG( SG_CLIPPER, SG_ALERT, "Cannot open file: " << path ); - exit(-1); + exit(-1); } - // gpc_polygon *poly = new gpc_polygon; - // poly->num_contours = 0; - // poly->contour = NULL; TGPolygon poly; Point3D p; Point3D OSRef; in >> skipcomment; while ( !in.eof() ) { - in >> poly_name; - cout << "poly name = " << poly_name << endl; - poly_type = get_area_type( poly_name ); - cout << "poly type (int) = " << (int)poly_type << endl; - in >> contours; - cout << "num contours = " << contours << endl; + 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(); + poly.erase(); - for ( i = 0; i < contours; ++i ) { - in >> count; + 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); - } + if ( count < 3 ) { + SG_LOG( SG_CLIPPER, SG_ALERT, "Polygon with less than 3 data points." ); + exit(-1); + } - in >> hole_flag; + in >> hole_flag; + + in >> startx; + in >> starty; + OSRef = Point3D(startx, starty, -9999.0); - 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); + p = OSGB36ToWGS84(OSRef); - poly.add_node( i, p ); - SG_LOG( SG_CLIPPER, SG_BULK, "0 = " - << startx << ", " << starty ); + poly.add_node( i, p ); + nodes.unique_add( p ); - for ( j = 1; j < count - 1; ++j ) { - in >> x; - in >> y; - OSRef = Point3D( x, y, -9999.0 ); - p = OSGB36ToWGS84(OSRef); + 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 ); - SG_LOG( SG_CLIPPER, SG_BULK, j << " = " << x << ", " << y ); - } + poly.add_node( i, p ); + nodes.unique_add( p ); + SG_LOG( SG_CLIPPER, SG_BULK, j << " = " << x << ", " << y ); + } - in >> lastx; - in >> lasty; + 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); + 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 ); - SG_LOG( SG_CLIPPER, SG_BULK, count - 1 << " = " - << lastx << ", " << lasty ); - } - - // gpc_add_contour( poly, &v_list, hole_flag ); - } + 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); + add_poly(area, poly, material); - // FILE *ofp= fopen("outfile", "w"); - // gpc_write_polygon(ofp, &polys.landuse); - - in >> skipcomment; + in >> skipcomment; } return true; } // Add a polygon to the clipper. -void TGClipper::add_poly( int area, const TGPolygon &poly ) +void TGClipper::add_poly( int area, const TGPolygon &poly, string material ) { + TGSuperPoly sp; + if ( area < TG_MAX_AREA_TYPES ) { - polys_in.polys[area].push_back(poly); + 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); + SG_LOG( SG_CLIPPER, SG_ALERT, "Polygon type out of range = " << area); + exit(-1); } } @@ -310,9 +307,6 @@ void TGClipper::add_poly( int area, const TGPolygon &poly ) void TGClipper::move_slivers( TGPolygon& in, TGPolygon& out ) { // traverse each contour of the polygon and attempt to identify // likely slivers - - // cout << "Begin move slivers" << endl; - int i; out.erase(); @@ -328,36 +322,27 @@ void TGClipper::move_slivers( TGPolygon& in, TGPolygon& out ) { // process contours in reverse order so deleting a contour doesn't // foul up our sequence for ( i = in.contours() - 1; i >= 0; --i ) { - // cout << "contour " << i << endl; + min_angle = in.minangle_contour( i ); + area = in.area_contour( 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; - /* cout << " min_angle (rad) = " - << min_angle << endl; - cout << " min_angle (deg) = " - << min_angle * 180.0 / SGD_PI << endl; - cout << " area = " << area << endl; */ + // check if this is a hole + hole_flag = in.get_hole_flag( 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 ); - } - } + 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 ); + } + } } } @@ -373,62 +358,44 @@ void TGClipper::merge_slivers( TGPolyList& clipped, TGPolygon& slivers ) { point_list contour; int original_contours, result_contours; bool done; - int area, i, j, k; + int area, i, j; for ( i = 0; i < slivers.contours(); ++i ) { - // cout << "Merging sliver = " << i << endl; + // cout << "Merging sliver = " << i << endl; - // make the sliver polygon - contour = slivers.get_contour( i ); - sliver.erase(); - sliver.add_contour( contour, 0 ); - done = false; + // 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 ) { + 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; - } + 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.polys[area].size() && !done; - ++j ) - { - // cout << " polygon = " << j << endl; + // 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(); - poly = clipped.polys[area][j]; - 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 ( original_contours == result_contours ) { - // cout << " FOUND a poly to merge the sliver with" << endl; - clipped.polys[area][j] = result; - done = true; - // poly.write("orig"); - // sliver.write("sliver"); - // result.write("result"); - // cout << "press return: "; - // string input; - // cin >> input; - //} else { - // cout << " poly not a match" << endl; - // cout << " original = " << original_contours - // << " result = " << result_contours << endl; - // cout << " sliver = " << endl; - // for ( k = 0; k < (int)contour.size(); ++k ) { - // cout << " " << contour[k].x() << ", " - // << contour[k].y() << endl; - // } - } - } - } - if ( !done ) { - // cout << "no suitable polys found for sliver merge" << endl; - } + if ( !done ) { + // cout << "no suitable polys found for sliver merge" << endl; + } } } @@ -439,22 +406,31 @@ bool TGClipper::clip_all(const point2d& min, const point2d& max) { TGPolygon accum, tmp; TGPolygon slivers, remains; int i, j; - - // gpcpoly_iterator current, last; + 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(); - cout << " (" << min.x << "," << min.y << ") (" - << max.x << "," << max.y << ")" << endl; - - // set up clipping tile + // set up clipping tile : and remember to add the nodes! polys_in.safety_base.erase(); - polys_in.safety_base.add_node( 0, Point3D(min.x, min.y, -9999.0) ); - polys_in.safety_base.add_node( 0, Point3D(max.x, min.y, -9999.0) ); - polys_in.safety_base.add_node( 0, Point3D(max.x, max.y, -9999.0) ); - polys_in.safety_base.add_node( 0, Point3D(min.x, max.y, -9999.0) ); + + 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 @@ -467,31 +443,26 @@ bool TGClipper::clip_all(const point2d& min, const point2d& max) { island_mask.erase(); for ( i = 0; i < TG_MAX_AREA_TYPES; i++ ) { if ( is_landmass_area( i ) && !m_ignore_landmass ) { - for ( unsigned j = 0; j < (int)polys_in.polys[i].size(); ++j ) { - land_mask = - tgPolygonUnion( land_mask, polys_in.polys[i][j] ); + 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.polys[i].size(); j++) { - water_mask = - tgPolygonUnion( water_mask, polys_in.polys[i][j] ); + 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.polys[i].size(); j++) { - island_mask = - tgPolygonUnion( island_mask, polys_in.polys[i][j] ); + 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 ) { - cout << "num polys of type (" << i << ") = " - << polys_in.polys[i].size() << endl; - for( j = 0; j < (int)polys_in.polys[i].size(); ++j ) { - TGPolygon current = polys_in.polys[i][j]; - SG_LOG( SG_CLIPPER, SG_INFO, get_area_name( (AreaType)i ) - << " = " << current.contours() ); + 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; @@ -502,61 +473,59 @@ bool TGClipper::clip_all(const point2d& min, const point2d& max) { // 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. - // + // + // 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 ); - } + // 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; + 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); - } + 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); + // 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); - } + // merge any slivers with previously clipped + // neighboring polygons + if ( slivers.contours() > 0 ) { + merge_slivers(polys_clipped, slivers); + } - // add the sliverless result polygon (from after the - // move_slivers) to the clipped polys list - if ( result_diff.contours() > 0 ) { - polys_clipped.polys[i].push_back(result_diff); + // 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 ); - // static int count = 0; - // cout << "Writing clipped polygon to next-result" << count - // << endl; - // char filename[256]; - // sprintf(filename, "next-result-%02d-%02d", i, count++); - // result_diff.write(filename); - } - } - accum = result_union; - } + 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 @@ -568,45 +537,31 @@ bool TGClipper::clip_all(const point2d& min, const point2d& max) { 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; + // 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); - } + // merge any slivers with previously clipped + // neighboring polygons + if ( slivers.contours() > 0 ) { + merge_slivers(polys_clipped, slivers); + } - if ( remains.contours() > 0 ) { - polys_clipped.polys[(int)get_sliver_target_area_type()].push_back(remains); - } + 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); + } } -#if 0 - FILE *ofp; - - // tmp output accum - if ( accum.num_contours ) { - ofp = fopen("accum", "w"); - gpc_write_polygon(ofp, 1, &accum); - fclose(ofp); - } - - // tmp output safety_base - if ( remains->num_contours ) { - ofp= fopen("remains", "w"); - gpc_write_polygon(ofp, 1, remains); - fclose(ofp); - } -#endif - 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 index 3356e210..5fd6e3a2 100644 --- a/src/BuildTiles/Clipper/clipper.hxx +++ b/src/BuildTiles/Clipper/clipper.hxx @@ -35,8 +35,10 @@ #include -#include -#include +//#include +#include +#include +#include #include #include @@ -49,18 +51,21 @@ class TGPolyList { public: - poly_list polys[TG_MAX_AREA_TYPES]; + 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; + //TGTriNodes fixed_elevations; + TGNodes nodes; public: @@ -80,7 +85,7 @@ public: bool load_osgb36_polys(const std::string& path); // Add a polygon. - void add_poly(int area, const TGPolygon &poly); + void add_poly(int area, const TGPolygon &poly, std::string material); // Remove any slivers from in polygon and move them to out // polygon. @@ -99,7 +104,9 @@ public: inline TGPolyList get_polys_clipped() const { return polys_clipped; } // Return the fixed elevation points list - inline TGTriNodes get_fixed_elevations() const { return fixed_elevations; } + inline TGNodes get_nodes() const { return nodes; } + + inline node_list get_fixed_elevations_nodes() { return nodes.get_fixed_elevation_nodes(); } double nudge; diff --git a/src/BuildTiles/GenOutput/genobj.cxx b/src/BuildTiles/GenOutput/genobj.cxx index d25307f4..1e049d99 100644 --- a/src/BuildTiles/GenOutput/genobj.cxx +++ b/src/BuildTiles/GenOutput/genobj.cxx @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -49,7 +50,7 @@ void TGGenOutput::calc_gbs( TGConstruct& c ) { gbs_center = SGVec3d::fromGeod( c.get_bucket().get_center() ); double dist_squared, radius_squared = 0; - for ( int i = 0; i < wgs84_nodes.size(); ++i ) { + 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; @@ -58,127 +59,45 @@ void TGGenOutput::calc_gbs( TGConstruct& c ) { gbs_radius = sqrt(radius_squared); } - -#if 0 -#define FG_STANDARD_TEXTURE_DIMENSION 1000.0 // meters - -// traverse the specified fan and attempt to calculate "none -// stretching" texture coordinates -int_list TGGenOutput::calc_tex_coords( TGConstruct& c, point_list geod_nodes, - int_list fan ) -{ - // cout << "calculating texture coordinates for a specific fan of size = " - // << fan.size() << endl; - - SGBucket b = c.get_bucket(); - double clat = b.get_center_lat(); - double clat_rad = clat * SGD_DEGREES_TO_RADIANS; - double cos_lat = cos( clat_rad ); - double local_radius = cos_lat * SG_EQUATORIAL_RADIUS_M; - double local_perimeter = 2.0 * local_radius * SGD_PI; - double degree_width = local_perimeter / 360.0; - - // cout << "clat = " << clat << endl; - // cout << "clat (radians) = " << clat_rad << endl; - // cout << "cos(lat) = " << cos_lat << endl; - // cout << "local_radius = " << local_radius << endl; - // cout << "local_perimeter = " << local_perimeter << endl; - // cout << "degree_width = " << degree_width << endl; - - double perimeter = 2.0 * SG_EQUATORIAL_RADIUS_M * SG_DPI; - double degree_height = perimeter / 360.0; - // cout << "degree_height = " << degree_height << endl; - - // find min/max of fan - Point3D min, max, p, t; - bool first = true; - - for ( int i = 0; i < (int)fan.size(); ++i ) { - p = geod_nodes[ fan[i] ]; - t.setx( p.x() * ( degree_width / FG_STANDARD_TEXTURE_DIMENSION ) ); - t.sety( p.y() * ( degree_height / FG_STANDARD_TEXTURE_DIMENSION ) ); - - if ( first ) { - min = max = t; - first = false; - } else { - if ( t.x() < min.x() ) { - min.setx( t.x() ); - } - if ( t.y() < min.y() ) { - min.sety( t.y() ); - } - if ( t.x() > max.x() ) { - max.setx( t.x() ); - } - if ( t.y() > max.y() ) { - max.sety( t.y() ); - } - } - } - min.setx( (double)( (int)min.x() - 1 ) ); - min.sety( (double)( (int)min.y() - 1 ) ); - // cout << "found min = " << min << endl; - - // generate tex_list - Point3D shifted_t; - int index; - int_list tex; - tex.clear(); - for ( int i = 0; i < (int)fan.size(); ++i ) { - p = geod_nodes[ fan[i] ]; - t.setx( p.x() * ( degree_width / FG_STANDARD_TEXTURE_DIMENSION ) ); - t.sety( p.y() * ( degree_height / FG_STANDARD_TEXTURE_DIMENSION ) ); - shifted_t = t - min; - if ( shifted_t.x() < SG_EPSILON ) { - shifted_t.setx( 0.0 ); - } - if ( shifted_t.y() < SG_EPSILON ) { - shifted_t.sety( 0.0 ); - } - shifted_t.setz( 0.0 ); - // cout << "shifted_t = " << shifted_t << endl; - index = tex_coords.unique_add( shifted_t ); - tex.push_back( index ); - } - - return tex; -} -#endif - - // build the necessary output structures based on the triangulation // data -int TGGenOutput::build( TGConstruct& c ) { - int i, j, k; +int TGGenOutput::build_fans( TGConstruct& c ) { +// TGTriNodes trinodes = c.get_tri_nodes(); + TGNodes* nodes = c.get_nodes(); - TGTriNodes trinodes = c.get_tri_nodes(); + string tile_id = c.get_bucket().gen_index_str(); // copy the geodetic node list into this class - geod_nodes = trinodes.get_node_list(); + 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; - for ( 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 ( (int)t_current->get_attribute() == i ) { - area_tris.push_back( *t_current ); - } - } + // 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() ); - if ( (int)area_tris.size() > 0 ) { - cout << "generating fans for area = " << i << endl; - fans[i] = f.greedy_build( area_tris ); - } + 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 @@ -187,37 +106,38 @@ int TGGenOutput::build( TGConstruct& c ) { cout << "c.get_useUKGrid() = " << c.get_useUKGrid() << endl; tex_coords.clear(); std::vector < SGGeod > convGeodNodes; - for ( k = 0; k < geod_nodes.size(); k++ ) { + 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 ( i = 0; i < TG_MAX_AREA_TYPES; ++i ) { + + for ( unsigned int i = 0; i < TG_MAX_AREA_TYPES; ++i ) { // cout << " area = " << i << endl; - for ( j = 0; j < (int)fans[i].size(); ++j ) { - // int_list t_list = calc_tex_coords( c, geod_nodes, fans[i][j] ); - // cout << fans[i][j].size() << " === " - // << t_list.size() << endl; - SGBucket b = c.get_bucket(); - Point3D ourPosition; + 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() ); - ourPosition.setlon(b.get_chunk_lon()); - ourPosition.setlat(b.get_chunk_lat()); + SGBucket b = c.get_bucket(); + Point3D ourPosition; - 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, fans[i][j], 1.0 ); - for ( k = 0; k < (int)tp_list.size(); ++k ) { + 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, fans[i][j] ); - for ( k = 0; k < (int)tp_list.size(); ++k ) { + } 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 ) ); @@ -225,8 +145,8 @@ int TGGenOutput::build( TGConstruct& c ) { } } - textures[i].push_back( ti_list ); - } + textures[i].push_back( ti_list ); + } } // calculate the global bounding sphere @@ -237,21 +157,132 @@ int TGGenOutput::build( TGConstruct& c ) { } +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& fans, + const opt_list& primitives, Point3D *center, double *radius ) { - cout << "calculate group bounding sphere for " << fans.size() << " fans." - << endl; + 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 = fans.begin(); - const_opt_list_iterator f_last = fans.end(); + 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(); @@ -325,130 +356,8 @@ void TGGenOutput::calc_bounding_sphere( TGConstruct& c, const TGTriEle& t, *radius = sqrt(max_squared); } - -#if 0 -// write out the fgfs scenery file -int TGGenOutput::write_orig( TGConstruct &c ) { - Point3D p; - int i; - - string base = c.get_output_base(); - SGBucket b = c.get_bucket(); - - string dir = base + b.gen_base_path(); - -#ifdef _MSC_VER - fg_mkdir( dir.c_str() ); -#else - string command = "mkdir -p " + dir; - system(command.c_str()); -#endif - - string file = dir + "/" + b.gen_index_str(); - cout << "Output file = " << file << endl; - - FILE *fp; - if ( (fp = fopen( file.c_str(), "w" )) == NULL ) { - cout << "ERROR: opening " << file << " for writing!" << endl; - exit(-1); - } - - // write headers - fprintf(fp, "# FGFS Scenery\n"); - fprintf(fp, "# Version %s\n", FG_SCENERY_FILE_FORMAT); - - time_t calendar_time = time(NULL); - struct tm *local_tm; - local_tm = localtime( &calendar_time ); - char time_str[256]; - strftime( time_str, 256, "%a %b %d %H:%M:%S %Z %Y", local_tm); - fprintf(fp, "# Created %s\n", time_str ); - fprintf(fp, "\n"); - - // write global bounding sphere - fprintf(fp, "# gbs %.5f %.5f %.5f %.2f\n", - gbs_center.x(), gbs_center.y(), gbs_center.z(), gbs_radius); - fprintf(fp, "\n"); - - // write nodes - point_list wgs84_nodes = c.get_wgs84_nodes(); - cout << "writing nodes = " << wgs84_nodes.size() << endl; - fprintf(fp, "# vertex list\n"); - const_point_list_iterator w_current = wgs84_nodes.begin(); - const_point_list_iterator w_last = wgs84_nodes.end(); - for ( ; w_current != w_last; ++w_current ) { - p = *w_current - gbs_center; - fprintf(fp, "v %.5f %.5f %.5f\n", p.x(), p.y(), p.z()); - } - fprintf(fp, "\n"); - - // write vertex normals - point_list point_normals = c.get_point_normals(); - cout << "writing normals = " << point_normals.size() << endl; - fprintf(fp, "# vertex normal list\n"); - const_point_list_iterator n_current = point_normals.begin(); - const_point_list_iterator n_last = point_normals.end(); - for ( ; n_current != n_last; ++n_current ) { - p = *n_current; - fprintf(fp, "vn %.5f %.5f %.5f\n", p.x(), p.y(), p.z()); - } - fprintf(fp, "\n"); - - // write texture coordinates - point_list tex_coord_list = tex_coords.get_node_list(); - fprintf(fp, "# texture coordinate list\n"); - for ( i = 0; i < (int)tex_coord_list.size(); ++i ) { - p = tex_coord_list[i]; - fprintf(fp, "vt %.5f %.5f\n", p.x(), p.y()); - } - fprintf(fp, "\n"); - - // write triangles (grouped by type for now) - Point3D center; - double radius; - fprintf(fp, "# triangle groups\n"); - fprintf(fp, "\n"); - - int total_tris = 0; - for ( i = 0; i < TG_MAX_AREA_TYPES; ++i ) { - if ( (int)fans[i].size() > 0 ) { - string attr_name = get_area_name( (AreaType)i ); - calc_group_bounding_sphere( c, fans[i], ¢er, &radius ); - cout << "writing " << (int)fans[i].size() << " fans for " - << attr_name << endl; - - fprintf(fp, "# usemtl %s\n", attr_name.c_str() ); - fprintf(fp, "# bs %.4f %.4f %.4f %.2f\n", - center.x(), center.y(), center.z(), radius); - - for ( int j = 0; j < (int)fans[i].size(); ++j ) { - fprintf( fp, "tf" ); - total_tris += fans[i][j].size() - 2; - for ( int k = 0; k < (int)fans[i][j].size(); ++k ) { - fprintf( fp, " %d/%d", fans[i][j][k], textures[i][j][k] ); - } - fprintf( fp, "\n" ); - } - - fprintf( fp, "\n" ); - } - } - cout << "wrote " << total_tris << " tris to output file" << endl; - - fclose(fp); - - command = "gzip --force --best " + file; - system(command.c_str()); - - return 1; -} -#endif - - -// write out the fgfs scenery file -int TGGenOutput::write( TGConstruct &c ) { - int i; - +// 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(); @@ -457,12 +366,12 @@ int TGGenOutput::write( TGConstruct &c ) { name += ".btg"; std::vector< SGVec3d > wgs84_nodes; - for ( i = 0; i < c.get_wgs84_nodes().size(); i++ ) { + 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 ( i = 0; i < c.get_point_normals().size(); i++ ) { + for ( unsigned int i = 0; i < c.get_point_normals().size(); i++ ) { Point3D node = c.get_point_normals()[i]; normals.push_back( node.toSGVec3f() ); } @@ -472,7 +381,7 @@ int TGGenOutput::write( TGConstruct &c ) { printf("vn %.5f %.5f %.5f\n", p.x(), p.y(), p.z()); } */ std::vector< SGVec2f > texcoords; - for ( i = 0; i < tex_coords.get_node_list().size(); i++ ) { + 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() ); } @@ -487,17 +396,16 @@ int TGGenOutput::write( TGConstruct &c ) { group_list fans_v; group_list fans_tc; string_list fan_materials; fans_v.clear(); fans_tc.clear(); fan_materials.clear(); - for ( i = 0; i < TG_MAX_AREA_TYPES; ++i ) { - if ( (int)fans[i].size() > 0 ) { - cout << "creating " << fans[i].size() << " fans of type " - << i << endl; + 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 ( int j = 0; j < (int)fans[i].size(); ++j ) { + for ( unsigned int j = 0; j < primitives[i].size(); ++j ) { vs.clear(); tcs.clear(); - for ( int k = 0; k < (int)fans[i][j].size(); ++k ) { - vs.push_back( fans[i][j][k] ); + 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 ); @@ -529,4 +437,83 @@ int TGGenOutput::write( TGConstruct &c ) { 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 index 3a24bb9c..ab3d605b 100644 --- a/src/BuildTiles/GenOutput/genobj.hxx +++ b/src/BuildTiles/GenOutput/genobj.hxx @@ -59,8 +59,8 @@ private: // texture coordinates TGTriNodes tex_coords; - // fan list - opt_list fans[TG_MAX_AREA_TYPES]; + // fan / triangle list + opt_list primitives[TG_MAX_AREA_TYPES]; // textures pointer list tex_list textures[TG_MAX_AREA_TYPES]; @@ -93,10 +93,12 @@ public: // build the necessary output structures based on the // triangulation data - int build( TGConstruct& c ); + int build_fans( TGConstruct& c ); + int build_tris( TGConstruct& c ); // write out the fgfs scenery file - int write( TGConstruct &c ); + int write_fans( TGConstruct &c ); + int write_tris( TGConstruct &c ); }; diff --git a/src/BuildTiles/Main/construct.hxx b/src/BuildTiles/Main/construct.hxx index 07829450..249831ab 100644 --- a/src/BuildTiles/Main/construct.hxx +++ b/src/BuildTiles/Main/construct.hxx @@ -92,10 +92,11 @@ private: // Fixed elevations (from polygon input data with z values // pre-specified) - TGTriNodes fixed_elevations; + node_list fixed_elevations; // raw node list (after triangulation) TGTriNodes tri_nodes; + TGNodes nodes; // node list in geodetic coords (with fixed elevation) point_list geod_nodes; @@ -115,10 +116,6 @@ private: // face normal list (for flat shading) point_list face_normals; - // normal list (for each point) in cart coords (for smooth - // shading) - point_list point_normals; - public: // Constructor @@ -167,33 +164,32 @@ public: 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 TGTriNodes get_fixed_elevations() const { return fixed_elevations; } - inline void set_fixed_elevations( TGTriNodes n ) { fixed_elevations = n; } + // 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) - inline TGTriNodes get_tri_nodes() const { return tri_nodes; } - inline void set_tri_nodes( TGTriNodes n ) { tri_nodes = n; } + // 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; } - // triangle elements (after triangulation) + 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 ); - } + inline void set_tri_attribute( int num, AreaType a ) { tri_elements[num].set_attribute( a ); } - // edge segments (after triangulation) + // 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 geod_nodes; } - inline void set_geod_nodes( point_list n ) { geod_nodes = n; } + 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 wgs84_nodes; } - inline void set_wgs84_nodes( point_list n ) { wgs84_nodes = n; } + 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 { @@ -209,8 +205,7 @@ public: // normal list (for each point) in cart coords (for smooth // shading) - inline point_list get_point_normals() const { return point_normals; } - inline void set_point_normals( point_list n ) { point_normals = n; } + inline point_list get_point_normals() const { return nodes.get_normals(); } }; diff --git a/src/BuildTiles/Main/main.cxx b/src/BuildTiles/Main/main.cxx index 546beff4..d38de906 100644 --- a/src/BuildTiles/Main/main.cxx +++ b/src/BuildTiles/Main/main.cxx @@ -21,6 +21,10 @@ // $Id: main.cxx,v 1.58 2005-09-28 16:40:32 curt Exp $ +// TODO TODO TODO : Get rid of construct - data hiding is moretrouble than it's worth right now. +// constantly needing to call set after every operation.... + + #ifdef HAVE_CONFIG_H # include #endif @@ -44,11 +48,20 @@ #include #include #include +#include +#include + #include +#include +#include +#include +#include +#include #include #include +#include #include #include #include @@ -59,15 +72,11 @@ #include "construct.hxx" #include "usgs.hxx" -using std::cout; -using std::cerr; -using std::endl; using std::string; using std::vector; vector load_dirs; - static const double cover_size = 1.0 / 120.0; static const double half_cover_size = cover_size * 0.5; @@ -80,20 +89,17 @@ static const double half_cover_size = cover_size * 0.5; // 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 ) { +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()) { - cout << "directory not found:" << dir.str() << "\n"; + SG_LOG(SG_GENERAL, SG_ALERT, "directory not found:" << dir.str()); return 0; } @@ -108,11 +114,11 @@ static int actual_load_polys( const SGPath& dir, { // skipped! } else if (lext == "osgb36") { - cout << "Loading osgb36 poly definition file\n"; + SG_LOG(SG_GENERAL, SG_ALERT, "Loading osgb36 poly definition file"); clipper.load_osgb36_polys( p.str() ); ++counter; } else { - cout << "ext = '" << lext << "'" << endl; + SG_LOG(SG_GENERAL, SG_ALERT, "ext = '" << lext << "'"); clipper.load_polys( p.str() ); ++counter; } @@ -129,16 +135,13 @@ static int actual_load_polys( const SGPath& dir, // 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 ); + accum = tgPolygonUnion( accum, poly ); } else { - accum = poly; + accum = poly; } } - -static AreaType get_area_type (const LandCover &cover, - double xpos, double ypos, - double dx, double dy) +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); @@ -204,7 +207,7 @@ static double measure_roughness( const TGArray &array, TGPolygon &poly ) { // metric of 1.0. Less than 1.0 is relatively flat. More than // 1.0 is relatively rough. - cout << "roughness = " << diff / 50.0 << endl; + SG_LOG(SG_GENERAL, SG_ALERT, "roughness = " << diff / 50.0 ); return diff / 50.0; } @@ -212,10 +215,9 @@ static double measure_roughness( const TGArray &array, TGPolygon &poly ) { // 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 ) +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) @@ -223,13 +225,13 @@ static void make_area( const LandCover &cover, const TGArray &array, 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)); + // 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); @@ -240,8 +242,7 @@ static void make_area( const LandCover &cover, const TGArray &array, // 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 ) +static int actual_load_landcover ( TGConstruct &c, const TGArray &array, TGClipper &clipper ) { int count = 0; @@ -259,21 +260,14 @@ static int actual_load_landcover ( TGConstruct &c, const TGArray &array, - 0.5 * c.get_bucket().get_height() - quarter_cover_size; - cout << "raster land cover: tile at " - << base_lon << ',' << base_lat << endl; + 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(); - cout << "raster land cover: extends to " - << max_lon << ',' << max_lat << endl; - - // cout << "raster land cover: width = " << c.get_bucket().get_width() - // << " height = " << c.get_bucket().get_height() << endl; - - // cout << "cover_size = " << cover_size << endl; + SG_LOG(SG_GENERAL, SG_ALERT, "raster land cover: extends to " << max_lon << ',' << max_lat); double x1 = base_lon; double y1 = base_lat; @@ -282,8 +276,7 @@ static int actual_load_landcover ( TGConstruct &c, const TGArray &array, while ( x1 < max_lon ) { while ( y1 < max_lat ) { - make_area( cover, array, polys, - x1, y1, x2, y2, half_cover_size, half_cover_size ); + make_area( cover, array, polys, x1, y1, x2, y2, half_cover_size, half_cover_size ); y1 = y2; y2 += cover_size; @@ -300,12 +293,12 @@ static int actual_load_landcover ( TGConstruct &c, const TGArray &array, // 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] ); + clipper.add_poly( i, polys[i], get_area_name((AreaType)i )); count++; } } } catch ( string e ) { - cerr << "Died with exception: " << e << endl; + SG_LOG(SG_GENERAL, SG_ALERT, "Died with exception: " << e); exit(-1); } @@ -332,15 +325,15 @@ static int load_polys( TGConstruct& c, const TGArray &array ) { // 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; - cout << "poly_path = " << poly_path << endl; - count += actual_load_polys( poly_path, c, clipper ); - cout << " loaded " << count << " total polys" << endl; + 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); + count += actual_load_landcover (c, array, clipper); } point2d min, max; @@ -350,12 +343,15 @@ static int load_polys( TGConstruct& c, const TGArray &array ) { max.y = c.get_bucket().get_center_lat() + 0.5 * c.get_bucket().get_height(); // do clipping - cout << "clipping polygons" << endl; + 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() ); + // c.set_fixed_elevations( clipper.get_fixed_elevations_nodes() ); + + // really set nodes + c.set_nodes( clipper.get_nodes() ); return count; } @@ -368,16 +364,15 @@ static bool load_array( TGConstruct& c, TGArray& array) { 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(); - cout << "array_path = " << array_path << endl; + 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) ) { - cout << "Found Array file " << array_path << endl; - break; - } else { - cout << "Failed to open Array file " << array_path << endl; - } + 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(); @@ -387,10 +382,9 @@ static bool load_array( TGConstruct& c, TGArray& array) { 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 ) { +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 @@ -398,42 +392,41 @@ static void first_triangulate( TGConstruct& c, const TGArray& array, point_list fit_list = array.get_fitted_list(); TGPolyList gpc_polys = c.get_clipped_polys(); - cout << "ready to build node list and polygons" << endl; + SG_LOG(SG_GENERAL, SG_ALERT, "ready to build node list and polygons"); t.build( corner_list, fit_list, gpc_polys ); - cout << "done building node list and polygons" << endl; + SG_LOG(SG_GENERAL, SG_ALERT, "done building node list and polygons"); - cout << "ready to do triangulation" << endl; + SG_LOG(SG_GENERAL, SG_ALERT, "ready to do triangulation"); t.run_triangulate( 0.0, 1 ); - cout << "finished triangulation" << endl; + 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 ) { +static void second_triangulate( TGConstruct& c, TGTriangle& t ) { t.rebuild( c ); - cout << "done re building node list and polygons" << endl; - cout << "ready to do second triangulation" << endl; - - cout << " (pre) nodes = " << c.get_tri_nodes().size() << endl; - cout << " (pre) normals = " << c.get_point_normals().size() << endl; + 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 ); - cout << " (post) nodes = " << t.get_out_nodes().size() << endl; - - cout << "finished second triangulation" << endl; + 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); + 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 @@ -452,143 +445,187 @@ static double distanceSphere( const Point3D p1, const Point3D p2 ) { 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(); - cout << "fixing node heights" << endl; - - point_list raw_nodes = c.get_tri_nodes().get_node_list(); - + SG_LOG(SG_GENERAL, SG_ALERT, "fixing node heights"); + for ( i = 0; i < (int)raw_nodes.size(); ++i ) { - //cout << " fixing = " << raw_nodes[i] << " "; - int index = c.get_fixed_elevations().find( raw_nodes[i] ); - if ( index >= 0 ) { - // found an elevation we want to preserve - z = c.get_fixed_elevations().get_node(index).z(); - //cout << " forced = " << z << endl; + // 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 ); - //cout << " interpolated = " << z << endl; + SG_LOG(SG_GENERAL, SG_ALERT, "no Fixed elevation at " << i << ":" << raw_nodes[i] << " z is " << z ); + c.get_nodes()->SetElevation( i, z ); } - raw_nodes[i].setz( z ); } - triele_list tris = c.get_tri_elements(); - TGTriEle t; - Point3D p; - AreaType a; - int n1, n2, n3; + // 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); + } - cout << "flattening lake connected nodes (and smoothing streams)" << endl; + double e1, e2, e3, min; + int n1, n2, n3; - for ( int count = 0; count < 3; ++count ) { - for ( i = 0; i < (int)tris.size(); ++i ) { - double e1, e2, e3, ave, min; + e1 = tri_poly.get_pt( k, 0 ).z(); + n1 = c.get_nodes()->find( tri_poly.get_pt( k, 0 ) ); - t = tris[i]; - n1 = t.get_n1(); - n2 = t.get_n2(); - n3 = t.get_n3(); - a = (AreaType)((int)(t.get_attribute())); + e2 = tri_poly.get_pt( k, 1 ).z(); + n2 = c.get_nodes()->find( tri_poly.get_pt( k, 1 ) ); - // scale elevation of all water nodes based on the average - // of the elevations of the nodes of the triangle of which - // they are a member. This could really suck for certain - // cases, but it is my first stab at something reasonable. - // It might be better to eventually iterate, and allow - // some flexibility in elevations to handle rivers and - // things like that. - if ( is_lake_area( a ) ) { - e1 = raw_nodes[n1].z(); - e2 = raw_nodes[n2].z(); - e3 = raw_nodes[n3].z(); + 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]; } - ave = (e1 + e2 + e3) / 3.0; - - raw_nodes[n1].setz( min ); - raw_nodes[n2].setz( min ); - raw_nodes[n3].setz( min ); - } else if ( is_stream_area( a ) ) { - e1 = raw_nodes[n1].z(); - e2 = raw_nodes[n2].z(); - e3 = raw_nodes[n3].z(); + min = e1; + if ( e2 < min ) { min = e2; } + if ( e3 < min ) { min = e3; } - 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] ); + c.get_nodes()->SetElevation( n1, min ); + c.get_nodes()->SetElevation( n2, min ); + c.get_nodes()->SetElevation( n3, min ); + } + } + } - double max1 = d1 * 0.20 + min; - double max2 = d2 * 0.20 + min; - double max3 = d3 * 0.20 + 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); + } - if ( max1 < e1 ) { raw_nodes[n1].setz( max1 ); } - if ( max2 < e2 ) { raw_nodes[n2].setz( max2 ); } - if ( max3 < e3 ) { raw_nodes[n3].setz( max3 ); } - } else if ( is_road_area( a ) ) { - e1 = raw_nodes[n1].z(); - e2 = raw_nodes[n2].z(); - e3 = raw_nodes[n3].z(); + double e1, e2, e3, min; + int n1, n2, n3; + Point3D p; - 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] ); + e1 = tri_poly.get_pt( k, 0 ).z(); + n1 = c.get_nodes()->find( tri_poly.get_pt( k, 0 ) ); - double max1 = d1 * 0.30 + min; - double max2 = d2 * 0.30 + min; - double max3 = d3 * 0.30 + min; + e2 = tri_poly.get_pt( k, 1 ).z(); + n2 = c.get_nodes()->find( tri_poly.get_pt( k, 1 ) ); - if ( max1 < e1 ) { raw_nodes[n1].setz( max1 ); } - if ( max2 < e2 ) { raw_nodes[n2].setz( max2 ); } - if ( max3 < e3 ) { raw_nodes[n3].setz( max3 ); } - } - } + 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 ); + } + } + } } - - cout << "flattening ocean connected nodes" << endl; - - for ( i = 0; i < (int)tris.size(); ++i ) { - // set all ocean nodes to 0.0 - t = tris[i]; - n1 = t.get_n1(); - n2 = t.get_n2(); - n3 = t.get_n3(); - a = (AreaType)((int)(t.get_attribute())); - - if ( is_ocean_area( a ) ) { - raw_nodes[n1].setz( 0.0 ); - raw_nodes[n2].setz( 0.0 ); - raw_nodes[n3].setz( 0.0 ); - } - - } - - TGTriNodes tmp; - tmp.set_node_list( raw_nodes ); - c.set_tri_nodes( tmp ); } +#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. static void fix_land_cover_assignments( TGConstruct& c ) { - cout << "Fixing up default land cover types" << endl; + SG_LOG(SG_GENERAL, SG_ALERT, "Fixing up default land cover types"); // the list of node locations TGTriNodes trinodes = c.get_tri_nodes(); point_list geod_nodes = trinodes.get_node_list(); @@ -597,8 +634,8 @@ static void fix_land_cover_assignments( TGConstruct& c ) { triele_list tri_elements = c.get_tri_elements(); // traverse the triangle element groups - cout << " Total Nodes = " << geod_nodes.size() << endl; - cout << " Total triangles = " << tri_elements.size() << endl; + SG_LOG(SG_GENERAL, SG_ALERT, " Total Nodes = " << geod_nodes.size()); + SG_LOG(SG_GENERAL, SG_ALERT, " Total triangles = " << tri_elements.size()); for ( unsigned int i = 0; i < tri_elements.size(); ++i ) { TGTriEle t = tri_elements[i]; if ( t.get_attribute() == get_default_area_type() ) { @@ -647,38 +684,39 @@ 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; - cout << "generating wgs84 list" << endl; + 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]; + geod = raw_nodes[i]; - // convert to radians - radians = Point3D( geod.x() * SGD_DEGREES_TO_RADIANS, - geod.y() * SGD_DEGREES_TO_RADIANS, - geod.z() ); + // convert to radians + radians = Point3D( geod.x() * SGD_DEGREES_TO_RADIANS, + geod.y() * SGD_DEGREES_TO_RADIANS, + geod.z() ); cart = sgGeodToCart(radians); - // cout << cart << endl; - geod_nodes.push_back(geod); + geod_nodes.push_back(geod); wgs84_nodes.push_back(cart); } c.set_geod_nodes( geod_nodes ); c.set_wgs84_nodes( wgs84_nodes ); } - +#endif // build the node -> element (triangle) reverse lookup table. there // is an entry for each point containing a list of all the triangles @@ -693,24 +731,38 @@ static belongs_to_list gen_node_ele_lookup_table( TGConstruct& c ) { // initialize reverse_ele_lookup structure by creating an empty // list for each point point_list wgs84_nodes = c.get_wgs84_nodes(); + + SG_LOG(SG_GENERAL, SG_ALERT, "there are " << wgs84_nodes.size() << " wgs84 nodes" ); + const_point_list_iterator w_current = wgs84_nodes.begin(); const_point_list_iterator w_last = wgs84_nodes.end(); for ( ; w_current != w_last; ++w_current ) { - reverse_ele_lookup.push_back( ele_list ); + reverse_ele_lookup.push_back( ele_list ); } + SG_LOG(SG_GENERAL, SG_ALERT, "1 " ); + // traverse triangle structure building reverse lookup table triele_list tri_elements = c.get_tri_elements(); const_triele_list_iterator current = tri_elements.begin(); const_triele_list_iterator last = tri_elements.end(); int counter = 0; + + SG_LOG(SG_GENERAL, SG_ALERT, "2 " ); + for ( ; current != last; ++current ) { - reverse_ele_lookup[ current->get_n1() ].push_back( counter ); - reverse_ele_lookup[ current->get_n2() ].push_back( counter ); - reverse_ele_lookup[ current->get_n3() ].push_back( counter ); - ++counter; + + //SG_LOG(SG_GENERAL, SG_ALERT, "CURRENT " << current ); +// SG_LOG(SG_GENERAL, SG_ALERT, "N1: " << current->get_n1() << " N2: " << current->get_n2() << " N3: " << current->get_n3() ); + + reverse_ele_lookup[ current->get_n1() ].push_back( counter ); + reverse_ele_lookup[ current->get_n2() ].push_back( counter ); + reverse_ele_lookup[ current->get_n3() ].push_back( counter ); + ++counter; } + SG_LOG(SG_GENERAL, SG_ALERT, "3 " ); + return reverse_ele_lookup; } @@ -750,28 +802,25 @@ static Point3D calc_normal( TGConstruct& c, int i ) { double area = tri_ele_area( c, tri_elements[i] ); // cout << " area = " << area << endl; if ( area < area_eps ) { - degenerate = true; + degenerate = true; } // cout << " " << p1 << endl; // cout << " " << p2 << endl; // cout << " " << p3 << endl; - if ( fabs(p1.x() - p2.x()) < SG_EPSILON && - fabs(p1.x() - p3.x()) < SG_EPSILON ) { - degenerate = true; + if ( fabs(p1.x() - p2.x()) < SG_EPSILON && fabs(p1.x() - p3.x()) < SG_EPSILON ) { + degenerate = true; } - if ( fabs(p1.y() - p2.y()) < SG_EPSILON && - fabs(p1.y() - p3.y()) < SG_EPSILON ) { - degenerate = true; + if ( fabs(p1.y() - p2.y()) < SG_EPSILON && fabs(p1.y() - p3.y()) < SG_EPSILON ) { + degenerate = true; } - if ( fabs(p1.z() - p2.z()) < SG_EPSILON && - fabs(p1.z() - p3.z()) < SG_EPSILON ) { - degenerate = true; + if ( fabs(p1.z() - p2.z()) < SG_EPSILON && fabs(p1.z() - p3.z()) < SG_EPSILON ) { + degenerate = true; } if ( degenerate ) { normal = normalize(SGVec3d(p1.x(), p1.y(), p1.z())); - cout << "Degenerate tri!" << endl; + SG_LOG(SG_GENERAL, SG_ALERT, "Degenerate tri!"); } else { v1[0] = p2.x() - p1.x(); v1[1] = p2.y() - p1.y(); @@ -791,14 +840,13 @@ static point_list gen_face_normals( TGConstruct& c ) { point_list face_normals; // traverse triangle structure building the face normal table - - cout << "calculating face normals" << endl; + SG_LOG(SG_GENERAL, SG_ALERT, "calculating face normals"); triele_list tri_elements = c.get_tri_elements(); for ( int i = 0; i < (int)tri_elements.size(); i++ ) { - Point3D p = calc_normal(c, i ); - //cout << p << endl; - face_normals.push_back( p ); + Point3D p = calc_normal(c, i ); + //cout << p << endl; + face_normals.push_back( p ); } return face_normals; @@ -810,7 +858,7 @@ static point_list gen_point_normals( TGConstruct& c ) { point_list point_normals; Point3D normal; - cout << "calculating node normals" << endl; + SG_LOG(SG_GENERAL, SG_ALERT, "calculating node normals"); point_list wgs84_nodes = c.get_wgs84_nodes(); belongs_to_list reverse_ele_lookup = c.get_reverse_ele_lookup(); @@ -819,42 +867,40 @@ static point_list gen_point_normals( TGConstruct& c ) { // for each node for ( int i = 0; i < (int)wgs84_nodes.size(); ++i ) { - int_list tri_list = reverse_ele_lookup[i]; - double total_area = 0.0; + int_list tri_list = reverse_ele_lookup[i]; + double total_area = 0.0; - Point3D average( 0.0 ); + Point3D average( 0.0 ); - // for each triangle that shares this node - for ( int j = 0; j < (int)tri_list.size(); ++j ) { - normal = face_normals[ tri_list[j] ]; - double area = tri_ele_area( c, tri_elements[ tri_list[j] ] ); - normal *= area; // scale normal weight relative to area - total_area += area; - average += normal; - // cout << normal << endl; - } + // for each triangle that shares this node + for ( int j = 0; j < (int)tri_list.size(); ++j ) { + normal = face_normals[ tri_list[j] ]; + double area = tri_ele_area( c, tri_elements[ tri_list[j] ] ); + normal *= area; // scale normal weight relative to area + total_area += area; + average += normal; + // cout << normal << endl; + } - average /= total_area; - //cout << "average = " << average << endl; + average /= total_area; + //cout << "average = " << average << endl; - point_normals.push_back( average ); + point_normals.push_back( average ); } - cout << "1st" << endl; - cout << "wgs84 node list size = " << wgs84_nodes.size() << endl; - cout << "normal list size = " << point_normals.size() << endl; + SG_LOG(SG_GENERAL, SG_ALERT, "1st"); + SG_LOG(SG_GENERAL, SG_ALERT, "wgs84 node list size = " << wgs84_nodes.size()); + SG_LOG(SG_GENERAL, SG_ALERT, "normal list size = " << point_normals.size()); return point_normals; } - // generate the flight gear scenery file static void do_output( TGConstruct& c, TGGenOutput& output ) { - output.build( c ); - output.write( c ); + 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(); @@ -870,7 +916,7 @@ static void do_custom_objects( const TGConstruct& c ) { FILE *fp; if ( (fp = fopen( dest_ind.c_str(), "w" )) == NULL ) { - cout << "ERROR: opening " << dest_ind << " for writing!" << endl; + SG_LOG(SG_GENERAL, SG_ALERT, "ERROR: opening " << dest_ind << " for writing!"); exit(-1); } @@ -889,23 +935,23 @@ static void do_custom_objects( const TGConstruct& c ) { index.append( b.gen_index_str() ); index.concat(".ind"); string index_file = index.str_native(); - //cout << "collecting custom objects from " << index_file << endl; + //SG_LOG(SG_GENERAL, SG_ALERT, "collecting custom objects from " << index_file); sg_gzifstream in( index_file ); - if ( ! in.is_open() ) { - //cout << "No custom objects" << endl; - } else { - while ( ! in.eof() ) { - cout << "Collecting custom objects from " << index_file << endl; + 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); - cout << "line = " << line << endl; + SG_LOG(SG_GENERAL, SG_ALERT, "line = " << line); int result = sscanf( line, "%s %s", token, name ); - cout << "scanf scanned " << result << " tokens" << endl; + SG_LOG(SG_GENERAL, SG_ALERT, "scanf scanned " << result << " tokens" ); if ( result > 0 ) { - cout << "token = " << token << " name = " << name << endl; + SG_LOG(SG_GENERAL, SG_ALERT, "token = " << token << " name = " << name ); if ( strcmp( token, "OBJECT" ) == 0 ) { SGPath srcbase(base); @@ -932,43 +978,292 @@ static void do_custom_objects( const TGConstruct& c ) { 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 ) +{ + 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; +} + +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 ) { - cout << "Construct tile, bucket = " << c.get_bucket() << endl; + 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; + // 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; } - TGTriangle t; + // 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()); - cout << "number of fitted nodes = " << t.get_out_nodes_size() << endl; - + // 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 ) ); @@ -996,17 +1291,16 @@ static void construct_tile( TGConstruct& c ) { // 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() ) { - cout << "oops, need to add normals :-(" << endl; - 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 ) { - cout << "adding a normal for " << c.get_tri_nodes().get_node(i) - << endl; - Point3D p = tgFakeNormal( c.get_tri_nodes().get_node(i) ); - normals.push_back( p ); - } - c.set_point_normals( normals ); + 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 ) { @@ -1019,40 +1313,434 @@ static void construct_tile( TGConstruct& 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 ); + + 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 ); + } + c.set_point_normals( normals ); + } +#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 ); + } + } + } + } + + std::vector< SGVec3d > 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 ]); + } + + 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 = c.get_output_base(); + SGBucket b = c.get_bucket(); + string binname = b.gen_index_str(); + binname += ".btg"; + string txtname = b.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, 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 static void usage( const string name ) { - cout << "Usage: " << name << endl; - cout << "[ --output-dir=" << endl; - cout << " --work-dir=" << endl; - cout << " --cover=" << endl; - cout << " --tile-id=" << endl; - cout << " --lon=" << endl; - cout << " --lat=" << endl; - cout << " --xdist=" << endl; - cout << " --ydist=" << endl; - cout << " --nudge=" << endl; - cout << " --priorities=" << endl; - cout << " --usgs-map=" << endl; - cout << " --useUKgrid" << endl; - cout << " --no-write-shared-edges" << endl; - cout << " --use-own-shared-edges" << endl; - cout << " --ignore-landmass" << endl; - cout << " ] " << endl; + SG_LOG(SG_GENERAL, SG_ALERT, "Usage: " << name); + SG_LOG(SG_GENERAL, SG_ALERT, "[ --output-dir="); + SG_LOG(SG_GENERAL, SG_ALERT, " --work-dir="); + SG_LOG(SG_GENERAL, SG_ALERT, " --cover="); + SG_LOG(SG_GENERAL, SG_ALERT, " --tile-id="); + SG_LOG(SG_GENERAL, SG_ALERT, " --lon="); + SG_LOG(SG_GENERAL, SG_ALERT, " --lat="); + SG_LOG(SG_GENERAL, SG_ALERT, " --xdist="); + SG_LOG(SG_GENERAL, SG_ALERT, " --ydist="); + SG_LOG(SG_GENERAL, SG_ALERT, " --nudge="); + SG_LOG(SG_GENERAL, SG_ALERT, " --priorities="); + SG_LOG(SG_GENERAL, SG_ALERT, " --usgs-map="); + SG_LOG(SG_GENERAL, SG_ALERT, " --useUKgrid"); + SG_LOG(SG_GENERAL, SG_ALERT, " --no-write-shared-edges"); + SG_LOG(SG_GENERAL, SG_ALERT, " --use-own-shared-edges"); + SG_LOG(SG_GENERAL, SG_ALERT, " --ignore-landmass"); + SG_LOG(SG_GENERAL, SG_ALERT, " ] "); exit(-1); } - int main(int argc, char **argv) { string output_dir = "."; string work_dir = "."; @@ -1086,71 +1774,72 @@ int main(int argc, char **argv) { // int arg_pos; for (arg_pos = 1; arg_pos < argc; arg_pos++) { - string arg = argv[arg_pos]; + string arg = argv[arg_pos]; - if (arg.find("--output-dir=") == 0) { - output_dir = arg.substr(13); - } else if (arg.find("--work-dir=") == 0) { - work_dir = arg.substr(11); - } else if (arg.find("--tile-id=") == 0) { - tile_id = atol(arg.substr(10).c_str()); - } else if (arg.find("--lon=") == 0) { - lon = atof(arg.substr(6).c_str()); - } else if (arg.find("--lat=") == 0) { - lat = atof(arg.substr(6).c_str()); - } else if (arg.find("--xdist=") == 0) { - xdist = atof(arg.substr(8).c_str()); - } else if (arg.find("--ydist=") == 0) { - ydist = atof(arg.substr(8).c_str()); - } else if (arg.find("--nudge=") == 0) { - nudge = atof(arg.substr(8).c_str())*SG_EPSILON; - } else if (arg.find("--cover=") == 0) { - cover = arg.substr(8); - } else if (arg.find("--priorities=") == 0) { - priorities_file = arg.substr(13); - } else if (arg.find("--usgs-map=") == 0) { - usgs_map_file = arg.substr(11); - } else if (arg.find("--useUKgrid") == 0) { + if (arg.find("--output-dir=") == 0) { + output_dir = arg.substr(13); + } else if (arg.find("--work-dir=") == 0) { + work_dir = arg.substr(11); + } else if (arg.find("--tile-id=") == 0) { + tile_id = atol(arg.substr(10).c_str()); + } else if (arg.find("--lon=") == 0) { + lon = atof(arg.substr(6).c_str()); + } else if (arg.find("--lat=") == 0) { + lat = atof(arg.substr(6).c_str()); + } else if (arg.find("--xdist=") == 0) { + xdist = atof(arg.substr(8).c_str()); + } else if (arg.find("--ydist=") == 0) { + ydist = atof(arg.substr(8).c_str()); + } else if (arg.find("--nudge=") == 0) { + nudge = atof(arg.substr(8).c_str())*SG_EPSILON; + } else if (arg.find("--cover=") == 0) { + cover = arg.substr(8); + } else if (arg.find("--priorities=") == 0) { + priorities_file = arg.substr(13); + } else if (arg.find("--usgs-map=") == 0) { + usgs_map_file = arg.substr(11); + } else if (arg.find("--useUKgrid") == 0) { useUKgrid = true; - } else if (arg.find("--no-write-shared-edges") == 0) { - writeSharedEdges = false; - } else if (arg.find("--use-own-shared-edges") == 0) { - useOwnSharedEdges = true; - } else if (arg.find("--ignore-landmass") == 0) { - ignoreLandmass = true; - } else if (arg.find("--") == 0) { - usage(argv[0]); - } else { - break; - } + } else if (arg.find("--no-write-shared-edges") == 0) { + writeSharedEdges = false; + } else if (arg.find("--use-own-shared-edges") == 0) { + useOwnSharedEdges = true; + } else if (arg.find("--ignore-landmass") == 0) { + ignoreLandmass = true; + } else if (arg.find("--") == 0) { + usage(argv[0]); + } else { + break; + } } - cout << "Output directory is " << output_dir << endl; - cout << "Working directory is " << work_dir << endl; + SG_LOG(SG_GENERAL, SG_ALERT, "Output directory is " << output_dir); + SG_LOG(SG_GENERAL, SG_ALERT, "Working directory is " << work_dir); if ( tile_id > 0 ) { - cout << "Tile id is " << tile_id << endl; + SG_LOG(SG_GENERAL, SG_ALERT, "Tile id is " << tile_id); } else { - cout << "Center longitude is " << lon << endl; - cout << "Center latitude is " << lat << endl; - cout << "X distance is " << xdist << endl; - cout << "Y distance is " << ydist << endl; + SG_LOG(SG_GENERAL, SG_ALERT, "Center longitude is " << lon); + SG_LOG(SG_GENERAL, SG_ALERT, "Center latitude is " << lat); + SG_LOG(SG_GENERAL, SG_ALERT, "X distance is " << xdist); + SG_LOG(SG_GENERAL, SG_ALERT, "Y distance is " << ydist); } - cout << "Nudge is " << nudge << endl; + SG_LOG(SG_GENERAL, SG_ALERT, "Nudge is " << nudge); for (int i = arg_pos; i < argc; i++) { - load_dirs.push_back(argv[i]); - cout << "Load directory: " << argv[i] << endl; + load_dirs.push_back(argv[i]); + SG_LOG(SG_GENERAL, SG_ALERT, "Load directory: " << argv[i]); } - cout << "Priorities file is " << priorities_file << endl; + SG_LOG(SG_GENERAL, SG_ALERT, "Priorities file is " << priorities_file); if ( ! load_area_types( priorities_file ) ) { - SG_LOG(SG_GENERAL, SG_ALERT, "Failed to load priorities file " << priorities_file); - exit(-1); + SG_LOG(SG_GENERAL, SG_ALERT, "Failed to load priorities file " << priorities_file); + exit(-1); } - cout << "USGS Map file is " << usgs_map_file << endl; + SG_LOG(SG_GENERAL, SG_ALERT, "USGS Map file is " << usgs_map_file); if ( ! load_usgs_map( usgs_map_file ) ) { - SG_LOG(SG_GENERAL, SG_ALERT, "Failed to load USGS map file " << usgs_map_file); + SG_LOG(SG_GENERAL, SG_ALERT, "Failed to load USGS map file " << usgs_map_file); exit(-1); } + #if defined( __CYGWIN__ ) || defined( __CYGWIN32__ ) || defined( _MSC_VER ) // the next bit crashes Cygwin for me - DCL // MSVC does not have the function or variable type defined - BRF @@ -1182,7 +1871,7 @@ int main(int argc, char **argv) { SG_LOG(SG_GENERAL, SG_ALERT, "Error setting RLIMIT_CPU, aborting"); exit(-1); } else { - cout << "Setting RLIMIT_CPU to " << limit.rlim_cur << " seconds" << endl; + SG_LOG(SG_GENERAL, SG_ALERT, "Setting RLIMIT_CPU to " << limit.rlim_cur << " seconds"); }; #endif // end of stuff that crashes Cygwin @@ -1202,64 +1891,60 @@ int main(int argc, char **argv) { c.set_max_nodes( (int)(TG_MAX_NODES * 0.8) ); if (tile_id == -1) { - if (xdist == -1 || ydist == -1) { - // construct the tile around the specified location - cout << "Building single tile at " << lat << ',' << lon << endl; - SGBucket b( lon, lat ); - c.set_bucket( b ); - construct_tile( c ); - } else { - // build all the tiles in an area + 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 ); + } 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); + double min_x = lon - xdist; + double min_y = lat - ydist; + SGBucket b_min( min_x, min_y ); + SGBucket b_max( lon + xdist, lat + ydist ); - cout << "Building tile(s) at " << lat << ',' << lon - << " with x distance " << xdist - << " and y distance " << ydist << endl; - double min_x = lon - xdist; - double min_y = lat - ydist; - SGBucket b_min( min_x, min_y ); - SGBucket b_max( lon + xdist, lat + ydist ); + SGBucket b_start(550401L); + bool do_tile = true; - SGBucket b_start(550401L); - bool do_tile = true; + if ( b_min == b_max ) { + c.set_bucket( b_min ); + construct_tile( c ); + } else { + SGBucket b_cur; + int dx, dy, i, j; - if ( b_min == b_max ) { - c.set_bucket( b_min ); - construct_tile( c ); - } else { - SGBucket b_cur; - int dx, dy, i, j; - - sgBucketDiff(b_min, b_max, &dx, &dy); - cout << " construction area spans tile boundaries" << endl; - cout << " dx = " << dx << " dy = " << dy << endl; + sgBucketDiff(b_min, b_max, &dx, &dy); + SG_LOG(SG_GENERAL, SG_ALERT, " construction area spans tile boundaries"); + SG_LOG(SG_GENERAL, SG_ALERT, " dx = " << dx << " dy = " << dy); - for ( j = 0; j <= dy; j++ ) { - for ( i = 0; i <= dx; i++ ) { - b_cur = sgBucketOffset(min_x, min_y, i, j); + for ( j = 0; j <= dy; j++ ) { + for ( i = 0; i <= dx; i++ ) { + b_cur = sgBucketOffset(min_x, min_y, i, j); - if ( b_cur == b_start ) { - do_tile = true; - } + if ( b_cur == b_start ) { + do_tile = true; + } - if ( do_tile ) { - c.set_bucket( b_cur ); - construct_tile( c ); - } else { - cout << "skipping " << b_cur << endl; - } - } - } - // string answer; cin >> answer; - } - } + if ( do_tile ) { + c.set_bucket( b_cur ); + construct_tile( c ); + } else { + SG_LOG(SG_GENERAL, SG_ALERT, "skipping " << b_cur); + } + } + } + } + } } else { - // construct the specified tile - cout << "Building tile " << tile_id << endl; - SGBucket b( tile_id ); - c.set_bucket( b ); - construct_tile( c ); + // 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 ); } - cout << "[Finished successfully]" << endl; + SG_LOG(SG_GENERAL, SG_ALERT, "[Finished successfully]"); return 0; } diff --git a/src/BuildTiles/Match/match.cxx b/src/BuildTiles/Match/match.cxx index f1344d9c..65220b12 100644 --- a/src/BuildTiles/Match/match.cxx +++ b/src/BuildTiles/Match/match.cxx @@ -27,9 +27,11 @@ #include #include +#include #include #include #include +#include #include "match.hxx" @@ -369,6 +371,9 @@ void TGMatch::split_tile( TGConstruct& c ) { 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() ); + for ( i = 0; i < (int)nodes.size(); ++i ) { Point3D node = nodes[i]; Point3D normal = point_normals[i]; @@ -423,6 +428,7 @@ void TGMatch::split_tile( TGConstruct& c ) { } } +#if 0 // UNUSED // separate area edge segment into components cout << " extracting (shared) area edge segments" << endl; @@ -494,6 +500,10 @@ void TGMatch::split_tile( TGConstruct& c ) { cout << " " << body_nodes[i] << endl; } */ +#endif + + SG_LOG(SG_GENERAL, SG_ALERT, "SPLIT TILE COMPLETE " ); + } @@ -677,6 +687,55 @@ void insert_normal( point_list& normals, Point3D n, int i ) { normals[i] = n; } +// Just add nodes and normals to the node list +void TGMatch::add_shared_nodes( TGConstruct& c ) { + TGNodes* nodes; + nodes = c.get_nodes(); + + cout << " BEFORE ADDING SHARED NODES: " << nodes->size() << endl; + + if ( sw_flag ) { + nodes->unique_add_fixed_elevation( sw_node ); + } + + if ( se_flag ) { + nodes->unique_add_fixed_elevation( se_node ); + } + + if ( nw_flag ) { + nodes->unique_add_fixed_elevation( nw_node ); + } + + if ( ne_flag ) { + nodes->unique_add_fixed_elevation( ne_node ); + } + + if ( north_flag ) { + for (unsigned int i = 0; i < north_nodes.size(); i++) { + nodes->unique_add_fixed_elevation( north_nodes[i] ); + } + } + + if ( south_flag ) { + for (unsigned int i = 0; i < south_nodes.size(); i++) { + nodes->unique_add_fixed_elevation( south_nodes[i] ); + } + } + + if ( east_flag ) { + for (unsigned int i = 0; i < east_nodes.size(); i++) { + nodes->unique_add_fixed_elevation( east_nodes[i] ); + } + } + + if ( west_flag ) { + for (unsigned int i = 0; i < west_nodes.size(); i++) { + nodes->unique_add_fixed_elevation( west_nodes[i] ); + } + } + + cout << " AFTER ADDING SHARED NODES: " << nodes->size() << endl; +} // reassemble the tile pieces (combining the shared data and our own // data) @@ -805,6 +864,7 @@ void TGMatch::assemble_tile( TGConstruct& c ) { TGTriSeg(n1, n2, marker) ); } +#if 0 // UNUSED c.set_tri_nodes( new_nodes ); c.set_point_normals( new_normals ); c.set_tri_segs( new_segs ); @@ -812,5 +872,6 @@ void TGMatch::assemble_tile( TGConstruct& c ) { cout << "after adding all segments (should be the same):" << endl; cout << " new_nodes = " << new_nodes.size() << endl; cout << " new normals = " << new_normals.size() << endl; +#endif } diff --git a/src/BuildTiles/Match/match.hxx b/src/BuildTiles/Match/match.hxx index 3bd9c68c..d8c9013d 100644 --- a/src/BuildTiles/Match/match.hxx +++ b/src/BuildTiles/Match/match.hxx @@ -95,6 +95,10 @@ public: // try to find info for the specified shared component void load_shared( const TGConstruct& c, neighbor_type n ); + // NEW TILE MATCHING - PRE TRIANGULATION + // Just add nodes and normals to the node list + 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 diff --git a/src/BuildTiles/Triangulate/triangle.cxx b/src/BuildTiles/Triangulate/triangle.cxx index 1cf30163..a4be9654 100644 --- a/src/BuildTiles/Triangulate/triangle.cxx +++ b/src/BuildTiles/Triangulate/triangle.cxx @@ -24,6 +24,7 @@ #include #include +#include #include #include "triangle.hxx" @@ -75,8 +76,9 @@ TGTriangle::build( const point_list& corner_list, } // next process the polygons + TGSuperPoly sp; TGPolygon gpc_poly; - const_poly_list_iterator current, last; + const_superpoly_list_iterator current, last; // process polygons in priority order cout << "prepairing node list and polygons" << endl; @@ -84,16 +86,15 @@ TGTriangle::build( const point_list& corner_list, for ( i = 0; i < TG_MAX_AREA_TYPES; ++i ) { polylist[i].clear(); - cout << "area type = " << i << " polys = " << gpc_polys.polys[i].size() - << endl; + cout << "area type = " << i << " polys = " << gpc_polys.superpolys[i].size() << endl; debug_counter = 0; - current = gpc_polys.polys[i].begin(); - last = gpc_polys.polys[i].end(); + current = gpc_polys.superpolys[i].begin(); + last = gpc_polys.superpolys[i].end(); for ( ; current != last; ++current ) { - gpc_poly = *current; + sp = *current; + gpc_poly = sp.get_poly(); - cout << "processing a polygon, contours = " - << gpc_poly.contours() << endl; + // cout << "processing a polygon, contours = " << gpc_poly.contours() << endl; if (gpc_poly.contours() <= 0 ) { cout << "FATAL ERROR! no contours in this polygon" << endl; @@ -102,9 +103,7 @@ TGTriangle::build( const point_list& corner_list, 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; + // cout << " processing contour = " << j << ", nodes = " << gpc_poly.contour_size( j ) << ", hole = " << gpc_poly.get_hole_flag( j ) << endl; /* char junkn[256]; @@ -149,8 +148,7 @@ TGTriangle::build( const point_list& corner_list, gpc_poly = remove_bad_contours( gpc_poly ); gpc_poly = remove_cycles( gpc_poly ); - cout << "after sanity checks, contours = " - << gpc_poly.contours() << endl; + // cout << "after sanity checks, contours = " << gpc_poly.contours() << endl; /* for ( j = 0; j < gpc_poly.contours(); ++j ) { @@ -162,9 +160,9 @@ TGTriangle::build( const point_list& corner_list, } */ - cout << "before calc_points_inside()" << endl; + // cout << "before calc_points_inside()" << endl; calc_points_inside( gpc_poly ); - cout << "after calc_points_inside()" << endl; + // cout << "after calc_points_inside()" << endl; #if 0 // old way @@ -240,8 +238,7 @@ TGTriangle::build( const point_list& corner_list, // process each polygon in list for ( ; tp_current != tp_last; ++tp_current ) { poly = *tp_current; - cout << " processing a polygon with contours = " - << poly.contours() << endl; + // 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 ); @@ -280,15 +277,16 @@ TGTriangle::build( const point_list& corner_list, 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; } @@ -307,8 +305,12 @@ int TGTriangle::run_triangulate( double angle, const int pass ) { 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)); @@ -465,6 +467,7 @@ int TGTriangle::run_triangulate( double angle, const int pass ) { // 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 { @@ -474,6 +477,13 @@ int TGTriangle::run_triangulate( double angle, const int pass ) { 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 ) { @@ -494,6 +504,8 @@ int TGTriangle::run_triangulate( double angle, const int pass ) { // now copy the results back into the corresponding TGTriangle // structures + + cout << "TRIANGULATE : NUMBER OF OUTPUT NODES: " << out.numberofpoints << endl; // nodes out_nodes.clear(); diff --git a/src/Lib/Geometry/CMakeLists.txt b/src/Lib/Geometry/CMakeLists.txt index 05fbbdd5..e44ccb30 100644 --- a/src/Lib/Geometry/CMakeLists.txt +++ b/src/Lib/Geometry/CMakeLists.txt @@ -8,6 +8,7 @@ add_library(Geometry STATIC poly_support.cxx poly_extra.cxx rectangle.cxx + tg_nodes.cxx trinodes.cxx trisegs.cxx util.cxx @@ -17,6 +18,7 @@ add_library(Geometry STATIC poly_support.hxx poly_extra.hxx rectangle.hxx + tg_nodes.hxx trinodes.hxx trisegs.hxx util.hxx diff --git a/src/Lib/Geometry/poly_extra.cxx b/src/Lib/Geometry/poly_extra.cxx index 4dc81682..f1043c5b 100644 --- a/src/Lib/Geometry/poly_extra.cxx +++ b/src/Lib/Geometry/poly_extra.cxx @@ -114,4 +114,67 @@ TGPolygon add_nodes_to_poly( const TGPolygon& poly, return result; } +// Divide segment if there are other existing points on it, return the +// new polygon +void add_intermediate_tgnodes( int contour, const Point3D& start, + const Point3D& end, const TGNodes* nodes, + TGPolygon *result ) +{ + point_list points = nodes->get_geod_nodes(); + + SG_LOG(SG_GENERAL, SG_DEBUG, " add_intermediate_nodes()"); + char buf[200]; + snprintf(buf, 199, " %.7f %.7f %.7f <=> %.7f %.7f %.7f\n", + start.x(), start.y(), start.z(), end.x(), end.y(), end.z() ); + SG_LOG(SG_GENERAL, SG_DEBUG, buf); + + Point3D new_pt; + bool found_extra = find_intermediate_node( start, end, points, &new_pt ); + + if ( found_extra ) { + SG_LOG(SG_GENERAL, SG_DEBUG, "dividing " << start << " " << new_pt << " " << end); + add_intermediate_tgnodes( contour, start, new_pt, nodes, result ); + + result->add_node( contour, new_pt ); + SG_LOG(SG_GENERAL, SG_INFO, " added = " << new_pt); + + add_intermediate_tgnodes( contour, new_pt, end, nodes, result ); + } +} + +TGPolygon add_tgnodes_to_poly( const TGPolygon& poly, + const TGNodes* nodes ) { + TGPolygon result; result.erase(); + Point3D p0, p1; + + SG_LOG(SG_GENERAL, SG_DEBUG, "add_nodes_to_poly"); + for ( int i = 0; i < poly.contours(); ++i ) { + SG_LOG(SG_GENERAL, SG_DEBUG, "contour = " << i); + for ( int j = 0; j < poly.contour_size(i) - 1; ++j ) { + p0 = poly.get_pt( i, j ); + p1 = poly.get_pt( i, j + 1 ); + + // add start of segment + result.add_node( i, p0 ); + + // add intermediate points + add_intermediate_tgnodes( i, p0, p1, nodes, &result ); + + // end of segment is beginning of next segment + } + p0 = poly.get_pt( i, poly.contour_size(i) - 1 ); + p1 = poly.get_pt( i, 0 ); + + // add start of segment + result.add_node( i, p0 ); + + // add intermediate points + add_intermediate_tgnodes( i, p0, p1, nodes, &result ); + + // maintain original hole flag setting + result.set_hole_flag( i, poly.get_hole_flag( i ) ); + } + + return result; +} diff --git a/src/Lib/Geometry/poly_extra.hxx b/src/Lib/Geometry/poly_extra.hxx index d7526ed7..78e72a7e 100644 --- a/src/Lib/Geometry/poly_extra.hxx +++ b/src/Lib/Geometry/poly_extra.hxx @@ -29,6 +29,8 @@ #include #include +#include + #include @@ -46,5 +48,8 @@ void add_intermediate_nodes( int contour, const Point3D& start, TGPolygon add_nodes_to_poly( const TGPolygon& poly, const TGTriNodes& tmp_nodes ); +TGPolygon add_tgnodes_to_poly( const TGPolygon& poly, + const TGNodes* nodes ); + #endif // _POLY_EXTRA_HXX diff --git a/src/Lib/Geometry/tg_nodes.cxx b/src/Lib/Geometry/tg_nodes.cxx new file mode 100644 index 00000000..92c1c74e --- /dev/null +++ b/src/Lib/Geometry/tg_nodes.cxx @@ -0,0 +1,185 @@ +#include + +#include "tg_nodes.hxx" + +// Find the index of the specified point (compair to the same +// tolerance as unique_add(). Returns -1 if not found. +int TGNodes::find( const Point3D& p ) const { + const_node_list_iterator current, last; + Point3D pos; + int counter = 0; + + // see if point already exists + current = tg_node_list.begin(); + last = tg_node_list.end(); + for ( ; current != last; ++current ) { + pos = current->GetPosition(); + if ( close_enough_2d(p, pos ) ) { + return counter; + } + + ++counter; + } + + return -1; +} + +int TGNodes::unique_add( const Point3D& p ) { + node_list_iterator current, last; + int counter = 0; + + // see if point already exists + current = tg_node_list.begin(); + last = tg_node_list.end(); + + for ( ; current != last; ++current ) { + if ( close_enough_3d(p, (*current).GetPosition() ) ) { + // cout << "found an existing match!" << endl; + return counter; + } + + ++counter; + } + + TGNode node( p ); + node.SetFixedPosition( false ); + + // add to list + tg_node_list.push_back( node ); + + return counter; +} + +int TGNodes::unique_add_fixed_elevation( const Point3D& p ) { + node_list_iterator current, last; + int counter = 0; + + // see if point already exists + current = tg_node_list.begin(); + last = tg_node_list.end(); + + for ( ; current != last; ++current ) { + if ( close_enough_3d(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 + (*current).SetPosition( p ); + (*current).SetFixedPosition( true ); + + return counter; + } + + ++counter; + } + + TGNode node( p ); + node.SetFixedPosition( true ); + + // add to list + tg_node_list.push_back( node ); + + return counter; +} + +point_list TGNodes::get_geod_nodes( void ) const { + point_list points; + const_node_list_iterator current, last; + + // see if point already exists + current = tg_node_list.begin(); + last = tg_node_list.end(); + + for ( ; current != last; ++current ) { + points.push_back( (*current).GetPosition() ); + } + + return points; +} + +std::vector< SGVec3d > TGNodes::get_wgs84_nodes_as_SGVec3d( void ) const { + std::vector< SGVec3d > points; + Point3D pos; + const_node_list_iterator current, last; + + current = tg_node_list.begin(); + last = tg_node_list.end(); + + for ( ; current != last; ++current ) { + pos = (*current).GetPosition(); + + SGGeod geod = SGGeod::fromDegM( pos.x(), pos.y(), pos.z() ); + SGVec3d cart = SGVec3d::fromGeod(geod); + + points.push_back( cart ); + } + + return points; +} + +point_list TGNodes::get_wgs84_nodes_as_Point3d( void ) const { + point_list points; + Point3D pos; + const_node_list_iterator current, last; + + current = tg_node_list.begin(); + last = tg_node_list.end(); + + for ( ; current != last; ++current ) { + pos = (*current).GetPosition(); + + SGGeod geod = SGGeod::fromDegM( pos.x(), pos.y(), pos.z() ); + SGVec3d cart = SGVec3d::fromGeod(geod); + + points.push_back( Point3D::fromSGVec3( cart ) ); + } + + return points; +} + +node_list TGNodes::get_fixed_elevation_nodes( void ) const { + node_list fixed_elev; + const_node_list_iterator current, last; + + // see if point already exists + current = tg_node_list.begin(); + last = tg_node_list.end(); + + for ( ; current != last; ++current ) { + if ( (*current).GetFixedPosition() ) { + fixed_elev.push_back( (*current) ); + } + } + + return fixed_elev; +} + +point_list TGNodes::get_normals( void ) const { + point_list points; + const_node_list_iterator current, last; + + // see if point already exists + current = tg_node_list.begin(); + last = tg_node_list.end(); + + for ( ; current != last; ++current ) { + points.push_back( (*current).GetNormal() ); + } + + return points; +} + +bool TGNodes::LookupFixedElevation( Point3D p, double* z ) +{ + int index = find( p ); + bool found = false; + + if (index >= 0) { + TGNode node = tg_node_list[index]; + if ( node.GetFixedPosition() ) { + *z = tg_node_list[index].GetPosition().z(); + found = true; + } + } + + return found; +} diff --git a/src/Lib/Geometry/tg_nodes.hxx b/src/Lib/Geometry/tg_nodes.hxx new file mode 100644 index 00000000..77d3fb50 --- /dev/null +++ b/src/Lib/Geometry/tg_nodes.hxx @@ -0,0 +1,192 @@ +#ifndef _TG_NODES_HXX +#define _TG_NODES_HXX + + +#ifndef __cplusplus +# error This library requires C++ +#endif + +#include +#include +#include + +#define FG_PROXIMITY_EPSILON 0.000001 +#define FG_COURSE_EPSILON 0.0001 + +typedef std::vector < unsigned int > TGIdxList; + +class TGNode { +public: + TGNode( Point3D p ) { + position = p; + normal = Point3D(); + + + fixed_position = false; // no matter what - don't move x, y, or z (likely a hole around an airport generated ny genapts) + fixed_normal = false; // no matter what - don't modify the normal - likely on a normal generated on a shared edge + + faces.clear(); + neighbors.clear(); + } + + inline void SetFixedPosition( bool fix ) + { + if (!fixed_position) { + fixed_position = fix; + } + } + + inline bool GetFixedPosition( void ) const { return fixed_position; } + inline void SetFixedNormal( bool fix ) { fixed_normal = fix; } + inline bool GetFixedNormal( void ) const { return fixed_normal; } + + inline void SetPosition( const Point3D& p ) + { + if (!fixed_position) { + position = p; + } + } + + inline void SetElevation( double z ) + { + if (!fixed_position) { + position.setelev( z ); + } + } + + inline Point3D GetPosition( void ) const { return position; } + inline void SetNormal( const Point3D& n ) { normal = n; } + inline Point3D GetNormal( void ) const { return normal; } + +private: + Point3D position; + Point3D normal; + + bool fixed_position; + bool fixed_normal; + + TGIdxList faces; + TGIdxList neighbors; +}; +typedef std::vector < TGNode > node_list; +typedef node_list::iterator node_list_iterator; +typedef node_list::const_iterator const_node_list_iterator; + + +/* This class handles ALL of the nodes in a tile : 3d nodes in elevation data, 2d nodes generated from landclass, etc) */ + +class TGNodes { +public: + + // Constructor and destructor + TGNodes( void ) {} + ~TGNodes( void ) {} + + // delete all the data out of node_list + inline void clear() { tg_node_list.clear(); } + + // Add a point to the point list if it doesn't already exist. + // Returns the index (starting at zero) of the point in the list. + int unique_add( const Point3D& p ); + + // Add a point to the point list if it doesn't already exist + // (checking all three dimensions.) Returns the index (starting + // at zero) of the point in the list. + int unique_add_fixed_elevation( const Point3D& p ); + node_list get_fixed_elevation_nodes( void ) const; + + + // Add the point with no uniqueness checking + int simple_add( const Point3D& p ); + + // Add a point to the point list if it doesn't already exist. + // Returns the index (starting at zero) of the point in the list. + // Use a course proximity check + int course_add( const Point3D& p ); + + // Find the index of the specified point (compair to the same + // tolerance as unique_add(). Returns -1 if not found. + int find( const Point3D& p ) const; + + bool LookupFixedElevation( Point3D p, double* z ); + void SetElevation( int idx, double z ) { tg_node_list[idx].SetElevation( z ); } + + // return the master node list + inline node_list& get_node_list() { return tg_node_list; } + inline const node_list& get_node_list() const { return tg_node_list; } + + // return a point list of geodetic nodes + point_list get_geod_nodes() const; + + // return a point list of wgs84 nodes + std::vector< SGVec3d > get_wgs84_nodes_as_SGVec3d() const; + point_list get_wgs84_nodes_as_Point3d() const; + + // return a point list of normals + point_list get_normals() const; + + // return the ith point + inline TGNode get_node( int i ) const { return tg_node_list[i]; } + + // return the size of the node list + inline size_t size() const { return tg_node_list.size(); } + +private: + node_list tg_node_list; + + // return true of the two points are "close enough" as defined by + // FG_PROXIMITY_EPSILON + bool close_enough_2d( const Point3D& p1, const Point3D& p2 ) const; + + // return true of the two points are "close enough" as defined by + // FG_PROXIMITY_EPSILON + bool close_enough_3d( const Point3D& p1, const Point3D& p2 ) const; + + // return true of the two points are "close enough" as defined by + // FG_COURSE_EPSILON + bool course_close_enough( const Point3D& p1, const Point3D& p2 ); +}; + + +// return true of the two points are "close enough" as defined by +// FG_PROXIMITY_EPSILON checking just x and y dimensions +inline bool TGNodes::close_enough_2d( const Point3D& p1, const Point3D& p2 ) + const +{ + if ( ( fabs(p1.x() - p2.x()) < FG_PROXIMITY_EPSILON ) && + ( fabs(p1.y() - p2.y()) < FG_PROXIMITY_EPSILON ) ) { + return true; + } else { + return false; + } +} + + +// return true of the two points are "close enough" as defined by +// FG_PROXIMITY_EPSILON check all three dimensions +inline bool TGNodes::close_enough_3d( const Point3D& p1, const Point3D& p2 ) + const +{ + if ( ( fabs(p1.x() - p2.x()) < FG_PROXIMITY_EPSILON ) && + ( fabs(p1.y() - p2.y()) < FG_PROXIMITY_EPSILON ) && + ( fabs(p1.z() - p2.z()) < FG_PROXIMITY_EPSILON ) ) { + return true; + } else { + return false; + } +} + + +// return true of the two points are "close enough" as defined by +// FG_COURSE_EPSILON +inline bool TGNodes::course_close_enough( const Point3D& p1, const Point3D& p2 ) +{ + if ( ( fabs(p1.x() - p2.x()) < FG_COURSE_EPSILON ) && + ( fabs(p1.y() - p2.y()) < FG_COURSE_EPSILON ) ) { + return true; + } else { + return false; + } +} + +#endif // _TG_NODES_HXX