}
-// 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;
+ }
+ }
+ }
}
}
}
// 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" );
// 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++);
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
}
#endif
+#include <Main/construct_types.hxx>
#include <Triangulate/polygon.hxx>
#include STL_STRING
// #define FG_MAX_VERTICES 100000
-class point2d {
-public:
- double x, y;
-};
-
-
class FGPolyList {
public:
poly_list polys[FG_MAX_AREA_TYPES];
// 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);
typedef point_list::const_iterator const_point_list_iterator;
+class point2d {
+public:
+ double x, y;
+};
+
+
#endif // _CONSTRUCT_TYPES_HXX
}
+// 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,
}
+// 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
//
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();
#include <Include/compiler.h>
+#include <string>
#include <vector>
#include <Main/construct_types.hxx>
#include "trinodes.hxx"
+FG_USING_STD(string);
FG_USING_STD(vector);
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() ) {
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 );
};
// 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();
// 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 );