Pcbnew: add a new primitive pad shape: chamfered round rect pad.

Allows 0 to 4 chamfered corners, not only one.

A custom shape allow this kind of shape. However because it is a primitive,
it is easier to edit and it support thermal reliefs.
This commit is contained in:
jean-pierre charras 2018-08-29 09:13:07 +02:00
parent d25d62295a
commit d259459a14
27 changed files with 11700 additions and 9119 deletions

View File

@ -491,6 +491,25 @@ void CINFO3D_VISU::createNewPadWithClearance( const D_PAD* aPad,
}
break;
case PAD_SHAPE_CHAMFERED_RECT:
{
wxSize shapesize( aPad->GetSize() );
shapesize.x += aClearanceValue.x * 2;
shapesize.y += aClearanceValue.y * 2;
SHAPE_POLY_SET polyList; // Will contain the pad outlines in board coordinates
int corner_radius = aPad->GetRoundRectCornerRadius( shapesize );
TransformRoundChamferedRectToPolygon( polyList, PadShapePos, shapesize, aPad->GetOrientation(),
corner_radius, aPad->GetChamferRectRatio(),
aPad->GetChamferPositions(), 32 );
// Add the PAD polygon
Convert_shape_line_polygon_to_triangles( polyList, *aDstContainer, m_biuTo3Dunits, *aPad );
}
break;
case PAD_SHAPE_CUSTOM:
{
SHAPE_POLY_SET polyList; // Will contain the pad outlines in board coordinates
@ -575,6 +594,7 @@ void CINFO3D_VISU::createNewPad( const D_PAD* aPad,
case PAD_SHAPE_CIRCLE:
case PAD_SHAPE_OVAL:
case PAD_SHAPE_ROUNDRECT:
case PAD_SHAPE_CHAMFERED_RECT:
case PAD_SHAPE_CUSTOM:
createNewPadWithClearance( aPad, aDstContainer, aInflateValue );
break;

View File

@ -52,6 +52,7 @@ void CINFO3D_VISU::buildPadShapePolygon( const D_PAD* aPad,
case PAD_SHAPE_CIRCLE:
case PAD_SHAPE_OVAL:
case PAD_SHAPE_ROUNDRECT:
case PAD_SHAPE_CHAMFERED_RECT:
{
// We are using TransformShapeWithClearanceToPolygon to build the shape.
// Currently, this method uses only the same inflate value for X and Y dirs.

View File

@ -207,24 +207,19 @@ void GetRoundRectCornerCenters( wxPoint aCenters[4], int aRadius,
aCenters[ii] += aPosition;
}
/**
* Function TransformRoundRectToPolygon
* convert a rectangle with rounded corners to a polygon
* Convert arcs to multiple straight lines
* @param aCornerBuffer = a buffer to store the polygon
* @param aPosition = the coordinate of the center of the rectangle
* @param aSize = the size of the rectangle
* @param aCornerRadius = radius of rounded corners
* @param aRotation = rotation in 0.1 degrees of the rectangle
* @param aCircleToSegmentsCount = the number of segments to approximate a circle
*/
void TransformRoundRectToPolygon( SHAPE_POLY_SET& aCornerBuffer,
void TransformRoundChamferedRectToPolygon( SHAPE_POLY_SET& aCornerBuffer,
const wxPoint& aPosition, const wxSize& aSize,
double aRotation, int aCornerRadius,
double aChamferRatio, int aChamferCorners,
int aCircleToSegmentsCount )
{
// Build the basic shape in orientation 0.0, position 0,0 for chamfered corners
// or in actual position/orientation for round rect only
wxPoint corners[4];
GetRoundRectCornerCenters( corners, aCornerRadius, aPosition, aSize, aRotation );
GetRoundRectCornerCenters( corners, aCornerRadius,
aChamferCorners ? wxPoint( 0, 0 ) : aPosition,
aSize, aChamferCorners ? 0.0 : aRotation );
SHAPE_POLY_SET outline;
outline.NewOutline();
@ -234,6 +229,68 @@ void TransformRoundRectToPolygon( SHAPE_POLY_SET& aCornerBuffer,
outline.Inflate( aCornerRadius, aCircleToSegmentsCount );
if( aChamferCorners == RECT_NO_CHAMFER ) // no chamfer
{
// Add the outline:
aCornerBuffer.Append( outline );
return;
}
// Now we have the round rect outline, in position 0,0 orientation 0.0.
// Chamfer the corner(s).
int chamfer_value = aChamferRatio * std::min( aSize.x, aSize.y );
SHAPE_POLY_SET chamfered_corner; // corner shape for the current corner to chamfer
int corner_id[4] =
{
RECT_CHAMFER_TOP_LEFT, RECT_CHAMFER_TOP_RIGHT,
RECT_CHAMFER_BOTTOM_LEFT, RECT_CHAMFER_BOTTOM_RIGHT
};
// Depending on the corner position, signX[] and signY[] give the sign of chamfer
// coordinates relative to the corner position
// The first corner is the top left corner, then top right, bottom left and bottom right
int signX[4] = {1, -1, 1,-1 };
int signY[4] = {1, 1, -1,-1 };
for( int ii = 0; ii < 4; ii++ )
{
if( (corner_id[ii] & aChamferCorners) == 0 )
continue;
VECTOR2I corner_pos( -signX[ii]*aSize.x/2, -signY[ii]*aSize.y/2 );
if( aCornerRadius )
{
// We recreate a rectangular area covering the full rounded corner (max size = aSize/2)
// to rebuild the corner before chamfering, to be sure the rounded corner shape does not
// overlap the chamfered corner shape:
chamfered_corner.RemoveAllContours();
chamfered_corner.NewOutline();
chamfered_corner.Append( 0, 0 );
chamfered_corner.Append( 0, signY[ii]*aSize.y/2 );
chamfered_corner.Append( signX[ii]*aSize.x/2, signY[ii]*aSize.y/2 );
chamfered_corner.Append( signX[ii]*aSize.x/2, 0 );
chamfered_corner.Move( corner_pos );
outline.BooleanAdd( chamfered_corner, SHAPE_POLY_SET::PM_STRICTLY_SIMPLE );
}
// Now chamfer this corner
chamfered_corner.RemoveAllContours();
chamfered_corner.NewOutline();
chamfered_corner.Append( 0, 0 );
chamfered_corner.Append( 0, signY[ii]*chamfer_value );
chamfered_corner.Append( signX[ii]*chamfer_value, 0 );
chamfered_corner.Move( corner_pos );
outline.BooleanSubtract( chamfered_corner, SHAPE_POLY_SET::PM_STRICTLY_SIMPLE );
}
// Rotate and move the outline:
if( aRotation != 0.0 )
outline.Rotate( DECIDEG2RAD( -aRotation ), VECTOR2I( 0, 0 ) );
outline.Move( VECTOR2I( aPosition ) );
// Add the outline:
aCornerBuffer.Append( outline );
}

View File

@ -44,8 +44,11 @@ blind
blind_buried_vias_allowed
bold
bottom
bottom_left
bottom_right
center
chamfer
chamfer_ratio
circle
clearance
comment
@ -176,6 +179,8 @@ thermal_gap
thermal_bridge_width
thickness
top
top_left
top_right
trace_width
tracks
trace_min

View File

@ -747,8 +747,8 @@ void DXF_PLOTTER::FlashPadRoundRect( const wxPoint& aPadPos, const wxSize& aSize
{
SHAPE_POLY_SET outline;
const int segmentToCircleCount = 64;
TransformRoundRectToPolygon( outline, aPadPos, aSize, aOrient,
aCornerRadius, segmentToCircleCount );
TransformRoundChamferedRectToPolygon( outline, aPadPos, aSize, aOrient,
aCornerRadius, 0.0, 0, segmentToCircleCount );
// TransformRoundRectToPolygon creates only one convex polygon
SHAPE_LINE_CHAIN& poly = outline.Outline( 0 );

View File

@ -842,8 +842,8 @@ void GERBER_PLOTTER::FlashPadRoundRect( const wxPoint& aPadPos, const wxSize& aS
// TODO: use Aperture macro and flash it
SHAPE_POLY_SET outline;
const int segmentToCircleCount = 64;
TransformRoundRectToPolygon( outline, aPadPos, aSize, aOrient,
aCornerRadius, segmentToCircleCount );
TransformRoundChamferedRectToPolygon( outline, aPadPos, aSize, aOrient,
aCornerRadius, 0.0, 0, segmentToCircleCount );
if( aTraceMode != FILLED )
outline.Inflate( -GetCurrentLineWidth()/2, 16 );

View File

@ -642,8 +642,8 @@ void HPGL_PLOTTER::FlashPadRoundRect( const wxPoint& aPadPos, const wxSize& aSiz
aCornerRadius = std::min( aCornerRadius, std::min( size.x, size.y ) /2 );
}
TransformRoundRectToPolygon( outline, aPadPos, size, aOrient,
aCornerRadius, segmentToCircleCount );
TransformRoundChamferedRectToPolygon( outline, aPadPos, size, aOrient,
aCornerRadius, 0.0, 0, segmentToCircleCount );
// TransformRoundRectToPolygon creates only one convex polygon
std::vector< wxPoint > cornerList;

View File

@ -201,8 +201,8 @@ void PSLIKE_PLOTTER::FlashPadRoundRect( const wxPoint& aPadPos, const wxSize& aS
SHAPE_POLY_SET outline;
const int segmentToCircleCount = 64;
TransformRoundRectToPolygon( outline, aPadPos, size, aOrient,
aCornerRadius, segmentToCircleCount );
TransformRoundChamferedRectToPolygon( outline, aPadPos, size, aOrient,
aCornerRadius, 0.0, 0, segmentToCircleCount );
std::vector< wxPoint > cornerList;
cornerList.reserve( segmentToCircleCount + 5 );

View File

@ -36,6 +36,21 @@
#include <macros.h>
#include <geometry/shape_poly_set.h>
// The chamfer positions of chamfered rect shape.
// the position is relative to a pad with orientation = 0
// we can have 1 to 4 chamfered corners (0 corner = roundrect)
// The position list is the OR of corner to chamfer
enum RECT_CHAMFER_POSITIONS
{
RECT_NO_CHAMFER = 0,
RECT_CHAMFER_TOP_LEFT = 1,
RECT_CHAMFER_TOP_RIGHT = 2,
RECT_CHAMFER_BOTTOM_LEFT = 4,
RECT_CHAMFER_BOTTOM_RIGHT = 8,
};
/**
* Function TransformCircleToPolygon
* convert a circle to a polygon, using multiple straight lines
@ -86,20 +101,29 @@ void TransformOvalClearanceToPolygon( SHAPE_POLY_SET& aCornerBuffer,
void GetRoundRectCornerCenters( wxPoint aCenters[4], int aRadius,
const wxPoint& aPosition, const wxSize& aSize, double aRotation );
/**
* Function TransformRoundRectToPolygon
* convert a rectangle with rounded corners to a polygon
* Convert arcs to multiple straight lines
* convert a rectangle with rounded corners and/or chamfered corners to a polygon
* Convert rounded corners arcs to multiple straight lines
* @param aCornerBuffer = a buffer to store the polygon
* @param aPosition = the coordinate of the center of the rectangle
* @param aSize = the size of the rectangle
* @param aCornerRadius = radius of rounded corners
* @param aCornerRadius = radius of rounded corners (can be 0)
* @param aRotation = rotation in 0.1 degrees of the rectangle
* @param aChamferRatio = ratio between smaller rect size and chamfer value
* @param aChamferCorners = identifier of the corners to chamfer:
* 0 = no chamfer
* 1 = TOP_LEFT
* 2 = TOP_RIGHT
* 4 = BOTTOM_LEFT
* 8 = BOTTOM_RIGHT
* One can have more than one chamfered corner by ORing the corner identifers
* @param aCircleToSegmentsCount = the number of segments to approximate a circle
*/
void TransformRoundRectToPolygon( SHAPE_POLY_SET& aCornerBuffer,
void TransformRoundChamferedRectToPolygon( SHAPE_POLY_SET& aCornerBuffer,
const wxPoint& aPosition, const wxSize& aSize,
double aRotation, int aCornerRadius,
double aChamferRatio, int aChamferCorners,
int aCircleToSegmentsCount );
/**

View File

@ -35,6 +35,7 @@ enum PAD_SHAPE_T
PAD_SHAPE_OVAL,
PAD_SHAPE_TRAPEZOID,
PAD_SHAPE_ROUNDRECT,
PAD_SHAPE_CHAMFERED_RECT, // Rectangle with a champered corner ( and with rounded other corners)
PAD_SHAPE_CUSTOM // A shape defined by user, using a set of basic shapes
// (thick segments, circles, arcs, polygons
};

View File

@ -767,18 +767,22 @@ void D_PAD::TransformShapeWithClearanceToPolygon( SHAPE_POLY_SET& aCornerBuffer,
}
break;
case PAD_SHAPE_CHAMFERED_RECT:
case PAD_SHAPE_ROUNDRECT:
{
SHAPE_POLY_SET outline;
int pad_radius = GetRoundRectCornerRadius();
int clearance = int( aClearanceValue * aCorrectionFactor );
int rounding_radius = pad_radius + clearance;
int rounding_radius = GetRoundRectCornerRadius() + clearance;
wxSize shapesize( m_Size );
shapesize.x += clearance*2;
shapesize.y += clearance*2;
bool doChamfer = GetShape() == PAD_SHAPE_CHAMFERED_RECT;
TransformRoundRectToPolygon( outline, padShapePos, shapesize, angle,
rounding_radius, aCircleToSegmentsCount );
TransformRoundChamferedRectToPolygon( outline, padShapePos, shapesize, angle,
rounding_radius,
doChamfer ? GetChamferRectRatio() : 0.0,
doChamfer ? GetChamferPositions() : 0,
aCircleToSegmentsCount );
aCornerBuffer.Append( outline );
}
@ -819,6 +823,7 @@ void D_PAD::BuildPadShapePolygon( SHAPE_POLY_SET& aCornerBuffer,
case PAD_SHAPE_CIRCLE:
case PAD_SHAPE_OVAL:
case PAD_SHAPE_ROUNDRECT:
case PAD_SHAPE_CHAMFERED_RECT:
{
// We are using TransformShapeWithClearanceToPolygon to build the shape.
// Currently, this method uses only the same inflate value for X and Y dirs.
@ -1172,7 +1177,8 @@ void CreateThermalReliefPadPolygon( SHAPE_POLY_SET& aCornerBuffer,
}
break;
case PAD_SHAPE_ROUNDRECT: // thermal shape is the same for round rect and rect.
case PAD_SHAPE_CHAMFERED_RECT:
case PAD_SHAPE_ROUNDRECT: // thermal shape is the same for rectangular shapes.
case PAD_SHAPE_RECT:
{
/* we create 4 copper holes and put them in position 1, 2, 3 and 4

View File

@ -78,11 +78,14 @@ D_PAD::D_PAD( MODULE* parent ) :
m_LocalSolderPasteMargin = 0;
m_LocalSolderPasteMarginRatio = 0.0;
// Parameters for round rect only:
m_padRoundRectRadiusScale = 0.25; // from IPC-7351C standard
m_padRoundRectRadiusScale = 0.25; // from IPC-7351C standard
// Parameters for chamfered rect only:
m_padChamferRectScale = 0.2; // Size of chamfer: ratio of smallest of X,Y size
m_chamferPositions = RECT_NO_CHAMFER; // No chamfered corner
m_ZoneConnection = PAD_ZONE_CONN_INHERITED; // Use parent setting by default
m_ThermalWidth = 0; // Use parent setting by default
m_ThermalGap = 0; // Use parent setting by default
m_ZoneConnection = PAD_ZONE_CONN_INHERITED; // Use parent setting by default
m_ThermalWidth = 0; // Use parent setting by default
m_ThermalGap = 0; // Use parent setting by default
m_customShapeClearanceArea = CUST_PAD_SHAPE_IN_ZONE_OUTLINE;
@ -169,6 +172,14 @@ int D_PAD::boundingRadius() const
radius += 1 + KiROUND( EuclideanNorm( wxSize( x - radius, y - radius )));
break;
case PAD_SHAPE_CHAMFERED_RECT:
radius = GetRoundRectCornerRadius();
x = m_Size.x >> 1;
y = m_Size.y >> 1;
radius += 1 + KiROUND( EuclideanNorm( wxSize( x - radius, y - radius )));
// TODO: modify radius if the chamfer is smaller than corner radius
break;
case PAD_SHAPE_CUSTOM:
radius = 0;
@ -293,6 +304,7 @@ const EDA_RECT D_PAD::GetBoundingBox() const
case PAD_SHAPE_RECT:
case PAD_SHAPE_ROUNDRECT:
case PAD_SHAPE_CHAMFERED_RECT:
// Use two opposite corners and track their rotation
// (use symmetry for other points)
quadrant1.x = m_Size.x/2;
@ -919,17 +931,23 @@ bool D_PAD::HitTest( const wxPoint& aPosition ) const
break;
case PAD_SHAPE_CHAMFERED_RECT:
case PAD_SHAPE_ROUNDRECT:
{
{
// Check for hit in polygon
SHAPE_POLY_SET outline;
const int segmentToCircleCount = ARC_APPROX_SEGMENTS_COUNT_HIGH_DEF;
TransformRoundRectToPolygon( outline, wxPoint(0,0), GetSize(), m_Orient,
GetRoundRectCornerRadius(), segmentToCircleCount );
bool doChamfer = GetShape() == PAD_SHAPE_CHAMFERED_RECT;
TransformRoundChamferedRectToPolygon( outline, wxPoint(0,0), GetSize(), m_Orient,
GetRoundRectCornerRadius(),
doChamfer ? GetChamferRectRatio() : 0.0,
doChamfer ? GetChamferPositions() : 0,
segmentToCircleCount );
const SHAPE_LINE_CHAIN &poly = outline.COutline( 0 );
return TestPointInsidePolygon( (const wxPoint*)&poly.CPoint(0), poly.PointCount(), delta );
}
}
break;
case PAD_SHAPE_CUSTOM:
@ -978,6 +996,7 @@ bool D_PAD::HitTest( const EDA_RECT& aRect, bool aContained, int aAccuracy ) con
return arect.IntersectsCircle( GetPosition(), GetBoundingRadius() );
case PAD_SHAPE_RECT:
case PAD_SHAPE_CHAMFERED_RECT: // TODO use a finer shape analysis
shapeRect.SetOrigin( shapePos );
shapeRect.Inflate( m_Size.x / 2, m_Size.y / 2 );
return arect.Intersects( shapeRect, m_Orient );
@ -1082,8 +1101,6 @@ bool D_PAD::HitTest( const EDA_RECT& aRect, bool aContained, int aAccuracy ) con
* b) Test intersection of vertical rect
* c) Test intersection of each corner
*/
r = GetRoundRectCornerRadius();
/* Test A - intersection of horizontal rect */
@ -1224,6 +1241,9 @@ wxString D_PAD::ShowPadShape() const
case PAD_SHAPE_ROUNDRECT:
return _( "Roundrect" );
case PAD_SHAPE_CHAMFERED_RECT:
return _( "Chamferedrect" );
case PAD_SHAPE_CUSTOM:
return _( "CustomShape" );

View File

@ -658,6 +658,48 @@ public:
m_padRoundRectRadiusScale = std::min( aRadiusScale, 0.5 );
}
/**
* has meaning only for chamfered rect pads
* @return the ratio between the smaller Y or Y size and the radius
* of the rounded corners.
* Cannot be > 0.5
*/
double GetChamferRectRatio() const
{
return m_padChamferRectScale;
}
/**
* has meaning only for chamfered rect pads
* Set the ratio between the smaller Y or Y size and the radius
* of the rounded corners.
* Cannot be < 0.5 and obviously must be > 0
*/
void SetChamferRectRatio( double aChamferScale )
{
if( aChamferScale < 0.0 )
aChamferScale = 0.0;
m_padChamferRectScale = std::min( aChamferScale, 0.5 );
}
/**
* has meaning only for chamfered rect pads
* @return the position of the chamfer for a 0 orientation
*/
int GetChamferPositions() const { return m_chamferPositions; }
/**
* has meaning only for chamfered rect pads
* set the position of the chamfer for a 0 orientation, one of
* PAD_CHAMFER_TOP_LEFT, PAD_CHAMFER_TOP_RIGHT,
* PAD_CHAMFER_BOTTOM_LEFT, PAD_CHAMFER_BOTTOM_RIGHT
*/
void SetChamferPositions( int aChamferPositions )
{
m_chamferPositions = aChamferPositions;
}
/**
* Function GetSubRatsnest
* @return int - the netcode
@ -835,6 +877,9 @@ private: // Private variable members:
double m_padRoundRectRadiusScale; ///< scaling factor from smallest m_Size coord
///< to corner radius, default 0.25
double m_padChamferRectScale; ///< scaling factor from smallest m_Size coord
///< to chamfer value, default 0.25
int m_chamferPositions; ///< the positions of the chamfered position for a 0 orientation
PAD_SHAPE_T m_anchorPadShape; ///< for custom shaped pads: shape of pad anchor,
///< PAD_SHAPE_RECT, PAD_SHAPE_CIRCLE

View File

@ -43,9 +43,13 @@
#include <pcb_painter.h>
#include <widgets/net_selector.h>
#include <dialog_pad_properties.h>
#include <dialog_pad_properties.h>
#include <html_messagebox.h>
#include <convert_basic_shapes_to_polygon.h> // for enum RECT_CHAMFER_POSITIONS definition
// list of pad shapes, ordered like the pad shape wxChoice in dialog.
static PAD_SHAPE_T code_shape[] =
@ -55,6 +59,7 @@ static PAD_SHAPE_T code_shape[] =
PAD_SHAPE_RECT,
PAD_SHAPE_TRAPEZOID,
PAD_SHAPE_ROUNDRECT,
PAD_SHAPE_CHAMFERED_RECT,
PAD_SHAPE_CUSTOM, // choice = CHOICE_SHAPE_CUSTOM_CIRC_ANCHOR
PAD_SHAPE_CUSTOM // choice = PAD_SHAPE_CUSTOM_RECT_ANCHOR
};
@ -68,6 +73,7 @@ enum CODE_CHOICE
CHOICE_SHAPE_RECT,
CHOICE_SHAPE_TRAPEZOID,
CHOICE_SHAPE_ROUNDRECT,
CHOICE_SHAPE_CHAMFERED_RECT,
CHOICE_SHAPE_CUSTOM_CIRC_ANCHOR,
CHOICE_SHAPE_CUSTOM_RECT_ANCHOR
};
@ -452,11 +458,15 @@ void DIALOG_PAD_PROPERTIES::updateRoundRectCornerValues()
{
// Note: use m_tcCornerSizeRatio->ChangeValue() to avoid generating a wxEVT_TEXT event
if( m_dummyPad->GetShape() == PAD_SHAPE_ROUNDRECT )
if( m_dummyPad->GetShape() == PAD_SHAPE_ROUNDRECT ||
m_dummyPad->GetShape() == PAD_SHAPE_CHAMFERED_RECT )
{
auto ratio = wxString::Format( "%.1f", m_dummyPad->GetRoundRectRadiusRatio() * 100 );
m_tcCornerSizeRatio->ChangeValue( ratio );
m_cornerRadius.SetValue( m_dummyPad->GetRoundRectCornerRadius() );
ratio = wxString::Format( "%.1f", m_dummyPad->GetChamferRectRatio() * 100 );
m_tcChamferRatio->ChangeValue( ratio );
}
else if( m_dummyPad->GetShape() == PAD_SHAPE_RECT )
{
@ -473,7 +483,8 @@ void DIALOG_PAD_PROPERTIES::updateRoundRectCornerValues()
void DIALOG_PAD_PROPERTIES::onCornerRadiusChange( wxCommandEvent& event )
{
if( m_dummyPad->GetShape() != PAD_SHAPE_ROUNDRECT )
if( m_dummyPad->GetShape() != PAD_SHAPE_ROUNDRECT &&
m_dummyPad->GetShape() != PAD_SHAPE_CHAMFERED_RECT )
return;
wxString value = m_tcCornerRadius->GetValue();
@ -499,27 +510,55 @@ void DIALOG_PAD_PROPERTIES::onCornerRadiusChange( wxCommandEvent& event )
void DIALOG_PAD_PROPERTIES::onCornerSizePercentChange( wxCommandEvent& event )
{
if( m_dummyPad->GetShape() != PAD_SHAPE_ROUNDRECT )
if( m_dummyPad->GetShape() != PAD_SHAPE_ROUNDRECT &&
m_dummyPad->GetShape() != PAD_SHAPE_CHAMFERED_RECT )
return;
wxString value = m_tcCornerSizeRatio->GetValue();
double rrRadiusRatioPercent;
double ratioPercent;
if( value.ToDouble( &rrRadiusRatioPercent ) )
bool asChanged = false;
if( value.ToDouble( &ratioPercent ) )
{
// Clamp rrRadiusRatioPercent to acceptable value (0.0 to 50.0)
if( rrRadiusRatioPercent < 0.0 )
// Clamp ratioPercent to acceptable value (0.0 to 50.0)
if( ratioPercent < 0.0 )
{
rrRadiusRatioPercent = 0.0;
ratioPercent = 0.0;
m_tcCornerSizeRatio->ChangeValue( "0.0" );
}
if( rrRadiusRatioPercent > 50.0 )
if( ratioPercent > 50.0 )
{
rrRadiusRatioPercent = 0.5;
ratioPercent = 0.5;
m_tcCornerSizeRatio->ChangeValue( "50.0" );
}
asChanged = true;
}
value = m_tcChamferRatio->GetValue();
if( value.ToDouble( &ratioPercent ) )
{
// Clamp ratioPercent to acceptable value (0.0 to 50.0)
if( ratioPercent < 0.0 )
{
ratioPercent = 0.0;
m_tcChamferRatio->ChangeValue( "0.0" );
}
if( ratioPercent > 50.0 )
{
ratioPercent = 0.5;
m_tcChamferRatio->ChangeValue( "50.0" );
}
asChanged = true;
}
if( asChanged )
{
transferDataToPad( m_dummyPad );
m_cornerRadius.ChangeValue( m_dummyPad->GetRoundRectCornerRadius() );
redraw();
@ -705,6 +744,7 @@ void DIALOG_PAD_PROPERTIES::initValues()
case PAD_SHAPE_RECT: m_PadShape->SetSelection( CHOICE_SHAPE_RECT ); break;
case PAD_SHAPE_TRAPEZOID: m_PadShape->SetSelection( CHOICE_SHAPE_TRAPEZOID ); break;
case PAD_SHAPE_ROUNDRECT: m_PadShape->SetSelection( CHOICE_SHAPE_ROUNDRECT ); break;
case PAD_SHAPE_CHAMFERED_RECT: m_PadShape->SetSelection( CHOICE_SHAPE_CHAMFERED_RECT ); break;
case PAD_SHAPE_CUSTOM:
if( m_dummyPad->GetAnchorPadShape() == PAD_SHAPE_RECT )
@ -714,6 +754,12 @@ void DIALOG_PAD_PROPERTIES::initValues()
break;
}
m_cbTopLeft->SetValue( (m_dummyPad->GetChamferPositions() & RECT_CHAMFER_TOP_LEFT) );
m_cbTopRight->SetValue( (m_dummyPad->GetChamferPositions() & RECT_CHAMFER_TOP_RIGHT) );
m_cbBottomLeft->SetValue( (m_dummyPad->GetChamferPositions() & RECT_CHAMFER_BOTTOM_LEFT) );
m_cbBottomRight->SetValue( (m_dummyPad->GetChamferPositions() & RECT_CHAMFER_BOTTOM_RIGHT) );
enablePrimitivePage( PAD_SHAPE_CUSTOM == m_dummyPad->GetShape() );
// Type of pad selection
@ -866,6 +912,7 @@ void DIALOG_PAD_PROPERTIES::onChangePadMode( wxCommandEvent& event )
}
void DIALOG_PAD_PROPERTIES::OnPadShapeSelection( wxCommandEvent& event )
{
bool is_custom = false;
@ -909,6 +956,7 @@ void DIALOG_PAD_PROPERTIES::OnPadShapeSelection( wxCommandEvent& event )
break;
case CHOICE_SHAPE_ROUNDRECT:
case CHOICE_SHAPE_CHAMFERED_RECT:
m_trapDelta.Enable( false );
m_trapAxisLabel->Enable( false );
m_trapAxisCtrl->Enable( false );
@ -934,11 +982,20 @@ void DIALOG_PAD_PROPERTIES::OnPadShapeSelection( wxCommandEvent& event )
enablePrimitivePage( is_custom );
// A few widgets are enabled only for rounded rect pads:
m_staticTextCornerSizeRatio->Enable( m_PadShape->GetSelection() == CHOICE_SHAPE_ROUNDRECT );
m_tcCornerSizeRatio->Enable( m_PadShape->GetSelection() == CHOICE_SHAPE_ROUNDRECT );
m_staticTextCornerSizeRatioUnit->Enable( m_PadShape->GetSelection() == CHOICE_SHAPE_ROUNDRECT );
m_cornerRadius.Enable( m_PadShape->GetSelection() == CHOICE_SHAPE_ROUNDRECT );
// A few widgets are enabled only for rounded rect and chamfered pads:
bool chamfered_rect_enable = m_PadShape->GetSelection() == CHOICE_SHAPE_CHAMFERED_RECT;
bool round_rect_enable = m_PadShape->GetSelection() == CHOICE_SHAPE_ROUNDRECT ||
chamfered_rect_enable;
m_staticTextCornerSizeRatio->Enable( round_rect_enable );
m_tcCornerSizeRatio->Enable( round_rect_enable );
m_staticTextCornerSizeRatioUnit->Enable( round_rect_enable );
m_cornerRadius.Enable( round_rect_enable );
m_cbTopLeft->Enable( chamfered_rect_enable );
m_cbTopRight->Enable( chamfered_rect_enable );
m_cbBottomLeft->Enable( chamfered_rect_enable );
m_cbBottomRight->Enable( chamfered_rect_enable );
m_tcChamferRatio->Enable( chamfered_rect_enable );
// PAD_SHAPE_CUSTOM type has constraints for zone connection and thermal shape:
// only not connected or solid connection is allowed to avoid destroying the shape.
@ -1223,7 +1280,8 @@ bool DIALOG_PAD_PROPERTIES::padValuesOK()
}
if( m_dummyPad->GetShape() == PAD_SHAPE_ROUNDRECT )
if( m_dummyPad->GetShape() == PAD_SHAPE_ROUNDRECT ||
m_dummyPad->GetShape() == PAD_SHAPE_CHAMFERED_RECT )
{
wxString value = m_tcCornerSizeRatio->GetValue();
double rrRadiusRatioPercent;
@ -1494,6 +1552,8 @@ bool DIALOG_PAD_PROPERTIES::TransferDataFromWindow()
m_currentPad->SetThermalWidth( m_padMaster->GetThermalWidth() );
m_currentPad->SetThermalGap( m_padMaster->GetThermalGap() );
m_currentPad->SetRoundRectRadiusRatio( m_padMaster->GetRoundRectRadiusRatio() );
m_currentPad->SetChamferRectRatio( m_padMaster->GetChamferRectRatio() );
m_currentPad->SetChamferPositions( m_padMaster->GetChamferPositions() );
if( m_currentPad->GetShape() == PAD_SHAPE_CUSTOM )
{
@ -1664,6 +1724,22 @@ bool DIALOG_PAD_PROPERTIES::transferDataToPad( D_PAD* aPad )
aPad->SetName( m_PadNumCtrl->GetValue() );
aPad->SetNetCode( m_PadNetSelector->GetSelectedNetcode() );
int chamfers = 0;
if( m_cbTopLeft->GetValue() )
chamfers |= RECT_CHAMFER_TOP_LEFT;
if( m_cbTopRight->GetValue() )
chamfers |= RECT_CHAMFER_TOP_RIGHT;
if( m_cbBottomLeft->GetValue() )
chamfers |= RECT_CHAMFER_BOTTOM_LEFT;
if( m_cbBottomRight->GetValue() )
chamfers |= RECT_CHAMFER_BOTTOM_RIGHT;
aPad->SetChamferPositions( chamfers );
// Clear some values, according to the pad type and shape
switch( aPad->GetShape() )
{
@ -1684,6 +1760,7 @@ bool DIALOG_PAD_PROPERTIES::transferDataToPad( D_PAD* aPad )
break;
case PAD_SHAPE_ROUNDRECT:
case PAD_SHAPE_CHAMFERED_RECT:
aPad->SetDelta( wxSize( 0, 0 ) );
break;
@ -1737,13 +1814,18 @@ bool DIALOG_PAD_PROPERTIES::transferDataToPad( D_PAD* aPad )
break;
}
if( aPad->GetShape() == PAD_SHAPE_ROUNDRECT )
if( aPad->GetShape() == PAD_SHAPE_ROUNDRECT || aPad->GetShape() == PAD_SHAPE_CHAMFERED_RECT )
{
wxString value = m_tcCornerSizeRatio->GetValue();
double rrRadiusRatioPercent;
double ratioPercent;
if( value.ToDouble( &rrRadiusRatioPercent ) )
aPad->SetRoundRectRadiusRatio( rrRadiusRatioPercent / 100.0 );
if( value.ToDouble( &ratioPercent ) )
aPad->SetRoundRectRadiusRatio( ratioPercent / 100.0 );
value = m_tcChamferRatio->GetValue();
if( value.ToDouble( &ratioPercent ) )
aPad->SetChamferRectRatio( ratioPercent / 100.0 );
}
LSET padLayerMask;

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,12 +1,11 @@
///////////////////////////////////////////////////////////////////////////
// C++ code generated with wxFormBuilder (version Dec 30 2017)
// C++ code generated with wxFormBuilder (version Dec 1 2018)
// http://www.wxformbuilder.org/
//
// PLEASE DO *NOT* EDIT THIS FILE!
///////////////////////////////////////////////////////////////////////////
#ifndef __DIALOG_PAD_PROPERTIES_BASE_H__
#define __DIALOG_PAD_PROPERTIES_BASE_H__
#pragma once
#include <wx/artprov.h>
#include <wx/xrc/xmlres.h>
@ -25,12 +24,12 @@ class WX_GRID;
#include <widgets/net_selector.h>
#include <wx/choice.h>
#include <wx/combobox.h>
#include <wx/checkbox.h>
#include <wx/sizer.h>
#include <wx/bitmap.h>
#include <wx/image.h>
#include <wx/icon.h>
#include <wx/statbmp.h>
#include <wx/checkbox.h>
#include <wx/statbox.h>
#include <wx/panel.h>
#include <wx/simplebook.h>
@ -53,20 +52,20 @@ class WX_GRID;
class DIALOG_PAD_PROPERTIES_BASE : public DIALOG_SHIM
{
private:
protected:
enum
{
wxID_DIALOG_EDIT_PAD = 1000,
wxID_PADNUMCTRL
};
wxNotebook* m_notebook;
wxPanel* m_panelGeneral;
wxStaticText* m_PadNumText;
wxTextCtrl* m_PadNumCtrl;
wxStaticText* m_PadNameText;
NET_SELECTOR* m_PadNetSelector;
NET_SELECTOR* m_PadNetSelector;
wxStaticText* m_staticText44;
wxChoice* m_PadType;
wxStaticText* m_staticText45;
@ -106,6 +105,14 @@ class DIALOG_PAD_PROPERTIES_BASE : public DIALOG_SHIM
wxStaticText* m_cornerRadiusLabel;
wxTextCtrl* m_tcCornerRadius;
wxStaticText* m_cornerRadiusUnits;
wxStaticText* m_staticTextChamferRatio;
TEXT_CTRL_EVAL* m_tcChamferRatio;
wxStaticText* m_staticTextChamferRatioUnit;
wxStaticText* m_staticTextChamferCorner;
wxCheckBox* m_cbTopLeft;
wxCheckBox* m_cbTopRight;
wxCheckBox* m_cbBottomLeft;
wxCheckBox* m_cbBottomRight;
wxStaticText* m_holeShapeLabel;
wxChoice* m_holeShapeCtrl;
wxStaticText* m_staticText51;
@ -185,7 +192,7 @@ class DIALOG_PAD_PROPERTIES_BASE : public DIALOG_SHIM
wxStdDialogButtonSizer* m_sdbSizer;
wxButton* m_sdbSizerOK;
wxButton* m_sdbSizerCancel;
// Virtual event handlers, overide them in your derived class
virtual void OnInitDialog( wxInitDialogEvent& event ) { event.Skip(); }
virtual void OnUpdateUI( wxUpdateUIEvent& event ) { event.Skip(); }
@ -208,13 +215,13 @@ class DIALOG_PAD_PROPERTIES_BASE : public DIALOG_SHIM
virtual void OnPaintShowPanel( wxPaintEvent& event ) { event.Skip(); }
virtual void onChangePadMode( wxCommandEvent& event ) { event.Skip(); }
virtual void OnCancel( wxCommandEvent& event ) { event.Skip(); }
public:
DIALOG_PAD_PROPERTIES_BASE( wxWindow* parent, wxWindowID id = wxID_DIALOG_EDIT_PAD, const wxString& title = _("Pad Properties"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( -1,-1 ), long style = wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER );
DIALOG_PAD_PROPERTIES_BASE( wxWindow* parent, wxWindowID id = wxID_DIALOG_EDIT_PAD, const wxString& title = _("Pad Properties"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( -1,-1 ), long style = wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER );
~DIALOG_PAD_PROPERTIES_BASE();
};
///////////////////////////////////////////////////////////////////////////////
@ -223,24 +230,24 @@ class DIALOG_PAD_PROPERTIES_BASE : public DIALOG_SHIM
class DIALOG_PAD_PRIMITIVES_PROPERTIES_BASE : public DIALOG_SHIM
{
private:
protected:
wxStaticText* m_staticTextPosStart;
wxStaticText* m_startXLabel;
wxTextCtrl* m_startXCtrl;
TEXT_CTRL_EVAL* m_startXCtrl;
wxStaticText* m_startXUnits;
wxStaticText* m_startYLabel;
wxTextCtrl* m_startYCtrl;
TEXT_CTRL_EVAL* m_startYCtrl;
wxStaticText* m_startYUnits;
wxStaticText* m_staticTextPosEnd;
wxStaticText* m_endXLabel;
wxTextCtrl* m_endXCtrl;
TEXT_CTRL_EVAL* m_endXCtrl;
wxStaticText* m_endXUnits;
wxStaticText* m_endYLabel;
wxTextCtrl* m_endYCtrl;
TEXT_CTRL_EVAL* m_endYCtrl;
wxStaticText* m_endYUnits;
wxStaticText* m_radiusLabel;
wxTextCtrl* m_radiusCtrl;
TEXT_CTRL_EVAL* m_radiusCtrl;
wxStaticText* m_radiusUnits;
wxStaticText* m_thicknessLabel;
wxTextCtrl* m_thicknessCtrl;
@ -250,12 +257,12 @@ class DIALOG_PAD_PRIMITIVES_PROPERTIES_BASE : public DIALOG_SHIM
wxStdDialogButtonSizer* m_sdbSizer;
wxButton* m_sdbSizerOK;
wxButton* m_sdbSizerCancel;
public:
DIALOG_PAD_PRIMITIVES_PROPERTIES_BASE( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = wxEmptyString, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( -1,-1 ), long style = wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER );
DIALOG_PAD_PRIMITIVES_PROPERTIES_BASE( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = wxEmptyString, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( -1,-1 ), long style = wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER );
~DIALOG_PAD_PRIMITIVES_PROPERTIES_BASE();
};
///////////////////////////////////////////////////////////////////////////////
@ -264,17 +271,17 @@ class DIALOG_PAD_PRIMITIVES_PROPERTIES_BASE : public DIALOG_SHIM
class DIALOG_PAD_PRIMITIVES_TRANSFORM_BASE : public DIALOG_SHIM
{
private:
protected:
wxStaticText* m_staticTextMove;
wxStaticText* m_xLabel;
wxTextCtrl* m_xCtrl;
TEXT_CTRL_EVAL* m_xCtrl;
wxStaticText* m_xUnits;
wxStaticText* m_yLabel;
wxTextCtrl* m_yCtrl;
TEXT_CTRL_EVAL* m_yCtrl;
wxStaticText* m_yUnits;
wxStaticText* m_rotationLabel;
wxTextCtrl* m_rotationCtrl;
TEXT_CTRL_EVAL* m_rotationCtrl;
wxStaticText* m_rotationUnits;
wxStaticText* m_scaleLabel;
TEXT_CTRL_EVAL* m_scaleCtrl;
@ -284,12 +291,12 @@ class DIALOG_PAD_PRIMITIVES_TRANSFORM_BASE : public DIALOG_SHIM
wxStdDialogButtonSizer* m_sdbSizer;
wxButton* m_sdbSizerOK;
wxButton* m_sdbSizerCancel;
public:
DIALOG_PAD_PRIMITIVES_TRANSFORM_BASE( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("Pad Custom Shape Geometry Transform"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( -1,-1 ), long style = wxDEFAULT_DIALOG_STYLE );
DIALOG_PAD_PRIMITIVES_TRANSFORM_BASE( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("Pad Custom Shape Geometry Transform"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( -1,-1 ), long style = wxDEFAULT_DIALOG_STYLE );
~DIALOG_PAD_PRIMITIVES_TRANSFORM_BASE();
};
///////////////////////////////////////////////////////////////////////////////
@ -298,13 +305,13 @@ class DIALOG_PAD_PRIMITIVES_TRANSFORM_BASE : public DIALOG_SHIM
class DIALOG_PAD_PRIMITIVE_POLY_PROPS_BASE : public DIALOG_SHIM
{
private:
protected:
WX_GRID* m_gridCornersList;
wxBitmapButton* m_addButton;
wxBitmapButton* m_deleteButton;
wxStaticText* m_thicknessLabel;
wxTextCtrl* m_thicknessCtrl;
TEXT_CTRL_EVAL* m_thicknessCtrl;
wxStaticText* m_thicknessUnits;
wxPanel* m_panelPoly;
wxStaticBitmap* m_warningIcon;
@ -315,7 +322,7 @@ class DIALOG_PAD_PRIMITIVE_POLY_PROPS_BASE : public DIALOG_SHIM
wxStdDialogButtonSizer* m_sdbSizer;
wxButton* m_sdbSizerOK;
wxButton* m_sdbSizerCancel;
// Virtual event handlers, overide them in your derived class
virtual void onGridSelect( wxGridRangeSelectEvent& event ) { event.Skip(); }
virtual void onCellSelect( wxGridEvent& event ) { event.Skip(); }
@ -323,13 +330,12 @@ class DIALOG_PAD_PRIMITIVE_POLY_PROPS_BASE : public DIALOG_SHIM
virtual void OnButtonDelete( wxCommandEvent& event ) { event.Skip(); }
virtual void onPaintPolyPanel( wxPaintEvent& event ) { event.Skip(); }
virtual void onPolyPanelResize( wxSizeEvent& event ) { event.Skip(); }
public:
DIALOG_PAD_PRIMITIVE_POLY_PROPS_BASE( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("Basic Shape Polygon"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( -1,-1 ), long style = wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER );
DIALOG_PAD_PRIMITIVE_POLY_PROPS_BASE( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("Basic Shape Polygon"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( -1,-1 ), long style = wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER );
~DIALOG_PAD_PRIMITIVE_POLY_PROPS_BASE();
};
#endif //__DIALOG_PAD_PROPERTIES_BASE_H__

View File

@ -898,7 +898,7 @@ bool DRC::checkClearancePadToPad( D_PAD* aRefPad, D_PAD* aPad )
// priority is aRefPad = ROUND then OVAL then RECT/ROUNDRECT then other
if( aRefPad->GetShape() != aPad->GetShape() && aRefPad->GetShape() != PAD_SHAPE_CIRCLE )
{
// pad ref shape is here oval, rect, roundrect, trapezoid or custom
// pad ref shape is here oval, rect, roundrect, chamfered rect, trapezoid or custom
switch( aPad->GetShape() )
{
case PAD_SHAPE_CIRCLE:
@ -916,6 +916,7 @@ bool DRC::checkClearancePadToPad( D_PAD* aRefPad, D_PAD* aPad )
break;
case PAD_SHAPE_TRAPEZOID:
case PAD_SHAPE_CHAMFERED_RECT:
case PAD_SHAPE_CUSTOM:
break;
}
@ -962,6 +963,7 @@ bool DRC::checkClearancePadToPad( D_PAD* aRefPad, D_PAD* aPad )
case PAD_SHAPE_TRAPEZOID:
case PAD_SHAPE_ROUNDRECT:
case PAD_SHAPE_CHAMFERED_RECT:
case PAD_SHAPE_RECT:
case PAD_SHAPE_CUSTOM:
// pad_angle = pad orient relative to the aRefPad orient
@ -975,6 +977,17 @@ bool DRC::checkClearancePadToPad( D_PAD* aRefPad, D_PAD* aPad )
GetRoundRectCornerCenters( polyref, padRadius, wxPoint( 0, 0 ),
aRefPad->GetSize(), aRefPad->GetOrientation() );
}
else if( aRefPad->GetShape() == PAD_SHAPE_CHAMFERED_RECT )
{
// The reference pad can be rotated. calculate the rotated
// coordinates ( note, the ref pad position is the origin of
// coordinates for this drc test)
int padRadius = aRefPad->GetRoundRectCornerRadius();
TransformRoundChamferedRectToPolygon( polysetref, wxPoint( 0, 0 ), aRefPad->GetSize(),
aRefPad->GetOrientation(),
padRadius, aRefPad->GetChamferRectRatio(),
aRefPad->GetChamferPositions(), 64 );
}
else if( aRefPad->GetShape() == PAD_SHAPE_CUSTOM )
{
polysetref.Append( aRefPad->GetCustomShapeAsPolygon() );
@ -996,6 +1009,7 @@ bool DRC::checkClearancePadToPad( D_PAD* aRefPad, D_PAD* aPad )
{
case PAD_SHAPE_ROUNDRECT:
case PAD_SHAPE_RECT:
case PAD_SHAPE_CHAMFERED_RECT:
case PAD_SHAPE_TRAPEZOID:
case PAD_SHAPE_CUSTOM:
if( aPad->GetShape() == PAD_SHAPE_ROUNDRECT )
@ -1005,6 +1019,17 @@ bool DRC::checkClearancePadToPad( D_PAD* aRefPad, D_PAD* aPad )
GetRoundRectCornerCenters( polycompare, padRadius, relativePadPos,
aPad->GetSize(), aPad->GetOrientation() );
}
else if( aPad->GetShape() == PAD_SHAPE_CHAMFERED_RECT )
{
// The reference pad can be rotated. calculate the rotated
// coordinates ( note, the ref pad position is the origin of
// coordinates for this drc test)
int padRadius = aPad->GetRoundRectCornerRadius();
TransformRoundChamferedRectToPolygon( polysetcompare, relativePadPos, aPad->GetSize(),
aPad->GetOrientation(),
padRadius, aPad->GetChamferRectRatio(),
aPad->GetChamferPositions(), 64 );
}
else if( aPad->GetShape() == PAD_SHAPE_CUSTOM )
{
polysetcompare.Append( aPad->GetCustomShapeAsPolygon() );
@ -1375,6 +1400,36 @@ bool DRC::checkClearanceSegmToPad( const D_PAD* aPad, int aSegmentWidth, int aMi
const SHAPE_LINE_CHAIN& refpoly = polyset.COutline( 0 );
if( !poly2segmentDRC( (wxPoint*) &refpoly.CPoint( 0 ),
refpoly.PointCount(),
wxPoint( 0, 0 ), wxPoint(m_segmLength,0),
distToLine ) )
return false;
}
break;
case PAD_SHAPE_CHAMFERED_RECT:
{
SHAPE_POLY_SET polyset;
// The pad can be rotated. calculate the coordinates
// relatives to the segment being tested
// Note, the pad position relative to the segment origin
// is m_padToTestPos
int padRadius = aPad->GetRoundRectCornerRadius();
TransformRoundChamferedRectToPolygon( polyset, m_padToTestPos, aPad->GetSize(),
aPad->GetOrientation(),
padRadius, aPad->GetChamferRectRatio(),
aPad->GetChamferPositions(), 64 );
// Rotate also coordinates by m_segmAngle, because the segment orient
// is m_segmAngle.
// we are using a horizontal segment for test, because we know here
// only the lenght and orientation of the segment
// therefore all coordinates of the pad to test must be rotated by
// m_segmAngle (they are already relative to the segment origin)
polyset.Rotate( DECIDEG2RAD( -m_segmAngle ), VECTOR2I( 0, 0 ) );
const SHAPE_LINE_CHAIN& refpoly = polyset.COutline( 0 );
if( !poly2segmentDRC( (wxPoint*) &refpoly.CPoint( 0 ),
refpoly.PointCount(),
wxPoint( 0, 0 ), wxPoint(m_segmLength,0),

View File

@ -1116,14 +1116,15 @@ static void export_vrml_padshape( MODEL_VRML& aModel, VRML_LAYER* aTinLayer, D_P
break;
case PAD_SHAPE_ROUNDRECT:
case PAD_SHAPE_CHAMFERED_RECT:
{
SHAPE_POLY_SET polySet;
int segmentToCircleCount = ARC_APPROX_SEGMENTS_COUNT_HIGH_DEF;
const int corner_radius = aPad->GetRoundRectCornerRadius( aPad->GetSize() );
TransformRoundRectToPolygon( polySet, wxPoint( 0, 0 ), aPad->GetSize(),
0.0, corner_radius, segmentToCircleCount );
TransformRoundChamferedRectToPolygon( polySet, wxPoint( 0, 0 ), aPad->GetSize(),
0.0, corner_radius, 0.0, 0, segmentToCircleCount );
std::vector< wxRealPoint > cornerList;
// TransformRoundRectToPolygon creates only one convex polygon
// TransformRoundChamferedRectToPolygon creates only one convex polygon
SHAPE_LINE_CHAIN poly( polySet.Outline( 0 ) );
for( int ii = 0; ii < poly.PointCount(); ++ii )
@ -1170,7 +1171,7 @@ static void export_vrml_padshape( MODEL_VRML& aModel, VRML_LAYER* aTinLayer, D_P
pad_dy = 0;
case PAD_SHAPE_TRAPEZOID:
{
{
double coord[8] =
{
-pad_w + pad_dy, -pad_h - pad_dx,
@ -1209,10 +1210,7 @@ static void export_vrml_padshape( MODEL_VRML& aModel, VRML_LAYER* aTinLayer, D_P
throw( std::runtime_error( aTinLayer->GetError() ) );
break;
}
default:
break;
}
}
}

View File

@ -51,6 +51,7 @@
#include <boost/ptr_container/ptr_map.hpp>
#include <memory.h>
#include <connectivity/connectivity_data.h>
#include <convert_basic_shapes_to_polygon.h> // for enum RECT_CHAMFER_POSITIONS definition
using namespace PCB_KEYS_T;
@ -1248,12 +1249,13 @@ void PCB_IO::format( D_PAD* aPad, int aNestLevel ) const
switch( aPad->GetShape() )
{
case PAD_SHAPE_CIRCLE: shape = "circle"; break;
case PAD_SHAPE_RECT: shape = "rect"; break;
case PAD_SHAPE_OVAL: shape = "oval"; break;
case PAD_SHAPE_TRAPEZOID: shape = "trapezoid"; break;
case PAD_SHAPE_ROUNDRECT: shape = "roundrect"; break;
case PAD_SHAPE_CUSTOM: shape = "custom"; break;
case PAD_SHAPE_CIRCLE: shape = "circle"; break;
case PAD_SHAPE_RECT: shape = "rect"; break;
case PAD_SHAPE_OVAL: shape = "oval"; break;
case PAD_SHAPE_TRAPEZOID: shape = "trapezoid"; break;
case PAD_SHAPE_CHAMFERED_RECT:
case PAD_SHAPE_ROUNDRECT: shape = "roundrect"; break;
case PAD_SHAPE_CUSTOM: shape = "custom"; break;
default:
THROW_IO_ERROR( wxString::Format( _( "unknown pad type: %d"), aPad->GetShape() ) );
@ -1311,13 +1313,38 @@ void PCB_IO::format( D_PAD* aPad, int aNestLevel ) const
formatLayers( aPad->GetLayerSet() );
// Output the radius ratio for rounded rect pads
if( aPad->GetShape() == PAD_SHAPE_ROUNDRECT )
// Output the radius ratio for rounded and chamfered rect pads
if( aPad->GetShape() == PAD_SHAPE_ROUNDRECT || aPad->GetShape() == PAD_SHAPE_CHAMFERED_RECT)
{
m_out->Print( 0, " (roundrect_rratio %s)",
Double2Str( aPad->GetRoundRectRadiusRatio() ).c_str() );
}
// Output the chamfer corners for chamfered rect pads
if( aPad->GetShape() == PAD_SHAPE_CHAMFERED_RECT)
{
m_out->Print( 0, "\n" );
m_out->Print( aNestLevel+1, "(chamfer_ratio %s)",
Double2Str( aPad->GetChamferRectRatio() ).c_str() );
m_out->Print( 0, " (chamfer" );
if( ( aPad->GetChamferPositions() & RECT_CHAMFER_TOP_LEFT ) )
m_out->Print( 0, " top_left" );
if( ( aPad->GetChamferPositions() & RECT_CHAMFER_TOP_RIGHT ) )
m_out->Print( 0, " top_right" );
if( ( aPad->GetChamferPositions() & RECT_CHAMFER_BOTTOM_LEFT ) )
m_out->Print( 0, " bottom_left" );
if( ( aPad->GetChamferPositions() & RECT_CHAMFER_BOTTOM_RIGHT ) )
m_out->Print( 0, " bottom_right" );
m_out->Print( 0, ")" );
}
std::string output;
// Unconnected pad is default net so don't save it.

View File

@ -341,6 +341,7 @@ void D_PAD::Draw( EDA_DRAW_PANEL* aPanel, wxDC* aDC, GR_DRAWMODE aDraw_mode,
void D_PAD::DrawShape( EDA_RECT* aClipBox, wxDC* aDC, PAD_DRAWINFO& aDrawInfo )
{
#define SEGCOUNT 32 // number of segments to approximate a circle
wxPoint coord[12];
double angle = m_Orient;
int seg_width;
@ -436,42 +437,29 @@ void D_PAD::DrawShape( EDA_RECT* aClipBox, wxDC* aDC, PAD_DRAWINFO& aDrawInfo )
}
break;
case PAD_SHAPE_CHAMFERED_RECT:
case PAD_SHAPE_ROUNDRECT:
{
{
// Use solder[Paste/Mask]size or pad size to build pad shape to draw
wxSize size( GetSize() );
size += aDrawInfo.m_Mask_margin * 2;
int corner_radius = GetRoundRectCornerRadius( size );
bool doChamfer = GetShape() == PAD_SHAPE_CHAMFERED_RECT;
SHAPE_POLY_SET outline;
TransformRoundChamferedRectToPolygon( outline, shape_pos, size, GetOrientation(),
corner_radius, GetChamferRectRatio(),
doChamfer ? GetChamferPositions() : 0,
SEGCOUNT );
// Draw the polygon: Inflate creates only one convex polygon
SHAPE_POLY_SET outline;
bool filled = aDrawInfo.m_ShowPadFilled;
if( filled )
{
wxPoint centers[4];
GetRoundRectCornerCenters( centers, corner_radius, shape_pos,
size, GetOrientation() );
GRClosedPoly( aClipBox, aDC, 4, centers, true, corner_radius*2,
aDrawInfo.m_Color, aDrawInfo.m_Color );
}
else
{
TransformRoundRectToPolygon( outline, shape_pos, size, GetOrientation(),
corner_radius, 64 );
SHAPE_LINE_CHAIN& poly = outline.Outline( 0 );
if( outline.OutlineCount() > 0 )
{
SHAPE_LINE_CHAIN& poly = outline.Outline( 0 );
if( poly.PointCount() > 0 )
{
GRClosedPoly( aClipBox, aDC, poly.PointCount(),
(wxPoint*)&poly.Point( 0 ), aDrawInfo.m_ShowPadFilled, 0,
aDrawInfo.m_Color, aDrawInfo.m_Color );
}
}
}
GRClosedPoly( aClipBox, aDC, poly.PointCount(),
(wxPoint*)&poly.Point( 0 ), filled, 0,
aDrawInfo.m_Color, aDrawInfo.m_Color );
if( aDrawInfo.m_PadClearance )
{
@ -481,27 +469,23 @@ void D_PAD::DrawShape( EDA_RECT* aClipBox, wxDC* aDC, PAD_DRAWINFO& aDrawInfo )
size.y += aDrawInfo.m_PadClearance * 2;
corner_radius = GetRoundRectCornerRadius() + aDrawInfo.m_PadClearance;
TransformRoundRectToPolygon( outline, shape_pos, size, GetOrientation(),
corner_radius, ARC_APPROX_SEGMENTS_COUNT_HIGH_DEF );
TransformRoundChamferedRectToPolygon( outline, shape_pos, size, GetOrientation(),
corner_radius, GetChamferRectRatio(),
doChamfer ? GetChamferPositions() : 0,
SEGCOUNT );
if( outline.OutlineCount() > 0 )
{
// Draw the polygon: Inflate creates only one convex polygon
SHAPE_LINE_CHAIN& clearance_poly = outline.Outline( 0 );
// Draw the polygon: Inflate creates only one convex polygon
SHAPE_LINE_CHAIN& clearance_poly = outline.Outline( 0 );
if( clearance_poly.PointCount() > 0 )
{
GRClosedPoly( aClipBox, aDC, clearance_poly.PointCount(),
(wxPoint*)&clearance_poly.Point( 0 ), false, 0,
aDrawInfo.m_Color, aDrawInfo.m_Color );
}
}
GRClosedPoly( aClipBox, aDC, clearance_poly.PointCount(),
(wxPoint*)&clearance_poly.Point( 0 ), false, 0,
aDrawInfo.m_Color, aDrawInfo.m_Color );
}
}
}
break;
case PAD_SHAPE_CUSTOM:
{
{
// The full shape has 2 items
// 1- The anchor pad: a round or rect pad located at pad position
// 2- The custom complex shape
@ -586,10 +570,7 @@ void D_PAD::DrawShape( EDA_RECT* aClipBox, wxDC* aDC, PAD_DRAWINFO& aDrawInfo )
}
}
break;
}
default:
break;
}
}
// Draw the pad hole

View File

@ -816,13 +816,17 @@ void PCB_PAINTER::draw( const D_PAD* aPad, int aLayer )
break;
case PAD_SHAPE_ROUNDRECT:
case PAD_SHAPE_CHAMFERED_RECT:
{
SHAPE_POLY_SET polySet;
wxSize prsize( size.x * 2, size.y * 2 );
wxSize prsize( size.x * 2, size.y * 2 ); // size is the half pad area size)
const int segmentToCircleCount = 64;
const int corner_radius = aPad->GetRoundRectCornerRadius( prsize );
TransformRoundRectToPolygon( polySet, wxPoint( 0, 0 ), prsize,
0.0, corner_radius, segmentToCircleCount );
bool doChamfer = shape == PAD_SHAPE_CHAMFERED_RECT;
TransformRoundChamferedRectToPolygon( polySet, wxPoint( 0, 0 ), prsize,
0.0, corner_radius, aPad->GetChamferRectRatio(),
doChamfer ? aPad->GetChamferPositions() : 0, segmentToCircleCount );
m_gal->DrawPolygon( polySet );
break;
}

View File

@ -49,6 +49,7 @@
#include <pcb_plot_params.h>
#include <zones.h>
#include <pcb_parser.h>
#include <convert_basic_shapes_to_polygon.h> // for RECT_CHAMFER_POSITIONS definition
using namespace PCB_KEYS_T;
@ -2455,6 +2456,8 @@ D_PAD* PCB_PARSER::parseD_PAD( MODULE* aParent )
break;
case T_roundrect:
// Note: the shape can be PAD_SHAPE_ROUNDRECT or PAD_SHAPE_CHAMFERED_RECT
// (if champfer parameters are found later in pad descr.)
pad->SetShape( PAD_SHAPE_ROUNDRECT );
break;
@ -2636,6 +2639,56 @@ D_PAD* PCB_PARSER::parseD_PAD( MODULE* aParent )
NeedRIGHT();
break;
case T_chamfer_ratio:
pad->SetChamferRectRatio( parseDouble( "chamfer ratio" ) );
if( pad->GetChamferRectRatio() > 0 )
pad->SetShape( PAD_SHAPE_CHAMFERED_RECT );
NeedRIGHT();
break;
case T_chamfer:
{
int chamfers = 0;
bool end_list = false;
while( !end_list )
{
token = NextTok();
switch( token )
{
case T_top_left:
chamfers |= RECT_CHAMFER_TOP_LEFT;
break;
case T_top_right:
chamfers |= RECT_CHAMFER_TOP_RIGHT;
break;
case T_bottom_left:
chamfers |= RECT_CHAMFER_BOTTOM_LEFT;
break;
case T_bottom_right:
chamfers |= RECT_CHAMFER_BOTTOM_RIGHT;
break;
case T_RIGHT:
pad->SetChamferPositions( chamfers );
end_list = true;
break;
default:
Expecting( "chamfer_top_left chamfer_top_right chamfer_bottom_left or chamfer_bottom_right" );
}
}
if( pad->GetChamferPositions() != RECT_NO_CHAMFER )
pad->SetShape( PAD_SHAPE_CHAMFERED_RECT );
}
break;
case T_options:
parseD_PAD_option( pad.get() );
break;

View File

@ -443,6 +443,7 @@ void PlotStandardLayer( BOARD *aBoard, PLOTTER* aPlotter,
case PAD_SHAPE_TRAPEZOID:
case PAD_SHAPE_RECT:
case PAD_SHAPE_ROUNDRECT:
case PAD_SHAPE_CHAMFERED_RECT:
pad->SetSize( padPlotsSize );
itemplotter.PlotPad( pad, color, plotMode );
break;

View File

@ -7,7 +7,7 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 1992-2017 KiCad Developers, see AUTHORS.txt for contributors.
* Copyright (C) 1992-2018 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -45,6 +45,7 @@
#include <class_drawsegment.h>
#include <class_pcb_target.h>
#include <class_dimension.h>
#include <convert_basic_shapes_to_polygon.h>
#include <pcbnew.h>
#include <pcbplot.h>
@ -186,6 +187,23 @@ void BRDITEMS_PLOTTER::PlotPad( D_PAD* aPad, COLOR4D aColor, EDA_DRAW_MODE_T aPl
aPad->GetOrientation(), aPlotMode, &gbr_metadata );
break;
case PAD_SHAPE_CHAMFERED_RECT:
{
SHAPE_POLY_SET polygons;
const int segmentToCircleCount = 64;
const int corner_radius = aPad->GetRoundRectCornerRadius( aPad->GetSize() );
TransformRoundChamferedRectToPolygon( polygons, shape_pos, aPad->GetSize(),
aPad->GetOrientation(), corner_radius, aPad->GetChamferRectRatio(),
aPad->GetChamferPositions(), segmentToCircleCount );
if( polygons.OutlineCount() == 0 )
break;
int min_dim = std::min( aPad->GetSize().x, aPad->GetSize().y ) /2;
m_plotter->FlashPadCustom( shape_pos,wxSize( min_dim, min_dim ), &polygons, aPlotMode, &gbr_metadata );
}
break;
case PAD_SHAPE_CUSTOM:
{
SHAPE_POLY_SET polygons;

View File

@ -612,6 +612,7 @@ std::unique_ptr<PNS::SOLID> PNS_KICAD_IFACE::syncPad( D_PAD* aPad )
break;
}
case PAD_SHAPE_CHAMFERED_RECT:
case PAD_SHAPE_ROUNDRECT:
{
SHAPE_POLY_SET outline;
@ -624,9 +625,7 @@ std::unique_ptr<PNS::SOLID> PNS_KICAD_IFACE::syncPad( D_PAD* aPad )
SHAPE_SIMPLE* shape = new SHAPE_SIMPLE();
for( int ii = 0; ii < poly.PointCount(); ++ii )
{
shape->Append( wxPoint( poly.Point( ii ).x, poly.Point( ii ).y ) );
}
shape->Append( poly.Point( ii ) );
solid->SetShape( shape );
}
@ -708,6 +707,7 @@ std::unique_ptr<PNS::SOLID> PNS_KICAD_IFACE::syncPad( D_PAD* aPad )
break;
}
case PAD_SHAPE_CHAMFERED_RECT:
case PAD_SHAPE_ROUNDRECT:
{
SHAPE_POLY_SET outline;

View File

@ -323,7 +323,6 @@ PADSTACK* SPECCTRA_DB::makePADSTACK( BOARD* aBoard, D_PAD* aPad )
switch( aPad->GetShape() )
{
default:
case PAD_SHAPE_CIRCLE:
{
double diameter = scale( aPad->GetSize().x );
@ -491,6 +490,7 @@ PADSTACK* SPECCTRA_DB::makePADSTACK( BOARD* aBoard, D_PAD* aPad )
}
break;
case PAD_SHAPE_CHAMFERED_RECT:
case PAD_SHAPE_ROUNDRECT:
{
// Export the shape as as polygon, round rect does not exist as primitive
@ -511,8 +511,13 @@ PADSTACK* SPECCTRA_DB::makePADSTACK( BOARD* aBoard, D_PAD* aPad )
psize.x += extra_clearance*2;
psize.y += extra_clearance*2;
rradius += extra_clearance;
TransformRoundRectToPolygon( cornerBuffer, wxPoint(0,0), psize,
0, rradius, circleToSegmentsCount );
bool doChamfer = aPad->GetShape() == PAD_SHAPE_CHAMFERED_RECT;
TransformRoundChamferedRectToPolygon( cornerBuffer, wxPoint(0,0), psize,
0, rradius,
aPad->GetChamferRectRatio(),
doChamfer ? aPad->GetChamferPositions() : 0,
circleToSegmentsCount );
SHAPE_LINE_CHAIN& polygonal_shape = cornerBuffer.Outline( 0 );
for( int ndx=0; ndx < reportedLayers; ++ndx )