From d3932f5f25d4cf129618dd39da8812d7091b347f Mon Sep 17 00:00:00 2001 From: Marco Mattila Date: Wed, 23 Feb 2011 23:34:28 +0200 Subject: [PATCH] Pcbnew: Fix add similar/cutout zone. Fix zone corner smoothing for zones with cutouts. --- pcbnew/zones_by_polygon.cpp | 4 +- polygon/PolyLine.cpp | 411 +++++++++++++++--------------------- polygon/PolyLine.h | 44 +--- 3 files changed, 177 insertions(+), 282 deletions(-) diff --git a/pcbnew/zones_by_polygon.cpp b/pcbnew/zones_by_polygon.cpp index feb2091c95..f7393b5c02 100644 --- a/pcbnew/zones_by_polygon.cpp +++ b/pcbnew/zones_by_polygon.cpp @@ -65,7 +65,7 @@ void WinEDA_PcbFrame::Add_Similar_Zone( wxDC* DC, ZONE_CONTAINER* zone_container // Use the general event handle to set others params (like toolbar) */ wxCommandEvent evt; evt.SetId( ID_PCB_ZONES_BUTT ); - Process_Special_Functions( evt ); + OnSelectTool( evt ); } @@ -91,7 +91,7 @@ void WinEDA_PcbFrame::Add_Zone_Cutout( wxDC* DC, ZONE_CONTAINER* zone_container // Use the general event handle to set others params (like toolbar) */ wxCommandEvent evt; evt.SetId( ID_PCB_ZONES_BUTT ); - Process_Special_Functions( evt ); + OnSelectTool( evt ); } diff --git a/polygon/PolyLine.cpp b/polygon/PolyLine.cpp index 336c26b08c..cc95947f15 100644 --- a/polygon/PolyLine.cpp +++ b/polygon/PolyLine.cpp @@ -907,211 +907,199 @@ void CPolyLine::RemoveContour( int icont ) } -int CPolyLine::Chamfer( unsigned int aIndex, unsigned int aDistance ) -{ - int x1, y1; - long xa, ya, xb, yb, nx, ny; - - if( !aDistance ) - return 0; - - x1 = corner[aIndex].x; - y1 = corner[aIndex].y; - - if( aIndex == 0 ) - { - xa = corner[corner.size()-1].x - x1; - ya = corner[corner.size()-1].y - y1; - } - else - { - xa = corner[aIndex-1].x - x1; - ya = corner[aIndex-1].y - y1; - } - - if( aIndex == corner.size()-1 ) - { - xb = corner[0].x - x1; - yb = corner[0].y - y1; - } - else - { - xb = corner[aIndex+1].x - x1; - yb = corner[aIndex+1].y - y1; - } - - // Move the first vertex into new position - nx = (long) ( (double) (aDistance*xa)/sqrt( (double) (xa*xa + ya*ya) ) ); - ny = (long) ( (double) (aDistance*ya)/sqrt( (double) (xa*xa + ya*ya) ) ); - corner[aIndex].x = x1 + nx; - corner[aIndex].y = y1 + ny; - - // Add one new vertex - nx = (long) ( (double) (aDistance*xb)/sqrt( (double) (xb*xb + yb*yb) ) ); - ny = (long) ( (double) (aDistance*yb)/sqrt( (double) (xb*xb + yb*yb) ) ); - InsertCorner( aIndex, x1 + nx, y1 + ny ); - - return 1; // Added one vertex -} - - CPolyLine* CPolyLine::Chamfer( unsigned int aDistance ) { CPolyLine* newPoly = new CPolyLine; - unsigned int lena, lenb; - newPoly->Copy( this ); - for( unsigned int i = 0, index = 0; i < corner.size(); i++, index++ ) + if( !aDistance ) { - if( i == 0 ) - lena = GetEdgeLength( corner.size()-1 ); - else - lena = GetEdgeLength( i - 1 ); - lenb = GetEdgeLength( i ); + newPoly->Copy( this ); + return newPoly; + } - unsigned int distance = aDistance; + for( int contour = 0; contour < GetNumContours(); contour++ ) + { + unsigned int startIndex = GetContourStart( contour ); + unsigned int endIndex = GetContourEnd( contour ); - // Chamfer one half of an edge at most - if( 0.5*lena < distance ) - distance = (unsigned int) 0.5*lena; + for( unsigned int index = startIndex; index <= endIndex; index++ ) + { + int x1, y1, nx, ny; + long long xa, ya, xb, yb; - if( 0.5*lenb < distance ) - distance = (unsigned int) 0.5*lenb; + x1 = corner[index].x; + y1 = corner[index].y; - // Chamfer this corner and keep tract of added vertices - index += newPoly->Chamfer( index, distance ); + if( index == startIndex ) + { + xa = corner[endIndex].x - x1; + ya = corner[endIndex].y - y1; + } + else + { + xa = corner[index-1].x - x1; + ya = corner[index-1].y - y1; + } + + if( index == endIndex ) + { + xb = corner[startIndex].x - x1; + yb = corner[startIndex].y - y1; + } + else + { + xb = corner[index+1].x - x1; + yb = corner[index+1].y - y1; + } + + unsigned int lena = (unsigned int)sqrt( (double)(xa*xa + ya*ya) ); + unsigned int lenb = (unsigned int)sqrt( (double)(xb*xb + yb*yb) ); + unsigned int distance = aDistance; + + // Chamfer one half of an edge at most + if( 0.5*lena < distance ) + distance = 0.5*lena; + + if( 0.5*lenb < distance ) + distance = 0.5*lenb; + + nx = (int) ( (double) (distance*xa)/sqrt( (double) (xa*xa + ya*ya) ) ); + ny = (int) ( (double) (distance*ya)/sqrt( (double) (xa*xa + ya*ya) ) ); + + if( index == startIndex ) + newPoly->Start( GetLayer(), x1 + nx, y1 + ny, GetHatchStyle() ); + else + newPoly->AppendCorner( x1 + nx, y1 + ny ); + + nx = (int) ( (double) (distance*xb)/sqrt( (double) (xb*xb + yb*yb) ) ); + ny = (int) ( (double) (distance*yb)/sqrt( (double) (xb*xb + yb*yb) ) ); + newPoly->AppendCorner( x1 + nx, y1 + ny ); + } + newPoly->Close(); } return newPoly; } -int CPolyLine::Fillet( unsigned int aIndex, unsigned int aRadius, - unsigned int aSegments ) -{ - int x1, y1; // Current vertex - int xa, ya; // Previous vertex - int xb, yb; // Next vertex - double nx, ny; - - if( !aRadius ) - return 0; - - x1 = corner[aIndex].x; - y1 = corner[aIndex].y; - - if( aIndex == 0 ) - { - xa = corner[corner.size()-1].x - x1; - ya = corner[corner.size()-1].y - y1; - } - else - { - xa = corner[aIndex-1].x - x1; - ya = corner[aIndex-1].y - y1; - } - - if( aIndex == corner.size()-1 ) - { - xb = corner[0].x - x1; - yb = corner[0].y - y1; - } - else - { - xb = corner[aIndex+1].x - x1; - yb = corner[aIndex+1].y - y1; - } - - double lena = sqrt( (double) (xa*xa + ya*ya) ); - double lenb = sqrt( (double) (xb*xb + yb*yb) ); - double cosine = ( xa*xb + ya*yb )/( lena*lenb ); - - // Calculate fillet arc absolute center point (xc, yx) - double k = aRadius / sqrt( .5*( 1-cosine ) ); - double lenab = sqrt( ( xa/lena + xb/lenb )*( xa/lena + xb/lenb ) + - ( ya/lena + yb/lenb )*( ya/lena + yb/lenb ) ); - double xc = x1 + k*( xa/lena + xb/lenb )/lenab; - double yc = y1 + k*( ya/lena + yb/lenb )/lenab; - - // Calculate arc start and end vectors - k = aRadius / sqrt( 2/( 1+cosine )-1 ); - double xs = x1 + k*xa/lena - xc; - double ys = y1 + k*ya/lena - yc; - double xe = x1 + k*xb/lenb - xc; - double ye = y1 + k*yb/lenb - yc; - - // Cosine of arc angle - double argument = ( xs*xe + ys*ye ) / ( aRadius*aRadius ); - - if( argument < -1 ) // Just in case... - argument = -1; - else if( argument > 1 ) - argument = 1; - - double arcAngle = acos( argument ); - - // Calculate the number of segments - double tempSegments = (double)aSegments * ( arcAngle / ( 2*M_PI ) ); - - if( tempSegments - (int)tempSegments > 0 ) - tempSegments++; - aSegments = (unsigned int) tempSegments; - - double deltaAngle = arcAngle / aSegments; - double startAngle = atan2( -ys, xs ); - - // Flip arc for inner corners - if( xa*yb - ya*xb <= 0 ) - deltaAngle *= -1; - - // Move first vertex into new position - nx = xc + xs + 0.5; - ny = yc + ys + 0.5; - corner[aIndex].x = (int)nx; - corner[aIndex].y = (int)ny; - - // Add new vertices - unsigned int nVertices = 0; - for( unsigned int j = 0; j < aSegments; j++ ) - { - nx = xc + cos( startAngle + (j+1)*deltaAngle )*aRadius + 0.5; - ny = yc - sin( startAngle + (j+1)*deltaAngle )*aRadius + 0.5; - InsertCorner( aIndex + nVertices, (int)nx, (int)ny ); - nVertices++; - } - - return nVertices; // Return the number of added vertices -} - - CPolyLine* CPolyLine::Fillet( unsigned int aRadius, unsigned int aSegments ) { CPolyLine* newPoly = new CPolyLine; - unsigned int lena, lenb; - newPoly->Copy( this ); - for( unsigned int i = 0, index = 0; i < corner.size(); i++, index++ ) + if( !aRadius ) { - if( i == 0 ) - lena = GetEdgeLength( corner.size()-1 ); - else - lena = GetEdgeLength( i - 1 ); - lenb = GetEdgeLength( i ); - - unsigned int radius = aRadius; - double denom = sqrt( 2.0/( 1+GetCosine( i ) )-1 ); - - // Limit rounding distance to one half of an edge - if( 0.5*lena*denom < radius ) - radius = (unsigned int) ( 0.5 * (double) lena * denom ); - - if( 0.5*lenb*denom < radius ) - radius = (unsigned int) ( 0.5 * (double) lenb * denom ); - - // Round this corner and keep tract of added vertices - index += newPoly->Fillet( index, radius, aSegments ); + newPoly->Copy( this ); + return newPoly; } + for( int contour = 0; contour < GetNumContours(); contour++ ) + { + unsigned int startIndex = GetContourStart( contour ); + unsigned int endIndex = GetContourEnd( contour ); + + for( unsigned int index = startIndex; index <= endIndex; index++ ) + { + + int x1, y1; // Current vertex + long long xa, ya; // Previous vertex + long long xb, yb; // Next vertex + double nx, ny; + + x1 = corner[index].x; + y1 = corner[index].y; + + if( index == startIndex ) + { + xa = corner[endIndex].x - x1; + ya = corner[endIndex].y - y1; + } + else + { + xa = corner[index-1].x - x1; + ya = corner[index-1].y - y1; + } + + if( index == endIndex ) + { + xb = corner[startIndex].x - x1; + yb = corner[startIndex].y - y1; + } + else + { + xb = corner[index+1].x - x1; + yb = corner[index+1].y - y1; + } + + double lena = sqrt( (double) (xa*xa + ya*ya) ); + double lenb = sqrt( (double) (xb*xb + yb*yb) ); + double cosine = ( xa*xb + ya*yb )/( lena*lenb ); + + unsigned int radius = aRadius; + double denom = sqrt( 2.0/( 1+cosine )-1 ); + + // Limit rounding distance to one half of an edge + if( 0.5*lena*denom < radius ) + radius = 0.5*lena*denom; + + if( 0.5*lenb*denom < radius ) + radius = 0.5*lenb*denom; + + // Calculate fillet arc absolute center point (xc, yx) + double k = radius / sqrt( .5*( 1-cosine ) ); + double lenab = sqrt( ( xa/lena + xb/lenb )*( xa/lena + xb/lenb ) + + ( ya/lena + yb/lenb )*( ya/lena + yb/lenb ) ); + double xc = x1 + k*( xa/lena + xb/lenb )/lenab; + double yc = y1 + k*( ya/lena + yb/lenb )/lenab; + + // Calculate arc start and end vectors + k = radius / sqrt( 2/( 1+cosine )-1 ); + double xs = x1 + k*xa/lena - xc; + double ys = y1 + k*ya/lena - yc; + double xe = x1 + k*xb/lenb - xc; + double ye = y1 + k*yb/lenb - yc; + + // Cosine of arc angle + double argument = ( xs*xe + ys*ye ) / ( radius*radius ); + + if( argument < -1 ) // Just in case... + argument = -1; + else if( argument > 1 ) + argument = 1; + + double arcAngle = acos( argument ); + + // Calculate the number of segments + double tempSegments = (double)aSegments * ( arcAngle / ( 2*M_PI ) ); + + if( tempSegments - (int)tempSegments > 0 ) + tempSegments++; + unsigned int segments = (unsigned int) tempSegments; + + double deltaAngle = arcAngle / segments; + double startAngle = atan2( -ys, xs ); + + // Flip arc for inner corners + if( xa*yb - ya*xb <= 0 ) + deltaAngle *= -1; + + nx = xc + xs + 0.5; + ny = yc + ys + 0.5; + if( index == startIndex ) + newPoly->Start( GetLayer(), (int)nx, (int)ny, GetHatchStyle() ); + else + newPoly->AppendCorner( (int)nx, (int)ny ); + + unsigned int nVertices = 0; + for( unsigned int j = 0; j < segments; j++ ) + { + nx = xc + cos( startAngle + (j+1)*deltaAngle )*radius + 0.5; + ny = yc - sin( startAngle + (j+1)*deltaAngle )*radius + 0.5; + newPoly->AppendCorner( (int)nx, (int)ny ); + nVertices++; + } + } + newPoly->Close(); + } return newPoly; } @@ -1205,63 +1193,6 @@ int CPolyLine::GetEndContour( int ic ) } -unsigned int CPolyLine::GetEdgeLength( unsigned int aIndex ) -{ - long xa, ya, xb, yb; - xa = corner[aIndex].x; - ya = corner[aIndex].y; - - if( aIndex == corner.size()-1 ) - { - xb = corner[0].x; - yb = corner[0].y; - } - else - { - xb = corner[aIndex+1].x; - yb = corner[aIndex+1].y; - } - - return (unsigned int) sqrt( (double) (xb-xa)*(xb-xa) + (yb-ya)*(yb-ya) ); -} - - -double CPolyLine::GetCosine( unsigned int aIndex ) -{ - int x1, y1; - long xa, ya, xb, yb; - x1 = corner[aIndex].x; - y1 = corner[aIndex].y; - - if( aIndex == 0 ) - { - xa = corner[corner.size()-1].x - x1; - ya = corner[corner.size()-1].y - y1; - } - else - { - xa = corner[aIndex-1].x - x1; - ya = corner[aIndex-1].y - y1; - } - - if( aIndex == corner.size() - 1 ) - { - xb = corner[0].x - x1; - yb = corner[0].y - y1; - } - else - { - xb = corner[aIndex+1].x - x1; - yb = corner[aIndex+1].y - y1; - } - - double lena = sqrt( (double)xa*xa + ya*ya ); - double lenb = sqrt( (double)xb*xb + yb*yb ); - - return ( xa*xb + ya*yb )/( lena*lenb ); -} - - CRect CPolyLine::GetBounds() { CRect r = GetCornerBounds(); diff --git a/polygon/PolyLine.h b/polygon/PolyLine.h index 948ea081c4..5f608b07c2 100644 --- a/polygon/PolyLine.h +++ b/polygon/PolyLine.h @@ -132,15 +132,6 @@ public: void Close( int style = STRAIGHT, bool bDraw = false ); void RemoveContour( int icont ); - /** - * Function Chamfer - * chamfers a corner. - * @param aIndex is the corner index. - * @param aDistance is the chamfering distance. - * @return int - The number of segments added. - */ - int Chamfer( unsigned int aIndex, unsigned int aDistance ); - /** * Function Chamfer * returns a chamfered version of a polygon. @@ -149,17 +140,6 @@ public: */ CPolyLine* Chamfer( unsigned int aDistance ); - /** - * Function Fillet - * rounds a corner. - * @param aIndex is the corner index. - * @param aDistance is the fillet radius. - * @param aSegments is the number of segments / 360 degrees. - * @return int - The number of segments added. - */ - int Fillet( unsigned int aIndex, unsigned int aRadius, - unsigned int aSegments ); - /** * Function Fillet * returns a filleted version of a polygon. @@ -200,28 +180,12 @@ public: int GetY( int ic ); int GetEndContour( int ic ); - /** - * Function GetEdgeLength - * returns the length of the edge starting at given corner index. - * @param aIndex is the corner index. - * @return unsigned int - the length of the edge. - */ - unsigned int GetEdgeLength( unsigned int aIndex ); - - /** - * Function GetCosine - * returns the cosine between the two edge vectors at a corner. - * @param aIndex is the corner index. - * @return double - the cosine value. - */ - double GetCosine( unsigned int aIndex ); - - int GetUtility( int ic ) { return corner[ic].utility; }; - void SetUtility( int ic, int utility ) { corner[ic].utility = utility; }; + int GetUtility( int ic ) { return corner[ic].utility; }; + void SetUtility( int ic, int utility ) { corner[ic].utility = utility; }; int GetSideStyle( int is ); - int GetHatchStyle() { return m_HatchStyle; } - void SetHatch( int hatch ) { Undraw(); m_HatchStyle = hatch; Draw(); }; + int GetHatchStyle() { return m_HatchStyle; } + void SetHatch( int hatch ) { Undraw(); m_HatchStyle = hatch; Draw(); }; void SetX( int ic, int x ); void SetY( int ic, int y ); void SetEndContour( int ic, bool end_contour );