diff --git a/pcbnew/convert_drawsegment_list_to_polygon.cpp b/pcbnew/convert_drawsegment_list_to_polygon.cpp index a60fa37801..5805b73221 100644 --- a/pcbnew/convert_drawsegment_list_to_polygon.cpp +++ b/pcbnew/convert_drawsegment_list_to_polygon.cpp @@ -750,6 +750,7 @@ bool BuildBoardPolygonOutlines( BOARD* aBoard, SHAPE_POLY_SET& aOutlines, wxString* aErrorText, unsigned int aTolerance, wxPoint* aErrorLocation ) { PCB_TYPE_COLLECTOR items; + bool success = false; // Get all the DRAWSEGMENTS and module graphics into 'items', // then keep only those on layer == Edge_Cuts. @@ -765,15 +766,17 @@ bool BuildBoardPolygonOutlines( BOARD* aBoard, SHAPE_POLY_SET& aOutlines, segList.push_back( static_cast< DRAWSEGMENT* >( items[ii] ) ); } - bool success = ConvertOutlineToPolygon( segList, aOutlines, aErrorText, aTolerance, aErrorLocation ); + if( segList.size() ) + { + success = ConvertOutlineToPolygon( segList, aOutlines, aErrorText, aTolerance, + aErrorLocation ); + } if( !success || !aOutlines.OutlineCount() ) { - // Creates a valid polygon outline is not possible. - // So uses the board edge cuts bounding box to create a - // rectangular outline - // When no edge cuts items, build a contour - // from global bounding box + // Couldn't create a valid polygon outline. Use the board edge cuts bounding box to + // create a rectangular outline, or, failing that, the bounding box of the items on + // the board. EDA_RECT bbbox = aBoard->GetBoardEdgesBoundingBox(); diff --git a/pcbnew/drc/drc.cpp b/pcbnew/drc/drc.cpp index 7763051886..03163d2d6d 100644 --- a/pcbnew/drc/drc.cpp +++ b/pcbnew/drc/drc.cpp @@ -65,11 +65,11 @@ DRC::DRC() : PCB_TOOL_BASE( "pcbnew.DRCTool" ), m_pcbEditorFrame( nullptr ), m_pcb( nullptr ), + m_board_outline_valid( false ), m_drcDialog( nullptr ), m_largestClearance( 0 ) { // establish initial values for everything: - m_doPad2PadTest = true; // enable pad to pad clearance tests m_doUnconnectedTest = true; // enable unconnected tests m_doZonesTest = false; // disable zone to items clearance tests m_doKeepoutTest = true; // enable keepout areas to items clearance tests @@ -401,7 +401,10 @@ void DRC::RunTests( wxTextCtrl* aMessages ) m_largestClearance = bds.GetBiggestClearanceValue(); - if( !bds.Ignore( DRCE_INVALID_OUTLINE ) ) + if( !bds.Ignore( DRCE_INVALID_OUTLINE ) + || !bds.Ignore( DRCE_TRACK_NEAR_EDGE ) + || !bds.Ignore( DRCE_VIA_NEAR_EDGE ) + || !bds.Ignore( DRCE_PAD_NEAR_EDGE ) ) { if( aMessages ) { @@ -441,7 +444,9 @@ void DRC::RunTests( wxTextCtrl* aMessages ) } // test pad to pad clearances, nothing to do with tracks, vias or zones. - if( m_doPad2PadTest ) + if( !bds.Ignore( DRCE_PAD_NEAR_EDGE ) + || !bds.Ignore( DRCE_PAD_NEAR_PAD ) + || !bds.Ignore( DRCE_HOLE_NEAR_PAD ) ) { if( aMessages ) { @@ -449,7 +454,7 @@ void DRC::RunTests( wxTextCtrl* aMessages ) wxSafeYield(); } - testPad2Pad( commit ); + testPadClearances( commit ); } // test drilled holes @@ -657,16 +662,17 @@ void DRC::updatePointers() } -void DRC::testPad2Pad( BOARD_COMMIT& aCommit ) +void DRC::testPadClearances( BOARD_COMMIT& aCommit ) { - std::vector sortedPads; + BOARD_DESIGN_SETTINGS& bds = m_pcb->GetDesignSettings(); + std::vector sortedPads; m_pcb->GetSortedPadListByXthenYCoord( sortedPads ); if( sortedPads.empty() ) return; - // find the max size of the pads (used to stop the test) + // find the max size of the pads (used to stop the pad-to-pad tests) int max_size = 0; for( D_PAD* pad : sortedPads ) @@ -688,9 +694,50 @@ void DRC::testPad2Pad( BOARD_COMMIT& aCommit ) // Test the pads for( auto& pad : sortedPads ) { - int x_limit = pad->GetPosition().x + pad->GetBoundingRadius() + max_size; + if( !bds.Ignore( DRCE_PAD_NEAR_EDGE ) && m_board_outline_valid ) + { + static DRAWSEGMENT dummyEdge; + dummyEdge.SetLayer( Edge_Cuts ); - doPadToPadsDrc( aCommit, pad, &pad, listEnd, x_limit ); + int minClearance = pad->GetClearance( &dummyEdge, &m_clearanceSource ); + + if( bds.m_CopperEdgeClearance > minClearance ) + { + minClearance = bds.m_CopperEdgeClearance; + m_clearanceSource = _( "board edge" ); + } + + for( auto it = m_board_outlines.IterateSegmentsWithHoles(); it; it++ ) + { + int actual; + + if( !checkClearanceSegmToPad( *it, 0, pad, minClearance, &actual ) ) + { + actual = std::max( 0, actual ); + DRC_ITEM* drcItem = new DRC_ITEM( DRCE_PAD_NEAR_EDGE ); + + m_msg.Printf( drcItem->GetErrorText() + _( " (%s %s; actual %s)" ), + m_clearanceSource, + MessageTextFromValue( userUnits(), minClearance, true ), + MessageTextFromValue( userUnits(), actual, true ) ); + + drcItem->SetErrorMessage( m_msg ); + drcItem->SetItems( pad ); + + MARKER_PCB* marker = new MARKER_PCB( drcItem, pad->GetPosition() ); + addMarkerToPcb( aCommit, marker ); + + break; + } + } + } + + if( !bds.Ignore( DRCE_PAD_NEAR_PAD ) || !bds.Ignore( DRCE_HOLE_NEAR_PAD ) ) + { + int x_limit = pad->GetPosition().x + pad->GetBoundingRadius() + max_size; + + doPadToPadsDrc( aCommit, pad, &pad, listEnd, x_limit ); + } } } @@ -1070,8 +1117,13 @@ void DRC::testOutline( BOARD_COMMIT& aCommit ) wxPoint error_loc( m_pcb->GetBoardEdgesBoundingBox().GetPosition() ); m_board_outlines.RemoveAllContours(); + m_board_outline_valid = false; - if( !m_pcb->GetBoardPolygonOutlines( m_board_outlines, nullptr, &error_loc ) ) + if( m_pcb->GetBoardPolygonOutlines( m_board_outlines, nullptr, &error_loc ) ) + { + m_board_outline_valid = true; + } + else { DRC_ITEM* drcItem = new DRC_ITEM( DRCE_INVALID_OUTLINE ); diff --git a/pcbnew/drc/drc.h b/pcbnew/drc/drc.h index 4c56cc394c..b827e471e8 100644 --- a/pcbnew/drc/drc.h +++ b/pcbnew/drc/drc.h @@ -52,6 +52,8 @@ enum PCB_DRC_CODE { DRCE_TRACK_SEGMENTS_TOO_CLOSE, ///< 2 parallel track segments too close: segm ends between segref ends DRCE_TRACKS_CROSSING, ///< tracks are crossing DRCE_TRACK_NEAR_EDGE, ///< track too close to board edge + DRCE_VIA_NEAR_EDGE, ///< via too close to board edge + DRCE_PAD_NEAR_EDGE, ///< pad too close to board edge DRCE_PAD_NEAR_PAD, ///< pad too close to pad DRCE_PAD_NEAR_COPPER, ///< pad and copper graphic collide or are too close DRCE_ZONES_INTERSECT, ///< copper area outlines intersect @@ -163,6 +165,7 @@ private: PCB_EDIT_FRAME* m_pcbEditorFrame; // The pcb frame editor which owns the board BOARD* m_pcb; SHAPE_POLY_SET m_board_outlines; // The board outline including cutouts + bool m_board_outline_valid; DIALOG_DRC* m_drcDialog; std::vector m_unconnected; // list of unconnected pads @@ -214,7 +217,7 @@ private: */ void testTracks( BOARD_COMMIT& aCommit, wxWindow * aActiveWindow, bool aShowProgressBar ); - void testPad2Pad( BOARD_COMMIT& aCommit ); + void testPadClearances( BOARD_COMMIT& aCommit ); void testUnconnected(); diff --git a/pcbnew/drc/drc_clearance_test_functions.cpp b/pcbnew/drc/drc_clearance_test_functions.cpp index 8787239030..e0b80ddd1d 100644 --- a/pcbnew/drc/drc_clearance_test_functions.cpp +++ b/pcbnew/drc/drc_clearance_test_functions.cpp @@ -604,6 +604,7 @@ void DRC::doTrackDrc( BOARD_COMMIT& aCommit, TRACK* aRefSeg, TRACKS::iterator aS /***********************************************/ /* Phase 4: test DRC with to board edge */ /***********************************************/ + if( m_board_outline_valid ) { static DRAWSEGMENT dummyEdge; dummyEdge.SetLayer( Edge_Cuts ); @@ -651,7 +652,9 @@ void DRC::doTrackDrc( BOARD_COMMIT& aCommit, TRACK* aRefSeg, TRACKS::iterator aS BOARD::IterateForward( m_pcb->Drawings(), inspector, nullptr, types ); int actual = std::max( 0.0, sqrt( center2center_squared ) - halfWidth ); - DRC_ITEM* drcItem = new DRC_ITEM( DRCE_TRACK_NEAR_EDGE ); + int errorCode = ( aRefSeg->Type() == PCB_VIA_T ) ? DRCE_VIA_NEAR_EDGE + : DRCE_TRACK_NEAR_EDGE; + DRC_ITEM* drcItem = new DRC_ITEM( errorCode ); m_msg.Printf( drcItem->GetErrorText() + _( " (%s clearance %s; actual %s)" ), m_clearanceSource, diff --git a/pcbnew/drc/drc_item.cpp b/pcbnew/drc/drc_item.cpp index f792bbeae6..efc827ed3c 100644 --- a/pcbnew/drc/drc_item.cpp +++ b/pcbnew/drc/drc_item.cpp @@ -92,6 +92,8 @@ wxString DRC_ITEM::GetErrorText( int aCode, bool aTranslate ) const case DRCE_TOO_SMALL_MICROVIA_DRILL: msg = _HKI( "Micro via drill too small" ); break; case DRCE_DRILLED_HOLES_TOO_CLOSE: msg = _HKI( "Drilled holes too close together" ); break; case DRCE_TRACK_NEAR_EDGE: msg = _HKI( "Track too close to board edge" ); break; + case DRCE_VIA_NEAR_EDGE: msg = _HKI( "Via too close to board edge" ); break; + case DRCE_PAD_NEAR_EDGE: msg = _HKI( "Pad too close to board edge" ); break; case DRCE_INVALID_OUTLINE: msg = _HKI( "Board has malformed outline" ); break; case DRCE_NETCLASS_TRACKWIDTH: msg = _HKI( "NetClass Track Width too small" ); break;