1
0
Fork 0

another stability checkpoint

- found a bug in the polygon library: remove_small_cycles.
  If the cycle wrapped around the end of the point list, it went undetected.
  I created a new detection method, that is slower, but handles this case
  FIXES DNAK
- Added a new polygon cleaner function remove_spikes
  triangulation library doesn't like when segments for close to 0 degree
  angles.  When such an angle is seen (<.1 degree), the point is removed
  FIXES LFKJ (linear features) and YBAF (pavements and base polys)
- I also modified the runway shoulder code to use 11+ meter width.
  I was having problens with polys very close to this leaving a gap.
  The code needs revisiting, since I now see z-fighting betwen the shoulder
  and grass border.

From this point on, all my checkins need to get past the previous checkins
airport.  I am now parsing past LFSB
This commit is contained in:
Peter Sadrozinski 2012-02-05 00:10:06 -05:00 committed by Christian Schmitt
parent 1090e602c2
commit 9f96783df6
7 changed files with 280 additions and 32 deletions

View file

@ -668,6 +668,8 @@ void Airport::BuildBtg(const string& root, const string_list& elev_src )
poly = remove_dups( poly );
poly = remove_bad_contours( poly );
poly = remove_tiny_contours( poly );
poly = remove_spikes( poly );
poly = remove_bad_contours( poly );
rwy_polys[k].set_poly( poly );
}
@ -682,6 +684,8 @@ void Airport::BuildBtg(const string& root, const string_list& elev_src )
poly = remove_dups( poly );
poly = remove_bad_contours( poly );
poly = remove_tiny_contours( poly );
poly = remove_spikes( poly );
poly = remove_bad_contours( poly );
pvmt_polys[k].set_poly( poly );
}
@ -696,6 +700,8 @@ void Airport::BuildBtg(const string& root, const string_list& elev_src )
poly = remove_dups( poly );
poly = remove_bad_contours( poly );
poly = remove_tiny_contours( poly );
poly = remove_spikes( poly );
poly = remove_bad_contours( poly );
line_polys[k].set_poly( poly );
}
@ -715,6 +721,8 @@ void Airport::BuildBtg(const string& root, const string_list& elev_src )
base_poly = remove_dups( base_poly );
base_poly = remove_bad_contours( base_poly );
base_poly = remove_tiny_contours( base_poly );
base_poly = remove_spikes( base_poly );
base_poly = remove_bad_contours( base_poly );
gettimeofday(&cleanup_end, NULL);
timersub(&cleanup_end, &cleanup_start, &cleanup_time);
@ -729,9 +737,12 @@ void Airport::BuildBtg(const string& root, const string_list& elev_src )
TGPolygon poly = rwy_polys[i].get_poly();
#if 0
if ( i == 62 ) {
if ( i == 162 ) {
tgChopNormalPolygon( "/home/pete", "Base", poly, false );
verbose_triangulation = true;
} else {
verbose_triangulation = false;
}
#endif
@ -754,7 +765,9 @@ void Airport::BuildBtg(const string& root, const string_list& elev_src )
TGPolygon poly = pvmt_polys[i].get_poly();
#if 0
if ( i == 0 ) {
if ( i == 1 ) {
SG_LOG(SG_GENERAL, SG_INFO, "Problem poly: " << poly );
tgChopNormalPolygon( "/home/pete", "Base", poly, false );
verbose_triangulation = true;
} else {
@ -788,7 +801,9 @@ void Airport::BuildBtg(const string& root, const string_list& elev_src )
TGPolygon poly = line_polys[i].get_poly();
#if 0
if ( i == 4558 ) {
if ( i == 627 ) {
SG_LOG(SG_GENERAL, SG_INFO, "Problem poly: " << poly );
tgChopNormalPolygon( "/home/pete", "Base", poly, false );
verbose_triangulation = true;
} else {
@ -809,6 +824,8 @@ void Airport::BuildBtg(const string& root, const string_list& elev_src )
#if 0
{
SG_LOG(SG_GENERAL, SG_INFO, "Problem poly: " << base_poly );
tgChopNormalPolygon( "/home/pete", "Base", base_poly, false );
verbose_triangulation = true;
}

View file

@ -343,10 +343,12 @@ void Runway::BuildShoulder( float alt_m,
double shoulder_width = 0.0f;
if (rwy.shoulder > 0){ // Add a shoulder to the runway
shoulder_width = rwy.width * 0.15;
if (shoulder_width > 8.0){
shoulder_width = 8.0;
}
//shoulder_width = rwy.width * 0.15;
//if (shoulder_width > 11.0){
// shoulder_width = 11.0;
//}
shoulder_width = 11.0f;
if (rwy.shoulder == 1){
shoulder_surface = "pa_shoulder";
} else if (rwy.shoulder == 2){
@ -368,13 +370,10 @@ void Runway::BuildShoulder( float alt_m,
// we need to break these shoulders up into managable pieces, as we're asked to triangulate
// 3-4 km long by 1m wide strips - jrs-can't handle it.
double max_dist = (double)shoulder_width * 50.0f;
double max_dist = (double)shoulder_width * 25.0f;
int numSegs = (rwy.length / max_dist) + 1;
double dist = rwy.length / (double)numSegs;
//int numSegs = 1;
//double dist = rwy.length;
// Create both shoulder sides
for (int i=0; i<2; ++i){
double step;
@ -384,9 +383,9 @@ void Runway::BuildShoulder( float alt_m,
/* If the are 'equal' there's a good chance roundoff error can create a */
/* REALY thin long polygon, which causes a segfault */
if (i == 0){
step= (rwy.width + shoulder_width)*0.5;
step= (rwy.width + shoulder_width) * 0.5;
} else if (i == 1) {
step= -(rwy.width + shoulder_width)*0.5;
step= -(rwy.width + shoulder_width) * 0.5;
}
double left_hdg = rwy.heading - 90.0;
@ -398,7 +397,7 @@ void Runway::BuildShoulder( float alt_m,
for (int j=0; j<numSegs; j++)
{
geo_direct_wgs_84 ( alt_m, ref.y(), ref.x(), rwy.heading, (j*dist), &lat, &lon, &r );
TGPolygon shoulderSegment = gen_wgs84_rect( lat, lon, rwy.heading, dist, shoulder_width+0.1 );
TGPolygon shoulderSegment = gen_wgs84_rect( lat, lon, rwy.heading, dist, shoulder_width+1.0f );
TGSuperPoly sp;
TGTexParams tp;

View file

@ -37,6 +37,7 @@
#include <simgear/compiler.h>
#include <stdio.h>
#include <cassert>
#include <cmath>
#include <istream>
@ -170,7 +171,9 @@ operator >> ( std::istream& in, Point3D& p)
inline std::ostream&
operator<< ( std::ostream& out, const Point3D& p )
{
return out << p.n[PX] << ", " << p.n[PY] << ", " << p.n[PZ];
char buff[128];
sprintf( buff, "(%3.10lf, %3.10lf, %3.10lf)", p.n[PX], p.n[PY], p.n[PZ]);
return out << buff;
}
///////////////////////////

View file

@ -1076,21 +1076,35 @@ TGPolygon reduce_degeneracy( const TGPolygon& poly ) {
}
// find short cycles in a contour and snip them out.
#if 0
static point_list remove_small_cycles( const point_list& contour ) {
point_list result;
result.clear();
#if 0 // this isn't detected !
(5.3060288916,7.2584178625,-9999.0000000000)
(5.3060247586,7.2584197157,-9999.0000000000)
(5.3059325744,7.2582152235,-9999.0000000000)
(5.3059201957,7.2582207878,-9999.0000000000)
(5.3060123814,7.2584252839,-9999.0000000000)
(5.3060247586,7.2584197157,-9999.0000000000)
#endif
unsigned int i = 0;
while ( i < contour.size() ) {
result.push_back( contour[i] );
for ( unsigned int j = i + 1; j < contour.size(); ++j ) {
if ( contour[i] == contour[j] && i + 4 > j ) {
// cout << "detected a small cycle: i = "
// << i << " j = " << j << endl;
//for ( unsigned int k = i; k <= j; ++k ) {
// cout << " " << contour[k] << endl;
//}
i = j;
if ( contour[i] == contour[j] ) {
if ( i + 4 > j ) {
SG_LOG(SG_GENERAL, SG_INFO, "detected a small cycle: i = " << i << " j = " << j );
for ( unsigned int k = i; k <= j; ++k ) {
SG_LOG(SG_GENERAL, SG_INFO, " " << contour[k] );
}
i = j;
}
else {
SG_LOG(SG_GENERAL, SG_INFO, "detected a cycle, but i = " << i << " j = " << j );
}
}
}
++i;
@ -1098,6 +1112,93 @@ static point_list remove_small_cycles( const point_list& contour ) {
return result;
}
#endif
static point_list remove_small_cycles( const point_list& contour ) {
point_list result;
bool found;
result.clear();
int iters = 0;
#if 0 // this isn't detected !
(5.3060288916,7.2584178625,-9999.0000000000)
(5.3060247586,7.2584197157,-9999.0000000000)
(5.3059325744,7.2582152235,-9999.0000000000)
(5.3059201957,7.2582207878,-9999.0000000000)
(5.3060123814,7.2584252839,-9999.0000000000)
(5.3060247586,7.2584197157,-9999.0000000000)
#endif
for ( unsigned int i = 0; i < contour.size(); i++ )
{
result.push_back( contour[i] );
}
SG_LOG(SG_GENERAL, SG_DEBUG, "remove small cycles : original contour has " << result.size() << " points" );
do
{
found = false;
// Step 1 - find a duplicate point
for ( unsigned int i = 0; i < result.size() && !found; i++ ) {
// first check until the end of the vector
for ( unsigned int j = i + 1; j < result.size() && !found; j++ ) {
if ( result[i] == result[j] ) {
SG_LOG(SG_GENERAL, SG_DEBUG, "detected a dupe: i = " << i << " j = " << j );
// We found a dupe - calculate the distance between them
if ( i + 4 > j ) {
// it's within target distance - remove the points in between, and start again
if ( j-i == 1 ) {
SG_LOG(SG_GENERAL, SG_DEBUG, "detected a small cycle: i = " << i << " j = " << j << " Erasing " << i );
result.erase( result.begin()+i );
} else {
SG_LOG(SG_GENERAL, SG_DEBUG, "detected a small cycle: i = " << i << " j = " << j << " Erasing from " << i << " to " << j-1 );
result.erase( result.begin()+i,result.begin()+(j-1) );
}
found = true;
}
}
}
// then check from beginning to the first point (wrap around)
for ( unsigned int j = 0; j < i && !found; j++ ) {
if ( (i != j) && (result[i] == result[j]) ) {
SG_LOG(SG_GENERAL, SG_DEBUG, "detected a dupe: i = " << i << " j = " << j );
// We found a dupe - calculate the distance between them
if ( (result.size() - i + j) < 4 ) {
// it's within target distance - remove from the end point to the end of the vector
if ( i == result.size() - 1 ) {
SG_LOG(SG_GENERAL, SG_DEBUG, "detected a small cycle: i = " << i << " j = " << j << " Erasing " << result.size()-1 );
result.erase( result.begin()+result.size()-1 );
} else {
SG_LOG(SG_GENERAL, SG_DEBUG, "detected a small cycle: i = " << i << " j = " << j << " Erasing from " << i << " to " << result.size()-1 );
result.erase( result.begin()+i, result.begin()+result.size()-1 );
}
// then remove from the beginning of the vector to the beginning point
if ( j == 1 ) {
SG_LOG(SG_GENERAL, SG_DEBUG, "detected a small cycle: i = " << i << " j = " << j << " Erasing " << j-1 );
result.erase( result.begin() );
} else if ( j > 1) {
SG_LOG(SG_GENERAL, SG_DEBUG, "detected a small cycle: i = " << i << " j = " << j << " Erasing from 0 " << " to " << j-1 );
result.erase( result.begin(), result.begin()+j-1 );
}
found = true;
}
}
}
}
iters++;
SG_LOG(SG_GENERAL, SG_DEBUG, "remove small cycles : after " << iters << "iterations, contour has " << result.size() << " points" );
} while( found );
return result;
}
// Occasionally the outline of the clipped polygon can take a side
@ -1108,15 +1209,108 @@ TGPolygon remove_cycles( const TGPolygon& poly ) {
TGPolygon result;
// cout << "remove cycles: " << poly << endl;
for ( int i = 0; i < poly.contours(); ++i ) {
point_list contour = poly.get_contour(i);
contour = remove_small_cycles( contour );
result.add_contour( contour, poly.get_hole_flag(i) );
point_list contour = poly.get_contour(i);
contour = remove_small_cycles( contour );
result.add_contour( contour, poly.get_hole_flag(i) );
}
return result;
}
static double CalculateTheta( Point3D p0, Point3D p1, Point3D p2 )
{
Point3D u, v;
double udist, vdist, uv_dot, tmp;
// u . v = ||u|| * ||v|| * cos(theta)
u = p1 - p0;
udist = sqrt( u.x() * u.x() + u.y() * u.y() );
// printf("udist = %.6f\n", udist);
v = p1 - p2;
vdist = sqrt( v.x() * v.x() + v.y() * v.y() );
// printf("vdist = %.6f\n", vdist);
uv_dot = u.x() * v.x() + u.y() * v.y();
// printf("uv_dot = %.6f\n", uv_dot);
tmp = uv_dot / (udist * vdist);
// printf("tmp = %.6f\n", tmp);
return acos(tmp);
}
static point_list remove_contour_spikes( const point_list& contour ) {
point_list result;
result.clear();
int iters = 0;
double theta;
bool found;
Point3D cur, prev, next;
for ( unsigned int i = 0; i < contour.size(); i++ )
{
result.push_back( contour[i] );
}
do
{
SG_LOG(SG_GENERAL, SG_DEBUG, "remove_contour_spikes: start new iteration");
found = false;
// Step 1 - find a duplicate point
for ( unsigned int i = 0; i < result.size() && !found; i++ ) {
if (i == 0) {
SG_LOG(SG_GENERAL, SG_DEBUG, " cur is first point: " << i << ": " << result[0]);
cur = result[0];
prev = result[result.size()-1];
next = result[1];
} else if ( i == result.size()-1 ) {
SG_LOG(SG_GENERAL, SG_DEBUG, " cur is last point: " << i << ": " << result[i]);
cur = result[i];
prev = result[i-1];
next = result[0];
} else {
SG_LOG(SG_GENERAL, SG_DEBUG, " cur is: " << i << ": " << result[i] );
cur = result[i];
prev = result[i-1];
next = result[i+1];
}
theta = SGMiscd::rad2deg(CalculateTheta(prev, cur, next));
if ( abs(theta) < 0.1 ) {
SG_LOG(SG_GENERAL, SG_DEBUG, "remove_contour_spikes: (theta is " << theta << ") erasing " << i << " prev is " << prev << " cur is " << cur << " next is " << next );
result.erase( result.begin()+i );
found = true;
}
}
iters++;
SG_LOG(SG_GENERAL, SG_DEBUG, "remove_contour_spikes : after " << iters << "iterations, contour has " << result.size() << " points" );
} while( found );
return result;
}
TGPolygon remove_spikes( const TGPolygon& poly )
{
TGPolygon result;
// cout << "remove spikes: " << poly << endl;
for ( int i = 0; i < poly.contours(); ++i ) {
point_list contour = poly.get_contour(i);
contour = remove_contour_spikes( contour );
result.add_contour( contour, poly.get_hole_flag(i) );
}
return result;
}
// remove any degenerate contours
TGPolygon remove_bad_contours( const TGPolygon &poly ) {
TGPolygon result;

View file

@ -91,6 +91,11 @@ TGPolygon reduce_degeneracy( const TGPolygon& poly );
// extraneous nonsense.
TGPolygon remove_cycles( const TGPolygon& poly );
// Occasionally the outline of the clipped polygon can have long spikes
// that come close to doubling back on the same segment - this kills
// triangulation
TGPolygon remove_spikes( const TGPolygon& poly );
// Find a point in the given node list that lies between start and
// end, return true if something found, false if nothing found.

View file

@ -831,6 +831,20 @@ TGPolygon tgPolygonExpand(const TGPolygon &poly, double delta)
return result;
}
TGPolygon tgPolygonSimplify(const TGPolygon &poly)
{
TGPolygon result;
Polygons clipper_poly;
make_clipper_poly( poly, &clipper_poly );
SimplifyPolygons(clipper_poly);
make_tg_poly_from_clipper( clipper_poly, &result );
return result;
}
#if 0
// Wrapper for the fast Polygon Triangulation based on Seidel's
// Algorithm by Atul Narkhede and Dinesh Manocha
@ -977,15 +991,26 @@ TGPolygon polygon_to_tristrip_old( const TGPolygon& in_poly ) {
ostream &
operator<< (ostream &output, const TGPolygon &poly)
{
char buff[128];
int nContours = poly.contours();
output << nContours << endl;
output << "Contours : " << nContours << endl;
for (int i = 0; i < nContours; i++) {
int nPoints = poly.contour_size(i);
output << nPoints << endl;
output << poly.get_hole_flag(i) << endl;
for (int j = 0; j < nPoints; j++) {
output << poly.get_pt(i, j) << endl;
}
int nPoints = poly.contour_size(i);
if ( poly.get_hole_flag(i) ) {
output << " hole contour " << i << " has " << nPoints << " points " << endl;
} else {
output << " boundary contour " << i << " has " << nPoints << " points " << endl;
}
for (int j = 0; j < nPoints; j++) {
sprintf( buff, "(%3.10lf,%3.10lf,%3.10lf)",
poly.get_pt(i, j).x(),
poly.get_pt(i, j).y(),
poly.get_pt(i, j).z()
);
output << buff << endl;
}
}
return output; // MSVC

View file

@ -278,6 +278,11 @@ TGPolygon tgPolygonUnionClipper( const TGPolygon& subject, const TGPolygon& clip
// Expand / Shrink
TGPolygon tgPolygonExpand(const TGPolygon &poly, double delta);
// Simplify
TGPolygon tgPolygonSimplify(const TGPolygon &poly);
// Output
std::ostream &operator<<(std::ostream &output, const TGPolygon &poly);