- refactor construct.cxx into smaller files
- remove Match - tile matching now handled in tgconstruct_shared.cxx
This commit is contained in:
parent
c39e3e0542
commit
cc0d913712
22 changed files with 3965 additions and 3418 deletions
|
@ -1,6 +1,24 @@
|
||||||
|
include_directories(${GPC_INCLUDE_DIR})
|
||||||
|
|
||||||
add_executable(tg-construct
|
add_executable(tg-construct
|
||||||
construct.cxx
|
tgconstruct.hxx
|
||||||
construct.hxx
|
tgconstruct.cxx
|
||||||
|
tgconstruct_cleanup.cxx
|
||||||
|
tgconstruct_clip.cxx
|
||||||
|
tgconstruct_debug.cxx
|
||||||
|
tgconstruct_elevation.cxx
|
||||||
|
tgconstruct_landclass.cxx
|
||||||
|
tgconstruct_lookup.cxx
|
||||||
|
tgconstruct_math.cxx
|
||||||
|
tgconstruct_output.cxx
|
||||||
|
tgconstruct_poly.cxx
|
||||||
|
tgconstruct_shared.cxx
|
||||||
|
tgconstruct_tesselate.cxx
|
||||||
|
tgconstruct_texture.cxx
|
||||||
|
tglandclass.cxx
|
||||||
|
tglandclass.hxx
|
||||||
|
tgshape.cxx
|
||||||
|
tgshape.hxx
|
||||||
priorities.cxx
|
priorities.cxx
|
||||||
priorities.hxx
|
priorities.hxx
|
||||||
usgs.cxx
|
usgs.cxx
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,567 +0,0 @@
|
||||||
// construct.hxx -- Class to manage the primary data used in the
|
|
||||||
// construction process
|
|
||||||
//
|
|
||||||
// Written by Curtis Olson, started May 1999.
|
|
||||||
//
|
|
||||||
// Copyright (C) 1999 Curtis L. Olson - http://www.flightgear.org/~curt
|
|
||||||
//
|
|
||||||
// This program is free software; you can redistribute it and/or
|
|
||||||
// modify it under the terms of the GNU General Public License as
|
|
||||||
// published by the Free Software Foundation; either version 2 of the
|
|
||||||
// License, or (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This program is distributed in the hope that it will be useful, but
|
|
||||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
// General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with this program; if not, write to the Free Software
|
|
||||||
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
||||||
//
|
|
||||||
// $Id: construct.hxx,v 1.13 2004-11-19 22:25:49 curt Exp $
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef _CONSTRUCT_HXX
|
|
||||||
#define _CONSTRUCT_HXX
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef __cplusplus
|
|
||||||
# error This library requires C++
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
#define TG_MAX_AREA_TYPES 128
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
#include <vector>
|
|
||||||
#include <iomanip>
|
|
||||||
|
|
||||||
#include <simgear/compiler.h>
|
|
||||||
#include <simgear/bucket/newbucket.hxx>
|
|
||||||
#include <simgear/misc/sg_path.hxx>
|
|
||||||
#include <simgear/debug/logstream.hxx>
|
|
||||||
|
|
||||||
#include <Array/array.hxx>
|
|
||||||
|
|
||||||
#include <Polygon/superpoly.hxx>
|
|
||||||
#include <Polygon/texparams.hxx>
|
|
||||||
#include <Geometry/tg_nodes.hxx>
|
|
||||||
|
|
||||||
#include <landcover/landcover.hxx>
|
|
||||||
|
|
||||||
#include "priorities.hxx"
|
|
||||||
|
|
||||||
#define FIND_SLIVERS (1)
|
|
||||||
#define USE_ACCUMULATOR (1)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class TGShape
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
TGPolygon clip_mask;
|
|
||||||
bool textured;
|
|
||||||
superpoly_list sps;
|
|
||||||
texparams_list tps;
|
|
||||||
AreaType area;
|
|
||||||
unsigned int id;
|
|
||||||
|
|
||||||
void GetName( char* name ) const
|
|
||||||
{
|
|
||||||
sprintf( name, "%s_%d", get_area_name( (AreaType)area ).c_str(), id );
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetMask( TGPolygon mask )
|
|
||||||
{
|
|
||||||
clip_mask = mask;
|
|
||||||
}
|
|
||||||
|
|
||||||
void BuildMask( void )
|
|
||||||
{
|
|
||||||
TGPolygon poly;
|
|
||||||
clip_mask.erase();
|
|
||||||
|
|
||||||
for (unsigned int i=0; i<sps.size(); i++)
|
|
||||||
{
|
|
||||||
poly = sps[i].get_poly();
|
|
||||||
clip_mask = tgPolygonUnionClipper( clip_mask, poly );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void IntersectPolys( void )
|
|
||||||
{
|
|
||||||
if ( sps.size() > 1 ) {
|
|
||||||
TGPolygon original, intersect;
|
|
||||||
|
|
||||||
for (unsigned int i=0; i<sps.size(); i++)
|
|
||||||
{
|
|
||||||
original = sps[i].get_poly();
|
|
||||||
|
|
||||||
intersect = tgPolygonIntClipper( clip_mask, original );
|
|
||||||
|
|
||||||
sps[i].set_poly( intersect );
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
sps[0].set_poly( clip_mask );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Friends for serialization
|
|
||||||
friend std::istream& operator>> ( std::istream&, TGShape& );
|
|
||||||
friend std::ostream& operator<< ( std::ostream&, const TGShape& );
|
|
||||||
};
|
|
||||||
|
|
||||||
// input from stream
|
|
||||||
inline std::istream& operator >> ( std::istream& in, TGShape& p)
|
|
||||||
{
|
|
||||||
int i, count;
|
|
||||||
|
|
||||||
// First, load the clipmask
|
|
||||||
in >> p.clip_mask;
|
|
||||||
|
|
||||||
// Then load superpolys
|
|
||||||
in >> count;
|
|
||||||
for (i=0; i<count; i++) {
|
|
||||||
TGSuperPoly sp;
|
|
||||||
in >> sp;
|
|
||||||
p.sps.push_back( sp );
|
|
||||||
}
|
|
||||||
|
|
||||||
// Then load texparams
|
|
||||||
in >> count;
|
|
||||||
for (i=0; i<count; i++) {
|
|
||||||
TGTexParams tp;
|
|
||||||
in >> tp;
|
|
||||||
p.tps.push_back( tp );
|
|
||||||
}
|
|
||||||
|
|
||||||
// Load the id, area type and textured flag
|
|
||||||
in >> p.id;
|
|
||||||
in >> p.area;
|
|
||||||
in >> p.textured;
|
|
||||||
|
|
||||||
return in;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline std::ostream& operator<< ( std::ostream& out, const TGShape& p )
|
|
||||||
{
|
|
||||||
int i, count;
|
|
||||||
TGSuperPoly sp;
|
|
||||||
TGTexParams tp;
|
|
||||||
|
|
||||||
// First, save the clipmask
|
|
||||||
out << p.clip_mask;
|
|
||||||
|
|
||||||
// Then save superpolys
|
|
||||||
count = p.sps.size();
|
|
||||||
out << count << "\n";
|
|
||||||
for (i=0; i<count; i++) {
|
|
||||||
out << p.sps[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Then save texparams
|
|
||||||
count = p.tps.size();
|
|
||||||
out << count << "\n";
|
|
||||||
for (i=0; i<count; i++) {
|
|
||||||
out << p.tps[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Save the id, area type and textured flag
|
|
||||||
out << p.id << " ";
|
|
||||||
out << p.area << " ";
|
|
||||||
out << p.textured << "\n";
|
|
||||||
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
typedef std::vector < TGShape > shape_list;
|
|
||||||
typedef shape_list::iterator shape_list_iterator;
|
|
||||||
typedef shape_list::const_iterator const_shape_list_iterator;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class TGLandclass
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
void clear(void)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i=0; i<TG_MAX_AREA_TYPES; i++) {
|
|
||||||
shapes[i].clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
inline unsigned int area_size( unsigned int area )
|
|
||||||
{
|
|
||||||
return shapes[area].size();
|
|
||||||
}
|
|
||||||
inline unsigned int shape_size( unsigned int area, unsigned int shape )
|
|
||||||
{
|
|
||||||
return shapes[area][shape].sps.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void add_shape( unsigned int area, TGShape shape )
|
|
||||||
{
|
|
||||||
shapes[area].push_back( shape );
|
|
||||||
}
|
|
||||||
inline TGShape& get_shape( unsigned int area, unsigned int shape )
|
|
||||||
{
|
|
||||||
return shapes[area][shape];
|
|
||||||
}
|
|
||||||
|
|
||||||
inline TGPolygon get_mask( unsigned int area, unsigned int shape )
|
|
||||||
{
|
|
||||||
return shapes[area][shape].clip_mask;
|
|
||||||
}
|
|
||||||
inline void set_mask( unsigned int area, unsigned int shape, TGPolygon mask )
|
|
||||||
{
|
|
||||||
shapes[area][shape].clip_mask = mask;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool get_textured( unsigned int area, unsigned int shape )
|
|
||||||
{
|
|
||||||
return shapes[area][shape].textured;
|
|
||||||
}
|
|
||||||
inline void set_textured( unsigned int area, unsigned int shape, bool t )
|
|
||||||
{
|
|
||||||
shapes[area][shape].textured = t;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
inline TGSuperPoly& get_superpoly( unsigned int area, unsigned int shape, unsigned int segment )
|
|
||||||
{
|
|
||||||
return shapes[area][shape].sps[segment];
|
|
||||||
}
|
|
||||||
inline void set_superpoly( unsigned int area, unsigned int shape, unsigned int segment, TGSuperPoly sp )
|
|
||||||
{
|
|
||||||
shapes[area][shape].sps[segment] = sp;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline TGPolygon get_poly( unsigned int area, unsigned int shape, unsigned int segment )
|
|
||||||
{
|
|
||||||
return shapes[area][shape].sps[segment].get_poly();
|
|
||||||
}
|
|
||||||
inline void set_poly( unsigned int area, unsigned int shape, unsigned int segment, TGPolygon poly )
|
|
||||||
{
|
|
||||||
return shapes[area][shape].sps[segment].set_poly( poly );
|
|
||||||
}
|
|
||||||
|
|
||||||
inline TGPolygon get_tris( unsigned int area, unsigned int shape, unsigned int segment )
|
|
||||||
{
|
|
||||||
return shapes[area][shape].sps[segment].get_tris();
|
|
||||||
}
|
|
||||||
inline void set_tris( unsigned int area, unsigned int shape, unsigned int segment, TGPolygon tris )
|
|
||||||
{
|
|
||||||
shapes[area][shape].sps[segment].set_tris( tris );
|
|
||||||
}
|
|
||||||
|
|
||||||
inline Point3D get_face_normal( unsigned int area, unsigned int shape, unsigned int segment, unsigned int tri )
|
|
||||||
{
|
|
||||||
return shapes[area][shape].sps[segment].get_face_normal( tri );
|
|
||||||
}
|
|
||||||
|
|
||||||
inline double get_face_area( unsigned int area, unsigned int shape, unsigned int segment, unsigned int tri )
|
|
||||||
{
|
|
||||||
return shapes[area][shape].sps[segment].get_face_area( tri );
|
|
||||||
}
|
|
||||||
|
|
||||||
inline std::string get_flag( unsigned int area, unsigned int shape, unsigned int segment )
|
|
||||||
{
|
|
||||||
return shapes[area][shape].sps[segment].get_flag();
|
|
||||||
}
|
|
||||||
|
|
||||||
inline std::string get_material( unsigned int area, unsigned int shape, unsigned int segment )
|
|
||||||
{
|
|
||||||
return shapes[area][shape].sps[segment].get_material();
|
|
||||||
}
|
|
||||||
inline TGTexParams& get_texparams( unsigned int area, unsigned int shape, unsigned int segment )
|
|
||||||
{
|
|
||||||
return shapes[area][shape].tps[segment];
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
inline TGPolygon get_texcoords( unsigned int area, unsigned int shape, unsigned int segment )
|
|
||||||
{
|
|
||||||
return shapes[area][shape].sps[segment].get_texcoords();
|
|
||||||
}
|
|
||||||
inline void set_texcoords( unsigned int area, unsigned int shape, unsigned int segment, TGPolygon tcs )
|
|
||||||
{
|
|
||||||
return shapes[area][shape].sps[segment].set_texcoords( tcs );
|
|
||||||
}
|
|
||||||
|
|
||||||
inline TGPolyNodes get_tri_idxs( unsigned int area, unsigned int shape, unsigned int segment )
|
|
||||||
{
|
|
||||||
return shapes[area][shape].sps[segment].get_tri_idxs();
|
|
||||||
}
|
|
||||||
inline void set_tri_idxs( unsigned int area, unsigned int shape, unsigned int segment, TGPolyNodes tis )
|
|
||||||
{
|
|
||||||
return shapes[area][shape].sps[segment].set_tri_idxs( tis );
|
|
||||||
}
|
|
||||||
|
|
||||||
// Friends for serialization
|
|
||||||
friend std::istream& operator>> ( std::istream&, TGLandclass& );
|
|
||||||
friend std::ostream& operator<< ( std::ostream&, const TGLandclass& );
|
|
||||||
|
|
||||||
private:
|
|
||||||
shape_list shapes[TG_MAX_AREA_TYPES];
|
|
||||||
};
|
|
||||||
|
|
||||||
// input from stream
|
|
||||||
inline std::istream& operator >> ( std::istream& in, TGLandclass& lc)
|
|
||||||
{
|
|
||||||
int i, j, count;
|
|
||||||
|
|
||||||
// Load all landclass shapes
|
|
||||||
for (i=0; i<TG_MAX_AREA_TYPES; i++) {
|
|
||||||
in >> count;
|
|
||||||
|
|
||||||
for (j=0; j<count; j++) {
|
|
||||||
TGShape shape;
|
|
||||||
|
|
||||||
in >> shape;
|
|
||||||
lc.shapes[i].push_back( shape );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return in;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline std::ostream& operator<< ( std::ostream& out, const TGLandclass& lc )
|
|
||||||
{
|
|
||||||
int i, j, count;
|
|
||||||
TGShape shape;
|
|
||||||
|
|
||||||
// Save all landclass shapes
|
|
||||||
for (i=0; i<TG_MAX_AREA_TYPES; i++) {
|
|
||||||
count = lc.shapes[i].size();
|
|
||||||
out << count << "\n";
|
|
||||||
for (j=0; j<count; j++) {
|
|
||||||
out << lc.shapes[i][j] << " ";
|
|
||||||
}
|
|
||||||
out << "\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Stage2 shared edge data
|
|
||||||
struct TGNeighborFaces {
|
|
||||||
public:
|
|
||||||
Point3D node;
|
|
||||||
|
|
||||||
double_list elevations; // we'll take the average
|
|
||||||
double_list face_areas;
|
|
||||||
point_list face_normals;
|
|
||||||
};
|
|
||||||
typedef std::vector < TGNeighborFaces > neighbor_face_list;
|
|
||||||
typedef neighbor_face_list::iterator neighbor_face_list_iterator;
|
|
||||||
typedef neighbor_face_list::const_iterator const_neighbor_face_list_iterator;
|
|
||||||
|
|
||||||
|
|
||||||
class TGConstruct {
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
// path to land-cover file (if any)
|
|
||||||
std::string cover;
|
|
||||||
|
|
||||||
// paths
|
|
||||||
std::string work_base;
|
|
||||||
std::string output_base;
|
|
||||||
std::string share_base;
|
|
||||||
|
|
||||||
std::vector<std::string> load_dirs;
|
|
||||||
|
|
||||||
// flag indicating whether to align texture coords within the UK
|
|
||||||
// with the UK grid
|
|
||||||
bool useUKGrid;
|
|
||||||
|
|
||||||
// flag indicating whether to ignore the landmass
|
|
||||||
bool ignoreLandmass;
|
|
||||||
|
|
||||||
// I think we should remove this
|
|
||||||
double nudge;
|
|
||||||
|
|
||||||
// path to the debug shapes
|
|
||||||
std::string debug_path;
|
|
||||||
|
|
||||||
bool debug_all;
|
|
||||||
|
|
||||||
// list of shapes to dump during debug
|
|
||||||
std::vector<unsigned int> debug_areas;
|
|
||||||
std::vector<unsigned int> debug_shapes;
|
|
||||||
|
|
||||||
// OGR encode variables
|
|
||||||
// For debug:
|
|
||||||
void* ds_id; // If we are going to build shapefiles
|
|
||||||
void* l_id; // datasource and layer IDs
|
|
||||||
char ds_name[128];
|
|
||||||
char layer_name[128];
|
|
||||||
char feature_name[128];
|
|
||||||
|
|
||||||
// this bucket
|
|
||||||
SGBucket bucket;
|
|
||||||
|
|
||||||
// Elevation data
|
|
||||||
TGArray array;
|
|
||||||
|
|
||||||
// land class polygons
|
|
||||||
TGLandclass polys_in;
|
|
||||||
TGLandclass polys_clipped;
|
|
||||||
|
|
||||||
// All Nodes
|
|
||||||
TGNodes nodes;
|
|
||||||
|
|
||||||
// Neighbor Faces
|
|
||||||
neighbor_face_list neighbor_faces;
|
|
||||||
|
|
||||||
private:
|
|
||||||
// Load Data
|
|
||||||
void LoadElevationArray( void );
|
|
||||||
int LoadLandclassPolys( void );
|
|
||||||
// Load Data Helpers
|
|
||||||
bool load_poly(const std::string& path);
|
|
||||||
bool load_osgb36_poly(const std::string& path);
|
|
||||||
void add_poly(int area, const TGPolygon &poly, std::string material);
|
|
||||||
|
|
||||||
// Clip Data
|
|
||||||
bool ClipLandclassPolys( void );
|
|
||||||
// Clip Helpers
|
|
||||||
void move_slivers( TGPolygon& in, TGPolygon& out );
|
|
||||||
void merge_slivers( TGLandclass& clipped, poly_list& slivers_list );
|
|
||||||
|
|
||||||
// Shared edge Matching
|
|
||||||
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 );
|
|
||||||
|
|
||||||
// Tesselation
|
|
||||||
void TesselatePolys( void );
|
|
||||||
|
|
||||||
// Elevation and Flattening
|
|
||||||
void CalcElevations( void );
|
|
||||||
void AverageEdgeElevations( void );
|
|
||||||
|
|
||||||
// Normals and texture coords
|
|
||||||
void LookupNodesPerVertex( void );
|
|
||||||
void LookupFacesPerNode( void );
|
|
||||||
void CalcFaceNormals( void );
|
|
||||||
void CalcPointNormals( void );
|
|
||||||
void CalcTextureCoordinates( void );
|
|
||||||
// Helpers
|
|
||||||
TGPolygon linear_tex_coords( const TGPolygon& tri, const TGTexParams& tp );
|
|
||||||
TGPolygon area_tex_coords( const TGPolygon& tri );
|
|
||||||
|
|
||||||
// Output
|
|
||||||
void WriteBtgFile( void );
|
|
||||||
void AddCustomObjects( void );
|
|
||||||
|
|
||||||
// Misc
|
|
||||||
void calc_normals( point_list& wgs84_nodes, TGSuperPoly& sp );
|
|
||||||
double calc_tri_area( int_list& triangle_nodes );
|
|
||||||
|
|
||||||
// debug
|
|
||||||
bool IsDebugShape( unsigned int id );
|
|
||||||
bool IsDebugArea( unsigned int area );
|
|
||||||
|
|
||||||
void WriteDebugShape( const char* layer_name, const TGShape& shape );
|
|
||||||
void WriteDebugPoly( const char* layer_name, const char* name, const TGPolygon& poly );
|
|
||||||
void WriteDebugPolys( const char* layer_name, const poly_list& polys );
|
|
||||||
|
|
||||||
public:
|
|
||||||
// Constructor
|
|
||||||
TGConstruct();
|
|
||||||
|
|
||||||
// Destructor
|
|
||||||
~TGConstruct();
|
|
||||||
|
|
||||||
void set_bucket( SGBucket b ) { bucket = b; }
|
|
||||||
|
|
||||||
// New shared edge matching
|
|
||||||
void SaveToIntermediateFiles( int stage );
|
|
||||||
void LoadFromIntermediateFiles( int stage );
|
|
||||||
|
|
||||||
// Three stage construct
|
|
||||||
void ConstructBucketStage1();
|
|
||||||
void ConstructBucketStage2();
|
|
||||||
void ConstructBucketStage3();
|
|
||||||
|
|
||||||
void calc_gc_course_dist( const Point3D& start, const Point3D& dest,
|
|
||||||
double *course, double *dist );
|
|
||||||
double distanceSphere( const Point3D p1, const Point3D p2 );
|
|
||||||
|
|
||||||
int load_landcover ();
|
|
||||||
void add_to_polys( TGPolygon &accum, const TGPolygon &poly);
|
|
||||||
double measure_roughness( TGPolygon &poly );
|
|
||||||
AreaType get_landcover_type (const LandCover &cover, double xpos, double ypos, double dx, double dy);
|
|
||||||
void make_area( const LandCover &cover, TGPolygon *polys,
|
|
||||||
double x1, double y1, double x2, double y2,
|
|
||||||
double half_dx, double half_dy );
|
|
||||||
|
|
||||||
// land cover file
|
|
||||||
inline std::string get_cover () const { return cover; }
|
|
||||||
inline void set_cover (const std::string &s) { cover = s; }
|
|
||||||
|
|
||||||
// paths
|
|
||||||
void set_paths( const std::string work, const std::string share, const std::string output, const std::vector<std::string> load_dirs );
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
inline std::string get_work_base() const { return work_base; }
|
|
||||||
inline void set_work_base( const std::string s ) { work_base = s; }
|
|
||||||
inline std::string get_output_base() const { return output_base; }
|
|
||||||
inline void set_output_base( const std::string s ) { output_base = s; }
|
|
||||||
inline std::string get_share_base() const { return share_base; }
|
|
||||||
inline void set_share_base( const std::string s ) { share_base = s; }
|
|
||||||
inline void set_load_dirs( const std::vector<std::string> ld ) { load_dirs = ld; }
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void set_options( bool uk_grid, bool ignore_lm, double n );
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
// UK grid flag
|
|
||||||
inline bool get_useUKGrid() const { return useUKGrid; }
|
|
||||||
inline void set_useUKGrid( const bool b ) { useUKGrid = b; }
|
|
||||||
|
|
||||||
// Nudge
|
|
||||||
inline void set_nudge( double n ) { nudge = n; }
|
|
||||||
|
|
||||||
// ignore landmass flag
|
|
||||||
inline void set_ignore_landmass( const bool b) { ignoreLandmass = b; }
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// TODO : REMOVE
|
|
||||||
inline TGNodes* get_nodes() { return &nodes; }
|
|
||||||
|
|
||||||
// node list in geodetic coords (with fixed elevation)
|
|
||||||
inline point_list get_geod_nodes() const { return nodes.get_geod_nodes(); }
|
|
||||||
|
|
||||||
// normal list (for each point) in cart coords (for smooth
|
|
||||||
// shading)
|
|
||||||
inline point_list get_point_normals() const { return nodes.get_normals(); }
|
|
||||||
|
|
||||||
// Debug
|
|
||||||
void set_debug( std::string path, std::vector<std::string> area_defs, std::vector<std::string> shape_defs );
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
#endif // _CONSTRUCT_HXX
|
|
|
@ -29,36 +29,36 @@
|
||||||
# include <config.h>
|
# include <config.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <simgear/compiler.h>
|
//#include <simgear/compiler.h>
|
||||||
|
|
||||||
#include <iostream>
|
//#include <iostream>
|
||||||
#include <string>
|
//#include <string>
|
||||||
#include <vector>
|
//#include <vector>
|
||||||
#include <algorithm>
|
//#include <algorithm>
|
||||||
|
|
||||||
#include <simgear/constants.h>
|
//#include <simgear/constants.h>
|
||||||
#include <simgear/bucket/newbucket.hxx>
|
//#include <simgear/bucket/newbucket.hxx>
|
||||||
#include <simgear/debug/logstream.hxx>
|
#include <simgear/debug/logstream.hxx>
|
||||||
#include <simgear/misc/sg_dir.hxx>
|
//#include <simgear/misc/sg_dir.hxx>
|
||||||
#include <simgear/misc/sg_path.hxx>
|
//#include <simgear/misc/sg_path.hxx>
|
||||||
#include <simgear/math/sg_types.hxx>
|
//#include <simgear/math/sg_types.hxx>
|
||||||
|
|
||||||
#include <simgear/math/SGMath.hxx>
|
//#include <simgear/math/SGMath.hxx>
|
||||||
#include <simgear/misc/sgstream.hxx>
|
//#include <simgear/misc/sgstream.hxx>
|
||||||
|
|
||||||
|
|
||||||
#include <boost/foreach.hpp>
|
//#include <boost/foreach.hpp>
|
||||||
|
|
||||||
#include <Geometry/poly_support.hxx>
|
#include <Geometry/poly_support.hxx>
|
||||||
#include <landcover/landcover.hxx>
|
//#include <landcover/landcover.hxx>
|
||||||
|
|
||||||
#include "construct.hxx"
|
#include "tgconstruct.hxx"
|
||||||
#include "usgs.hxx"
|
#include "usgs.hxx"
|
||||||
|
|
||||||
using std::string;
|
using std::string;
|
||||||
using std::vector;
|
using std::vector;
|
||||||
|
|
||||||
using namespace std;
|
//using namespace std;
|
||||||
|
|
||||||
vector<string> load_dirs;
|
vector<string> load_dirs;
|
||||||
double nudge=0.0;
|
double nudge=0.0;
|
||||||
|
@ -327,7 +327,7 @@ int main(int argc, char **argv) {
|
||||||
stage1->set_paths( work_dir, share_dir, output_dir, load_dirs );
|
stage1->set_paths( work_dir, share_dir, output_dir, load_dirs );
|
||||||
stage1->set_options( useUKgrid, ignoreLandmass, nudge );
|
stage1->set_options( useUKgrid, ignoreLandmass, nudge );
|
||||||
stage1->set_bucket( b_cur );
|
stage1->set_bucket( b_cur );
|
||||||
stage1->set_debug( debug_dir, debug_defs );
|
stage1->set_debug( debug_dir, debug_area_defs, debug_shape_defs );
|
||||||
|
|
||||||
stage1->ConstructBucketStage1();
|
stage1->ConstructBucketStage1();
|
||||||
stage1->SaveToIntermediateFiles(1);
|
stage1->SaveToIntermediateFiles(1);
|
||||||
|
|
235
src/BuildTiles/Main/tgconstruct.cxx
Normal file
235
src/BuildTiles/Main/tgconstruct.cxx
Normal file
|
@ -0,0 +1,235 @@
|
||||||
|
// construct.cxx -- Class to manage the primary data used in the
|
||||||
|
// construction process
|
||||||
|
//
|
||||||
|
// Written by Curtis Olson, started May 1999.
|
||||||
|
//
|
||||||
|
// Copyright (C) 1999 Curtis L. Olson - http://www.flightgear.org/~curt
|
||||||
|
//
|
||||||
|
// This program is free software; you can redistribute it and/or
|
||||||
|
// modify it under the terms of the GNU General Public License as
|
||||||
|
// published by the Free Software Foundation; either version 2 of the
|
||||||
|
// License, or (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful, but
|
||||||
|
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
// General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
//
|
||||||
|
// $Id: construct.cxx,v 1.4 2004-11-19 22:25:49 curt Exp $
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
# include <config.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <iomanip>
|
||||||
|
|
||||||
|
//#include <boost/foreach.hpp>
|
||||||
|
|
||||||
|
//#include <simgear/compiler.h>
|
||||||
|
//#include <simgear/constants.h>
|
||||||
|
//#include <simgear/math/sg_geodesy.hxx>
|
||||||
|
//#include <simgear/math/SGGeometry.hxx>
|
||||||
|
//#include <simgear/misc/sg_dir.hxx>
|
||||||
|
//#include <simgear/misc/texcoord.hxx>
|
||||||
|
//#include <simgear/io/sg_binobj.hxx>
|
||||||
|
//#include <simgear/structure/exception.hxx>
|
||||||
|
#include <simgear/debug/logstream.hxx>
|
||||||
|
//#include <CGAL/Plane_3.h>
|
||||||
|
|
||||||
|
//#include <Geometry/poly_support.hxx>
|
||||||
|
//#include <Geometry/poly_extra.hxx>
|
||||||
|
|
||||||
|
#include "tgconstruct.hxx"
|
||||||
|
//#include "usgs.hxx"
|
||||||
|
|
||||||
|
//using std::string;
|
||||||
|
|
||||||
|
// Constructor
|
||||||
|
TGConstruct::TGConstruct():
|
||||||
|
useUKGrid(false),
|
||||||
|
ignoreLandmass(false),
|
||||||
|
debug_all(false),
|
||||||
|
ds_id((void*)-1)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
|
||||||
|
// Destructor
|
||||||
|
TGConstruct::~TGConstruct() {
|
||||||
|
array.close();
|
||||||
|
|
||||||
|
// land class polygons
|
||||||
|
polys_in.clear();
|
||||||
|
polys_clipped.clear();
|
||||||
|
|
||||||
|
// All Nodes
|
||||||
|
nodes.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
// TGConstruct: Setup
|
||||||
|
void TGConstruct::set_paths( const std::string work, const std::string share, const std::string output, const std::vector<std::string> load ) {
|
||||||
|
work_base = work;
|
||||||
|
share_base = share;
|
||||||
|
output_base = output;
|
||||||
|
load_dirs = load;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TGConstruct::set_options( bool uk_grid, bool ignore_lm, double n ) {
|
||||||
|
useUKGrid = uk_grid;
|
||||||
|
ignoreLandmass = ignore_lm;
|
||||||
|
nudge = n;
|
||||||
|
}
|
||||||
|
|
||||||
|
// master construction routine
|
||||||
|
// TODO : Split each step into its own function, and move
|
||||||
|
// into seperate files by major functionality
|
||||||
|
// loading, clipping, tesselating, normals, and output
|
||||||
|
// Also, we are still calculating some thing more than one
|
||||||
|
// (like face area - need to move this into superpoly )
|
||||||
|
void TGConstruct::ConstructBucketStage1() {
|
||||||
|
// First, set the precision of floating point logging:
|
||||||
|
SG_LOG(SG_GENERAL, SG_ALERT, std::setprecision(12) << std::fixed);
|
||||||
|
SG_LOG(SG_GENERAL, SG_ALERT, "\nConstructing tile ID " << bucket.gen_index_str() << " in " << bucket.gen_base_path() );
|
||||||
|
|
||||||
|
/* If we have some debug IDs, create a datasource */
|
||||||
|
if ( debug_shapes.size() || debug_all ) {
|
||||||
|
sprintf(ds_name, "%s/constructdbg_%s", debug_path.c_str(), bucket.gen_index_str().c_str() );
|
||||||
|
SG_LOG(SG_GENERAL, SG_ALERT, "Debug_string: " << ds_name );
|
||||||
|
} else {
|
||||||
|
strcpy( ds_name, "" );
|
||||||
|
}
|
||||||
|
|
||||||
|
// STEP 1)
|
||||||
|
// Load grid of elevation data (Array)
|
||||||
|
LoadElevationArray();
|
||||||
|
|
||||||
|
// STEP 2)
|
||||||
|
// Clip 2D polygons against one another
|
||||||
|
if ( LoadLandclassPolys() == 0 ) {
|
||||||
|
// don't build the tile if there is no 2d data ... it *must*
|
||||||
|
// be ocean and the sim can build the tile on the fly.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// STEP 3)
|
||||||
|
// Load the land use polygons if the --cover option was specified
|
||||||
|
if ( get_cover().size() > 0 ) {
|
||||||
|
load_landcover();
|
||||||
|
}
|
||||||
|
|
||||||
|
// STEP 4)
|
||||||
|
// Clip the Landclass polygons
|
||||||
|
ClipLandclassPolys();
|
||||||
|
|
||||||
|
// STEP 5)
|
||||||
|
// Clean the polys - after this, we shouldn't change their shape (other than slightly for
|
||||||
|
// fix T-Junctions - as This is the end of the first pass for multicore design
|
||||||
|
CleanClippedPolys();
|
||||||
|
|
||||||
|
// STEP 6)
|
||||||
|
// Save the tile boundary info for stage 2 (just x,y coords of points on the boundary)
|
||||||
|
SaveSharedEdgeData( 1 );
|
||||||
|
}
|
||||||
|
|
||||||
|
void TGConstruct::ConstructBucketStage2() {
|
||||||
|
// First, set the precision of floating point logging:
|
||||||
|
SG_LOG(SG_GENERAL, SG_ALERT, std::setprecision(12) << std::fixed);
|
||||||
|
SG_LOG(SG_GENERAL, SG_ALERT, "\nConstructing tile ID " << bucket.gen_index_str() << " in " << bucket.gen_base_path() );
|
||||||
|
|
||||||
|
/* If we have some debug IDs, create a datasource */
|
||||||
|
if ( debug_shapes.size() || debug_all ) {
|
||||||
|
sprintf(ds_name, "%s/constructdbg_%s", debug_path.c_str(), bucket.gen_index_str().c_str() );
|
||||||
|
SG_LOG(SG_GENERAL, SG_ALERT, "Debug_string: " << ds_name );
|
||||||
|
} else {
|
||||||
|
strcpy( ds_name, "" );
|
||||||
|
}
|
||||||
|
|
||||||
|
// STEP 7)
|
||||||
|
// Need the array of elevation data for stage 2
|
||||||
|
LoadElevationArray();
|
||||||
|
|
||||||
|
// STEP 6)
|
||||||
|
// Merge in Shared data - should just be x,y nodes on the borders from stage1
|
||||||
|
LoadSharedEdgeData( 1 );
|
||||||
|
|
||||||
|
// STEP 7)
|
||||||
|
// Fix T-Junctions by finding nodes that lie close to polygon edges, and
|
||||||
|
// inserting them into the edge
|
||||||
|
FixTJunctions();
|
||||||
|
|
||||||
|
// STEP 8)
|
||||||
|
// Generate triangles - we can't generate the node-face lookup table
|
||||||
|
// until all polys are tesselated, as extra nodes can still be generated
|
||||||
|
TesselatePolys();
|
||||||
|
|
||||||
|
// STEP 9)
|
||||||
|
// Generate triangle vertex coordinates to node index lists
|
||||||
|
// NOTE: After this point, no new nodes can be added
|
||||||
|
LookupNodesPerVertex();
|
||||||
|
|
||||||
|
// STEP 10)
|
||||||
|
// Interpolate elevations, and flatten stuff
|
||||||
|
CalcElevations();
|
||||||
|
|
||||||
|
// STEP 11)
|
||||||
|
// Generate face_connected list
|
||||||
|
LookupFacesPerNode();
|
||||||
|
|
||||||
|
// STEP 12)
|
||||||
|
// Save the tile boundary info for stage 3
|
||||||
|
// includes elevation info, and a list of connected triangles
|
||||||
|
SaveSharedEdgeData( 2 );
|
||||||
|
}
|
||||||
|
|
||||||
|
void TGConstruct::ConstructBucketStage3() {
|
||||||
|
// First, set the precision of floating point logging:
|
||||||
|
SG_LOG(SG_GENERAL, SG_ALERT, std::setprecision(12) << std::fixed);
|
||||||
|
SG_LOG(SG_GENERAL, SG_ALERT, "\nConstructing tile ID " << bucket.gen_index_str() << " in " << bucket.gen_base_path() );
|
||||||
|
|
||||||
|
/* If we have some debug IDs, create a datasource */
|
||||||
|
if ( debug_shapes.size() || debug_all ) {
|
||||||
|
sprintf(ds_name, "%s/constructdbg_%s", debug_path.c_str(), bucket.gen_index_str().c_str() );
|
||||||
|
SG_LOG(SG_GENERAL, SG_ALERT, "Debug_string: " << ds_name );
|
||||||
|
} else {
|
||||||
|
strcpy( ds_name, "" );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load in the neighbor faces and elevation data
|
||||||
|
LoadSharedEdgeDataStage2();
|
||||||
|
|
||||||
|
// STEP 12)
|
||||||
|
// Average out the elevation for nodes on tile boundaries
|
||||||
|
AverageEdgeElevations();
|
||||||
|
|
||||||
|
// STEP 12)
|
||||||
|
// Calculate Face Normals
|
||||||
|
CalcFaceNormals();
|
||||||
|
|
||||||
|
// STEP 13)
|
||||||
|
// Calculate Point Normals
|
||||||
|
CalcPointNormals();
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
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 );
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// STEP 14)
|
||||||
|
// Calculate Texture Coordinates
|
||||||
|
CalcTextureCoordinates();
|
||||||
|
|
||||||
|
// STEP 16)
|
||||||
|
// Generate the btg file
|
||||||
|
WriteBtgFile();
|
||||||
|
|
||||||
|
// STEP 17)
|
||||||
|
// Write Custom objects to .stg file
|
||||||
|
AddCustomObjects();
|
||||||
|
}
|
271
src/BuildTiles/Main/tgconstruct.hxx
Normal file
271
src/BuildTiles/Main/tgconstruct.hxx
Normal file
|
@ -0,0 +1,271 @@
|
||||||
|
// construct.hxx -- Class to manage the primary data used in the
|
||||||
|
// construction process
|
||||||
|
//
|
||||||
|
// Written by Curtis Olson, started May 1999.
|
||||||
|
//
|
||||||
|
// Copyright (C) 1999 Curtis L. Olson - http://www.flightgear.org/~curt
|
||||||
|
//
|
||||||
|
// This program is free software; you can redistribute it and/or
|
||||||
|
// modify it under the terms of the GNU General Public License as
|
||||||
|
// published by the Free Software Foundation; either version 2 of the
|
||||||
|
// License, or (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful, but
|
||||||
|
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
// General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
//
|
||||||
|
// $Id: construct.hxx,v 1.13 2004-11-19 22:25:49 curt Exp $
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef _CONSTRUCT_HXX
|
||||||
|
#define _CONSTRUCT_HXX
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef __cplusplus
|
||||||
|
# error This library requires C++
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#define TG_MAX_AREA_TYPES 128
|
||||||
|
|
||||||
|
//#include <string>
|
||||||
|
//#include <vector>
|
||||||
|
|
||||||
|
//#include <simgear/compiler.h>
|
||||||
|
//#include <simgear/bucket/newbucket.hxx>
|
||||||
|
//#include <simgear/misc/sg_path.hxx>
|
||||||
|
//#include <simgear/debug/logstream.hxx>
|
||||||
|
|
||||||
|
#include <Array/array.hxx>
|
||||||
|
|
||||||
|
//#include <Polygon/superpoly.hxx>
|
||||||
|
//#include <Polygon/texparams.hxx>
|
||||||
|
#include <Geometry/tg_nodes.hxx>
|
||||||
|
|
||||||
|
#include <landcover/landcover.hxx>
|
||||||
|
|
||||||
|
#include "tglandclass.hxx"
|
||||||
|
//#include "priorities.hxx"
|
||||||
|
|
||||||
|
#define FIND_SLIVERS (0)
|
||||||
|
#define USE_ACCUMULATOR (1)
|
||||||
|
|
||||||
|
|
||||||
|
// Stage2 shared edge data
|
||||||
|
struct TGNeighborFaces {
|
||||||
|
public:
|
||||||
|
Point3D node;
|
||||||
|
|
||||||
|
double_list elevations; // we'll take the average
|
||||||
|
double_list face_areas;
|
||||||
|
point_list face_normals;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef std::vector < TGNeighborFaces > neighbor_face_list;
|
||||||
|
typedef neighbor_face_list::iterator neighbor_face_list_iterator;
|
||||||
|
typedef neighbor_face_list::const_iterator const_neighbor_face_list_iterator;
|
||||||
|
|
||||||
|
|
||||||
|
class TGConstruct {
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
// path to land-cover file (if any)
|
||||||
|
std::string cover;
|
||||||
|
|
||||||
|
// paths
|
||||||
|
std::string work_base;
|
||||||
|
std::string output_base;
|
||||||
|
std::string share_base;
|
||||||
|
|
||||||
|
std::vector<std::string> load_dirs;
|
||||||
|
|
||||||
|
const static double gSnap = 0.00000001; // approx 1 mm
|
||||||
|
|
||||||
|
// flag indicating whether to align texture coords within the UK
|
||||||
|
// with the UK grid
|
||||||
|
bool useUKGrid;
|
||||||
|
|
||||||
|
// flag indicating whether to ignore the landmass
|
||||||
|
bool ignoreLandmass;
|
||||||
|
|
||||||
|
// I think we should remove this
|
||||||
|
double nudge;
|
||||||
|
|
||||||
|
// path to the debug shapes
|
||||||
|
std::string debug_path;
|
||||||
|
|
||||||
|
bool debug_all;
|
||||||
|
|
||||||
|
// list of shapes to dump during debug
|
||||||
|
std::vector<unsigned int> debug_areas;
|
||||||
|
std::vector<unsigned int> debug_shapes;
|
||||||
|
|
||||||
|
// OGR encode variables
|
||||||
|
// For debug:
|
||||||
|
void* ds_id; // If we are going to build shapefiles
|
||||||
|
void* l_id; // datasource and layer IDs
|
||||||
|
char ds_name[128];
|
||||||
|
char layer_name[128];
|
||||||
|
char feature_name[128];
|
||||||
|
|
||||||
|
// this bucket
|
||||||
|
SGBucket bucket;
|
||||||
|
|
||||||
|
// Elevation data
|
||||||
|
TGArray array;
|
||||||
|
|
||||||
|
// land class polygons
|
||||||
|
TGLandclass polys_in;
|
||||||
|
TGLandclass polys_clipped;
|
||||||
|
|
||||||
|
// All Nodes
|
||||||
|
TGNodes nodes;
|
||||||
|
|
||||||
|
// Neighbor Faces
|
||||||
|
neighbor_face_list neighbor_faces;
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Load Data
|
||||||
|
void LoadElevationArray( void );
|
||||||
|
int LoadLandclassPolys( void );
|
||||||
|
// Load Data Helpers
|
||||||
|
bool load_poly(const std::string& path);
|
||||||
|
bool load_osgb36_poly(const std::string& path);
|
||||||
|
void add_poly(int area, const TGPolygon &poly, std::string material);
|
||||||
|
|
||||||
|
// Clip Data
|
||||||
|
bool ClipLandclassPolys( void );
|
||||||
|
// Clip Helpers
|
||||||
|
void move_slivers( TGPolygon& in, TGPolygon& out );
|
||||||
|
void merge_slivers( TGLandclass& clipped, poly_list& slivers_list );
|
||||||
|
|
||||||
|
// Shared edge Matching
|
||||||
|
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 );
|
||||||
|
|
||||||
|
// Tesselation
|
||||||
|
void TesselatePolys( void );
|
||||||
|
|
||||||
|
// Elevation and Flattening
|
||||||
|
void CalcElevations( void );
|
||||||
|
void AverageEdgeElevations( void );
|
||||||
|
|
||||||
|
// Normals and texture coords
|
||||||
|
void LookupNodesPerVertex( void );
|
||||||
|
void LookupFacesPerNode( void );
|
||||||
|
void CalcFaceNormals( void );
|
||||||
|
void CalcPointNormals( void );
|
||||||
|
void CalcTextureCoordinates( void );
|
||||||
|
// Helpers
|
||||||
|
SGVec3d calc_normal( double area, Point3D p1, Point3D p2, Point3D p3 );
|
||||||
|
TGPolygon linear_tex_coords( const TGPolygon& tri, const TGTexParams& tp );
|
||||||
|
TGPolygon area_tex_coords( const TGPolygon& tri );
|
||||||
|
|
||||||
|
// Output
|
||||||
|
void WriteBtgFile( void );
|
||||||
|
void AddCustomObjects( void );
|
||||||
|
|
||||||
|
// Misc
|
||||||
|
void calc_normals( point_list& wgs84_nodes, TGSuperPoly& sp );
|
||||||
|
double calc_tri_area( int_list& triangle_nodes );
|
||||||
|
|
||||||
|
// debug
|
||||||
|
bool IsDebugShape( unsigned int id );
|
||||||
|
bool IsDebugArea( unsigned int area );
|
||||||
|
|
||||||
|
void WriteDebugShape( const char* layer_name, const TGShape& shape );
|
||||||
|
void WriteDebugPoly( const char* layer_name, const char* name, const TGPolygon& poly );
|
||||||
|
void WriteDebugPolys( const char* layer_name, const poly_list& polys );
|
||||||
|
|
||||||
|
public:
|
||||||
|
// Constructor
|
||||||
|
TGConstruct();
|
||||||
|
|
||||||
|
// Destructor
|
||||||
|
~TGConstruct();
|
||||||
|
|
||||||
|
void set_bucket( SGBucket b ) { bucket = b; }
|
||||||
|
|
||||||
|
// New shared edge matching
|
||||||
|
void SaveToIntermediateFiles( int stage );
|
||||||
|
void LoadFromIntermediateFiles( int stage );
|
||||||
|
|
||||||
|
// Three stage construct
|
||||||
|
void ConstructBucketStage1();
|
||||||
|
void ConstructBucketStage2();
|
||||||
|
void ConstructBucketStage3();
|
||||||
|
|
||||||
|
int load_landcover ();
|
||||||
|
double measure_roughness( TGPolygon &poly );
|
||||||
|
AreaType get_landcover_type (const LandCover &cover, double xpos, double ypos, double dx, double dy);
|
||||||
|
void make_area( const LandCover &cover, TGPolygon *polys,
|
||||||
|
double x1, double y1, double x2, double y2,
|
||||||
|
double half_dx, double half_dy );
|
||||||
|
|
||||||
|
// land cover file
|
||||||
|
inline std::string get_cover () const { return cover; }
|
||||||
|
inline void set_cover (const std::string &s) { cover = s; }
|
||||||
|
|
||||||
|
// paths
|
||||||
|
void set_paths( const std::string work, const std::string share, const std::string output, const std::vector<std::string> load_dirs );
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
inline std::string get_work_base() const { return work_base; }
|
||||||
|
inline void set_work_base( const std::string s ) { work_base = s; }
|
||||||
|
inline std::string get_output_base() const { return output_base; }
|
||||||
|
inline void set_output_base( const std::string s ) { output_base = s; }
|
||||||
|
inline std::string get_share_base() const { return share_base; }
|
||||||
|
inline void set_share_base( const std::string s ) { share_base = s; }
|
||||||
|
inline void set_load_dirs( const std::vector<std::string> ld ) { load_dirs = ld; }
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void set_options( bool uk_grid, bool ignore_lm, double n );
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
// UK grid flag
|
||||||
|
inline bool get_useUKGrid() const { return useUKGrid; }
|
||||||
|
inline void set_useUKGrid( const bool b ) { useUKGrid = b; }
|
||||||
|
|
||||||
|
// Nudge
|
||||||
|
inline void set_nudge( double n ) { nudge = n; }
|
||||||
|
|
||||||
|
// ignore landmass flag
|
||||||
|
inline void set_ignore_landmass( const bool b) { ignoreLandmass = b; }
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// TODO : REMOVE
|
||||||
|
inline TGNodes* get_nodes() { return &nodes; }
|
||||||
|
|
||||||
|
// node list in geodetic coords (with fixed elevation)
|
||||||
|
inline point_list get_geod_nodes() const { return nodes.get_geod_nodes(); }
|
||||||
|
|
||||||
|
// normal list (for each point) in cart coords (for smooth
|
||||||
|
// shading)
|
||||||
|
inline point_list get_point_normals() const { return nodes.get_normals(); }
|
||||||
|
|
||||||
|
// Debug
|
||||||
|
void set_debug( std::string path, std::vector<std::string> area_defs, std::vector<std::string> shape_defs );
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // _CONSTRUCT_HXX
|
210
src/BuildTiles/Main/tgconstruct_cleanup.cxx
Normal file
210
src/BuildTiles/Main/tgconstruct_cleanup.cxx
Normal file
|
@ -0,0 +1,210 @@
|
||||||
|
// construct.cxx -- Class to manage the primary data used in the
|
||||||
|
// construction process
|
||||||
|
//
|
||||||
|
// Written by Curtis Olson, started May 1999.
|
||||||
|
//
|
||||||
|
// Copyright (C) 1999 Curtis L. Olson - http://www.flightgear.org/~curt
|
||||||
|
//
|
||||||
|
// This program is free software; you can redistribute it and/or
|
||||||
|
// modify it under the terms of the GNU General Public License as
|
||||||
|
// published by the Free Software Foundation; either version 2 of the
|
||||||
|
// License, or (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful, but
|
||||||
|
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
// General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
//
|
||||||
|
// $Id: construct.cxx,v 1.4 2004-11-19 22:25:49 curt Exp $
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
# include <config.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//#include <iostream>
|
||||||
|
|
||||||
|
//#include <simgear/compiler.h>
|
||||||
|
#include <simgear/debug/logstream.hxx>
|
||||||
|
|
||||||
|
#include <Geometry/poly_support.hxx>
|
||||||
|
#include <Geometry/poly_extra.hxx>
|
||||||
|
|
||||||
|
#include "tgconstruct.hxx"
|
||||||
|
|
||||||
|
using std::string;
|
||||||
|
|
||||||
|
void TGConstruct::FixTJunctions( void ) {
|
||||||
|
int before, after;
|
||||||
|
|
||||||
|
// traverse each poly, and add intermediate nodes
|
||||||
|
for ( unsigned int i = 0; i < TG_MAX_AREA_TYPES; ++i ) {
|
||||||
|
for( unsigned int j = 0; j < polys_clipped.area_size(i); ++j ) {
|
||||||
|
for( unsigned int k = 0; k < polys_clipped.shape_size(i, j); ++k ) {
|
||||||
|
TGPolygon current = polys_clipped.get_poly(i, j, k);
|
||||||
|
|
||||||
|
before = current.total_size();
|
||||||
|
current = add_tgnodes_to_poly( current, &nodes );
|
||||||
|
after = current.total_size();
|
||||||
|
|
||||||
|
if (before != after) {
|
||||||
|
SG_LOG( SG_CLIPPER, SG_INFO, "Fixed T-Junctions in " << get_area_name( (AreaType)i ) << ":" << j+1 << "-" << k << " of " << (int)polys_clipped.area_size(i) << " nodes increased from " << before << " to " << after );
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Save it back */
|
||||||
|
polys_clipped.set_poly( i, j, k, current );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Attempt to merge slivers into a list of polygons.
|
||||||
|
//
|
||||||
|
// For each sliver contour, see if a union with another polygon yields
|
||||||
|
// a polygon with no increased contours (i.e. the sliver is adjacent
|
||||||
|
// and can be merged.) If so, replace the clipped polygon with the
|
||||||
|
// new polygon that has the sliver merged in.
|
||||||
|
void TGConstruct::merge_slivers( TGLandclass& clipped, poly_list& slivers_list ) {
|
||||||
|
TGPolygon poly, result, slivers, sliver;
|
||||||
|
point_list contour;
|
||||||
|
int original_contours, result_contours;
|
||||||
|
bool done;
|
||||||
|
int area, shape, segment, i, j;
|
||||||
|
int merged = 0;
|
||||||
|
int total = 0;
|
||||||
|
|
||||||
|
for ( i = 0; i < (int)slivers_list.size(); i++ ) {
|
||||||
|
slivers = slivers_list[i];
|
||||||
|
|
||||||
|
for ( j = 0; j < slivers.contours(); ++j ) {
|
||||||
|
// make the sliver polygon
|
||||||
|
contour = slivers.get_contour( j );
|
||||||
|
total++;
|
||||||
|
|
||||||
|
sliver.erase();
|
||||||
|
sliver.add_contour( contour, 0 );
|
||||||
|
done = false;
|
||||||
|
|
||||||
|
for ( area = 0; area < TG_MAX_AREA_TYPES && !done; ++area ) {
|
||||||
|
if ( is_hole_area( area ) ) {
|
||||||
|
// don't merge a non-hole sliver in with a hole
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
for ( shape = 0; shape < (int)clipped.area_size(area) && !done; ++shape ) {
|
||||||
|
unsigned int shape_id = clipped.get_shape( area, shape ).id;
|
||||||
|
|
||||||
|
for ( segment = 0; segment < (int)clipped.shape_size(area, shape) && !done; ++segment ) {
|
||||||
|
|
||||||
|
poly = clipped.get_poly( area, shape, segment );
|
||||||
|
original_contours = poly.contours();
|
||||||
|
result = tgPolygonUnion( poly, sliver );
|
||||||
|
result_contours = result.contours();
|
||||||
|
|
||||||
|
if ( original_contours == result_contours ) {
|
||||||
|
SG_LOG(SG_GENERAL, SG_INFO, "MERGED SLIVER " << i << ", " << j << " into area " << get_area_name( (AreaType)area ) << " id: " << shape_id << " segment: " << segment );
|
||||||
|
|
||||||
|
clipped.set_poly( area, shape, segment, result );
|
||||||
|
merged++;
|
||||||
|
|
||||||
|
/* add the sliver to the clip_mask, too */
|
||||||
|
TGPolygon mask = clipped.get_mask( area, shape );
|
||||||
|
result = tgPolygonUnion( mask, sliver );
|
||||||
|
clipped.set_mask( area, shape, result );
|
||||||
|
|
||||||
|
if ( IsDebugShape( shape_id ) ) {
|
||||||
|
WriteDebugShape( "with_slivers", clipped.get_shape( area, shape ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
done = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
slivers_list.clear();
|
||||||
|
|
||||||
|
SG_LOG(SG_GENERAL, SG_INFO, " UNMERGED SLIVERS: " << total - merged );
|
||||||
|
}
|
||||||
|
|
||||||
|
void TGConstruct::CleanClippedPolys() {
|
||||||
|
|
||||||
|
// Clean the polys
|
||||||
|
for ( unsigned int area = 0; area < TG_MAX_AREA_TYPES; area++ ) {
|
||||||
|
for( unsigned int shape = 0; shape < polys_clipped.area_size(area); shape++ ) {
|
||||||
|
unsigned int id = polys_clipped.get_shape( area, shape ).id;
|
||||||
|
|
||||||
|
// step 1 : snap
|
||||||
|
for ( unsigned int segment = 0; segment < polys_clipped.shape_size(area, shape); segment++ ) {
|
||||||
|
TGPolygon poly = polys_clipped.get_poly(area, shape, segment);
|
||||||
|
poly = snap(poly, gSnap);
|
||||||
|
polys_clipped.set_poly( area, shape, segment, poly );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( IsDebugShape( id ) ) {
|
||||||
|
WriteDebugShape( "snapped", polys_clipped.get_shape( area, shape ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
// step 2 : remove_dups
|
||||||
|
for ( unsigned int segment = 0; segment < polys_clipped.shape_size(area, shape); segment++ ) {
|
||||||
|
TGPolygon poly = polys_clipped.get_poly(area, shape, segment);
|
||||||
|
poly = remove_dups( poly );
|
||||||
|
polys_clipped.set_poly( area, shape, segment, poly );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( IsDebugShape( id ) ) {
|
||||||
|
WriteDebugShape( "rem dupes", polys_clipped.get_shape( area, shape ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
// step 3 : remove_bad_contours
|
||||||
|
for ( unsigned int segment = 0; segment < polys_clipped.shape_size(area, shape); segment++ ) {
|
||||||
|
TGPolygon poly = polys_clipped.get_poly(area, shape, segment);
|
||||||
|
poly = remove_bad_contours( poly );
|
||||||
|
polys_clipped.set_poly( area, shape, segment, poly );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( IsDebugShape( id ) ) {
|
||||||
|
WriteDebugShape( "rem bad contours", polys_clipped.get_shape( area, shape ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
// todo - add up all segments in a shape for printout
|
||||||
|
#if 0
|
||||||
|
after = poly.total_size();
|
||||||
|
if (before != after) {
|
||||||
|
SG_LOG( SG_CLIPPER, SG_INFO, "Cleanined poly " << get_area_name( (AreaType)area ) <<
|
||||||
|
":" << shape+1 << "-" << segment << " of " << polys_clipped.area_size(area) << " before: " << before << " after: " << after );
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
328
src/BuildTiles/Main/tgconstruct_clip.cxx
Normal file
328
src/BuildTiles/Main/tgconstruct_clip.cxx
Normal file
|
@ -0,0 +1,328 @@
|
||||||
|
// tgconstruct_clip.cxx -- handle polygon clipping
|
||||||
|
//
|
||||||
|
// Written by Curtis Olson, started May 1999.
|
||||||
|
//
|
||||||
|
// Copyright (C) 1999 Curtis L. Olson - http://www.flightgear.org/~curt
|
||||||
|
//
|
||||||
|
// This program is free software; you can redistribute it and/or
|
||||||
|
// modify it under the terms of the GNU General Public License as
|
||||||
|
// published by the Free Software Foundation; either version 2 of the
|
||||||
|
// License, or (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful, but
|
||||||
|
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
// General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
//
|
||||||
|
// $Id: construct.cxx,v 1.4 2004-11-19 22:25:49 curt Exp $
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
# include <config.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <simgear/debug/logstream.hxx>
|
||||||
|
|
||||||
|
#include "tgconstruct.hxx"
|
||||||
|
|
||||||
|
using std::string;
|
||||||
|
|
||||||
|
bool TGConstruct::ClipLandclassPolys( void ) {
|
||||||
|
TGPolygon clipped, tmp;
|
||||||
|
TGPolygon remains;
|
||||||
|
TGPolygon safety_base;
|
||||||
|
poly_list slivers;
|
||||||
|
int i, j;
|
||||||
|
Point3D p;
|
||||||
|
point2d min, max;
|
||||||
|
|
||||||
|
#if !USE_ACCUMULATOR
|
||||||
|
TGPolygon accum;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Get clip bounds
|
||||||
|
min.x = bucket.get_center_lon() - 0.5 * bucket.get_width();
|
||||||
|
min.y = bucket.get_center_lat() - 0.5 * bucket.get_height();
|
||||||
|
max.x = bucket.get_center_lon() + 0.5 * bucket.get_width();
|
||||||
|
max.y = bucket.get_center_lat() + 0.5 * bucket.get_height();
|
||||||
|
|
||||||
|
#if USE_ACCUMULATOR
|
||||||
|
|
||||||
|
tgPolygonInitClipperAccumulator();
|
||||||
|
|
||||||
|
#else
|
||||||
|
accum.erase();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// set up clipping tile : and remember to add the nodes!
|
||||||
|
safety_base.erase();
|
||||||
|
|
||||||
|
p = Point3D(min.x, min.y, -9999.0);
|
||||||
|
safety_base.add_node( 0, p );
|
||||||
|
nodes.unique_add( p );
|
||||||
|
|
||||||
|
p = Point3D(max.x, min.y, -9999.0);
|
||||||
|
safety_base.add_node( 0, p );
|
||||||
|
nodes.unique_add( p );
|
||||||
|
|
||||||
|
p = Point3D(max.x, max.y, -9999.0);
|
||||||
|
safety_base.add_node( 0, p );
|
||||||
|
nodes.unique_add( p );
|
||||||
|
|
||||||
|
p = Point3D(min.x, max.y, -9999.0);
|
||||||
|
safety_base.add_node( 0, p );
|
||||||
|
nodes.unique_add( p );
|
||||||
|
|
||||||
|
// set up land mask, we clip most things to this since it is our
|
||||||
|
// best representation of land vs. ocean. If we have other less
|
||||||
|
// accurate data that spills out into the ocean, we want to just
|
||||||
|
// clip it.
|
||||||
|
// also set up a mask for all water and islands
|
||||||
|
TGPolygon land_mask, water_mask, island_mask;
|
||||||
|
land_mask.erase();
|
||||||
|
water_mask.erase();
|
||||||
|
island_mask.erase();
|
||||||
|
|
||||||
|
for ( i = 0; i < TG_MAX_AREA_TYPES; i++ ) {
|
||||||
|
if ( is_landmass_area( i ) && !ignoreLandmass ) {
|
||||||
|
for ( unsigned int j = 0; j < polys_in.area_size(i); ++j ) {
|
||||||
|
land_mask = tgPolygonUnion( polys_in.get_mask(i, j), land_mask );
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if ( is_water_area( i ) ) {
|
||||||
|
for (unsigned int j = 0; j < polys_in.area_size(i); j++) {
|
||||||
|
water_mask = tgPolygonUnion( polys_in.get_mask(i, j), water_mask );
|
||||||
|
}
|
||||||
|
} else if ( is_island_area( i ) ) {
|
||||||
|
for (unsigned int j = 0; j < polys_in.area_size(i); j++) {
|
||||||
|
island_mask = tgPolygonUnion( polys_in.get_mask(i, j), island_mask );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dump the masks
|
||||||
|
if ( debug_all || debug_shapes.size() ) {
|
||||||
|
WriteDebugPoly( "land_mask", "", land_mask );
|
||||||
|
WriteDebugPoly( "water_mask", "", water_mask );
|
||||||
|
WriteDebugPoly( "island_mask", "", island_mask );
|
||||||
|
}
|
||||||
|
|
||||||
|
// process polygons in priority order
|
||||||
|
for ( i = 0; i < TG_MAX_AREA_TYPES; ++i ) {
|
||||||
|
for( j = 0; j < (int)polys_in.area_size(i); ++j ) {
|
||||||
|
TGPolygon current = polys_in.get_mask(i, j);
|
||||||
|
TGPolygon before;
|
||||||
|
char layer_name[64];
|
||||||
|
|
||||||
|
SG_LOG( SG_CLIPPER, SG_INFO, "Clipping " << get_area_name( (AreaType)i ) << "(" << i << "):" << j+1 << " of " << polys_in.area_size(i) << " id " << polys_in.get_shape( i, j ).id );
|
||||||
|
|
||||||
|
tmp = current;
|
||||||
|
|
||||||
|
if ( IsDebugShape( polys_in.get_shape( i, j ).id ) ) {
|
||||||
|
char name[32];
|
||||||
|
sprintf(name, "shape %d,%d", i,j);
|
||||||
|
sprintf(layer_name, "premask_%d_%d_%d", i, j, polys_in.get_shape( i, j ).id);
|
||||||
|
WriteDebugPoly( layer_name, name, tmp );
|
||||||
|
|
||||||
|
//sprintf(name, "accum %d,%d", i,j);
|
||||||
|
//WriteDebugPoly( layer_name, name, accum );
|
||||||
|
}
|
||||||
|
|
||||||
|
// if not a hole, clip the area to the land_mask
|
||||||
|
if ( !ignoreLandmass && !is_hole_area( i ) ) {
|
||||||
|
before = tmp;
|
||||||
|
|
||||||
|
tmp = tgPolygonInt( tmp, land_mask );
|
||||||
|
|
||||||
|
if (tmp.total_size() != before.total_size()) {
|
||||||
|
SG_LOG( SG_CLIPPER, SG_INFO, "Clip w/land mask gave odd result" );
|
||||||
|
// exit(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// if a water area, cut out potential islands
|
||||||
|
if ( is_water_area( i ) ) {
|
||||||
|
// clip against island mask
|
||||||
|
tmp = tgPolygonDiff( tmp, island_mask );
|
||||||
|
|
||||||
|
if (tmp.total_size() != before.total_size()) {
|
||||||
|
SG_LOG( SG_CLIPPER, SG_INFO, "Clip w/island mask gave odd result" );
|
||||||
|
// exit(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( IsDebugShape( polys_in.get_shape( i, j ).id ) ) {
|
||||||
|
char name[32];
|
||||||
|
sprintf(name, "shape %d,%d", i,j);
|
||||||
|
sprintf(layer_name, "preclip_shape_%d_%d_%d", i, j, polys_in.get_shape( i, j ).id);
|
||||||
|
WriteDebugPoly( layer_name, name, tmp );
|
||||||
|
|
||||||
|
#if !USE_ACCUMULATOR
|
||||||
|
sprintf(name, "accum %d,%d", i,j);
|
||||||
|
sprintf(layer_name, "preclip_accum_%d_%d", i, j);
|
||||||
|
WriteDebugPoly( layer_name, name, accum );
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
// set debug for this clip
|
||||||
|
if ( (i == 14) && ( j == 0 ) ) {
|
||||||
|
sglog().setLogLevels( SG_ALL, SG_DEBUG );
|
||||||
|
}
|
||||||
|
|
||||||
|
#if USE_ACCUMULATOR
|
||||||
|
clipped = tgPolygonDiffClipperWithAccumulator( tmp );
|
||||||
|
#else
|
||||||
|
clipped = tgPolygonDiff( tmp, accum );
|
||||||
|
#endif
|
||||||
|
|
||||||
|
sglog().setLogLevels( SG_ALL, SG_INFO );
|
||||||
|
|
||||||
|
|
||||||
|
// only add to output list if the clip left us with a polygon
|
||||||
|
if ( clipped.contours() > 0 ) {
|
||||||
|
|
||||||
|
#if FIND_SLIVERS
|
||||||
|
// move slivers from clipped polygon to slivers polygon
|
||||||
|
tgPolygonFindSlivers( clipped, slivers );
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// add the sliverless result polygon to the clipped polys list
|
||||||
|
if ( clipped.contours() > 0 ) {
|
||||||
|
TGShape shape;
|
||||||
|
|
||||||
|
// copy all of the superpolys and texparams
|
||||||
|
shape.SetMask( clipped );
|
||||||
|
shape.textured = polys_in.get_textured( i, j );
|
||||||
|
shape.id = polys_in.get_shape( i, j ).id;
|
||||||
|
|
||||||
|
shape.area= polys_in.get_shape( i, j ).area;
|
||||||
|
shape.sps = polys_in.get_shape( i, j ).sps;
|
||||||
|
shape.tps = polys_in.get_shape( i, j ).tps;
|
||||||
|
|
||||||
|
// shape.sps.push_back( sp );
|
||||||
|
polys_clipped.add_shape( i, shape );
|
||||||
|
|
||||||
|
if ( IsDebugShape( shape.id ) ) {
|
||||||
|
WriteDebugShape( "clipped", shape );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#if USE_ACCUMULATOR
|
||||||
|
tgPolygonAddToClipperAccumulator( tmp, false );
|
||||||
|
#else
|
||||||
|
accum = tgPolygonUnion( tmp, accum );
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if ( IsDebugShape( polys_in.get_shape( i, j ).id ) ) {
|
||||||
|
char name[32];
|
||||||
|
sprintf(name, "shape %d,%d", i,j);
|
||||||
|
sprintf(layer_name, "postclip_shape_%d_%d_%d", i, j, polys_in.get_shape( i, j ).id );
|
||||||
|
WriteDebugPoly( layer_name, name, tmp );
|
||||||
|
|
||||||
|
#if !USE_ACCUMULATOR
|
||||||
|
sprintf(name, "accum %d,%d", i,j);
|
||||||
|
sprintf(layer_name, "postclip_accum_%d_%d", i, j);
|
||||||
|
WriteDebugPoly( layer_name, name, accum );
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( debug_all || debug_shapes.size() ) {
|
||||||
|
// Dump the sliver list
|
||||||
|
WriteDebugPolys( "poly_slivers", slivers );
|
||||||
|
}
|
||||||
|
|
||||||
|
#if FIND_SLIVERS
|
||||||
|
// Now, merge any slivers with clipped polys
|
||||||
|
merge_slivers(polys_clipped, slivers);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
slivers.clear();
|
||||||
|
|
||||||
|
// finally, what ever is left over goes to ocean
|
||||||
|
#if USE_ACCUMULATOR
|
||||||
|
remains = tgPolygonDiffClipperWithAccumulator( safety_base );
|
||||||
|
#else
|
||||||
|
remains = tgPolygonDiff( safety_base, accum );
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if ( remains.contours() > 0 ) {
|
||||||
|
// cout << "remains contours = " << remains.contours() << endl;
|
||||||
|
// move slivers from remains polygon to slivers polygon
|
||||||
|
|
||||||
|
#if FIND_SLIVERS
|
||||||
|
tgPolygonFindSlivers( remains, slivers );
|
||||||
|
#endif
|
||||||
|
// cout << " After sliver move:" << endl;
|
||||||
|
// cout << " remains = " << remains.contours() << endl;
|
||||||
|
// cout << " slivers = " << slivers.contours() << endl;
|
||||||
|
|
||||||
|
#if FIND_SLIVERS
|
||||||
|
// merge any slivers with previously clipped
|
||||||
|
// neighboring polygons
|
||||||
|
if ( slivers.size() > 0 ) {
|
||||||
|
|
||||||
|
if ( debug_all || debug_shapes.size() ) {
|
||||||
|
// Dump the sliver list
|
||||||
|
WriteDebugPolys( "remains_slivers", slivers );
|
||||||
|
}
|
||||||
|
|
||||||
|
merge_slivers(polys_clipped, slivers);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if ( remains.contours() > 0 ) {
|
||||||
|
TGSuperPoly sp;
|
||||||
|
TGShape shape;
|
||||||
|
|
||||||
|
string material = get_area_name(get_sliver_target_area_type());
|
||||||
|
|
||||||
|
sp.set_material( material );
|
||||||
|
sp.set_poly( remains );
|
||||||
|
shape.SetMask( remains );
|
||||||
|
shape.textured = false;
|
||||||
|
shape.sps.push_back( sp );
|
||||||
|
|
||||||
|
polys_clipped.add_shape( (int)get_sliver_target_area_type(), shape );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#if USE_ACCUMULATOR
|
||||||
|
|
||||||
|
tgPolygonFreeClipperAccumulator();
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Once clipping is complete, intersect the individual segments with their clip masks
|
||||||
|
for (unsigned int area = 0; area < TG_MAX_AREA_TYPES; area++) {
|
||||||
|
for (unsigned int shape = 0; shape < polys_clipped.area_size(area); shape++ ) {
|
||||||
|
SG_LOG( SG_CLIPPER, SG_INFO, "Seperating segments from clip mask for " << get_area_name( (AreaType)area ) << ":" << shape+1 << " of " << polys_clipped.area_size(area) );
|
||||||
|
polys_clipped.get_shape(area, shape).IntersectPolys();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now make sure any newly added intersection nodes are added to the tgnodes
|
||||||
|
for (unsigned int area = 0; area < TG_MAX_AREA_TYPES; area++) {
|
||||||
|
for (unsigned int shape = 0; shape < polys_clipped.area_size(area); shape++ ) {
|
||||||
|
for (unsigned int segment = 0; segment < polys_clipped.shape_size(area, shape); segment++) {
|
||||||
|
TGPolygon poly = polys_clipped.get_poly( area, shape, segment );
|
||||||
|
|
||||||
|
SG_LOG( SG_CLIPPER, SG_INFO, "Collecting nodes for " << get_area_name( (AreaType)area ) << ":" << shape+1 << "-" << segment << " of " << polys_clipped.area_size(area) );
|
||||||
|
|
||||||
|
for (int con=0; con < poly.contours(); con++) {
|
||||||
|
for (int node = 0; node < poly.contour_size( con ); node++) {
|
||||||
|
// ensure we have all nodes...
|
||||||
|
nodes.unique_add( poly.get_pt( con, node ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
206
src/BuildTiles/Main/tgconstruct_debug.cxx
Normal file
206
src/BuildTiles/Main/tgconstruct_debug.cxx
Normal file
|
@ -0,0 +1,206 @@
|
||||||
|
// tgconstruct_debug.cxx -- Class toimplement construct debug
|
||||||
|
//
|
||||||
|
// Written by Curtis Olson, started May 1999.
|
||||||
|
//
|
||||||
|
// Copyright (C) 1999 Curtis L. Olson - http://www.flightgear.org/~curt
|
||||||
|
//
|
||||||
|
// This program is free software; you can redistribute it and/or
|
||||||
|
// modify it under the terms of the GNU General Public License as
|
||||||
|
// published by the Free Software Foundation; either version 2 of the
|
||||||
|
// License, or (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful, but
|
||||||
|
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
// General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
//
|
||||||
|
// $Id: construct.cxx,v 1.4 2004-11-19 22:25:49 curt Exp $
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
# include <config.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
#include <simgear/debug/logstream.hxx>
|
||||||
|
#include <Geometry/poly_support.hxx>
|
||||||
|
|
||||||
|
#include "tgconstruct.hxx"
|
||||||
|
|
||||||
|
using std::string;
|
||||||
|
|
||||||
|
void TGConstruct::set_debug( std::string path, std::vector<string> area_defs, std::vector<string> shape_defs )
|
||||||
|
{
|
||||||
|
SG_LOG(SG_GENERAL, SG_ALERT, "Set debug Path " << path);
|
||||||
|
|
||||||
|
debug_path = path;
|
||||||
|
|
||||||
|
/* Find any ids for our tile */
|
||||||
|
for (unsigned int i=0; i< area_defs.size(); i++) {
|
||||||
|
string dsd = area_defs[i];
|
||||||
|
size_t d_pos = dsd.find(":");
|
||||||
|
string tile = dsd.substr(0, d_pos);
|
||||||
|
|
||||||
|
if( tile == bucket.gen_index_str() ) {
|
||||||
|
dsd.erase(0, d_pos+1);
|
||||||
|
|
||||||
|
if ( dsd == "all" ) {
|
||||||
|
debug_all = true;
|
||||||
|
} else {
|
||||||
|
std::stringstream ss(dsd);
|
||||||
|
int i;
|
||||||
|
|
||||||
|
while (ss >> i)
|
||||||
|
{
|
||||||
|
SG_LOG(SG_GENERAL, SG_ALERT, "Adding debug file " << i);
|
||||||
|
|
||||||
|
debug_areas.push_back(i);
|
||||||
|
|
||||||
|
if (ss.peek() == ',')
|
||||||
|
ss.ignore();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (unsigned int i=0; i< shape_defs.size(); i++) {
|
||||||
|
string dsd = shape_defs[i];
|
||||||
|
size_t d_pos = dsd.find(":");
|
||||||
|
string tile = dsd.substr(0, d_pos);
|
||||||
|
|
||||||
|
if( tile == bucket.gen_index_str() ) {
|
||||||
|
dsd.erase(0, d_pos+1);
|
||||||
|
|
||||||
|
if ( dsd == "all" ) {
|
||||||
|
debug_all = true;
|
||||||
|
} else {
|
||||||
|
std::stringstream ss(dsd);
|
||||||
|
int i;
|
||||||
|
|
||||||
|
while (ss >> i)
|
||||||
|
{
|
||||||
|
SG_LOG(SG_GENERAL, SG_ALERT, "Adding debug file " << i);
|
||||||
|
|
||||||
|
debug_shapes.push_back(i);
|
||||||
|
|
||||||
|
if (ss.peek() == ',')
|
||||||
|
ss.ignore();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TGConstruct::IsDebugShape( unsigned int id )
|
||||||
|
{
|
||||||
|
bool is_debug = false;
|
||||||
|
|
||||||
|
/* Check global flag */
|
||||||
|
if ( debug_all ) {
|
||||||
|
is_debug = true;
|
||||||
|
} else {
|
||||||
|
for (unsigned int i=0; i<debug_shapes.size(); i++) {
|
||||||
|
if ( debug_shapes[i] == id ) {
|
||||||
|
is_debug = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return is_debug;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TGConstruct::IsDebugArea( unsigned int area )
|
||||||
|
{
|
||||||
|
bool is_debug = false;
|
||||||
|
|
||||||
|
/* Check global flag */
|
||||||
|
if ( debug_all ) {
|
||||||
|
is_debug = true;
|
||||||
|
} else {
|
||||||
|
for (unsigned int i=0; i<debug_areas.size(); i++) {
|
||||||
|
if ( debug_areas[i] == area ) {
|
||||||
|
is_debug = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return is_debug;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TGConstruct::WriteDebugShape( const char* layer_name, const TGShape& shape )
|
||||||
|
{
|
||||||
|
char name[64];
|
||||||
|
shape.GetName( name );
|
||||||
|
|
||||||
|
ds_id = tgShapefileOpenDatasource( ds_name );
|
||||||
|
l_id = tgShapefileOpenLayer( ds_id, layer_name );
|
||||||
|
|
||||||
|
tgShapefileCreateFeature( ds_id, l_id, shape.clip_mask, name );
|
||||||
|
|
||||||
|
// close after each write
|
||||||
|
ds_id = tgShapefileCloseDatasource( ds_id );
|
||||||
|
}
|
||||||
|
|
||||||
|
void TGConstruct::WriteDebugPoly( const char* layer_name, const char* name, const TGPolygon& poly )
|
||||||
|
{
|
||||||
|
ds_id = tgShapefileOpenDatasource( ds_name );
|
||||||
|
l_id = tgShapefileOpenLayer( ds_id, layer_name );
|
||||||
|
|
||||||
|
tgShapefileCreateFeature( ds_id, l_id, poly, name );
|
||||||
|
|
||||||
|
// close after each write
|
||||||
|
ds_id = tgShapefileCloseDatasource( ds_id );
|
||||||
|
}
|
||||||
|
|
||||||
|
void TGConstruct::WriteDebugPolys( const char* layer_name, const poly_list& polys )
|
||||||
|
{
|
||||||
|
ds_id = tgShapefileOpenDatasource( ds_name );
|
||||||
|
l_id = tgShapefileOpenLayer( ds_id, layer_name );
|
||||||
|
|
||||||
|
for( unsigned int i=0; i<polys.size(); i++ ) {
|
||||||
|
sprintf( feature_name, "poly_%d", i );
|
||||||
|
tgShapefileCreateFeature( ds_id, l_id, polys[i], feature_name );
|
||||||
|
}
|
||||||
|
|
||||||
|
// close after each write
|
||||||
|
ds_id = tgShapefileCloseDatasource( ds_id );
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO : Add to TGNodes class
|
||||||
|
#if 0
|
||||||
|
|
||||||
|
bool TGNodesSortByLon( const TGNode& n1, const TGNode& n2 )
|
||||||
|
{
|
||||||
|
return ( n1.GetPosition().x() < n2.GetPosition().x() );
|
||||||
|
}
|
||||||
|
|
||||||
|
static void dump_lat_nodes( TGConstruct& c, double lat ) {
|
||||||
|
node_list all_nodes = c.get_nodes()->get_node_list();
|
||||||
|
node_list sorted_nodes;
|
||||||
|
for (unsigned int i=0; i<all_nodes.size(); i++) {
|
||||||
|
if ( fabs( all_nodes[i].GetPosition().y() - lat ) < 0.0000001 ) {
|
||||||
|
sorted_nodes.push_back( all_nodes[i] );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sort( sorted_nodes.begin(), sorted_nodes.end(), TGNodesSortByLon );
|
||||||
|
|
||||||
|
for (unsigned int i=0; i<sorted_nodes.size(); i++) {
|
||||||
|
string fixed;
|
||||||
|
|
||||||
|
if ( sorted_nodes[i].GetFixedPosition() ) {
|
||||||
|
fixed = " z is fixed elevation ";
|
||||||
|
} else {
|
||||||
|
fixed = " z is interpolated elevation ";
|
||||||
|
}
|
||||||
|
|
||||||
|
SG_LOG(SG_GENERAL, SG_ALERT, "Point[" << i << "] is " << sorted_nodes[i].GetPosition() << fixed );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
256
src/BuildTiles/Main/tgconstruct_elevation.cxx
Normal file
256
src/BuildTiles/Main/tgconstruct_elevation.cxx
Normal file
|
@ -0,0 +1,256 @@
|
||||||
|
// tgconstruct_elevation.cxx -- handle elevation functionality for tgconstruct
|
||||||
|
//
|
||||||
|
// Written by Curtis Olson, started May 1999.
|
||||||
|
//
|
||||||
|
// Copyright (C) 1999 Curtis L. Olson - http://www.flightgear.org/~curt
|
||||||
|
//
|
||||||
|
// This program is free software; you can redistribute it and/or
|
||||||
|
// modify it under the terms of the GNU General Public License as
|
||||||
|
// published by the Free Software Foundation; either version 2 of the
|
||||||
|
// License, or (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful, but
|
||||||
|
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
// General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
//
|
||||||
|
// $Id: construct.cxx,v 1.4 2004-11-19 22:25:49 curt Exp $
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
# include <config.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <simgear/debug/logstream.hxx>
|
||||||
|
|
||||||
|
#include "tgconstruct.hxx"
|
||||||
|
|
||||||
|
using std::string;
|
||||||
|
|
||||||
|
// Load elevation data from an Array file (a regular grid of elevation data)
|
||||||
|
// and return list of fitted nodes.
|
||||||
|
void TGConstruct::LoadElevationArray( void ) {
|
||||||
|
string base = bucket.gen_base_path();
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for ( i = 0; i < (int)load_dirs.size(); ++i ) {
|
||||||
|
string array_path = work_base + "/" + load_dirs[i] + "/" + base + "/" + bucket.gen_index_str();
|
||||||
|
|
||||||
|
if ( array.open(array_path) ) {
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
SG_LOG(SG_GENERAL, SG_DEBUG, "Failed to open Array file " << array_path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
array.parse( bucket );
|
||||||
|
array.remove_voids( );
|
||||||
|
|
||||||
|
point_list corner_list = array.get_corner_list();
|
||||||
|
for (unsigned int i=0; i<corner_list.size(); i++) {
|
||||||
|
nodes.unique_add(corner_list[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
point_list fit_list = array.get_fitted_list();
|
||||||
|
for (unsigned int i=0; i<fit_list.size(); i++) {
|
||||||
|
nodes.unique_add(fit_list[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void calc_gc_course_dist( const Point3D& start, const Point3D& dest,
|
||||||
|
double *course, double *dist ) {
|
||||||
|
SGGeoc gs = start.toSGGeoc();
|
||||||
|
SGGeoc gd = dest.toSGGeoc();
|
||||||
|
*course = SGGeoc::courseRad(gs, gd);
|
||||||
|
*dist = SGGeoc::distanceM(gs, gd);
|
||||||
|
}
|
||||||
|
|
||||||
|
// calculate spherical distance between two points (lon, lat specified
|
||||||
|
// in degrees, result returned in meters)
|
||||||
|
static double distanceSphere( const Point3D p1, const Point3D p2 ) {
|
||||||
|
Point3D r1( p1.x() * SG_DEGREES_TO_RADIANS,
|
||||||
|
p1.y() * SG_DEGREES_TO_RADIANS,
|
||||||
|
p1.z() );
|
||||||
|
Point3D r2( p2.x() * SG_DEGREES_TO_RADIANS,
|
||||||
|
p2.y() * SG_DEGREES_TO_RADIANS,
|
||||||
|
p2.z() );
|
||||||
|
|
||||||
|
double course, dist_m;
|
||||||
|
calc_gc_course_dist( r1, r2, &course, &dist_m );
|
||||||
|
|
||||||
|
return dist_m;
|
||||||
|
}
|
||||||
|
|
||||||
|
// fix the elevations of the geodetic nodes
|
||||||
|
// This should be done in the nodes class itself, except for the need for the triangle type
|
||||||
|
// hopefully, this will get better when we have the area lookup via superpoly...
|
||||||
|
void TGConstruct::CalcElevations( void )
|
||||||
|
{
|
||||||
|
TGPolyNodes tri_nodes;
|
||||||
|
double e1, e2, e3, min;
|
||||||
|
int n1, n2, n3;
|
||||||
|
Point3D p;
|
||||||
|
|
||||||
|
SG_LOG(SG_GENERAL, SG_ALERT, "fixing node heights");
|
||||||
|
|
||||||
|
for (int i = 0; i < (int)nodes.size(); ++i) {
|
||||||
|
TGNode node = nodes.get_node( i );
|
||||||
|
Point3D pos = node.GetPosition();
|
||||||
|
|
||||||
|
if ( !node.GetFixedPosition() ) {
|
||||||
|
// set elevation as interpolated point from DEM data.
|
||||||
|
nodes.SetElevation( i, array.altitude_from_grid(pos.x() * 3600.0, pos.y() * 3600.0) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// now flatten some stuff
|
||||||
|
for (unsigned int area = 0; area < TG_MAX_AREA_TYPES; area++) {
|
||||||
|
if ( is_lake_area( (AreaType)area ) ) {
|
||||||
|
for (int shape = 0; shape < (int)polys_clipped.area_size(area); ++shape ) {
|
||||||
|
for (int segment = 0; segment < (int)polys_clipped.shape_size(area, shape); ++segment ) {
|
||||||
|
|
||||||
|
SG_LOG( SG_CLIPPER, SG_INFO, "Flattening " << get_area_name( (AreaType)area ) << ":" << shape+1 << "-" << segment << " of " << (int)polys_clipped.area_size(area) );
|
||||||
|
tri_nodes = polys_clipped.get_tri_idxs( area, shape, segment );
|
||||||
|
|
||||||
|
for (int tri=0; tri < tri_nodes.contours(); tri++) {
|
||||||
|
if (tri_nodes.contour_size( tri ) != 3) {
|
||||||
|
SG_LOG(SG_GENERAL, SG_ALERT, "triangle doesnt have 3 nodes" << tri_nodes.contour_size( tri ) );
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
n1 = tri_nodes.get_pt( tri, 0 );
|
||||||
|
e1 = nodes.get_node(n1).GetPosition().z();
|
||||||
|
n2 = tri_nodes.get_pt( tri, 1 );
|
||||||
|
e2 = nodes.get_node(n2).GetPosition().z();
|
||||||
|
n3 = tri_nodes.get_pt( tri, 2 );
|
||||||
|
e3 = nodes.get_node(n3).GetPosition().z();
|
||||||
|
|
||||||
|
min = e1;
|
||||||
|
if ( e2 < min ) { min = e2; }
|
||||||
|
if ( e3 < min ) { min = e3; }
|
||||||
|
|
||||||
|
nodes.SetElevation( n1, min );
|
||||||
|
nodes.SetElevation( n2, min );
|
||||||
|
nodes.SetElevation( n3, min );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( is_stream_area( (AreaType)area ) ) {
|
||||||
|
for (int shape = 0; shape < (int)polys_clipped.area_size(area); ++shape ) {
|
||||||
|
for (int segment = 0; segment < (int)polys_clipped.shape_size(area, shape); ++segment ) {
|
||||||
|
|
||||||
|
SG_LOG( SG_CLIPPER, SG_INFO, "Flattening " << get_area_name( (AreaType)area ) << ":" << shape+1 << "-" << segment << " of " << (int)polys_clipped.area_size(area) );
|
||||||
|
tri_nodes = polys_clipped.get_tri_idxs( area, shape, segment );
|
||||||
|
|
||||||
|
for (int tri=0; tri < tri_nodes.contours(); tri++) {
|
||||||
|
if (tri_nodes.contour_size( tri ) != 3) {
|
||||||
|
SG_LOG(SG_GENERAL, SG_ALERT, "triangle doesnt have 3 nodes" << tri_nodes.contour_size( tri ) );
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
point_list raw_nodes = nodes.get_geod_nodes();
|
||||||
|
|
||||||
|
n1 = tri_nodes.get_pt( tri, 0 );
|
||||||
|
e1 = nodes.get_node(n1).GetPosition().z();
|
||||||
|
n2 = tri_nodes.get_pt( tri, 1 );
|
||||||
|
e2 = nodes.get_node(n2).GetPosition().z();
|
||||||
|
n3 = tri_nodes.get_pt( tri, 2 );
|
||||||
|
e3 = nodes.get_node(n3).GetPosition().z();
|
||||||
|
|
||||||
|
min = e1;
|
||||||
|
p = raw_nodes[n1];
|
||||||
|
|
||||||
|
if ( e2 < min ) { min = e2; p = raw_nodes[n2]; }
|
||||||
|
if ( e3 < min ) { min = e3; p = raw_nodes[n3]; }
|
||||||
|
|
||||||
|
double d1 = 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 ) { nodes.SetElevation( n1, max1 ); }
|
||||||
|
if ( max2 < e2 ) { nodes.SetElevation( n2, max2 ); }
|
||||||
|
if ( max3 < e3 ) { nodes.SetElevation( n3, max3 ); }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( is_road_area( (AreaType)area ) ) {
|
||||||
|
for (int shape = 0; shape < (int)polys_clipped.area_size(area); ++shape ) {
|
||||||
|
for (int segment = 0; segment < (int)polys_clipped.shape_size(area, shape); ++segment ) {
|
||||||
|
|
||||||
|
SG_LOG( SG_CLIPPER, SG_INFO, "Flattening " << get_area_name( (AreaType)area ) << ":" << shape+1 << "-" << segment << " of " << (int)polys_clipped.area_size(area) );
|
||||||
|
tri_nodes = polys_clipped.get_tri_idxs( area, shape, segment );
|
||||||
|
|
||||||
|
for (int tri=0; tri < tri_nodes.contours(); tri++) {
|
||||||
|
if (tri_nodes.contour_size( tri ) != 3) {
|
||||||
|
SG_LOG(SG_GENERAL, SG_ALERT, "triangle doesnt have 3 nodes" << tri_nodes.contour_size( tri ) );
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
point_list raw_nodes = nodes.get_geod_nodes();
|
||||||
|
|
||||||
|
n1 = tri_nodes.get_pt( tri, 0 );
|
||||||
|
e1 = nodes.get_node(n1).GetPosition().z();
|
||||||
|
n2 = tri_nodes.get_pt( tri, 1 );
|
||||||
|
e2 = nodes.get_node(n2).GetPosition().z();
|
||||||
|
n3 = tri_nodes.get_pt( tri, 2 );
|
||||||
|
e3 = nodes.get_node(n3).GetPosition().z();
|
||||||
|
|
||||||
|
min = e1;
|
||||||
|
p = raw_nodes[n1];
|
||||||
|
|
||||||
|
if ( e2 < min ) { min = e2; p = raw_nodes[n2]; }
|
||||||
|
if ( e3 < min ) { min = e3; p = raw_nodes[n3]; }
|
||||||
|
|
||||||
|
double d1 = 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 ) { nodes.SetElevation( n1, max1 ); }
|
||||||
|
if ( max2 < e2 ) { nodes.SetElevation( n2, max2 ); }
|
||||||
|
if ( max3 < e3 ) { nodes.SetElevation( n3, max3 ); }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( is_ocean_area( (AreaType)area ) ) {
|
||||||
|
for (int shape = 0; shape < (int)polys_clipped.area_size(area); ++shape ) {
|
||||||
|
for (int segment = 0; segment < (int)polys_clipped.shape_size(area, shape); ++segment ) {
|
||||||
|
|
||||||
|
SG_LOG( SG_CLIPPER, SG_INFO, "Flattening " << get_area_name( (AreaType)area ) << ":" << shape+1 << "-" << segment << " of " << (int)polys_clipped.area_size(area) );
|
||||||
|
tri_nodes = polys_clipped.get_tri_idxs( area, shape, segment );
|
||||||
|
|
||||||
|
for (int tri=0; tri < tri_nodes.contours(); tri++) {
|
||||||
|
if (tri_nodes.contour_size( tri ) != 3) {
|
||||||
|
SG_LOG(SG_GENERAL, SG_ALERT, "triangle doesnt have 3 nodes" << tri_nodes.contour_size( tri ) );
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
n1 = tri_nodes.get_pt( tri, 0 );
|
||||||
|
n2 = tri_nodes.get_pt( tri, 1 );
|
||||||
|
n3 = tri_nodes.get_pt( tri, 2 );
|
||||||
|
|
||||||
|
nodes.SetElevation( n1, 0.0 );
|
||||||
|
nodes.SetElevation( n2, 0.0 );
|
||||||
|
nodes.SetElevation( n3, 0.0 );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
215
src/BuildTiles/Main/tgconstruct_landclass.cxx
Normal file
215
src/BuildTiles/Main/tgconstruct_landclass.cxx
Normal file
|
@ -0,0 +1,215 @@
|
||||||
|
// construct.cxx -- Class to manage the primary data used in the
|
||||||
|
// construction process
|
||||||
|
//
|
||||||
|
// Written by Curtis Olson, started May 1999.
|
||||||
|
//
|
||||||
|
// Copyright (C) 1999 Curtis L. Olson - http://www.flightgear.org/~curt
|
||||||
|
//
|
||||||
|
// This program is free software; you can redistribute it and/or
|
||||||
|
// modify it under the terms of the GNU General Public License as
|
||||||
|
// published by the Free Software Foundation; either version 2 of the
|
||||||
|
// License, or (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful, but
|
||||||
|
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
// General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
//
|
||||||
|
// $Id: construct.cxx,v 1.4 2004-11-19 22:25:49 curt Exp $
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
# include <config.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <simgear/debug/logstream.hxx>
|
||||||
|
|
||||||
|
#include "tgconstruct.hxx"
|
||||||
|
#include "usgs.hxx"
|
||||||
|
|
||||||
|
using std::string;
|
||||||
|
|
||||||
|
// If we don't offset land use squares by some amount, then we can get
|
||||||
|
// land use square boundaries coinciding with tile boundaries.
|
||||||
|
//
|
||||||
|
// This can foul up our edge matching scheme because a subsequently
|
||||||
|
// generated adjacent tile might be forced to have edge nodes not
|
||||||
|
// found in the first tile and not on the shared edge. This can lead
|
||||||
|
// to gaps. If we put skirts around everything that might hide the
|
||||||
|
// problem.
|
||||||
|
static const double cover_size = 1.0 / 120.0;
|
||||||
|
static const double half_cover_size = cover_size * 0.5;
|
||||||
|
static const double quarter_cover_size = cover_size * 0.25;
|
||||||
|
|
||||||
|
// make the area specified area, look up the land cover type, and add
|
||||||
|
// it to polys
|
||||||
|
void TGConstruct::make_area( const LandCover &cover, TGPolygon *polys,
|
||||||
|
double x1, double y1, double x2, double y2,
|
||||||
|
double half_dx, double half_dy )
|
||||||
|
{
|
||||||
|
const double fudge = 0.0001; // (0.0001 degrees =~ 10 meters)
|
||||||
|
|
||||||
|
AreaType area = get_landcover_type( cover,
|
||||||
|
x1 + half_dx, y1 + half_dy,
|
||||||
|
x2 - x1, y2 - y1 );
|
||||||
|
|
||||||
|
if ( area != get_default_area_type() ) {
|
||||||
|
// Create a square polygon and merge it into the list.
|
||||||
|
TGPolygon poly;
|
||||||
|
poly.erase();
|
||||||
|
poly.add_node(0, Point3D(x1 - fudge, y1 - fudge, 0.0));
|
||||||
|
poly.add_node(0, Point3D(x1 - fudge, y2 + fudge, 0.0));
|
||||||
|
poly.add_node(0, Point3D(x2 + fudge, y2 + fudge, 0.0));
|
||||||
|
poly.add_node(0, Point3D(x2 + fudge, y1 - fudge, 0.0));
|
||||||
|
|
||||||
|
if ( measure_roughness( poly ) < 1.0 ) {
|
||||||
|
// Add this poly to the area accumulator
|
||||||
|
if ( polys[area].contours() > 0 ) {
|
||||||
|
polys[area] = tgPolygonUnion( polys[area], poly );
|
||||||
|
} else {
|
||||||
|
polys[area] = poly;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Come up with a "rough" metric for the roughness of the terrain
|
||||||
|
// coverted by a polygon
|
||||||
|
double TGConstruct::measure_roughness( TGPolygon &poly ) {
|
||||||
|
int i;
|
||||||
|
unsigned int j;
|
||||||
|
|
||||||
|
// find the elevation range
|
||||||
|
double max_z = -9999.0;
|
||||||
|
double min_z = 9999.0;
|
||||||
|
|
||||||
|
for ( i = 0; i < poly.contours(); ++i ) {
|
||||||
|
point_list points = poly.get_contour( i );
|
||||||
|
for ( j = 0; j < points.size(); ++j ) {
|
||||||
|
double z;
|
||||||
|
z = array.altitude_from_grid( points[j].x() * 3600.0,
|
||||||
|
points[j].y() * 3600.0 );
|
||||||
|
if ( z < -9000 ) {
|
||||||
|
z = array.closest_nonvoid_elev( points[j].x() * 3600.0,
|
||||||
|
points[j].y() * 3600.0 );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( z < min_z ) {
|
||||||
|
min_z = z;
|
||||||
|
}
|
||||||
|
if ( z > max_z ) {
|
||||||
|
max_z = z;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
double diff = max_z - min_z;
|
||||||
|
|
||||||
|
// 50m difference in polygon elevation range yields a roughness
|
||||||
|
// metric of 1.0. Less than 1.0 is relatively flat. More than
|
||||||
|
// 1.0 is relatively rough.
|
||||||
|
|
||||||
|
SG_LOG(SG_GENERAL, SG_ALERT, "roughness = " << diff / 50.0 );
|
||||||
|
|
||||||
|
return diff / 50.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
AreaType TGConstruct::get_landcover_type (const LandCover &cover, double xpos, double ypos, double dx, double dy)
|
||||||
|
{
|
||||||
|
// Look up the land cover for the square
|
||||||
|
int cover_value = cover.getValue(xpos, ypos);
|
||||||
|
AreaType area = translateUSGSCover(cover_value);
|
||||||
|
|
||||||
|
if ( area != get_default_area_type() ) {
|
||||||
|
// Non-default area is fine.
|
||||||
|
return area;
|
||||||
|
} else {
|
||||||
|
// If we're stuck with the default area, try to borrow from a
|
||||||
|
// neighbour.
|
||||||
|
for (double x = xpos - dx; x <= xpos + dx; x += dx) {
|
||||||
|
for (double y = ypos - dy; y < ypos + dx; y += dy) {
|
||||||
|
if (x != xpos || y != ypos) {
|
||||||
|
cover_value = cover.getValue(x, y);
|
||||||
|
area = translateUSGSCover(cover_value);
|
||||||
|
if (area != get_default_area_type() ) {
|
||||||
|
return area;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// OK, give up and return default
|
||||||
|
return get_default_area_type();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Generate polygons from land-cover raster. Horizontally- or
|
||||||
|
// vertically-adjacent polygons will be merged automatically.
|
||||||
|
int TGConstruct::load_landcover()
|
||||||
|
{
|
||||||
|
int count = 0;
|
||||||
|
|
||||||
|
try {
|
||||||
|
|
||||||
|
LandCover cover(get_cover());
|
||||||
|
TGPolygon polys[TG_MAX_AREA_TYPES];
|
||||||
|
TGPolygon poly; // working polygon
|
||||||
|
|
||||||
|
// Get the lower left (SW) corner of the tile
|
||||||
|
double base_lon = bucket.get_center_lon()
|
||||||
|
- 0.5 * bucket.get_width()
|
||||||
|
- quarter_cover_size;
|
||||||
|
double base_lat = bucket.get_center_lat()
|
||||||
|
- 0.5 * bucket.get_height()
|
||||||
|
- quarter_cover_size;
|
||||||
|
|
||||||
|
SG_LOG(SG_GENERAL, SG_ALERT, "raster land cover: tile at " << base_lon << ',' << base_lat);
|
||||||
|
|
||||||
|
double max_lon = bucket.get_center_lon()
|
||||||
|
+ 0.5 * bucket.get_width();
|
||||||
|
double max_lat = bucket.get_center_lat()
|
||||||
|
+ 0.5 * bucket.get_height();
|
||||||
|
|
||||||
|
SG_LOG(SG_GENERAL, SG_ALERT, "raster land cover: extends to " << max_lon << ',' << max_lat);
|
||||||
|
|
||||||
|
double x1 = base_lon;
|
||||||
|
double y1 = base_lat;
|
||||||
|
double x2 = x1 + cover_size;
|
||||||
|
double y2 = y1 + cover_size;
|
||||||
|
|
||||||
|
while ( x1 < max_lon ) {
|
||||||
|
while ( y1 < max_lat ) {
|
||||||
|
make_area( cover, polys, x1, y1, x2, y2, half_cover_size, half_cover_size );
|
||||||
|
|
||||||
|
y1 = y2;
|
||||||
|
y2 += cover_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
x1 = x2;
|
||||||
|
x2 += cover_size;
|
||||||
|
y1 = base_lat;
|
||||||
|
y2 = y1 + cover_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now that we're finished looking up land cover, we have a list
|
||||||
|
// of lists of polygons, one (possibly-empty) list for each area
|
||||||
|
// type. Add the remaining polygons to the clipper.
|
||||||
|
for ( int i = 0; i < TG_MAX_AREA_TYPES; i++ ) {
|
||||||
|
if ( polys[i].contours() ) {
|
||||||
|
// TODO : REMOVE add_poly
|
||||||
|
add_poly( i, polys[i], get_area_name((AreaType)i ));
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch ( string e ) {
|
||||||
|
SG_LOG(SG_GENERAL, SG_ALERT, "Died with exception: " << e);
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return the number of polygons actually read.
|
||||||
|
return count;
|
||||||
|
}
|
82
src/BuildTiles/Main/tgconstruct_lookup.cxx
Normal file
82
src/BuildTiles/Main/tgconstruct_lookup.cxx
Normal file
|
@ -0,0 +1,82 @@
|
||||||
|
// tgconstruct_lookup.cxx -- Lookup function to store precomputed pointers
|
||||||
|
// greatly optimize certain stages
|
||||||
|
//
|
||||||
|
// Written by Curtis Olson, started May 1999.
|
||||||
|
//
|
||||||
|
// Copyright (C) 1999 Curtis L. Olson - http://www.flightgear.org/~curt
|
||||||
|
//
|
||||||
|
// This program is free software; you can redistribute it and/or
|
||||||
|
// modify it under the terms of the GNU General Public License as
|
||||||
|
// published by the Free Software Foundation; either version 2 of the
|
||||||
|
// License, or (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful, but
|
||||||
|
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
// General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
//
|
||||||
|
// $Id: construct.cxx,v 1.4 2004-11-19 22:25:49 curt Exp $
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
# include <config.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <simgear/debug/logstream.hxx>
|
||||||
|
|
||||||
|
#include "tgconstruct.hxx"
|
||||||
|
|
||||||
|
// This function populates the Superpoly tri_idx polygon.
|
||||||
|
// This polygon is a mirror of tris, except the verticies are
|
||||||
|
// indexes into the node array (cast as unsigned long)
|
||||||
|
void TGConstruct::LookupNodesPerVertex( void )
|
||||||
|
{
|
||||||
|
SG_LOG(SG_GENERAL, SG_ALERT, "LookupNodexPerVertex");
|
||||||
|
|
||||||
|
// for each node, traverse all the triangles - and create face lists
|
||||||
|
for ( unsigned int area = 0; area < TG_MAX_AREA_TYPES; area++ ) {
|
||||||
|
for( unsigned int shape = 0; shape < polys_clipped.area_size(area); shape++ ) {
|
||||||
|
for ( unsigned int segment = 0; segment < polys_clipped.shape_size(area, shape); segment++ ) {
|
||||||
|
TGPolygon tris = polys_clipped.get_tris( area, shape, segment );
|
||||||
|
TGPolyNodes tri_nodes;
|
||||||
|
int idx;
|
||||||
|
|
||||||
|
for (int tri=0; tri < tris.contours(); tri++) {
|
||||||
|
for (int vertex = 0; vertex < tris.contour_size(tri); vertex++) {
|
||||||
|
idx = nodes.find( tris.get_pt( tri, vertex ) );
|
||||||
|
if (idx >= 0) {
|
||||||
|
tri_nodes.add_node( tri, idx );
|
||||||
|
} else {
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
polys_clipped.set_tri_idxs(area, shape, segment, tri_nodes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TGConstruct::LookupFacesPerNode( void )
|
||||||
|
{
|
||||||
|
SG_LOG(SG_GENERAL, SG_ALERT, "LookupFacesPerNode");
|
||||||
|
|
||||||
|
// Add each face that includes a node to the node's face list
|
||||||
|
for ( unsigned int area = 0; area < TG_MAX_AREA_TYPES; area++ ) {
|
||||||
|
for( unsigned int shape = 0; shape < polys_clipped.area_size(area); shape++ ) {
|
||||||
|
for ( unsigned int segment = 0; segment < polys_clipped.shape_size(area, shape); segment++ ) {
|
||||||
|
TGPolygon tris = polys_clipped.get_tris(area, shape, segment);
|
||||||
|
|
||||||
|
for (int tri=0; tri < tris.contours(); tri++) {
|
||||||
|
for (int sub = 0; sub < tris.contour_size(tri); sub++) {
|
||||||
|
int n = nodes.find( tris.get_pt( tri, sub ) );
|
||||||
|
nodes.AddFace( n, area, shape, segment, tri );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
190
src/BuildTiles/Main/tgconstruct_math.cxx
Normal file
190
src/BuildTiles/Main/tgconstruct_math.cxx
Normal file
|
@ -0,0 +1,190 @@
|
||||||
|
// tgconstruct_math.cxx -- Implement needed math functions
|
||||||
|
//
|
||||||
|
// Written by Curtis Olson, started May 1999.
|
||||||
|
//
|
||||||
|
// Copyright (C) 1999 Curtis L. Olson - http://www.flightgear.org/~curt
|
||||||
|
//
|
||||||
|
// This program is free software; you can redistribute it and/or
|
||||||
|
// modify it under the terms of the GNU General Public License as
|
||||||
|
// published by the Free Software Foundation; either version 2 of the
|
||||||
|
// License, or (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful, but
|
||||||
|
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
// General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
//
|
||||||
|
// $Id: construct.cxx,v 1.4 2004-11-19 22:25:49 curt Exp $
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
# include <config.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <simgear/debug/logstream.hxx>
|
||||||
|
#include <Geometry/poly_support.hxx>
|
||||||
|
|
||||||
|
#include "tgconstruct.hxx"
|
||||||
|
|
||||||
|
//using std::string;
|
||||||
|
|
||||||
|
double TGConstruct::calc_tri_area( int_list& triangle_nodes ) {
|
||||||
|
Point3D p1 = nodes.get_node( triangle_nodes[0] ).GetPosition();
|
||||||
|
Point3D p2 = nodes.get_node( triangle_nodes[1] ).GetPosition();
|
||||||
|
Point3D p3 = nodes.get_node( triangle_nodes[2] ).GetPosition();
|
||||||
|
|
||||||
|
return triangle_area( p1, p2, p3 );
|
||||||
|
}
|
||||||
|
|
||||||
|
SGVec3d TGConstruct::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 normal;
|
||||||
|
TGPolyNodes tri_nodes = sp.get_tri_idxs();
|
||||||
|
int_list face_nodes;
|
||||||
|
double_list face_areas;
|
||||||
|
point_list face_normals;
|
||||||
|
double area;
|
||||||
|
|
||||||
|
face_normals.clear();
|
||||||
|
face_areas.clear();
|
||||||
|
|
||||||
|
for (int i=0; i<tri_nodes.contours(); i++) {
|
||||||
|
face_nodes = tri_nodes.get_contour(i);
|
||||||
|
|
||||||
|
Point3D p1 = wgs84_nodes[ face_nodes[0] ];
|
||||||
|
Point3D p2 = wgs84_nodes[ face_nodes[1] ];
|
||||||
|
Point3D p3 = wgs84_nodes[ face_nodes[2] ];
|
||||||
|
|
||||||
|
area = calc_tri_area( face_nodes );
|
||||||
|
|
||||||
|
normal = calc_normal( area, p1, p2, p3 );
|
||||||
|
|
||||||
|
face_normals.push_back( Point3D::fromSGVec3( normal ) );
|
||||||
|
face_areas.push_back( area );
|
||||||
|
}
|
||||||
|
|
||||||
|
sp.set_face_normals( face_normals );
|
||||||
|
sp.set_face_areas( face_areas );
|
||||||
|
}
|
||||||
|
|
||||||
|
void TGConstruct::CalcFaceNormals( void )
|
||||||
|
{
|
||||||
|
// traverse the superpols, and calc normals for each tri within
|
||||||
|
point_list wgs84_nodes = nodes.get_wgs84_nodes_as_Point3d();
|
||||||
|
|
||||||
|
for (unsigned int area = 0; area < TG_MAX_AREA_TYPES; area++) {
|
||||||
|
for (unsigned int shape = 0; shape < polys_clipped.area_size(area); shape++ ) {
|
||||||
|
for ( unsigned int segment = 0; segment < polys_clipped.shape_size(area, shape); segment++ ) {
|
||||||
|
SG_LOG( SG_CLIPPER, SG_INFO, "Calculating face normals for " << get_area_name( (AreaType)area ) << ":" << shape+1 << "-" << segment << " of " << polys_in.area_size(area) );
|
||||||
|
calc_normals( wgs84_nodes, polys_clipped.get_superpoly( area, shape, segment ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TGConstruct::CalcPointNormals( void )
|
||||||
|
{
|
||||||
|
// traverse triangle structure building the face normal table
|
||||||
|
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 one_percent = nodes.size() / 100;
|
||||||
|
unsigned int cur_percent = 1;
|
||||||
|
|
||||||
|
for ( unsigned int i = 0; i<nodes.size(); i++ ) {
|
||||||
|
TGNode node = nodes.get_node( i );
|
||||||
|
TGFaceList faces = node.GetFaces();
|
||||||
|
TGNeighborFaces* neighbor_faces = NULL;
|
||||||
|
double total_area = 0.0;
|
||||||
|
|
||||||
|
Point3D average( 0.0 );
|
||||||
|
|
||||||
|
if ( i == one_percent ) {
|
||||||
|
SG_LOG(SG_GENERAL, SG_ALERT, "Calculating point normals: " << cur_percent << "%" );
|
||||||
|
one_percent += nodes.size() / 100;
|
||||||
|
cur_percent += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// for each triangle that shares this node
|
||||||
|
for ( unsigned int j = 0; j < faces.size(); ++j ) {
|
||||||
|
unsigned int at = faces[j].area;
|
||||||
|
unsigned int shape = faces[j].shape;
|
||||||
|
unsigned int segment = faces[j].seg;
|
||||||
|
unsigned int tri = faces[j].tri;
|
||||||
|
int_list face_nodes;
|
||||||
|
|
||||||
|
normal = polys_clipped.get_face_normal( at, shape, segment, tri );
|
||||||
|
face_nodes = polys_clipped.get_tri_idxs( at, shape, segment ).get_contour( tri ) ;
|
||||||
|
face_area = polys_clipped.get_face_area( at, shape, segment, tri );
|
||||||
|
|
||||||
|
normal *= face_area; // scale normal weight relative to area
|
||||||
|
total_area += face_area;
|
||||||
|
average += normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if this node exists in the shared edge db, add the faces from the neighbooring tile
|
||||||
|
neighbor_faces = FindNeighborFaces( node.GetPosition() );
|
||||||
|
if ( neighbor_faces ) {
|
||||||
|
int num_faces = neighbor_faces->face_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 );
|
||||||
|
}
|
||||||
|
}
|
252
src/BuildTiles/Main/tgconstruct_output.cxx
Normal file
252
src/BuildTiles/Main/tgconstruct_output.cxx
Normal file
|
@ -0,0 +1,252 @@
|
||||||
|
// tgconstruct_output.cxx --Handle writing out the btg and stg files
|
||||||
|
//
|
||||||
|
// Written by Curtis Olson, started May 1999.
|
||||||
|
//
|
||||||
|
// Copyright (C) 1999 Curtis L. Olson - http://www.flightgear.org/~curt
|
||||||
|
//
|
||||||
|
// This program is free software; you can redistribute it and/or
|
||||||
|
// modify it under the terms of the GNU General Public License as
|
||||||
|
// published by the Free Software Foundation; either version 2 of the
|
||||||
|
// License, or (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful, but
|
||||||
|
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
// General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
//
|
||||||
|
// $Id: construct.cxx,v 1.4 2004-11-19 22:25:49 curt Exp $
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
# include <config.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <simgear/math/SGGeometry.hxx>
|
||||||
|
#include <simgear/misc/sg_dir.hxx>
|
||||||
|
#include <simgear/io/sg_binobj.hxx>
|
||||||
|
#include <simgear/structure/exception.hxx>
|
||||||
|
#include <simgear/debug/logstream.hxx>
|
||||||
|
#include <Geometry/trinodes.hxx>
|
||||||
|
|
||||||
|
#include "tgconstruct.hxx"
|
||||||
|
|
||||||
|
using std::string;
|
||||||
|
|
||||||
|
// collect custom objects and move to scenery area
|
||||||
|
void TGConstruct::AddCustomObjects( void ) {
|
||||||
|
// Create/open the output .stg file for writing
|
||||||
|
SGPath dest_d(output_base.c_str());
|
||||||
|
dest_d.append(bucket.gen_base_path().c_str());
|
||||||
|
string dest_dir = dest_d.str_native();
|
||||||
|
SGPath dest_i(dest_d);
|
||||||
|
dest_i.append(bucket.gen_index_str());
|
||||||
|
dest_i.concat(".stg");
|
||||||
|
string dest_ind = dest_i.str_native();
|
||||||
|
|
||||||
|
FILE *fp;
|
||||||
|
if ( (fp = fopen( dest_ind.c_str(), "w" )) == NULL ) {
|
||||||
|
SG_LOG( SG_GENERAL, SG_ALERT, "ERROR: opening " << dest_ind << " for writing!" );
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start with the default custom object which is the base terrain
|
||||||
|
fprintf(fp, "OBJECT_BASE %s.btg\n", bucket.gen_index_str().c_str());
|
||||||
|
|
||||||
|
char line[2048]; // big enough?
|
||||||
|
char token[256];
|
||||||
|
char name[256];
|
||||||
|
|
||||||
|
for ( int i = 0; i < (int)load_dirs.size(); ++i ) {
|
||||||
|
SGPath base(work_base.c_str());
|
||||||
|
base.append(load_dirs[i]);
|
||||||
|
base.append( bucket.gen_base_path() );
|
||||||
|
SGPath index(base);
|
||||||
|
index.append( bucket.gen_index_str() );
|
||||||
|
index.concat(".ind");
|
||||||
|
string index_file = index.str_native();
|
||||||
|
|
||||||
|
sg_gzifstream in( index_file );
|
||||||
|
|
||||||
|
if ( ! in.is_open() ) {
|
||||||
|
//No custom objects
|
||||||
|
} else {
|
||||||
|
while ( ! in.eof() ) {
|
||||||
|
SG_LOG( SG_GENERAL, SG_INFO, "Collecting custom objects from " << index_file );
|
||||||
|
in.getline(line, 2048);
|
||||||
|
SG_LOG( SG_GENERAL, SG_INFO, "line = " << line );
|
||||||
|
|
||||||
|
int result = sscanf( line, "%s %s", token, name );
|
||||||
|
SG_LOG( SG_GENERAL, SG_INFO, "scanf scanned " << result << " tokens" );
|
||||||
|
|
||||||
|
if ( result > 0 ) {
|
||||||
|
SG_LOG( SG_GENERAL, SG_INFO, "token = " << token << " name = " << name );
|
||||||
|
|
||||||
|
if ( strcmp( token, "OBJECT" ) == 0 ) {
|
||||||
|
SGPath srcbase(base);
|
||||||
|
srcbase.append(name);
|
||||||
|
srcbase.concat(".gz");
|
||||||
|
string basecom = srcbase.str_native();
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
string command = "copy " + basecom + " " + dest_dir;
|
||||||
|
#else
|
||||||
|
string command = "cp " + basecom + " " + dest_dir;
|
||||||
|
#endif
|
||||||
|
SG_LOG( SG_GENERAL, SG_INFO, "running " << command );
|
||||||
|
system( command.c_str() );
|
||||||
|
|
||||||
|
fprintf(fp, "OBJECT %s\n", name);
|
||||||
|
} else {
|
||||||
|
fprintf(fp, "%s\n", line);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(fp);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TGConstruct::WriteBtgFile( void )
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
|
||||||
|
for (unsigned int area = 0; area < TG_MAX_AREA_TYPES; area++) {
|
||||||
|
// only tesselate non holes
|
||||||
|
if ( !is_hole_area( area ) ) {
|
||||||
|
for (unsigned int shape = 0; shape < polys_clipped.area_size(area); shape++ ) {
|
||||||
|
for ( unsigned int segment = 0; segment < polys_clipped.shape_size(area, shape); segment++ ) {
|
||||||
|
SG_LOG( SG_CLIPPER, SG_INFO, "Ouput nodes for " << get_area_name( (AreaType)area ) << ":" <<
|
||||||
|
shape+1 << "-" << segment << " of " << polys_clipped.area_size(area) );
|
||||||
|
|
||||||
|
TGPolyNodes tri_nodes = polys_clipped.get_tri_idxs(area, shape, segment);
|
||||||
|
TGPolygon tri_txs = polys_clipped.get_texcoords(area, shape, segment);
|
||||||
|
string material = polys_clipped.get_material(area, shape, segment);
|
||||||
|
|
||||||
|
for (int k = 0; k < tri_nodes.contours(); ++k) {
|
||||||
|
tri_v.clear();
|
||||||
|
tri_n.clear();
|
||||||
|
tri_tc.clear();
|
||||||
|
for (int l = 0; l < tri_nodes.contour_size(k); ++l) {
|
||||||
|
index = tri_nodes.get_pt( k, l );
|
||||||
|
tri_v.push_back( index );
|
||||||
|
|
||||||
|
// add the node's normal
|
||||||
|
index = normals.unique_add( nodes.GetNormal( index ) );
|
||||||
|
tri_n.push_back( index );
|
||||||
|
|
||||||
|
Point3D tc = tri_txs.get_pt( k, l );
|
||||||
|
index = texcoords.unique_add( tc );
|
||||||
|
tri_tc.push_back( index );
|
||||||
|
}
|
||||||
|
tris_v.push_back( tri_v );
|
||||||
|
tris_n.push_back( tri_n );
|
||||||
|
tris_tc.push_back( tri_tc );
|
||||||
|
tri_materials.push_back( material );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector< SGVec3d > wgs84_nodes = nodes.get_wgs84_nodes_as_SGVec3d();
|
||||||
|
SGSphered d;
|
||||||
|
|
||||||
|
for (int i = 0; i < (int)wgs84_nodes.size(); ++i)
|
||||||
|
{
|
||||||
|
d.expandBy(wgs84_nodes[ i ]);
|
||||||
|
}
|
||||||
|
|
||||||
|
SGVec3d gbs_center = d.getCenter();
|
||||||
|
double gbs_radius = d.getRadius();
|
||||||
|
SG_LOG(SG_GENERAL, SG_DEBUG, "gbs center = " << gbs_center);
|
||||||
|
SG_LOG(SG_GENERAL, SG_DEBUG, "Done with wgs84 node mapping");
|
||||||
|
SG_LOG(SG_GENERAL, SG_DEBUG, " center = " << gbs_center << " radius = " << gbs_radius );
|
||||||
|
|
||||||
|
// null structures
|
||||||
|
group_list fans_v; fans_v.clear();
|
||||||
|
group_list fans_n; fans_n.clear();
|
||||||
|
group_list fans_tc; fans_tc.clear();
|
||||||
|
string_list fan_materials; fan_materials.clear();
|
||||||
|
|
||||||
|
string base = output_base;
|
||||||
|
string binname = bucket.gen_index_str();
|
||||||
|
binname += ".btg";
|
||||||
|
string txtname = bucket.gen_index_str();
|
||||||
|
txtname += ".txt";
|
||||||
|
|
||||||
|
std::vector< SGVec3f > normals_3f;
|
||||||
|
for (int i=0; i < (int)normals.get_node_list().size(); i++ )
|
||||||
|
{
|
||||||
|
Point3D node = normals.get_node_list()[i];
|
||||||
|
normals_3f.push_back( node.toSGVec3f() );
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector< SGVec2f > texcoords_2f;
|
||||||
|
for (int i=0; i < (int)texcoords.get_node_list().size(); i++ )
|
||||||
|
{
|
||||||
|
Point3D node = texcoords.get_node_list()[i];
|
||||||
|
texcoords_2f.push_back( node.toSGVec2f() );
|
||||||
|
}
|
||||||
|
|
||||||
|
SGBinObject obj;
|
||||||
|
|
||||||
|
obj.set_gbs_center( gbs_center );
|
||||||
|
obj.set_gbs_radius( gbs_radius );
|
||||||
|
obj.set_wgs84_nodes( wgs84_nodes );
|
||||||
|
obj.set_normals( normals_3f );
|
||||||
|
obj.set_texcoords( texcoords_2f );
|
||||||
|
obj.set_pts_v( pts_v );
|
||||||
|
obj.set_pts_n( pts_n );
|
||||||
|
obj.set_pt_materials( pt_materials );
|
||||||
|
obj.set_tris_v( tris_v );
|
||||||
|
obj.set_tris_n( tris_n );
|
||||||
|
obj.set_tris_tc( tris_tc );
|
||||||
|
obj.set_tri_materials( tri_materials );
|
||||||
|
obj.set_strips_v( strips_v );
|
||||||
|
obj.set_strips_n( strips_n );
|
||||||
|
obj.set_strips_tc( strips_tc );
|
||||||
|
obj.set_strip_materials( strip_materials );
|
||||||
|
obj.set_fans_v( fans_v );
|
||||||
|
obj.set_fans_n( fans_n );
|
||||||
|
obj.set_fans_tc( fans_tc );
|
||||||
|
obj.set_fan_materials( fan_materials );
|
||||||
|
|
||||||
|
bool result;
|
||||||
|
result = obj.write_bin( base, binname, bucket );
|
||||||
|
if ( !result )
|
||||||
|
{
|
||||||
|
throw sg_exception("error writing file. :-(");
|
||||||
|
}
|
||||||
|
if (debug_all || debug_shapes.size())
|
||||||
|
{
|
||||||
|
result = obj.write_ascii( base, txtname, bucket );
|
||||||
|
if ( !result )
|
||||||
|
{
|
||||||
|
throw sg_exception("error writing file. :-(");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
419
src/BuildTiles/Main/tgconstruct_poly.cxx
Normal file
419
src/BuildTiles/Main/tgconstruct_poly.cxx
Normal file
|
@ -0,0 +1,419 @@
|
||||||
|
// tgconstruct_poly.cxx -- load and handle polygon data
|
||||||
|
//
|
||||||
|
// Written by Curtis Olson, started May 1999.
|
||||||
|
//
|
||||||
|
// Copyright (C) 1999 Curtis L. Olson - http://www.flightgear.org/~curt
|
||||||
|
//
|
||||||
|
// This program is free software; you can redistribute it and/or
|
||||||
|
// modify it under the terms of the GNU General Public License as
|
||||||
|
// published by the Free Software Foundation; either version 2 of the
|
||||||
|
// License, or (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful, but
|
||||||
|
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
// General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
//
|
||||||
|
// $Id: construct.cxx,v 1.4 2004-11-19 22:25:49 curt Exp $
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
# include <config.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <boost/foreach.hpp>
|
||||||
|
|
||||||
|
#include <simgear/misc/sg_dir.hxx>
|
||||||
|
#include <simgear/debug/logstream.hxx>
|
||||||
|
|
||||||
|
#include <Geometry/poly_support.hxx>
|
||||||
|
#include <Osgb36/osgb36.hxx>
|
||||||
|
|
||||||
|
#include "tgconstruct.hxx"
|
||||||
|
|
||||||
|
using std::string;
|
||||||
|
|
||||||
|
static unsigned int cur_poly_id = 0;
|
||||||
|
|
||||||
|
// Add a polygon to the clipper. - only used by load_osgb36_poly - make that function more like ogr load
|
||||||
|
void TGConstruct::add_poly( int area, const TGPolygon &poly, string material ) {
|
||||||
|
TGShape shape;
|
||||||
|
TGSuperPoly sp;
|
||||||
|
|
||||||
|
if ( area < TG_MAX_AREA_TYPES ) {
|
||||||
|
sp.set_poly( poly );
|
||||||
|
sp.set_material( material );
|
||||||
|
|
||||||
|
shape.sps.push_back( sp );
|
||||||
|
|
||||||
|
polys_in.add_shape( area, shape );
|
||||||
|
} else {
|
||||||
|
SG_LOG( SG_CLIPPER, SG_ALERT, "Polygon type out of range = " << area);
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TGConstruct::load_poly(const string& path) {
|
||||||
|
bool poly3d = false;
|
||||||
|
bool with_tp = false;
|
||||||
|
string first_line;
|
||||||
|
string poly_name;
|
||||||
|
AreaType poly_type;
|
||||||
|
int contours, count, i, j, k;
|
||||||
|
int hole_flag;
|
||||||
|
int num_polys;
|
||||||
|
double startx, starty, startz, x, y, z, lastx, lasty, lastz;
|
||||||
|
|
||||||
|
sg_gzifstream in( path );
|
||||||
|
|
||||||
|
if ( !in ) {
|
||||||
|
SG_LOG( SG_CLIPPER, SG_ALERT, "Cannot open file: " << path );
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
TGPolygon poly;
|
||||||
|
TGTexParams tp;
|
||||||
|
Point3D p;
|
||||||
|
|
||||||
|
// (this could break things, why is it here) in >> skipcomment;
|
||||||
|
while ( !in.eof() ) {
|
||||||
|
in >> first_line;
|
||||||
|
if ( first_line == "#2D" ) {
|
||||||
|
poly3d = false;
|
||||||
|
with_tp = false;
|
||||||
|
|
||||||
|
in >> poly_name;
|
||||||
|
num_polys = 1;
|
||||||
|
} else if ( first_line == "#2D_WITH_MASK" ) {
|
||||||
|
poly3d = false;
|
||||||
|
with_tp = false;
|
||||||
|
|
||||||
|
in >> poly_name;
|
||||||
|
in >> num_polys;
|
||||||
|
} else if ( first_line == "#2D_WITH_TPS" ) {
|
||||||
|
poly3d = false;
|
||||||
|
with_tp = true;
|
||||||
|
|
||||||
|
in >> poly_name;
|
||||||
|
in >> num_polys;
|
||||||
|
} else if ( first_line == "#3D" ) {
|
||||||
|
poly3d = true;
|
||||||
|
with_tp = false;
|
||||||
|
|
||||||
|
in >> poly_name;
|
||||||
|
num_polys = 1;
|
||||||
|
} else {
|
||||||
|
// support old format (default to 2d)
|
||||||
|
poly3d = false;
|
||||||
|
with_tp = false;
|
||||||
|
|
||||||
|
poly_name = first_line;
|
||||||
|
num_polys = 1;
|
||||||
|
}
|
||||||
|
poly_type = get_area_type( poly_name );
|
||||||
|
|
||||||
|
int area = (int)poly_type;
|
||||||
|
string material;
|
||||||
|
|
||||||
|
// only allow 1000 shapes per material
|
||||||
|
int extension = polys_in.area_size( area ) / 1000;
|
||||||
|
|
||||||
|
if (extension)
|
||||||
|
{
|
||||||
|
char buff[32];
|
||||||
|
sprintf( buff, "%s_%d", get_area_name( area ).c_str(), extension );
|
||||||
|
material = buff;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
material = get_area_name( area );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Generate a new Shape for the poly
|
||||||
|
TGShape shape;
|
||||||
|
TGSuperPoly sp;
|
||||||
|
|
||||||
|
for (k=0; k<num_polys;k++) {
|
||||||
|
|
||||||
|
if ( with_tp ) {
|
||||||
|
double width, length;
|
||||||
|
double heading;
|
||||||
|
double minu, maxu;
|
||||||
|
double minv, maxv;
|
||||||
|
|
||||||
|
in >> x;
|
||||||
|
in >> y;
|
||||||
|
in >> width;
|
||||||
|
in >> length;
|
||||||
|
in >> heading;
|
||||||
|
in >> minu;
|
||||||
|
in >> maxu;
|
||||||
|
in >> minv;
|
||||||
|
in >> maxv;
|
||||||
|
|
||||||
|
tp.set_ref( Point3D(x, y, 0.0f) );
|
||||||
|
tp.set_width( width );
|
||||||
|
tp.set_length( length );
|
||||||
|
tp.set_heading( heading );
|
||||||
|
tp.set_minu( minu );
|
||||||
|
tp.set_maxu( maxu );
|
||||||
|
tp.set_minv( minv );
|
||||||
|
tp.set_maxv( maxv );
|
||||||
|
}
|
||||||
|
|
||||||
|
in >> contours;
|
||||||
|
|
||||||
|
poly.erase();
|
||||||
|
|
||||||
|
for ( i = 0; i < contours; ++i ) {
|
||||||
|
in >> count;
|
||||||
|
|
||||||
|
if ( count < 3 ) {
|
||||||
|
SG_LOG( SG_CLIPPER, SG_ALERT, "Polygon with less than 3 data points." );
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
in >> hole_flag;
|
||||||
|
|
||||||
|
in >> startx;
|
||||||
|
in >> starty;
|
||||||
|
if ( poly3d ) {
|
||||||
|
in >> startz;
|
||||||
|
} else {
|
||||||
|
startz = -9999.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
p = Point3D(startx+nudge, starty+nudge, startz);
|
||||||
|
p.snap( gSnap );
|
||||||
|
poly.add_node( i, p );
|
||||||
|
|
||||||
|
if ( poly3d ) {
|
||||||
|
nodes.unique_add_fixed_elevation( p );
|
||||||
|
} else {
|
||||||
|
nodes.unique_add( p );
|
||||||
|
}
|
||||||
|
|
||||||
|
for ( j = 1; j < count - 1; ++j ) {
|
||||||
|
in >> x;
|
||||||
|
in >> y;
|
||||||
|
if ( poly3d ) {
|
||||||
|
in >> z;
|
||||||
|
} else {
|
||||||
|
z = -9999.0;
|
||||||
|
}
|
||||||
|
p = Point3D( x+nudge, y+nudge, z );
|
||||||
|
p.snap( gSnap );
|
||||||
|
poly.add_node( i, p );
|
||||||
|
if ( poly3d ) {
|
||||||
|
nodes.unique_add_fixed_elevation( p );
|
||||||
|
} else {
|
||||||
|
nodes.unique_add( p );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
in >> lastx;
|
||||||
|
in >> lasty;
|
||||||
|
if ( poly3d ) {
|
||||||
|
in >> lastz;
|
||||||
|
} else {
|
||||||
|
lastz = -9999.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( (fabs(startx - lastx) < SG_EPSILON) &&
|
||||||
|
(fabs(starty - lasty) < SG_EPSILON) &&
|
||||||
|
(fabs(startz - lastz) < SG_EPSILON) ) {
|
||||||
|
// last point same as first, discard
|
||||||
|
} else {
|
||||||
|
p = Point3D( lastx+nudge, lasty+nudge, lastz );
|
||||||
|
p.snap( gSnap );
|
||||||
|
poly.add_node( i, p );
|
||||||
|
if ( poly3d ) {
|
||||||
|
nodes.unique_add_fixed_elevation( p );
|
||||||
|
} else {
|
||||||
|
nodes.unique_add( p );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
poly = remove_dups( poly );
|
||||||
|
|
||||||
|
sp.set_poly( poly );
|
||||||
|
sp.set_material( material );
|
||||||
|
shape.sps.push_back( sp );
|
||||||
|
|
||||||
|
if ( with_tp ) {
|
||||||
|
shape.textured = true;
|
||||||
|
shape.tps.push_back( tp );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
shape.textured = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
in >> skipcomment;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Once the full poly is loaded, build the clip mask
|
||||||
|
shape.BuildMask();
|
||||||
|
shape.area = area;
|
||||||
|
shape.id = cur_poly_id++;
|
||||||
|
|
||||||
|
polys_in.add_shape( area, shape );
|
||||||
|
|
||||||
|
if ( IsDebugShape( shape.id ) ) {
|
||||||
|
WriteDebugShape( "loaded", shape );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Load a polygon definition file containing osgb36 Eastings and Northings
|
||||||
|
// and convert them to WGS84 Latitude and Longitude
|
||||||
|
bool TGConstruct::load_osgb36_poly(const string& path) {
|
||||||
|
string poly_name;
|
||||||
|
AreaType poly_type;
|
||||||
|
int contours, count, i, j;
|
||||||
|
int hole_flag;
|
||||||
|
double startx, starty, x, y, lastx, lasty;
|
||||||
|
|
||||||
|
SG_LOG( SG_CLIPPER, SG_INFO, "Loading " << path << " ..." );
|
||||||
|
|
||||||
|
sg_gzifstream in( path );
|
||||||
|
|
||||||
|
if ( !in ) {
|
||||||
|
SG_LOG( SG_CLIPPER, SG_ALERT, "Cannot open file: " << path );
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
TGPolygon poly;
|
||||||
|
|
||||||
|
Point3D p;
|
||||||
|
Point3D OSRef;
|
||||||
|
in >> skipcomment;
|
||||||
|
while ( !in.eof() ) {
|
||||||
|
in >> poly_name;
|
||||||
|
SG_LOG( SG_CLIPPER, SG_INFO, "poly name = " << poly_name);
|
||||||
|
poly_type = get_area_type( poly_name );
|
||||||
|
SG_LOG( SG_CLIPPER, SG_INFO, "poly type (int) = " << (int)poly_type);
|
||||||
|
in >> contours;
|
||||||
|
SG_LOG( SG_CLIPPER, SG_INFO, "num contours = " << contours);
|
||||||
|
|
||||||
|
poly.erase();
|
||||||
|
|
||||||
|
for ( i = 0; i < contours; ++i ) {
|
||||||
|
in >> count;
|
||||||
|
|
||||||
|
if ( count < 3 ) {
|
||||||
|
SG_LOG( SG_CLIPPER, SG_ALERT, "Polygon with less than 3 data points." );
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
in >> hole_flag;
|
||||||
|
|
||||||
|
in >> startx;
|
||||||
|
in >> starty;
|
||||||
|
OSRef = Point3D(startx, starty, -9999.0);
|
||||||
|
|
||||||
|
//Convert from OSGB36 Eastings/Northings to WGS84 Lat/Lon
|
||||||
|
//Note that startx and starty themselves must not be altered since we compare them with unaltered lastx and lasty later
|
||||||
|
p = OSGB36ToWGS84(OSRef);
|
||||||
|
|
||||||
|
poly.add_node( i, p );
|
||||||
|
nodes.unique_add( p );
|
||||||
|
|
||||||
|
SG_LOG( SG_CLIPPER, SG_BULK, "0 = " << startx << ", " << starty );
|
||||||
|
|
||||||
|
for ( j = 1; j < count - 1; ++j ) {
|
||||||
|
in >> x;
|
||||||
|
in >> y;
|
||||||
|
OSRef = Point3D( x, y, -9999.0 );
|
||||||
|
p = OSGB36ToWGS84(OSRef);
|
||||||
|
|
||||||
|
poly.add_node( i, p );
|
||||||
|
nodes.unique_add( p );
|
||||||
|
SG_LOG( SG_CLIPPER, SG_BULK, j << " = " << x << ", " << y );
|
||||||
|
}
|
||||||
|
|
||||||
|
in >> lastx;
|
||||||
|
in >> lasty;
|
||||||
|
|
||||||
|
if ( (fabs(startx - lastx) < SG_EPSILON) &&
|
||||||
|
(fabs(starty - lasty) < SG_EPSILON) ) {
|
||||||
|
// last point same as first, discard
|
||||||
|
} else {
|
||||||
|
OSRef = Point3D( lastx, lasty, -9999.0 );
|
||||||
|
p = OSGB36ToWGS84(OSRef);
|
||||||
|
|
||||||
|
poly.add_node( i, p );
|
||||||
|
nodes.unique_add( p );
|
||||||
|
SG_LOG( SG_CLIPPER, SG_BULK, count - 1 << " = " << lastx << ", " << lasty );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO : Make like OGR
|
||||||
|
int area = (int)poly_type;
|
||||||
|
string material = get_area_name( area );
|
||||||
|
add_poly(area, poly, material);
|
||||||
|
// END TODO
|
||||||
|
|
||||||
|
in >> skipcomment;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// load all 2d polygons from the specified load disk directories and
|
||||||
|
// clip against each other to resolve any overlaps
|
||||||
|
int TGConstruct::LoadLandclassPolys( void ) {
|
||||||
|
int i;
|
||||||
|
|
||||||
|
string base = bucket.gen_base_path();
|
||||||
|
string poly_path;
|
||||||
|
int count = 0;
|
||||||
|
|
||||||
|
polys_in.clear();
|
||||||
|
|
||||||
|
// load 2D polygons from all directories provided
|
||||||
|
for ( i = 0; i < (int)load_dirs.size(); ++i ) {
|
||||||
|
poly_path = work_base + "/" + load_dirs[i] + '/' + base;
|
||||||
|
|
||||||
|
string tile_str = bucket.gen_index_str();
|
||||||
|
simgear::Dir d(poly_path);
|
||||||
|
if (!d.exists()) {
|
||||||
|
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"))
|
||||||
|
{
|
||||||
|
// skipped!
|
||||||
|
} else if (lext == "osgb36") {
|
||||||
|
SG_LOG(SG_GENERAL, SG_ALERT, " Loading osgb36 poly definition file " << p.file());
|
||||||
|
load_osgb36_poly( p.str() );
|
||||||
|
++count;
|
||||||
|
} else {
|
||||||
|
load_poly( p.str() );
|
||||||
|
SG_LOG(SG_GENERAL, SG_ALERT, " Loaded " << p.file());
|
||||||
|
++count;
|
||||||
|
}
|
||||||
|
} // of directory file children
|
||||||
|
}
|
||||||
|
SG_LOG(SG_GENERAL, SG_ALERT, " Total polys used for this tile: " << count );
|
||||||
|
return count;
|
||||||
|
}
|
551
src/BuildTiles/Main/tgconstruct_shared.cxx
Normal file
551
src/BuildTiles/Main/tgconstruct_shared.cxx
Normal file
|
@ -0,0 +1,551 @@
|
||||||
|
// construct_intermediate.cxx -- Handle all intermediate and shared data files
|
||||||
|
//
|
||||||
|
// Written by Curtis Olson, started May 1999.
|
||||||
|
//
|
||||||
|
// Copyright (C) 1999 Curtis L. Olson - http://www.flightgear.org/~curt
|
||||||
|
//
|
||||||
|
// This program is free software; you can redistribute it and/or
|
||||||
|
// modify it under the terms of the GNU General Public License as
|
||||||
|
// published by the Free Software Foundation; either version 2 of the
|
||||||
|
// License, or (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful, but
|
||||||
|
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
// General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
//
|
||||||
|
// $Id: construct.cxx,v 1.4 2004-11-19 22:25:49 curt Exp $
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
# include <config.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <iomanip>
|
||||||
|
|
||||||
|
#include <simgear/misc/sg_dir.hxx>
|
||||||
|
#include <simgear/debug/logstream.hxx>
|
||||||
|
|
||||||
|
#include <Geometry/poly_support.hxx>
|
||||||
|
|
||||||
|
#include "tgconstruct.hxx"
|
||||||
|
|
||||||
|
using std::string;
|
||||||
|
|
||||||
|
void TGConstruct::SaveSharedEdgeData( int stage )
|
||||||
|
{
|
||||||
|
string dir;
|
||||||
|
string file;
|
||||||
|
|
||||||
|
switch( stage ) {
|
||||||
|
case 1:
|
||||||
|
{
|
||||||
|
point_list north, south, east, west;
|
||||||
|
int nCount;
|
||||||
|
|
||||||
|
nodes.get_geod_edge( bucket, north, south, east, west );
|
||||||
|
|
||||||
|
dir = share_base + "/stage1/" + bucket.gen_base_path();
|
||||||
|
|
||||||
|
SGPath sgp( dir );
|
||||||
|
sgp.append( "dummy" );
|
||||||
|
sgp.create_dir( 0755 );
|
||||||
|
|
||||||
|
file = dir + "/" + bucket.gen_index_str() + "_edges";
|
||||||
|
std::ofstream ofs_e( file.c_str() );
|
||||||
|
|
||||||
|
// first, set the precision
|
||||||
|
ofs_e << std::setprecision(12);
|
||||||
|
ofs_e << std::fixed;
|
||||||
|
|
||||||
|
// north
|
||||||
|
nCount = north.size();
|
||||||
|
ofs_e << nCount << "\n";
|
||||||
|
for (int i=0; i<nCount; i++) {
|
||||||
|
ofs_e << north[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
// south
|
||||||
|
nCount = south.size();
|
||||||
|
ofs_e << nCount << "\n";
|
||||||
|
for (int i=0; i<nCount; i++) {
|
||||||
|
ofs_e << south[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
// east
|
||||||
|
nCount = east.size();
|
||||||
|
ofs_e << nCount << "\n";
|
||||||
|
for (int i=0; i<nCount; i++) {
|
||||||
|
ofs_e << east[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
// west
|
||||||
|
nCount = west.size();
|
||||||
|
ofs_e << nCount << "\n";
|
||||||
|
for (int i=0; i<nCount; i++) {
|
||||||
|
ofs_e << west[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
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<faces.size(); j++) {
|
||||||
|
// for each connected face, get the nodes
|
||||||
|
unsigned int at = faces[j].area;
|
||||||
|
unsigned int shape = faces[j].shape;
|
||||||
|
unsigned int segment = faces[j].seg;
|
||||||
|
unsigned int tri = faces[j].tri;
|
||||||
|
|
||||||
|
int_list face_nodes = polys_clipped.get_tri_idxs( at, shape, segment ).get_contour( tri ) ;
|
||||||
|
{
|
||||||
|
Point3D p1 = nodes.get_node( face_nodes[0] ).GetPosition();
|
||||||
|
Point3D p2 = nodes.get_node( face_nodes[1] ).GetPosition();
|
||||||
|
Point3D p3 = nodes.get_node( face_nodes[2] ).GetPosition();
|
||||||
|
|
||||||
|
Point3D wgs_p1 = nodes.get_node( face_nodes[0] ).GetWgs84AsPoint3D();
|
||||||
|
Point3D wgs_p2 = nodes.get_node( face_nodes[1] ).GetWgs84AsPoint3D();
|
||||||
|
Point3D wgs_p3 = nodes.get_node( face_nodes[2] ).GetWgs84AsPoint3D();
|
||||||
|
|
||||||
|
double face_area = triangle_area( p1, p2, p3 );
|
||||||
|
Point3D face_normal = Point3D::fromSGVec3( calc_normal( face_area, wgs_p1, wgs_p2, wgs_p3 ) );
|
||||||
|
|
||||||
|
ofs_e << face_area << " ";
|
||||||
|
ofs_e << face_normal;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ofs_e << "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
TGNeighborFaces* TGConstruct::FindNeighborFaces( Point3D node )
|
||||||
|
{
|
||||||
|
TGNeighborFaces* faces = NULL;
|
||||||
|
|
||||||
|
for (unsigned int i=0; i<neighbor_faces.size(); i++) {
|
||||||
|
if ( node == neighbor_faces[i].node ) {
|
||||||
|
faces = &neighbor_faces[i];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return faces;
|
||||||
|
}
|
||||||
|
|
||||||
|
TGNeighborFaces* TGConstruct::AddNeighborFaces( Point3D node )
|
||||||
|
{
|
||||||
|
TGNeighborFaces faces;
|
||||||
|
faces.node = node;
|
||||||
|
|
||||||
|
neighbor_faces.push_back( faces );
|
||||||
|
|
||||||
|
return &neighbor_faces[neighbor_faces.size()-1];
|
||||||
|
}
|
||||||
|
|
||||||
|
void TGConstruct::ReadNeighborFaces( std::ifstream& in )
|
||||||
|
{
|
||||||
|
int count;
|
||||||
|
|
||||||
|
// read the count
|
||||||
|
in >> count;
|
||||||
|
|
||||||
|
for (int i=0; i<count; i++) {
|
||||||
|
TGNeighborFaces* pFaces;
|
||||||
|
Point3D node;
|
||||||
|
int num_faces;
|
||||||
|
|
||||||
|
in >> 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<num_faces; j++)
|
||||||
|
{
|
||||||
|
double area;
|
||||||
|
Point3D normal;
|
||||||
|
|
||||||
|
in >> 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<nCount; i++) {
|
||||||
|
// write the 3d point
|
||||||
|
ofs_e << north[i];
|
||||||
|
WriteNeighborFaces( ofs_e, north[i] );
|
||||||
|
}
|
||||||
|
ofs_e.close();
|
||||||
|
|
||||||
|
// south edge
|
||||||
|
file = dir + "/" + bucket.gen_index_str() + "_south_edge";
|
||||||
|
ofs_e.open( file.c_str() );
|
||||||
|
ofs_e << std::setprecision(12);
|
||||||
|
ofs_e << std::fixed;
|
||||||
|
|
||||||
|
nCount = south.size();
|
||||||
|
ofs_e << nCount << "\n";
|
||||||
|
for (int i=0; i<nCount; i++) {
|
||||||
|
ofs_e << south[i];
|
||||||
|
WriteNeighborFaces( ofs_e, south[i] );
|
||||||
|
}
|
||||||
|
ofs_e.close();
|
||||||
|
|
||||||
|
// east edge
|
||||||
|
file = dir + "/" + bucket.gen_index_str() + "_east_edge";
|
||||||
|
ofs_e.open( file.c_str() );
|
||||||
|
ofs_e << std::setprecision(12);
|
||||||
|
ofs_e << std::fixed;
|
||||||
|
|
||||||
|
nCount = east.size();
|
||||||
|
ofs_e << nCount << "\n";
|
||||||
|
for (int i=0; i<nCount; i++) {
|
||||||
|
ofs_e << east[i];
|
||||||
|
WriteNeighborFaces( ofs_e, east[i] );
|
||||||
|
}
|
||||||
|
ofs_e.close();
|
||||||
|
|
||||||
|
// west egde
|
||||||
|
file = dir + "/" + bucket.gen_index_str() + "_west_edge";
|
||||||
|
ofs_e.open( file.c_str() );
|
||||||
|
ofs_e << std::setprecision(12);
|
||||||
|
ofs_e << std::fixed;
|
||||||
|
|
||||||
|
nCount = west.size();
|
||||||
|
ofs_e << nCount << "\n";
|
||||||
|
for (int i=0; i<nCount; i++) {
|
||||||
|
ofs_e << west[i];
|
||||||
|
WriteNeighborFaces( ofs_e, west[i] );
|
||||||
|
}
|
||||||
|
ofs_e.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
void TGConstruct::LoadSharedEdgeDataStage2( void )
|
||||||
|
{
|
||||||
|
string dir;
|
||||||
|
string file;
|
||||||
|
std::ifstream ifs_edge;
|
||||||
|
double clon = bucket.get_center_lon();
|
||||||
|
double clat = bucket.get_center_lat();
|
||||||
|
SGBucket b;
|
||||||
|
|
||||||
|
// Read Northern tile and add its southern node faces
|
||||||
|
b = sgBucketOffset(clon, clat, 0, 1);
|
||||||
|
dir = share_base + "/stage2/" + b.gen_base_path();
|
||||||
|
file = dir + "/" + b.gen_index_str() + "_south_edge";
|
||||||
|
ifs_edge.open( file.c_str() );
|
||||||
|
if ( ifs_edge.is_open() ) {
|
||||||
|
ReadNeighborFaces( ifs_edge );
|
||||||
|
}
|
||||||
|
ifs_edge.close();
|
||||||
|
|
||||||
|
// Read Southern tile and add its northern node faces
|
||||||
|
b = sgBucketOffset(clon, clat, 0, -1);
|
||||||
|
dir = share_base + "/stage2/" + b.gen_base_path();
|
||||||
|
file = dir + "/" + b.gen_index_str() + "_north_edge";
|
||||||
|
ifs_edge.open( file.c_str() );
|
||||||
|
if ( ifs_edge.is_open() ) {
|
||||||
|
ReadNeighborFaces( ifs_edge );
|
||||||
|
}
|
||||||
|
ifs_edge.close();
|
||||||
|
|
||||||
|
// Read Eastern tile and add its western node faces
|
||||||
|
b = sgBucketOffset(clon, clat, 1, 0);
|
||||||
|
dir = share_base + "/stage2/" + b.gen_base_path();
|
||||||
|
file = dir + "/" + b.gen_index_str() + "_west_edge";
|
||||||
|
ifs_edge.open( file.c_str() );
|
||||||
|
if ( ifs_edge.is_open() ) {
|
||||||
|
ReadNeighborFaces( ifs_edge );
|
||||||
|
}
|
||||||
|
ifs_edge.close();
|
||||||
|
|
||||||
|
// Read Western tile and add its eastern node faces
|
||||||
|
b = sgBucketOffset(clon, clat, -1, 0);
|
||||||
|
dir = share_base + "/stage2/" + b.gen_base_path();
|
||||||
|
file = dir + "/" + b.gen_index_str() + "_east_edge";
|
||||||
|
ifs_edge.open( file.c_str() );
|
||||||
|
if ( ifs_edge.is_open() ) {
|
||||||
|
ReadNeighborFaces( ifs_edge );
|
||||||
|
}
|
||||||
|
ifs_edge.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void TGConstruct::SaveToIntermediateFiles( int stage )
|
||||||
|
{
|
||||||
|
string dir;
|
||||||
|
string file;
|
||||||
|
|
||||||
|
switch( stage ) {
|
||||||
|
case 1: // Save the clipped polys and node list
|
||||||
|
{
|
||||||
|
dir = share_base + "/stage1/" + bucket.gen_base_path();
|
||||||
|
|
||||||
|
SGPath sgp( dir );
|
||||||
|
sgp.append( "dummy" );
|
||||||
|
sgp.create_dir( 0755 );
|
||||||
|
|
||||||
|
file = dir + "/" + bucket.gen_index_str() + "_clipped_polys";
|
||||||
|
std::ofstream ofs_cp( file.c_str() );
|
||||||
|
|
||||||
|
// first, set the precision
|
||||||
|
ofs_cp << std::setprecision(15);
|
||||||
|
ofs_cp << std::fixed;
|
||||||
|
ofs_cp << polys_clipped;
|
||||||
|
ofs_cp.close();
|
||||||
|
|
||||||
|
|
||||||
|
file = dir + "/" + bucket.gen_index_str() + "_nodes";
|
||||||
|
std::ofstream ofs_n( file.c_str() );
|
||||||
|
|
||||||
|
// first, set the precision
|
||||||
|
ofs_n << std::setprecision(15);
|
||||||
|
ofs_n << std::fixed;
|
||||||
|
ofs_n << nodes;
|
||||||
|
ofs_n.close();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case 2: // Save the clipped polys and node list
|
||||||
|
{
|
||||||
|
dir = share_base + "/stage2/" + bucket.gen_base_path();
|
||||||
|
|
||||||
|
SGPath sgp( dir );
|
||||||
|
sgp.append( "dummy" );
|
||||||
|
sgp.create_dir( 0755 );
|
||||||
|
|
||||||
|
file = dir + "/" + bucket.gen_index_str() + "_clipped_polys";
|
||||||
|
std::ofstream ofs_cp( file.c_str() );
|
||||||
|
|
||||||
|
// first, set the precision
|
||||||
|
ofs_cp << std::setprecision(15);
|
||||||
|
ofs_cp << std::fixed;
|
||||||
|
ofs_cp << polys_clipped;
|
||||||
|
ofs_cp.close();
|
||||||
|
|
||||||
|
file = dir + "/" + bucket.gen_index_str() + "_nodes";
|
||||||
|
std::ofstream ofs_n( file.c_str() );
|
||||||
|
|
||||||
|
// first, set the precision
|
||||||
|
ofs_n << std::setprecision(15);
|
||||||
|
ofs_n << std::fixed;
|
||||||
|
ofs_n << nodes;
|
||||||
|
ofs_n.close();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TGConstruct::LoadNeighboorEdgeDataStage1( SGBucket& b, point_list& north, point_list& south, point_list& east, point_list& west )
|
||||||
|
{
|
||||||
|
string dir;
|
||||||
|
string file;
|
||||||
|
Point3D pt;
|
||||||
|
int nCount;
|
||||||
|
|
||||||
|
dir = share_base + "/stage1/" + b.gen_base_path();
|
||||||
|
file = dir + "/" + b.gen_index_str() + "_edges";
|
||||||
|
std::ifstream ifs_edges( file.c_str() );
|
||||||
|
|
||||||
|
north.clear();
|
||||||
|
south.clear();
|
||||||
|
east.clear();
|
||||||
|
west.clear();
|
||||||
|
|
||||||
|
if ( ifs_edges.is_open() ) {
|
||||||
|
// North
|
||||||
|
ifs_edges >> nCount;
|
||||||
|
SG_LOG( SG_CLIPPER, SG_INFO, "loading " << nCount << "Points on " << b.gen_index_str() << " north boundary");
|
||||||
|
for (int i=0; i<nCount; i++) {
|
||||||
|
ifs_edges >> pt;
|
||||||
|
north.push_back(pt);
|
||||||
|
}
|
||||||
|
|
||||||
|
// South
|
||||||
|
ifs_edges >> nCount;
|
||||||
|
SG_LOG( SG_CLIPPER, SG_INFO, "loading " << nCount << "Points on " << b.gen_index_str() << " south boundary");
|
||||||
|
for (int i=0; i<nCount; i++) {
|
||||||
|
ifs_edges >> pt;
|
||||||
|
south.push_back(pt);
|
||||||
|
}
|
||||||
|
|
||||||
|
// East
|
||||||
|
ifs_edges >> nCount;
|
||||||
|
SG_LOG( SG_CLIPPER, SG_INFO, "loading " << nCount << "Points on " << b.gen_index_str() << " east boundary");
|
||||||
|
for (int i=0; i<nCount; i++) {
|
||||||
|
ifs_edges >> pt;
|
||||||
|
east.push_back(pt);
|
||||||
|
}
|
||||||
|
|
||||||
|
// West
|
||||||
|
ifs_edges >> nCount;
|
||||||
|
SG_LOG( SG_CLIPPER, SG_INFO, "loading " << nCount << "Points on " << b.gen_index_str() << " west boundary");
|
||||||
|
for (int i=0; i<nCount; i++) {
|
||||||
|
ifs_edges >> pt;
|
||||||
|
west.push_back(pt);
|
||||||
|
}
|
||||||
|
|
||||||
|
ifs_edges.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TGConstruct::LoadSharedEdgeData( int stage )
|
||||||
|
{
|
||||||
|
switch( stage ) {
|
||||||
|
case 1:
|
||||||
|
{
|
||||||
|
// we need to read just 4 buckets for stage 1 - 1 for each edge
|
||||||
|
point_list north, south, east, west;
|
||||||
|
SGBucket nb, sb, eb, wb;
|
||||||
|
double clon = bucket.get_center_lon();
|
||||||
|
double clat = bucket.get_center_lat();
|
||||||
|
|
||||||
|
// Read North tile and add its southern nodes
|
||||||
|
nb = sgBucketOffset(clon, clat, 0, 1);
|
||||||
|
LoadNeighboorEdgeDataStage1( nb, north, south, east, west );
|
||||||
|
// Add southern nodes from northern tile
|
||||||
|
for (unsigned int i=0; i<south.size(); i++) {
|
||||||
|
nodes.unique_add( south[i] );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read South Tile and add its northern nodes
|
||||||
|
sb = sgBucketOffset(clon, clat, 0, -1);
|
||||||
|
LoadNeighboorEdgeDataStage1( sb, north, south, east, west );
|
||||||
|
for (unsigned int i=0; i<north.size(); i++) {
|
||||||
|
nodes.unique_add( north[i] );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read East Tile and add its western nodes
|
||||||
|
eb = sgBucketOffset(clon, clat, 1, 0);
|
||||||
|
LoadNeighboorEdgeDataStage1( eb, north, south, east, west );
|
||||||
|
for (unsigned int i=0; i<west.size(); i++) {
|
||||||
|
nodes.unique_add( west[i] );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read West Tile and add its eastern nodes
|
||||||
|
wb = sgBucketOffset(clon, clat, -1, 0);
|
||||||
|
LoadNeighboorEdgeDataStage1( wb, north, south, east, west );
|
||||||
|
for (unsigned int i=0; i<east.size(); i++) {
|
||||||
|
nodes.unique_add( east[i] );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TGConstruct::LoadFromIntermediateFiles( int stage )
|
||||||
|
{
|
||||||
|
string dir;
|
||||||
|
string file;
|
||||||
|
|
||||||
|
switch( stage ) {
|
||||||
|
case 1: // Load the clipped polys and node list
|
||||||
|
{
|
||||||
|
dir = share_base + "/stage1/" + bucket.gen_base_path();
|
||||||
|
file = dir + "/" + bucket.gen_index_str() + "_clipped_polys";
|
||||||
|
|
||||||
|
std::ifstream ifs_cp( file.c_str() );
|
||||||
|
ifs_cp >> polys_clipped;
|
||||||
|
ifs_cp.close();
|
||||||
|
|
||||||
|
file = dir + "/" + bucket.gen_index_str() + "_nodes";
|
||||||
|
|
||||||
|
std::ifstream ifs_n( file.c_str() );
|
||||||
|
ifs_n >> nodes;
|
||||||
|
ifs_n.close();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case 2: // Load the clipped polys and node list
|
||||||
|
{
|
||||||
|
dir = share_base + "/stage2/" + bucket.gen_base_path();
|
||||||
|
file = dir + "/" + bucket.gen_index_str() + "_clipped_polys";
|
||||||
|
|
||||||
|
std::ifstream ifs_cp( file.c_str() );
|
||||||
|
ifs_cp >> polys_clipped;
|
||||||
|
ifs_cp.close();
|
||||||
|
|
||||||
|
file = dir + "/" + bucket.gen_index_str() + "_nodes";
|
||||||
|
|
||||||
|
std::ifstream ifs_n( file.c_str() );
|
||||||
|
ifs_n >> nodes;
|
||||||
|
ifs_n.close();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
81
src/BuildTiles/Main/tgconstruct_tesselate.cxx
Normal file
81
src/BuildTiles/Main/tgconstruct_tesselate.cxx
Normal file
|
@ -0,0 +1,81 @@
|
||||||
|
// construct.cxx -- Class to manage the primary data used in the
|
||||||
|
// construction process
|
||||||
|
//
|
||||||
|
// Written by Curtis Olson, started May 1999.
|
||||||
|
//
|
||||||
|
// Copyright (C) 1999 Curtis L. Olson - http://www.flightgear.org/~curt
|
||||||
|
//
|
||||||
|
// This program is free software; you can redistribute it and/or
|
||||||
|
// modify it under the terms of the GNU General Public License as
|
||||||
|
// published by the Free Software Foundation; either version 2 of the
|
||||||
|
// License, or (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful, but
|
||||||
|
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
// General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
//
|
||||||
|
// $Id: construct.cxx,v 1.4 2004-11-19 22:25:49 curt Exp $
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
# include <config.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//#include <simgear/compiler.h>
|
||||||
|
#include <simgear/debug/logstream.hxx>
|
||||||
|
|
||||||
|
#include <Geometry/poly_support.hxx>
|
||||||
|
//#include <Geometry/poly_extra.hxx>
|
||||||
|
|
||||||
|
#include "tgconstruct.hxx"
|
||||||
|
|
||||||
|
//using std::string;
|
||||||
|
|
||||||
|
void TGConstruct::TesselatePolys( void )
|
||||||
|
{
|
||||||
|
// tesselate the polygons and prepair them for final output
|
||||||
|
point_list poly_extra;
|
||||||
|
Point3D min, max;
|
||||||
|
|
||||||
|
for (unsigned int area = 0; area < TG_MAX_AREA_TYPES; area++) {
|
||||||
|
for (unsigned int shape = 0; shape < polys_clipped.area_size(area); shape++ ) {
|
||||||
|
unsigned int id = polys_clipped.get_shape( area, shape ).id;
|
||||||
|
|
||||||
|
if ( IsDebugShape( id ) ) {
|
||||||
|
WriteDebugShape( "preteselate", polys_clipped.get_shape(area, shape) );
|
||||||
|
}
|
||||||
|
|
||||||
|
for ( unsigned int segment = 0; segment < polys_clipped.shape_size(area, shape); segment++ ) {
|
||||||
|
TGPolygon poly = polys_clipped.get_poly(area, shape, segment);
|
||||||
|
|
||||||
|
poly.get_bounding_box(min, max);
|
||||||
|
poly_extra = nodes.get_geod_inside( min, max );
|
||||||
|
|
||||||
|
SG_LOG( SG_CLIPPER, SG_INFO, "Tesselating " << get_area_name( (AreaType)area ) << "(" << area << "): " <<
|
||||||
|
shape+1 << "-" << segment << " of " << (int)polys_clipped.area_size(area) <<
|
||||||
|
": id = " << id );
|
||||||
|
|
||||||
|
if ( IsDebugShape( id ) ) {
|
||||||
|
SG_LOG( SG_CLIPPER, SG_INFO, poly );
|
||||||
|
}
|
||||||
|
|
||||||
|
TGPolygon tri = polygon_tesselate_alt_with_extra_cgal( poly, poly_extra, false );
|
||||||
|
|
||||||
|
// ensure all added nodes are accounted for
|
||||||
|
for (int k=0; k< tri.contours(); k++) {
|
||||||
|
for (int l = 0; l < tri.contour_size(k); l++) {
|
||||||
|
// ensure we have all nodes...
|
||||||
|
nodes.unique_add( tri.get_pt( k, l ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save the triangulation
|
||||||
|
polys_clipped.set_tris( area, shape, segment, tri );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
187
src/BuildTiles/Main/tgconstruct_texture.cxx
Normal file
187
src/BuildTiles/Main/tgconstruct_texture.cxx
Normal file
|
@ -0,0 +1,187 @@
|
||||||
|
|
||||||
|
// tgconstruct_texture.cxx --Handle texture coordinate generation in tgconstruct
|
||||||
|
//
|
||||||
|
// Written by Curtis Olson, started May 1999.
|
||||||
|
//
|
||||||
|
// Copyright (C) 1999 Curtis L. Olson - http://www.flightgear.org/~curt
|
||||||
|
//
|
||||||
|
// This program is free software; you can redistribute it and/or
|
||||||
|
// modify it under the terms of the GNU General Public License as
|
||||||
|
// published by the Free Software Foundation; either version 2 of the
|
||||||
|
// License, or (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful, but
|
||||||
|
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
// General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
//
|
||||||
|
// $Id: construct.cxx,v 1.4 2004-11-19 22:25:49 curt Exp $
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
# include <config.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <simgear/math/sg_geodesy.hxx>
|
||||||
|
#include <simgear/misc/texcoord.hxx>
|
||||||
|
#include <simgear/debug/logstream.hxx>
|
||||||
|
|
||||||
|
#include "tgconstruct.hxx"
|
||||||
|
|
||||||
|
TGPolygon TGConstruct::area_tex_coords( const TGPolygon& tri )
|
||||||
|
{
|
||||||
|
TGPolygon result;
|
||||||
|
result.erase();
|
||||||
|
|
||||||
|
// lots of conversion needed to use simgear API - perhaps we need a new simgear API?
|
||||||
|
for (int c=0; c<tri.contours(); c++)
|
||||||
|
{
|
||||||
|
// get the points, and calculate the elevations
|
||||||
|
point_list nodes = tri.get_contour(c);
|
||||||
|
std::vector< SGGeod > conv_geods;
|
||||||
|
point_list tex_coords;
|
||||||
|
|
||||||
|
for (int i = 0; i < (int)nodes.size(); ++i )
|
||||||
|
{
|
||||||
|
SGGeod conv_geod = SGGeod::fromDegM( nodes[i].x(), nodes[i].y(), nodes[i].z() );
|
||||||
|
SG_LOG(SG_GENERAL, SG_DEBUG, "geod pt = " << nodes[i] );
|
||||||
|
conv_geods.push_back( conv_geod );
|
||||||
|
}
|
||||||
|
|
||||||
|
// now calculate texture coordinates
|
||||||
|
// generate identity interger list...
|
||||||
|
std::vector< int > node_idx;
|
||||||
|
for (int i = 0; i < (int)conv_geods.size(); i++) {
|
||||||
|
node_idx.push_back(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector< SGVec2f > tp_list = sgCalcTexCoords( bucket, conv_geods, node_idx );
|
||||||
|
// generate a contour of texture coordinates from the tp list
|
||||||
|
for (int i = 0; i < (int)tp_list.size(); i++)
|
||||||
|
{
|
||||||
|
tex_coords.push_back( Point3D::fromSGVec2( tp_list[i] ) );
|
||||||
|
}
|
||||||
|
result.add_contour( tex_coords, 0 );
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
TGPolygon TGConstruct::linear_tex_coords( const TGPolygon& tri, const TGTexParams& tp )
|
||||||
|
{
|
||||||
|
TGPolygon result;
|
||||||
|
int i, j;
|
||||||
|
|
||||||
|
result.erase();
|
||||||
|
|
||||||
|
Point3D ref = tp.get_ref();
|
||||||
|
double width = tp.get_width();
|
||||||
|
double length = tp.get_length();
|
||||||
|
double heading = tp.get_heading();
|
||||||
|
double minu = tp.get_minu();
|
||||||
|
double maxu = tp.get_maxu();
|
||||||
|
double minv = tp.get_minv();
|
||||||
|
double maxv = tp.get_maxv();
|
||||||
|
SG_LOG( SG_GENERAL, SG_DEBUG, "section ref = " << ref );
|
||||||
|
SG_LOG( SG_GENERAL, SG_DEBUG, " width = " << width );
|
||||||
|
SG_LOG( SG_GENERAL, SG_DEBUG, " length = " << length );
|
||||||
|
SG_LOG( SG_GENERAL, SG_DEBUG, " heading = " << heading );
|
||||||
|
SG_LOG( SG_GENERAL, SG_DEBUG, " minv = " << minv );
|
||||||
|
SG_LOG( SG_GENERAL, SG_DEBUG, " maxv = " << maxv );
|
||||||
|
SG_LOG( SG_GENERAL, SG_DEBUG, " heading = " << heading );
|
||||||
|
|
||||||
|
Point3D p, t;
|
||||||
|
double x, y, tx, ty;
|
||||||
|
|
||||||
|
for ( i = 0; i < tri.contours(); ++i )
|
||||||
|
{
|
||||||
|
for ( j = 0; j < tri.contour_size( i ); ++j )
|
||||||
|
{
|
||||||
|
p = tri.get_pt( i, j );
|
||||||
|
SG_LOG(SG_GENERAL, SG_DEBUG, "tex coords for contour " << i << " point " << j << ": " << p );
|
||||||
|
|
||||||
|
//
|
||||||
|
// 1. Calculate distance and bearing from the center of
|
||||||
|
// the feature
|
||||||
|
//
|
||||||
|
|
||||||
|
// given alt, lat1, lon1, lat2, lon2, calculate starting
|
||||||
|
// and ending az1, az2 and distance (s). Lat, lon, and
|
||||||
|
// azimuth are in degrees. distance in meters
|
||||||
|
double az1, az2, dist;
|
||||||
|
geo_inverse_wgs_84( 0, ref.y(), ref.x(), p.y(), p.x(),
|
||||||
|
&az1, &az2, &dist );
|
||||||
|
SG_LOG(SG_GENERAL, SG_DEBUG, "basic course from ref = " << az2);
|
||||||
|
|
||||||
|
//
|
||||||
|
// 2. Rotate this back into a coordinate system where Y
|
||||||
|
// runs the length of the runway and X runs crossways.
|
||||||
|
//
|
||||||
|
|
||||||
|
double course = az2 - heading;
|
||||||
|
while ( course < -360 ) { course += 360; }
|
||||||
|
while ( course > 360 ) { course -= 360; }
|
||||||
|
SG_LOG( SG_GENERAL, SG_DEBUG,
|
||||||
|
" course = " << course << " dist = " << dist );
|
||||||
|
|
||||||
|
//
|
||||||
|
// 3. Convert from polar to cartesian coordinates
|
||||||
|
//
|
||||||
|
|
||||||
|
x = sin( course * SGD_DEGREES_TO_RADIANS ) * dist;
|
||||||
|
y = cos( course * SGD_DEGREES_TO_RADIANS ) * dist;
|
||||||
|
SG_LOG(SG_GENERAL, SG_DEBUG, " x = " << x << " y = " << y);
|
||||||
|
|
||||||
|
//
|
||||||
|
// 4. Map x, y point into texture coordinates
|
||||||
|
//
|
||||||
|
double tmp;
|
||||||
|
|
||||||
|
tmp = x / width;
|
||||||
|
tx = tmp * (maxu - minu) + minu;
|
||||||
|
|
||||||
|
if ( tx < -1.0 ) { tx = -1.0; }
|
||||||
|
if ( tx > 1.0 ) { tx = 1.0; }
|
||||||
|
|
||||||
|
SG_LOG(SG_GENERAL, SG_DEBUG, " (" << tx << ")");
|
||||||
|
|
||||||
|
ty = (y/length) + minv;
|
||||||
|
SG_LOG(SG_GENERAL, SG_DEBUG, " (" << ty << ")");
|
||||||
|
|
||||||
|
t = Point3D( tx, ty, 0 );
|
||||||
|
SG_LOG(SG_GENERAL, SG_DEBUG, " (" << tx << ", " << ty << ")");
|
||||||
|
|
||||||
|
result.add_node( i, t );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TGConstruct::CalcTextureCoordinates( void )
|
||||||
|
{
|
||||||
|
for ( unsigned int area = 0; area < TG_MAX_AREA_TYPES; area++ ) {
|
||||||
|
for( unsigned int shape = 0; shape < polys_clipped.area_size(area); shape++ ) {
|
||||||
|
for ( unsigned int segment = 0; segment < polys_clipped.shape_size(area, shape); segment++ ) {
|
||||||
|
TGPolygon poly = polys_clipped.get_poly(area, shape, segment);
|
||||||
|
SG_LOG( SG_CLIPPER, SG_INFO, "Texturing " << get_area_name( (AreaType)area ) << "(" << area << "): " <<
|
||||||
|
shape+1 << "-" << segment << " of " << polys_clipped.area_size(area) );
|
||||||
|
|
||||||
|
TGPolygon tri = polys_clipped.get_tris( area, shape, segment );
|
||||||
|
TGPolygon tc;
|
||||||
|
|
||||||
|
if ( polys_clipped.get_textured( area, shape ) ) {
|
||||||
|
SG_LOG(SG_GENERAL, SG_DEBUG, "USE TEXTURE PARAMS for tex coord calculations" );
|
||||||
|
tc = linear_tex_coords( tri, polys_clipped.get_texparams(area, shape, segment) );
|
||||||
|
} else {
|
||||||
|
SG_LOG(SG_GENERAL, SG_DEBUG, "USE SIMGEAR for tex coord calculations" );
|
||||||
|
tc = area_tex_coords( tri );
|
||||||
|
}
|
||||||
|
polys_clipped.set_texcoords( area, shape, segment, tc );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
80
src/BuildTiles/Main/tglandclass.cxx
Normal file
80
src/BuildTiles/Main/tglandclass.cxx
Normal file
|
@ -0,0 +1,80 @@
|
||||||
|
// TGLandclass.cxx -- Class toSimnplify dealing with shape heiarchy:
|
||||||
|
// landclass contains each area (layer) of a tile
|
||||||
|
// Each area is a list of shapes
|
||||||
|
// A shape has 1 or more segments
|
||||||
|
// (when the shape represents line data)
|
||||||
|
// And the segment is a superpoly, containing
|
||||||
|
// - a polygon, triangulation, point normals, face normals, etc.
|
||||||
|
//
|
||||||
|
// Written by Curtis Olson, started May 1999.
|
||||||
|
//
|
||||||
|
// Copyright (C) 1999 Curtis L. Olson - http://www.flightgear.org/~curt
|
||||||
|
//
|
||||||
|
// This program is free software; you can redistribute it and/or
|
||||||
|
// modify it under the terms of the GNU General Public License as
|
||||||
|
// published by the Free Software Foundation; either version 2 of the
|
||||||
|
// License, or (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful, but
|
||||||
|
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
// General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
//
|
||||||
|
// $Id: construct.hxx,v 1.13 2004-11-19 22:25:49 curt Exp $
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
# include <config.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "tglandclass.hxx"
|
||||||
|
|
||||||
|
void TGLandclass::clear(void)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i=0; i<TG_MAX_AREA_TYPES; i++) {
|
||||||
|
shapes[i].clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// input from stream
|
||||||
|
std::istream& operator >> ( std::istream& in, TGLandclass& lc)
|
||||||
|
{
|
||||||
|
int i, j, count;
|
||||||
|
|
||||||
|
// Load all landclass shapes
|
||||||
|
for (i=0; i<TG_MAX_AREA_TYPES; i++) {
|
||||||
|
in >> count;
|
||||||
|
|
||||||
|
for (j=0; j<count; j++) {
|
||||||
|
TGShape shape;
|
||||||
|
|
||||||
|
in >> shape;
|
||||||
|
lc.shapes[i].push_back( shape );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return in;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::ostream& operator<< ( std::ostream& out, const TGLandclass& lc )
|
||||||
|
{
|
||||||
|
int i, j, count;
|
||||||
|
TGShape shape;
|
||||||
|
|
||||||
|
// Save all landclass shapes
|
||||||
|
for (i=0; i<TG_MAX_AREA_TYPES; i++) {
|
||||||
|
count = lc.shapes[i].size();
|
||||||
|
out << count << "\n";
|
||||||
|
for (j=0; j<count; j++) {
|
||||||
|
out << lc.shapes[i][j] << " ";
|
||||||
|
}
|
||||||
|
out << "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
159
src/BuildTiles/Main/tglandclass.hxx
Normal file
159
src/BuildTiles/Main/tglandclass.hxx
Normal file
|
@ -0,0 +1,159 @@
|
||||||
|
// TGLandclass.hxx -- Class toSimnplify dealing with shape heiarchy:
|
||||||
|
// landclass contains each area (layer) of a tile
|
||||||
|
// Each area is a list of shapes
|
||||||
|
// A shape has 1 or more segments
|
||||||
|
// (when the shape represents line data)
|
||||||
|
// And the segment is a superpoly, containing
|
||||||
|
// - a polygon, triangulation, point normals, face normals, etc.
|
||||||
|
//
|
||||||
|
// Written by Curtis Olson, started May 1999.
|
||||||
|
//
|
||||||
|
// Copyright (C) 1999 Curtis L. Olson - http://www.flightgear.org/~curt
|
||||||
|
//
|
||||||
|
// This program is free software; you can redistribute it and/or
|
||||||
|
// modify it under the terms of the GNU General Public License as
|
||||||
|
// published by the Free Software Foundation; either version 2 of the
|
||||||
|
// License, or (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful, but
|
||||||
|
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
// General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
//
|
||||||
|
// $Id: construct.hxx,v 1.13 2004-11-19 22:25:49 curt Exp $
|
||||||
|
|
||||||
|
#ifndef _TGLANDCLASS_HXX
|
||||||
|
#define _TGLANDCLASS_HXX
|
||||||
|
|
||||||
|
#ifndef __cplusplus
|
||||||
|
# error This library requires C++
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define TG_MAX_AREA_TYPES 128
|
||||||
|
|
||||||
|
#include "tgshape.hxx"
|
||||||
|
|
||||||
|
class TGLandclass
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void clear(void);
|
||||||
|
|
||||||
|
inline unsigned int area_size( unsigned int area )
|
||||||
|
{
|
||||||
|
return shapes[area].size();
|
||||||
|
}
|
||||||
|
inline unsigned int shape_size( unsigned int area, unsigned int shape )
|
||||||
|
{
|
||||||
|
return shapes[area][shape].sps.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void add_shape( unsigned int area, TGShape shape )
|
||||||
|
{
|
||||||
|
shapes[area].push_back( shape );
|
||||||
|
}
|
||||||
|
inline TGShape& get_shape( unsigned int area, unsigned int shape )
|
||||||
|
{
|
||||||
|
return shapes[area][shape];
|
||||||
|
}
|
||||||
|
|
||||||
|
inline TGPolygon get_mask( unsigned int area, unsigned int shape )
|
||||||
|
{
|
||||||
|
return shapes[area][shape].clip_mask;
|
||||||
|
}
|
||||||
|
inline void set_mask( unsigned int area, unsigned int shape, TGPolygon mask )
|
||||||
|
{
|
||||||
|
shapes[area][shape].clip_mask = mask;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool get_textured( unsigned int area, unsigned int shape )
|
||||||
|
{
|
||||||
|
return shapes[area][shape].textured;
|
||||||
|
}
|
||||||
|
inline void set_textured( unsigned int area, unsigned int shape, bool t )
|
||||||
|
{
|
||||||
|
shapes[area][shape].textured = t;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline TGSuperPoly& get_superpoly( unsigned int area, unsigned int shape, unsigned int segment )
|
||||||
|
{
|
||||||
|
return shapes[area][shape].sps[segment];
|
||||||
|
}
|
||||||
|
inline void set_superpoly( unsigned int area, unsigned int shape, unsigned int segment, TGSuperPoly sp )
|
||||||
|
{
|
||||||
|
shapes[area][shape].sps[segment] = sp;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline TGPolygon get_poly( unsigned int area, unsigned int shape, unsigned int segment )
|
||||||
|
{
|
||||||
|
return shapes[area][shape].sps[segment].get_poly();
|
||||||
|
}
|
||||||
|
inline void set_poly( unsigned int area, unsigned int shape, unsigned int segment, TGPolygon poly )
|
||||||
|
{
|
||||||
|
return shapes[area][shape].sps[segment].set_poly( poly );
|
||||||
|
}
|
||||||
|
|
||||||
|
inline TGPolygon get_tris( unsigned int area, unsigned int shape, unsigned int segment )
|
||||||
|
{
|
||||||
|
return shapes[area][shape].sps[segment].get_tris();
|
||||||
|
}
|
||||||
|
inline void set_tris( unsigned int area, unsigned int shape, unsigned int segment, TGPolygon tris )
|
||||||
|
{
|
||||||
|
shapes[area][shape].sps[segment].set_tris( tris );
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Point3D get_face_normal( unsigned int area, unsigned int shape, unsigned int segment, unsigned int tri )
|
||||||
|
{
|
||||||
|
return shapes[area][shape].sps[segment].get_face_normal( tri );
|
||||||
|
}
|
||||||
|
|
||||||
|
inline double get_face_area( unsigned int area, unsigned int shape, unsigned int segment, unsigned int tri )
|
||||||
|
{
|
||||||
|
return shapes[area][shape].sps[segment].get_face_area( tri );
|
||||||
|
}
|
||||||
|
|
||||||
|
inline std::string get_flag( unsigned int area, unsigned int shape, unsigned int segment )
|
||||||
|
{
|
||||||
|
return shapes[area][shape].sps[segment].get_flag();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline std::string get_material( unsigned int area, unsigned int shape, unsigned int segment )
|
||||||
|
{
|
||||||
|
return shapes[area][shape].sps[segment].get_material();
|
||||||
|
}
|
||||||
|
inline TGTexParams& get_texparams( unsigned int area, unsigned int shape, unsigned int segment )
|
||||||
|
{
|
||||||
|
return shapes[area][shape].tps[segment];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline TGPolygon get_texcoords( unsigned int area, unsigned int shape, unsigned int segment )
|
||||||
|
{
|
||||||
|
return shapes[area][shape].sps[segment].get_texcoords();
|
||||||
|
}
|
||||||
|
inline void set_texcoords( unsigned int area, unsigned int shape, unsigned int segment, TGPolygon tcs )
|
||||||
|
{
|
||||||
|
return shapes[area][shape].sps[segment].set_texcoords( tcs );
|
||||||
|
}
|
||||||
|
|
||||||
|
inline TGPolyNodes get_tri_idxs( unsigned int area, unsigned int shape, unsigned int segment )
|
||||||
|
{
|
||||||
|
return shapes[area][shape].sps[segment].get_tri_idxs();
|
||||||
|
}
|
||||||
|
inline void set_tri_idxs( unsigned int area, unsigned int shape, unsigned int segment, TGPolyNodes tis )
|
||||||
|
{
|
||||||
|
return shapes[area][shape].sps[segment].set_tri_idxs( tis );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Friends for serialization
|
||||||
|
friend std::istream& operator>> ( std::istream&, TGLandclass& );
|
||||||
|
friend std::ostream& operator<< ( std::ostream&, const TGLandclass& );
|
||||||
|
|
||||||
|
private:
|
||||||
|
shape_list shapes[TG_MAX_AREA_TYPES];
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // _TGLANDCLASS_HXX
|
135
src/BuildTiles/Main/tgshape.cxx
Normal file
135
src/BuildTiles/Main/tgshape.cxx
Normal file
|
@ -0,0 +1,135 @@
|
||||||
|
// TGShape.cxx -- Class to handle polygons shapes generated in ogr-decode
|
||||||
|
// A shape may consist of many polygons when it is generated
|
||||||
|
// from a polyline. They are kept together to speed up clipping
|
||||||
|
// but also must be represented as seperate polygons in order to
|
||||||
|
// keep track of textur parameters.
|
||||||
|
//
|
||||||
|
// Written by Curtis Olson, started May 1999.
|
||||||
|
//
|
||||||
|
// Copyright (C) 1999 Curtis L. Olson - http://www.flightgear.org/~curt
|
||||||
|
//
|
||||||
|
// This program is free software; you can redistribute it and/or
|
||||||
|
// modify it under the terms of the GNU General Public License as
|
||||||
|
// published by the Free Software Foundation; either version 2 of the
|
||||||
|
// License, or (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful, but
|
||||||
|
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
// General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
//
|
||||||
|
// $Id: construct.cxx,v 1.4 2004-11-19 22:25:49 curt Exp $
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
# include <config.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "tgshape.hxx"
|
||||||
|
|
||||||
|
void TGShape::GetName( char* name ) const
|
||||||
|
{
|
||||||
|
sprintf( name, "%s_%d", get_area_name( (AreaType)area ).c_str(), id );
|
||||||
|
}
|
||||||
|
|
||||||
|
void TGShape::SetMask( TGPolygon mask )
|
||||||
|
{
|
||||||
|
clip_mask = mask;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TGShape::BuildMask( void )
|
||||||
|
{
|
||||||
|
TGPolygon poly;
|
||||||
|
clip_mask.erase();
|
||||||
|
|
||||||
|
for (unsigned int i=0; i<sps.size(); i++)
|
||||||
|
{
|
||||||
|
poly = sps[i].get_poly();
|
||||||
|
clip_mask = tgPolygonUnion( clip_mask, poly );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TGShape::IntersectPolys( void )
|
||||||
|
{
|
||||||
|
if ( sps.size() > 1 ) {
|
||||||
|
TGPolygon original, intersect;
|
||||||
|
|
||||||
|
for (unsigned int i=0; i<sps.size(); i++)
|
||||||
|
{
|
||||||
|
original = sps[i].get_poly();
|
||||||
|
|
||||||
|
intersect = tgPolygonInt( clip_mask, original );
|
||||||
|
|
||||||
|
sps[i].set_poly( intersect );
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
sps[0].set_poly( clip_mask );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Serialization
|
||||||
|
// input from stream
|
||||||
|
std::istream& operator >> ( std::istream& in, TGShape& p)
|
||||||
|
{
|
||||||
|
int i, count;
|
||||||
|
|
||||||
|
// First, load the clipmask
|
||||||
|
in >> p.clip_mask;
|
||||||
|
|
||||||
|
// Then load superpolys
|
||||||
|
in >> count;
|
||||||
|
for (i=0; i<count; i++) {
|
||||||
|
TGSuperPoly sp;
|
||||||
|
in >> sp;
|
||||||
|
p.sps.push_back( sp );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Then load texparams
|
||||||
|
in >> count;
|
||||||
|
for (i=0; i<count; i++) {
|
||||||
|
TGTexParams tp;
|
||||||
|
in >> tp;
|
||||||
|
p.tps.push_back( tp );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load the id, area type and textured flag
|
||||||
|
in >> p.id;
|
||||||
|
in >> p.area;
|
||||||
|
in >> p.textured;
|
||||||
|
|
||||||
|
return in;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::ostream& operator<< ( std::ostream& out, const TGShape& p )
|
||||||
|
{
|
||||||
|
int i, count;
|
||||||
|
TGSuperPoly sp;
|
||||||
|
TGTexParams tp;
|
||||||
|
|
||||||
|
// First, save the clipmask
|
||||||
|
out << p.clip_mask;
|
||||||
|
|
||||||
|
// Then save superpolys
|
||||||
|
count = p.sps.size();
|
||||||
|
out << count << "\n";
|
||||||
|
for (i=0; i<count; i++) {
|
||||||
|
out << p.sps[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Then save texparams
|
||||||
|
count = p.tps.size();
|
||||||
|
out << count << "\n";
|
||||||
|
for (i=0; i<count; i++) {
|
||||||
|
out << p.tps[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save the id, area type and textured flag
|
||||||
|
out << p.id << " ";
|
||||||
|
out << p.area << " ";
|
||||||
|
out << p.textured << "\n";
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
71
src/BuildTiles/Main/tgshape.hxx
Normal file
71
src/BuildTiles/Main/tgshape.hxx
Normal file
|
@ -0,0 +1,71 @@
|
||||||
|
// TGShape.hxx -- Class to handle polygons shapes generated in ogr-decode
|
||||||
|
// A shape may consist of many polygons when it is generated
|
||||||
|
// from a polyline. They are kept together to speed up clipping
|
||||||
|
// but also must be represented as seperate polygons in order to
|
||||||
|
// keep track of textur parameters.
|
||||||
|
//
|
||||||
|
// Written by Curtis Olson, started May 1999.
|
||||||
|
//
|
||||||
|
// Copyright (C) 1999 Curtis L. Olson - http://www.flightgear.org/~curt
|
||||||
|
//
|
||||||
|
// This program is free software; you can redistribute it and/or
|
||||||
|
// modify it under the terms of the GNU General Public License as
|
||||||
|
// published by the Free Software Foundation; either version 2 of the
|
||||||
|
// License, or (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful, but
|
||||||
|
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
// General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
//
|
||||||
|
// $Id: construct.hxx,v 1.13 2004-11-19 22:25:49 curt Exp $
|
||||||
|
|
||||||
|
#ifndef _TGSHAPE_HXX
|
||||||
|
#define _TGSHAPE_HXX
|
||||||
|
|
||||||
|
#ifndef __cplusplus
|
||||||
|
# error This library requires C++
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define TG_MAX_AREA_TYPES 128
|
||||||
|
|
||||||
|
//#include <string>
|
||||||
|
//#include <vector>
|
||||||
|
|
||||||
|
//#include <simgear/compiler.h>
|
||||||
|
//#include <simgear/debug/logstream.hxx>
|
||||||
|
|
||||||
|
#include <Polygon/superpoly.hxx>
|
||||||
|
#include <Polygon/texparams.hxx>
|
||||||
|
|
||||||
|
#include "priorities.hxx"
|
||||||
|
|
||||||
|
class TGShape
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
TGPolygon clip_mask;
|
||||||
|
bool textured;
|
||||||
|
superpoly_list sps;
|
||||||
|
texparams_list tps;
|
||||||
|
AreaType area;
|
||||||
|
unsigned int id;
|
||||||
|
|
||||||
|
void GetName( char* name ) const;
|
||||||
|
void SetMask( TGPolygon mask );
|
||||||
|
void BuildMask( void );
|
||||||
|
void IntersectPolys( void );
|
||||||
|
|
||||||
|
// Friends for serialization
|
||||||
|
friend std::istream& operator>> ( std::istream&, TGShape& );
|
||||||
|
friend std::ostream& operator<< ( std::ostream&, const TGShape& );
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef std::vector < TGShape > shape_list;
|
||||||
|
typedef shape_list::iterator shape_list_iterator;
|
||||||
|
typedef shape_list::const_iterator const_shape_list_iterator;
|
||||||
|
|
||||||
|
#endif // _TGSHAPE_HXX
|
Loading…
Reference in a new issue