/* * Function Distance * Calculates the distance between a segment and a polygon (with holes): * param aStart is the starting point of the segment. * param aEnd is the ending point of the segment. * param aWidth is the width of the segment. * return distance between the segment and outline. * 0 if segment intersects or is inside */ int CPolyLine::Distance( wxPoint aStart, wxPoint aEnd, int aWidth ) { // We calculate the min dist between the segment and each outline segment // However, if the segment to test is inside the outline, and does not cross // any edge, it can be seen outside the polygon. // Therefore test if a segment end is inside ( testing only one end is enough ) if( TestPointInside( aStart.x, aStart.y ) ) return 0; int distance = INT_MAX; int polycount = GetContoursCount(); for( int icont = 0; icont < polycount; icont++ ) { int ic_start = GetContourStart( icont ); int ic_end = GetContourEnd( icont ); // now test spacing between area outline and segment for( int ic2 = ic_start; ic2 <= ic_end; ic2++ ) { int bx1 = GetX( ic2 ); int by1 = GetY( ic2 ); int bx2, by2; if( ic2 == ic_end ) { bx2 = GetX( ic_start ); by2 = GetY( ic_start ); } else { bx2 = GetX( ic2 + 1 ); by2 = GetY( ic2 + 1 ); } int d = GetClearanceBetweenSegments( bx1, by1, bx2, by2, 0, aStart.x, aStart.y, aEnd.x, aEnd.y, aWidth, 1, // min clearance, should be > 0 NULL, NULL ); if( distance > d ) distance = d; if( distance <= 0 ) return 0; } } return distance; }
bool DRC::doEdgeZoneDrc( ZONE_CONTAINER* aArea, int aCornerIndex ) { if( !aArea->IsOnCopperLayer() ) // Cannot have a Drc error if not on copper layer return true; wxPoint start = aArea->GetCornerPosition( aCornerIndex ); wxPoint end; // Search the end point of the edge starting at aCornerIndex if( aArea->Outline()->m_CornersList[aCornerIndex].end_contour == false && aCornerIndex < (aArea->GetNumCorners() - 1) ) { end = aArea->GetCornerPosition( aCornerIndex + 1 ); } else // aCornerIndex is the last corner of an outline. // the corresponding end point of the segment is the first corner of the outline { int ii = aCornerIndex - 1; end = aArea->GetCornerPosition( ii ); while( ii >= 0 ) { if( aArea->Outline()->m_CornersList[ii].end_contour ) break; end = aArea->GetCornerPosition( ii ); ii--; } } // iterate through all areas for( int ia2 = 0; ia2 < m_pcb->GetAreaCount(); ia2++ ) { ZONE_CONTAINER* area_to_test = m_pcb->GetArea( ia2 ); int zone_clearance = std::max( area_to_test->GetZoneClearance(), aArea->GetZoneClearance() ); // test for same layer if( area_to_test->GetLayer() != aArea->GetLayer() ) continue; // Test for same net if( ( aArea->GetNetCode() == area_to_test->GetNetCode() ) && (aArea->GetNetCode() >= 0) ) continue; // test for same priority if( area_to_test->GetPriority() != aArea->GetPriority() ) continue; // test for same type if( area_to_test->GetIsKeepout() != aArea->GetIsKeepout() ) continue; // For keepout, there is no clearance, so use a minimal value for it // use 1, not 0 as value to avoid some issues in tests if( area_to_test->GetIsKeepout() ) zone_clearance = 1; // test for ending line inside area_to_test if( area_to_test->Outline()->TestPointInside( end.x, end.y ) ) { // COPPERAREA_COPPERAREA error: corner inside copper area m_currentMarker = fillMarker( aArea, end, COPPERAREA_INSIDE_COPPERAREA, m_currentMarker ); return false; } // now test spacing between areas int ax1 = start.x; int ay1 = start.y; int ax2 = end.x; int ay2 = end.y; for( int icont2 = 0; icont2 < area_to_test->Outline()->GetContoursCount(); icont2++ ) { int ic_start2 = area_to_test->Outline()->GetContourStart( icont2 ); int ic_end2 = area_to_test->Outline()->GetContourEnd( icont2 ); for( int ic2 = ic_start2; ic2<=ic_end2; ic2++ ) { int bx1 = area_to_test->Outline()->GetX( ic2 ); int by1 = area_to_test->Outline()->GetY( ic2 ); int bx2, by2; if( ic2 == ic_end2 ) { bx2 = area_to_test->Outline()->GetX( ic_start2 ); by2 = area_to_test->Outline()->GetY( ic_start2 ); } else { bx2 = area_to_test->Outline()->GetX( ic2 + 1 ); by2 = area_to_test->Outline()->GetY( ic2 + 1 ); } int x, y; // variables containing the intersecting point coordinates int d = GetClearanceBetweenSegments( bx1, by1, bx2, by2, 0, ax1, ay1, ax2, ay2, 0, zone_clearance, &x, &y ); if( d < zone_clearance ) { // COPPERAREA_COPPERAREA error : edge intersect or too close m_currentMarker = fillMarker( aArea, wxPoint( x, y ), COPPERAREA_CLOSE_TO_COPPERAREA, m_currentMarker ); return false; } } } } return true; }
int BOARD::Test_Drc_Areas_Outlines_To_Areas_Outlines( ZONE_CONTAINER* aArea_To_Examine, bool aCreate_Markers ) { int nerrors = 0; // iterate through all areas for( int ia = 0; ia < GetAreaCount(); ia++ ) { ZONE_CONTAINER* Area_Ref = GetArea( ia ); CPolyLine* refSmoothedPoly = Area_Ref->GetSmoothedPoly(); if( !Area_Ref->IsOnCopperLayer() ) continue; // When testing only a single area, skip all others if( aArea_To_Examine && (aArea_To_Examine != Area_Ref) ) continue; for( int ia2 = 0; ia2 < GetAreaCount(); ia2++ ) { ZONE_CONTAINER* area_to_test = GetArea( ia2 ); CPolyLine* testSmoothedPoly = area_to_test->GetSmoothedPoly(); if( Area_Ref == area_to_test ) continue; // test for same layer if( Area_Ref->GetLayer() != area_to_test->GetLayer() ) continue; // Test for same net if( Area_Ref->GetNetCode() == area_to_test->GetNetCode() && Area_Ref->GetNetCode() >= 0 ) continue; // test for different priorities if( Area_Ref->GetPriority() != area_to_test->GetPriority() ) continue; // test for different types if( Area_Ref->GetIsKeepout() != area_to_test->GetIsKeepout() ) continue; // Examine a candidate zone: compare area_to_test to Area_Ref // Get clearance used in zone to zone test. The policy used to // obtain that value is now part of the zone object itself by way of // ZONE_CONTAINER::GetClearance(). int zone2zoneClearance = Area_Ref->GetClearance( area_to_test ); // Keepout areas have no clearance, so set zone2zoneClearance to 1 // ( zone2zoneClearance = 0 can create problems in test functions) if( Area_Ref->GetIsKeepout() ) zone2zoneClearance = 1; // test for some corners of Area_Ref inside area_to_test for( int ic = 0; ic < refSmoothedPoly->GetCornersCount(); ic++ ) { int x = refSmoothedPoly->GetX( ic ); int y = refSmoothedPoly->GetY( ic ); if( testSmoothedPoly->TestPointInside( x, y ) ) { // COPPERAREA_COPPERAREA error: copper area ref corner inside copper area if( aCreate_Markers ) { wxString msg1 = Area_Ref->GetSelectMenuText(); wxString msg2 = area_to_test->GetSelectMenuText(); MARKER_PCB* marker = new MARKER_PCB( COPPERAREA_INSIDE_COPPERAREA, wxPoint( x, y ), msg1, wxPoint( x, y ), msg2, wxPoint( x, y ) ); Add( marker ); } nerrors++; } } // test for some corners of area_to_test inside Area_Ref for( int ic2 = 0; ic2 < testSmoothedPoly->GetCornersCount(); ic2++ ) { int x = testSmoothedPoly->GetX( ic2 ); int y = testSmoothedPoly->GetY( ic2 ); if( refSmoothedPoly->TestPointInside( x, y ) ) { // COPPERAREA_COPPERAREA error: copper area corner inside copper area ref if( aCreate_Markers ) { wxString msg1 = area_to_test->GetSelectMenuText(); wxString msg2 = Area_Ref->GetSelectMenuText(); MARKER_PCB* marker = new MARKER_PCB( COPPERAREA_INSIDE_COPPERAREA, wxPoint( x, y ), msg1, wxPoint( x, y ), msg2, wxPoint( x, y ) ); Add( marker ); } nerrors++; } } // now test spacing between areas for( int icont = 0; icont < refSmoothedPoly->GetContoursCount(); icont++ ) { int ic_start = refSmoothedPoly->GetContourStart( icont ); int ic_end = refSmoothedPoly->GetContourEnd( icont ); for( int ic = ic_start; ic<=ic_end; ic++ ) { int ax1 = refSmoothedPoly->GetX( ic ); int ay1 = refSmoothedPoly->GetY( ic ); int ax2, ay2; if( ic == ic_end ) { ax2 = refSmoothedPoly->GetX( ic_start ); ay2 = refSmoothedPoly->GetY( ic_start ); } else { ax2 = refSmoothedPoly->GetX( ic + 1 ); ay2 = refSmoothedPoly->GetY( ic + 1 ); } for( int icont2 = 0; icont2 < testSmoothedPoly->GetContoursCount(); icont2++ ) { int ic_start2 = testSmoothedPoly->GetContourStart( icont2 ); int ic_end2 = testSmoothedPoly->GetContourEnd( icont2 ); for( int ic2 = ic_start2; ic2<=ic_end2; ic2++ ) { int bx1 = testSmoothedPoly->GetX( ic2 ); int by1 = testSmoothedPoly->GetY( ic2 ); int bx2, by2; if( ic2 == ic_end2 ) { bx2 = testSmoothedPoly->GetX( ic_start2 ); by2 = testSmoothedPoly->GetY( ic_start2 ); } else { bx2 = testSmoothedPoly->GetX( ic2 + 1 ); by2 = testSmoothedPoly->GetY( ic2 + 1 ); } int x, y; int d = GetClearanceBetweenSegments( bx1, by1, bx2, by2, 0, ax1, ay1, ax2, ay2, 0, zone2zoneClearance, &x, &y ); if( d < zone2zoneClearance ) { // COPPERAREA_COPPERAREA error : intersect or too close if( aCreate_Markers ) { wxString msg1 = Area_Ref->GetSelectMenuText(); wxString msg2 = area_to_test->GetSelectMenuText(); MARKER_PCB* marker = new MARKER_PCB( COPPERAREA_CLOSE_TO_COPPERAREA, wxPoint( x, y ), msg1, wxPoint( x, y ), msg2, wxPoint( x, y ) ); Add( marker ); } nerrors++; } } } } } } } return nerrors; }
bool DRC::doEdgeZoneDrc( ZONE_CONTAINER* aArea, int aCornerIndex ) { if( !aArea->IsOnCopperLayer() ) // Cannot have a Drc error if not on copper layer return true; wxString str; wxPoint start = aArea->GetCornerPosition( aCornerIndex ); wxPoint end; // Search the end point of the edge starting at aCornerIndex if( aArea->m_Poly->corner[aCornerIndex].end_contour == false && aCornerIndex < (aArea->GetNumCorners() - 1) ) { end = aArea->GetCornerPosition( aCornerIndex + 1 ); } else // aCornerIndex is the last corner of an outline. // the corresponding end point of the segment is the first corner of the outline { int ii = aCornerIndex - 1; end = aArea->GetCornerPosition( ii ); while( ii >= 0 ) { if( aArea->m_Poly->corner[ii].end_contour ) break; end = aArea->GetCornerPosition( ii ); ii--; } } // iterate through all areas for( int ia2 = 0; ia2 < m_pcb->GetAreaCount(); ia2++ ) { ZONE_CONTAINER* Area_To_Test = m_pcb->GetArea( ia2 ); int zone_clearance = max( Area_To_Test->m_ZoneClearance, aArea->m_ZoneClearance ); // test for same layer if( Area_To_Test->GetLayer() != aArea->GetLayer() ) continue; // Test for same net if( ( aArea->GetNet() == Area_To_Test->GetNet() ) && (aArea->GetNet() >= 0) ) continue; // test for same priority if( Area_To_Test->GetPriority() != aArea->GetPriority() ) continue; // test for ending line inside Area_To_Test int x = end.x; int y = end.y; if( Area_To_Test->m_Poly->TestPointInside( x, y ) ) { // COPPERAREA_COPPERAREA error: corner inside copper area m_currentMarker = fillMarker( aArea, wxPoint( x, y ), COPPERAREA_INSIDE_COPPERAREA, m_currentMarker ); return false; } // now test spacing between areas int astyle = CPolyLine::STRAIGHT; int ax1 = start.x; int ay1 = start.y; int ax2 = end.x; int ay2 = end.y; for( int icont2 = 0; icont2 < Area_To_Test->m_Poly->GetNumContours(); icont2++ ) { int ic_start2 = Area_To_Test->m_Poly->GetContourStart( icont2 ); int ic_end2 = Area_To_Test->m_Poly->GetContourEnd( icont2 ); for( int ic2 = ic_start2; ic2<=ic_end2; ic2++ ) { int bx1 = Area_To_Test->m_Poly->GetX( ic2 ); int by1 = Area_To_Test->m_Poly->GetY( ic2 ); int bx2, by2; if( ic2 == ic_end2 ) { bx2 = Area_To_Test->m_Poly->GetX( ic_start2 ); by2 = Area_To_Test->m_Poly->GetY( ic_start2 ); } else { bx2 = Area_To_Test->m_Poly->GetX( ic2 + 1 ); by2 = Area_To_Test->m_Poly->GetY( ic2 + 1 ); } int bstyle = Area_To_Test->m_Poly->GetSideStyle( ic2 ); int x, y; int d = GetClearanceBetweenSegments( bx1, by1, bx2, by2, bstyle, 0, ax1, ay1, ax2, ay2, astyle, 0, zone_clearance, &x, &y ); if( d < zone_clearance ) { // COPPERAREA_COPPERAREA error : edge intersect or too close m_currentMarker = fillMarker( aArea, wxPoint( x, y ), COPPERAREA_CLOSE_TO_COPPERAREA, m_currentMarker ); return false; } } } } return true; }
bool DRC::doEdgeZoneDrc( ZONE_CONTAINER* aArea, int aCornerIndex ) { if( !aArea->IsOnCopperLayer() ) // Cannot have a Drc error if not on copper layer return true; // Get polygon, contour and vertex index. SHAPE_POLY_SET::VERTEX_INDEX index; // If the vertex does not exist, there is no conflict if( !aArea->Outline()->GetRelativeIndices( aCornerIndex, &index ) ) return true; // Retrieve the selected contour SHAPE_LINE_CHAIN contour; contour = aArea->Outline()->Polygon( index.m_polygon )[index.m_contour]; // Retrieve the segment that starts at aCornerIndex-th corner. SEG selectedSegment = contour.Segment( index.m_vertex ); VECTOR2I start = selectedSegment.A; VECTOR2I end = selectedSegment.B; // iterate through all areas for( int ia2 = 0; ia2 < m_pcb->GetAreaCount(); ia2++ ) { ZONE_CONTAINER* area_to_test = m_pcb->GetArea( ia2 ); int zone_clearance = std::max( area_to_test->GetZoneClearance(), aArea->GetZoneClearance() ); // test for same layer if( area_to_test->GetLayer() != aArea->GetLayer() ) continue; // Test for same net if( ( aArea->GetNetCode() == area_to_test->GetNetCode() ) && (aArea->GetNetCode() >= 0) ) continue; // test for same priority if( area_to_test->GetPriority() != aArea->GetPriority() ) continue; // test for same type if( area_to_test->GetIsKeepout() != aArea->GetIsKeepout() ) continue; // For keepout, there is no clearance, so use a minimal value for it // use 1, not 0 as value to avoid some issues in tests if( area_to_test->GetIsKeepout() ) zone_clearance = 1; // test for ending line inside area_to_test if( area_to_test->Outline()->Contains( end ) ) { // COPPERAREA_COPPERAREA error: corner inside copper area m_currentMarker = fillMarker( aArea, static_cast<wxPoint>( end ), COPPERAREA_INSIDE_COPPERAREA, m_currentMarker ); return false; } // now test spacing between areas int ax1 = start.x; int ay1 = start.y; int ax2 = end.x; int ay2 = end.y; // Iterate through all edges in the polygon. SHAPE_POLY_SET::SEGMENT_ITERATOR iterator; for( iterator = area_to_test->Outline()->IterateSegmentsWithHoles(); iterator; iterator++ ) { SEG segment = *iterator; int bx1 = segment.A.x; int by1 = segment.A.y; int bx2 = segment.B.x; int by2 = segment.B.y; int x, y; // variables containing the intersecting point coordinates int d = GetClearanceBetweenSegments( bx1, by1, bx2, by2, 0, ax1, ay1, ax2, ay2, 0, zone_clearance, &x, &y ); if( d < zone_clearance ) { // COPPERAREA_COPPERAREA error : edge intersect or too close m_currentMarker = fillMarker( aArea, wxPoint( x, y ), COPPERAREA_CLOSE_TO_COPPERAREA, m_currentMarker ); return false; } } } return true; }
int BOARD::Test_Drc_Areas_Outlines_To_Areas_Outlines( ZONE_CONTAINER* aArea_To_Examine, bool aCreate_Markers ) { int nerrors = 0; // iterate through all areas for( int ia = 0; ia < GetAreaCount(); ia++ ) { ZONE_CONTAINER* Area_Ref = GetArea( ia ); SHAPE_POLY_SET* refSmoothedPoly = Area_Ref->GetSmoothedPoly(); if( !Area_Ref->IsOnCopperLayer() ) continue; // When testing only a single area, skip all others if( aArea_To_Examine && (aArea_To_Examine != Area_Ref) ) continue; for( int ia2 = 0; ia2 < GetAreaCount(); ia2++ ) { ZONE_CONTAINER* area_to_test = GetArea( ia2 ); SHAPE_POLY_SET* testSmoothedPoly = area_to_test->GetSmoothedPoly(); if( Area_Ref == area_to_test ) continue; // test for same layer if( Area_Ref->GetLayer() != area_to_test->GetLayer() ) continue; // Test for same net if( Area_Ref->GetNetCode() == area_to_test->GetNetCode() && Area_Ref->GetNetCode() >= 0 ) continue; // test for different priorities if( Area_Ref->GetPriority() != area_to_test->GetPriority() ) continue; // test for different types if( Area_Ref->GetIsKeepout() != area_to_test->GetIsKeepout() ) continue; // Examine a candidate zone: compare area_to_test to Area_Ref // Get clearance used in zone to zone test. The policy used to // obtain that value is now part of the zone object itself by way of // ZONE_CONTAINER::GetClearance(). int zone2zoneClearance = Area_Ref->GetClearance( area_to_test ); // Keepout areas have no clearance, so set zone2zoneClearance to 1 // ( zone2zoneClearance = 0 can create problems in test functions) if( Area_Ref->GetIsKeepout() ) zone2zoneClearance = 1; // test for some corners of Area_Ref inside area_to_test for( auto iterator = refSmoothedPoly->IterateWithHoles(); iterator; iterator++ ) { VECTOR2I currentVertex = *iterator; if( testSmoothedPoly->Contains( currentVertex ) ) { // COPPERAREA_COPPERAREA error: copper area ref corner inside copper area if( aCreate_Markers ) { int x = currentVertex.x; int y = currentVertex.y; wxString msg1 = Area_Ref->GetSelectMenuText(); wxString msg2 = area_to_test->GetSelectMenuText(); MARKER_PCB* marker = new MARKER_PCB( COPPERAREA_INSIDE_COPPERAREA, wxPoint( x, y ), msg1, wxPoint( x, y ), msg2, wxPoint( x, y ) ); Add( marker ); } nerrors++; } } // test for some corners of area_to_test inside Area_Ref for( auto iterator = testSmoothedPoly->IterateWithHoles(); iterator; iterator++ ) { VECTOR2I currentVertex = *iterator; if( refSmoothedPoly->Contains( currentVertex ) ) { // COPPERAREA_COPPERAREA error: copper area corner inside copper area ref if( aCreate_Markers ) { int x = currentVertex.x; int y = currentVertex.y; wxString msg1 = area_to_test->GetSelectMenuText(); wxString msg2 = Area_Ref->GetSelectMenuText(); MARKER_PCB* marker = new MARKER_PCB( COPPERAREA_INSIDE_COPPERAREA, wxPoint( x, y ), msg1, wxPoint( x, y ), msg2, wxPoint( x, y ) ); Add( marker ); } nerrors++; } } // Iterate through all the segments of refSmoothedPoly for( auto refIt = refSmoothedPoly->IterateSegmentsWithHoles(); refIt; refIt++ ) { // Build ref segment SEG refSegment = *refIt; // Iterate through all the segments in testSmoothedPoly for( auto testIt = testSmoothedPoly->IterateSegmentsWithHoles(); testIt; testIt++ ) { // Build test segment SEG testSegment = *testIt; int x, y; int ax1, ay1, ax2, ay2; ax1 = refSegment.A.x; ay1 = refSegment.A.y; ax2 = refSegment.B.x; ay2 = refSegment.B.y; int bx1, by1, bx2, by2; bx1 = testSegment.A.x; by1 = testSegment.A.y; bx2 = testSegment.B.x; by2 = testSegment.B.y; int d = GetClearanceBetweenSegments( bx1, by1, bx2, by2, 0, ax1, ay1, ax2, ay2, 0, zone2zoneClearance, &x, &y ); if( d < zone2zoneClearance ) { // COPPERAREA_COPPERAREA error : intersect or too close if( aCreate_Markers ) { wxString msg1 = Area_Ref->GetSelectMenuText(); wxString msg2 = area_to_test->GetSelectMenuText(); MARKER_PCB* marker = new MARKER_PCB( COPPERAREA_CLOSE_TO_COPPERAREA, wxPoint( x, y ), msg1, wxPoint( x, y ), msg2, wxPoint( x, y ) ); Add( marker ); } nerrors++; } } } } } return nerrors; }