CPolyLine* CPolyLine::Fillet( unsigned int aRadius, unsigned int aSegments ) { CPolyLine* newPoly = new CPolyLine; if( !aRadius ) { newPoly->Copy( this ); return newPoly; } int polycount = GetContoursCount(); for( int contour = 0; contour < polycount; 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 = m_CornersList[index].x; y1 = m_CornersList[index].y; if( index == startIndex ) { xa = m_CornersList[endIndex].x - x1; ya = m_CornersList[endIndex].y - y1; } else { xa = m_CornersList[index - 1].x - x1; ya = m_CornersList[index - 1].y - y1; } if( index == endIndex ) { xb = m_CornersList[startIndex].x - x1; yb = m_CornersList[startIndex].y - y1; } else { xb = m_CornersList[index + 1].x - x1; yb = m_CornersList[index + 1].y - y1; } double lena = hypot( xa, ya ); double lenb = hypot( xb, yb ); double cosine = ( xa * xb + ya * yb ) / ( lena * lenb ); double radius = aRadius; double denom = sqrt( 2.0 / ( 1 + cosine ) - 1 ); // Do nothing in case of parallel edges if( std::isinf( denom ) ) continue; // 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; ny = yc + ys; if( index == startIndex ) newPoly->Start( GetLayer(), KiROUND( nx ), KiROUND( ny ), GetHatchStyle() ); else newPoly->AppendCorner( KiROUND( nx ), KiROUND( ny ) ); for( unsigned int j = 0; j < segments; j++ ) { nx = xc + cos( startAngle + (j + 1) * deltaAngle ) * radius; ny = yc - sin( startAngle + (j + 1) * deltaAngle ) * radius; newPoly->AppendCorner( KiROUND( nx ), KiROUND( ny ) ); } } newPoly->CloseLastContour(); } return newPoly; }
CPolyLine* CPolyLine::Chamfer( unsigned int aDistance ) { CPolyLine* newPoly = new CPolyLine; if( !aDistance ) { newPoly->Copy( this ); return newPoly; } int polycount = GetContoursCount(); for( int contour = 0; contour < polycount; contour++ ) { unsigned int startIndex = GetContourStart( contour ); unsigned int endIndex = GetContourEnd( contour ); for( unsigned int index = startIndex; index <= endIndex; index++ ) { int x1, y1, nx, ny; long long xa, ya, xb, yb; x1 = m_CornersList[index].x; y1 = m_CornersList[index].y; if( index == startIndex ) { xa = m_CornersList[endIndex].x - x1; ya = m_CornersList[endIndex].y - y1; } else { xa = m_CornersList[index - 1].x - x1; ya = m_CornersList[index - 1].y - y1; } if( index == endIndex ) { xb = m_CornersList[startIndex].x - x1; yb = m_CornersList[startIndex].y - y1; } else { xb = m_CornersList[index + 1].x - x1; yb = m_CornersList[index + 1].y - y1; } unsigned int lena = KiROUND( hypot( xa, ya ) ); unsigned int lenb = KiROUND( hypot( xb, yb ) ); unsigned int distance = aDistance; // Chamfer one half of an edge at most if( 0.5 * lena < distance ) distance = int( 0.5 * lena ); if( 0.5 * lenb < distance ) distance = int( 0.5 * lenb ); nx = KiROUND( (distance * xa) / hypot( xa, ya ) ); ny = KiROUND( (distance * ya) / hypot( xa, ya ) ); if( index == startIndex ) newPoly->Start( GetLayer(), x1 + nx, y1 + ny, GetHatchStyle() ); else newPoly->AppendCorner( x1 + nx, y1 + ny ); nx = KiROUND( (distance * xb) / hypot( xb, yb ) ); ny = KiROUND( (distance * yb) / hypot( xb, yb ) ); newPoly->AppendCorner( x1 + nx, y1 + ny ); } newPoly->CloseLastContour(); } return newPoly; }