/* * This program source code file is part of KiCad, a free EDA CAD application. * * Copyright (C) 2017 Jean-Pierre Charras, jp.charras at wanadoo.fr * Copyright (C) 1992-2017 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 */ /** * @file class_pad.h * @brief Pad object description */ #ifndef PAD_H_ #define PAD_H_ #include #include #include #include #include // PARAM_CFG_ARRAY #include "zones.h" class LINE_READER; class EDA_3D_CANVAS; class EDA_DRAW_PANEL; class MODULE; class TRACK; class MSG_PANEL_INFO; namespace KIGFX { class VIEW; }; // Helper class to store parameters used to draw a pad class PAD_DRAWINFO { public: EDA_DRAW_PANEL* m_DrawPanel; // the EDA_DRAW_PANEL used to draw a PAD ; can be null GR_DRAWMODE m_DrawMode; // the draw mode COLOR4D m_Color; // color used to draw the pad shape , from pad layers and // visible layers COLOR4D m_HoleColor; // color used to draw the pad hole COLOR4D m_NPHoleColor; // color used to draw a pad Not Plated hole int m_PadClearance; // clearance value, used to draw the pad area outlines wxSize m_Mask_margin; // margin, used to draw solder paste when only one layer is shown bool m_Display_padnum; // true to show pad number bool m_Display_netname; // true to show net name bool m_ShowPadFilled; // true to show pad as solid area, false to show pas in // sketch mode bool m_ShowNCMark; // true to show pad not connected mark bool m_ShowNotPlatedHole; // true when the pad hole in not plated, to draw a specific // pad shape bool m_IsPrinting; // true to print, false to display on screen. wxPoint m_Offset; // general draw offset PAD_DRAWINFO(); }; class D_PAD : public BOARD_CONNECTED_ITEM { public: static int m_PadSketchModePenSize; ///< Pen size used to draw pads in sketch mode ///< (mode used to print pads on silkscreen layer) public: D_PAD( MODULE* parent ); // 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. * this is default values only, they can be changed for a given pad */ static LSET StandardMask(); ///< layer set for a through hole pad static LSET SMDMask(); ///< layer set for a SMD pad on Front layer static LSET ConnSMDMask(); ///< layer set for a SMD pad on Front layer ///< used for edge board connectors static LSET UnplatedHoleMask(); ///< layer set for a mechanical unplated through hole pad static inline bool ClassOf( const EDA_ITEM* aItem ) { return aItem && PCB_PAD_T == aItem->Type(); } D_PAD* Next() const { return static_cast( Pnext ); } MODULE* GetParent() const { return (MODULE*) m_Parent; } /** * Imports the pad settings from aMasterPad. * The result is "this" has the same settinds (sizes, shapes ... ) * as aMasterPad * @param aMasterPad = the template pad */ void ImportSettingsFromMaster( const D_PAD& aMasterPad ); /** * @return true if the pad has a footprint parent flipped * (on the back/bottom layer) */ bool IsFlipped() const; /** * Set the pad name (sometimes called pad number, although * it can be an array ref like AA12 * the pad name is limited to 4 ASCII chars */ void SetPadName( const wxString& name ); // Change pad name /** * @return the pad name * the pad name is limited to 4 ASCII chars */ wxString GetPadName() const; /** * @return the pad name in a wxUint32 which is possible * because the pad name is limited to 4 ASCII chars * The packed pad name should be used only to compare 2 * pad names, not to try to print this name */ wxUint32 GetPackedPadName() const { return m_NumPadName; } /** * Function IncrementPadName * * Increments the pad name to the next available name in the module. * * @param aSkipUnconnectable skips any pads that are not connectable (for example NPTH) * @param aFillSequenceGaps if true, the next reference in a sequence * like A1,A3,A4 will be A2. If false, it will be A5. * @return pad name incremented */ bool IncrementPadName( bool aSkipUnconnectable, bool aFillSequenceGaps ); bool PadNameEqual( const D_PAD* other ) const { return m_NumPadName == other->m_NumPadName; // hide tricks behind sensible API } /** * Function GetShape * @return the shape of this pad. */ PAD_SHAPE_T GetShape() const { return m_padShape; } void SetShape( PAD_SHAPE_T aShape ) { m_padShape = aShape; m_boundingRadius = -1; } void SetPosition( const wxPoint& aPos ) override { m_Pos = aPos; } const wxPoint& GetPosition() const override { return m_Pos; } void SetY( int y ) { m_Pos.y = y; } void SetX( int x ) { m_Pos.x = x; } void SetPos0( const wxPoint& aPos ) { m_Pos0 = aPos; } const wxPoint& GetPos0() const { return m_Pos0; } void SetY0( int y ) { m_Pos0.y = y; } void SetX0( int x ) { m_Pos0.x = x; } void SetSize( const wxSize& aSize ) { m_Size = aSize; m_boundingRadius = -1; } const wxSize& GetSize() const { return m_Size; } void SetDelta( const wxSize& aSize ) { m_DeltaSize = aSize; m_boundingRadius = -1; } const wxSize& GetDelta() const { return m_DeltaSize; } void SetDrillSize( const wxSize& aSize ) { m_Drill = aSize; } const wxSize& GetDrillSize() const { return m_Drill; } void SetOffset( const wxPoint& aOffset ) { m_Offset = aOffset; } const wxPoint& GetOffset() const { return m_Offset; } void Flip( const wxPoint& aCentre ) override; /** * Function SetOrientation * sets the rotation angle of the pad. * @param aAngle is tenths of degrees, but will soon be degrees. If it is * outside of 0 - 3600, then it will be normalized before being saved. */ void SetOrientation( double aAngle ); /** * Set orientation in degrees */ void SetOrientationDegrees( double aOrientation ) { SetOrientation( aOrientation*10.0 ); } /** * Function GetOrientation * returns the rotation angle of the pad in tenths of degrees, but soon degrees. */ double GetOrientation() const { return m_Orient; } double GetOrientationDegrees() const { return m_Orient/10.0; } double GetOrientationRadians() const { return m_Orient*M_PI/1800; } void SetDrillShape( PAD_DRILL_SHAPE_T aDrillShape ) { m_drillShape = aDrillShape; } PAD_DRILL_SHAPE_T GetDrillShape() const { return m_drillShape; } /** * Function GetOblongDrillGeometry calculates the start point, end point and width * of an equivalent segment which have the same position and width as the hole * Usefull to plot/draw oblong holes like segments with rounded ends * used in draw and plot functions * @param aStartPoint = first point of the equivalent segment, relative to the pad position. * @param aEndPoint = second point of the equivalent segment, relative to the pad position. * @param aWidth = width equivalent segment. */ void GetOblongDrillGeometry( wxPoint& aStartPoint, wxPoint& aEndPoint, int& aWidth ) const; void SetLayerSet( LSET aLayerMask ) { m_layerMask = aLayerMask; } LSET GetLayerSet() const override { return m_layerMask; } void SetAttribute( PAD_ATTR_T aAttribute ); PAD_ATTR_T GetAttribute() const { return m_Attribute; } void SetPadToDieLength( int aLength ) { m_LengthPadToDie = aLength; } int GetPadToDieLength() const { return m_LengthPadToDie; } int GetLocalSolderMaskMargin() const { return m_LocalSolderMaskMargin; } void SetLocalSolderMaskMargin( int aMargin ) { m_LocalSolderMaskMargin = aMargin; } int GetLocalClearance() const { return m_LocalClearance; } void SetLocalClearance( int aClearance ) { m_LocalClearance = aClearance; } int GetLocalSolderPasteMargin() const { return m_LocalSolderPasteMargin; } void SetLocalSolderPasteMargin( int aMargin ) { m_LocalSolderPasteMargin = aMargin; } double GetLocalSolderPasteMarginRatio() const { return m_LocalSolderPasteMarginRatio; } void SetLocalSolderPasteMarginRatio( double aRatio ) { m_LocalSolderPasteMarginRatio = aRatio; } /** * Function TransformShapeWithClearanceToPolygon * Convert the pad shape to a closed polygon * Used in filling zones calculations * Circles and arcs are approximated by segments * @param aCornerBuffer = a buffer to store the polygon * @param aClearanceValue = the clearance around the pad * @param aCircleToSegmentsCount = the number of segments to approximate a circle * @param aCorrectionFactor = the correction to apply to circles radius to keep * clearance when the circle is approximated by segment bigger or equal * to the real clearance value (usually near from 1.0) */ void TransformShapeWithClearanceToPolygon( SHAPE_POLY_SET& aCornerBuffer, int aClearanceValue, int aCircleToSegmentsCount, double aCorrectionFactor ) const; /** * Function GetClearance * returns the clearance in internal units. If \a aItem is not NULL then the * returned clearance is the greater of this object's clearance and * aItem's clearance. If \a aItem is NULL, then this objects clearance * is returned. * @param aItem is another BOARD_CONNECTED_ITEM or NULL * @return int - the clearance in internal units. */ int GetClearance( BOARD_CONNECTED_ITEM* aItem = NULL ) const override; // Mask margins handling: /** * Function GetSolderMaskMargin * @return the margin for the solder mask layer * usually > 0 (mask shape bigger than pad * value is * 1 - the local value * 2 - if null, the parent footprint value * 1 - if null, the global value */ int GetSolderMaskMargin() const; /** * Function GetSolderPasteMargin * @return the margin for the solder mask layer * usually < 0 (mask shape smaller than pad * because the margin can be dependent on the pad size, the margin has a x and a y value * value is * 1 - the local value * 2 - if null, the parent footprint value * 1 - if null, the global value */ wxSize GetSolderPasteMargin() const; void SetZoneConnection( ZoneConnection aType ) { m_ZoneConnection = aType; } ZoneConnection GetZoneConnection() const; void SetThermalWidth( int aWidth ) { m_ThermalWidth = aWidth; } int GetThermalWidth() const; void SetThermalGap( int aGap ) { m_ThermalGap = aGap; } int GetThermalGap() const; /* drawing functions */ void Draw( EDA_DRAW_PANEL* aPanel, wxDC* aDC, GR_DRAWMODE aDrawMode, const wxPoint& aOffset = ZeroOffset ) override; /** * Function DrawShape * basic function to draw a pad. *

* This function is used by Draw after calculation of parameters (color, ) final * orientation transforms are set. It can also be called to draw a pad on any panel * even if this panel is not a EDA_DRAW_PANEL for instance on a wxPanel inside the * pad editor. *

*/ void DrawShape( EDA_RECT* aClipBox, wxDC* aDC, PAD_DRAWINFO& aDrawInfo ); /** * Function BuildPadPolygon * Has meaning only for polygonal pads (trapezoid and rectangular) * Build the Corner list of the polygonal shape, * depending on shape, extra size (clearance ...) and orientation * @param aCoord = a buffer to fill (4 corners). * @param aInflateValue = wxSize: the clearance or margin value. value > 0: * inflate, < 0 deflate * @param aRotation = full rotation of the polygon */ 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, * depending on shape, extra size (clearance ...) pad and orientation * This function is similar to TransformShapeWithClearanceToPolygon, * but the difference is BuildPadShapePolygon creates a polygon shape exactly * similar to pad shape, which a size inflated by aInflateValue * and TransformShapeWithClearanceToPolygon creates a more complex shape (for instance * a rectangular pad is converted in a rectangulr shape with ronded corners) * @param aCornerBuffer = a buffer to fill. * @param aInflateValue = the clearance or margin value. * value > 0: inflate, < 0 deflate, = 0 : no change * the clearance can have different values for x and y directions * (relative to the pad) * @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/clearance when the arcs are approximated by segments */ void BuildPadShapePolygon( SHAPE_POLY_SET& aCornerBuffer, wxSize aInflateValue, int aSegmentsPerCircle, double aCorrectionFactor ) const; /** * Function BuildPadDrillShapePolygon * Build the Corner list of the polygonal drill shape, * depending on shape pad hole and orientation * @param aCornerBuffer = a buffer to fill. * @param aInflateValue = the clearance or margin value. * value > 0: inflate, < 0 deflate, = 0 : no change * @param aSegmentsPerCircle = number of segments to approximate a circle * (used for round and oblong shapes only(16 to 32 is a good value) * @return false if the pad has no hole, true otherwise */ bool BuildPadDrillShapePolygon( SHAPE_POLY_SET& aCornerBuffer, int aInflateValue, int aSegmentsPerCircle ) const; /** * Function BuildSegmentFromOvalShape * Has meaning only for OVAL (and ROUND) pads * Build an equivalent segment having the same shape as the OVAL shape, * Useful in draw function and in DRC and HitTest functions, * because segments are already well handled by track tests * @param aSegStart = the starting point of the equivalent segment relative to the shape * position. * @param aSegEnd = the ending point of the equivalent segment, relative to the shape position * @param aRotation = full rotation of the segment * @param aRotation = full rotation of the segment * @param aMargin = a margin around the shape (for instance mask margin) * @return the width of the segment */ int BuildSegmentFromOvalShape( wxPoint& aSegStart, wxPoint& aSegEnd, double aRotation, const wxSize& aMargin ) const; void StringPadName( wxString& text ) const; // Return pad name as string in a buffer /** * Function GetBoundingRadius * returns the radius of a minimum sized circle which fully encloses this pad. * The center is the pad position */ int GetBoundingRadius() const { // Any member function which would affect this calculation should set // m_boundingRadius to -1 to re-trigger the calculation from here. // Currently that is only m_Size, m_DeltaSize, and m_padShape accessors. if( m_boundingRadius == -1 ) { m_boundingRadius = boundingRadius(); } return m_boundingRadius; } 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() const { 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 */ int GetSubRatsnest() const { return m_SubRatsnest; } void SetSubRatsnest( int aSubRatsnest ) { m_SubRatsnest = aSubRatsnest; } void GetMsgPanelInfo( std::vector< MSG_PANEL_ITEM >& aList ) override; bool IsOnLayer( LAYER_ID aLayer ) const override { return m_layerMask[aLayer]; } bool HitTest( const wxPoint& aPosition ) const override; wxString GetClass() const override { return wxT( "PAD" ); } // Virtual function: const EDA_RECT GetBoundingBox() const override; ///> Set absolute coordinates. void SetDrawCoord(); ///> Set relative coordinates. void SetLocalCoord(); /** * Function Compare * compares two pads and return 0 if they are equal. * @return int - <0 if left less than right, 0 if equal, >0 if left greater than right. */ static int Compare( const D_PAD* padref, const D_PAD* padcmp ); void Move( const wxPoint& aMoveVector ) override { m_Pos += aMoveVector; SetLocalCoord(); } void Rotate( const wxPoint& aRotCentre, double aAngle ) override; wxString GetSelectMenuText() const override; BITMAP_DEF GetMenuImage() const override; /** * Function ShowPadShape * @return the name of the shape */ wxString ShowPadShape() const; /** * Function ShowPadAttr * @return the name of the pad type (attribute) : STD, SMD ... */ wxString ShowPadAttr() const; /** * Function AppendConfigs * appends to @a aResult the configuration setting accessors which will later * allow reading or writing of configuration file information directly into * this object. */ void AppendConfigs( PARAM_CFG_ARRAY* aResult ); EDA_ITEM* Clone() const override; /** * same as Clone, but returns a D_PAD item. * Useful mainly for pythons scripts, because Clone (virtual function) * returns an EDA_ITEM. */ D_PAD* Duplicate() const { return (D_PAD*) Clone(); } /// @copydoc VIEW_ITEM::ViewGetLayers() virtual void ViewGetLayers( int aLayers[], int& aCount ) const override; /// @copydoc VIEW_ITEM::ViewGetLOD() virtual unsigned int ViewGetLOD( int aLayer, KIGFX::VIEW* aView ) const override; /// @copydoc VIEW_ITEM::ViewBBox() virtual const BOX2I ViewBBox() const override; /** * Function CopyNetlistSettings * copies the netlist settings to \a aPad, and the net name. * Used to copy some pad parameters when replacing a footprint by an other * footprint when reading a netlist, or in exchange footprint dialog * * The netlist settings are all of the #D_PAD settings not define by a #D_PAD in * a netlist. * The copied settings are the net name and optionally include local clearance, etc. * The pad physical geometry settings are not copied. * * @param aPad is the #D_PAD to copy the settings to. * @param aCopyLocalSettings = false to copy only the net name * true to also copy local prms */ void CopyNetlistSettings( D_PAD* aPad, bool aCopyLocalSettings ); #if defined(DEBUG) virtual void Show( int nestLevel, std::ostream& os ) const override { ShowDummy( os ); } #endif private: /** * Function boundingRadius * returns a calculated radius of a bounding circle for this pad. */ 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 #ifndef SWIG /// Pad name (4 char) or a long identifier (used in pad name /// comparisons because this is faster than string comparison) union { #define PADNAMEZ 4 char m_Padname[PADNAMEZ]; // zero padded at end to full size wxUint32 m_NumPadName; // same number of bytes as m_Padname[] }; #endif 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 int m_SubRatsnest; ///< variable used in rats nest computations ///< handle subnet (block) number in ratsnest connection 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_Size; ///< X and Y size ( relative to orient 0) 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 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. */ wxPoint m_Offset; 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 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 double m_Orient; ///< in 1/10 degrees 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 int m_LocalClearance; /// 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; }; #endif // PAD_H_