Pcbnew: Add rounded rect pad shape.

This commit is contained in:
jean-pierre charras 2016-04-06 20:15:49 +02:00
parent e1b308b3b1
commit 4a838fb8c3
27 changed files with 2562 additions and 928 deletions

View File

@ -296,6 +296,7 @@ set( COMMON_SRCS
geometry/shape_poly_set.cpp
geometry/shape_collisions.cpp
geometry/shape_file_io.cpp
geometry/convex_hull.cpp
)
add_library( common STATIC ${COMMON_SRCS} )
add_dependencies( common lib-dependencies )

View File

@ -74,6 +74,13 @@ void GetRoundRectCornerCenters( wxPoint aCenters[4], int aRadius,
size.x -= aRadius;
size.y -= aRadius;
// Ensure size is > 0, to avoid generating unusable shapes
// which can crash kicad.
if( size.x <= 1 )
size.x = 1;
if( size.y <= 1 )
size.y = 1;
aCenters[0].x = -size.x;
aCenters[0].y = size.y;

View File

@ -0,0 +1,167 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2016 Jean-Pierre Charras, jp.charras at wanadoo.fr
* Copyright (C) 1992-2016 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
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
/*
* Implementation of Andrew's monotone chain 2D convex hull algorithm.
* Asymptotic complexity: O(n log n).
* See http://www.algorithmist.com/index.php/Monotone_Chain_Convex_Hull
* (Licence GNU Free Documentation License 1.2)
*
* Pseudo-code:
*
* Input: a list P of points in the plane.
*
* Sort the points of P by x-coordinate (in case of a tie, sort by y-coordinate).
*
* Initialize U and L as empty lists.
* The lists will hold the vertices of upper and lower hulls respectively.
*
* for i = 1, 2, ..., n:
* while L contains at least two points and the sequence of last two points
* of L and the point P[i] does not make a counter-clockwise turn:
* remove the last point from L
* append P[i] to L
*
* for i = n, n-1, ..., 1:
* while U contains at least two points and the sequence of last two points
* of U and the point P[i] does not make a counter-clockwise turn:
* remove the last point from U
* append P[i] to U
*
* Remove the last point of each list (it's the same as the first point of the other list).
* Concatenate L and U to obtain the convex hull of P.
* Points in the result will be listed in counter-clockwise order.
*/
#include <geometry/shape_poly_set.h>
#include <geometry/convex_hull.h>
#include <algorithm>
#include <wx/wx.h>
#include <trigo.h>
typedef long long coord2_t; // must be big enough to hold 2*max(|coordinate|)^2
// this function is used to sort points.
// Andrew's monotone chain 2D convex hull algorithm needs a sorted set of points
static bool compare_point( const wxPoint& ref, const wxPoint& p )
{
return ref.x < p.x || (ref.x == p.x && ref.y < p.y);
}
// 2D cross product of OA and OB vectors, i.e. z-component of their 3D cross product.
// Returns a positive value, if OAB makes a counter-clockwise turn,
// negative for clockwise turn, and zero if the points are collinear.
static coord2_t cross_product( const wxPoint& O, const wxPoint& A, const wxPoint& B )
{
return (coord2_t) (A.x - O.x) * (coord2_t) (B.y - O.y)
- (coord2_t) (A.y - O.y) * (coord2_t) (B.x - O.x);
}
// Fills aResult with a list of points on the convex hull in counter-clockwise order.
void BuildConvexHull( std::vector<wxPoint>& aResult, const std::vector<wxPoint>& aPoly )
{
std::vector<wxPoint> poly = aPoly;
int point_count = poly.size();
if( point_count < 2 ) // Should not happen, but who know
return;
// Sort points lexicographically
// Andrew's monotone chain 2D convex hull algorithm needs that
std::sort( poly.begin(), poly.end(), compare_point );
int k = 0;
// Store room (2 * n points) for result:
// The actual convex hull use less points. the room will be adjusted later
aResult.resize( 2 * point_count );
// Build lower hull
for( int ii = 0; ii < point_count; ++ii )
{
while( k >= 2 && cross_product( aResult[k - 2], aResult[k - 1], poly[ii] ) <= 0 )
k--;
aResult[k++] = poly[ii];
}
// Build upper hull
for( int ii = point_count - 2, t = k + 1; ii >= 0; ii-- )
{
while( k >= t && cross_product( aResult[k - 2], aResult[k - 1], poly[ii] ) <= 0 )
k--;
aResult[k++] = poly[ii];
}
// The last point in the list is the same as the first one.
// This is not needed, and sometimes create issues ( 0 length polygon segment:
// remove it:
if( k > 1 && aResult[0] == aResult[k - 1] )
k -= 1;
aResult.resize( k );
}
void BuildConvexHull( std::vector<wxPoint>& aResult,
const SHAPE_POLY_SET& aPolygons )
{
BuildConvexHull( aResult, aPolygons, wxPoint( 0, 0 ), 0.0 );
}
void BuildConvexHull( std::vector<wxPoint>& aResult,
const SHAPE_POLY_SET& aPolygons,
wxPoint aPosition, double aRotation )
{
// Build the convex hull of the SHAPE_POLY_SET
std::vector<wxPoint> buf;
for( int cnt = 0; cnt < aPolygons.OutlineCount(); cnt++ )
{
const SHAPE_LINE_CHAIN& poly = aPolygons.COutline( cnt );
for( int ii = 0; ii < poly.PointCount(); ++ii )
{
buf.push_back( wxPoint( poly.CPoint( ii ).x, poly.CPoint( ii ).y ) );
}
}
BuildConvexHull(aResult, buf );
// Move and rotate the points according to aPosition and aRotation
for( unsigned ii = 0; ii < aResult.size(); ii++ )
{
RotatePoint( &aResult[ii], aRotation );
aResult[ii] += aPosition;
}
}

View File

@ -382,7 +382,11 @@ const optional<SHAPE_LINE_CHAIN::INTERSECTION> SHAPE_LINE_CHAIN::SelfIntersectin
is.p = s2a;
return is;
}
else if( CSegment( s1 ).Contains( s2b ) )
else if( CSegment( s1 ).Contains( s2b ) &&
// for closed polylines, the ending point of the
// last segment == starting point of the first segment
// this is a normal case, not self intersecting case
!( IsClosed() && s1 == 0 && s2 == SegmentCount()-1 ) )
{
INTERSECTION is;
is.our = CSegment( s1 );

View File

@ -142,6 +142,8 @@ rect_delta
reference
right
rotate
roundrect
roundrect_rratio
scale
segment
segment_width

View File

@ -0,0 +1,59 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2016 Jean-Pierre Charras, jp.charras at wanadoo.fr
* Copyright (C) 1992-2016 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
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
#ifndef __CONVEX_HULL_H
#define __CONVEX_HULL_H
#include <vector>
class wxPoint; // Defined in wxWidgets
class SHAPE_POLY_SET;
/**
* Calculate the convex hull of a list of points
* in counter-clockwise order.
* @param aResult = a vector to store the convex polygon.
* @param aPoly is the list of points.
*/
void BuildConvexHull( std::vector<wxPoint>& aResult, const std::vector<wxPoint>& aPoly);
/**
* Calculate the convex hull of a SHAPE_POLY_SET
* @param aResult = a vector to store the convex polygon.
* @param aPolygons = the SHAPE_POLY_SET
*/
void BuildConvexHull( std::vector<wxPoint>& aResult, const SHAPE_POLY_SET& aPolygons );
/**
* Calculate the convex hull (rotated and moved) of a SHAPE_POLY_SET
* @param aResult = a vector to store the convex polygon.
* @param aPolygons is the set of polygons
* @param aPosition = the final position of the convex hull
* @param aRotation = the rotation of the convex hull
*/
void BuildConvexHull( std::vector<wxPoint>& aResult, const SHAPE_POLY_SET& aPolygons,
wxPoint aPosition, double aRotation );
#endif // __CONVEX_HULL_H

View File

@ -146,9 +146,9 @@ public:
{
SHAPE_LINE_CHAIN rv;
rv.Append( m_p0 );
rv.Append( m_p0.x, m_p0.y + m_w );
rv.Append( m_p0.x + m_h, m_p0.y + m_w );
rv.Append( m_p0.x + m_h, m_p0.y );
rv.Append( m_p0.x, m_p0.y + m_h );
rv.Append( m_p0.x + m_w, m_p0.y + m_h );
rv.Append( m_p0.x + m_w, m_p0.y );
rv.Append( m_p0 );
rv.SetClosed( true );
return rv;

View File

@ -1,7 +1,7 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 1992-2014 KiCad Developers, see CHANGELOG.TXT for contributors.
* Copyright (C) 1992-2016 KiCad Developers, see CHANGELOG.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
@ -27,6 +27,7 @@
/**
* Enum PAD_SHAPE_T
* is the set of pad shapes, used with D_PAD::{Set,Get}Shape()
* The double name is for compatibility with old Python scripts
*/
enum PAD_SHAPE_T
{
@ -37,13 +38,12 @@ enum PAD_SHAPE_T
PAD_SHAPE_OVAL,
PAD_OVAL = PAD_SHAPE_OVAL,
PAD_SHAPE_TRAPEZOID,
PAD_TRAPEZOID = PAD_SHAPE_TRAPEZOID
PAD_SHAPE_ROUNDRECT,
};
/**
* Enum PAD_DRILL_SHAPE_T
* is the set of pad drill shapes, used with D_PAD::{Set,Get}DrillShape()
* The double name is for convenience of Python devs
*/
enum PAD_DRILL_SHAPE_T
{
@ -59,14 +59,14 @@ enum PAD_DRILL_SHAPE_T
*/
enum PAD_ATTR_T
{
PAD_ATTRIB_STANDARD, ///< Usual pad
PAD_ATTRIB_STANDARD, ///< Usual pad
PAD_STANDARD = PAD_ATTRIB_STANDARD,
PAD_ATTRIB_SMD, ///< Smd pad, appears on the solder paste layer (default)
PAD_ATTRIB_SMD, ///< Smd pad, appears on the solder paste layer (default)
PAD_SMD = PAD_ATTRIB_SMD,
PAD_ATTRIB_CONN, ///< Like smd, does not appear on the solder paste layer (default)
PAD_CONN = PAD_ATTRIB_CONN,
PAD_ATTRIB_HOLE_NOT_PLATED, ///< like PAD_STANDARD, but not plated
///< mechanical use only, no connection allowed
PAD_ATTRIB_CONN, ///< Like smd, does not appear on the solder paste layer (default)
///< Used for edgecard connectors for instance
PAD_ATTRIB_HOLE_NOT_PLATED, ///< like PAD_STANDARD, but not plated
///< mechanical use only, no connection allowed
PAD_HOLE_NOT_PLATED = PAD_ATTRIB_HOLE_NOT_PLATED
};

View File

@ -1,8 +1,8 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2009-2014 Jean-Pierre Charras, jp.charras at wanadoo.fr
* Copyright (C) 1992-2012 KiCad Developers, see AUTHORS.txt for contributors.
* Copyright (C) 2009-2016 Jean-Pierre Charras, jp.charras at wanadoo.fr
* Copyright (C) 1992-2016 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
@ -552,7 +552,7 @@ void TRACK::TransformShapeWithClearanceToPolygon( SHAPE_POLY_SET& aCornerBuffer,
* clearance when the circle is approximated by segment bigger or equal
* to the real clearance value (usually near from 1.0)
*/
void D_PAD:: TransformShapeWithClearanceToPolygon( SHAPE_POLY_SET& aCornerBuffer,
void D_PAD::TransformShapeWithClearanceToPolygon( SHAPE_POLY_SET& aCornerBuffer,
int aClearanceValue,
int aCircleToSegmentsCount,
double aCorrectionFactor ) const
@ -561,14 +561,14 @@ void D_PAD:: TransformShapeWithClearanceToPolygon( SHAPE_POLY_SET& aCornerBuffer
int dx = (m_Size.x / 2) + aClearanceValue;
int dy = (m_Size.y / 2) + aClearanceValue;
wxPoint PadShapePos = ShapePos(); /* Note: for pad having a shape offset,
wxPoint padShapePos = ShapePos(); /* Note: for pad having a shape offset,
* the pad position is NOT the shape position */
switch( GetShape() )
{
case PAD_SHAPE_CIRCLE:
dx = KiROUND( dx * aCorrectionFactor );
TransformCircleToPolygon( aCornerBuffer, PadShapePos, dx,
TransformCircleToPolygon( aCornerBuffer, padShapePos, dx,
aCircleToSegmentsCount );
break;
@ -591,8 +591,8 @@ void D_PAD:: TransformShapeWithClearanceToPolygon( SHAPE_POLY_SET& aCornerBuffer
}
RotatePoint( &shape_offset, angle );
wxPoint start = PadShapePos - shape_offset;
wxPoint end = PadShapePos + shape_offset;
wxPoint start = padShapePos - shape_offset;
wxPoint end = padShapePos + shape_offset;
TransformRoundedEndsSegmentToPolygon( aCornerBuffer, start, end,
aCircleToSegmentsCount, width );
}
@ -605,18 +605,33 @@ void D_PAD:: TransformShapeWithClearanceToPolygon( SHAPE_POLY_SET& aCornerBuffer
BuildPadPolygon( corners, wxSize( 0, 0 ), angle );
SHAPE_POLY_SET outline;
outline.NewOutline();
for( int ii = 0; ii < 4; ii++ )
{
corners[ii] += PadShapePos;
corners[ii] += padShapePos;
outline.Append( corners[ii].x, corners[ii].y );
}
double rounding_radius = aClearanceValue * aCorrectionFactor;
int rounding_radius = int( aClearanceValue * aCorrectionFactor );
outline.Inflate( rounding_radius, aCircleToSegmentsCount );
outline.Inflate( (int) rounding_radius, aCircleToSegmentsCount );
aCornerBuffer.Append( outline );
}
break;
case PAD_SHAPE_ROUNDRECT:
{
SHAPE_POLY_SET outline;
int pad_radius = GetRoundRectCornerRadius();
int clearance = int( aClearanceValue * aCorrectionFactor );
int rounding_radius = pad_radius + clearance;
wxSize shapesize( m_Size );
shapesize.x += clearance*2;
shapesize.y += clearance*2;
TransformRoundRectToPolygon( outline, padShapePos, shapesize, angle,
rounding_radius, aCircleToSegmentsCount );
aCornerBuffer.Append( outline );
}
@ -624,6 +639,10 @@ void D_PAD:: TransformShapeWithClearanceToPolygon( SHAPE_POLY_SET& aCornerBuffer
}
}
/*
* Function BuildPadShapePolygon
* Build the Corner list of the polygonal shape,
@ -636,12 +655,13 @@ void D_PAD::BuildPadShapePolygon( SHAPE_POLY_SET& aCornerBuffer,
double aCorrectionFactor ) const
{
wxPoint corners[4];
wxPoint PadShapePos = ShapePos(); /* Note: for pad having a shape offset,
* the pad position is NOT the shape position */
wxPoint padShapePos = ShapePos(); /* Note: for pad having a shape offset,
* the pad position is NOT the shape position */
switch( GetShape() )
{
case PAD_SHAPE_CIRCLE:
case PAD_SHAPE_OVAL:
case PAD_SHAPE_ROUNDRECT:
TransformShapeWithClearanceToPolygon( aCornerBuffer, aInflateValue.x,
aSegmentsPerCircle, aCorrectionFactor );
break;
@ -653,7 +673,7 @@ void D_PAD::BuildPadShapePolygon( SHAPE_POLY_SET& aCornerBuffer,
BuildPadPolygon( corners, aInflateValue, m_Orient );
for( int ii = 0; ii < 4; ii++ )
{
corners[ii] += PadShapePos; // Shift origin to position
corners[ii] += padShapePos; // Shift origin to position
aCornerBuffer.Append( corners[ii].x, corners[ii].y );
}
@ -734,7 +754,7 @@ void CreateThermalReliefPadPolygon( SHAPE_POLY_SET& aCornerBuffer,
double aThermalRot )
{
wxPoint corner, corner_end;
wxPoint PadShapePos = aPad.ShapePos(); // Note: for pad having a shape offset,
wxPoint padShapePos = aPad.ShapePos(); // Note: for pad having a shape offset,
// the pad position is NOT the shape position
wxSize copper_thickness;
@ -836,7 +856,7 @@ void CreateThermalReliefPadPolygon( SHAPE_POLY_SET& aCornerBuffer,
{
corner = corners_buffer[ii];
RotatePoint( &corner, th_angle + angle_pad ); // Rotate by segment angle and pad orientation
corner += PadShapePos;
corner += padShapePos;
aCornerBuffer.Append( corner.x, corner.y );
}
@ -940,7 +960,7 @@ void CreateThermalReliefPadPolygon( SHAPE_POLY_SET& aCornerBuffer,
{
wxPoint cpos = corners_buffer[ic];
RotatePoint( &cpos, angle );
cpos += PadShapePos;
cpos += padShapePos;
aCornerBuffer.Append( cpos.x, cpos.y );
}
@ -966,7 +986,7 @@ void CreateThermalReliefPadPolygon( SHAPE_POLY_SET& aCornerBuffer,
{
wxPoint cpos = corners_buffer[ic];
RotatePoint( &cpos, angle );
cpos += PadShapePos;
cpos += padShapePos;
aCornerBuffer.Append( cpos.x, cpos.y );
}
@ -975,7 +995,8 @@ void CreateThermalReliefPadPolygon( SHAPE_POLY_SET& aCornerBuffer,
}
break;
case PAD_SHAPE_RECT: // draw 4 Holes
case PAD_SHAPE_ROUNDRECT: // thermal shape is the same for round rect and rect.
case PAD_SHAPE_RECT:
{
/* we create 4 copper holes and put them in position 1, 2, 3 and 4
* here is the area of the rectangular pad + its thermal gap
@ -1039,7 +1060,7 @@ void CreateThermalReliefPadPolygon( SHAPE_POLY_SET& aCornerBuffer,
{
wxPoint cpos = corners_buffer[ic];
RotatePoint( &cpos, angle ); // Rotate according to module orientation
cpos += PadShapePos; // Shift origin to position
cpos += padShapePos; // Shift origin to position
aCornerBuffer.Append( cpos.x, cpos.y );
}
@ -1063,7 +1084,7 @@ void CreateThermalReliefPadPolygon( SHAPE_POLY_SET& aCornerBuffer,
{
wxPoint cpos = corners_buffer[ic];
RotatePoint( &cpos, angle );
cpos += PadShapePos;
cpos += padShapePos;
aCornerBuffer.Append( cpos.x, cpos.y );
}
@ -1110,7 +1131,7 @@ void CreateThermalReliefPadPolygon( SHAPE_POLY_SET& aCornerBuffer,
{
wxPoint cpos = stubBuffer[ii];
RotatePoint( &cpos, aPad.GetOrientation() );
cpos += PadShapePos;
cpos += padShapePos;
stub.Append( cpos.x, cpos.y );
}
@ -1132,7 +1153,7 @@ void CreateThermalReliefPadPolygon( SHAPE_POLY_SET& aCornerBuffer,
{
wxPoint cpos = stubBuffer[ii];
RotatePoint( &cpos, aPad.GetOrientation() );
cpos += PadShapePos;
cpos += padShapePos;
stub.Append( cpos.x, cpos.y );
}

View File

@ -1,9 +1,9 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2012 Jean-Pierre Charras, jean-pierre.charras@ujf-grenoble.fr
* Copyright (C) 2016 Jean-Pierre Charras, jp.charras at wanadoo.fr
* Copyright (C) 2012 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
* Copyright (C) 1992-2012 KiCad Developers, see AUTHORS.txt for contributors.
* Copyright (C) 1992-2016 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
@ -30,24 +30,20 @@
#include <fctsys.h>
#include <PolyLine.h>
#include <common.h>
#include <confirm.h>
#include <kicad_string.h>
#include <trigo.h>
#include <richio.h>
#include <wxstruct.h>
#include <macros.h>
#include <msgpanel.h>
#include <base_units.h>
#include <pcbnew.h>
#include <pcbnew_id.h> // ID_TRACK_BUTT
#include <class_board.h>
#include <class_module.h>
#include <polygon_test_point_inside.h>
#include <convert_from_iu.h>
#include <boost/foreach.hpp>
#include <convert_basic_shapes_to_polygon.h>
int D_PAD::m_PadSketchModePenSize = 0; // Pen size used to draw pads in sketch mode
@ -74,6 +70,9 @@ D_PAD::D_PAD( MODULE* parent ) :
m_LocalSolderMaskMargin = 0;
m_LocalSolderPasteMargin = 0;
m_LocalSolderPasteMarginRatio = 0.0;
// Parameters for round rect only:
m_padRoundRectRadiusScale = 0.25; // from IPC-7351C standard
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
@ -114,6 +113,12 @@ LSET D_PAD::UnplatedHoleMask()
return saved;
}
bool D_PAD::IsFlipped()
{
if( GetParent() && GetParent()->GetLayer() == B_Cu )
return true;
return false;
}
int D_PAD::boundingRadius() const
{
@ -140,6 +145,13 @@ int D_PAD::boundingRadius() const
radius = 1 + KiROUND( hypot( x, y ) / 2 );
break;
case PAD_SHAPE_ROUNDRECT:
radius = GetRoundRectCornerRadius();
x = m_Size.x >> 1;
y = m_Size.y >> 1;
radius += 1 + KiROUND( EuclideanNorm( wxSize( x - radius, y - radius )));
break;
default:
radius = 0;
}
@ -148,6 +160,16 @@ int D_PAD::boundingRadius() const
}
int D_PAD::GetRoundRectCornerRadius( const wxSize& aSize ) const
{
// radius of rounded corners, usually 25% of shorter pad edge for now
int r = aSize.x > aSize.y ? aSize.y : aSize.x;
r = int( r * m_padRoundRectRadiusScale );
return r;
}
const EDA_RECT D_PAD::GetBoundingBox() const
{
EDA_RECT area;
@ -162,8 +184,7 @@ const EDA_RECT D_PAD::GetBoundingBox() const
break;
case PAD_SHAPE_OVAL:
//Use the maximal two most distant points and track their rotation
// (utilise symmetry to avoid four points)
// Calculate the position of each rounded ent
quadrant1.x = m_Size.x/2;
quadrant1.y = 0;
quadrant2.x = 0;
@ -171,15 +192,21 @@ const EDA_RECT D_PAD::GetBoundingBox() const
RotatePoint( &quadrant1, m_Orient );
RotatePoint( &quadrant2, m_Orient );
// Calculate the max position of each end, relative to the pad position
// (the min position is symetrical)
dx = std::max( std::abs( quadrant1.x ) , std::abs( quadrant2.x ) );
dy = std::max( std::abs( quadrant1.y ) , std::abs( quadrant2.y ) );
area.SetOrigin( m_Pos.x-dx, m_Pos.y-dy );
area.SetSize( 2*dx, 2*dy );
// Set the bbox
area.SetOrigin( m_Pos );
area.Inflate( dx, dy );
break;
case PAD_SHAPE_RECT:
//Use two corners and track their rotation
// (utilise symmetry to avoid four points)
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;
@ -189,8 +216,10 @@ const EDA_RECT D_PAD::GetBoundingBox() const
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 ) );
area.SetOrigin( m_Pos.x-dx, m_Pos.y-dy );
area.SetSize( 2*dx, 2*dy );
// Set the bbox
area.SetOrigin( m_Pos );
area.Inflate( dx, dy );
break;
case PAD_SHAPE_TRAPEZOID:
@ -275,17 +304,13 @@ void D_PAD::SetOrientation( double aAngle )
void D_PAD::Flip( const wxPoint& aCentre )
{
int y = GetPosition().y - aCentre.y;
y = -y; // invert about x axis.
y += aCentre.y;
int y = GetPosition().y;
MIRROR( y, aCentre.y ); // invert about x axis.
SetY( y );
m_Pos0.y = -m_Pos0.y;
m_Offset.y = -m_Offset.y;
m_DeltaSize.y = -m_DeltaSize.y;
MIRROR( m_Pos0.y, 0 );
MIRROR( m_Offset.y, 0 );
MIRROR( m_DeltaSize.y, 0 );
SetOrientation( -GetOrientation() );
@ -434,6 +459,7 @@ void D_PAD::Copy( D_PAD* source )
m_ZoneConnection = source->m_ZoneConnection;
m_ThermalWidth = source->m_ThermalWidth;
m_ThermalGap = source->m_ThermalGap;
m_padRoundRectRadiusScale = source->m_padRoundRectRadiusScale;
SetSubRatsnest( 0 );
SetSubNet( 0 );
@ -766,6 +792,19 @@ bool D_PAD::HitTest( const wxPoint& aPosition ) const
return true;
break;
case PAD_SHAPE_ROUNDRECT:
{
// Check for hit in polygon
SHAPE_POLY_SET outline;
const int segmentToCircleCount = 32;
TransformRoundRectToPolygon( outline, wxPoint(0,0), GetSize(), m_Orient,
GetRoundRectCornerRadius(), segmentToCircleCount );
const SHAPE_LINE_CHAIN &poly = outline.COutline( 0 );
return TestPointInsidePolygon( (const wxPoint*)&poly.CPoint(0), poly.PointCount(), delta );
}
break;
}
return false;
@ -806,6 +845,8 @@ int D_PAD::Compare( const D_PAD* padref, const D_PAD* padcmp )
if( ( diff = padref->m_DeltaSize.y - padcmp->m_DeltaSize.y ) != 0 )
return diff;
// TODO: test custom shapes
// Dick: specctra_export needs this
// Lorenzo: gencad also needs it to implement padstacks!
@ -852,6 +893,9 @@ wxString D_PAD::ShowPadShape() const
case PAD_SHAPE_TRAPEZOID:
return _( "Trap" );
case PAD_SHAPE_ROUNDRECT:
return _( "Roundrect" );
default:
return wxT( "???" );
}

View File

@ -1,8 +1,8 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2004 Jean-Pierre Charras, jaen-pierre.charras@gipsa-lab.inpg.com
* Copyright (C) 1992-2011 KiCad Developers, see AUTHORS.txt for contributors.
* Copyright (C) 2016 Jean-Pierre Charras, jaen-pierre.charras@gipsa-lab.inpg.com
* Copyright (C) 1992-2016 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
@ -105,6 +105,12 @@ public:
MODULE* GetParent() const { return (MODULE*) m_Parent; }
/**
* @return true if the pad has a footprint parent flipped
* (on the back/bottom layer)
*/
bool IsFlipped();
/**
* Set the pad name (sometimes called pad number, although
* it can be an array ref like AA12
@ -180,8 +186,10 @@ public:
void SetOffset( const wxPoint& aOffset ) { m_Offset = aOffset; }
const wxPoint& GetOffset() const { return m_Offset; }
void Flip( const wxPoint& aCentre ); // Virtual function
/**
* Function SetOrientation
* sets the rotation angle of the pad.
@ -198,6 +206,7 @@ public:
void SetDrillShape( PAD_DRILL_SHAPE_T aDrillShape )
{ m_drillShape = aDrillShape; }
PAD_DRILL_SHAPE_T GetDrillShape() const { return m_drillShape; }
/**
@ -323,6 +332,27 @@ public:
*/
void BuildPadPolygon( wxPoint aCoord[4], wxSize aInflateValue, double aRotation ) const;
/**
* Function GetRoundRectCornerRadius
* Has meaning only for rounded rect pads
* @return The radius of the rounded corners for this pad.
*/
int GetRoundRectCornerRadius() const
{
return GetRoundRectCornerRadius( m_Size );
}
/**
* Helper function GetRoundRectCornerRadius
* Has meaning only for rounded rect pads
* Returns the radius of the rounded corners of a rectangle
* size aSize, using others setting of the pad
* @param aSize = size of the of the round rect. Usually the pad size
* but can be the size of the pad on solder mask or solder paste
* @return The radius of the rounded corners for this pad size.
*/
int GetRoundRectCornerRadius( const wxSize& aSize ) const;
/**
* Function BuildPadShapePolygon
* Build the Corner list of the polygonal shape,
@ -340,7 +370,7 @@ public:
* @param aSegmentsPerCircle = number of segments to approximate a circle
* (used for round and oblong shapes only (16 to 32 is a good value)
* @param aCorrectionFactor = the correction to apply to circles radius to keep
* the pad size when the circle is approximated by segments
* the pad size/clearance when the arcs are approximated by segments
*/
void BuildPadShapePolygon( SHAPE_POLY_SET& aCornerBuffer,
wxSize aInflateValue, int aSegmentsPerCircle,
@ -382,6 +412,7 @@ public:
/**
* Function GetBoundingRadius
* returns the radius of a minimum sized circle which fully encloses this pad.
* The center is the pad position
*/
int GetBoundingRadius() const
{
@ -398,6 +429,33 @@ public:
const wxPoint ShapePos() const;
/**
* has meaning only for rounded rect pads
* @return the scaling factor between the smaller Y or Y size and the radius
* of the rounded corners.
* Cannot be > 0.5
* the normalized IPC-7351C value is 0.25
*/
double GetRoundRectRadiusRatio()
{
return m_padRoundRectRadiusScale;
}
/**
* has meaning only for rounded rect pads
* Set the scaling factor between the smaller Y or Y size and the radius
* of the rounded corners.
* Cannot be < 0.5 and obviously must be > 0
* the normalized IPC-7351C value is 0.25
*/
void SetRoundRectRadiusRatio( double aRadiusScale )
{
if( aRadiusScale < 0.0 )
aRadiusScale = 0.0;
m_padRoundRectRadiusScale = std::min( aRadiusScale, 0.5 );
}
/**
* Function GetSubRatsnest
* @return int - the netcode
@ -517,6 +575,8 @@ private:
*/
int boundingRadius() const;
private: // Private variable members:
// Actually computed and cached on demand by the accessor
mutable int m_boundingRadius; ///< radius of the circle containing the pad shape
@ -531,8 +591,9 @@ private:
wxPoint m_Pos; ///< pad Position on board
PAD_SHAPE_T m_padShape; ///< Shape: PAD_CIRCLE, PAD_RECT, PAD_OVAL, PAD_TRAPEZOID
PAD_SHAPE_T m_padShape; ///< Shape: PAD_SHAPE_CIRCLE, PAD_SHAPE_RECT,
///< PAD_SHAPE_OVAL, PAD_SHAPE_TRAPEZOID,
///< PAD_SHAPE_ROUNDRECT, PAD_SHAPE_POLYGON
int m_SubRatsnest; ///< variable used in rats nest computations
///< handle subnet (block) number in ratsnest connection
@ -545,15 +606,17 @@ private:
PAD_DRILL_SHAPE_T m_drillShape; ///< PAD_DRILL_SHAPE_CIRCLE, PAD_DRILL_SHAPE_OBLONG
double m_padRoundRectRadiusScale; ///< scaling factor from smallest m_Size coord
///< to corner radius, default 0.25
/**
* m_Offset is useful only for oblong pads (it can be used for other
* m_Offset is useful only for oblong and rect pads (it can be used for other
* shapes, but without any interest).
* This is the offset between the pad hole and the pad shape (you must
* understand here pad shape = copper area around the hole)
* Most of cases, the hole is the center of the shape (m_Offset = 0).
* But some board designers use oblong pads with a hole moved to one of the
* oblong pad shape ends.
* But some board designers use oblong/rect pads with a hole moved to one of the
* oblong/rect pad shape ends.
* In all cases the pad position is the pad hole.
* The physical shape position (used to draw it for instance) is pad
* position (m_Pos) + m_Offset.
@ -582,14 +645,16 @@ private:
/// Usually the local clearance is null
int m_LocalClearance;
// Local mask margins: when 0, the parent footprint design values are used
/// Local mask margins: when 0, the parent footprint design values are used
int m_LocalSolderMaskMargin; ///< Local solder mask margin
int m_LocalSolderPasteMargin; ///< Local solder paste margin absolute value
double m_LocalSolderPasteMarginRatio; ///< Local solder mask margin ratio value of pad size
///< The final margin is the sum of these 2 values
/// how the connection to zone is made: no connection, thermal relief ...
ZoneConnection m_ZoneConnection;
int m_ThermalWidth;
int m_ThermalGap;
};

View File

@ -1,10 +1,10 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2012 Jean-Pierre Charras, jean-pierre.charras@ujf-grenoble.fr
* Copyright (C) 2016 Jean-Pierre Charras, jean-pierre.charras@ujf-grenoble.fr
* Copyright (C) 2012 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
* Copyright (C) 2012 Wayne Stambaugh <stambaughw@verizon.net>
* Copyright (C) 1992-2015 KiCad Developers, see AUTHORS.txt for contributors.
* Copyright (C) 1992-2016 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
@ -40,6 +40,8 @@
#include <pcbnew_id.h> // ID_TRACK_BUTT
#include <pcbnew.h>
#include <class_board.h>
#include <convert_basic_shapes_to_polygon.h>
/* uncomment this line to show this pad with its specfic size and color
@ -315,7 +317,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 )
{
wxPoint coord[4];
wxPoint coord[12];
double angle = m_Orient;
int seg_width;
@ -392,15 +394,71 @@ void D_PAD::DrawShape( EDA_RECT* aClipBox, wxDC* aDC, PAD_DRAWINFO& aDrawInfo )
if( aDrawInfo.m_PadClearance )
{
BuildPadPolygon( coord, wxSize( aDrawInfo.m_PadClearance,
aDrawInfo.m_PadClearance ), angle );
for( int ii = 0; ii < 4; ii++ )
coord[ii] += shape_pos;
#define SEGCOUNT 32 // number of segments to approximate a circle
SHAPE_POLY_SET outline;
TransformShapeWithClearanceToPolygon( outline, aDrawInfo.m_PadClearance, SEGCOUNT, 1.0 );
GRClosedPoly( aClipBox, aDC, 4, coord, 0, aDrawInfo.m_Color, aDrawInfo.m_Color );
// Draw the polygon: Inflate creates only one convex polygon
SHAPE_LINE_CHAIN& poly = outline.Outline( 0 );
GRClosedPoly( aClipBox, aDC, poly.PointCount(),
(wxPoint*)&poly.Point( 0 ), false, 0,
aDrawInfo.m_Color, aDrawInfo.m_Color );
}
break;
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 );
// 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 );
GRClosedPoly( aClipBox, aDC, poly.PointCount(),
(wxPoint*)&poly.Point( 0 ), aDrawInfo.m_ShowPadFilled, 0,
aDrawInfo.m_Color, aDrawInfo.m_Color );
}
if( aDrawInfo.m_PadClearance )
{
outline.RemoveAllContours();
size = GetSize();
size.x += aDrawInfo.m_PadClearance * 2;
size.y += aDrawInfo.m_PadClearance * 2;
corner_radius = GetRoundRectCornerRadius() + aDrawInfo.m_PadClearance;
TransformRoundRectToPolygon( outline, shape_pos, size, GetOrientation(),
corner_radius, 32 );
// Draw the polygon: Inflate creates only one convex polygon
SHAPE_LINE_CHAIN& clearance_poly = outline.Outline( 0 );
GRClosedPoly( aClipBox, aDC, clearance_poly.PointCount(),
(wxPoint*)&clearance_poly.Point( 0 ), false, 0,
aDrawInfo.m_Color, aDrawInfo.m_Color );
}
}
break;
default:
break;
}

View File

@ -1,15 +1,15 @@
/**
* @file dialog_pad_properties.cpp
* @brief Pad editing functions and dialog pad editor.
* @brief dialog pad properties editor.
*/
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015 Jean-Pierre Charras, jp.charras at wanadoo.fr
* Copyright (C) 2016 Jean-Pierre Charras, jp.charras at wanadoo.fr
* Copyright (C) 2013 Dick Hollenbeck, dick@softplc.com
* Copyright (C) 2008-2013 Wayne Stambaugh <stambaughw@verizon.net>
* Copyright (C) 1992-2015 KiCad Developers, see AUTHORS.txt for contributors.
* Copyright (C) 1992-2016 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
@ -46,20 +46,30 @@
#include <class_board.h>
#include <class_module.h>
#include <origin_viewitem.h>
#include <dialog_pad_properties_base.h>
#include <dialog_pad_properties.h>
#include <html_messagebox.h>
// list of pad shapes.
// list of pad shapes, ordered like the pad shape wxChoice in dialog.
static PAD_SHAPE_T code_shape[] = {
PAD_SHAPE_CIRCLE,
PAD_SHAPE_OVAL,
PAD_SHAPE_RECT,
PAD_SHAPE_TRAPEZOID
PAD_SHAPE_TRAPEZOID,
PAD_SHAPE_ROUNDRECT,
};
// the ordered index of the pad shape wxChoice in dialog.
// keep it consistent with code_shape[] and dialog strings
enum CODE_CHOICE {
CHOICE_SHAPE_CIRCLE = 0,
CHOICE_SHAPE_OVAL,
CHOICE_SHAPE_RECT,
CHOICE_SHAPE_TRAPEZOID,
CHOICE_SHAPE_ROUNDRECT,
};
static PAD_ATTR_T code_type[] = {
PAD_ATTRIB_STANDARD,
@ -85,81 +95,9 @@ static const LSET std_pad_layers[] = {
};
/**
* class DIALOG_PAD_PROPERTIES, derived from DIALOG_PAD_PROPERTIES_BASE,
* created by wxFormBuilder
*/
class DIALOG_PAD_PROPERTIES : public DIALOG_PAD_PROPERTIES_BASE
{
public:
DIALOG_PAD_PROPERTIES( PCB_BASE_FRAME* aParent, D_PAD* aPad );
~DIALOG_PAD_PROPERTIES()
{
delete m_dummyPad;
delete m_axisOrigin;
}
private:
PCB_BASE_FRAME* m_parent;
KIGFX::ORIGIN_VIEWITEM* m_axisOrigin;
D_PAD* m_currentPad; // pad currently being edited
D_PAD* m_dummyPad; // a working copy used to show changes
D_PAD* m_padMaster; // The pad used to create new pads in board or
// footprint editor
BOARD* m_board; // the main board: this is the board handled by
// the PCB editor, if running or the dummy
// board used by the footprint editor
// (could happen when the Footprint editor will be run
// alone, outside the board editor
bool m_isFlipped; // true if the parent footprint (therefore pads) is flipped (mirrored)
// in this case, some Y coordinates values must be negated
bool m_canUpdate;
bool m_canEditNetName; // true only if the called is the board editor
private:
void initValues();
bool padValuesOK(); ///< test if all values are acceptable for the pad
void redraw();
/**
* Function setPadLayersList
* updates the CheckBox states in pad layers list,
* @param layer_mask = pad layer mask (ORed layers bit mask)
*/
void setPadLayersList( LSET layer_mask );
/// Copy values from dialog field to aPad's members
bool transferDataToPad( D_PAD* aPad );
// event handlers:
void OnResize( wxSizeEvent& event );
void OnPadShapeSelection( wxCommandEvent& event );
void OnDrillShapeSelected( wxCommandEvent& event );
void PadOrientEvent( wxCommandEvent& event );
void PadTypeSelected( wxCommandEvent& event );
void OnSetLayers( wxCommandEvent& event );
void OnCancelButtonClick( wxCommandEvent& event );
void OnPaintShowPanel( wxPaintEvent& event );
/// Called when a dimension has changed.
/// Update the graphical pad shown in the panel.
void OnValuesChanged( wxCommandEvent& event );
/// Updates the different parameters for the component being edited.
/// Fired from the OK button click.
void PadPropertiesAccept( wxCommandEvent& event );
};
void PCB_BASE_FRAME::InstallPadOptionsFrame( D_PAD* aPad )
{
DIALOG_PAD_PROPERTIES dlg( this, aPad );
dlg.ShowModal();
}
@ -170,7 +108,7 @@ DIALOG_PAD_PROPERTIES::DIALOG_PAD_PROPERTIES( PCB_BASE_FRAME* aParent, D_PAD* aP
m_canUpdate = false;
m_parent = aParent;
m_currentPad = aPad; // aPad can be NULL, if the dialog is called
// from the module editor to set default pad characteristics
// from the footprint editor to set default pad setup
m_board = m_parent->GetBoard();
@ -179,9 +117,11 @@ DIALOG_PAD_PROPERTIES::DIALOG_PAD_PROPERTIES( PCB_BASE_FRAME* aParent, D_PAD* aP
if( aPad )
m_dummyPad->Copy( aPad );
else // We are editing a "master" pad, i.e. a pad used to create new pads
else // We are editing a "master" pad, i.e. a template to create new pads
m_dummyPad->Copy( m_padMaster );
// Show the X and Y axis. It is usefull because pads can have an offset
// or a complex shape. Showing the pad reference position is important
m_axisOrigin = new KIGFX::ORIGIN_VIEWITEM( KIGFX::COLOR4D(0.0, 0.0, 0.8, 1.0),
KIGFX::ORIGIN_VIEWITEM::CROSS,
20000,
@ -198,7 +138,6 @@ DIALOG_PAD_PROPERTIES::DIALOG_PAD_PROPERTIES( PCB_BASE_FRAME* aParent, D_PAD* aP
m_panelShowPadGal->GetView()->Add( m_dummyPad );
m_panelShowPadGal->GetView()->Add( m_axisOrigin );
m_panelShowPadGal->StartDrawing();
Connect( wxEVT_SIZE, wxSizeEventHandler( DIALOG_PAD_PROPERTIES::OnResize ) );
}
else
@ -209,7 +148,7 @@ DIALOG_PAD_PROPERTIES::DIALOG_PAD_PROPERTIES( PCB_BASE_FRAME* aParent, D_PAD* aP
initValues();
m_sdbSizer1OK->SetDefault();
m_sdbSizerOK->SetDefault();
GetSizer()->SetSizeHints( this );
m_PadNumCtrl->SetFocus();
@ -255,7 +194,7 @@ void DIALOG_PAD_PROPERTIES::OnPaintShowPanel( wxPaintEvent& event )
dc.SetDeviceOrigin( dc_size.x / 2, dc_size.y / 2 );
// Calculate a suitable scale to fit the available draw area
int dim = m_dummyPad->GetSize().x + std::abs( m_dummyPad->GetDelta().y );
int dim = m_dummyPad->GetBoundingRadius() *2;
// Invalid x size. User could enter zero, or have deleted all text prior to
// entering a new value; this is also treated as zero. If dim is left at
@ -303,16 +242,69 @@ void DIALOG_PAD_PROPERTIES::OnPaintShowPanel( wxPaintEvent& event )
GRResetPenAndBrush( &dc );
m_dummyPad->DrawShape( NULL, &dc, drawInfo );
// Draw X and Y axis.
// this is particularly useful to show the reference position of pads
// with offset and no hole
GRLine( NULL, &dc, -dim, 0, dim, 0, 0, BLUE ); // X axis
GRLine( NULL, &dc, 0, -dim, 0, dim, 0, BLUE ); // Y axis
// Draw X and Y axis. Hhis is particularly useful to show the
// reference position of pads with offset and no hole, or custom pad shapes
const int linethickness = 0;
GRLine( NULL, &dc, -int( dc_size.x/scale ), 0, int( dc_size.x/scale ), 0,
linethickness, LIGHTBLUE ); // X axis
GRLine( NULL, &dc, 0, -int( dc_size.y/scale ), 0, int( dc_size.y/scale ),
linethickness, LIGHTBLUE ); // Y axis
event.Skip();
}
void DIALOG_PAD_PROPERTIES::updateRoundRectCornerValues()
{
// Note:
// To avoid generating a wxEVT_TEXT event from m_tcCornerSizeRatio
// we use ChangeValue instead of SetValue, to set the displayed string
if( m_dummyPad->GetShape() == PAD_SHAPE_ROUNDRECT )
{
m_tcCornerSizeRatio->ChangeValue( wxString::Format( "%.1f",
m_dummyPad->GetRoundRectRadiusRatio()*100 ) );
m_staticTextCornerRadiusValue->SetLabel( StringFromValue( g_UserUnit,
m_dummyPad->GetRoundRectCornerRadius() ) );
}
else
{
m_tcCornerSizeRatio->ChangeValue( wxEmptyString );
m_staticTextCornerRadiusValue->SetLabel( wxEmptyString );
}
}
void DIALOG_PAD_PROPERTIES::onCornerSizePercentChange( wxCommandEvent& event )
{
if( m_dummyPad->GetShape() != PAD_SHAPE_ROUNDRECT )
return;
wxString value = m_tcCornerSizeRatio->GetValue();
double rrRadiusRatioPercent;
if( value.ToDouble( &rrRadiusRatioPercent ) )
{
// Clamp rrRadiusRatioPercent to acceptable value (0.0 to 50.0)
if( rrRadiusRatioPercent < 0.0 )
{
rrRadiusRatioPercent = 0.0;
m_tcCornerSizeRatio->ChangeValue( "0.0" );
}
if( rrRadiusRatioPercent > 50.0 )
{
rrRadiusRatioPercent = 0.5;
m_tcCornerSizeRatio->ChangeValue( "50.0" );
}
transferDataToPad( m_dummyPad );
m_staticTextCornerRadiusValue->SetLabel( StringFromValue( g_UserUnit,
m_dummyPad->GetRoundRectCornerRadius() ) );
redraw();
}
}
void DIALOG_PAD_PROPERTIES::initValues()
{
wxString msg;
@ -344,16 +336,14 @@ void DIALOG_PAD_PROPERTIES::initValues()
if( m_currentPad )
{
MODULE* module = m_currentPad->GetParent();
MODULE* footprint = m_currentPad->GetParent();
m_isFlipped = m_currentPad->IsFlipped();
if( module->GetLayer() == B_Cu )
{
m_isFlipped = true;
if( m_isFlipped )
m_staticModuleSideValue->SetLabel( _( "Back side (footprint is mirrored)" ) );
}
//Internal angles are in 0.1 degree
msg.Printf( wxT( "%.1f" ), module->GetOrientation() / 10.0 );
// Diplay footprint rotation ( angles are in 0.1 degree )
msg.Printf( wxT( "%.1f" ), footprint->GetOrientation() / 10.0 );
m_staticModuleRotValue->SetLabel( msg );
}
@ -376,24 +366,20 @@ void DIALOG_PAD_PROPERTIES::initValues()
m_PadNumCtrl->SetValue( m_dummyPad->GetPadName() );
m_PadNetNameCtrl->SetValue( m_dummyPad->GetNetname() );
// Display current unit name in dialog:
m_PadPosX_Unit->SetLabel( GetAbbreviatedUnitsLabel( g_UserUnit ) );
m_PadPosY_Unit->SetLabel( GetAbbreviatedUnitsLabel( g_UserUnit ) );
m_PadDrill_X_Unit->SetLabel( GetAbbreviatedUnitsLabel( g_UserUnit ) );
m_PadDrill_Y_Unit->SetLabel( GetAbbreviatedUnitsLabel( g_UserUnit ) );
m_PadShapeSizeX_Unit->SetLabel( GetAbbreviatedUnitsLabel( g_UserUnit ) );
m_PadShapeSizeY_Unit->SetLabel( GetAbbreviatedUnitsLabel( g_UserUnit ) );
m_PadShapeOffsetX_Unit->SetLabel( GetAbbreviatedUnitsLabel( g_UserUnit ) );
m_PadShapeOffsetY_Unit->SetLabel( GetAbbreviatedUnitsLabel( g_UserUnit ) );
m_PadShapeDelta_Unit->SetLabel( GetAbbreviatedUnitsLabel( g_UserUnit ) );
m_PadLengthDie_Unit->SetLabel( GetAbbreviatedUnitsLabel( g_UserUnit ) );
// Set the unit name in dialog:
wxStaticText* unitTexts[] =
{
m_PadPosX_Unit, m_PadPosY_Unit,
m_PadDrill_X_Unit, m_PadDrill_Y_Unit,
m_PadShapeSizeX_Unit, m_PadShapeSizeY_Unit,
m_PadShapeOffsetX_Unit,m_PadShapeOffsetY_Unit,
m_PadShapeDelta_Unit, m_PadLengthDie_Unit,
m_NetClearanceUnits, m_SolderMaskMarginUnits, m_SolderPasteMarginUnits,
m_ThermalWidthUnits, m_ThermalGapUnits, m_staticTextCornerSizeUnit
};
// Display current pad masks clearances units
m_NetClearanceUnits->SetLabel( GetAbbreviatedUnitsLabel( g_UserUnit ) );
m_SolderMaskMarginUnits->SetLabel( GetAbbreviatedUnitsLabel( g_UserUnit ) );
m_SolderPasteMarginUnits->SetLabel( GetAbbreviatedUnitsLabel( g_UserUnit ) );
m_ThermalWidthUnits->SetLabel( GetAbbreviatedUnitsLabel( g_UserUnit ) );
m_ThermalGapUnits->SetLabel( GetAbbreviatedUnitsLabel( g_UserUnit ) );
for( unsigned ii = 0; ii < DIM( unitTexts ); ++ii )
unitTexts[ii]->SetLabel( GetAbbreviatedUnitsLabel( g_UserUnit ) );
// Display current pad parameters units:
PutValueInLocalUnits( *m_PadPosition_X_Ctrl, m_dummyPad->GetPosition().x );
@ -462,9 +448,8 @@ void DIALOG_PAD_PROPERTIES::initValues()
if( m_currentPad )
{
MODULE* module = m_currentPad->GetParent();
angle = m_currentPad->GetOrientation() - module->GetOrientation();
MODULE* footprint = m_currentPad->GetParent();
angle = m_currentPad->GetOrientation() - footprint->GetOrientation();
if( m_isFlipped )
angle = -angle;
@ -508,19 +493,23 @@ void DIALOG_PAD_PROPERTIES::initValues()
{
default:
case PAD_SHAPE_CIRCLE:
m_PadShape->SetSelection( 0 );
m_PadShape->SetSelection( CHOICE_SHAPE_CIRCLE );
break;
case PAD_SHAPE_OVAL:
m_PadShape->SetSelection( 1 );
m_PadShape->SetSelection( CHOICE_SHAPE_OVAL );
break;
case PAD_SHAPE_RECT:
m_PadShape->SetSelection( 2 );
m_PadShape->SetSelection( CHOICE_SHAPE_RECT );
break;
case PAD_SHAPE_TRAPEZOID:
m_PadShape->SetSelection( 3 );
m_PadShape->SetSelection( CHOICE_SHAPE_TRAPEZOID );
break;
case PAD_SHAPE_ROUNDRECT:
m_PadShape->SetSelection( CHOICE_SHAPE_ROUNDRECT );
break;
}
@ -557,6 +546,15 @@ void DIALOG_PAD_PROPERTIES::initValues()
setPadLayersList( m_dummyPad->GetLayerSet() );
OnDrillShapeSelected( cmd_event );
OnPadShapeSelection( cmd_event );
updateRoundRectCornerValues();
}
// A small helper function, to display coordinates:
static wxString formatCoord( wxPoint aCoord )
{
return wxString::Format( "X=%s Y=%s",
CoordinateToString( aCoord.x, true ),
CoordinateToString( aCoord.y, true ) );
}
@ -571,7 +569,7 @@ void DIALOG_PAD_PROPERTIES::OnPadShapeSelection( wxCommandEvent& event )
{
switch( m_PadShape->GetSelection() )
{
case 0: // PAD_SHAPE_CIRCLE:
case CHOICE_SHAPE_CIRCLE:
m_ShapeDelta_Ctrl->Enable( false );
m_trapDeltaDirChoice->Enable( false );
m_ShapeSize_Y_Ctrl->Enable( false );
@ -579,7 +577,7 @@ void DIALOG_PAD_PROPERTIES::OnPadShapeSelection( wxCommandEvent& event )
m_ShapeOffset_Y_Ctrl->Enable( false );
break;
case 1: // PAD_SHAPE_OVAL:
case CHOICE_SHAPE_OVAL:
m_ShapeDelta_Ctrl->Enable( false );
m_trapDeltaDirChoice->Enable( false );
m_ShapeSize_Y_Ctrl->Enable( true );
@ -587,7 +585,7 @@ void DIALOG_PAD_PROPERTIES::OnPadShapeSelection( wxCommandEvent& event )
m_ShapeOffset_Y_Ctrl->Enable( true );
break;
case 2: // PAD_SHAPE_RECT:
case CHOICE_SHAPE_RECT:
m_ShapeDelta_Ctrl->Enable( false );
m_trapDeltaDirChoice->Enable( false );
m_ShapeSize_Y_Ctrl->Enable( true );
@ -595,16 +593,36 @@ void DIALOG_PAD_PROPERTIES::OnPadShapeSelection( wxCommandEvent& event )
m_ShapeOffset_Y_Ctrl->Enable( true );
break;
case 3: // PAD_SHAPE_TRAPEZOID:
case CHOICE_SHAPE_TRAPEZOID:
m_ShapeDelta_Ctrl->Enable( true );
m_trapDeltaDirChoice->Enable( true );
m_ShapeSize_Y_Ctrl->Enable( true );
m_ShapeOffset_X_Ctrl->Enable( true );
m_ShapeOffset_Y_Ctrl->Enable( true );
break;
case CHOICE_SHAPE_ROUNDRECT:
m_ShapeDelta_Ctrl->Enable( false );
m_trapDeltaDirChoice->Enable( false );
m_ShapeSize_Y_Ctrl->Enable( true );
m_ShapeOffset_X_Ctrl->Enable( true );
m_ShapeOffset_Y_Ctrl->Enable( true );
break;
}
// A few widgets are enabled only for rounded rect pads:
bool roundrect = m_PadShape->GetSelection() == CHOICE_SHAPE_ROUNDRECT;
m_staticTextCornerSizeRatio->Enable( roundrect );
m_tcCornerSizeRatio->Enable( roundrect );
m_staticTextCornerSizeRatioUnit->Enable( roundrect );
m_staticTextCornerRadius->Enable( roundrect );
m_staticTextCornerRadiusValue->Enable( roundrect );
m_staticTextCornerSizeUnit->Enable( roundrect );
transferDataToPad( m_dummyPad );
updateRoundRectCornerValues();
redraw();
}
@ -831,6 +849,23 @@ bool DIALOG_PAD_PROPERTIES::padValuesOK()
break;
}
if( m_dummyPad->GetShape() == PAD_SHAPE_ROUNDRECT )
{
wxString value = m_tcCornerSizeRatio->GetValue();
double rrRadiusRatioPercent;
if( !value.ToDouble( &rrRadiusRatioPercent ) )
error_msgs.Add( _( "Incorrect corner size value" ) );
else
{
if( rrRadiusRatioPercent < 0.0 )
error_msgs.Add( _( "Incorrect (negative) corner size value" ) );
else if( rrRadiusRatioPercent > 50.0 )
error_msgs.Add( _( "Corner size value must be smaller than 50%" ) );
}
}
if( error_msgs.GetCount() )
{
HTML_MESSAGE_BOX dlg( this, _("Pad setup errors list" ) );
@ -883,10 +918,10 @@ void DIALOG_PAD_PROPERTIES::PadPropertiesAccept( wxCommandEvent& event )
if( m_currentPad ) // Set current Pad parameters
{
wxSize size;
MODULE* module = m_currentPad->GetParent();
MODULE* footprint = m_currentPad->GetParent();
m_parent->SaveCopyInUndoList( module, UR_CHANGED );
module->SetLastEditTime();
m_parent->SaveCopyInUndoList( footprint, UR_CHANGED );
footprint->SetLastEditTime();
// redraw the area where the pad was, without pad (delete pad on screen)
m_currentPad->SetFlags( DO_NOT_DRAW );
@ -903,15 +938,16 @@ void DIALOG_PAD_PROPERTIES::PadPropertiesAccept( wxCommandEvent& event )
rastnestIsChanged = true;
}
// compute the pos 0 value, i.e. pad position for module with orientation = 0
// i.e. relative to module origin (module position)
wxPoint pt = m_currentPad->GetPosition() - module->GetPosition();
// compute the pos 0 value, i.e. pad position for footprint with orientation = 0
// i.e. relative to footprint origin (footprint position)
wxPoint pt = m_currentPad->GetPosition() - footprint->GetPosition();
RotatePoint( &pt, -module->GetOrientation() );
RotatePoint( &pt, -footprint->GetOrientation() );
m_currentPad->SetPos0( pt );
m_currentPad->SetOrientation( m_padMaster->GetOrientation() * isign + module->GetOrientation() );
m_currentPad->SetOrientation( m_padMaster->GetOrientation() * isign
+ footprint->GetOrientation() );
m_currentPad->SetSize( m_padMaster->GetSize() );
@ -935,7 +971,9 @@ void DIALOG_PAD_PROPERTIES::PadPropertiesAccept( wxCommandEvent& event )
}
if( m_isFlipped )
{
m_currentPad->SetLayerSet( FlipLayerMask( m_currentPad->GetLayerSet() ) );
}
m_currentPad->SetPadName( m_padMaster->GetPadName() );
@ -967,8 +1005,9 @@ void DIALOG_PAD_PROPERTIES::PadPropertiesAccept( wxCommandEvent& event )
m_currentPad->SetZoneConnection( m_padMaster->GetZoneConnection() );
m_currentPad->SetThermalWidth( m_padMaster->GetThermalWidth() );
m_currentPad->SetThermalGap( m_padMaster->GetThermalGap() );
m_currentPad->SetRoundRectRadiusRatio( m_padMaster->GetRoundRectRadiusRatio() );
module->CalculateBoundingBox();
footprint->CalculateBoundingBox();
m_parent->SetMsgPanel( m_currentPad );
// redraw the area where the pad was
@ -991,6 +1030,7 @@ bool DIALOG_PAD_PROPERTIES::transferDataToPad( D_PAD* aPad )
aPad->SetAttribute( code_type[m_PadType->GetSelection()] );
aPad->SetShape( code_shape[m_PadShape->GetSelection()] );
// Read pad clearances values:
aPad->SetLocalClearance( ValueFromTextCtrl( *m_NetClearanceValueCtrl ) );
aPad->SetLocalSolderMaskMargin( ValueFromTextCtrl( *m_SolderMaskMarginCtrl ) );
@ -1055,6 +1095,7 @@ bool DIALOG_PAD_PROPERTIES::transferDataToPad( D_PAD* aPad )
// Read pad shape size:
x = ValueFromTextCtrl( *m_ShapeSize_X_Ctrl );
y = ValueFromTextCtrl( *m_ShapeSize_Y_Ctrl );
if( aPad->GetShape() == PAD_SHAPE_CIRCLE )
y = x;
@ -1148,6 +1189,10 @@ bool DIALOG_PAD_PROPERTIES::transferDataToPad( D_PAD* aPad )
case PAD_SHAPE_TRAPEZOID:
break;
case PAD_SHAPE_ROUNDRECT:
aPad->SetDelta( wxSize( 0, 0 ) );
break;
default:
;
}
@ -1164,7 +1209,7 @@ bool DIALOG_PAD_PROPERTIES::transferDataToPad( D_PAD* aPad )
// PAD_ATTRIB_CONN has just a default non technical layers that differs from SMD
// and are intended to be used in virtual edge board connectors
// However we can accept a non null offset,
// mainly to allow complex pads build from a set of from basic pad shapes
// mainly to allow complex pads build from a set of basic pad shapes
aPad->SetDrillSize( wxSize( 0, 0 ) );
break;
@ -1181,6 +1226,15 @@ bool DIALOG_PAD_PROPERTIES::transferDataToPad( D_PAD* aPad )
break;
}
if( aPad->GetShape() == PAD_SHAPE_ROUNDRECT )
{
wxString value = m_tcCornerSizeRatio->GetValue();
double rrRadiusRatioPercent;
if( value.ToDouble( &rrRadiusRatioPercent ) )
aPad->SetRoundRectRadiusRatio( rrRadiusRatioPercent / 100.0 );
}
LSET padLayerMask;
switch( m_rbCopperLayersSel->GetSelection() )
@ -1245,12 +1299,10 @@ void DIALOG_PAD_PROPERTIES::OnValuesChanged( wxCommandEvent& event )
if( m_canUpdate )
{
transferDataToPad( m_dummyPad );
// If the pad size has changed, update the displayed values
// for rounded rect pads
updateRoundRectCornerValues();
redraw();
}
}
void DIALOG_PAD_PROPERTIES::OnCancelButtonClick( wxCommandEvent& event )
{
EndModal( wxID_CANCEL );
}

View File

@ -0,0 +1,123 @@
/**
* @file dialog_pad_properties.cpp
* @brief dialog pad properties editor.
*/
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2016 Jean-Pierre Charras, jp.charras at wanadoo.fr
* Copyright (C) 2013 Dick Hollenbeck, dick@softplc.com
* Copyright (C) 2008-2013 Wayne Stambaugh <stambaughw@verizon.net>
* Copyright (C) 1992-2016 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
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
#ifndef _DIALOG_PAD_PROPERTIES_H_
#define _DIALOG_PAD_PROPERTIES_H_
#include <fctsys.h>
#include <common.h>
#include <class_drawpanel.h>
#include <pcbnew.h>
#include <wxBasePcbFrame.h>
#include <pcbcommon.h>
#include <base_units.h>
#include <class_board.h>
#include <class_module.h>
#include <origin_viewitem.h>
#include <dialog_pad_properties_base.h>
/**
* class DIALOG_PAD_PROPERTIES, derived from DIALOG_PAD_PROPERTIES_BASE,
* created by wxFormBuilder
*/
class DIALOG_PAD_PROPERTIES : public DIALOG_PAD_PROPERTIES_BASE
{
public:
DIALOG_PAD_PROPERTIES( PCB_BASE_FRAME* aParent, D_PAD* aPad );
~DIALOG_PAD_PROPERTIES()
{
delete m_dummyPad;
delete m_axisOrigin;
}
private:
PCB_BASE_FRAME* m_parent;
KIGFX::ORIGIN_VIEWITEM* m_axisOrigin;
D_PAD* m_currentPad; // pad currently being edited
D_PAD* m_dummyPad; // a working copy used to show changes
D_PAD* m_padMaster; // The pad used to create new pads in board or
// footprint editor
BOARD* m_board; // the main board: this is the board handled by
// the PCB editor, if running or the dummy
// board used by the footprint editor
// (could happen when the Footprint editor will be run
// alone, outside the board editor
bool m_isFlipped; // true if the parent footprint (therefore pads) is flipped (mirrored)
// in this case, some Y coordinates values must be negated
bool m_canUpdate;
bool m_canEditNetName; // true only if the caller is the board editor
private:
void initValues();
bool padValuesOK(); ///< test if all values are acceptable for the pad
void redraw();
void updateRoundRectCornerValues();
/**
* Function setPadLayersList
* updates the CheckBox states in pad layers list,
* @param layer_mask = pad layer mask (ORed layers bit mask)
*/
void setPadLayersList( LSET layer_mask );
/// Copy values from dialog field to aPad's members
bool transferDataToPad( D_PAD* aPad );
// event handlers:
void OnResize( wxSizeEvent& event );
void OnPadShapeSelection( wxCommandEvent& event );
void OnDrillShapeSelected( wxCommandEvent& event );
void PadOrientEvent( wxCommandEvent& event );
void PadTypeSelected( wxCommandEvent& event );
void OnSetLayers( wxCommandEvent& event );
void OnPaintShowPanel( wxPaintEvent& event );
// Called when corner setup value is changed for rounded rect pads
void onCornerSizePercentChange( wxCommandEvent& event );
/// Called when a dimension has changed.
/// Update the graphical pad shown in the panel.
void OnValuesChanged( wxCommandEvent& event );
/// Updates the different parameters for the component being edited.
/// Fired from the OK button click.
void PadPropertiesAccept( wxCommandEvent& event );
};
#endif // #ifndef _DIALOG_PAD_PROPERTIES_H_

View File

@ -1,5 +1,5 @@
///////////////////////////////////////////////////////////////////////////
// C++ code generated with wxFormBuilder (version Jun 5 2014)
// C++ code generated with wxFormBuilder (version Mar 28 2016)
// http://www.wxformbuilder.org/
//
// PLEASE DO "NOT" EDIT THIS FILE!
@ -40,7 +40,6 @@ DIALOG_PAD_PROPERTIES_BASE::DIALOG_PAD_PROPERTIES_BASE( wxWindow* parent, wxWind
fgSizerPadType->Add( m_PadNumText, 0, wxALIGN_CENTER_VERTICAL|wxLEFT|wxTOP, 5 );
m_PadNumCtrl = new wxTextCtrl( m_panelGeneral, wxID_PADNUMCTRL, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
m_PadNumCtrl->SetMaxLength( 0 );
fgSizerPadType->Add( m_PadNumCtrl, 0, wxEXPAND|wxLEFT|wxRIGHT|wxTOP, 5 );
m_PadNameText = new wxStaticText( m_panelGeneral, wxID_ANY, _("Net name:"), wxDefaultPosition, wxDefaultSize, 0 );
@ -48,7 +47,6 @@ DIALOG_PAD_PROPERTIES_BASE::DIALOG_PAD_PROPERTIES_BASE( wxWindow* parent, wxWind
fgSizerPadType->Add( m_PadNameText, 0, wxALIGN_CENTER_VERTICAL|wxLEFT|wxRIGHT|wxTOP, 5 );
m_PadNetNameCtrl = new wxTextCtrl( m_panelGeneral, wxID_PADNETNAMECTRL, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
m_PadNetNameCtrl->SetMaxLength( 0 );
fgSizerPadType->Add( m_PadNetNameCtrl, 0, wxEXPAND|wxLEFT|wxRIGHT|wxTOP, 5 );
m_staticText44 = new wxStaticText( m_panelGeneral, wxID_ANY, _("Pad type:"), wxDefaultPosition, wxDefaultSize, 0 );
@ -65,7 +63,7 @@ DIALOG_PAD_PROPERTIES_BASE::DIALOG_PAD_PROPERTIES_BASE( wxWindow* parent, wxWind
m_staticText45->Wrap( -1 );
fgSizerPadType->Add( m_staticText45, 0, wxALIGN_CENTER_VERTICAL|wxBOTTOM|wxLEFT|wxTOP, 5 );
wxString m_PadShapeChoices[] = { _("Circular"), _("Oval"), _("Rectangular"), _("Trapezoidal") };
wxString m_PadShapeChoices[] = { _("Circular"), _("Oval"), _("Rectangular"), _("Trapezoidal"), _("Rounded Rectangle") };
int m_PadShapeNChoices = sizeof( m_PadShapeChoices ) / sizeof( wxString );
m_PadShape = new wxChoice( m_panelGeneral, wxID_ANY, wxDefaultPosition, wxDefaultSize, m_PadShapeNChoices, m_PadShapeChoices, 0 );
m_PadShape->SetSelection( 0 );
@ -75,7 +73,7 @@ DIALOG_PAD_PROPERTIES_BASE::DIALOG_PAD_PROPERTIES_BASE( wxWindow* parent, wxWind
m_LeftBoxSizer->Add( fgSizerPadType, 0, wxEXPAND|wxTOP|wxRIGHT|wxLEFT, 5 );
wxFlexGridSizer* fgSizerShapeType;
fgSizerShapeType = new wxFlexGridSizer( 11, 3, 0, 0 );
fgSizerShapeType = new wxFlexGridSizer( 0, 3, 0, 0 );
fgSizerShapeType->AddGrowableCol( 1 );
fgSizerShapeType->SetFlexibleDirection( wxBOTH );
fgSizerShapeType->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED );
@ -85,7 +83,6 @@ DIALOG_PAD_PROPERTIES_BASE::DIALOG_PAD_PROPERTIES_BASE( wxWindow* parent, wxWind
fgSizerShapeType->Add( m_staticText4, 0, wxALIGN_CENTER_VERTICAL|wxLEFT|wxTOP, 5 );
m_PadPosition_X_Ctrl = new wxTextCtrl( m_panelGeneral, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
m_PadPosition_X_Ctrl->SetMaxLength( 0 );
fgSizerShapeType->Add( m_PadPosition_X_Ctrl, 0, wxEXPAND|wxLEFT|wxTOP, 5 );
m_PadPosX_Unit = new wxStaticText( m_panelGeneral, wxID_ANY, _("Inch"), wxDefaultPosition, wxDefaultSize, 0 );
@ -97,7 +94,6 @@ DIALOG_PAD_PROPERTIES_BASE::DIALOG_PAD_PROPERTIES_BASE( wxWindow* parent, wxWind
fgSizerShapeType->Add( m_staticText41, 0, wxALIGN_CENTER_VERTICAL|wxLEFT|wxTOP, 5 );
m_PadPosition_Y_Ctrl = new wxTextCtrl( m_panelGeneral, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
m_PadPosition_Y_Ctrl->SetMaxLength( 0 );
fgSizerShapeType->Add( m_PadPosition_Y_Ctrl, 0, wxEXPAND|wxLEFT|wxTOP, 5 );
m_PadPosY_Unit = new wxStaticText( m_panelGeneral, wxID_ANY, _("Inch"), wxDefaultPosition, wxDefaultSize, 0 );
@ -109,7 +105,6 @@ DIALOG_PAD_PROPERTIES_BASE::DIALOG_PAD_PROPERTIES_BASE( wxWindow* parent, wxWind
fgSizerShapeType->Add( m_staticText12, 0, wxALIGN_CENTER_VERTICAL|wxLEFT|wxTOP, 5 );
m_ShapeSize_X_Ctrl = new wxTextCtrl( m_panelGeneral, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
m_ShapeSize_X_Ctrl->SetMaxLength( 0 );
fgSizerShapeType->Add( m_ShapeSize_X_Ctrl, 0, wxEXPAND|wxLEFT|wxTOP, 5 );
m_PadShapeSizeX_Unit = new wxStaticText( m_panelGeneral, wxID_ANY, _("Inch"), wxDefaultPosition, wxDefaultSize, 0 );
@ -121,16 +116,15 @@ DIALOG_PAD_PROPERTIES_BASE::DIALOG_PAD_PROPERTIES_BASE( wxWindow* parent, wxWind
fgSizerShapeType->Add( m_staticText15, 0, wxALIGN_CENTER_VERTICAL|wxLEFT|wxTOP, 5 );
m_ShapeSize_Y_Ctrl = new wxTextCtrl( m_panelGeneral, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
m_ShapeSize_Y_Ctrl->SetMaxLength( 0 );
fgSizerShapeType->Add( m_ShapeSize_Y_Ctrl, 0, wxEXPAND|wxLEFT|wxTOP, 5 );
m_PadShapeSizeY_Unit = new wxStaticText( m_panelGeneral, wxID_ANY, _("Inch"), wxDefaultPosition, wxDefaultSize, 0 );
m_PadShapeSizeY_Unit->Wrap( -1 );
fgSizerShapeType->Add( m_PadShapeSizeY_Unit, 0, wxALIGN_CENTER_VERTICAL|wxLEFT|wxRIGHT|wxTOP, 5 );
m_staticText48 = new wxStaticText( m_panelGeneral, wxID_ANY, _("Orientation:"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticText48->Wrap( -1 );
fgSizerShapeType->Add( m_staticText48, 0, wxALIGN_CENTER_VERTICAL|wxLEFT|wxTOP, 5 );
m_PadOrientText = new wxStaticText( m_panelGeneral, wxID_ANY, _("Orientation:"), wxDefaultPosition, wxDefaultSize, 0 );
m_PadOrientText->Wrap( -1 );
fgSizerShapeType->Add( m_PadOrientText, 0, wxALIGN_CENTER_VERTICAL|wxLEFT|wxTOP, 5 );
wxString m_PadOrientChoices[] = { _("0"), _("90"), _("-90"), _("180"), _("Custom") };
int m_PadOrientNChoices = sizeof( m_PadOrientChoices ) / sizeof( wxString );
@ -142,12 +136,10 @@ DIALOG_PAD_PROPERTIES_BASE::DIALOG_PAD_PROPERTIES_BASE( wxWindow* parent, wxWind
m_staticText491->Wrap( -1 );
fgSizerShapeType->Add( m_staticText491, 0, wxALIGN_CENTER_VERTICAL|wxLEFT|wxRIGHT|wxTOP, 5 );
m_PadOrientText = new wxStaticText( m_panelGeneral, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
m_PadOrientText->Wrap( -1 );
fgSizerShapeType->Add( m_PadOrientText, 0, wxALIGN_CENTER_VERTICAL|wxLEFT|wxTOP, 5 );
fgSizerShapeType->Add( 0, 0, 1, wxEXPAND, 5 );
m_PadOrientCtrl = new wxTextCtrl( m_panelGeneral, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
m_PadOrientCtrl->SetMaxLength( 0 );
fgSizerShapeType->Add( m_PadOrientCtrl, 0, wxEXPAND|wxLEFT|wxTOP, 5 );
m_customOrientUnits = new wxStaticText( m_panelGeneral, wxID_ANY, _("0.1 deg"), wxDefaultPosition, wxDefaultSize, 0 );
@ -159,7 +151,6 @@ DIALOG_PAD_PROPERTIES_BASE::DIALOG_PAD_PROPERTIES_BASE( wxWindow* parent, wxWind
fgSizerShapeType->Add( m_staticText17, 0, wxALIGN_CENTER_VERTICAL|wxLEFT|wxTOP, 5 );
m_ShapeOffset_X_Ctrl = new wxTextCtrl( m_panelGeneral, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
m_ShapeOffset_X_Ctrl->SetMaxLength( 0 );
fgSizerShapeType->Add( m_ShapeOffset_X_Ctrl, 0, wxEXPAND|wxLEFT|wxTOP, 5 );
m_PadShapeOffsetX_Unit = new wxStaticText( m_panelGeneral, wxID_ANY, _("Inch"), wxDefaultPosition, wxDefaultSize, 0 );
@ -171,7 +162,6 @@ DIALOG_PAD_PROPERTIES_BASE::DIALOG_PAD_PROPERTIES_BASE( wxWindow* parent, wxWind
fgSizerShapeType->Add( m_staticText19, 0, wxALIGN_CENTER_VERTICAL|wxLEFT|wxTOP, 5 );
m_ShapeOffset_Y_Ctrl = new wxTextCtrl( m_panelGeneral, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
m_ShapeOffset_Y_Ctrl->SetMaxLength( 0 );
fgSizerShapeType->Add( m_ShapeOffset_Y_Ctrl, 0, wxEXPAND|wxLEFT|wxTOP, 5 );
m_PadShapeOffsetY_Unit = new wxStaticText( m_panelGeneral, wxID_ANY, _("Inch"), wxDefaultPosition, wxDefaultSize, 0 );
@ -185,19 +175,26 @@ DIALOG_PAD_PROPERTIES_BASE::DIALOG_PAD_PROPERTIES_BASE( wxWindow* parent, wxWind
fgSizerShapeType->Add( m_staticText38, 0, wxALIGN_CENTER_VERTICAL|wxLEFT|wxTOP, 5 );
m_LengthPadToDieCtrl = new wxTextCtrl( m_panelGeneral, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
m_LengthPadToDieCtrl->SetMaxLength( 0 );
fgSizerShapeType->Add( m_LengthPadToDieCtrl, 0, wxEXPAND|wxLEFT|wxTOP, 5 );
m_PadLengthDie_Unit = new wxStaticText( m_panelGeneral, wxID_ANY, _("Inch"), wxDefaultPosition, wxDefaultSize, 0 );
m_PadLengthDie_Unit->Wrap( -1 );
fgSizerShapeType->Add( m_PadLengthDie_Unit, 0, wxALIGN_CENTER_VERTICAL|wxLEFT|wxRIGHT|wxTOP, 5 );
m_staticline4 = new wxStaticLine( m_panelGeneral, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_HORIZONTAL );
fgSizerShapeType->Add( m_staticline4, 0, wxEXPAND | wxALL, 5 );
m_staticline5 = new wxStaticLine( m_panelGeneral, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_HORIZONTAL );
fgSizerShapeType->Add( m_staticline5, 0, wxEXPAND | wxALL, 5 );
m_staticline6 = new wxStaticLine( m_panelGeneral, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_HORIZONTAL );
fgSizerShapeType->Add( m_staticline6, 0, wxEXPAND | wxALL, 5 );
m_staticText21 = new wxStaticText( m_panelGeneral, wxID_ANY, _("Trapezoid delta:"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticText21->Wrap( -1 );
fgSizerShapeType->Add( m_staticText21, 0, wxALIGN_CENTER_VERTICAL|wxTOP|wxLEFT, 5 );
m_ShapeDelta_Ctrl = new wxTextCtrl( m_panelGeneral, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
m_ShapeDelta_Ctrl->SetMaxLength( 0 );
fgSizerShapeType->Add( m_ShapeDelta_Ctrl, 0, wxEXPAND|wxLEFT|wxTOP, 5 );
m_PadShapeDelta_Unit = new wxStaticText( m_panelGeneral, wxID_ANY, _("Inch"), wxDefaultPosition, wxDefaultSize, 0 );
@ -208,50 +205,56 @@ DIALOG_PAD_PROPERTIES_BASE::DIALOG_PAD_PROPERTIES_BASE( wxWindow* parent, wxWind
m_staticText23->Wrap( -1 );
fgSizerShapeType->Add( m_staticText23, 0, wxALIGN_CENTER_VERTICAL|wxBOTTOM|wxLEFT|wxTOP, 5 );
wxString m_trapDeltaDirChoiceChoices[] = { _("Horiz."), _("Vert.") };
wxString m_trapDeltaDirChoiceChoices[] = { _("Horizotal"), _("Vertical") };
int m_trapDeltaDirChoiceNChoices = sizeof( m_trapDeltaDirChoiceChoices ) / sizeof( wxString );
m_trapDeltaDirChoice = new wxChoice( m_panelGeneral, wxID_ANY, wxDefaultPosition, wxDefaultSize, m_trapDeltaDirChoiceNChoices, m_trapDeltaDirChoiceChoices, 0 );
m_trapDeltaDirChoice->SetSelection( 0 );
fgSizerShapeType->Add( m_trapDeltaDirChoice, 0, wxBOTTOM|wxEXPAND|wxLEFT|wxTOP, 5 );
m_staticText521 = new wxStaticText( m_panelGeneral, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
m_staticText521->Wrap( -1 );
fgSizerShapeType->Add( m_staticText521, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5 );
fgSizerShapeType->Add( 0, 0, 1, wxEXPAND, 5 );
m_staticline7 = new wxStaticLine( m_panelGeneral, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_HORIZONTAL );
fgSizerShapeType->Add( m_staticline7, 0, wxEXPAND | wxALL, 5 );
m_staticline8 = new wxStaticLine( m_panelGeneral, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_HORIZONTAL );
fgSizerShapeType->Add( m_staticline8, 0, wxEXPAND | wxALL, 5 );
m_staticline9 = new wxStaticLine( m_panelGeneral, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_HORIZONTAL );
fgSizerShapeType->Add( m_staticline9, 0, wxEXPAND | wxALL, 5 );
m_staticTextCornerSizeRatio = new wxStaticText( m_panelGeneral, wxID_ANY, _("Corner size ( % of width):"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticTextCornerSizeRatio->Wrap( -1 );
m_staticTextCornerSizeRatio->SetToolTip( _("Corner radius in % of the pad width.\nThe width is the smaller value between size X and size Y\nThe max value is 50%") );
fgSizerShapeType->Add( m_staticTextCornerSizeRatio, 0, wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT, 5 );
m_tcCornerSizeRatio = new wxTextCtrl( m_panelGeneral, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
fgSizerShapeType->Add( m_tcCornerSizeRatio, 0, wxEXPAND|wxALIGN_CENTER_VERTICAL|wxTOP|wxBOTTOM|wxLEFT, 5 );
m_staticTextCornerSizeRatioUnit = new wxStaticText( m_panelGeneral, wxID_ANY, _("%"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticTextCornerSizeRatioUnit->Wrap( -1 );
fgSizerShapeType->Add( m_staticTextCornerSizeRatioUnit, 0, wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT, 5 );
m_staticTextCornerRadius = new wxStaticText( m_panelGeneral, wxID_ANY, _("Corner radius:"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticTextCornerRadius->Wrap( -1 );
m_staticTextCornerRadius->SetToolTip( _("Corner radius.\nCan be no more than half pad width.\nThe width is the smaller value between size X and size Y\nNote: IPC norm gives a max value = 0.25mm") );
fgSizerShapeType->Add( m_staticTextCornerRadius, 0, wxALL, 5 );
m_staticTextCornerRadiusValue = new wxStaticText( m_panelGeneral, wxID_ANY, _("dummy"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticTextCornerRadiusValue->Wrap( -1 );
m_staticTextCornerRadiusValue->SetToolTip( _("Corner radius.\nCan be no more than half pad width.\nThe width is the smaller value between size X and size Y\nNote: IPC norm gives a max value = 0.25mm") );
fgSizerShapeType->Add( m_staticTextCornerRadiusValue, 0, wxALL, 5 );
m_staticTextCornerSizeUnit = new wxStaticText( m_panelGeneral, wxID_ANY, _("unit"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticTextCornerSizeUnit->Wrap( -1 );
fgSizerShapeType->Add( m_staticTextCornerSizeUnit, 0, wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT, 5 );
m_LeftBoxSizer->Add( fgSizerShapeType, 0, wxBOTTOM|wxRIGHT|wxLEFT|wxEXPAND, 5 );
wxStaticBoxSizer* sbSizeModuleInfo;
sbSizeModuleInfo = new wxStaticBoxSizer( new wxStaticBox( m_panelGeneral, wxID_ANY, _("Parent footprint orientation") ), wxVERTICAL );
wxFlexGridSizer* fgSizer4;
fgSizer4 = new wxFlexGridSizer( 2, 2, 0, 0 );
fgSizer4->AddGrowableCol( 1 );
fgSizer4->SetFlexibleDirection( wxBOTH );
fgSizer4->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED );
m_staticTitleModuleRot = new wxStaticText( m_panelGeneral, wxID_ANY, _("Rotation:"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticTitleModuleRot->Wrap( -1 );
fgSizer4->Add( m_staticTitleModuleRot, 0, wxALIGN_CENTER_VERTICAL|wxLEFT|wxTOP, 5 );
m_staticModuleRotValue = new wxStaticText( m_panelGeneral, wxID_ANY, _("0"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticModuleRotValue->Wrap( -1 );
fgSizer4->Add( m_staticModuleRotValue, 0, wxEXPAND|wxLEFT|wxRIGHT|wxTOP, 5 );
m_staticTitleModuleSide = new wxStaticText( m_panelGeneral, wxID_ANY, _("Board side:"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticTitleModuleSide->Wrap( -1 );
fgSizer4->Add( m_staticTitleModuleSide, 0, wxALIGN_CENTER_VERTICAL|wxBOTTOM|wxLEFT|wxTOP, 5 );
m_staticModuleSideValue = new wxStaticText( m_panelGeneral, wxID_ANY, _("Front side"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticModuleSideValue->Wrap( -1 );
fgSizer4->Add( m_staticModuleSideValue, 0, wxALL|wxEXPAND, 5 );
sbSizeModuleInfo->Add( fgSizer4, 0, 0, 5 );
m_LeftBoxSizer->Add( sbSizeModuleInfo, 0, wxBOTTOM|wxRIGHT|wxLEFT|wxEXPAND, 5 );
bGeneralSizer->Add( m_LeftBoxSizer, 3, wxALL|wxEXPAND, 5 );
@ -267,41 +270,39 @@ DIALOG_PAD_PROPERTIES_BASE::DIALOG_PAD_PROPERTIES_BASE( wxWindow* parent, wxWind
fgSizerGeometry->SetFlexibleDirection( wxBOTH );
fgSizerGeometry->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED );
m_staticText47 = new wxStaticText( m_panelGeneral, wxID_ANY, _("Shape:"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticText47 = new wxStaticText( sbSizer2->GetStaticBox(), wxID_ANY, _("Shape:"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticText47->Wrap( -1 );
fgSizerGeometry->Add( m_staticText47, 0, wxALIGN_CENTER_VERTICAL|wxLEFT|wxTOP, 5 );
wxString m_DrillShapeCtrlChoices[] = { _("Circular hole"), _("Oval hole") };
int m_DrillShapeCtrlNChoices = sizeof( m_DrillShapeCtrlChoices ) / sizeof( wxString );
m_DrillShapeCtrl = new wxChoice( m_panelGeneral, wxID_ANY, wxDefaultPosition, wxDefaultSize, m_DrillShapeCtrlNChoices, m_DrillShapeCtrlChoices, 0 );
m_DrillShapeCtrl = new wxChoice( sbSizer2->GetStaticBox(), wxID_ANY, wxDefaultPosition, wxDefaultSize, m_DrillShapeCtrlNChoices, m_DrillShapeCtrlChoices, 0 );
m_DrillShapeCtrl->SetSelection( 0 );
fgSizerGeometry->Add( m_DrillShapeCtrl, 0, wxEXPAND|wxLEFT|wxTOP, 5 );
m_staticText51 = new wxStaticText( m_panelGeneral, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
m_staticText51 = new wxStaticText( sbSizer2->GetStaticBox(), wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
m_staticText51->Wrap( -1 );
fgSizerGeometry->Add( m_staticText51, 0, wxALIGN_CENTER_VERTICAL|wxLEFT|wxRIGHT|wxTOP, 5 );
m_textPadDrillX = new wxStaticText( m_panelGeneral, wxID_ANY, _("Size X:"), wxDefaultPosition, wxDefaultSize, 0 );
m_textPadDrillX = new wxStaticText( sbSizer2->GetStaticBox(), wxID_ANY, _("Size X:"), wxDefaultPosition, wxDefaultSize, 0 );
m_textPadDrillX->Wrap( -1 );
fgSizerGeometry->Add( m_textPadDrillX, 0, wxALIGN_CENTER_VERTICAL|wxLEFT|wxTOP, 5 );
m_PadDrill_X_Ctrl = new wxTextCtrl( m_panelGeneral, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
m_PadDrill_X_Ctrl->SetMaxLength( 0 );
m_PadDrill_X_Ctrl = new wxTextCtrl( sbSizer2->GetStaticBox(), wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
fgSizerGeometry->Add( m_PadDrill_X_Ctrl, 0, wxEXPAND|wxLEFT|wxTOP, 5 );
m_PadDrill_X_Unit = new wxStaticText( m_panelGeneral, wxID_ANY, _("Inch"), wxDefaultPosition, wxDefaultSize, 0 );
m_PadDrill_X_Unit = new wxStaticText( sbSizer2->GetStaticBox(), wxID_ANY, _("Inch"), wxDefaultPosition, wxDefaultSize, 0 );
m_PadDrill_X_Unit->Wrap( -1 );
fgSizerGeometry->Add( m_PadDrill_X_Unit, 0, wxALIGN_CENTER_VERTICAL|wxLEFT|wxRIGHT|wxTOP, 5 );
m_textPadDrillY = new wxStaticText( m_panelGeneral, wxID_ANY, _("Size Y:"), wxDefaultPosition, wxDefaultSize, 0 );
m_textPadDrillY = new wxStaticText( sbSizer2->GetStaticBox(), wxID_ANY, _("Size Y:"), wxDefaultPosition, wxDefaultSize, 0 );
m_textPadDrillY->Wrap( -1 );
fgSizerGeometry->Add( m_textPadDrillY, 0, wxALIGN_CENTER_VERTICAL|wxBOTTOM|wxLEFT|wxTOP, 5 );
m_PadDrill_Y_Ctrl = new wxTextCtrl( m_panelGeneral, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
m_PadDrill_Y_Ctrl->SetMaxLength( 0 );
m_PadDrill_Y_Ctrl = new wxTextCtrl( sbSizer2->GetStaticBox(), wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
fgSizerGeometry->Add( m_PadDrill_Y_Ctrl, 0, wxBOTTOM|wxEXPAND|wxLEFT|wxTOP, 5 );
m_PadDrill_Y_Unit = new wxStaticText( m_panelGeneral, wxID_ANY, _("Inch"), wxDefaultPosition, wxDefaultSize, 0 );
m_PadDrill_Y_Unit = new wxStaticText( sbSizer2->GetStaticBox(), wxID_ANY, _("Inch"), wxDefaultPosition, wxDefaultSize, 0 );
m_PadDrill_Y_Unit->Wrap( -1 );
fgSizerGeometry->Add( m_PadDrill_Y_Unit, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5 );
@ -317,13 +318,13 @@ DIALOG_PAD_PROPERTIES_BASE::DIALOG_PAD_PROPERTIES_BASE( wxWindow* parent, wxWind
wxBoxSizer* bSizer11;
bSizer11 = new wxBoxSizer( wxHORIZONTAL );
m_staticText511 = new wxStaticText( m_panelGeneral, wxID_ANY, _("Copper:"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticText511 = new wxStaticText( m_LayersSizer->GetStaticBox(), wxID_ANY, _("Copper:"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticText511->Wrap( -1 );
bSizer11->Add( m_staticText511, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
wxString m_rbCopperLayersSelChoices[] = { _("Front layer"), _("Back layer"), _("All copper layers"), _("None") };
int m_rbCopperLayersSelNChoices = sizeof( m_rbCopperLayersSelChoices ) / sizeof( wxString );
m_rbCopperLayersSel = new wxChoice( m_panelGeneral, wxID_ANY, wxDefaultPosition, wxDefaultSize, m_rbCopperLayersSelNChoices, m_rbCopperLayersSelChoices, 0 );
m_rbCopperLayersSel = new wxChoice( m_LayersSizer->GetStaticBox(), wxID_ANY, wxDefaultPosition, wxDefaultSize, m_rbCopperLayersSelNChoices, m_rbCopperLayersSelChoices, 0 );
m_rbCopperLayersSel->SetSelection( 0 );
bSizer11->Add( m_rbCopperLayersSel, 1, wxALL|wxEXPAND, 5 );
@ -331,39 +332,39 @@ DIALOG_PAD_PROPERTIES_BASE::DIALOG_PAD_PROPERTIES_BASE( wxWindow* parent, wxWind
m_LayersSizer->Add( bSizer11, 0, wxEXPAND, 5 );
wxStaticBoxSizer* sbSizerTechlayers;
sbSizerTechlayers = new wxStaticBoxSizer( new wxStaticBox( m_panelGeneral, wxID_ANY, _("Technical Layers") ), wxVERTICAL );
sbSizerTechlayers = new wxStaticBoxSizer( new wxStaticBox( m_LayersSizer->GetStaticBox(), wxID_ANY, _("Technical Layers") ), wxVERTICAL );
m_PadLayerAdhCmp = new wxCheckBox( m_panelGeneral, wxID_ANY, _("Front adhesive"), wxDefaultPosition, wxDefaultSize, 0 );
m_PadLayerAdhCmp = new wxCheckBox( sbSizerTechlayers->GetStaticBox(), wxID_ANY, _("Front adhesive"), wxDefaultPosition, wxDefaultSize, 0 );
sbSizerTechlayers->Add( m_PadLayerAdhCmp, 0, wxTOP|wxRIGHT|wxLEFT, 5 );
m_PadLayerAdhCu = new wxCheckBox( m_panelGeneral, wxID_ANY, _("Back adhesive"), wxDefaultPosition, wxDefaultSize, 0 );
m_PadLayerAdhCu = new wxCheckBox( sbSizerTechlayers->GetStaticBox(), wxID_ANY, _("Back adhesive"), wxDefaultPosition, wxDefaultSize, 0 );
sbSizerTechlayers->Add( m_PadLayerAdhCu, 0, wxTOP|wxRIGHT|wxLEFT, 5 );
m_PadLayerPateCmp = new wxCheckBox( m_panelGeneral, wxID_ANY, _("Front solder paste"), wxDefaultPosition, wxDefaultSize, 0 );
m_PadLayerPateCmp = new wxCheckBox( sbSizerTechlayers->GetStaticBox(), wxID_ANY, _("Front solder paste"), wxDefaultPosition, wxDefaultSize, 0 );
sbSizerTechlayers->Add( m_PadLayerPateCmp, 0, wxTOP|wxRIGHT|wxLEFT, 5 );
m_PadLayerPateCu = new wxCheckBox( m_panelGeneral, wxID_ANY, _("Back solder paste"), wxDefaultPosition, wxDefaultSize, 0 );
m_PadLayerPateCu = new wxCheckBox( sbSizerTechlayers->GetStaticBox(), wxID_ANY, _("Back solder paste"), wxDefaultPosition, wxDefaultSize, 0 );
sbSizerTechlayers->Add( m_PadLayerPateCu, 0, wxTOP|wxRIGHT|wxLEFT, 5 );
m_PadLayerSilkCmp = new wxCheckBox( m_panelGeneral, wxID_ANY, _("Front silk screen"), wxDefaultPosition, wxDefaultSize, 0 );
m_PadLayerSilkCmp = new wxCheckBox( sbSizerTechlayers->GetStaticBox(), wxID_ANY, _("Front silk screen"), wxDefaultPosition, wxDefaultSize, 0 );
sbSizerTechlayers->Add( m_PadLayerSilkCmp, 0, wxTOP|wxRIGHT|wxLEFT, 5 );
m_PadLayerSilkCu = new wxCheckBox( m_panelGeneral, wxID_ANY, _("Back silk screen"), wxDefaultPosition, wxDefaultSize, 0 );
m_PadLayerSilkCu = new wxCheckBox( sbSizerTechlayers->GetStaticBox(), wxID_ANY, _("Back silk screen"), wxDefaultPosition, wxDefaultSize, 0 );
sbSizerTechlayers->Add( m_PadLayerSilkCu, 0, wxTOP|wxRIGHT|wxLEFT, 5 );
m_PadLayerMaskCmp = new wxCheckBox( m_panelGeneral, wxID_ANY, _("Front solder mask"), wxDefaultPosition, wxDefaultSize, 0 );
m_PadLayerMaskCmp = new wxCheckBox( sbSizerTechlayers->GetStaticBox(), wxID_ANY, _("Front solder mask"), wxDefaultPosition, wxDefaultSize, 0 );
sbSizerTechlayers->Add( m_PadLayerMaskCmp, 0, wxTOP|wxRIGHT|wxLEFT, 5 );
m_PadLayerMaskCu = new wxCheckBox( m_panelGeneral, wxID_ANY, _("Back solder mask"), wxDefaultPosition, wxDefaultSize, 0 );
m_PadLayerMaskCu = new wxCheckBox( sbSizerTechlayers->GetStaticBox(), wxID_ANY, _("Back solder mask"), wxDefaultPosition, wxDefaultSize, 0 );
sbSizerTechlayers->Add( m_PadLayerMaskCu, 0, wxTOP|wxRIGHT|wxLEFT, 5 );
m_PadLayerDraft = new wxCheckBox( m_panelGeneral, wxID_ANY, _("Drafting notes"), wxDefaultPosition, wxDefaultSize, 0 );
m_PadLayerDraft = new wxCheckBox( sbSizerTechlayers->GetStaticBox(), wxID_ANY, _("Drafting notes"), wxDefaultPosition, wxDefaultSize, 0 );
sbSizerTechlayers->Add( m_PadLayerDraft, 0, wxTOP|wxRIGHT|wxLEFT, 5 );
m_PadLayerECO1 = new wxCheckBox( m_panelGeneral, wxID_ANY, _("E.C.O.1"), wxDefaultPosition, wxDefaultSize, 0 );
m_PadLayerECO1 = new wxCheckBox( sbSizerTechlayers->GetStaticBox(), wxID_ANY, _("E.C.O.1"), wxDefaultPosition, wxDefaultSize, 0 );
sbSizerTechlayers->Add( m_PadLayerECO1, 0, wxTOP|wxRIGHT|wxLEFT, 5 );
m_PadLayerECO2 = new wxCheckBox( m_panelGeneral, wxID_ANY, _("E.C.O.2"), wxDefaultPosition, wxDefaultSize, 0 );
m_PadLayerECO2 = new wxCheckBox( sbSizerTechlayers->GetStaticBox(), wxID_ANY, _("E.C.O.2"), wxDefaultPosition, wxDefaultSize, 0 );
sbSizerTechlayers->Add( m_PadLayerECO2, 0, wxALL, 5 );
@ -372,6 +373,37 @@ DIALOG_PAD_PROPERTIES_BASE::DIALOG_PAD_PROPERTIES_BASE( wxWindow* parent, wxWind
bSizer10->Add( m_LayersSizer, 0, wxALL|wxEXPAND, 5 );
wxStaticBoxSizer* sbSizeModuleInfo;
sbSizeModuleInfo = new wxStaticBoxSizer( new wxStaticBox( m_panelGeneral, wxID_ANY, _("Parent footprint orientation") ), wxVERTICAL );
wxFlexGridSizer* fgSizer4;
fgSizer4 = new wxFlexGridSizer( 2, 2, 0, 0 );
fgSizer4->AddGrowableCol( 1 );
fgSizer4->SetFlexibleDirection( wxBOTH );
fgSizer4->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED );
m_staticTitleModuleRot = new wxStaticText( sbSizeModuleInfo->GetStaticBox(), wxID_ANY, _("Rotation:"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticTitleModuleRot->Wrap( -1 );
fgSizer4->Add( m_staticTitleModuleRot, 0, wxALIGN_CENTER_VERTICAL|wxLEFT|wxTOP, 5 );
m_staticModuleRotValue = new wxStaticText( sbSizeModuleInfo->GetStaticBox(), wxID_ANY, _("0"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticModuleRotValue->Wrap( -1 );
fgSizer4->Add( m_staticModuleRotValue, 0, wxEXPAND|wxLEFT|wxRIGHT|wxTOP, 5 );
m_staticTitleModuleSide = new wxStaticText( sbSizeModuleInfo->GetStaticBox(), wxID_ANY, _("Board side:"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticTitleModuleSide->Wrap( -1 );
fgSizer4->Add( m_staticTitleModuleSide, 0, wxALIGN_CENTER_VERTICAL|wxBOTTOM|wxLEFT|wxTOP, 5 );
m_staticModuleSideValue = new wxStaticText( sbSizeModuleInfo->GetStaticBox(), wxID_ANY, _("Front side"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticModuleSideValue->Wrap( -1 );
fgSizer4->Add( m_staticModuleSideValue, 0, wxALL|wxEXPAND, 5 );
sbSizeModuleInfo->Add( fgSizer4, 0, 0, 5 );
bSizer10->Add( sbSizeModuleInfo, 0, wxBOTTOM|wxRIGHT|wxLEFT|wxEXPAND, 5 );
bGeneralSizer->Add( bSizer10, 2, wxALL|wxEXPAND, 5 );
@ -396,59 +428,55 @@ DIALOG_PAD_PROPERTIES_BASE::DIALOG_PAD_PROPERTIES_BASE( wxWindow* parent, wxWind
fgClearancesGridSizer->SetFlexibleDirection( wxBOTH );
fgClearancesGridSizer->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED );
m_staticTextNetClearance = new wxStaticText( m_localSettingsPanel, wxID_ANY, _("Net pad clearance:"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticTextNetClearance = new wxStaticText( sbClearancesSizer->GetStaticBox(), wxID_ANY, _("Net pad clearance:"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticTextNetClearance->Wrap( -1 );
m_staticTextNetClearance->SetToolTip( _("This is the local net clearance for pad.\nIf 0, the footprint local value or the Netclass value is used") );
fgClearancesGridSizer->Add( m_staticTextNetClearance, 0, wxALIGN_CENTER_VERTICAL|wxLEFT|wxTOP, 5 );
m_NetClearanceValueCtrl = new wxTextCtrl( m_localSettingsPanel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
m_NetClearanceValueCtrl->SetMaxLength( 0 );
m_NetClearanceValueCtrl = new wxTextCtrl( sbClearancesSizer->GetStaticBox(), wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
fgClearancesGridSizer->Add( m_NetClearanceValueCtrl, 0, wxEXPAND|wxLEFT|wxTOP, 5 );
m_NetClearanceUnits = new wxStaticText( m_localSettingsPanel, wxID_ANY, _("Inch"), wxDefaultPosition, wxDefaultSize, 0 );
m_NetClearanceUnits = new wxStaticText( sbClearancesSizer->GetStaticBox(), wxID_ANY, _("Inch"), wxDefaultPosition, wxDefaultSize, 0 );
m_NetClearanceUnits->Wrap( -1 );
fgClearancesGridSizer->Add( m_NetClearanceUnits, 0, wxALIGN_CENTER_VERTICAL|wxLEFT|wxRIGHT|wxTOP, 5 );
m_MaskClearanceTitle = new wxStaticText( m_localSettingsPanel, wxID_ANY, _("Solder mask clearance:"), wxDefaultPosition, wxDefaultSize, 0 );
m_MaskClearanceTitle = new wxStaticText( sbClearancesSizer->GetStaticBox(), wxID_ANY, _("Solder mask clearance:"), wxDefaultPosition, wxDefaultSize, 0 );
m_MaskClearanceTitle->Wrap( -1 );
m_MaskClearanceTitle->SetToolTip( _("This is the local clearance between this pad and the solder mask\nIf 0, the footprint local value or the global value is used") );
fgClearancesGridSizer->Add( m_MaskClearanceTitle, 0, wxALIGN_CENTER_VERTICAL|wxLEFT|wxTOP, 5 );
m_SolderMaskMarginCtrl = new wxTextCtrl( m_localSettingsPanel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
m_SolderMaskMarginCtrl->SetMaxLength( 0 );
m_SolderMaskMarginCtrl = new wxTextCtrl( sbClearancesSizer->GetStaticBox(), wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
fgClearancesGridSizer->Add( m_SolderMaskMarginCtrl, 0, wxEXPAND|wxLEFT|wxTOP, 5 );
m_SolderMaskMarginUnits = new wxStaticText( m_localSettingsPanel, wxID_ANY, _("Inch"), wxDefaultPosition, wxDefaultSize, 0 );
m_SolderMaskMarginUnits = new wxStaticText( sbClearancesSizer->GetStaticBox(), wxID_ANY, _("Inch"), wxDefaultPosition, wxDefaultSize, 0 );
m_SolderMaskMarginUnits->Wrap( -1 );
fgClearancesGridSizer->Add( m_SolderMaskMarginUnits, 0, wxALIGN_CENTER_VERTICAL|wxLEFT|wxRIGHT|wxTOP, 5 );
m_staticTextSolderPaste = new wxStaticText( m_localSettingsPanel, wxID_ANY, _("Solder paste clearance:"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticTextSolderPaste = new wxStaticText( sbClearancesSizer->GetStaticBox(), wxID_ANY, _("Solder paste clearance:"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticTextSolderPaste->Wrap( -1 );
m_staticTextSolderPaste->SetToolTip( _("This is the local clearance between this pad and the solder paste.\nIf 0 the footprint value or the global value is used..\nThe final clearance value is the sum of this value and the clearance value ratio\nA negative value means a smaller mask size than pad size") );
fgClearancesGridSizer->Add( m_staticTextSolderPaste, 0, wxALIGN_CENTER_VERTICAL|wxLEFT|wxTOP, 5 );
m_SolderPasteMarginCtrl = new wxTextCtrl( m_localSettingsPanel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
m_SolderPasteMarginCtrl->SetMaxLength( 0 );
m_SolderPasteMarginCtrl = new wxTextCtrl( sbClearancesSizer->GetStaticBox(), wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
fgClearancesGridSizer->Add( m_SolderPasteMarginCtrl, 0, wxEXPAND|wxLEFT|wxTOP, 5 );
m_SolderPasteMarginUnits = new wxStaticText( m_localSettingsPanel, wxID_ANY, _("Inch"), wxDefaultPosition, wxDefaultSize, 0 );
m_SolderPasteMarginUnits = new wxStaticText( sbClearancesSizer->GetStaticBox(), wxID_ANY, _("Inch"), wxDefaultPosition, wxDefaultSize, 0 );
m_SolderPasteMarginUnits->Wrap( -1 );
fgClearancesGridSizer->Add( m_SolderPasteMarginUnits, 0, wxALIGN_CENTER_VERTICAL|wxLEFT|wxRIGHT|wxTOP, 5 );
m_staticTextRatio = new wxStaticText( m_localSettingsPanel, wxID_ANY, _("Solder paste ratio clearance:"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticTextRatio = new wxStaticText( sbClearancesSizer->GetStaticBox(), wxID_ANY, _("Solder paste ratio clearance:"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticTextRatio->Wrap( -1 );
m_staticTextRatio->SetToolTip( _("This is the local clearance ratio in per cent between this pad and the solder paste.\nA value of 10 means the clearance value is 10 per cent of the pad size\nIf 0 the footprint value or the global value is used..\nThe final clearance value is the sum of this value and the clearance value\nA negative value means a smaller mask size than pad size.") );
fgClearancesGridSizer->Add( m_staticTextRatio, 0, wxALIGN_CENTER_VERTICAL|wxBOTTOM|wxLEFT|wxTOP, 5 );
m_SolderPasteMarginRatioCtrl = new wxTextCtrl( m_localSettingsPanel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
m_SolderPasteMarginRatioCtrl->SetMaxLength( 0 );
m_SolderPasteMarginRatioCtrl = new wxTextCtrl( sbClearancesSizer->GetStaticBox(), wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
fgClearancesGridSizer->Add( m_SolderPasteMarginRatioCtrl, 0, wxBOTTOM|wxEXPAND|wxLEFT|wxTOP, 5 );
m_SolderPasteRatioMarginUnits = new wxStaticText( m_localSettingsPanel, wxID_ANY, _("%"), wxDefaultPosition, wxDefaultSize, 0 );
m_SolderPasteRatioMarginUnits = new wxStaticText( sbClearancesSizer->GetStaticBox(), wxID_ANY, _("%"), wxDefaultPosition, wxDefaultSize, 0 );
m_SolderPasteRatioMarginUnits->Wrap( -1 );
fgClearancesGridSizer->Add( m_SolderPasteRatioMarginUnits, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5 );
@ -467,41 +495,39 @@ DIALOG_PAD_PROPERTIES_BASE::DIALOG_PAD_PROPERTIES_BASE( wxWindow* parent, wxWind
fgSizer41->SetFlexibleDirection( wxBOTH );
fgSizer41->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED );
m_staticText40 = new wxStaticText( m_localSettingsPanel, wxID_ANY, _("Pad connection:"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticText40 = new wxStaticText( sbSizerZonesSettings->GetStaticBox(), wxID_ANY, _("Pad connection:"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticText40->Wrap( -1 );
fgSizer41->Add( m_staticText40, 0, wxALIGN_CENTER_VERTICAL|wxLEFT|wxTOP, 5 );
wxString m_ZoneConnectionChoiceChoices[] = { _("From parent footprint"), _("Solid"), _("Thermal relief"), _("None") };
int m_ZoneConnectionChoiceNChoices = sizeof( m_ZoneConnectionChoiceChoices ) / sizeof( wxString );
m_ZoneConnectionChoice = new wxChoice( m_localSettingsPanel, wxID_ANY, wxDefaultPosition, wxDefaultSize, m_ZoneConnectionChoiceNChoices, m_ZoneConnectionChoiceChoices, 0 );
m_ZoneConnectionChoice = new wxChoice( sbSizerZonesSettings->GetStaticBox(), wxID_ANY, wxDefaultPosition, wxDefaultSize, m_ZoneConnectionChoiceNChoices, m_ZoneConnectionChoiceChoices, 0 );
m_ZoneConnectionChoice->SetSelection( 0 );
fgSizer41->Add( m_ZoneConnectionChoice, 0, wxLEFT|wxTOP|wxEXPAND, 5 );
m_staticText53 = new wxStaticText( m_localSettingsPanel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
m_staticText53 = new wxStaticText( sbSizerZonesSettings->GetStaticBox(), wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
m_staticText53->Wrap( -1 );
fgSizer41->Add( m_staticText53, 0, wxALIGN_CENTER_VERTICAL|wxLEFT|wxRIGHT|wxTOP, 5 );
m_staticText49 = new wxStaticText( m_localSettingsPanel, wxID_ANY, _("Thermal relief width:"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticText49 = new wxStaticText( sbSizerZonesSettings->GetStaticBox(), wxID_ANY, _("Thermal relief width:"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticText49->Wrap( -1 );
fgSizer41->Add( m_staticText49, 0, wxALIGN_CENTER_VERTICAL|wxLEFT|wxTOP, 5 );
m_ThermalWidthCtrl = new wxTextCtrl( m_localSettingsPanel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
m_ThermalWidthCtrl->SetMaxLength( 0 );
m_ThermalWidthCtrl = new wxTextCtrl( sbSizerZonesSettings->GetStaticBox(), wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
fgSizer41->Add( m_ThermalWidthCtrl, 0, wxEXPAND|wxLEFT|wxTOP, 5 );
m_ThermalWidthUnits = new wxStaticText( m_localSettingsPanel, wxID_ANY, _("Inch"), wxDefaultPosition, wxDefaultSize, 0 );
m_ThermalWidthUnits = new wxStaticText( sbSizerZonesSettings->GetStaticBox(), wxID_ANY, _("Inch"), wxDefaultPosition, wxDefaultSize, 0 );
m_ThermalWidthUnits->Wrap( -1 );
fgSizer41->Add( m_ThermalWidthUnits, 0, wxALIGN_CENTER_VERTICAL|wxLEFT|wxRIGHT|wxTOP, 5 );
m_staticText52 = new wxStaticText( m_localSettingsPanel, wxID_ANY, _("Thermal relief gap:"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticText52 = new wxStaticText( sbSizerZonesSettings->GetStaticBox(), wxID_ANY, _("Thermal relief gap:"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticText52->Wrap( -1 );
fgSizer41->Add( m_staticText52, 0, wxALIGN_CENTER_VERTICAL|wxBOTTOM|wxLEFT|wxTOP, 5 );
m_ThermalGapCtrl = new wxTextCtrl( m_localSettingsPanel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
m_ThermalGapCtrl->SetMaxLength( 0 );
m_ThermalGapCtrl = new wxTextCtrl( sbSizerZonesSettings->GetStaticBox(), wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
fgSizer41->Add( m_ThermalGapCtrl, 0, wxBOTTOM|wxEXPAND|wxLEFT|wxTOP, 5 );
m_ThermalGapUnits = new wxStaticText( m_localSettingsPanel, wxID_ANY, _("Inch"), wxDefaultPosition, wxDefaultSize, 0 );
m_ThermalGapUnits = new wxStaticText( sbSizerZonesSettings->GetStaticBox(), wxID_ANY, _("Inch"), wxDefaultPosition, wxDefaultSize, 0 );
m_ThermalGapUnits->Wrap( -1 );
fgSizer41->Add( m_ThermalGapUnits, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5 );
@ -526,7 +552,7 @@ DIALOG_PAD_PROPERTIES_BASE::DIALOG_PAD_PROPERTIES_BASE( wxWindow* parent, wxWind
bSizerPanelClearance->Fit( m_localSettingsPanel );
m_notebook->AddPage( m_localSettingsPanel, _("Local Clearance and Settings"), false );
bSizerUpper->Add( m_notebook, 0, wxALL, 5 );
bSizerUpper->Add( m_notebook, 0, wxALL|wxEXPAND, 5 );
wxBoxSizer* bSizerDisplayPad;
bSizerDisplayPad = new wxBoxSizer( wxVERTICAL );
@ -552,19 +578,18 @@ DIALOG_PAD_PROPERTIES_BASE::DIALOG_PAD_PROPERTIES_BASE( wxWindow* parent, wxWind
m_MainSizer->Add( m_staticTextWarningPadFlipped, 0, wxALL, 5 );
m_sdbSizer1 = new wxStdDialogButtonSizer();
m_sdbSizer1OK = new wxButton( this, wxID_OK );
m_sdbSizer1->AddButton( m_sdbSizer1OK );
m_sdbSizer1Cancel = new wxButton( this, wxID_CANCEL );
m_sdbSizer1->AddButton( m_sdbSizer1Cancel );
m_sdbSizer1->Realize();
m_sdbSizer = new wxStdDialogButtonSizer();
m_sdbSizerOK = new wxButton( this, wxID_OK );
m_sdbSizer->AddButton( m_sdbSizerOK );
m_sdbSizerCancel = new wxButton( this, wxID_CANCEL );
m_sdbSizer->AddButton( m_sdbSizerCancel );
m_sdbSizer->Realize();
m_MainSizer->Add( m_sdbSizer1, 0, wxALIGN_RIGHT|wxBOTTOM|wxRIGHT|wxLEFT, 5 );
m_MainSizer->Add( m_sdbSizer, 0, wxALIGN_RIGHT|wxBOTTOM|wxRIGHT|wxLEFT, 5 );
this->SetSizer( m_MainSizer );
this->Layout();
m_MainSizer->Fit( this );
this->Centre( wxBOTH );
@ -581,6 +606,7 @@ DIALOG_PAD_PROPERTIES_BASE::DIALOG_PAD_PROPERTIES_BASE( wxWindow* parent, wxWind
m_ShapeOffset_Y_Ctrl->Connect( wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( DIALOG_PAD_PROPERTIES_BASE::OnValuesChanged ), NULL, this );
m_ShapeDelta_Ctrl->Connect( wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( DIALOG_PAD_PROPERTIES_BASE::OnValuesChanged ), NULL, this );
m_trapDeltaDirChoice->Connect( wxEVT_COMMAND_CHOICE_SELECTED, wxCommandEventHandler( DIALOG_PAD_PROPERTIES_BASE::OnSetLayers ), NULL, this );
m_tcCornerSizeRatio->Connect( wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( DIALOG_PAD_PROPERTIES_BASE::onCornerSizePercentChange ), NULL, this );
m_DrillShapeCtrl->Connect( wxEVT_COMMAND_CHOICE_SELECTED, wxCommandEventHandler( DIALOG_PAD_PROPERTIES_BASE::OnDrillShapeSelected ), NULL, this );
m_PadDrill_X_Ctrl->Connect( wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( DIALOG_PAD_PROPERTIES_BASE::OnValuesChanged ), NULL, this );
m_PadDrill_Y_Ctrl->Connect( wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( DIALOG_PAD_PROPERTIES_BASE::OnValuesChanged ), NULL, this );
@ -598,8 +624,7 @@ DIALOG_PAD_PROPERTIES_BASE::DIALOG_PAD_PROPERTIES_BASE( wxWindow* parent, wxWind
m_PadLayerECO2->Connect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_PAD_PROPERTIES_BASE::OnSetLayers ), NULL, this );
m_NetClearanceValueCtrl->Connect( wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( DIALOG_PAD_PROPERTIES_BASE::OnValuesChanged ), NULL, this );
m_panelShowPad->Connect( wxEVT_PAINT, wxPaintEventHandler( DIALOG_PAD_PROPERTIES_BASE::OnPaintShowPanel ), NULL, this );
m_sdbSizer1Cancel->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_PAD_PROPERTIES_BASE::OnCancelButtonClick ), NULL, this );
m_sdbSizer1OK->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_PAD_PROPERTIES_BASE::PadPropertiesAccept ), NULL, this );
m_sdbSizerOK->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_PAD_PROPERTIES_BASE::PadPropertiesAccept ), NULL, this );
}
DIALOG_PAD_PROPERTIES_BASE::~DIALOG_PAD_PROPERTIES_BASE()
@ -617,6 +642,7 @@ DIALOG_PAD_PROPERTIES_BASE::~DIALOG_PAD_PROPERTIES_BASE()
m_ShapeOffset_Y_Ctrl->Disconnect( wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( DIALOG_PAD_PROPERTIES_BASE::OnValuesChanged ), NULL, this );
m_ShapeDelta_Ctrl->Disconnect( wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( DIALOG_PAD_PROPERTIES_BASE::OnValuesChanged ), NULL, this );
m_trapDeltaDirChoice->Disconnect( wxEVT_COMMAND_CHOICE_SELECTED, wxCommandEventHandler( DIALOG_PAD_PROPERTIES_BASE::OnSetLayers ), NULL, this );
m_tcCornerSizeRatio->Disconnect( wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( DIALOG_PAD_PROPERTIES_BASE::onCornerSizePercentChange ), NULL, this );
m_DrillShapeCtrl->Disconnect( wxEVT_COMMAND_CHOICE_SELECTED, wxCommandEventHandler( DIALOG_PAD_PROPERTIES_BASE::OnDrillShapeSelected ), NULL, this );
m_PadDrill_X_Ctrl->Disconnect( wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( DIALOG_PAD_PROPERTIES_BASE::OnValuesChanged ), NULL, this );
m_PadDrill_Y_Ctrl->Disconnect( wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( DIALOG_PAD_PROPERTIES_BASE::OnValuesChanged ), NULL, this );
@ -634,7 +660,6 @@ DIALOG_PAD_PROPERTIES_BASE::~DIALOG_PAD_PROPERTIES_BASE()
m_PadLayerECO2->Disconnect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_PAD_PROPERTIES_BASE::OnSetLayers ), NULL, this );
m_NetClearanceValueCtrl->Disconnect( wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( DIALOG_PAD_PROPERTIES_BASE::OnValuesChanged ), NULL, this );
m_panelShowPad->Disconnect( wxEVT_PAINT, wxPaintEventHandler( DIALOG_PAD_PROPERTIES_BASE::OnPaintShowPanel ), NULL, this );
m_sdbSizer1Cancel->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_PAD_PROPERTIES_BASE::OnCancelButtonClick ), NULL, this );
m_sdbSizer1OK->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_PAD_PROPERTIES_BASE::PadPropertiesAccept ), NULL, this );
m_sdbSizerOK->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_PAD_PROPERTIES_BASE::PadPropertiesAccept ), NULL, this );
}

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,5 @@
///////////////////////////////////////////////////////////////////////////
// C++ code generated with wxFormBuilder (version Jun 5 2014)
// C++ code generated with wxFormBuilder (version Mar 28 2016)
// http://www.wxformbuilder.org/
//
// PLEASE DO "NOT" EDIT THIS FILE!
@ -23,6 +23,7 @@ class DIALOG_SHIM;
#include <wx/textctrl.h>
#include <wx/choice.h>
#include <wx/sizer.h>
#include <wx/statline.h>
#include <wx/statbox.h>
#include <wx/checkbox.h>
#include <wx/panel.h>
@ -73,10 +74,9 @@ class DIALOG_PAD_PROPERTIES_BASE : public DIALOG_SHIM
wxStaticText* m_staticText15;
wxTextCtrl* m_ShapeSize_Y_Ctrl;
wxStaticText* m_PadShapeSizeY_Unit;
wxStaticText* m_staticText48;
wxStaticText* m_PadOrientText;
wxChoice* m_PadOrient;
wxStaticText* m_staticText491;
wxStaticText* m_PadOrientText;
wxTextCtrl* m_PadOrientCtrl;
wxStaticText* m_customOrientUnits;
wxStaticText* m_staticText17;
@ -88,16 +88,23 @@ class DIALOG_PAD_PROPERTIES_BASE : public DIALOG_SHIM
wxStaticText* m_staticText38;
wxTextCtrl* m_LengthPadToDieCtrl;
wxStaticText* m_PadLengthDie_Unit;
wxStaticLine* m_staticline4;
wxStaticLine* m_staticline5;
wxStaticLine* m_staticline6;
wxStaticText* m_staticText21;
wxTextCtrl* m_ShapeDelta_Ctrl;
wxStaticText* m_PadShapeDelta_Unit;
wxStaticText* m_staticText23;
wxChoice* m_trapDeltaDirChoice;
wxStaticText* m_staticText521;
wxStaticText* m_staticTitleModuleRot;
wxStaticText* m_staticModuleRotValue;
wxStaticText* m_staticTitleModuleSide;
wxStaticText* m_staticModuleSideValue;
wxStaticLine* m_staticline7;
wxStaticLine* m_staticline8;
wxStaticLine* m_staticline9;
wxStaticText* m_staticTextCornerSizeRatio;
wxTextCtrl* m_tcCornerSizeRatio;
wxStaticText* m_staticTextCornerSizeRatioUnit;
wxStaticText* m_staticTextCornerRadius;
wxStaticText* m_staticTextCornerRadiusValue;
wxStaticText* m_staticTextCornerSizeUnit;
wxStaticText* m_staticText47;
wxChoice* m_DrillShapeCtrl;
wxStaticText* m_staticText51;
@ -120,6 +127,10 @@ class DIALOG_PAD_PROPERTIES_BASE : public DIALOG_SHIM
wxCheckBox* m_PadLayerDraft;
wxCheckBox* m_PadLayerECO1;
wxCheckBox* m_PadLayerECO2;
wxStaticText* m_staticTitleModuleRot;
wxStaticText* m_staticModuleRotValue;
wxStaticText* m_staticTitleModuleSide;
wxStaticText* m_staticModuleSideValue;
wxPanel* m_localSettingsPanel;
wxStaticText* m_staticTextNetClearance;
wxTextCtrl* m_NetClearanceValueCtrl;
@ -146,9 +157,9 @@ class DIALOG_PAD_PROPERTIES_BASE : public DIALOG_SHIM
wxPanel* m_panelShowPad;
PCB_DRAW_PANEL_GAL* m_panelShowPadGal;
wxStaticText* m_staticTextWarningPadFlipped;
wxStdDialogButtonSizer* m_sdbSizer1;
wxButton* m_sdbSizer1OK;
wxButton* m_sdbSizer1Cancel;
wxStdDialogButtonSizer* m_sdbSizer;
wxButton* m_sdbSizerOK;
wxButton* m_sdbSizerCancel;
// Virtual event handlers, overide them in your derived class
virtual void OnValuesChanged( wxCommandEvent& event ) { event.Skip(); }
@ -156,15 +167,15 @@ class DIALOG_PAD_PROPERTIES_BASE : public DIALOG_SHIM
virtual void OnPadShapeSelection( wxCommandEvent& event ) { event.Skip(); }
virtual void PadOrientEvent( wxCommandEvent& event ) { event.Skip(); }
virtual void OnSetLayers( wxCommandEvent& event ) { event.Skip(); }
virtual void onCornerSizePercentChange( wxCommandEvent& event ) { event.Skip(); }
virtual void OnDrillShapeSelected( wxCommandEvent& event ) { event.Skip(); }
virtual void OnPaintShowPanel( wxPaintEvent& event ) { event.Skip(); }
virtual void OnCancelButtonClick( wxCommandEvent& event ) { event.Skip(); }
virtual void PadPropertiesAccept( 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|wxSUNKEN_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( 785,659 ), long style = wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER|wxSUNKEN_BORDER );
~DIALOG_PAD_PROPERTIES_BASE();
};

View File

@ -5,9 +5,9 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2004-2015 Jean-Pierre Charras, jean-pierre.charras@gipsa-lab.inpg.fr
* Copyright (C) 2004-2016 Jean-Pierre Charras, jean-pierre.charras@gipsa-lab.inpg.fr
* Copyright (C) 2007 Dick Hollenbeck, dick@softplc.com
* Copyright (C) 2015 KiCad Developers, see change_log.txt for contributors.
* Copyright (C) 2016 KiCad Developers, see change_log.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
@ -27,9 +27,9 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
/****************************/
/* DRC control */
/****************************/
/**
* DRC control: these functions make a DRC between pads, tracks and pads versus tracks
*/
#include <fctsys.h>
#include <wxPcbStruct.h>
@ -45,41 +45,37 @@
#include <class_marker_pcb.h>
#include <math_for_graphics.h>
#include <polygon_test_point_inside.h>
#include <convert_basic_shapes_to_polygon.h>
/* compare 2 trapezoids (can be rectangle) and return true if distance > aDist
/* compare 2 convex polygons and return true if distance > aDist
* i.e if for each edge of the first polygon distance from each edge of the other polygon
* is >= aDist
*/
bool trapezoid2trapezoidDRC( wxPoint aTref[4], wxPoint aTcompare[4], int aDist )
bool poly2polyDRC( wxPoint* aTref, int aTrefCount,
wxPoint* aTcompare, int aTcompareCount, int aDist )
{
/* Test if one polygon is contained in the other and thus the polygon overlap.
* This case is not covered by the following check if one polygond is
* This case is not covered by the following check if one polygone is
* completely contained in the other (because edges don't intersect)!
*/
if( TestPointInsidePolygon( aTref, 4, aTcompare[0] ) )
if( TestPointInsidePolygon( aTref, aTrefCount, aTcompare[0] ) )
return false;
if( TestPointInsidePolygon( aTcompare, 4, aTref[0] ) )
if( TestPointInsidePolygon( aTcompare, aTcompareCount, aTref[0] ) )
return false;
int ii, jj, kk, ll;
for( ii = 0, jj = 3; ii<4; jj = ii, ii++ ) // for all edges in aTref
{
for( kk = 0, ll = 3; kk < 4; ll = kk, kk++ ) // for all edges in aTcompare
{
for( int ii = 0, jj = aTrefCount - 1; ii < aTrefCount; jj = ii, ii++ )
{ // for all edges in aTref
for( int kk = 0, ll = aTcompareCount - 1; kk < aTcompareCount; ll = kk, kk++ )
{ // for all edges in aTcompare
double d;
int intersect = TestForIntersectionOfStraightLineSegments( aTref[ii].x,
aTref[ii].y,
aTref[jj].x,
aTref[jj].y,
aTcompare[kk].x,
aTcompare[kk].y,
aTcompare[ll].x,
aTcompare[ll].y,
NULL, NULL, &d );
if( intersect || (d< aDist) )
int intersect = TestForIntersectionOfStraightLineSegments(
aTref[ii].x, aTref[ii].y, aTref[jj].x, aTref[jj].y,
aTcompare[kk].x, aTcompare[kk].y, aTcompare[ll].x, aTcompare[ll].y,
NULL, NULL, &d );
if( intersect || ( d< aDist ) )
return false;
}
}
@ -87,58 +83,50 @@ bool trapezoid2trapezoidDRC( wxPoint aTref[4], wxPoint aTcompare[4], int aDist )
return true;
}
/* compare a trapezoids (can be rectangle) and a segment and return true if distance > aDist
*/
bool trapezoid2segmentDRC( wxPoint aTref[4], wxPoint aSegStart, wxPoint aSegEnd, int aDist )
bool poly2segmentDRC( wxPoint* aTref, int aTrefCount, wxPoint aSegStart, wxPoint aSegEnd, int aDist )
{
/* Test if the segment is contained in the polygon.
* This case is not covered by the following check if the segment is
* completely contained in the polygon (because edges don't intersect)!
*/
if( TestPointInsidePolygon( aTref, 4, aSegStart ) )
if( TestPointInsidePolygon( aTref, aTrefCount, aSegStart ) )
return false;
int ii, jj;
for( ii = 0, jj = 3; ii < 4; jj = ii, ii++ ) // for all edges in aTref
{
for( int ii = 0, jj = aTrefCount-1; ii < aTrefCount; jj = ii, ii++ )
{ // for all edges in polygon
double d;
int intersect = TestForIntersectionOfStraightLineSegments( aTref[ii].x,
aTref[ii].y,
aTref[jj].x,
aTref[jj].y,
aSegStart.x,
aSegStart.y,
aSegEnd.x,
aSegEnd.y,
NULL, NULL, &d );
if( intersect || (d< aDist) )
int intersect = TestForIntersectionOfStraightLineSegments(
aTref[ii].x, aTref[ii].y, aTref[jj].x, aTref[jj].y,
aSegStart.x, aSegStart.y, aSegEnd.x, aSegEnd.y,
NULL, NULL, &d );
if( intersect || ( d < aDist) )
return false;
}
return true;
}
/* compare a trapezoid to a point and return true if distance > aDist
/* compare a polygon to a point and return true if distance > aDist
* do not use this function for horizontal or vertical rectangles
* because there is a faster an easier way to compare the distance
*/
bool trapezoid2pointDRC( wxPoint aTref[4], wxPoint aPcompare, int aDist )
bool convex2pointDRC( wxPoint* aTref, int aTrefCount, wxPoint aPcompare, int aDist )
{
/* Test if aPcompare point is contained in the polygon.
* This case is not covered by the following check if this point is inside the polygon
*/
if( TestPointInsidePolygon( aTref, 4, aPcompare ) )
if( TestPointInsidePolygon( aTref, aTrefCount, aPcompare ) )
{
return false;
}
// Test distance between aPcompare and each segment of the polygon:
for( int ii = 0, jj = 3; ii < 4; jj = ii, ii++ ) // for all edge in polygon
for( int ii = 0, jj = aTrefCount - 1; ii < aTrefCount; jj = ii, ii++ ) // for all edge in polygon
{
if( TestSegmentHit( aTref[ii], aTref[jj], aPcompare, aDist ) )
if( TestSegmentHit( aPcompare, aTref[ii], aTref[jj], aDist ) )
return false;
}
@ -577,12 +565,13 @@ bool DRC::doTrackDrc( TRACK* aRefSeg, TRACK* aStart, bool testPads )
/* test DRC between 2 pads.
* this function can be also used to test DRC between a pas and a hole,
* because a hole is like a round pad.
* this function can be also used to test DRC between a pad and a hole,
* because a hole is like a round or oval pad.
*/
bool DRC::checkClearancePadToPad( D_PAD* aRefPad, D_PAD* aPad )
{
int dist;
double pad_angle;
// Get the clearance between the 2 pads. this is the min distance between aRefPad and aPad
int dist_min = aRefPad->GetClearance( aPad );
@ -607,10 +596,12 @@ bool DRC::checkClearancePadToPad( D_PAD* aRefPad, D_PAD* aPad )
swap_pads = false;
// swap pads to make comparisons easier
// priority is aRefPad = ROUND then OVAL then RECT then other
// Note also a ROUNDRECT pad with a corner radius = r can be considered as
// a smaller RECT (size - 2*r) with a clearance increased by r
// 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 or trapezoid
// pad ref shape is here oval, rect, roundrect, trapezoid or custom
switch( aPad->GetShape() )
{
case PAD_SHAPE_CIRCLE:
@ -622,6 +613,7 @@ bool DRC::checkClearancePadToPad( D_PAD* aRefPad, D_PAD* aPad )
break;
case PAD_SHAPE_RECT:
case PAD_SHAPE_ROUNDRECT:
if( aRefPad->GetShape() != PAD_SHAPE_OVAL )
swap_pads = true;
break;
@ -637,10 +629,20 @@ bool DRC::checkClearancePadToPad( D_PAD* aRefPad, D_PAD* aPad )
relativePadPos = -relativePadPos;
}
// corners of aRefPad (used only for rect/roundrect/trap pad)
wxPoint polyref[4];
// corners of aRefPad (used only for custom pad)
SHAPE_POLY_SET polysetref;
// corners of aPad (used only for rect/roundrect/trap pad)
wxPoint polycompare[4];
// corners of aPad (used only custom pad)
SHAPE_POLY_SET polysetcompare;
/* Because pad exchange, aRefPad shape is PAD_SHAPE_CIRCLE or PAD_SHAPE_OVAL,
* if one of the 2 pads was a PAD_SHAPE_CIRCLE or PAD_SHAPE_OVAL.
* Therefore, if aRefPad is a PAD_SHAPE_SHAPE_RECT or a PAD_SHAPE_TRAPEZOID,
* aPad is also a PAD_SHAPE_RECT or a PAD_SHAPE_TRAPEZOID
* Therefore, if aRefPad is a PAD_SHAPE_RECT, PAD_SHAPE_ROUNDRECT or a PAD_SHAPE_TRAPEZOID,
* aPad is also a PAD_SHAPE_RECT, PAD_SHAPE_ROUNDRECT or a PAD_SHAPE_TRAPEZOID
*/
bool diag = true;
@ -660,6 +662,63 @@ bool DRC::checkClearancePadToPad( D_PAD* aRefPad, D_PAD* aPad )
diag = checkClearanceSegmToPad( aPad, aRefPad->GetSize().x, dist_min );
break;
case PAD_SHAPE_TRAPEZOID:
case PAD_SHAPE_ROUNDRECT:
case PAD_SHAPE_RECT:
// pad_angle = pad orient relative to the aRefPad orient
pad_angle = aRefPad->GetOrientation() + aPad->GetOrientation();
NORMALIZE_ANGLE_POS( pad_angle );
if( aRefPad->GetShape() == PAD_SHAPE_ROUNDRECT )
{
int padRadius = aRefPad->GetRoundRectCornerRadius();
dist_min += padRadius;
GetRoundRectCornerCenters( polyref, padRadius, wxPoint( 0, 0 ),
aRefPad->GetSize(), aRefPad->GetOrientation() );
}
else
aRefPad->BuildPadPolygon( polyref, wxSize( 0, 0 ), aRefPad->GetOrientation() );
switch( aPad->GetShape() )
{
case PAD_SHAPE_ROUNDRECT:
case PAD_SHAPE_RECT:
case PAD_SHAPE_TRAPEZOID:
if( aPad->GetShape() == PAD_SHAPE_ROUNDRECT )
{
int padRadius = aPad->GetRoundRectCornerRadius();
dist_min += padRadius;
GetRoundRectCornerCenters( polycompare, padRadius, relativePadPos,
aPad->GetSize(), aPad->GetOrientation() );
}
else
{
aPad->BuildPadPolygon( polycompare, wxSize( 0, 0 ), aPad->GetOrientation() );
// Move aPad shape to relativePadPos
for( int ii = 0; ii < 4; ii++ )
polycompare[ii] += relativePadPos;
}
// And now test polygons:
if( polysetref.OutlineCount() )
{
const SHAPE_LINE_CHAIN& refpoly = polysetref.COutline( 0 );
// And now test polygons:
if( !poly2polyDRC( (wxPoint*) &refpoly.CPoint( 0 ), refpoly.PointCount(),
polycompare, 4, dist_min ) )
diag = false;
}
else if( !poly2polyDRC( polyref, 4, polycompare, 4, dist_min ) )
diag = false;
break;
default:
wxLogDebug( wxT( "DRC::checkClearancePadToPad: unexpected pad shape %d" ), aPad->GetShape() );
break;
}
break;
case PAD_SHAPE_OVAL: /* an oval pad is like a track segment */
{
/* Create a track segment with same dimensions as the oval aRefPad
@ -702,26 +761,8 @@ bool DRC::checkClearancePadToPad( D_PAD* aRefPad, D_PAD* aPad )
break;
}
case PAD_SHAPE_TRAPEZOID:
case PAD_SHAPE_RECT:
{
wxPoint polyref[4]; // Shape of aRefPad
wxPoint polycompare[4]; // Shape of aPad
aRefPad->BuildPadPolygon( polyref, wxSize( 0, 0 ), aRefPad->GetOrientation() );
aPad->BuildPadPolygon( polycompare, wxSize( 0, 0 ), aPad->GetOrientation() );
// Move aPad shape to relativePadPos
for( int ii = 0; ii < 4; ii++ )
polycompare[ii] += relativePadPos;
// And now test polygons:
if( !trapezoid2trapezoidDRC( polyref, polycompare, dist_min ) )
diag = false;
}
break;
default:
wxLogDebug( wxT( "DRC::checkClearancePadToPad: unexpected pad shape" ) );
wxLogDebug( wxT( "DRC::checkClearancePadToPad: unknown pad shape" ) );
break;
}
@ -737,7 +778,7 @@ bool DRC::checkClearancePadToPad( D_PAD* aRefPad, D_PAD* aPad )
bool DRC::checkClearanceSegmToPad( const D_PAD* aPad, int aSegmentWidth, int aMinDist )
{
wxSize padHalfsize; // half dimension of the pad
wxPoint startPoint, endPoint;
int r;
int segmHalfWidth = aSegmentWidth / 2;
int distToLine = segmHalfWidth + aMinDist;
@ -770,8 +811,8 @@ bool DRC::checkClearanceSegmToPad( const D_PAD* aPad, int aSegmentWidth, int aMi
m_xcliphi = m_padToTestPos.x + distToLine + padHalfsize.x;
m_ycliphi = m_padToTestPos.y + distToLine + padHalfsize.y;
startPoint.x = startPoint.y = 0;
endPoint = m_segmEnd;
wxPoint startPoint;
wxPoint endPoint = m_segmEnd;
double orient = aPad->GetOrientation();
@ -849,6 +890,13 @@ bool DRC::checkClearanceSegmToPad( const D_PAD* aPad, int aSegmentWidth, int aMi
}
break;
case PAD_SHAPE_ROUNDRECT:
// a round rect is a smaller rect, with a clearance augmented by the corners radius
r = aPad->GetRoundRectCornerRadius();
padHalfsize.x -= r;
padHalfsize.y -= r;
distToLine += r;
// Fall through
case PAD_SHAPE_RECT:
// the area to test is a rounded rectangle.
// this can be done by testing 2 rectangles and 4 circles (the corners)
@ -923,10 +971,11 @@ bool DRC::checkClearanceSegmToPad( const D_PAD* aPad, int aSegmentWidth, int aMi
RotatePoint( &poly[ii], m_segmAngle );
}
if( !trapezoid2segmentDRC( poly, wxPoint( 0, 0 ), wxPoint(m_segmLength,0), distToLine ) )
if( !poly2segmentDRC( poly, 4, wxPoint( 0, 0 ), wxPoint(m_segmLength,0), distToLine ) )
return false;
break;
}
break;
}
return true;

View File

@ -365,12 +365,12 @@ private:
/**
* Helper function checkMarginToCircle
* Check the distance from a point to
* a segment. the segment is expected starting at 0,0, and on the X axis
* Check the distance from a point to a segment.
* The segment is expected starting at 0,0, and on the X axis
* (used to test DRC between a segment and a round pad, via or round end of a track
* @param aCentre The coordinate of the circle's center
* @param aRadius A "keep out" radius centered over the circle
* @param aLength The length of the segment (i.e. coordinate of end, becuase it is on
* @param aLength The length of the segment (i.e. coordinate of end, because it is on
* the X axis)
* @return bool - true if distance >= radius, else
* false when distance < aRadius

View File

@ -1229,6 +1229,7 @@ void PCB_IO::format( D_PAD* aPad, int aNestLevel ) const
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;
default:
THROW_IO_ERROR( wxString::Format( _( "unknown pad type: %d"), aPad->GetShape() ) );
@ -1287,6 +1288,13 @@ void PCB_IO::format( D_PAD* aPad, int aNestLevel ) const
formatLayers( aPad->GetLayerSet(), 0 );
// Output the radius ratio for rounded rect pads
if( aPad->GetShape() == PAD_SHAPE_ROUNDRECT )
{
m_out->Print( 0, "(roundrect_rratio %s)",
Double2Str( aPad->GetRoundRectRadiusRatio() ).c_str() );
}
std::string output;
// Unconnected pad is default net so don't save it.

View File

@ -51,19 +51,12 @@ void PCB_BASE_FRAME::Export_Pad_Settings( D_PAD* aPad )
SetMsgPanel( aPad );
D_PAD& mp = GetDesignSettings().m_Pad_Master;
mp.SetShape( aPad->GetShape() );
mp.SetAttribute( aPad->GetAttribute() );
mp.SetLayerSet( aPad->GetLayerSet() );
// Copy all settings. Some of them are not used, but they break anything
mp.Copy( aPad );
// The pad orientation, for historical reasons is the
// pad rotation + parent rotation.
// store only the pad rotation.
mp.SetOrientation( aPad->GetOrientation() - aPad->GetParent()->GetOrientation() );
mp.SetSize( aPad->GetSize() );
mp.SetDelta( aPad->GetDelta() );
mp.SetOffset( aPad->GetOffset() );
mp.SetDrillSize( aPad->GetDrillSize() );
mp.SetDrillShape( aPad->GetDrillShape() );
}
@ -113,6 +106,7 @@ void PCB_BASE_FRAME::Import_Pad_Settings( D_PAD* aPad, bool aDraw )
aPad->SetDrillSize( wxSize( 0, 0 ) );
aPad->SetOffset( wxPoint( 0, 0 ) );
break;
default:
;
}

View File

@ -38,6 +38,7 @@
#include <pcb_painter.h>
#include <gal/graphics_abstraction_layer.h>
#include <convert_basic_shapes_to_polygon.h>
using namespace KIGFX;
@ -653,6 +654,38 @@ void PCB_PAINTER::draw( const D_PAD* aPad, int aLayer )
m_gal->DrawRectangle( VECTOR2D( -size.x, -size.y ), VECTOR2D( size.x, size.y ) );
break;
case PAD_SHAPE_ROUNDRECT:
{
std::deque<VECTOR2D> pointList;
// Use solder[Paste/Mask]size or pad size to build pad shape
SHAPE_POLY_SET outline;
wxSize prsize( size.x*2, size.y*2 );
const int segmentToCircleCount = 64;
int corner_radius = aPad->GetRoundRectCornerRadius( prsize );
TransformRoundRectToPolygon( outline, wxPoint( 0, 0 ), prsize,
0.0 , corner_radius, segmentToCircleCount );
// Draw the polygon: Inflate creates only one convex polygon
SHAPE_LINE_CHAIN& poly = outline.Outline( 0 );
for( int ii = 0; ii < poly.PointCount(); ii++ )
pointList.push_back( poly.Point( ii ) );
if( m_pcbSettings.m_sketchMode[ITEM_GAL_LAYER( PADS_VISIBLE )] )
{
// Add the beginning point to close the outline
pointList.push_back( pointList.front() );
m_gal->DrawPolyline( pointList );
}
else
{
m_gal->DrawPolygon( pointList );
}
break;
}
case PAD_SHAPE_TRAPEZOID:
{
std::deque<VECTOR2D> pointList;
@ -667,7 +700,7 @@ void PCB_PAINTER::draw( const D_PAD* aPad, int aLayer )
pointList.push_back( VECTOR2D( corners[2] ) );
pointList.push_back( VECTOR2D( corners[3] ) );
if( m_pcbSettings.m_sketchMode[PADS_VISIBLE] )
if( m_pcbSettings.m_sketchMode[ITEM_GAL_LAYER( PADS_VISIBLE )] )
{
// Add the beginning point to close the outline
pointList.push_back( pointList.front() );

View File

@ -2203,8 +2203,12 @@ D_PAD* PCB_PARSER::parseD_PAD( MODULE* aParent ) throw( IO_ERROR, PARSE_ERROR )
pad->SetShape( PAD_SHAPE_TRAPEZOID );
break;
case T_roundrect:
pad->SetShape( PAD_SHAPE_ROUNDRECT );
break;
default:
Expecting( "circle, rectangle, oval, or trapezoid" );
Expecting( "circle, rectangle, roundrect, oval, trapezoid or custom" );
}
for( token = NextTok(); token != T_RIGHT; token = NextTok() )
@ -2372,10 +2376,15 @@ D_PAD* PCB_PARSER::parseD_PAD( MODULE* aParent ) throw( IO_ERROR, PARSE_ERROR )
NeedRIGHT();
break;
case T_roundrect_rratio:
pad->SetRoundRectRadiusRatio( parseDouble( "roundrect radius ratio" ) );
NeedRIGHT();
break;
default:
Expecting( "at, drill, layers, net, die_length, solder_mask_margin, "
Expecting( "at, drill, layers, net, die_length, solder_mask_margin, roundrect_rratio,"
"solder_paste_margin, solder_paste_margin_ratio, clearance, "
"zone_connect, thermal_width, or thermal_gap" );
"zone_connect, fp_poly, basic_shapes, thermal_width, or thermal_gap" );
}
}

View File

@ -380,6 +380,7 @@ void PlotStandardLayer( BOARD *aBoard, PLOTTER* aPlotter,
// Fall through:
case PAD_SHAPE_TRAPEZOID:
case PAD_SHAPE_RECT:
case PAD_SHAPE_ROUNDRECT:
default:
itemplotter.PlotPad( pad, color, plotMode );
break;
@ -869,7 +870,6 @@ static void initializePlotter( PLOTTER *aPlotter, BOARD * aBoard,
aPlotter->SetViewport( offset, IU_PER_DECIMILS, compound_scale,
aPlotOpts->GetMirror() );
// has meaning only for gerber plotter. Must be called only after SetViewport
aPlotter->SetGerberCoordinatesFormat( aPlotOpts->GetGerberPrecision() );

View File

@ -84,13 +84,18 @@ void BRDITEMS_PLOTTER::PlotPad( D_PAD* aPad, EDA_COLOR_T aColor, EDA_DRAW_MODE_T
case PAD_SHAPE_TRAPEZOID:
{
wxPoint coord[4];
aPad->BuildPadPolygon( coord, wxSize(0,0), 0 );
m_plotter->FlashPadTrapez( shape_pos, coord,
aPad->GetOrientation(), aPlotMode );
wxPoint coord[4];
aPad->BuildPadPolygon( coord, wxSize(0,0), 0 );
m_plotter->FlashPadTrapez( shape_pos, coord,
aPad->GetOrientation(), aPlotMode );
}
break;
case PAD_SHAPE_ROUNDRECT:
m_plotter->FlashPadRoundRect( shape_pos, aPad->GetSize(), aPad->GetRoundRectCornerRadius(),
aPad->GetOrientation(), aPlotMode );
break;
case PAD_SHAPE_RECT:
default:
m_plotter->FlashPadRect( shape_pos, aPad->GetSize(),

View File

@ -60,6 +60,8 @@
#include <class_track.h>
#include <ratsnest_data.h>
#include <layers_id_colors_and_visibility.h>
#include <geometry/convex_hull.h>
// an ugly singleton for drawing debug items within the router context.
// To be fixed sometime in the future.
@ -267,6 +269,27 @@ PNS_ITEM* PNS_ROUTER::syncPad( D_PAD* aPad )
break;
}
case PAD_SHAPE_ROUNDRECT:
{
SHAPE_POLY_SET outline;
const int segmentToCircleCount = 64;
aPad->BuildPadShapePolygon( outline, wxSize( 0, 0 ),
segmentToCircleCount, 1.0 );
// TransformRoundRectToPolygon creates only one convex polygon
SHAPE_LINE_CHAIN& poly = outline.Outline( 0 );
SHAPE_CONVEX* shape = new SHAPE_CONVEX();
for( int ii = 0; ii < poly.PointCount(); ++ii )
{
shape->Append( wxPoint( poly.Point( ii ).x, poly.Point( ii ).y ) );
}
solid->SetShape( shape );
}
break;
default:
TRACEn( 0, "unsupported pad shape" );
delete solid;
@ -344,6 +367,26 @@ PNS_ITEM* PNS_ROUTER::syncPad( D_PAD* aPad )
break;
}
case PAD_SHAPE_ROUNDRECT:
{
SHAPE_POLY_SET outline;
const int segmentToCircleCount = 32;
aPad->BuildPadShapePolygon( outline, wxSize( 0, 0 ),
segmentToCircleCount, 1.0 );
// TransformRoundRectToPolygon creates only one convex polygon
SHAPE_LINE_CHAIN& poly = outline.Outline( 0 );
SHAPE_CONVEX* shape = new SHAPE_CONVEX();
for( int ii = 0; ii < poly.PointCount(); ++ii )
{
shape->Append( wxPoint( poly.Point( ii ).x, poly.Point( ii ).y ) );
}
solid->SetShape( shape );
}
break;
default:
TRACEn( 0, "unsupported pad shape" );
delete solid;

View File

@ -4,8 +4,8 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2012 Jean-Pierre Charras, jean-pierre.charras@ujf-grenoble.fr
* Copyright (C) 1992-2012 KiCad Developers, see AUTHORS.txt for contributors.
* Copyright (C) 2016 Jean-Pierre Charras, jp.charras at wanadoo.fr
* Copyright (C) 1992-2016 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
@ -197,12 +197,14 @@ void ZONE_CONTAINER::buildFeatureHoleList( BOARD* aPcb, SHAPE_POLY_SET& aFeature
continue;
}
// Pads are removed from zone if the setup is PAD_ZONE_CONN_NONE
if( GetPadConnection( pad ) == PAD_ZONE_CONN_NONE )
{
int gap = zone_clearance;
int thermalGap = GetThermalReliefGap( pad );
gap = std::max( gap, thermalGap );
item_boundingbox = pad->GetBoundingBox();
item_boundingbox.Inflate( gap );
if( item_boundingbox.Intersects( zone_boundingbox ) )
{