Implement DRC checks for copper graphic items.

Also greatly improves the location of many DRC markers.

Fixes: lp:1619133
* https://bugs.launchpad.net/kicad/+bug/1619133
This commit is contained in:
Jeff Young 2018-08-27 14:50:50 +01:00
parent 35a31a9787
commit 7b4f9cef50
5 changed files with 386 additions and 429 deletions

View File

@ -32,7 +32,8 @@
#include <trigo.h> #include <trigo.h>
#include <base_units.h> #include <base_units.h>
#include <board_design_settings.h> #include <board_design_settings.h>
#include <class_edge_mod.h>
#include <class_drawsegment.h>
#include <class_module.h> #include <class_module.h>
#include <class_track.h> #include <class_track.h>
#include <class_pad.h> #include <class_pad.h>
@ -42,7 +43,7 @@
#include <view/view.h> #include <view/view.h>
#include <geometry/seg.h> #include <geometry/seg.h>
#include <math_for_graphics.h> #include <math_for_graphics.h>
#include <geometry/geometry_utils.h>
#include <connectivity_data.h> #include <connectivity_data.h>
#include <connectivity_algo.h> #include <connectivity_algo.h>
@ -55,6 +56,8 @@
#include <dialog_drc.h> #include <dialog_drc.h>
#include <wx/progdlg.h> #include <wx/progdlg.h>
#include <board_commit.h> #include <board_commit.h>
#include <geometry/shape_segment.h>
#include <geometry/shape_arc.h>
void DRC::ShowDRCDialog( wxWindow* aParent ) void DRC::ShowDRCDialog( wxWindow* aParent )
{ {
@ -177,7 +180,11 @@ int DRC::DrcOnCreatingTrack( TRACK* aRefSegm, TRACK* aList )
if( !doTrackDrc( aRefSegm, aList, true ) ) if( !doTrackDrc( aRefSegm, aList, true ) )
{ {
if( m_currentMarker ) if( m_currentMarker )
{
m_pcbEditorFrame->SetMsgPanel( m_currentMarker ); m_pcbEditorFrame->SetMsgPanel( m_currentMarker );
delete m_currentMarker;
m_currentMarker = nullptr;
}
m_drcInLegacyRoutingMode = drc_state; m_drcInLegacyRoutingMode = drc_state;
m_reportAllTrackErrors = rpt_state; m_reportAllTrackErrors = rpt_state;
@ -186,11 +193,13 @@ int DRC::DrcOnCreatingTrack( TRACK* aRefSegm, TRACK* aList )
if( !doTrackKeepoutDrc( aRefSegm ) ) if( !doTrackKeepoutDrc( aRefSegm ) )
{ {
wxASSERT( m_currentMarker ); if( m_currentMarker )
{
m_pcbEditorFrame->SetMsgPanel( m_currentMarker );
delete m_currentMarker;
m_currentMarker = nullptr;
}
m_pcbEditorFrame->SetMsgPanel( m_currentMarker );
delete m_currentMarker;
m_currentMarker = nullptr;
m_drcInLegacyRoutingMode = drc_state; m_drcInLegacyRoutingMode = drc_state;
m_reportAllTrackErrors = rpt_state; m_reportAllTrackErrors = rpt_state;
return BAD_DRC; return BAD_DRC;
@ -496,7 +505,7 @@ void DRC::RunTests( wxTextCtrl* aMessages )
wxSafeYield(); wxSafeYield();
} }
testTexts(); testCopperTextAndGraphics();
// find overlapping courtyard ares. // find overlapping courtyard ares.
if( m_pcb->GetDesignSettings().m_ProhibitOverlappingCourtyards if( m_pcb->GetDesignSettings().m_ProhibitOverlappingCourtyards
@ -589,8 +598,7 @@ bool DRC::doNetClass( const NETCLASSPTR& nc, wxString& msg )
FmtVal( g.m_TrackMinWidth ) FmtVal( g.m_TrackMinWidth )
); );
addMarkerToPcb( fillMarker( DRCE_NETCLASS_TRACKWIDTH, msg, m_currentMarker ) ); addMarkerToPcb( newMarker( DRCE_NETCLASS_TRACKWIDTH, msg ) );
m_currentMarker = nullptr;
ret = false; ret = false;
} }
@ -602,8 +610,7 @@ bool DRC::doNetClass( const NETCLASSPTR& nc, wxString& msg )
FmtVal( g.m_ViasMinSize ) FmtVal( g.m_ViasMinSize )
); );
addMarkerToPcb( fillMarker( DRCE_NETCLASS_VIASIZE, msg, m_currentMarker ) ); addMarkerToPcb( newMarker( DRCE_NETCLASS_VIASIZE, msg ) );
m_currentMarker = nullptr;
ret = false; ret = false;
} }
@ -615,8 +622,7 @@ bool DRC::doNetClass( const NETCLASSPTR& nc, wxString& msg )
FmtVal( g.m_ViasMinDrill ) FmtVal( g.m_ViasMinDrill )
); );
addMarkerToPcb( fillMarker( DRCE_NETCLASS_VIADRILLSIZE, msg, m_currentMarker ) ); addMarkerToPcb( newMarker( DRCE_NETCLASS_VIADRILLSIZE, msg ) );
m_currentMarker = nullptr;
ret = false; ret = false;
} }
@ -625,11 +631,9 @@ bool DRC::doNetClass( const NETCLASSPTR& nc, wxString& msg )
msg.Printf( _( "NETCLASS: \"%s\" has uVia Dia:%s which is less than global:%s" ), msg.Printf( _( "NETCLASS: \"%s\" has uVia Dia:%s which is less than global:%s" ),
GetChars( nc->GetName() ), GetChars( nc->GetName() ),
FmtVal( nc->GetuViaDiameter() ), FmtVal( nc->GetuViaDiameter() ),
FmtVal( g.m_MicroViasMinSize ) FmtVal( g.m_MicroViasMinSize ) );
);
addMarkerToPcb( fillMarker( DRCE_NETCLASS_uVIASIZE, msg, m_currentMarker ) ); addMarkerToPcb( newMarker( DRCE_NETCLASS_uVIASIZE, msg ) );
m_currentMarker = nullptr;
ret = false; ret = false;
} }
@ -638,11 +642,9 @@ bool DRC::doNetClass( const NETCLASSPTR& nc, wxString& msg )
msg.Printf( _( "NETCLASS: \"%s\" has uVia Drill:%s which is less than global:%s" ), msg.Printf( _( "NETCLASS: \"%s\" has uVia Drill:%s which is less than global:%s" ),
GetChars( nc->GetName() ), GetChars( nc->GetName() ),
FmtVal( nc->GetuViaDrill() ), FmtVal( nc->GetuViaDrill() ),
FmtVal( g.m_MicroViasMinDrill ) FmtVal( g.m_MicroViasMinDrill ) );
);
addMarkerToPcb( fillMarker( DRCE_NETCLASS_uVIADRILLSIZE, msg, m_currentMarker ) ); addMarkerToPcb( newMarker( DRCE_NETCLASS_uVIADRILLSIZE, msg ) );
m_currentMarker = nullptr;
ret = false; ret = false;
} }
@ -889,24 +891,21 @@ void DRC::testZones()
// if it differs from the net name from net code, there is a DRC issue // if it differs from the net name from net code, there is a DRC issue
for( int ii = 0; ii < m_pcb->GetAreaCount(); ii++ ) for( int ii = 0; ii < m_pcb->GetAreaCount(); ii++ )
{ {
ZONE_CONTAINER* test_area = m_pcb->GetArea( ii ); ZONE_CONTAINER* zone = m_pcb->GetArea( ii );
if( !test_area->IsOnCopperLayer() ) if( !zone->IsOnCopperLayer() )
continue; continue;
int netcode = test_area->GetNetCode(); int netcode = zone->GetNetCode();
// a netcode < 0 or > 0 and no pad in net is a error or strange // a netcode < 0 or > 0 and no pad in net is a error or strange
// perhaps a "dead" net, which happens when all pads in this net were removed // perhaps a "dead" net, which happens when all pads in this net were removed
// Remark: a netcode < 0 should not happen (this is more a bug somewhere) // Remark: a netcode < 0 should not happen (this is more a bug somewhere)
int pads_in_net = (test_area->GetNetCode() > 0) ? int pads_in_net = ( netcode > 0 ) ? m_pcb->GetConnectivity()->GetPadCount( netcode ) : 1;
m_pcb->GetConnectivity()->GetPadCount( test_area->GetNetCode() ) : 1;
if( ( netcode < 0 ) || pads_in_net == 0 ) if( ( netcode < 0 ) || pads_in_net == 0 )
{ {
addMarkerToPcb( fillMarker( test_area, test_area->GetPosition(), wxPoint markerPos = zone->GetPosition();
DRCE_SUSPICIOUS_NET_FOR_ZONE_OUTLINE, m_currentMarker ) ); addMarkerToPcb( newMarker( markerPos, zone, DRCE_SUSPICIOUS_NET_FOR_ZONE_OUTLINE ) );
m_currentMarker = nullptr;
} }
} }
@ -938,13 +937,10 @@ void DRC::testKeepoutAreas()
if( !area->IsOnLayer( segm->GetLayer() ) ) if( !area->IsOnLayer( segm->GetLayer() ) )
continue; continue;
if( area->Outline()->Distance( SEG( segm->GetStart(), segm->GetEnd() ), SEG trackSeg( segm->GetStart(), segm->GetEnd() );
segm->GetWidth() ) == 0 )
{ if( area->Outline()->Distance( trackSeg, segm->GetWidth() ) == 0 )
addMarkerToPcb( fillMarker( segm, area, addMarkerToPcb( newMarker( segm, area, DRCE_TRACK_INSIDE_KEEPOUT ) );
DRCE_TRACK_INSIDE_KEEPOUT, m_currentMarker ) );
m_currentMarker = nullptr;
}
} }
else if( segm->Type() == PCB_VIA_T ) else if( segm->Type() == PCB_VIA_T )
{ {
@ -957,11 +953,7 @@ void DRC::testKeepoutAreas()
continue; continue;
if( area->Outline()->Distance( segm->GetPosition() ) < segm->GetWidth()/2 ) if( area->Outline()->Distance( segm->GetPosition() ) < segm->GetWidth()/2 )
{ addMarkerToPcb( newMarker( segm, area, DRCE_VIA_INSIDE_KEEPOUT ) );
addMarkerToPcb( fillMarker( segm, NULL,
DRCE_VIA_INSIDE_KEEPOUT, m_currentMarker ) );
m_currentMarker = nullptr;
}
} }
} }
// Test pads: TODO // Test pads: TODO
@ -969,38 +961,151 @@ void DRC::testKeepoutAreas()
} }
void DRC::testTexts() void DRC::testCopperTextAndGraphics()
{ {
// Test text items for vias, tracks and pads inside text areas // Test copper items for clearance violations with vias, tracks and pads
for( BOARD_ITEM* brdItem : m_pcb->Drawings() ) for( BOARD_ITEM* brdItem : m_pcb->Drawings() )
{ {
if( brdItem->Type() == PCB_TEXT_T && IsCopperLayer( brdItem->GetLayer() ) ) if( IsCopperLayer( brdItem->GetLayer() ) )
doText( brdItem ); {
if( brdItem->Type() == PCB_TEXT_T )
testCopperTextItem( brdItem );
else if( brdItem->Type() == PCB_LINE_T )
testCopperDrawItem( static_cast<DRAWSEGMENT*>( brdItem ));
}
} }
for( MODULE* module : m_pcb->Modules() ) for( MODULE* module : m_pcb->Modules() )
{ {
if( IsCopperLayer( module->Reference().GetLayer() ) ) if( IsCopperLayer( module->Reference().GetLayer() ) )
doText( &module->Reference() ); testCopperTextItem( &module->Reference());
if( IsCopperLayer( module->Value().GetLayer() ) ) if( IsCopperLayer( module->Value().GetLayer() ) )
doText( &module->Value() ); testCopperTextItem( &module->Value());
for( BOARD_ITEM* item = module->GraphicalItemsList(); item; item = item->Next() ) for( BOARD_ITEM* item = module->GraphicalItemsList(); item; item = item->Next() )
{ {
if( item->Type() == PCB_MODULE_TEXT_T && IsCopperLayer( item->GetLayer() ) ) if( IsCopperLayer( item->GetLayer() ) )
doText( item ); {
if( item->Type() == PCB_MODULE_TEXT_T )
testCopperTextItem( item );
else if( item->Type() == PCB_MODULE_EDGE_T )
testCopperDrawItem( static_cast<DRAWSEGMENT*>( item ));
}
} }
} }
} }
void DRC::doText( BOARD_ITEM* aTextItem ) void DRC::testCopperDrawItem( DRAWSEGMENT* aItem )
{
std::vector<SEG> itemShape;
int itemWidth = aItem->GetWidth();
switch( aItem->GetShape() )
{
case S_ARC:
{
SHAPE_ARC arc( aItem->GetCenter(), aItem->GetArcStart(), (double) aItem->GetAngle() / 10.0 );
auto l = arc.ConvertToPolyline();
for( int i = 0; i < l.SegmentCount(); i++ )
itemShape.push_back( l.CSegment(i) );
break;
}
case S_SEGMENT:
itemShape.push_back( SEG( aItem->GetStart(), aItem->GetEnd() ) );
break;
case S_CIRCLE:
{
// SHAPE_CIRCLE has no ConvertToPolyline() method, so use a 360.0 SHAPE_ARC
SHAPE_ARC circle( aItem->GetCenter(), aItem->GetEnd(), 360.0 );
auto l = circle.ConvertToPolyline();
for( int i = 0; i < l.SegmentCount(); i++ )
itemShape.push_back( l.CSegment(i) );
break;
}
case S_CURVE:
{
aItem->RebuildBezierToSegmentsPointsList( aItem->GetWidth() );
wxPoint start_pt = aItem->GetBezierPoints()[0];
for( unsigned int jj = 1; jj < aItem->GetBezierPoints().size(); jj++ )
{
wxPoint end_pt = aItem->GetBezierPoints()[jj];
itemShape.push_back( SEG( start_pt, end_pt ) );
start_pt = end_pt;
}
break;
}
default:
break;
}
// Test tracks and vias
for( TRACK* track = m_pcb->m_Track; track != NULL; track = track->Next() )
{
if( !track->IsOnLayer( aItem->GetLayer() ) )
continue;
int minDist = ( track->GetWidth() + itemWidth ) / 2 + track->GetClearance( NULL );
SEG trackAsSeg( track->GetStart(), track->GetEnd() );
for( const auto& itemSeg : itemShape )
{
if( trackAsSeg.Distance( itemSeg ) < minDist )
{
if( track->Type() == PCB_VIA_T )
addMarkerToPcb( newMarker( track, aItem, itemSeg, DRCE_VIA_NEAR_COPPER ) );
else
addMarkerToPcb( newMarker( track, aItem, itemSeg, DRCE_TRACK_NEAR_COPPER ) );
break;
}
}
}
// Test pads
for( auto pad : m_pcb->GetPads() )
{
if( !pad->IsOnLayer( aItem->GetLayer() ) )
continue;
const int segmentCount = 18;
double correctionFactor = GetCircletoPolyCorrectionFactor( segmentCount );
SHAPE_POLY_SET padOutline;
// We incorporate "minDist" into the pad's outline
pad->TransformShapeWithClearanceToPolygon( padOutline, pad->GetClearance( NULL ),
segmentCount, correctionFactor );
for( const auto& itemSeg : itemShape )
{
if( padOutline.Distance( itemSeg, itemWidth ) == 0 )
{
addMarkerToPcb( newMarker( pad, aItem, DRCE_PAD_NEAR_COPPER ) );
break;
}
}
}
}
void DRC::testCopperTextItem( BOARD_ITEM* aTextItem )
{ {
EDA_TEXT* text = dynamic_cast<EDA_TEXT*>( aTextItem ); EDA_TEXT* text = dynamic_cast<EDA_TEXT*>( aTextItem );
std::vector<wxPoint> textShape; // a buffer to store the text shape (set of segments) std::vector<wxPoint> textShape; // a buffer to store the text shape (set of segments)
std::vector<D_PAD*> padList = m_pcb->GetPads(); int textWidth = text->GetThickness();
// So far the bounding box makes up the text-area // So far the bounding box makes up the text-area
text->TransformTextShapeToSegmentList( textShape ); text->TransformTextShapeToSegmentList( textShape );
@ -1008,103 +1113,51 @@ void DRC::doText( BOARD_ITEM* aTextItem )
if( textShape.size() == 0 ) // Should not happen (empty text?) if( textShape.size() == 0 ) // Should not happen (empty text?)
return; return;
// Test tracks and vias
for( TRACK* track = m_pcb->m_Track; track != NULL; track = track->Next() ) for( TRACK* track = m_pcb->m_Track; track != NULL; track = track->Next() )
{ {
if( !track->IsOnLayer( aTextItem->GetLayer() ) ) if( !track->IsOnLayer( aTextItem->GetLayer() ) )
continue; continue;
// Test the distance between each segment and the current track/via int minDist = ( track->GetWidth() + textWidth ) / 2 + track->GetClearance( NULL );
int min_dist = ( track->GetWidth() + text->GetThickness() ) / 2 + SEG trackAsSeg( track->GetStart(), track->GetEnd() );
track->GetClearance( NULL );
if( track->Type() == PCB_TRACE_T ) for( unsigned jj = 0; jj < textShape.size(); jj += 2 )
{ {
SEG segref( track->GetStart(), track->GetEnd() ); SEG textSeg( textShape[jj], textShape[jj+1] );
wxPoint markerPos;
int closestApproach = INT_MAX;
// Error condition: Distance between text segment and track segment is if( trackAsSeg.Distance( textSeg ) < minDist )
// smaller than the clearance of the track
for( unsigned jj = 0; jj < textShape.size() && closestApproach > 0; jj += 2 )
{ {
SEG segtest( textShape[jj], textShape[jj+1] ); if( track->Type() == PCB_VIA_T )
int dist = segref.Distance( segtest ); addMarkerToPcb( newMarker( track, aTextItem, textSeg, DRCE_VIA_NEAR_COPPER ) );
else
if( dist < closestApproach ) addMarkerToPcb( newMarker( track, aTextItem, textSeg, DRCE_TRACK_NEAR_COPPER ) );
{
markerPos = textShape[jj];
closestApproach = dist;
}
}
if( closestApproach < min_dist )
{
addMarkerToPcb( fillMarker( markerPos, track, aTextItem,
DRCE_TRACK_INSIDE_TEXT, m_currentMarker ) );
m_currentMarker = nullptr;
break; break;
} }
} }
else if( track->Type() == PCB_VIA_T )
{
// Error condition: Distance between text segment and via is
// smaller than the clearance of the via
for( unsigned jj = 0; jj < textShape.size(); jj += 2 )
{
SEG segtest( textShape[jj], textShape[jj+1] );
if( segtest.PointCloserThan( track->GetPosition(), min_dist ) )
{
addMarkerToPcb( fillMarker( track->GetPosition(), track, aTextItem,
DRCE_VIA_INSIDE_TEXT, m_currentMarker ) );
m_currentMarker = nullptr;
break;
}
}
}
} }
// Test pads // Test pads
for( unsigned ii = 0; ii < padList.size(); ii++ ) for( auto pad : m_pcb->GetPads() )
{ {
D_PAD* pad = padList[ii];
if( !pad->IsOnLayer( aTextItem->GetLayer() ) ) if( !pad->IsOnLayer( aTextItem->GetLayer() ) )
continue; continue;
wxPoint shape_pos = pad->ShapePos(); const int segmentCount = 18;
double correctionFactor = GetCircletoPolyCorrectionFactor( segmentCount );
SHAPE_POLY_SET padOutline;
// We incorporate "minDist" into the pad's outline
pad->TransformShapeWithClearanceToPolygon( padOutline, pad->GetClearance( NULL ),
segmentCount, correctionFactor );
for( unsigned jj = 0; jj < textShape.size(); jj += 2 ) for( unsigned jj = 0; jj < textShape.size(); jj += 2 )
{ {
/* In order to make some calculations more easier or faster, SEG textSeg( textShape[jj], textShape[jj+1] );
* pads and tracks coordinates will be made relative
* to the segment origin
*/
wxPoint origin = textShape[jj]; // origin will be the origin of other coordinates
m_segmEnd = textShape[jj+1] - origin;
wxPoint delta = m_segmEnd;
m_segmAngle = 0;
// for a non horizontal or vertical segment Compute the segment angle if( padOutline.Distance( textSeg, textWidth ) == 0 )
// in tenths of degrees and its length
if( delta.x || delta.y ) // delta.x == delta.y == 0 for vias
{ {
// Compute the segment angle in 0,1 degrees addMarkerToPcb( newMarker( pad, aTextItem, DRCE_PAD_NEAR_COPPER ) );
m_segmAngle = ArcTangente( delta.y, delta.x );
// Compute the segment length: we build an equivalent rotated segment,
// this segment is horizontal, therefore dx = length
RotatePoint( &delta, m_segmAngle ); // delta.x = length, delta.y = 0
}
m_segmLength = delta.x;
m_padToTestPos = shape_pos - origin;
if( !checkClearanceSegmToPad( pad, text->GetThickness(), pad->GetClearance(NULL) ) )
{
addMarkerToPcb( fillMarker( pad, aTextItem, DRCE_PAD_INSIDE_TEXT,
m_currentMarker ) );
m_currentMarker = nullptr;
break; break;
} }
} }
@ -1120,10 +1173,7 @@ void DRC::testDisabledLayers()
auto createMarker = [&]( BOARD_ITEM* aItem ) auto createMarker = [&]( BOARD_ITEM* aItem )
{ {
m_currentMarker = fillMarker( aItem, aItem->GetPosition(), DRCE_DISABLED_LAYER_ITEM, addMarkerToPcb( newMarker( aItem->GetPosition(), aItem, DRCE_DISABLED_LAYER_ITEM ) );
m_currentMarker );
addMarkerToPcb( m_currentMarker );
m_currentMarker = nullptr;
}; };
for( auto track : board->Tracks() ) for( auto track : board->Tracks() )
@ -1170,8 +1220,7 @@ bool DRC::doTrackKeepoutDrc( TRACK* aRefSeg )
if( area->Outline()->Distance( SEG( aRefSeg->GetStart(), aRefSeg->GetEnd() ), if( area->Outline()->Distance( SEG( aRefSeg->GetStart(), aRefSeg->GetEnd() ),
aRefSeg->GetWidth() ) == 0 ) aRefSeg->GetWidth() ) == 0 )
{ {
m_currentMarker = fillMarker( aRefSeg, NULL, m_currentMarker = newMarker( aRefSeg, area, DRCE_TRACK_INSIDE_KEEPOUT );
DRCE_TRACK_INSIDE_KEEPOUT, m_currentMarker );
return false; return false;
} }
} }
@ -1187,8 +1236,7 @@ bool DRC::doTrackKeepoutDrc( TRACK* aRefSeg )
if( area->Outline()->Distance( aRefSeg->GetPosition() ) < aRefSeg->GetWidth()/2 ) if( area->Outline()->Distance( aRefSeg->GetPosition() ) < aRefSeg->GetWidth()/2 )
{ {
m_currentMarker = fillMarker( aRefSeg, NULL, m_currentMarker = newMarker( aRefSeg, area, DRCE_VIA_INSIDE_KEEPOUT );
DRCE_VIA_INSIDE_KEEPOUT, m_currentMarker );
return false; return false;
} }
} }
@ -1270,8 +1318,7 @@ bool DRC::doPadToPadsDrc( D_PAD* aRefPad, D_PAD** aStart, D_PAD** aEnd, int x_li
if( !checkClearancePadToPad( aRefPad, &dummypad ) ) if( !checkClearancePadToPad( aRefPad, &dummypad ) )
{ {
// here we have a drc error on pad! // here we have a drc error on pad!
m_currentMarker = fillMarker( pad, aRefPad, m_currentMarker = newMarker( pad, aRefPad, DRCE_HOLE_NEAR_PAD );
DRCE_HOLE_NEAR_PAD, m_currentMarker );
return false; return false;
} }
} }
@ -1287,8 +1334,7 @@ bool DRC::doPadToPadsDrc( D_PAD* aRefPad, D_PAD** aStart, D_PAD** aEnd, int x_li
if( !checkClearancePadToPad( pad, &dummypad ) ) if( !checkClearancePadToPad( pad, &dummypad ) )
{ {
// here we have a drc error on aRefPad! // here we have a drc error on aRefPad!
m_currentMarker = fillMarker( aRefPad, pad, m_currentMarker = newMarker( aRefPad, pad, DRCE_HOLE_NEAR_PAD );
DRCE_HOLE_NEAR_PAD, m_currentMarker );
return false; return false;
} }
} }
@ -1323,7 +1369,7 @@ bool DRC::doPadToPadsDrc( D_PAD* aRefPad, D_PAD** aStart, D_PAD** aEnd, int x_li
if( !checkClearancePadToPad( aRefPad, pad ) ) if( !checkClearancePadToPad( aRefPad, pad ) )
{ {
// here we have a drc error! // here we have a drc error!
m_currentMarker = fillMarker( aRefPad, pad, DRCE_PAD_NEAR_PAD1, m_currentMarker ); m_currentMarker = newMarker( aRefPad, pad, DRCE_PAD_NEAR_PAD1 );
return false; return false;
} }
} }
@ -1342,15 +1388,12 @@ bool DRC::doFootprintOverlappingDrc()
// Update courtyard polygons, and test for missing courtyard definition: // Update courtyard polygons, and test for missing courtyard definition:
for( MODULE* footprint = m_pcb->m_Modules; footprint; footprint = footprint->Next() ) for( MODULE* footprint = m_pcb->m_Modules; footprint; footprint = footprint->Next() )
{ {
wxPoint pos = footprint->GetPosition();
bool is_ok = footprint->BuildPolyCourtyard(); bool is_ok = footprint->BuildPolyCourtyard();
if( !is_ok && m_pcb->GetDesignSettings().m_ProhibitOverlappingCourtyards ) if( !is_ok && m_pcb->GetDesignSettings().m_ProhibitOverlappingCourtyards )
{ {
m_currentMarker = fillMarker( footprint, footprint->GetPosition(), addMarkerToPcb( newMarker( pos, footprint, DRCE_MALFORMED_COURTYARD_IN_FOOTPRINT ) );
DRCE_MALFORMED_COURTYARD_IN_FOOTPRINT,
m_currentMarker );
addMarkerToPcb( m_currentMarker );
m_currentMarker = nullptr;
success = false; success = false;
} }
@ -1361,11 +1404,7 @@ bool DRC::doFootprintOverlappingDrc()
footprint->GetPolyCourtyardBack().OutlineCount() == 0 && footprint->GetPolyCourtyardBack().OutlineCount() == 0 &&
is_ok ) is_ok )
{ {
m_currentMarker = fillMarker( footprint, footprint->GetPosition(), addMarkerToPcb( newMarker( pos, footprint, DRCE_MISSING_COURTYARD_IN_FOOTPRINT ) );
DRCE_MISSING_COURTYARD_IN_FOOTPRINT,
m_currentMarker );
addMarkerToPcb( m_currentMarker );
m_currentMarker = nullptr;
success = false; success = false;
} }
} }
@ -1399,10 +1438,8 @@ bool DRC::doFootprintOverlappingDrc()
{ {
//Overlap between footprint and candidate //Overlap between footprint and candidate
VECTOR2I& pos = courtyard.Vertex( 0, 0, -1 ); VECTOR2I& pos = courtyard.Vertex( 0, 0, -1 );
m_currentMarker = fillMarker( wxPoint( pos.x, pos.y ), footprint, candidate, addMarkerToPcb( newMarker( wxPoint( pos.x, pos.y ), footprint, candidate,
DRCE_OVERLAPPING_FOOTPRINTS, m_currentMarker ); DRCE_OVERLAPPING_FOOTPRINTS ) );
addMarkerToPcb( m_currentMarker );
m_currentMarker = nullptr;
success = false; success = false;
} }
} }
@ -1432,10 +1469,8 @@ bool DRC::doFootprintOverlappingDrc()
{ {
//Overlap between footprint and candidate //Overlap between footprint and candidate
VECTOR2I& pos = courtyard.Vertex( 0, 0, -1 ); VECTOR2I& pos = courtyard.Vertex( 0, 0, -1 );
m_currentMarker = fillMarker( wxPoint( pos.x, pos.y ), footprint, candidate, addMarkerToPcb( newMarker( wxPoint( pos.x, pos.y ), footprint, candidate,
DRCE_OVERLAPPING_FOOTPRINTS, m_currentMarker ); DRCE_OVERLAPPING_FOOTPRINTS ) );
addMarkerToPcb( m_currentMarker );
m_currentMarker = nullptr;
success = false; success = false;
} }
} }

View File

@ -31,6 +31,7 @@
#include <vector> #include <vector>
#include <memory> #include <memory>
#include <geometry/seg.h>
#define OK_DRC 0 #define OK_DRC 0
#define BAD_DRC 1 #define BAD_DRC 1
@ -81,18 +82,18 @@
#define DRCE_VIA_INSIDE_KEEPOUT 38 ///< Via in inside a keepout area #define DRCE_VIA_INSIDE_KEEPOUT 38 ///< Via in inside a keepout area
#define DRCE_TRACK_INSIDE_KEEPOUT 39 ///< Track in inside a keepout area #define DRCE_TRACK_INSIDE_KEEPOUT 39 ///< Track in inside a keepout area
#define DRCE_PAD_INSIDE_KEEPOUT 40 ///< Pad in inside a keepout area #define DRCE_PAD_INSIDE_KEEPOUT 40 ///< Pad in inside a keepout area
#define DRCE_VIA_INSIDE_TEXT 41 ///< Via in inside a text area #define DRCE_TRACK_NEAR_COPPER 41 ///< track & copper graphic collide or are too close
#define DRCE_TRACK_INSIDE_TEXT 42 ///< Track in inside a text area #define DRCE_VIA_NEAR_COPPER 42 ///< via and copper graphic collide or are too close
#define DRCE_PAD_INSIDE_TEXT 43 ///< Pad in inside a text area #define DRCE_PAD_NEAR_COPPER 43 ///< pad and copper graphic collide or are too close
#define DRCE_OVERLAPPING_FOOTPRINTS 44 ///< footprint courtyards overlap #define DRCE_TRACK_NEAR_ZONE 44 ///< track & zone collide or are too close together
#define DRCE_MISSING_COURTYARD_IN_FOOTPRINT 45 ///< footprint has no courtyard defined #define DRCE_OVERLAPPING_FOOTPRINTS 45 ///< footprint courtyards overlap
#define DRCE_MALFORMED_COURTYARD_IN_FOOTPRINT 46 ///< footprint has a courtyard but malformed #define DRCE_MISSING_COURTYARD_IN_FOOTPRINT 46 ///< footprint has no courtyard defined
#define DRCE_MALFORMED_COURTYARD_IN_FOOTPRINT 47 ///< footprint has a courtyard but malformed
///< (not convertible to a closed polygon with holes) ///< (not convertible to a closed polygon with holes)
#define DRCE_MICRO_VIA_NOT_ALLOWED 47 ///< micro vias are not allowed #define DRCE_MICRO_VIA_NOT_ALLOWED 48 ///< micro vias are not allowed
#define DRCE_BURIED_VIA_NOT_ALLOWED 48 ///< buried vias are not allowed #define DRCE_BURIED_VIA_NOT_ALLOWED 49 ///< buried vias are not allowed
#define DRCE_DISABLED_LAYER_ITEM 49 ///< item on a disabled layer #define DRCE_DISABLED_LAYER_ITEM 50 ///< item on a disabled layer
#define DRCE_DRILLED_HOLES_TOO_CLOSE 50 ///< overlapping drilled holes break drill bits #define DRCE_DRILLED_HOLES_TOO_CLOSE 51 ///< overlapping drilled holes break drill bits
#define DRCE_TRACK_NEAR_ZONE 51 ///< track & zone collide or are too close together
class EDA_DRAW_PANEL; class EDA_DRAW_PANEL;
@ -107,6 +108,10 @@ class MARKER_PCB;
class DRC_ITEM; class DRC_ITEM;
class NETCLASS; class NETCLASS;
class EDA_TEXT; class EDA_TEXT;
class DRAWSEGMENT;
class wxWindow;
class wxString;
class wxTextCtrl;
/** /**
@ -227,53 +232,39 @@ private:
/** /**
* Function fillMarker * Function newMarker
* Optionally creates a marker and fills it in with information, but does not add it to * Creates a marker on a track, via or pad.
* the BOARD. Use this to report any kind of DRC problem, or unconnected pad problem.
* *
* @param aTrack/aPad The reference item. * @param aTrack/aPad The reference item.
* @param aItem Another item on the BOARD, such as a VIA, SEGZONE, or TRACK, which is * @param aConflitItem Another item on the board which is in conflict with the
* in conflict with the reference item. * reference item.
* @param aErrorCode An ID for the particular type of error that is being reported. * @param aErrorCode An ID for the particular type of error that is being reported.
* @param fillMe A MARKER_PCB* which is to be filled in, or NULL if one is to be created.
*/ */
MARKER_PCB* fillMarker( TRACK* aTrack, BOARD_ITEM* aItem, int aErrorCode, MARKER_PCB* fillMe ); MARKER_PCB* newMarker( TRACK* aTrack, BOARD_ITEM* aConflitItem, const SEG& aConflictSeg,
int aErrorCode );
MARKER_PCB* fillMarker( D_PAD* aPad, BOARD_ITEM* aItem, int aErrorCode, MARKER_PCB* fillMe ); MARKER_PCB* newMarker( TRACK* aTrack, ZONE_CONTAINER* aConflictZone, int aErrorCode );
MARKER_PCB* newMarker( D_PAD* aPad, BOARD_ITEM* aConflictItem, int aErrorCode );
/** /**
* Function fillMarker * Function newMarker
* Optionally creates a marker and fills it in with information, but does not add it to * Creates a marker at a given location.
* the BOARD. Use this to report any kind of DRC problem, or unconnected pad problem.
* *
* @param aItem The reference item. * @param aItem The reference item.
* @param aPos Usually the position of the item, but could be more specific for a zone. * @param aPos Usually the position of the item, but could be more specific for a zone.
* @param aErrorCode An ID for the particular type of error that is being reported. * @param aErrorCode An ID for the particular type of error that is being reported.
* @param fillMe A MARKER_PCB* which is to be filled in, or NULL if one is to be created.
*/ */
MARKER_PCB* fillMarker( BOARD_ITEM* aItem, const wxPoint& aPos, int aErrorCode, MARKER_PCB* newMarker( const wxPoint& aPos, BOARD_ITEM* aItem, int aErrorCode );
MARKER_PCB* fillMe );
MARKER_PCB* newMarker( const wxPoint& aPos, BOARD_ITEM* aItem, BOARD_ITEM* bItem,
int aErrorCode );
/** /**
* Function fillMarker * Create a MARKER which will report on a generic problem with the board which is
* Optionally creates a marker and fills it in with information, but does not add it to
* the BOARD. Use this to report any kind of DRC problem, or unconnected pad problem.
*
* @param aPos The reference location.
* @param aErrorCode An ID for the particular type of error that is being reported.
* @param aItem The first item in conflict.
* @param bItem (Optional) The second item in conflict or NULL.
* @param aErrorCode An ID for the particular type of error that is being reported.
* @param fillMe A MARKER_PCB* which is to be filled in, or NULL if one is to be created.
*/
MARKER_PCB* fillMarker( const wxPoint& aPos, BOARD_ITEM* aItem, BOARD_ITEM* bItem,
int aErrorCode, MARKER_PCB* fillMe );
/**
* Fill a MARKER which will report on a generic problem with the board which is
* not geographically locatable. * not geographically locatable.
*/ */
MARKER_PCB* fillMarker( int aErrorCode, const wxString& aMessage, MARKER_PCB* fillMe ); MARKER_PCB* newMarker( int aErrorCode, const wxString& aMessage );
/** /**
* Adds a DRC marker to the PCB through the COMMIT mechanism. * Adds a DRC marker to the PCB through the COMMIT mechanism.
@ -314,9 +305,11 @@ private:
void testKeepoutAreas(); void testKeepoutAreas();
// aTextItem is type BOARD_ITEM* to accept either TEXTE_PCB or TEXTE_MODULE // aTextItem is type BOARD_ITEM* to accept either TEXTE_PCB or TEXTE_MODULE
void doText( BOARD_ITEM* aTextItem ); void testCopperTextItem( BOARD_ITEM* aTextItem );
void testTexts(); void testCopperDrawItem( DRAWSEGMENT* aDrawing );
void testCopperTextAndGraphics();
///> Tests for items placed on disabled layers (causing false connections). ///> Tests for items placed on disabled layers (causing false connections).
void testDisabledLayers(); void testDisabledLayers();

View File

@ -204,21 +204,23 @@ bool DRC::doTrackDrc( TRACK* aRefSeg, TRACK* aStart, bool testPads )
if( aRefSeg->Type() == PCB_VIA_T ) if( aRefSeg->Type() == PCB_VIA_T )
{ {
VIA *refvia = static_cast<VIA*>( aRefSeg ); VIA *refvia = static_cast<VIA*>( aRefSeg );
wxPoint refviaPos = refvia->GetPosition();
// test if the via size is smaller than minimum // test if the via size is smaller than minimum
if( refvia->GetViaType() == VIA_MICROVIA ) if( refvia->GetViaType() == VIA_MICROVIA )
{ {
if( refvia->GetWidth() < dsnSettings.m_MicroViasMinSize ) if( refvia->GetWidth() < dsnSettings.m_MicroViasMinSize )
{ {
markers.push_back( fillMarker( refvia, nullptr, markers.push_back( newMarker( refviaPos, refvia, DRCE_TOO_SMALL_MICROVIA ) );
DRCE_TOO_SMALL_MICROVIA, nullptr ) );
if( !handleNewMarker() ) if( !handleNewMarker() )
return false; return false;
} }
if( refvia->GetDrillValue() < dsnSettings.m_MicroViasMinDrill ) if( refvia->GetDrillValue() < dsnSettings.m_MicroViasMinDrill )
{ {
markers.push_back( fillMarker( refvia, nullptr, markers.push_back( newMarker( refviaPos, refvia, DRCE_TOO_SMALL_MICROVIA_DRILL ) );
DRCE_TOO_SMALL_MICROVIA_DRILL, nullptr ) );
if( !handleNewMarker() ) if( !handleNewMarker() )
return false; return false;
} }
@ -227,16 +229,16 @@ bool DRC::doTrackDrc( TRACK* aRefSeg, TRACK* aStart, bool testPads )
{ {
if( refvia->GetWidth() < dsnSettings.m_ViasMinSize ) if( refvia->GetWidth() < dsnSettings.m_ViasMinSize )
{ {
markers.push_back( fillMarker( refvia, nullptr, markers.push_back( newMarker( refviaPos, refvia, DRCE_TOO_SMALL_VIA ) );
DRCE_TOO_SMALL_VIA, nullptr ) );
if( !handleNewMarker() ) if( !handleNewMarker() )
return false; return false;
} }
if( refvia->GetDrillValue() < dsnSettings.m_ViasMinDrill ) if( refvia->GetDrillValue() < dsnSettings.m_ViasMinDrill )
{ {
markers.push_back( fillMarker( refvia, nullptr, markers.push_back( newMarker( refviaPos, refvia, DRCE_TOO_SMALL_VIA_DRILL ) );
DRCE_TOO_SMALL_VIA_DRILL, nullptr ) );
if( !handleNewMarker() ) if( !handleNewMarker() )
return false; return false;
} }
@ -247,28 +249,25 @@ bool DRC::doTrackDrc( TRACK* aRefSeg, TRACK* aStart, bool testPads )
// and a default via hole can be bigger than some vias sizes // and a default via hole can be bigger than some vias sizes
if( refvia->GetDrillValue() > refvia->GetWidth() ) if( refvia->GetDrillValue() > refvia->GetWidth() )
{ {
markers.push_back( fillMarker( refvia, nullptr, markers.push_back( newMarker( refviaPos, refvia, DRCE_VIA_HOLE_BIGGER ) );
DRCE_VIA_HOLE_BIGGER, nullptr ) );
if( !handleNewMarker() ) if( !handleNewMarker() )
return false; return false;
} }
// test if the type of via is allowed due to design rules // test if the type of via is allowed due to design rules
if( ( refvia->GetViaType() == VIA_MICROVIA ) && if( refvia->GetViaType() == VIA_MICROVIA && !dsnSettings.m_MicroViasAllowed )
( m_pcb->GetDesignSettings().m_MicroViasAllowed == false ) )
{ {
markers.push_back( fillMarker( refvia, nullptr, markers.push_back( newMarker( refviaPos, refvia, DRCE_MICRO_VIA_NOT_ALLOWED ) );
DRCE_MICRO_VIA_NOT_ALLOWED, nullptr ) );
if( !handleNewMarker() ) if( !handleNewMarker() )
return false; return false;
} }
// test if the type of via is allowed due to design rules // test if the type of via is allowed due to design rules
if( ( refvia->GetViaType() == VIA_BLIND_BURIED ) && if( refvia->GetViaType() == VIA_BLIND_BURIED && !dsnSettings.m_BlindBuriedViaAllowed )
( m_pcb->GetDesignSettings().m_BlindBuriedViaAllowed == false ) )
{ {
markers.push_back( fillMarker( refvia, nullptr, markers.push_back( newMarker( refviaPos, refvia, DRCE_BURIED_VIA_NOT_ALLOWED ) );
DRCE_BURIED_VIA_NOT_ALLOWED, nullptr ) );
if( !handleNewMarker() ) if( !handleNewMarker() )
return false; return false;
} }
@ -286,15 +285,15 @@ bool DRC::doTrackDrc( TRACK* aRefSeg, TRACK* aStart, bool testPads )
if( layer1 > layer2 ) if( layer1 > layer2 )
std::swap( layer1, layer2 ); std::swap( layer1, layer2 );
if( layer2 == B_Cu && layer1 == m_pcb->GetDesignSettings().GetCopperLayerCount() - 2 ) if( layer2 == B_Cu && layer1 == dsnSettings.GetCopperLayerCount() - 2 )
err = false; err = false;
else if( layer1 == F_Cu && layer2 == In1_Cu ) else if( layer1 == F_Cu && layer2 == In1_Cu )
err = false; err = false;
if( err ) if( err )
{ {
markers.push_back( fillMarker( refvia, nullptr, markers.push_back( newMarker( refviaPos, refvia, DRCE_MICRO_VIA_INCORRECT_LAYER_PAIR ) );
DRCE_MICRO_VIA_INCORRECT_LAYER_PAIR, nullptr ) );
if( !handleNewMarker() ) if( !handleNewMarker() )
return false; return false;
} }
@ -305,8 +304,10 @@ bool DRC::doTrackDrc( TRACK* aRefSeg, TRACK* aStart, bool testPads )
{ {
if( aRefSeg->GetWidth() < dsnSettings.m_TrackMinWidth ) if( aRefSeg->GetWidth() < dsnSettings.m_TrackMinWidth )
{ {
markers.push_back( fillMarker( aRefSeg, nullptr, wxPoint refsegMiddle = ( aRefSeg->GetStart() + aRefSeg->GetEnd() ) / 2;
DRCE_TOO_SMALL_TRACK_WIDTH, nullptr ) );
markers.push_back( newMarker( refsegMiddle, aRefSeg, DRCE_TOO_SMALL_TRACK_WIDTH ) );
if( !handleNewMarker() ) if( !handleNewMarker() )
return false; return false;
} }
@ -353,6 +354,8 @@ bool DRC::doTrackDrc( TRACK* aRefSeg, TRACK* aStart, bool testPads )
for( unsigned ii = 0; ii < pad_count; ++ii ) for( unsigned ii = 0; ii < pad_count; ++ii )
{ {
D_PAD* pad = pads[ii]; D_PAD* pad = pads[ii];
SEG padSeg( pad->GetPosition(), pad->GetPosition() );
/* No problem if pads are on another layer, /* No problem if pads are on another layer,
* But if a drill hole exists (a pad on a single layer can have a hole!) * But if a drill hole exists (a pad on a single layer can have a hole!)
@ -378,8 +381,9 @@ bool DRC::doTrackDrc( TRACK* aRefSeg, TRACK* aStart, bool testPads )
if( !checkClearanceSegmToPad( &dummypad, aRefSeg->GetWidth(), if( !checkClearanceSegmToPad( &dummypad, aRefSeg->GetWidth(),
netclass->GetClearance() ) ) netclass->GetClearance() ) )
{ {
markers.push_back( fillMarker( aRefSeg, pad, markers.push_back( newMarker( aRefSeg, pad, padSeg,
DRCE_TRACK_NEAR_THROUGH_HOLE, nullptr ) ); DRCE_TRACK_NEAR_THROUGH_HOLE ) );
if( !handleNewMarker() ) if( !handleNewMarker() )
return false; return false;
} }
@ -397,11 +401,10 @@ bool DRC::doTrackDrc( TRACK* aRefSeg, TRACK* aStart, bool testPads )
shape_pos = pad->ShapePos(); shape_pos = pad->ShapePos();
m_padToTestPos = shape_pos - origin; m_padToTestPos = shape_pos - origin;
if( !checkClearanceSegmToPad( pad, aRefSeg->GetWidth(), if( !checkClearanceSegmToPad( pad, aRefSeg->GetWidth(), aRefSeg->GetClearance( pad ) ) )
aRefSeg->GetClearance( pad ) ) )
{ {
markers.push_back( fillMarker( aRefSeg, pad, markers.push_back( newMarker( aRefSeg, pad, padSeg, DRCE_TRACK_NEAR_PAD ) );
DRCE_TRACK_NEAR_PAD, nullptr ) );
if( !handleNewMarker() ) if( !handleNewMarker() )
return false; return false;
} }
@ -445,14 +448,15 @@ bool DRC::doTrackDrc( TRACK* aRefSeg, TRACK* aStart, bool testPads )
{ {
delta = track->GetEnd() - track->GetStart(); delta = track->GetEnd() - track->GetStart();
segStartPoint = aRefSeg->GetStart() - track->GetStart(); segStartPoint = aRefSeg->GetStart() - track->GetStart();
wxPoint pos = aRefSeg->GetPosition();
if( track->Type() == PCB_VIA_T ) if( track->Type() == PCB_VIA_T )
{ {
// Test distance between two vias, i.e. two circles, trivial case // Test distance between two vias, i.e. two circles, trivial case
if( EuclideanNorm( segStartPoint ) < w_dist ) if( EuclideanNorm( segStartPoint ) < w_dist )
{ {
markers.push_back( fillMarker( aRefSeg, track, markers.push_back( newMarker( pos, aRefSeg, track, DRCE_VIA_NEAR_VIA ) );
DRCE_VIA_NEAR_VIA, nullptr ) );
if( !handleNewMarker() ) if( !handleNewMarker() )
return false; return false;
} }
@ -468,8 +472,8 @@ bool DRC::doTrackDrc( TRACK* aRefSeg, TRACK* aStart, bool testPads )
if( !checkMarginToCircle( segStartPoint, w_dist, delta.x ) ) if( !checkMarginToCircle( segStartPoint, w_dist, delta.x ) )
{ {
markers.push_back( fillMarker( track, aRefSeg, markers.push_back( newMarker( pos, aRefSeg, track, DRCE_VIA_NEAR_TRACK ) );
DRCE_VIA_NEAR_TRACK, nullptr ) );
if( !handleNewMarker() ) if( !handleNewMarker() )
return false; return false;
} }
@ -487,13 +491,15 @@ bool DRC::doTrackDrc( TRACK* aRefSeg, TRACK* aStart, bool testPads )
RotatePoint( &segStartPoint, m_segmAngle ); RotatePoint( &segStartPoint, m_segmAngle );
RotatePoint( &segEndPoint, m_segmAngle ); RotatePoint( &segEndPoint, m_segmAngle );
SEG seg( segStartPoint, segEndPoint );
if( track->Type() == PCB_VIA_T ) if( track->Type() == PCB_VIA_T )
{ {
if( checkMarginToCircle( segStartPoint, w_dist, m_segmLength ) ) if( checkMarginToCircle( segStartPoint, w_dist, m_segmLength ) )
continue; continue;
markers.push_back( fillMarker( aRefSeg, track, markers.push_back( newMarker( aRefSeg, track, seg, DRCE_TRACK_NEAR_VIA ) );
DRCE_TRACK_NEAR_VIA, nullptr ) );
if( !handleNewMarker() ) if( !handleNewMarker() )
return false; return false;
} }
@ -520,16 +526,16 @@ bool DRC::doTrackDrc( TRACK* aRefSeg, TRACK* aStart, bool testPads )
// Fine test : we consider the rounded shape of each end of the track segment: // Fine test : we consider the rounded shape of each end of the track segment:
if( segStartPoint.x >= 0 && segStartPoint.x <= m_segmLength ) if( segStartPoint.x >= 0 && segStartPoint.x <= m_segmLength )
{ {
markers.push_back( fillMarker( aRefSeg, track, markers.push_back( newMarker( aRefSeg, track, seg, DRCE_TRACK_ENDS1 ) );
DRCE_TRACK_ENDS1, nullptr ) );
if( !handleNewMarker() ) if( !handleNewMarker() )
return false; return false;
} }
if( !checkMarginToCircle( segStartPoint, w_dist, m_segmLength ) ) if( !checkMarginToCircle( segStartPoint, w_dist, m_segmLength ) )
{ {
markers.push_back( fillMarker( aRefSeg, track, markers.push_back( newMarker( aRefSeg, track, seg, DRCE_TRACK_ENDS2 ) );
DRCE_TRACK_ENDS2, nullptr ) );
if( !handleNewMarker() ) if( !handleNewMarker() )
return false; return false;
} }
@ -543,16 +549,16 @@ bool DRC::doTrackDrc( TRACK* aRefSeg, TRACK* aStart, bool testPads )
// Fine test : we consider the rounded shape of the ends // Fine test : we consider the rounded shape of the ends
if( segEndPoint.x >= 0 && segEndPoint.x <= m_segmLength ) if( segEndPoint.x >= 0 && segEndPoint.x <= m_segmLength )
{ {
markers.push_back( fillMarker( aRefSeg, track, markers.push_back( newMarker( aRefSeg, track, seg, DRCE_TRACK_ENDS3 ) );
DRCE_TRACK_ENDS3, nullptr ) );
if( !handleNewMarker() ) if( !handleNewMarker() )
return false; return false;
} }
if( !checkMarginToCircle( segEndPoint, w_dist, m_segmLength ) ) if( !checkMarginToCircle( segEndPoint, w_dist, m_segmLength ) )
{ {
markers.push_back( fillMarker( aRefSeg, track, markers.push_back( newMarker( aRefSeg, track, seg, DRCE_TRACK_ENDS4 ) );
DRCE_TRACK_ENDS4, nullptr ) );
if( !handleNewMarker() ) if( !handleNewMarker() )
return false; return false;
} }
@ -560,20 +566,20 @@ bool DRC::doTrackDrc( TRACK* aRefSeg, TRACK* aStart, bool testPads )
if( segStartPoint.x <= 0 && segEndPoint.x >= 0 ) if( segStartPoint.x <= 0 && segEndPoint.x >= 0 )
{ {
// the segment straddles the reference range (this actually only // the segment straddles the reference range (this actually only
// checks if it straddles the origin, because the other cases where already // checks if it straddles the origin, because the other cases where already
// handled) // handled)
// X.............X // X.............X
// O--REF--+ // O--REF--+
markers.push_back( fillMarker( aRefSeg, track, markers.push_back( newMarker( aRefSeg, track, seg, DRCE_TRACK_SEGMENTS_TOO_CLOSE ) );
DRCE_TRACK_SEGMENTS_TOO_CLOSE, nullptr ) );
if( !handleNewMarker() ) if( !handleNewMarker() )
return false; return false;
} }
} }
else if( segStartPoint.x == segEndPoint.x ) // perpendicular segments else if( segStartPoint.x == segEndPoint.x ) // perpendicular segments
{ {
if( ( segStartPoint.x <= ( -w_dist ) ) || ( segStartPoint.x >= ( m_segmLength + w_dist ) ) ) if( segStartPoint.x <= -w_dist || segStartPoint.x >= m_segmLength + w_dist )
continue; continue;
// Test if segments are crossing // Test if segments are crossing
@ -582,8 +588,8 @@ bool DRC::doTrackDrc( TRACK* aRefSeg, TRACK* aStart, bool testPads )
if( ( segStartPoint.y < 0 ) && ( segEndPoint.y > 0 ) ) if( ( segStartPoint.y < 0 ) && ( segEndPoint.y > 0 ) )
{ {
markers.push_back( fillMarker( aRefSeg, track, markers.push_back( newMarker( aRefSeg, track, seg, DRCE_TRACKS_CROSSING ) );
DRCE_TRACKS_CROSSING, nullptr ) );
if( !handleNewMarker() ) if( !handleNewMarker() )
return false; return false;
} }
@ -591,15 +597,15 @@ bool DRC::doTrackDrc( TRACK* aRefSeg, TRACK* aStart, bool testPads )
// At this point the drc error is due to an end near a reference segm end // At this point the drc error is due to an end near a reference segm end
if( !checkMarginToCircle( segStartPoint, w_dist, m_segmLength ) ) if( !checkMarginToCircle( segStartPoint, w_dist, m_segmLength ) )
{ {
markers.push_back( fillMarker( aRefSeg, track, markers.push_back( newMarker( aRefSeg, track, seg, DRCE_ENDS_PROBLEM1 ) );
DRCE_ENDS_PROBLEM1, nullptr ) );
if( !handleNewMarker() ) if( !handleNewMarker() )
return false; return false;
} }
if( !checkMarginToCircle( segEndPoint, w_dist, m_segmLength ) ) if( !checkMarginToCircle( segEndPoint, w_dist, m_segmLength ) )
{ {
markers.push_back( fillMarker( aRefSeg, track, markers.push_back( newMarker( aRefSeg, track, seg, DRCE_ENDS_PROBLEM2 ) );
DRCE_ENDS_PROBLEM2, nullptr ) );
if( !handleNewMarker() ) if( !handleNewMarker() )
return false; return false;
} }
@ -627,8 +633,8 @@ bool DRC::doTrackDrc( TRACK* aRefSeg, TRACK* aStart, bool testPads )
if( !checkLine( segStartPoint, segEndPoint ) ) if( !checkLine( segStartPoint, segEndPoint ) )
{ {
markers.push_back( fillMarker( aRefSeg, track, markers.push_back( newMarker( aRefSeg, track, seg, DRCE_ENDS_PROBLEM3 ) );
DRCE_ENDS_PROBLEM3, nullptr ) );
if( !handleNewMarker() ) if( !handleNewMarker() )
return false; return false;
} }
@ -656,16 +662,16 @@ bool DRC::doTrackDrc( TRACK* aRefSeg, TRACK* aStart, bool testPads )
if( !checkMarginToCircle( relStartPos, w_dist, delta.x ) ) if( !checkMarginToCircle( relStartPos, w_dist, delta.x ) )
{ {
markers.push_back( fillMarker( aRefSeg, track, markers.push_back( newMarker( aRefSeg, track, seg, DRCE_ENDS_PROBLEM4 ) );
DRCE_ENDS_PROBLEM4, nullptr ) );
if( !handleNewMarker() ) if( !handleNewMarker() )
return false; return false;
} }
if( !checkMarginToCircle( relEndPos, w_dist, delta.x ) ) if( !checkMarginToCircle( relEndPos, w_dist, delta.x ) )
{ {
markers.push_back( fillMarker( aRefSeg, track, markers.push_back( newMarker( aRefSeg, track, seg, DRCE_ENDS_PROBLEM5 ) );
DRCE_ENDS_PROBLEM5, nullptr ) );
if( !handleNewMarker() ) if( !handleNewMarker() )
return false; return false;
} }
@ -682,26 +688,20 @@ bool DRC::doTrackDrc( TRACK* aRefSeg, TRACK* aStart, bool testPads )
for( ZONE_CONTAINER* zone : m_pcb->Zones() ) for( ZONE_CONTAINER* zone : m_pcb->Zones() )
{ {
if( zone->GetIsKeepout() if( zone->GetFilledPolysList().IsEmpty() || zone->GetIsKeepout() )
|| zone->GetLayer() != aRefSeg->GetLayer() continue;
|| ( aRefSeg->GetNetCode() == zone->GetNetCode() && aRefSeg->GetNetCode() > 0 ) )
{ if( !( layerMask & zone->GetLayerSet() ).any() )
continue;
if( zone->GetNetCode() && zone->GetNetCode() == net_code_ref )
continue; continue;
}
int clearance = zone->GetClearance( aRefSeg ); int clearance = zone->GetClearance( aRefSeg );
SHAPE_POLY_SET* outline; SHAPE_POLY_SET* outline = const_cast<SHAPE_POLY_SET*>( &zone->GetFilledPolysList() );
if( zone->IsFilled() )
outline = const_cast<SHAPE_POLY_SET*>( &zone->GetFilledPolysList() );
else
outline = zone->Outline();
if( outline->Distance( refSeg, aRefSeg->GetWidth() ) < clearance ) if( outline->Distance( refSeg, aRefSeg->GetWidth() ) < clearance )
{ addMarkerToPcb( newMarker( aRefSeg, zone, DRCE_TRACK_NEAR_ZONE ) );
addMarkerToPcb( fillMarker( aRefSeg, zone, DRCE_TRACK_NEAR_ZONE, m_currentMarker ) );
m_currentMarker = nullptr;
}
} }
if( markers.size() > 0 ) if( markers.size() > 0 )
@ -766,10 +766,8 @@ bool DRC::doEdgeZoneDrc( ZONE_CONTAINER* aArea, int aCornerIndex )
// test for ending line inside area_to_test // test for ending line inside area_to_test
if( area_to_test->Outline()->Contains( end ) ) if( area_to_test->Outline()->Contains( end ) )
{ {
// COPPERAREA_COPPERAREA error: corner inside copper area wxPoint pos( end.x, end.y );
m_currentMarker = fillMarker( aArea, static_cast<wxPoint>( end ), m_currentMarker = newMarker( pos, aArea, area_to_test, COPPERAREA_INSIDE_COPPERAREA );
COPPERAREA_INSIDE_COPPERAREA,
m_currentMarker );
return false; return false;
} }
@ -801,9 +799,8 @@ bool DRC::doEdgeZoneDrc( ZONE_CONTAINER* aArea, int aCornerIndex )
if( d < zone_clearance ) if( d < zone_clearance )
{ {
// COPPERAREA_COPPERAREA error : edge intersect or too close // COPPERAREA_COPPERAREA error : edge intersect or too close
m_currentMarker = fillMarker( aArea, wxPoint( x, y ), m_currentMarker = newMarker( wxPoint( x, y ), aArea, area_to_test,
COPPERAREA_CLOSE_TO_COPPERAREA, COPPERAREA_CLOSE_TO_COPPERAREA );
m_currentMarker );
return false; return false;
} }

View File

@ -118,21 +118,17 @@ wxString DRC_ITEM::GetErrorText() const
case DRCE_VIA_INSIDE_KEEPOUT: case DRCE_VIA_INSIDE_KEEPOUT:
return wxString( _( "Via inside keepout area" ) ); return wxString( _( "Via inside keepout area" ) );
case DRCE_TRACK_INSIDE_KEEPOUT: case DRCE_TRACK_INSIDE_KEEPOUT:
return wxString( _( "Track inside keepout area" ) ); return wxString( _( "Track inside keepout area" ) );
case DRCE_PAD_INSIDE_KEEPOUT: case DRCE_PAD_INSIDE_KEEPOUT:
return wxString( _( "Pad inside keepout area" ) ); return wxString( _( "Pad inside keepout area" ) );
case DRCE_VIA_INSIDE_TEXT: case DRCE_VIA_NEAR_COPPER:
return wxString( _( "Via inside text" ) ); return wxString( _( "Via too close to copper item" ) );
case DRCE_TRACK_NEAR_COPPER:
case DRCE_TRACK_INSIDE_TEXT: return wxString( _( "Track too close to copper item" ) );
return wxString( _( "Track inside text" ) ); case DRCE_PAD_NEAR_COPPER:
return wxString( _( "Pad too close to copper item" ) );
case DRCE_PAD_INSIDE_TEXT:
return wxString( _( "Pad inside text" ) );
case DRCE_OVERLAPPING_FOOTPRINTS: case DRCE_OVERLAPPING_FOOTPRINTS:
return wxString( _( "Courtyards overlap" ) ); return wxString( _( "Courtyards overlap" ) );

View File

@ -36,6 +36,7 @@
#include <common.h> #include <common.h>
#include <pcbnew.h> #include <pcbnew.h>
#include <board_design_settings.h> #include <board_design_settings.h>
#include <geometry/geometry_utils.h>
#include <pcb_edit_frame.h> #include <pcb_edit_frame.h>
#include <drc.h> #include <drc.h>
#include <class_pad.h> #include <class_pad.h>
@ -48,161 +49,96 @@
#include <class_board_item.h> #include <class_board_item.h>
MARKER_PCB* DRC::fillMarker( TRACK* aTrack, BOARD_ITEM* bItem, int aErrorCode, MARKER_PCB* fillMe ) const int EPSILON = Mils2iu( 5 );
MARKER_PCB* DRC::newMarker( TRACK* aTrack, ZONE_CONTAINER* aConflictZone, int aErrorCode )
{ {
EDA_UNITS_T units = m_pcbEditorFrame->GetUserUnits(); auto conflictOutline = const_cast<SHAPE_POLY_SET*>( &aConflictZone->GetFilledPolysList() );
const int EPSILON = Mils2iu( 5 ); wxPoint markerPos;
wxPoint pt1 = aTrack->GetPosition();
wxPoint pt2 = aTrack->GetEnd();
wxPoint posA; // If the mid-point is in the zone, then that's a fine place for the marker
wxPoint posB = wxPoint(); if( conflictOutline->Distance( ( pt1 + pt2 ) / 2 ) == 0 )
markerPos = ( pt1 + pt2 ) / 2;
if( bItem ) // aItem might be NULL // Otherwise do a binary search for a "good enough" marker location
{
if( bItem->Type() == PCB_PAD_T )
{
posB = posA = ((D_PAD*)bItem)->GetPosition();
}
else if( bItem->Type() == PCB_VIA_T )
{
posB = posA = ((VIA*)bItem)->GetPosition();
}
else if( bItem->Type() == PCB_TRACE_T )
{
TRACK* bTrack = (TRACK*) bItem;
SEG bTrackSeg( bTrack->GetPosition(), bTrack->GetEnd() );
wxPoint pt1 = aTrack->GetPosition();
wxPoint pt2 = aTrack->GetEnd();
// Do a binary search for a "good enough" marker location
while( GetLineLength( pt1, pt2 ) > EPSILON )
{
if( bTrackSeg.Distance( pt1 ) < bTrackSeg.Distance( pt2 ) )
pt2 = ( pt1 + pt2 ) / 2;
else
pt1 = ( pt1 + pt2 ) / 2;
}
// Once we're within EPSILON pt1 and pt2 are "equivalent"
posA = pt1;
posB = bTrack->GetPosition();
}
else if( bItem->Type() == PCB_ZONE_T || bItem->Type() == PCB_ZONE_AREA_T )
{
ZONE_CONTAINER* zone = static_cast<ZONE_CONTAINER*>( bItem );
SHAPE_POLY_SET* outline;
if( zone->IsFilled() )
outline = const_cast<SHAPE_POLY_SET*>( &zone->GetFilledPolysList() );
else
outline = zone->Outline();
wxPoint pt1 = aTrack->GetPosition();
wxPoint pt2 = aTrack->GetEnd();
// If the mid-point is in the zone, then that's a fine place for the marker
if( outline->Distance( ( pt1 + pt2 ) / 2 ) == 0 )
posA = ( pt1 + pt2 ) / 2;
// Otherwise do a binary search for a "good enough" marker location
else
{
while( GetLineLength( pt1, pt2 ) > EPSILON )
{
if( outline->Distance( pt1 ) < outline->Distance( pt2 ) )
pt2 = ( pt1 + pt2 ) / 2;
else
pt1 = ( pt1 + pt2 ) / 2;
}
// Once we're within EPSILON pt1 and pt2 are "equivalent"
posA = pt1;
}
posB = ((ZONE_CONTAINER*)bItem)->GetPosition();
}
}
else else
posA = aTrack->GetPosition();
if( fillMe )
fillMe->SetData( units, aErrorCode, posA, aTrack, aTrack->GetPosition(), bItem, posB );
else
fillMe = new MARKER_PCB( units, aErrorCode, posA, aTrack, aTrack->GetPosition(), bItem, posB );
return fillMe;
}
MARKER_PCB* DRC::fillMarker( D_PAD* aPad, BOARD_ITEM* aItem, int aErrorCode, MARKER_PCB* fillMe )
{
EDA_UNITS_T units = m_pcbEditorFrame->GetUserUnits();
wxPoint posA = aPad->GetPosition();
wxPoint posB;
if( aItem )
{ {
switch( aItem->Type() ) while( GetLineLength( pt1, pt2 ) > EPSILON )
{ {
case PCB_PAD_T: if( conflictOutline->Distance( pt1 ) < conflictOutline->Distance( pt2 ) )
posB = ((D_PAD*)aItem)->GetPosition(); pt2 = ( pt1 + pt2 ) / 2;
break; else
pt1 = ( pt1 + pt2 ) / 2;
case PCB_TEXT_T:
posB = ((TEXTE_PCB*)aItem)->GetPosition();
break;
case PCB_MODULE_TEXT_T:
posB = ((TEXTE_MODULE*)aItem)->GetPosition();
break;
default:
wxLogDebug( wxT("fillMarker: unsupported item") );
break;
} }
// Once we're within EPSILON pt1 and pt2 are "equivalent"
markerPos = pt1;
} }
if( fillMe ) return new MARKER_PCB( m_pcbEditorFrame->GetUserUnits(), aErrorCode, markerPos,
fillMe->SetData( units, aErrorCode, posA, aPad, posA, aItem, posB ); aTrack, aTrack->GetPosition(),
else aConflictZone, aConflictZone->GetPosition() );
fillMe = new MARKER_PCB( units, aErrorCode, posA, aPad, posA, aItem, posB );
return fillMe;
} }
MARKER_PCB* DRC::fillMarker(BOARD_ITEM *aItem, const wxPoint &aPos, int aErrorCode, MARKER_PCB* DRC::newMarker( TRACK* aTrack, BOARD_ITEM* aConflitItem, const SEG& aConflictSeg,
MARKER_PCB *fillMe) int aErrorCode )
{ {
return fillMarker(aPos, aItem, nullptr, aErrorCode, fillMe ); wxPoint markerPos;
wxPoint pt1 = aTrack->GetPosition();
wxPoint pt2 = aTrack->GetEnd();
// Do a binary search along the track for a "good enough" marker location
while( GetLineLength( pt1, pt2 ) > EPSILON )
{
if( aConflictSeg.Distance( pt1 ) < aConflictSeg.Distance( pt2 ) )
pt2 = ( pt1 + pt2 ) / 2;
else
pt1 = ( pt1 + pt2 ) / 2;
}
// Once we're within EPSILON pt1 and pt2 are "equivalent"
markerPos = pt1;
return new MARKER_PCB( m_pcbEditorFrame->GetUserUnits(), aErrorCode, markerPos,
aTrack, aTrack->GetPosition(),
aConflitItem, aConflitItem->GetPosition() );
} }
MARKER_PCB* DRC::fillMarker( const wxPoint& aPos, BOARD_ITEM* aItem, BOARD_ITEM* bItem, MARKER_PCB* DRC::newMarker( D_PAD* aPad, BOARD_ITEM* aConflictItem, int aErrorCode )
int aErrorCode, MARKER_PCB* fillMe )
{ {
EDA_UNITS_T units = m_pcbEditorFrame->GetUserUnits(); return new MARKER_PCB( m_pcbEditorFrame->GetUserUnits(), aErrorCode, aPad->GetPosition(),
aPad, aPad->GetPosition(),
if( fillMe ) aConflictItem, aConflictItem->GetPosition() );
fillMe->SetData( units, aErrorCode, aPos, aItem, aPos, bItem, aPos );
else
fillMe = new MARKER_PCB( units, aErrorCode, aPos, aItem, aPos, bItem, aPos );
return fillMe;
} }
MARKER_PCB* DRC::fillMarker( int aErrorCode, const wxString& aMessage, MARKER_PCB* fillMe ) MARKER_PCB* DRC::newMarker(const wxPoint &aPos, BOARD_ITEM *aItem, int aErrorCode )
{ {
wxPoint posA; // not displayed return new MARKER_PCB( m_pcbEditorFrame->GetUserUnits(), aErrorCode, aPos,
aItem, aItem->GetPosition(), nullptr, wxPoint() );
if( fillMe ) }
fillMe->SetData( aErrorCode, posA, aMessage, posA );
else
fillMe = new MARKER_PCB( aErrorCode, posA, aMessage, posA ); MARKER_PCB* DRC::newMarker( const wxPoint &aPos, BOARD_ITEM* aItem, BOARD_ITEM* bItem,
int aErrorCode )
fillMe->SetShowNoCoordinate(); {
return new MARKER_PCB( m_pcbEditorFrame->GetUserUnits(), aErrorCode, aPos,
return fillMe; aItem, aItem->GetPosition(), bItem, bItem->GetPosition() );
}
MARKER_PCB* DRC::newMarker( int aErrorCode, const wxString& aMessage )
{
MARKER_PCB* marker = new MARKER_PCB( aErrorCode, wxPoint(), aMessage, wxPoint() );
marker->SetShowNoCoordinate();
return marker;
} }