diff --git a/kicad/minizip/CMakeLists.txt b/kicad/minizip/CMakeLists.txt index 398836d159..ef45db842c 100644 --- a/kicad/minizip/CMakeLists.txt +++ b/kicad/minizip/CMakeLists.txt @@ -10,7 +10,7 @@ else(ZLIB_FOUND) # and we try to use it # 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. - 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") endif(ZLIB_FOUND) diff --git a/pcbnew/CMakeLists.txt b/pcbnew/CMakeLists.txt index db4387ba5e..9a2b8038b1 100644 --- a/pcbnew/CMakeLists.txt +++ b/pcbnew/CMakeLists.txt @@ -96,6 +96,7 @@ set(PCBNEW_SRCS dist.cpp dragsegm.cpp drc.cpp + drc_marker_functions.cpp edgemod.cpp edit.cpp editedge.cpp diff --git a/pcbnew/class_module.cpp b/pcbnew/class_module.cpp index d7ae2d2eaa..76d7420f92 100644 --- a/pcbnew/class_module.cpp +++ b/pcbnew/class_module.cpp @@ -697,7 +697,7 @@ void MODULE::Set_Rectangle_Encadrement() */ for( D_PAD* pad = m_Pads; pad; pad = pad->Next() ) { - rayon = pad->m_Rayon; + rayon = pad->m_ShapeMaxRadius; cx = pad->m_Pos0.x; cy = pad->m_Pos0.y; xmin = MIN( xmin, cx - rayon ); diff --git a/pcbnew/class_pad.cpp b/pcbnew/class_pad.cpp index 4b16269d97..0c0261094b 100644 --- a/pcbnew/class_pad.cpp +++ b/pcbnew/class_pad.cpp @@ -44,7 +44,7 @@ D_PAD::D_PAD( MODULE* parent ) : BOARD_CONNECTED_ITEM( parent, TYPE_PAD ) SetSubRatsnest( 0 ); // used in ratsnest // 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 ) { case PAD_CIRCLE: - m_Rayon = m_Size.x / 2; + m_ShapeMaxRadius = m_Size.x / 2; break; case PAD_OVAL: - m_Rayon = MAX( m_Size.x, m_Size.y ) / 2; + m_ShapeMaxRadius = MAX( m_Size.x, m_Size.y ) / 2; break; case PAD_RECT: - case PAD_TRAPEZOID: - m_Rayon = (int) ( sqrt( (double) m_Size.y * m_Size.y + m_ShapeMaxRadius = 1 + (int) ( sqrt( (double) m_Size.y * m_Size.y + (double) m_Size.x * m_Size.x ) / 2 ); 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() { // Calculate area: - ComputeRayon(); // calculate the radius of the area, considered as a + ComputeShapeMaxRadius(); // calculate the radius of the area, considered as a // circle EDA_Rect area; area.SetOrigin( m_Pos ); - area.Inflate( m_Rayon, m_Rayon ); + area.Inflate( m_ShapeMaxRadius, m_ShapeMaxRadius ); return area; } @@ -185,7 +193,7 @@ void D_PAD::Copy( D_PAD* source ) m_Size = source->m_Size; m_DeltaSize = source->m_DeltaSize; m_Pos0 = source->m_Pos0; - m_Rayon = source->m_Rayon; + m_ShapeMaxRadius = source->m_ShapeMaxRadius; m_PadShape = source->m_PadShape; m_Attribut = source->m_Attribut; m_Orient = source->m_Orient; @@ -401,7 +409,7 @@ int D_PAD::ReadDescr( FILE* File, int* LineNum ) m_PadShape = PAD_TRAPEZOID; break; } - ComputeRayon(); + ComputeShapeMaxRadius(); break; case 'D': @@ -766,7 +774,7 @@ bool D_PAD::HitTest( const wxPoint& ref_pos ) deltaY = ref_pos.y - shape_pos.y; /* 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; dx = m_Size.x >> 1; // dx also is the radius for rounded pads diff --git a/pcbnew/class_pad.h b/pcbnew/class_pad.h index 1a25802044..79803aea19 100644 --- a/pcbnew/class_pad.h +++ b/pcbnew/class_pad.h @@ -95,7 +95,7 @@ public: 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_Orient; // in 1/10 degrees 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 wxString ReturnStringPadName(); // Return pad name as string in a wxString void ReturnStringPadName( wxString& text ); // Return pad name as string in a buffer - void ComputeRayon(); // compute radius + void ComputeShapeMaxRadius(); // compute radius const wxPoint ReturnShapePos(); diff --git a/pcbnew/dialog_pad_properties.cpp b/pcbnew/dialog_pad_properties.cpp index 63110a20ea..2c8ba6a07a 100644 --- a/pcbnew/dialog_pad_properties.cpp +++ b/pcbnew/dialog_pad_properties.cpp @@ -647,7 +647,7 @@ void DIALOG_PAD_PROPERTIES::PadPropertiesAccept( wxCommandEvent& event ) m_CurrentPad->m_LocalSolderPasteMargin = g_Pad_Master.m_LocalSolderPasteMargin; m_CurrentPad->m_LocalSolderPasteMarginRatio = g_Pad_Master.m_LocalSolderPasteMarginRatio; - m_CurrentPad->ComputeRayon(); + m_CurrentPad->ComputeShapeMaxRadius(); Module->Set_Rectangle_Encadrement(); m_CurrentPad->DisplayInfo( m_Parent ); diff --git a/pcbnew/drc.cpp b/pcbnew/drc.cpp index 929e436449..8ea9b90709 100644 --- a/pcbnew/drc.cpp +++ b/pcbnew/drc.cpp @@ -2,7 +2,7 @@ /* * 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 Kicad Developers, see change_log.txt for contributors. * @@ -24,7 +24,6 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ - /****************************/ /* DRC control */ /****************************/ @@ -94,7 +93,6 @@ void DRC::DestroyDialog( int aReason ) DRC::DRC( WinEDA_PcbFrame* aPcbWindow ) { m_mainWindow = aPcbWindow; - m_drawPanel = aPcbWindow->DrawPanel; m_pcb = aPcbWindow->GetBoard(); m_ui = 0; @@ -116,8 +114,6 @@ DRC::DRC( WinEDA_PcbFrame* aPcbWindow ) m_ycliplo = 0; m_xcliphi = 0; m_ycliphi = 0; - - m_drawPanel = 0; } @@ -288,13 +284,11 @@ void DRC::ListUnconnectedPads() void DRC::updatePointers() { // update my pointers, m_mainWindow is the only unchangable one - m_drawPanel = m_mainWindow->DrawPanel; m_pcb = m_mainWindow->GetBoard(); 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_UnconnectedListBox->SetList( new DRC_LIST_UNCONNECTED( &m_unconnected ) ); } } @@ -450,8 +444,8 @@ void DRC::testPad2Pad() { D_PAD* pad = sortedPads[i]; - if( pad->m_Rayon > max_size ) // m_Rayon is the radius value of the circle containing the pad - max_size = pad->m_Rayon; + if( pad->m_ShapeMaxRadius > max_size ) // m_ShapeMaxRadius is the radius value of the circle containing the pad + max_size = pad->m_ShapeMaxRadius; } // Test the pads @@ -462,7 +456,7 @@ void DRC::testPad2Pad() D_PAD* pad = sortedPads[i]; 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 ) ) { @@ -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 ) /***********************************************************************/ @@ -801,11 +664,12 @@ bool DRC::doTrackDrc( TRACK* aRefSeg, TRACK* aStart, bool testPads ) /* 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 - int refsegm_half_width = aRefSeg->m_Width >> 1; - if( testPads ) { for( unsigned ii = 0; iiGetPadsCount(); ++ii ) @@ -818,22 +682,21 @@ bool DRC::doTrackDrc( TRACK* aRefSeg, TRACK* aStart, bool testPads ) */ 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 */ if( pad->m_Drill.x == 0 ) continue; - pseudo_pad.m_Size = pad->m_Drill; - pseudo_pad.SetPosition( pad->GetPosition() ); - pseudo_pad.m_PadShape = pad->m_DrillShape; - pseudo_pad.m_Orient = pad->m_Orient; - pseudo_pad.ComputeRayon(); // compute the radius + dummypad.m_Size = pad->m_Drill; + dummypad.SetPosition( pad->GetPosition() ); + dummypad.m_PadShape = pad->m_DrillShape; + dummypad.m_Orient = pad->m_Orient; + 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; - m_padToTestPos.y = pseudo_pad.GetPosition().y - origin.y; - - if( !checkClearanceSegmToPad( &pseudo_pad, refsegm_half_width, + if( !checkClearanceSegmToPad( &dummypad, aRefSeg->m_Width, netclass->GetClearance() ) ) { m_currentMarker = fillMarker( aRefSeg, pad, @@ -852,10 +715,10 @@ bool DRC::doTrackDrc( TRACK* aRefSeg, TRACK* aStart, bool testPads ) // DRC for the pad shape_pos = pad->ReturnShapePos(); - m_padToTestPos.x = shape_pos.x - origin.x; - m_padToTestPos.y = shape_pos.y - origin.y; + m_padToTestPos.x = shape_pos.x - origin.x; + 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, DRCE_TRACK_NEAR_PAD, m_currentMarker ); @@ -1118,11 +981,18 @@ bool DRC::doPadToPadsDrc( D_PAD* aRefPad, LISTE_PAD* aStart, LISTE_PAD* aEnd, int x_limit ) /*****************************************************************************/ { - 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 - - dummypad.m_Masque_Layer = ALL_CU_LAYERS; + // 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. + // 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_listm_DrillShape == PAD_CIRCLE ) continue; - if( pad->m_Orient == aRefPad->m_Orient ) // for oval holes: must also have the same orientation + if( pad->m_Orient == aRefPad->m_Orient ) // for oval holes: must also have the same orientation continue; } /* Here, we must test clearance between holes and pads * dummypad size and shape is adjusted to pad drill size and shape */ - if( pad->m_Drill.x ) // pad under testing has a hole, test this hole against pad reference + if( pad->m_Drill.x ) // pad under testing has a hole, test this hole against pad reference { dummypad.SetPosition( pad->GetPosition() ); 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.ComputeShapeMaxRadius(); // compute the radius of the circle containing this pad if( !checkClearancePadToPad( aRefPad, &dummypad ) ) { // 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.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.ComputeShapeMaxRadius(); // compute the radius of the circle containing this pad if( !checkClearancePadToPad( pad, &dummypad ) ) { // here we have a drc erroron aRefPad! @@ -1187,6 +1059,7 @@ bool DRC::doPadToPadsDrc( D_PAD* aRefPad, LISTE_PAD* aStart, LISTE_PAD* aEnd, continue; } + // The pad must be in a net (i.e pt_pad->GetNet() != 0 ), // But no problem if pads have the same netcode (same net) 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 ) { - wxPoint rel_pos; - int dist;; + int dist; - wxPoint shape_pos; 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 ); - rel_pos = aPad->ReturnShapePos(); - shape_pos = aRefPad->ReturnShapePos(); + // relativePadPos is the aPad shape position relative to the aRefPad shape position + wxPoint relativePadPos = aPad->ReturnShapePos() - aRefPad->ReturnShapePos(); - // rel_pos is the aPad position relative to the aRefPad position - rel_pos -= shape_pos; - - dist = (int) hypot( rel_pos.x, rel_pos.y ); + dist = (int) hypot( relativePadPos.x, relativePadPos.y ); + // return true if clearance between aRefPad and aPad is >= dist_min, else false bool diag = true; // 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; /* 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 ) { EXCHG( aRefPad, aPad ); - rel_pos = -rel_pos; + relativePadPos = -relativePadPos; } /* 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 ) { - 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_segmAngle = 0; m_segmEnd.x = m_segmEnd.y = 0; - m_padToTestPos.x = rel_pos.x; - m_padToTestPos.y = rel_pos.y; - - diag = checkClearanceSegmToPad( aPad, aRefPad->m_Rayon, dist_min ); + m_padToTestPos.x = relativePadPos.x; + m_padToTestPos.y = relativePadPos.y; + diag = checkClearanceSegmToPad( aPad, aRefPad->m_Size.x, dist_min ); break; 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 = aRefPad->m_Orient + aPad->m_Orient; @@ -1315,13 +1191,13 @@ bool DRC::checkClearancePadToPad( D_PAD* aRefPad, D_PAD* aPad ) // Test DRC: diag = false; - rel_pos.x = ABS( rel_pos.x ); - rel_pos.y = ABS( rel_pos.y ); + relativePadPos.x = ABS( relativePadPos.x ); + 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; - 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; } else // al least on pad has any other orient. Test is more tricky @@ -1405,10 +1281,10 @@ bool DRC::checkClearancePadToPad( D_PAD* aRefPad, D_PAD* aPad ) { /* Create a track segment with same dimensions as the oval aRefPad * and use checkClearanceSegmToPad function to test aPad to aRefPad clearance - */ + */ int segm_width; - m_segmAngle = aRefPad->m_Orient; // Segment orient. - if( aRefPad->m_Size.y < aRefPad->m_Size.x ) // Build an horizontal equiv segment + m_segmAngle = aRefPad->m_Orient; // Segment orient. + if( aRefPad->m_Size.y < aRefPad->m_Size.x ) // Build an horizontal equiv segment { segm_width = aRefPad->m_Size.y; m_segmLength = aRefPad->m_Size.x - aRefPad->m_Size.y; @@ -1420,19 +1296,20 @@ bool DRC::checkClearancePadToPad( D_PAD* aRefPad, D_PAD* aPad ) 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 */ 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 - 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 - m_padToTestPos = rel_pos - segstart; + m_padToTestPos = relativePadPos - segstart; + // Calculate segment end m_segmEnd.x = -2 * segstart.x; 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; } @@ -1448,28 +1325,39 @@ 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 - int orient; - int x0, y0, xf, yf; - int seuil; - int deltay; + int orient; + int x0, y0, xf, yf; + int seuil; + int deltay; - seuil = w_segm + aMinDist; - padHalfsize.x = pad_to_test->m_Size.x >> 1; - padHalfsize.y = pad_to_test->m_Size.y >> 1; + int segmHalfWidth = aSegmentWidth / 2; + seuil = segmHalfWidth + aMinDist; + 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 - * avec le segment en tst */ + /* Easy case: just test the distance between segment and pad centre + * calculate pad coordinates in the X,Y axis with X axis = segment to test + */ 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 { - /* 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_ycliplo = m_padToTestPos.y - seuil - padHalfsize.y; 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; 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( &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 ) ) return true; - /* Erreur DRC : analyse fine de la forme de la pastille */ - - switch( pad_to_test->m_PadShape ) + /* segment intersects the bounding box. But there is not always a DRC error. + * A fine analysis of the pad shape must be done. + */ + switch( aPad->m_PadShape ) { default: return false; 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 ) { 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; - /* ici: padHalfsize.x = rayon, - * delta = dist centre cercles a centre pad */ + // ici: padHalfsize.x = rayon, 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_ycliplo = m_padToTestPos.y - w_segm - deltay; + m_ycliplo = m_padToTestPos.y - segmHalfWidth - deltay; 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 ) ) return false; - /* test des 2 cercles */ - x0 = m_padToTestPos.x; /* x0,y0 = centre du cercle superieur du pad ovale */ + // test the first circle + x0 = m_padToTestPos.x; // x0,y0 = centre of the upper circle of the oval shape 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 ) ) 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; RotatePoint( &x0, &y0, m_padToTestPos.x, m_padToTestPos.y, orient ); RotatePoint( &x0, &y0, m_segmAngle ); diff --git a/pcbnew/drc_marker_functions.cpp b/pcbnew/drc_marker_functions.cpp new file mode 100644 index 0000000000..37087584c4 --- /dev/null +++ b/pcbnew/drc_marker_functions.cpp @@ -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; +} + diff --git a/pcbnew/drc_stuff.h b/pcbnew/drc_stuff.h index c7f679de83..53b282bacc 100644 --- a/pcbnew/drc_stuff.h +++ b/pcbnew/drc_stuff.h @@ -179,7 +179,6 @@ private: int m_ycliphi; WinEDA_PcbFrame* m_mainWindow; - WinEDA_DrawPanel* m_drawPanel; BOARD* m_pcb; DIALOG_DRC_CONTROL* m_ui; @@ -306,7 +305,7 @@ private: * Function checkClearancePadToPad * @param aRefPad The reference pad to check * @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 ); @@ -315,18 +314,18 @@ private: * Function checkClearanceSegmToPad * check the distance from a pad to segment. This function uses several * instance variable not passed in: - * segmLength = length of the segment being tested - * segmAngle = angle d'inclinaison du segment; - * finx, finy = end coordinate of the segment - * spot_cX, spot_cY = position of pad / origin of segment - * @param pad_to_test Is the pad involved in the check - * @param w_segm Hhalf width of the segment to test - * @param dist_min Is the minimum clearance needed + * m_segmLength = length of the segment being tested + * m_segmAngle = angle of the segment with the X axis; + * m_segmEnd = end coordinate of the segment + * m_padToTestPos = position of pad relative to the origin of segment + * @param aPad Is the pad involved in the check + * @param aSegmentWidth width of the segment to test + * @param aMinDist Is the minimum clearance needed * - * @return false distance >= dist_min, - * true if distance < dist_min + * @return true 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 ); /** diff --git a/pcbnew/globaleditpad.cpp b/pcbnew/globaleditpad.cpp index d6e3f9727a..f805c89863 100644 --- a/pcbnew/globaleditpad.cpp +++ b/pcbnew/globaleditpad.cpp @@ -4,17 +4,10 @@ #include "fctsys.h" -//#include "gr_basic.h" #include "common.h" #include "class_drawpanel.h" #include "confirm.h" #include "pcbnew.h" - -//#include "trigo.h" - -//#include "drag.h" - -//#include "protos.h" #include "dialog_global_pads_edition_base.h" @@ -104,6 +97,8 @@ void DIALOG_GLOBAL_PADS_EDITION::PadPropertiesAccept( wxCommandEvent& event ) EndModal( returncode ); break; } + + m_Parent->OnModify(); } @@ -272,7 +267,7 @@ void WinEDA_BasePcbFrame::Global_Import_Pad_Settings( D_PAD* aPad, bool aDraw ) break; } - pt_pad->ComputeRayon(); + pt_pad->ComputeShapeMaxRadius(); } Module->Set_Rectangle_Encadrement(); diff --git a/pcbnew/move-drag_pads.cpp b/pcbnew/move-drag_pads.cpp index 78b16dd851..6e4f9e7f06 100644 --- a/pcbnew/move-drag_pads.cpp +++ b/pcbnew/move-drag_pads.cpp @@ -110,7 +110,7 @@ void WinEDA_BasePcbFrame::Export_Pad_Settings( D_PAD* pt_pad ) ( (MODULE*) pt_pad->GetParent() )->m_Orient; g_Pad_Master.m_Size = pt_pad->m_Size; 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_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->ComputeRayon(); + aPad->ComputeShapeMaxRadius(); if( aDraw ) DrawPanel->PostDirtyRect( aPad->GetBoundingBox() ); @@ -234,7 +234,7 @@ void WinEDA_BasePcbFrame::AddPad( MODULE* Module, bool draw ) void WinEDA_BasePcbFrame::DeletePad( D_PAD* aPad, bool aQuery ) { MODULE* Module; - + if( aPad == NULL ) return; diff --git a/pcbnew/muonde.cpp b/pcbnew/muonde.cpp index 10773ed894..a660fbb205 100644 --- a/pcbnew/muonde.cpp +++ b/pcbnew/muonde.cpp @@ -265,7 +265,7 @@ MODULE* WinEDA_PcbFrame::Genere_Self( wxDC* DC ) PtPad->m_Masque_Layer = g_TabOneLayerMask[Module->GetLayer()]; PtPad->m_Attribut = PAD_SMD; PtPad->m_PadShape = PAD_CIRCLE; - PtPad->m_Rayon = PtPad->m_Size.x / 2; + PtPad->ComputeShapeMaxRadius(); D_PAD* newpad = new D_PAD( Module ); newpad->Copy( PtPad );