Added support for clipper library
- still some issues, but it 'mostly' works (change #define in src/lib/polygon to select clipper library) - added performance statistics
This commit is contained in:
parent
4fb1944964
commit
2e07528da3
6 changed files with 281 additions and 42 deletions
|
@ -358,6 +358,13 @@ void Airport::BuildBtg(const string& root, const string_list& elev_src )
|
|||
double apt_lon = 0.0, apt_lat = 0.0;
|
||||
int rwy_count = 0;
|
||||
|
||||
struct timeval build_start;
|
||||
struct timeval build_end;
|
||||
struct timeval cleanup_start;
|
||||
struct timeval cleanup_end;
|
||||
struct timeval triangulation_start;
|
||||
struct timeval triangulation_end;
|
||||
|
||||
// Find the average of all the runway long / lats
|
||||
// TODO : Need runway object...
|
||||
for (i=0; i<runways.size(); i++)
|
||||
|
@ -392,6 +399,9 @@ void Airport::BuildBtg(const string& root, const string_list& elev_src )
|
|||
}
|
||||
}
|
||||
|
||||
// Starting to clip the polys
|
||||
gettimeofday(&build_start, NULL);
|
||||
|
||||
// Add the linear features
|
||||
if (features.size())
|
||||
{
|
||||
|
@ -490,6 +500,11 @@ void Airport::BuildBtg(const string& root, const string_list& elev_src )
|
|||
TGPolygon divided_base = tgPolygonSplitLongEdges( filled_base, 200.0 );
|
||||
TGPolygon base_poly = tgPolygonDiff( divided_base, accum );
|
||||
|
||||
gettimeofday(&build_end, NULL);
|
||||
timersub(&build_end, &build_start, &build_time);
|
||||
|
||||
gettimeofday(&cleanup_start, NULL);
|
||||
|
||||
// add segments to polygons to remove any possible "T"
|
||||
// intersections
|
||||
TGTriNodes tmp_nodes;
|
||||
|
@ -632,6 +647,7 @@ void Airport::BuildBtg(const string& root, const string_list& elev_src )
|
|||
line_polys[k].set_poly( poly );
|
||||
}
|
||||
|
||||
|
||||
|
||||
SG_LOG(SG_GENERAL, SG_DEBUG, "add nodes base ");
|
||||
SG_LOG(SG_GENERAL, SG_DEBUG, " before: " << base_poly);
|
||||
|
@ -650,6 +666,11 @@ void Airport::BuildBtg(const string& root, const string_list& elev_src )
|
|||
// write_polygon( base_poly, "base-fin" );
|
||||
SG_LOG(SG_GENERAL, SG_DEBUG, " after clean up: " << base_poly);
|
||||
|
||||
gettimeofday(&cleanup_end, NULL);
|
||||
timersub(&cleanup_end, &cleanup_start, &cleanup_time);
|
||||
|
||||
gettimeofday(&triangulation_start, NULL);
|
||||
|
||||
// tesselate the polygons and prepair them for final output
|
||||
for ( i = 0; i < (int)rwy_polys.size(); ++i )
|
||||
{
|
||||
|
@ -711,6 +732,9 @@ void Airport::BuildBtg(const string& root, const string_list& elev_src )
|
|||
SG_LOG(SG_GENERAL, SG_DEBUG, "Tesselating base");
|
||||
TGPolygon base_tris = polygon_tesselate_alt( base_poly );
|
||||
|
||||
gettimeofday(&triangulation_end, NULL);
|
||||
timersub(&triangulation_end, &triangulation_start, &triangulation_time);
|
||||
|
||||
//
|
||||
// We should now have the runway polygons all generated with their
|
||||
// corresponding triangles and texture coordinates, and the
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#include "runway.hxx"
|
||||
#include "object.hxx"
|
||||
|
@ -82,6 +83,21 @@ public:
|
|||
return icao;
|
||||
}
|
||||
|
||||
void GetBuildTime( struct timeval& tm )
|
||||
{
|
||||
tm = build_time;
|
||||
}
|
||||
|
||||
void GetTriangulationTime( struct timeval& tm )
|
||||
{
|
||||
tm = triangulation_time;
|
||||
}
|
||||
|
||||
void GetCleanupTime( struct timeval& tm )
|
||||
{
|
||||
tm = cleanup_time;
|
||||
}
|
||||
|
||||
void BuildOsg( osg::Group* airport );
|
||||
void BuildBtg( const string& root, const string_list& elev_src );
|
||||
|
||||
|
@ -101,6 +117,11 @@ private:
|
|||
SignList signs;
|
||||
HelipadList helipads;
|
||||
ClosedPoly* boundary;
|
||||
|
||||
// stats
|
||||
struct timeval build_time;
|
||||
struct timeval cleanup_time;
|
||||
struct timeval triangulation_time;
|
||||
};
|
||||
|
||||
typedef std::vector <Airport *> AirportList;
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
#include <sys/time.h>
|
||||
|
||||
#include <simgear/debug/logstream.hxx>
|
||||
#include <simgear/misc/sgstream.hxx>
|
||||
|
||||
|
@ -102,6 +104,12 @@ void Parser::Parse()
|
|||
char tmp[2048];
|
||||
bool done = false;
|
||||
int i;
|
||||
struct timeval parse_start;
|
||||
struct timeval parse_end;
|
||||
struct timeval parse_time;
|
||||
struct timeval build_time;
|
||||
struct timeval clean_time;
|
||||
struct timeval triangulation_time;
|
||||
|
||||
ifstream in( filename.c_str() );
|
||||
if ( !in.is_open() )
|
||||
|
@ -114,12 +122,12 @@ void Parser::Parse()
|
|||
for (i=0; i<parse_positions.size(); i++)
|
||||
{
|
||||
SetState(STATE_NONE);
|
||||
|
||||
in.clear();
|
||||
|
||||
SG_LOG( SG_GENERAL, SG_ALERT, "seeking to " << parse_positions[i] );
|
||||
in.seekg(parse_positions[i], ios::beg);
|
||||
|
||||
gettimeofday(&parse_start, NULL);
|
||||
while ( !in.eof() && (cur_state != STATE_DONE ) )
|
||||
{
|
||||
in.getline(tmp, 2048);
|
||||
|
@ -127,15 +135,27 @@ void Parser::Parse()
|
|||
// Parse the line
|
||||
ParseLine(tmp);
|
||||
}
|
||||
gettimeofday(&parse_end, NULL);
|
||||
timersub(&parse_end, &parse_start, &parse_time);
|
||||
|
||||
// write the airport BTG
|
||||
if (cur_airport)
|
||||
{
|
||||
cur_airport->BuildBtg( work_dir, elevation );
|
||||
|
||||
cur_airport->GetBuildTime( build_time );
|
||||
cur_airport->GetCleanupTime( clean_time );
|
||||
cur_airport->GetTriangulationTime( triangulation_time );
|
||||
|
||||
delete cur_airport;
|
||||
cur_airport = NULL;
|
||||
}
|
||||
|
||||
|
||||
SG_LOG( SG_GENERAL, SG_ALERT, "Time to parse " << parse_time.tv_sec << ":" << parse_time.tv_usec );
|
||||
SG_LOG( SG_GENERAL, SG_ALERT, "Time to build " << build_time.tv_sec << ":" << build_time.tv_usec );
|
||||
SG_LOG( SG_GENERAL, SG_ALERT, "Time to clean up " << clean_time.tv_sec << ":" << clean_time.tv_usec );
|
||||
SG_LOG( SG_GENERAL, SG_ALERT, "Time to triangulate " << triangulation_time.tv_sec << ":" << triangulation_time.tv_usec );
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2,15 +2,17 @@
|
|||
|
||||
add_library(Polygon STATIC
|
||||
chop-bin.cxx
|
||||
clipper.cpp
|
||||
index.cxx
|
||||
polygon.cxx
|
||||
simple_clip.cxx
|
||||
superpoly.cxx
|
||||
chop.hxx
|
||||
clipper.hpp
|
||||
index.hxx
|
||||
names.hxx
|
||||
point2d.hxx
|
||||
polygon.hxx
|
||||
simple_clip.hxx
|
||||
superpoly.hxx
|
||||
)
|
||||
)
|
||||
|
|
|
@ -39,6 +39,11 @@
|
|||
#include <cstdlib>
|
||||
#include <ostream>
|
||||
|
||||
// TEMP : clipper debugging
|
||||
#include <simgear/debug/logstream.hxx>
|
||||
|
||||
|
||||
|
||||
//Workaround for older compilers that don't have std::abs
|
||||
#if (__GNUC__ == 2 && __GNUC_MINOR__ <= 97) || (defined(_MSC_VER) && _MSC_VER <= 1500)
|
||||
namespace std
|
||||
|
@ -1367,6 +1372,7 @@ void Clipper::SetWindingCount(TEdge &edge)
|
|||
}
|
||||
|
||||
//update windCnt2 ...
|
||||
|
||||
if ( IsNonZeroAltFillType(edge) )
|
||||
{
|
||||
//nonZero filling ...
|
||||
|
@ -1634,6 +1640,7 @@ void Clipper::DeleteFromSEL(TEdge *e)
|
|||
if( SelPrev ) SelPrev->nextInSEL = SelNext;
|
||||
else m_SortedEdges = SelNext;
|
||||
if( SelNext ) SelNext->prevInSEL = SelPrev;
|
||||
|
||||
e->nextInSEL = 0;
|
||||
e->prevInSEL = 0;
|
||||
}
|
||||
|
@ -1915,6 +1922,7 @@ void Clipper::AppendPolygon(TEdge *e1, TEdge *e2)
|
|||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
OutRec* Clipper::CreateOutRec()
|
||||
{
|
||||
OutRec* result = new OutRec;
|
||||
|
@ -1930,6 +1938,7 @@ OutRec* Clipper::CreateOutRec()
|
|||
void Clipper::AddOutPt(TEdge *e, TEdge *altE, const IntPoint &pt)
|
||||
{
|
||||
bool ToFront = (e->side == esLeft);
|
||||
|
||||
if( e->outIdx < 0 )
|
||||
{
|
||||
OutRec *outRec = CreateOutRec();
|
||||
|
@ -2210,7 +2219,9 @@ void Clipper::ProcessHorizontal(TEdge *horzEdge)
|
|||
if( horzEdge->nextInLML )
|
||||
{
|
||||
if( horzEdge->outIdx >= 0 )
|
||||
{
|
||||
AddOutPt( horzEdge, 0, IntPoint(horzEdge->xtop, horzEdge->ytop));
|
||||
}
|
||||
UpdateEdgeIntoAEL( horzEdge );
|
||||
}
|
||||
else
|
||||
|
@ -2469,7 +2480,10 @@ void Clipper::ProcessEdgesAtTopOfScanbeam(const long64 topY)
|
|||
{
|
||||
if( IsIntermediate( e, topY ) )
|
||||
{
|
||||
if( e->outIdx >= 0 ) AddOutPt(e, 0, IntPoint(e->xtop,e->ytop));
|
||||
if( e->outIdx >= 0 )
|
||||
{
|
||||
AddOutPt(e, 0, IntPoint(e->xtop,e->ytop));
|
||||
}
|
||||
UpdateEdgeIntoAEL(e);
|
||||
|
||||
//if output polygons share an edge, they'll need joining later ...
|
||||
|
@ -2548,6 +2562,7 @@ void Clipper::FixupOutPolygon(OutRec &outRec)
|
|||
void Clipper::BuildResult(Polygons &polys)
|
||||
{
|
||||
int k = 0;
|
||||
|
||||
polys.resize(m_PolyOuts.size());
|
||||
for (PolyOutList::size_type i = 0; i < m_PolyOuts.size(); ++i)
|
||||
{
|
||||
|
|
|
@ -25,9 +25,16 @@
|
|||
//
|
||||
// http://www.cs.man.ac.uk/aig/staff/alan/software/
|
||||
//
|
||||
|
||||
// which clipping lib to use?
|
||||
#define CLIP_GPC
|
||||
//#define CLIP_CLIPPER
|
||||
|
||||
#ifdef CLIP_GPC
|
||||
extern "C" {
|
||||
#include <gpc.h>
|
||||
}
|
||||
#endif
|
||||
|
||||
#include <simgear/constants.h>
|
||||
#include <simgear/debug/logstream.hxx>
|
||||
|
@ -41,6 +48,11 @@ extern "C" {
|
|||
#include "polygon.hxx"
|
||||
#include "point2d.hxx"
|
||||
|
||||
#ifdef CLIP_CLIPPER
|
||||
#include "clipper.hpp"
|
||||
using namespace ClipperLib;
|
||||
#endif
|
||||
|
||||
using std::endl;
|
||||
|
||||
// Constructor
|
||||
|
@ -299,7 +311,15 @@ void TGPolygon::write_contour( const int contour, const string& file ) const {
|
|||
fclose(fp);
|
||||
}
|
||||
|
||||
// Set operation type
|
||||
typedef enum {
|
||||
POLY_DIFF, // Difference
|
||||
POLY_INT, // Intersection
|
||||
POLY_XOR, // Exclusive or
|
||||
POLY_UNION // Union
|
||||
} clip_op;
|
||||
|
||||
#ifdef CLIP_GPC
|
||||
//
|
||||
// wrapper functions for gpc polygon clip routines
|
||||
//
|
||||
|
@ -310,9 +330,6 @@ void make_gpc_poly( const TGPolygon& in, gpc_polygon *out ) {
|
|||
v_list.num_vertices = 0;
|
||||
v_list.vertex = new gpc_vertex[FG_MAX_VERTICES];
|
||||
|
||||
// SG_LOG(SG_GENERAL, SG_DEBUG, "making a gpc_poly");
|
||||
// SG_LOG(SG_GENERAL, SG_DEBUG, " input contours = " << in.contours());
|
||||
|
||||
Point3D p;
|
||||
// build the gpc_polygon structures
|
||||
for ( int i = 0; i < in.contours(); ++i ) {
|
||||
|
@ -323,6 +340,14 @@ void make_gpc_poly( const TGPolygon& in, gpc_polygon *out ) {
|
|||
throw sg_exception(message);;
|
||||
}
|
||||
|
||||
#if 0
|
||||
SG_LOG(SG_GENERAL, SG_ALERT,
|
||||
" make_clipper_poly : processing contour " << i << ", nodes = "
|
||||
<< in.contour_size(i) << ", hole = "
|
||||
<< in.get_hole_flag(i)
|
||||
);
|
||||
#endif
|
||||
|
||||
for ( int j = 0; j < in.contour_size( i ); ++j ) {
|
||||
p = in.get_pt( i, j );
|
||||
v_list.vertex[j].x = p.x();
|
||||
|
@ -336,16 +361,6 @@ void make_gpc_poly( const TGPolygon& in, gpc_polygon *out ) {
|
|||
delete [] v_list.vertex;
|
||||
}
|
||||
|
||||
|
||||
// Set operation type
|
||||
typedef enum {
|
||||
POLY_DIFF, // Difference
|
||||
POLY_INT, // Intersection
|
||||
POLY_XOR, // Exclusive or
|
||||
POLY_UNION // Union
|
||||
} clip_op;
|
||||
|
||||
|
||||
// Generic clipping routine
|
||||
TGPolygon polygon_clip( clip_op poly_op, const TGPolygon& subject,
|
||||
const TGPolygon& clip )
|
||||
|
@ -371,13 +386,13 @@ TGPolygon polygon_clip( clip_op poly_op, const TGPolygon& subject,
|
|||
|
||||
gpc_op op;
|
||||
if ( poly_op == POLY_DIFF ) {
|
||||
op = GPC_DIFF;
|
||||
op = GPC_DIFF;
|
||||
} else if ( poly_op == POLY_INT ) {
|
||||
op = GPC_INT;
|
||||
op = GPC_INT;
|
||||
} else if ( poly_op == POLY_XOR ) {
|
||||
op = GPC_XOR;
|
||||
op = GPC_XOR;
|
||||
} else if ( poly_op == POLY_UNION ) {
|
||||
op = GPC_UNION;
|
||||
op = GPC_UNION;
|
||||
} else {
|
||||
throw sg_exception("Unknown polygon op, exiting.");
|
||||
}
|
||||
|
@ -385,29 +400,12 @@ TGPolygon polygon_clip( clip_op poly_op, const TGPolygon& subject,
|
|||
gpc_polygon_clip( op, gpc_subject, gpc_clip, gpc_result );
|
||||
|
||||
for ( int i = 0; i < gpc_result->num_contours; ++i ) {
|
||||
// SG_LOG(SG_GENERAL, SG_DEBUG,
|
||||
// " processing contour = " << i << ", nodes = "
|
||||
// << gpc_result->contour[i].num_vertices << ", hole = "
|
||||
// << gpc_result->hole[i]);
|
||||
|
||||
// sprintf(junkn, "g.%d", junkc++);
|
||||
// junkfp = fopen(junkn, "w");
|
||||
for ( int j = 0; j < gpc_result->contour[i].num_vertices; j++ ) {
|
||||
Point3D p( gpc_result->contour[i].vertex[j].x, gpc_result->contour[i].vertex[j].y, -9999.0 );
|
||||
result.add_node(i, p);
|
||||
}
|
||||
|
||||
for ( int j = 0; j < gpc_result->contour[i].num_vertices; j++ ) {
|
||||
Point3D p( gpc_result->contour[i].vertex[j].x,
|
||||
gpc_result->contour[i].vertex[j].y,
|
||||
-9999.0 );
|
||||
// junkp = in_nodes.get_node( index );
|
||||
// fprintf(junkfp, "%.4f %.4f\n", junkp.x(), junkp.y());
|
||||
result.add_node(i, p);
|
||||
// SG_LOG(SG_GENERAL, SG_DEBUG, " - " << index);
|
||||
}
|
||||
// fprintf(junkfp, "%.4f %.4f\n",
|
||||
// gpc_result->contour[i].vertex[0].x,
|
||||
// gpc_result->contour[i].vertex[0].y);
|
||||
// fclose(junkfp);
|
||||
|
||||
result.set_hole_flag( i, gpc_result->hole[i] );
|
||||
result.set_hole_flag( i, gpc_result->hole[i] );
|
||||
}
|
||||
|
||||
// free allocated memory
|
||||
|
@ -417,7 +415,166 @@ TGPolygon polygon_clip( clip_op poly_op, const TGPolygon& subject,
|
|||
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CLIP_CLIPPER
|
||||
|
||||
#define FIXEDPT (1000000000000)
|
||||
|
||||
IntPoint MakeClipperPoint( Point3D pt )
|
||||
{
|
||||
long64 x, y;
|
||||
|
||||
x = (long64)( pt.x() * FIXEDPT );
|
||||
y = (long64)( pt.y() * FIXEDPT );
|
||||
|
||||
return IntPoint( x, y );
|
||||
}
|
||||
|
||||
Point3D MakeTGPoint( IntPoint pt )
|
||||
{
|
||||
double x, y;
|
||||
|
||||
x = (double)( ((double)pt.X) / (double)FIXEDPT );
|
||||
y = (double)( ((double)pt.Y) / (double)FIXEDPT );
|
||||
|
||||
return Point3D( x, y, -9999.0f);
|
||||
}
|
||||
|
||||
void make_clipper_poly( const TGPolygon& in, Polygons *out )
|
||||
{
|
||||
Polygon contour;
|
||||
Point3D p;
|
||||
int i, j;
|
||||
|
||||
if (in.contours())
|
||||
{
|
||||
// assume contour 0 is boundary, 1..x are holes
|
||||
// create the boundary
|
||||
|
||||
#if 0
|
||||
SG_LOG(SG_GENERAL, SG_ALERT,
|
||||
" make_clipper_poly : processing boundary contour, nodes = "
|
||||
<< in.contour_size(0) << ", hole = "
|
||||
<< in.get_hole_flag(0)
|
||||
);
|
||||
#endif
|
||||
|
||||
for (j=0; j<in.contour_size(0); ++j)
|
||||
{
|
||||
p = in.get_pt( 0, j );
|
||||
contour.push_back(MakeClipperPoint(p));
|
||||
}
|
||||
out->push_back(contour);
|
||||
|
||||
// create the holes
|
||||
for (i=1; i<in.contours(); ++i )
|
||||
{
|
||||
#if 0
|
||||
SG_LOG(SG_GENERAL, SG_ALERT,
|
||||
" make_clipper_poly : processing hole " << i << ", nodes = "
|
||||
<< in.contour_size(i) << ", hole = "
|
||||
<< in.get_hole_flag(i)
|
||||
);
|
||||
#endif
|
||||
|
||||
contour.clear();
|
||||
for (j=0; j<in.contour_size(i); ++j)
|
||||
{
|
||||
p = in.get_pt( i, j );
|
||||
contour.push_back(MakeClipperPoint(p));
|
||||
}
|
||||
out->push_back(contour);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TGPolygon polygon_clip( clip_op poly_op, const TGPolygon& subject, const TGPolygon& clip )
|
||||
{
|
||||
TGPolygon result;
|
||||
|
||||
Polygons clipper_subject;
|
||||
make_clipper_poly( subject, &clipper_subject );
|
||||
|
||||
Polygons clipper_clip;
|
||||
make_clipper_poly( clip, &clipper_clip );
|
||||
|
||||
//ExPolygons clipper_result;
|
||||
Polygons clipper_result;
|
||||
|
||||
ClipType op;
|
||||
if ( poly_op == POLY_DIFF ) {
|
||||
op = ctDifference;
|
||||
} else if ( poly_op == POLY_INT ) {
|
||||
op = ctIntersection;
|
||||
} else if ( poly_op == POLY_XOR ) {
|
||||
op = ctXor;
|
||||
} else if ( poly_op == POLY_UNION ) {
|
||||
op = ctUnion;
|
||||
} else {
|
||||
throw sg_exception("Unknown polygon op, exiting.");
|
||||
}
|
||||
|
||||
Clipper c;
|
||||
c.Clear();
|
||||
c.AddPolygons(clipper_subject, ptSubject);
|
||||
c.AddPolygons(clipper_clip, ptClip);
|
||||
|
||||
Point3D p;
|
||||
int res_contour = 0;
|
||||
if (c.Execute(op, clipper_result, pftEvenOdd, pftEvenOdd))
|
||||
{
|
||||
#if 0 // ExPolygons
|
||||
for (int i=0; i<clipper_result.size(); i++)
|
||||
{
|
||||
struct ExPolygon* pg = &clipper_result[i];
|
||||
|
||||
// Get the boundary contour
|
||||
for (int j = 0; j < pg->outer.size(); j++)
|
||||
{
|
||||
p = Point3D( pg->outer[j].X, pg->outer[j].Y, -9999.0 );
|
||||
result.add_node(res_contour, p);
|
||||
}
|
||||
result.set_hole_flag(res_contour, 0);
|
||||
res_contour++;
|
||||
|
||||
// then the holes
|
||||
for (int j = 0; j < pg->holes.size(); j++)
|
||||
{
|
||||
for (int k = 0; k < pg->holes[j].size(); k++)
|
||||
{
|
||||
p = Point3D( pg->holes[j].at(k).X, pg->holes[j].at(k).Y, -9999.0 );
|
||||
result.add_node(res_contour, p);
|
||||
}
|
||||
result.set_hole_flag(res_contour, 1);
|
||||
res_contour++;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
for (int i=0; i<clipper_result.size(); i++)
|
||||
{
|
||||
Polygon* pg = &clipper_result[i];
|
||||
IntPoint ip;
|
||||
|
||||
for (int j = 0; j < pg->size(); j++)
|
||||
{
|
||||
ip = IntPoint( pg->at(j).X, pg->at(j).Y );
|
||||
result.add_node(i, MakeTGPoint(ip));
|
||||
}
|
||||
if (i==0)
|
||||
{
|
||||
result.set_hole_flag(i, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
result.set_hole_flag(i, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Difference
|
||||
TGPolygon tgPolygonDiff( const TGPolygon& subject, const TGPolygon& clip ) {
|
||||
|
|
Loading…
Add table
Reference in a new issue