Add support for custom pad shape. Full support in DRC and PnS.
add option to use shape or convex hull as clearance area in zones. simplify code to handle clearance area
This commit is contained in:
parent
3d1bebe9f8
commit
e2d3fcec02
|
@ -495,8 +495,23 @@ void CINFO3D_VISU::createNewPadWithClearance( const D_PAD* aPad,
|
|||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
wxFAIL_MSG( "CINFO3D_VISU::createNewPadWithClearance - a pad shape type is not implemented" );
|
||||
case PAD_SHAPE_CUSTOM:
|
||||
{
|
||||
SHAPE_POLY_SET polyList; // Will contain the pad outlines in board coordinates
|
||||
polyList.Append( aPad->GetCustomShapeAsPolygon() );
|
||||
aPad->BasicShapesAsPolygonToBoardPosition( &polyList, aPad->ShapePos(), aPad->GetOrientation() );
|
||||
|
||||
if( aClearanceValue )
|
||||
polyList.Inflate( aClearanceValue, 32 );
|
||||
|
||||
// This convert the poly in outline and holes
|
||||
polyList.Simplify( SHAPE_POLY_SET::PM_FAST );
|
||||
polyList.Simplify( SHAPE_POLY_SET::PM_STRICTLY_SIMPLE );
|
||||
|
||||
// Add the PAD polygon
|
||||
Convert_shape_line_polygon_to_triangles( polyList, *aDstContainer, m_biuTo3Dunits, *aPad );
|
||||
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -565,13 +580,10 @@ void CINFO3D_VISU::createNewPad( const D_PAD* aPad,
|
|||
{
|
||||
switch( aPad->GetShape() )
|
||||
{
|
||||
default:
|
||||
wxFAIL_MSG( wxT( "CINFO3D_VISU::createNewPad: found a not implemented pad shape (new shape?)" ) );
|
||||
break;
|
||||
|
||||
case PAD_SHAPE_CIRCLE:
|
||||
case PAD_SHAPE_OVAL:
|
||||
case PAD_SHAPE_ROUNDRECT:
|
||||
case PAD_SHAPE_CUSTOM:
|
||||
createNewPadWithClearance( aPad, aDstContainer, aInflateValue.x );
|
||||
break;
|
||||
|
||||
|
|
|
@ -75,8 +75,13 @@ void CINFO3D_VISU::buildPadShapePolygon( const D_PAD* aPad,
|
|||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
wxFAIL_MSG( wxT( "CINFO3D_VISU::buildPadShapePolygon: found a not implemented pad shape (new shape?)" ) );
|
||||
case PAD_SHAPE_CUSTOM:
|
||||
{
|
||||
SHAPE_POLY_SET polyList; // Will contain the pad outlines in board coordinates
|
||||
polyList.Append( aPad->GetCustomShapeAsPolygon() );
|
||||
aPad->BasicShapesAsPolygonToBoardPosition( &polyList, aPad->ShapePos(), aPad->GetOrientation() );
|
||||
aCornerBuffer.Append( polyList );
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -96,14 +101,15 @@ void CINFO3D_VISU::buildPadShapeThickOutlineAsPolygon( const D_PAD* aPad,
|
|||
return;
|
||||
}
|
||||
|
||||
|
||||
// For other shapes, draw polygon outlines
|
||||
SHAPE_POLY_SET corners;
|
||||
|
||||
unsigned int nr_sides_per_circle = GetNrSegmentsCircle( glm::min( aPad->GetSize().x,
|
||||
aPad->GetSize().y) );
|
||||
|
||||
buildPadShapePolygon( aPad, corners, wxSize( 0, 0 ),
|
||||
nr_sides_per_circle, GetCircleCorrectionFactor( nr_sides_per_circle ) );
|
||||
nr_sides_per_circle,
|
||||
GetCircleCorrectionFactor( nr_sides_per_circle ) );
|
||||
|
||||
// Add outlines as thick segments in polygon buffer
|
||||
|
||||
|
|
|
@ -325,6 +325,10 @@ if( KICAD_USE_OCE )
|
|||
add_definitions( -DKICAD_USE_OCE )
|
||||
endif()
|
||||
|
||||
if( KICAD_USE_CUSTOM_PADS )
|
||||
add_definitions( -DKICAD_USE_CUSTOM_PADS )
|
||||
endif()
|
||||
|
||||
if( USE_WX_GRAPHICS_CONTEXT OR APPLE )
|
||||
add_definitions( -DUSE_WX_GRAPHICS_CONTEXT )
|
||||
endif()
|
||||
|
|
|
@ -379,6 +379,7 @@ set( PCB_COMMON_SRCS
|
|||
../pcbnew/class_mire.cpp
|
||||
../pcbnew/class_module.cpp
|
||||
../pcbnew/class_pad.cpp
|
||||
../pcbnew/class_pad_custom_shape_functions.cpp
|
||||
../pcbnew/class_pad_draw_functions.cpp
|
||||
../pcbnew/class_pcb_text.cpp
|
||||
../pcbnew/class_text_mod.cpp
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
|
||||
add_net
|
||||
allowed
|
||||
anchor
|
||||
angle
|
||||
arc
|
||||
arc_segments
|
||||
|
@ -52,6 +53,9 @@ connect
|
|||
connect_pads
|
||||
copperpour
|
||||
crossbar
|
||||
custom
|
||||
outline
|
||||
convexhull
|
||||
date
|
||||
descr
|
||||
die_length
|
||||
|
@ -117,6 +121,7 @@ none
|
|||
not_allowed
|
||||
np_thru_hole
|
||||
offset
|
||||
options
|
||||
oval
|
||||
pad
|
||||
pads
|
||||
|
@ -135,6 +140,7 @@ placed
|
|||
plus
|
||||
polygon
|
||||
portrait
|
||||
primitives
|
||||
priority
|
||||
pts
|
||||
radius
|
||||
|
|
|
@ -35,6 +35,8 @@ enum PAD_SHAPE_T
|
|||
PAD_SHAPE_OVAL,
|
||||
PAD_SHAPE_TRAPEZOID,
|
||||
PAD_SHAPE_ROUNDRECT,
|
||||
PAD_SHAPE_CUSTOM // A shape defined by user, using a set of basic shapes
|
||||
// (thick segments, circles, arcs, polygons
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -132,6 +132,7 @@ set( PCBNEW_DIALOGS
|
|||
dialogs/dialog_non_copper_zones_properties_base.cpp
|
||||
dialogs/dialog_pad_properties.cpp
|
||||
dialogs/dialog_pad_properties_base.cpp
|
||||
dialogs/dialog_pad_basicshapes_properties.cpp
|
||||
dialogs/dialog_plot_base.cpp
|
||||
dialogs/dialog_plot.cpp
|
||||
dialogs/dialog_position_relative.cpp
|
||||
|
|
|
@ -704,6 +704,18 @@ void D_PAD::TransformShapeWithClearanceToPolygon( SHAPE_POLY_SET& aCornerBuffer,
|
|||
aCornerBuffer.Append( outline );
|
||||
}
|
||||
break;
|
||||
|
||||
case PAD_SHAPE_CUSTOM:
|
||||
{
|
||||
int clearance = KiROUND( aClearanceValue * aCorrectionFactor );
|
||||
|
||||
SHAPE_POLY_SET outline; // Will contain the corners in board coordinates
|
||||
outline.Append( m_customShapeAsPolygon );
|
||||
BasicShapesAsPolygonToBoardPosition( &outline, GetPosition(), GetOrientation() );
|
||||
outline.Inflate( clearance, aCircleToSegmentsCount );
|
||||
aCornerBuffer.Append( outline );
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -730,6 +742,7 @@ void D_PAD::BuildPadShapePolygon( SHAPE_POLY_SET& aCornerBuffer,
|
|||
case PAD_SHAPE_CIRCLE:
|
||||
case PAD_SHAPE_OVAL:
|
||||
case PAD_SHAPE_ROUNDRECT:
|
||||
case PAD_SHAPE_CUSTOM:
|
||||
TransformShapeWithClearanceToPolygon( aCornerBuffer, aInflateValue.x,
|
||||
aSegmentsPerCircle, aCorrectionFactor );
|
||||
break;
|
||||
|
|
|
@ -56,7 +56,6 @@ static wxString LayerMaskDescribe( const BOARD* aBoard, LSET aMask );
|
|||
|
||||
int D_PAD::m_PadSketchModePenSize = 0; // Pen size used to draw pads in sketch mode
|
||||
|
||||
|
||||
D_PAD::D_PAD( MODULE* parent ) :
|
||||
BOARD_CONNECTED_ITEM( parent, PCB_PAD_T )
|
||||
{
|
||||
|
@ -72,6 +71,8 @@ D_PAD::D_PAD( MODULE* parent ) :
|
|||
}
|
||||
|
||||
SetShape( PAD_SHAPE_CIRCLE ); // Default pad shape is PAD_CIRCLE.
|
||||
SetAnchorPadShape( PAD_SHAPE_CIRCLE ); // Default shape for custom shaped pads
|
||||
// is PAD_CIRCLE.
|
||||
SetDrillShape( PAD_DRILL_SHAPE_CIRCLE ); // Default pad drill shape is a circle.
|
||||
m_Attribute = PAD_ATTRIB_STANDARD; // Default pad type is NORMAL (thru hole)
|
||||
m_LocalClearance = 0;
|
||||
|
@ -85,6 +86,8 @@ D_PAD::D_PAD( MODULE* parent ) :
|
|||
m_ThermalWidth = 0; // Use parent setting by default
|
||||
m_ThermalGap = 0; // Use parent setting by default
|
||||
|
||||
m_customShapeClearanceArea = CUST_PAD_SHAPE_IN_ZONE_OUTLINE;
|
||||
|
||||
// Set layers mask to default for a standard thru hole pad.
|
||||
m_layerMask = StandardMask();
|
||||
|
||||
|
@ -160,6 +163,22 @@ int D_PAD::boundingRadius() const
|
|||
radius += 1 + KiROUND( EuclideanNorm( wxSize( x - radius, y - radius )));
|
||||
break;
|
||||
|
||||
case PAD_SHAPE_CUSTOM:
|
||||
radius = 0;
|
||||
|
||||
for( int cnt = 0; cnt < m_customShapeAsPolygon.OutlineCount(); ++cnt )
|
||||
{
|
||||
const SHAPE_LINE_CHAIN& poly = m_customShapeAsPolygon.COutline( cnt );
|
||||
for( int ii = 0; ii < poly.PointCount(); ++ii )
|
||||
{
|
||||
int dist = KiROUND( poly.CPoint( ii ).EuclideanNorm() );
|
||||
radius = std::max( radius, dist );
|
||||
}
|
||||
}
|
||||
|
||||
radius += 1;
|
||||
break;
|
||||
|
||||
default:
|
||||
radius = 0;
|
||||
}
|
||||
|
@ -306,6 +325,32 @@ const EDA_RECT D_PAD::GetBoundingBox() const
|
|||
area.SetSize( dx-x, dy-y );
|
||||
break;
|
||||
|
||||
case PAD_SHAPE_CUSTOM:
|
||||
{
|
||||
SHAPE_POLY_SET polySet( m_customShapeAsPolygon );
|
||||
// Move shape to actual position
|
||||
BasicShapesAsPolygonToBoardPosition( &polySet, GetPosition(), GetOrientation() );
|
||||
quadrant1 = m_Pos;
|
||||
quadrant2 = m_Pos;
|
||||
|
||||
for( int cnt = 0; cnt < polySet.OutlineCount(); ++cnt )
|
||||
{
|
||||
const SHAPE_LINE_CHAIN& poly = polySet.COutline( cnt );
|
||||
|
||||
for( int ii = 0; ii < poly.PointCount(); ++ii )
|
||||
{
|
||||
quadrant1.x = std::min( quadrant1.x, poly.CPoint( ii ).x );
|
||||
quadrant1.y = std::min( quadrant1.y, poly.CPoint( ii ).y );
|
||||
quadrant2.x = std::max( quadrant2.x, poly.CPoint( ii ).x );
|
||||
quadrant2.y = std::max( quadrant2.y, poly.CPoint( ii ).y );
|
||||
}
|
||||
}
|
||||
|
||||
area.SetOrigin( quadrant1 );
|
||||
area.SetEnd( quadrant2 );
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -379,10 +424,48 @@ void D_PAD::Flip( const wxPoint& aCentre )
|
|||
// So the copper layers count is not taken in account
|
||||
SetLayerSet( FlipLayerMask( m_layerMask ) );
|
||||
|
||||
// Flip the basic shapes, in custom pads
|
||||
FlipBasicShapes();
|
||||
|
||||
// m_boundingRadius = -1; the shape has not been changed
|
||||
}
|
||||
|
||||
|
||||
// Flip the basic shapes, in custom pads
|
||||
void D_PAD::FlipBasicShapes()
|
||||
{
|
||||
// Flip custom shapes
|
||||
for( unsigned ii = 0; ii < m_basicShapes.size(); ++ii )
|
||||
{
|
||||
PAD_CS_PRIMITIVE& primitive = m_basicShapes[ii];
|
||||
|
||||
MIRROR( primitive.m_Start.y, 0 );
|
||||
MIRROR( primitive.m_End.y, 0 );
|
||||
primitive.m_ArcAngle = -primitive.m_ArcAngle;
|
||||
|
||||
switch( primitive.m_Shape )
|
||||
{
|
||||
case S_POLYGON: // polygon
|
||||
for( unsigned jj = 0; jj < primitive.m_Poly.size(); jj++ )
|
||||
MIRROR( primitive.m_Poly[jj].y, 0 );
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Flip local coordinates in merged Polygon
|
||||
for( int cnt = 0; cnt < m_customShapeAsPolygon.OutlineCount(); ++cnt )
|
||||
{
|
||||
SHAPE_LINE_CHAIN& poly = m_customShapeAsPolygon.Outline( cnt );
|
||||
|
||||
for( int ii = 0; ii < poly.PointCount(); ++ii )
|
||||
MIRROR( poly.Point( ii ).y, 0 );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void D_PAD::AppendConfigs( PARAM_CFG_ARRAY* aResult )
|
||||
{
|
||||
// Parameters stored in config are only significant parameters
|
||||
|
@ -817,6 +900,17 @@ bool D_PAD::HitTest( const wxPoint& aPosition ) const
|
|||
return TestPointInsidePolygon( (const wxPoint*)&poly.CPoint(0), poly.PointCount(), delta );
|
||||
}
|
||||
break;
|
||||
|
||||
case PAD_SHAPE_CUSTOM:
|
||||
// Check for hit in polygon
|
||||
RotatePoint( &delta, -m_Orient );
|
||||
|
||||
if( m_customShapeAsPolygon.OutlineCount() )
|
||||
{
|
||||
const SHAPE_LINE_CHAIN& poly = m_customShapeAsPolygon.COutline( 0 );
|
||||
return TestPointInsidePolygon( (const wxPoint*)&poly.CPoint(0), poly.PointCount(), delta );
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return false;
|
||||
|
@ -1096,6 +1190,9 @@ wxString D_PAD::ShowPadShape() const
|
|||
case PAD_SHAPE_ROUNDRECT:
|
||||
return _( "Roundrect" );
|
||||
|
||||
case PAD_SHAPE_CUSTOM:
|
||||
return _( "CustomShape" );
|
||||
|
||||
default:
|
||||
return wxT( "???" );
|
||||
}
|
||||
|
@ -1334,4 +1431,9 @@ void D_PAD::ImportSettingsFromMaster( const D_PAD& aMasterPad )
|
|||
default:
|
||||
;
|
||||
}
|
||||
|
||||
// Add or remove custom pad shapes:
|
||||
SetBasicShapes( aMasterPad.GetBasicShapes() );
|
||||
SetAnchorPadShape( aMasterPad.GetAnchorPadShape() );
|
||||
MergeBasicShapesAsPolygon();
|
||||
}
|
||||
|
|
|
@ -38,6 +38,13 @@
|
|||
#include <config_params.h> // PARAM_CFG_ARRAY
|
||||
#include "zones.h"
|
||||
|
||||
class DRAWSEGMENT;
|
||||
|
||||
enum CUST_PAD_SHAPE_IN_ZONE
|
||||
{
|
||||
CUST_PAD_SHAPE_IN_ZONE_OUTLINE,
|
||||
CUST_PAD_SHAPE_IN_ZONE_CONVEXHULL
|
||||
};
|
||||
|
||||
class LINE_READER;
|
||||
class EDA_3D_CANVAS;
|
||||
|
@ -76,6 +83,38 @@ public:
|
|||
PAD_DRAWINFO();
|
||||
};
|
||||
|
||||
/** Helper class to handle a primitive (basic shape: polygon, segment, circle or arc)
|
||||
* to build a custom pad full shape from a set of primitives
|
||||
*/
|
||||
class PAD_CS_PRIMITIVE
|
||||
{
|
||||
public:
|
||||
STROKE_T m_Shape; /// S_SEGMENT, S_ARC, S_CIRCLE, S_POLYGON only (same as DRAWSEGMENT)
|
||||
int m_Thickness; /// thickness of segment or outline
|
||||
/// For filled S_CIRCLE shape, thickness = 0.
|
||||
// if thickness is not = 0 S_CIRCLE shape is a ring
|
||||
int m_Radius; /// radius of a circle
|
||||
double m_ArcAngle; /// angle of an arc, from its starting point, in 0.1 deg
|
||||
wxPoint m_Start; /// is also the center of the circle and arc
|
||||
wxPoint m_End; /// is also the start point of the arc
|
||||
std::vector<wxPoint> m_Poly;
|
||||
|
||||
PAD_CS_PRIMITIVE( STROKE_T aShape ):
|
||||
m_Shape( aShape ), m_Thickness( 0 ), m_Radius( 0 ), m_ArcAngle( 0 )
|
||||
{
|
||||
}
|
||||
|
||||
// Accessors (helpers for arc and circle shapes)
|
||||
wxPoint GetCenter() { return m_Start; } /// returns the center of a circle or arc
|
||||
wxPoint GetArcStart() { return m_End; } /// returns the start point of an arc
|
||||
|
||||
/** Export the PAD_CS_PRIMITIVE parameters to a DRAWSEGMENT
|
||||
* useful to draw a primitive shape
|
||||
* @param aTarget is the DRAWSEGMENT to initialize
|
||||
*/
|
||||
void ExportTo( DRAWSEGMENT* aTarget );
|
||||
};
|
||||
|
||||
|
||||
class D_PAD : public BOARD_CONNECTED_ITEM
|
||||
{
|
||||
|
@ -169,6 +208,43 @@ public:
|
|||
void SetPosition( const wxPoint& aPos ) override { m_Pos = aPos; }
|
||||
const wxPoint& GetPosition() const override { return m_Pos; }
|
||||
|
||||
/**
|
||||
* Function GetAnchorPadShape
|
||||
* @return the shape of the anchor pad shape, for custom shaped pads.
|
||||
*/
|
||||
PAD_SHAPE_T GetAnchorPadShape() const { return m_anchorPadShape; }
|
||||
|
||||
/**
|
||||
* @return the option for the custom pad shape to use as clearance area
|
||||
* in copper zones
|
||||
*/
|
||||
CUST_PAD_SHAPE_IN_ZONE GetCustomShapeInZoneOpt() const
|
||||
{
|
||||
return m_customShapeClearanceArea;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the option for the custom pad shape to use as clearance area
|
||||
* in copper zones
|
||||
* @param aOption is the clearance area shape CUST_PAD_SHAPE_IN_ZONE option
|
||||
*/
|
||||
void SetCustomShapeInZoneOpt( CUST_PAD_SHAPE_IN_ZONE aOption )
|
||||
{
|
||||
m_customShapeClearanceArea = aOption;
|
||||
}
|
||||
|
||||
/**
|
||||
* Function SetAnchorPadShape
|
||||
* Set the shape of the anchor pad for custm shped pads.
|
||||
* @param the shape of the anchor pad shape( currently, only
|
||||
* PAD_SHAPE_RECT or PAD_SHAPE_CIRCLE.
|
||||
*/
|
||||
void SetAnchorPadShape( PAD_SHAPE_T aShape )
|
||||
{
|
||||
m_anchorPadShape = ( aShape == PAD_SHAPE_RECT ) ? PAD_SHAPE_RECT : PAD_SHAPE_CIRCLE;
|
||||
m_boundingRadius = -1;
|
||||
}
|
||||
|
||||
void SetY( int y ) { m_Pos.y = y; }
|
||||
void SetX( int x ) { m_Pos.x = x; }
|
||||
|
||||
|
@ -190,9 +266,80 @@ public:
|
|||
void SetOffset( const wxPoint& aOffset ) { m_Offset = aOffset; }
|
||||
const wxPoint& GetOffset() const { return m_Offset; }
|
||||
|
||||
/**
|
||||
* Has meaning only for free 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 arc
|
||||
*/
|
||||
void AddBasicShape( std::vector<wxPoint>& aPoly, int aThickness ); ///< add a polygonal basic shape
|
||||
void AddBasicShape( wxPoint aStart, wxPoint aEnd, int aThickness ); ///< segment basic shape
|
||||
void AddBasicShape( wxPoint aCenter, int aRadius, int aThickness ); ///< ring or circle basic shape
|
||||
void AddBasicShape( wxPoint aCenter, wxPoint aStart,
|
||||
int aArcAngle, int aThickness ); ///< arc basic shape
|
||||
|
||||
|
||||
/**
|
||||
* Merge all basic shapes, converted to a polygon in one polygon,
|
||||
* in m_customShapeAsPolygon
|
||||
* @return true if OK, false in there is more than one polygon
|
||||
* in m_customShapeAsPolygon
|
||||
* @param aMergedPolygon = the SHAPE_POLY_SET to fill.
|
||||
* if NULL, m_customShapeAsPolygon is the target
|
||||
* @param aCircleToSegmentsCount = number of segment to approximate a circle
|
||||
* (default = 32)
|
||||
* Note: The corners coordinates are relative to the pad position, orientation 0,
|
||||
*/
|
||||
bool MergeBasicShapesAsPolygon( SHAPE_POLY_SET * aMergedPolygon = NULL,
|
||||
int aCircleToSegmentsCount = 32 );
|
||||
|
||||
/**
|
||||
* clear the basic shapes list
|
||||
*/
|
||||
void DeleteBasicShapesList();
|
||||
|
||||
/**
|
||||
* When created, the corners coordinates are relative to the pad position, orientation 0,
|
||||
* in m_customShapeAsPolygon
|
||||
* BasicShapesAsPolygonToBoardPosition transform these coordinates to actual
|
||||
* (board) coordinates
|
||||
* @param aMergedPolygon = the corners coordinates, relative to aPosition and
|
||||
* rotated by aRotation
|
||||
* @param aPosition = the position of the shape (usually the pad shape, but
|
||||
* not always, when moving the pad)
|
||||
* @param aRotation = the rotation of the shape (usually the pad rotation, but
|
||||
* not always, in DRC)
|
||||
*/
|
||||
void BasicShapesAsPolygonToBoardPosition( SHAPE_POLY_SET * aMergedPolygon,
|
||||
wxPoint aPosition, double aRotation ) const;
|
||||
|
||||
/**
|
||||
* Accessor to the basic shape list
|
||||
*/
|
||||
const std::vector<PAD_CS_PRIMITIVE>& GetBasicShapes() const { return m_basicShapes; }
|
||||
|
||||
/**
|
||||
* Accessor to the custom shape as one polygon
|
||||
*/
|
||||
const SHAPE_POLY_SET& GetCustomShapeAsPolygon() const { return m_customShapeAsPolygon; }
|
||||
|
||||
void Flip( const wxPoint& aCentre ) override;
|
||||
|
||||
/**
|
||||
* Flip the basic shapes, in custom pads
|
||||
*/
|
||||
void FlipBasicShapes();
|
||||
|
||||
/**
|
||||
* Import to the basic shape list
|
||||
* @return true if OK, false if issues
|
||||
* (more than one polygon to build the polygon shape list)
|
||||
*/
|
||||
bool SetBasicShapes( const std::vector<PAD_CS_PRIMITIVE>& aBasicShapesList );
|
||||
|
||||
|
||||
/**
|
||||
* Function SetOrientation
|
||||
|
@ -217,7 +364,6 @@ public:
|
|||
|
||||
void SetDrillShape( PAD_DRILL_SHAPE_T aDrillShape )
|
||||
{ m_drillShape = aDrillShape; }
|
||||
|
||||
PAD_DRILL_SHAPE_T GetDrillShape() const { return m_drillShape; }
|
||||
|
||||
/**
|
||||
|
@ -607,6 +753,25 @@ private: // Private variable members:
|
|||
///< PAD_SHAPE_OVAL, PAD_SHAPE_TRAPEZOID,
|
||||
///< PAD_SHAPE_ROUNDRECT, PAD_SHAPE_POLYGON
|
||||
|
||||
/** for free shape pads: a list of basic shapes,
|
||||
* in local coordinates, orient 0, coordinates relative to m_Pos
|
||||
* They are expected to define only one copper area.
|
||||
*/
|
||||
std::vector<PAD_CS_PRIMITIVE> m_basicShapes;
|
||||
|
||||
/** for free shape pads: the set of basic shapes, merged as one polygon,
|
||||
* in local coordinates, orient 0, coordinates relative to m_Pos
|
||||
*/
|
||||
SHAPE_POLY_SET m_customShapeAsPolygon;
|
||||
|
||||
/**
|
||||
* 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
|
||||
|
||||
|
@ -621,6 +786,9 @@ private: // Private variable members:
|
|||
double m_padRoundRectRadiusScale; ///< scaling factor from smallest m_Size coord
|
||||
///< to corner radius, default 0.25
|
||||
|
||||
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).
|
||||
|
|
|
@ -0,0 +1,267 @@
|
|||
/*
|
||||
* 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
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file class_pad_custom_shape_functions.cpp
|
||||
* class D_PAD functions specific to custom shaped pads.
|
||||
*/
|
||||
|
||||
#include <fctsys.h>
|
||||
#include <PolyLine.h>
|
||||
#include <trigo.h>
|
||||
#include <wxstruct.h>
|
||||
|
||||
#include <pcbnew.h>
|
||||
|
||||
#include <class_pad.h>
|
||||
#include <class_drawsegment.h>
|
||||
#include <convert_basic_shapes_to_polygon.h>
|
||||
#include <geometry/shape_rect.h>
|
||||
#include <geometry/convex_hull.h>
|
||||
|
||||
|
||||
void PAD_CS_PRIMITIVE::ExportTo( DRAWSEGMENT* aTarget )
|
||||
{
|
||||
aTarget->SetShape( m_Shape );
|
||||
aTarget->SetWidth( m_Thickness );
|
||||
aTarget->SetStart( m_Start );
|
||||
aTarget->SetEnd( m_End );
|
||||
|
||||
// in a DRAWSEGMENT the radius of a circle is calculated from the
|
||||
// center and one point on the circle outline (stored in m_End)
|
||||
if( m_Shape == S_CIRCLE )
|
||||
{
|
||||
wxPoint end = m_Start;
|
||||
end.x += m_Radius;
|
||||
aTarget->SetEnd( end );
|
||||
}
|
||||
|
||||
aTarget->SetAngle( m_ArcAngle );
|
||||
aTarget->SetPolyPoints( m_Poly );
|
||||
}
|
||||
|
||||
/*
|
||||
* Has meaning only for free shape pads.
|
||||
* add a free shape to the shape list.
|
||||
* the shape is a polygon (can be with thick outline), segment, circle or arc
|
||||
*/
|
||||
void D_PAD::AddBasicShape( std::vector<wxPoint>& aPoly, int aThickness )
|
||||
{
|
||||
PAD_CS_PRIMITIVE shape( S_POLYGON );
|
||||
shape.m_Poly = aPoly;
|
||||
shape.m_Thickness = aThickness;
|
||||
m_basicShapes.push_back( shape );
|
||||
|
||||
MergeBasicShapesAsPolygon();
|
||||
}
|
||||
|
||||
|
||||
void D_PAD::AddBasicShape( wxPoint aStart, wxPoint aEnd, int aThickness )
|
||||
{
|
||||
PAD_CS_PRIMITIVE shape( S_SEGMENT );
|
||||
shape.m_Start = aStart;
|
||||
shape.m_End = aEnd;
|
||||
shape.m_Thickness = aThickness;
|
||||
m_basicShapes.push_back( shape );
|
||||
|
||||
MergeBasicShapesAsPolygon();
|
||||
}
|
||||
|
||||
|
||||
void D_PAD::AddBasicShape( wxPoint aCenter, wxPoint aStart, int aArcAngle, int aThickness )
|
||||
{
|
||||
PAD_CS_PRIMITIVE shape( S_ARC );
|
||||
shape.m_Start = aCenter;
|
||||
shape.m_End = aStart;
|
||||
shape.m_ArcAngle = aArcAngle;
|
||||
shape.m_Thickness = aThickness;
|
||||
m_basicShapes.push_back( shape );
|
||||
|
||||
MergeBasicShapesAsPolygon();
|
||||
}
|
||||
|
||||
|
||||
void D_PAD::AddBasicShape( wxPoint aCenter, int aRadius, int aThickness )
|
||||
{
|
||||
PAD_CS_PRIMITIVE shape( S_CIRCLE );
|
||||
shape.m_Start = aCenter;
|
||||
shape.m_Radius = aRadius;
|
||||
shape.m_Thickness = aThickness;
|
||||
m_basicShapes.push_back( shape );
|
||||
|
||||
MergeBasicShapesAsPolygon();
|
||||
}
|
||||
|
||||
|
||||
bool D_PAD::SetBasicShapes( const std::vector<PAD_CS_PRIMITIVE>& aBasicShapesList )
|
||||
{
|
||||
// clear old list
|
||||
m_basicShapes.clear();
|
||||
|
||||
// Import to the basic shape list
|
||||
if( aBasicShapesList.size() )
|
||||
m_basicShapes = aBasicShapesList;
|
||||
|
||||
// Only one polygon is expected (pad area = only one copper area)
|
||||
return MergeBasicShapesAsPolygon();
|
||||
}
|
||||
|
||||
// clear the basic shapes list and associated data
|
||||
void D_PAD::DeleteBasicShapesList()
|
||||
{
|
||||
m_basicShapes.clear();
|
||||
m_customShapeAsPolygon.RemoveAllContours();
|
||||
}
|
||||
|
||||
|
||||
/* Merge all basic shapes, converted to a polygon in one polygon,
|
||||
* return true if OK, false in there is more than one polygon
|
||||
* in aMergedPolygon
|
||||
*/
|
||||
bool D_PAD::MergeBasicShapesAsPolygon( SHAPE_POLY_SET* aMergedPolygon,
|
||||
int aCircleToSegmentsCount )
|
||||
{
|
||||
// if aMergedPolygon == NULL, use m_customShapeAsPolygon as target
|
||||
|
||||
if( !aMergedPolygon )
|
||||
aMergedPolygon = &m_customShapeAsPolygon;
|
||||
|
||||
aMergedPolygon->RemoveAllContours();
|
||||
|
||||
// Add the anchor pad shape in aMergedPolygon, others in aux_polyset:
|
||||
// The anchor pad is always at 0,0
|
||||
switch( GetAnchorPadShape() )
|
||||
{
|
||||
default:
|
||||
case PAD_SHAPE_CIRCLE:
|
||||
TransformCircleToPolygon( *aMergedPolygon, wxPoint( 0,0 ), GetSize().x/2,
|
||||
aCircleToSegmentsCount );
|
||||
break;
|
||||
|
||||
case PAD_SHAPE_RECT:
|
||||
{
|
||||
SHAPE_RECT rect( -GetSize().x/2, -GetSize().y/2, GetSize().x, GetSize().y );
|
||||
aMergedPolygon->AddOutline( rect.Outline() );
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
SHAPE_POLY_SET aux_polyset;
|
||||
|
||||
for( unsigned cnt = 0; cnt < m_basicShapes.size(); ++cnt )
|
||||
{
|
||||
const PAD_CS_PRIMITIVE& bshape = m_basicShapes[cnt];
|
||||
|
||||
switch( bshape.m_Shape )
|
||||
{
|
||||
case S_SEGMENT: // usual segment : line with rounded ends
|
||||
TransformRoundedEndsSegmentToPolygon( aux_polyset,
|
||||
bshape.m_Start, bshape.m_End, aCircleToSegmentsCount, bshape.m_Thickness );
|
||||
break;
|
||||
|
||||
case S_ARC: // Arc with rounded ends
|
||||
TransformArcToPolygon( aux_polyset,
|
||||
bshape.m_Start, bshape.m_End, bshape.m_ArcAngle,
|
||||
aCircleToSegmentsCount, bshape.m_Thickness );
|
||||
break;
|
||||
|
||||
case S_CIRCLE: // ring or circle
|
||||
if( bshape.m_Thickness ) // ring
|
||||
TransformRingToPolygon( aux_polyset,
|
||||
bshape.m_Start, bshape.m_Radius,
|
||||
aCircleToSegmentsCount, bshape.m_Thickness ) ;
|
||||
else // Filled circle
|
||||
TransformCircleToPolygon( aux_polyset,
|
||||
bshape.m_Start, bshape.m_Radius,
|
||||
aCircleToSegmentsCount ) ;
|
||||
break;
|
||||
|
||||
case S_POLYGON: // polygon
|
||||
if( bshape.m_Poly.size() < 2 )
|
||||
break; // Malformed polygon.
|
||||
|
||||
{
|
||||
// Insert the polygon:
|
||||
const std::vector< wxPoint>& poly = bshape.m_Poly;
|
||||
aux_polyset.NewOutline();
|
||||
|
||||
if( bshape.m_Thickness )
|
||||
{
|
||||
SHAPE_POLY_SET polyset;
|
||||
polyset.NewOutline();
|
||||
|
||||
for( unsigned ii = 0; ii < poly.size(); ii++ )
|
||||
polyset.Append( poly[ii].x, poly[ii].y );
|
||||
|
||||
polyset.Inflate( bshape.m_Thickness/2, 32 );
|
||||
|
||||
aux_polyset.Append( polyset );
|
||||
}
|
||||
|
||||
else
|
||||
for( unsigned ii = 0; ii < poly.size(); ii++ )
|
||||
aux_polyset.Append( poly[ii].x, poly[ii].y );
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Merge all polygons:
|
||||
if( aux_polyset.OutlineCount() )
|
||||
{
|
||||
aMergedPolygon->BooleanAdd( aux_polyset, SHAPE_POLY_SET::PM_FAST );
|
||||
aMergedPolygon->Fracture( SHAPE_POLY_SET::PM_FAST );
|
||||
}
|
||||
|
||||
m_boundingRadius = -1; // The current bouding radius is no more valid.
|
||||
|
||||
return aMergedPolygon->OutlineCount() <= 1;
|
||||
}
|
||||
|
||||
void D_PAD::BasicShapesAsPolygonToBoardPosition( SHAPE_POLY_SET * aMergedPolygon,
|
||||
wxPoint aPosition, double aRotation ) const
|
||||
{
|
||||
if( aMergedPolygon->OutlineCount() == 0 )
|
||||
return;
|
||||
|
||||
// Move, rotate, ... coordinates in aMergedPolygon according to the
|
||||
// pad position and orientation
|
||||
for( int cnt = 0; cnt < aMergedPolygon->OutlineCount(); ++cnt )
|
||||
{
|
||||
SHAPE_LINE_CHAIN& poly = aMergedPolygon->Outline( cnt );
|
||||
|
||||
for( int ii = 0; ii < poly.PointCount(); ++ii )
|
||||
{
|
||||
wxPoint corner( poly.Point( ii ).x, poly.Point( ii ).y );
|
||||
RotatePoint( &corner, aRotation );
|
||||
corner += aPosition;
|
||||
|
||||
poly.Point( ii ).x = corner.x;
|
||||
poly.Point( ii ).y = corner.y;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -460,6 +460,93 @@ void D_PAD::DrawShape( EDA_RECT* aClipBox, wxDC* aDC, PAD_DRAWINFO& aDrawInfo )
|
|||
}
|
||||
break;
|
||||
|
||||
case PAD_SHAPE_CUSTOM:
|
||||
{
|
||||
// The full shape has 2 items
|
||||
// 1- The anchor pad: a round or rect pad located at pad position
|
||||
// 2- The custom complex shape
|
||||
// Note: The anchor pad shape is containing by the custom complex shape polygon
|
||||
// The anchor pad is shown to help user to see where is the anchor, only in sketch mode
|
||||
// (In filled mode, it is merged with the basic shapes)
|
||||
wxPoint pad_pos = GetPosition() - aDrawInfo.m_Offset;
|
||||
|
||||
// In sketch mode only: Draw the anchor pad: a round or rect pad
|
||||
if( !aDrawInfo.m_ShowPadFilled )
|
||||
{
|
||||
if( GetAnchorPadShape() == PAD_SHAPE_RECT )
|
||||
{
|
||||
wxPoint poly[4];
|
||||
poly[0] = wxPoint( - halfsize.x, - halfsize.y );
|
||||
poly[1] = wxPoint( - halfsize.x, + halfsize.y );
|
||||
poly[2] = wxPoint( + halfsize.x, + halfsize.y );
|
||||
poly[3] = wxPoint( + halfsize.x, - halfsize.y );
|
||||
|
||||
for( int ii = 0; ii < 4; ++ii )
|
||||
{
|
||||
RotatePoint( &poly[ii], m_Orient );
|
||||
poly[ii] += pad_pos;
|
||||
}
|
||||
|
||||
GRClosedPoly( aClipBox, aDC, 4, poly, false, 0,
|
||||
aDrawInfo.m_Color, aDrawInfo.m_Color );
|
||||
}
|
||||
else
|
||||
{
|
||||
GRCircle( aClipBox, aDC, pad_pos.x, pad_pos.y,
|
||||
halfsize.x,
|
||||
m_PadSketchModePenSize, aDrawInfo.m_Color );
|
||||
}
|
||||
}
|
||||
|
||||
SHAPE_POLY_SET outline; // Will contain the corners in board coordinates
|
||||
outline.Append( m_customShapeAsPolygon );
|
||||
BasicShapesAsPolygonToBoardPosition( &outline, pad_pos, GetOrientation() );
|
||||
SHAPE_LINE_CHAIN* poly;
|
||||
|
||||
const int segmentToCircleCount = 32;
|
||||
|
||||
if( aDrawInfo.m_Mask_margin.x )
|
||||
{
|
||||
SHAPE_POLY_SET clearance_outline;
|
||||
clearance_outline.Append( outline );
|
||||
clearance_outline.Inflate( aDrawInfo.m_Mask_margin.x, segmentToCircleCount );
|
||||
|
||||
poly = &clearance_outline.Outline( 0 );
|
||||
}
|
||||
else
|
||||
{
|
||||
// Draw the polygon: only one polygon is expected
|
||||
// However we provide a multi polygon shape drawing
|
||||
// ( for the future or to show a non expected shape )
|
||||
for( int jj = 0; jj < outline.OutlineCount(); ++jj )
|
||||
{
|
||||
poly = &outline.Outline( jj );
|
||||
|
||||
GRClosedPoly( aClipBox, aDC, poly->PointCount(),
|
||||
(wxPoint*)&poly->Point( 0 ), aDrawInfo.m_ShowPadFilled, 0,
|
||||
aDrawInfo.m_Color, aDrawInfo.m_Color );
|
||||
}
|
||||
}
|
||||
|
||||
if( aDrawInfo.m_PadClearance )
|
||||
{
|
||||
SHAPE_POLY_SET clearance_outline;
|
||||
clearance_outline.Append( outline );
|
||||
|
||||
clearance_outline.Inflate( aDrawInfo.m_PadClearance, segmentToCircleCount );
|
||||
|
||||
for( int jj = 0; jj < clearance_outline.OutlineCount(); ++jj )
|
||||
{
|
||||
poly = &clearance_outline.Outline( jj );
|
||||
|
||||
GRClosedPoly( aClipBox, aDC, poly->PointCount(),
|
||||
(wxPoint*)&poly->Point( 0 ), false, 0,
|
||||
aDrawInfo.m_Color, aDrawInfo.m_Color );
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,587 @@
|
|||
/**
|
||||
* @file dialog_pad_basicshapes_properties.cpp
|
||||
* @brief basic shapes for pads crude editor.
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include <fctsys.h>
|
||||
#include <common.h>
|
||||
#include <confirm.h>
|
||||
#include <pcbnew.h>
|
||||
#include <trigo.h>
|
||||
#include <macros.h>
|
||||
#include <wxBasePcbFrame.h>
|
||||
#include <base_units.h>
|
||||
#include <gr_basic.h>
|
||||
|
||||
#include <class_board.h>
|
||||
#include <class_module.h>
|
||||
|
||||
#include <dialog_pad_properties.h>
|
||||
|
||||
DIALOG_PAD_BASICSHAPES_PROPERTIES::DIALOG_PAD_BASICSHAPES_PROPERTIES(
|
||||
wxWindow* aParent, PAD_CS_PRIMITIVE * aShape )
|
||||
: DIALOG_PAD_BASICSHAPES_PROPERTIES_BASE( aParent )
|
||||
{
|
||||
m_shape = aShape;
|
||||
TransferDataToWindow();
|
||||
|
||||
m_sdbSizerOK->SetDefault();
|
||||
GetSizer()->SetSizeHints( this );
|
||||
}
|
||||
|
||||
bool DIALOG_PAD_BASICSHAPES_PROPERTIES::TransferDataToWindow()
|
||||
{
|
||||
if( m_shape == NULL )
|
||||
return false;
|
||||
|
||||
// Shows the text info about circle or ring only for S_CIRCLE shape
|
||||
if( m_shape->m_Shape != S_CIRCLE )
|
||||
m_staticTextInfo->Show( false );
|
||||
|
||||
PutValueInLocalUnits( *m_textCtrlThickness, m_shape->m_Thickness );
|
||||
|
||||
// Update units and parameters names according to the shape to edit:
|
||||
wxString unit = GetAbbreviatedUnitsLabel();
|
||||
m_staticTextPosUnit->SetLabel( unit );
|
||||
m_staticTextEndUnit->SetLabel( unit );
|
||||
m_staticTextThicknessUnit->SetLabel( unit );
|
||||
|
||||
m_staticTextAngleUnit->SetLabel( wxEmptyString );
|
||||
m_staticTextAngle->SetLabel( wxEmptyString );
|
||||
|
||||
switch( m_shape->m_Shape )
|
||||
{
|
||||
case S_SEGMENT: // Segment with rounded ends
|
||||
SetTitle( _( "Segment" ) );
|
||||
PutValueInLocalUnits( *m_textCtrPosX, m_shape->m_Start.x );
|
||||
PutValueInLocalUnits( *m_textCtrPosY, m_shape->m_Start.y );
|
||||
PutValueInLocalUnits( *m_textCtrEndX, m_shape->m_End.x );
|
||||
PutValueInLocalUnits( *m_textCtrEndY, m_shape->m_End.y );
|
||||
m_textCtrAngle->Show( false );
|
||||
m_staticTextAngleUnit->Show( false );
|
||||
m_staticTextAngle->Show( false );
|
||||
break;
|
||||
|
||||
case S_ARC: // Arc with rounded ends
|
||||
SetTitle( _( "Arc" ) );
|
||||
m_staticTextPosEnd->SetLabel( _( "Center" ) );
|
||||
PutValueInLocalUnits( *m_textCtrEndX, m_shape->m_Start.x ); // Start point of arc
|
||||
PutValueInLocalUnits( *m_textCtrEndY, m_shape->m_Start.y );
|
||||
PutValueInLocalUnits( *m_textCtrPosX, m_shape->m_End.x ); // arc center
|
||||
PutValueInLocalUnits( *m_textCtrPosY, m_shape->m_End.y );
|
||||
m_textCtrAngle->SetValue( FMT_ANGLE( m_shape->m_ArcAngle ) );
|
||||
m_staticTextAngle->SetLabel( _( "Angle" ) );
|
||||
m_staticTextAngleUnit->SetLabel( _( "degree" ) );
|
||||
break;
|
||||
|
||||
case S_CIRCLE: // ring or circle
|
||||
if( m_shape->m_Thickness )
|
||||
SetTitle( _( "Ring" ) );
|
||||
else
|
||||
SetTitle( _( "Circle" ) );
|
||||
|
||||
// End point does not exist for a circle or ring:
|
||||
m_textCtrEndX->Show( false );
|
||||
m_textCtrEndY->Show( false );
|
||||
m_staticTextPosEnd->Show( false );
|
||||
m_staticTextEndUnit->Show( false );
|
||||
m_staticTextEndX->Show( false );
|
||||
m_staticTextEndY->Show( false );
|
||||
|
||||
// Circle center uses position controls:
|
||||
m_staticTextPosStart->SetLabel( _( "Center" ) );
|
||||
PutValueInLocalUnits( *m_textCtrPosX, m_shape->m_Start.x );
|
||||
PutValueInLocalUnits( *m_textCtrPosY, m_shape->m_Start.y );
|
||||
PutValueInLocalUnits( *m_textCtrAngle, m_shape->m_Radius );
|
||||
m_staticTextAngleUnit->SetLabel( unit );
|
||||
m_staticTextAngle->SetLabel( _( "Radius" ) );
|
||||
break;
|
||||
|
||||
case S_POLYGON: // polygon
|
||||
SetTitle( "Polygon" );
|
||||
m_staticTextPosStart->SetLabel( wxEmptyString );
|
||||
m_staticTextPosEnd->SetLabel( wxEmptyString );
|
||||
m_staticTextAngle->SetLabel( _( "corners count" ) );
|
||||
m_textCtrAngle->SetValue( wxString::Format( "%d", m_shape->m_Poly.size() ) );
|
||||
break;
|
||||
|
||||
default:
|
||||
SetTitle( "Unknown basic shape" );
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DIALOG_PAD_BASICSHAPES_PROPERTIES::TransferDataFromWindow()
|
||||
{
|
||||
// Transfer data out of the GUI.
|
||||
m_shape->m_Thickness = ValueFromString( g_UserUnit, m_textCtrlThickness->GetValue() );
|
||||
|
||||
switch( m_shape->m_Shape )
|
||||
{
|
||||
case S_SEGMENT: // Segment with rounded ends
|
||||
m_shape->m_Start.x = ValueFromString( g_UserUnit, m_textCtrPosX->GetValue() );
|
||||
m_shape->m_Start.y = ValueFromString( g_UserUnit, m_textCtrPosY->GetValue() );
|
||||
m_shape->m_End.x = ValueFromString( g_UserUnit, m_textCtrEndX->GetValue() );
|
||||
m_shape->m_End.y = ValueFromString( g_UserUnit, m_textCtrEndY->GetValue() );
|
||||
break;
|
||||
|
||||
case S_ARC: // Arc with rounded ends
|
||||
// Start point of arc
|
||||
m_shape->m_Start.x = ValueFromString( g_UserUnit, m_textCtrEndX->GetValue() );
|
||||
m_shape->m_Start.y = ValueFromString( g_UserUnit, m_textCtrEndY->GetValue() );
|
||||
// arc center
|
||||
m_shape->m_End.x = ValueFromString( g_UserUnit, m_textCtrPosX->GetValue() );
|
||||
m_shape->m_End.y = ValueFromString( g_UserUnit, m_textCtrPosY->GetValue() );
|
||||
m_shape->m_ArcAngle = ValueFromString( DEGREES, m_textCtrAngle->GetValue() );
|
||||
break;
|
||||
|
||||
case S_CIRCLE: // ring or circle
|
||||
m_shape->m_Start.x = ValueFromString( g_UserUnit, m_textCtrPosX->GetValue() );
|
||||
m_shape->m_Start.y = ValueFromString( g_UserUnit, m_textCtrPosY->GetValue() );
|
||||
//radius
|
||||
m_shape->m_Radius = ValueFromString( g_UserUnit, m_textCtrAngle->GetValue() );
|
||||
break;
|
||||
|
||||
case S_POLYGON: // polygon
|
||||
// polygon has a specific dialog editor. No nothing here
|
||||
break;
|
||||
|
||||
default:
|
||||
SetTitle( "Unknown basic shape" );
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
DIALOG_PAD_BASIC_SHP_POLY_PROPS::DIALOG_PAD_BASIC_SHP_POLY_PROPS(
|
||||
wxWindow* aParent, PAD_CS_PRIMITIVE * aShape )
|
||||
: DIALOG_PAD_BASIC_SHP_POLY_PROPS_BASE( aParent ),
|
||||
m_shape( aShape ), m_currshape( *m_shape )
|
||||
{
|
||||
TransferDataToWindow();
|
||||
|
||||
m_sdbSizerOK->SetDefault();
|
||||
GetSizer()->SetSizeHints( this );
|
||||
|
||||
// TODO: move wxEVT_GRID_CELL_CHANGING in wxFormbuilder, when it support it
|
||||
m_gridCornersList->Connect( wxEVT_GRID_CELL_CHANGING,
|
||||
wxGridEventHandler( DIALOG_PAD_BASIC_SHP_POLY_PROPS::onCellChanging ), NULL, this );
|
||||
}
|
||||
|
||||
|
||||
DIALOG_PAD_BASIC_SHP_POLY_PROPS::~DIALOG_PAD_BASIC_SHP_POLY_PROPS()
|
||||
{
|
||||
m_gridCornersList->Disconnect( wxEVT_GRID_CELL_CHANGING,
|
||||
wxGridEventHandler( DIALOG_PAD_BASIC_SHP_POLY_PROPS::onCellChanging ), NULL, this );
|
||||
}
|
||||
|
||||
|
||||
bool DIALOG_PAD_BASIC_SHP_POLY_PROPS::TransferDataToWindow()
|
||||
{
|
||||
if( m_shape == NULL )
|
||||
return false;
|
||||
|
||||
// Update units and parameters names according to the shape to edit:
|
||||
wxString unit = GetAbbreviatedUnitsLabel();
|
||||
m_staticTextThicknessUnit->SetLabel( unit );
|
||||
|
||||
PutValueInLocalUnits( *m_textCtrlThickness, m_currshape.m_Thickness );
|
||||
|
||||
// Test for acceptable polygon (more than 2 corners, and not self-intersecting)
|
||||
// A warning message is displayed if not OK
|
||||
Validate();
|
||||
|
||||
// If the number of corners is < 2 (Happens for a new shape, prepare 2 dummy corners
|
||||
while( m_currshape.m_Poly.size() < 2 )
|
||||
m_currshape.m_Poly.push_back( wxPoint( 0, 0 ) );
|
||||
|
||||
// Populates the list of corners
|
||||
int extra_rows = m_currshape.m_Poly.size() - m_gridCornersList->GetNumberRows();
|
||||
|
||||
if( extra_rows > 0 )
|
||||
{
|
||||
m_gridCornersList->AppendRows( extra_rows );
|
||||
}
|
||||
else if( extra_rows < 0 )
|
||||
{
|
||||
extra_rows = -extra_rows;
|
||||
m_gridCornersList->DeleteRows( 0, extra_rows );
|
||||
}
|
||||
|
||||
// enter others corner coordinates
|
||||
wxString msg;
|
||||
for( unsigned row = 0; row < m_currshape.m_Poly.size(); ++row )
|
||||
{
|
||||
// Row label is "Corner x"
|
||||
msg.Printf( "Corner %d", row+1 );
|
||||
m_gridCornersList->SetRowLabelValue( row, msg );
|
||||
|
||||
msg = StringFromValue( g_UserUnit, m_currshape.m_Poly[row].x );
|
||||
m_gridCornersList->SetCellValue( row, 0, msg );
|
||||
|
||||
msg = StringFromValue( g_UserUnit, m_currshape.m_Poly[row].y );
|
||||
m_gridCornersList->SetCellValue( row, 1, msg );
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DIALOG_PAD_BASIC_SHP_POLY_PROPS::TransferDataFromWindow()
|
||||
{
|
||||
if( !Validate() )
|
||||
return false;
|
||||
|
||||
// Transfer data out of the GUI.
|
||||
m_currshape.m_Thickness = ValueFromString( g_UserUnit, m_textCtrlThickness->GetValue() );
|
||||
*m_shape = m_currshape;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// test for a valid polygon (a not self intersectiong polygon)
|
||||
bool DIALOG_PAD_BASIC_SHP_POLY_PROPS::Validate()
|
||||
{
|
||||
if( m_currshape.m_Poly.size() < 3 )
|
||||
{
|
||||
m_staticTextValidate->SetLabel( _(" Incorrect polygon: less than 3 corners" ) );
|
||||
m_staticTextValidate->Show( true );
|
||||
return false;
|
||||
}
|
||||
|
||||
bool valid = true;
|
||||
|
||||
SHAPE_LINE_CHAIN polyline;
|
||||
|
||||
for( unsigned ii = 0; ii < m_currshape.m_Poly.size(); ++ii )
|
||||
polyline.Append( m_currshape.m_Poly[ii].x, m_currshape.m_Poly[ii].y );
|
||||
|
||||
// The polyline describes a polygon: close it.
|
||||
polyline.SetClosed( true );
|
||||
|
||||
// Remove redundant corners:
|
||||
polyline.Simplify();
|
||||
|
||||
if( polyline.PointCount() < 3 )
|
||||
{
|
||||
m_staticTextValidate->SetLabel( _("Incorrect polygon: too few corners after simplification" ) );
|
||||
valid = false;
|
||||
}
|
||||
|
||||
if( valid && polyline.SelfIntersecting() )
|
||||
{
|
||||
m_staticTextValidate->SetLabel( _("Incorrect polygon: self intersecting" ) );
|
||||
valid = false;
|
||||
}
|
||||
|
||||
if( valid )
|
||||
m_staticTextValidate->SetLabel( _("Polygon:" ) );
|
||||
|
||||
if( polyline.PointCount() != (int)m_currshape.m_Poly.size() )
|
||||
{ // Happens after simplification
|
||||
m_currshape.m_Poly.clear();
|
||||
|
||||
for( int ii = 0; ii < polyline.PointCount(); ++ii )
|
||||
m_currshape.m_Poly.push_back( wxPoint( polyline.CPoint( ii ).x, polyline.CPoint( ii ).y ) );
|
||||
|
||||
m_staticTextValidate->SetLabel( _("Polygon: redundant corners removed" ) );
|
||||
}
|
||||
|
||||
return valid;
|
||||
}
|
||||
|
||||
|
||||
void DIALOG_PAD_BASIC_SHP_POLY_PROPS::onButtonAdd( wxCommandEvent& event )
|
||||
{
|
||||
// Insert a new corner after the currently selected:
|
||||
int row = -1;
|
||||
|
||||
if( m_gridCornersList->GetNumberRows() )
|
||||
{
|
||||
wxArrayInt selections = m_gridCornersList->GetSelectedRows();
|
||||
|
||||
if( selections.size() > 0 )
|
||||
{
|
||||
std::sort( selections.begin(), selections.end() );
|
||||
row = selections[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
row = m_gridCornersList->GetGridCursorRow();
|
||||
}
|
||||
|
||||
if( row < 0 )
|
||||
{
|
||||
wxMessageBox( _( "Select a corner before adding a new corner" ) );
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
row = 0;
|
||||
|
||||
m_gridCornersList->SelectRow( row, false );
|
||||
|
||||
if( m_currshape.m_Poly.size() == 0 )
|
||||
m_currshape.m_Poly.push_back( wxPoint(0,0) );
|
||||
else
|
||||
m_currshape.m_Poly.insert( m_currshape.m_Poly.begin() + row + 1, wxPoint(0,0) );
|
||||
|
||||
TransferDataToWindow();
|
||||
|
||||
m_panelPoly->Refresh();
|
||||
}
|
||||
|
||||
void DIALOG_PAD_BASIC_SHP_POLY_PROPS::OnButtonDelete( wxCommandEvent& event )
|
||||
{
|
||||
wxArrayInt selections = m_gridCornersList->GetSelectedRows();
|
||||
std::sort( selections.begin(), selections.end() );
|
||||
|
||||
// remove corners:
|
||||
for( int ii = selections.size()-1; ii >= 0 ; --ii )
|
||||
{
|
||||
m_currshape.m_Poly.erase( m_currshape.m_Poly.begin() + selections[ii] );
|
||||
}
|
||||
|
||||
// Unselect all raws:
|
||||
m_gridCornersList->SelectRow( -1, false );
|
||||
|
||||
TransferDataToWindow();
|
||||
|
||||
m_panelPoly->Refresh();
|
||||
}
|
||||
|
||||
void DIALOG_PAD_BASIC_SHP_POLY_PROPS::onPaintPolyPanel( wxPaintEvent& event )
|
||||
{
|
||||
wxPaintDC dc( m_panelPoly );
|
||||
wxSize dc_size = dc.GetSize();
|
||||
dc.SetDeviceOrigin( dc_size.x / 2, dc_size.y / 2 );
|
||||
|
||||
// Calculate a suitable scale to fit the available draw area
|
||||
wxSize minsize;
|
||||
|
||||
for( unsigned ii = 0; ii < m_currshape.m_Poly.size(); ++ii )
|
||||
{
|
||||
minsize.x = std::max( minsize.x, std::abs( m_currshape.m_Poly[ii].x ) );
|
||||
minsize.y = std::max( minsize.y, std::abs( m_currshape.m_Poly[ii].y ) );
|
||||
}
|
||||
|
||||
// The draw origin is the center of the window.
|
||||
// Therefore the window size is twice the minsize just calculated
|
||||
minsize.x *= 2;
|
||||
minsize.y *= 2;
|
||||
minsize.x += m_currshape.m_Thickness;
|
||||
minsize.y += m_currshape.m_Thickness;
|
||||
|
||||
// Avoid null or too small size:
|
||||
int mindim = Millimeter2iu( 0.5 );
|
||||
|
||||
if( minsize.x < mindim )
|
||||
minsize.x = mindim;
|
||||
|
||||
if( minsize.y < mindim )
|
||||
minsize.y = mindim;
|
||||
|
||||
double scale = std::min( (double) dc_size.x / minsize.x, (double) dc_size.y / minsize.y );
|
||||
|
||||
// Give a margin
|
||||
scale *= 0.9;
|
||||
dc.SetUserScale( scale, scale );
|
||||
|
||||
GRResetPenAndBrush( &dc );
|
||||
|
||||
// Draw X and Y axis. This is particularly useful to show the
|
||||
// reference position of basic shape
|
||||
// Axis are drawn before the polygon to avoid masking segments on axis
|
||||
GRLine( NULL, &dc, -int( dc_size.x/scale ), 0, int( dc_size.x/scale ), 0, 0, LIGHTBLUE ); // X axis
|
||||
GRLine( NULL, &dc, 0, -int( dc_size.y/scale ), 0, int( dc_size.y/scale ), 0, LIGHTBLUE ); // Y axis
|
||||
|
||||
// Draw polygon.
|
||||
// The selected edge(s) are shown in selectcolor, the others in normalcolor.
|
||||
EDA_COLOR_T normalcolor = WHITE;
|
||||
EDA_COLOR_T selectcolor = RED;
|
||||
|
||||
for( unsigned ii = 0; ii < m_currshape.m_Poly.size(); ++ii )
|
||||
{
|
||||
EDA_COLOR_T color = normalcolor;
|
||||
|
||||
if( m_gridCornersList->IsInSelection (ii, 0) ||
|
||||
m_gridCornersList->IsInSelection (ii, 1) ||
|
||||
m_gridCornersList->GetGridCursorRow() == (int)ii )
|
||||
color = selectcolor;
|
||||
|
||||
unsigned jj = ii + 1;
|
||||
|
||||
if( jj >= m_currshape.m_Poly.size() )
|
||||
jj = 0;
|
||||
|
||||
GRLine( NULL, &dc, m_currshape.m_Poly[ii], m_currshape.m_Poly[jj], m_currshape.m_Thickness, color );
|
||||
}
|
||||
|
||||
event.Skip();
|
||||
}
|
||||
|
||||
void DIALOG_PAD_BASIC_SHP_POLY_PROPS::onPolyPanelResize( wxSizeEvent& event )
|
||||
{
|
||||
m_panelPoly->Refresh();
|
||||
event.Skip();
|
||||
}
|
||||
|
||||
void DIALOG_PAD_BASIC_SHP_POLY_PROPS::onGridSelect( wxGridRangeSelectEvent& event )
|
||||
{
|
||||
m_panelPoly->Refresh();
|
||||
}
|
||||
|
||||
void DIALOG_PAD_BASIC_SHP_POLY_PROPS::onCellChanging( wxGridEvent& event )
|
||||
{
|
||||
int row = event.GetRow();
|
||||
int col = event.GetCol();
|
||||
|
||||
wxString msg = event.GetString();
|
||||
|
||||
if( msg.IsEmpty() )
|
||||
return;
|
||||
|
||||
int value = ValueFromString( g_UserUnit, msg );
|
||||
|
||||
if( col == 0 ) // Set the X value
|
||||
m_currshape.m_Poly[row].x = value;
|
||||
else // Set the Y value
|
||||
m_currshape.m_Poly[row].y = value;
|
||||
|
||||
m_currshape.m_Thickness = ValueFromString( g_UserUnit, m_textCtrlThickness->GetValue() );
|
||||
|
||||
Validate();
|
||||
|
||||
m_panelPoly->Refresh();
|
||||
}
|
||||
|
||||
|
||||
// A dialog to apply geometry transforms to a shape or set of shapes
|
||||
// (move, rotate around origin, scaling factor, duplication).
|
||||
DIALOG_PAD_BASICSHAPES_TRANSFORM::DIALOG_PAD_BASICSHAPES_TRANSFORM(
|
||||
wxWindow* aParent,
|
||||
std::vector<PAD_CS_PRIMITIVE*>& aList, bool aShowDuplicate )
|
||||
:DIALOG_PAD_BASICSHAPES_TRANSFORM_BASE( aParent ), m_list( aList )
|
||||
{
|
||||
wxString unit = GetAbbreviatedUnitsLabel();
|
||||
m_staticTextMoveUnit->SetLabel( unit );
|
||||
|
||||
if( !aShowDuplicate ) // means no duplicate transform
|
||||
{
|
||||
m_staticTextDupCnt->Enable( false );
|
||||
m_spinCtrlDuplicateCount->Enable( false );
|
||||
}
|
||||
|
||||
m_sdbSizerOK->SetDefault();
|
||||
GetSizer()->SetSizeHints( this );
|
||||
}
|
||||
|
||||
// A helper function in geometry transform
|
||||
inline void geom_transf( wxPoint& aCoord, wxPoint& aMove, double aScale, double aRotation )
|
||||
{
|
||||
aCoord.x = KiROUND( aCoord.x * aScale );
|
||||
aCoord.y = KiROUND( aCoord.y * aScale );
|
||||
aCoord += aMove;
|
||||
RotatePoint( &aCoord, aRotation );
|
||||
}
|
||||
|
||||
void DIALOG_PAD_BASICSHAPES_TRANSFORM::Transform( std::vector<PAD_CS_PRIMITIVE>* aList, int aDuplicateCount )
|
||||
{
|
||||
// Get parameters from dlg:
|
||||
wxPoint moveVect;
|
||||
moveVect.x = ValueFromString( g_UserUnit, m_textCtrMoveX->GetValue() );
|
||||
moveVect.y = ValueFromString( g_UserUnit, m_textCtrMoveY->GetValue() );
|
||||
|
||||
double rotation = DoubleValueFromString( DEGREES, m_textCtrAngle->GetValue() );
|
||||
double scale = DoubleValueFromString( UNSCALED_UNITS, m_textCtrlScalingFactor->GetValue() );
|
||||
|
||||
// Avoid too small /too large scale, which could create issues:
|
||||
if( scale < 0.01 )
|
||||
scale = 0.01;
|
||||
|
||||
if( scale > 100.0 )
|
||||
scale = 100.0;
|
||||
|
||||
// Transform shapes
|
||||
// shapes are scaled, then moved then rotated.
|
||||
// if aList != NULL, the initial shape will be duplicated, and transform
|
||||
// applied to the duplicated shape
|
||||
do {
|
||||
for( unsigned idx = 0; idx < m_list.size(); ++idx )
|
||||
{
|
||||
PAD_CS_PRIMITIVE* shape;
|
||||
|
||||
if( aList == NULL )
|
||||
shape = m_list[idx];
|
||||
else
|
||||
{
|
||||
PAD_CS_PRIMITIVE new_shape( *m_list[idx] );
|
||||
aList->push_back( new_shape );
|
||||
shape = &aList->back();
|
||||
}
|
||||
|
||||
// Transform parameters common to all shape types (some can be unused)
|
||||
shape->m_Thickness = KiROUND( shape->m_Thickness * scale );
|
||||
geom_transf( shape->m_Start, moveVect, scale, rotation );
|
||||
geom_transf( shape->m_End, moveVect, scale, rotation );
|
||||
|
||||
// specific parameters:
|
||||
switch( shape->m_Shape )
|
||||
{
|
||||
case S_SEGMENT: // Segment with rounded ends
|
||||
break;
|
||||
|
||||
case S_ARC: // Arc with rounded ends
|
||||
break;
|
||||
|
||||
case S_CIRCLE: // ring or circle
|
||||
shape->m_Radius = KiROUND( shape->m_Radius * scale );
|
||||
break;
|
||||
|
||||
case S_POLYGON: // polygon
|
||||
for( unsigned ii = 0; ii < shape->m_Poly.size(); ++ii )
|
||||
geom_transf( shape->m_Poly[ii], moveVect, scale, rotation );
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Prepare new transform on duplication:
|
||||
// Each new item is rotated (or moved) by the transform from the last duplication
|
||||
rotation += rotation;
|
||||
moveVect += moveVect;
|
||||
} while( aList && --aDuplicateCount > 0 );
|
||||
}
|
||||
|
|
@ -6,10 +6,10 @@
|
|||
/*
|
||||
* 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) 2017 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.
|
||||
* 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
|
||||
|
@ -32,6 +32,7 @@
|
|||
#include <fctsys.h>
|
||||
#include <common.h>
|
||||
#include <gr_basic.h>
|
||||
#include <trigo.h>
|
||||
#include <class_drawpanel.h>
|
||||
#include <confirm.h>
|
||||
#include <pcbnew.h>
|
||||
|
@ -53,6 +54,8 @@ static PAD_SHAPE_T code_shape[] = {
|
|||
PAD_SHAPE_RECT,
|
||||
PAD_SHAPE_TRAPEZOID,
|
||||
PAD_SHAPE_ROUNDRECT,
|
||||
PAD_SHAPE_CUSTOM, // choice = CHOICE_SHAPE_CUSTOM_CIRC_ANCHOR
|
||||
PAD_SHAPE_CUSTOM // choice = PAD_SHAPE_CUSTOM_RECT_ANCHOR
|
||||
};
|
||||
|
||||
// the ordered index of the pad shape wxChoice in dialog.
|
||||
|
@ -63,6 +66,8 @@ enum CODE_CHOICE {
|
|||
CHOICE_SHAPE_RECT,
|
||||
CHOICE_SHAPE_TRAPEZOID,
|
||||
CHOICE_SHAPE_ROUNDRECT,
|
||||
CHOICE_SHAPE_CUSTOM_CIRC_ANCHOR,
|
||||
CHOICE_SHAPE_CUSTOM_RECT_ANCHOR
|
||||
};
|
||||
|
||||
|
||||
|
@ -121,33 +126,14 @@ DIALOG_PAD_PROPERTIES::DIALOG_PAD_PROPERTIES( PCB_BASE_FRAME* aParent, D_PAD* aP
|
|||
else // We are editing a "master" pad, i.e. a template to create new pads
|
||||
*m_dummyPad = *m_padMaster;
|
||||
|
||||
// Show the X and Y axis. It is usefull because pad shape can have an offset
|
||||
// or be a complex shape.
|
||||
m_axisOrigin = new KIGFX::ORIGIN_VIEWITEM( KIGFX::COLOR4D(0.0, 0.0, 0.8, 1.0),
|
||||
KIGFX::ORIGIN_VIEWITEM::CROSS,
|
||||
Millimeter2iu( 0.2 ),
|
||||
VECTOR2D( m_dummyPad->GetPosition() ) );
|
||||
m_axisOrigin->SetDrawAtZero( true );
|
||||
|
||||
if( m_parent->IsGalCanvasActive() )
|
||||
{
|
||||
|
||||
m_panelShowPadGal->UseColorScheme( &m_parent->Settings().Colors() );
|
||||
m_panelShowPadGal->SwitchBackend( m_parent->GetGalCanvas()->GetBackend() );
|
||||
m_panelShowPadGal->Show();
|
||||
m_panelShowPad->Hide();
|
||||
m_panelShowPadGal->GetView()->Add( m_dummyPad );
|
||||
m_panelShowPadGal->GetView()->Add( m_axisOrigin );
|
||||
m_panelShowPadGal->StartDrawing();
|
||||
Connect( wxEVT_SIZE, wxSizeEventHandler( DIALOG_PAD_PROPERTIES::OnResize ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
m_panelShowPad->Show();
|
||||
m_panelShowPadGal->Hide();
|
||||
}
|
||||
// Initialize canvas to be able to display the dummy pad:
|
||||
prepareCanvas();
|
||||
|
||||
initValues();
|
||||
|
||||
// Usually, TransferDataToWindow is called by OnInitDialog
|
||||
// calling it here fixes all widgets sizes, and FinishDialogSettings can
|
||||
// safely fix minsizes
|
||||
TransferDataToWindow();
|
||||
|
||||
m_sdbSizerOK->SetDefault();
|
||||
|
@ -157,12 +143,48 @@ DIALOG_PAD_PROPERTIES::DIALOG_PAD_PROPERTIES( PCB_BASE_FRAME* aParent, D_PAD* aP
|
|||
FinishDialogSettings();
|
||||
}
|
||||
|
||||
|
||||
void DIALOG_PAD_PROPERTIES::OnInitDialog( wxInitDialogEvent& event )
|
||||
{
|
||||
m_PadNumCtrl->SetFocus();
|
||||
m_PadNumCtrl->SetSelection( -1, -1 );
|
||||
}
|
||||
|
||||
void DIALOG_PAD_PROPERTIES::prepareCanvas()
|
||||
{
|
||||
// Initialize the canvases (legacy or gal) to display the pad
|
||||
// Enable the suitable canvas and make some inits
|
||||
|
||||
// Show the X and Y axis. It is usefull because pad shape can have an offset
|
||||
// or be a complex shape.
|
||||
KIGFX::COLOR4D axis_color = LIGHTBLUE;
|
||||
|
||||
m_axisOrigin = new KIGFX::ORIGIN_VIEWITEM( axis_color,
|
||||
KIGFX::ORIGIN_VIEWITEM::CROSS,
|
||||
Millimeter2iu( 0.2 ),
|
||||
VECTOR2D( m_dummyPad->GetPosition() ) );
|
||||
m_axisOrigin->SetDrawAtZero( true );
|
||||
|
||||
if( m_parent->IsGalCanvasActive() )
|
||||
{
|
||||
m_panelShowPadGal->UseColorScheme( &m_parent->Settings().Colors() );
|
||||
m_panelShowPadGal->SwitchBackend( m_parent->GetGalCanvas()->GetBackend() );
|
||||
m_panelShowPadGal->Show();
|
||||
m_panelShowPad->Hide();
|
||||
m_panelShowPadGal->GetView()->Add( m_dummyPad );
|
||||
m_panelShowPadGal->GetView()->Add( m_axisOrigin );
|
||||
|
||||
m_panelShowPadGal->StartDrawing();
|
||||
Connect( wxEVT_SIZE, wxSizeEventHandler( DIALOG_PAD_PROPERTIES::OnResize ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
m_panelShowPad->Show();
|
||||
m_panelShowPadGal->Hide();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void DIALOG_PAD_PROPERTIES::OnPaintShowPanel( wxPaintEvent& event )
|
||||
{
|
||||
wxPaintDC dc( m_panelShowPad );
|
||||
|
@ -221,6 +243,7 @@ void DIALOG_PAD_PROPERTIES::OnPaintShowPanel( wxPaintEvent& event )
|
|||
|
||||
// If the pad is a circle, use the x size here instead.
|
||||
int ysize;
|
||||
|
||||
if( m_dummyPad->GetShape() == PAD_SHAPE_CIRCLE )
|
||||
ysize = m_dummyPad->GetSize().x;
|
||||
else
|
||||
|
@ -249,7 +272,63 @@ void DIALOG_PAD_PROPERTIES::OnPaintShowPanel( wxPaintEvent& event )
|
|||
GRResetPenAndBrush( &dc );
|
||||
m_dummyPad->DrawShape( NULL, &dc, drawInfo );
|
||||
|
||||
// Draw X and Y axis. Hhis is particularly useful to show the
|
||||
// draw selected primitives:
|
||||
COLOR4D hcolor = CYAN;
|
||||
long select = m_listCtrlShapes->GetFirstSelected();
|
||||
wxPoint start, end, center;
|
||||
|
||||
while( select >= 0 )
|
||||
{
|
||||
PAD_CS_PRIMITIVE& primitive = m_primitives[select];
|
||||
|
||||
// The best way to calculate parameters to draw a primitive is to
|
||||
// use a dummy DRAWSEGMENT and use its methods
|
||||
// Note: in legacy canvas, the pad has the 0,0 position
|
||||
DRAWSEGMENT dummySegment;
|
||||
primitive.ExportTo( &dummySegment );
|
||||
dummySegment.Rotate( wxPoint( 0, 0), m_dummyPad->GetOrientation() );
|
||||
|
||||
switch( primitive.m_Shape )
|
||||
{
|
||||
case S_SEGMENT: // usual segment : line with rounded ends
|
||||
GRFilledSegment( NULL, &dc, dummySegment.GetStart(), dummySegment.GetEnd(),
|
||||
primitive.m_Thickness, hcolor );
|
||||
break;
|
||||
|
||||
case S_ARC: // Arc with rounded ends
|
||||
GRArc1( NULL, &dc, dummySegment.GetArcEnd(), dummySegment.GetArcStart(),
|
||||
dummySegment.GetCenter(), primitive.m_Thickness, hcolor );
|
||||
break;
|
||||
|
||||
case S_CIRCLE: // ring or circle
|
||||
if( primitive.m_Thickness )
|
||||
{
|
||||
GRCircle( NULL, &dc, dummySegment.GetCenter(), primitive.m_Radius,
|
||||
primitive.m_Thickness, hcolor );
|
||||
}
|
||||
else
|
||||
{
|
||||
GRFilledCircle( NULL, &dc, dummySegment.GetCenter(),
|
||||
primitive.m_Radius, hcolor );
|
||||
}
|
||||
break;
|
||||
|
||||
case S_POLYGON: // polygon
|
||||
{
|
||||
std::vector<wxPoint>& poly = dummySegment.GetPolyPoints();
|
||||
GRClosedPoly( NULL, &dc, poly.size(), &poly[0], /* filled */ true,
|
||||
primitive.m_Thickness, hcolor, hcolor );
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
select = m_listCtrlShapes->GetNextSelected( select );
|
||||
}
|
||||
|
||||
// Draw X and Y axis. This 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,
|
||||
|
@ -376,8 +455,13 @@ void DIALOG_PAD_PROPERTIES::initValues()
|
|||
|
||||
// flip pad's layers
|
||||
m_dummyPad->SetLayerSet( FlipLayerMask( m_dummyPad->GetLayerSet() ) );
|
||||
|
||||
// flip custom pad shapes
|
||||
m_dummyPad->FlipBasicShapes();
|
||||
}
|
||||
|
||||
m_primitives = m_dummyPad->GetBasicShapes();
|
||||
|
||||
m_staticTextWarningPadFlipped->Show(m_isFlipped);
|
||||
|
||||
m_PadNumCtrl->SetValue( m_dummyPad->GetPadName() );
|
||||
|
@ -463,6 +547,11 @@ void DIALOG_PAD_PROPERTIES::initValues()
|
|||
break;
|
||||
}
|
||||
|
||||
if( m_dummyPad->GetCustomShapeInZoneOpt() == CUST_PAD_SHAPE_IN_ZONE_CONVEXHULL )
|
||||
m_ZoneCustomPadShape->SetSelection( 1 );
|
||||
else
|
||||
m_ZoneCustomPadShape->SetSelection( 0 );
|
||||
|
||||
if( m_currentPad )
|
||||
{
|
||||
angle = m_currentPad->GetOrientation();
|
||||
|
@ -531,6 +620,13 @@ void DIALOG_PAD_PROPERTIES::initValues()
|
|||
case PAD_SHAPE_ROUNDRECT:
|
||||
m_PadShape->SetSelection( CHOICE_SHAPE_ROUNDRECT );
|
||||
break;
|
||||
|
||||
case PAD_SHAPE_CUSTOM:
|
||||
if( m_dummyPad->GetAnchorPadShape() == PAD_SHAPE_RECT )
|
||||
m_PadShape->SetSelection( CHOICE_SHAPE_CUSTOM_RECT_ANCHOR );
|
||||
else
|
||||
m_PadShape->SetSelection( CHOICE_SHAPE_CUSTOM_CIRC_ANCHOR );
|
||||
break;
|
||||
}
|
||||
|
||||
m_OrientValue = angle / 10.0;
|
||||
|
@ -566,8 +662,90 @@ void DIALOG_PAD_PROPERTIES::initValues()
|
|||
OnDrillShapeSelected( cmd_event );
|
||||
OnPadShapeSelection( cmd_event );
|
||||
updateRoundRectCornerValues();
|
||||
|
||||
// Update basic shapes list
|
||||
displayBasicShapesList();
|
||||
}
|
||||
|
||||
// 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 ) );
|
||||
}
|
||||
|
||||
void DIALOG_PAD_PROPERTIES::displayBasicShapesList()
|
||||
{
|
||||
m_listCtrlShapes->ClearAll();
|
||||
|
||||
wxListItem itemCol;
|
||||
itemCol.SetImage(-1);
|
||||
|
||||
for( int ii = 0; ii < 5; ++ii )
|
||||
m_listCtrlShapes->InsertColumn(ii, itemCol);
|
||||
|
||||
wxString bs_info[5];
|
||||
|
||||
for( unsigned ii = 0; ii < m_primitives.size(); ++ii )
|
||||
{
|
||||
const PAD_CS_PRIMITIVE& primitive = m_primitives[ii];
|
||||
|
||||
for( unsigned jj = 0; jj < 5; ++jj )
|
||||
bs_info[jj].Empty();
|
||||
|
||||
bs_info[4] = wxString::Format( _( "width %s" ),
|
||||
CoordinateToString( primitive.m_Thickness, true ) );
|
||||
|
||||
switch( primitive.m_Shape )
|
||||
{
|
||||
case S_SEGMENT: // usual segment : line with rounded ends
|
||||
bs_info[0] = _( "Segment" );
|
||||
bs_info[1] = _( "from " ) + formatCoord( primitive.m_Start );
|
||||
bs_info[2] = _( "to " ) + formatCoord( primitive.m_End );
|
||||
break;
|
||||
|
||||
case S_ARC: // Arc with rounded ends
|
||||
bs_info[0] = _( "Arc" );
|
||||
bs_info[1] = _( "center " ) + formatCoord( primitive.m_Start ); // Center
|
||||
bs_info[2] = _( "start " ) + formatCoord( primitive.m_End ); // Start point
|
||||
bs_info[3] = wxString::Format( _( "angle %s" ), FMT_ANGLE( primitive.m_ArcAngle ) );
|
||||
break;
|
||||
|
||||
case S_CIRCLE: // ring or circle
|
||||
if( primitive.m_Thickness )
|
||||
bs_info[0] = _( "ring" );
|
||||
else
|
||||
bs_info[0] = _( "circle" );
|
||||
|
||||
bs_info[1] = formatCoord( primitive.m_Start );
|
||||
bs_info[2] = wxString::Format( _( "radius %s" ),
|
||||
CoordinateToString( primitive.m_Radius, true ) );
|
||||
break;
|
||||
|
||||
case S_POLYGON: // polygon
|
||||
bs_info[0] = "Polygon";
|
||||
bs_info[1] = wxString::Format( _( "corners count %d" ), primitive.m_Poly.size() );
|
||||
break;
|
||||
|
||||
default:
|
||||
bs_info[0] = "Unknown primitive";
|
||||
break;
|
||||
}
|
||||
|
||||
long tmp = m_listCtrlShapes->InsertItem(ii, bs_info[0]);
|
||||
m_listCtrlShapes->SetItemData(tmp, ii);
|
||||
|
||||
for( int jj = 0, col = 0; jj < 5; ++jj )
|
||||
{
|
||||
m_listCtrlShapes->SetItem(tmp, col++, bs_info[jj]);
|
||||
}
|
||||
}
|
||||
|
||||
// Now columns are filled, ensure correct width of columns
|
||||
for( unsigned ii = 0; ii < 5; ++ii )
|
||||
m_listCtrlShapes->SetColumnWidth( ii, wxLIST_AUTOSIZE );
|
||||
}
|
||||
|
||||
void DIALOG_PAD_PROPERTIES::OnResize( wxSizeEvent& event )
|
||||
{
|
||||
|
@ -578,6 +756,8 @@ void DIALOG_PAD_PROPERTIES::OnResize( wxSizeEvent& event )
|
|||
|
||||
void DIALOG_PAD_PROPERTIES::OnPadShapeSelection( wxCommandEvent& event )
|
||||
{
|
||||
bool is_custom = false;
|
||||
|
||||
switch( m_PadShape->GetSelection() )
|
||||
{
|
||||
case CHOICE_SHAPE_CIRCLE:
|
||||
|
@ -622,11 +802,30 @@ void DIALOG_PAD_PROPERTIES::OnPadShapeSelection( wxCommandEvent& event )
|
|||
m_tcCornerSizeRatio->ChangeValue( wxString::Format( "%.1f",
|
||||
m_dummyPad->GetRoundRectRadiusRatio()*100 ) );
|
||||
break;
|
||||
|
||||
case CHOICE_SHAPE_CUSTOM_CIRC_ANCHOR: // PAD_SHAPE_CUSTOM, circular anchor
|
||||
case CHOICE_SHAPE_CUSTOM_RECT_ANCHOR: // PAD_SHAPE_CUSTOM, rect anchor
|
||||
is_custom = true;
|
||||
m_ShapeDelta_Ctrl->Enable( false );
|
||||
m_trapDeltaDirChoice->Enable( false );
|
||||
m_ShapeSize_Y_Ctrl->Enable(
|
||||
m_PadShape->GetSelection() == CHOICE_SHAPE_CUSTOM_RECT_ANCHOR );
|
||||
m_ShapeOffset_X_Ctrl->Enable( false );
|
||||
m_ShapeOffset_Y_Ctrl->Enable( false );
|
||||
break;
|
||||
}
|
||||
|
||||
// A few widgets are enabled only for rounded rect pads:
|
||||
m_tcCornerSizeRatio->Enable( m_PadShape->GetSelection() == CHOICE_SHAPE_ROUNDRECT );
|
||||
|
||||
// PAD_SHAPE_CUSTOM type has constraints for zone connection and thermal shape:
|
||||
// only not connected is allowed to avoid destroying the shape.
|
||||
// Enable/disable options
|
||||
m_ZoneConnectionChoice->Enable( !is_custom );
|
||||
m_ThermalWidthCtrl->Enable( !is_custom );
|
||||
m_ThermalGapCtrl->Enable( !is_custom );
|
||||
m_ZoneCustomPadShape->Enable( is_custom );
|
||||
|
||||
transferDataToPad( m_dummyPad );
|
||||
|
||||
updateRoundRectCornerValues();
|
||||
|
@ -872,6 +1071,14 @@ bool DIALOG_PAD_PROPERTIES::padValuesOK()
|
|||
}
|
||||
}
|
||||
|
||||
if( m_dummyPad->GetShape() == PAD_SHAPE_CUSTOM )
|
||||
{
|
||||
if( !m_dummyPad->MergeBasicShapesAsPolygon( ) )
|
||||
error_msgs.Add(
|
||||
_( "Incorrect pad shape: the shape must be equivalent to only one polygon" ) );
|
||||
}
|
||||
|
||||
|
||||
if( error_msgs.GetCount() )
|
||||
{
|
||||
HTML_MESSAGE_BOX dlg( this, _("Pad setup errors list" ) );
|
||||
|
@ -887,7 +1094,77 @@ void DIALOG_PAD_PROPERTIES::redraw()
|
|||
{
|
||||
if( m_parent->IsGalCanvasActive() )
|
||||
{
|
||||
m_parent->GetGalCanvas()->GetView()->Update( m_dummyPad );
|
||||
auto view = m_panelShowPadGal->GetView();
|
||||
m_panelShowPadGal->StopDrawing();
|
||||
|
||||
view->SetTopLayer( F_SilkS );
|
||||
|
||||
view->Update( m_dummyPad );
|
||||
|
||||
// delete previous items if highlight list
|
||||
while( m_highligth.size() )
|
||||
{
|
||||
delete m_highligth.back(); // the dtor also removes item from view
|
||||
m_highligth.pop_back();
|
||||
}
|
||||
|
||||
// highlight selected primitives:
|
||||
long select = m_listCtrlShapes->GetFirstSelected();
|
||||
|
||||
while( select >= 0 )
|
||||
{
|
||||
PAD_CS_PRIMITIVE& primitive = m_primitives[select];
|
||||
|
||||
DRAWSEGMENT* dummySegment = new DRAWSEGMENT;
|
||||
dummySegment->SetLayer( F_SilkS );
|
||||
primitive.ExportTo( dummySegment );
|
||||
dummySegment->Rotate( wxPoint( 0, 0), m_dummyPad->GetOrientation() );
|
||||
dummySegment->Move( m_dummyPad->GetPosition() );
|
||||
|
||||
// Update selected primitive (highligth selected)
|
||||
switch( primitive.m_Shape )
|
||||
{
|
||||
case S_SEGMENT:
|
||||
case S_ARC:
|
||||
break;
|
||||
|
||||
case S_CIRCLE: // ring or circle
|
||||
if( primitive.m_Thickness == 0 ) // filled circle
|
||||
{ // the filled circle option does not exist in a DRAWSEGMENT
|
||||
// but it is easy to create it with a circle having the
|
||||
// right radius and outline width
|
||||
wxPoint end = dummySegment->GetCenter();
|
||||
end.x += primitive.m_Radius/2;
|
||||
dummySegment->SetEnd( end );
|
||||
dummySegment->SetWidth( primitive.m_Radius );
|
||||
}
|
||||
break;
|
||||
|
||||
case S_POLYGON: // polygon
|
||||
{
|
||||
std::vector<wxPoint>& poly = dummySegment->GetPolyPoints();
|
||||
|
||||
for( unsigned ii = 0; ii < poly.size(); ii++ )
|
||||
{
|
||||
poly[ii] += m_dummyPad->GetPosition();
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
delete dummySegment;
|
||||
dummySegment = nullptr;
|
||||
break;
|
||||
}
|
||||
|
||||
if( dummySegment )
|
||||
{
|
||||
view->Add( dummySegment );
|
||||
m_highligth.push_back( dummySegment );
|
||||
}
|
||||
|
||||
select = m_listCtrlShapes->GetNextSelected( select );
|
||||
}
|
||||
|
||||
BOX2I bbox = m_dummyPad->ViewBBox();
|
||||
|
||||
|
@ -897,14 +1174,15 @@ void DIALOG_PAD_PROPERTIES::redraw()
|
|||
BOX2I drawbox;
|
||||
drawbox.Move( m_dummyPad->GetPosition() );
|
||||
drawbox.Inflate( bbox.GetSize().x*2, bbox.GetSize().y*2 );
|
||||
m_panelShowPadGal->GetView()->SetBoundary( drawbox );
|
||||
view->SetBoundary( drawbox );
|
||||
|
||||
// Autozoom
|
||||
m_panelShowPadGal->GetView()->SetViewport( BOX2D( bbox.GetOrigin(), bbox.GetSize() ) );
|
||||
view->SetViewport( BOX2D( bbox.GetOrigin(), bbox.GetSize() ) );
|
||||
|
||||
// Add a margin
|
||||
m_panelShowPadGal->GetView()->SetScale( m_panelShowPadGal->GetView()->GetScale() * 0.7 );
|
||||
view->SetScale( m_panelShowPadGal->GetView()->GetScale() * 0.7 );
|
||||
|
||||
m_panelShowPadGal->StartDrawing();
|
||||
m_panelShowPadGal->Refresh();
|
||||
}
|
||||
}
|
||||
|
@ -1004,6 +1282,19 @@ bool DIALOG_PAD_PROPERTIES::TransferDataFromWindow()
|
|||
|
||||
m_currentPad->SetPadToDieLength( m_padMaster->GetPadToDieLength() );
|
||||
|
||||
if( m_padMaster->GetShape() != PAD_SHAPE_CUSTOM )
|
||||
m_padMaster->DeleteBasicShapesList();
|
||||
|
||||
|
||||
m_currentPad->SetAnchorPadShape( m_padMaster->GetAnchorPadShape() );
|
||||
m_currentPad->SetBasicShapes( m_padMaster->GetBasicShapes() );
|
||||
|
||||
if( m_isFlipped )
|
||||
{
|
||||
m_currentPad->SetLayerSet( FlipLayerMask( m_currentPad->GetLayerSet() ) );
|
||||
m_currentPad->FlipBasicShapes();
|
||||
}
|
||||
|
||||
if( m_currentPad->GetLayerSet() != m_padMaster->GetLayerSet() )
|
||||
{
|
||||
rastnestIsChanged = true;
|
||||
|
@ -1055,6 +1346,9 @@ bool DIALOG_PAD_PROPERTIES::TransferDataFromWindow()
|
|||
m_currentPad->SetShape( PAD_SHAPE_RECT );
|
||||
}
|
||||
|
||||
// define the way the clearnce area is defined in zones
|
||||
m_currentPad->SetCustomShapeInZoneOpt( m_padMaster->GetCustomShapeInZoneOpt() );
|
||||
|
||||
if( footprint )
|
||||
footprint->CalculateBoundingBox();
|
||||
|
||||
|
@ -1088,7 +1382,11 @@ bool DIALOG_PAD_PROPERTIES::transferDataToPad( D_PAD* aPad )
|
|||
|
||||
aPad->SetAttribute( code_type[m_PadType->GetSelection()] );
|
||||
aPad->SetShape( code_shape[m_PadShape->GetSelection()] );
|
||||
aPad->SetAnchorPadShape( m_PadShape->GetSelection() == CHOICE_SHAPE_CUSTOM_RECT_ANCHOR ?
|
||||
PAD_SHAPE_RECT : PAD_SHAPE_CIRCLE );
|
||||
|
||||
if( aPad->GetShape() == PAD_SHAPE_CUSTOM )
|
||||
aPad->SetBasicShapes( m_primitives );
|
||||
|
||||
// Read pad clearances values:
|
||||
aPad->SetLocalClearance( ValueFromTextCtrl( *m_NetClearanceValueCtrl ) );
|
||||
|
@ -1158,6 +1456,10 @@ bool DIALOG_PAD_PROPERTIES::transferDataToPad( D_PAD* aPad )
|
|||
if( aPad->GetShape() == PAD_SHAPE_CIRCLE )
|
||||
y = x;
|
||||
|
||||
// for custom shped pads, the pad size is the anchor pad size:
|
||||
if( aPad->GetShape() == PAD_SHAPE_CUSTOM && aPad->GetAnchorPadShape() == PAD_SHAPE_CIRCLE )
|
||||
y = x;
|
||||
|
||||
aPad->SetSize( wxSize( x, y ) );
|
||||
|
||||
// Read pad length die
|
||||
|
@ -1248,6 +1550,27 @@ bool DIALOG_PAD_PROPERTIES::transferDataToPad( D_PAD* aPad )
|
|||
aPad->SetDelta( wxSize( 0, 0 ) );
|
||||
break;
|
||||
|
||||
case PAD_SHAPE_CUSTOM:
|
||||
aPad->SetOffset( wxPoint( 0, 0 ) );
|
||||
aPad->SetDelta( wxSize( 0, 0 ) );
|
||||
|
||||
// The pad custom has a "anchor pad" (a basic shape: round or rect pad)
|
||||
// that is the minimal area of this pad, and is usefull to ensure a hole
|
||||
// diameter is acceptable, and is used in Gerber files as flashed area
|
||||
// reference
|
||||
if( aPad->GetAnchorPadShape() == PAD_SHAPE_CIRCLE )
|
||||
{
|
||||
x = aPad->GetSize().x;
|
||||
aPad->SetSize( wxSize( x, x ) );
|
||||
}
|
||||
|
||||
// define the way the clearance area is defined in zones
|
||||
aPad->SetCustomShapeInZoneOpt( m_ZoneCustomPadShape->GetSelection() == 0 ?
|
||||
CUST_PAD_SHAPE_IN_ZONE_OUTLINE :
|
||||
CUST_PAD_SHAPE_IN_ZONE_CONVEXHULL );
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
;
|
||||
}
|
||||
|
@ -1361,3 +1684,227 @@ void DIALOG_PAD_PROPERTIES::OnValuesChanged( wxCommandEvent& event )
|
|||
redraw();
|
||||
}
|
||||
}
|
||||
|
||||
void DIALOG_PAD_PROPERTIES::editBasicShape()
|
||||
{
|
||||
long select = m_listCtrlShapes->GetFirstSelected();
|
||||
|
||||
if( select < 0 )
|
||||
{
|
||||
wxMessageBox( _( "No shape selected" ) );
|
||||
return;
|
||||
}
|
||||
|
||||
PAD_CS_PRIMITIVE& shape = m_primitives[select];
|
||||
|
||||
if( shape.m_Shape == S_POLYGON )
|
||||
{
|
||||
DIALOG_PAD_BASIC_SHP_POLY_PROPS dlg( this, &shape );
|
||||
|
||||
if( dlg.ShowModal() != wxID_OK )
|
||||
return;
|
||||
|
||||
dlg.TransferDataFromWindow();
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
DIALOG_PAD_BASICSHAPES_PROPERTIES dlg( this, &shape );
|
||||
|
||||
if( dlg.ShowModal() != wxID_OK )
|
||||
return;
|
||||
|
||||
dlg.TransferDataFromWindow();
|
||||
}
|
||||
|
||||
displayBasicShapesList();
|
||||
|
||||
if( m_canUpdate )
|
||||
{
|
||||
transferDataToPad( m_dummyPad );
|
||||
redraw();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void DIALOG_PAD_PROPERTIES::OnPrimitiveSelection( wxListEvent& event )
|
||||
{
|
||||
// Called on a double click on the basic shapes list
|
||||
// To Do: highligth the primitive(s) currently selected.
|
||||
redraw();
|
||||
}
|
||||
|
||||
|
||||
/// Called on a double click on the basic shapes list
|
||||
void DIALOG_PAD_PROPERTIES::onCustomShapeDClick( wxMouseEvent& event )
|
||||
{
|
||||
editBasicShape();
|
||||
}
|
||||
|
||||
|
||||
// Called on a click on basic shapes list panel button
|
||||
void DIALOG_PAD_PROPERTIES::onEditShape( wxCommandEvent& event )
|
||||
{
|
||||
editBasicShape();
|
||||
}
|
||||
|
||||
// Called on a click on basic shapes list panel button
|
||||
void DIALOG_PAD_PROPERTIES::onDeleteShape( wxCommandEvent& event )
|
||||
{
|
||||
long select = m_listCtrlShapes->GetFirstSelected();
|
||||
|
||||
if( select < 0 )
|
||||
return;
|
||||
|
||||
// Multiple selections are allowed. get them and remove corresponding shapes
|
||||
std::vector<long> indexes;
|
||||
indexes.push_back( select );
|
||||
|
||||
while( ( select = m_listCtrlShapes->GetNextSelected( select ) ) >= 0 )
|
||||
indexes.push_back( select );
|
||||
|
||||
// Erase all select shapes
|
||||
for( unsigned ii = indexes.size(); ii > 0; --ii )
|
||||
m_primitives.erase( m_primitives.begin() + indexes[ii-1] );
|
||||
|
||||
displayBasicShapesList();
|
||||
|
||||
if( m_canUpdate )
|
||||
{
|
||||
transferDataToPad( m_dummyPad );
|
||||
redraw();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void DIALOG_PAD_PROPERTIES::onAddShape( wxCommandEvent& event )
|
||||
{
|
||||
// Ask user for shape type
|
||||
wxString shapelist[] =
|
||||
{
|
||||
_( "Segment" ), _( "Arc" ), _( "ring/circle" ), _( "polygon" )
|
||||
};
|
||||
|
||||
int type = wxGetSingleChoiceIndex( wxEmptyString, _( " Select shape type:" ),
|
||||
DIM( shapelist ), shapelist, 0 );
|
||||
|
||||
STROKE_T listtype[] =
|
||||
{
|
||||
S_SEGMENT, S_ARC, S_CIRCLE, S_POLYGON
|
||||
};
|
||||
|
||||
PAD_CS_PRIMITIVE basicShape( listtype[type] );
|
||||
|
||||
if( listtype[type] == S_POLYGON )
|
||||
{
|
||||
DIALOG_PAD_BASIC_SHP_POLY_PROPS dlg( this, &basicShape );
|
||||
|
||||
if( dlg.ShowModal() != wxID_OK )
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
DIALOG_PAD_BASICSHAPES_PROPERTIES dlg( this, &basicShape );
|
||||
|
||||
if( dlg.ShowModal() != wxID_OK )
|
||||
return;
|
||||
}
|
||||
|
||||
m_primitives.push_back( basicShape );
|
||||
|
||||
displayBasicShapesList();
|
||||
|
||||
if( m_canUpdate )
|
||||
{
|
||||
transferDataToPad( m_dummyPad );
|
||||
redraw();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void DIALOG_PAD_PROPERTIES::onImportShape( wxCommandEvent& event )
|
||||
{
|
||||
wxMessageBox( "Not yet available" );
|
||||
}
|
||||
|
||||
|
||||
void DIALOG_PAD_PROPERTIES::onGeometryTransform( wxCommandEvent& event )
|
||||
{
|
||||
long select = m_listCtrlShapes->GetFirstSelected();
|
||||
|
||||
if( select < 0 )
|
||||
{
|
||||
wxMessageBox( _( "No shape selected" ) );
|
||||
return;
|
||||
}
|
||||
|
||||
// Multiple selections are allowed. Build selected shapes list
|
||||
std::vector<long> indexes;
|
||||
indexes.push_back( select );
|
||||
|
||||
std::vector<PAD_CS_PRIMITIVE*> shapeList;
|
||||
shapeList.push_back( &m_primitives[select] );
|
||||
|
||||
while( ( select = m_listCtrlShapes->GetNextSelected( select ) ) >= 0 )
|
||||
{
|
||||
indexes.push_back( select );
|
||||
shapeList.push_back( &m_primitives[select] );
|
||||
}
|
||||
|
||||
DIALOG_PAD_BASICSHAPES_TRANSFORM dlg( this, shapeList );
|
||||
|
||||
if( dlg.ShowModal() != wxID_OK )
|
||||
return;
|
||||
|
||||
// Transfert new settings:
|
||||
dlg.Transform();
|
||||
|
||||
displayBasicShapesList();
|
||||
|
||||
if( m_canUpdate )
|
||||
{
|
||||
transferDataToPad( m_dummyPad );
|
||||
redraw();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void DIALOG_PAD_PROPERTIES::onDuplicateShape( wxCommandEvent& event )
|
||||
{
|
||||
long select = m_listCtrlShapes->GetFirstSelected();
|
||||
|
||||
if( select < 0 )
|
||||
{
|
||||
wxMessageBox( _( "No shape selected" ) );
|
||||
return;
|
||||
}
|
||||
|
||||
// Multiple selections are allowed. Build selected shapes list
|
||||
std::vector<long> indexes;
|
||||
indexes.push_back( select );
|
||||
|
||||
std::vector<PAD_CS_PRIMITIVE*> shapeList;
|
||||
shapeList.push_back( &m_primitives[select] );
|
||||
|
||||
while( ( select = m_listCtrlShapes->GetNextSelected( select ) ) >= 0 )
|
||||
{
|
||||
indexes.push_back( select );
|
||||
shapeList.push_back( &m_primitives[select] );
|
||||
}
|
||||
|
||||
DIALOG_PAD_BASICSHAPES_TRANSFORM dlg( this, shapeList, true );
|
||||
|
||||
if( dlg.ShowModal() != wxID_OK )
|
||||
return;
|
||||
|
||||
// Transfert new settings:
|
||||
dlg.Transform( &m_primitives, dlg.GetDuplicateCount() );
|
||||
|
||||
displayBasicShapesList();
|
||||
|
||||
if( m_canUpdate )
|
||||
{
|
||||
transferDataToPad( m_dummyPad );
|
||||
redraw();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -40,6 +40,7 @@
|
|||
|
||||
#include <class_board.h>
|
||||
#include <class_module.h>
|
||||
#include <class_drawsegment.h>
|
||||
|
||||
#include <origin_viewitem.h>
|
||||
|
||||
|
@ -56,7 +57,6 @@ class DIALOG_PAD_PROPERTIES : public DIALOG_PAD_PROPERTIES_BASE
|
|||
{
|
||||
public:
|
||||
DIALOG_PAD_PROPERTIES( PCB_BASE_FRAME* aParent, D_PAD* aPad );
|
||||
void OnInitDialog( wxInitDialogEvent& event ) override;
|
||||
~DIALOG_PAD_PROPERTIES()
|
||||
{
|
||||
delete m_dummyPad;
|
||||
|
@ -80,13 +80,23 @@ private:
|
|||
bool m_canUpdate;
|
||||
bool m_canEditNetName; // true only if the caller is the board editor
|
||||
|
||||
// for free shape pads: the list of primitives (basic shapes),
|
||||
// in local coordinates, orient 0, coordinates relative to m_Pos
|
||||
// They are expected to define only one copper area.
|
||||
std::vector<PAD_CS_PRIMITIVE> m_primitives;
|
||||
|
||||
std::vector<DRAWSEGMENT*> m_highligth; // shapes highlighted in GAL mode
|
||||
|
||||
wxFloatingPointValidator<double> m_OrientValidator;
|
||||
double m_OrientValue;
|
||||
|
||||
private:
|
||||
void prepareCanvas(); // Initialize the canvases (legacy or gal) to display the pad
|
||||
void initValues();
|
||||
void displayBasicShapesList();
|
||||
bool padValuesOK(); ///< test if all values are acceptable for the pad
|
||||
void redraw();
|
||||
void editBasicShape();
|
||||
void updateRoundRectCornerValues();
|
||||
|
||||
/**
|
||||
|
@ -100,6 +110,7 @@ private:
|
|||
bool transferDataToPad( D_PAD* aPad );
|
||||
|
||||
// event handlers:
|
||||
void OnInitDialog( wxInitDialogEvent& event ) override;
|
||||
void OnResize( wxSizeEvent& event );
|
||||
|
||||
void OnPadShapeSelection( wxCommandEvent& event ) override;
|
||||
|
@ -120,8 +131,128 @@ private:
|
|||
|
||||
/// Updates the different parameters for the component being edited.
|
||||
/// Automatically fired from the OK button click.
|
||||
|
||||
bool TransferDataFromWindow() override;
|
||||
bool TransferDataToWindow() override;
|
||||
|
||||
/// Event handlers of basic shapes list panel
|
||||
void onDeleteShape( wxCommandEvent& event ) override;
|
||||
void onEditShape( wxCommandEvent& event ) override;
|
||||
void onAddShape( wxCommandEvent& event ) override;
|
||||
void onImportShape( wxCommandEvent& event ) override;
|
||||
void onGeometryTransform( wxCommandEvent& event ) override;
|
||||
void onDuplicateShape( wxCommandEvent& event ) override;
|
||||
|
||||
/// Called on a double click on the basic shapes list
|
||||
void onCustomShapeDClick( wxMouseEvent& event ) override;
|
||||
/// Called on selection/deselection of a basic shape
|
||||
void OnPrimitiveSelection( wxListEvent& event ) override;
|
||||
};
|
||||
|
||||
/**
|
||||
* a dialog to edit basics shapes parameters.
|
||||
* Polygonal shape is not handles by this dialog
|
||||
*/
|
||||
class DIALOG_PAD_BASICSHAPES_PROPERTIES: public DIALOG_PAD_BASICSHAPES_PROPERTIES_BASE
|
||||
{
|
||||
public:
|
||||
DIALOG_PAD_BASICSHAPES_PROPERTIES( wxWindow* aParent, PAD_CS_PRIMITIVE * aShape );
|
||||
|
||||
/**
|
||||
* Function TransferDataFromWindow
|
||||
* Transfer data out of the GUI.
|
||||
*/
|
||||
bool TransferDataFromWindow() override;
|
||||
|
||||
private:
|
||||
/**
|
||||
* Function TransferDataToWindow
|
||||
* Transfer data into the GUI.
|
||||
*/
|
||||
bool TransferDataToWindow() override;
|
||||
|
||||
// The basic shape currently edited
|
||||
PAD_CS_PRIMITIVE * m_shape;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* a dialog to edit basic polygonal shape parameters
|
||||
*/
|
||||
class DIALOG_PAD_BASIC_SHP_POLY_PROPS: public DIALOG_PAD_BASIC_SHP_POLY_PROPS_BASE
|
||||
{
|
||||
// The basic shape currently edited
|
||||
PAD_CS_PRIMITIVE * m_shape;
|
||||
|
||||
// The working copy of the basic shape currently edited
|
||||
PAD_CS_PRIMITIVE m_currshape;
|
||||
|
||||
public:
|
||||
DIALOG_PAD_BASIC_SHP_POLY_PROPS( wxWindow* aParent, PAD_CS_PRIMITIVE * aShape );
|
||||
~DIALOG_PAD_BASIC_SHP_POLY_PROPS();
|
||||
|
||||
/**
|
||||
* Function TransferDataFromWindow
|
||||
* Transfer data out of the GUI.
|
||||
*/
|
||||
bool TransferDataFromWindow() override;
|
||||
|
||||
private:
|
||||
/**
|
||||
* Function TransferDataToWindow
|
||||
* Transfer data into the GUI.
|
||||
*/
|
||||
bool TransferDataToWindow() override;
|
||||
|
||||
/**
|
||||
* test for a valid polygon (a not self intersectiong polygon)
|
||||
*/
|
||||
bool Validate() override;
|
||||
|
||||
// Events handlers:
|
||||
void OnValidateButton( wxCommandEvent& event );
|
||||
void onButtonAdd( wxCommandEvent& event ) override;
|
||||
void OnButtonDelete( wxCommandEvent& event ) override;
|
||||
void onPaintPolyPanel( wxPaintEvent& event ) override;
|
||||
void onPolyPanelResize( wxSizeEvent& event ) override;
|
||||
void onGridSelect( wxGridRangeSelectEvent& event ) override;
|
||||
void onCellChanging( wxGridEvent& event );
|
||||
void onCellSelect( wxGridEvent& event ) override
|
||||
{
|
||||
event.Skip();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/** A dialog to apply geometry transforms to a shape or set of shapes
|
||||
* (move, rotate around origin, scaling factor, duplication).
|
||||
* shapes are scaled, then moved then rotated.
|
||||
* aList is a list of shapes to transform or duplicate
|
||||
* if aShowDuplicate == false, the parameter "Duplicate count" is disabled
|
||||
*/
|
||||
|
||||
class DIALOG_PAD_BASICSHAPES_TRANSFORM : public DIALOG_PAD_BASICSHAPES_TRANSFORM_BASE
|
||||
{
|
||||
public:
|
||||
DIALOG_PAD_BASICSHAPES_TRANSFORM( wxWindow* aParent,
|
||||
std::vector<PAD_CS_PRIMITIVE*>& aList, bool aShowDuplicate = false );
|
||||
|
||||
/**
|
||||
* Apply geometric transform (rotation, move, scale) defined in dialog
|
||||
* aDuplicate = 1 .. n to duplicate the list of shapes
|
||||
* aDuplicate = 0 to transform the list of shapes
|
||||
* The duplicated items are transformed, but the initial shpes are not modified.
|
||||
* The duplicated items are added to aList
|
||||
*/
|
||||
void Transform( std::vector<PAD_CS_PRIMITIVE>* aList = NULL, int aDuplicateCount = 0 );
|
||||
|
||||
/**
|
||||
* @return the number of duplicate, chosen by user
|
||||
*/
|
||||
int GetDuplicateCount() { return m_spinCtrlDuplicateCount->GetValue(); }
|
||||
|
||||
private:
|
||||
std::vector<PAD_CS_PRIMITIVE*>& m_list;
|
||||
};
|
||||
|
||||
#endif // #ifndef _DIALOG_PAD_PROPERTIES_H_
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
///////////////////////////////////////////////////////////////////////////
|
||||
// C++ code generated with wxFormBuilder (version Jul 17 2016)
|
||||
// C++ code generated with wxFormBuilder (version Jul 2 2017)
|
||||
// http://www.wxformbuilder.org/
|
||||
//
|
||||
// PLEASE DO "NOT" EDIT THIS FILE!
|
||||
|
@ -63,10 +63,10 @@ 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"), _("Rounded Rectangle") };
|
||||
wxString m_PadShapeChoices[] = { _("Circular"), _("Oval"), _("Rectangular"), _("Trapezoidal"), _("Rounded Rectangle"), _("Custom Shape with Circular Anchor"), _("Custom Shape with Rectangular Anchor") };
|
||||
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 );
|
||||
m_PadShape->SetSelection( 6 );
|
||||
fgSizerPadType->Add( m_PadShape, 0, wxALL|wxEXPAND, 5 );
|
||||
|
||||
|
||||
|
@ -223,7 +223,7 @@ DIALOG_PAD_PROPERTIES_BASE::DIALOG_PAD_PROPERTIES_BASE( wxWindow* parent, wxWind
|
|||
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 ( percent of width):"), wxDefaultPosition, wxDefaultSize, 0 );
|
||||
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 percent of the pad width.\nThe width is the smaller value between size X and size Y\nThe max value is 50 percent ") );
|
||||
|
||||
|
@ -486,56 +486,67 @@ DIALOG_PAD_PROPERTIES_BASE::DIALOG_PAD_PROPERTIES_BASE( wxWindow* parent, wxWind
|
|||
|
||||
bSizerClearance->Add( sbClearancesSizer, 0, wxALL|wxEXPAND, 5 );
|
||||
|
||||
wxStaticBoxSizer* sbSizerZonesSettings;
|
||||
sbSizerZonesSettings = new wxStaticBoxSizer( new wxStaticBox( m_localSettingsPanel, wxID_ANY, _("Copper Zones") ), wxVERTICAL );
|
||||
m_sbSizerZonesSettings = new wxStaticBoxSizer( new wxStaticBox( m_localSettingsPanel, wxID_ANY, _("Copper Zones") ), wxVERTICAL );
|
||||
|
||||
wxFlexGridSizer* fgSizer41;
|
||||
fgSizer41 = new wxFlexGridSizer( 3, 3, 0, 0 );
|
||||
fgSizer41->AddGrowableCol( 1 );
|
||||
fgSizer41->SetFlexibleDirection( wxBOTH );
|
||||
fgSizer41->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED );
|
||||
wxFlexGridSizer* fgSizerCopperZonesOpts;
|
||||
fgSizerCopperZonesOpts = new wxFlexGridSizer( 3, 3, 0, 0 );
|
||||
fgSizerCopperZonesOpts->AddGrowableCol( 1 );
|
||||
fgSizerCopperZonesOpts->SetFlexibleDirection( wxBOTH );
|
||||
fgSizerCopperZonesOpts->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED );
|
||||
|
||||
m_staticText40 = new wxStaticText( sbSizerZonesSettings->GetStaticBox(), wxID_ANY, _("Pad connection:"), wxDefaultPosition, wxDefaultSize, 0 );
|
||||
m_staticText40 = new wxStaticText( m_sbSizerZonesSettings->GetStaticBox(), wxID_ANY, _("Pad connection:"), wxDefaultPosition, wxDefaultSize, 0 );
|
||||
m_staticText40->Wrap( -1 );
|
||||
fgSizer41->Add( m_staticText40, 0, wxALIGN_CENTER_VERTICAL|wxLEFT|wxTOP, 5 );
|
||||
fgSizerCopperZonesOpts->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( sbSizerZonesSettings->GetStaticBox(), wxID_ANY, wxDefaultPosition, wxDefaultSize, m_ZoneConnectionChoiceNChoices, m_ZoneConnectionChoiceChoices, 0 );
|
||||
m_ZoneConnectionChoice = new wxChoice( m_sbSizerZonesSettings->GetStaticBox(), wxID_ANY, wxDefaultPosition, wxDefaultSize, m_ZoneConnectionChoiceNChoices, m_ZoneConnectionChoiceChoices, 0 );
|
||||
m_ZoneConnectionChoice->SetSelection( 0 );
|
||||
fgSizer41->Add( m_ZoneConnectionChoice, 0, wxLEFT|wxTOP|wxEXPAND, 5 );
|
||||
fgSizerCopperZonesOpts->Add( m_ZoneConnectionChoice, 0, wxLEFT|wxTOP|wxEXPAND, 5 );
|
||||
|
||||
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( sbSizerZonesSettings->GetStaticBox(), wxID_ANY, _("Thermal relief width:"), wxDefaultPosition, wxDefaultSize, 0 );
|
||||
fgSizerCopperZonesOpts->Add( 0, 0, 1, wxEXPAND, 5 );
|
||||
|
||||
m_staticText49 = new wxStaticText( m_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 );
|
||||
fgSizerCopperZonesOpts->Add( m_staticText49, 0, wxALIGN_CENTER_VERTICAL|wxLEFT|wxTOP, 5 );
|
||||
|
||||
m_ThermalWidthCtrl = new wxTextCtrl( sbSizerZonesSettings->GetStaticBox(), wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
|
||||
fgSizer41->Add( m_ThermalWidthCtrl, 0, wxEXPAND|wxLEFT|wxTOP, 5 );
|
||||
m_ThermalWidthCtrl = new wxTextCtrl( m_sbSizerZonesSettings->GetStaticBox(), wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
|
||||
fgSizerCopperZonesOpts->Add( m_ThermalWidthCtrl, 0, wxEXPAND|wxLEFT|wxTOP, 5 );
|
||||
|
||||
m_ThermalWidthUnits = new wxStaticText( sbSizerZonesSettings->GetStaticBox(), wxID_ANY, _("Inch"), wxDefaultPosition, wxDefaultSize, 0 );
|
||||
m_ThermalWidthUnits = new wxStaticText( m_sbSizerZonesSettings->GetStaticBox(), wxID_ANY, _("Inch"), wxDefaultPosition, wxDefaultSize, 0 );
|
||||
m_ThermalWidthUnits->Wrap( -1 );
|
||||
fgSizer41->Add( m_ThermalWidthUnits, 0, wxALIGN_CENTER_VERTICAL|wxLEFT|wxRIGHT|wxTOP, 5 );
|
||||
fgSizerCopperZonesOpts->Add( m_ThermalWidthUnits, 0, wxALIGN_CENTER_VERTICAL|wxLEFT|wxRIGHT|wxTOP, 5 );
|
||||
|
||||
m_staticText52 = new wxStaticText( sbSizerZonesSettings->GetStaticBox(), wxID_ANY, _("Thermal relief gap:"), wxDefaultPosition, wxDefaultSize, 0 );
|
||||
m_staticText52 = new wxStaticText( m_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 );
|
||||
fgSizerCopperZonesOpts->Add( m_staticText52, 0, wxALIGN_CENTER_VERTICAL|wxBOTTOM|wxLEFT|wxTOP, 5 );
|
||||
|
||||
m_ThermalGapCtrl = new wxTextCtrl( sbSizerZonesSettings->GetStaticBox(), wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
|
||||
fgSizer41->Add( m_ThermalGapCtrl, 0, wxBOTTOM|wxEXPAND|wxLEFT|wxTOP, 5 );
|
||||
m_ThermalGapCtrl = new wxTextCtrl( m_sbSizerZonesSettings->GetStaticBox(), wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
|
||||
fgSizerCopperZonesOpts->Add( m_ThermalGapCtrl, 0, wxBOTTOM|wxEXPAND|wxLEFT|wxTOP, 5 );
|
||||
|
||||
m_ThermalGapUnits = new wxStaticText( sbSizerZonesSettings->GetStaticBox(), wxID_ANY, _("Inch"), wxDefaultPosition, wxDefaultSize, 0 );
|
||||
m_ThermalGapUnits = new wxStaticText( m_sbSizerZonesSettings->GetStaticBox(), wxID_ANY, _("Inch"), wxDefaultPosition, wxDefaultSize, 0 );
|
||||
m_ThermalGapUnits->Wrap( -1 );
|
||||
fgSizer41->Add( m_ThermalGapUnits, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5 );
|
||||
fgSizerCopperZonesOpts->Add( m_ThermalGapUnits, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5 );
|
||||
|
||||
m_staticTextcps = new wxStaticText( m_sbSizerZonesSettings->GetStaticBox(), wxID_ANY, _("Custom pad shape in zone:"), wxDefaultPosition, wxDefaultSize, 0 );
|
||||
m_staticTextcps->Wrap( -1 );
|
||||
fgSizerCopperZonesOpts->Add( m_staticTextcps, 0, wxALL, 5 );
|
||||
|
||||
wxString m_ZoneCustomPadShapeChoices[] = { _("Use pad shape"), _("Use pad convex hull") };
|
||||
int m_ZoneCustomPadShapeNChoices = sizeof( m_ZoneCustomPadShapeChoices ) / sizeof( wxString );
|
||||
m_ZoneCustomPadShape = new wxChoice( m_sbSizerZonesSettings->GetStaticBox(), wxID_ANY, wxDefaultPosition, wxDefaultSize, m_ZoneCustomPadShapeNChoices, m_ZoneCustomPadShapeChoices, 0 );
|
||||
m_ZoneCustomPadShape->SetSelection( 0 );
|
||||
fgSizerCopperZonesOpts->Add( m_ZoneCustomPadShape, 0, wxALL|wxEXPAND, 5 );
|
||||
|
||||
|
||||
sbSizerZonesSettings->Add( fgSizer41, 0, wxEXPAND, 5 );
|
||||
fgSizerCopperZonesOpts->Add( 0, 0, 1, wxEXPAND, 5 );
|
||||
|
||||
|
||||
bSizerClearance->Add( sbSizerZonesSettings, 0, wxALL|wxEXPAND, 5 );
|
||||
m_sbSizerZonesSettings->Add( fgSizerCopperZonesOpts, 0, wxEXPAND, 5 );
|
||||
|
||||
|
||||
bSizerClearance->Add( m_sbSizerZonesSettings, 0, wxALL|wxEXPAND, 5 );
|
||||
|
||||
m_staticTextWarning = new wxStaticText( m_localSettingsPanel, wxID_ANY, _("Set fields to 0 to use parent or global values"), wxDefaultPosition, wxDefaultSize, 0 );
|
||||
m_staticTextWarning->Wrap( -1 );
|
||||
|
@ -551,6 +562,65 @@ DIALOG_PAD_PROPERTIES_BASE::DIALOG_PAD_PROPERTIES_BASE( wxWindow* parent, wxWind
|
|||
m_localSettingsPanel->Layout();
|
||||
bSizerPanelClearance->Fit( m_localSettingsPanel );
|
||||
m_notebook->AddPage( m_localSettingsPanel, _("Local Clearance and Settings"), false );
|
||||
m_panelCustomShape = new wxPanel( m_notebook, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL );
|
||||
m_bSizerPanelShapes = new wxBoxSizer( wxVERTICAL );
|
||||
|
||||
m_staticTextShapesList = new wxStaticText( m_panelCustomShape, wxID_ANY, _("Primitives list"), wxDefaultPosition, wxDefaultSize, 0 );
|
||||
m_staticTextShapesList->Wrap( -1 );
|
||||
m_staticTextShapesList->SetFont( wxFont( wxNORMAL_FONT->GetPointSize(), wxFONTFAMILY_DEFAULT, wxFONTSTYLE_ITALIC, wxFONTWEIGHT_BOLD, false, wxEmptyString ) );
|
||||
|
||||
m_bSizerPanelShapes->Add( m_staticTextShapesList, 0, wxALL|wxALIGN_CENTER_HORIZONTAL, 5 );
|
||||
|
||||
m_staticTextShapesListWraning = new wxStaticText( m_panelCustomShape, wxID_ANY, _(" Coordinates are relative to anchor pad, orientation 0"), wxDefaultPosition, wxDefaultSize, 0 );
|
||||
m_staticTextShapesListWraning->Wrap( -1 );
|
||||
m_staticTextShapesListWraning->SetFont( wxFont( wxNORMAL_FONT->GetPointSize(), wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD, false, wxEmptyString ) );
|
||||
|
||||
m_bSizerPanelShapes->Add( m_staticTextShapesListWraning, 0, wxALL|wxALIGN_CENTER_HORIZONTAL, 5 );
|
||||
|
||||
m_listCtrlShapes = new wxListView( m_panelCustomShape, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLC_HRULES|wxLC_NO_HEADER|wxLC_REPORT );
|
||||
m_bSizerPanelShapes->Add( m_listCtrlShapes, 1, wxALL|wxEXPAND, 5 );
|
||||
|
||||
wxBoxSizer* bSizerButtons;
|
||||
bSizerButtons = new wxBoxSizer( wxVERTICAL );
|
||||
|
||||
wxBoxSizer* bSizerButtonsUpper;
|
||||
bSizerButtonsUpper = new wxBoxSizer( wxHORIZONTAL );
|
||||
|
||||
m_buttonDel = new wxButton( m_panelCustomShape, wxID_ANY, _("Delete Shape"), wxDefaultPosition, wxDefaultSize, 0 );
|
||||
bSizerButtonsUpper->Add( m_buttonDel, 0, wxALL, 5 );
|
||||
|
||||
m_buttonEditShape = new wxButton( m_panelCustomShape, wxID_ANY, _("Edit Shape"), wxDefaultPosition, wxDefaultSize, 0 );
|
||||
bSizerButtonsUpper->Add( m_buttonEditShape, 0, wxALL, 5 );
|
||||
|
||||
m_buttonAddShape = new wxButton( m_panelCustomShape, wxID_ANY, _("Add Shape"), wxDefaultPosition, wxDefaultSize, 0 );
|
||||
bSizerButtonsUpper->Add( m_buttonAddShape, 0, wxALL, 5 );
|
||||
|
||||
m_buttonDup = new wxButton( m_panelCustomShape, wxID_ANY, _("Duplicate Shape"), wxDefaultPosition, wxDefaultSize, 0 );
|
||||
bSizerButtonsUpper->Add( m_buttonDup, 0, wxALL, 5 );
|
||||
|
||||
|
||||
bSizerButtons->Add( bSizerButtonsUpper, 0, wxALIGN_CENTER_HORIZONTAL, 5 );
|
||||
|
||||
wxBoxSizer* bSizerButtonsLower;
|
||||
bSizerButtonsLower = new wxBoxSizer( wxHORIZONTAL );
|
||||
|
||||
m_buttonGeometry = new wxButton( m_panelCustomShape, wxID_ANY, _("Geometry Transform"), wxDefaultPosition, wxDefaultSize, 0 );
|
||||
bSizerButtonsLower->Add( m_buttonGeometry, 0, wxALL, 5 );
|
||||
|
||||
m_buttonImport = new wxButton( m_panelCustomShape, wxID_ANY, _("Import Shapes"), wxDefaultPosition, wxDefaultSize, 0 );
|
||||
bSizerButtonsLower->Add( m_buttonImport, 0, wxALL, 5 );
|
||||
|
||||
|
||||
bSizerButtons->Add( bSizerButtonsLower, 0, wxALIGN_CENTER_HORIZONTAL, 5 );
|
||||
|
||||
|
||||
m_bSizerPanelShapes->Add( bSizerButtons, 0, wxALIGN_CENTER_HORIZONTAL, 5 );
|
||||
|
||||
|
||||
m_panelCustomShape->SetSizer( m_bSizerPanelShapes );
|
||||
m_panelCustomShape->Layout();
|
||||
m_bSizerPanelShapes->Fit( m_panelCustomShape );
|
||||
m_notebook->AddPage( m_panelCustomShape, _("Custom Shape"), false );
|
||||
|
||||
bSizerUpper->Add( m_notebook, 0, wxALL|wxEXPAND, 5 );
|
||||
|
||||
|
@ -624,6 +694,15 @@ DIALOG_PAD_PROPERTIES_BASE::DIALOG_PAD_PROPERTIES_BASE( wxWindow* parent, wxWind
|
|||
m_PadLayerECO1->Connect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_PAD_PROPERTIES_BASE::OnSetLayers ), NULL, this );
|
||||
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_listCtrlShapes->Connect( wxEVT_LEFT_DCLICK, wxMouseEventHandler( DIALOG_PAD_PROPERTIES_BASE::onCustomShapeDClick ), NULL, this );
|
||||
m_listCtrlShapes->Connect( wxEVT_COMMAND_LIST_ITEM_DESELECTED, wxListEventHandler( DIALOG_PAD_PROPERTIES_BASE::OnPrimitiveSelection ), NULL, this );
|
||||
m_listCtrlShapes->Connect( wxEVT_COMMAND_LIST_ITEM_SELECTED, wxListEventHandler( DIALOG_PAD_PROPERTIES_BASE::OnPrimitiveSelection ), NULL, this );
|
||||
m_buttonDel->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_PAD_PROPERTIES_BASE::onDeleteShape ), NULL, this );
|
||||
m_buttonEditShape->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_PAD_PROPERTIES_BASE::onEditShape ), NULL, this );
|
||||
m_buttonAddShape->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_PAD_PROPERTIES_BASE::onAddShape ), NULL, this );
|
||||
m_buttonDup->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_PAD_PROPERTIES_BASE::onDuplicateShape ), NULL, this );
|
||||
m_buttonGeometry->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_PAD_PROPERTIES_BASE::onGeometryTransform ), NULL, this );
|
||||
m_buttonImport->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_PAD_PROPERTIES_BASE::onImportShape ), NULL, this );
|
||||
m_panelShowPad->Connect( wxEVT_PAINT, wxPaintEventHandler( DIALOG_PAD_PROPERTIES_BASE::OnPaintShowPanel ), NULL, this );
|
||||
}
|
||||
|
||||
|
@ -660,6 +739,415 @@ DIALOG_PAD_PROPERTIES_BASE::~DIALOG_PAD_PROPERTIES_BASE()
|
|||
m_PadLayerECO1->Disconnect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_PAD_PROPERTIES_BASE::OnSetLayers ), NULL, this );
|
||||
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_listCtrlShapes->Disconnect( wxEVT_LEFT_DCLICK, wxMouseEventHandler( DIALOG_PAD_PROPERTIES_BASE::onCustomShapeDClick ), NULL, this );
|
||||
m_listCtrlShapes->Disconnect( wxEVT_COMMAND_LIST_ITEM_DESELECTED, wxListEventHandler( DIALOG_PAD_PROPERTIES_BASE::OnPrimitiveSelection ), NULL, this );
|
||||
m_listCtrlShapes->Disconnect( wxEVT_COMMAND_LIST_ITEM_SELECTED, wxListEventHandler( DIALOG_PAD_PROPERTIES_BASE::OnPrimitiveSelection ), NULL, this );
|
||||
m_buttonDel->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_PAD_PROPERTIES_BASE::onDeleteShape ), NULL, this );
|
||||
m_buttonEditShape->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_PAD_PROPERTIES_BASE::onEditShape ), NULL, this );
|
||||
m_buttonAddShape->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_PAD_PROPERTIES_BASE::onAddShape ), NULL, this );
|
||||
m_buttonDup->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_PAD_PROPERTIES_BASE::onDuplicateShape ), NULL, this );
|
||||
m_buttonGeometry->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_PAD_PROPERTIES_BASE::onGeometryTransform ), NULL, this );
|
||||
m_buttonImport->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_PAD_PROPERTIES_BASE::onImportShape ), NULL, this );
|
||||
m_panelShowPad->Disconnect( wxEVT_PAINT, wxPaintEventHandler( DIALOG_PAD_PROPERTIES_BASE::OnPaintShowPanel ), NULL, this );
|
||||
|
||||
}
|
||||
|
||||
DIALOG_PAD_BASICSHAPES_PROPERTIES_BASE::DIALOG_PAD_BASICSHAPES_PROPERTIES_BASE( wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style ) : DIALOG_SHIM( parent, id, title, pos, size, style )
|
||||
{
|
||||
this->SetSizeHints( wxDefaultSize, wxDefaultSize );
|
||||
|
||||
wxBoxSizer* bSizermain;
|
||||
bSizermain = new wxBoxSizer( wxVERTICAL );
|
||||
|
||||
m_staticTextInfo = new wxStaticText( this, wxID_ANY, _("Filled circle: set thickness to 0\nRing: set thickness to the width of the ring"), wxDefaultPosition, wxDefaultSize, 0 );
|
||||
m_staticTextInfo->Wrap( -1 );
|
||||
m_staticTextInfo->SetFont( wxFont( wxNORMAL_FONT->GetPointSize(), wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD, false, wxEmptyString ) );
|
||||
|
||||
bSizermain->Add( m_staticTextInfo, 0, wxALL|wxALIGN_CENTER_HORIZONTAL, 5 );
|
||||
|
||||
wxFlexGridSizer* fgSizerShapeProperties;
|
||||
fgSizerShapeProperties = new wxFlexGridSizer( 0, 6, 0, 0 );
|
||||
fgSizerShapeProperties->AddGrowableCol( 2 );
|
||||
fgSizerShapeProperties->AddGrowableCol( 4 );
|
||||
fgSizerShapeProperties->SetFlexibleDirection( wxBOTH );
|
||||
fgSizerShapeProperties->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED );
|
||||
|
||||
m_staticTextPosStart = new wxStaticText( this, wxID_ANY, _("Start point"), wxDefaultPosition, wxDefaultSize, 0 );
|
||||
m_staticTextPosStart->Wrap( -1 );
|
||||
fgSizerShapeProperties->Add( m_staticTextPosStart, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
|
||||
|
||||
m_staticTextStartX = new wxStaticText( this, wxID_ANY, _("X"), wxDefaultPosition, wxDefaultSize, 0 );
|
||||
m_staticTextStartX->Wrap( -1 );
|
||||
fgSizerShapeProperties->Add( m_staticTextStartX, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_RIGHT|wxTOP|wxBOTTOM|wxLEFT, 5 );
|
||||
|
||||
m_textCtrPosX = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
|
||||
fgSizerShapeProperties->Add( m_textCtrPosX, 0, wxALL|wxALIGN_CENTER_VERTICAL|wxEXPAND, 5 );
|
||||
|
||||
m_staticTextStartY = new wxStaticText( this, wxID_ANY, _("Y"), wxDefaultPosition, wxDefaultSize, 0 );
|
||||
m_staticTextStartY->Wrap( -1 );
|
||||
fgSizerShapeProperties->Add( m_staticTextStartY, 0, wxALIGN_RIGHT|wxALIGN_CENTER_VERTICAL|wxTOP|wxBOTTOM|wxLEFT, 5 );
|
||||
|
||||
m_textCtrPosY = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
|
||||
fgSizerShapeProperties->Add( m_textCtrPosY, 0, wxALL|wxEXPAND, 5 );
|
||||
|
||||
m_staticTextPosUnit = new wxStaticText( this, wxID_ANY, _("unit"), wxDefaultPosition, wxDefaultSize, 0 );
|
||||
m_staticTextPosUnit->Wrap( -1 );
|
||||
fgSizerShapeProperties->Add( m_staticTextPosUnit, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
|
||||
|
||||
m_staticTextPosEnd = new wxStaticText( this, wxID_ANY, _("End point"), wxDefaultPosition, wxDefaultSize, 0 );
|
||||
m_staticTextPosEnd->Wrap( -1 );
|
||||
fgSizerShapeProperties->Add( m_staticTextPosEnd, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
|
||||
|
||||
m_staticTextEndX = new wxStaticText( this, wxID_ANY, _("X"), wxDefaultPosition, wxDefaultSize, 0 );
|
||||
m_staticTextEndX->Wrap( -1 );
|
||||
fgSizerShapeProperties->Add( m_staticTextEndX, 0, wxALIGN_RIGHT|wxALIGN_CENTER_VERTICAL|wxTOP|wxBOTTOM|wxLEFT, 5 );
|
||||
|
||||
m_textCtrEndX = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
|
||||
fgSizerShapeProperties->Add( m_textCtrEndX, 0, wxALL|wxEXPAND|wxALIGN_CENTER_VERTICAL, 5 );
|
||||
|
||||
m_staticTextEndY = new wxStaticText( this, wxID_ANY, _("Y"), wxDefaultPosition, wxDefaultSize, 0 );
|
||||
m_staticTextEndY->Wrap( -1 );
|
||||
fgSizerShapeProperties->Add( m_staticTextEndY, 0, wxALIGN_RIGHT|wxTOP|wxBOTTOM|wxLEFT, 5 );
|
||||
|
||||
m_textCtrEndY = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
|
||||
fgSizerShapeProperties->Add( m_textCtrEndY, 0, wxALL|wxALIGN_CENTER_VERTICAL|wxEXPAND, 5 );
|
||||
|
||||
m_staticTextEndUnit = new wxStaticText( this, wxID_ANY, _("unit"), wxDefaultPosition, wxDefaultSize, 0 );
|
||||
m_staticTextEndUnit->Wrap( -1 );
|
||||
fgSizerShapeProperties->Add( m_staticTextEndUnit, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
|
||||
|
||||
m_staticTextAngle = new wxStaticText( this, wxID_ANY, _("Angle"), wxDefaultPosition, wxDefaultSize, 0 );
|
||||
m_staticTextAngle->Wrap( -1 );
|
||||
fgSizerShapeProperties->Add( m_staticTextAngle, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
|
||||
|
||||
|
||||
fgSizerShapeProperties->Add( 0, 0, 1, wxEXPAND, 5 );
|
||||
|
||||
m_textCtrAngle = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
|
||||
fgSizerShapeProperties->Add( m_textCtrAngle, 0, wxALL|wxALIGN_CENTER_VERTICAL|wxEXPAND, 5 );
|
||||
|
||||
|
||||
fgSizerShapeProperties->Add( 0, 0, 1, wxEXPAND, 5 );
|
||||
|
||||
|
||||
fgSizerShapeProperties->Add( 0, 0, 1, wxEXPAND, 5 );
|
||||
|
||||
m_staticTextAngleUnit = new wxStaticText( this, wxID_ANY, _("degree"), wxDefaultPosition, wxDefaultSize, 0 );
|
||||
m_staticTextAngleUnit->Wrap( -1 );
|
||||
fgSizerShapeProperties->Add( m_staticTextAngleUnit, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
|
||||
|
||||
m_staticTextThickness = new wxStaticText( this, wxID_ANY, _("Thickness"), wxDefaultPosition, wxDefaultSize, 0 );
|
||||
m_staticTextThickness->Wrap( -1 );
|
||||
fgSizerShapeProperties->Add( m_staticTextThickness, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
|
||||
|
||||
|
||||
fgSizerShapeProperties->Add( 0, 0, 1, wxEXPAND, 5 );
|
||||
|
||||
m_textCtrlThickness = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
|
||||
fgSizerShapeProperties->Add( m_textCtrlThickness, 0, wxALL|wxALIGN_CENTER_VERTICAL|wxEXPAND, 5 );
|
||||
|
||||
|
||||
fgSizerShapeProperties->Add( 0, 0, 1, wxEXPAND, 5 );
|
||||
|
||||
|
||||
fgSizerShapeProperties->Add( 0, 0, 1, wxEXPAND, 5 );
|
||||
|
||||
m_staticTextThicknessUnit = new wxStaticText( this, wxID_ANY, _("unit"), wxDefaultPosition, wxDefaultSize, 0 );
|
||||
m_staticTextThicknessUnit->Wrap( -1 );
|
||||
fgSizerShapeProperties->Add( m_staticTextThicknessUnit, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
|
||||
|
||||
|
||||
bSizermain->Add( fgSizerShapeProperties, 1, wxEXPAND, 5 );
|
||||
|
||||
m_staticline1 = new wxStaticLine( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_HORIZONTAL );
|
||||
bSizermain->Add( m_staticline1, 0, wxEXPAND | wxALL, 5 );
|
||||
|
||||
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();
|
||||
|
||||
bSizermain->Add( m_sdbSizer, 0, wxALIGN_RIGHT|wxALL, 5 );
|
||||
|
||||
|
||||
this->SetSizer( bSizermain );
|
||||
this->Layout();
|
||||
|
||||
this->Centre( wxBOTH );
|
||||
}
|
||||
|
||||
DIALOG_PAD_BASICSHAPES_PROPERTIES_BASE::~DIALOG_PAD_BASICSHAPES_PROPERTIES_BASE()
|
||||
{
|
||||
}
|
||||
|
||||
DIALOG_PAD_BASICSHAPES_TRANSFORM_BASE::DIALOG_PAD_BASICSHAPES_TRANSFORM_BASE( wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style ) : DIALOG_SHIM( parent, id, title, pos, size, style )
|
||||
{
|
||||
this->SetSizeHints( wxDefaultSize, wxDefaultSize );
|
||||
|
||||
wxBoxSizer* bSizermain;
|
||||
bSizermain = new wxBoxSizer( wxVERTICAL );
|
||||
|
||||
wxFlexGridSizer* fgSizerShapeProperties;
|
||||
fgSizerShapeProperties = new wxFlexGridSizer( 0, 6, 0, 0 );
|
||||
fgSizerShapeProperties->AddGrowableCol( 2 );
|
||||
fgSizerShapeProperties->AddGrowableCol( 4 );
|
||||
fgSizerShapeProperties->SetFlexibleDirection( wxBOTH );
|
||||
fgSizerShapeProperties->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED );
|
||||
|
||||
m_staticTextMove = new wxStaticText( this, wxID_ANY, _("Move vector"), wxDefaultPosition, wxDefaultSize, 0 );
|
||||
m_staticTextMove->Wrap( -1 );
|
||||
fgSizerShapeProperties->Add( m_staticTextMove, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
|
||||
|
||||
m_staticTextMoveX = new wxStaticText( this, wxID_ANY, _("X"), wxDefaultPosition, wxDefaultSize, 0 );
|
||||
m_staticTextMoveX->Wrap( -1 );
|
||||
fgSizerShapeProperties->Add( m_staticTextMoveX, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
|
||||
|
||||
m_textCtrMoveX = new wxTextCtrl( this, wxID_ANY, _("0"), wxDefaultPosition, wxDefaultSize, 0 );
|
||||
fgSizerShapeProperties->Add( m_textCtrMoveX, 0, wxALL|wxALIGN_CENTER_VERTICAL|wxEXPAND, 5 );
|
||||
|
||||
m_staticTextMoveY = new wxStaticText( this, wxID_ANY, _("Y"), wxDefaultPosition, wxDefaultSize, 0 );
|
||||
m_staticTextMoveY->Wrap( -1 );
|
||||
fgSizerShapeProperties->Add( m_staticTextMoveY, 0, wxALL, 5 );
|
||||
|
||||
m_textCtrMoveY = new wxTextCtrl( this, wxID_ANY, _("0"), wxDefaultPosition, wxDefaultSize, 0 );
|
||||
fgSizerShapeProperties->Add( m_textCtrMoveY, 0, wxALL|wxEXPAND, 5 );
|
||||
|
||||
m_staticTextMoveUnit = new wxStaticText( this, wxID_ANY, _("unit"), wxDefaultPosition, wxDefaultSize, 0 );
|
||||
m_staticTextMoveUnit->Wrap( -1 );
|
||||
fgSizerShapeProperties->Add( m_staticTextMoveUnit, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
|
||||
|
||||
m_staticTextAngle = new wxStaticText( this, wxID_ANY, _("Rotation"), wxDefaultPosition, wxDefaultSize, 0 );
|
||||
m_staticTextAngle->Wrap( -1 );
|
||||
fgSizerShapeProperties->Add( m_staticTextAngle, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
|
||||
|
||||
|
||||
fgSizerShapeProperties->Add( 0, 0, 1, wxEXPAND, 5 );
|
||||
|
||||
m_textCtrAngle = new wxTextCtrl( this, wxID_ANY, _("0"), wxDefaultPosition, wxDefaultSize, 0 );
|
||||
fgSizerShapeProperties->Add( m_textCtrAngle, 0, wxALL|wxALIGN_CENTER_VERTICAL|wxEXPAND, 5 );
|
||||
|
||||
|
||||
fgSizerShapeProperties->Add( 0, 0, 1, wxEXPAND, 5 );
|
||||
|
||||
|
||||
fgSizerShapeProperties->Add( 0, 0, 1, wxEXPAND, 5 );
|
||||
|
||||
m_staticTextAngleUnit = new wxStaticText( this, wxID_ANY, _("degree"), wxDefaultPosition, wxDefaultSize, 0 );
|
||||
m_staticTextAngleUnit->Wrap( -1 );
|
||||
fgSizerShapeProperties->Add( m_staticTextAngleUnit, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
|
||||
|
||||
m_staticTextSF = new wxStaticText( this, wxID_ANY, _("Scaling factor"), wxDefaultPosition, wxDefaultSize, 0 );
|
||||
m_staticTextSF->Wrap( -1 );
|
||||
fgSizerShapeProperties->Add( m_staticTextSF, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
|
||||
|
||||
|
||||
fgSizerShapeProperties->Add( 0, 0, 1, wxEXPAND, 5 );
|
||||
|
||||
m_textCtrlScalingFactor = new wxTextCtrl( this, wxID_ANY, _("1.0"), wxDefaultPosition, wxDefaultSize, 0 );
|
||||
fgSizerShapeProperties->Add( m_textCtrlScalingFactor, 0, wxALL|wxALIGN_CENTER_VERTICAL|wxEXPAND, 5 );
|
||||
|
||||
|
||||
fgSizerShapeProperties->Add( 0, 0, 1, wxEXPAND, 5 );
|
||||
|
||||
|
||||
fgSizerShapeProperties->Add( 0, 0, 1, wxEXPAND, 5 );
|
||||
|
||||
|
||||
fgSizerShapeProperties->Add( 0, 0, 1, wxEXPAND, 5 );
|
||||
|
||||
m_staticTextDupCnt = new wxStaticText( this, wxID_ANY, _("Duplicate count"), wxDefaultPosition, wxDefaultSize, 0 );
|
||||
m_staticTextDupCnt->Wrap( -1 );
|
||||
fgSizerShapeProperties->Add( m_staticTextDupCnt, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
|
||||
|
||||
|
||||
fgSizerShapeProperties->Add( 0, 0, 1, wxEXPAND, 5 );
|
||||
|
||||
m_spinCtrlDuplicateCount = new wxSpinCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS, 1, 100, 1 );
|
||||
fgSizerShapeProperties->Add( m_spinCtrlDuplicateCount, 0, wxALL|wxEXPAND, 5 );
|
||||
|
||||
|
||||
fgSizerShapeProperties->Add( 0, 0, 1, wxEXPAND, 5 );
|
||||
|
||||
|
||||
fgSizerShapeProperties->Add( 0, 0, 1, wxEXPAND, 5 );
|
||||
|
||||
|
||||
fgSizerShapeProperties->Add( 0, 0, 1, wxEXPAND, 5 );
|
||||
|
||||
|
||||
bSizermain->Add( fgSizerShapeProperties, 1, wxEXPAND, 5 );
|
||||
|
||||
m_staticline1 = new wxStaticLine( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_HORIZONTAL );
|
||||
bSizermain->Add( m_staticline1, 0, wxEXPAND | wxALL, 5 );
|
||||
|
||||
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();
|
||||
|
||||
bSizermain->Add( m_sdbSizer, 0, wxALIGN_RIGHT|wxALL, 5 );
|
||||
|
||||
|
||||
this->SetSizer( bSizermain );
|
||||
this->Layout();
|
||||
|
||||
this->Centre( wxBOTH );
|
||||
}
|
||||
|
||||
DIALOG_PAD_BASICSHAPES_TRANSFORM_BASE::~DIALOG_PAD_BASICSHAPES_TRANSFORM_BASE()
|
||||
{
|
||||
}
|
||||
|
||||
DIALOG_PAD_BASIC_SHP_POLY_PROPS_BASE::DIALOG_PAD_BASIC_SHP_POLY_PROPS_BASE( wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style ) : DIALOG_SHIM( parent, id, title, pos, size, style )
|
||||
{
|
||||
this->SetSizeHints( wxDefaultSize, wxDefaultSize );
|
||||
|
||||
wxBoxSizer* bSizerMain;
|
||||
bSizerMain = new wxBoxSizer( wxVERTICAL );
|
||||
|
||||
m_staticTextShapesListWarning = new wxStaticText( this, wxID_ANY, _(" Coordinates are relative to anchor pad, orientation 0"), wxDefaultPosition, wxDefaultSize, 0 );
|
||||
m_staticTextShapesListWarning->Wrap( -1 );
|
||||
m_staticTextShapesListWarning->SetFont( wxFont( wxNORMAL_FONT->GetPointSize(), wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD, false, wxEmptyString ) );
|
||||
|
||||
bSizerMain->Add( m_staticTextShapesListWarning, 0, wxALL|wxALIGN_CENTER_HORIZONTAL, 5 );
|
||||
|
||||
m_staticTextValidate = new wxStaticText( this, wxID_ANY, _("Incorrect polygon"), wxDefaultPosition, wxDefaultSize, 0 );
|
||||
m_staticTextValidate->Wrap( -1 );
|
||||
m_staticTextValidate->SetFont( wxFont( wxNORMAL_FONT->GetPointSize(), wxFONTFAMILY_DEFAULT, wxFONTSTYLE_ITALIC, wxFONTWEIGHT_BOLD, false, wxEmptyString ) );
|
||||
|
||||
bSizerMain->Add( m_staticTextValidate, 0, wxALL, 5 );
|
||||
|
||||
wxBoxSizer* bSizerUpper;
|
||||
bSizerUpper = new wxBoxSizer( wxVERTICAL );
|
||||
|
||||
wxBoxSizer* bSizer23;
|
||||
bSizer23 = new wxBoxSizer( wxHORIZONTAL );
|
||||
|
||||
wxBoxSizer* bSizerCornerlist;
|
||||
bSizerCornerlist = new wxBoxSizer( wxVERTICAL );
|
||||
|
||||
m_gridCornersList = new wxGrid( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0 );
|
||||
|
||||
// Grid
|
||||
m_gridCornersList->CreateGrid( 1, 2 );
|
||||
m_gridCornersList->EnableEditing( true );
|
||||
m_gridCornersList->EnableGridLines( true );
|
||||
m_gridCornersList->EnableDragGridSize( false );
|
||||
m_gridCornersList->SetMargins( 0, 0 );
|
||||
|
||||
// Columns
|
||||
m_gridCornersList->EnableDragColMove( false );
|
||||
m_gridCornersList->EnableDragColSize( true );
|
||||
m_gridCornersList->SetColLabelSize( 30 );
|
||||
m_gridCornersList->SetColLabelValue( 0, _("Pos X") );
|
||||
m_gridCornersList->SetColLabelValue( 1, _("Pos Y") );
|
||||
m_gridCornersList->SetColLabelAlignment( wxALIGN_CENTRE, wxALIGN_CENTRE );
|
||||
|
||||
// Rows
|
||||
m_gridCornersList->AutoSizeRows();
|
||||
m_gridCornersList->EnableDragRowSize( false );
|
||||
m_gridCornersList->SetRowLabelSize( 80 );
|
||||
m_gridCornersList->SetRowLabelAlignment( wxALIGN_CENTRE, wxALIGN_CENTRE );
|
||||
|
||||
// Label Appearance
|
||||
|
||||
// Cell Defaults
|
||||
m_gridCornersList->SetDefaultCellAlignment( wxALIGN_LEFT, wxALIGN_TOP );
|
||||
bSizerCornerlist->Add( m_gridCornersList, 1, wxALL, 5 );
|
||||
|
||||
wxBoxSizer* bSizerRightButts;
|
||||
bSizerRightButts = new wxBoxSizer( wxHORIZONTAL );
|
||||
|
||||
m_buttonAdd = new wxButton( this, wxID_ANY, _("Add"), wxDefaultPosition, wxDefaultSize, 0 );
|
||||
bSizerRightButts->Add( m_buttonAdd, 0, wxALL, 5 );
|
||||
|
||||
m_buttonDelete = new wxButton( this, wxID_ANY, _("Delete"), wxDefaultPosition, wxDefaultSize, 0 );
|
||||
bSizerRightButts->Add( m_buttonDelete, 0, wxALL, 5 );
|
||||
|
||||
|
||||
bSizerCornerlist->Add( bSizerRightButts, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_CENTER_HORIZONTAL, 5 );
|
||||
|
||||
|
||||
bSizer23->Add( bSizerCornerlist, 0, wxEXPAND, 5 );
|
||||
|
||||
m_panelPoly = new wxPanel( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSUNKEN_BORDER|wxTAB_TRAVERSAL );
|
||||
m_panelPoly->SetBackgroundColour( wxColour( 0, 0, 0 ) );
|
||||
m_panelPoly->SetMinSize( wxSize( 300,300 ) );
|
||||
|
||||
bSizer23->Add( m_panelPoly, 1, wxEXPAND | wxALL, 5 );
|
||||
|
||||
|
||||
bSizerUpper->Add( bSizer23, 1, wxEXPAND, 5 );
|
||||
|
||||
wxFlexGridSizer* fgSizerThickness;
|
||||
fgSizerThickness = new wxFlexGridSizer( 0, 5, 0, 0 );
|
||||
fgSizerThickness->AddGrowableCol( 1 );
|
||||
fgSizerThickness->SetFlexibleDirection( wxBOTH );
|
||||
fgSizerThickness->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED );
|
||||
|
||||
m_staticTextThickness = new wxStaticText( this, wxID_ANY, _("Outline thickness"), wxDefaultPosition, wxDefaultSize, 0 );
|
||||
m_staticTextThickness->Wrap( -1 );
|
||||
fgSizerThickness->Add( m_staticTextThickness, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
|
||||
|
||||
m_textCtrlThickness = new wxTextCtrl( this, wxID_ANY, _("0"), wxDefaultPosition, wxDefaultSize, 0 );
|
||||
fgSizerThickness->Add( m_textCtrlThickness, 0, wxALL|wxEXPAND|wxALIGN_CENTER_VERTICAL, 5 );
|
||||
|
||||
m_staticTextThicknessUnit = new wxStaticText( this, wxID_ANY, _("unit"), wxDefaultPosition, wxDefaultSize, 0 );
|
||||
m_staticTextThicknessUnit->Wrap( -1 );
|
||||
fgSizerThickness->Add( m_staticTextThicknessUnit, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
|
||||
|
||||
|
||||
fgSizerThickness->Add( 10, 10, 0, 0, 5 );
|
||||
|
||||
m_staticTextInfo = new wxStaticText( this, wxID_ANY, _("(Thickness outline is usually set to 0)"), wxDefaultPosition, wxDefaultSize, 0 );
|
||||
m_staticTextInfo->Wrap( -1 );
|
||||
fgSizerThickness->Add( m_staticTextInfo, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
|
||||
|
||||
|
||||
bSizerUpper->Add( fgSizerThickness, 0, 0, 5 );
|
||||
|
||||
|
||||
bSizerMain->Add( bSizerUpper, 1, wxEXPAND, 5 );
|
||||
|
||||
m_staticline3 = new wxStaticLine( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_HORIZONTAL );
|
||||
bSizerMain->Add( m_staticline3, 0, wxEXPAND | wxALL, 5 );
|
||||
|
||||
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();
|
||||
|
||||
bSizerMain->Add( m_sdbSizer, 0, wxEXPAND|wxALL, 5 );
|
||||
|
||||
|
||||
this->SetSizer( bSizerMain );
|
||||
this->Layout();
|
||||
|
||||
this->Centre( wxBOTH );
|
||||
|
||||
// Connect Events
|
||||
m_gridCornersList->Connect( wxEVT_GRID_RANGE_SELECT, wxGridRangeSelectEventHandler( DIALOG_PAD_BASIC_SHP_POLY_PROPS_BASE::onGridSelect ), NULL, this );
|
||||
m_gridCornersList->Connect( wxEVT_GRID_SELECT_CELL, wxGridEventHandler( DIALOG_PAD_BASIC_SHP_POLY_PROPS_BASE::onCellSelect ), NULL, this );
|
||||
m_buttonAdd->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_PAD_BASIC_SHP_POLY_PROPS_BASE::onButtonAdd ), NULL, this );
|
||||
m_buttonDelete->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_PAD_BASIC_SHP_POLY_PROPS_BASE::OnButtonDelete ), NULL, this );
|
||||
m_panelPoly->Connect( wxEVT_PAINT, wxPaintEventHandler( DIALOG_PAD_BASIC_SHP_POLY_PROPS_BASE::onPaintPolyPanel ), NULL, this );
|
||||
m_panelPoly->Connect( wxEVT_SIZE, wxSizeEventHandler( DIALOG_PAD_BASIC_SHP_POLY_PROPS_BASE::onPolyPanelResize ), NULL, this );
|
||||
}
|
||||
|
||||
DIALOG_PAD_BASIC_SHP_POLY_PROPS_BASE::~DIALOG_PAD_BASIC_SHP_POLY_PROPS_BASE()
|
||||
{
|
||||
// Disconnect Events
|
||||
m_gridCornersList->Disconnect( wxEVT_GRID_RANGE_SELECT, wxGridRangeSelectEventHandler( DIALOG_PAD_BASIC_SHP_POLY_PROPS_BASE::onGridSelect ), NULL, this );
|
||||
m_gridCornersList->Disconnect( wxEVT_GRID_SELECT_CELL, wxGridEventHandler( DIALOG_PAD_BASIC_SHP_POLY_PROPS_BASE::onCellSelect ), NULL, this );
|
||||
m_buttonAdd->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_PAD_BASIC_SHP_POLY_PROPS_BASE::onButtonAdd ), NULL, this );
|
||||
m_buttonDelete->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_PAD_BASIC_SHP_POLY_PROPS_BASE::OnButtonDelete ), NULL, this );
|
||||
m_panelPoly->Disconnect( wxEVT_PAINT, wxPaintEventHandler( DIALOG_PAD_BASIC_SHP_POLY_PROPS_BASE::onPaintPolyPanel ), NULL, this );
|
||||
m_panelPoly->Disconnect( wxEVT_SIZE, wxSizeEventHandler( DIALOG_PAD_BASIC_SHP_POLY_PROPS_BASE::onPolyPanelResize ), NULL, this );
|
||||
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,5 +1,5 @@
|
|||
///////////////////////////////////////////////////////////////////////////
|
||||
// C++ code generated with wxFormBuilder (version Jul 17 2016)
|
||||
// C++ code generated with wxFormBuilder (version Jul 2 2017)
|
||||
// http://www.wxformbuilder.org/
|
||||
//
|
||||
// PLEASE DO "NOT" EDIT THIS FILE!
|
||||
|
@ -12,6 +12,7 @@
|
|||
#include <wx/xrc/xmlres.h>
|
||||
#include <wx/intl.h>
|
||||
class DIALOG_SHIM;
|
||||
class wxListView;
|
||||
|
||||
#include "dialog_shim.h"
|
||||
#include <wx/string.h>
|
||||
|
@ -30,11 +31,14 @@ class DIALOG_SHIM;
|
|||
#include <wx/bitmap.h>
|
||||
#include <wx/image.h>
|
||||
#include <wx/icon.h>
|
||||
#include <wx/listctrl.h>
|
||||
#include <wx/button.h>
|
||||
#include <wx/notebook.h>
|
||||
#include <wxBasePcbFrame.h>
|
||||
#include <pcb_draw_panel_gal.h>
|
||||
#include <wx/button.h>
|
||||
#include <wx/dialog.h>
|
||||
#include <wx/spinctrl.h>
|
||||
#include <wx/grid.h>
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
@ -145,16 +149,29 @@ class DIALOG_PAD_PROPERTIES_BASE : public DIALOG_SHIM
|
|||
wxStaticText* m_staticTextRatio;
|
||||
wxTextCtrl* m_SolderPasteMarginRatioCtrl;
|
||||
wxStaticText* m_SolderPasteRatioMarginUnits;
|
||||
wxStaticBoxSizer* m_sbSizerZonesSettings;
|
||||
wxStaticText* m_staticText40;
|
||||
wxChoice* m_ZoneConnectionChoice;
|
||||
wxStaticText* m_staticText53;
|
||||
wxStaticText* m_staticText49;
|
||||
wxTextCtrl* m_ThermalWidthCtrl;
|
||||
wxStaticText* m_ThermalWidthUnits;
|
||||
wxStaticText* m_staticText52;
|
||||
wxTextCtrl* m_ThermalGapCtrl;
|
||||
wxStaticText* m_ThermalGapUnits;
|
||||
wxStaticText* m_staticTextcps;
|
||||
wxChoice* m_ZoneCustomPadShape;
|
||||
wxStaticText* m_staticTextWarning;
|
||||
wxPanel* m_panelCustomShape;
|
||||
wxBoxSizer* m_bSizerPanelShapes;
|
||||
wxStaticText* m_staticTextShapesList;
|
||||
wxStaticText* m_staticTextShapesListWraning;
|
||||
wxListView* m_listCtrlShapes;
|
||||
wxButton* m_buttonDel;
|
||||
wxButton* m_buttonEditShape;
|
||||
wxButton* m_buttonAddShape;
|
||||
wxButton* m_buttonDup;
|
||||
wxButton* m_buttonGeometry;
|
||||
wxButton* m_buttonImport;
|
||||
wxPanel* m_panelShowPad;
|
||||
PCB_DRAW_PANEL_GAL* m_panelShowPadGal;
|
||||
KIGFX::GAL_DISPLAY_OPTIONS m_galOptions;
|
||||
|
@ -172,6 +189,14 @@ class DIALOG_PAD_PROPERTIES_BASE : public DIALOG_SHIM
|
|||
virtual void OnSetLayers( wxCommandEvent& event ) { event.Skip(); }
|
||||
virtual void onCornerSizePercentChange( wxCommandEvent& event ) { event.Skip(); }
|
||||
virtual void OnDrillShapeSelected( wxCommandEvent& event ) { event.Skip(); }
|
||||
virtual void onCustomShapeDClick( wxMouseEvent& event ) { event.Skip(); }
|
||||
virtual void OnPrimitiveSelection( wxListEvent& event ) { event.Skip(); }
|
||||
virtual void onDeleteShape( wxCommandEvent& event ) { event.Skip(); }
|
||||
virtual void onEditShape( wxCommandEvent& event ) { event.Skip(); }
|
||||
virtual void onAddShape( wxCommandEvent& event ) { event.Skip(); }
|
||||
virtual void onDuplicateShape( wxCommandEvent& event ) { event.Skip(); }
|
||||
virtual void onGeometryTransform( wxCommandEvent& event ) { event.Skip(); }
|
||||
virtual void onImportShape( wxCommandEvent& event ) { event.Skip(); }
|
||||
virtual void OnPaintShowPanel( wxPaintEvent& event ) { event.Skip(); }
|
||||
|
||||
|
||||
|
@ -182,4 +207,115 @@ class DIALOG_PAD_PROPERTIES_BASE : public DIALOG_SHIM
|
|||
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
/// Class DIALOG_PAD_BASICSHAPES_PROPERTIES_BASE
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
class DIALOG_PAD_BASICSHAPES_PROPERTIES_BASE : public DIALOG_SHIM
|
||||
{
|
||||
private:
|
||||
|
||||
protected:
|
||||
wxStaticText* m_staticTextInfo;
|
||||
wxStaticText* m_staticTextPosStart;
|
||||
wxStaticText* m_staticTextStartX;
|
||||
wxTextCtrl* m_textCtrPosX;
|
||||
wxStaticText* m_staticTextStartY;
|
||||
wxTextCtrl* m_textCtrPosY;
|
||||
wxStaticText* m_staticTextPosUnit;
|
||||
wxStaticText* m_staticTextPosEnd;
|
||||
wxStaticText* m_staticTextEndX;
|
||||
wxTextCtrl* m_textCtrEndX;
|
||||
wxStaticText* m_staticTextEndY;
|
||||
wxTextCtrl* m_textCtrEndY;
|
||||
wxStaticText* m_staticTextEndUnit;
|
||||
wxStaticText* m_staticTextAngle;
|
||||
wxTextCtrl* m_textCtrAngle;
|
||||
wxStaticText* m_staticTextAngleUnit;
|
||||
wxStaticText* m_staticTextThickness;
|
||||
wxTextCtrl* m_textCtrlThickness;
|
||||
wxStaticText* m_staticTextThicknessUnit;
|
||||
wxStaticLine* m_staticline1;
|
||||
wxStdDialogButtonSizer* m_sdbSizer;
|
||||
wxButton* m_sdbSizerOK;
|
||||
wxButton* m_sdbSizerCancel;
|
||||
|
||||
public:
|
||||
|
||||
DIALOG_PAD_BASICSHAPES_PROPERTIES_BASE( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = wxEmptyString, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( 561,243 ), long style = wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER );
|
||||
~DIALOG_PAD_BASICSHAPES_PROPERTIES_BASE();
|
||||
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
/// Class DIALOG_PAD_BASICSHAPES_TRANSFORM_BASE
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
class DIALOG_PAD_BASICSHAPES_TRANSFORM_BASE : public DIALOG_SHIM
|
||||
{
|
||||
private:
|
||||
|
||||
protected:
|
||||
wxStaticText* m_staticTextMove;
|
||||
wxStaticText* m_staticTextMoveX;
|
||||
wxTextCtrl* m_textCtrMoveX;
|
||||
wxStaticText* m_staticTextMoveY;
|
||||
wxTextCtrl* m_textCtrMoveY;
|
||||
wxStaticText* m_staticTextMoveUnit;
|
||||
wxStaticText* m_staticTextAngle;
|
||||
wxTextCtrl* m_textCtrAngle;
|
||||
wxStaticText* m_staticTextAngleUnit;
|
||||
wxStaticText* m_staticTextSF;
|
||||
wxTextCtrl* m_textCtrlScalingFactor;
|
||||
wxStaticText* m_staticTextDupCnt;
|
||||
wxSpinCtrl* m_spinCtrlDuplicateCount;
|
||||
wxStaticLine* m_staticline1;
|
||||
wxStdDialogButtonSizer* m_sdbSizer;
|
||||
wxButton* m_sdbSizerOK;
|
||||
wxButton* m_sdbSizerCancel;
|
||||
|
||||
public:
|
||||
|
||||
DIALOG_PAD_BASICSHAPES_TRANSFORM_BASE( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("Pad Custom Shape Geometry Transform"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( 472,208 ), long style = wxDEFAULT_DIALOG_STYLE );
|
||||
~DIALOG_PAD_BASICSHAPES_TRANSFORM_BASE();
|
||||
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
/// Class DIALOG_PAD_BASIC_SHP_POLY_PROPS_BASE
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
class DIALOG_PAD_BASIC_SHP_POLY_PROPS_BASE : public DIALOG_SHIM
|
||||
{
|
||||
private:
|
||||
|
||||
protected:
|
||||
wxStaticText* m_staticTextShapesListWarning;
|
||||
wxStaticText* m_staticTextValidate;
|
||||
wxGrid* m_gridCornersList;
|
||||
wxButton* m_buttonAdd;
|
||||
wxButton* m_buttonDelete;
|
||||
wxPanel* m_panelPoly;
|
||||
wxStaticText* m_staticTextThickness;
|
||||
wxTextCtrl* m_textCtrlThickness;
|
||||
wxStaticText* m_staticTextThicknessUnit;
|
||||
wxStaticText* m_staticTextInfo;
|
||||
wxStaticLine* m_staticline3;
|
||||
wxStdDialogButtonSizer* m_sdbSizer;
|
||||
wxButton* m_sdbSizerOK;
|
||||
wxButton* m_sdbSizerCancel;
|
||||
|
||||
// Virtual event handlers, overide them in your derived class
|
||||
virtual void onGridSelect( wxGridRangeSelectEvent& event ) { event.Skip(); }
|
||||
virtual void onCellSelect( wxGridEvent& event ) { event.Skip(); }
|
||||
virtual void onButtonAdd( wxCommandEvent& event ) { event.Skip(); }
|
||||
virtual void OnButtonDelete( wxCommandEvent& event ) { event.Skip(); }
|
||||
virtual void onPaintPolyPanel( wxPaintEvent& event ) { event.Skip(); }
|
||||
virtual void onPolyPanelResize( wxSizeEvent& event ) { event.Skip(); }
|
||||
|
||||
|
||||
public:
|
||||
|
||||
DIALOG_PAD_BASIC_SHP_POLY_PROPS_BASE( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("Basic Shape Polygon"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( 503,396 ), long style = wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER );
|
||||
~DIALOG_PAD_BASIC_SHP_POLY_PROPS_BASE();
|
||||
|
||||
};
|
||||
|
||||
#endif //__DIALOG_PAD_PROPERTIES_BASE_H__
|
||||
|
|
|
@ -5,9 +5,9 @@
|
|||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2004-2016 Jean-Pierre Charras, jean-pierre.charras@gipsa-lab.inpg.fr
|
||||
* Copyright (C) 2004-2017 Jean-Pierre Charras, jp.charras at wanadoo.fr
|
||||
* Copyright (C) 2007 Dick Hollenbeck, dick@softplc.com
|
||||
* Copyright (C) 2016 KiCad Developers, see change_log.txt for contributors.
|
||||
* Copyright (C) 2017 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
|
||||
|
@ -603,7 +603,9 @@ bool DRC::checkClearancePadToPad( D_PAD* aRefPad, D_PAD* aPad )
|
|||
dist = KiROUND( EuclideanNorm( relativePadPos ) );
|
||||
|
||||
// Quick test: Clearance is OK if the bounding circles are further away than "dist_min"
|
||||
if( (dist - aRefPad->GetBoundingRadius() - aPad->GetBoundingRadius()) >= dist_min )
|
||||
int delta = dist - aRefPad->GetBoundingRadius() - aPad->GetBoundingRadius();
|
||||
|
||||
if( delta >= dist_min )
|
||||
return true;
|
||||
|
||||
/* Here, pads are near and DRC depend on the pad shapes
|
||||
|
@ -639,7 +641,8 @@ bool DRC::checkClearancePadToPad( D_PAD* aRefPad, D_PAD* aPad )
|
|||
swap_pads = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
case PAD_SHAPE_TRAPEZOID:
|
||||
case PAD_SHAPE_CUSTOM:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -686,6 +689,7 @@ bool DRC::checkClearancePadToPad( D_PAD* aRefPad, D_PAD* aPad )
|
|||
case PAD_SHAPE_TRAPEZOID:
|
||||
case PAD_SHAPE_ROUNDRECT:
|
||||
case PAD_SHAPE_RECT:
|
||||
case PAD_SHAPE_CUSTOM:
|
||||
// pad_angle = pad orient relative to the aRefPad orient
|
||||
pad_angle = aRefPad->GetOrientation() + aPad->GetOrientation();
|
||||
NORMALIZE_ANGLE_POS( pad_angle );
|
||||
|
@ -697,14 +701,29 @@ bool DRC::checkClearancePadToPad( D_PAD* aRefPad, D_PAD* aPad )
|
|||
GetRoundRectCornerCenters( polyref, padRadius, wxPoint( 0, 0 ),
|
||||
aRefPad->GetSize(), aRefPad->GetOrientation() );
|
||||
}
|
||||
else if( aRefPad->GetShape() == PAD_SHAPE_CUSTOM )
|
||||
{
|
||||
polysetref.Append( aRefPad->GetCustomShapeAsPolygon() );
|
||||
|
||||
// The reference pad can be rotated. calculate the rotated
|
||||
// coordiantes ( note, the ref pad position is the origin of
|
||||
// coordinates for this drc test)
|
||||
aRefPad->BasicShapesAsPolygonToBoardPosition( &polysetref,
|
||||
wxPoint( 0, 0 ), aRefPad->GetOrientation() );
|
||||
}
|
||||
else
|
||||
{
|
||||
// BuildPadPolygon has meaning for rect a trapeziod shapes
|
||||
// and returns the 4 corners
|
||||
aRefPad->BuildPadPolygon( polyref, wxSize( 0, 0 ), aRefPad->GetOrientation() );
|
||||
}
|
||||
|
||||
switch( aPad->GetShape() )
|
||||
{
|
||||
case PAD_SHAPE_ROUNDRECT:
|
||||
case PAD_SHAPE_RECT:
|
||||
case PAD_SHAPE_TRAPEZOID:
|
||||
case PAD_SHAPE_CUSTOM:
|
||||
if( aPad->GetShape() == PAD_SHAPE_ROUNDRECT )
|
||||
{
|
||||
int padRadius = aPad->GetRoundRectCornerRadius();
|
||||
|
@ -712,6 +731,16 @@ bool DRC::checkClearancePadToPad( D_PAD* aRefPad, D_PAD* aPad )
|
|||
GetRoundRectCornerCenters( polycompare, padRadius, relativePadPos,
|
||||
aPad->GetSize(), aPad->GetOrientation() );
|
||||
}
|
||||
else if( aPad->GetShape() == PAD_SHAPE_CUSTOM )
|
||||
{
|
||||
polysetcompare.Append( aPad->GetCustomShapeAsPolygon() );
|
||||
|
||||
// The pad to compare can be rotated. calculate the rotated
|
||||
// coordinattes ( note, the pad to compare position
|
||||
// is the relativePadPos for this drc test
|
||||
aPad->BasicShapesAsPolygonToBoardPosition( &polysetcompare,
|
||||
relativePadPos, aPad->GetOrientation() );
|
||||
}
|
||||
else
|
||||
{
|
||||
aPad->BuildPadPolygon( polycompare, wxSize( 0, 0 ), aPad->GetOrientation() );
|
||||
|
@ -720,9 +749,11 @@ bool DRC::checkClearancePadToPad( D_PAD* aRefPad, D_PAD* aPad )
|
|||
for( int ii = 0; ii < 4; ii++ )
|
||||
polycompare[ii] += relativePadPos;
|
||||
}
|
||||
|
||||
// And now test polygons:
|
||||
if( polysetref.OutlineCount() )
|
||||
// And now test polygons: We have 3 cases:
|
||||
// one poly is complex and the other is basic (has only 4 corners)
|
||||
// both polys are complex
|
||||
// both polys are basic (have only 4 corners) the most usual case
|
||||
if( polysetref.OutlineCount() && polysetcompare.OutlineCount() == 0)
|
||||
{
|
||||
const SHAPE_LINE_CHAIN& refpoly = polysetref.COutline( 0 );
|
||||
// And now test polygons:
|
||||
|
@ -730,6 +761,24 @@ bool DRC::checkClearancePadToPad( D_PAD* aRefPad, D_PAD* aPad )
|
|||
polycompare, 4, dist_min ) )
|
||||
diag = false;
|
||||
}
|
||||
else if( polysetref.OutlineCount() == 0 && polysetcompare.OutlineCount())
|
||||
{
|
||||
const SHAPE_LINE_CHAIN& cmppoly = polysetcompare.COutline( 0 );
|
||||
// And now test polygons:
|
||||
if( !poly2polyDRC( (wxPoint*) &cmppoly.CPoint( 0 ), cmppoly.PointCount(),
|
||||
polyref, 4, dist_min ) )
|
||||
diag = false;
|
||||
}
|
||||
else if( polysetref.OutlineCount() && polysetcompare.OutlineCount() )
|
||||
{
|
||||
const SHAPE_LINE_CHAIN& refpoly = polysetref.COutline( 0 );
|
||||
const SHAPE_LINE_CHAIN& cmppoly = polysetcompare.COutline( 0 );
|
||||
|
||||
// And now test polygons:
|
||||
if( !poly2polyDRC( (wxPoint*) &refpoly.CPoint( 0 ), refpoly.PointCount(),
|
||||
(wxPoint*) &cmppoly.CPoint( 0 ), cmppoly.PointCount(), dist_min ) )
|
||||
diag = false;
|
||||
}
|
||||
else if( !poly2polyDRC( polyref, 4, polycompare, 4, dist_min ) )
|
||||
diag = false;
|
||||
break;
|
||||
|
@ -783,7 +832,7 @@ bool DRC::checkClearancePadToPad( D_PAD* aRefPad, D_PAD* aPad )
|
|||
}
|
||||
|
||||
default:
|
||||
wxLogDebug( wxT( "DRC::checkClearancePadToPad: unknown pad shape" ) );
|
||||
wxMessageBox( wxT( "DRC::checkClearancePadToPad: unknown pad shape" ) );
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -798,14 +847,33 @@ 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
|
||||
int r;
|
||||
// Note:
|
||||
// we are using a horizontal segment for test, because we know here
|
||||
// only the length and orientation+ of the segment
|
||||
// Therefore the coordinates of the shape of pad to compare
|
||||
// must be calculated in a axis system rotated by m_segmAngle
|
||||
// and centered to the segment origin, before they can be tested
|
||||
// against the segment
|
||||
// We are using:
|
||||
// m_padToTestPos the position of the pad shape in this axis system
|
||||
// m_segmAngle the axis system rotation
|
||||
|
||||
int segmHalfWidth = aSegmentWidth / 2;
|
||||
int distToLine = segmHalfWidth + aMinDist;
|
||||
|
||||
wxSize padHalfsize; // half dimension of the pad
|
||||
|
||||
if( aPad->GetShape() == PAD_SHAPE_CUSTOM )
|
||||
{
|
||||
// For a custom pad, the pad size has no meaning, we only can
|
||||
// use the bounding radius
|
||||
padHalfsize.x = padHalfsize.y = aPad->GetBoundingRadius();
|
||||
}
|
||||
else
|
||||
{
|
||||
padHalfsize.x = aPad->GetSize().x >> 1;
|
||||
padHalfsize.y = aPad->GetSize().y >> 1;
|
||||
}
|
||||
|
||||
if( aPad->GetShape() == PAD_SHAPE_TRAPEZOID ) // The size is bigger, due to GetDelta() extra size
|
||||
{
|
||||
|
@ -848,7 +916,10 @@ bool DRC::checkClearanceSegmToPad( const D_PAD* aPad, int aSegmentWidth, int aMi
|
|||
*/
|
||||
switch( aPad->GetShape() )
|
||||
{
|
||||
default:
|
||||
case PAD_SHAPE_CIRCLE:
|
||||
// This case was already tested, so it cannot be found here.
|
||||
// it is here just to avoid compil warning, and to remember
|
||||
// it is already tested.
|
||||
return false;
|
||||
|
||||
case PAD_SHAPE_OVAL:
|
||||
|
@ -912,11 +983,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();
|
||||
int 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.
|
||||
|
@ -992,11 +1065,41 @@ bool DRC::checkClearanceSegmToPad( const D_PAD* aPad, int aSegmentWidth, int aMi
|
|||
RotatePoint( &poly[ii], m_segmAngle );
|
||||
}
|
||||
|
||||
if( !poly2segmentDRC( poly, 4, wxPoint( 0, 0 ), wxPoint(m_segmLength,0), distToLine ) )
|
||||
if( !poly2segmentDRC( poly, 4, wxPoint( 0, 0 ),
|
||||
wxPoint(m_segmLength,0), distToLine ) )
|
||||
return false;
|
||||
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case PAD_SHAPE_CUSTOM:
|
||||
{
|
||||
SHAPE_POLY_SET polyset;
|
||||
polyset.Append( aPad->GetCustomShapeAsPolygon() );
|
||||
// The pad can be rotated. calculate the coordinates
|
||||
// relatives to the segment being tested
|
||||
// Note, the pad position relative to the segment origin
|
||||
// is m_padToTestPos
|
||||
aPad->BasicShapesAsPolygonToBoardPosition( &polyset,
|
||||
m_padToTestPos, orient );
|
||||
|
||||
// Rotate all coordinates by m_segmAngle, because the segment orient
|
||||
// is m_segmAngle
|
||||
// we are using a horizontal segment for test, because we know here
|
||||
// only the lenght and orientation+ of the segment
|
||||
// therefore all coordinates of the pad to test must be rotated by
|
||||
// m_segmAngle (they are already relative to the segment origin)
|
||||
aPad->BasicShapesAsPolygonToBoardPosition( &polyset,
|
||||
wxPoint( 0, 0 ), m_segmAngle );
|
||||
|
||||
const SHAPE_LINE_CHAIN& refpoly = polyset.COutline( 0 );
|
||||
|
||||
if( !poly2segmentDRC( (wxPoint*) &refpoly.CPoint( 0 ),
|
||||
refpoly.PointCount(),
|
||||
wxPoint( 0, 0 ), wxPoint(m_segmLength,0),
|
||||
distToLine ) )
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
|
|
@ -1243,6 +1243,7 @@ void PCB_IO::format( D_PAD* aPad, int aNestLevel ) const
|
|||
case PAD_SHAPE_OVAL: shape = "oval"; break;
|
||||
case PAD_SHAPE_TRAPEZOID: shape = "trapezoid"; break;
|
||||
case PAD_SHAPE_ROUNDRECT: shape = "roundrect"; break;
|
||||
case PAD_SHAPE_CUSTOM: shape = "custom"; break;
|
||||
|
||||
default:
|
||||
THROW_IO_ERROR( wxString::Format( _( "unknown pad type: %d"), aPad->GetShape() ) );
|
||||
|
@ -1346,6 +1347,107 @@ void PCB_IO::format( D_PAD* aPad, int aNestLevel ) const
|
|||
m_out->Print( aNestLevel+1, "%s", output.c_str()+1 ); // +1 skips 1st space on 1st element
|
||||
}
|
||||
|
||||
if( aPad->GetShape() == PAD_SHAPE_CUSTOM )
|
||||
{
|
||||
m_out->Print( 0, "\n");
|
||||
m_out->Print( aNestLevel+1, "(options" );
|
||||
|
||||
if( aPad->GetCustomShapeInZoneOpt() == CUST_PAD_SHAPE_IN_ZONE_CONVEXHULL )
|
||||
m_out->Print( 0, " (clearance convexhull)" );
|
||||
#if 1 // Set to 1 to output the default option
|
||||
else
|
||||
m_out->Print( 0, " (clearance outline)" );
|
||||
#endif
|
||||
|
||||
// Output the anchor pad shape (circle/rect)
|
||||
if( aPad->GetAnchorPadShape() == PAD_SHAPE_RECT )
|
||||
shape = "rect";
|
||||
else
|
||||
shape = "circle";
|
||||
|
||||
m_out->Print( 0, " (anchor %s)", shape );
|
||||
|
||||
m_out->Print( 0, ")"); // end of (options ...
|
||||
|
||||
// Output graphic primitive of the pad shape
|
||||
m_out->Print( 0, "\n");
|
||||
m_out->Print( aNestLevel+1, "(primitives" );
|
||||
|
||||
int nested_level = aNestLevel+2;
|
||||
|
||||
// Output all basic shapes
|
||||
for( unsigned icnt = 0; icnt < aPad->GetBasicShapes().size(); ++icnt )
|
||||
{
|
||||
m_out->Print( 0, "\n");
|
||||
|
||||
const PAD_CS_PRIMITIVE& primitive = aPad->GetBasicShapes()[icnt];
|
||||
|
||||
switch( primitive.m_Shape )
|
||||
{
|
||||
case S_SEGMENT: // usual segment : line with rounded ends
|
||||
m_out->Print( nested_level, "(gr_line (start %s) (end %s) (width %s))",
|
||||
FMT_IU( primitive.m_Start ).c_str(),
|
||||
FMT_IU( primitive.m_End ).c_str(),
|
||||
FMT_IU( primitive.m_Thickness ).c_str() );
|
||||
break;
|
||||
|
||||
case S_ARC: // Arc with rounded ends
|
||||
m_out->Print( nested_level, "(gr_arc (start %s) (end %s) (angle %s) (width %s))",
|
||||
FMT_IU( primitive.m_Start ).c_str(),
|
||||
FMT_IU( primitive.m_End ).c_str(),
|
||||
FMT_ANGLE( primitive.m_ArcAngle ).c_str(),
|
||||
FMT_IU( primitive.m_Thickness ).c_str() );
|
||||
break;
|
||||
|
||||
case S_CIRCLE: // ring or circle (circle if width == 0
|
||||
m_out->Print( nested_level, "(gr_circle (center %s) (end %s %s) (width %s))",
|
||||
FMT_IU( primitive.m_Start ).c_str(),
|
||||
FMT_IU( primitive.m_Start.x + primitive.m_Radius ).c_str(),
|
||||
FMT_IU( primitive.m_Start.y ).c_str(),
|
||||
FMT_IU( primitive.m_Thickness ).c_str() );
|
||||
break;
|
||||
|
||||
case S_POLYGON: // polygon
|
||||
if( primitive.m_Poly.size() < 2 )
|
||||
break; // Malformed polygon.
|
||||
|
||||
{
|
||||
m_out->Print( nested_level, "(gr_poly (pts\n");
|
||||
|
||||
// Write the polygon corners coordinates:
|
||||
const std::vector< wxPoint>& poly = primitive.m_Poly;
|
||||
int newLine = 0;
|
||||
|
||||
for( unsigned ii = 0; ii < poly.size(); ii++ )
|
||||
{
|
||||
if( newLine == 0 )
|
||||
m_out->Print( nested_level+1, " (xy %s)", FMT_IU( wxPoint( poly[ii].x, poly[ii].y ) ).c_str() );
|
||||
else
|
||||
m_out->Print( 0, " (xy %s)", FMT_IU( wxPoint( poly[ii].x, poly[ii].y ) ).c_str() );
|
||||
|
||||
if( ++newLine > 4 )
|
||||
{
|
||||
newLine = 0;
|
||||
m_out->Print( 0, "\n" );
|
||||
}
|
||||
}
|
||||
|
||||
if( primitive.m_Thickness != 0 )
|
||||
m_out->Print( 0, ") (width %s))", FMT_IU( primitive.m_Thickness ).c_str() );
|
||||
else
|
||||
m_out->Print( 0, "))");
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
m_out->Print( 0, "\n");
|
||||
m_out->Print( aNestLevel+1, ")" ); // end of (basic_shapes
|
||||
}
|
||||
|
||||
m_out->Print( 0, ")\n" );
|
||||
}
|
||||
|
||||
|
|
|
@ -73,6 +73,10 @@ void PCB_BASE_FRAME::Import_Pad_Settings( D_PAD* aPad, bool aDraw )
|
|||
|
||||
aPad->ImportSettingsFromMaster( mp );
|
||||
|
||||
aPad->SetBasicShapes( mp.GetBasicShapes() );
|
||||
aPad->SetAnchorPadShape( mp.GetAnchorPadShape() );
|
||||
aPad->MergeBasicShapesAsPolygon();
|
||||
|
||||
if( aDraw )
|
||||
m_canvas->RefreshDrawingRect( aPad->GetBoundingBox() );
|
||||
|
||||
|
|
|
@ -681,6 +681,8 @@ void PCB_PAINTER::draw( const D_PAD* aPad, int aLayer )
|
|||
m_gal->Translate( VECTOR2D( aPad->GetPosition() ) );
|
||||
m_gal->Rotate( -aPad->GetOrientationRadians() );
|
||||
|
||||
int custom_margin = 0; // a clearance/margin for custom shape, for solder paste/mask
|
||||
|
||||
// Choose drawing settings depending on if we are drawing a pad itself or a hole
|
||||
if( aLayer == LAYER_PADS_HOLES || aLayer == LAYER_NON_PLATED )
|
||||
{
|
||||
|
@ -692,6 +694,7 @@ void PCB_PAINTER::draw( const D_PAD* aPad, int aLayer )
|
|||
{
|
||||
// Drawing soldermask
|
||||
int soldermaskMargin = aPad->GetSolderMaskMargin();
|
||||
custom_margin = soldermaskMargin;
|
||||
|
||||
m_gal->Translate( VECTOR2D( aPad->GetOffset() ) );
|
||||
size = VECTOR2D( aPad->GetSize().x / 2.0 + soldermaskMargin,
|
||||
|
@ -702,6 +705,8 @@ void PCB_PAINTER::draw( const D_PAD* aPad, int aLayer )
|
|||
{
|
||||
// Drawing solderpaste
|
||||
wxSize solderpasteMargin = aPad->GetSolderPasteMargin();
|
||||
// try to find a clearance which can be used for custom shapes
|
||||
custom_margin = solderpasteMargin.x;
|
||||
|
||||
m_gal->Translate( VECTOR2D( aPad->GetOffset() ) );
|
||||
size = VECTOR2D( aPad->GetSize().x / 2.0 + solderpasteMargin.x,
|
||||
|
@ -788,6 +793,55 @@ void PCB_PAINTER::draw( const D_PAD* aPad, int aLayer )
|
|||
break;
|
||||
}
|
||||
|
||||
case PAD_SHAPE_CUSTOM:
|
||||
{ // Draw the complex custom shape
|
||||
std::deque<VECTOR2D> pointList;
|
||||
|
||||
// Use solder[Paste/Mask]size or pad size to build pad shape
|
||||
// however, solder[Paste/Mask] size has no actual meaning for a
|
||||
// custom shape, because it is a set of basic shapes
|
||||
// We use the custom_margin (good for solder mask, but approximative
|
||||
// for solder paste).
|
||||
if( custom_margin )
|
||||
{
|
||||
SHAPE_POLY_SET outline;
|
||||
outline.Append( aPad->GetCustomShapeAsPolygon() );
|
||||
const int segmentToCircleCount = 32;
|
||||
outline.Inflate( custom_margin, segmentToCircleCount );
|
||||
|
||||
// Draw the polygon: only one polygon is expected
|
||||
SHAPE_LINE_CHAIN& poly = outline.Outline( 0 );
|
||||
|
||||
for( int ii = 0; ii < poly.PointCount(); ii++ )
|
||||
pointList.push_back( poly.Point( ii ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
// Draw the polygon: only one polygon is expected
|
||||
// However we provide a multi polygon shape drawing
|
||||
// ( for the future or to show even an incorrect shape
|
||||
const SHAPE_POLY_SET& outline = aPad->GetCustomShapeAsPolygon();
|
||||
|
||||
for( int jj = 0; jj < outline.OutlineCount(); ++jj )
|
||||
{
|
||||
const SHAPE_LINE_CHAIN& poly = outline.COutline( jj );
|
||||
|
||||
for( int ii = 0; ii < poly.PointCount(); ii++ )
|
||||
pointList.push_back( poly.CPoint( ii ) );
|
||||
}
|
||||
}
|
||||
|
||||
if( m_pcbSettings.m_sketchMode[LAYER_PADS] )
|
||||
{
|
||||
// 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;
|
||||
|
|
|
@ -1910,7 +1910,6 @@ MODULE* PCB_PARSER::parseMODULE_unchecked( wxArrayString* aInitialComments )
|
|||
Expecting( "smd and/or virtual" );
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case T_fp_text:
|
||||
|
@ -2307,6 +2306,10 @@ D_PAD* PCB_PARSER::parseD_PAD( MODULE* aParent )
|
|||
pad->SetShape( PAD_SHAPE_ROUNDRECT );
|
||||
break;
|
||||
|
||||
case T_custom:
|
||||
pad->SetShape( PAD_SHAPE_CUSTOM );
|
||||
break;
|
||||
|
||||
default:
|
||||
Expecting( "circle, rectangle, roundrect, oval, trapezoid or custom" );
|
||||
}
|
||||
|
@ -2481,17 +2484,141 @@ D_PAD* PCB_PARSER::parseD_PAD( MODULE* aParent )
|
|||
NeedRIGHT();
|
||||
break;
|
||||
|
||||
case T_options:
|
||||
parseD_PAD_option( pad.get() );
|
||||
break;
|
||||
|
||||
case T_primitives:
|
||||
for( token = NextTok(); token != T_RIGHT; token = NextTok() )
|
||||
{
|
||||
if( token == T_LEFT )
|
||||
token = NextTok();
|
||||
|
||||
// Currently, I am using parseDRAWSEGMENT() to read basic shapes parameters,
|
||||
// because they are the same as a DRAWSEGMENT.
|
||||
// However it could be better to write a specific parser, to avoid possible issues
|
||||
// if the DRAWSEGMENT parser is modified.
|
||||
DRAWSEGMENT* dummysegm = NULL;
|
||||
|
||||
switch( token )
|
||||
{
|
||||
case T_gr_arc:
|
||||
dummysegm = parseDRAWSEGMENT();
|
||||
pad->AddBasicShape( dummysegm->GetCenter(), dummysegm->GetArcStart(),
|
||||
dummysegm->GetAngle(), dummysegm->GetWidth() );
|
||||
break;
|
||||
|
||||
case T_gr_line:
|
||||
dummysegm = parseDRAWSEGMENT();
|
||||
pad->AddBasicShape( dummysegm->GetStart(), dummysegm->GetEnd(),
|
||||
dummysegm->GetWidth() );
|
||||
break;
|
||||
|
||||
case T_gr_circle:
|
||||
dummysegm = parseDRAWSEGMENT();
|
||||
pad->AddBasicShape( dummysegm->GetCenter(), dummysegm->GetRadius(),
|
||||
dummysegm->GetWidth() );
|
||||
break;
|
||||
|
||||
case T_gr_poly:
|
||||
dummysegm = parseDRAWSEGMENT();
|
||||
pad->AddBasicShape( dummysegm->GetPolyPoints(), dummysegm->GetWidth() );
|
||||
break;
|
||||
|
||||
default:
|
||||
Expecting( "at, drill, layers, net, die_length, solder_mask_margin, roundrect_rratio,"
|
||||
"solder_paste_margin, solder_paste_margin_ratio, clearance, "
|
||||
"zone_connect, fp_poly, basic_shapes, thermal_width, or thermal_gap" );
|
||||
Expecting( "gr_line, gr_arc, gr_circle or gr_poly" );
|
||||
break;
|
||||
}
|
||||
|
||||
delete dummysegm;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
Expecting( "at, drill, layers, net, die_length, solder_mask_margin, roundrect_rratio,\n"
|
||||
"solder_paste_margin, solder_paste_margin_ratio, clearance,\n"
|
||||
"zone_connect, fp_poly, primitives, thermal_width, or thermal_gap" );
|
||||
}
|
||||
}
|
||||
|
||||
// Be sure the custom shape polygon is built:
|
||||
if( pad->GetShape() == PAD_SHAPE_CUSTOM )
|
||||
pad->MergeBasicShapesAsPolygon();
|
||||
|
||||
return pad.release();
|
||||
}
|
||||
|
||||
|
||||
bool PCB_PARSER::parseD_PAD_option( D_PAD* aPad )
|
||||
{
|
||||
// Parse only the (option ...) inside a pad description
|
||||
for( T token = NextTok(); token != T_RIGHT; token = NextTok() )
|
||||
{
|
||||
if( token != T_LEFT )
|
||||
Expecting( T_LEFT );
|
||||
|
||||
token = NextTok();
|
||||
|
||||
switch( token )
|
||||
{
|
||||
case T_anchor:
|
||||
token = NextTok();
|
||||
// Custom shaped pads have a "anchor pad", which is the reference
|
||||
// for connection calculations.
|
||||
// Because this is an anchor, only the 2 very basic shapes are managed:
|
||||
// circle and rect. The default is circle
|
||||
switch( token )
|
||||
{
|
||||
case T_circle: // default
|
||||
break;
|
||||
|
||||
case T_rect:
|
||||
aPad->SetAnchorPadShape( PAD_SHAPE_RECT );
|
||||
break;
|
||||
|
||||
default:
|
||||
// Currently, because pad options is a moving target
|
||||
// just skip unknown keywords
|
||||
break;
|
||||
}
|
||||
NeedRIGHT();
|
||||
break;
|
||||
|
||||
case T_clearance:
|
||||
token = NextTok();
|
||||
// Custom shaped pads have a clearance area that is the pad shape
|
||||
// (like usual pads) or the convew hull of the pad shape.
|
||||
switch( token )
|
||||
{
|
||||
case T_outline:
|
||||
aPad->SetCustomShapeInZoneOpt( CUST_PAD_SHAPE_IN_ZONE_OUTLINE );
|
||||
break;
|
||||
|
||||
case T_convexhull:
|
||||
aPad->SetCustomShapeInZoneOpt( CUST_PAD_SHAPE_IN_ZONE_CONVEXHULL );
|
||||
break;
|
||||
|
||||
default:
|
||||
// Currently, because pad options is a moving target
|
||||
// just skip unknown keywords
|
||||
break;
|
||||
}
|
||||
NeedRIGHT();
|
||||
break;
|
||||
|
||||
default:
|
||||
// Currently, because pad options is a moving target
|
||||
// just skip unknown keywords
|
||||
while( (token = NextTok() ) != T_RIGHT )
|
||||
{}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
TRACK* PCB_PARSER::parseTRACK()
|
||||
{
|
||||
wxCHECK_MSG( CurTok() == T_segment, NULL,
|
||||
|
|
|
@ -134,6 +134,8 @@ class PCB_PARSER : public PCB_LEXER
|
|||
TEXTE_MODULE* parseTEXTE_MODULE();
|
||||
EDGE_MODULE* parseEDGE_MODULE();
|
||||
D_PAD* parseD_PAD( MODULE* aParent = NULL );
|
||||
// Parse only the (option ...) inside a pad description
|
||||
bool parseD_PAD_option( D_PAD* aPad );
|
||||
TRACK* parseTRACK();
|
||||
VIA* parseVIA();
|
||||
ZONE_CONTAINER* parseZONE_CONTAINER();
|
||||
|
|
|
@ -182,6 +182,19 @@ void BRDITEMS_PLOTTER::PlotPad( D_PAD* aPad, COLOR4D aColor, EDA_DRAW_MODE_T aPl
|
|||
aPad->GetOrientation(), aPlotMode, &gbr_metadata );
|
||||
break;
|
||||
|
||||
case PAD_SHAPE_CUSTOM:
|
||||
{
|
||||
SHAPE_POLY_SET polygons;
|
||||
aPad->MergeBasicShapesAsPolygon(&polygons, 64 );
|
||||
|
||||
if( polygons.OutlineCount() == 0 )
|
||||
break;
|
||||
|
||||
aPad->BasicShapesAsPolygonToBoardPosition( &polygons, shape_pos, aPad->GetOrientation() );
|
||||
m_plotter->FlashPadCustom( shape_pos, aPad->GetSize(), &polygons, aPlotMode, &gbr_metadata );
|
||||
}
|
||||
break;
|
||||
|
||||
case PAD_SHAPE_RECT:
|
||||
default:
|
||||
m_plotter->FlashPadRect( shape_pos, aPad->GetSize(),
|
||||
|
|
|
@ -626,6 +626,26 @@ std::unique_ptr<PNS::SOLID> PNS_KICAD_IFACE::syncPad( D_PAD* aPad )
|
|||
}
|
||||
break;
|
||||
|
||||
case PAD_SHAPE_CUSTOM:
|
||||
{
|
||||
SHAPE_POLY_SET outline;
|
||||
outline.Append( aPad->GetCustomShapeAsPolygon() );
|
||||
aPad->BasicShapesAsPolygonToBoardPosition( &outline, wx_c, aPad->GetOrientation() );
|
||||
|
||||
for( int jj = 0; jj < outline.OutlineCount(); ++jj )
|
||||
{
|
||||
SHAPE_CONVEX* shape = new SHAPE_CONVEX();
|
||||
const SHAPE_LINE_CHAIN& poly = outline.COutline( jj );
|
||||
|
||||
for( int ii = 0; ii < poly.PointCount(); ii++ )
|
||||
shape->Append( wxPoint( poly.CPoint( ii ).x, poly.CPoint( ii ).y ) );
|
||||
|
||||
solid->SetShape( shape );
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
wxLogTrace( "PNS", "unsupported pad shape" );
|
||||
return nullptr;
|
||||
|
@ -722,6 +742,26 @@ std::unique_ptr<PNS::SOLID> PNS_KICAD_IFACE::syncPad( D_PAD* aPad )
|
|||
break;
|
||||
}
|
||||
|
||||
case PAD_SHAPE_CUSTOM:
|
||||
{
|
||||
SHAPE_POLY_SET outline;
|
||||
outline.Append( aPad->GetCustomShapeAsPolygon() );
|
||||
aPad->BasicShapesAsPolygonToBoardPosition( &outline, wx_c, aPad->GetOrientation() );
|
||||
|
||||
for( int jj = 0; jj < outline.OutlineCount(); ++jj )
|
||||
{
|
||||
SHAPE_CONVEX* shape = new SHAPE_CONVEX();
|
||||
const SHAPE_LINE_CHAIN& poly = outline.COutline( jj );
|
||||
|
||||
for( int ii = 0; ii < poly.PointCount(); ii++ )
|
||||
shape->Append( wxPoint( poly.CPoint( ii ).x, poly.CPoint( ii ).y ) );
|
||||
|
||||
solid->SetShape( shape );
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
wxLogTrace( "PNS", "unsupported pad shape" );
|
||||
return nullptr;
|
||||
|
|
|
@ -69,6 +69,7 @@
|
|||
|
||||
#include <geometry/shape_poly_set.h>
|
||||
#include <geometry/shape_file_io.h>
|
||||
#include <geometry/convex_hull.h>
|
||||
|
||||
/* DEBUG OPTION:
|
||||
* To emit zone data to a file when filling zones for the debugging purposes,
|
||||
|
@ -194,6 +195,31 @@ void ZONE_CONTAINER::buildFeatureHoleList( BOARD* aPcb, SHAPE_POLY_SET& aFeature
|
|||
if( item_boundingbox.Intersects( zone_boundingbox ) )
|
||||
{
|
||||
int clearance = std::max( zone_clearance, item_clearance );
|
||||
|
||||
// PAD_SHAPE_CUSTOM can have a specific keepout, to avoid to break the shape
|
||||
if( pad->GetShape() == PAD_SHAPE_CUSTOM &&
|
||||
pad->GetCustomShapeInZoneOpt() == CUST_PAD_SHAPE_IN_ZONE_CONVEXHULL )
|
||||
{
|
||||
// the pad shape in zone can be its convex hull or
|
||||
// the shape itself
|
||||
SHAPE_POLY_SET outline( pad->GetCustomShapeAsPolygon() );
|
||||
outline.Inflate( KiROUND( clearance*correctionFactor) , segsPerCircle );
|
||||
pad->BasicShapesAsPolygonToBoardPosition( &outline,
|
||||
pad->GetPosition(), pad->GetOrientation() );
|
||||
|
||||
if( pad->GetCustomShapeInZoneOpt() == CUST_PAD_SHAPE_IN_ZONE_CONVEXHULL )
|
||||
{
|
||||
std::vector<wxPoint> convex_hull;
|
||||
BuildConvexHull( convex_hull, outline );
|
||||
|
||||
aFeatures.NewOutline();
|
||||
for( unsigned ii = 0; ii < convex_hull.size(); ++ii )
|
||||
aFeatures.Append( convex_hull[ii] );
|
||||
}
|
||||
else
|
||||
aFeatures.Append( outline );
|
||||
}
|
||||
else
|
||||
pad->TransformShapeWithClearanceToPolygon( aFeatures,
|
||||
clearance,
|
||||
segsPerCircle,
|
||||
|
@ -204,7 +230,10 @@ void ZONE_CONTAINER::buildFeatureHoleList( BOARD* aPcb, SHAPE_POLY_SET& aFeature
|
|||
}
|
||||
|
||||
// Pads are removed from zone if the setup is PAD_ZONE_CONN_NONE
|
||||
if( GetPadConnection( pad ) == PAD_ZONE_CONN_NONE )
|
||||
// or if they have a custom shape, because a thermal relief will break
|
||||
// the shape
|
||||
if( GetPadConnection( pad ) == PAD_ZONE_CONN_NONE ||
|
||||
pad->GetShape() == PAD_SHAPE_CUSTOM )
|
||||
{
|
||||
int gap = zone_clearance;
|
||||
int thermalGap = GetThermalReliefGap( pad );
|
||||
|
@ -214,10 +243,28 @@ void ZONE_CONTAINER::buildFeatureHoleList( BOARD* aPcb, SHAPE_POLY_SET& aFeature
|
|||
|
||||
if( item_boundingbox.Intersects( zone_boundingbox ) )
|
||||
{
|
||||
// PAD_SHAPE_CUSTOM has a specific keepout, to avoid to break the shape
|
||||
// the pad shape in zone can be its convex hull or the shape itself
|
||||
if( pad->GetShape() == PAD_SHAPE_CUSTOM &&
|
||||
pad->GetCustomShapeInZoneOpt() == CUST_PAD_SHAPE_IN_ZONE_CONVEXHULL )
|
||||
{
|
||||
// the pad shape in zone can be its convex hull or
|
||||
// the shape itself
|
||||
SHAPE_POLY_SET outline( pad->GetCustomShapeAsPolygon() );
|
||||
outline.Inflate( KiROUND( gap*correctionFactor) , segsPerCircle );
|
||||
pad->BasicShapesAsPolygonToBoardPosition( &outline,
|
||||
pad->GetPosition(), pad->GetOrientation() );
|
||||
|
||||
std::vector<wxPoint> convex_hull;
|
||||
BuildConvexHull( convex_hull, outline );
|
||||
|
||||
aFeatures.NewOutline();
|
||||
for( unsigned ii = 0; ii < convex_hull.size(); ++ii )
|
||||
aFeatures.Append( convex_hull[ii] );
|
||||
}
|
||||
else
|
||||
pad->TransformShapeWithClearanceToPolygon( aFeatures,
|
||||
gap,
|
||||
segsPerCircle,
|
||||
correctionFactor );
|
||||
gap, segsPerCircle, correctionFactor );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue