Reverted commits that remove boost::polygon dependency (need more testing).
This commit is contained in:
+128
-295
@@ -4,9 +4,6 @@
|
||||
* Copyright (C) 2015 CERN
|
||||
* @author Tomasz Wlostowski <[email protected]>
|
||||
*
|
||||
* Point in polygon algorithm adapted from Clipper Library (C) Angus Johnson,
|
||||
* subject to Clipper library license.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
@@ -28,34 +25,22 @@
|
||||
|
||||
#include <vector>
|
||||
#include <cstdio>
|
||||
#include <geometry/shape.h>
|
||||
#include <geometry/shape_line_chain.h>
|
||||
#include <set>
|
||||
#include <list>
|
||||
#include <algorithm>
|
||||
|
||||
#include <boost/foreach.hpp>
|
||||
|
||||
#include <geometry/shape.h>
|
||||
#include <geometry/shape_line_chain.h>
|
||||
#include <geometry/shape_poly_set.h>
|
||||
#include "geometry/shape_poly_set.h"
|
||||
|
||||
using namespace ClipperLib;
|
||||
|
||||
SHAPE_POLY_SET::SHAPE_POLY_SET() :
|
||||
SHAPE( SH_POLY_SET )
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
SHAPE_POLY_SET::~SHAPE_POLY_SET()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
int SHAPE_POLY_SET::NewOutline()
|
||||
{
|
||||
SHAPE_LINE_CHAIN empty_path;
|
||||
POLYGON poly;
|
||||
Path empty_path;
|
||||
Paths poly;
|
||||
poly.push_back( empty_path );
|
||||
m_polys.push_back( poly );
|
||||
return m_polys.size() - 1;
|
||||
@@ -64,13 +49,12 @@ int SHAPE_POLY_SET::NewOutline()
|
||||
|
||||
int SHAPE_POLY_SET::NewHole( int aOutline )
|
||||
{
|
||||
m_polys.back().push_back( SHAPE_LINE_CHAIN() );
|
||||
|
||||
return m_polys.back().size() - 2;
|
||||
assert( false );
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
int SHAPE_POLY_SET::Append( int x, int y, int aOutline, int aHole )
|
||||
int SHAPE_POLY_SET::AppendVertex( int x, int y, int aOutline, int aHole )
|
||||
{
|
||||
if( aOutline < 0 )
|
||||
aOutline += m_polys.size();
|
||||
@@ -85,13 +69,13 @@ int SHAPE_POLY_SET::Append( int x, int y, int aOutline, int aHole )
|
||||
assert( aOutline < (int)m_polys.size() );
|
||||
assert( idx < (int)m_polys[aOutline].size() );
|
||||
|
||||
m_polys[aOutline][idx].Append( x, y );
|
||||
m_polys[aOutline][idx].push_back( IntPoint( x, y ) );
|
||||
|
||||
return m_polys[aOutline][idx].PointCount();
|
||||
return m_polys[aOutline][idx].size();
|
||||
}
|
||||
|
||||
|
||||
int SHAPE_POLY_SET::VertexCount( int aOutline , int aHole ) const
|
||||
int SHAPE_POLY_SET::VertexCount( int aOutline, int aHole ) const
|
||||
{
|
||||
if( aOutline < 0 )
|
||||
aOutline += m_polys.size();
|
||||
@@ -106,11 +90,11 @@ int SHAPE_POLY_SET::VertexCount( int aOutline , int aHole ) const
|
||||
assert ( aOutline < (int)m_polys.size() );
|
||||
assert ( idx < (int)m_polys[aOutline].size() );
|
||||
|
||||
return m_polys[aOutline][idx].PointCount();
|
||||
return m_polys[aOutline][idx].size();
|
||||
}
|
||||
|
||||
|
||||
const VECTOR2I& SHAPE_POLY_SET::CVertex( int index, int aOutline , int aHole ) const
|
||||
const VECTOR2I SHAPE_POLY_SET::GetVertex( int index, int aOutline, int aHole ) const
|
||||
{
|
||||
if( aOutline < 0 )
|
||||
aOutline += m_polys.size();
|
||||
@@ -125,26 +109,8 @@ const VECTOR2I& SHAPE_POLY_SET::CVertex( int index, int aOutline , int aHole ) c
|
||||
assert( aOutline < (int)m_polys.size() );
|
||||
assert( idx < (int)m_polys[aOutline].size() );
|
||||
|
||||
return m_polys[aOutline][idx].CPoint( index );
|
||||
}
|
||||
|
||||
|
||||
VECTOR2I& SHAPE_POLY_SET::Vertex( int index, int aOutline , int aHole )
|
||||
{
|
||||
if( aOutline < 0 )
|
||||
aOutline += m_polys.size();
|
||||
|
||||
int idx;
|
||||
|
||||
if( aHole < 0 )
|
||||
idx = 0;
|
||||
else
|
||||
idx = aHole + 1;
|
||||
|
||||
assert( aOutline < (int)m_polys.size() );
|
||||
assert( idx < (int)m_polys[aOutline].size() );
|
||||
|
||||
return m_polys[aOutline][idx].Point( index );
|
||||
IntPoint p = m_polys[aOutline][idx][index];
|
||||
return VECTOR2I (p.X, p.Y);
|
||||
}
|
||||
|
||||
|
||||
@@ -152,9 +118,13 @@ int SHAPE_POLY_SET::AddOutline( const SHAPE_LINE_CHAIN& aOutline )
|
||||
{
|
||||
assert( aOutline.IsClosed() );
|
||||
|
||||
POLYGON poly;
|
||||
Path p = convert( aOutline );
|
||||
Paths poly;
|
||||
|
||||
poly.push_back( aOutline );
|
||||
if( !Orientation( p ) )
|
||||
ReversePath( p ); // outlines are always CW
|
||||
|
||||
poly.push_back( p );
|
||||
|
||||
m_polys.push_back( poly );
|
||||
|
||||
@@ -169,60 +139,49 @@ int SHAPE_POLY_SET::AddHole( const SHAPE_LINE_CHAIN& aHole, int aOutline )
|
||||
if( aOutline < 0 )
|
||||
aOutline += m_polys.size();
|
||||
|
||||
POLYGON& poly = m_polys[aOutline];
|
||||
Paths& poly = m_polys[aOutline];
|
||||
|
||||
assert( poly.size() );
|
||||
|
||||
poly.push_back( aHole );
|
||||
Path p = convert( aHole );
|
||||
|
||||
if( Orientation( p ) )
|
||||
ReversePath( p ); // holes are always CCW
|
||||
|
||||
poly.push_back( p );
|
||||
|
||||
return poly.size() - 1;
|
||||
}
|
||||
|
||||
|
||||
const Path SHAPE_POLY_SET::convertToClipper( const SHAPE_LINE_CHAIN& aPath, bool aRequiredOrientation )
|
||||
const ClipperLib::Path SHAPE_POLY_SET::convert( const SHAPE_LINE_CHAIN& aPath )
|
||||
{
|
||||
Path c_path;
|
||||
|
||||
for( int i = 0; i < aPath.PointCount(); i++ )
|
||||
{
|
||||
const VECTOR2I& vertex = aPath.CPoint( i );
|
||||
c_path.push_back( IntPoint( vertex.x, vertex.y ) );
|
||||
c_path.push_back( ClipperLib::IntPoint( vertex.x, vertex.y ) );
|
||||
}
|
||||
|
||||
if( Orientation( c_path ) != aRequiredOrientation )
|
||||
ReversePath( c_path );
|
||||
|
||||
return c_path;
|
||||
}
|
||||
|
||||
|
||||
const SHAPE_LINE_CHAIN SHAPE_POLY_SET::convertFromClipper( const Path& aPath )
|
||||
{
|
||||
SHAPE_LINE_CHAIN lc;
|
||||
|
||||
for( unsigned int i = 0; i < aPath.size(); i++ )
|
||||
lc.Append( aPath[i].X, aPath[i].Y );
|
||||
|
||||
return lc;
|
||||
}
|
||||
|
||||
|
||||
void SHAPE_POLY_SET::booleanOp( ClipType type, const SHAPE_POLY_SET& b )
|
||||
void SHAPE_POLY_SET::booleanOp( ClipperLib::ClipType type, const SHAPE_POLY_SET& b )
|
||||
{
|
||||
Clipper c;
|
||||
|
||||
c.StrictlySimple( true );
|
||||
|
||||
BOOST_FOREACH( const POLYGON& poly, m_polys )
|
||||
BOOST_FOREACH( Paths& subject, m_polys )
|
||||
{
|
||||
for( unsigned int i = 0; i < poly.size(); i++ )
|
||||
c.AddPath( convertToClipper( poly[i], i > 0 ? false : true ), ptSubject, true );
|
||||
c.AddPaths( subject, ptSubject, true );
|
||||
}
|
||||
|
||||
BOOST_FOREACH( const POLYGON& poly, b.m_polys )
|
||||
BOOST_FOREACH( const Paths& clip, b.m_polys )
|
||||
{
|
||||
for( unsigned int i = 0; i < poly.size(); i++ )
|
||||
c.AddPath( convertToClipper( poly[i], i > 0 ? false : true ), ptClip, true );
|
||||
c.AddPaths( clip, ptClip, true );
|
||||
}
|
||||
|
||||
PolyTree solution;
|
||||
@@ -233,39 +192,41 @@ void SHAPE_POLY_SET::booleanOp( ClipType type, const SHAPE_POLY_SET& b )
|
||||
}
|
||||
|
||||
|
||||
void SHAPE_POLY_SET::BooleanAdd( const SHAPE_POLY_SET& b )
|
||||
void SHAPE_POLY_SET::Add( const SHAPE_POLY_SET& b )
|
||||
{
|
||||
booleanOp( ctUnion, b );
|
||||
}
|
||||
|
||||
|
||||
void SHAPE_POLY_SET::BooleanSubtract( const SHAPE_POLY_SET& b )
|
||||
void SHAPE_POLY_SET::Subtract( const SHAPE_POLY_SET& b )
|
||||
{
|
||||
booleanOp( ctDifference, b );
|
||||
}
|
||||
|
||||
|
||||
void SHAPE_POLY_SET::Inflate( int aFactor, int aCircleSegmentsCount )
|
||||
void SHAPE_POLY_SET::Erode( int aFactor )
|
||||
{
|
||||
ClipperOffset c;
|
||||
|
||||
BOOST_FOREACH( const POLYGON& poly, m_polys )
|
||||
{
|
||||
for( unsigned int i = 0; i < poly.size(); i++ )
|
||||
c.AddPath( convertToClipper( poly[i], i > 0 ? false : true ), jtRound, etClosedPolygon );
|
||||
}
|
||||
BOOST_FOREACH( Paths& p, m_polys )
|
||||
c.AddPaths(p, jtRound, etClosedPolygon );
|
||||
|
||||
PolyTree solution;
|
||||
|
||||
c.ArcTolerance = (double)fabs( aFactor ) / M_PI / aCircleSegmentsCount;
|
||||
|
||||
c.Execute( solution, aFactor );
|
||||
|
||||
importTree( &solution );
|
||||
m_polys.clear();
|
||||
|
||||
for( PolyNode* n = solution.GetFirst(); n; n = n->GetNext() )
|
||||
{
|
||||
Paths ps;
|
||||
ps.push_back( n->Contour );
|
||||
m_polys.push_back( ps );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void SHAPE_POLY_SET::importTree( PolyTree* tree)
|
||||
void SHAPE_POLY_SET::importTree( ClipperLib::PolyTree* tree )
|
||||
{
|
||||
m_polys.clear();
|
||||
|
||||
@@ -273,37 +234,37 @@ void SHAPE_POLY_SET::importTree( PolyTree* tree)
|
||||
{
|
||||
if( !n->IsHole() )
|
||||
{
|
||||
POLYGON paths;
|
||||
paths.push_back( convertFromClipper( n->Contour ) );
|
||||
Paths paths;
|
||||
paths.push_back( n->Contour );
|
||||
|
||||
for( unsigned int i = 0; i < n->Childs.size(); i++ )
|
||||
paths.push_back( convertFromClipper( n->Childs[i]->Contour ) );
|
||||
for( unsigned i = 0; i < n->Childs.size(); i++ )
|
||||
paths.push_back( n->Childs[i]->Contour );
|
||||
|
||||
m_polys.push_back(paths);
|
||||
m_polys.push_back( paths );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Polygon fracturing code. Work in progress.
|
||||
|
||||
// Polygon fracturing code. Work in progress.
|
||||
struct FractureEdge
|
||||
{
|
||||
FractureEdge( bool connected, SHAPE_LINE_CHAIN* owner, int index ) :
|
||||
FractureEdge( bool connected, Path* owner, int index ) :
|
||||
m_connected( connected ),
|
||||
m_next( NULL )
|
||||
{
|
||||
m_p1 = owner->CPoint( index );
|
||||
m_p2 = owner->CPoint( index + 1 );
|
||||
m_p1 = (*owner)[index];
|
||||
m_p2 = (*owner)[(index + 1) % owner->size()];
|
||||
}
|
||||
|
||||
FractureEdge( int y = 0 ) :
|
||||
FractureEdge( int64_t y = 0 ) :
|
||||
m_connected( false ),
|
||||
m_next( NULL )
|
||||
{
|
||||
m_p1.x = m_p2.y = y;
|
||||
m_p1.Y = m_p2.Y = y;
|
||||
}
|
||||
|
||||
FractureEdge( bool connected, const VECTOR2I& p1, const VECTOR2I& p2 ) :
|
||||
FractureEdge( bool connected, const IntPoint& p1, const IntPoint& p2 ) :
|
||||
m_connected( connected ),
|
||||
m_p1( p1 ),
|
||||
m_p2( p2 ),
|
||||
@@ -313,14 +274,14 @@ struct FractureEdge
|
||||
|
||||
bool matches( int y ) const
|
||||
{
|
||||
int y_min = std::min( m_p1.y, m_p2.y );
|
||||
int y_max = std::max( m_p1.y, m_p2.y );
|
||||
int y_min = std::min( m_p1.Y, m_p2.Y );
|
||||
int y_max = std::max( m_p1.Y, m_p2.Y );
|
||||
|
||||
return ( y >= y_min ) && ( y <= y_max );
|
||||
}
|
||||
|
||||
bool m_connected;
|
||||
VECTOR2I m_p1, m_p2;
|
||||
IntPoint m_p1, m_p2;
|
||||
FractureEdge* m_next;
|
||||
};
|
||||
|
||||
@@ -329,10 +290,10 @@ typedef std::vector<FractureEdge*> FractureEdgeSet;
|
||||
|
||||
static int processEdge( FractureEdgeSet& edges, FractureEdge* edge )
|
||||
{
|
||||
int x = edge->m_p1.x;
|
||||
int y = edge->m_p1.y;
|
||||
int min_dist = std::numeric_limits<int>::max();
|
||||
int x_nearest = 0;
|
||||
int64_t x = edge->m_p1.X;
|
||||
int64_t y = edge->m_p1.Y;
|
||||
int64_t min_dist = std::numeric_limits<int64_t>::max();
|
||||
int64_t x_nearest = 0;
|
||||
|
||||
FractureEdge* e_nearest = NULL;
|
||||
|
||||
@@ -341,14 +302,15 @@ static int processEdge( FractureEdgeSet& edges, FractureEdge* edge )
|
||||
if( !(*i)->matches( y ) )
|
||||
continue;
|
||||
|
||||
int x_intersect;
|
||||
int64_t x_intersect;
|
||||
|
||||
if( (*i)->m_p1.y == (*i)->m_p2.y ) // horizontal edge
|
||||
x_intersect = std::max ( (*i)->m_p1.x, (*i)->m_p2.x );
|
||||
if( (*i)->m_p1.Y == (*i)->m_p2.Y ) // horizontal edge
|
||||
x_intersect = std::max( (*i)->m_p1.X, (*i)->m_p2.X );
|
||||
else
|
||||
x_intersect = (*i)->m_p1.x + rescale((*i)->m_p2.x - (*i)->m_p1.x, y - (*i)->m_p1.y, (*i)->m_p2.y - (*i)->m_p1.y );
|
||||
x_intersect = (*i)->m_p1.X + rescale((*i)->m_p2.X - (*i)->m_p1.X,
|
||||
y - (*i)->m_p1.Y, (*i)->m_p2.Y - (*i)->m_p1.Y );
|
||||
|
||||
int dist = ( x - x_intersect );
|
||||
int64_t dist = ( x - x_intersect );
|
||||
|
||||
if( dist > 0 && dist < min_dist )
|
||||
{
|
||||
@@ -362,9 +324,9 @@ static int processEdge( FractureEdgeSet& edges, FractureEdge* edge )
|
||||
{
|
||||
int count = 0;
|
||||
|
||||
FractureEdge* lead1 = new FractureEdge( true, VECTOR2I( x_nearest, y ), VECTOR2I( x, y ) );
|
||||
FractureEdge* lead2 = new FractureEdge( true, VECTOR2I( x, y ), VECTOR2I( x_nearest, y ) );
|
||||
FractureEdge* split_2 = new FractureEdge( true, VECTOR2I( x_nearest, y ), e_nearest->m_p2 );
|
||||
FractureEdge* lead1 = new FractureEdge( true, IntPoint( x_nearest, y), IntPoint( x, y ) );
|
||||
FractureEdge* lead2 = new FractureEdge( true, IntPoint( x, y), IntPoint( x_nearest, y ) );
|
||||
FractureEdge* split_2 = new FractureEdge( true, IntPoint( x_nearest, y ), e_nearest->m_p2 );
|
||||
|
||||
edges.push_back( split_2 );
|
||||
edges.push_back( lead1 );
|
||||
@@ -372,11 +334,11 @@ static int processEdge( FractureEdgeSet& edges, FractureEdge* edge )
|
||||
|
||||
FractureEdge* link = e_nearest->m_next;
|
||||
|
||||
e_nearest->m_p2 = VECTOR2I( x_nearest, y );
|
||||
e_nearest->m_p2 = IntPoint( x_nearest, y );
|
||||
e_nearest->m_next = lead1;
|
||||
lead1->m_next = edge;
|
||||
FractureEdge* last;
|
||||
|
||||
FractureEdge*last;
|
||||
for( last = edge; last->m_next != edge; last = last->m_next )
|
||||
{
|
||||
last->m_connected = true;
|
||||
@@ -394,7 +356,8 @@ static int processEdge( FractureEdgeSet& edges, FractureEdge* edge )
|
||||
return 0;
|
||||
}
|
||||
|
||||
void SHAPE_POLY_SET::fractureSingle( POLYGON& paths )
|
||||
|
||||
void SHAPE_POLY_SET::fractureSingle( ClipperLib::Paths& paths )
|
||||
{
|
||||
FractureEdgeSet edges;
|
||||
FractureEdgeSet border_edges;
|
||||
@@ -407,23 +370,21 @@ void SHAPE_POLY_SET::fractureSingle( POLYGON& paths )
|
||||
|
||||
int num_unconnected = 0;
|
||||
|
||||
BOOST_FOREACH( SHAPE_LINE_CHAIN& path, paths )
|
||||
BOOST_FOREACH( Path& path, paths )
|
||||
{
|
||||
int index = 0;
|
||||
|
||||
FractureEdge *prev = NULL, *first_edge = NULL;
|
||||
|
||||
int x_min = std::numeric_limits<int>::max();
|
||||
int64_t x_min = std::numeric_limits<int64_t>::max();
|
||||
|
||||
for( int i = 0; i < path.PointCount(); i++ )
|
||||
for( unsigned i = 0; i < path.size(); i++ )
|
||||
{
|
||||
const VECTOR2I& p = path.CPoint( i );
|
||||
|
||||
if( p.x < x_min )
|
||||
x_min = p.x;
|
||||
if( path[i].X < x_min )
|
||||
x_min = path[i].X;
|
||||
}
|
||||
|
||||
for( int i = 0; i < path.PointCount(); i++ )
|
||||
for( unsigned i = 0; i < path.size(); i++ )
|
||||
{
|
||||
FractureEdge* fe = new FractureEdge( first, &path, index++ );
|
||||
|
||||
@@ -436,7 +397,7 @@ void SHAPE_POLY_SET::fractureSingle( POLYGON& paths )
|
||||
if( prev )
|
||||
prev->m_next = fe;
|
||||
|
||||
if( i == path.PointCount() - 1 )
|
||||
if( i == path.size() - 1 )
|
||||
fe->m_next = first_edge;
|
||||
|
||||
prev = fe;
|
||||
@@ -444,27 +405,27 @@ void SHAPE_POLY_SET::fractureSingle( POLYGON& paths )
|
||||
|
||||
if( !first )
|
||||
{
|
||||
if( fe->m_p1.x == x_min )
|
||||
if( fe->m_p1.X == x_min )
|
||||
border_edges.push_back( fe );
|
||||
}
|
||||
|
||||
if( !fe->m_connected )
|
||||
num_unconnected++;
|
||||
}
|
||||
|
||||
first = false; // first path is always the outline
|
||||
}
|
||||
|
||||
// keep connecting holes to the main outline, until there's no holes left...
|
||||
while( num_unconnected > 0 )
|
||||
{
|
||||
int x_min = std::numeric_limits<int>::max();
|
||||
|
||||
int64_t x_min = std::numeric_limits<int64_t>::max();
|
||||
FractureEdge* smallestX = NULL;
|
||||
|
||||
// find the left-most hole edge and merge with the outline
|
||||
for( FractureEdgeSet::iterator i = border_edges.begin(); i != border_edges.end(); ++i )
|
||||
{
|
||||
int xt = (*i)->m_p1.x;
|
||||
int64_t xt = (*i)->m_p1.X;
|
||||
|
||||
if( ( xt < x_min ) && ! (*i)->m_connected )
|
||||
{
|
||||
@@ -477,16 +438,13 @@ void SHAPE_POLY_SET::fractureSingle( POLYGON& paths )
|
||||
}
|
||||
|
||||
paths.clear();
|
||||
SHAPE_LINE_CHAIN newPath;
|
||||
|
||||
newPath.SetClosed( true );
|
||||
|
||||
Path newPath;
|
||||
FractureEdge* e;
|
||||
|
||||
for( e = root; e->m_next != root; e = e->m_next )
|
||||
newPath.Append( e->m_p1 );
|
||||
newPath.push_back( e->m_p1 );
|
||||
|
||||
newPath.Append( e->m_p1 );
|
||||
newPath.push_back( e->m_p1 );
|
||||
|
||||
for( FractureEdgeSet::iterator i = edges.begin(); i != edges.end(); ++i )
|
||||
delete *i;
|
||||
@@ -497,9 +455,7 @@ void SHAPE_POLY_SET::fractureSingle( POLYGON& paths )
|
||||
|
||||
void SHAPE_POLY_SET::Fracture()
|
||||
{
|
||||
Simplify(); // remove overlallping holes/degeneracy
|
||||
|
||||
BOOST_FOREACH( POLYGON& paths, m_polys )
|
||||
BOOST_FOREACH( Paths& paths, m_polys )
|
||||
{
|
||||
fractureSingle( paths );
|
||||
}
|
||||
@@ -508,9 +464,12 @@ void SHAPE_POLY_SET::Fracture()
|
||||
|
||||
void SHAPE_POLY_SET::Simplify()
|
||||
{
|
||||
SHAPE_POLY_SET empty;
|
||||
|
||||
booleanOp( ctUnion, empty );
|
||||
for( unsigned i = 0; i < m_polys.size(); i++ )
|
||||
{
|
||||
Paths out;
|
||||
SimplifyPolygons( m_polys[i], out, pftNonZero );
|
||||
m_polys[i] = out;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -523,11 +482,13 @@ const std::string SHAPE_POLY_SET::Format() const
|
||||
for( unsigned i = 0; i < m_polys.size(); i++ )
|
||||
{
|
||||
ss << "poly " << m_polys[i].size() << "\n";
|
||||
|
||||
for( unsigned j = 0; j < m_polys[i].size(); j++)
|
||||
{
|
||||
ss << m_polys[i][j].PointCount() << "\n";
|
||||
for( int v = 0; v < m_polys[i][j].PointCount(); v++)
|
||||
ss << m_polys[i][j].CPoint( v ).x << " " << m_polys[i][j].CPoint( v ).y << "\n";
|
||||
ss << m_polys[i][j].size() << "\n";
|
||||
|
||||
for( unsigned v = 0; v < m_polys[i][j].size(); v++)
|
||||
ss << m_polys[i][j][v].X << " " << m_polys[i][j][v].Y << "\n";
|
||||
}
|
||||
ss << "\n";
|
||||
}
|
||||
@@ -554,8 +515,7 @@ bool SHAPE_POLY_SET::Parse( std::stringstream& aStream )
|
||||
|
||||
for( int i = 0; i < n_polys; i++ )
|
||||
{
|
||||
POLYGON paths;
|
||||
|
||||
ClipperLib::Paths paths;
|
||||
aStream >> tmp;
|
||||
|
||||
if( tmp != "poly" )
|
||||
@@ -569,26 +529,23 @@ bool SHAPE_POLY_SET::Parse( std::stringstream& aStream )
|
||||
|
||||
for( int j = 0; j < n_outlines; j++ )
|
||||
{
|
||||
SHAPE_LINE_CHAIN outline;
|
||||
|
||||
outline.SetClosed( true );
|
||||
ClipperLib::Path outline;
|
||||
|
||||
aStream >> tmp;
|
||||
int n_vertices = atoi( tmp.c_str() );
|
||||
for( int v = 0; v < n_vertices; v++ )
|
||||
{
|
||||
VECTOR2I p;
|
||||
ClipperLib::IntPoint p;
|
||||
|
||||
aStream >> tmp; p.x = atoi( tmp.c_str() );
|
||||
aStream >> tmp; p.y = atoi( tmp.c_str() );
|
||||
outline.Append( p );
|
||||
aStream >> tmp; p.X = atoi( tmp.c_str() );
|
||||
aStream >> tmp; p.Y = atoi( tmp.c_str() );
|
||||
outline.push_back( p );
|
||||
}
|
||||
|
||||
paths.push_back( outline );
|
||||
}
|
||||
|
||||
m_polys.push_back( paths );
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -600,146 +557,22 @@ const BOX2I SHAPE_POLY_SET::BBox( int aClearance ) const
|
||||
|
||||
for( unsigned i = 0; i < m_polys.size(); i++ )
|
||||
{
|
||||
if( first )
|
||||
bb = m_polys[i][0].BBox();
|
||||
else
|
||||
bb.Merge( m_polys[i][0].BBox() );
|
||||
for( unsigned j = 0; j < m_polys[i].size(); j++)
|
||||
{
|
||||
for( unsigned v = 0; v < m_polys[i][j].size(); v++)
|
||||
{
|
||||
VECTOR2I p( m_polys[i][j][v].X, m_polys[i][j][v].Y );
|
||||
|
||||
if( first )
|
||||
bb = BOX2I( p, VECTOR2I( 0, 0 ) );
|
||||
else
|
||||
bb.Merge( p );
|
||||
|
||||
first = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bb.Inflate( aClearance );
|
||||
return bb;
|
||||
}
|
||||
|
||||
|
||||
void SHAPE_POLY_SET::RemoveAllContours()
|
||||
{
|
||||
m_polys.clear();
|
||||
}
|
||||
|
||||
|
||||
void SHAPE_POLY_SET::DeletePolygon( int aIdx )
|
||||
{
|
||||
m_polys.erase( m_polys.begin() + aIdx );
|
||||
}
|
||||
|
||||
|
||||
void SHAPE_POLY_SET::Append( const SHAPE_POLY_SET& aSet )
|
||||
{
|
||||
m_polys.insert( m_polys.end(), aSet.m_polys.begin(), aSet.m_polys.end() );
|
||||
}
|
||||
|
||||
|
||||
void SHAPE_POLY_SET::Append( const VECTOR2I& aP, int aOutline, int aHole )
|
||||
{
|
||||
Append( aP.x, aP.y, aOutline, aHole );
|
||||
}
|
||||
|
||||
|
||||
bool SHAPE_POLY_SET::Contains( const VECTOR2I& aP, int aSubpolyIndex ) const
|
||||
{
|
||||
// fixme: support holes!
|
||||
|
||||
if( aSubpolyIndex >= 0 )
|
||||
return pointInPolygon( aP, m_polys[aSubpolyIndex][0] );
|
||||
|
||||
BOOST_FOREACH ( const POLYGON& polys, m_polys )
|
||||
{
|
||||
if( pointInPolygon( aP, polys[0] ) )
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool SHAPE_POLY_SET::pointInPolygon( const VECTOR2I& aP, const SHAPE_LINE_CHAIN& aPath ) const
|
||||
{
|
||||
int result = 0;
|
||||
int cnt = aPath.PointCount();
|
||||
|
||||
if ( !aPath.BBox().Contains( aP ) ) // test with bounding box first
|
||||
return false;
|
||||
|
||||
if( cnt < 3 )
|
||||
return false;
|
||||
|
||||
VECTOR2I ip = aPath.CPoint( 0 );
|
||||
|
||||
for( int i = 1; i <= cnt; ++i )
|
||||
{
|
||||
VECTOR2I ipNext = ( i == cnt ? aPath.CPoint( 0 ) : aPath.CPoint( i ) );
|
||||
|
||||
if( ipNext.y == aP.y )
|
||||
{
|
||||
if( ( ipNext.x == aP.x ) || ( ip.y == aP.y &&
|
||||
( ( ipNext.x > aP.x ) == ( ip.x < aP.x ) ) ) )
|
||||
return true;
|
||||
}
|
||||
|
||||
if( ( ip.y < aP.y ) != ( ipNext.y < aP.y ) )
|
||||
{
|
||||
if( ip.x >= aP.x )
|
||||
{
|
||||
if( ipNext.x > aP.x )
|
||||
result = 1 - result;
|
||||
else
|
||||
{
|
||||
int64_t d = (int64_t)( ip.x - aP.x ) * (int64_t)( ipNext.y - aP.y ) -
|
||||
(int64_t)( ipNext.x - aP.x ) * (int64_t)( ip.y - aP.y );
|
||||
|
||||
if( !d )
|
||||
return true;
|
||||
|
||||
if( ( d > 0 ) == ( ipNext.y > ip.y ) )
|
||||
result = 1 - result;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if( ipNext.x > aP.x )
|
||||
{
|
||||
int64_t d = (int64_t)( ip.x - aP.x ) * (int64_t)( ipNext.y - aP.y ) -
|
||||
(int64_t)( ipNext.x - aP.x ) * (int64_t)( ip.y - aP.y );
|
||||
|
||||
if( !d )
|
||||
return -1;
|
||||
|
||||
if( ( d > 0 ) == ( ipNext.y > ip.y ) )
|
||||
result = 1 - result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ip = ipNext;
|
||||
}
|
||||
|
||||
return result ? true : false;
|
||||
}
|
||||
|
||||
|
||||
void SHAPE_POLY_SET::Move( const VECTOR2I& aVector )
|
||||
{
|
||||
BOOST_FOREACH( POLYGON &poly, m_polys )
|
||||
{
|
||||
BOOST_FOREACH( SHAPE_LINE_CHAIN &path, poly )
|
||||
{
|
||||
path.Move( aVector );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int SHAPE_POLY_SET::TotalVertices() const
|
||||
{
|
||||
int c = 0;
|
||||
|
||||
BOOST_FOREACH( const POLYGON& poly, m_polys )
|
||||
{
|
||||
BOOST_FOREACH ( const SHAPE_LINE_CHAIN& path, poly )
|
||||
{
|
||||
c += path.PointCount();
|
||||
}
|
||||
}
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user