diff --git a/pcbnew/zones_test_and_combine_areas.cpp b/pcbnew/zones_test_and_combine_areas.cpp index 35e3bcef6d..4039cc6ece 100644 --- a/pcbnew/zones_test_and_combine_areas.cpp +++ b/pcbnew/zones_test_and_combine_areas.cpp @@ -1,975 +1,975 @@ -/****************************************************************************/ -/* functions to test, merges and cut polygons used as copper areas outlines */ -/****************************************************************************/ - -#include - -#include "fctsys.h" - -#include "common.h" -#include "pcbnew.h" - -using namespace std; - -#undef ASSERT -#define ASSERT wxASSERT - -bool bDontShowSelfIntersectionArcsWarning; -bool bDontShowSelfIntersectionWarning; -bool bDontShowIntersectionArcsWarning; -bool bDontShowIntersectionWarning; - - -#define poly m_Poly - -// carea: describes a copper area -#define carea ZONE_CONTAINER - - -/** - * Function AddArea - * add empty copper area to net - * @return pointer to the new area - */ -ZONE_CONTAINER* BOARD::AddArea( int netcode, int layer, int x, int y, int hatch ) -{ - ZONE_CONTAINER* new_area = InsertArea( netcode, m_ZoneDescriptorList.size( - ) - 1, layer, x, y, hatch ); - - return new_area; -} - - -/** - * remove copper area from net - * @param area = area to remove - * @return 0 - */ -int BOARD::RemoveArea( ZONE_CONTAINER* area_to_remove ) -{ - Delete( area_to_remove ); - return 0; -} - - -/** - * Function InsertArea - * add empty copper area to net, inserting after m_ZoneDescriptorList[iarea] - * @return pointer to the new area - */ -ZONE_CONTAINER* BOARD::InsertArea( int netcode, int iarea, int layer, int x, int y, int hatch ) -{ - ZONE_CONTAINER* new_area = new ZONE_CONTAINER( this ); - - new_area->SetNet( netcode ); - new_area->SetLayer( layer ); - new_area->m_TimeStamp = GetTimeStamp(); - if( iarea < (int) ( m_ZoneDescriptorList.size() - 1) ) - m_ZoneDescriptorList.insert( m_ZoneDescriptorList.begin() + iarea + 1, new_area ); - else - m_ZoneDescriptorList.push_back( new_area ); - - new_area->poly->Start( layer, 1, 10 * NM_PER_MIL, x, y, - hatch ); - return new_area; -} - - -/** - * Function CompleteArea - * complete copper area contour by adding a line from last to first corner - * if there is only 1 or 2 corners, remove (delete) the area - * @param area_to_complete = area to complete or remove - * @param style = style of last corner - * @return 1 if Ok, 0 if area removed - */ -int BOARD::CompleteArea( ZONE_CONTAINER* area_to_complete, int style ) -{ - if( area_to_complete->poly->GetNumCorners() > 2 ) - { - area_to_complete->poly->Close( style ); - return 1; - } - else - { - RemoveArea( area_to_complete ); - } - return 0; -} - - -/** - * 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->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 cr; - cr.reserve( n_cont ); - for( int icont = 0; icontGetCornerBounds( icont ) ); - - for( int icont = 0; icontGetContourStart( 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 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; -} - - -/** - * Function ClipAreaPolygon - * Process an area that has been modified, by clipping its polygon against itself. - * This may change the number and order of copper areas in the net. - * @param bMessageBoxInt == TRUE, shows message when clipping occurs. - * @param bMessageBoxArc == TRUE, shows message when clipping can't be done due to arcs. - * @return: - * -1 if arcs intersect other sides, so polygon can't be clipped - * 0 if no intersecting sides - * 1 if intersecting sides - * Also sets areas->utility1 flags if areas are modified - */ -int BOARD::ClipAreaPolygon( ZONE_CONTAINER* CurrArea, - bool bMessageBoxArc, bool bMessageBoxInt, bool bRetainArcs ) -{ - CPolyLine* p = CurrArea->poly; - int test = TestAreaPolygon( CurrArea ); // this sets utility2 flag - - if( test == -1 && !bRetainArcs ) - test = 1; - if( test == -1 ) - { - // arc intersections, don't clip unless bRetainArcs == false - if( bMessageBoxArc && bDontShowSelfIntersectionArcsWarning == false ) - { - wxString str; - str.Printf( wxT( "Area %X of net \"%s\" has arcs intersecting other sides.\n" ), - CurrArea->m_TimeStamp, CurrArea->m_Netname.GetData() ); - str += wxT( "This may cause problems with other editing operations,\n" ); - str += wxT( "such as adding cutouts. It can't be fixed automatically.\n" ); - str += wxT( "Manual correction is recommended." ); - wxMessageBox( str ); - -// bDontShowSelfIntersectionArcsWarning = dlg.bDontShowBoxState; - } - return -1; // arcs intersect with other sides, error - } - - // mark all areas as unmodified except this one - for( unsigned ia = 0; ia < m_ZoneDescriptorList.size(); ia++ ) - m_ZoneDescriptorList[ia]->utility = 0; - - CurrArea->utility = 1; - - if( test == 1 ) - { - // non-arc intersections, clip the polygon - if( bMessageBoxInt && bDontShowSelfIntersectionWarning == false ) - { - wxString str; - str.Printf( wxT( "Area %d of net \"%s\" is self-intersecting and will be clipped.\n" ), - CurrArea->m_TimeStamp, CurrArea->m_Netname.GetData() ); - str += wxT( "This may result in splitting the area.\n" ); - str += wxT( "If the area is complex, this may take a few seconds." ); - wxMessageBox( str ); - -// bDontShowSelfIntersectionWarning = dlg.bDontShowBoxState; - } - } - -//** TODO test for cutouts outside of area -//** if( test == 1 ) - { - std::vector * pa = new std::vector; - p->Undraw(); - int n_poly = CurrArea->poly->NormalizeWithGpc( pa, bRetainArcs ); - if( n_poly > 1 ) // i.e if clippinf has created some polygons, we must add these new copper areas - { - for( int ip = 1; ip < n_poly; ip++ ) - { - // create new copper area and copy poly into it - CPolyLine* new_p = (*pa)[ip - 1]; - CurrArea = AddArea( CurrArea->GetNet(), CurrArea->GetLayer(), 0, 0, 0 ); - - // remove the poly that was automatically created for the new area - // and replace it with a poly from NormalizeWithGpc - delete CurrArea->poly; - CurrArea->poly = new_p; - CurrArea->poly->Draw(); - CurrArea->utility = 1; - } - } - p->Draw(); - delete pa; - } - return test; -} - - -/** - * Process an area that has been modified, by clipping its polygon against - * itself and the polygons for any other areas on the same net. - * This may change the number and order of copper areas in the net. - * @param modified_area = area to test - * @param bMessageBox : if TRUE, shows message boxes when clipping occurs. - * @return : - * -1 if arcs intersect other sides, so polygon can't be clipped - * 0 if no intersecting sides - * 1 if intersecting sides, polygon clipped - */ -int BOARD::AreaPolygonModified( ZONE_CONTAINER* modified_area, - bool bMessageBoxArc, - bool bMessageBoxInt ) -{ - // clip polygon against itself - int test = ClipAreaPolygon( modified_area, bMessageBoxArc, bMessageBoxInt ); - - if( test == -1 ) - return test; - - // now see if we need to clip against other areas - bool bCheckAllAreas = false; - if( test == 1 ) - bCheckAllAreas = TRUE; - else - bCheckAllAreas = TestAreaIntersections( modified_area ); - if( bCheckAllAreas ) - CombineAllAreasInNet( modified_area->GetNet(), bMessageBoxInt, TRUE ); - - return test; -} - - -/** - * Function CombineAllAreasInNet - * Checks all copper areas in net for intersections, combining them if found - * @param aNetCode = net to consider - * @param bMessageBox : if true display warning message box - * @param bUseUtility : if true, don't check areas if both utility flags are 0 - * Sets utility flag = 1 for any areas modified - * If an area has self-intersecting arcs, doesn't try to combine it - */ -int BOARD::CombineAllAreasInNet( int aNetCode, bool bMessageBox, bool bUseUtility ) -{ - if( m_ZoneDescriptorList.size() > 1 ) - { - // start by testing all area polygons to set utility2 flags - for( unsigned ia = 0; ia < m_ZoneDescriptorList.size(); ia++ ) - if( m_ZoneDescriptorList[ia]->GetNet() == aNetCode ) - TestAreaPolygon( m_ZoneDescriptorList[ia] ); - - // now loop through all combinations - for( unsigned ia1 = 0; ia1 < m_ZoneDescriptorList.size() - 1; ia1++ ) - { - ZONE_CONTAINER* curr_area = m_ZoneDescriptorList[ia1]; - if( curr_area->GetNet() != aNetCode ) - continue; - - // legal polygon - CRect b1 = curr_area->poly->GetCornerBounds(); - bool mod_ia1 = false; - for( unsigned ia2 = m_ZoneDescriptorList.size() - 1; ia2 > ia1; ia2-- ) - { - ZONE_CONTAINER* area2 = m_ZoneDescriptorList[ia2]; - if( curr_area->poly->GetLayer() == area2->poly->GetLayer() - && curr_area->utility2 != -1 && area2->utility2 != -1 ) - { - CRect b2 = area2->poly->GetCornerBounds(); - if( !( b1.left > b2.right || b1.right < b2.left - || b1.bottom > b2.top || b1.top < b2.bottom ) ) - { - // check ia2 against 1a1 - if( curr_area->utility || area2->utility || bUseUtility == - false ) - { - int ret = TestAreaIntersection( curr_area, area2 ); - if( ret == 1 ) - ret = CombineAreas( curr_area, area2 ); - if( ret == 1 ) - { - if( bMessageBox && bDontShowIntersectionWarning == false ) - { - wxString str; - str.Printf( - wxT( - "Areas %d and %d of net \"%s\" intersect and will be combined.\n" ), - ia1 + 1, - ia2 + 1, - curr_area->m_Netname.GetData() ); - str += wxT( - "If they are complex, this may take a few seconds." ); - wxMessageBox( str ); - -// bDontShowIntersectionWarning = dlg.bDontShowBoxState; - } - mod_ia1 = TRUE; - } - else if( ret == 2 ) - { - if( bMessageBox && bDontShowIntersectionArcsWarning == false ) - { - wxString str; - str.Printf( - wxT( - "Areas %d and %d of net \"%s\" intersect, but some of the intersecting sides are arcs.\n" ), - ia1 + 1, - ia2 + 1, - curr_area->m_Netname.GetData() ); - str += wxT( "Therefore, these areas can't be combined." ); - wxMessageBox( str ); - -// bDontShowIntersectionArcsWarning = dlg.bDontShowBoxState; - } - } - } - } - } - } - - if( mod_ia1 ) - ia1--; // if modified, we need to check it again - } - } - return 0; -} - - -/** - * Function TestAreaIntersections - * Check for intersection of a given copper area with other areas in same net - * @param area_to_test = area to compare to all other areas in the same net - */ -bool BOARD::TestAreaIntersections( ZONE_CONTAINER* area_to_test ) -{ - CPolyLine* poly1 = area_to_test->poly; - - for( unsigned ia2 = 0; ia2 < m_ZoneDescriptorList.size(); ia2++ ) - { - ZONE_CONTAINER* area2 = m_ZoneDescriptorList[ia2]; - if( area_to_test->GetNet() != area_to_test->GetNet() ) - continue; - if( area_to_test != area2 ) - { - // see if areas are on same layer - if( area_to_test->GetLayer() != area2->GetLayer() ) - continue; - - CPolyLine* poly2 = area2->poly; - - // test bounding rects - CRect b1 = poly1->GetCornerBounds(); - CRect b2 = poly2->GetCornerBounds(); - if( b1.bottom > b2.top - || b1.top < b2.bottom - || b1.left > b2.right - || b1.right < b2.left ) - continue; - - // test for intersecting segments - for( int icont1 = 0; icont1GetNumContours(); icont1++ ) - { - int is1 = poly1->GetContourStart( icont1 ); - int ie1 = poly1->GetContourEnd( icont1 ); - for( int ic1 = is1; ic1<=ie1; ic1++ ) - { - int xi1 = poly1->GetX( ic1 ); - int yi1 = poly1->GetY( ic1 ); - int xf1, yf1, style1; - if( ic1 < ie1 ) - { - xf1 = poly1->GetX( ic1 + 1 ); - yf1 = poly1->GetY( ic1 + 1 ); - } - else - { - xf1 = poly1->GetX( is1 ); - yf1 = poly1->GetY( is1 ); - } - style1 = poly1->GetSideStyle( ic1 ); - for( int icont2 = 0; icont2GetNumContours(); icont2++ ) - { - int is2 = poly2->GetContourStart( icont2 ); - int ie2 = poly2->GetContourEnd( icont2 ); - for( int ic2 = is2; ic2<=ie2; ic2++ ) - { - int xi2 = poly2->GetX( ic2 ); - int yi2 = poly2->GetY( ic2 ); - int xf2, yf2, style2; - if( ic2 < ie2 ) - { - xf2 = poly2->GetX( ic2 + 1 ); - yf2 = poly2->GetY( ic2 + 1 ); - } - else - { - xf2 = poly2->GetX( is2 ); - yf2 = poly2->GetY( is2 ); - } - style2 = poly2->GetSideStyle( ic2 ); - int n_int = FindSegmentIntersections( xi1, yi1, xf1, yf1, style1, - xi2, yi2, xf2, yf2, style2 ); - if( n_int ) - return TRUE; - } - } - } - } - } - } - - return false; -} - - -/** - * Function TestAreaIntersection - * Test for intersection of 2 copper areas - * area_to_test must be after area_ref in m_ZoneDescriptorList - * @param area_ref = area reference - * @param area_to_test = area to compare for intersection calculations - * @return : 0 if no intersection - * 1 if intersection - * 2 if arcs intersect - */ -int BOARD::TestAreaIntersection( ZONE_CONTAINER* area_ref, ZONE_CONTAINER* area_to_test ) -{ - // see if areas are on same layer - if( area_ref->GetLayer() != area_to_test->GetLayer() ) - return 0; - - CPolyLine* poly1 = area_ref->poly; - CPolyLine* poly2 = area_to_test->poly; - - // test bounding rects - CRect b1 = poly1->GetCornerBounds(); - CRect b2 = poly2->GetCornerBounds(); - if( b1.bottom > b2.top - || b1.top < b2.bottom - || b1.left > b2.right - || b1.right < b2.left ) - return 0; - - // now test for intersecting segments - bool bInt = false; - bool bArcInt = false; - for( int icont1 = 0; icont1GetNumContours(); icont1++ ) - { - int is1 = poly1->GetContourStart( icont1 ); - int ie1 = poly1->GetContourEnd( icont1 ); - for( int ic1 = is1; ic1<=ie1; ic1++ ) - { - int xi1 = poly1->GetX( ic1 ); - int yi1 = poly1->GetY( ic1 ); - int xf1, yf1, style1; - if( ic1 < ie1 ) - { - xf1 = poly1->GetX( ic1 + 1 ); - yf1 = poly1->GetY( ic1 + 1 ); - } - else - { - xf1 = poly1->GetX( is1 ); - yf1 = poly1->GetY( is1 ); - } - style1 = poly1->GetSideStyle( ic1 ); - for( int icont2 = 0; icont2GetNumContours(); icont2++ ) - { - int is2 = poly2->GetContourStart( icont2 ); - int ie2 = poly2->GetContourEnd( icont2 ); - for( int ic2 = is2; ic2<=ie2; ic2++ ) - { - int xi2 = poly2->GetX( ic2 ); - int yi2 = poly2->GetY( ic2 ); - int xf2, yf2, style2; - if( ic2 < ie2 ) - { - xf2 = poly2->GetX( ic2 + 1 ); - yf2 = poly2->GetY( ic2 + 1 ); - } - else - { - xf2 = poly2->GetX( is2 ); - yf2 = poly2->GetY( is2 ); - } - style2 = poly2->GetSideStyle( ic2 ); - int n_int = FindSegmentIntersections( xi1, yi1, xf1, yf1, style1, - xi2, yi2, xf2, yf2, style2 ); - if( n_int ) - { - bInt = TRUE; - if( style1 != CPolyLine::STRAIGHT || style2 != CPolyLine::STRAIGHT ) - bArcInt = TRUE; - break; - } - } - - if( bArcInt ) - break; - } - - if( bArcInt ) - break; - } - - if( bArcInt ) - break; - } - - if( !bInt ) - return 0; - if( bArcInt ) - return 2; - return 1; -} - - -/** - * Function CombineAreas - * If possible, combine 2 copper areas - * area_ref must be BEFORE area_to_combine in m_ZoneDescriptorList - * area_to_combine will be deleted, if areas are combined - * @return : 0 if no intersection - * 1 if intersection - * 2 if arcs intersect - */ -int BOARD::CombineAreas( ZONE_CONTAINER* area_ref, ZONE_CONTAINER* area_to_combine ) -{ - if( area_ref == area_to_combine ) - ASSERT( 0 ); -#if 0 - - // test for intersection - int test = TestAreaIntersection( area_ref, area_to_combine ); - if( test != 1 ) - return test; // no intersection -#endif - - // polygons intersect, combine them - CPolyLine* poly1 = area_ref->poly; - CPolyLine* poly2 = area_to_combine->poly; - std::vector arc_array1; - std::vector arc_array2; - poly1->MakeGpcPoly( -1, &arc_array1 ); - poly2->MakeGpcPoly( -1, &arc_array2 ); - int n_ext_cont1 = 0; - for( int ic = 0; icGetGpcPoly()->num_contours; ic++ ) - if( !( (poly1->GetGpcPoly()->hole)[ic] ) ) - n_ext_cont1++; - - int n_ext_cont2 = 0; - for( int ic = 0; icGetGpcPoly()->num_contours; ic++ ) - if( !( (poly2->GetGpcPoly()->hole)[ic] ) ) - n_ext_cont2++; - - gpc_polygon* union_gpc = new gpc_polygon; - gpc_polygon_clip( GPC_UNION, poly1->GetGpcPoly(), poly2->GetGpcPoly(), union_gpc ); - - // get number of outside contours - int n_union_ext_cont = 0; - for( int ic = 0; icnum_contours; ic++ ) - if( !( (union_gpc->hole)[ic] ) ) - n_union_ext_cont++; - - // if no intersection, free new gpc and return - if( n_union_ext_cont == n_ext_cont1 + n_ext_cont2 ) - { - gpc_free_polygon( union_gpc ); - delete union_gpc; - return 0; - } - - // intersection, replace area_ref->m_Poly with combined areas and remove area_to_combine - RemoveArea( area_to_combine ); - area_ref->m_Poly->RemoveAllContours(); - - // create area with external contour - for( int ic = 0; icnum_contours; ic++ ) - { - if( !(union_gpc->hole)[ic] ) - { - // external contour, replace this poly - for( int i = 0; icontour[ic].num_vertices; i++ ) - { - int x = ( (union_gpc->contour)[ic].vertex )[i].x; - int y = ( (union_gpc->contour)[ic].vertex )[i].y; - if( i==0 ) - { - area_ref->m_Poly->Start( area_ref->GetLayer(), 0, 0, x, y, area_ref->m_Poly->GetHatchStyle() ); - } - else - area_ref->m_Poly->AppendCorner( x, y ); - } - - area_ref->m_Poly->Close(); - } - } - - // add holes - for( int ic = 0; icnum_contours; ic++ ) - { - if( (union_gpc->hole)[ic] ) - { - // hole - for( int i = 0; icontour[ic].num_vertices; i++ ) - { - int x = ( (union_gpc->contour)[ic].vertex )[i].x; - int y = ( (union_gpc->contour)[ic].vertex )[i].y; - area_ref->m_Poly->AppendCorner( x, y ); - } - - area_ref->m_Poly->Close(); - } - } - - area_ref->utility = 1; - area_ref->m_Poly->RestoreArcs( &arc_array1 ); - area_ref->m_Poly->RestoreArcs( &arc_array2 ); - area_ref->m_Poly->Draw(); - gpc_free_polygon( union_gpc ); - delete union_gpc; - return 1; -} - - -#if 0 -void dra_areas( CDlgLog* log, int copper_layers, - int units, BOOL check_unrouted, - CArray * board_outline, - DesignRules* dr, DRErrorList* drelist ) -{ - CString d_str, x_str, y_str; - CString str; - CString str2; - long nerrors = 0; - - // now iterate through all areas - for( int ia = 0; ianareas; ia++ ) - { - carea* a = &net->area[ia]; - - // iterate through all nets again - POSITION pos2 = pos; - void* ptr2; - CString name2; - while( pos2 != NULL ) - { - m_nlist->m_map.GetNextAssoc( pos2, name2, ptr2 ); - cnet* net2 = (cnet*) ptr2; - for( int ia2 = 0; ia2nareas; ia2++ ) - { - carea* a2 = &net2->area[ia2]; - - // test for same layer - if( a->poly->GetLayer() == a2->poly->GetLayer() ) - { - // test for points inside one another - for( int ic = 0; icpoly->GetNumCorners(); ic++ ) - { - int x = a->poly->GetX( ic ); - int y = a->poly->GetY( ic ); - if( a2->poly->TestPointInside( x, y ) ) - { - // COPPERAREA_COPPERAREA error - id id_a = net->id; - id_a.st = ID_AREA; - id_a.i = ia; - id_a.sst = ID_SEL_CORNER; - id_a.ii = ic; - str.Format( - "%ld: \"%s\" copper area inside \"%s\" inside copper area\r\n", - nerrors + 1, - net->name, - net2->name ); - DRError* dre = drelist->Add( nerrors, - DRError::COPPERAREA_INSIDE_COPPERAREA, - &str, - &net->name, - &net2->name, - id_a, - id_a, - x, - y, - x, - y, - 0, - 0 ); - if( dre ) - { - nerrors++; - if( log ) - log->AddLine( str ); - } - } - } - - for( int ic2 = 0; ic2poly->GetNumCorners(); ic2++ ) - { - int x = a2->poly->GetX( ic2 ); - int y = a2->poly->GetY( ic2 ); - if( a->poly->TestPointInside( x, y ) ) - { - // COPPERAREA_COPPERAREA error - id id_a = net2->id; - id_a.st = ID_AREA; - id_a.i = ia2; - id_a.sst = ID_SEL_CORNER; - id_a.ii = ic2; - str.Format( "%ld: \"%s\" copper area inside \"%s\" copper area\r\n", - nerrors + 1, net2->name, net->name ); - DRError* dre = drelist->Add( nerrors, - DRError::COPPERAREA_INSIDE_COPPERAREA, - &str, - &net2->name, - &net->name, - id_a, - id_a, - x, - y, - x, - y, - 0, - 0 ); - if( dre ) - { - nerrors++; - if( log ) - log->AddLine( str ); - } - } - } - - // now test spacing between areas - for( int icont = 0; icontpoly->GetNumContours(); icont++ ) - { - int ic_start = a->poly->GetContourStart( icont ); - int ic_end = a->poly->GetContourEnd( icont ); - for( int ic = ic_start; ic<=ic_end; ic++ ) - { - id id_a = net->id; - id_a.st = ID_AREA; - id_a.i = ia; - id_a.sst = ID_SIDE; - id_a.ii = ic; - int ax1 = a->poly->GetX( ic ); - int ay1 = a->poly->GetY( ic ); - int ax2, ay2; - if( ic == ic_end ) - { - ax2 = a->poly->GetX( ic_start ); - ay2 = a->poly->GetY( ic_start ); - } - else - { - ax2 = a->poly->GetX( ic + 1 ); - ay2 = a->poly->GetY( ic + 1 ); - } - int astyle = a->poly->GetSideStyle( ic ); - for( int icont2 = 0; icont2poly->GetNumContours(); icont2++ ) - { - int ic_start2 = a2->poly->GetContourStart( icont2 ); - int ic_end2 = a2->poly->GetContourEnd( icont2 ); - for( int ic2 = ic_start2; ic2<=ic_end2; ic2++ ) - { - id id_b = net2->id; - id_b.st = ID_AREA; - id_b.i = ia2; - id_b.sst = ID_SIDE; - id_b.ii = ic2; - int bx1 = a2->poly->GetX( ic2 ); - int by1 = a2->poly->GetY( ic2 ); - int bx2, by2; - if( ic2 == ic_end2 ) - { - bx2 = a2->poly->GetX( ic_start2 ); - by2 = a2->poly->GetY( ic_start2 ); - } - else - { - bx2 = a2->poly->GetX( ic2 + 1 ); - by2 = a2->poly->GetY( ic2 + 1 ); - } - int bstyle = a2->poly->GetSideStyle( ic2 ); - int x, y; - int d = ::GetClearanceBetweenSegments( bx1, - by1, - bx2, - by2, - bstyle, - 0, - ax1, - ay1, - ax2, - ay2, - astyle, - 0, - dr->copper_copper, - &x, - &y ); - if( d < dr->copper_copper ) - { - // COPPERAREA_COPPERAREA error - ::MakeCStringFromDimension( &d_str, - d, - units, - TRUE, - TRUE, - TRUE, - 1 ); - ::MakeCStringFromDimension( &x_str, - x, - units, - FALSE, - TRUE, - TRUE, - 1 ); - ::MakeCStringFromDimension( &y_str, - y, - units, - FALSE, - TRUE, - TRUE, - 1 ); - str.Format( - "%ld: \"%s\" copper area to \"%s\" copper area = %s, x=%s, y=%s\r\n", - nerrors + 1, - net->name, - net2->name, - d_str, - x_str, - y_str ); - DRError* dre = drelist->Add( - nerrors, - DRError:: - COPPERAREA_COPPERAREA, - &str, - &net->name, - &net2->name, - id_a, - id_b, - x, - y, - x, - y, - 0, - 0 ); - if( dre ) - { - nerrors++; - if( log ) - log->AddLine( str ); - } - } - } - } - } - } - } - } - } - } -} - - -#endif +/****************************************************************************/ +/* functions to test, merges and cut polygons used as copper areas outlines */ +/****************************************************************************/ + +#include + +#include "fctsys.h" + +#include "common.h" +#include "pcbnew.h" + +using namespace std; + +#undef ASSERT +#define ASSERT wxASSERT + +bool bDontShowSelfIntersectionArcsWarning; +bool bDontShowSelfIntersectionWarning; +bool bDontShowIntersectionArcsWarning; +bool bDontShowIntersectionWarning; + + +#define poly m_Poly + +// carea: describes a copper area +#define carea ZONE_CONTAINER + + +/** + * Function AddArea + * add empty copper area to net + * @return pointer to the new area + */ +ZONE_CONTAINER* BOARD::AddArea( int netcode, int layer, int x, int y, int hatch ) +{ + ZONE_CONTAINER* new_area = InsertArea( netcode, m_ZoneDescriptorList.size( + ) - 1, layer, x, y, hatch ); + + return new_area; +} + + +/** + * remove copper area from net + * @param area = area to remove + * @return 0 + */ +int BOARD::RemoveArea( ZONE_CONTAINER* area_to_remove ) +{ + Delete( area_to_remove ); + return 0; +} + + +/** + * Function InsertArea + * add empty copper area to net, inserting after m_ZoneDescriptorList[iarea] + * @return pointer to the new area + */ +ZONE_CONTAINER* BOARD::InsertArea( int netcode, int iarea, int layer, int x, int y, int hatch ) +{ + ZONE_CONTAINER* new_area = new ZONE_CONTAINER( this ); + + new_area->SetNet( netcode ); + new_area->SetLayer( layer ); + new_area->m_TimeStamp = GetTimeStamp(); + if( iarea < (int) ( m_ZoneDescriptorList.size() - 1) ) + m_ZoneDescriptorList.insert( m_ZoneDescriptorList.begin() + iarea + 1, new_area ); + else + m_ZoneDescriptorList.push_back( new_area ); + + new_area->poly->Start( layer, 1, 10 * NM_PER_MIL, x, y, + hatch ); + return new_area; +} + + +/** + * Function CompleteArea + * complete copper area contour by adding a line from last to first corner + * if there is only 1 or 2 corners, remove (delete) the area + * @param area_to_complete = area to complete or remove + * @param style = style of last corner + * @return 1 if Ok, 0 if area removed + */ +int BOARD::CompleteArea( ZONE_CONTAINER* area_to_complete, int style ) +{ + if( area_to_complete->poly->GetNumCorners() > 2 ) + { + area_to_complete->poly->Close( style ); + return 1; + } + else + { + RemoveArea( area_to_complete ); + } + return 0; +} + + +/** + * 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->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 cr; + cr.reserve( n_cont ); + for( int icont = 0; icontGetCornerBounds( icont ) ); + + for( int icont = 0; icontGetContourStart( 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 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; +} + + +/** + * Function ClipAreaPolygon + * Process an area that has been modified, by clipping its polygon against itself. + * This may change the number and order of copper areas in the net. + * @param bMessageBoxInt == TRUE, shows message when clipping occurs. + * @param bMessageBoxArc == TRUE, shows message when clipping can't be done due to arcs. + * @return: + * -1 if arcs intersect other sides, so polygon can't be clipped + * 0 if no intersecting sides + * 1 if intersecting sides + * Also sets areas->utility1 flags if areas are modified + */ +int BOARD::ClipAreaPolygon( ZONE_CONTAINER* CurrArea, + bool bMessageBoxArc, bool bMessageBoxInt, bool bRetainArcs ) +{ + CPolyLine* p = CurrArea->poly; + int test = TestAreaPolygon( CurrArea ); // this sets utility2 flag + + if( test == -1 && !bRetainArcs ) + test = 1; + if( test == -1 ) + { + // arc intersections, don't clip unless bRetainArcs == false + if( bMessageBoxArc && bDontShowSelfIntersectionArcsWarning == false ) + { + wxString str; + str.Printf( wxT( "Area %X of net \"%s\" has arcs intersecting other sides.\n" ), + CurrArea->m_TimeStamp, CurrArea->m_Netname.GetData() ); + str += wxT( "This may cause problems with other editing operations,\n" ); + str += wxT( "such as adding cutouts. It can't be fixed automatically.\n" ); + str += wxT( "Manual correction is recommended." ); + wxMessageBox( str ); + +// bDontShowSelfIntersectionArcsWarning = dlg.bDontShowBoxState; + } + return -1; // arcs intersect with other sides, error + } + + // mark all areas as unmodified except this one + for( unsigned ia = 0; ia < m_ZoneDescriptorList.size(); ia++ ) + m_ZoneDescriptorList[ia]->utility = 0; + + CurrArea->utility = 1; + + if( test == 1 ) + { + // non-arc intersections, clip the polygon + if( bMessageBoxInt && bDontShowSelfIntersectionWarning == false ) + { + wxString str; + str.Printf( wxT( "Area %d of net \"%s\" is self-intersecting and will be clipped.\n" ), + CurrArea->m_TimeStamp, CurrArea->m_Netname.GetData() ); + str += wxT( "This may result in splitting the area.\n" ); + str += wxT( "If the area is complex, this may take a few seconds." ); + wxMessageBox( str ); + +// bDontShowSelfIntersectionWarning = dlg.bDontShowBoxState; + } + } + +//** TODO test for cutouts outside of area +//** if( test == 1 ) + { + std::vector * pa = new std::vector; + p->Undraw(); + int n_poly = CurrArea->poly->NormalizeWithGpc( pa, bRetainArcs ); + if( n_poly > 1 ) // i.e if clippinf has created some polygons, we must add these new copper areas + { + for( int ip = 1; ip < n_poly; ip++ ) + { + // create new copper area and copy poly into it + CPolyLine* new_p = (*pa)[ip - 1]; + CurrArea = AddArea( CurrArea->GetNet(), CurrArea->GetLayer(), 0, 0, 0 ); + + // remove the poly that was automatically created for the new area + // and replace it with a poly from NormalizeWithGpc + delete CurrArea->poly; + CurrArea->poly = new_p; + CurrArea->poly->Draw(); + CurrArea->utility = 1; + } + } + p->Draw(); + delete pa; + } + return test; +} + + +/** + * Process an area that has been modified, by clipping its polygon against + * itself and the polygons for any other areas on the same net. + * This may change the number and order of copper areas in the net. + * @param modified_area = area to test + * @param bMessageBox : if TRUE, shows message boxes when clipping occurs. + * @return : + * -1 if arcs intersect other sides, so polygon can't be clipped + * 0 if no intersecting sides + * 1 if intersecting sides, polygon clipped + */ +int BOARD::AreaPolygonModified( ZONE_CONTAINER* modified_area, + bool bMessageBoxArc, + bool bMessageBoxInt ) +{ + // clip polygon against itself + int test = ClipAreaPolygon( modified_area, bMessageBoxArc, bMessageBoxInt ); + + if( test == -1 ) + return test; + + // now see if we need to clip against other areas + bool bCheckAllAreas = false; + if( test == 1 ) + bCheckAllAreas = TRUE; + else + bCheckAllAreas = TestAreaIntersections( modified_area ); + if( bCheckAllAreas ) + CombineAllAreasInNet( modified_area->GetNet(), bMessageBoxInt, TRUE ); + + return test; +} + + +/** + * Function CombineAllAreasInNet + * Checks all copper areas in net for intersections, combining them if found + * @param aNetCode = net to consider + * @param bMessageBox : if true display warning message box + * @param bUseUtility : if true, don't check areas if both utility flags are 0 + * Sets utility flag = 1 for any areas modified + * If an area has self-intersecting arcs, doesn't try to combine it + */ +int BOARD::CombineAllAreasInNet( int aNetCode, bool bMessageBox, bool bUseUtility ) +{ + if( m_ZoneDescriptorList.size() > 1 ) + { + // start by testing all area polygons to set utility2 flags + for( unsigned ia = 0; ia < m_ZoneDescriptorList.size(); ia++ ) + if( m_ZoneDescriptorList[ia]->GetNet() == aNetCode ) + TestAreaPolygon( m_ZoneDescriptorList[ia] ); + + // now loop through all combinations + for( unsigned ia1 = 0; ia1 < m_ZoneDescriptorList.size() - 1; ia1++ ) + { + ZONE_CONTAINER* curr_area = m_ZoneDescriptorList[ia1]; + if( curr_area->GetNet() != aNetCode ) + continue; + + // legal polygon + CRect b1 = curr_area->poly->GetCornerBounds(); + bool mod_ia1 = false; + for( unsigned ia2 = m_ZoneDescriptorList.size() - 1; ia2 > ia1; ia2-- ) + { + ZONE_CONTAINER* area2 = m_ZoneDescriptorList[ia2]; + if( curr_area->poly->GetLayer() == area2->poly->GetLayer() + && curr_area->utility2 != -1 && area2->utility2 != -1 ) + { + CRect b2 = area2->poly->GetCornerBounds(); + if( !( b1.left > b2.right || b1.right < b2.left + || b1.bottom > b2.top || b1.top < b2.bottom ) ) + { + // check ia2 against 1a1 + if( curr_area->utility || area2->utility || bUseUtility == + false ) + { + int ret = TestAreaIntersection( curr_area, area2 ); + if( ret == 1 ) + ret = CombineAreas( curr_area, area2 ); + if( ret == 1 ) + { + if( bMessageBox && bDontShowIntersectionWarning == false ) + { + wxString str; + str.Printf( + wxT( + "Areas %d and %d of net \"%s\" intersect and will be combined.\n" ), + ia1 + 1, + ia2 + 1, + curr_area->m_Netname.GetData() ); + str += wxT( + "If they are complex, this may take a few seconds." ); + wxMessageBox( str ); + +// bDontShowIntersectionWarning = dlg.bDontShowBoxState; + } + mod_ia1 = TRUE; + } + else if( ret == 2 ) + { + if( bMessageBox && bDontShowIntersectionArcsWarning == false ) + { + wxString str; + str.Printf( + wxT( + "Areas %d and %d of net \"%s\" intersect, but some of the intersecting sides are arcs.\n" ), + ia1 + 1, + ia2 + 1, + curr_area->m_Netname.GetData() ); + str += wxT( "Therefore, these areas can't be combined." ); + wxMessageBox( str ); + +// bDontShowIntersectionArcsWarning = dlg.bDontShowBoxState; + } + } + } + } + } + } + + if( mod_ia1 ) + ia1--; // if modified, we need to check it again + } + } + return 0; +} + + +/** + * Function TestAreaIntersections + * Check for intersection of a given copper area with other areas in same net + * @param area_to_test = area to compare to all other areas in the same net + */ +bool BOARD::TestAreaIntersections( ZONE_CONTAINER* area_to_test ) +{ + CPolyLine* poly1 = area_to_test->poly; + + for( unsigned ia2 = 0; ia2 < m_ZoneDescriptorList.size(); ia2++ ) + { + ZONE_CONTAINER* area2 = m_ZoneDescriptorList[ia2]; + if( area_to_test->GetNet() != area_to_test->GetNet() ) + continue; + if( area_to_test != area2 ) + { + // see if areas are on same layer + if( area_to_test->GetLayer() != area2->GetLayer() ) + continue; + + CPolyLine* poly2 = area2->poly; + + // test bounding rects + CRect b1 = poly1->GetCornerBounds(); + CRect b2 = poly2->GetCornerBounds(); + if( b1.bottom > b2.top + || b1.top < b2.bottom + || b1.left > b2.right + || b1.right < b2.left ) + continue; + + // test for intersecting segments + for( int icont1 = 0; icont1GetNumContours(); icont1++ ) + { + int is1 = poly1->GetContourStart( icont1 ); + int ie1 = poly1->GetContourEnd( icont1 ); + for( int ic1 = is1; ic1<=ie1; ic1++ ) + { + int xi1 = poly1->GetX( ic1 ); + int yi1 = poly1->GetY( ic1 ); + int xf1, yf1, style1; + if( ic1 < ie1 ) + { + xf1 = poly1->GetX( ic1 + 1 ); + yf1 = poly1->GetY( ic1 + 1 ); + } + else + { + xf1 = poly1->GetX( is1 ); + yf1 = poly1->GetY( is1 ); + } + style1 = poly1->GetSideStyle( ic1 ); + for( int icont2 = 0; icont2GetNumContours(); icont2++ ) + { + int is2 = poly2->GetContourStart( icont2 ); + int ie2 = poly2->GetContourEnd( icont2 ); + for( int ic2 = is2; ic2<=ie2; ic2++ ) + { + int xi2 = poly2->GetX( ic2 ); + int yi2 = poly2->GetY( ic2 ); + int xf2, yf2, style2; + if( ic2 < ie2 ) + { + xf2 = poly2->GetX( ic2 + 1 ); + yf2 = poly2->GetY( ic2 + 1 ); + } + else + { + xf2 = poly2->GetX( is2 ); + yf2 = poly2->GetY( is2 ); + } + style2 = poly2->GetSideStyle( ic2 ); + int n_int = FindSegmentIntersections( xi1, yi1, xf1, yf1, style1, + xi2, yi2, xf2, yf2, style2 ); + if( n_int ) + return TRUE; + } + } + } + } + } + } + + return false; +} + + +/** + * Function TestAreaIntersection + * Test for intersection of 2 copper areas + * area_to_test must be after area_ref in m_ZoneDescriptorList + * @param area_ref = area reference + * @param area_to_test = area to compare for intersection calculations + * @return : 0 if no intersection + * 1 if intersection + * 2 if arcs intersect + */ +int BOARD::TestAreaIntersection( ZONE_CONTAINER* area_ref, ZONE_CONTAINER* area_to_test ) +{ + // see if areas are on same layer + if( area_ref->GetLayer() != area_to_test->GetLayer() ) + return 0; + + CPolyLine* poly1 = area_ref->poly; + CPolyLine* poly2 = area_to_test->poly; + + // test bounding rects + CRect b1 = poly1->GetCornerBounds(); + CRect b2 = poly2->GetCornerBounds(); + if( b1.bottom > b2.top + || b1.top < b2.bottom + || b1.left > b2.right + || b1.right < b2.left ) + return 0; + + // now test for intersecting segments + bool bInt = false; + bool bArcInt = false; + for( int icont1 = 0; icont1GetNumContours(); icont1++ ) + { + int is1 = poly1->GetContourStart( icont1 ); + int ie1 = poly1->GetContourEnd( icont1 ); + for( int ic1 = is1; ic1<=ie1; ic1++ ) + { + int xi1 = poly1->GetX( ic1 ); + int yi1 = poly1->GetY( ic1 ); + int xf1, yf1, style1; + if( ic1 < ie1 ) + { + xf1 = poly1->GetX( ic1 + 1 ); + yf1 = poly1->GetY( ic1 + 1 ); + } + else + { + xf1 = poly1->GetX( is1 ); + yf1 = poly1->GetY( is1 ); + } + style1 = poly1->GetSideStyle( ic1 ); + for( int icont2 = 0; icont2GetNumContours(); icont2++ ) + { + int is2 = poly2->GetContourStart( icont2 ); + int ie2 = poly2->GetContourEnd( icont2 ); + for( int ic2 = is2; ic2<=ie2; ic2++ ) + { + int xi2 = poly2->GetX( ic2 ); + int yi2 = poly2->GetY( ic2 ); + int xf2, yf2, style2; + if( ic2 < ie2 ) + { + xf2 = poly2->GetX( ic2 + 1 ); + yf2 = poly2->GetY( ic2 + 1 ); + } + else + { + xf2 = poly2->GetX( is2 ); + yf2 = poly2->GetY( is2 ); + } + style2 = poly2->GetSideStyle( ic2 ); + int n_int = FindSegmentIntersections( xi1, yi1, xf1, yf1, style1, + xi2, yi2, xf2, yf2, style2 ); + if( n_int ) + { + bInt = TRUE; + if( style1 != CPolyLine::STRAIGHT || style2 != CPolyLine::STRAIGHT ) + bArcInt = TRUE; + break; + } + } + + if( bArcInt ) + break; + } + + if( bArcInt ) + break; + } + + if( bArcInt ) + break; + } + + if( !bInt ) + return 0; + if( bArcInt ) + return 2; + return 1; +} + + +/** + * Function CombineAreas + * If possible, combine 2 copper areas + * area_ref must be BEFORE area_to_combine in m_ZoneDescriptorList + * area_to_combine will be deleted, if areas are combined + * @return : 0 if no intersection + * 1 if intersection + * 2 if arcs intersect + */ +int BOARD::CombineAreas( ZONE_CONTAINER* area_ref, ZONE_CONTAINER* area_to_combine ) +{ + if( area_ref == area_to_combine ) + ASSERT( 0 ); +#if 0 + + // test for intersection + int test = TestAreaIntersection( area_ref, area_to_combine ); + if( test != 1 ) + return test; // no intersection +#endif + + // polygons intersect, combine them + CPolyLine* poly1 = area_ref->poly; + CPolyLine* poly2 = area_to_combine->poly; + std::vector arc_array1; + std::vector arc_array2; + poly1->MakeGpcPoly( -1, &arc_array1 ); + poly2->MakeGpcPoly( -1, &arc_array2 ); + int n_ext_cont1 = 0; + for( int ic = 0; icGetGpcPoly()->num_contours; ic++ ) + if( !( (poly1->GetGpcPoly()->hole)[ic] ) ) + n_ext_cont1++; + + int n_ext_cont2 = 0; + for( int ic = 0; icGetGpcPoly()->num_contours; ic++ ) + if( !( (poly2->GetGpcPoly()->hole)[ic] ) ) + n_ext_cont2++; + + gpc_polygon* union_gpc = new gpc_polygon; + gpc_polygon_clip( GPC_UNION, poly1->GetGpcPoly(), poly2->GetGpcPoly(), union_gpc ); + + // get number of outside contours + int n_union_ext_cont = 0; + for( int ic = 0; icnum_contours; ic++ ) + if( !( (union_gpc->hole)[ic] ) ) + n_union_ext_cont++; + + // if no intersection, free new gpc and return + if( n_union_ext_cont == n_ext_cont1 + n_ext_cont2 ) + { + gpc_free_polygon( union_gpc ); + delete union_gpc; + return 0; + } + + // intersection, replace area_ref->m_Poly with combined areas and remove area_to_combine + RemoveArea( area_to_combine ); + area_ref->m_Poly->RemoveAllContours(); + + // create area with external contour + for( int ic = 0; icnum_contours; ic++ ) + { + if( !(union_gpc->hole)[ic] ) + { + // external contour, replace this poly + for( int i = 0; icontour[ic].num_vertices; i++ ) + { + int x = ( (union_gpc->contour)[ic].vertex )[i].x; + int y = ( (union_gpc->contour)[ic].vertex )[i].y; + if( i==0 ) + { + area_ref->m_Poly->Start( area_ref->GetLayer(), 0, 0, x, y, area_ref->m_Poly->GetHatchStyle() ); + } + else + area_ref->m_Poly->AppendCorner( x, y ); + } + + area_ref->m_Poly->Close(); + } + } + + // add holes + for( int ic = 0; icnum_contours; ic++ ) + { + if( (union_gpc->hole)[ic] ) + { + // hole + for( int i = 0; icontour[ic].num_vertices; i++ ) + { + int x = ( (union_gpc->contour)[ic].vertex )[i].x; + int y = ( (union_gpc->contour)[ic].vertex )[i].y; + area_ref->m_Poly->AppendCorner( x, y ); + } + + area_ref->m_Poly->Close(); + } + } + + area_ref->utility = 1; + area_ref->m_Poly->RestoreArcs( &arc_array1 ); + area_ref->m_Poly->RestoreArcs( &arc_array2 ); + area_ref->m_Poly->Draw(); + gpc_free_polygon( union_gpc ); + delete union_gpc; + return 1; +} + + +#if 0 +void dra_areas( CDlgLog* log, int copper_layers, + int units, BOOL check_unrouted, + CArray * board_outline, + DesignRules* dr, DRErrorList* drelist ) +{ + CString d_str, x_str, y_str; + CString str; + CString str2; + long nerrors = 0; + + // now iterate through all areas + for( int ia = 0; ianareas; ia++ ) + { + carea* a = &net->area[ia]; + + // iterate through all nets again + POSITION pos2 = pos; + void* ptr2; + CString name2; + while( pos2 != NULL ) + { + m_nlist->m_map.GetNextAssoc( pos2, name2, ptr2 ); + cnet* net2 = (cnet*) ptr2; + for( int ia2 = 0; ia2nareas; ia2++ ) + { + carea* a2 = &net2->area[ia2]; + + // test for same layer + if( a->poly->GetLayer() == a2->poly->GetLayer() ) + { + // test for points inside one another + for( int ic = 0; icpoly->GetNumCorners(); ic++ ) + { + int x = a->poly->GetX( ic ); + int y = a->poly->GetY( ic ); + if( a2->poly->TestPointInside( x, y ) ) + { + // COPPERAREA_COPPERAREA error + id id_a = net->id; + id_a.st = ID_AREA; + id_a.i = ia; + id_a.sst = ID_SEL_CORNER; + id_a.ii = ic; + str.Format( + "%ld: \"%s\" copper area inside \"%s\" inside copper area\r\n", + nerrors + 1, + net->name, + net2->name ); + DRError* dre = drelist->Add( nerrors, + DRError::COPPERAREA_INSIDE_COPPERAREA, + &str, + &net->name, + &net2->name, + id_a, + id_a, + x, + y, + x, + y, + 0, + 0 ); + if( dre ) + { + nerrors++; + if( log ) + log->AddLine( str ); + } + } + } + + for( int ic2 = 0; ic2poly->GetNumCorners(); ic2++ ) + { + int x = a2->poly->GetX( ic2 ); + int y = a2->poly->GetY( ic2 ); + if( a->poly->TestPointInside( x, y ) ) + { + // COPPERAREA_COPPERAREA error + id id_a = net2->id; + id_a.st = ID_AREA; + id_a.i = ia2; + id_a.sst = ID_SEL_CORNER; + id_a.ii = ic2; + str.Format( "%ld: \"%s\" copper area inside \"%s\" copper area\r\n", + nerrors + 1, net2->name, net->name ); + DRError* dre = drelist->Add( nerrors, + DRError::COPPERAREA_INSIDE_COPPERAREA, + &str, + &net2->name, + &net->name, + id_a, + id_a, + x, + y, + x, + y, + 0, + 0 ); + if( dre ) + { + nerrors++; + if( log ) + log->AddLine( str ); + } + } + } + + // now test spacing between areas + for( int icont = 0; icontpoly->GetNumContours(); icont++ ) + { + int ic_start = a->poly->GetContourStart( icont ); + int ic_end = a->poly->GetContourEnd( icont ); + for( int ic = ic_start; ic<=ic_end; ic++ ) + { + id id_a = net->id; + id_a.st = ID_AREA; + id_a.i = ia; + id_a.sst = ID_SIDE; + id_a.ii = ic; + int ax1 = a->poly->GetX( ic ); + int ay1 = a->poly->GetY( ic ); + int ax2, ay2; + if( ic == ic_end ) + { + ax2 = a->poly->GetX( ic_start ); + ay2 = a->poly->GetY( ic_start ); + } + else + { + ax2 = a->poly->GetX( ic + 1 ); + ay2 = a->poly->GetY( ic + 1 ); + } + int astyle = a->poly->GetSideStyle( ic ); + for( int icont2 = 0; icont2poly->GetNumContours(); icont2++ ) + { + int ic_start2 = a2->poly->GetContourStart( icont2 ); + int ic_end2 = a2->poly->GetContourEnd( icont2 ); + for( int ic2 = ic_start2; ic2<=ic_end2; ic2++ ) + { + id id_b = net2->id; + id_b.st = ID_AREA; + id_b.i = ia2; + id_b.sst = ID_SIDE; + id_b.ii = ic2; + int bx1 = a2->poly->GetX( ic2 ); + int by1 = a2->poly->GetY( ic2 ); + int bx2, by2; + if( ic2 == ic_end2 ) + { + bx2 = a2->poly->GetX( ic_start2 ); + by2 = a2->poly->GetY( ic_start2 ); + } + else + { + bx2 = a2->poly->GetX( ic2 + 1 ); + by2 = a2->poly->GetY( ic2 + 1 ); + } + int bstyle = a2->poly->GetSideStyle( ic2 ); + int x, y; + int d = ::GetClearanceBetweenSegments( bx1, + by1, + bx2, + by2, + bstyle, + 0, + ax1, + ay1, + ax2, + ay2, + astyle, + 0, + dr->copper_copper, + &x, + &y ); + if( d < dr->copper_copper ) + { + // COPPERAREA_COPPERAREA error + ::MakeCStringFromDimension( &d_str, + d, + units, + TRUE, + TRUE, + TRUE, + 1 ); + ::MakeCStringFromDimension( &x_str, + x, + units, + FALSE, + TRUE, + TRUE, + 1 ); + ::MakeCStringFromDimension( &y_str, + y, + units, + FALSE, + TRUE, + TRUE, + 1 ); + str.Format( + "%ld: \"%s\" copper area to \"%s\" copper area = %s, x=%s, y=%s\r\n", + nerrors + 1, + net->name, + net2->name, + d_str, + x_str, + y_str ); + DRError* dre = drelist->Add( + nerrors, + DRError:: + COPPERAREA_COPPERAREA, + &str, + &net->name, + &net2->name, + id_a, + id_b, + x, + y, + x, + y, + 0, + 0 ); + if( dre ) + { + nerrors++; + if( log ) + log->AddLine( str ); + } + } + } + } + } + } + } + } + } + } +} + + +#endif