/** * Function TestLineChainEqualCPolyLine * tests the equality between a SHAPE_LINE_CHAIN polygon and a polygon inside a * CPolyLine object using Boost test suite. * @param lineChain is a SHAPE_LINE_CHAIN polygon object. * @param polyLine is a CPolyLine polygon object. * @param contourIdx is the index of the contour inside polyLine that has to be tested * against lineChain. */ void TestLineChainEqualCPolyLine(SHAPE_LINE_CHAIN& lineChain, CPolyLine& polyLine, int contourIdx = 0) { // Arrays to store the polygon points lexicographically ordered std::vector<VECTOR2I> chainPoints; std::vector<VECTOR2I> polyPoints; // Populate the array storing the new data with the lineChain corners for (int pointIdx = 0; pointIdx < lineChain.PointCount(); pointIdx++) { chainPoints.push_back(lineChain.Point(pointIdx)); } int start = polyLine.GetContourStart(contourIdx); int end = polyLine.GetContourEnd(contourIdx); // Populate the array storing the legacy data with the polyLine corners for (int pointIdx = start; pointIdx <= end; pointIdx++) { polyPoints.push_back( VECTOR2I(polyLine.GetX(pointIdx), polyLine.GetY(pointIdx)) ); } // Order the vectors in a lexicographic way std::sort(chainPoints.begin(), chainPoints.end(), lexicographicOrder); std::sort(polyPoints.begin(), polyPoints.end(), lexicographicOrder); // Compare every point coordinate to check the equality BOOST_CHECK_EQUAL_COLLECTIONS(chainPoints.begin(), chainPoints.end(), polyPoints.begin(), polyPoints.end()); }
// Restore arcs to a polygon where they were replaced with steps // If pa != NULL, also use polygons in pa array // int CPolyLine::RestoreArcs( CArray<CArc> * arc_array, CArray<CPolyLine*> * pa ) { // get poly info int n_polys = 1; if( pa ) n_polys += pa->GetSize(); CPolyLine * poly; // undraw polys and clear utility flag for all corners for( int ip=0; ip<n_polys; ip++ ) { if( ip == 0 ) poly = this; else poly = (*pa)[ip-1]; poly->Undraw(); for( int ic=0; ic<poly->GetNumCorners(); ic++ ) poly->SetUtility( ic, 0 ); // clear utility flag } // find arcs and replace them BOOL bFound; int arc_start; int arc_end; for( int iarc=0; iarc<arc_array->GetSize(); iarc++ ) { int arc_xi = (*arc_array)[iarc].xi; int arc_yi = (*arc_array)[iarc].yi; int arc_xf = (*arc_array)[iarc].xf; int arc_yf = (*arc_array)[iarc].yf; int n_steps = (*arc_array)[iarc].n_steps; int style = (*arc_array)[iarc].style; bFound = FALSE; // loop through polys for( int ip=0; ip<n_polys; ip++ ) { if( ip == 0 ) poly = this; else poly = (*pa)[ip-1]; for( int icont=0; icont<poly->GetNumContours(); icont++ ) { int ic_start = poly->GetContourStart(icont); int ic_end = poly->GetContourEnd(icont); if( (ic_end-ic_start) > n_steps ) { for( int ic=ic_start; ic<=ic_end; ic++ ) { int ic_next = ic+1; if( ic_next > ic_end ) ic_next = ic_start; int xi = poly->GetX(ic); int yi = poly->GetY(ic); if( xi == arc_xi && yi == arc_yi ) { // test for forward arc int ic2 = ic + n_steps; if( ic2 > ic_end ) ic2 = ic2 - ic_end + ic_start - 1; int xf = poly->GetX(ic2); int yf = poly->GetY(ic2); if( xf == arc_xf && yf == arc_yf ) { // arc from ic to ic2 bFound = TRUE; arc_start = ic; arc_end = ic2; } else { // try reverse arc ic2 = ic - n_steps; if( ic2 < ic_start ) ic2 = ic2 - ic_start + ic_end + 1; xf = poly->GetX(ic2); yf = poly->GetY(ic2); if( xf == arc_xf && yf == arc_yf ) { // arc from ic2 to ic bFound = TRUE; arc_start = ic2; arc_end = ic; style = 3 - style; } } if( bFound ) { poly->side_style[arc_start] = style; // mark corners for deletion from arc_start+1 to arc_end-1 for( int i=arc_start+1; i!=arc_end; ) { if( i > ic_end ) i = ic_start; poly->SetUtility( i, 1 ); if( i == ic_end ) i = ic_start; else i++; } break; } } if( bFound ) break; } } if( bFound ) break; } } if( bFound ) (*arc_array)[iarc].bFound = TRUE; } // now delete all marked corners for( int ip=0; ip<n_polys; ip++ ) { if( ip == 0 ) poly = this; else poly = (*pa)[ip-1]; for( int ic=poly->GetNumCorners()-1; ic>=0; ic-- ) { if( poly->GetUtility(ic) ) poly->DeleteCorner( ic, FALSE ); } } return 0; }
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; }
/** * Function TestAreaPolygon * Test an area for self-intersection. * * @param CurrArea = copper area to test * @return : * -1 if arcs intersect other sides * 0 if no intersecting sides * 1 if intersecting sides, but no intersecting arcs * Also sets utility2 flag of area with return value */ int BOARD::TestAreaPolygon( ZONE_CONTAINER* CurrArea ) { CPolyLine* p = CurrArea->m_Poly; // first, check for sides intersecting other sides, especially arcs bool bInt = false; bool bArcInt = false; int n_cont = p->GetNumContours(); // make bounding rect for each contour std::vector<CRect> cr; cr.reserve( n_cont ); for( int icont = 0; icont<n_cont; icont++ ) cr.push_back( p->GetCornerBounds( icont ) ); for( int icont = 0; icont<n_cont; icont++ ) { int is_start = p->GetContourStart( icont ); int is_end = p->GetContourEnd( icont ); for( int is = is_start; is<=is_end; is++ ) { int is_prev = is - 1; if( is_prev < is_start ) is_prev = is_end; int is_next = is + 1; if( is_next > is_end ) is_next = is_start; int style = p->GetSideStyle( is ); int x1i = p->GetX( is ); int y1i = p->GetY( is ); int x1f = p->GetX( is_next ); int y1f = p->GetY( is_next ); // check for intersection with any other sides for( int icont2 = icont; icont2<n_cont; icont2++ ) { if( cr[icont].left > cr[icont2].right || cr[icont].bottom > cr[icont2].top || cr[icont2].left > cr[icont].right || cr[icont2].bottom > cr[icont].top ) { // rectangles don't overlap, do nothing } else { int is2_start = p->GetContourStart( icont2 ); int is2_end = p->GetContourEnd( icont2 ); for( int is2 = is2_start; is2<=is2_end; is2++ ) { int is2_prev = is2 - 1; if( is2_prev < is2_start ) is2_prev = is2_end; int is2_next = is2 + 1; if( is2_next > is2_end ) is2_next = is2_start; if( icont != icont2 || (is2 != is && is2 != is_prev && is2 != is_next && is != is2_prev && is != is2_next ) ) { int style2 = p->GetSideStyle( is2 ); int x2i = p->GetX( is2 ); int y2i = p->GetY( is2 ); int x2f = p->GetX( is2_next ); int y2f = p->GetY( is2_next ); int ret = FindSegmentIntersections( x1i, y1i, x1f, y1f, style, x2i, y2i, x2f, y2f, style2 ); if( ret ) { // intersection between non-adjacent sides bInt = true; if( style != CPolyLine::STRAIGHT || style2 != CPolyLine::STRAIGHT ) { bArcInt = true; break; } } } } } if( bArcInt ) break; } if( bArcInt ) break; } if( bArcInt ) break; } if( bArcInt ) CurrArea->utility2 = -1; else if( bInt ) CurrArea->utility2 = 1; else CurrArea->utility2 = 0; return CurrArea->utility2; }