From c39e3e05424152ad6ad390b8f6f9f96174a51a3d Mon Sep 17 00:00:00 2001 From: Peter Sadrozinski Date: Sun, 9 Sep 2012 16:32:42 -0400 Subject: [PATCH] elevation averaging and neighbor tile faces included in point normal calculation --- src/BuildTiles/Main/construct.cxx | 397 ++++++++++++++++++++++++++---- src/BuildTiles/Main/construct.hxx | 32 ++- 2 files changed, 374 insertions(+), 55 deletions(-) diff --git a/src/BuildTiles/Main/construct.cxx b/src/BuildTiles/Main/construct.cxx index 16950fbe..037381d6 100644 --- a/src/BuildTiles/Main/construct.cxx +++ b/src/BuildTiles/Main/construct.cxx @@ -617,15 +617,15 @@ int TGConstruct::LoadLandclassPolys( void ) { SG_LOG(SG_GENERAL, SG_DEBUG, "directory not found: " << poly_path); continue; } - + simgear::PathList files = d.children(simgear::Dir::TYPE_FILE); SG_LOG( SG_CLIPPER, SG_ALERT, files.size() << " Polys in " << d.path() ); - + BOOST_FOREACH(const SGPath& p, files) { if (p.file_base() != tile_str) { continue; } - + string lext = p.complete_lower_extension(); if ((lext == "arr") || (lext == "arr.gz") || (lext == "btg.gz") || (lext == "fit") || (lext == "fit.gz") || (lext == "ind")) @@ -794,7 +794,7 @@ int TGConstruct::load_landcover() while ( x1 < max_lon ) { while ( y1 < max_lat ) { make_area( cover, polys, x1, y1, x2, y2, half_cover_size, half_cover_size ); - + y1 = y2; y2 += cover_size; } @@ -1702,9 +1702,50 @@ double TGConstruct::calc_tri_area( int_list& triangle_nodes ) { return triangle_area( p1, p2, p3 ); } +static SGVec3d calc_normal( double area, Point3D p1, Point3D p2, Point3D p3 ) { + SGVec3d v1, v2, normal; + + // do some sanity checking. With the introduction of landuse + // areas, we can get some long skinny triangles that blow up our + // "normal" calculations here. Let's check for really small + // triangle areas and check if one dimension of the triangle + // coordinates is nearly coincident. If so, assign the "default" + // normal of straight up. + + bool degenerate = false; + const double area_eps = 1.0e-12; + if ( area < area_eps ) { + 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.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())); + } else { + v1[0] = p2.x() - p1.x(); + v1[1] = p2.y() - p1.y(); + v1[2] = p2.z() - p1.z(); + v2[0] = p3.x() - p1.x(); + v2[1] = p3.y() - p1.y(); + v2[2] = p3.z() - p1.z(); + normal = normalize(cross(v1, v2)); + } + + return normal; +} + void TGConstruct::calc_normals( point_list& wgs84_nodes, TGSuperPoly& sp ) { // for each face in the superpoly, calculate a face normal - SGVec3d v1, v2, normal; + SGVec3d normal; TGPolyNodes tri_nodes = sp.get_tri_idxs(); int_list face_nodes; double_list face_areas; @@ -1723,41 +1764,8 @@ void TGConstruct::calc_normals( point_list& wgs84_nodes, TGSuperPoly& sp ) { area = calc_tri_area( face_nodes ); - // do some sanity checking. With the introduction of landuse - // areas, we can get some long skinny triangles that blow up our - // "normal" calculations here. Let's check for really small - // triangle areas and check if one dimension of the triangle - // coordinates is nearly coincident. If so, assign the "default" - // normal of straight up. + normal = calc_normal( area, p1, p2, p3 ); - bool degenerate = false; - const double area_eps = 1.0e-12; - if ( area < area_eps ) { - 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.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())); - } else { - v1[0] = p2.x() - p1.x(); - v1[1] = p2.y() - p1.y(); - v1[2] = p2.z() - p1.z(); - v2[0] = p3.x() - p1.x(); - v2[1] = p3.y() - p1.y(); - v2[2] = p3.z() - p1.z(); - normal = normalize(cross(v1, v2)); - } - face_normals.push_back( Point3D::fromSGVec3( normal ) ); face_areas.push_back( area ); } @@ -1787,13 +1795,16 @@ void TGConstruct::CalcPointNormals( void ) SG_LOG(SG_GENERAL, SG_ALERT, "Calculating point normals: 0%"); Point3D normal; + double face_area; + point_list wgs84_nodes = nodes.get_wgs84_nodes_as_Point3d(); unsigned int ten_percent = nodes.size() / 10; unsigned int cur_percent = 10; - + for ( unsigned int i = 0; iface_areas.size(); + for ( int j = 0; j < num_faces; j++ ) { + normal = neighbor_faces->face_normals[j]; + face_area = neighbor_faces->face_areas[j]; + SG_LOG(SG_GENERAL, SG_ALERT, "\tAdding face area " << face_area << " and normal " << normal << " to node " << node.GetPosition() ); + + normal *= face_area; + total_area += face_area; + average += normal; + } + } + average /= total_area; nodes.SetNormal( i, average ); } @@ -1856,7 +1882,6 @@ void TGConstruct::TesselatePolys( void ) SG_LOG( SG_CLIPPER, SG_INFO, std::setprecision(12) << std::fixed << poly ); } -// TGPolygon tri = polygon_tesselate_alt_with_extra( poly, poly_extra, false ); TGPolygon tri = polygon_tesselate_alt_with_extra_cgal( poly, poly_extra, false ); // ensure all added nodes are accounted for @@ -2094,6 +2119,30 @@ void TGConstruct::CleanClippedPolys() { } } +void TGConstruct::AverageEdgeElevations( void ) +{ + for ( unsigned int i = 0; i < neighbor_faces.size(); i++ ) { + TGNeighborFaces faces = neighbor_faces[i]; + double elevation = 0.0; + unsigned int num_elevations = faces.elevations.size(); + + for ( unsigned int j = 0; j < num_elevations; j++ ) { + elevation += faces.elevations[j]; + } + + elevation = elevation / num_elevations; + + /* Find this node, and update it's elevation */ + int idx = nodes.find( faces.node ); + TGNode node = nodes.get_node( idx ); + + if ( !node.GetFixedPosition() ) { + // set elevation as the average between all tiles that have it + nodes.SetElevation( idx, elevation ); + } + } +} + void TGConstruct::CalcTextureCoordinates( void ) { for ( unsigned int area = 0; area < TG_MAX_AREA_TYPES; area++ ) { @@ -2176,9 +2225,260 @@ void TGConstruct::SaveSharedEdgeData( int stage ) ofs_e.close(); } break; + + case 2: + { + // for stage 2, we need enough info on a node to average out elevation and + // generate a correct normal + // we will use the Point3D, as stage1 above, then a point list per node + // to store the neighboors. + // + // NOTE: Some neighboors (likely 2) are on the shared border. + // Before calculating face normals for the node, all elevation data for + // neighboors needs to be completed. So after all border nodes' elevations + // are updated, we'll need to traverse all of these point lists, and update + // any border nodes elevation as well + SaveSharedEdgeDataStage2(); + } + break; } } +void TGConstruct::WriteNeighborFaces( std::ofstream& ofs_e, Point3D pt ) +{ + // find all neighboors of this point + int n = nodes.find( pt ); + TGNode node = nodes.get_node( n ); + TGFaceList faces = node.GetFaces(); + + // write the number of neighboor faces + ofs_e << faces.size() << "\n"; + + // write out each face normal and size + for (unsigned int j=0; j> count; + + for (int i=0; i> node; + + // look to see if we already have this node + // If we do, (it's a corner) add more faces to it. + // otherwise, initialize it with our elevation data + pFaces = FindNeighborFaces( node ); + if ( !pFaces ) { + pFaces = AddNeighborFaces( node ); + + // new face - let's add our elevation first + int idx = nodes.find( node ); + if (idx >= 0) { + TGNode local = nodes.get_node( idx ); + pFaces->elevations.push_back( local.GetPosition().z() ); + } + } + + // remember all of the elevation data for the node, so we can average + pFaces->elevations.push_back( node.z() ); + + in >> num_faces; + for (int j=0; j> area; + pFaces->face_areas.push_back( area ); + + in >> normal; + pFaces->face_normals.push_back( normal ); + } + } +} + +void TGConstruct::SaveSharedEdgeDataStage2( void ) +{ + string dir; + string file; + point_list north, south, east, west; + std::ofstream ofs_e; + int nCount; + + nodes.get_geod_edge( bucket, north, south, east, west ); + + dir = share_base + "/stage2/" + bucket.gen_base_path(); + + SGPath sgp( dir ); + sgp.append( "dummy" ); + sgp.create_dir( 0755 ); + + + // north edge + file = dir + "/" + bucket.gen_index_str() + "_north_edge"; + ofs_e.open( file.c_str() ); + ofs_e << std::setprecision(12); + ofs_e << std::fixed; + + nCount = north.size(); + ofs_e << nCount << "\n"; + for (int i=0; i neighbor_face_list; +typedef neighbor_face_list::iterator neighbor_face_list_iterator; +typedef neighbor_face_list::const_iterator const_neighbor_face_list_iterator; - - -// forward declaration -class TGMatch; - class TGConstruct { private: @@ -413,8 +419,8 @@ private: // All Nodes TGNodes nodes; - // SHared Edges match data - // TGMatch match; + // Neighbor Faces + neighbor_face_list neighbor_faces; private: // Load Data @@ -432,14 +438,19 @@ private: void merge_slivers( TGLandclass& clipped, poly_list& slivers_list ); // Shared edge Matching - void LoadSharedEdgeData( void ); - void SaveSharedEdgeData( void ); - + void SaveSharedEdgeDataStage2( void ); + void LoadSharedEdgeDataStage2( void ); + void WriteSharedEdgeNeighboorFaces( std::ofstream& ofs_e, Point3D pt ); void LoadSharedEdgeData( int stage ); void LoadNeighboorEdgeDataStage1( SGBucket& b, point_list& north, point_list& south, point_list& east, point_list& west ); void SaveSharedEdgeData( int stage ); + void ReadNeighborFaces( std::ifstream& ifs_e ); + void WriteNeighborFaces( std::ofstream& ofs_e, Point3D pt ); + TGNeighborFaces* AddNeighborFaces( Point3D node ); + TGNeighborFaces* FindNeighborFaces( Point3D node ); + // Polygon Cleaning void CleanClippedPolys( void ); void FixTJunctions( void ); @@ -449,6 +460,7 @@ private: // Elevation and Flattening void CalcElevations( void ); + void AverageEdgeElevations( void ); // Normals and texture coords void LookupNodesPerVertex( void );