drc: more code cleaning. Added comments and fixed some erroneous comments. Fixed bug 638839.

fixed bug 641982 (I hope)
This commit is contained in:
jean-pierre charras 2010-09-18 19:55:08 +02:00
parent 577a79bc59
commit ed54bdfc9d
12 changed files with 333 additions and 264 deletions

View File

@ -10,7 +10,7 @@ else(ZLIB_FOUND)
# and we try to use it # and we try to use it
# Unfortunately, we have no way to know exactlty the path of zlib.h becuase this file # Unfortunately, we have no way to know exactlty the path of zlib.h becuase this file
# is in wxWidgets sources, not in wxWidgets include path. # is in wxWidgets sources, not in wxWidgets include path.
find_path(ZLIB_INCLUDE_DIR PATHS ${wxWidgets_ROOT_DIR}/../src/zlib/ ${wxWidgets_ROOT_DIR}/src/zlib/ DOC "location of zlib include files") find_path(ZLIB_INCLUDE_DIR zlib.h PATHS ${wxWidgets_ROOT_DIR}/../src/zlib/ ${wxWidgets_ROOT_DIR}/src/zlib/ DOC "location of zlib include files")
find_file(ZLIB_LIBRARIES NAMES ${wxWidgets_LIB_DIR}/libwxzlib-2.8.a ZLIB_LIBRARIES NAMES ${wxWidgets_LIB_DIR}/libwxzlib-2.9.a libwxzlib.a PATHS ${wxWidgets_ROOT_DIR}/lib/ PATH_SUFFIXES gcc_dll DOC "location of wxzlib library file") find_file(ZLIB_LIBRARIES NAMES ${wxWidgets_LIB_DIR}/libwxzlib-2.8.a ZLIB_LIBRARIES NAMES ${wxWidgets_LIB_DIR}/libwxzlib-2.9.a libwxzlib.a PATHS ${wxWidgets_ROOT_DIR}/lib/ PATH_SUFFIXES gcc_dll DOC "location of wxzlib library file")
endif(ZLIB_FOUND) endif(ZLIB_FOUND)

View File

@ -96,6 +96,7 @@ set(PCBNEW_SRCS
dist.cpp dist.cpp
dragsegm.cpp dragsegm.cpp
drc.cpp drc.cpp
drc_marker_functions.cpp
edgemod.cpp edgemod.cpp
edit.cpp edit.cpp
editedge.cpp editedge.cpp

View File

@ -697,7 +697,7 @@ void MODULE::Set_Rectangle_Encadrement()
*/ */
for( D_PAD* pad = m_Pads; pad; pad = pad->Next() ) for( D_PAD* pad = m_Pads; pad; pad = pad->Next() )
{ {
rayon = pad->m_Rayon; rayon = pad->m_ShapeMaxRadius;
cx = pad->m_Pos0.x; cx = pad->m_Pos0.x;
cy = pad->m_Pos0.y; cy = pad->m_Pos0.y;
xmin = MIN( xmin, cx - rayon ); xmin = MIN( xmin, cx - rayon );

View File

@ -44,7 +44,7 @@ D_PAD::D_PAD( MODULE* parent ) : BOARD_CONNECTED_ITEM( parent, TYPE_PAD )
SetSubRatsnest( 0 ); // used in ratsnest SetSubRatsnest( 0 ); // used in ratsnest
// calculations // calculations
ComputeRayon(); ComputeShapeMaxRadius();
} }
@ -53,25 +53,33 @@ D_PAD::~D_PAD()
} }
/* Calculate the radius of the pad. /* Calculate the radius of the circle containing the pad.
*/ */
void D_PAD::ComputeRayon() void D_PAD::ComputeShapeMaxRadius()
{ {
switch( m_PadShape & 0x7F ) switch( m_PadShape & 0x7F )
{ {
case PAD_CIRCLE: case PAD_CIRCLE:
m_Rayon = m_Size.x / 2; m_ShapeMaxRadius = m_Size.x / 2;
break; break;
case PAD_OVAL: case PAD_OVAL:
m_Rayon = MAX( m_Size.x, m_Size.y ) / 2; m_ShapeMaxRadius = MAX( m_Size.x, m_Size.y ) / 2;
break; break;
case PAD_RECT: case PAD_RECT:
case PAD_TRAPEZOID: m_ShapeMaxRadius = 1 + (int) ( sqrt( (double) m_Size.y * m_Size.y
m_Rayon = (int) ( sqrt( (double) m_Size.y * m_Size.y
+ (double) m_Size.x * m_Size.x ) / 2 ); + (double) m_Size.x * m_Size.x ) / 2 );
break; break;
case PAD_TRAPEZOID:
{ wxSize fullsize = m_Size;
fullsize.x += ABS(m_DeltaSize.y); // Remember: m_DeltaSize.y is the m_Size.x change
fullsize.y += ABS(m_DeltaSize.x); // Remember: m_DeltaSize.x is the m_Size.y change
m_ShapeMaxRadius = 1 + (int) ( sqrt( (double) m_Size.y * m_Size.y
+ (double) m_Size.x * m_Size.x ) / 2 );
}
break;
} }
} }
@ -84,11 +92,11 @@ void D_PAD::ComputeRayon()
EDA_Rect D_PAD::GetBoundingBox() EDA_Rect D_PAD::GetBoundingBox()
{ {
// Calculate area: // Calculate area:
ComputeRayon(); // calculate the radius of the area, considered as a ComputeShapeMaxRadius(); // calculate the radius of the area, considered as a
// circle // circle
EDA_Rect area; EDA_Rect area;
area.SetOrigin( m_Pos ); area.SetOrigin( m_Pos );
area.Inflate( m_Rayon, m_Rayon ); area.Inflate( m_ShapeMaxRadius, m_ShapeMaxRadius );
return area; return area;
} }
@ -185,7 +193,7 @@ void D_PAD::Copy( D_PAD* source )
m_Size = source->m_Size; m_Size = source->m_Size;
m_DeltaSize = source->m_DeltaSize; m_DeltaSize = source->m_DeltaSize;
m_Pos0 = source->m_Pos0; m_Pos0 = source->m_Pos0;
m_Rayon = source->m_Rayon; m_ShapeMaxRadius = source->m_ShapeMaxRadius;
m_PadShape = source->m_PadShape; m_PadShape = source->m_PadShape;
m_Attribut = source->m_Attribut; m_Attribut = source->m_Attribut;
m_Orient = source->m_Orient; m_Orient = source->m_Orient;
@ -401,7 +409,7 @@ int D_PAD::ReadDescr( FILE* File, int* LineNum )
m_PadShape = PAD_TRAPEZOID; break; m_PadShape = PAD_TRAPEZOID; break;
} }
ComputeRayon(); ComputeShapeMaxRadius();
break; break;
case 'D': case 'D':
@ -766,7 +774,7 @@ bool D_PAD::HitTest( const wxPoint& ref_pos )
deltaY = ref_pos.y - shape_pos.y; deltaY = ref_pos.y - shape_pos.y;
/* Quick test: a test point must be inside the circle. */ /* Quick test: a test point must be inside the circle. */
if( ( abs( deltaX ) > m_Rayon ) || ( abs( deltaY ) > m_Rayon ) ) if( ( abs( deltaX ) > m_ShapeMaxRadius ) || ( abs( deltaY ) > m_ShapeMaxRadius ) )
return false; return false;
dx = m_Size.x >> 1; // dx also is the radius for rounded pads dx = m_Size.x >> 1; // dx also is the radius for rounded pads

View File

@ -95,7 +95,7 @@ public:
wxPoint m_Pos0; // Initial Pad position (i.e. pas position relative to the module anchor, orientation 0 wxPoint m_Pos0; // Initial Pad position (i.e. pas position relative to the module anchor, orientation 0
int m_Rayon; // radius of pad circle int m_ShapeMaxRadius; // radius of the circle containing the pad shape
int m_Attribut; // NORMAL, PAD_SMD, PAD_CONN int m_Attribut; // NORMAL, PAD_SMD, PAD_CONN
int m_Orient; // in 1/10 degrees int m_Orient; // in 1/10 degrees
static int m_PadSketchModePenSize; // Pen size used to draw pads in sketch mode static int m_PadSketchModePenSize; // Pen size used to draw pads in sketch mode
@ -252,7 +252,7 @@ public:
void SetPadName( const wxString& name ); // Change pad name void SetPadName( const wxString& name ); // Change pad name
wxString ReturnStringPadName(); // Return pad name as string in a wxString wxString ReturnStringPadName(); // Return pad name as string in a wxString
void ReturnStringPadName( wxString& text ); // Return pad name as string in a buffer void ReturnStringPadName( wxString& text ); // Return pad name as string in a buffer
void ComputeRayon(); // compute radius void ComputeShapeMaxRadius(); // compute radius
const wxPoint ReturnShapePos(); const wxPoint ReturnShapePos();

View File

@ -647,7 +647,7 @@ void DIALOG_PAD_PROPERTIES::PadPropertiesAccept( wxCommandEvent& event )
m_CurrentPad->m_LocalSolderPasteMargin = g_Pad_Master.m_LocalSolderPasteMargin; m_CurrentPad->m_LocalSolderPasteMargin = g_Pad_Master.m_LocalSolderPasteMargin;
m_CurrentPad->m_LocalSolderPasteMarginRatio = g_Pad_Master.m_LocalSolderPasteMarginRatio; m_CurrentPad->m_LocalSolderPasteMarginRatio = g_Pad_Master.m_LocalSolderPasteMarginRatio;
m_CurrentPad->ComputeRayon(); m_CurrentPad->ComputeShapeMaxRadius();
Module->Set_Rectangle_Encadrement(); Module->Set_Rectangle_Encadrement();
m_CurrentPad->DisplayInfo( m_Parent ); m_CurrentPad->DisplayInfo( m_Parent );

View File

@ -2,7 +2,7 @@
/* /*
* This program source code file is part of KICAD, a free EDA CAD application. * This program source code file is part of KICAD, a free EDA CAD application.
* *
* Copyright (C) 2004-2007 Jean-Pierre Charras, jean-pierre.charras@inpg.fr * Copyright (C) 2004-2007 Jean-Pierre Charras, jean-pierre.charras@gipsa-lab.inpg.fr
* Copyright (C) 2007 Dick Hollenbeck, dick@softplc.com * Copyright (C) 2007 Dick Hollenbeck, dick@softplc.com
* Copyright (C) 2007 Kicad Developers, see change_log.txt for contributors. * Copyright (C) 2007 Kicad Developers, see change_log.txt for contributors.
* *
@ -24,7 +24,6 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/ */
/****************************/ /****************************/
/* DRC control */ /* DRC control */
/****************************/ /****************************/
@ -94,7 +93,6 @@ void DRC::DestroyDialog( int aReason )
DRC::DRC( WinEDA_PcbFrame* aPcbWindow ) DRC::DRC( WinEDA_PcbFrame* aPcbWindow )
{ {
m_mainWindow = aPcbWindow; m_mainWindow = aPcbWindow;
m_drawPanel = aPcbWindow->DrawPanel;
m_pcb = aPcbWindow->GetBoard(); m_pcb = aPcbWindow->GetBoard();
m_ui = 0; m_ui = 0;
@ -116,8 +114,6 @@ DRC::DRC( WinEDA_PcbFrame* aPcbWindow )
m_ycliplo = 0; m_ycliplo = 0;
m_xcliphi = 0; m_xcliphi = 0;
m_ycliphi = 0; m_ycliphi = 0;
m_drawPanel = 0;
} }
@ -288,13 +284,11 @@ void DRC::ListUnconnectedPads()
void DRC::updatePointers() void DRC::updatePointers()
{ {
// update my pointers, m_mainWindow is the only unchangable one // update my pointers, m_mainWindow is the only unchangable one
m_drawPanel = m_mainWindow->DrawPanel;
m_pcb = m_mainWindow->GetBoard(); m_pcb = m_mainWindow->GetBoard();
if( m_ui ) // Use diag list boxes only in DRC dialog if( m_ui ) // Use diag list boxes only in DRC dialog
{ {
m_ui->m_ClearanceListBox->SetList( new DRC_LIST_MARKERS( m_pcb ) ); m_ui->m_ClearanceListBox->SetList( new DRC_LIST_MARKERS( m_pcb ) );
m_ui->m_UnconnectedListBox->SetList( new DRC_LIST_UNCONNECTED( &m_unconnected ) ); m_ui->m_UnconnectedListBox->SetList( new DRC_LIST_UNCONNECTED( &m_unconnected ) );
} }
} }
@ -450,8 +444,8 @@ void DRC::testPad2Pad()
{ {
D_PAD* pad = sortedPads[i]; D_PAD* pad = sortedPads[i];
if( pad->m_Rayon > max_size ) // m_Rayon is the radius value of the circle containing the pad if( pad->m_ShapeMaxRadius > max_size ) // m_ShapeMaxRadius is the radius value of the circle containing the pad
max_size = pad->m_Rayon; max_size = pad->m_ShapeMaxRadius;
} }
// Test the pads // Test the pads
@ -462,7 +456,7 @@ void DRC::testPad2Pad()
D_PAD* pad = sortedPads[i]; D_PAD* pad = sortedPads[i];
int x_limit = max_size + pad->GetClearance() + int x_limit = max_size + pad->GetClearance() +
pad->m_Rayon + pad->GetPosition().x; pad->m_ShapeMaxRadius + pad->GetPosition().x;
if( !doPadToPadsDrc( pad, &sortedPads[i], listEnd, x_limit ) ) if( !doPadToPadsDrc( pad, &sortedPads[i], listEnd, x_limit ) )
{ {
@ -558,137 +552,6 @@ void DRC::testZones( bool adoTestFillSegments )
} }
MARKER_PCB* DRC::fillMarker( TRACK* aTrack, BOARD_ITEM* aItem, int aErrorCode, MARKER_PCB* fillMe )
{
wxString textA = aTrack->MenuText( m_pcb );
wxString textB;
wxPoint position;
wxPoint posB;
if( aItem ) // aItem might be NULL
{
textB = aItem->MenuText( m_pcb );
posB = aItem->GetPosition();
if( aItem->Type() == TYPE_PAD )
position = aItem->GetPosition();
else if( aItem->Type() == TYPE_VIA )
position = aItem->GetPosition();
else if( aItem->Type() == TYPE_TRACK )
{
TRACK* track = (TRACK*) aItem;
wxPoint endPos = track->m_End;
// either of aItem's start or end will be used for the marker position
// first assume start, then switch at end if needed. decision made on
// distance from end of aTrack.
position = track->m_Start;
double dToEnd = hypot( endPos.x - aTrack->m_End.x,
endPos.y - aTrack->m_End.y );
double dToStart = hypot( position.x - aTrack->m_End.x,
position.y - aTrack->m_End.y );
if( dToEnd < dToStart )
position = endPos;
}
}
else
position = aTrack->GetPosition();
if( fillMe )
{
if( aItem )
fillMe->SetData( aErrorCode, position,
textA, aTrack->GetPosition(),
textB, posB );
else
fillMe->SetData( aErrorCode, position,
textA, aTrack->GetPosition() );
}
else
{
if( aItem )
fillMe = new MARKER_PCB( aErrorCode, position,
textA, aTrack->GetPosition(),
textB, posB );
else
fillMe = new MARKER_PCB( aErrorCode, position,
textA, aTrack->GetPosition() );
}
return fillMe;
}
MARKER_PCB* DRC::fillMarker( D_PAD* aPad, D_PAD* bPad, int aErrorCode, MARKER_PCB* fillMe )
{
wxString textA = aPad->MenuText( m_pcb );
wxString textB = bPad->MenuText( m_pcb );
wxPoint posA = aPad->GetPosition();
wxPoint posB = bPad->GetPosition();
if( fillMe )
fillMe->SetData( aErrorCode, posA, textA, posA, textB, posB );
else
fillMe = new MARKER_PCB( aErrorCode, posA, textA, posA, textB, posB );
return fillMe;
}
MARKER_PCB* DRC::fillMarker( ZONE_CONTAINER* aArea, int aErrorCode, MARKER_PCB* fillMe )
{
wxString textA = aArea->MenuText( m_pcb );
wxPoint posA = aArea->GetPosition();
if( fillMe )
fillMe->SetData( aErrorCode, posA, textA, posA );
else
fillMe = new MARKER_PCB( aErrorCode, posA, textA, posA );
return fillMe;
}
MARKER_PCB* DRC::fillMarker( const ZONE_CONTAINER* aArea,
const wxPoint& aPos,
int aErrorCode,
MARKER_PCB* fillMe )
{
wxString textA = aArea->MenuText( m_pcb );
wxPoint posA = aPos;
if( fillMe )
fillMe->SetData( aErrorCode, posA, textA, posA );
else
fillMe = new MARKER_PCB( aErrorCode, posA, textA, posA );
return fillMe;
}
MARKER_PCB* DRC::fillMarker( int aErrorCode, const wxString& aMessage, MARKER_PCB* fillMe )
{
wxPoint posA; // not displayed
if( fillMe )
fillMe->SetData( aErrorCode, posA, aMessage, posA );
else
fillMe = new MARKER_PCB( aErrorCode, posA, aMessage, posA );
fillMe->SetShowNoCoordinate();
return fillMe;
}
/***********************************************************************/ /***********************************************************************/
bool DRC::doTrackDrc( TRACK* aRefSeg, TRACK* aStart, bool testPads ) bool DRC::doTrackDrc( TRACK* aRefSeg, TRACK* aStart, bool testPads )
/***********************************************************************/ /***********************************************************************/
@ -801,11 +664,12 @@ bool DRC::doTrackDrc( TRACK* aRefSeg, TRACK* aStart, bool testPads )
/* Phase 1 : test DRC track to pads : */ /* Phase 1 : test DRC track to pads : */
/******************************************/ /******************************************/
D_PAD pseudo_pad( (MODULE*) NULL ); // construct this once outside following loop // Use a dummy pad to test DRC tracks versus holes, for pads not on all copper layers
// but having a hole
D_PAD dummypad( (MODULE*) NULL ); // construct this once outside following loop
dummypad.m_Masque_Layer = ALL_CU_LAYERS; // Ensure the hole is on all layers
// Compute the min distance to pads // Compute the min distance to pads
int refsegm_half_width = aRefSeg->m_Width >> 1;
if( testPads ) if( testPads )
{ {
for( unsigned ii = 0; ii<m_pcb->GetPadsCount(); ++ii ) for( unsigned ii = 0; ii<m_pcb->GetPadsCount(); ++ii )
@ -818,22 +682,21 @@ bool DRC::doTrackDrc( TRACK* aRefSeg, TRACK* aStart, bool testPads )
*/ */
if( (pad->m_Masque_Layer & layerMask ) == 0 ) if( (pad->m_Masque_Layer & layerMask ) == 0 )
{ {
/* We must test the pad hole. In order to use the function "checkClearanceSegmToPad", /* We must test the pad hole. In order to use the function checkClearanceSegmToPad(),
* a pseudo pad is used, with a shape and a size like the hole * a pseudo pad is used, with a shape and a size like the hole
*/ */
if( pad->m_Drill.x == 0 ) if( pad->m_Drill.x == 0 )
continue; continue;
pseudo_pad.m_Size = pad->m_Drill; dummypad.m_Size = pad->m_Drill;
pseudo_pad.SetPosition( pad->GetPosition() ); dummypad.SetPosition( pad->GetPosition() );
pseudo_pad.m_PadShape = pad->m_DrillShape; dummypad.m_PadShape = pad->m_DrillShape;
pseudo_pad.m_Orient = pad->m_Orient; dummypad.m_Orient = pad->m_Orient;
pseudo_pad.ComputeRayon(); // compute the radius dummypad.ComputeShapeMaxRadius(); // compute the radius of the circle containing this pad
m_padToTestPos.x = dummypad.GetPosition().x - origin.x;
m_padToTestPos.y = dummypad.GetPosition().y - origin.y;
m_padToTestPos.x = pseudo_pad.GetPosition().x - origin.x; if( !checkClearanceSegmToPad( &dummypad, aRefSeg->m_Width,
m_padToTestPos.y = pseudo_pad.GetPosition().y - origin.y;
if( !checkClearanceSegmToPad( &pseudo_pad, refsegm_half_width,
netclass->GetClearance() ) ) netclass->GetClearance() ) )
{ {
m_currentMarker = fillMarker( aRefSeg, pad, m_currentMarker = fillMarker( aRefSeg, pad,
@ -855,7 +718,7 @@ bool DRC::doTrackDrc( TRACK* aRefSeg, TRACK* aStart, bool testPads )
m_padToTestPos.x = shape_pos.x - origin.x; m_padToTestPos.x = shape_pos.x - origin.x;
m_padToTestPos.y = shape_pos.y - origin.y; m_padToTestPos.y = shape_pos.y - origin.y;
if( !checkClearanceSegmToPad( pad, refsegm_half_width, aRefSeg->GetClearance( pad ) ) ) if( !checkClearanceSegmToPad( pad, aRefSeg->m_Width, aRefSeg->GetClearance( pad ) ) )
{ {
m_currentMarker = fillMarker( aRefSeg, pad, m_currentMarker = fillMarker( aRefSeg, pad,
DRCE_TRACK_NEAR_PAD, m_currentMarker ); DRCE_TRACK_NEAR_PAD, m_currentMarker );
@ -1120,9 +983,16 @@ bool DRC::doPadToPadsDrc( D_PAD* aRefPad, LISTE_PAD* aStart, LISTE_PAD* aEnd,
{ {
int layerMask = aRefPad->m_Masque_Layer & ALL_CU_LAYERS; int layerMask = aRefPad->m_Masque_Layer & ALL_CU_LAYERS;
static D_PAD dummypad( (MODULE*) NULL ); // used to test DRC pad to holes: this dummypad is the hole to test // used to test DRC pad to holes: this dummypad is a pad hole to test
// pad to pad hole DRC, using pad to pad DRC test.
dummypad.m_Masque_Layer = ALL_CU_LAYERS; // this dummy pad is a circle or an oval.
static D_PAD dummypad( (MODULE*) NULL );
dummypad.m_Masque_Layer = ALL_CU_LAYERS; // za hole is on all layers
dummypad.m_LocalClearance = 1; /* Use the minimal local clerance value for the dummy pad
* the clearance of the active pad will be used
* as minimum distance to a hole
* (a value = 0 means use netclass value)
*/
for( LISTE_PAD* pad_list = aStart; pad_list<aEnd; ++pad_list ) for( LISTE_PAD* pad_list = aStart; pad_list<aEnd; ++pad_list )
{ {
@ -1159,8 +1029,9 @@ bool DRC::doPadToPadsDrc( D_PAD* aRefPad, LISTE_PAD* aStart, LISTE_PAD* aEnd,
{ {
dummypad.SetPosition( pad->GetPosition() ); dummypad.SetPosition( pad->GetPosition() );
dummypad.m_Size = pad->m_Drill; dummypad.m_Size = pad->m_Drill;
dummypad.m_PadShape = pad->m_DrillShape == PAD_OVAL ? PAD_OVAL : PAD_CIRCLE; dummypad.m_PadShape = (pad->m_DrillShape == PAD_OVAL) ? PAD_OVAL : PAD_CIRCLE;
dummypad.m_Orient = pad->m_Orient; dummypad.m_Orient = pad->m_Orient;
dummypad.ComputeShapeMaxRadius(); // compute the radius of the circle containing this pad
if( !checkClearancePadToPad( aRefPad, &dummypad ) ) if( !checkClearancePadToPad( aRefPad, &dummypad ) )
{ {
// here we have a drc error on pad! // here we have a drc error on pad!
@ -1174,8 +1045,9 @@ bool DRC::doPadToPadsDrc( D_PAD* aRefPad, LISTE_PAD* aStart, LISTE_PAD* aEnd,
{ {
dummypad.SetPosition( aRefPad->GetPosition() ); dummypad.SetPosition( aRefPad->GetPosition() );
dummypad.m_Size = aRefPad->m_Drill; dummypad.m_Size = aRefPad->m_Drill;
dummypad.m_PadShape = aRefPad->m_DrillShape == PAD_OVAL ? PAD_OVAL : PAD_CIRCLE; dummypad.m_PadShape = (aRefPad->m_DrillShape == PAD_OVAL) ? PAD_OVAL : PAD_CIRCLE;
dummypad.m_Orient = aRefPad->m_Orient; dummypad.m_Orient = aRefPad->m_Orient;
dummypad.ComputeShapeMaxRadius(); // compute the radius of the circle containing this pad
if( !checkClearancePadToPad( pad, &dummypad ) ) if( !checkClearancePadToPad( pad, &dummypad ) )
{ {
// here we have a drc erroron aRefPad! // here we have a drc erroron aRefPad!
@ -1187,6 +1059,7 @@ bool DRC::doPadToPadsDrc( D_PAD* aRefPad, LISTE_PAD* aStart, LISTE_PAD* aEnd,
continue; continue;
} }
// The pad must be in a net (i.e pt_pad->GetNet() != 0 ), // The pad must be in a net (i.e pt_pad->GetNet() != 0 ),
// But no problem if pads have the same netcode (same net) // But no problem if pads have the same netcode (same net)
if( pad->GetNet() && ( aRefPad->GetNet() == pad->GetNet() ) ) if( pad->GetNet() && ( aRefPad->GetNet() == pad->GetNet() ) )
@ -1229,28 +1102,29 @@ wxPoint rotate( wxPoint p, int angle )
} }
/* test DRC between 2 pads.
* this function can be also used to test DRC between a pas and a hole,
* because a hole is like a round pad.
*/
bool DRC::checkClearancePadToPad( D_PAD* aRefPad, D_PAD* aPad ) bool DRC::checkClearancePadToPad( D_PAD* aRefPad, D_PAD* aPad )
{ {
wxPoint rel_pos; int dist;
int dist;;
wxPoint shape_pos;
int pad_angle; int pad_angle;
// Get the clerance between the 2 pads. this is the min distance between aRefPad and aPad
int dist_min = aRefPad->GetClearance( aPad ); int dist_min = aRefPad->GetClearance( aPad );
rel_pos = aPad->ReturnShapePos(); // relativePadPos is the aPad shape position relative to the aRefPad shape position
shape_pos = aRefPad->ReturnShapePos(); wxPoint relativePadPos = aPad->ReturnShapePos() - aRefPad->ReturnShapePos();
// rel_pos is the aPad position relative to the aRefPad position dist = (int) hypot( relativePadPos.x, relativePadPos.y );
rel_pos -= shape_pos;
dist = (int) hypot( rel_pos.x, rel_pos.y );
// return true if clearance between aRefPad and aPad is >= dist_min, else false
bool diag = true; bool diag = true;
// Quick test: Clearance is OK if the bounding circles are further away than "dist_min" // Quick test: Clearance is OK if the bounding circles are further away than "dist_min"
if( (dist - aRefPad->m_Rayon - aPad->m_Rayon) >= dist_min ) if( (dist - aRefPad->m_ShapeMaxRadius - aPad->m_ShapeMaxRadius) >= dist_min )
goto exit; goto exit;
/* Here, pads are near and DRC depend on the pad shapes /* Here, pads are near and DRC depend on the pad shapes
@ -1268,7 +1142,7 @@ bool DRC::checkClearancePadToPad( D_PAD* aRefPad, D_PAD* aPad )
if( swap_pads ) if( swap_pads )
{ {
EXCHG( aRefPad, aPad ); EXCHG( aRefPad, aPad );
rel_pos = -rel_pos; relativePadPos = -relativePadPos;
} }
/* Because pad exchange, aRefPad shape is PAD_CIRCLE or PAD_OVAL, /* Because pad exchange, aRefPad shape is PAD_CIRCLE or PAD_OVAL,
@ -1278,20 +1152,22 @@ bool DRC::checkClearancePadToPad( D_PAD* aRefPad, D_PAD* aPad )
*/ */
switch( aRefPad->m_PadShape ) switch( aRefPad->m_PadShape )
{ {
case PAD_CIRCLE: // aRefPad is like a track segment with a null lenght case PAD_CIRCLE:
/* One can use checkClearanceSegmToPad to test clearance
* aRefPad is like a track segment with a null lenght and a witdth = m_Size.x
*/
m_segmLength = 0; m_segmLength = 0;
m_segmAngle = 0; m_segmAngle = 0;
m_segmEnd.x = m_segmEnd.y = 0; m_segmEnd.x = m_segmEnd.y = 0;
m_padToTestPos.x = rel_pos.x; m_padToTestPos.x = relativePadPos.x;
m_padToTestPos.y = rel_pos.y; m_padToTestPos.y = relativePadPos.y;
diag = checkClearanceSegmToPad( aPad, aRefPad->m_Size.x, dist_min );
diag = checkClearanceSegmToPad( aPad, aRefPad->m_Rayon, dist_min );
break; break;
case PAD_RECT: case PAD_RECT:
RotatePoint( &rel_pos, aRefPad->m_Orient ); RotatePoint( &relativePadPos, aRefPad->m_Orient );
// pad_angle = pad orient relative to the aRefPad orient // pad_angle = pad orient relative to the aRefPad orient
pad_angle = aRefPad->m_Orient + aPad->m_Orient; pad_angle = aRefPad->m_Orient + aPad->m_Orient;
@ -1315,13 +1191,13 @@ bool DRC::checkClearancePadToPad( D_PAD* aRefPad, D_PAD* aPad )
// Test DRC: // Test DRC:
diag = false; diag = false;
rel_pos.x = ABS( rel_pos.x ); relativePadPos.x = ABS( relativePadPos.x );
rel_pos.y = ABS( rel_pos.y ); relativePadPos.y = ABS( relativePadPos.y );
if( ( rel_pos.x - ( (size.x + aRefPad->m_Size.x) / 2 ) ) >= dist_min ) if( ( relativePadPos.x - ( (size.x + aRefPad->m_Size.x) / 2 ) ) >= dist_min )
diag = true; diag = true;
if( ( rel_pos.y - ( (size.y + aRefPad->m_Size.y) / 2 ) ) >= dist_min ) if( ( relativePadPos.y - ( (size.y + aRefPad->m_Size.y) / 2 ) ) >= dist_min )
diag = true; diag = true;
} }
else // al least on pad has any other orient. Test is more tricky else // al least on pad has any other orient. Test is more tricky
@ -1420,7 +1296,7 @@ bool DRC::checkClearancePadToPad( D_PAD* aRefPad, D_PAD* aPad )
m_segmAngle += 900; m_segmAngle += 900;
} }
/* the start point must be 0,0 and currently rel_pos /* the start point must be 0,0 and currently relativePadPos
* is relative the center of pad coordinate */ * is relative the center of pad coordinate */
wxPoint segstart; wxPoint segstart;
segstart.x = -m_segmLength / 2; // Start point coordinate of the horizontal equivalent segment segstart.x = -m_segmLength / 2; // Start point coordinate of the horizontal equivalent segment
@ -1428,11 +1304,12 @@ bool DRC::checkClearancePadToPad( D_PAD* aRefPad, D_PAD* aPad )
RotatePoint( &segstart, m_segmAngle ); // True start point coordinate of the equivalent segment RotatePoint( &segstart, m_segmAngle ); // True start point coordinate of the equivalent segment
// move pad position relative to the segment origin // move pad position relative to the segment origin
m_padToTestPos = rel_pos - segstart; m_padToTestPos = relativePadPos - segstart;
// Calculate segment end // Calculate segment end
m_segmEnd.x = -2 * segstart.x; m_segmEnd.x = -2 * segstart.x;
m_segmEnd.y = -2 * segstart.y; // end of segment coordinate m_segmEnd.y = -2 * segstart.y; // end of segment coordinate
diag = checkClearanceSegmToPad( aPad, segm_width / 2, dist_min ); diag = checkClearanceSegmToPad( aPad, segm_width, dist_min );
break; break;
} }
@ -1448,7 +1325,11 @@ exit: // the only way out (hopefully) for simpler debugging
} }
bool DRC::checkClearanceSegmToPad( const D_PAD* pad_to_test, int w_segm, int aMinDist ) /* test if distance between a segment is > aMinDist
* segment start point is assumed in (0,0) and segment start point in m_segmEnd
* and have aSegmentWidth.
*/
bool DRC::checkClearanceSegmToPad( const D_PAD* aPad, int aSegmentWidth, int aMinDist )
{ {
wxSize padHalfsize; // half the dimension of the pad wxSize padHalfsize; // half the dimension of the pad
int orient; int orient;
@ -1456,20 +1337,27 @@ bool DRC::checkClearanceSegmToPad( const D_PAD* pad_to_test, int w_segm, int aMi
int seuil; int seuil;
int deltay; int deltay;
seuil = w_segm + aMinDist; int segmHalfWidth = aSegmentWidth / 2;
padHalfsize.x = pad_to_test->m_Size.x >> 1; seuil = segmHalfWidth + aMinDist;
padHalfsize.y = pad_to_test->m_Size.y >> 1; padHalfsize.x = aPad->m_Size.x >> 1;
padHalfsize.y = aPad->m_Size.y >> 1;
if( pad_to_test->m_PadShape == PAD_CIRCLE ) if( aPad->m_PadShape == PAD_CIRCLE )
{ {
/* calcul des coord centre du pad dans le repere axe X confondu /* Easy case: just test the distance between segment and pad centre
* avec le segment en tst */ * calculate pad coordinates in the X,Y axis with X axis = segment to test
*/
RotatePoint( &m_padToTestPos.x, &m_padToTestPos.y, m_segmAngle ); RotatePoint( &m_padToTestPos.x, &m_padToTestPos.y, m_segmAngle );
return checkMarginToCircle( m_padToTestPos.x, m_padToTestPos.y, seuil + padHalfsize.x, m_segmLength ); return checkMarginToCircle( m_padToTestPos.x, m_padToTestPos.y,
seuil + padHalfsize.x, m_segmLength );
} }
else else
{ {
/* calcul de la "surface de securite" du pad de reference */ /* calculate the bounding box of the pad, including the clearance and the segment width
* if the line from 0 to m_segmEnd does not intersect this bounding box,
* the clearance is always OK
* But if intersect, a better analysis of the pad shape must be done.
*/
m_xcliplo = m_padToTestPos.x - seuil - padHalfsize.x; m_xcliplo = m_padToTestPos.x - seuil - padHalfsize.x;
m_ycliplo = m_padToTestPos.y - seuil - padHalfsize.y; m_ycliplo = m_padToTestPos.y - seuil - padHalfsize.y;
m_xcliphi = m_padToTestPos.x + seuil + padHalfsize.x; m_xcliphi = m_padToTestPos.x + seuil + padHalfsize.x;
@ -1480,7 +1368,7 @@ bool DRC::checkClearanceSegmToPad( const D_PAD* pad_to_test, int w_segm, int aMi
xf = m_segmEnd.x; xf = m_segmEnd.x;
yf = m_segmEnd.y; yf = m_segmEnd.y;
orient = pad_to_test->m_Orient; orient = aPad->m_Orient;
RotatePoint( &x0, &y0, m_padToTestPos.x, m_padToTestPos.y, -orient ); RotatePoint( &x0, &y0, m_padToTestPos.x, m_padToTestPos.y, -orient );
RotatePoint( &xf, &yf, m_padToTestPos.x, m_padToTestPos.y, -orient ); RotatePoint( &xf, &yf, m_padToTestPos.x, m_padToTestPos.y, -orient );
@ -1488,15 +1376,19 @@ bool DRC::checkClearanceSegmToPad( const D_PAD* pad_to_test, int w_segm, int aMi
if( checkLine( x0, y0, xf, yf ) ) if( checkLine( x0, y0, xf, yf ) )
return true; return true;
/* Erreur DRC : analyse fine de la forme de la pastille */ /* segment intersects the bounding box. But there is not always a DRC error.
* A fine analysis of the pad shape must be done.
switch( pad_to_test->m_PadShape ) */
switch( aPad->m_PadShape )
{ {
default: default:
return false; return false;
case PAD_OVAL: case PAD_OVAL:
/* test de la pastille ovale ramenee au type ovale vertical */ /* an oval is a complex shape, but is a rectangle and 2 circles
* these 3 basic shapes are more easy to test.
*/
/* We use a vertical oval shape. for horizontal ovals, swap x and y size and rotate the shape*/
if( padHalfsize.x > padHalfsize.y ) if( padHalfsize.x > padHalfsize.y )
{ {
EXCHG( padHalfsize.x, padHalfsize.y ); EXCHG( padHalfsize.x, padHalfsize.y );
@ -1506,28 +1398,30 @@ bool DRC::checkClearanceSegmToPad( const D_PAD* pad_to_test, int w_segm, int aMi
} }
deltay = padHalfsize.y - padHalfsize.x; deltay = padHalfsize.y - padHalfsize.x;
/* ici: padHalfsize.x = rayon, // ici: padHalfsize.x = rayon, delta = dist centre cercles a centre pad
* delta = dist centre cercles a centre pad */
/* Test du rectangle separant les 2 demi cercles */ // Test the rectangle area between the two circles
m_xcliplo = m_padToTestPos.x - seuil - padHalfsize.x; m_xcliplo = m_padToTestPos.x - seuil - padHalfsize.x;
m_ycliplo = m_padToTestPos.y - w_segm - deltay; m_ycliplo = m_padToTestPos.y - segmHalfWidth - deltay;
m_xcliphi = m_padToTestPos.x + seuil + padHalfsize.x; m_xcliphi = m_padToTestPos.x + seuil + padHalfsize.x;
m_ycliphi = m_padToTestPos.y + w_segm + deltay; m_ycliphi = m_padToTestPos.y + segmHalfWidth + deltay;
if( !checkLine( x0, y0, xf, yf ) ) if( !checkLine( x0, y0, xf, yf ) )
return false; return false;
/* test des 2 cercles */ // test the first circle
x0 = m_padToTestPos.x; /* x0,y0 = centre du cercle superieur du pad ovale */ x0 = m_padToTestPos.x; // x0,y0 = centre of the upper circle of the oval shape
y0 = m_padToTestPos.y + deltay; y0 = m_padToTestPos.y + deltay;
RotatePoint( &x0, &y0, m_padToTestPos.x, m_padToTestPos.y, orient );
RotatePoint( &x0, &y0, m_segmAngle );
// Calculate the actual position of the circle, given the pad orientation:
RotatePoint( &x0, &y0, m_padToTestPos.x, m_padToTestPos.y, orient );
// Calculate the actual position of the circle in the new X,Y axis:
RotatePoint( &x0, &y0, m_segmAngle );
if( !checkMarginToCircle( x0, y0, padHalfsize.x + seuil, m_segmLength ) ) if( !checkMarginToCircle( x0, y0, padHalfsize.x + seuil, m_segmLength ) )
return false; return false;
x0 = m_padToTestPos.x; /* x0,y0 = centre du cercle inferieur du pad ovale */ // test the second circle
x0 = m_padToTestPos.x; // x0,y0 = centre of the lower circle of the oval shape
y0 = m_padToTestPos.y - deltay; y0 = m_padToTestPos.y - deltay;
RotatePoint( &x0, &y0, m_padToTestPos.x, m_padToTestPos.y, orient ); RotatePoint( &x0, &y0, m_padToTestPos.x, m_padToTestPos.y, orient );
RotatePoint( &x0, &y0, m_segmAngle ); RotatePoint( &x0, &y0, m_segmAngle );

View File

@ -0,0 +1,172 @@
/*
* drc_marker_functions.cpp
*/
/*
* This program source code file is part of KICAD, a free EDA CAD application.
*
* Copyright (C) 2010 Dick Hollenbeck, dick@softplc.com
* Copyright (C) 2004-2010 Jean-Pierre Charras, jean-pierre.charras@gipsa-lab.inpg.fr
* Copyright (C) 2007 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
* 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
*/
/* Methods of class DRC to initialize drc markers with messages
* according to items and error ode
*/
#include "fctsys.h"
#include "common.h"
//#include "class_drawpanel.h"
#include "pcbnew.h"
//#include "wxPcbStruct.h"
#include "class_board_design_settings.h"
#include "drc_stuff.h"
MARKER_PCB* DRC::fillMarker( TRACK* aTrack, BOARD_ITEM* aItem, int aErrorCode, MARKER_PCB* fillMe )
{
wxString textA = aTrack->MenuText( m_pcb );
wxString textB;
wxPoint position;
wxPoint posB;
if( aItem ) // aItem might be NULL
{
textB = aItem->MenuText( m_pcb );
posB = aItem->GetPosition();
if( aItem->Type() == TYPE_PAD )
position = aItem->GetPosition();
else if( aItem->Type() == TYPE_VIA )
position = aItem->GetPosition();
else if( aItem->Type() == TYPE_TRACK )
{
TRACK* track = (TRACK*) aItem;
wxPoint endPos = track->m_End;
// either of aItem's start or end will be used for the marker position
// first assume start, then switch at end if needed. decision made on
// distance from end of aTrack.
position = track->m_Start;
double dToEnd = hypot( endPos.x - aTrack->m_End.x,
endPos.y - aTrack->m_End.y );
double dToStart = hypot( position.x - aTrack->m_End.x,
position.y - aTrack->m_End.y );
if( dToEnd < dToStart )
position = endPos;
}
}
else
position = aTrack->GetPosition();
if( fillMe )
{
if( aItem )
fillMe->SetData( aErrorCode, position,
textA, aTrack->GetPosition(),
textB, posB );
else
fillMe->SetData( aErrorCode, position,
textA, aTrack->GetPosition() );
}
else
{
if( aItem )
fillMe = new MARKER_PCB( aErrorCode, position,
textA, aTrack->GetPosition(),
textB, posB );
else
fillMe = new MARKER_PCB( aErrorCode, position,
textA, aTrack->GetPosition() );
}
return fillMe;
}
MARKER_PCB* DRC::fillMarker( D_PAD* aPad, D_PAD* bPad, int aErrorCode, MARKER_PCB* fillMe )
{
wxString textA = aPad->MenuText( m_pcb );
wxString textB = bPad->MenuText( m_pcb );
wxPoint posA = aPad->GetPosition();
wxPoint posB = bPad->GetPosition();
if( fillMe )
fillMe->SetData( aErrorCode, posA, textA, posA, textB, posB );
else
fillMe = new MARKER_PCB( aErrorCode, posA, textA, posA, textB, posB );
return fillMe;
}
MARKER_PCB* DRC::fillMarker( ZONE_CONTAINER* aArea, int aErrorCode, MARKER_PCB* fillMe )
{
wxString textA = aArea->MenuText( m_pcb );
wxPoint posA = aArea->GetPosition();
if( fillMe )
fillMe->SetData( aErrorCode, posA, textA, posA );
else
fillMe = new MARKER_PCB( aErrorCode, posA, textA, posA );
return fillMe;
}
MARKER_PCB* DRC::fillMarker( const ZONE_CONTAINER* aArea,
const wxPoint& aPos,
int aErrorCode,
MARKER_PCB* fillMe )
{
wxString textA = aArea->MenuText( m_pcb );
wxPoint posA = aPos;
if( fillMe )
fillMe->SetData( aErrorCode, posA, textA, posA );
else
fillMe = new MARKER_PCB( aErrorCode, posA, textA, posA );
return fillMe;
}
MARKER_PCB* DRC::fillMarker( int aErrorCode, const wxString& aMessage, MARKER_PCB* fillMe )
{
wxPoint posA; // not displayed
if( fillMe )
fillMe->SetData( aErrorCode, posA, aMessage, posA );
else
fillMe = new MARKER_PCB( aErrorCode, posA, aMessage, posA );
fillMe->SetShowNoCoordinate();
return fillMe;
}

View File

@ -179,7 +179,6 @@ private:
int m_ycliphi; int m_ycliphi;
WinEDA_PcbFrame* m_mainWindow; WinEDA_PcbFrame* m_mainWindow;
WinEDA_DrawPanel* m_drawPanel;
BOARD* m_pcb; BOARD* m_pcb;
DIALOG_DRC_CONTROL* m_ui; DIALOG_DRC_CONTROL* m_ui;
@ -306,7 +305,7 @@ private:
* Function checkClearancePadToPad * Function checkClearancePadToPad
* @param aRefPad The reference pad to check * @param aRefPad The reference pad to check
* @param aPad Another pad to check against * @param aPad Another pad to check against
* @return bool - true if clearance between aRefPad and pad is >= dist_min, else false * @return bool - true if clearance between aRefPad and aPad is >= dist_min, else false
*/ */
bool checkClearancePadToPad( D_PAD* aRefPad, D_PAD* aPad ); bool checkClearancePadToPad( D_PAD* aRefPad, D_PAD* aPad );
@ -315,18 +314,18 @@ private:
* Function checkClearanceSegmToPad * Function checkClearanceSegmToPad
* check the distance from a pad to segment. This function uses several * check the distance from a pad to segment. This function uses several
* instance variable not passed in: * instance variable not passed in:
* segmLength = length of the segment being tested * m_segmLength = length of the segment being tested
* segmAngle = angle d'inclinaison du segment; * m_segmAngle = angle of the segment with the X axis;
* finx, finy = end coordinate of the segment * m_segmEnd = end coordinate of the segment
* spot_cX, spot_cY = position of pad / origin of segment * m_padToTestPos = position of pad relative to the origin of segment
* @param pad_to_test Is the pad involved in the check * @param aPad Is the pad involved in the check
* @param w_segm Hhalf width of the segment to test * @param aSegmentWidth width of the segment to test
* @param dist_min Is the minimum clearance needed * @param aMinDist Is the minimum clearance needed
* *
* @return false distance >= dist_min, * @return true distance >= dist_min,
* true if distance < dist_min * false if distance < dist_min
*/ */
bool checkClearanceSegmToPad( const D_PAD* pad_to_test, int w_segm, int dist_min ); bool checkClearanceSegmToPad( const D_PAD* aPad, int aSegmentWidth, int aMinDist );
/** /**

View File

@ -4,17 +4,10 @@
#include "fctsys.h" #include "fctsys.h"
//#include "gr_basic.h"
#include "common.h" #include "common.h"
#include "class_drawpanel.h" #include "class_drawpanel.h"
#include "confirm.h" #include "confirm.h"
#include "pcbnew.h" #include "pcbnew.h"
//#include "trigo.h"
//#include "drag.h"
//#include "protos.h"
#include "dialog_global_pads_edition_base.h" #include "dialog_global_pads_edition_base.h"
@ -104,6 +97,8 @@ void DIALOG_GLOBAL_PADS_EDITION::PadPropertiesAccept( wxCommandEvent& event )
EndModal( returncode ); EndModal( returncode );
break; break;
} }
m_Parent->OnModify();
} }
@ -272,7 +267,7 @@ void WinEDA_BasePcbFrame::Global_Import_Pad_Settings( D_PAD* aPad, bool aDraw )
break; break;
} }
pt_pad->ComputeRayon(); pt_pad->ComputeShapeMaxRadius();
} }
Module->Set_Rectangle_Encadrement(); Module->Set_Rectangle_Encadrement();

View File

@ -110,7 +110,7 @@ void WinEDA_BasePcbFrame::Export_Pad_Settings( D_PAD* pt_pad )
( (MODULE*) pt_pad->GetParent() )->m_Orient; ( (MODULE*) pt_pad->GetParent() )->m_Orient;
g_Pad_Master.m_Size = pt_pad->m_Size; g_Pad_Master.m_Size = pt_pad->m_Size;
g_Pad_Master.m_DeltaSize = pt_pad->m_DeltaSize; g_Pad_Master.m_DeltaSize = pt_pad->m_DeltaSize;
pt_pad->ComputeRayon(); pt_pad->ComputeShapeMaxRadius();
g_Pad_Master.m_Offset = pt_pad->m_Offset; g_Pad_Master.m_Offset = pt_pad->m_Offset;
g_Pad_Master.m_Drill = pt_pad->m_Drill; g_Pad_Master.m_Drill = pt_pad->m_Drill;
@ -163,7 +163,7 @@ void WinEDA_BasePcbFrame::Import_Pad_Settings( D_PAD* aPad, bool aDraw )
aPad->m_Offset.y = 0; aPad->m_Offset.y = 0;
} }
aPad->ComputeRayon(); aPad->ComputeShapeMaxRadius();
if( aDraw ) if( aDraw )
DrawPanel->PostDirtyRect( aPad->GetBoundingBox() ); DrawPanel->PostDirtyRect( aPad->GetBoundingBox() );

View File

@ -265,7 +265,7 @@ MODULE* WinEDA_PcbFrame::Genere_Self( wxDC* DC )
PtPad->m_Masque_Layer = g_TabOneLayerMask[Module->GetLayer()]; PtPad->m_Masque_Layer = g_TabOneLayerMask[Module->GetLayer()];
PtPad->m_Attribut = PAD_SMD; PtPad->m_Attribut = PAD_SMD;
PtPad->m_PadShape = PAD_CIRCLE; PtPad->m_PadShape = PAD_CIRCLE;
PtPad->m_Rayon = PtPad->m_Size.x / 2; PtPad->ComputeShapeMaxRadius();
D_PAD* newpad = new D_PAD( Module ); D_PAD* newpad = new D_PAD( Module );
newpad->Copy( PtPad ); newpad->Copy( PtPad );