17 changed files with 1837 additions and 451 deletions
-
12bitmaps/Add_Zone_Cutout.xpm
-
8change_log.txt
-
25include/wxPcbStruct.h
-
BINinternat/fr/kicad.mo
-
599internat/fr/kicad.po
-
117pcbnew/class_board.h
-
139pcbnew/class_zone.cpp
-
7pcbnew/class_zone.h
-
2pcbnew/dialog_zones_by_polygon.cpp
-
24pcbnew/edit.cpp
-
2pcbnew/makefile.include
-
4pcbnew/onrightclick.cpp
-
38pcbnew/zone_filling_algorithm.cpp
-
315pcbnew/zones_by_polygon.cpp
-
975pcbnew/zones_test_and_combine_areas.cpp
-
13polygon/PolyLine.cpp
-
8polygon/PolyLine.h
599
internat/fr/kicad.po
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
@ -0,0 +1,975 @@ |
|||
/****************************************************************************/ |
|||
/* functions to test, merges and cut polygons used as copper areas outlines */ |
|||
/****************************************************************************/ |
|||
|
|||
#include <vector>
|
|||
|
|||
#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<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; |
|||
} |
|||
|
|||
|
|||
/**
|
|||
* 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<CPolyLine*> * pa = new std::vector<CPolyLine*>; |
|||
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; icont1<poly1->GetNumContours(); 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; icont2<poly2->GetNumContours(); 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; icont1<poly1->GetNumContours(); 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; icont2<poly2->GetNumContours(); 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<CArc> arc_array1; |
|||
std::vector<CArc> arc_array2; |
|||
poly1->MakeGpcPoly( -1, &arc_array1 ); |
|||
poly2->MakeGpcPoly( -1, &arc_array2 ); |
|||
int n_ext_cont1 = 0; |
|||
for( int ic = 0; ic<poly1->GetGpcPoly()->num_contours; ic++ ) |
|||
if( !( (poly1->GetGpcPoly()->hole)[ic] ) ) |
|||
n_ext_cont1++; |
|||
|
|||
int n_ext_cont2 = 0; |
|||
for( int ic = 0; ic<poly2->GetGpcPoly()->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; ic<union_gpc->num_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; ic<union_gpc->num_contours; ic++ ) |
|||
{ |
|||
if( !(union_gpc->hole)[ic] ) |
|||
{ |
|||
// external contour, replace this poly
|
|||
for( int i = 0; i<union_gpc->contour[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; ic<union_gpc->num_contours; ic++ ) |
|||
{ |
|||
if( (union_gpc->hole)[ic] ) |
|||
{ |
|||
// hole
|
|||
for( int i = 0; i<union_gpc->contour[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<CPolyLine> * 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; ia<net->nareas; 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; ia2<net2->nareas; 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; ic<a->poly->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; ic2<a2->poly->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; icont<a->poly->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; icont2<a2->poly->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
|
|||
Write
Preview
Loading…
Cancel
Save
Reference in new issue