1
0
Fork 0

Added new texturing method. Added sanity check for polygon file

reading.

New texturing method TG_TEX_HORIZ_REF requires that each polygon
has a reference texture coordinate specified for a specific point on the
polygon. The coordinate changes parallel to a direction (also
stored) and the other texture coordinate changes perpendicular
to this direction. The reference texture coordinates in polygons
of the same type can be chosen to match that of their neighbours
to produce a continous map onto a texture. This technique can
be used to texture rivers or cliffs as their direction
changes.

The sanity checks simply make sure that the number of contours
or polygons reported in a file are not too large. This could
happen if a polygon file was generated by a previous version
of terragear tools with an incompatible layout of polygon
information, or a non-polygon file is present in the input
directory and is opened as a polygon file.
This commit is contained in:
James.Hester 2019-02-24 23:03:00 +11:00
parent b718d909a4
commit 61ea3cd50a
9 changed files with 214 additions and 85 deletions

View file

@ -75,14 +75,21 @@ int TGConstruct::LoadLandclassPolys( void ) {
unsigned int count;
sgReadUInt( fp, &count );
if ( count > 1000000 ) {
SG_LOG( SG_GENERAL, SG_ALERT, " Too many polys in " << p.realpath() << ":" << count );
exit( EXIT_FAILURE );
}
SG_LOG( SG_GENERAL, SG_DEBUG, " Load " << count << " polys from " << p.realpath() );
for ( unsigned int idx = 0; idx < count; ++idx ) {
poly.LoadFromGzFile( fp );
if ( poly.LoadFromGzFile( fp ) == EXIT_FAILURE ) {
SG_LOG( SG_GENERAL, SG_DEBUG, "Failed to load from " << p.realpath() );
return EXIT_FAILURE;
}
int area = area_defs.get_area_priority( poly.GetFlag() );
material = area_defs.get_area_name( area );
bool isRoad = area_defs.is_road_area( area );
poly.SetMaterial( material );
poly.SetId( cur_poly_id++ );

View file

@ -30,14 +30,18 @@
void TGConstruct::CalcTextureCoordinates( void )
{
std::vector<SGGeod> geod_nodes;
nodes.get_geod_nodes( geod_nodes );
for ( unsigned int area = 0; area < area_defs.size(); area++ ) {
for( unsigned int p = 0; p < polys_clipped.area_size(area); p++ ) {
tgPolygon poly = polys_clipped.get_poly(area, p);
SG_LOG( SG_CLIPPER, SG_DEBUG, "Texturing " << area_defs.get_area_name(area) << "(" << area << "): " <<
p+1 << " of " << polys_clipped.area_size(area) << " with " << poly.GetMaterial() );
poly.Texture( );
poly.Texture( geod_nodes );
polys_clipped.set_poly(area, p, poly);
}
}
}
}

View file

@ -137,10 +137,18 @@ void TGArray::load_cliffs(const string & height_base)
gzFile fp = gzopen( p.c_str(), "rb" );
unsigned int count;
sgReadUInt( fp, &count );
SG_LOG( SG_GENERAL, SG_DEBUG, " Load " << count << " contours from " << p.realpath() );
// Sanity check
if ( count > 100000 ) {
SG_LOG( SG_GENERAL, SG_ALERT, "Too many polys (" << count << ") in " << p.realpath() );
exit(EXIT_FAILURE);
}
SG_LOG( SG_GENERAL, SG_DEBUG, " Load " << count << " polys from " << p.realpath() );
for ( unsigned int i=0; i<count; i++ ) {
poly.LoadFromGzFile( fp );
if ( poly.LoadFromGzFile( fp ) == EXIT_FAILURE ) {
SG_LOG( SG_GENERAL, SG_ALERT, "Error in file " << p.realpath() );
exit(EXIT_FAILURE);
}
if ( poly.Contours()==1 ) { //should always have one contour
cliffs_list.push_back(poly.GetContour(0));
} else {

View file

@ -33,6 +33,11 @@ tgPolygon tgChopper::Clip( const tgPolygon& subject,
// need to set center latitude for geodetic texturing
result.SetTexMethod( TG_TEX_BY_GEODE, b.get_center_lat() );
}
if ( subject.GetTexMethod() == TG_TEX_BY_HORIZ_REF ) {
// need to preserve reference point and coord
result.SetTexReference( subject.GetTexRefPt(), subject.GetRefTexCoord() );
}
result.SetFlag(type);
if (!subject.IsClosed()) {
result.SetOpen();
@ -133,6 +138,11 @@ void tgChopper::Add( const tgPolygon& subject, const std::string& type )
// need to set center latitude for geodetic texturing
clipped.SetTexMethod( TG_TEX_BY_GEODE, b_clip.get_center_lat() );
}
if ( subject.GetTexMethod() == TG_TEX_BY_HORIZ_REF ) {
// need to preserve reference point and coord
clipped.SetTexReference( subject.GetTexRefPt(), subject.GetRefTexCoord() );
}
clipped.SetFlag(type);
ClipRow( clipped, b_clip.get_center_lat(), type );

View file

@ -995,6 +995,11 @@ tgContour tgContour::Expand( const tgContour& subject, double offset )
}
tgpolygon_list tgContour::ExpandToPolygons( const tgContour& subject, double width )
{
return ExpandToPolygons(subject,width,TG_TEX_BY_TPS_CLIPU);
}
tgpolygon_list tgContour::ExpandToPolygons( const tgContour& subject, double width, int texturing )
{
SGGeod cur_inner;
SGGeod cur_outer;
@ -1007,6 +1012,7 @@ tgpolygon_list tgContour::ExpandToPolygons( const tgContour& subject, double wid
tgPolygon segment;
tgAccumulator accum("ExpandToPolygons");
tgpolygon_list result;
double total_length = 0; //Will become texture cooordinate
// generate poly and texparam lists for each line segment
for (unsigned int i = 0; i < subject.GetSize(); i++)
@ -1055,47 +1061,58 @@ tgpolygon_list tgContour::ExpandToPolygons( const tgContour& subject, double wid
expanded.AddNode( prev_inner );
expanded.AddNode( prev_outer );
// we need to extend one of the points so we're sure we don't create adjacent edges
if (turn_dir == 0)
{
// turned right - offset outer
if ( intersection( prev_inner, prev_outer, cur_inner, cur_outer, intersect ) )
{
// yes - make a triangle with inner edge = 0
expanded.AddNode( cur_outer );
cur_inner = prev_inner;
}
else
{
expanded.AddNode( cur_outer );
expanded.AddNode( cur_inner );
}
}
else
{
// turned left - offset inner
if ( intersection( prev_inner, prev_outer, cur_inner, cur_outer, intersect ) )
{
// yes - make a triangle with outer edge = 0
expanded.AddNode( cur_inner );
cur_outer = prev_outer;
}
else
{
expanded.AddNode( cur_outer );
expanded.AddNode( cur_inner );
}
}
// we need to extend one of the points so we're sure we don't create adjacent edges
if (turn_dir == 0)
{
// turned right - offset outer
if ( intersection( prev_inner, prev_outer, cur_inner, cur_outer, intersect ) )
{
// yes - make a triangle with inner edge = 0
expanded.AddNode( cur_outer );
cur_inner = prev_inner;
}
else
{
expanded.AddNode( cur_outer );
expanded.AddNode( cur_inner );
}
}
else
{
// turned left - offset inner
if ( intersection( prev_inner, prev_outer, cur_inner, cur_outer, intersect ) )
{
// yes - make a triangle with outer edge = 0
expanded.AddNode( cur_inner );
cur_outer = prev_outer;
}
else
{
expanded.AddNode( cur_outer );
expanded.AddNode( cur_inner );
}
}
double last_end_v = 0.0;
expanded.SetHole(false);
segment.AddContour(expanded);
segment.SetTexParams( prev_inner, width, 20.0f, heading );
segment.SetTexLimits( 0, last_end_v, 1, 1 );
segment.SetTexMethod( TG_TEX_BY_TPS_CLIPU, -1.0, 0.0, 1.0, 0.0 );
if( texturing == TG_TEX_BY_TPS_CLIPU )
{
segment.SetTexLimits( 0, last_end_v, 1, 1 );
segment.SetTexMethod( TG_TEX_BY_TPS_CLIPU, -1.0, 0.0, 1.0, 0.0 );
}
else
{
segment.SetTexMethod( TG_TEX_BY_HORIZ_REF );
segment.SetTexReference( prev_mp, total_length ); //Ref is midpoint
SG_LOG(SG_GENERAL, SG_DEBUG, "HORIZ_REF " << total_length);
}
result.push_back( segment );
total_length = total_length + dist; //Total length of line
// BUG??: value will never be utilized
last_end_v = 1.0f - (fmod( (double)(dist - last_end_v), (double)1.0f ));
}
@ -1131,6 +1148,11 @@ void tgContour::LoadFromGzFile( gzFile& fp )
// Load the nodelist
sgReadUInt( fp, &count );
// Sanity check
if ( count > 1000000 ) {
SG_LOG(SG_GENERAL,SG_ALERT, "Got bad contour count " << count);
exit(1);
}
for (unsigned int i = 0; i < count; i++) {
sgReadGeod( fp, node );
node_list.push_back( node );

View file

@ -46,13 +46,13 @@ public:
return hole;
}
bool GetOpen(void) const {
return keep_open;
}
bool GetOpen(void) const {
return keep_open;
}
void SetOpen(bool o) {
keep_open = o;
}
void SetOpen(bool o) {
keep_open = o;
}
unsigned int GetSize( void ) const {
return node_list.size();
@ -65,15 +65,19 @@ public:
void AddNode( SGGeod n ) {
node_list.push_back( n );
}
void SetNode( unsigned int i, SGGeod n ) {
node_list[i] = n;
}
void DelNode( unsigned int i ) {
node_list.erase( node_list.begin()+i);
}
SGGeod GetNode( unsigned int i ) const {
return node_list[i];
}
SGGeod const& operator[]( int index ) const {
return node_list[index];
}
@ -83,6 +87,7 @@ public:
node_list.erase( node_list.begin() + idx );
}
}
void RemoveNodeRange( unsigned int from, unsigned int to ) {
if ( ( from < to ) && ( to < node_list.size() ) ) {
node_list.erase( node_list.begin()+from,node_list.begin()+to );
@ -139,6 +144,7 @@ public:
static tgContour Expand( const tgContour& subject, double offset );
static tgpolygon_list ExpandToPolygons( const tgContour& subject, double width );
static tgpolygon_list ExpandToPolygons( const tgContour& subject, double width, int texturing );
static void ToShapefile( const tgContour& subject, const std::string& datasource, const std::string& layer, const std::string& feature );
@ -151,7 +157,7 @@ public:
private:
std::vector<SGGeod> node_list;
bool hole;
bool keep_open; //If non-closed contour, keep open
bool keep_open; //If non-closed contour, keep open
};
typedef std::vector <tgContour> tgcontour_list;

View file

@ -207,7 +207,7 @@ void tgPolygon::InheritElevations( const tgPolygon& source )
}
}
void tgPolygon::Texture( void )
void tgPolygon::Texture( const std::vector<SGGeod>& geod_nodes )
{
SGGeod p;
SGVec2f t;
@ -240,8 +240,10 @@ void tgPolygon::Texture( void )
case TG_TEX_BY_TPS_CLIPU:
case TG_TEX_BY_TPS_CLIPV:
case TG_TEX_BY_TPS_CLIPUV:
case TG_TEX_BY_HORIZ_REF:
{
for ( unsigned int i = 0; i < triangles.size(); i++ ) {
SG_LOG(SG_GENERAL, SG_DEBUG, "Triangle " << i);
for ( unsigned int j = 0; j < 3; j++ ) {
p = triangles[i].GetNode( j );
SG_LOG(SG_GENERAL, SG_DEBUG, "point = " << p);
@ -277,28 +279,42 @@ void tgPolygon::Texture( void )
//
// 4. Map x, y point into texture coordinates
//
float tmp;
tmp = (float)x / (float)tp.width;
float tx = tmp * (float)(tp.maxu - tp.minu) + (float)tp.minu;
SG_LOG(SG_GENERAL, SG_DEBUG, " (" << tx << ")");
// clip u?
if ( (tp.method == TG_TEX_BY_TPS_CLIPU) || (tp.method == TG_TEX_BY_TPS_CLIPUV) ) {
if ( tx < (float)tp.min_clipu ) { tx = (float)tp.min_clipu; }
if ( tx > (float)tp.max_clipu ) { tx = (float)tp.max_clipu; }
float tmp,tx,ty;
if ( tp.method == TG_TEX_BY_HORIZ_REF ) {
// The horizontal coordinate is textured as a continuous
// coordinate through all polygons, the vertical coordinate
// is based on (geodetic) height only
SGGeod fullpt = geod_nodes[ GetTriIdx(i,j) ];
SG_LOG(SG_GENERAL, SG_DEBUG, "full pt = " << fullpt);
SG_LOG(SG_GENERAL, SG_DEBUG, "texture start = " << tp.custom_s);
ty = fullpt.getElevationM();
tx = tp.custom_s - (float) y;
// and scale...we assume a 1000m x 1000m scale
tx = tx / 1000.0;
ty = ty / 1000.0;
}
else
{
tmp = (float)x / (float)tp.width;
tx = tmp * (float)(tp.maxu - tp.minu) + (float)tp.minu;
SG_LOG(SG_GENERAL, SG_DEBUG, " (" << tx << ")");
tmp = (float)y / (float)tp.length;
float ty = tmp * (float)(tp.maxv - tp.minv) + (float)tp.minv;
SG_LOG(SG_GENERAL, SG_DEBUG, " (" << ty << ")");
// clip u?
if ( (tp.method == TG_TEX_BY_TPS_CLIPU) || (tp.method == TG_TEX_BY_TPS_CLIPUV) ) {
if ( tx < (float)tp.min_clipu ) { tx = (float)tp.min_clipu; }
if ( tx > (float)tp.max_clipu ) { tx = (float)tp.max_clipu; }
}
// clip v?
if ( (tp.method == TG_TEX_BY_TPS_CLIPV) || (tp.method == TG_TEX_BY_TPS_CLIPUV) ) {
if ( ty < (float)tp.min_clipv ) { ty = (float)tp.min_clipv; }
if ( ty > (float)tp.max_clipv ) { ty = (float)tp.max_clipv; }
tmp = (float)y / (float)tp.length;
ty = tmp * (float)(tp.maxv - tp.minv) + (float)tp.minv;
SG_LOG(SG_GENERAL, SG_DEBUG, " (" << ty << ")");
// clip v?
if ( (tp.method == TG_TEX_BY_TPS_CLIPV) || (tp.method == TG_TEX_BY_TPS_CLIPUV) ) {
if ( ty < (float)tp.min_clipv ) { ty = (float)tp.min_clipv; }
if ( ty > (float)tp.max_clipv ) { ty = (float)tp.max_clipv; }
}
}
t = SGVec2f( tx, ty );
SG_LOG(SG_GENERAL, SG_DEBUG, " (" << tx << ", " << ty << ")");
@ -333,7 +349,7 @@ void tgPolygon::SaveToGzFile( gzFile& fp ) const
sgWriteInt( fp, (int)preserve3d );
}
void tgPolygon::LoadFromGzFile( gzFile& fp )
int tgPolygon::LoadFromGzFile( gzFile& fp )
{
unsigned int count;
tgContour contour;
@ -345,6 +361,12 @@ void tgPolygon::LoadFromGzFile( gzFile& fp )
// Load the contours
sgReadUInt( fp, &count );
// Sanity check
if ( count > 100000 ) {
SG_LOG(SG_GENERAL,SG_ALERT, "Got bad contour count " << count);
return EXIT_FAILURE;
}
for (unsigned int i = 0; i < count; i++) {
contour.LoadFromGzFile( fp );
AddContour(contour);
@ -352,13 +374,20 @@ void tgPolygon::LoadFromGzFile( gzFile& fp )
// load the triangles
sgReadUInt( fp, &count );
// Sanity check
if ( count > 1000000 ) {
SG_LOG(SG_GENERAL,SG_ALERT, "Got bad triangle count " << count);
return EXIT_FAILURE;
}
for (unsigned int i = 0; i < count; i++) {
triangle.LoadFromGzFile( fp );
AddTriangle(triangle);
}
// Load the tex params
tp.LoadFromGzFile( fp );
if ( tp.LoadFromGzFile( fp ) == EXIT_FAILURE ) {
return EXIT_FAILURE;
}
// and the rest
sgReadString( fp, &strbuff );
@ -374,6 +403,7 @@ void tgPolygon::LoadFromGzFile( gzFile& fp )
}
sgReadInt( fp, (int *)&preserve3d );
return EXIT_SUCCESS;
}
void tgPolygon::ToClipperFile( const tgPolygon& subject, const std::string& path, const std::string& filename )
@ -513,14 +543,22 @@ void tgTexParams::SaveToGzFile( gzFile& fp ) const
sgWriteDouble( fp, min_clipv );
sgWriteDouble( fp, max_clipv );
}
if ( method == TG_TEX_BY_HORIZ_REF ) {
sgWriteDouble( fp, custom_s );
}
}
}
void tgTexParams::LoadFromGzFile( gzFile& fp )
int tgTexParams::LoadFromGzFile( gzFile& fp )
{
// Load the parameters
sgReadInt( fp, (int*)&method );
// Sanity check
if ( method > 100 ) {
SG_LOG( SG_GENERAL,SG_ALERT, "Got bad texture method " << method );
return EXIT_FAILURE;
}
if ( method == TG_TEX_BY_GEODE ) {
sgReadDouble( fp, &center_lat );
} else {
@ -545,5 +583,10 @@ void tgTexParams::LoadFromGzFile( gzFile& fp )
sgReadDouble( fp, &min_clipv );
sgReadDouble( fp, &max_clipv );
}
if ( method == TG_TEX_BY_HORIZ_REF) {
sgReadDouble( fp, &custom_s );
}
}
}
return EXIT_SUCCESS;
}

View file

@ -206,7 +206,8 @@ typedef enum {
TG_TEX_BY_TPS_NOCLIP,
TG_TEX_BY_TPS_CLIPU,
TG_TEX_BY_TPS_CLIPV,
TG_TEX_BY_TPS_CLIPUV
TG_TEX_BY_TPS_CLIPUV,
TG_TEX_BY_HORIZ_REF //Tex coord calculated from ht and horiz reference
} tgTexMethod;
class tgTexParams
@ -227,12 +228,14 @@ public:
double min_clipv;
double max_clipv;
double custom_s;
tgTexMethod method;
double center_lat;
void SaveToGzFile( gzFile& fp ) const;
void LoadFromGzFile( gzFile& fp );
int LoadFromGzFile( gzFile& fp );
// Friend for output
friend std::ostream& operator<< ( std::ostream&, const tgTexParams& );
@ -245,6 +248,7 @@ public:
preserve3d = false;
closed = true;
id = 0;
tp.method = TG_TEX_BY_GEODE;
}
~tgPolygon() {
@ -405,6 +409,7 @@ public:
void SetTexMethod( tgTexMethod m ) {
tp.method = m;
}
void SetTexMethod( tgTexMethod m, double min_cu, double min_cv, double max_cu, double max_cv ) {
tp.method = m;
tp.min_clipu = min_cu;
@ -416,10 +421,24 @@ public:
tp.method = m;
tp.center_lat = cl;
}
void SetTexReference( SGGeod g, double tex_coord ) {
tp.ref = g;
tp.custom_s = tex_coord;
}
SGGeod GetTexRefPt() const {
return tp.ref;
}
double GetRefTexCoord() const {
return tp.custom_s;
}
tgTexMethod GetTexMethod( void ) const {
return tp.method;
}
void Texture( void );
void Texture( const std::vector<SGGeod>& geod_nodes );
// Tesselation
void Tesselate( void );
@ -463,7 +482,7 @@ public:
// IO
void SaveToGzFile( gzFile& fp ) const;
void LoadFromGzFile( gzFile& fp );
int LoadFromGzFile( gzFile& fp );
friend std::ostream& operator<< ( std::ostream&, const tgPolygon& );
@ -476,7 +495,7 @@ private:
bool preserve3d;
unsigned int id; // unique polygon id for debug
tgTexParams tp;
bool closed; // if we treat it as a closed shape
bool closed; // if we treat it as a closed shape
};
#endif // _POLYGON_HXX

View file

@ -57,6 +57,7 @@ string area_type="Default";
string area_type_col;
int continue_on_errors=0;
bool texture_lines = false;
bool texture_cliffs = false;
int seperate_segments = 0;
int max_segment_length=0; // ==0 => don't split
int start_record=0;
@ -99,7 +100,7 @@ private:
virtual void run();
void processPoint(OGRPoint* poGeometry, const string& area_type, int width );
void processLineString(OGRLineString* poGeometry, const string& area_type, int width, int with_texture );
void processLineString(OGRLineString* poGeometry, const string& area_type, int width, int with_texture, bool texture_cliffs );
void processPolygon(OGRPolygon* poGeometry, const string& area_type );
private:
@ -128,7 +129,7 @@ void Decoder::processPoint(OGRPoint* poGeometry, const string& area_type, int wi
chopper.Add( shape, area_type );
}
void Decoder::processLineString(OGRLineString* poGeometry, const string& area_type, int width, int with_texture )
void Decoder::processLineString(OGRLineString* poGeometry, const string& area_type, int width, int with_texture, bool texture_cliffs )
{
tgpolygon_list segments;
tgContour line;
@ -184,15 +185,17 @@ void Decoder::processLineString(OGRLineString* poGeometry, const string& area_ty
line.AddNode( SGGeodesy::direct(p1, heading, EP_STRETCH) );
// make a plygons from the line segments
segments = tgContour::ExpandToPolygons( line, width );
int texturing;
if ( with_texture ) {
texturing = TG_TEX_BY_TPS_CLIPU;
}
else {
texturing = TG_TEX_BY_GEODE;
}
if ( texture_cliffs ) texturing = TG_TEX_BY_HORIZ_REF;
segments = tgContour::ExpandToPolygons( line, width, texturing );
for ( unsigned int i = 0; i < segments.size(); ++i ) {
segments[i].SetPreserve3D( false );
if (with_texture) {
segments[i].SetTexMethod( TG_TEX_BY_TPS_CLIPU );
} else {
segments[i].SetTexMethod( TG_TEX_BY_GEODE );
}
chopper.Add( segments[i], area_type );
}
}
@ -311,7 +314,8 @@ void Decoder::run()
}
}
processLineString((OGRLineString*)poGeometry, area_type_name, width, texture_lines);
processLineString((OGRLineString*)poGeometry, area_type_name, width, texture_lines,
texture_cliffs);
break;
}
case wkbMultiLineString: {
@ -326,7 +330,7 @@ void Decoder::run()
OGRMultiLineString* multilines=(OGRMultiLineString*)poGeometry;
for (int i = 0; i < multilines->getNumGeometries(); ++i) {
processLineString((OGRLineString*)(multilines->getGeometryRef(i)), area_type_name, width, texture_lines);
processLineString((OGRLineString*)(multilines->getGeometryRef(i)), area_type_name, width, texture_lines, texture_cliffs);
}
break;
}
@ -525,6 +529,8 @@ void usage(char* progname) {
SG_LOG( SG_GENERAL, SG_ALERT, " spatial query extents" );
SG_LOG( SG_GENERAL, SG_ALERT, "--texture-lines" );
SG_LOG( SG_GENERAL, SG_ALERT, " Enable textured lines" );
SG_LOG( SG_GENERAL, SG_ALERT, "--texture-cliffs" );
SG_LOG( SG_GENERAL, SG_ALERT, " Generate texture coordinates for cliff faces" );
SG_LOG( SG_GENERAL, SG_ALERT, "--threads" );
SG_LOG( SG_GENERAL, SG_ALERT, " Enable multithreading with user specified number of threads" );
SG_LOG( SG_GENERAL, SG_ALERT, "--all-threads" );
@ -623,6 +629,10 @@ int main( int argc, char **argv ) {
argv++;
argc--;
texture_lines=true;
} else if (!strcmp(argv[1],"--texture-cliffs")) {
argv++;
argc--;
texture_cliffs=true;
} else if (!strcmp(argv[1],"--seperate-segments")) {
argv++;
argc--;