more about zones. current No DRC for outlines

This commit is contained in:
CHARRAS 2008-01-04 12:27:16 +00:00
parent 945c14d4ea
commit ffd3a7133a
17 changed files with 1844 additions and 458 deletions

View File

@ -11,12 +11,12 @@ const char * add_zone_cutout[] = {
" ..............", " ..............",
".... ........", ".... ........",
"... ++++ .......", "... ++++ .......",
".. + + .....", ".. +++++++ .....",
". + + ...", ". ++ ++ ...",
". + + ..", ". ++ ++ ..",
". + + ..", ". ++ ++ ..",
". + + .", ". ++ ++ .",
".. + + ..", ".. ++++++++++ ..",
"... +++++++ ... ", "... +++++++ ... ",
".... .... ", ".... .... ",
"............ ", "............ ",

View File

@ -4,6 +4,14 @@ Started 2007-June-11
Please add newer entries at the top, list the date and your name with Please add newer entries at the top, list the date and your name with
email address. email address.
2008-jan-04 UPDATE Jean-Pierre Charras <jean-pierre.charras@inpg.fr>
================================================================================
+pcbnew:
More about zones:
Outlines can be edited. Outlines are merged if needeed.
Current No DRC for outlines
2008-jan-01 UPDATE Jean-Pierre Charras <jean-pierre.charras@inpg.fr> 2008-jan-01 UPDATE Jean-Pierre Charras <jean-pierre.charras@inpg.fr>
================================================================================ ================================================================================
+all +all

View File

@ -529,6 +529,24 @@ public:
*/ */
int Fill_All_Zones( wxDC* DC, bool verbose = TRUE ); int Fill_All_Zones( wxDC* DC, bool verbose = TRUE );
/**
* Function Add_Zone_Cutout
* Add a cutout zone to a given zone outline
* @param DC = current Device Context
* @param zone_container = parent zone outline
*/
void Add_Zone_Cutout( wxDC* DC , ZONE_CONTAINER * zone_container );
/**
* Function Add_Similar_Zone
* Add a zone to a given zone outline.
* if the zones are overlappeing they will be merged
* @param DC = current Device Context
* @param zone_container = parent zone outline
*/
void Add_Similar_Zone( wxDC* DC , ZONE_CONTAINER * zone_container );
/** /**
* Function Edit_Zone_Params * Function Edit_Zone_Params
* Edit params (layer, clearance, ...) for a zone outline * Edit params (layer, clearance, ...) for a zone outline
@ -548,6 +566,13 @@ public:
*/ */
void End_Move_Zone_Corner( wxDC* DC , ZONE_CONTAINER * zone_container ); void End_Move_Zone_Corner( wxDC* DC , ZONE_CONTAINER * zone_container );
/**
* Function End_Move_Zone_Corner
* Remove the currently selected corner in a zone outline
* the .m_CornerSelection is used as corner selection
*/
void Remove_Zone_Corner( wxDC* DC, ZONE_CONTAINER * zone_container );
// Target handling // Target handling
MIREPCB* Create_Mire( wxDC* DC ); MIREPCB* Create_Mire( wxDC* DC );
void Delete_Mire( MIREPCB* MirePcb, wxDC* DC ); void Delete_Mire( MIREPCB* MirePcb, wxDC* DC );

Binary file not shown.

File diff suppressed because it is too large Load Diff

View File

@ -224,6 +224,123 @@ public:
void Show( int nestLevel, std::ostream& os ); void Show( int nestLevel, std::ostream& os );
#endif #endif
/* Functions used in test, merge and cut outlines */
/**
* Function AddArea
* add empty copper area to net
* @return pointer to the new area
*/
ZONE_CONTAINER* AddArea( int netcode, int layer, int x, int y, int hatch );
/**
* remove copper area from net
* @param area = area to remove
* @return 0
*/
int RemoveArea( ZONE_CONTAINER* area_to_remove );
/**
* Function InsertArea
* add empty copper area to net, inserting after m_ZoneDescriptorList[iarea]
* @return pointer to the new area
*/
ZONE_CONTAINER* InsertArea( int netcode, int iarea, int layer, int x, int y, int hatch );
/**
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 CompleteArea( ZONE_CONTAINER* area_to_complete, int style );
/**
* 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 TestAreaPolygon( ZONE_CONTAINER* CurrArea );
/**
* 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 ClipAreaPolygon( ZONE_CONTAINER* CurrArea,
bool bMessageBoxArc, bool bMessageBoxInt, bool bRetainArcs = TRUE );
/**
* 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 AreaPolygonModified( ZONE_CONTAINER* modified_area,
bool bMessageBoxArc,
bool bMessageBoxInt );
/**
* 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 CombineAllAreasInNet( int aNetCode, bool bMessageBox, bool bUseUtility );
/**
* 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 TestAreaIntersections( ZONE_CONTAINER* area_to_test );
/**
* 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 TestAreaIntersection( ZONE_CONTAINER* area_ref, ZONE_CONTAINER* area_to_test );
/**
* Function CombineAreas
* If possible, combine 2 copper areas
* area_ref must be BEFORE area_to_combine
* area_to_combine will be deleted, if areas are combined
* @return : 0 if no intersection
* 1 if intersection
* 2 if arcs intersect
*/
int CombineAreas( ZONE_CONTAINER* area_ref, ZONE_CONTAINER* area_to_combine );
}; };
#endif // #ifndef CLASS_BOARD_H #endif // #ifndef CLASS_BOARD_H

View File

@ -8,30 +8,9 @@
#include "gr_basic.h" #include "gr_basic.h"
#include "common.h" #include "common.h"
#include "PolyLine.h"
#include "pcbnew.h" #include "pcbnew.h"
/************************/
/* class ZONE_CONTAINER */
/************************/
ZONE_CONTAINER::ZONE_CONTAINER( BOARD* parent ) :
BOARD_ITEM( parent, TYPEZONE_CONTAINER )
, CPolyLine( NULL )
{
m_NetCode = -1; // Net number for fast comparisons
m_CornerSelection = -1;
m_ZoneClearance = 200; // a reasonnable clerance value
m_GridFillValue = 50; // a reasonnable grid used for filling
m_PadOption = THERMAL_PAD;
}
ZONE_CONTAINER::~ZONE_CONTAINER()
{
}
/**********************/ /**********************/
/* Class EDGE_ZONE */ /* Class EDGE_ZONE */
/**********************/ /**********************/
@ -49,7 +28,6 @@ EDGE_ZONE:: ~EDGE_ZONE()
{ {
} }
/****************************************/ /****************************************/
bool EDGE_ZONE::Save( FILE* aFile ) const bool EDGE_ZONE::Save( FILE* aFile ) const
/****************************************/ /****************************************/
@ -57,6 +35,51 @@ bool EDGE_ZONE::Save( FILE* aFile ) const
return true; return true;
} }
/************************/
/* class ZONE_CONTAINER */
/************************/
ZONE_CONTAINER::ZONE_CONTAINER( BOARD* parent ) :
BOARD_ITEM( parent, TYPEZONE_CONTAINER )
{
m_NetCode = -1; // Net number for fast comparisons
m_CornerSelection = -1;
m_ZoneClearance = 200; // a reasonnable clerance value
m_GridFillValue = 50; // a reasonnable grid used for filling
m_PadOption = THERMAL_PAD;
utility = 0; // flags used in polygon calculations
utility2 = 0; // flags used in polygon calculations
m_Poly = new CPolyLine( NULL ); // Outlines
}
ZONE_CONTAINER::~ZONE_CONTAINER()
{
delete m_Poly;
m_Poly = NULL;
}
/*******************************************/
void ZONE_CONTAINER::SetNet( int anet_code )
/*******************************************/
{
m_NetCode = anet_code;
if ( m_Parent )
{
EQUIPOT* net = ((BOARD*) m_Parent)->FindNet( g_HightLigth_NetCode );
if( net )
m_Netname = net->m_Netname;
else m_Netname.Empty();
}
else m_Netname.Empty();
}
/********************************************/ /********************************************/
bool ZONE_CONTAINER::Save( FILE* aFile ) const bool ZONE_CONTAINER::Save( FILE* aFile ) const
/********************************************/ /********************************************/
@ -66,7 +89,7 @@ bool ZONE_CONTAINER::Save( FILE* aFile ) const
unsigned item_pos; unsigned item_pos;
int ret; int ret;
unsigned corners_count = corner.size(); unsigned corners_count = m_Poly->corner.size();
int outline_hatch; int outline_hatch;
fprintf( aFile, "$CZONE_OUTLINE\n"); fprintf( aFile, "$CZONE_OUTLINE\n");
@ -79,16 +102,16 @@ bool ZONE_CONTAINER::Save( FILE* aFile ) const
ret = fprintf( aFile, "ZLayer %d\n", m_Layer ); ret = fprintf( aFile, "ZLayer %d\n", m_Layer );
if ( ret < 1 ) return false; if ( ret < 1 ) return false;
// Save the ouline aux info // Save the ouline aux info
switch ( m_HatchStyle ) switch ( m_Poly->GetHatchStyle() )
{ {
default: default:
case NO_HATCH: case CPolyLine::NO_HATCH:
outline_hatch = 'N'; outline_hatch = 'N';
break; break;
case DIAGONAL_EDGE: case CPolyLine::DIAGONAL_EDGE:
outline_hatch = 'E'; outline_hatch = 'E';
break; break;
case DIAGONAL_FULL: case CPolyLine::DIAGONAL_FULL:
outline_hatch = 'F'; outline_hatch = 'F';
break; break;
} }
@ -99,8 +122,8 @@ bool ZONE_CONTAINER::Save( FILE* aFile ) const
for ( item_pos = 0; item_pos < corners_count; item_pos++ ) for ( item_pos = 0; item_pos < corners_count; item_pos++ )
{ {
ret = fprintf( aFile, "ZCorner %d %d %d \n", ret = fprintf( aFile, "ZCorner %d %d %d \n",
corner[item_pos].x, corner[item_pos].y, m_Poly->corner[item_pos].x, m_Poly->corner[item_pos].y,
corner[item_pos].end_contour ); m_Poly->corner[item_pos].end_contour );
if ( ret < 3 ) return false; if ( ret < 3 ) return false;
} }
fprintf( aFile, "$endCZONE_OUTLINE\n"); fprintf( aFile, "$endCZONE_OUTLINE\n");
@ -122,7 +145,7 @@ int ZONE_CONTAINER::ReadDescr( FILE* aFile, int* aLineNum )
char netname_buffer[1024]; char netname_buffer[1024];
int ret; int ret;
int n_corner_item = 0; int n_corner_item = 0;
int outline_hatch = NO_HATCH; int outline_hatch = CPolyLine::NO_HATCH;
bool error = false, has_corner = false; bool error = false, has_corner = false;
netname_buffer[0] = 0; netname_buffer[0] = 0;
@ -137,13 +160,13 @@ int ZONE_CONTAINER::ReadDescr( FILE* aFile, int* aLineNum )
else else
{ {
if ( ! has_corner ) if ( ! has_corner )
Start( m_Layer, 0, 0, m_Poly->Start( m_Layer, 0, 0,
x, y, x, y,
outline_hatch ); outline_hatch );
else else
AppendCorner( x, y ); m_Poly->AppendCorner( x, y );
has_corner = true; has_corner = true;
if ( flag ) Close(); if ( flag ) m_Poly->Close();
} }
} }
if( strnicmp(Line, "ZInfo", 5 ) == 0 ) // general info found if( strnicmp(Line, "ZInfo", 5 ) == 0 ) // general info found
@ -182,15 +205,15 @@ int ZONE_CONTAINER::ReadDescr( FILE* aFile, int* aLineNum )
{ {
case 'n': case 'n':
case 'N': case 'N':
outline_hatch = NO_HATCH; outline_hatch = CPolyLine::NO_HATCH;
break; break;
case 'e': case 'e':
case 'E': case 'E':
outline_hatch = DIAGONAL_EDGE; outline_hatch = CPolyLine::DIAGONAL_EDGE;
break; break;
case 'f': case 'f':
case 'F': case 'F':
outline_hatch = DIAGONAL_FULL; outline_hatch = CPolyLine::DIAGONAL_FULL;
break; break;
} }
} }
@ -245,32 +268,32 @@ void ZONE_CONTAINER::Draw( WinEDA_DrawPanel* panel, wxDC* DC, const wxPoint& off
// draw the lines // draw the lines
int i_start_contour = 0; int i_start_contour = 0;
for( unsigned ic = 0; ic < corner.size(); ic++ ) for( unsigned ic = 0; ic < m_Poly->corner.size(); ic++ )
{ {
int xi = corner[ic].x + offset.x; int xi = m_Poly->corner[ic].x + offset.x;
int yi = corner[ic].y + offset.y; int yi = m_Poly->corner[ic].y + offset.y;
int xf, yf; int xf, yf;
if( corner[ic].end_contour == FALSE && ic < corner.size() - 1 ) if( m_Poly->corner[ic].end_contour == FALSE && ic < m_Poly->corner.size() - 1 )
{ {
xf = corner[ic + 1].x + offset.x; xf = m_Poly->corner[ic + 1].x + offset.x;
yf = corner[ic + 1].y + offset.y; yf = m_Poly->corner[ic + 1].y + offset.y;
} }
else else
{ {
xf = corner[i_start_contour].x + offset.x; xf = m_Poly->corner[i_start_contour].x + offset.x;
yf = corner[i_start_contour].y + offset.y; yf = m_Poly->corner[i_start_contour].y + offset.y;
i_start_contour = ic + 1; i_start_contour = ic + 1;
} }
GRLine( &panel->m_ClipBox, DC, xi, yi, xf, yf, 0, color ); GRLine( &panel->m_ClipBox, DC, xi, yi, xf, yf, 0, color );
} }
// draw hatches // draw hatches
for( unsigned ic = 0; ic < m_HatchLines.size(); ic++ ) for( unsigned ic = 0; ic < m_Poly->m_HatchLines.size(); ic++ )
{ {
int xi = m_HatchLines[ic].xi + offset.x; int xi = m_Poly->m_HatchLines[ic].xi + offset.x;
int yi = m_HatchLines[ic].yi + offset.y; int yi = m_Poly->m_HatchLines[ic].yi + offset.y;
int xf = m_HatchLines[ic].xf + offset.x; int xf = m_Poly->m_HatchLines[ic].xf + offset.x;
int yf =m_HatchLines[ic].yf + offset.y; int yf =m_Poly->m_HatchLines[ic].yf + offset.y;
GRLine( &panel->m_ClipBox, DC, xi, yi, xf, yf, 0, color ); GRLine( &panel->m_ClipBox, DC, xi, yi, xf, yf, 0, color );
} }
@ -307,7 +330,7 @@ int ZONE_CONTAINER::HitTestForCorner( const wxPoint& refPos )
#define MIN_DIST_IN_PIXELS 5 #define MIN_DIST_IN_PIXELS 5
int dist; int dist;
unsigned item_pos, lim; unsigned item_pos, lim;
lim = corner.size(); lim = m_Poly->corner.size();
// Min distance to hit = MIN_DIST_IN_PIXELS pixels : // Min distance to hit = MIN_DIST_IN_PIXELS pixels :
WinEDA_BasePcbFrame* frame = ((BOARD*)GetParent())->m_PcbFrame; WinEDA_BasePcbFrame* frame = ((BOARD*)GetParent())->m_PcbFrame;
@ -315,7 +338,7 @@ int ZONE_CONTAINER::HitTestForCorner( const wxPoint& refPos )
for ( item_pos = 0; item_pos < lim; item_pos++ ) for ( item_pos = 0; item_pos < lim; item_pos++ )
{ {
dist = abs( corner[item_pos].x - refPos.x ) + abs( corner[item_pos].y - refPos.y ); dist = abs( m_Poly->corner[item_pos].x - refPos.x ) + abs( m_Poly->corner[item_pos].y - refPos.y );
if( dist <= min_dist ) if( dist <= min_dist )
return item_pos; return item_pos;
} }
@ -335,7 +358,7 @@ int ZONE_CONTAINER::HitTestForEdge( const wxPoint& refPos )
#define MIN_DIST_IN_PIXELS 5 #define MIN_DIST_IN_PIXELS 5
int dist; int dist;
unsigned item_pos, lim; unsigned item_pos, lim;
lim = corner.size(); lim = m_Poly->corner.size();
// Min distance to hit = MIN_DIST_IN_PIXELS pixels : // Min distance to hit = MIN_DIST_IN_PIXELS pixels :
WinEDA_BasePcbFrame* frame = ((BOARD*)GetParent())->m_PcbFrame; WinEDA_BasePcbFrame* frame = ((BOARD*)GetParent())->m_PcbFrame;
@ -351,7 +374,7 @@ int ZONE_CONTAINER::HitTestForEdge( const wxPoint& refPos )
* the last segment of the current outline starts at current corner, and ends * the last segment of the current outline starts at current corner, and ends
* at the first corner of the outline * at the first corner of the outline
*/ */
if( corner[item_pos].end_contour || end_segm >= lim) if( m_Poly->corner[item_pos].end_contour || end_segm >= lim)
{ {
unsigned tmp = first_corner_pos; unsigned tmp = first_corner_pos;
first_corner_pos = end_segm; // first_corner_pos is now the beginning of the next outline first_corner_pos = end_segm; // first_corner_pos is now the beginning of the next outline
@ -361,10 +384,10 @@ int ZONE_CONTAINER::HitTestForEdge( const wxPoint& refPos )
/* test the dist between segment and ref point */ /* test the dist between segment and ref point */
dist = (int) GetPointToLineSegmentDistance( refPos.x, dist = (int) GetPointToLineSegmentDistance( refPos.x,
refPos.y, refPos.y,
corner[item_pos].x, m_Poly->corner[item_pos].x,
corner[item_pos].y, m_Poly->corner[item_pos].y,
corner[end_segm].x, m_Poly->corner[end_segm].x,
corner[end_segm].y ); m_Poly->corner[end_segm].y );
if( dist <= min_dist ) if( dist <= min_dist )
return item_pos; return item_pos;
} }
@ -407,10 +430,10 @@ void ZONE_CONTAINER::Display_Infos( WinEDA_DrawFrame* frame )
Affiche_1_Parametre( frame, text_pos, _( "Layer" ), msg, BROWN ); Affiche_1_Parametre( frame, text_pos, _( "Layer" ), msg, BROWN );
text_pos += 8; text_pos += 8;
msg.Printf( wxT( "%d" ), corner.size() ); msg.Printf( wxT( "%d" ), m_Poly->corner.size() );
Affiche_1_Parametre( frame, text_pos, _( "Corners" ), msg, BLUE ); Affiche_1_Parametre( frame, text_pos, _( "Corners" ), msg, BLUE );
text_pos += 8; text_pos += 8;
msg.Printf( wxT( "%d" ), m_HatchLines.size() ); msg.Printf( wxT( "%d" ), m_Poly->m_HatchLines.size() );
Affiche_1_Parametre( frame, text_pos, _( "Hatch lines" ), msg, BLUE ); Affiche_1_Parametre( frame, text_pos, _( "Hatch lines" ), msg, BLUE );
} }

View File

@ -15,7 +15,7 @@
* others polygons inside this main polygon are holes. * others polygons inside this main polygon are holes.
*/ */
class ZONE_CONTAINER : public BOARD_ITEM, public CPolyLine class ZONE_CONTAINER : public BOARD_ITEM
{ {
public: public:
enum m_PadInZone { // How pads are covered by copper in zone enum m_PadInZone { // How pads are covered by copper in zone
@ -24,10 +24,12 @@ public:
PAD_IN_ZONE // pads are covered by copper PAD_IN_ZONE // pads are covered by copper
}; };
wxString m_Netname; // Net Name wxString m_Netname; // Net Name
CPolyLine * m_Poly; // outlines
int m_CornerSelection; // For corner moving, corner index to drag, or -1 if no selection int m_CornerSelection; // For corner moving, corner index to drag, or -1 if no selection
int m_ZoneClearance; // clearance value int m_ZoneClearance; // clearance value
int m_GridFillValue; // Grid used for filling int m_GridFillValue; // Grid used for filling
m_PadInZone m_PadOption; // see m_PadInZone m_PadInZone m_PadOption; // see m_PadInZone
int utility, utility2; // flags used in polygon calculations
private: private:
int m_NetCode; // Net number for fast comparisons int m_NetCode; // Net number for fast comparisons
@ -55,7 +57,7 @@ public:
const wxPoint& offset, int draw_mode ); const wxPoint& offset, int draw_mode );
int GetNet( void ) { return m_NetCode; } int GetNet( void ) { return m_NetCode; }
void SetNet( int anet_code ) { m_NetCode = anet_code; } void SetNet( int anet_code );
/** /**
* Function HitTest * Function HitTest
* tests if the given wxPoint is within the bounds of this object. * tests if the given wxPoint is within the bounds of this object.
@ -90,7 +92,6 @@ public:
* @return error level (0 = no error) * @return error level (0 = no error)
*/ */
int Fill_Zone( WinEDA_PcbFrame* frame, wxDC* DC, bool verbose = TRUE); int Fill_Zone( WinEDA_PcbFrame* frame, wxDC* DC, bool verbose = TRUE);
}; };
/*******************/ /*******************/

View File

@ -281,7 +281,7 @@ void WinEDA_ZoneFrame::CreateControls()
} }
if ( m_Zone_Container ) if ( m_Zone_Container )
s_Zone_Hatching = m_Zone_Container->GetHatch(); s_Zone_Hatching = m_Zone_Container->m_Poly->GetHatchStyle();
switch( s_Zone_Hatching ) switch( s_Zone_Hatching )
{ {
case CPolyLine::NO_HATCH: case CPolyLine::NO_HATCH:

View File

@ -450,11 +450,13 @@ void WinEDA_PcbFrame::Process_Special_Functions( wxCommandEvent& event )
break; break;
case ID_POPUP_PCB_ZONE_ADD_SIMILAR_ZONE: case ID_POPUP_PCB_ZONE_ADD_SIMILAR_ZONE:
wxMessageBox(wxT("ToDo")); DrawPanel->MouseToCursorSchema();
Add_Similar_Zone( &dc, (ZONE_CONTAINER*) GetCurItem() );
break; break;
case ID_POPUP_PCB_ZONE_ADD_CUTOUT_ZONE: case ID_POPUP_PCB_ZONE_ADD_CUTOUT_ZONE:
wxMessageBox(wxT("ToDo")); DrawPanel->MouseToCursorSchema();
Add_Zone_Cutout( &dc, (ZONE_CONTAINER*) GetCurItem() );
break; break;
case ID_POPUP_PCB_DELETE_ZONE_CONTAINER: case ID_POPUP_PCB_DELETE_ZONE_CONTAINER:
@ -469,23 +471,9 @@ void WinEDA_PcbFrame::Process_Special_Functions( wxCommandEvent& event )
} }
case ID_POPUP_PCB_DELETE_ZONE_CORNER: case ID_POPUP_PCB_DELETE_ZONE_CORNER:
{ Remove_Zone_Corner( &dc, (ZONE_CONTAINER*)GetCurItem() );
DrawPanel->MouseToCursorSchema();
ZONE_CONTAINER * zone_cont = (ZONE_CONTAINER*)GetCurItem();
zone_cont->Draw(DrawPanel,&dc, wxPoint(0,0), GR_XOR);
if ( zone_cont->GetNumCorners() <= 3 )
{
Delete_Zone( &dc, NULL, zone_cont->m_TimeStamp );
m_Pcb->Delete( zone_cont );
}
else
{
zone_cont->DeleteCorner(zone_cont->m_CornerSelection);
zone_cont->Draw(DrawPanel,&dc, wxPoint(0,0), GR_XOR);
}
SetCurItem( NULL ); SetCurItem( NULL );
break; break;
}
case ID_POPUP_PCB_MOVE_ZONE_CORNER: case ID_POPUP_PCB_MOVE_ZONE_CORNER:
{ {
@ -505,7 +493,7 @@ void WinEDA_PcbFrame::Process_Special_Functions( wxCommandEvent& event )
* and start move the new corner * and start move the new corner
*/ */
zone_cont->Draw(DrawPanel, &dc, wxPoint(0,0), GR_XOR); zone_cont->Draw(DrawPanel, &dc, wxPoint(0,0), GR_XOR);
zone_cont->InsertCorner( zone_cont->m_CornerSelection, pos.x, pos.y ); zone_cont->m_Poly->InsertCorner( zone_cont->m_CornerSelection, pos.x, pos.y );
zone_cont->m_CornerSelection++; zone_cont->m_CornerSelection++;
zone_cont->Draw(DrawPanel, &dc, wxPoint(0,0), GR_XOR); zone_cont->Draw(DrawPanel, &dc, wxPoint(0,0), GR_XOR);
Start_Move_Zone_Corner(&dc, zone_cont, zone_cont->m_CornerSelection, true); Start_Move_Zone_Corner(&dc, zone_cont, zone_cont->m_CornerSelection, true);

View File

@ -10,8 +10,10 @@ LIBVIEWER3D = ../3d-viewer/3d-viewer.a
ZONE_FILES = zones_by_polygon.o ZONE_FILES = zones_by_polygon.o
#ZONE_FILES = zones.o #ZONE_FILES = zones.o
OBJECTS= $(TARGET).o classpcb.o\ OBJECTS= $(TARGET).o classpcb.o\
$(ZONE_FILES)\ $(ZONE_FILES)\
zones_test_and_combine_areas.o\
zone_filling_algorithm.o\ zone_filling_algorithm.o\
lay2plot.o\ lay2plot.o\
modedit_undo_redo.o\ modedit_undo_redo.o\

View File

@ -658,10 +658,10 @@ void WinEDA_PcbFrame::createPopUpMenuForZones( ZONE_CONTAINER* edge_zone, wxMenu
aPopMenu->AppendSeparator(); aPopMenu->AppendSeparator();
ADD_MENUITEM( aPopMenu, ID_POPUP_PCB_ZONE_ADD_SIMILAR_ZONE, ADD_MENUITEM( aPopMenu, ID_POPUP_PCB_ZONE_ADD_SIMILAR_ZONE,
_( "Add Similar Zone" ), fill_zone_xpm ); _( "Add Similar Zone" ), add_zone_xpm );
ADD_MENUITEM( aPopMenu, ID_POPUP_PCB_ZONE_ADD_CUTOUT_ZONE, ADD_MENUITEM( aPopMenu, ID_POPUP_PCB_ZONE_ADD_CUTOUT_ZONE,
_( "Add Cutout Zone" ), add_zone_cutout ); _( "Add Cutout Area" ), add_zone_cutout );
aPopMenu->AppendSeparator(); aPopMenu->AppendSeparator();
ADD_MENUITEM( aPopMenu, ID_POPUP_PCB_FILL_ZONE, ADD_MENUITEM( aPopMenu, ID_POPUP_PCB_FILL_ZONE,

View File

@ -112,20 +112,20 @@ int ZONE_CONTAINER::Fill_Zone( WinEDA_PcbFrame* frame, wxDC* DC, bool verbose )
// trace the zone edges into the routing matrix // trace the zone edges into the routing matrix
int i_start_contour = 0; int i_start_contour = 0;
for( unsigned ic = 0; ic < corner.size(); ic++ ) for( unsigned ic = 0; ic < m_Poly->corner.size(); ic++ )
{ {
int xi = corner[ic].x - Pcb->m_BoundaryBox.m_Pos.x; int xi = m_Poly->corner[ic].x - Pcb->m_BoundaryBox.m_Pos.x;
int yi = corner[ic].y - Pcb->m_BoundaryBox.m_Pos.y; int yi = m_Poly->corner[ic].y - Pcb->m_BoundaryBox.m_Pos.y;
int xf, yf; int xf, yf;
if( corner[ic].end_contour == FALSE && ic < corner.size() - 1 ) if( m_Poly->corner[ic].end_contour == FALSE && ic < m_Poly->corner.size() - 1 )
{ {
xf = corner[ic + 1].x - Pcb->m_BoundaryBox.m_Pos.x; xf = m_Poly->corner[ic + 1].x - Pcb->m_BoundaryBox.m_Pos.x;
yf = corner[ic + 1].y - Pcb->m_BoundaryBox.m_Pos.y; yf = m_Poly->corner[ic + 1].y - Pcb->m_BoundaryBox.m_Pos.y;
} }
else else
{ {
xf = corner[i_start_contour].x - Pcb->m_BoundaryBox.m_Pos.x; xf = m_Poly->corner[i_start_contour].x - Pcb->m_BoundaryBox.m_Pos.x;
yf = corner[i_start_contour].y - Pcb->m_BoundaryBox.m_Pos.y; yf = m_Poly->corner[i_start_contour].y - Pcb->m_BoundaryBox.m_Pos.y;
i_start_contour = ic + 1; i_start_contour = ic + 1;
} }
TraceLignePcb( xi, yi, xf, yf, -1, HOLE | CELL_is_EDGE, WRITE_CELL ); TraceLignePcb( xi, yi, xf, yf, -1, HOLE | CELL_is_EDGE, WRITE_CELL );
@ -136,9 +136,8 @@ int ZONE_CONTAINER::Fill_Zone( WinEDA_PcbFrame* frame, wxDC* DC, bool verbose )
int cells_count = 0; int cells_count = 0;
for( ii = 0, pad = frame->m_Pcb->m_Pads; ii < frame->m_Pcb->m_NbPads; ii++, pad++ ) for( ii = 0, pad = frame->m_Pcb->m_Pads; ii < frame->m_Pcb->m_NbPads; ii++, pad++ )
{ {
int icont = 0;
wxPoint pos; wxPoint pos;
if( TestPointInsideContour( icont, (*pad)->m_Pos.x, (*pad)->m_Pos.y ) ) if( m_Poly->TestPointInside( (*pad)->m_Pos.x, (*pad)->m_Pos.y ) )
{ {
ZoneStartFill.x = ( (*pad)->m_Pos.x - Pcb->m_BoundaryBox.m_Pos.x + ZoneStartFill.x = ( (*pad)->m_Pos.x - Pcb->m_BoundaryBox.m_Pos.x +
(g_GridRoutingSize / 2) ) / g_GridRoutingSize; (g_GridRoutingSize / 2) ) / g_GridRoutingSize;
@ -196,20 +195,20 @@ int ZONE_CONTAINER::Fill_Zone( WinEDA_PcbFrame* frame, wxDC* DC, bool verbose )
/* Recreate zone limits on the routing matrix /* Recreate zone limits on the routing matrix
* (could be deleted by PlaceCells()) : */ * (could be deleted by PlaceCells()) : */
i_start_contour = 0; i_start_contour = 0;
for( unsigned ic = 0; ic < corner.size(); ic++ ) for( unsigned ic = 0; ic < m_Poly->corner.size(); ic++ )
{ {
int xi = corner[ic].x - Pcb->m_BoundaryBox.m_Pos.x; int xi = m_Poly->corner[ic].x - Pcb->m_BoundaryBox.m_Pos.x;
int yi = corner[ic].y - Pcb->m_BoundaryBox.m_Pos.y; int yi = m_Poly->corner[ic].y - Pcb->m_BoundaryBox.m_Pos.y;
int xf, yf; int xf, yf;
if( corner[ic].end_contour == FALSE && ic < corner.size() - 1 ) if( m_Poly->corner[ic].end_contour == FALSE && ic < m_Poly->corner.size() - 1 )
{ {
xf = corner[ic + 1].x - Pcb->m_BoundaryBox.m_Pos.x; xf = m_Poly->corner[ic + 1].x - Pcb->m_BoundaryBox.m_Pos.x;
yf = corner[ic + 1].y - Pcb->m_BoundaryBox.m_Pos.y; yf = m_Poly->corner[ic + 1].y - Pcb->m_BoundaryBox.m_Pos.y;
} }
else else
{ {
xf = corner[i_start_contour].x - Pcb->m_BoundaryBox.m_Pos.x; xf = m_Poly->corner[i_start_contour].x - Pcb->m_BoundaryBox.m_Pos.x;
yf = corner[i_start_contour].y - Pcb->m_BoundaryBox.m_Pos.y; yf = m_Poly->corner[i_start_contour].y - Pcb->m_BoundaryBox.m_Pos.y;
i_start_contour = ic + 1; i_start_contour = ic + 1;
} }
TraceLignePcb( xi, yi, xf, yf, -1, HOLE | CELL_is_EDGE, WRITE_CELL ); TraceLignePcb( xi, yi, xf, yf, -1, HOLE | CELL_is_EDGE, WRITE_CELL );
@ -219,9 +218,8 @@ int ZONE_CONTAINER::Fill_Zone( WinEDA_PcbFrame* frame, wxDC* DC, bool verbose )
* (could be deleted by PlaceCells()) : */ * (could be deleted by PlaceCells()) : */
for( ii = 0, pad = frame->m_Pcb->m_Pads; ii < frame->m_Pcb->m_NbPads; ii++, pad++ ) for( ii = 0, pad = frame->m_Pcb->m_Pads; ii < frame->m_Pcb->m_NbPads; ii++, pad++ )
{ {
int icont = 0;
wxPoint pos; wxPoint pos;
if( TestPointInsideContour( icont, (*pad)->m_Pos.x, (*pad)->m_Pos.y ) ) if( m_Poly->TestPointInside( (*pad)->m_Pos.x, (*pad)->m_Pos.y ) )
{ {
ZoneStartFill.x = ( (*pad)->m_Pos.x - Pcb->m_BoundaryBox.m_Pos.x + ZoneStartFill.x = ( (*pad)->m_Pos.x - Pcb->m_BoundaryBox.m_Pos.x +
(g_GridRoutingSize / 2) ) / g_GridRoutingSize; (g_GridRoutingSize / 2) ) / g_GridRoutingSize;

View File

@ -27,10 +27,9 @@ using namespace std;
#include "common.h" #include "common.h"
#include "pcbnew.h" #include "pcbnew.h"
#include "autorout.h" #include "autorout.h"
#include "cell.h"
#include "trigo.h" #include "id.h"
#include "protos.h" #include "protos.h"
@ -45,13 +44,15 @@ static void Abort_Zone_Move_Corner( WinEDA_DrawPanel* Panel, wxDC* DC );
static void Show_Zone_Corner_While_Move_Mouse( WinEDA_DrawPanel* panel, wxDC* DC, bool erase ); static void Show_Zone_Corner_While_Move_Mouse( WinEDA_DrawPanel* panel, wxDC* DC, bool erase );
/* Local variables */ /* Local variables */
static bool Zone_45_Only = FALSE; static bool Zone_45_Only = FALSE;
static ZONE_CONTAINER::m_PadInZone s_Zone_Pad_Options = ZONE_CONTAINER::THERMAL_PAD; static ZONE_CONTAINER::m_PadInZone s_Zone_Pad_Options = ZONE_CONTAINER::THERMAL_PAD;
static int s_Zone_Layer; // Layer used to create the current zone static int s_Zone_Layer; // Layer used to create the current zone
static int s_Zone_Hatching; // Option to show the zone area (outlines only, short hatches or full hatches static int s_Zone_Hatching; // Option to show the zone area (outlines only, short hatches or full hatches
static int s_NetcodeSelection; // Net code selection for the current zone static int s_NetcodeSelection; // Net code selection for the current zone
static wxPoint s_CornerInitialPosition; // Used to abort a move corner command static wxPoint s_CornerInitialPosition; // Used to abort a move corner command
static bool s_CornerIsNew; // Used to abort a move corner command (if it is a new corner, it must be deleted) static bool s_CornerIsNew; // Used to abort a move corner command (if it is a new corner, it must be deleted)
static bool s_AddCutoutToCurrentZone; // if true, the next outline will be addes to s_CurrentZone
static ZONE_CONTAINER* s_CurrentZone; // if != NULL, these ZONE_CONTAINER params will be used for the next zone
// key used to store net sort option in config file : // key used to store net sort option in config file :
#define ZONE_NET_SORT_OPTION_KEY wxT( "Zone_NetSort_Opt" ) #define ZONE_NET_SORT_OPTION_KEY wxT( "Zone_NetSort_Opt" )
@ -63,6 +64,44 @@ enum zone_cmd {
#include "dialog_zones_by_polygon.cpp" #include "dialog_zones_by_polygon.cpp"
/**********************************************************************************/
void WinEDA_PcbFrame::Add_Similar_Zone( wxDC* DC, ZONE_CONTAINER* zone_container )
/**********************************************************************************/
/**
* Function Add_Similar_Zone
* Add a zone to a given zone outline.
* if the zones are overlappeing they will be merged
* @param DC = current Device Context
* @param zone_container = parent zone outline
*/
{
s_AddCutoutToCurrentZone = false;
s_CurrentZone = zone_container;
wxCommandEvent evt;
evt.SetId( ID_PCB_ZONES_BUTT );
Process_Special_Functions( evt );
}
/**********************************************************************************/
void WinEDA_PcbFrame::Add_Zone_Cutout( wxDC* DC, ZONE_CONTAINER* zone_container )
/**********************************************************************************/
/**
* Function Add_Zone_Cutout
* Add a cutout zone to a given zone outline
* @param DC = current Device Context
* @param zone_container = parent zone outline
*/
{
s_AddCutoutToCurrentZone = true;
s_CurrentZone = zone_container;
wxCommandEvent evt;
evt.SetId( ID_PCB_ZONES_BUTT );
Process_Special_Functions( evt );
}
/*****************************************************************************/ /*****************************************************************************/
void WinEDA_PcbFrame::Delete_Zone( wxDC* DC, SEGZONE* aZone, long aTimestamp ) void WinEDA_PcbFrame::Delete_Zone( wxDC* DC, SEGZONE* aZone, long aTimestamp )
@ -174,6 +213,8 @@ static void Abort_Zone_Create_Outline( WinEDA_DrawPanel* Panel, wxDC* DC )
Panel->ManageCurseur = NULL; Panel->ManageCurseur = NULL;
Panel->ForceCloseManageCurseur = NULL; Panel->ForceCloseManageCurseur = NULL;
pcbframe->SetCurItem( NULL ); pcbframe->SetCurItem( NULL );
s_AddCutoutToCurrentZone = false;
s_CurrentZone = NULL;
} }
@ -228,9 +269,11 @@ void WinEDA_PcbFrame::Start_Move_Zone_Corner( wxDC* DC, ZONE_CONTAINER* zone_con
zone_container->m_Flags = IN_EDIT; zone_container->m_Flags = IN_EDIT;
DrawPanel->ManageCurseur = Show_Zone_Corner_While_Move_Mouse; DrawPanel->ManageCurseur = Show_Zone_Corner_While_Move_Mouse;
DrawPanel->ForceCloseManageCurseur = Abort_Zone_Move_Corner; DrawPanel->ForceCloseManageCurseur = Abort_Zone_Move_Corner;
s_CornerInitialPosition.x = zone_container->GetX( corner_id ); s_CornerInitialPosition.x = zone_container->m_Poly->GetX( corner_id );
s_CornerInitialPosition.y = zone_container->GetY( corner_id ); s_CornerInitialPosition.y = zone_container->m_Poly->GetY( corner_id );
s_CornerIsNew = IsNewCorner; s_CornerIsNew = IsNewCorner;
s_AddCutoutToCurrentZone = false;
s_CurrentZone = NULL;
} }
@ -248,6 +291,72 @@ void WinEDA_PcbFrame::End_Move_Zone_Corner( wxDC* DC, ZONE_CONTAINER* zone_conta
DrawPanel->ForceCloseManageCurseur = NULL; DrawPanel->ForceCloseManageCurseur = NULL;
zone_container->Draw( DrawPanel, DC, wxPoint( 0, 0 ), GR_OR ); zone_container->Draw( DrawPanel, DC, wxPoint( 0, 0 ), GR_OR );
GetScreen()->SetModify(); GetScreen()->SetModify();
s_AddCutoutToCurrentZone = false;
s_CurrentZone = NULL;
SetCurItem( NULL ); // This outine can be deleted when merging outlines
/* Combine zones if possible */
int layer = zone_container->GetLayer();
for( unsigned ii = 0; ii < m_Pcb->m_ZoneDescriptorList.size(); ii++ )
{
ZONE_CONTAINER* edge_zone = m_Pcb->m_ZoneDescriptorList[ii];
if( layer == edge_zone->GetLayer() )
edge_zone->Draw( DrawPanel, DC, wxPoint( 0, 0 ), GR_XOR );
}
m_Pcb->AreaPolygonModified( zone_container, true, false );
for( unsigned ii = 0; ii < m_Pcb->m_ZoneDescriptorList.size(); ii++ )
{
ZONE_CONTAINER* edge_zone = m_Pcb->m_ZoneDescriptorList[ii];
if( layer == edge_zone->GetLayer() )
edge_zone->Draw( DrawPanel, DC, wxPoint( 0, 0 ), GR_OR );
}
}
/*************************************************************************************/
void WinEDA_PcbFrame::Remove_Zone_Corner( wxDC* DC, ZONE_CONTAINER * zone_container )
/*************************************************************************************/
/**
* Function End_Move_Zone_Corner
* Remove the currently selected corner in a zone outline
* the .m_CornerSelection is used as corner selection
*/
{
if ( zone_container->m_Poly->GetNumCorners() <= 3 )
{
Delete_Zone( DC, NULL, zone_container->m_TimeStamp );
m_Pcb->Delete( zone_container );
return;
}
int layer = zone_container->GetLayer();
if ( DC )
{
for( unsigned ii = 0; ii < m_Pcb->m_ZoneDescriptorList.size(); ii++ )
{
ZONE_CONTAINER* edge_zone = m_Pcb->m_ZoneDescriptorList[ii];
if( layer == edge_zone->GetLayer() )
edge_zone->Draw( DrawPanel, DC, wxPoint( 0, 0 ), GR_XOR );
}
}
zone_container->m_Poly->DeleteCorner(zone_container->m_CornerSelection);
// modify zones outlines accordiing to the new zone_container shape
m_Pcb->AreaPolygonModified( zone_container, true, false );
if ( DC )
{
for( unsigned ii = 0; ii < m_Pcb->m_ZoneDescriptorList.size(); ii++ )
{
ZONE_CONTAINER* edge_zone = m_Pcb->m_ZoneDescriptorList[ii];
if( layer == edge_zone->GetLayer() )
edge_zone->Draw( DrawPanel, DC, wxPoint( 0, 0 ), GR_OR );
}
}
} }
@ -267,19 +376,21 @@ void Abort_Zone_Move_Corner( WinEDA_DrawPanel* Panel, wxDC* DC )
if( s_CornerIsNew ) if( s_CornerIsNew )
{ {
zone_container->DeleteCorner( zone_container->m_CornerSelection ); zone_container->m_Poly->DeleteCorner( zone_container->m_CornerSelection );
} }
else else
{ {
wxPoint pos = s_CornerInitialPosition; wxPoint pos = s_CornerInitialPosition;
zone_container->MoveCorner( zone_container->m_CornerSelection, pos.x, pos.y ); zone_container->m_Poly->MoveCorner( zone_container->m_CornerSelection, pos.x, pos.y );
} }
zone_container->Draw( Panel, DC, wxPoint( 0, 0 ), GR_XOR ); zone_container->Draw( Panel, DC, wxPoint( 0, 0 ), GR_XOR );
Panel->ManageCurseur = NULL; Panel->ManageCurseur = NULL;
Panel->ForceCloseManageCurseur = NULL; Panel->ForceCloseManageCurseur = NULL;
pcbframe->SetCurItem( NULL ); pcbframe->SetCurItem( NULL );
zone_container->m_Flags = 0; zone_container->m_Flags = 0;
s_AddCutoutToCurrentZone = false;
s_CurrentZone = NULL;
} }
@ -299,7 +410,7 @@ void Show_Zone_Corner_While_Move_Mouse( WinEDA_DrawPanel* Panel, wxDC* DC, bool
} }
wxPoint pos = pcbframe->GetScreen()->m_Curseur; wxPoint pos = pcbframe->GetScreen()->m_Curseur;
zone_container->MoveCorner( zone_container->m_CornerSelection, pos.x, pos.y ); zone_container->m_Poly->MoveCorner( zone_container->m_CornerSelection, pos.x, pos.y );
zone_container->Draw( Panel, DC, wxPoint( 0, 0 ), GR_XOR ); zone_container->Draw( Panel, DC, wxPoint( 0, 0 ), GR_XOR );
} }
@ -317,36 +428,61 @@ EDGE_ZONE* WinEDA_PcbFrame::Begin_Zone( wxDC* DC )
EDGE_ZONE* oldedge; EDGE_ZONE* oldedge;
EDGE_ZONE* newedge = NULL; EDGE_ZONE* newedge = NULL;
// verify if s_CurrentZone exists:
unsigned ii;
for( ii = 0; ii < m_Pcb->m_ZoneDescriptorList.size(); ii++ )
{
if( s_CurrentZone == m_Pcb->m_ZoneDescriptorList[ii] )
break;
}
if( ii == m_Pcb->m_ZoneDescriptorList.size() ) // Not found: coul be deleted since last selection
{
s_AddCutoutToCurrentZone = false;
s_CurrentZone = NULL;
}
oldedge = m_Pcb->m_CurrentLimitZone; oldedge = m_Pcb->m_CurrentLimitZone;
if( m_Pcb->m_CurrentLimitZone == NULL ) /* Start a new contour: init zone params (net and layer) */ if( m_Pcb->m_CurrentLimitZone == NULL ) /* Start a new contour: init zone params (net and layer) */
{ {
DrawPanel->m_IgnoreMouseEvents = TRUE; if( s_CurrentZone == NULL )
WinEDA_ZoneFrame* frame = new WinEDA_ZoneFrame( this ); {
DrawPanel->m_IgnoreMouseEvents = TRUE;
WinEDA_ZoneFrame* frame = new WinEDA_ZoneFrame( this );
int diag = frame->ShowModal(); int diag = frame->ShowModal();
frame->Destroy(); frame->Destroy();
DrawPanel->MouseToCursorSchema(); DrawPanel->MouseToCursorSchema();
DrawPanel->m_IgnoreMouseEvents = FALSE; DrawPanel->m_IgnoreMouseEvents = FALSE;
if( diag == ZONE_ABORT )
return NULL;
GetScreen()->m_Active_Layer = s_Zone_Layer;
if( diag == ZONE_ABORT )
return NULL;
}
else /* Start a new contour: init zone params (net and layer) from an existing zone */
{
GetScreen()->m_Active_Layer = s_Zone_Layer = s_CurrentZone->GetLayer();
s_Zone_Hatching = s_CurrentZone->m_Poly->GetHatchStyle();
}
/* Show the Net */ /* Show the Net */
if( (g_HightLigth_NetCode > 0) && (g_HightLigth_NetCode != s_NetcodeSelection) ) if( (g_HightLigth_NetCode > 0) && (g_HightLigth_NetCode != s_NetcodeSelection) )
{ {
Hight_Light( DC ); // Remove old hightlight selection Hight_Light( DC ); // Remove old hightlight selection
} }
if( s_CurrentZone )
s_NetcodeSelection = s_CurrentZone->GetNet();
g_HightLigth_NetCode = s_NetcodeSelection; g_HightLigth_NetCode = s_NetcodeSelection;
if( !g_HightLigt_Status ) if( !g_HightLigt_Status )
Hight_Light( DC ); Hight_Light( DC );
if( !s_AddCutoutToCurrentZone )
s_CurrentZone = NULL; // the zone is used only once
} }
// if first segment // if first segment
if( (m_Pcb->m_CurrentLimitZone == NULL ) /* Initial startt of a new outline */ if( (m_Pcb->m_CurrentLimitZone == NULL ) /* Initial start of a new outline */
|| (DrawPanel->ManageCurseur == NULL) ) /* reprise d'un trace complementaire */ || (DrawPanel->ManageCurseur == NULL) ) /* reprise d'un trace complementaire */
{ {
newedge = new EDGE_ZONE( m_Pcb ); newedge = new EDGE_ZONE( m_Pcb );
@ -400,6 +536,7 @@ void WinEDA_PcbFrame::End_Zone( wxDC* DC )
*/ */
{ {
EDGE_ZONE* edge; EDGE_ZONE* edge;
int layer = GetScreen()->m_Active_Layer;
if( m_Pcb->m_CurrentLimitZone ) if( m_Pcb->m_CurrentLimitZone )
{ {
@ -431,39 +568,74 @@ void WinEDA_PcbFrame::End_Zone( wxDC* DC )
DrawPanel->ManageCurseur = NULL; DrawPanel->ManageCurseur = NULL;
DrawPanel->ForceCloseManageCurseur = NULL; DrawPanel->ForceCloseManageCurseur = NULL;
/* Put edges in list */ // Undraw old drawings, because they can have important changes
ZONE_CONTAINER* polygon = new ZONE_CONTAINER( m_Pcb ); for( unsigned ii = 0; ii < m_Pcb->m_ZoneDescriptorList.size(); ii++ )
polygon->SetLayer( GetScreen()->m_Active_Layer );
polygon->SetNet( g_HightLigth_NetCode );
polygon->m_TimeStamp = GetTimeStamp();
EQUIPOT* net = m_Pcb->FindNet( g_HightLigth_NetCode );
if( net )
polygon->m_Netname = net->m_Netname;
edge = m_Pcb->m_CurrentLimitZone;
polygon->Start( GetScreen()->m_Active_Layer, 0, 0,
edge->m_Start.x, edge->m_Start.y,
s_Zone_Hatching );
edge = edge->Next();
while( edge )
{ {
polygon->AppendCorner( edge->m_Start.x, edge->m_Start.y ); ZONE_CONTAINER* edge_zone = m_Pcb->m_ZoneDescriptorList[ii];
edge = edge->Next(); if( layer == edge_zone->GetLayer() )
edge_zone->Draw( DrawPanel, DC, wxPoint( 0, 0 ), GR_XOR );
} }
polygon->Close(); // Close the current corner list /* Put edges in list */
polygon->SetHatch( s_Zone_Hatching ); ZONE_CONTAINER* new_zone_container;
polygon->m_PadOption = s_Zone_Pad_Options; if( s_CurrentZone == NULL )
polygon->m_ZoneClearance = g_DesignSettings.m_ZoneClearence; {
polygon->m_GridFillValue = g_GridRoutingSize; new_zone_container = new ZONE_CONTAINER( m_Pcb );
new_zone_container->SetLayer( layer );
new_zone_container->SetNet( g_HightLigth_NetCode );
new_zone_container->m_TimeStamp = GetTimeStamp();
m_Pcb->m_ZoneDescriptorList.push_back( polygon ); edge = m_Pcb->m_CurrentLimitZone;
new_zone_container->m_Poly->Start( layer, 0, 0,
edge->m_Start.x, edge->m_Start.y,
s_Zone_Hatching );
edge = edge->Next();
while( edge )
{
new_zone_container->m_Poly->AppendCorner( edge->m_Start.x, edge->m_Start.y );
edge = edge->Next();
}
new_zone_container->m_Poly->Close(); // Close the current corner list
new_zone_container->m_Poly->SetHatch( s_Zone_Hatching );
new_zone_container->m_PadOption = s_Zone_Pad_Options;
new_zone_container->m_ZoneClearance = g_DesignSettings.m_ZoneClearence;
new_zone_container->m_GridFillValue = g_GridRoutingSize;
m_Pcb->m_ZoneDescriptorList.push_back( new_zone_container );
}
else // Append this outline as a cutout to an existing zone
{
new_zone_container = s_CurrentZone;
edge = m_Pcb->m_CurrentLimitZone;
while( edge )
{
new_zone_container->m_Poly->AppendCorner( edge->m_Start.x, edge->m_Start.y );
edge = edge->Next();
}
new_zone_container->m_Poly->Close(); // Close the current corner list
}
s_AddCutoutToCurrentZone = false;
s_CurrentZone = NULL;
/* Remove the current temporary list */ /* Remove the current temporary list */
DelLimitesZone( DC, TRUE ); DelLimitesZone( DC, TRUE );
/* Redraw the real edge zone */ new_zone_container->m_Flags = 0;
polygon->Draw( DrawPanel, DC, wxPoint( 0, 0 ), GR_OR ); SetCurItem( NULL ); // This outine can be deleted when merging outlines
// Combine zones if possible :
m_Pcb->AreaPolygonModified( new_zone_container, true, false );
// Redraw the real edge zone :
for( unsigned ii = 0; ii < m_Pcb->m_ZoneDescriptorList.size(); ii++ )
{
ZONE_CONTAINER* edge_zone = m_Pcb->m_ZoneDescriptorList[ii];
if( layer == edge_zone->GetLayer() )
edge_zone->Draw( DrawPanel, DC, wxPoint( 0, 0 ), GR_OR );
}
GetScreen()->SetModify(); GetScreen()->SetModify();
} }
@ -540,19 +712,32 @@ void WinEDA_PcbFrame::Edit_Zone_Params( wxDC* DC, ZONE_CONTAINER* zone_container
if( diag == ZONE_ABORT ) if( diag == ZONE_ABORT )
return; return;
zone_container->Draw( DrawPanel, DC, wxPoint( 0, 0 ), GR_XOR ); // Undraw old zone outlines
for( unsigned ii = 0; ii < m_Pcb->m_ZoneDescriptorList.size(); ii++ )
{
ZONE_CONTAINER* edge_zone = m_Pcb->m_ZoneDescriptorList[ii];
edge_zone->Draw( DrawPanel, DC, wxPoint( 0, 0 ), GR_XOR );
}
zone_container->SetLayer( s_Zone_Layer ); zone_container->SetLayer( s_Zone_Layer );
zone_container->SetNet( s_NetcodeSelection ); zone_container->SetNet( s_NetcodeSelection );
EQUIPOT* net = m_Pcb->FindNet( s_NetcodeSelection ); EQUIPOT* net = m_Pcb->FindNet( s_NetcodeSelection );
if( net ) if( net )
zone_container->m_Netname = net->m_Netname; zone_container->m_Netname = net->m_Netname;
zone_container->SetHatch( s_Zone_Hatching ); zone_container->m_Poly->SetHatch( s_Zone_Hatching );
zone_container->m_PadOption = s_Zone_Pad_Options; zone_container->m_PadOption = s_Zone_Pad_Options;
zone_container->m_ZoneClearance = g_DesignSettings.m_ZoneClearence; zone_container->m_ZoneClearance = g_DesignSettings.m_ZoneClearence;
zone_container->m_GridFillValue = g_GridRoutingSize; zone_container->m_GridFillValue = g_GridRoutingSize;
zone_container->Draw( DrawPanel, DC, wxPoint( 0, 0 ), GR_OR ); // Combine zones if possible :
m_Pcb->AreaPolygonModified( zone_container, true, false );
// Redraw the real new zone outlines:
for( unsigned ii = 0; ii < m_Pcb->m_ZoneDescriptorList.size(); ii++ )
{
ZONE_CONTAINER* edge_zone = m_Pcb->m_ZoneDescriptorList[ii];
edge_zone->Draw( DrawPanel, DC, wxPoint( 0, 0 ), GR_OR );
}
GetScreen()->SetModify(); GetScreen()->SetModify();
} }
@ -587,11 +772,11 @@ int WinEDA_PcbFrame::Fill_Zone( wxDC* DC, ZONE_CONTAINER* zone_container, bool v
s_NetcodeSelection = zone_container->GetNet(); s_NetcodeSelection = zone_container->GetNet();
if( (g_HightLigth_NetCode > 0) && (g_HightLigth_NetCode != s_NetcodeSelection) && DC ) if( (g_HightLigth_NetCode > 0) && (g_HightLigth_NetCode != s_NetcodeSelection) && DC )
{ {
Hight_Light( DC ); // Remove old hightlight selection Hight_Light( DC ); // Remove old hightlight selection
} }
g_HightLigth_NetCode = s_NetcodeSelection; g_HightLigth_NetCode = s_NetcodeSelection;
if( !g_HightLigt_Status && DC) if( !g_HightLigt_Status && DC )
Hight_Light( DC ); Hight_Light( DC );
if( g_HightLigth_NetCode > 0 ) if( g_HightLigth_NetCode > 0 )
@ -613,7 +798,7 @@ int WinEDA_PcbFrame::Fill_Zone( wxDC* DC, ZONE_CONTAINER* zone_container, bool v
msg = _( "No Net" ); msg = _( "No Net" );
Affiche_1_Parametre( this, 22, _( "NetName" ), msg, RED ); Affiche_1_Parametre( this, 22, _( "NetName" ), msg, RED );
wxBusyCursor dummy; // Shows an hourglass cursor (removed by its destructor) wxBusyCursor dummy; // Shows an hourglass cursor (removed by its destructor)
zone_container->m_PadOption = s_Zone_Pad_Options; zone_container->m_PadOption = s_Zone_Pad_Options;
zone_container->m_ZoneClearance = g_DesignSettings.m_ZoneClearence; zone_container->m_ZoneClearance = g_DesignSettings.m_ZoneClearence;
zone_container->m_GridFillValue = g_GridRoutingSize; zone_container->m_GridFillValue = g_GridRoutingSize;
@ -641,22 +826,22 @@ int WinEDA_PcbFrame::Fill_All_Zones( wxDC* DC, bool verbose )
ZONE_CONTAINER* zone_container; ZONE_CONTAINER* zone_container;
int error_level = 0; int error_level = 0;
// Remove all zones : // Remove all zones :
if ( m_Pcb->m_Zone ) if( m_Pcb->m_Zone )
{ {
m_Pcb->m_Zone->DeleteStructList(); m_Pcb->m_Zone->DeleteStructList();
m_Pcb->m_Zone = NULL; m_Pcb->m_Zone = NULL;
m_Pcb->m_NbSegmZone = 0; m_Pcb->m_NbSegmZone = 0;
} }
for( unsigned ii = 0; ii < m_Pcb->m_ZoneDescriptorList.size(); ii++ ) for( unsigned ii = 0; ii < m_Pcb->m_ZoneDescriptorList.size(); ii++ )
{ {
zone_container = m_Pcb->m_ZoneDescriptorList[ii]; zone_container = m_Pcb->m_ZoneDescriptorList[ii];
error_level = Fill_Zone( NULL, zone_container, verbose ); error_level = Fill_Zone( NULL, zone_container, verbose );
if( error_level && ! verbose ) if( error_level && !verbose )
break; break;
} }
DrawPanel->Refresh(true); DrawPanel->Refresh( true );
return error_level; return error_level;
} }

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

View File

@ -748,6 +748,19 @@ void CPolyLine::RemoveContour( int icont )
Draw(); Draw();
} }
void CPolyLine::RemoveAllContours( void )
/**
* function RemoveAllContours
* removes all corners from the lists.
* Others params are not chnaged
*/
{
corner.clear( );
side_style.clear( );
}
/** Function InsertCorner /** Function InsertCorner
* insert a new corner between two existing corners * insert a new corner between two existing corners
* @param ic = index for the insertion point: the corner is inserted AFTER ic * @param ic = index for the insertion point: the corner is inserted AFTER ic

View File

@ -81,6 +81,7 @@ public:
void MoveCorner( int ic, int x, int y ); void MoveCorner( int ic, int x, int y );
void Close( int style = STRAIGHT, BOOL bDraw=TRUE ); void Close( int style = STRAIGHT, BOOL bDraw=TRUE );
void RemoveContour( int icont ); void RemoveContour( int icont );
void RemoveAllContours( void );
// drawing functions // drawing functions
void HighlightSide( int is ); void HighlightSide( int is );
@ -107,6 +108,7 @@ public:
// access functions // access functions
int GetLayer() { return m_layer;}
int GetNumCorners(); int GetNumCorners();
int GetNumSides(); int GetNumSides();
int GetClosed(); int GetClosed();
@ -125,7 +127,7 @@ public:
id GetId(); id GetId();
int GetSelBoxSize(); int GetSelBoxSize();
CDisplayList * GetDisplayList(){ return m_dlist; }; CDisplayList * GetDisplayList(){ return m_dlist; };
int GetHatch(){ return m_HatchStyle; } int GetHatchStyle(){ return m_HatchStyle; }
void SetHatch( int hatch ){ Undraw(); m_HatchStyle = hatch; Draw(); }; void SetHatch( int hatch ){ Undraw(); m_HatchStyle = hatch; Draw(); };
void SetX( int ic, int x ); void SetX( int ic, int x );
void SetY( int ic, int y ); void SetY( int ic, int y );
@ -159,14 +161,14 @@ private:
int m_Width; // line width int m_Width; // line width
int m_sel_box; // corner selection box width/2 int m_sel_box; // corner selection box width/2
int utility; int utility;
protected: public:
std::vector <CPolyPt> corner; // array of points for corners std::vector <CPolyPt> corner; // array of points for corners
std::vector <int> side_style; // array of styles for sides std::vector <int> side_style; // array of styles for sides
private: private:
std::vector <dl_element*> dl_side; // graphic elements std::vector <dl_element*> dl_side; // graphic elements
std::vector <dl_element*> dl_side_sel; std::vector <dl_element*> dl_side_sel;
std::vector <dl_element*> dl_corner_sel; std::vector <dl_element*> dl_corner_sel;
protected: public:
int m_HatchStyle; // hatch style, see enum above int m_HatchStyle; // hatch style, see enum above
std::vector <CSegment> m_HatchLines; // hatch lines std::vector <CSegment> m_HatchLines; // hatch lines
private: private: