pcbnew: tools for converting between custom-shaped pads and graphical shapes
This commit is contained in:
parent
bcde2a77e2
commit
ac095b6724
|
@ -79,9 +79,9 @@ void DRAWSEGMENT::Rotate( const wxPoint& aRotCentre, double aAngle )
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case S_POLYGON:
|
case S_POLYGON:
|
||||||
for( unsigned ii = 0; ii < m_PolyPoints.size(); ii++ )
|
for( auto iter = m_Poly.Iterate(); iter; iter++ )
|
||||||
{
|
{
|
||||||
RotatePoint( &m_PolyPoints[ii], aRotCentre, aAngle);
|
RotatePoint( *iter, VECTOR2I(aRotCentre), aAngle);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -411,10 +411,12 @@ const EDA_RECT DRAWSEGMENT::GetBoundingBox() const
|
||||||
{
|
{
|
||||||
wxPoint p_end;
|
wxPoint p_end;
|
||||||
MODULE* module = GetParentModule();
|
MODULE* module = GetParentModule();
|
||||||
|
bool first = true;
|
||||||
|
|
||||||
for( unsigned ii = 0; ii < m_PolyPoints.size(); ii++ )
|
for( auto iter = m_Poly.CIterate(); iter; iter++ )
|
||||||
{
|
{
|
||||||
wxPoint pt = m_PolyPoints[ii];
|
wxPoint pt ( iter->x, iter->y );
|
||||||
|
|
||||||
|
|
||||||
if( module ) // Transform, if we belong to a module
|
if( module ) // Transform, if we belong to a module
|
||||||
{
|
{
|
||||||
|
@ -422,19 +424,27 @@ const EDA_RECT DRAWSEGMENT::GetBoundingBox() const
|
||||||
pt += module->GetPosition();
|
pt += module->GetPosition();
|
||||||
}
|
}
|
||||||
|
|
||||||
if( ii == 0 )
|
|
||||||
|
if( first )
|
||||||
|
{
|
||||||
p_end = pt;
|
p_end = pt;
|
||||||
|
bbox.SetX( pt.x );
|
||||||
|
bbox.SetY( pt.y );
|
||||||
|
first = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
|
||||||
bbox.SetX( std::min( bbox.GetX(), pt.x ) );
|
bbox.SetX( std::min( bbox.GetX(), pt.x ) );
|
||||||
bbox.SetY( std::min( bbox.GetY(), pt.y ) );
|
bbox.SetY( std::min( bbox.GetY(), pt.y ) );
|
||||||
p_end.x = std::max( p_end.x, pt.x );
|
|
||||||
p_end.y = std::max( p_end.y, pt.y );
|
p_end.x = std::max( p_end.x, pt.x );
|
||||||
|
p_end.y = std::max( p_end.y, pt.y );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bbox.SetEnd( p_end );
|
bbox.SetEnd( p_end );
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -508,6 +518,18 @@ bool DRAWSEGMENT::HitTest( const wxPoint& aPosition ) const
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case S_POLYGON: // not yet handled
|
case S_POLYGON: // not yet handled
|
||||||
|
{
|
||||||
|
#define MAX_DIST_IN_MM 0.25
|
||||||
|
int distmax = Millimeter2iu( 0.25 );
|
||||||
|
SHAPE_POLY_SET::VERTEX_INDEX dummy;
|
||||||
|
auto poly = m_Poly;
|
||||||
|
|
||||||
|
if( poly.CollideVertex( VECTOR2I( aPosition ), dummy, distmax ) )
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if( poly.CollideEdge( VECTOR2I( aPosition ), dummy, distmax ) )
|
||||||
|
return true;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -710,3 +732,26 @@ void DRAWSEGMENT::computeArcBBox( EDA_RECT& aBBox ) const
|
||||||
angle -= 900;
|
angle -= 900;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DRAWSEGMENT::SetPolyPoints( const std::vector<wxPoint>& aPoints )
|
||||||
|
{
|
||||||
|
m_Poly.RemoveAllContours();
|
||||||
|
m_Poly.NewOutline();
|
||||||
|
|
||||||
|
for ( auto p : aPoints )
|
||||||
|
{
|
||||||
|
m_Poly.Append( p.x, p.y );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::vector<wxPoint> DRAWSEGMENT::GetPolyPoints() const
|
||||||
|
{
|
||||||
|
std::vector<wxPoint> rv;
|
||||||
|
|
||||||
|
for ( auto iter = m_Poly.CIterate(); iter; iter++ )
|
||||||
|
{
|
||||||
|
rv.push_back( wxPoint( iter->x, iter->y ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
|
@ -36,6 +36,7 @@
|
||||||
#include <trigo.h>
|
#include <trigo.h>
|
||||||
#include <common.h>
|
#include <common.h>
|
||||||
|
|
||||||
|
#include <geometry/shape_poly_set.h>
|
||||||
|
|
||||||
class LINE_READER;
|
class LINE_READER;
|
||||||
class EDA_DRAW_FRAME;
|
class EDA_DRAW_FRAME;
|
||||||
|
@ -57,7 +58,7 @@ protected:
|
||||||
wxPoint m_BezierC2; ///< Bezier Control Point 2
|
wxPoint m_BezierC2; ///< Bezier Control Point 2
|
||||||
|
|
||||||
std::vector<wxPoint> m_BezierPoints;
|
std::vector<wxPoint> m_BezierPoints;
|
||||||
std::vector<wxPoint> m_PolyPoints;
|
SHAPE_POLY_SET m_Poly;
|
||||||
|
|
||||||
// Computes the bounding box for an arc
|
// Computes the bounding box for an arc
|
||||||
void computeArcBBox( EDA_RECT& aBBox ) const;
|
void computeArcBBox( EDA_RECT& aBBox ) const;
|
||||||
|
@ -165,19 +166,18 @@ public:
|
||||||
|
|
||||||
// Accessors:
|
// Accessors:
|
||||||
const std::vector<wxPoint>& GetBezierPoints() const { return m_BezierPoints; }
|
const std::vector<wxPoint>& GetBezierPoints() const { return m_BezierPoints; }
|
||||||
const std::vector<wxPoint>& GetPolyPoints() const { return m_PolyPoints; }
|
|
||||||
// same accessor, to add/change corners of the polygon
|
const std::vector<wxPoint> GetPolyPoints() const;
|
||||||
std::vector<wxPoint>& GetPolyPoints() { return m_PolyPoints; }
|
SHAPE_POLY_SET& GetPolyShape() { return m_Poly; }
|
||||||
|
const SHAPE_POLY_SET& GetPolyShape() const { return m_Poly; }
|
||||||
|
void SetPolyShape( const SHAPE_POLY_SET& aShape ) { m_Poly = aShape; }
|
||||||
|
|
||||||
void SetBezierPoints( const std::vector<wxPoint>& aPoints )
|
void SetBezierPoints( const std::vector<wxPoint>& aPoints )
|
||||||
{
|
{
|
||||||
m_BezierPoints = aPoints;
|
m_BezierPoints = aPoints;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetPolyPoints( const std::vector<wxPoint>& aPoints )
|
void SetPolyPoints( const std::vector<wxPoint>& aPoints );
|
||||||
{
|
|
||||||
m_PolyPoints = aPoints;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Draw( EDA_DRAW_PANEL* panel, wxDC* DC,
|
void Draw( EDA_DRAW_PANEL* panel, wxDC* DC,
|
||||||
GR_DRAWMODE aDrawMode, const wxPoint& aOffset = ZeroOffset ) override;
|
GR_DRAWMODE aDrawMode, const wxPoint& aOffset = ZeroOffset ) override;
|
||||||
|
|
|
@ -202,7 +202,12 @@ void EDGE_MODULE::Draw( EDA_DRAW_PANEL* panel, wxDC* DC, GR_DRAWMODE draw_mode,
|
||||||
{
|
{
|
||||||
// We must compute absolute coordinates from m_PolyPoints
|
// We must compute absolute coordinates from m_PolyPoints
|
||||||
// which are relative to module position, orientation 0
|
// which are relative to module position, orientation 0
|
||||||
std::vector<wxPoint> points = m_PolyPoints;
|
std::vector<wxPoint> points;
|
||||||
|
|
||||||
|
for( auto iter = m_Poly.CIterate(); iter; iter++ )
|
||||||
|
{
|
||||||
|
points.push_back( wxPoint( iter->x,iter->y ) );
|
||||||
|
}
|
||||||
|
|
||||||
for( unsigned ii = 0; ii < points.size(); ii++ )
|
for( unsigned ii = 0; ii < points.size(); ii++ )
|
||||||
{
|
{
|
||||||
|
@ -300,8 +305,11 @@ void EDGE_MODULE::Flip( const wxPoint& aCentre )
|
||||||
case S_POLYGON:
|
case S_POLYGON:
|
||||||
// polygon corners coordinates are always relative to the
|
// polygon corners coordinates are always relative to the
|
||||||
// footprint position, orientation 0
|
// footprint position, orientation 0
|
||||||
for( unsigned ii = 0; ii < m_PolyPoints.size(); ii++ )
|
for( auto iter = m_Poly.Iterate(); iter; iter++ )
|
||||||
MIRROR( m_PolyPoints[ii].y, 0 );
|
{
|
||||||
|
MIRROR( iter->y, 0 );
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// DRAWSEGMENT items are not usually on copper layers, but
|
// DRAWSEGMENT items are not usually on copper layers, but
|
||||||
|
@ -338,12 +346,12 @@ void EDGE_MODULE::Mirror( wxPoint aCentre, bool aMirrorAroundXAxis )
|
||||||
case S_POLYGON:
|
case S_POLYGON:
|
||||||
// polygon corners coordinates are always relative to the
|
// polygon corners coordinates are always relative to the
|
||||||
// footprint position, orientation 0
|
// footprint position, orientation 0
|
||||||
for( unsigned ii = 0; ii < m_PolyPoints.size(); ii++ )
|
for( auto iter = m_Poly.Iterate(); iter; iter++ )
|
||||||
{
|
{
|
||||||
if( aMirrorAroundXAxis )
|
if( aMirrorAroundXAxis )
|
||||||
MIRROR( m_PolyPoints[ii].y, aCentre.y );
|
MIRROR( iter->y, aCentre.y );
|
||||||
else
|
else
|
||||||
MIRROR( m_PolyPoints[ii].x, aCentre.x );
|
MIRROR( iter->x, aCentre.x );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -378,8 +386,8 @@ void EDGE_MODULE::Move( const wxPoint& aMoveVector )
|
||||||
case S_POLYGON:
|
case S_POLYGON:
|
||||||
// polygon corners coordinates are always relative to the
|
// polygon corners coordinates are always relative to the
|
||||||
// footprint position, orientation 0
|
// footprint position, orientation 0
|
||||||
for( unsigned ii = 0; ii < m_PolyPoints.size(); ii++ )
|
for( auto iter = m_Poly.Iterate(); iter; iter++ )
|
||||||
m_PolyPoints[ii] += aMoveVector;
|
*iter += VECTOR2I( aMoveVector );
|
||||||
}
|
}
|
||||||
|
|
||||||
SetDrawCoord();
|
SetDrawCoord();
|
||||||
|
|
|
@ -272,13 +272,16 @@ public:
|
||||||
* a filled circle or ring ( if thickness == 0, this is a filled circle, else a ring)
|
* a filled circle or ring ( if thickness == 0, this is a filled circle, else a ring)
|
||||||
* a arc
|
* a arc
|
||||||
*/
|
*/
|
||||||
void AddPrimitive( std::vector<wxPoint>& aPoly, int aThickness ); ///< add a polygonal basic shape
|
void AddPrimitive( const SHAPE_POLY_SET& aPoly, int aThickness ); ///< add a polygonal basic shape
|
||||||
|
void AddPrimitive( const std::vector<wxPoint>& aPoly, int aThickness ); ///< add a polygonal basic shape
|
||||||
void AddPrimitive( wxPoint aStart, wxPoint aEnd, int aThickness ); ///< segment basic shape
|
void AddPrimitive( wxPoint aStart, wxPoint aEnd, int aThickness ); ///< segment basic shape
|
||||||
void AddPrimitive( wxPoint aCenter, int aRadius, int aThickness ); ///< ring or circle basic shape
|
void AddPrimitive( wxPoint aCenter, int aRadius, int aThickness ); ///< ring or circle basic shape
|
||||||
void AddPrimitive( wxPoint aCenter, wxPoint aStart,
|
void AddPrimitive( wxPoint aCenter, wxPoint aStart,
|
||||||
int aArcAngle, int aThickness ); ///< arc basic shape
|
int aArcAngle, int aThickness ); ///< arc basic shape
|
||||||
|
|
||||||
|
|
||||||
|
bool GetBestAnchorPosition( VECTOR2I& aPos );
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Merge all basic shapes, converted to a polygon in one polygon,
|
* Merge all basic shapes, converted to a polygon in one polygon,
|
||||||
* in m_customShapeAsPolygon
|
* in m_customShapeAsPolygon
|
||||||
|
@ -726,6 +729,9 @@ private:
|
||||||
*/
|
*/
|
||||||
int boundingRadius() const;
|
int boundingRadius() const;
|
||||||
|
|
||||||
|
bool buildCustomPadPolygon( SHAPE_POLY_SET* aMergedPolygon,
|
||||||
|
int aCircleToSegmentsCount );
|
||||||
|
|
||||||
private: // Private variable members:
|
private: // Private variable members:
|
||||||
|
|
||||||
// Actually computed and cached on demand by the accessor
|
// Actually computed and cached on demand by the accessor
|
||||||
|
|
|
@ -66,7 +66,18 @@ void PAD_CS_PRIMITIVE::ExportTo( DRAWSEGMENT* aTarget )
|
||||||
* add a free shape to the shape list.
|
* add a free shape to the shape list.
|
||||||
* the shape is a polygon (can be with thick outline), segment, circle or arc
|
* the shape is a polygon (can be with thick outline), segment, circle or arc
|
||||||
*/
|
*/
|
||||||
void D_PAD::AddPrimitive( std::vector<wxPoint>& aPoly, int aThickness )
|
|
||||||
|
void D_PAD::AddPrimitive( const SHAPE_POLY_SET& aPoly, int aThickness )
|
||||||
|
{
|
||||||
|
std::vector<wxPoint> points;
|
||||||
|
|
||||||
|
for( auto iter = aPoly.CIterate(); iter; iter++ )
|
||||||
|
points.push_back( wxPoint( iter->x, iter->y ) );
|
||||||
|
|
||||||
|
AddPrimitive( points, aThickness );
|
||||||
|
}
|
||||||
|
|
||||||
|
void D_PAD::AddPrimitive( const std::vector<wxPoint>& aPoly, int aThickness )
|
||||||
{
|
{
|
||||||
PAD_CS_PRIMITIVE shape( S_POLYGON );
|
PAD_CS_PRIMITIVE shape( S_POLYGON );
|
||||||
shape.m_Poly = aPoly;
|
shape.m_Poly = aPoly;
|
||||||
|
@ -135,38 +146,10 @@ void D_PAD::DeletePrimitivesList()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Merge all basic shapes, converted to a polygon in one polygon,
|
bool D_PAD::buildCustomPadPolygon( SHAPE_POLY_SET* aMergedPolygon,
|
||||||
* return true if OK, false in there is more than one polygon
|
int aCircleToSegmentsCount )
|
||||||
* in aMergedPolygon
|
|
||||||
*/
|
|
||||||
bool D_PAD::MergePrimitivesAsPolygon( 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;
|
SHAPE_POLY_SET aux_polyset;
|
||||||
|
|
||||||
for( unsigned cnt = 0; cnt < m_basicShapes.size(); ++cnt )
|
for( unsigned cnt = 0; cnt < m_basicShapes.size(); ++cnt )
|
||||||
|
@ -212,7 +195,9 @@ bool D_PAD::MergePrimitivesAsPolygon( SHAPE_POLY_SET* aMergedPolygon,
|
||||||
polyset.NewOutline();
|
polyset.NewOutline();
|
||||||
|
|
||||||
for( unsigned ii = 0; ii < poly.size(); ii++ )
|
for( unsigned ii = 0; ii < poly.size(); ii++ )
|
||||||
|
{
|
||||||
polyset.Append( poly[ii].x, poly[ii].y );
|
polyset.Append( poly[ii].x, poly[ii].y );
|
||||||
|
}
|
||||||
|
|
||||||
polyset.Inflate( bshape.m_Thickness/2, 32 );
|
polyset.Inflate( bshape.m_Thickness/2, 32 );
|
||||||
|
|
||||||
|
@ -230,13 +215,79 @@ bool D_PAD::MergePrimitivesAsPolygon( SHAPE_POLY_SET* aMergedPolygon,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Merge all polygons:
|
aux_polyset.Simplify( SHAPE_POLY_SET::PM_FAST );
|
||||||
|
|
||||||
|
// Merge all polygons, if more than one, pick the largest (area-wise)
|
||||||
if( aux_polyset.OutlineCount() )
|
if( aux_polyset.OutlineCount() )
|
||||||
{
|
{
|
||||||
|
|
||||||
|
if( aux_polyset.OutlineCount() >= 2)
|
||||||
|
{
|
||||||
|
int bestOutline = 0;
|
||||||
|
double maxArea = 0.0;
|
||||||
|
|
||||||
|
for( int i = 0; i < aux_polyset.OutlineCount(); i++ )
|
||||||
|
{
|
||||||
|
double area = aux_polyset.COutline(i).Area();
|
||||||
|
|
||||||
|
if ( area > maxArea )
|
||||||
|
{
|
||||||
|
maxArea = area;
|
||||||
|
bestOutline = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if( bestOutline != 0 )
|
||||||
|
aux_polyset.Polygon( 0 ) = aux_polyset.Polygon( bestOutline );
|
||||||
|
|
||||||
|
for (int i = 1; i < aux_polyset.OutlineCount(); i++ )
|
||||||
|
{
|
||||||
|
aux_polyset.DeletePolygon( i );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
aMergedPolygon->BooleanAdd( aux_polyset, SHAPE_POLY_SET::PM_FAST );
|
aMergedPolygon->BooleanAdd( aux_polyset, SHAPE_POLY_SET::PM_FAST );
|
||||||
aMergedPolygon->Fracture( SHAPE_POLY_SET::PM_FAST );
|
aMergedPolygon->Fracture( SHAPE_POLY_SET::PM_FAST );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return aMergedPolygon->OutlineCount() <= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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::MergePrimitivesAsPolygon( 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( !buildCustomPadPolygon( aMergedPolygon, aCircleToSegmentsCount ) )
|
||||||
|
return false;
|
||||||
|
|
||||||
m_boundingRadius = -1; // The current bouding radius is no more valid.
|
m_boundingRadius = -1; // The current bouding radius is no more valid.
|
||||||
|
|
||||||
return aMergedPolygon->OutlineCount() <= 1;
|
return aMergedPolygon->OutlineCount() <= 1;
|
||||||
|
@ -265,3 +316,79 @@ void D_PAD::CustomShapeAsPolygonToBoardPosition( SHAPE_POLY_SET * aMergedPolygon
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool D_PAD::GetBestAnchorPosition( VECTOR2I& aPos )
|
||||||
|
{
|
||||||
|
SHAPE_POLY_SET poly;
|
||||||
|
|
||||||
|
if ( !buildCustomPadPolygon( &poly, 16 ) )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
const int minSteps = 10;
|
||||||
|
const int maxSteps = 50;
|
||||||
|
|
||||||
|
int stepsX, stepsY;
|
||||||
|
|
||||||
|
auto bbox = poly.BBox();
|
||||||
|
|
||||||
|
if( bbox.GetWidth() < bbox.GetHeight() )
|
||||||
|
{
|
||||||
|
stepsX = minSteps;
|
||||||
|
stepsY = minSteps * (double) bbox.GetHeight() / (double )(bbox.GetWidth() + 1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
stepsY = minSteps;
|
||||||
|
stepsX = minSteps * (double) bbox.GetWidth() / (double )(bbox.GetHeight() + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
stepsX = std::max(minSteps, std::min( maxSteps, stepsX ) );
|
||||||
|
stepsY = std::max(minSteps, std::min( maxSteps, stepsY ) );
|
||||||
|
|
||||||
|
auto center = bbox.Centre();
|
||||||
|
|
||||||
|
auto minDist = std::numeric_limits<int64_t>::max();
|
||||||
|
int64_t minDistEdge;
|
||||||
|
|
||||||
|
if( GetAnchorPadShape() == PAD_SHAPE_CIRCLE )
|
||||||
|
{
|
||||||
|
minDistEdge = GetSize().x;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
minDistEdge = std::max( GetSize().x, GetSize().y );
|
||||||
|
}
|
||||||
|
|
||||||
|
boost::optional<VECTOR2I> bestAnchor;
|
||||||
|
|
||||||
|
for ( int y = 0; y < stepsY ; y++ )
|
||||||
|
for ( int x = 0; x < stepsX; x++ )
|
||||||
|
{
|
||||||
|
VECTOR2I p = bbox.GetPosition();
|
||||||
|
p.x += rescale( x, bbox.GetWidth(), (stepsX - 1) );
|
||||||
|
p.y += rescale( y, bbox.GetHeight(), (stepsY - 1) );
|
||||||
|
|
||||||
|
if ( poly.Contains(p) )
|
||||||
|
{
|
||||||
|
|
||||||
|
auto dist = (center - p).EuclideanNorm();
|
||||||
|
auto distEdge = poly.COutline(0).Distance( p, true );
|
||||||
|
if ( distEdge >= minDistEdge )
|
||||||
|
{
|
||||||
|
if ( dist < minDist )
|
||||||
|
{
|
||||||
|
bestAnchor = p;
|
||||||
|
minDist = dist;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( bestAnchor )
|
||||||
|
{
|
||||||
|
aPos = *bestAnchor;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
|
@ -312,6 +312,9 @@ bool DIALOG_GRAPHIC_ITEM_PROPERTIES::Validate()
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case S_POLYGON:
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
|
||||||
// Check start and end are not the same.
|
// Check start and end are not the same.
|
||||||
|
|
|
@ -329,7 +329,7 @@ void DIALOG_PAD_PROPERTIES::OnPaintShowPanel( wxPaintEvent& event )
|
||||||
|
|
||||||
case S_POLYGON: // polygon
|
case S_POLYGON: // polygon
|
||||||
{
|
{
|
||||||
std::vector<wxPoint>& poly = dummySegment.GetPolyPoints();
|
std::vector<wxPoint> poly = dummySegment.GetPolyPoints();
|
||||||
GRClosedPoly( NULL, &dc, poly.size(), &poly[0], /* filled */ true,
|
GRClosedPoly( NULL, &dc, poly.size(), &poly[0], /* filled */ true,
|
||||||
primitive.m_Thickness, hcolor, hcolor );
|
primitive.m_Thickness, hcolor, hcolor );
|
||||||
}
|
}
|
||||||
|
@ -1160,11 +1160,9 @@ void DIALOG_PAD_PROPERTIES::redraw()
|
||||||
|
|
||||||
case S_POLYGON: // polygon
|
case S_POLYGON: // polygon
|
||||||
{
|
{
|
||||||
std::vector<wxPoint>& poly = dummySegment->GetPolyPoints();
|
for( auto iter = dummySegment->GetPolyShape().Iterate(); iter; iter++ )
|
||||||
|
|
||||||
for( unsigned ii = 0; ii < poly.size(); ii++ )
|
|
||||||
{
|
{
|
||||||
poly[ii] += m_dummyPad->GetPosition();
|
(*iter) += VECTOR2I( m_dummyPad->GetPosition() );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -253,7 +253,7 @@ MODULE* try_load_footprint( const wxFileName& aFileName, IO_MGR::PCB_FILE_T aFil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
MODULE* FOOTPRINT_EDIT_FRAME::Import_Module()
|
MODULE* FOOTPRINT_EDIT_FRAME::Import_Module( const wxString& aName )
|
||||||
{
|
{
|
||||||
wxString lastOpenedPathForLoading = m_mruPath;
|
wxString lastOpenedPathForLoading = m_mruPath;
|
||||||
wxConfigBase* config = Kiface().KifaceSettings();
|
wxConfigBase* config = Kiface().KifaceSettings();
|
||||||
|
@ -261,7 +261,12 @@ MODULE* FOOTPRINT_EDIT_FRAME::Import_Module()
|
||||||
if( config )
|
if( config )
|
||||||
config->Read( EXPORT_IMPORT_LASTPATH_KEY, &lastOpenedPathForLoading );
|
config->Read( EXPORT_IMPORT_LASTPATH_KEY, &lastOpenedPathForLoading );
|
||||||
|
|
||||||
wxFileName fn = getFootprintFilenameFromUser( this, lastOpenedPathForLoading );
|
wxFileName fn;
|
||||||
|
|
||||||
|
if( aName != wxT("") )
|
||||||
|
fn = aName;
|
||||||
|
else
|
||||||
|
fn = getFootprintFilenameFromUser( this, lastOpenedPathForLoading );
|
||||||
|
|
||||||
if( !fn.IsOk() )
|
if( !fn.IsOk() )
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
|
@ -634,7 +634,7 @@ MODULE* PCB_EDIT_FRAME::Create_MuWavePolygonShape()
|
||||||
module->GraphicalItemsList().PushFront( edge );
|
module->GraphicalItemsList().PushFront( edge );
|
||||||
|
|
||||||
// Get the corner buffer of the polygonal edge
|
// Get the corner buffer of the polygonal edge
|
||||||
std::vector<wxPoint>& polyPoints = edge->GetPolyPoints();
|
std::vector<wxPoint> polyPoints;
|
||||||
polyPoints.reserve( PolyEdges.size() + 2 );
|
polyPoints.reserve( PolyEdges.size() + 2 );
|
||||||
|
|
||||||
// Init start point coord:
|
// Init start point coord:
|
||||||
|
@ -670,6 +670,7 @@ MODULE* PCB_EDIT_FRAME::Create_MuWavePolygonShape()
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
edge->SetPolyPoints( polyPoints );
|
||||||
PolyEdges.clear();
|
PolyEdges.clear();
|
||||||
module->CalculateBoundingBox();
|
module->CalculateBoundingBox();
|
||||||
GetBoard()->m_Status_Pcb = 0;
|
GetBoard()->m_Status_Pcb = 0;
|
||||||
|
|
|
@ -295,12 +295,13 @@ bool EDIT_TOOL::Init()
|
||||||
menu.AddItem( PCB_ACTIONS::properties, SELECTION_CONDITIONS::Count( 1 )
|
menu.AddItem( PCB_ACTIONS::properties, SELECTION_CONDITIONS::Count( 1 )
|
||||||
|| SELECTION_CONDITIONS::OnlyTypes( GENERAL_COLLECTOR::Tracks ) );
|
|| SELECTION_CONDITIONS::OnlyTypes( GENERAL_COLLECTOR::Tracks ) );
|
||||||
|
|
||||||
|
|
||||||
menu.AddItem( PCB_ACTIONS::moveExact, SELECTION_CONDITIONS::NotEmpty );
|
menu.AddItem( PCB_ACTIONS::moveExact, SELECTION_CONDITIONS::NotEmpty );
|
||||||
menu.AddItem( PCB_ACTIONS::positionRelative, SELECTION_CONDITIONS::NotEmpty );
|
menu.AddItem( PCB_ACTIONS::positionRelative, SELECTION_CONDITIONS::NotEmpty );
|
||||||
menu.AddItem( PCB_ACTIONS::duplicate, SELECTION_CONDITIONS::NotEmpty );
|
menu.AddItem( PCB_ACTIONS::duplicate, SELECTION_CONDITIONS::NotEmpty );
|
||||||
menu.AddItem( PCB_ACTIONS::createArray, SELECTION_CONDITIONS::NotEmpty );
|
menu.AddItem( PCB_ACTIONS::createArray, SELECTION_CONDITIONS::NotEmpty );
|
||||||
|
|
||||||
menu.AddSeparator();
|
|
||||||
menu.AddItem( PCB_ACTIONS::copyToClipboard, SELECTION_CONDITIONS::NotEmpty );
|
menu.AddItem( PCB_ACTIONS::copyToClipboard, SELECTION_CONDITIONS::NotEmpty );
|
||||||
menu.AddItem( PCB_ACTIONS::cutToClipboard, SELECTION_CONDITIONS::NotEmpty );
|
menu.AddItem( PCB_ACTIONS::cutToClipboard, SELECTION_CONDITIONS::NotEmpty );
|
||||||
menu.AddItem( PCB_ACTIONS::pasteFromClipboard );
|
menu.AddItem( PCB_ACTIONS::pasteFromClipboard );
|
||||||
|
@ -308,6 +309,8 @@ bool EDIT_TOOL::Init()
|
||||||
|
|
||||||
// Mirror only available in modedit
|
// Mirror only available in modedit
|
||||||
menu.AddItem( PCB_ACTIONS::mirror, editingModuleCondition && SELECTION_CONDITIONS::NotEmpty );
|
menu.AddItem( PCB_ACTIONS::mirror, editingModuleCondition && SELECTION_CONDITIONS::NotEmpty );
|
||||||
|
menu.AddItem( PCB_ACTIONS::createPadFromShapes, editingModuleCondition && SELECTION_CONDITIONS::NotEmpty );
|
||||||
|
menu.AddItem( PCB_ACTIONS::explodePadToShapes, editingModuleCondition && SELECTION_CONDITIONS::NotEmpty );
|
||||||
|
|
||||||
// Footprint actions
|
// Footprint actions
|
||||||
menu.AddItem( PCB_ACTIONS::editFootprintInFpEditor,
|
menu.AddItem( PCB_ACTIONS::editFootprintInFpEditor,
|
||||||
|
|
|
@ -59,6 +59,14 @@ TOOL_ACTION PCB_ACTIONS::placePad( "pcbnew.ModuleEditor.placePad",
|
||||||
AS_GLOBAL, 0,
|
AS_GLOBAL, 0,
|
||||||
_( "Add Pad" ), _( "Add a pad" ), NULL, AF_ACTIVATE );
|
_( "Add Pad" ), _( "Add a pad" ), NULL, AF_ACTIVATE );
|
||||||
|
|
||||||
|
TOOL_ACTION PCB_ACTIONS::createPadFromShapes( "pcbnew.ModuleEditor.createPadFromShapes",
|
||||||
|
AS_CONTEXT, 0,
|
||||||
|
_( "Create Pad from Selected Shapes" ), _( "Creates a custom-shaped pads from a set of selected shapes" ) );
|
||||||
|
|
||||||
|
TOOL_ACTION PCB_ACTIONS::explodePadToShapes( "pcbnew.ModuleEditor.explodePadToShapes",
|
||||||
|
AS_CONTEXT, 0,
|
||||||
|
_( "Explode Selected Pad to Graphical Shapes" ), _( "Converts a custom-shaped pads to a set of graphical shapes" ) );
|
||||||
|
|
||||||
TOOL_ACTION PCB_ACTIONS::enumeratePads( "pcbnew.ModuleEditor.enumeratePads",
|
TOOL_ACTION PCB_ACTIONS::enumeratePads( "pcbnew.ModuleEditor.enumeratePads",
|
||||||
AS_GLOBAL, 0,
|
AS_GLOBAL, 0,
|
||||||
_( "Enumerate Pads" ), _( "Enumerate pads" ), pad_enumerate_xpm, AF_ACTIVATE );
|
_( "Enumerate Pads" ), _( "Enumerate pads" ), pad_enumerate_xpm, AF_ACTIVATE );
|
||||||
|
@ -321,10 +329,209 @@ int MODULE_EDITOR_TOOLS::ModuleEdgeOutlines( const TOOL_EVENT& aEvent )
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int MODULE_EDITOR_TOOLS::ExplodePadToShapes( const TOOL_EVENT& aEvent )
|
||||||
|
{
|
||||||
|
SELECTION& selection = m_toolMgr->GetTool<SELECTION_TOOL>()->GetSelection();
|
||||||
|
BOARD_COMMIT commit( frame() );
|
||||||
|
|
||||||
|
if( selection.Size() != 1 )
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if( selection[0]->Type() != PCB_PAD_T )
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
auto pad = static_cast<D_PAD*>( selection[0] );
|
||||||
|
|
||||||
|
if( pad->GetShape() != PAD_SHAPE_CUSTOM )
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
commit.Modify( pad );
|
||||||
|
|
||||||
|
wxPoint anchor = pad->GetPosition();
|
||||||
|
|
||||||
|
for( auto prim : pad->GetPrimitives() )
|
||||||
|
{
|
||||||
|
auto ds = new EDGE_MODULE( board()->m_Modules );
|
||||||
|
|
||||||
|
ds->SetLayer( pad->GetLayer() );
|
||||||
|
ds->SetShape( prim.m_Shape );
|
||||||
|
ds->SetStart( prim.m_Start + anchor );
|
||||||
|
ds->SetEnd( prim.m_End + anchor );
|
||||||
|
ds->SetWidth( prim.m_Thickness );
|
||||||
|
|
||||||
|
for( auto&p : prim.m_Poly )
|
||||||
|
p += anchor;
|
||||||
|
|
||||||
|
ds->SetPolyPoints( prim.m_Poly );
|
||||||
|
ds->SetAngle( prim.m_ArcAngle );
|
||||||
|
|
||||||
|
commit.Add( ds );
|
||||||
|
}
|
||||||
|
|
||||||
|
pad->SetShape( pad->GetAnchorPadShape() );
|
||||||
|
commit.Push( _("Explode pad to shapes") );
|
||||||
|
|
||||||
|
m_toolMgr->RunAction( PCB_ACTIONS::selectionClear, true );
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int MODULE_EDITOR_TOOLS::CreatePadFromShapes( const TOOL_EVENT& aEvent )
|
||||||
|
{
|
||||||
|
SELECTION& selection = m_toolMgr->GetTool<SELECTION_TOOL>()->GetSelection();
|
||||||
|
|
||||||
|
std::unique_ptr<D_PAD> pad ( new D_PAD ( board()->m_Modules ) );
|
||||||
|
D_PAD *refPad = nullptr;
|
||||||
|
bool multipleRefPadsFound = false;
|
||||||
|
bool illegalItemsFound = false;
|
||||||
|
|
||||||
|
std::vector<PAD_CS_PRIMITIVE> shapes;
|
||||||
|
|
||||||
|
BOARD_COMMIT commit( frame() );
|
||||||
|
|
||||||
|
for( auto item : selection )
|
||||||
|
{
|
||||||
|
switch( item->Type() )
|
||||||
|
{
|
||||||
|
case PCB_PAD_T:
|
||||||
|
{
|
||||||
|
if( refPad )
|
||||||
|
multipleRefPadsFound = true;
|
||||||
|
|
||||||
|
refPad = static_cast<D_PAD*>( item );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case PCB_MODULE_EDGE_T:
|
||||||
|
{
|
||||||
|
auto em = static_cast<EDGE_MODULE*> ( item );
|
||||||
|
|
||||||
|
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();
|
||||||
|
|
||||||
|
for ( auto p : em->GetPolyPoints() )
|
||||||
|
shape.m_Poly.push_back(p);
|
||||||
|
|
||||||
|
shapes.push_back(shape);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
illegalItemsFound = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if( refPad && selection.Size() == 1 )
|
||||||
|
{
|
||||||
|
// don't convert a pad into itself...
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( multipleRefPadsFound )
|
||||||
|
{
|
||||||
|
DisplayErrorMessage( frame(), _("Cannot convert items to a custom-shaped pad: selection contains more than one reference pad. ") );
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( illegalItemsFound )
|
||||||
|
{
|
||||||
|
DisplayErrorMessage( frame(), _("Cannot convert items to a custom-shaped pad: selection contains unsupported items. Only graphical lines, circles, arcs and polygons are allowed.") );
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( refPad )
|
||||||
|
{
|
||||||
|
pad.reset( static_cast<D_PAD*>( refPad->Clone() ) );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pad->SetAnchorPadShape( PAD_SHAPE_CIRCLE );
|
||||||
|
pad->SetAttribute( PAD_ATTRIB_SMD );
|
||||||
|
pad->SetLayerSet( D_PAD::SMDMask() );
|
||||||
|
pad->SetSize ( wxSize( 10000, 10000 ) );
|
||||||
|
pad->IncrementPadName( true, true );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
pad->SetPrimitives( shapes );
|
||||||
|
pad->SetShape ( PAD_SHAPE_CUSTOM );
|
||||||
|
|
||||||
|
boost::optional<VECTOR2I> anchor;
|
||||||
|
VECTOR2I tmp;
|
||||||
|
|
||||||
|
if( refPad )
|
||||||
|
{
|
||||||
|
anchor = pad->GetPosition();
|
||||||
|
}
|
||||||
|
else if( pad->GetBestAnchorPosition( tmp ) )
|
||||||
|
{
|
||||||
|
anchor = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( !anchor )
|
||||||
|
{
|
||||||
|
DisplayErrorMessage( frame(), _("Cannot convert items to a custom-shaped pad: unable to determine the anchor point position. Consider adding a small anchor pad to the selection and try again.") );
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// relocate the shapes, they are relative to the anchor pad position
|
||||||
|
for( auto& shape : shapes )
|
||||||
|
{
|
||||||
|
shape.m_Start.x -= anchor->x;
|
||||||
|
shape.m_Start.y -= anchor->y;
|
||||||
|
shape.m_End.x -= anchor->x;
|
||||||
|
shape.m_End.y -= anchor->y;
|
||||||
|
|
||||||
|
for( auto&p : shape.m_Poly )
|
||||||
|
{
|
||||||
|
p.x -= anchor->x;
|
||||||
|
p.y -= anchor->y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
pad->SetPosition( wxPoint( anchor->x, anchor->y ) );
|
||||||
|
pad->SetPrimitives( shapes );
|
||||||
|
|
||||||
|
bool result = pad->MergePrimitivesAsPolygon();
|
||||||
|
|
||||||
|
if( !result )
|
||||||
|
{
|
||||||
|
DisplayErrorMessage( frame(), _("Cannot convert items to a custom-shaped pad: selected items do not form a single solid shape.") );
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto padPtr = pad.release();
|
||||||
|
|
||||||
|
commit.Add( padPtr );
|
||||||
|
for ( auto item : selection )
|
||||||
|
{
|
||||||
|
commit.Remove( item );
|
||||||
|
}
|
||||||
|
|
||||||
|
m_toolMgr->RunAction( PCB_ACTIONS::selectionClear, true );
|
||||||
|
m_toolMgr->RunAction( PCB_ACTIONS::selectItem, true, padPtr );
|
||||||
|
|
||||||
|
commit.Push(_("Create Pad From Selected Shapes") );
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
void MODULE_EDITOR_TOOLS::setTransitions()
|
void MODULE_EDITOR_TOOLS::setTransitions()
|
||||||
{
|
{
|
||||||
Go( &MODULE_EDITOR_TOOLS::PlacePad, PCB_ACTIONS::placePad.MakeEvent() );
|
Go( &MODULE_EDITOR_TOOLS::PlacePad, PCB_ACTIONS::placePad.MakeEvent() );
|
||||||
|
Go( &MODULE_EDITOR_TOOLS::CreatePadFromShapes, PCB_ACTIONS::createPadFromShapes.MakeEvent() );
|
||||||
|
Go( &MODULE_EDITOR_TOOLS::ExplodePadToShapes, PCB_ACTIONS::explodePadToShapes.MakeEvent() );
|
||||||
Go( &MODULE_EDITOR_TOOLS::EnumeratePads, PCB_ACTIONS::enumeratePads.MakeEvent() );
|
Go( &MODULE_EDITOR_TOOLS::EnumeratePads, PCB_ACTIONS::enumeratePads.MakeEvent() );
|
||||||
Go( &MODULE_EDITOR_TOOLS::ModuleTextOutlines, PCB_ACTIONS::moduleTextOutlines.MakeEvent() );
|
Go( &MODULE_EDITOR_TOOLS::ModuleTextOutlines, PCB_ACTIONS::moduleTextOutlines.MakeEvent() );
|
||||||
Go( &MODULE_EDITOR_TOOLS::ModuleEdgeOutlines, PCB_ACTIONS::moduleEdgeOutlines.MakeEvent() );
|
Go( &MODULE_EDITOR_TOOLS::ModuleEdgeOutlines, PCB_ACTIONS::moduleEdgeOutlines.MakeEvent() );
|
||||||
|
|
|
@ -82,6 +82,21 @@ public:
|
||||||
*/
|
*/
|
||||||
int ModuleEdgeOutlines( const TOOL_EVENT& aEvent );
|
int ModuleEdgeOutlines( const TOOL_EVENT& aEvent );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function CreatePadFromShapes()
|
||||||
|
*
|
||||||
|
* Creates a custom-shaped pad from a set of selected graphical shapes
|
||||||
|
*/
|
||||||
|
int CreatePadFromShapes( const TOOL_EVENT& aEvent );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function ExplodePadToShapes()
|
||||||
|
*
|
||||||
|
* Breaks apart a complex-shaped part into a set of graphical shapes
|
||||||
|
*/
|
||||||
|
int ExplodePadToShapes( const TOOL_EVENT& aEvent );
|
||||||
|
|
||||||
|
|
||||||
///> Sets up handlers for various events.
|
///> Sets up handlers for various events.
|
||||||
void setTransitions() override;
|
void setTransitions() override;
|
||||||
|
|
||||||
|
|
|
@ -80,6 +80,7 @@ public:
|
||||||
Add( PCB_ACTIONS::applyPadSettings );
|
Add( PCB_ACTIONS::applyPadSettings );
|
||||||
Add( PCB_ACTIONS::pushPadSettings );
|
Add( PCB_ACTIONS::pushPadSettings );
|
||||||
|
|
||||||
|
|
||||||
// show modedit-specific items
|
// show modedit-specific items
|
||||||
if( m_editingFootprint )
|
if( m_editingFootprint )
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue