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:
parent
1090e602c2
commit
9f96783df6
7 changed files with 280 additions and 32 deletions
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
///////////////////////////
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue