PolyLine.cpp: NormalizeAreaOutlines now removes null segments.

* CPolyLine::Chamfer (and CPolyLine::Fillet) :  removes null segments before calculating modified outlines.
  It fixes some incorrect outlines after chamfer or fillet due to null segments creating overflow during calculations.
* CPolyLine::Chamfer : code cleaning (avoid useless double to integer and integer to double conversions).
This commit is contained in:
jean-pierre charras 2016-06-26 16:39:15 +02:00
parent e47f0df068
commit 58ddb0fd37
2 changed files with 39 additions and 33 deletions

View File

@ -77,8 +77,8 @@ CPolyLine::~CPolyLine()
int CPolyLine::RemoveNullSegments() int CPolyLine::RemoveNullSegments()
{ {
int removed = 0; int removed = 0;
unsigned startcountour = 0; unsigned startcountour = 0;
for( unsigned icnt = 1; icnt < m_CornersList.GetCornersCount(); icnt ++ ) for( unsigned icnt = 1; icnt < m_CornersList.GetCornersCount(); icnt ++ )
{ {
unsigned last = icnt-1; unsigned last = icnt-1;
@ -107,17 +107,15 @@ CPolyLine::~CPolyLine()
} }
/** /* Convert a self-intersecting polygon to one (or more) non self-intersecting polygon(s)
* Function NormalizeAreaOutlines * and removes null segments.
* Convert a self-intersecting polygon to one (or more) non self-intersecting polygon(s) * param aNewPolygonList = a std::vector<CPolyLine*> reference where to store new CPolyLine
* @param aNewPolygonList = a std::vector<CPolyLine*> reference where to store new CPolyLine
* needed by the normalization * needed by the normalization
* @return the polygon count (always >= 1, because there is at least one polygon) * return the polygon count (always >= 1, because there is at least one polygon)
* There are new polygons only if the polygon count is > 1 * There are new polygons only if the polygon count is > 1
*/ */
int CPolyLine::NormalizeAreaOutlines( std::vector<CPolyLine*>* aNewPolygonList ) int CPolyLine::NormalizeAreaOutlines( std::vector<CPolyLine*>* aNewPolygonList )
{ {
SHAPE_POLY_SET polySet = ConvertPolyListToPolySet( m_CornersList ); SHAPE_POLY_SET polySet = ConvertPolyListToPolySet( m_CornersList );
// We are expecting only one main outline, but this main outline can have holes // We are expecting only one main outline, but this main outline can have holes
@ -165,6 +163,7 @@ int CPolyLine::NormalizeAreaOutlines( std::vector<CPolyLine*>* aNewPolygonList )
pnew.Polygon( 0 ) = polySet.CPolygon( ii ); pnew.Polygon( 0 ) = polySet.CPolygon( ii );
polyline->m_CornersList = ConvertPolySetToPolyList( pnew ); polyline->m_CornersList = ConvertPolySetToPolyList( pnew );
polyline->RemoveNullSegments();
} }
return polySet.OutlineCount(); return polySet.OutlineCount();
@ -285,6 +284,10 @@ void CPolyLine::RemoveContour( int icont )
CPolyLine* CPolyLine::Chamfer( unsigned int aDistance ) CPolyLine* CPolyLine::Chamfer( unsigned int aDistance )
{ {
// Null segments create serious issues in calculations.
// remove them:
RemoveNullSegments();
CPolyLine* newPoly = new CPolyLine; CPolyLine* newPoly = new CPolyLine;
if( !aDistance ) if( !aDistance )
@ -302,11 +305,11 @@ CPolyLine* CPolyLine::Chamfer( unsigned int aDistance )
for( unsigned int index = startIndex; index <= endIndex; index++ ) for( unsigned int index = startIndex; index <= endIndex; index++ )
{ {
int x1, y1, nx, ny; // Current vertex
long long xa, ya, xb, yb; int x1 = m_CornersList[index].x;
int y1 = m_CornersList[index].y;
x1 = m_CornersList[index].x; double xa, ya; // Previous vertex
y1 = m_CornersList[index].y; double xb, yb; // Next vertex
if( index == startIndex ) if( index == startIndex )
{ {
@ -330,28 +333,28 @@ CPolyLine* CPolyLine::Chamfer( unsigned int aDistance )
yb = m_CornersList[index + 1].y - y1; yb = m_CornersList[index + 1].y - y1;
} }
unsigned int lena = KiROUND( hypot( xa, ya ) ); double lena = hypot( xa, ya );
unsigned int lenb = KiROUND( hypot( xb, yb ) ); double lenb = hypot( xb, yb );
unsigned int distance = aDistance; double distance = aDistance;
// Chamfer one half of an edge at most // Chamfer one half of an edge at most
if( 0.5 * lena < distance ) if( 0.5 * lena < distance )
distance = int( 0.5 * lena ); distance = 0.5 * lena;
if( 0.5 * lenb < distance ) if( 0.5 * lenb < distance )
distance = int( 0.5 * lenb ); distance = 0.5 * lenb;
nx = KiROUND( (distance * xa) / hypot( xa, ya ) ); int nx1 = KiROUND( distance * xa / lena );
ny = KiROUND( (distance * ya) / hypot( xa, ya ) ); int ny1 = KiROUND( distance * ya / lena );
if( index == startIndex ) if( index == startIndex )
newPoly->Start( GetLayer(), x1 + nx, y1 + ny, GetHatchStyle() ); newPoly->Start( GetLayer(), x1 + nx1, y1 + ny1, GetHatchStyle() );
else else
newPoly->AppendCorner( x1 + nx, y1 + ny ); newPoly->AppendCorner( x1 + nx1, y1 + ny1 );
nx = KiROUND( (distance * xb) / hypot( xb, yb ) ); int nx2 = KiROUND( distance * xb / lenb );
ny = KiROUND( (distance * yb) / hypot( xb, yb ) ); int ny2 = KiROUND( distance * yb / lenb );
newPoly->AppendCorner( x1 + nx, y1 + ny ); newPoly->AppendCorner( x1 + nx2, y1 + ny2 );
} }
newPoly->CloseLastContour(); newPoly->CloseLastContour();
@ -363,6 +366,10 @@ CPolyLine* CPolyLine::Chamfer( unsigned int aDistance )
CPolyLine* CPolyLine::Fillet( unsigned int aRadius, unsigned int aSegments ) CPolyLine* CPolyLine::Fillet( unsigned int aRadius, unsigned int aSegments )
{ {
// Null segments create serious issues in calculations.
// remove them:
RemoveNullSegments();
CPolyLine* newPoly = new CPolyLine; CPolyLine* newPoly = new CPolyLine;
if( !aRadius ) if( !aRadius )
@ -380,13 +387,11 @@ CPolyLine* CPolyLine::Fillet( unsigned int aRadius, unsigned int aSegments )
for( unsigned int index = startIndex; index <= endIndex; index++ ) for( unsigned int index = startIndex; index <= endIndex; index++ )
{ {
int x1, y1; // Current vertex // Current vertex
long long xa, ya; // Previous vertex int x1 = m_CornersList[index].x;
long long xb, yb; // Next vertex int y1 = m_CornersList[index].y;
double nx, ny; double xa, ya; // Previous vertex
double xb, yb; // Next vertex
x1 = m_CornersList[index].x;
y1 = m_CornersList[index].y;
if( index == startIndex ) if( index == startIndex )
{ {
@ -467,8 +472,8 @@ CPolyLine* CPolyLine::Fillet( unsigned int aRadius, unsigned int aSegments )
if( xa * yb - ya * xb <= 0 ) if( xa * yb - ya * xb <= 0 )
deltaAngle *= -1; deltaAngle *= -1;
nx = xc + xs; double nx = xc + xs;
ny = yc + ys; double ny = yc + ys;
if( index == startIndex ) if( index == startIndex )
newPoly->Start( GetLayer(), KiROUND( nx ), KiROUND( ny ), GetHatchStyle() ); newPoly->Start( GetLayer(), KiROUND( nx ), KiROUND( ny ), GetHatchStyle() );

View File

@ -422,6 +422,7 @@ public:
/** /**
* Function NormalizeAreaOutlines * Function NormalizeAreaOutlines
* Convert a self-intersecting polygon to one (or more) non self-intersecting polygon(s) * Convert a self-intersecting polygon to one (or more) non self-intersecting polygon(s)
* Removes null segments.
* @param aNewPolygonList = a std::vector<CPolyLine*> reference where to store new CPolyLine * @param aNewPolygonList = a std::vector<CPolyLine*> reference where to store new CPolyLine
* needed by the normalization * needed by the normalization
* @return the polygon count (always >= 1, because there is at least one polygon) * @return the polygon count (always >= 1, because there is at least one polygon)