const EDA_RECT D_PAD::GetBoundingBox() const { EDA_RECT area; wxPoint quadrant1, quadrant2, quadrant3, quadrant4; int x, y, r, dx, dy; wxPoint center = ShapePos(); wxPoint endPoint; EDA_RECT endRect; switch( GetShape() ) { case PAD_SHAPE_CIRCLE: area.SetOrigin( center ); area.Inflate( m_Size.x / 2 ); break; case PAD_SHAPE_OVAL: /* To get the BoundingBox of an oval pad: * a) If the pad is ROUND, see method for PAD_SHAPE_CIRCLE above * OTHERWISE: * b) Construct EDA_RECT for portion between circular ends * c) Rotate that EDA_RECT * d) Add the circular ends to the EDA_RECT */ // Test if the shape is circular if( m_Size.x == m_Size.y ) { area.SetOrigin( center ); area.Inflate( m_Size.x / 2 ); break; } if( m_Size.x > m_Size.y ) { // Pad is horizontal dx = ( m_Size.x - m_Size.y ) / 2; dy = m_Size.y / 2; // Location of end-points x = dx; y = 0; r = dy; } else { // Pad is vertical dx = m_Size.x / 2; dy = ( m_Size.y - m_Size.x ) / 2; x = 0; y = dy; r = dx; } // Construct the center rectangle and rotate area.SetOrigin( center ); area.Inflate( dx, dy ); area = area.GetBoundingBoxRotated( center, m_Orient ); endPoint = wxPoint( x, y ); RotatePoint( &endPoint, m_Orient ); // Add points at each quadrant of circular regions endRect.SetOrigin( center + endPoint ); endRect.Inflate( r ); area.Merge( endRect ); endRect.SetSize( 0, 0 ); endRect.SetOrigin( center - endPoint ); endRect.Inflate( r ); area.Merge( endRect ); break; case PAD_SHAPE_RECT: case PAD_SHAPE_ROUNDRECT: // Use two opposite corners and track their rotation // (use symmetry for other points) quadrant1.x = m_Size.x/2; quadrant1.y = m_Size.y/2; quadrant2.x = -m_Size.x/2; quadrant2.y = m_Size.y/2; RotatePoint( &quadrant1, m_Orient ); RotatePoint( &quadrant2, m_Orient ); dx = std::max( std::abs( quadrant1.x ) , std::abs( quadrant2.x ) ); dy = std::max( std::abs( quadrant1.y ) , std::abs( quadrant2.y ) ); // Set the bbox area.SetOrigin( ShapePos() ); area.Inflate( dx, dy ); break; case PAD_SHAPE_TRAPEZOID: // Use the four corners and track their rotation // (Trapezoids will not be symmetric) quadrant1.x = (m_Size.x + m_DeltaSize.y)/2; quadrant1.y = (m_Size.y - m_DeltaSize.x)/2; quadrant2.x = -(m_Size.x + m_DeltaSize.y)/2; quadrant2.y = (m_Size.y + m_DeltaSize.x)/2; quadrant3.x = -(m_Size.x - m_DeltaSize.y)/2; quadrant3.y = -(m_Size.y + m_DeltaSize.x)/2; quadrant4.x = (m_Size.x - m_DeltaSize.y)/2; quadrant4.y = -(m_Size.y - m_DeltaSize.x)/2; RotatePoint( &quadrant1, m_Orient ); RotatePoint( &quadrant2, m_Orient ); RotatePoint( &quadrant3, m_Orient ); RotatePoint( &quadrant4, m_Orient ); x = std::min( quadrant1.x, std::min( quadrant2.x, std::min( quadrant3.x, quadrant4.x) ) ); y = std::min( quadrant1.y, std::min( quadrant2.y, std::min( quadrant3.y, quadrant4.y) ) ); dx = std::max( quadrant1.x, std::max( quadrant2.x, std::max( quadrant3.x, quadrant4.x) ) ); dy = std::max( quadrant1.y, std::max( quadrant2.y, std::max( quadrant3.y, quadrant4.y) ) ); area.SetOrigin( ShapePos().x + x, ShapePos().y + y ); area.SetSize( dx-x, dy-y ); break; case PAD_SHAPE_CUSTOM: { SHAPE_POLY_SET polySet( m_customShapeAsPolygon ); // Move shape to actual position CustomShapeAsPolygonToBoardPosition( &polySet, GetPosition(), GetOrientation() ); quadrant1 = m_Pos; quadrant2 = m_Pos; for( int cnt = 0; cnt < polySet.OutlineCount(); ++cnt ) { const SHAPE_LINE_CHAIN& poly = polySet.COutline( cnt ); for( int ii = 0; ii < poly.PointCount(); ++ii ) { quadrant1.x = std::min( quadrant1.x, poly.CPoint( ii ).x ); quadrant1.y = std::min( quadrant1.y, poly.CPoint( ii ).y ); quadrant2.x = std::max( quadrant2.x, poly.CPoint( ii ).x ); quadrant2.y = std::max( quadrant2.y, poly.CPoint( ii ).y ); } } area.SetOrigin( quadrant1 ); area.SetEnd( quadrant2 ); } break; default: break; } return area; }
void D_PAD::TransformShapeWithClearanceToPolygon( SHAPE_POLY_SET& aCornerBuffer, int aClearanceValue, int aError, bool ignoreLineWidth ) const { wxASSERT_MSG( !ignoreLineWidth, "IgnoreLineWidth has no meaning for pads." ); double angle = m_Orient; int dx = (m_Size.x / 2) + aClearanceValue; int dy = (m_Size.y / 2) + aClearanceValue; wxPoint padShapePos = ShapePos(); /* Note: for pad having a shape offset, * the pad position is NOT the shape position */ switch( GetShape() ) { case PAD_SHAPE_CIRCLE: { TransformCircleToPolygon( aCornerBuffer, padShapePos, dx, aError ); } break; case PAD_SHAPE_OVAL: // An oval pad has the same shape as a segment with rounded ends { int width; wxPoint shape_offset; if( dy > dx ) // Oval pad X/Y ratio for choosing translation axis { shape_offset.y = dy - dx; width = dx * 2; } else //if( dy <= dx ) { shape_offset.x = dy - dx; width = dy * 2; } RotatePoint( &shape_offset, angle ); wxPoint start = padShapePos - shape_offset; wxPoint end = padShapePos + shape_offset; TransformOvalClearanceToPolygon( aCornerBuffer, start, end, width, aError ); } break; case PAD_SHAPE_TRAPEZOID: case PAD_SHAPE_RECT: { wxPoint corners[4]; BuildPadPolygon( corners, wxSize( 0, 0 ), angle ); SHAPE_POLY_SET outline; outline.NewOutline(); for( int ii = 0; ii < 4; ii++ ) { corners[ii] += padShapePos; outline.Append( corners[ii].x, corners[ii].y ); } int numSegs = std::max( GetArcToSegmentCount( aClearanceValue, aError, 360.0 ), 6 ); double correction = GetCircletoPolyCorrectionFactor( numSegs ); int rounding_radius = KiROUND( aClearanceValue * correction ); outline.Inflate( rounding_radius, numSegs ); aCornerBuffer.Append( outline ); } break; case PAD_SHAPE_CHAMFERED_RECT: case PAD_SHAPE_ROUNDRECT: { SHAPE_POLY_SET outline; int radius = GetRoundRectCornerRadius() + aClearanceValue; int numSegs = std::max( GetArcToSegmentCount( radius, aError, 360.0 ), 6 ); double correction = GetCircletoPolyCorrectionFactor( numSegs ); int clearance = KiROUND( aClearanceValue * correction ); int rounding_radius = GetRoundRectCornerRadius() + clearance; wxSize shapesize( m_Size ); shapesize.x += clearance * 2; shapesize.y += clearance * 2; bool doChamfer = GetShape() == PAD_SHAPE_CHAMFERED_RECT; TransformRoundChamferedRectToPolygon( outline, padShapePos, shapesize, angle, rounding_radius, doChamfer ? GetChamferRectRatio() : 0.0, doChamfer ? GetChamferPositions() : 0, aError ); aCornerBuffer.Append( outline ); } break; case PAD_SHAPE_CUSTOM: { int numSegs = std::max( GetArcToSegmentCount( aClearanceValue, aError, 360.0 ), 6 ); double correction = GetCircletoPolyCorrectionFactor( numSegs ); int clearance = KiROUND( aClearanceValue * correction ); SHAPE_POLY_SET outline; // Will contain the corners in board coordinates outline.Append( m_customShapeAsPolygon ); CustomShapeAsPolygonToBoardPosition( &outline, GetPosition(), GetOrientation() ); outline.Simplify( SHAPE_POLY_SET::PM_FAST ); outline.Inflate( clearance, numSegs ); outline.Fracture( SHAPE_POLY_SET::PM_FAST ); aCornerBuffer.Append( outline ); } break; } }