diff --git a/libs/kimath/CMakeLists.txt b/libs/kimath/CMakeLists.txt index 40d418e7e8..907fa7c515 100644 --- a/libs/kimath/CMakeLists.txt +++ b/libs/kimath/CMakeLists.txt @@ -15,6 +15,7 @@ set( KIMATH_SRCS src/geometry/shape_file_io.cpp src/geometry/shape_line_chain.cpp src/geometry/shape_poly_set.cpp + src/geometry/shape_rect.cpp src/math/util.cpp ) diff --git a/libs/kimath/include/geometry/shape.h b/libs/kimath/include/geometry/shape.h index 7bb582f528..ce93951709 100644 --- a/libs/kimath/include/geometry/shape.h +++ b/libs/kimath/include/geometry/shape.h @@ -195,7 +195,5 @@ protected: SHAPE_TYPE m_type; }; -bool CollideShapes( const SHAPE* aA, const SHAPE* aB, int aClearance, int* aActual, - VECTOR2I* aMTV ); #endif // __SHAPE_H diff --git a/libs/kimath/include/geometry/shape_arc.h b/libs/kimath/include/geometry/shape_arc.h index 570d5fd28b..961a433d3a 100644 --- a/libs/kimath/include/geometry/shape_arc.h +++ b/libs/kimath/include/geometry/shape_arc.h @@ -26,11 +26,8 @@ #ifndef __SHAPE_ARC_H #define __SHAPE_ARC_H -#include #include -#include // for BOX2I #include // for VECTOR2I -#include class SHAPE_LINE_CHAIN; diff --git a/libs/kimath/include/geometry/shape_line_chain.h b/libs/kimath/include/geometry/shape_line_chain.h index 536735de2f..6614fa52f0 100644 --- a/libs/kimath/include/geometry/shape_line_chain.h +++ b/libs/kimath/include/geometry/shape_line_chain.h @@ -27,18 +27,10 @@ #define __SHAPE_LINE_CHAIN -#include // for max -#include -#include -#include // for wxPoint - -#include - #include #include #include #include -#include // for BOX2I #include @@ -485,8 +477,7 @@ public: /** * Function Replace() * - * Replaces points with indices in range [start_index, end_index] with a single - * point aP. + * Replaces points with indices in range [start_index, end_index] with a single point aP. * @param aStartIndex start of the point range to be replaced (inclusive) * @param aEndIndex end of the point range to be replaced (inclusive) * @param aP replacement point @@ -496,8 +487,8 @@ public: /** * Function Replace() * - * Replaces points with indices in range [start_index, end_index] with the points from - * line chain aLine. + * Replaces points with indices in range [start_index, end_index] with the points from line + * chain aLine. * @param aStartIndex start of the point range to be replaced (inclusive) * @param aEndIndex end of the point range to be replaced (inclusive) * @param aLine replacement line chain. @@ -526,8 +517,8 @@ public: /** * Function Split() * - * Inserts the point aP belonging to one of the our segments, splitting the adjacent - * segment in two. + * Inserts the point aP belonging to one of the our segments, splitting the adjacent segment + * in two. * @param aP the point to be inserted * @return index of the newly inserted point (or a negative value if aP does not lie on * our line) @@ -583,8 +574,8 @@ public: * * Finds all intersection points between our line chain and the segment aSeg. * @param aSeg the segment chain to find intersections with - * @param aIp reference to a vector to store found intersections. Intersection points - * are sorted with increasing distances from point aSeg.a. + * @param aIp reference to a vector to store found intersections. Intersection points are + * sorted with increasing distances from point aSeg.a. * @return number of intersections found */ int Intersect( const SEG& aSeg, INTERSECTIONS& aIp ) const; @@ -594,8 +585,8 @@ public: * * Finds all intersection points between our line chain and the line chain aChain. * @param aChain the line chain to find intersections with - * @param aIp reference to a vector to store found intersections. Intersection points - * are sorted with increasing path lengths from the starting point of aChain. + * @param aIp reference to a vector to store found intersections. Intersection points are + * sorted with increasing path lengths from the starting point of aChain. * @return number of intersections found */ int Intersect( const SHAPE_LINE_CHAIN& aChain, INTERSECTIONS& aIp ) const; @@ -603,10 +594,9 @@ public: /** * Function PathLength() * - * Computes the walk path length from the beginning of the line chain and - * the point aP belonging to our line. - * @return: path length in Euclidean metric or negative if aP does not belong to - * the line chain. + * Computes the walk path length from the beginning of the line chain and the point aP + * belonging to our line. + * @return: path length in Euclidean metric or -1 if aP does not belong to the line chain. */ int PathLength( const VECTOR2I& aP ) const; @@ -616,7 +606,7 @@ public: * Checks if point aP lies inside a polygon (any type) defined by the line chain. * For closed shapes only. * @param aPt point to check - * @param aUseBBoxCache gives better peformance if the bounding boxe caches have been + * @param aUseBBoxCache gives better peformance if the bounding box caches have been * generated. * @return true if the point is inside the shape (edge is not treated as being inside). */ @@ -676,7 +666,6 @@ public: /** * Creates a new Clipper path from the SHAPE_LINE_CHAIN in a given orientation - * */ ClipperLib::Path convertToClipper( bool aRequiredOrientation ) const; @@ -699,8 +688,8 @@ public: /** * Function NearestPoint() * - * Finds a point on the line chain that is closest to the line defined - * by the points of segment aSeg, also returns the distance. + * Finds a point on the line chain that is closest to the line defined by the points of + * segment aSeg, also returns the distance. * @param aSeg Segment defining the line. * @param dist reference receiving the distance to the nearest point. * @return the nearest point. @@ -794,9 +783,9 @@ private: std::vector m_points; /** - * Array of indices that refer to the index of the shape if the point - * is part of a larger shape, e.g. arc or spline. - * If the value is -1, the point is just a point + * Array of indices that refer to the index of the shape if the point is part of a larger + * shape, e.g. arc or spline. + * If the value is -1, the point is just a point. */ std::vector m_shapes; @@ -807,8 +796,9 @@ private: /// Width of the segments (for BBox calculations in RTree) /// TODO Adjust usage of SHAPE_LINE_CHAIN to account for where we need a width and where not - /// Alternatively, we could split the class into a LINE_CHAIN (no width) and SHAPE_LINE_CHAIN that derives from - /// SHAPE as well that does have a width. Not sure yet on the correct path. + /// Alternatively, we could split the class into a LINE_CHAIN (no width) and SHAPE_LINE_CHAIN + /// that derives from SHAPE as well that does have a width. Not sure yet on the correct path. + /// TODO Note that we also have SHAPE_SIMPLE which is a closed, filled SHAPE_LINE_CHAIN. int m_width; /// cached bounding box diff --git a/libs/kimath/include/geometry/shape_rect.h b/libs/kimath/include/geometry/shape_rect.h index 6a8b279c46..85de5782a1 100644 --- a/libs/kimath/include/geometry/shape_rect.h +++ b/libs/kimath/include/geometry/shape_rect.h @@ -138,6 +138,14 @@ public: m_p0 += aVector; } + /** + * Function Rotate() + * This function has limited utility for SHAPE_RECT as non-cartesian rotations will distort + * the rectangle. If you might need to handle non-90ยบ rotations then the SHAPE_RECT should + * first be converted to a SHAPE_SIMPLE which can then be free-rotated. + * @param aAngle + * @param aCenter + */ void Rotate( double aAngle, const VECTOR2I& aCenter = { 0, 0 } ) override { m_p0 -= aCenter; diff --git a/libs/kimath/src/convert_basic_shapes_to_polygon.cpp b/libs/kimath/src/convert_basic_shapes_to_polygon.cpp index 0a6511f843..51f14ca94d 100644 --- a/libs/kimath/src/convert_basic_shapes_to_polygon.cpp +++ b/libs/kimath/src/convert_basic_shapes_to_polygon.cpp @@ -366,6 +366,7 @@ void TransformSegmentToPolygon( SHAPE_POLY_SET& aCornerBuffer, wxPoint aStart, w int seg_len = KiROUND( EuclideanNorm( endp ) ); // Compute the outlines of the segment, and creates a polygon + // add right rounded end: for( int ii = 0; ii < 1800; ii += delta ) { @@ -448,7 +449,6 @@ void TransformArcToPolygon( SHAPE_POLY_SET& aCornerBuffer, wxPoint aCentre, wxPo void TransformRingToPolygon( SHAPE_POLY_SET& aCornerBuffer, wxPoint aCentre, int aRadius, int aError, int aWidth ) { - // Compute the corners positions and creates the poly int inner_radius = aRadius - ( aWidth / 2 ); int outer_radius = inner_radius + aWidth; diff --git a/libs/kimath/src/geometry/shape_arc.cpp b/libs/kimath/src/geometry/shape_arc.cpp index d457d3bf6f..b8ff0001f8 100644 --- a/libs/kimath/src/geometry/shape_arc.cpp +++ b/libs/kimath/src/geometry/shape_arc.cpp @@ -23,22 +23,15 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ -#include -#include -#include - #include #include // for SEG #include #include -#include // for cos, sin, M_PI, atan2, ceil -#include // for BOX2I -#include // for VECTOR2I, VECTOR2D, VECTOR2 -#include // for swap +#include SHAPE_ARC::SHAPE_ARC( const VECTOR2I& aArcCenter, const VECTOR2I& aArcStartPoint, - double aCenterAngle, int aWidth ) : + double aCenterAngle, int aWidth ) : SHAPE( SH_ARC ), m_width( aWidth ) { m_start = aArcStartPoint; @@ -53,7 +46,7 @@ SHAPE_ARC::SHAPE_ARC( const VECTOR2I& aArcCenter, const VECTOR2I& aArcStartPoint SHAPE_ARC::SHAPE_ARC( const VECTOR2I& aArcStart, const VECTOR2I& aArcMid, - const VECTOR2I& aArcEnd, int aWidth ) : + const VECTOR2I& aArcEnd, int aWidth ) : SHAPE( SH_ARC ), m_start( aArcStart ), m_mid( aArcMid ), m_end( aArcEnd ), m_width( aWidth ) { diff --git a/libs/kimath/src/geometry/shape_collisions.cpp b/libs/kimath/src/geometry/shape_collisions.cpp index 2257744b63..ec10e43f47 100644 --- a/libs/kimath/src/geometry/shape_collisions.cpp +++ b/libs/kimath/src/geometry/shape_collisions.cpp @@ -87,7 +87,8 @@ static inline bool Collide( const SHAPE_RECT& aA, const SHAPE_CIRCLE& aB, int aC bool inside = c.x >= p0.x && c.x <= ( p0.x + size.x ) && c.y >= p0.y && c.y <= ( p0.y + size.y ); - if( inside && !aMTV ) + // If we're not looking for MTV, short-circuit once we find a hard collision + if( !aMTV && inside ) { if( aActual ) *aActual = 0; @@ -102,7 +103,8 @@ static inline bool Collide( const SHAPE_RECT& aA, const SHAPE_CIRCLE& aB, int aC VECTOR2I pn = side.NearestPoint( c ); ecoord side_dist_sq = ( pn - c ).SquaredEuclideanNorm(); - if( ( side_dist_sq == 0 || side_dist_sq < min_dist_sq ) && !aMTV && !aActual ) + // If we're not looking for MTV or actual, short-circuit once we find any collision + if( !aMTV && !aActual && ( side_dist_sq == 0 || side_dist_sq < min_dist_sq ) ) return true; if( side_dist_sq < nearest_side_dist_sq ) @@ -163,18 +165,18 @@ static VECTOR2I pushoutForce( const SHAPE_CIRCLE& aA, const SEG& aB, int aCleara static inline bool Collide( const SHAPE_CIRCLE& aA, const SHAPE_LINE_CHAIN& aB, int aClearance, int* aActual, VECTOR2I* aMTV ) { - bool found = false; + bool collided = false; for( int s = 0; s < aB.SegmentCount(); s++ ) { if( aA.Collide( aB.CSegment( s ), aClearance, aActual ) ) { - found = true; + collided = true; break; } } - if( !found ) + if( !collided ) return false; if( aMTV ) @@ -229,18 +231,21 @@ static inline bool Collide( const SHAPE_CIRCLE& aA, const SHAPE_SIMPLE& aB, int static inline bool Collide( const SHAPE_CIRCLE& aA, const SHAPE_SEGMENT& aSeg, int aClearance, int* aActual, VECTOR2I* aMTV ) { - bool col = aA.Collide( aSeg.GetSeg(), aClearance + aSeg.GetWidth() / 2, aActual ); + if( !aA.Collide( aSeg.GetSeg(), aClearance + aSeg.GetWidth() / 2, aActual ) ) + return false; - if( col && aMTV ) + if( aMTV ) *aMTV = -pushoutForce( aA, aSeg.GetSeg(), aClearance + aSeg.GetWidth() / 2); - return col; + return true; } static inline bool Collide( const SHAPE_LINE_CHAIN& aA, const SHAPE_LINE_CHAIN& aB, int aClearance, int* aActual, VECTOR2I* aMTV ) { + // TODO: why doesn't this handle MTV? + for( int i = 0; i < aB.SegmentCount(); i++ ) { if( aA.Collide( aB.CSegment( i ), aClearance, aActual ) ) @@ -277,7 +282,8 @@ static inline bool Collide( const SHAPE_RECT& aA, const SHAPE_LINE_CHAIN& aB, in { minActual = std::min( minActual, actual ); - if( !aActual ) + // If we're not looking for MTV or Actual, short-circuit after any collision + if( !aActual && !aMTV ) return true; } } @@ -285,6 +291,8 @@ static inline bool Collide( const SHAPE_RECT& aA, const SHAPE_LINE_CHAIN& aB, in if( aActual ) *aActual = std::max( 0, minActual ); + // TODO: why doesn't this handle MTV? + return minActual < INT_MAX; } @@ -306,6 +314,8 @@ static inline bool Collide( const SHAPE_RECT& aA, const SHAPE_SEGMENT& aSeg, int if( aActual ) *aActual = std::max( 0, actual - aSeg.GetWidth() / 2 ); + // TODO: why doesn't this handle MTV? + return true; } @@ -323,6 +333,8 @@ static inline bool Collide( const SHAPE_SEGMENT& aA, const SHAPE_SEGMENT& aB, in if( aActual ) *aActual = std::max( 0, actual - aB.GetWidth() / 2 ); + // TODO: why doesn't this handle MTV? + return true; } @@ -340,6 +352,8 @@ static inline bool Collide( const SHAPE_LINE_CHAIN& aA, const SHAPE_SEGMENT& aB, if( aActual ) *aActual = std::max( 0, actual - aB.GetWidth() / 2 ); + // TODO: why doesn't this handle MTV? + return true; } @@ -431,7 +445,7 @@ inline bool CollCaseReversed ( const SHAPE* aA, const SHAPE* aB, int aClearance, } -bool CollideShapes( const SHAPE* aA, const SHAPE* aB, int aClearance, int* aActual, VECTOR2I* aMTV ) +bool collideShapes( const SHAPE* aA, const SHAPE* aB, int aClearance, int* aActual, VECTOR2I* aMTV ) { switch( aA->Type() ) { @@ -606,48 +620,13 @@ bool CollideShapes( const SHAPE* aA, const SHAPE* aB, int aClearance, int* aActu bool SHAPE::Collide( const SHAPE* aShape, int aClearance, VECTOR2I* aMTV ) const { - return CollideShapes( this, aShape, aClearance, nullptr, aMTV ); + return collideShapes( this, aShape, aClearance, nullptr, aMTV ); } bool SHAPE::Collide( const SHAPE* aShape, int aClearance, int* aActual ) const { - return CollideShapes( this, aShape, aClearance, aActual, nullptr ); + return collideShapes( this, aShape, aClearance, aActual, nullptr ); } -bool SHAPE_RECT::Collide( const SEG& aSeg, int aClearance, int* aActual ) const -{ - if( BBox( 0 ).Contains( aSeg.A ) || BBox( 0 ).Contains( aSeg.B ) ) - { - if( aActual ) - *aActual = 0; - - return true; - } - - VECTOR2I corners[] = { VECTOR2I( m_p0.x, m_p0.y ), - VECTOR2I( m_p0.x, m_p0.y + m_h ), - VECTOR2I( m_p0.x + m_w, m_p0.y + m_h ), - VECTOR2I( m_p0.x + m_w, m_p0.y ), - VECTOR2I( m_p0.x, m_p0.y ) }; - - SEG s( corners[0], corners[1] ); - SEG::ecoord dist_squared = s.SquaredDistance( aSeg ); - - for( int i = 1; i < 4; i++ ) - { - s = SEG( corners[i], corners[ i + 1] ); - dist_squared = std::min( dist_squared, s.SquaredDistance( aSeg ) ); - } - - if( dist_squared < (ecoord) aClearance * aClearance ) - { - if( aActual ) - *aActual = sqrt( dist_squared ); - - return true; - } - - return false; -} diff --git a/libs/kimath/src/geometry/shape_rect.cpp b/libs/kimath/src/geometry/shape_rect.cpp new file mode 100644 index 0000000000..1f19ba665a --- /dev/null +++ b/libs/kimath/src/geometry/shape_rect.cpp @@ -0,0 +1,63 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2015 CERN + * @author Tomasz Wlostowski + * + * 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 + */ + + +#include + + +bool SHAPE_RECT::Collide( const SEG& aSeg, int aClearance, int* aActual ) const +{ + if( BBox( 0 ).Contains( aSeg.A ) || BBox( 0 ).Contains( aSeg.B ) ) + { + if( aActual ) + *aActual = 0; + + return true; + } + + VECTOR2I corners[] = { VECTOR2I( m_p0.x, m_p0.y ), + VECTOR2I( m_p0.x, m_p0.y + m_h ), + VECTOR2I( m_p0.x + m_w, m_p0.y + m_h ), + VECTOR2I( m_p0.x + m_w, m_p0.y ), + VECTOR2I( m_p0.x, m_p0.y ) }; + + SEG s( corners[0], corners[1] ); + SEG::ecoord dist_squared = s.SquaredDistance( aSeg ); + + for( int i = 1; i < 4; i++ ) + { + s = SEG( corners[i], corners[ i + 1] ); + dist_squared = std::min( dist_squared, s.SquaredDistance( aSeg ) ); + } + + if( dist_squared < (ecoord) aClearance * aClearance ) + { + if( aActual ) + *aActual = sqrt( dist_squared ); + + return true; + } + + return false; +} diff --git a/pcbnew/class_pad.cpp b/pcbnew/class_pad.cpp index f7a1196052..4d22173c38 100644 --- a/pcbnew/class_pad.cpp +++ b/pcbnew/class_pad.cpp @@ -75,9 +75,9 @@ D_PAD::D_PAD( MODULE* parent ) : m_LocalSolderPasteMargin = 0; m_LocalSolderPasteMarginRatio = 0.0; // Parameters for round rect only: - m_padRoundRectRadiusScale = 0.25; // from IPC-7351C standard + m_roundedCornerScale = 0.25; // from IPC-7351C standard // Parameters for chamfered rect only: - m_padChamferRectScale = 0.2; // Size of chamfer: ratio of smallest of X,Y size + m_chamferScale = 0.2; // Size of chamfer: ratio of smallest of X,Y size m_chamferPositions = RECT_NO_CHAMFER; // No chamfered corner m_ZoneConnection = ZONE_CONNECTION::INHERITED; // Use parent setting by default @@ -162,7 +162,7 @@ int D_PAD::calcBoundingRadius() const int D_PAD::GetRoundRectCornerRadius() const { - return KiROUND( std::min( m_Size.x, m_Size.y ) * m_padRoundRectRadiusScale ); + return KiROUND( std::min( m_Size.x, m_Size.y ) * m_roundedCornerScale ); } @@ -177,7 +177,7 @@ void D_PAD::SetRoundRectCornerRadius( double aRadius ) void D_PAD::SetRoundRectRadiusRatio( double aRadiusScale ) { - m_padRoundRectRadiusScale = std::max( 0.0, std::min( aRadiusScale, 0.5 ) ); + m_roundedCornerScale = std::max( 0.0, std::min( aRadiusScale, 0.5 ) ); m_shapesDirty = true; } @@ -185,7 +185,7 @@ void D_PAD::SetRoundRectRadiusRatio( double aRadiusScale ) void D_PAD::SetChamferRectRatio( double aChamferScale ) { - m_padChamferRectScale = std::max( 0.0, std::min( aChamferScale, 0.5 ) ); + m_chamferScale = std::max( 0.0, std::min( aChamferScale, 0.5 ) ); m_shapesDirty = true; } diff --git a/pcbnew/class_pad.h b/pcbnew/class_pad.h index c34f8e2941..1301ff9e75 100644 --- a/pcbnew/class_pad.h +++ b/pcbnew/class_pad.h @@ -68,7 +68,8 @@ public: // Do not create a copy constructor & operator=. // The ones generated by the compiler are adequate. - /* Default layers used for pads, according to the pad type. + /* + * Default layers used for pads, according to the pad type. * this is default values only, they can be changed for a given pad */ static LSET StandardMask(); ///< layer set for a through hole pad @@ -229,14 +230,15 @@ public: const wxPoint& GetOffset() const { return m_Offset; } /** - * Has meaning only for free shape pads. + * Has meaning only for custom shape pads. * add a free shape to the shape list. * the shape can be * a polygon (outline can have a thickness) * a thick segment - * a filled circle or ring ( if thickness == 0, this is a filled circle, else a ring) + * a filled circle (thickness == 0) or ring + * a filled rect (thickness == 0) or rectangular outline * a arc - * a curve + * a bezier curve */ void AddPrimitivePoly( const SHAPE_POLY_SET& aPoly, int aThickness ); void AddPrimitivePoly( const std::vector& aPoly, int aThickness ); @@ -378,7 +380,13 @@ public: /** * Function GetEffectiveShapes - * Returns a list of SHAPE objects representing the pad's copper. + * Some pad shapes can be complex (rounded/chamfered rectangle), even without considering + * custom shapes. This routine returns a list of simple shapes which make up the pad for + * use with routing, collision determiniation, etc. + * + * Note that this list can contain a SHAPE_SIMPLE (a simple single-outline non-intersecting + * polygon), but should never contain a SHAPE_POLY_LIST (a complex polygon consisting of + * multiple outlines and/or holes). */ const std::vector>& GetEffectiveShapes() const; @@ -408,13 +416,13 @@ public: /** * Function GetSolderMaskMargin * @return the margin for the solder mask layer - * usually > 0 (mask shape bigger than pad + * usually > 0 (mask shape bigger than pad) * For pads also on copper layers, the value (used to build a default shape) is * 1 - the local value * 2 - if 0, the parent footprint value * 3 - if 0, the global value - * For pads NOT on copper layers, the value is the local value because there is - * not default shape to build + * For pads NOT on copper layers, the value is the local value because there is no default + * shape to build */ int GetSolderMaskMargin() const; @@ -430,7 +438,7 @@ public: * 3 - if 0, the global value * * For pads NOT on copper layers, the value is the local value because there is - * not default shape to build + * no default shape to build */ wxSize GetSolderPasteMargin() const; @@ -443,6 +451,11 @@ public: */ ZONE_CONNECTION GetEffectiveZoneConnection() const; + /** + * Set the width of the thermal spokes connecting the pad to a zone. If != 0 this will + * override similar settings in the parent footprint and zone. + * @param aWidth + */ void SetThermalWidth( int aWidth ) { m_ThermalWidth = aWidth; } int GetThermalWidth() const; @@ -451,7 +464,7 @@ public: /** * Function SetRoundRectCornerRadius - * Has meaning only for rounded rect pads + * has meaning only for rounded rect pads * @return The radius of the rounded corners for this pad. */ void SetRoundRectCornerRadius( double aRadius ); @@ -461,28 +474,24 @@ public: /** * 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 + * Set the ratio between the smaller X or Y size and the rounded corner radius. + * Cannot be > 0.5; the normalized IPC-7351C value is 0.25 */ void SetRoundRectRadiusRatio( double aRadiusScale ); - double GetRoundRectRadiusRatio() const { return m_padRoundRectRadiusScale; } + double GetRoundRectRadiusRatio() const { return m_roundedCornerScale; } /** * has meaning only for chamfered rect pads - * Set the ratio between the smaller Y or Y size and the radius - * of the rounded corners. - * Cannot be < 0.5 and obviously must be > 0 + * Set the ratio between the smaller X or Y size and chamfered corner size. + * Cannot be < 0.5. */ void SetChamferRectRatio( double aChamferScale ); - double GetChamferRectRatio() const { return m_padChamferRectScale; } + double GetChamferRectRatio() const { return m_chamferScale; } /** * has meaning only for chamfered rect pads - * set the position of the chamfer for a 0 orientation, one of - * RECT_CHAMFER_TOP_LEFT, RECT_CHAMFER_TOP_RIGHT, - * RECT_CHAMFER_BOTTOM_LEFT, RECT_CHAMFER_BOTTOM_RIGHT + * set the position of the chamfers for orientation 0. + * @param aPositions a bit-set of RECT_CHAMFER_POSITIONS */ void SetChamferPositions( int aPositions ) { m_chamferPositions = aPositions; } int GetChamferPositions() const { return m_chamferPositions; } @@ -509,7 +518,10 @@ public: return wxT( "PAD" ); } - // Virtual function: + /** + * Function GetBoundingBox + * The bounding box is cached, so this will be efficient most of the time. + */ const EDA_RECT GetBoundingBox() const override; ///> Set absolute coordinates. @@ -541,13 +553,13 @@ public: /** * Function ShowPadShape - * @return the name of the shape + * @return the GUI-appropriate name of the shape */ wxString ShowPadShape() const; /** * Function ShowPadAttr - * @return the name of the pad type (attribute) : STD, SMD ... + * @return the GUI-appropriate description of the pad type (attribute) : Std, SMD ... */ wxString ShowPadAttr() const; @@ -570,7 +582,8 @@ public: bool PadShouldBeNPTH() const; /** - * Rebuilds the shape cache for the pad and clears the dirty bit + * Rebuilds the effective shape cache (and bounding box and radius) for the pad and clears + * the dirty bit. */ void BuildEffectiveShapes() const; @@ -597,17 +610,18 @@ private: void addPadPrimitivesToPolygon( SHAPE_POLY_SET* aMergedPolygon, int aError ) const; private: - wxString m_name; ///< pad name (pin number in schematic) - wxString m_pinFunction; ///< pin function in schematic + wxString m_name; // Pad name (pin number in schematic) + wxString m_pinFunction; // Pin function in schematic - wxPoint m_Pos; ///< pad Position on board + wxPoint m_Pos; // Pad Position on board - PAD_SHAPE_T m_padShape; ///< Shape: PAD_SHAPE_CIRCLE, PAD_SHAPE_RECT, - ///< PAD_SHAPE_OVAL, PAD_SHAPE_TRAPEZOID, - ///< PAD_SHAPE_ROUNDRECT, PAD_SHAPE_POLYGON - - // Edit definitions of primitives for custom pad shapes. In local coordinates relative - // to m_Pos (NOT shapePos) at orient 0. + PAD_SHAPE_T m_padShape; // Shape: PAD_SHAPE_CIRCLE, PAD_SHAPE_RECT, + // PAD_SHAPE_OVAL, PAD_SHAPE_TRAPEZOID, + // PAD_SHAPE_ROUNDRECT, PAD_SHAPE_POLYGON + /* + * Editing definitions of primitives for custom pad shapes. In local coordinates relative + * to m_Pos (NOT shapePos) at orient 0. + */ std::vector> m_editPrimitives; mutable bool m_shapesDirty; @@ -616,83 +630,75 @@ private: mutable std::vector> m_effectiveShapes; mutable std::shared_ptr m_effectiveHoleShape; - /** + /* * How to build the custom shape in zone, to create the clearance area: * CUST_PAD_SHAPE_IN_ZONE_OUTLINE = use pad shape * CUST_PAD_SHAPE_IN_ZONE_CONVEXHULL = use the convex hull of the pad shape - * other values are currently reserved */ CUST_PAD_SHAPE_IN_ZONE m_customShapeClearanceArea; - int m_SubRatsnest; ///< variable used in rats nest computations - ///< handle subnet (block) number in ratsnest connection + int m_SubRatsnest; // Variable used to handle subnet (block) number in + // ratsnest computations - wxSize m_Drill; ///< Drill diam (drill shape = PAD_CIRCLE) or drill size - ///< (shape = OVAL) for drill shape = PAD_CIRCLE, drill - ///< diam = m_Drill.x + wxSize m_Drill; // Drill diameter (x == y) or slot dimensions (x != y) + wxSize m_Size; // X and Y size (relative to orient 0) - wxSize m_Size; ///< X and Y size ( relative to orient 0) + PAD_DRILL_SHAPE_T m_drillShape; // PAD_DRILL_SHAPE_CIRCLE, PAD_DRILL_SHAPE_OBLONG - PAD_DRILL_SHAPE_T m_drillShape; ///< PAD_DRILL_SHAPE_CIRCLE, PAD_DRILL_SHAPE_OBLONG + double m_roundedCornerScale; // Scaling factor of min(width, hieght) to corner + // radius, default 0.25 + double m_chamferScale; // Scaling factor of min(width, height) to chamfer + // size, default 0.25 + int m_chamferPositions; // The positions of the chamfers (at orient 0) - double m_padRoundRectRadiusScale; ///< scaling factor from smallest m_Size coord - ///< to corner radius, default 0.25 - double m_padChamferRectScale; ///< scaling factor from smallest m_Size coord - ///< to chamfer value, default 0.25 - int m_chamferPositions; ///< the positions of the chamfers for a 0 orientation + PAD_SHAPE_T m_anchorPadShape; // For custom shaped pads: shape of pad anchor, + // PAD_SHAPE_RECT, PAD_SHAPE_CIRCLE - PAD_SHAPE_T m_anchorPadShape; ///< for custom shaped pads: shape of pad anchor, - ///< PAD_SHAPE_RECT, PAD_SHAPE_CIRCLE - - /** - * 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/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. - * D_PAD::ShapePos() returns the physical shape position according to - * the offset and the pad rotation. + /* + * Most of the time the hole is the center of the shape (m_Offset = 0). But some designers + * use oblong/rect pads with a hole moved to one of the oblong/rect pad shape ends. + * In all cases the hole is at the pad position. This offset is from the hole to the center + * of the pad shape (ie: the copper area around the hole). + * ShapePos() returns the board shape position according to the offset and the pad rotation. */ wxPoint m_Offset; - LSET m_layerMask; ///< Bitwise layer :1= copper layer, 15= cmp, - ///< 2..14 = internal layers - ///< 16 .. 31 = technical layers + LSET m_layerMask; // Bitwise layer: 1 = copper layer, 15 = cmp, + // 2..14 = internal layers, 16..31 = technical layers - wxSize m_DeltaSize; ///< delta on rectangular shapes + wxSize m_DeltaSize; // Delta for PAD_SHAPE_TRAPEZOID; half the delta squeezes + // one end and half expands the other. It is only valid + // to have a single axis be non-0. - wxPoint m_Pos0; ///< Initial Pad position (i.e. pad position relative to the - ///< module anchor, orientation 0) + wxPoint m_Pos0; // Initial Pad position (i.e. pad position relative to the + // module anchor, orientation 0) - PAD_ATTR_T m_Attribute; ///< PAD_ATTRIB_NORMAL, PAD_ATTRIB_SMD, - ///< PAD_ATTRIB_CONN, PAD_ATTRIB_HOLE_NOT_PLATED - PAD_PROP_T m_Property; ///< property in fab files (BGA, FIDUCIAL, TEST POINT, CASTELLATED) + PAD_ATTR_T m_Attribute; // PAD_ATTRIB_NORMAL, PAD_ATTRIB_SMD, PAD_ATTRIB_CONN, + // PAD_ATTRIB_HOLE_NOT_PLATED + PAD_PROP_T m_Property; // Property in fab files (BGA, FIDUCIAL, TESTPOINT, etc.) - double m_Orient; ///< in 1/10 degrees + double m_Orient; // in 1/10 degrees - int m_LengthPadToDie; ///< Length net from pad to die, inside the package + int m_LengthPadToDie; // Length net from pad to die, inside the package - /// Local clearance. When null, the module default value is used. - /// when the module default value is null, the netclass value is used - /// Usually the local clearance is null + /* + * Pad clearances, margins, etc. exist in a hiearchy. If a given level is specified then + * the remaining levels are NOT consulted. + * + * LEVEL 1: (highest priority) local overrides (pad, footprint, etc.) + * LEVEL 2: Rules + * LEVEL 3: Accumulated local settings, netclass settings, & board design settings + * + * These are the LEVEL 1 settings for a pad. + */ int m_LocalClearance; + int m_LocalSolderMaskMargin; // Local solder mask margin + int m_LocalSolderPasteMargin; // Local solder paste margin absolute value + double m_LocalSolderPasteMarginRatio; // Local solder mask margin ratio of pad size + // The final margin is the sum of these 2 values - /// 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 ... - ZONE_CONNECTION m_ZoneConnection; - - int m_ThermalWidth; + ZONE_CONNECTION m_ZoneConnection; // No connection, thermal relief, etc. + int m_ThermalWidth; // Thermal spoke width. int m_ThermalGap; }; diff --git a/pcbnew/dialogs/dialog_pad_properties.cpp b/pcbnew/dialogs/dialog_pad_properties.cpp index 56b13750d8..4aee378704 100644 --- a/pcbnew/dialogs/dialog_pad_properties.cpp +++ b/pcbnew/dialogs/dialog_pad_properties.cpp @@ -815,7 +815,7 @@ void DIALOG_PAD_PROPERTIES::OnPadShapeSelection( wxCommandEvent& event ) case CHOICE_SHAPE_CHAMFERED_RECT: m_shapePropsBook->SetSelection( 3 ); - // A reasonable default is all corners chamferred. + // A reasonable default is all corners chamfered. if( !m_cbTopLeft->GetValue() && !m_cbTopRight->GetValue() && !m_cbBottomLeft->GetValue() && !m_cbBottomRight->GetValue() ) {