Flatten CS_PAD_PRIMITIVE out in favour of reusing DRAWSEGMENT.

(In prep for the eventual replacement of DRAWSEGMENT internals with
SHAPE.)
This commit is contained in:
Jeff Young 2020-06-24 12:12:39 +01:00
parent 5ee806c3a3
commit e376750f62
12 changed files with 360 additions and 555 deletions

View File

@ -131,6 +131,52 @@ void DRAWSEGMENT::Move( const wxPoint& aMoveVector )
}
void DRAWSEGMENT::Scale( double aScale )
{
auto scalePt = [&]( wxPoint& pt )
{
pt.x = KiROUND( pt.x * aScale );
pt.y = KiROUND( pt.y * aScale );
};
int radius = GetRadius();
scalePt( m_Start );
scalePt( m_End );
// specific parameters:
switch( m_Shape )
{
case S_CURVE:
scalePt( m_BezierC1 );
scalePt( m_BezierC2 );
break;
case S_CIRCLE: // ring or circle
m_End.x = m_Start.x + KiROUND( radius * aScale );
m_End.y = m_Start.y;
break;
case S_POLYGON: // polygon
{
std::vector<wxPoint> pts;
for( const VECTOR2I& pt : m_Poly.Outline( 0 ).CPoints() )
{
pts.emplace_back( pt );
scalePt( pts.back() );
}
SetPolyPoints( pts );
}
break;
default:
break;
}
}
void DRAWSEGMENT::Rotate( const wxPoint& aRotCentre, double aAngle )
{
switch( m_Shape )
@ -138,12 +184,30 @@ void DRAWSEGMENT::Rotate( const wxPoint& aRotCentre, double aAngle )
case S_ARC:
case S_SEGMENT:
case S_CIRCLE:
case S_RECT:
// these can all be done by just rotating the start and end points
RotatePoint( &m_Start, aRotCentre, aAngle);
RotatePoint( &m_End, aRotCentre, aAngle);
break;
case S_RECT:
if( KiROUND( aAngle ) % 900 == 0 )
{
RotatePoint( &m_Start, aRotCentre, aAngle );
RotatePoint( &m_End, aRotCentre, aAngle );
break;
}
// Convert non-cartesian-rotated rect to a diamond
m_Shape = S_POLYGON;
m_Poly.RemoveAllContours();
m_Poly.NewOutline();
m_Poly.Append( m_Start );
m_Poly.Append( m_End.x, m_Start.y );
m_Poly.Append( m_End );
m_Poly.Append( m_Start.x, m_End.y );
KI_FALLTHROUGH;
case S_POLYGON:
m_Poly.Rotate( -DECIDEG2RAD( aAngle ), VECTOR2I( aRotCentre ) );
break;

View File

@ -262,6 +262,8 @@ public:
virtual void Flip( const wxPoint& aCentre, bool aFlipLeftRight ) override;
void Scale( double aScale );
/**
* Function TransformShapeWithClearanceToPolygon
* Convert the draw segment to a closed polygon

View File

@ -43,6 +43,7 @@
#include <view/view.h>
#include <class_board.h>
#include <class_module.h>
#include <class_drawsegment.h>
#include <geometry/polygon_test_point_inside.h>
#include <convert_to_biu.h>
#include <convert_basic_shapes_to_polygon.h>
@ -309,24 +310,11 @@ void D_PAD::buildEffectiveShapes() const
if( GetShape() == PAD_SHAPE_CUSTOM )
{
#if 1
// For now we add these in as a single SHAPE_POLY_SET, but once we've moved them
// over to shapes themselves then we can just copy them across (with the requisite
// rotating and offsetting).
SHAPE_POLY_SET* poly = new SHAPE_POLY_SET();
MergePrimitivesAsPolygon( poly );
poly->Rotate( -DECIDEG2RAD( m_Orient ) );
poly->Move( shapePos );
add( poly );
#else
for( const std::shared_ptr<SHAPE>& primitive : m_basicShapes )
{
SHAPE* copy = primitive->Clone();
copy->Rotate( -DECIDEG2RAD( m_Orient ) );
copy->Move( shapePos );
add( copy );
}
#endif
}
// Bounding radius
@ -458,24 +446,8 @@ void D_PAD::Flip( const wxPoint& aCentre, bool aFlipLeftRight )
// Flip the basic shapes, in custom pads
void D_PAD::FlipPrimitives()
{
// Flip custom shapes
for( PAD_CS_PRIMITIVE& primitive : m_basicShapes )
{
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:
for( wxPoint& pt : primitive.m_Poly )
MIRROR( pt.y, 0 );
break;
default:
break;
}
}
for( std::shared_ptr<DRAWSEGMENT>& primitive : m_editPrimitives )
primitive->Flip( wxPoint( 0, 0 ), false );
m_shapesDirty = true;
}
@ -483,24 +455,8 @@ void D_PAD::FlipPrimitives()
void D_PAD::MirrorXPrimitives( int aX )
{
// Mirror custom shapes
for( PAD_CS_PRIMITIVE& primitive : m_basicShapes )
{
MIRROR( primitive.m_Start.x, aX );
MIRROR( primitive.m_End.x, aX );
primitive.m_ArcAngle = -primitive.m_ArcAngle;
switch( primitive.m_Shape )
{
case S_POLYGON: // polygon
for( wxPoint& pt : primitive.m_Poly )
MIRROR( pt.x, 0 );
break;
default:
break;
}
}
for( std::shared_ptr<DRAWSEGMENT>& primitive : m_editPrimitives )
primitive->Flip( wxPoint( aX, 0 ), true );
m_shapesDirty = true;
}

View File

@ -60,60 +60,6 @@ namespace KIGFX
class VIEW;
}
/** 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_RECT, 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
wxPoint m_Ctrl1; /// Bezier Control point 1
wxPoint m_Ctrl2; /// Bezier Control point 2
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
// Geometric transform
/** Move the primitive
* @param aMoveVector is the deplacement vector
*/
void Move( wxPoint aMoveVector );
/**
* Rotates the primitive about a point
* @param aRotCentre center of rotation
* @param aAngle angle in tenths of degree
*/
void Rotate( const wxPoint& aRotCentre, double aAngle );
/** 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 );
/** Export the PAD_CS_PRIMITIVE parameters to a EDGE_MODULE
* useful to convert a primitive shape to a EDGE_MODULE shape for editing in footprint editor
* @param aTarget is the EDGE_MODULE to initialize
*/
void ExportTo( EDGE_MODULE* aTarget );
};
class D_PAD : public BOARD_CONNECTED_ITEM
{
public:
@ -307,7 +253,10 @@ public:
/**
* Accessor to the basic shape list
*/
const std::vector<PAD_CS_PRIMITIVE>& GetPrimitives() const { return m_basicShapes; }
const std::vector<std::shared_ptr<DRAWSEGMENT>>& GetPrimitives() const
{
return m_editPrimitives;
}
void Flip( const wxPoint& aCentre, bool aFlipLeftRight ) override;
@ -324,12 +273,12 @@ public:
/**
* Import to the basic shape list
*/
void SetPrimitives( const std::vector<PAD_CS_PRIMITIVE>& aPrimitivesList );
void SetPrimitives( const std::vector<std::shared_ptr<DRAWSEGMENT>>& aPrimitivesList );
/**
* Add to the basic shape list
*/
void AddPrimitives( const std::vector<PAD_CS_PRIMITIVE>& aPrimitivesList );
void AddPrimitives( const std::vector<std::shared_ptr<DRAWSEGMENT>>& aPrimitivesList );
/**
@ -633,7 +582,7 @@ private:
*/
int calcBoundingRadius() const;
void addCustomPadPrimitivesToPolygon( SHAPE_POLY_SET* aMergedPolygon, int aError ) const;
void addPadPrimitivesToPolygon( SHAPE_POLY_SET* aMergedPolygon, int aError ) const;
void buildEffectiveShapes() const;
@ -647,17 +596,15 @@ private:
///< PAD_SHAPE_OVAL, PAD_SHAPE_TRAPEZOID,
///< PAD_SHAPE_ROUNDRECT, PAD_SHAPE_POLYGON
// Edit definitions of primitives for custom pad shapes. In local coordinates relative
// to m_Pos (NOT shapePos) at orient 0.
std::vector<std::shared_ptr<DRAWSEGMENT>> m_editPrimitives;
mutable bool m_shapesDirty;
mutable int m_effectiveBoundingRadius;
mutable std::vector<std::shared_ptr<SHAPE>> m_effectiveShapes;
mutable std::shared_ptr<SHAPE_SEGMENT> m_effectiveHoleShape;
/** 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;
/**
* How to build the custom shape in zone, to create the clearance area:
* CUST_PAD_SHAPE_IN_ZONE_OUTLINE = use pad shape

View File

@ -47,7 +47,7 @@
DIALOG_PAD_PRIMITIVES_PROPERTIES::DIALOG_PAD_PRIMITIVES_PROPERTIES( wxWindow* aParent,
PCB_BASE_FRAME* aFrame,
PAD_CS_PRIMITIVE * aShape ) :
DRAWSEGMENT* aShape ) :
DIALOG_PAD_PRIMITIVES_PROPERTIES_BASE( aParent ),
m_shape( aShape ),
m_startX( aFrame, m_startXLabel, m_startXCtrl, m_startXUnits, true ),
@ -76,19 +76,19 @@ bool DIALOG_PAD_PRIMITIVES_PROPERTIES::TransferDataToWindow()
return false;
// Shows the text info about circle or ring only for S_CIRCLE shape
if( m_shape->m_Shape != S_CIRCLE )
if( m_shape->GetShape() != S_CIRCLE )
m_staticTextInfo->Show( false );
m_thickness.SetValue( m_shape->m_Thickness );
m_thickness.SetValue( m_shape->GetWidth() );
switch( m_shape->m_Shape )
switch( m_shape->GetShape() )
{
case S_SEGMENT: // Segment with rounded ends
SetTitle( _( "Segment" ) );
m_startX.SetValue( m_shape->m_Start.x );
m_startY.SetValue( m_shape->m_Start.y );
m_endX.SetValue( m_shape->m_End.x );
m_endY.SetValue( m_shape->m_End.y );
m_startX.SetValue( m_shape->GetStart().x );
m_startY.SetValue( m_shape->GetStart().y );
m_endX.SetValue( m_shape->GetEnd().x );
m_endY.SetValue( m_shape->GetEnd().y );
m_ctrl1X.Show( false, true );
m_ctrl1Y.Show( false, true );
m_ctrl2X.Show( false, true );
@ -102,27 +102,27 @@ bool DIALOG_PAD_PRIMITIVES_PROPERTIES::TransferDataToWindow()
case S_CURVE: // Bezier line
SetTitle( _( "Bezier" ) );
m_startX.SetValue( m_shape->m_Start.x );
m_startY.SetValue( m_shape->m_Start.y );
m_endX.SetValue( m_shape->m_End.x );
m_endY.SetValue( m_shape->m_End.y );
m_ctrl1X.SetValue( m_shape->m_Ctrl1.x );
m_ctrl1Y.SetValue( m_shape->m_Ctrl1.y );
m_ctrl2X.SetValue( m_shape->m_Ctrl2.x );
m_ctrl2Y.SetValue( m_shape->m_Ctrl2.y );
m_startX.SetValue( m_shape->GetStart().x );
m_startY.SetValue( m_shape->GetStart().y );
m_endX.SetValue( m_shape->GetEnd().x );
m_endY.SetValue( m_shape->GetEnd().y );
m_ctrl1X.SetValue( m_shape->GetBezControl1().x );
m_ctrl1Y.SetValue( m_shape->GetBezControl1().y );
m_ctrl2X.SetValue( m_shape->GetBezControl2().x );
m_ctrl2Y.SetValue( m_shape->GetBezControl2().y );
m_radius.Show( false );
break;
case S_ARC: // Arc with rounded ends
SetTitle( _( "Arc" ) );
m_startX.SetValue( m_shape->m_End.x ); // confusingly, the start point of the arc
m_startY.SetValue( m_shape->m_End.y );
m_startX.SetValue( m_shape->GetEnd().x ); // confusingly, the start point of the arc
m_startY.SetValue( m_shape->GetEnd().y );
m_staticTextPosEnd->SetLabel( _( "Center" ) );
m_endX.SetValue( m_shape->m_Start.x ); // arc center
m_endY.SetValue( m_shape->m_Start.y );
m_endX.SetValue( m_shape->GetStart().x ); // arc center
m_endY.SetValue( m_shape->GetStart().y );
m_radiusLabel->SetLabel( _( "Angle:" ) );
m_radius.SetUnits( EDA_UNITS::DEGREES );
m_radius.SetValue( m_shape->m_ArcAngle );
m_radius.SetValue( m_shape->GetAngle() );
m_ctrl1X.Show( false, true );
m_ctrl1Y.Show( false, true );
m_ctrl2X.Show( false, true );
@ -134,7 +134,7 @@ bool DIALOG_PAD_PRIMITIVES_PROPERTIES::TransferDataToWindow()
break;
case S_CIRCLE: // ring or circle
if( m_shape->m_Thickness )
if( m_shape->GetWidth() )
SetTitle( _( "Ring" ) );
else
SetTitle( _( "Circle" ) );
@ -146,9 +146,9 @@ bool DIALOG_PAD_PRIMITIVES_PROPERTIES::TransferDataToWindow()
// Circle center uses position controls:
m_staticTextPosStart->SetLabel( _( "Center:" ) );
m_startX.SetValue( m_shape->m_Start.x );
m_startY.SetValue( m_shape->m_Start.y );
m_radius.SetValue( m_shape->m_Radius );
m_startX.SetValue( m_shape->GetStart().x );
m_startY.SetValue( m_shape->GetStart().y );
m_radius.SetValue( m_shape->GetRadius() );
m_ctrl1X.Show( false, true );
m_ctrl1Y.Show( false, true );
m_ctrl2X.Show( false, true );
@ -174,43 +174,34 @@ bool DIALOG_PAD_PRIMITIVES_PROPERTIES::TransferDataToWindow()
bool DIALOG_PAD_PRIMITIVES_PROPERTIES::TransferDataFromWindow()
{
// Transfer data out of the GUI.
m_shape->m_Thickness = m_thickness.GetValue();
m_shape->SetWidth( m_thickness.GetValue() );
switch( m_shape->m_Shape )
switch( m_shape->GetShape() )
{
case S_SEGMENT: // Segment with rounded ends
m_shape->m_Start.x = m_startX.GetValue();
m_shape->m_Start.y = m_startY.GetValue();
m_shape->m_End.x = m_endX.GetValue();
m_shape->m_End.y = m_endY.GetValue();
m_shape->SetStart( wxPoint( m_startX.GetValue(), m_startY.GetValue() ) );
m_shape->SetEnd( wxPoint( m_endX.GetValue(), m_endY.GetValue() ) );
break;
case S_CURVE: // Segment with rounded ends
m_shape->m_Start.x = m_startX.GetValue();
m_shape->m_Start.y = m_startY.GetValue();
m_shape->m_End.x = m_endX.GetValue();
m_shape->m_End.y = m_endY.GetValue();
m_shape->m_Ctrl1.x = m_ctrl1X.GetValue();
m_shape->m_Ctrl1.y = m_ctrl1Y.GetValue();
m_shape->m_Ctrl2.x = m_ctrl2X.GetValue();
m_shape->m_Ctrl2.y = m_ctrl2Y.GetValue();
m_shape->SetStart( wxPoint( m_startX.GetValue(), m_startY.GetValue() ) );
m_shape->SetEnd( wxPoint( m_endX.GetValue(), m_endY.GetValue() ) );
m_shape->SetBezControl1( wxPoint( m_ctrl1X.GetValue(), m_ctrl1Y.GetValue() ) );
m_shape->SetBezControl1( wxPoint( m_ctrl2X.GetValue(), m_ctrl2Y.GetValue() ) );
break;
case S_ARC: // Arc with rounded ends
// NB: we store the center of the arc in m_Start, and, confusingly,
// the start point in m_End
m_shape->m_Start.x = m_endX.GetValue();
m_shape->m_Start.y = m_endY.GetValue();
m_shape->m_End.x = m_startX.GetValue();
m_shape->m_End.y = m_startY.GetValue();
m_shape->SetStart( wxPoint( m_endX.GetValue(), m_endY.GetValue() ) );
m_shape->SetEnd( wxPoint( m_startX.GetValue(), m_startY.GetValue() ) );
// arc angle
m_shape->m_ArcAngle = m_radius.GetValue();
m_shape->SetAngle( m_radius.GetValue() );
break;
case S_CIRCLE: // ring or circle
m_shape->m_Start.x = m_startX.GetValue();
m_shape->m_Start.y = m_startY.GetValue();
m_shape->m_Radius = m_radius.GetValue();
m_shape->SetStart( wxPoint( m_startX.GetValue(), m_startY.GetValue() ) );
m_shape->SetEnd( m_shape->GetStart() + wxPoint( m_radius.GetValue(), 0 ) );
break;
case S_POLYGON: // polygon
@ -228,12 +219,14 @@ bool DIALOG_PAD_PRIMITIVES_PROPERTIES::TransferDataFromWindow()
DIALOG_PAD_PRIMITIVE_POLY_PROPS::DIALOG_PAD_PRIMITIVE_POLY_PROPS( wxWindow* aParent,
PCB_BASE_FRAME* aFrame,
PAD_CS_PRIMITIVE * aShape ) :
DRAWSEGMENT* aShape ) :
DIALOG_PAD_PRIMITIVE_POLY_PROPS_BASE( aParent ),
m_shape( aShape ),
m_currshape( *m_shape ),
m_thickness( aFrame, m_thicknessLabel, m_thicknessCtrl, m_thicknessUnits, true )
{
for( const VECTOR2I& pt : m_shape->GetPolyShape().Outline( 0 ).CPoints() )
m_currPoints.emplace_back( pt );
m_addButton->SetBitmap( KiBitmap( small_plus_xpm ) );
m_deleteButton->SetBitmap( KiBitmap( trash_xpm ) );
m_warningIcon->SetBitmap( KiBitmap( dialog_warning_xpm ) );
@ -265,10 +258,10 @@ bool DIALOG_PAD_PRIMITIVE_POLY_PROPS::TransferDataToWindow()
if( m_shape == NULL )
return false;
m_thickness.SetValue( m_currshape.m_Thickness );
m_thickness.SetValue( m_shape->GetWidth() );
// Populates the list of corners
int extra_rows = m_currshape.m_Poly.size() - m_gridCornersList->GetNumberRows();
int extra_rows = m_currPoints.size() - m_gridCornersList->GetNumberRows();
if( extra_rows > 0 )
{
@ -282,16 +275,16 @@ bool DIALOG_PAD_PRIMITIVE_POLY_PROPS::TransferDataToWindow()
// enter others corner coordinates
wxString msg;
for( unsigned row = 0; row < m_currshape.m_Poly.size(); ++row )
for( unsigned row = 0; row < m_currPoints.size(); ++row )
{
// Row label is "Corner x"
msg.Printf( "Corner %d", row+1 );
m_gridCornersList->SetRowLabelValue( row, msg );
msg = StringFromValue( GetUserUnits(), m_currshape.m_Poly[row].x, true, true );
msg = StringFromValue( GetUserUnits(), m_currPoints[row].x, true, true );
m_gridCornersList->SetCellValue( row, 0, msg );
msg = StringFromValue( GetUserUnits(), m_currshape.m_Poly[row].y, true, true );
msg = StringFromValue( GetUserUnits(), m_currPoints[row].y, true, true );
m_gridCornersList->SetCellValue( row, 1, msg );
}
@ -303,9 +296,8 @@ bool DIALOG_PAD_PRIMITIVE_POLY_PROPS::TransferDataFromWindow()
if( !Validate() )
return false;
m_currshape.m_Thickness = m_thickness.GetValue();
*m_shape = m_currshape;
m_shape->SetPolyPoints( m_currPoints );
m_shape->SetWidth( m_thickness.GetValue() );
return true;
}
@ -324,7 +316,7 @@ bool DIALOG_PAD_PRIMITIVE_POLY_PROPS::doValidate( bool aRemoveRedundantCorners )
if( !m_gridCornersList->CommitPendingChanges() )
return false;
if( m_currshape.m_Poly.size() < 3 )
if( m_currPoints.size() < 3 )
{
m_warningText->SetLabel( _("Polygon must have at least 3 corners" ) );
m_warningText->Show( true );
@ -334,13 +326,7 @@ bool DIALOG_PAD_PRIMITIVE_POLY_PROPS::doValidate( bool aRemoveRedundantCorners )
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 );
SHAPE_LINE_CHAIN polyline( m_currPoints, true );
// Remove redundant corners:
polyline.Simplify();
@ -362,12 +348,12 @@ bool DIALOG_PAD_PRIMITIVE_POLY_PROPS::doValidate( bool aRemoveRedundantCorners )
if( aRemoveRedundantCorners )
{
if( polyline.PointCount() != (int)m_currshape.m_Poly.size() )
if( polyline.PointCount() != (int) m_currPoints.size() )
{ // Happens after simplification
m_currshape.m_Poly.clear();
m_currPoints.clear();
for( int ii = 0; ii < polyline.PointCount(); ++ii )
m_currshape.m_Poly.emplace_back( polyline.CPoint( ii ).x, polyline.CPoint( ii ).y );
for( const VECTOR2I& pt : polyline.CPoints() )
m_currPoints.emplace_back( pt );
m_warningIcon->Show( true );
m_warningText->Show( true );
@ -401,10 +387,10 @@ void DIALOG_PAD_PRIMITIVE_POLY_PROPS::OnButtonAdd( wxCommandEvent& event )
return;
}
if( m_currshape.m_Poly.size() == 0 || row >= (int) m_currshape.m_Poly.size() )
m_currshape.m_Poly.emplace_back( 0, 0 );
if( m_currPoints.size() == 0 || row >= (int) m_currPoints.size() )
m_currPoints.emplace_back( 0, 0 );
else
m_currshape.m_Poly.insert( m_currshape.m_Poly.begin() + row, wxPoint( 0, 0 ) );
m_currPoints.insert( m_currPoints.begin() + row, wxPoint( 0, 0 ) );
Validate();
TransferDataToWindow();
@ -439,7 +425,7 @@ void DIALOG_PAD_PRIMITIVE_POLY_PROPS::OnButtonDelete( wxCommandEvent& event )
std::sort( selections.begin(), selections.end() );
for( int ii = selections.size()-1; ii >= 0 ; --ii )
m_currshape.m_Poly.erase( m_currshape.m_Poly.begin() + selections[ii] );
m_currPoints.erase( m_currPoints.begin() + selections[ii] );
Validate();
TransferDataToWindow();
@ -460,16 +446,16 @@ void DIALOG_PAD_PRIMITIVE_POLY_PROPS::onPaintPolyPanel( wxPaintEvent& event )
// Calculate a suitable scale to fit the available draw area
int minsize( Millimeter2iu( 0.5 ) );
for( unsigned ii = 0; ii < m_currshape.m_Poly.size(); ++ii )
for( unsigned ii = 0; ii < m_currPoints.size(); ++ii )
{
minsize = std::max( minsize, std::abs( m_currshape.m_Poly[ii].x ) );
minsize = std::max( minsize, std::abs( m_currshape.m_Poly[ii].y ) );
minsize = std::max( minsize, std::abs( m_currPoints[ii].x ) );
minsize = std::max( minsize, std::abs( m_currPoints[ii].y ) );
}
// The draw origin is the center of the window.
// Therefore the window size is twice the minsize just calculated
minsize *= 2;
minsize += m_currshape.m_Thickness;
minsize += m_thickness.GetValue();
// Give a margin
double scale = std::min( double( dc_size.x ) / minsize, double( dc_size.y ) / minsize ) * 0.9;
@ -487,7 +473,7 @@ void DIALOG_PAD_PRIMITIVE_POLY_PROPS::onPaintPolyPanel( wxPaintEvent& event )
EDA_COLOR_T normalcolor = WHITE;
EDA_COLOR_T selectcolor = RED;
for( unsigned ii = 0; ii < m_currshape.m_Poly.size(); ++ii )
for( unsigned ii = 0; ii < m_currPoints.size(); ++ii )
{
EDA_COLOR_T color = normalcolor;
@ -498,10 +484,10 @@ void DIALOG_PAD_PRIMITIVE_POLY_PROPS::onPaintPolyPanel( wxPaintEvent& event )
unsigned jj = ii + 1;
if( jj >= m_currshape.m_Poly.size() )
if( jj >= m_currPoints.size() )
jj = 0;
GRLine( NULL, &dc, m_currshape.m_Poly[ii] * scale, m_currshape.m_Poly[jj] * scale, m_currshape.m_Thickness * scale, color );
GRLine( NULL, &dc, m_currPoints[ii] * scale, m_currPoints[jj] * scale, m_thickness.GetValue() * scale, color );
}
event.Skip();
@ -528,11 +514,9 @@ void DIALOG_PAD_PRIMITIVE_POLY_PROPS::onCellChanging( wxGridEvent& event )
return;
if( col == 0 ) // Set the X value
m_currshape.m_Poly[row].x = ValueFromString( GetUserUnits(), msg, true );
m_currPoints[row].x = ValueFromString( GetUserUnits(), msg, true );
else // Set the Y value
m_currshape.m_Poly[row].y = ValueFromString( GetUserUnits(), msg, true );
m_currshape.m_Thickness = m_thickness.GetValue();
m_currPoints[row].y = ValueFromString( GetUserUnits(), msg, true );
Validate();
@ -544,7 +528,7 @@ void DIALOG_PAD_PRIMITIVE_POLY_PROPS::onCellChanging( wxGridEvent& event )
// (move, rotate around origin, scaling factor, duplication).
DIALOG_PAD_PRIMITIVES_TRANSFORM::DIALOG_PAD_PRIMITIVES_TRANSFORM( wxWindow* aParent,
PCB_BASE_FRAME* aFrame,
std::vector<PAD_CS_PRIMITIVE*>& aList,
std::vector<std::shared_ptr<DRAWSEGMENT>>& aList,
bool aShowDuplicate ) :
DIALOG_PAD_PRIMITIVES_TRANSFORM_BASE( aParent ),
m_list( aList ),
@ -575,7 +559,8 @@ inline void geom_transf( wxPoint& aCoord, wxPoint& aMove, double aScale, double
}
void DIALOG_PAD_PRIMITIVES_TRANSFORM::Transform( std::vector<PAD_CS_PRIMITIVE>* aList, int aDuplicateCount )
void DIALOG_PAD_PRIMITIVES_TRANSFORM::Transform( std::vector<std::shared_ptr<DRAWSEGMENT>>* aList,
int aDuplicateCount )
{
wxPoint move_vect( m_vectorX.GetValue(), m_vectorY.GetValue() );
double rotation = m_rotation.GetValue();
@ -599,48 +584,21 @@ void DIALOG_PAD_PRIMITIVES_TRANSFORM::Transform( std::vector<PAD_CS_PRIMITIVE>*
do {
for( unsigned idx = 0; idx < m_list.size(); ++idx )
{
PAD_CS_PRIMITIVE* shape;
std::shared_ptr<DRAWSEGMENT> 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();
aList->emplace_back( std::make_shared<DRAWSEGMENT>( *m_list[idx] ) );
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, currMoveVect, scale, curr_rotation );
geom_transf( shape->m_End, currMoveVect, scale, curr_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_CURVE: // Bezier with rounded ends
geom_transf( shape->m_Ctrl1, currMoveVect, scale, curr_rotation );
geom_transf( shape->m_Ctrl2, currMoveVect, scale, curr_rotation );
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], currMoveVect, scale, curr_rotation );
break;
default:
break;
}
shape->SetWidth( KiROUND( shape->GetWidth() * scale ) );
shape->Move( currMoveVect );
shape->Scale( scale );
shape->Rotate( wxPoint( 0, 0 ), curr_rotation );
}
// Prepare new transform on duplication:

View File

@ -700,49 +700,48 @@ void DIALOG_PAD_PROPERTIES::displayPrimitivesList()
for( unsigned ii = 0; ii < m_primitives.size(); ++ii )
{
const PAD_CS_PRIMITIVE& primitive = m_primitives[ii];
const std::shared_ptr<DRAWSEGMENT>& primitive = m_primitives[ii];
for( unsigned jj = 0; jj < 5; ++jj )
bs_info[jj].Empty();
bs_info[4] = wxString::Format( _( "width %s" ),
MessageTextFromValue( m_units, primitive.m_Thickness, true ) );
bs_info[4] = _( "width " ) + MessageTextFromValue( m_units, primitive->GetWidth(), true );
switch( primitive.m_Shape )
switch( primitive->GetShape() )
{
case S_SEGMENT: // usual segment : line with rounded ends
bs_info[0] = _( "Segment" );
bs_info[1] = _( "from " ) + formatCoord( m_units, primitive.m_Start );
bs_info[2] = _( "to " ) + formatCoord( m_units, primitive.m_End );
bs_info[1] = _( "from " ) + formatCoord( m_units, primitive->GetStart() );
bs_info[2] = _( "to " ) + formatCoord( m_units, primitive->GetEnd() );
break;
case S_CURVE: // Bezier segment
bs_info[0] = _( "Bezier" );
bs_info[1] = _( "from " ) + formatCoord( m_units, primitive.m_Start );
bs_info[2] = _( "to " ) + formatCoord( m_units, primitive.m_End );
bs_info[1] = _( "from " ) + formatCoord( m_units, primitive->GetStart() );
bs_info[2] = _( "to " ) + formatCoord( m_units, primitive->GetEnd() );
break;
case S_ARC: // Arc with rounded ends
bs_info[0] = _( "Arc" );
bs_info[1] = _( "center " ) + formatCoord( m_units, primitive.m_Start );// Center
bs_info[2] = _( "start " ) + formatCoord( m_units, primitive.m_End ); // Start point
bs_info[3] = wxString::Format( _( "angle %s" ), FormatAngle( primitive.m_ArcAngle ) );
bs_info[1] = _( "center " ) + formatCoord( m_units, primitive->GetCenter() );
bs_info[2] = _( "start " ) + formatCoord( m_units, primitive->GetArcStart() );
bs_info[3] = _( "angle " ) + FormatAngle( primitive->GetAngle() );
break;
case S_CIRCLE: // ring or circle
if( primitive.m_Thickness )
if( primitive->GetWidth() )
bs_info[0] = _( "ring" );
else
bs_info[0] = _( "circle" );
bs_info[1] = formatCoord( m_units, primitive.m_Start );
bs_info[2] = wxString::Format( _( "radius %s" ),
MessageTextFromValue( m_units, primitive.m_Radius, true ) );
bs_info[1] = formatCoord( m_units, primitive->GetStart() );
bs_info[2] = _( "radius " ) + MessageTextFromValue( m_units, primitive->GetRadius(), true );
break;
case S_POLYGON: // polygon
bs_info[0] = "Polygon";
bs_info[1] = wxString::Format( _( "corners count %d" ), (int) primitive.m_Poly.size() );
bs_info[1] = wxString::Format( _( "corners count %d" ),
(int) primitive->GetPolyShape().Outline( 0 ).PointCount() );
break;
default:
@ -1249,48 +1248,13 @@ void DIALOG_PAD_PROPERTIES::redraw()
while( select >= 0 )
{
PAD_CS_PRIMITIVE& primitive = m_primitives[select];
DRAWSEGMENT* dummySegment = new DRAWSEGMENT;
DRAWSEGMENT* dummySegment = (DRAWSEGMENT*) m_primitives[select]->Clone();
dummySegment->SetLayer( SELECTED_ITEMS_LAYER );
primitive.ExportTo( dummySegment );
dummySegment->Rotate( wxPoint( 0, 0), m_dummyPad->GetOrientation() );
dummySegment->Move( m_dummyPad->GetPosition() );
// Update selected primitive (highlight selected)
switch( primitive.m_Shape )
{
case S_SEGMENT:
case S_ARC:
case S_CURVE:
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:
break;
default:
delete dummySegment;
dummySegment = nullptr;
break;
}
if( dummySegment )
{
view->Add( dummySegment );
m_highlight.push_back( dummySegment );
}
view->Add( dummySegment );
m_highlight.push_back( dummySegment );
select = m_listCtrlPrimitives->GetNextSelected( select );
}
@ -1825,11 +1789,11 @@ void DIALOG_PAD_PROPERTIES::editPrimitive()
return;
}
PAD_CS_PRIMITIVE& shape = m_primitives[select];
std::shared_ptr<DRAWSEGMENT>& shape = m_primitives[select];
if( shape.m_Shape == S_POLYGON )
if( shape->GetShape() == S_POLYGON )
{
DIALOG_PAD_PRIMITIVE_POLY_PROPS dlg( this, m_parent, &shape );
DIALOG_PAD_PRIMITIVE_POLY_PROPS dlg( this, m_parent, shape.get() );
if( dlg.ShowModal() != wxID_OK )
return;
@ -1839,7 +1803,7 @@ void DIALOG_PAD_PROPERTIES::editPrimitive()
else
{
DIALOG_PAD_PRIMITIVES_PROPERTIES dlg( this, m_parent, &shape );
DIALOG_PAD_PRIMITIVES_PROPERTIES dlg( this, m_parent, shape.get() );
if( dlg.ShowModal() != wxID_OK )
return;
@ -1922,25 +1886,26 @@ void DIALOG_PAD_PROPERTIES::onAddPrimitive( wxCommandEvent& event )
STROKE_T listtype[] = { S_SEGMENT, S_ARC, S_CURVE, S_CIRCLE, S_POLYGON };
PAD_CS_PRIMITIVE primitive( listtype[type] );
primitive.m_Thickness = m_board->GetDesignSettings().GetLineThickness( F_Cu );
DRAWSEGMENT* primitive = new DRAWSEGMENT();
primitive->SetShape( listtype[type] );
primitive->SetWidth( m_board->GetDesignSettings().GetLineThickness( F_Cu ) );
if( listtype[type] == S_POLYGON )
{
DIALOG_PAD_PRIMITIVE_POLY_PROPS dlg( this, m_parent, &primitive );
DIALOG_PAD_PRIMITIVE_POLY_PROPS dlg( this, m_parent, primitive );
if( dlg.ShowModal() != wxID_OK )
return;
}
else
{
DIALOG_PAD_PRIMITIVES_PROPERTIES dlg( this, m_parent, &primitive );
DIALOG_PAD_PRIMITIVES_PROPERTIES dlg( this, m_parent, primitive );
if( dlg.ShowModal() != wxID_OK )
return;
}
m_primitives.push_back( primitive );
m_primitives.emplace_back( primitive );
displayPrimitivesList();
@ -1963,18 +1928,17 @@ void DIALOG_PAD_PROPERTIES::onGeometryTransform( wxCommandEvent& event )
}
// Multiple selections are allowed. Build selected shapes list
std::vector<PAD_CS_PRIMITIVE*> shapeList;
shapeList.push_back( &m_primitives[select] );
std::vector<std::shared_ptr<DRAWSEGMENT>> shapeList;
shapeList.emplace_back( m_primitives[select] );
while( ( select = m_listCtrlPrimitives->GetNextSelected( select ) ) >= 0 )
shapeList.push_back( &m_primitives[select] );
shapeList.emplace_back( m_primitives[select] );
DIALOG_PAD_PRIMITIVES_TRANSFORM dlg( this, m_parent, shapeList, false );
if( dlg.ShowModal() != wxID_OK )
return;
// Transfert new settings:
dlg.Transform();
displayPrimitivesList();
@ -1998,11 +1962,11 @@ void DIALOG_PAD_PROPERTIES::onDuplicatePrimitive( wxCommandEvent& event )
}
// Multiple selections are allowed. Build selected shapes list
std::vector<PAD_CS_PRIMITIVE*> shapeList;
shapeList.push_back( &m_primitives[select] );
std::vector<std::shared_ptr<DRAWSEGMENT>> shapeList;
shapeList.emplace_back( m_primitives[select] );
while( ( select = m_listCtrlPrimitives->GetNextSelected( select ) ) >= 0 )
shapeList.push_back( &m_primitives[select] );
shapeList.emplace_back( m_primitives[select] );
DIALOG_PAD_PRIMITIVES_TRANSFORM dlg( this, m_parent, shapeList, true );
@ -2012,7 +1976,7 @@ void DIALOG_PAD_PROPERTIES::onDuplicatePrimitive( wxCommandEvent& event )
// Transfer new settings
// save duplicates to a separate vector to avoid m_primitives reallocation,
// as shapeList contains pointers to its elements
std::vector<PAD_CS_PRIMITIVE> duplicates;
std::vector<std::shared_ptr<DRAWSEGMENT>> duplicates;
dlg.Transform( &duplicates, dlg.GetDuplicateCount() );
std::move( duplicates.begin(), duplicates.end(), std::back_inserter( m_primitives ) );

View File

@ -62,9 +62,9 @@ private:
bool m_canUpdate;
bool m_canEditNetName; // true only if the caller is the board editor
std::vector<PAD_CS_PRIMITIVE> m_primitives; // the list of custom shape primitives (basic
// shapes), in local coords, orient 0
// must define a single copper area
std::vector<std::shared_ptr<DRAWSEGMENT>> m_primitives; // the custom shape primitives in
// local coords, orient 0
// must define a single copper area
COLOR4D m_selectedColor; // color used to draw selected primitives when
// editing a custom pad shape
@ -167,7 +167,7 @@ class DIALOG_PAD_PRIMITIVES_PROPERTIES: public DIALOG_PAD_PRIMITIVES_PROPERTIES_
{
public:
DIALOG_PAD_PRIMITIVES_PROPERTIES( wxWindow* aParent, PCB_BASE_FRAME* aFrame,
PAD_CS_PRIMITIVE * aShape );
DRAWSEGMENT* aShape );
/**
* Function TransferDataFromWindow
@ -183,18 +183,18 @@ private:
bool TransferDataToWindow() override;
// The basic shape currently edited
PAD_CS_PRIMITIVE * m_shape;
DRAWSEGMENT* m_shape;
UNIT_BINDER m_startX;
UNIT_BINDER m_startY;
UNIT_BINDER m_ctrl1X;
UNIT_BINDER m_ctrl1Y;
UNIT_BINDER m_ctrl2X;
UNIT_BINDER m_ctrl2Y;
UNIT_BINDER m_endX;
UNIT_BINDER m_endY;
UNIT_BINDER m_radius;
UNIT_BINDER m_thickness;
UNIT_BINDER m_startX;
UNIT_BINDER m_startY;
UNIT_BINDER m_ctrl1X;
UNIT_BINDER m_ctrl1Y;
UNIT_BINDER m_ctrl2X;
UNIT_BINDER m_ctrl2Y;
UNIT_BINDER m_endX;
UNIT_BINDER m_endY;
UNIT_BINDER m_radius;
UNIT_BINDER m_thickness;
};
@ -204,16 +204,16 @@ private:
class DIALOG_PAD_PRIMITIVE_POLY_PROPS: public DIALOG_PAD_PRIMITIVE_POLY_PROPS_BASE
{
// The basic shape currently edited
PAD_CS_PRIMITIVE * m_shape;
DRAWSEGMENT* m_shape;
// The working copy of the basic shape currently edited
PAD_CS_PRIMITIVE m_currshape;
std::vector<wxPoint> m_currPoints;
UNIT_BINDER m_thickness;
UNIT_BINDER m_thickness;
public:
DIALOG_PAD_PRIMITIVE_POLY_PROPS( wxWindow* aParent, PCB_BASE_FRAME* aFrame,
PAD_CS_PRIMITIVE * aShape );
DRAWSEGMENT* aShape );
~DIALOG_PAD_PRIMITIVE_POLY_PROPS();
/**
@ -235,7 +235,6 @@ private:
bool Validate() override;
// Events handlers:
void OnValidateButton( wxCommandEvent& event );
void OnButtonAdd( wxCommandEvent& event ) override;
void OnButtonDelete( wxCommandEvent& event ) override;
void onPaintPolyPanel( wxPaintEvent& event ) override;
@ -263,7 +262,8 @@ class DIALOG_PAD_PRIMITIVES_TRANSFORM : public DIALOG_PAD_PRIMITIVES_TRANSFORM_B
{
public:
DIALOG_PAD_PRIMITIVES_TRANSFORM( wxWindow* aParent, PCB_BASE_FRAME* aFrame,
std::vector<PAD_CS_PRIMITIVE*>& aList, bool aShowDuplicate );
std::vector<std::shared_ptr<DRAWSEGMENT>>& aList,
bool aShowDuplicate );
/**
* Apply geometric transform (rotation, move, scale) defined in dialog
@ -272,7 +272,8 @@ public:
* 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 );
void Transform( std::vector<std::shared_ptr<DRAWSEGMENT>>* aList = NULL,
int aDuplicateCount = 0 );
/**
* @return the number of duplicate, chosen by user
@ -280,7 +281,7 @@ public:
int GetDuplicateCount() { return m_spinCtrlDuplicateCount->GetValue(); }
private:
std::vector<PAD_CS_PRIMITIVE*>& m_list;
std::vector<std::shared_ptr<DRAWSEGMENT>>& m_list;
UNIT_BINDER m_vectorX;
UNIT_BINDER m_vectorY;

View File

@ -1523,72 +1523,68 @@ void PCB_IO::format( D_PAD* aPad, int aNestLevel ) const
int nested_level = aNestLevel+2;
// Output all basic shapes
for( unsigned icnt = 0; icnt < aPad->GetPrimitives().size(); ++icnt )
for( const std::shared_ptr<DRAWSEGMENT> primitive : aPad->GetPrimitives() )
{
m_out->Print( 0, "\n");
const PAD_CS_PRIMITIVE& primitive = aPad->GetPrimitives()[icnt];
switch( primitive.m_Shape )
switch( primitive->GetShape() )
{
case S_SEGMENT: // usual segment : line with rounded ends
m_out->Print( nested_level, "(gr_line (start %s) (end %s) (width %s))",
FormatInternalUnits( primitive.m_Start ).c_str(),
FormatInternalUnits( primitive.m_End ).c_str(),
FormatInternalUnits( primitive.m_Thickness ).c_str() );
FormatInternalUnits( primitive->GetStart() ).c_str(),
FormatInternalUnits( primitive->GetEnd() ).c_str(),
FormatInternalUnits( primitive->GetWidth() ).c_str() );
break;
case S_RECT:
m_out->Print( nested_level, "(gr_rect (start %s) (end %s) (width %s))",
FormatInternalUnits( primitive.m_Start ).c_str(),
FormatInternalUnits( primitive.m_End ).c_str(),
FormatInternalUnits( primitive.m_Thickness ).c_str() );
FormatInternalUnits( primitive->GetStart() ).c_str(),
FormatInternalUnits( primitive->GetEnd() ).c_str(),
FormatInternalUnits( primitive->GetWidth() ).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))",
FormatInternalUnits( primitive.m_Start ).c_str(),
FormatInternalUnits( primitive.m_End ).c_str(),
FormatAngle( primitive.m_ArcAngle ).c_str(),
FormatInternalUnits( primitive.m_Thickness ).c_str() );
FormatInternalUnits( primitive->GetStart() ).c_str(),
FormatInternalUnits( primitive->GetEnd() ).c_str(),
FormatAngle( primitive->GetAngle() ).c_str(),
FormatInternalUnits( primitive->GetWidth() ).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))",
FormatInternalUnits( primitive.m_Start ).c_str(),
FormatInternalUnits( primitive.m_Start.x + primitive.m_Radius ).c_str(),
FormatInternalUnits( primitive.m_Start.y ).c_str(),
FormatInternalUnits( primitive.m_Thickness ).c_str() );
m_out->Print( nested_level, "(gr_circle (center %s) (end %s) (width %s))",
FormatInternalUnits( primitive->GetStart() ).c_str(),
FormatInternalUnits( primitive->GetEnd() ).c_str(),
FormatInternalUnits( primitive->GetWidth() ).c_str() );
break;
case S_CURVE: // Bezier Curve
m_out->Print( aNestLevel, "(gr_curve (pts (xy %s) (xy %s) (xy %s) (xy %s)) (width %s))",
FormatInternalUnits( primitive.m_Start ).c_str(),
FormatInternalUnits( primitive.m_Ctrl1 ).c_str(),
FormatInternalUnits( primitive.m_Ctrl2 ).c_str(),
FormatInternalUnits( primitive.m_End ).c_str(),
FormatInternalUnits( primitive.m_Thickness ).c_str() );
FormatInternalUnits( primitive->GetStart() ).c_str(),
FormatInternalUnits( primitive->GetBezControl1() ).c_str(),
FormatInternalUnits( primitive->GetBezControl2() ).c_str(),
FormatInternalUnits( primitive->GetEnd() ).c_str(),
FormatInternalUnits( primitive->GetWidth() ).c_str() );
break;
case S_POLYGON: // polygon
if( primitive.m_Poly.size() < 2 )
if( primitive->GetPolyShape().COutline( 0 ).CPoints().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++ )
for( const VECTOR2I &pt : primitive->GetPolyShape().COutline( 0 ).CPoints() )
{
if( newLine == 0 )
m_out->Print( nested_level+1, " (xy %s)",
FormatInternalUnits( wxPoint( poly[ii].x, poly[ii].y ) ).c_str() );
FormatInternalUnits( (wxPoint) pt ).c_str() );
else
m_out->Print( 0, " (xy %s)",
FormatInternalUnits( wxPoint( poly[ii].x, poly[ii].y ) ).c_str() );
FormatInternalUnits( (wxPoint) pt ).c_str() );
if( ++newLine > 4 )
{
@ -1597,7 +1593,7 @@ void PCB_IO::format( D_PAD* aPad, int aNestLevel ) const
}
}
m_out->Print( 0, ") (width %s))", FormatInternalUnits( primitive.m_Thickness ).c_str() );
m_out->Print( 0, ") (width %s))", FormatInternalUnits( primitive->GetWidth() ).c_str() );
}
break;

View File

@ -44,102 +44,6 @@
#include <geometry/shape_rect.h>
void PAD_CS_PRIMITIVE::ExportTo( DRAWSEGMENT* aTarget )
{
aTarget->SetShape( m_Shape );
aTarget->SetWidth( m_Thickness );
aTarget->SetStart( m_Start );
aTarget->SetEnd( m_End );
aTarget->SetBezControl1( m_Ctrl1 );
aTarget->SetBezControl2( m_Ctrl2 );
// 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 );
}
void PAD_CS_PRIMITIVE::ExportTo( EDGE_MODULE* aTarget )
{
ExportTo( static_cast<DRAWSEGMENT*>( aTarget ) );
// Initialize coordinates specific to the EDGE_MODULE (m_Start0 and m_End0)
aTarget->SetLocalCoord();
}
void PAD_CS_PRIMITIVE::Move( wxPoint aMoveVector )
{
m_Start += aMoveVector;
m_End += aMoveVector;
m_Ctrl1 += aMoveVector;
m_Ctrl2 += aMoveVector;
for( auto& corner : m_Poly )
corner += aMoveVector;
}
void PAD_CS_PRIMITIVE::Rotate( const wxPoint& aRotCentre, double aAngle )
{
switch( m_Shape )
{
case S_ARC:
case S_SEGMENT:
case S_CIRCLE:
// these can all be done by just rotating the start and end points
RotatePoint( &m_Start, aRotCentre, aAngle );
RotatePoint( &m_End, aRotCentre, aAngle );
break;
case S_RECT:
if( KiROUND( aAngle ) % 900 == 0 )
{
RotatePoint( &m_Start, aRotCentre, aAngle );
RotatePoint( &m_End, aRotCentre, aAngle );
break;
}
// Convert non-cartesian-rotated rect to a diamond
m_Shape = S_POLYGON;
m_Poly.clear();
m_Poly.emplace_back( m_Start );
m_Poly.emplace_back( m_End.x, m_Start.y );
m_Poly.emplace_back( m_End );
m_Poly.emplace_back( m_Start.x, m_End.y );
KI_FALLTHROUGH;
case S_POLYGON:
for( auto& pt : m_Poly )
RotatePoint( &pt, aRotCentre, aAngle );
break;
case S_CURVE:
RotatePoint( &m_Start, aRotCentre, aAngle );
RotatePoint( &m_End, aRotCentre, aAngle );
RotatePoint( &m_Ctrl1, aRotCentre, aAngle );
RotatePoint( &m_Ctrl2, aRotCentre, aAngle );
break;
default:
// un-handled edge transform
wxASSERT_MSG( false, wxT( "PAD_CS_PRIMITIVE::Rotate not implemented for "
+ BOARD_ITEM::ShowShape( m_Shape ) ) );
break;
}
}
/*
* Has meaning only for free shape pads.
* add a free shape to the shape list.
@ -164,21 +68,22 @@ void D_PAD::AddPrimitivePoly( const SHAPE_POLY_SET& aPoly, int aThickness )
void D_PAD::AddPrimitivePoly( const 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 );
DRAWSEGMENT* item = new DRAWSEGMENT();
item->SetShape( S_POLYGON );
item->SetPolyPoints( aPoly );
item->SetWidth( aThickness );
m_editPrimitives.emplace_back( item );
m_shapesDirty = true;
}
void D_PAD::AddPrimitiveSegment( const wxPoint& aStart, const 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 );
DRAWSEGMENT* item = new DRAWSEGMENT();
item->SetStart( aStart );
item->SetEnd( aEnd );
item->SetWidth( aThickness );
m_editPrimitives.emplace_back( item );
m_shapesDirty = true;
}
@ -186,12 +91,13 @@ void D_PAD::AddPrimitiveSegment( const wxPoint& aStart, const wxPoint& aEnd, int
void D_PAD::AddPrimitiveArc( const wxPoint& aCenter, const 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 );
DRAWSEGMENT* item = new DRAWSEGMENT();
item->SetShape( S_ARC );
item->SetCenter( aCenter );
item->SetArcStart( aStart );
item->SetAngle( aArcAngle );
item->SetWidth( aThickness );
m_editPrimitives.emplace_back( item );
m_shapesDirty = true;
}
@ -199,56 +105,59 @@ void D_PAD::AddPrimitiveArc( const wxPoint& aCenter, const wxPoint& aStart, int
void D_PAD::AddPrimitiveCurve( const wxPoint& aStart, const wxPoint& aEnd, const wxPoint& aCtrl1,
const wxPoint& aCtrl2, int aThickness )
{
PAD_CS_PRIMITIVE shape( S_CURVE );
shape.m_Start = aStart;
shape.m_End = aEnd;
shape.m_Ctrl1 = aCtrl1;
shape.m_Ctrl2 = aCtrl2;
shape.m_Thickness = aThickness;
m_basicShapes.push_back( shape );
DRAWSEGMENT* item = new DRAWSEGMENT();
item->SetShape( S_CURVE );
item->SetStart( aStart );
item->SetEnd( aEnd );
item->SetBezControl1( aCtrl1 );
item->SetBezControl2( aCtrl2 );
item->SetWidth( aThickness );
m_editPrimitives.emplace_back( item );
m_shapesDirty = true;
}
void D_PAD::AddPrimitiveCircle( const 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 );
DRAWSEGMENT* item = new DRAWSEGMENT();
item->SetShape( S_CIRCLE );
item->SetStart( aCenter );
item->SetEnd( wxPoint( aCenter.x + aRadius, aCenter.y ) );
item->SetWidth( aThickness );
m_editPrimitives.emplace_back( item );
m_shapesDirty = true;
}
void D_PAD::AddPrimitiveRect( const wxPoint& aStart, const wxPoint& aEnd, int aThickness )
{
PAD_CS_PRIMITIVE shape( S_RECT );
shape.m_Start = aStart;
shape.m_End = aEnd;
shape.m_Thickness = aThickness;
m_basicShapes.push_back( shape );
DRAWSEGMENT* item = new DRAWSEGMENT();
item->SetShape( S_RECT );
item->SetStart( aStart );
item->SetEnd( aEnd );
item->SetWidth( aThickness );
m_editPrimitives.emplace_back( item );
m_shapesDirty = true;
}
void D_PAD::SetPrimitives( const std::vector<PAD_CS_PRIMITIVE>& aPrimitivesList )
void D_PAD::SetPrimitives( const std::vector<std::shared_ptr<DRAWSEGMENT>>& aPrimitivesList )
{
// clear old list
m_basicShapes.clear();
m_editPrimitives.clear();
// Import to the basic shape list
if( aPrimitivesList.size() )
m_basicShapes = aPrimitivesList;
m_editPrimitives = aPrimitivesList;
m_shapesDirty = true;
}
void D_PAD::AddPrimitives( const std::vector<PAD_CS_PRIMITIVE>& aPrimitivesList )
void D_PAD::AddPrimitives( const std::vector<std::shared_ptr<DRAWSEGMENT>>& aPrimitivesList )
{
for( const auto& prim : aPrimitivesList )
m_basicShapes.push_back( prim );
for( const std::shared_ptr<DRAWSEGMENT>& prim : aPrimitivesList )
m_editPrimitives.push_back( prim );
m_shapesDirty = true;
}
@ -257,56 +166,62 @@ void D_PAD::AddPrimitives( const std::vector<PAD_CS_PRIMITIVE>& aPrimitivesList
// clear the basic shapes list and associated data
void D_PAD::DeletePrimitivesList()
{
m_basicShapes.clear();
m_editPrimitives.clear();
m_shapesDirty = true;
}
void D_PAD::addCustomPadPrimitivesToPolygon( SHAPE_POLY_SET* aMergedPolygon, int aError ) const
void D_PAD::addPadPrimitivesToPolygon( SHAPE_POLY_SET* aMergedPolygon, int aError ) const
{
SHAPE_POLY_SET polyset;
for( const PAD_CS_PRIMITIVE& bshape : m_basicShapes )
for( const std::shared_ptr<DRAWSEGMENT>& primitive : m_editPrimitives )
{
switch( bshape.m_Shape )
int lineWidth = primitive->GetWidth();
switch( primitive->GetShape() )
{
case S_CURVE:
{
std::vector<wxPoint> ctrlPoints = { bshape.m_Start, bshape.m_Ctrl1, bshape.m_Ctrl2,
bshape.m_End };
std::vector<wxPoint> ctrlPoints = { primitive->GetStart(), primitive->GetBezControl1(),
primitive->GetBezControl2(), primitive->GetEnd() };
BEZIER_POLY converter( ctrlPoints );
std::vector< wxPoint> poly;
converter.GetPoly( poly, bshape.m_Thickness );
converter.GetPoly( poly, lineWidth );
for( unsigned ii = 1; ii < poly.size(); ii++ )
{
TransformSegmentToPolygon( polyset, poly[ ii - 1 ], poly[ ii ], aError,
bshape.m_Thickness );
TransformSegmentToPolygon( polyset, poly[ ii - 1 ], poly[ ii ], aError, lineWidth );
}
break;
}
case S_SEGMENT: // usual segment : line with rounded ends
{
TransformSegmentToPolygon( polyset, bshape.m_Start, bshape.m_End, aError,
bshape.m_Thickness );
TransformSegmentToPolygon( polyset, primitive->GetStart(), primitive->GetEnd(),
aError, lineWidth );
break;
}
case S_ARC: // Arc with rounded ends
{
TransformArcToPolygon( polyset, bshape.m_Start, bshape.m_End, bshape.m_ArcAngle,
aError, bshape.m_Thickness );
TransformArcToPolygon( polyset, primitive->GetStart(), primitive->GetEnd(),
primitive->GetAngle(), aError, lineWidth );
break;
}
case S_CIRCLE: // ring or circle
{
if( bshape.m_Thickness ) // ring
TransformRingToPolygon( polyset, bshape.m_Start, bshape.m_Radius, aError,
bshape.m_Thickness );
if( primitive->GetWidth() ) // ring
{
TransformRingToPolygon( polyset, primitive->GetStart(), primitive->GetRadius(),
aError, lineWidth );
}
else // Filled circle
TransformCircleToPolygon( polyset, bshape.m_Start, bshape.m_Radius, aError );
{
TransformCircleToPolygon( polyset, primitive->GetStart(), primitive->GetRadius(),
aError );
}
break;
}
@ -316,23 +231,23 @@ void D_PAD::addCustomPadPrimitivesToPolygon( SHAPE_POLY_SET* aMergedPolygon, int
SHAPE_POLY_SET poly;
poly.NewOutline();
if( bshape.m_Shape == S_RECT )
if( primitive->GetShape() == S_RECT )
{
poly.Append( bshape.m_Start );
poly.Append( bshape.m_End.x, bshape.m_Start.y );
poly.Append( bshape.m_End );
poly.Append( bshape.m_Start.x, bshape.m_End.y );
poly.Append( primitive->GetStart() );
poly.Append( primitive->GetEnd().x, primitive->GetStart().y );
poly.Append( primitive->GetEnd() );
poly.Append( primitive->GetStart().x, primitive->GetEnd().y );
}
else
{
for( const wxPoint& pt : bshape.m_Poly )
for( const VECTOR2I& pt : primitive->GetPolyShape().Outline( 0 ).CPoints() )
poly.Append( pt );
}
if( bshape.m_Thickness )
if( primitive->GetWidth() > 0 )
{
int numSegs = std::max( GetArcToSegmentCount( bshape.m_Thickness / 2, aError, 360.0 ), 6 );
poly.Inflate( bshape.m_Thickness / 2, numSegs );
int numSegs = std::max( GetArcToSegmentCount( lineWidth / 2, aError, 360.0 ), 6 );
poly.Inflate( lineWidth / 2, numSegs );
}
// Insert the polygon:
@ -343,8 +258,8 @@ void D_PAD::addCustomPadPrimitivesToPolygon( SHAPE_POLY_SET* aMergedPolygon, int
default:
// un-handled primitive
wxASSERT_MSG( false, "D_PAD::addCustomPadPrimitivesToPolygon not implemented for "
+ BOARD_ITEM::ShowShape( bshape.m_Shape ) );
wxASSERT_MSG( false, "D_PAD::addPadPrimitivesToPolygon not implemented for "
+ BOARD_ITEM::ShowShape( primitive->GetShape() ) );
break;
}
}
@ -386,14 +301,14 @@ void D_PAD::MergePrimitivesAsPolygon( SHAPE_POLY_SET* aMergedPolygon ) const
break;
}
addCustomPadPrimitivesToPolygon( aMergedPolygon, maxError );
addPadPrimitivesToPolygon( aMergedPolygon, maxError );
}
bool D_PAD::GetBestAnchorPosition( VECTOR2I& aPos )
{
SHAPE_POLY_SET poly;
addCustomPadPrimitivesToPolygon( &poly, ARC_LOW_DEF );
addPadPrimitivesToPolygon( &poly, ARC_LOW_DEF );
if( poly.OutlineCount() > 1 )
return false;

View File

@ -659,7 +659,6 @@ void PCB_PAINTER::draw( const VIA* aVia, int aLayer )
void PCB_PAINTER::draw( const D_PAD* aPad, int aLayer )
{
double m, n;
double orientation = aPad->GetOrientation();
// Draw description layer

View File

@ -1,7 +1,4 @@
%ignore std::vector<PAD_CS_PRIMITIVE>::resize;
%ignore std::vector<PAD_CS_PRIMITIVE>::vector(size_type);
%template(PAD_CS_PRIMITIVE_Vector) std::vector<PAD_CS_PRIMITIVE>;
%include pad_shapes.h
%include class_pad.h

View File

@ -396,11 +396,20 @@ int FOOTPRINT_EDITOR_TOOLS::ExplodePadToShapes( const TOOL_EVENT& aEvent )
wxPoint anchor = pad->GetPosition();
for( auto prim : pad->GetPrimitives() )
for( const std::shared_ptr<DRAWSEGMENT>& primitive : pad->GetPrimitives() )
{
auto ds = new EDGE_MODULE( board()->GetFirstModule() );
EDGE_MODULE* ds = new EDGE_MODULE( board()->GetFirstModule() );
ds->SetShape( primitive->GetShape() );
ds->SetWidth( primitive->GetWidth() );
ds->SetStart( primitive->GetStart() );
ds->SetEnd( primitive->GetEnd() );
ds->SetBezControl1( primitive->GetBezControl1() );
ds->SetBezControl2( primitive->GetBezControl2() );
ds->SetAngle( primitive->GetAngle() );
ds->SetPolyShape( primitive->GetPolyShape() );
ds->SetLocalCoord();
prim.ExportTo( ds ); // ExportTo exports to a DRAWSEGMENT
// Fix an arbitray draw layer for this EDGE_MODULE
ds->SetLayer( Dwgs_User ); //pad->GetLayer() );
ds->Move( anchor );
@ -435,11 +444,11 @@ int FOOTPRINT_EDITOR_TOOLS::CreatePadFromShapes( const TOOL_EVENT& aEvent )
bool multipleRefPadsFound = false;
bool illegalItemsFound = false;
std::vector<PAD_CS_PRIMITIVE> shapes;
std::vector<std::shared_ptr<DRAWSEGMENT>> shapes;
BOARD_COMMIT commit( m_frame );
for( auto item : selection )
for( EDA_ITEM* item : selection )
{
switch( item->Type() )
{
@ -454,19 +463,18 @@ int FOOTPRINT_EDITOR_TOOLS::CreatePadFromShapes( const TOOL_EVENT& aEvent )
case PCB_MODULE_EDGE_T:
{
auto em = static_cast<EDGE_MODULE*> ( item );
EDGE_MODULE* em = static_cast<EDGE_MODULE*>( item );
DRAWSEGMENT* ds = new DRAWSEGMENT;
PAD_CS_PRIMITIVE shape( em->GetShape() );
shape.m_Start = em->GetStart();
shape.m_End = em->GetEnd();
shape.m_Radius = em->GetRadius();
shape.m_Thickness = em->GetWidth();
shape.m_ArcAngle = em->GetAngle();
shape.m_Ctrl1 = em->GetBezControl1();
shape.m_Ctrl2 = em->GetBezControl2();
shape.m_Poly = em->BuildPolyPointsList();
shapes.push_back( shape );
ds->SetShape( em->GetShape() );
ds->SetWidth( em->GetWidth() );
ds->SetStart( em->GetStart() );
ds->SetEnd( em->GetEnd() );
ds->SetBezControl1( em->GetBezControl1() );
ds->SetBezControl2( em->GetBezControl2() );
ds->SetAngle( em->GetAngle() );
ds->SetPolyShape( em->GetPolyShape() );
shapes.emplace_back( ds );
break;
}
@ -534,12 +542,11 @@ int FOOTPRINT_EDITOR_TOOLS::CreatePadFromShapes( const TOOL_EVENT& aEvent )
int maxError = board()->GetDesignSettings().m_MaxError;
refPad->TransformShapeWithClearanceToPolygon( existingOutline, 0, maxError );
PAD_CS_PRIMITIVE shape( S_POLYGON );
DRAWSEGMENT* shape = new DRAWSEGMENT;
shape->SetShape( S_POLYGON );
shape->SetPolyShape( existingOutline );
for( auto ii = existingOutline.Iterate(); ii; ii++ )
shape.m_Poly.emplace_back( ii->x, ii->y );
shapes.push_back( shape );
shapes.emplace_back( shape );
deltaAngle = refPad->GetOrientation();
pad->SetOrientation( 0.0 );
@ -589,10 +596,10 @@ int FOOTPRINT_EDITOR_TOOLS::CreatePadFromShapes( const TOOL_EVENT& aEvent )
// relocate the shapes, they are relative to the anchor pad position
for( auto& shape : shapes )
for( std::shared_ptr<DRAWSEGMENT>& shape : shapes )
{
shape.Move( wxPoint( -anchor->x, -anchor->y ) );
shape.Rotate( wxPoint( 0, 0 ), -deltaAngle );
shape->Move( wxPoint( -anchor->x, -anchor->y ) );
shape->Rotate( wxPoint( 0, 0 ), -deltaAngle );
}
pad->SetPosition( wxPoint( anchor->x, anchor->y ) );
@ -610,13 +617,12 @@ int FOOTPRINT_EDITOR_TOOLS::CreatePadFromShapes( const TOOL_EVENT& aEvent )
return 0;
}
auto padPtr = pad.release();
D_PAD* padPtr = pad.release();
commit.Add( padPtr );
for ( auto item : selection )
{
for ( EDA_ITEM* item : selection )
commit.Remove( item );
}
m_toolMgr->RunAction( PCB_ACTIONS::selectionClear, true );
commit.Push(_("Create Pad from Selected Shapes") );