]> git.mxchange.org Git - flightgear.git/commitdiff
Sliver detection and elimination:
authorcurt <curt>
Mon, 7 Jun 1999 03:40:33 +0000 (03:40 +0000)
committercurt <curt>
Mon, 7 Jun 1999 03:40:33 +0000 (03:40 +0000)
After I clip a polygon against the more important stuff, I
check the area and minimum interior angle of each of it's contours.
If both (area and min interior angle) are below some threshhold I'm
calling it a sliver.  Then I go and look for another polygon such that
result = polygon_union( poly, sliver ) yields a result that doesn't
have anymore contours than the original poly.  This means the sliver
is adjacent to poly.  So I replace poly with result (the union) and
keep going.

Tools/Construct/Clipper/clipper.cxx
Tools/Construct/Clipper/clipper.hxx
Tools/Construct/Main/construct_types.hxx
Tools/Construct/Triangulate/polygon.cxx
Tools/Construct/Triangulate/polygon.hxx
Tools/Construct/Triangulate/triangle.cxx

index f3c69cb8d01866fcca932150d3ad44635959b353..0b8bd3b63c22b1151a7b1c91a1d92eeae5c009a4 100644 (file)
@@ -152,17 +152,110 @@ bool FGClipper::load_polys(const string& path) {
 }
 
 
-// merge any slivers in the specified polygon with larger
-// neighboring polygons of higher priorigy
-void FGClipper::merge_slivers(FGPolygon& poly) {
-    cout << "Begin merge slivers" << endl;
+// remove any slivers from in polygon and move them to out polygon.
+void FGClipper::move_slivers( FGPolygon& in, FGPolygon& out ) {
+    cout << "Begin move slivers" << endl;
     // traverse each contour of the polygon and attempt to identify
     // likely slivers
-    for ( int i = 0; i < poly.contours(); ++i ) {
+
+    out.erase();
+
+    double angle_cutoff = 10.0 * DEG_TO_RAD;
+    double area_cutoff = 0.00001;
+    double min_angle;
+    double area;
+
+    point_list contour;
+    int hole_flag;
+
+    // process contours in reverse order so deleting a contour doesn't
+    // foul up our sequence
+    for ( int i = in.contours() - 1; i >= 0; --i ) {
        cout << "contour " << i << endl;
-       for (int j = 0; j < poly.contour_size( i ); ++j ) {
-           // cout << poly->contour[i].vertex[j].x << ","
-           //      << poly->contour[i].vertex[j].y << endl;
+
+       min_angle = in.minangle_contour( i );
+       area = in.area_contour( i );
+
+       cout << "  min_angle (rad) = " 
+            << min_angle << endl;
+       cout << "  min_angle (deg) = " 
+            << min_angle * 180.0 / FG_PI << endl;
+       cout << "  area = " << area << endl;
+
+       if ( (min_angle < angle_cutoff) && (area < area_cutoff)  ) {
+           cout << "      WE THINK IT'S A SLIVER!" << endl;
+
+           // check if this is a hole
+           hole_flag = in.get_hole_flag( i );
+
+           if ( hole_flag ) {
+               // just delete/eliminate/remove sliver holes
+               in.delete_contour( i );
+           } else {
+               // move sliver contour to out polygon
+               contour = in.get_contour( i );
+               in.delete_contour( i );
+               out.add_contour( contour, hole_flag );
+           }
+       }
+    }
+}
+
+
+// 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 FGClipper::merge_slivers( FGPolyList& clipped, FGPolygon& slivers ) {
+    FGPolygon poly, result, sliver;
+    point_list contour;
+    int original_contours, result_contours;
+    bool done;
+
+    for ( int i = 0; i < slivers.contours(); ++i ) {
+       cout << "Merging sliver = " << i << endl;
+
+       // make the sliver polygon
+       contour = slivers.get_contour( i );
+       sliver.erase();
+       sliver.add_contour( contour, 0 );
+       done = false;
+
+       for ( int area = 0; area < FG_MAX_AREA_TYPES && !done; ++area ) {
+           cout << "  testing area = " << area << " with " 
+                << clipped.polys[area].size() << " polys" << endl;
+           for ( int j = 0; 
+                 j < (int)clipped.polys[area].size() && !done;
+                 ++j )
+           {
+               cout << "  polygon = " << j << endl;
+
+               poly = clipped.polys[area][j];
+               original_contours = poly.contours();
+               result = polygon_union( poly, sliver );
+               result_contours = result.contours();
+
+               if ( original_contours == result_contours ) {
+                   cout << "    FOUND a poly to merge the sliver with" << endl;
+                   clipped.polys[area][j] = result;
+                   done = true;
+                   // poly.write("orig");
+                   // sliver.write("sliver");
+                   // result.write("result");
+                   // cout << "press return: ";
+                   // string input;
+                   // cin >> input;
+               } else {
+                   cout << "    poly not a match" << endl;
+                   cout << "    original = " << original_contours
+                        << " result = " << result_contours << endl;
+                   cout << "    sliver = " << endl;
+                   for ( int k = 0; k < (int)contour.size(); ++k ) {
+                       cout << "      " << contour[k].x() << ", "
+                            << contour[k].y() << endl;
+                   }
+               }
+           }
        }
     }
 }
@@ -171,7 +264,7 @@ void FGClipper::merge_slivers(FGPolygon& poly) {
 // Do actually clipping work
 bool FGClipper::clip_all(const point2d& min, const point2d& max) {
     FGPolygon accum, result_union, tmp;
-    FGPolygon result_diff, remains;
+    FGPolygon result_diff, slivers, remains;
     // gpcpoly_iterator current, last;
 
     FG_LOG( FG_CLIPPER, FG_INFO, "Running master clipper" );
@@ -258,10 +351,23 @@ bool FGClipper::clip_all(const point2d& min, const point2d& max) {
 
            // only add to output list if the clip left us with a polygon
            if ( result_diff.contours() > 0 ) {
-               // merge any slivers with larger neighboring polygons
-               merge_slivers(result_diff);
-
-               polys_clipped.polys[i].push_back(result_diff);
+               // move slivers from result_diff polygon to slivers polygon
+               move_slivers(result_diff, slivers);
+               cout << "  After sliver move:" << endl;
+               cout << "    result_diff = " << result_diff.contours() << endl;
+               cout << "    slivers = " << slivers.contours() << endl;
+
+               // merge any slivers with previously clipped
+               // neighboring polygons
+               if ( slivers.contours() > 0 ) {
+                   merge_slivers(polys_clipped, slivers);
+               }
+
+               // add the sliverless result polygon (from after the
+               // move_slivers) to the clipped polys list
+               if ( result_diff.contours() > 0  ) {
+                   polys_clipped.polys[i].push_back(result_diff);
+               }
 
                // char filename[256];
                // sprintf(filename, "next-result-%02d", count++);
@@ -282,7 +388,22 @@ bool FGClipper::clip_all(const point2d& min, const point2d& max) {
     remains = polygon_diff( polys_in.safety_base, accum );
 
     if ( remains.contours() > 0 ) {
-       polys_clipped.polys[(int)OceanArea].push_back(remains);
+       cout << "remains contours = " << remains.contours() << endl;
+       // move slivers from remains polygon to slivers polygon
+       move_slivers(remains, slivers);
+       cout << "  After sliver move:" << endl;
+       cout << "    remains = " << remains.contours() << endl;
+       cout << "    slivers = " << slivers.contours() << endl;
+
+       // merge any slivers with previously clipped
+       // neighboring polygons
+       if ( slivers.contours() > 0 ) {
+           merge_slivers(polys_clipped, slivers);
+       }
+
+       if ( remains.contours() > 0 ) {
+           polys_clipped.polys[(int)OceanArea].push_back(remains);
+       }
     }
 
 #if 0
index df0b62cfcfdea6cc392f2238230b1011b7299320..def0fbbac8d07edf5b5597b9468ea940162cb080 100644 (file)
@@ -45,6 +45,7 @@ extern "C" {
 }
 #endif
 
+#include <Main/construct_types.hxx>
 #include <Triangulate/polygon.hxx>
 
 #include STL_STRING
@@ -64,12 +65,6 @@ FG_USING_STD(vector);
 // #define FG_MAX_VERTICES 100000
 
 
-class point2d {
-public:
-    double x, y;
-};
-
-
 class FGPolyList {
 public:
     poly_list polys[FG_MAX_AREA_TYPES];
@@ -99,9 +94,15 @@ public:
     // Load a polygon definition file
     bool load_polys(const string& path);
 
-    // merge any slivers in the specified polygon with larger
-    // neighboring polygons of higher priorigy
-    void merge_slivers( FGPolygon& poly);
+    // remove any slivers from in polygon and move them to out
+    // polygon.
+    void move_slivers( FGPolygon& in, FGPolygon& out );
+
+    // 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 merge_slivers( FGPolyList& clipped, FGPolygon& slivers );
     
     // Do actually clipping work
     bool clip_all(const point2d& min, const point2d& max);
index f470fffa0e4818143ecdb0333390856bc48f6b33..f24fd141c1f232f3932463b13dd013236b6b6928 100644 (file)
@@ -48,6 +48,12 @@ typedef point_list::iterator point_list_iterator;
 typedef point_list::const_iterator const_point_list_iterator;
 
 
+class point2d {
+public:
+    double x, y;
+};
+
+
 #endif // _CONSTRUCT_TYPES_HXX
 
 
index 3e25e89e50ec9cb5dc9c77eb2993b81882bfda9f..142f231f653439d54e516bb76a142197a55cd593 100644 (file)
@@ -57,6 +57,33 @@ static double slope( const Point3D& p0, const Point3D& p1 ) {
 }
 
 
+// Calculate theta of angle (a, b, c)
+static double calc_angle(point2d a, point2d b, point2d c) {
+    point2d u, v;
+    double udist, vdist, uv_dot, tmp;
+
+    // u . v = ||u|| * ||v|| * cos(theta)
+
+    u.x = b.x - a.x;
+    u.y = b.y - a.y;
+    udist = sqrt( u.x * u.x + u.y * u.y );
+    // printf("udist = %.6f\n", udist);
+
+    v.x = b.x - c.x;
+    v.y = b.y - c.y;
+    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);
+}
+
+
 // Given a line segment specified by two endpoints p1 and p2, return
 // the y value of a point on the line that intersects with the
 // verticle line through x.  Return true if an intersection is found,
@@ -218,6 +245,81 @@ void FGPolygon::calc_point_inside( const int contour,
 }
 
 
+// return the perimeter of a contour (assumes simple polygons,
+// i.e. non-self intersecting.)
+double FGPolygon::area_contour( const int contour ) {
+    // area = 1/2 * sum[i = 0 to k-1][x(i)*y(i+1) - x(i+1)*y(i)]
+    // where k is defined as 0
+
+    point_list c = poly[contour];
+    int size = c.size();
+    double sum = 0.0;
+
+    for ( int i = 0; i < size; ++i ) {
+       sum += c[(i+1)%size].x() * c[i].y() - c[i].x() * c[(i+1)%size].y();
+    }
+
+    return sum / 2.0;
+}
+
+
+// return the smallest interior angle of the polygon
+double FGPolygon::minangle_contour( const int contour ) {
+    point_list c = poly[contour];
+    int size = c.size();
+    int p1_index, p2_index, p3_index;
+    point2d p1, p2, p3;
+    double angle;
+    double min_angle = 2.0 * FG_PI;
+
+    for ( int i = 0; i < size; ++i ) {
+       p1_index = i - 1;
+       if ( p1_index < 0 ) {
+           p1_index += size;
+       }
+
+       p2_index = i;
+
+       p3_index = i + 1;
+       if ( p3_index >= size ) {
+           p3_index -= size;
+       }
+
+       p1.x = c[p1_index].x();
+       p1.y = c[p1_index].y();
+
+       p2.x = c[p2_index].x();
+       p2.y = c[p2_index].y();
+
+       p3.x = c[p3_index].x();
+       p3.y = c[p3_index].y();
+
+       angle = calc_angle( p1, p2, p3 );
+
+       if ( angle < min_angle ) {
+           min_angle = angle;
+       }
+    }
+
+    return min_angle;
+}
+
+
+// output
+void FGPolygon::write( const string& file ) {
+    FILE *fp = fopen( file.c_str(), "w" );
+    
+    for ( int i = 0; i < (int)poly.size(); ++i ) {
+       for ( int j = 0; j < (int)poly[i].size(); ++j ) {
+           fprintf(fp, "%.6f %.6f\n", poly[i][j].x(), poly[i][j].y());
+       }
+       fprintf(fp, "%.6f %.6f\n", poly[i][0].x(), poly[i][0].y());
+    }
+
+    fclose(fp);
+}
+
+
 //
 // wrapper functions for gpc polygon clip routines
 //
@@ -228,13 +330,13 @@ void make_gpc_poly( const FGPolygon& in, gpc_polygon *out ) {
     v_list.num_vertices = 0;
     v_list.vertex = new gpc_vertex[FG_MAX_VERTICES];
 
-    cout << "making a gpc_poly" << endl;
-    cout << "  input contours = " << in.contours() << endl;
+    // cout << "making a gpc_poly" << endl;
+    // cout << "  input contours = " << in.contours() << endl;
 
     Point3D p;
     // build the gpc_polygon structures
     for ( int i = 0; i < in.contours(); ++i ) {
-       cout << "    contour " << i << " = " << in.contour_size( i ) << endl;
+       // cout << "    contour " << i << " = " << in.contour_size( i ) << endl;
        for ( int j = 0; j < in.contour_size( i ); ++j ) {
            p = in.get_pt( i, j );
            v_list.vertex[j].x = p.x();
index cf5469710923f47cc9b906a074251a3c0cbee381..7624e367ae54e39d750f7ad92cb4128fc986157d 100644 (file)
 
 #include <Include/compiler.h>
 
+#include <string>
 #include <vector>
 
 #include <Main/construct_types.hxx>
 
 #include "trinodes.hxx"
 
+FG_USING_STD(string);
 FG_USING_STD(vector);
 
 
@@ -63,6 +65,26 @@ public:
     FGPolygon( void );
     ~FGPolygon( void );
 
+    // Add a contour
+    inline void add_contour( const point_list contour, const int hole_flag ) {
+       poly.push_back( contour );
+       hole_list.push_back( hole_flag );
+    }
+
+    // Get a contour
+    inline point_list get_contour( const int i ) const {
+       return poly[i];
+    }
+
+    // Delete a contour
+    inline void delete_contour( const int i ) {
+       polytype_iterator start_poly = poly.begin();
+       poly.erase( start_poly + i );
+
+       int_list_iterator start_hole = hole_list.begin();
+       hole_list.erase( start_hole + i );
+    }
+
     // Add the specified node (index) to the polygon
     inline void add_node( int contour, Point3D p ) {
        if ( contour >= (int)poly.size() ) {
@@ -104,8 +126,20 @@ public:
        hole_list[contour] = flag;
     }
 
+    // erase
     inline void erase() { poly.clear(); }
 
+    // informational
+
+    // return the area of a contour (assumes simple polygons,
+    // i.e. non-self intersecting.)
+    double area_contour( const int contour );
+
+    // return the smallest interior angle of the polygon
+    double minangle_contour( const int contour );
+
+    // output
+    void write( const string& file );
 };
 
 
index d10babca7a6731e22067ce4a97dbe663787363bb..88feafda02d1ec30d750e934191e4f9f06591f52 100644 (file)
@@ -168,11 +168,12 @@ FGTriangle::build( const point_list& corner_list,
     // traverse the polygon lists and build the segment (edge) list
     // that is used by the "Triangle" lib.
 
+    cout << "building segment list" << endl;
     int i1, i2;
     Point3D p1, p2;
     point_list node_list = in_nodes.get_node_list();
     for ( int i = 0; i < FG_MAX_AREA_TYPES; ++i ) {
-       // cout << "area type = " << i << endl;
+       cout << "area type = " << i << endl;
        poly_list_iterator tp_current, tp_last;
        tp_current = polylist[i].begin();
        tp_last = polylist[i].end();
@@ -180,7 +181,8 @@ FGTriangle::build( const point_list& corner_list,
        // process each polygon in list
        for ( ; tp_current != tp_last; ++tp_current ) {
            poly = *tp_current;
-
+           cout << "  processing a polygon with contours = " 
+                << poly.contours() << endl;
            for ( int j = 0; j < (int)poly.contours(); ++j) {
                for ( int k = 0; k < (int)(poly.contour_size(j) - 1); ++k ) {
                    p1 = poly.get_pt( j, k );