Commit 75b3c3bf authored by charras's avatar charras

Switch to polygons in zones (old way no more supported)

areas can be now filled using solid polygons, or using segments to fill areas inside polygons.
parent 7de4bfe6
...@@ -5,6 +5,14 @@ Started 2007-June-11 ...@@ -5,6 +5,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-Dec-03 UPDATE Jean-Pierre Charras <jean-pierre.charras@inpg.fr>
================================================================================
++pcbnew
Switch to polygons in zones (old way no more supported)
areas can be now filled using solid polygons, or using segments to fill areas inside polygons.
results are same, but using segments can be better (faster redraw time) for polygons having a lot
of segments (more than 10000)
2008-Dec-02 UPDATE Wayne Stambaugh <stambaughw@verizon.net> 2008-Dec-02 UPDATE Wayne Stambaugh <stambaughw@verizon.net>
================================================================================ ================================================================================
++build fixes ++build fixes
......
...@@ -866,7 +866,7 @@ static bool IsGRSPolyDrawable( EDA_Rect* ClipBox, int n, int* Points ) ...@@ -866,7 +866,7 @@ static bool IsGRSPolyDrawable( EDA_Rect* ClipBox, int n, int* Points )
/************************************************************************/ /************************************************************************/
/* Routine to draw a new polyline and fill it if Fill, in screen space. */ /* Routine to draw a new polyline and fill it if Fill, in screen space. */
/************************************************************************/ /************************************************************************/
void GRSPoly( EDA_Rect* ClipBox, wxDC* DC, int n, int* Points, int Fill, void GRSPoly( EDA_Rect* ClipBox, wxDC* DC, int n, int* Points, bool Fill,
int width, int Color, int BgColor ) int width, int Color, int BgColor )
{ {
if( !IsGRSPolyDrawable( ClipBox, n, Points ) ) if( !IsGRSPolyDrawable( ClipBox, n, Points ) )
...@@ -898,14 +898,14 @@ void GRSPoly( EDA_Rect* ClipBox, wxDC* DC, int n, int* Points, int Fill, ...@@ -898,14 +898,14 @@ void GRSPoly( EDA_Rect* ClipBox, wxDC* DC, int n, int* Points, int Fill,
/* Routine to draw a new closed polyline and fill it if Fill, in screen space */ /* Routine to draw a new closed polyline and fill it if Fill, in screen space */
/******************************************************************************/ /******************************************************************************/
void GRSClosedPoly( EDA_Rect* ClipBox, wxDC* DC, int n, int* Points, void GRSClosedPoly( EDA_Rect* ClipBox, wxDC* DC, int n, int* Points,
int Fill, int Color, int BgColor ) bool Fill, int Color, int BgColor )
{ {
GRSClosedPoly( ClipBox, DC, n, Points, Fill, 0, Color, BgColor ); GRSClosedPoly( ClipBox, DC, n, Points, Fill, 0, Color, BgColor );
} }
void GRSClosedPoly( EDA_Rect* ClipBox, wxDC* DC, int n, int* Points, void GRSClosedPoly( EDA_Rect* ClipBox, wxDC* DC, int n, int* Points,
int Fill, int width, int Color, int BgColor ) bool Fill, int width, int Color, int BgColor )
{ {
int startx, starty; int startx, starty;
...@@ -939,7 +939,7 @@ void GRSClosedPoly( EDA_Rect* ClipBox, wxDC* DC, int n, int* Points, ...@@ -939,7 +939,7 @@ void GRSClosedPoly( EDA_Rect* ClipBox, wxDC* DC, int n, int* Points,
/* Routine to draw a new polyline and fill it if Fill, in drawing space. */ /* Routine to draw a new polyline and fill it if Fill, in drawing space. */
/************************************************************************/ /************************************************************************/
void GRPoly( EDA_Rect* ClipBox, wxDC* DC, int n, int* Points, void GRPoly( EDA_Rect* ClipBox, wxDC* DC, int n, int* Points,
int Fill, int width, int Color, int BgColor ) bool Fill, int width, int Color, int BgColor )
{ {
int ii, jj; int ii, jj;
...@@ -960,14 +960,14 @@ void GRPoly( EDA_Rect* ClipBox, wxDC* DC, int n, int* Points, ...@@ -960,14 +960,14 @@ void GRPoly( EDA_Rect* ClipBox, wxDC* DC, int n, int* Points,
/* Routine to draw a closed polyline and fill it if Fill, in object space */ /* Routine to draw a closed polyline and fill it if Fill, in object space */
/**************************************************************************/ /**************************************************************************/
void GRClosedPoly( EDA_Rect* ClipBox, wxDC* DC, int n, int* Points, void GRClosedPoly( EDA_Rect* ClipBox, wxDC* DC, int n, int* Points,
int Fill, int Color, int BgColor ) bool Fill, int Color, int BgColor )
{ {
GRClosedPoly( ClipBox, DC, n, Points, Fill, 0, Color, BgColor ); GRClosedPoly( ClipBox, DC, n, Points, Fill, 0, Color, BgColor );
} }
void GRClosedPoly( EDA_Rect* ClipBox, wxDC* DC, int n, int* Points, void GRClosedPoly( EDA_Rect* ClipBox, wxDC* DC, int n, int* Points,
int Fill, int width, int Color, int BgColor ) bool Fill, int width, int Color, int BgColor )
{ {
int ii, jj; int ii, jj;
......
...@@ -96,15 +96,11 @@ void GRSMoveRel(int x, int y); ...@@ -96,15 +96,11 @@ void GRSMoveRel(int x, int y);
void GRLineRel(EDA_Rect * ClipBox, wxDC * DC, int x, int y, int width, int Color); void GRLineRel(EDA_Rect * ClipBox, wxDC * DC, int x, int y, int width, int Color);
void GRSLineRel(EDA_Rect * ClipBox, wxDC * DC, int x, int y, int width, int Color); void GRSLineRel(EDA_Rect * ClipBox, wxDC * DC, int x, int y, int width, int Color);
void GRPoly(EDA_Rect * ClipBox, wxDC * DC, int n, int *Points, void GRPoly(EDA_Rect * ClipBox, wxDC * DC, int n, int *Points,
int Fill, int width, int Color, int BgColor); bool Fill, int width, int Color, int BgColor);
void GRClosedPoly(EDA_Rect * ClipBox, wxDC * DC, int n, int *Points, void GRClosedPoly(EDA_Rect * ClipBox, wxDC * DC, int n, int *Points, bool Fill, int Color, int BgColor);
int Fill, int Color, int BgColor); void GRClosedPoly(EDA_Rect * ClipBox, wxDC * DC, int n, int *Points, bool Fill, int width, int Color, int BgColor);
void GRClosedPoly(EDA_Rect * ClipBox, wxDC * DC, int n, int *Points, void GRSPoly(EDA_Rect * ClipBox, wxDC * DC, int n, int *Points, bool Fill, int width, int Color, int BgColor);
int Fill, int width, int Color, int BgColor); void GRSClosedPoly(EDA_Rect * ClipBox, wxDC * DC, int n, int *Points, bool Fill, int width, int Color, int BgColor);
void GRSPoly(EDA_Rect * ClipBox, wxDC * DC, int n, int *Points,
int Fill, int width, int Color, int BgColor);
void GRSClosedPoly(EDA_Rect * ClipBox, wxDC * DC, int n, int *Points,
int Fill, int width, int Color, int BgColor);
void GRCircle(EDA_Rect * ClipBox, wxDC * DC, int x, int y, int r, int Color); void GRCircle(EDA_Rect * ClipBox, wxDC * DC, int x, int y, int r, int Color);
void GRCircle(EDA_Rect * ClipBox, wxDC * DC, int x, int y, int r, int width, int Color); void GRCircle(EDA_Rect * ClipBox, wxDC * DC, int x, int y, int r, int width, int Color);
void GRFilledCircle(EDA_Rect * ClipBox, wxDC * DC, int x, int y, int r, void GRFilledCircle(EDA_Rect * ClipBox, wxDC * DC, int x, int y, int r,
......
...@@ -53,7 +53,7 @@ BOARD::BOARD( EDA_BaseStruct* parent, WinEDA_BasePcbFrame* frame ) : ...@@ -53,7 +53,7 @@ BOARD::BOARD( EDA_BaseStruct* parent, WinEDA_BasePcbFrame* frame ) :
m_Pads = NULL; // pointeur liste d'acces aux pads m_Pads = NULL; // pointeur liste d'acces aux pads
m_Ratsnest = NULL; // pointeur liste rats m_Ratsnest = NULL; // pointeur liste rats
m_LocalRatsnest = NULL; // pointeur liste rats local m_LocalRatsnest = NULL; // pointeur liste rats local
m_CurrentZoneContour = NULL; // This ZONE_CONTAINER handle the zone contour cuurently in progress m_CurrentZoneContour = NULL; // This ZONE_CONTAINER handle the zone contour currently in progress
// de determination des contours de zone // de determination des contours de zone
for( int layer=0; layer<NB_COPPER_LAYERS; ++layer ) for( int layer=0; layer<NB_COPPER_LAYERS; ++layer )
...@@ -84,6 +84,13 @@ BOARD::~BOARD() ...@@ -84,6 +84,13 @@ BOARD::~BOARD()
m_Zone->DeleteStructList(); m_Zone->DeleteStructList();
m_Zone = 0; m_Zone = 0;
while ( m_ZoneDescriptorList.size() )
{
ZONE_CONTAINER* area_to_remove = m_ZoneDescriptorList[0];
Delete( area_to_remove );
}
MyFree( m_Pads ); MyFree( m_Pads );
m_Pads = 0; m_Pads = 0;
...@@ -264,6 +271,18 @@ void BOARD::Add( BOARD_ITEM* aBoardItem, int aControl ) ...@@ -264,6 +271,18 @@ void BOARD::Add( BOARD_ITEM* aBoardItem, int aControl )
} }
break; break;
case TYPEZONE:
{ // Add item to head of list (starting in m_Zone)
aBoardItem->SetParent( this );
aBoardItem->SetBack( this ); // item will be the first item: back chain to the board
BOARD_ITEM* next_item = m_Zone; // Remember old the first item
aBoardItem->SetNext( next_item ); // Chain the new one ton the old item
if( next_item ) // Back chain the old item to the new one
next_item->SetBack( aBoardItem );
m_Zone = (SEGZONE*) aBoardItem; // Add to head of list
}
break;
case TYPEMODULE: case TYPEMODULE:
// this is an insert, not an append which may also be needed. // this is an insert, not an append which may also be needed.
{ {
...@@ -278,7 +297,7 @@ void BOARD::Add( BOARD_ITEM* aBoardItem, int aControl ) ...@@ -278,7 +297,7 @@ void BOARD::Add( BOARD_ITEM* aBoardItem, int aControl )
// other types may use linked list // other types may use linked list
default: default:
wxFAIL_MSG( wxT("BOARD::Add() needs work") ); wxFAIL_MSG( wxT("BOARD::Add() needs work: BOARD_ITEM type not handled") );
} }
} }
......
...@@ -153,7 +153,7 @@ bool ZONE_CONTAINER::Save( FILE* aFile ) const ...@@ -153,7 +153,7 @@ bool ZONE_CONTAINER::Save( FILE* aFile ) const
if( ret < 1 ) if( ret < 1 )
return false; return false;
ret = fprintf( aFile, "ZOptions %d %d %c %d %d\n", m_GridFillValue, m_ArcToSegmentsCount, ret = fprintf( aFile, "ZOptions %d %d %c %d %d\n", m_FillMode, m_ArcToSegmentsCount,
m_DrawOptions ? 'S' : 'F', m_ThermalReliefGapValue, m_ThermalReliefCopperBridgeValue ); m_DrawOptions ? 'S' : 'F', m_ThermalReliefGapValue, m_ThermalReliefCopperBridgeValue );
if( ret < 3 ) if( ret < 3 )
return false; return false;
...@@ -176,7 +176,7 @@ bool ZONE_CONTAINER::Save( FILE* aFile ) const ...@@ -176,7 +176,7 @@ bool ZONE_CONTAINER::Save( FILE* aFile ) const
for( item_pos = 0; item_pos < m_FilledPolysList.size(); item_pos++ ) for( item_pos = 0; item_pos < m_FilledPolysList.size(); item_pos++ )
{ {
const CPolyPt* corner = &m_FilledPolysList[item_pos]; const CPolyPt* corner = &m_FilledPolysList[item_pos];
ret = fprintf( aFile, "%d %d %d\n", corner->x, corner->y, corner->end_contour ); ret = fprintf( aFile, "%d %d %d %d\n", corner->x, corner->y, corner->end_contour, corner->utility );
if( ret < 3 ) if( ret < 3 )
return false; return false;
} }
...@@ -287,16 +287,16 @@ int ZONE_CONTAINER::ReadDescr( FILE* aFile, int* aLineNum ) ...@@ -287,16 +287,16 @@ int ZONE_CONTAINER::ReadDescr( FILE* aFile, int* aLineNum )
} }
if( strnicmp( Line, "ZOptions", 8 ) == 0 ) // Options info found if( strnicmp( Line, "ZOptions", 8 ) == 0 ) // Options info found
{ {
int gridsize = 50; int fillmode = 1;
int arcsegmentcount = 16; int arcsegmentcount = 16;
char drawopt = 'F'; char drawopt = 'F';
text = Line + 8; text = Line + 8;
ret = sscanf( text, "%d %d %c %d %d", &gridsize, &arcsegmentcount, &drawopt, ret = sscanf( text, "%d %d %c %d %d", &fillmode, &arcsegmentcount, &drawopt,
&m_ThermalReliefGapValue, &m_ThermalReliefCopperBridgeValue ); &m_ThermalReliefGapValue, &m_ThermalReliefCopperBridgeValue );
if( ret < 1 ) // Must find 1 or more args. if( ret < 1 ) // Must find 1 or more args.
return false; return false;
else else
m_GridFillValue = gridsize; m_FillMode = fillmode ? 1 : 0;
if( arcsegmentcount >= 32 ) if( arcsegmentcount >= 32 )
m_ArcToSegmentsCount = 32; m_ArcToSegmentsCount = 32;
...@@ -354,11 +354,13 @@ int ZONE_CONTAINER::ReadDescr( FILE* aFile, int* aLineNum ) ...@@ -354,11 +354,13 @@ int ZONE_CONTAINER::ReadDescr( FILE* aFile, int* aLineNum )
if( strnicmp( Line, "$endPOLYSCORNERS", 4 ) == 0 ) if( strnicmp( Line, "$endPOLYSCORNERS", 4 ) == 0 )
break; break;
CPolyPt corner; CPolyPt corner;
int itmp; int end_contour, utility;
ret = sscanf( Line, "%d %d %d", &corner.x, &corner.y, &itmp ); utility = 0;
ret = sscanf( Line, "%d %d %d %d", &corner.x, &corner.y, &end_contour, &utility );
if( ret < 3 ) if( ret < 3 )
return false; return false;
corner.end_contour = itmp ? true : false; corner.end_contour = end_contour ? true : false;
corner.utility = utility;
m_FilledPolysList.push_back( corner ); m_FilledPolysList.push_back( corner );
} }
} }
...@@ -371,7 +373,7 @@ int ZONE_CONTAINER::ReadDescr( FILE* aFile, int* aLineNum ) ...@@ -371,7 +373,7 @@ int ZONE_CONTAINER::ReadDescr( FILE* aFile, int* aLineNum )
if( !IsOnCopperLayer() ) if( !IsOnCopperLayer() )
{ {
m_GridFillValue = 0; m_FillMode = 0;
SetNet( 0 ); SetNet( 0 );
} }
...@@ -424,6 +426,8 @@ void ZONE_CONTAINER::Draw( WinEDA_DrawPanel* panel, wxDC* DC, int draw_mode, con ...@@ -424,6 +426,8 @@ void ZONE_CONTAINER::Draw( WinEDA_DrawPanel* panel, wxDC* DC, int draw_mode, con
if( color & HIGHT_LIGHT_FLAG ) if( color & HIGHT_LIGHT_FLAG )
color = ColorRefs[color & MASKCOLOR].m_LightColor; color = ColorRefs[color & MASKCOLOR].m_LightColor;
SetAlpha( &color, 150 );
// draw the lines // draw the lines
int i_start_contour = 0; int i_start_contour = 0;
for( int ic = 0; ic < GetNumCorners(); ic++ ) for( int ic = 0; ic < GetNumCorners(); ic++ )
...@@ -452,6 +456,19 @@ void ZONE_CONTAINER::Draw( WinEDA_DrawPanel* panel, wxDC* DC, int draw_mode, con ...@@ -452,6 +456,19 @@ void ZONE_CONTAINER::Draw( WinEDA_DrawPanel* panel, wxDC* DC, int draw_mode, con
} }
} }
/* this is local class to handle 2 integers that are a corner coordinate
* One could use wxPoint insteed.
* However, this class has only 2 integers
* if changes happen in wxPoint ( like virtual functions) they will be not suitable
* So i prefer use this simple class to handle a coordinate.
*/
class corner_coord
{
public:
int x;
int y;
};
/************************************************************************************/ /************************************************************************************/
void ZONE_CONTAINER::DrawFilledArea( WinEDA_DrawPanel* panel, void ZONE_CONTAINER::DrawFilledArea( WinEDA_DrawPanel* panel,
...@@ -467,9 +484,10 @@ void ZONE_CONTAINER::DrawFilledArea( WinEDA_DrawPanel* panel, ...@@ -467,9 +484,10 @@ void ZONE_CONTAINER::DrawFilledArea( WinEDA_DrawPanel* panel,
* @param aDrawMode = GR_OR, GR_XOR, GR_COPY .. * @param aDrawMode = GR_OR, GR_XOR, GR_COPY ..
*/ */
{ {
static int* CornersBuffer = NULL; static vector < char > CornersTypeBuffer;
static unsigned CornersBufferSize = 0; static vector < corner_coord > CornersBuffer;
bool sketch_mode = m_DrawOptions; // false to show filled polys, true to show polygons outlines only (test and debug purposes)
bool outline_mode = m_DrawOptions; // false to show filled polys, true to show polygons outlines only (test and debug purposes)
if( DC == NULL ) if( DC == NULL )
return; return;
...@@ -477,9 +495,7 @@ void ZONE_CONTAINER::DrawFilledArea( WinEDA_DrawPanel* panel, ...@@ -477,9 +495,7 @@ void ZONE_CONTAINER::DrawFilledArea( WinEDA_DrawPanel* panel,
if( !DisplayOpt.DisplayZones ) if( !DisplayOpt.DisplayZones )
return; return;
unsigned imax = m_FilledPolysList.size(); if( m_FilledPolysList.size() == 0 ) // Nothing to draw
if( imax == 0 ) // Nothing to draw
return; return;
int curr_layer = ( (PCB_SCREEN*) panel->GetScreen() )->m_Active_Layer; int curr_layer = ( (PCB_SCREEN*) panel->GetScreen() )->m_Active_Layer;
...@@ -509,55 +525,60 @@ void ZONE_CONTAINER::DrawFilledArea( WinEDA_DrawPanel* panel, ...@@ -509,55 +525,60 @@ void ZONE_CONTAINER::DrawFilledArea( WinEDA_DrawPanel* panel,
if( color & HIGHT_LIGHT_FLAG ) if( color & HIGHT_LIGHT_FLAG )
color = ColorRefs[color & MASKCOLOR].m_LightColor; color = ColorRefs[color & MASKCOLOR].m_LightColor;
// We need a buffer to store corners coordinates: SetAlpha( &color, 150 );
if( CornersBuffer == NULL )
{
CornersBufferSize = imax * 4;
CornersBuffer = (int*) MyMalloc( CornersBufferSize * sizeof(int) );
}
if( (imax * 4) > CornersBufferSize ) CornersTypeBuffer.clear();
{ CornersBuffer.clear();
CornersBufferSize = imax * 4;
CornersBuffer = (int*) realloc( CornersBuffer, CornersBufferSize * sizeof(int) );
}
// Draw all filled areas // Draw all filled areas
int corners_count = 0; int imax = m_FilledPolysList.size() - 1;
for( unsigned ic = 0, ii = 0; ic < imax; ic++ ) for( int ic = 0; ic <= imax; ic++ )
{ {
CPolyPt* corner = &m_FilledPolysList[ic]; CPolyPt* corner = &m_FilledPolysList[ic];
CornersBuffer[ii++] = corner->x + offset.x; corner_coord coord;
CornersBuffer[ii++] = corner->y + offset.y; coord.x = corner->x + offset.x;
corners_count++; coord.y = corner->y + offset.y;
if( corner->end_contour ) CornersBuffer.push_back(coord);
{ // Draw the current filled area CornersTypeBuffer.push_back((char) corner->utility);
if( sketch_mode ) if( (corner->end_contour) || (ic == imax) ) // the last corner of a filled area is found: draw it
GRClosedPoly( &panel->m_ClipBox, DC, corners_count, CornersBuffer, { /* Draw the current filled area: draw segments ouline first
false, 0, color, color ); * Curiously, draw segments ouline first and after draw filled polygons
else * with oulines thickness = 0 is a faster than
* just draw filled polygons but with oulines thickness = m_ZoneMinThickness
* So DO NOT use draw filled polygons with oulines having a thickness > 0
* Note: Extra segments ( added by kbool to joint holes with external outline) are not drawn
*/
{ {
// Draw outlines: // Draw outlines:
if ( m_ZoneMinThickness > 1 ) if ( (m_ZoneMinThickness > 1) || outline_mode )
{
int ilim = CornersBuffer.size()-1;
for ( int is = 0, ie = ilim; is <= ilim; ie = is, is++ )
{ {
int ilim = corners_count * 2; int x0 = CornersBuffer[is].x;
for ( int is = 0, ie = ilim-2; is < ilim; ie = is, is+=2 ) int y0 = CornersBuffer[is].y;
int x1 = CornersBuffer[ie].x;
int y1 = CornersBuffer[ie].y;
if ( CornersTypeBuffer[ie] == 0 ) // Draw only basic outlines, not extra segments
{ {
int x0 = CornersBuffer[is]; if( (!DisplayOpt.DisplayPcbTrackFill) || GetState( FORCE_SKETCH ) )
int y0 = CornersBuffer[is+1]; GRCSegm( &panel->m_ClipBox, DC,
int x1 = CornersBuffer[ie]; x0, y0, x1 , y1,
int y1 = CornersBuffer[ie+1]; m_ZoneMinThickness, color );
else
GRFillCSegm( &panel->m_ClipBox, DC, GRFillCSegm( &panel->m_ClipBox, DC,
x0, y0, x1 , y1, x0, y0, x1 , y1,
m_ZoneMinThickness, color ); m_ZoneMinThickness, color );
} }
} }
}
// Draw areas: // Draw areas:
GRPoly( &panel->m_ClipBox, DC, corners_count, CornersBuffer, if( (m_FillMode == 0 ) && ! outline_mode )
GRPoly( &panel->m_ClipBox, DC, CornersBuffer.size(), (int*)&CornersBuffer[0].x,
true, 0, color, color ); true, 0, color, color );
} }
corners_count = 0; CornersTypeBuffer.clear();
ii = 0; CornersBuffer.clear();
} }
} }
} }
...@@ -884,11 +905,11 @@ void ZONE_CONTAINER::Display_Infos( WinEDA_DrawFrame* frame ) ...@@ -884,11 +905,11 @@ void ZONE_CONTAINER::Display_Infos( WinEDA_DrawFrame* frame )
Affiche_1_Parametre( frame, text_pos, _( "Corners" ), msg, BLUE ); Affiche_1_Parametre( frame, text_pos, _( "Corners" ), msg, BLUE );
text_pos += 6; text_pos += 6;
if( m_GridFillValue ) if( m_FillMode )
msg.Printf( wxT( "%d" ), m_GridFillValue ); msg.Printf( _( "Segments" ), m_FillMode );
else else
msg = _( "No Grid" ); msg = _( "Polygons" );
Affiche_1_Parametre( frame, text_pos, _( "Fill Grid" ), msg, BROWN ); Affiche_1_Parametre( frame, text_pos, _( "Fill mode" ), msg, BROWN );
// Useful for statistics : // Useful for statistics :
text_pos += 9; text_pos += 9;
...@@ -913,12 +934,21 @@ void ZONE_CONTAINER::Display_Infos( WinEDA_DrawFrame* frame ) ...@@ -913,12 +934,21 @@ void ZONE_CONTAINER::Display_Infos( WinEDA_DrawFrame* frame )
*/ */
void ZONE_CONTAINER::Move( const wxPoint& offset ) void ZONE_CONTAINER::Move( const wxPoint& offset )
{ {
/* move outlines */
for( unsigned ii = 0; ii < m_Poly->corner.size(); ii++ ) for( unsigned ii = 0; ii < m_Poly->corner.size(); ii++ )
{ {
SetCornerPosition( ii, GetCornerPosition( ii ) + offset ); SetCornerPosition( ii, GetCornerPosition( ii ) + offset );
} }
m_Poly->Hatch(); m_Poly->Hatch();
/* move filled areas: */
for( unsigned ic = 0; ic < m_FilledPolysList.size(); ic++ )
{
CPolyPt* corner = &m_FilledPolysList[ic];
corner->x += offset.x;
corner->y += offset.y;
}
} }
...@@ -1001,7 +1031,7 @@ void ZONE_CONTAINER::Copy( ZONE_CONTAINER* src ) ...@@ -1001,7 +1031,7 @@ void ZONE_CONTAINER::Copy( ZONE_CONTAINER* src )
m_Poly->Copy( src->m_Poly ); // copy outlines m_Poly->Copy( src->m_Poly ); // copy outlines
m_CornerSelection = -1; // For corner moving, corner index to drag, or -1 if no selection m_CornerSelection = -1; // For corner moving, corner index to drag, or -1 if no selection
m_ZoneClearance = src->m_ZoneClearance; // clearance value m_ZoneClearance = src->m_ZoneClearance; // clearance value
m_GridFillValue = src->m_GridFillValue; // Grid used for filling m_FillMode = src->m_FillMode; // Grid used for filling
m_PadOption = src->m_PadOption; m_PadOption = src->m_PadOption;
m_Poly->SetHatch( src->m_Poly->GetHatchStyle() ); m_Poly->SetHatch( src->m_Poly->GetHatchStyle() );
} }
......
...@@ -27,7 +27,7 @@ public: ...@@ -27,7 +27,7 @@ public:
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_ZoneMinThickness; // Min thickness value in filled areas int m_ZoneMinThickness; // Min thickness value in filled areas
int m_GridFillValue; // Grid used for filling, 0 = use polygonal areas to fill int m_FillMode; // How to fillingareas: 0 = use polygonal areas , != 0 fill with segments
int m_ArcToSegmentsCount; // number of segments to convert a cirlce to a polygon (uses 16 or 32) int m_ArcToSegmentsCount; // number of segments to convert a cirlce to a polygon (uses 16 or 32)
int m_PadOption; // int m_PadOption; //
int m_ThermalReliefGapValue; // tickness of the gap in thermal reliefs int m_ThermalReliefGapValue; // tickness of the gap in thermal reliefs
...@@ -255,6 +255,17 @@ public: ...@@ -255,6 +255,17 @@ public:
*/ */
int Fill_Zone( WinEDA_PcbFrame* frame, wxDC* DC, bool verbose = TRUE ); int Fill_Zone( WinEDA_PcbFrame* frame, wxDC* DC, bool verbose = TRUE );
/** Function Fill_Zone_Areas_With_Segments()
* Fill sub areas in a zone with segments with m_ZoneMinThickness width
* A scan is made line per line, on the whole filled areas, with a step of m_ZoneMinThickness.
* all intersecting points with the horizontal infinite line and polygons to fill are calculated
* a list of SEGZONE items is built, line per line
* @param aFrame = reference to the main frame
* @return number of segments created
*/
int Fill_Zone_Areas_With_Segments( WinEDA_PcbFrame* aFrame );
/* Geometric transformations: */ /* Geometric transformations: */
/** /**
......
...@@ -24,9 +24,9 @@ ...@@ -24,9 +24,9 @@
ZONE_SETTING::ZONE_SETTING( void ) ZONE_SETTING::ZONE_SETTING( void )
{ {
m_GridFillValue = 250; // Grid value for filling zone by segments, 0 to used polygons to fill m_FillMode = 1; // Mode for filling zone : 1 use segments, 0 use polygons
m_ZoneClearance = 200; // Clearance value m_ZoneClearance = 200; // Clearance value
m_ZoneMinThickness = 0; // Min thickness value in filled areas m_ZoneMinThickness = 100; // Min thickness value in filled areas
m_NetcodeSelection = 0; // Net code selection for the current zone m_NetcodeSelection = 0; // Net code selection for the current zone
m_CurrentZone_Layer = 0; // Layer used to create the current zone m_CurrentZone_Layer = 0; // Layer used to create the current zone
m_Zone_HatchingStyle = CPolyLine::DIAGONAL_EDGE; // Option to show the zone area (outlines only, short hatches or full hatches m_Zone_HatchingStyle = CPolyLine::DIAGONAL_EDGE; // Option to show the zone area (outlines only, short hatches or full hatches
...@@ -46,7 +46,7 @@ ZONE_SETTING::ZONE_SETTING( void ) ...@@ -46,7 +46,7 @@ ZONE_SETTING::ZONE_SETTING( void )
*/ */
void ZONE_SETTING::ImportSetting( const ZONE_CONTAINER& aSource ) void ZONE_SETTING::ImportSetting( const ZONE_CONTAINER& aSource )
{ {
m_GridFillValue = aSource.m_GridFillValue; m_FillMode = aSource.m_FillMode;
m_ZoneClearance = aSource.m_ZoneClearance; m_ZoneClearance = aSource.m_ZoneClearance;
m_ZoneMinThickness = aSource.m_ZoneMinThickness; m_ZoneMinThickness = aSource.m_ZoneMinThickness;
m_NetcodeSelection = aSource.GetNet(); m_NetcodeSelection = aSource.GetNet();
...@@ -63,20 +63,25 @@ void ZONE_SETTING::ImportSetting( const ZONE_CONTAINER& aSource ) ...@@ -63,20 +63,25 @@ void ZONE_SETTING::ImportSetting( const ZONE_CONTAINER& aSource )
/** function ExportSetting /** function ExportSetting
* copy settings to a given zone * copy settings to a given zone
* @param aTarget: the given zone * @param aTarget: the given zone
* Note: parameters NOT exported (because they cannot be safely exported): * @param aFullExport: if false: some parameters are NOT exported
* because they must not be exported when export settings from a zone to others zones
* Currently:
* m_NetcodeSelection * m_NetcodeSelection
*/ */
void ZONE_SETTING::ExportSetting( ZONE_CONTAINER& aTarget ) void ZONE_SETTING::ExportSetting( ZONE_CONTAINER& aTarget, bool aFullExport )
{ {
aTarget.m_GridFillValue = m_GridFillValue; aTarget.m_FillMode = m_FillMode;
aTarget.m_ZoneClearance = m_ZoneClearance; aTarget.m_ZoneClearance = m_ZoneClearance;
aTarget.m_ZoneMinThickness = m_ZoneMinThickness; aTarget.m_ZoneMinThickness = m_ZoneMinThickness;
aTarget.SetNet( m_NetcodeSelection );
aTarget.SetLayer( m_CurrentZone_Layer );
aTarget.m_Poly->SetHatch( m_Zone_HatchingStyle ); aTarget.m_Poly->SetHatch( m_Zone_HatchingStyle );
aTarget.m_ArcToSegmentsCount = m_ArcToSegmentsCount; aTarget.m_ArcToSegmentsCount = m_ArcToSegmentsCount;
aTarget.m_DrawOptions = m_FilledAreasShowMode; aTarget.m_DrawOptions = m_FilledAreasShowMode;
aTarget.m_ThermalReliefGapValue = m_ThermalReliefGapValue; aTarget.m_ThermalReliefGapValue = m_ThermalReliefGapValue;
aTarget.m_ThermalReliefCopperBridgeValue = m_ThermalReliefCopperBridgeValue; aTarget.m_ThermalReliefCopperBridgeValue = m_ThermalReliefCopperBridgeValue;
aTarget.m_PadOption = m_Zone_Pad_Options; aTarget.m_PadOption = m_Zone_Pad_Options;
if ( aFullExport )
{
aTarget.SetNet( m_NetcodeSelection );
aTarget.SetLayer( m_CurrentZone_Layer );
}
} }
...@@ -17,7 +17,7 @@ ...@@ -17,7 +17,7 @@
class ZONE_SETTING class ZONE_SETTING
{ {
public: public:
int m_GridFillValue; // Grid value for filling zone by segments, 0 to used polygons to fill int m_FillMode; // Mode for filling zone : 1 use segments, 0 use polygons
int m_ZoneClearance; // Clearance value int m_ZoneClearance; // Clearance value
int m_ZoneMinThickness; // Min thickness value in filled areas int m_ZoneMinThickness; // Min thickness value in filled areas
int m_NetcodeSelection; // Net code selection for the current zone int m_NetcodeSelection; // Net code selection for the current zone
...@@ -41,8 +41,12 @@ public: ...@@ -41,8 +41,12 @@ public:
/** function ExportSetting /** function ExportSetting
* copy settings to a given zone * copy settings to a given zone
* @param aTarget: the given zone * @param aTarget: the given zone
* @param aFullExport: if false: some parameters are NOT exported
* because they must not be exported when export settings from a zone to others zones
* Currently:
* m_NetcodeSelection
*/ */
void ExportSetting( ZONE_CONTAINER& aTarget ); void ExportSetting( ZONE_CONTAINER& aTarget, bool aFullExport = true);
}; };
......
...@@ -66,31 +66,10 @@ void dialog_copper_zone::OnInitDialog( wxInitDialogEvent& event ) ...@@ -66,31 +66,10 @@ void dialog_copper_zone::OnInitDialog( wxInitDialogEvent& event )
wxString msg; wxString msg;
msg = m_GridCtrl->GetLabel() + ReturnUnitSymbol( g_UnitMetric );
m_GridCtrl->SetLabel( msg );
if( g_Zone_45_Only ) if( g_Zone_45_Only )
m_OrientEdgesOpt->SetSelection( 1 ); m_OrientEdgesOpt->SetSelection( 1 );
static const int GridList[4] = { 25, 50, 100, 250 }; m_FillModeCtrl->SetSelection(m_Zone_Setting->m_FillMode ? 1 : 0);
int selection = 0;
int grid_routing = m_Zone_Setting->m_GridFillValue;
for( unsigned ii = 0; ii < 4; ii++ )
{
msg = ReturnStringFromValue( g_UnitMetric,
GridList[ii],
m_Parent->m_InternalUnits );
m_GridCtrl->SetString( ii, msg );
if( grid_routing == GridList[ii] )
selection = ii;
}
if( grid_routing == 0 ) // No Grid: fill with polygons
selection = 4;
m_GridCtrl->SetSelection( selection );
AddUnitSymbol( *m_ClearanceValueTitle, g_UnitMetric ); AddUnitSymbol( *m_ClearanceValueTitle, g_UnitMetric );
msg = ReturnStringFromValue( g_UnitMetric, msg = ReturnStringFromValue( g_UnitMetric,
...@@ -294,29 +273,7 @@ bool dialog_copper_zone::AcceptOptions( bool aPromptForErrors, bool aUseExportab ...@@ -294,29 +273,7 @@ bool dialog_copper_zone::AcceptOptions( bool aPromptForErrors, bool aUseExportab
m_Config->Write( ZONE_NET_FILTER_STRING_KEY, Filter ); m_Config->Write( ZONE_NET_FILTER_STRING_KEY, Filter );
} }
switch( m_GridCtrl->GetSelection() ) m_Zone_Setting->m_FillMode = (m_FillModeCtrl->GetSelection() == 0) ? 0 : 1;
{
case 0:
m_Zone_Setting->m_GridFillValue = 25;
break;
case 1:
m_Zone_Setting->m_GridFillValue = 50;
break;
default:
case 2:
m_Zone_Setting->m_GridFillValue = 100;
break;
case 3:
m_Zone_Setting->m_GridFillValue = 250;
break;
case 4:
m_Zone_Setting->m_GridFillValue = 0;
break;
}
wxString txtvalue = m_ZoneClearanceCtrl->GetValue(); wxString txtvalue = m_ZoneClearanceCtrl->GetValue();
m_Zone_Setting->m_ZoneClearance = m_Zone_Setting->m_ZoneClearance =
...@@ -325,6 +282,12 @@ bool dialog_copper_zone::AcceptOptions( bool aPromptForErrors, bool aUseExportab ...@@ -325,6 +282,12 @@ bool dialog_copper_zone::AcceptOptions( bool aPromptForErrors, bool aUseExportab
txtvalue = m_ZoneMinThicknessCtrl->GetValue(); txtvalue = m_ZoneMinThicknessCtrl->GetValue();
m_Zone_Setting->m_ZoneMinThickness = m_Zone_Setting->m_ZoneMinThickness =
ReturnValueFromString( g_UnitMetric, txtvalue, m_Parent->m_InternalUnits ); ReturnValueFromString( g_UnitMetric, txtvalue, m_Parent->m_InternalUnits );
if ( m_Zone_Setting->m_ZoneMinThickness < 10 )
{
DisplayError( this,
_( "Error :\nyou must choose a copper min thickness value bigger than 0.001 inch or 0.00254 mm)" ) );
return false;
}
if( m_OrientEdgesOpt->GetSelection() == 0 ) if( m_OrientEdgesOpt->GetSelection() == 0 )
g_Zone_45_Only = FALSE; g_Zone_45_Only = FALSE;
...@@ -462,14 +425,12 @@ void dialog_copper_zone::ExportSetupToOtherCopperZones( wxCommandEvent& event ) ...@@ -462,14 +425,12 @@ void dialog_copper_zone::ExportSetupToOtherCopperZones( wxCommandEvent& event )
if( !AcceptOptions( true, true ) ) if( !AcceptOptions( true, true ) )
return; return;
// Export settings ( but layer ) to others zones: // Export settings ( but layer and netcode ) to others zones:
BOARD* pcb = m_Parent->m_Pcb; BOARD* pcb = m_Parent->m_Pcb;
for( int ii = 0; ii < pcb->GetAreaCount(); ii++ ) for( int ii = 0; ii < pcb->GetAreaCount(); ii++ )
{ {
ZONE_CONTAINER* zone = pcb->GetArea( ii ); ZONE_CONTAINER* zone = pcb->GetArea( ii );
int zone_layer = zone->GetLayer(); m_Zone_Setting->ExportSetting( *zone, false ); // false = partiel export
m_Zone_Setting->ExportSetting( *zone );
zone->SetLayer( zone_layer );
m_Parent->GetScreen()->SetModify(); m_Parent->GetScreen()->SetModify();
} }
} }
......
...@@ -37,24 +37,34 @@ dialog_copper_zone_base::dialog_copper_zone_base( wxWindow* parent, wxWindowID i ...@@ -37,24 +37,34 @@ dialog_copper_zone_base::dialog_copper_zone_base( wxWindow* parent, wxWindowID i
wxStaticBoxSizer* m_FillOptionsBox; wxStaticBoxSizer* m_FillOptionsBox;
m_FillOptionsBox = new wxStaticBoxSizer( new wxStaticBox( this, wxID_ANY, _("Zone Fill Options:") ), wxVERTICAL ); m_FillOptionsBox = new wxStaticBoxSizer( new wxStaticBox( this, wxID_ANY, _("Zone Fill Options:") ), wxVERTICAL );
wxString m_GridCtrlChoices[] = { _("0.00000"), _("0.00000"), _("0.00000"), _("0.00000"), _("No grid (For tests only!)") }; wxString m_FillModeCtrlChoices[] = { _("Use polygons"), _("Use segments") };
int m_GridCtrlNChoices = sizeof( m_GridCtrlChoices ) / sizeof( wxString ); int m_FillModeCtrlNChoices = sizeof( m_FillModeCtrlChoices ) / sizeof( wxString );
m_GridCtrl = new wxRadioBox( this, ID_RADIOBOX_GRID_SELECTION, _("Grid Size for Filling"), wxDefaultPosition, wxDefaultSize, m_GridCtrlNChoices, m_GridCtrlChoices, 1, wxRA_SPECIFY_COLS ); m_FillModeCtrl = new wxRadioBox( this, ID_RADIOBOX_FILL_MODE_SELECTION, _("Filling Mode:"), wxDefaultPosition, wxDefaultSize, m_FillModeCtrlNChoices, m_FillModeCtrlChoices, 1, wxRA_SPECIFY_COLS );
m_GridCtrl->SetSelection( 1 ); m_FillModeCtrl->SetSelection( 1 );
m_FillOptionsBox->Add( m_GridCtrl, 0, wxALL|wxEXPAND, 5 ); m_FillModeCtrl->SetToolTip( _("Filled areas can use solid polygons or segments.\nDepending on the complexity and the size of the zone,\nsometime polygons are better and sometime segments are better") );
m_FillOptionsBox->Add( m_FillModeCtrl, 0, wxEXPAND|wxBOTTOM|wxRIGHT|wxLEFT, 5 );
wxString m_ArcApproximationOptChoices[] = { _("16 segments / 360 deg"), _("32 segments / 360 deg") };
int m_ArcApproximationOptNChoices = sizeof( m_ArcApproximationOptChoices ) / sizeof( wxString );
m_ArcApproximationOpt = new wxRadioBox( this, wxID_ARC_APPROX, _("Arcs Approximation:"), wxDefaultPosition, wxDefaultSize, m_ArcApproximationOptNChoices, m_ArcApproximationOptChoices, 1, wxRA_SPECIFY_COLS );
m_ArcApproximationOpt->SetSelection( 1 );
m_ArcApproximationOpt->SetToolTip( _("Number of segments to approximate a circle in filling calculations.\n16 segment is faster to calculate and when redraw screen.\n32 segment give a better quality") );
m_FillOptionsBox->Add( m_ArcApproximationOpt, 0, wxEXPAND|wxBOTTOM|wxRIGHT|wxLEFT, 5 );
wxString m_PadInZoneOptChoices[] = { _("Include pads"), _("Thermal relief"), _("Exclude pads") }; wxString m_PadInZoneOptChoices[] = { _("Include pads"), _("Thermal relief"), _("Exclude pads") };
int m_PadInZoneOptNChoices = sizeof( m_PadInZoneOptChoices ) / sizeof( wxString ); int m_PadInZoneOptNChoices = sizeof( m_PadInZoneOptChoices ) / sizeof( wxString );
m_PadInZoneOpt = new wxRadioBox( this, wxID_PADS_IN_ZONE_OPTIONS, _("Pad in Zone:"), wxDefaultPosition, wxDefaultSize, m_PadInZoneOptNChoices, m_PadInZoneOptChoices, 1, wxRA_SPECIFY_COLS ); m_PadInZoneOpt = new wxRadioBox( this, wxID_PADS_IN_ZONE_OPTIONS, _("Pad in Zone:"), wxDefaultPosition, wxDefaultSize, m_PadInZoneOptNChoices, m_PadInZoneOptChoices, 1, wxRA_SPECIFY_COLS );
m_PadInZoneOpt->SetSelection( 1 ); m_PadInZoneOpt->SetSelection( 0 );
m_FillOptionsBox->Add( m_PadInZoneOpt, 0, wxALL|wxEXPAND, 5 ); m_FillOptionsBox->Add( m_PadInZoneOpt, 0, wxEXPAND|wxBOTTOM|wxRIGHT|wxLEFT, 5 );
wxStaticBoxSizer* m_ThermalShapesParamsSizer; wxStaticBoxSizer* m_ThermalShapesParamsSizer;
m_ThermalShapesParamsSizer = new wxStaticBoxSizer( new wxStaticBox( this, wxID_ANY, _("Thermal Reliefs Parameters") ), wxVERTICAL ); m_ThermalShapesParamsSizer = new wxStaticBoxSizer( new wxStaticBox( this, wxID_ANY, _("Thermal Reliefs:") ), wxVERTICAL );
m_AntipadSizeText = new wxStaticText( this, wxID_ANY, _("Antipad Size"), wxDefaultPosition, wxDefaultSize, 0 ); m_AntipadSizeText = new wxStaticText( this, wxID_ANY, _("Antipad Size"), wxDefaultPosition, wxDefaultSize, 0 );
m_AntipadSizeText->Wrap( -1 ); m_AntipadSizeText->Wrap( -1 );
m_ThermalShapesParamsSizer->Add( m_AntipadSizeText, 0, wxTOP|wxRIGHT|wxLEFT, 5 ); m_ThermalShapesParamsSizer->Add( m_AntipadSizeText, 0, wxRIGHT|wxLEFT, 5 );
m_AntipadSizeValue = new wxTextCtrl( this, wxID_ANTIPAD_SIZE, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 ); m_AntipadSizeValue = new wxTextCtrl( this, wxID_ANTIPAD_SIZE, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
m_AntipadSizeValue->SetToolTip( _("Define the gap around the pad") ); m_AntipadSizeValue->SetToolTip( _("Define the gap around the pad") );
...@@ -63,7 +73,7 @@ dialog_copper_zone_base::dialog_copper_zone_base( wxWindow* parent, wxWindowID i ...@@ -63,7 +73,7 @@ dialog_copper_zone_base::dialog_copper_zone_base( wxWindow* parent, wxWindowID i
m_CopperBridgeWidthText = new wxStaticText( this, wxID_ANY, _("Copper Width"), wxDefaultPosition, wxDefaultSize, 0 ); m_CopperBridgeWidthText = new wxStaticText( this, wxID_ANY, _("Copper Width"), wxDefaultPosition, wxDefaultSize, 0 );
m_CopperBridgeWidthText->Wrap( -1 ); m_CopperBridgeWidthText->Wrap( -1 );
m_ThermalShapesParamsSizer->Add( m_CopperBridgeWidthText, 0, wxTOP|wxRIGHT|wxLEFT, 5 ); m_ThermalShapesParamsSizer->Add( m_CopperBridgeWidthText, 0, wxRIGHT|wxLEFT, 5 );
m_CopperWidthValue = new wxTextCtrl( this, wxID_COPPER_BRIDGE_VALUE, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 ); m_CopperWidthValue = new wxTextCtrl( this, wxID_COPPER_BRIDGE_VALUE, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
m_CopperWidthValue->SetToolTip( _("Define the tickness of copper in thermal reliefs") ); m_CopperWidthValue->SetToolTip( _("Define the tickness of copper in thermal reliefs") );
...@@ -97,19 +107,11 @@ dialog_copper_zone_base::dialog_copper_zone_base( wxWindow* parent, wxWindowID i ...@@ -97,19 +107,11 @@ dialog_copper_zone_base::dialog_copper_zone_base( wxWindow* parent, wxWindowID i
wxString m_OutlineAppearanceCtrlChoices[] = { _("Line"), _("Hatched outline"), _("Full hatched") }; wxString m_OutlineAppearanceCtrlChoices[] = { _("Line"), _("Hatched outline"), _("Full hatched") };
int m_OutlineAppearanceCtrlNChoices = sizeof( m_OutlineAppearanceCtrlChoices ) / sizeof( wxString ); int m_OutlineAppearanceCtrlNChoices = sizeof( m_OutlineAppearanceCtrlChoices ) / sizeof( wxString );
m_OutlineAppearanceCtrl = new wxRadioBox( this, ID_RADIOBOX_OUTLINES_OPTION, _("Outlines Appearance"), wxDefaultPosition, wxDefaultSize, m_OutlineAppearanceCtrlNChoices, m_OutlineAppearanceCtrlChoices, 1, wxRA_SPECIFY_COLS ); m_OutlineAppearanceCtrl = new wxRadioBox( this, ID_RADIOBOX_OUTLINES_OPTION, _("Outlines Appearance"), wxDefaultPosition, wxDefaultSize, m_OutlineAppearanceCtrlNChoices, m_OutlineAppearanceCtrlChoices, 1, wxRA_SPECIFY_COLS );
m_OutlineAppearanceCtrl->SetSelection( 1 ); m_OutlineAppearanceCtrl->SetSelection( 0 );
m_OutlineAppearanceCtrl->SetToolTip( _("Choose how a zone outline is displayed\n- Single line\n- Short hatching\n- Full zone area hatched") ); m_OutlineAppearanceCtrl->SetToolTip( _("Choose how a zone outline is displayed\n- Single line\n- Short hatching\n- Full zone area hatched") );
m_OutilinesBoxOpt->Add( m_OutlineAppearanceCtrl, 0, wxALL|wxEXPAND, 5 ); m_OutilinesBoxOpt->Add( m_OutlineAppearanceCtrl, 0, wxALL|wxEXPAND, 5 );
wxString m_ArcApproximationOptChoices[] = { _("16 segments / 360 deg"), _("32 segments / 360 deg") };
int m_ArcApproximationOptNChoices = sizeof( m_ArcApproximationOptChoices ) / sizeof( wxString );
m_ArcApproximationOpt = new wxRadioBox( this, wxID_ARC_APPROX, _("Arcs Approximation:"), wxDefaultPosition, wxDefaultSize, m_ArcApproximationOptNChoices, m_ArcApproximationOptChoices, 1, wxRA_SPECIFY_COLS );
m_ArcApproximationOpt->SetSelection( 1 );
m_ArcApproximationOpt->SetToolTip( _("Number of segments to approximate a circle in filling calculations.\n16 segment is faster to calculate and when redraw screen.\n32 segment give a better quality") );
m_OutilinesBoxOpt->Add( m_ArcApproximationOpt, 0, wxALL|wxEXPAND, 5 );
wxStaticBoxSizer* m_OthersOptionsSizer; wxStaticBoxSizer* m_OthersOptionsSizer;
m_OthersOptionsSizer = new wxStaticBoxSizer( new wxStaticBox( this, wxID_ANY, _("Others Options:") ), wxVERTICAL ); m_OthersOptionsSizer = new wxStaticBoxSizer( new wxStaticBox( this, wxID_ANY, _("Others Options:") ), wxVERTICAL );
...@@ -139,11 +141,6 @@ dialog_copper_zone_base::dialog_copper_zone_base( wxWindow* parent, wxWindowID i ...@@ -139,11 +141,6 @@ dialog_copper_zone_base::dialog_copper_zone_base( wxWindow* parent, wxWindowID i
m_MiddleBoxSizer->Add( m_OutilinesBoxOpt, 1, wxEXPAND, 5 ); m_MiddleBoxSizer->Add( m_OutilinesBoxOpt, 1, wxEXPAND, 5 );
m_ExportSetupButton = new wxButton( this, wxID_BUTTON_EXPORT, _("Export to others zones"), wxDefaultPosition, wxDefaultSize, 0 );
m_ExportSetupButton->SetToolTip( _("Export this zone setup to all others copper zones") );
m_MiddleBoxSizer->Add( m_ExportSetupButton, 0, wxALL|wxALIGN_CENTER_HORIZONTAL, 5 );
m_MiddleBox->Add( m_MiddleBoxSizer, 0, 0, 5 ); m_MiddleBox->Add( m_MiddleBoxSizer, 0, 0, 5 );
m_ExportableSetupSizer->Add( m_MiddleBox, 1, wxEXPAND, 5 ); m_ExportableSetupSizer->Add( m_MiddleBox, 1, wxEXPAND, 5 );
...@@ -156,12 +153,17 @@ dialog_copper_zone_base::dialog_copper_zone_base( wxWindow* parent, wxWindowID i ...@@ -156,12 +153,17 @@ dialog_copper_zone_base::dialog_copper_zone_base( wxWindow* parent, wxWindowID i
wxBoxSizer* m_RightBoxSizer; wxBoxSizer* m_RightBoxSizer;
m_RightBoxSizer = new wxBoxSizer( wxVERTICAL ); m_RightBoxSizer = new wxBoxSizer( wxVERTICAL );
m_ExportSetupButton = new wxButton( this, wxID_BUTTON_EXPORT, _("Export Setup to others zones"), wxDefaultPosition, wxDefaultSize, 0 );
m_ExportSetupButton->SetToolTip( _("Export this zone setup to all others copper zones") );
m_RightBoxSizer->Add( m_ExportSetupButton, 0, wxALL|wxALIGN_CENTER_HORIZONTAL|wxEXPAND, 5 );
m_OkButton = new wxButton( this, wxID_OK, _("Ok"), wxDefaultPosition, wxDefaultSize, 0 ); m_OkButton = new wxButton( this, wxID_OK, _("Ok"), wxDefaultPosition, wxDefaultSize, 0 );
m_OkButton->SetDefault(); m_OkButton->SetDefault();
m_RightBoxSizer->Add( m_OkButton, 0, wxALL|wxALIGN_CENTER_HORIZONTAL, 5 ); m_RightBoxSizer->Add( m_OkButton, 0, wxALL|wxALIGN_CENTER_HORIZONTAL|wxEXPAND, 5 );
m_ButtonCancel = new wxButton( this, wxID_CANCEL, _("Cancel"), wxDefaultPosition, wxDefaultSize, 0 ); m_ButtonCancel = new wxButton( this, wxID_CANCEL, _("Cancel"), wxDefaultPosition, wxDefaultSize, 0 );
m_RightBoxSizer->Add( m_ButtonCancel, 0, wxALL|wxALIGN_CENTER_HORIZONTAL, 5 ); m_RightBoxSizer->Add( m_ButtonCancel, 0, wxALL|wxALIGN_CENTER_HORIZONTAL|wxEXPAND, 5 );
m_RightBoxSizer->Add( 5, 20, 0, wxEXPAND, 5 ); m_RightBoxSizer->Add( 5, 20, 0, wxEXPAND, 5 );
...@@ -172,7 +174,7 @@ dialog_copper_zone_base::dialog_copper_zone_base( wxWindow* parent, wxWindowID i ...@@ -172,7 +174,7 @@ dialog_copper_zone_base::dialog_copper_zone_base( wxWindow* parent, wxWindowID i
wxString m_NetSortingOptionChoices[] = { _("Alphabetic"), _("Advanced") }; wxString m_NetSortingOptionChoices[] = { _("Alphabetic"), _("Advanced") };
int m_NetSortingOptionNChoices = sizeof( m_NetSortingOptionChoices ) / sizeof( wxString ); int m_NetSortingOptionNChoices = sizeof( m_NetSortingOptionChoices ) / sizeof( wxString );
m_NetSortingOption = new wxRadioBox( this, ID_NET_SORTING_OPTION, _("Net sorting:"), wxDefaultPosition, wxDefaultSize, m_NetSortingOptionNChoices, m_NetSortingOptionChoices, 1, wxRA_SPECIFY_COLS ); m_NetSortingOption = new wxRadioBox( this, ID_NET_SORTING_OPTION, _("Net sorting:"), wxDefaultPosition, wxDefaultSize, m_NetSortingOptionNChoices, m_NetSortingOptionChoices, 1, wxRA_SPECIFY_COLS );
m_NetSortingOption->SetSelection( 1 ); m_NetSortingOption->SetSelection( 0 );
m_NetSortingOption->SetToolTip( _("Nets can be sorted:\nBy alphabetic order\nBy number of pads in the net (advanced)") ); m_NetSortingOption->SetToolTip( _("Nets can be sorted:\nBy alphabetic order\nBy number of pads in the net (advanced)") );
m_NetSortOptSizer->Add( m_NetSortingOption, 0, wxALL|wxEXPAND, 5 ); m_NetSortOptSizer->Add( m_NetSortingOption, 0, wxALL|wxEXPAND, 5 );
......
...@@ -32,7 +32,7 @@ ...@@ -32,7 +32,7 @@
<property name="minimum_size"></property> <property name="minimum_size"></property>
<property name="name">dialog_copper_zone_base</property> <property name="name">dialog_copper_zone_base</property>
<property name="pos"></property> <property name="pos"></property>
<property name="size">545,493</property> <property name="size">566,582</property>
<property name="style">wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER</property> <property name="style">wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER</property>
<property name="subclass"></property> <property name="subclass"></property>
<property name="title">Fill Zones Options</property> <property name="title">Fill Zones Options</property>
...@@ -119,29 +119,29 @@ ...@@ -119,29 +119,29 @@
<event name="OnUpdateUI"></event> <event name="OnUpdateUI"></event>
<object class="sizeritem" expanded="1"> <object class="sizeritem" expanded="1">
<property name="border">5</property> <property name="border">5</property>
<property name="flag">wxALL|wxEXPAND</property> <property name="flag">wxEXPAND|wxBOTTOM|wxRIGHT|wxLEFT</property>
<property name="proportion">0</property> <property name="proportion">0</property>
<object class="wxRadioBox" expanded="1"> <object class="wxRadioBox" expanded="1">
<property name="bg"></property> <property name="bg"></property>
<property name="choices">&quot;0.00000&quot; &quot;0.00000&quot; &quot;0.00000&quot; &quot;0.00000&quot; &quot;No grid (For tests only!)&quot;</property> <property name="choices">&quot;Use polygons&quot; &quot;Use segments&quot;</property>
<property name="context_help"></property> <property name="context_help"></property>
<property name="enabled">1</property> <property name="enabled">1</property>
<property name="fg"></property> <property name="fg"></property>
<property name="font"></property> <property name="font"></property>
<property name="hidden">0</property> <property name="hidden">0</property>
<property name="id"> ID_RADIOBOX_GRID_SELECTION</property> <property name="id"> ID_RADIOBOX_FILL_MODE_SELECTION</property>
<property name="label">Grid Size for Filling</property> <property name="label">Filling Mode:</property>
<property name="majorDimension">1</property> <property name="majorDimension">1</property>
<property name="maximum_size"></property> <property name="maximum_size"></property>
<property name="minimum_size"></property> <property name="minimum_size"></property>
<property name="name">m_GridCtrl</property> <property name="name">m_FillModeCtrl</property>
<property name="permission">protected</property> <property name="permission">protected</property>
<property name="pos"></property> <property name="pos"></property>
<property name="selection">1</property> <property name="selection">1</property>
<property name="size"></property> <property name="size"></property>
<property name="style">wxRA_SPECIFY_COLS</property> <property name="style">wxRA_SPECIFY_COLS</property>
<property name="subclass"></property> <property name="subclass"></property>
<property name="tooltip"></property> <property name="tooltip">Filled areas can use solid polygons or segments.&#x0A;Depending on the complexity and the size of the zone,&#x0A;sometime polygons are better and sometime segments are better</property>
<property name="window_extra_style"></property> <property name="window_extra_style"></property>
<property name="window_name"></property> <property name="window_name"></property>
<property name="window_style"></property> <property name="window_style"></property>
...@@ -173,7 +173,61 @@ ...@@ -173,7 +173,61 @@
</object> </object>
<object class="sizeritem" expanded="1"> <object class="sizeritem" expanded="1">
<property name="border">5</property> <property name="border">5</property>
<property name="flag">wxALL|wxEXPAND</property> <property name="flag">wxEXPAND|wxBOTTOM|wxRIGHT|wxLEFT</property>
<property name="proportion">0</property>
<object class="wxRadioBox" expanded="1">
<property name="bg"></property>
<property name="choices">&quot;16 segments / 360 deg&quot; &quot;32 segments / 360 deg&quot;</property>
<property name="context_help"></property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="font"></property>
<property name="hidden">0</property>
<property name="id">wxID_ARC_APPROX</property>
<property name="label">Arcs Approximation:</property>
<property name="majorDimension">1</property>
<property name="maximum_size"></property>
<property name="minimum_size"></property>
<property name="name">m_ArcApproximationOpt</property>
<property name="permission">protected</property>
<property name="pos"></property>
<property name="selection">1</property>
<property name="size"></property>
<property name="style">wxRA_SPECIFY_COLS</property>
<property name="subclass"></property>
<property name="tooltip">Number of segments to approximate a circle in filling calculations.&#x0A;16 segment is faster to calculate and when redraw screen.&#x0A;32 segment give a better quality</property>
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style"></property>
<event name="OnChar"></event>
<event name="OnEnterWindow"></event>
<event name="OnEraseBackground"></event>
<event name="OnKeyDown"></event>
<event name="OnKeyUp"></event>
<event name="OnKillFocus"></event>
<event name="OnLeaveWindow"></event>
<event name="OnLeftDClick"></event>
<event name="OnLeftDown"></event>
<event name="OnLeftUp"></event>
<event name="OnMiddleDClick"></event>
<event name="OnMiddleDown"></event>
<event name="OnMiddleUp"></event>
<event name="OnMotion"></event>
<event name="OnMouseEvents"></event>
<event name="OnMouseWheel"></event>
<event name="OnPaint"></event>
<event name="OnRadioBox"></event>
<event name="OnRightDClick"></event>
<event name="OnRightDown"></event>
<event name="OnRightUp"></event>
<event name="OnSetFocus"></event>
<event name="OnSize"></event>
<event name="OnUpdateUI"></event>
</object>
</object>
<object class="sizeritem" expanded="1">
<property name="border">5</property>
<property name="flag">wxEXPAND|wxBOTTOM|wxRIGHT|wxLEFT</property>
<property name="proportion">0</property> <property name="proportion">0</property>
<object class="wxRadioBox" expanded="1"> <object class="wxRadioBox" expanded="1">
<property name="bg"></property> <property name="bg"></property>
...@@ -191,7 +245,7 @@ ...@@ -191,7 +245,7 @@
<property name="name">m_PadInZoneOpt</property> <property name="name">m_PadInZoneOpt</property>
<property name="permission">protected</property> <property name="permission">protected</property>
<property name="pos"></property> <property name="pos"></property>
<property name="selection">1</property> <property name="selection">0</property>
<property name="size"></property> <property name="size"></property>
<property name="style">wxRA_SPECIFY_COLS</property> <property name="style">wxRA_SPECIFY_COLS</property>
<property name="subclass"></property> <property name="subclass"></property>
...@@ -231,7 +285,7 @@ ...@@ -231,7 +285,7 @@
<property name="proportion">0</property> <property name="proportion">0</property>
<object class="wxStaticBoxSizer" expanded="1"> <object class="wxStaticBoxSizer" expanded="1">
<property name="id">wxID_ANY</property> <property name="id">wxID_ANY</property>
<property name="label">Thermal Reliefs Parameters</property> <property name="label">Thermal Reliefs:</property>
<property name="minimum_size"></property> <property name="minimum_size"></property>
<property name="name">m_ThermalShapesParamsSizer</property> <property name="name">m_ThermalShapesParamsSizer</property>
<property name="orient">wxVERTICAL</property> <property name="orient">wxVERTICAL</property>
...@@ -239,7 +293,7 @@ ...@@ -239,7 +293,7 @@
<event name="OnUpdateUI"></event> <event name="OnUpdateUI"></event>
<object class="sizeritem" expanded="1"> <object class="sizeritem" expanded="1">
<property name="border">5</property> <property name="border">5</property>
<property name="flag">wxTOP|wxRIGHT|wxLEFT</property> <property name="flag">wxRIGHT|wxLEFT</property>
<property name="proportion">0</property> <property name="proportion">0</property>
<object class="wxStaticText" expanded="1"> <object class="wxStaticText" expanded="1">
<property name="bg"></property> <property name="bg"></property>
...@@ -345,7 +399,7 @@ ...@@ -345,7 +399,7 @@
</object> </object>
<object class="sizeritem" expanded="1"> <object class="sizeritem" expanded="1">
<property name="border">5</property> <property name="border">5</property>
<property name="flag">wxTOP|wxRIGHT|wxLEFT</property> <property name="flag">wxRIGHT|wxLEFT</property>
<property name="proportion">0</property> <property name="proportion">0</property>
<object class="wxStaticText" expanded="1"> <object class="wxStaticText" expanded="1">
<property name="bg"></property> <property name="bg"></property>
...@@ -569,7 +623,7 @@ ...@@ -569,7 +623,7 @@
<property name="name">m_OutlineAppearanceCtrl</property> <property name="name">m_OutlineAppearanceCtrl</property>
<property name="permission">protected</property> <property name="permission">protected</property>
<property name="pos"></property> <property name="pos"></property>
<property name="selection">1</property> <property name="selection">0</property>
<property name="size"></property> <property name="size"></property>
<property name="style">wxRA_SPECIFY_COLS</property> <property name="style">wxRA_SPECIFY_COLS</property>
<property name="subclass"></property> <property name="subclass"></property>
...@@ -603,60 +657,6 @@ ...@@ -603,60 +657,6 @@
<event name="OnUpdateUI"></event> <event name="OnUpdateUI"></event>
</object> </object>
</object> </object>
<object class="sizeritem" expanded="1">
<property name="border">5</property>
<property name="flag">wxALL|wxEXPAND</property>
<property name="proportion">0</property>
<object class="wxRadioBox" expanded="1">
<property name="bg"></property>
<property name="choices">&quot;16 segments / 360 deg&quot; &quot;32 segments / 360 deg&quot;</property>
<property name="context_help"></property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="font"></property>
<property name="hidden">0</property>
<property name="id">wxID_ARC_APPROX</property>
<property name="label">Arcs Approximation:</property>
<property name="majorDimension">1</property>
<property name="maximum_size"></property>
<property name="minimum_size"></property>
<property name="name">m_ArcApproximationOpt</property>
<property name="permission">protected</property>
<property name="pos"></property>
<property name="selection">1</property>
<property name="size"></property>
<property name="style">wxRA_SPECIFY_COLS</property>
<property name="subclass"></property>
<property name="tooltip">Number of segments to approximate a circle in filling calculations.&#x0A;16 segment is faster to calculate and when redraw screen.&#x0A;32 segment give a better quality</property>
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style"></property>
<event name="OnChar"></event>
<event name="OnEnterWindow"></event>
<event name="OnEraseBackground"></event>
<event name="OnKeyDown"></event>
<event name="OnKeyUp"></event>
<event name="OnKillFocus"></event>
<event name="OnLeaveWindow"></event>
<event name="OnLeftDClick"></event>
<event name="OnLeftDown"></event>
<event name="OnLeftUp"></event>
<event name="OnMiddleDClick"></event>
<event name="OnMiddleDown"></event>
<event name="OnMiddleUp"></event>
<event name="OnMotion"></event>
<event name="OnMouseEvents"></event>
<event name="OnMouseWheel"></event>
<event name="OnPaint"></event>
<event name="OnRadioBox"></event>
<event name="OnRightDClick"></event>
<event name="OnRightDown"></event>
<event name="OnRightUp"></event>
<event name="OnSetFocus"></event>
<event name="OnSize"></event>
<event name="OnUpdateUI"></event>
</object>
</object>
<object class="sizeritem" expanded="1"> <object class="sizeritem" expanded="1">
<property name="border">5</property> <property name="border">5</property>
<property name="flag">wxEXPAND</property> <property name="flag">wxEXPAND</property>
...@@ -937,9 +937,34 @@ ...@@ -937,9 +937,34 @@
</object> </object>
</object> </object>
</object> </object>
</object>
</object>
</object>
</object>
</object>
</object>
<object class="sizeritem" expanded="1"> <object class="sizeritem" expanded="1">
<property name="border">5</property> <property name="border">5</property>
<property name="flag">wxALL|wxALIGN_CENTER_HORIZONTAL</property> <property name="flag">wxEXPAND</property>
<property name="proportion">0</property>
<object class="spacer" expanded="1">
<property name="height">0</property>
<property name="permission">protected</property>
<property name="width">0</property>
</object>
</object>
<object class="sizeritem" expanded="1">
<property name="border">5</property>
<property name="flag">wxALIGN_CENTER_VERTICAL</property>
<property name="proportion">0</property>
<object class="wxBoxSizer" expanded="1">
<property name="minimum_size"></property>
<property name="name">m_RightBoxSizer</property>
<property name="orient">wxVERTICAL</property>
<property name="permission">none</property>
<object class="sizeritem" expanded="1">
<property name="border">5</property>
<property name="flag">wxALL|wxALIGN_CENTER_HORIZONTAL|wxEXPAND</property>
<property name="proportion">0</property> <property name="proportion">0</property>
<object class="wxButton" expanded="1"> <object class="wxButton" expanded="1">
<property name="bg"></property> <property name="bg"></property>
...@@ -950,7 +975,7 @@ ...@@ -950,7 +975,7 @@
<property name="font"></property> <property name="font"></property>
<property name="hidden">0</property> <property name="hidden">0</property>
<property name="id">wxID_BUTTON_EXPORT</property> <property name="id">wxID_BUTTON_EXPORT</property>
<property name="label">Export to others zones</property> <property name="label">Export Setup to others zones</property>
<property name="maximum_size"></property> <property name="maximum_size"></property>
<property name="minimum_size"></property> <property name="minimum_size"></property>
<property name="name">m_ExportSetupButton</property> <property name="name">m_ExportSetupButton</property>
...@@ -989,34 +1014,9 @@ ...@@ -989,34 +1014,9 @@
<event name="OnUpdateUI"></event> <event name="OnUpdateUI"></event>
</object> </object>
</object> </object>
</object>
</object>
</object>
</object>
</object>
</object>
<object class="sizeritem" expanded="1"> <object class="sizeritem" expanded="1">
<property name="border">5</property> <property name="border">5</property>
<property name="flag">wxEXPAND</property> <property name="flag">wxALL|wxALIGN_CENTER_HORIZONTAL|wxEXPAND</property>
<property name="proportion">0</property>
<object class="spacer" expanded="1">
<property name="height">0</property>
<property name="permission">protected</property>
<property name="width">0</property>
</object>
</object>
<object class="sizeritem" expanded="1">
<property name="border">5</property>
<property name="flag">wxALIGN_CENTER_VERTICAL</property>
<property name="proportion">0</property>
<object class="wxBoxSizer" expanded="1">
<property name="minimum_size"></property>
<property name="name">m_RightBoxSizer</property>
<property name="orient">wxVERTICAL</property>
<property name="permission">none</property>
<object class="sizeritem" expanded="1">
<property name="border">5</property>
<property name="flag">wxALL|wxALIGN_CENTER_HORIZONTAL</property>
<property name="proportion">0</property> <property name="proportion">0</property>
<object class="wxButton" expanded="1"> <object class="wxButton" expanded="1">
<property name="bg"></property> <property name="bg"></property>
...@@ -1068,7 +1068,7 @@ ...@@ -1068,7 +1068,7 @@
</object> </object>
<object class="sizeritem" expanded="1"> <object class="sizeritem" expanded="1">
<property name="border">5</property> <property name="border">5</property>
<property name="flag">wxALL|wxALIGN_CENTER_HORIZONTAL</property> <property name="flag">wxALL|wxALIGN_CENTER_HORIZONTAL|wxEXPAND</property>
<property name="proportion">0</property> <property name="proportion">0</property>
<object class="wxButton" expanded="1"> <object class="wxButton" expanded="1">
<property name="bg"></property> <property name="bg"></property>
...@@ -1160,7 +1160,7 @@ ...@@ -1160,7 +1160,7 @@
<property name="name">m_NetSortingOption</property> <property name="name">m_NetSortingOption</property>
<property name="permission">protected</property> <property name="permission">protected</property>
<property name="pos"></property> <property name="pos"></property>
<property name="selection">1</property> <property name="selection">0</property>
<property name="size"></property> <property name="size"></property>
<property name="style">wxRA_SPECIFY_COLS</property> <property name="style">wxRA_SPECIFY_COLS</property>
<property name="subclass"></property> <property name="subclass"></property>
......
...@@ -47,12 +47,12 @@ class dialog_copper_zone_base : public wxDialog ...@@ -47,12 +47,12 @@ class dialog_copper_zone_base : public wxDialog
protected: protected:
enum enum
{ {
ID_RADIOBOX_GRID_SELECTION = 1000, ID_RADIOBOX_FILL_MODE_SELECTION = 1000,
wxID_ARC_APPROX,
wxID_PADS_IN_ZONE_OPTIONS, wxID_PADS_IN_ZONE_OPTIONS,
wxID_ANTIPAD_SIZE, wxID_ANTIPAD_SIZE,
wxID_COPPER_BRIDGE_VALUE, wxID_COPPER_BRIDGE_VALUE,
ID_RADIOBOX_OUTLINES_OPTION, ID_RADIOBOX_OUTLINES_OPTION,
wxID_ARC_APPROX,
wxID_BUTTON_EXPORT, wxID_BUTTON_EXPORT,
ID_NET_SORTING_OPTION, ID_NET_SORTING_OPTION,
ID_TEXTCTRL_NETNAMES_FILTER, ID_TEXTCTRL_NETNAMES_FILTER,
...@@ -60,7 +60,8 @@ class dialog_copper_zone_base : public wxDialog ...@@ -60,7 +60,8 @@ class dialog_copper_zone_base : public wxDialog
ID_LAYER_CHOICE, ID_LAYER_CHOICE,
}; };
wxRadioBox* m_GridCtrl; wxRadioBox* m_FillModeCtrl;
wxRadioBox* m_ArcApproximationOpt;
wxRadioBox* m_PadInZoneOpt; wxRadioBox* m_PadInZoneOpt;
wxStaticText* m_AntipadSizeText; wxStaticText* m_AntipadSizeText;
wxTextCtrl* m_AntipadSizeValue; wxTextCtrl* m_AntipadSizeValue;
...@@ -69,14 +70,13 @@ class dialog_copper_zone_base : public wxDialog ...@@ -69,14 +70,13 @@ class dialog_copper_zone_base : public wxDialog
wxRadioBox* m_OrientEdgesOpt; wxRadioBox* m_OrientEdgesOpt;
wxRadioBox* m_OutlineAppearanceCtrl; wxRadioBox* m_OutlineAppearanceCtrl;
wxRadioBox* m_ArcApproximationOpt;
wxCheckBox* m_ShowFilledAreasInSketchOpt; wxCheckBox* m_ShowFilledAreasInSketchOpt;
wxStaticText* m_ClearanceValueTitle; wxStaticText* m_ClearanceValueTitle;
wxTextCtrl* m_ZoneClearanceCtrl; wxTextCtrl* m_ZoneClearanceCtrl;
wxStaticText* m_MinThicknessValueTitle; wxStaticText* m_MinThicknessValueTitle;
wxTextCtrl* m_ZoneMinThicknessCtrl; wxTextCtrl* m_ZoneMinThicknessCtrl;
wxButton* m_ExportSetupButton;
wxButton* m_ExportSetupButton;
wxButton* m_OkButton; wxButton* m_OkButton;
wxButton* m_ButtonCancel; wxButton* m_ButtonCancel;
...@@ -98,7 +98,7 @@ class dialog_copper_zone_base : public wxDialog ...@@ -98,7 +98,7 @@ class dialog_copper_zone_base : public wxDialog
public: public:
dialog_copper_zone_base( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("Fill Zones Options"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( 545,493 ), long style = wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER ); dialog_copper_zone_base( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("Fill Zones Options"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( 566,582 ), long style = wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER );
~dialog_copper_zone_base(); ~dialog_copper_zone_base();
}; };
......
...@@ -748,6 +748,7 @@ void PlotFilledAreas( ZONE_CONTAINER * aZone, int aFormat ) ...@@ -748,6 +748,7 @@ void PlotFilledAreas( ZONE_CONTAINER * aZone, int aFormat )
corners_count++; corners_count++;
if( corner->end_contour ) if( corner->end_contour )
{ // Plot the current filled area { // Plot the current filled area
if( aZone->m_FillMode == 0) // We are using solid polygons (if != 0: using segments in m_Zone)
PlotFilledPolygon( aFormat, corners_count, CornersBuffer ); PlotFilledPolygon( aFormat, corners_count, CornersBuffer );
if ( aZone->m_ZoneMinThickness > 0 ) if ( aZone->m_ZoneMinThickness > 0 )
PlotPolygon( aFormat, corners_count, CornersBuffer, aZone->m_ZoneMinThickness ); PlotPolygon( aFormat, corners_count, CornersBuffer, aZone->m_ZoneMinThickness );
......
...@@ -2,6 +2,9 @@ ...@@ -2,6 +2,9 @@
* Algos used to fill a zone defined by a polygon and a filling starting point * Algos used to fill a zone defined by a polygon and a filling starting point
*/ */
#include <algorithm> // sort
#include "fctsys.h" #include "fctsys.h"
#include "gr_basic.h" #include "gr_basic.h"
...@@ -15,18 +18,14 @@ ...@@ -15,18 +18,14 @@
#include "protos.h" #include "protos.h"
/* Local functions */ /* Local functions */
static void Genere_Segments_Zone( WinEDA_PcbFrame* frame, wxDC* DC, int net_code, int layer );
/* Local variables */ /* Local variables */
static bool Zone_Debug = false;
static unsigned long s_TimeStamp; /* Time stamp common to all segments relative to the new created zone */
/***********************************************************/ /***********************************************************/
int ZONE_CONTAINER::BuildFilledPolysListData( BOARD * aPcb ) int ZONE_CONTAINER::BuildFilledPolysListData( BOARD* aPcb )
/***********************************************************/ /***********************************************************/
/** function BuildFilledPolysListData /** function BuildFilledPolysListData
* Build m_FilledPolysList data from real outlines (m_Poly) * Build m_FilledPolysList data from real outlines (m_Poly)
* in order to have drawable (and plottable) filled polygons * in order to have drawable (and plottable) filled polygons
...@@ -37,488 +36,188 @@ int ZONE_CONTAINER::BuildFilledPolysListData( BOARD * aPcb ) ...@@ -37,488 +36,188 @@ int ZONE_CONTAINER::BuildFilledPolysListData( BOARD * aPcb )
* AddClearanceAreasPolygonsToPolysList() to do that for copper layers * AddClearanceAreasPolygonsToPolysList() to do that for copper layers
*/ */
{ {
// Currently, for copper zones, we can use segment filling or filling by polygon areas
// if m_GridFillValue == 0 polygon areas will be used (No Grid)
if ( IsOnCopperLayer() && ( m_GridFillValue != 0 ) )
return 0;
m_FilledPolysList.clear(); m_FilledPolysList.clear();
/* convert outlines + holes to outlines without holes (adding extra segments if necessary) /* convert outlines + holes to outlines without holes (adding extra segments if necessary)
* m_Poly data is expected normalized, i.e. NormalizeAreaOutlines was used after building this zone * m_Poly data is expected normalized, i.e. NormalizeAreaOutlines was used after building this zone
*/ */
if ( GetNumCorners( ) <= 2 ) // malformed zone. Kbool does not like it ... if( GetNumCorners() <= 2 ) // malformed zone. Kbool does not like it ...
return 0; return 0;
m_Poly->MakeKboolPoly( -1, -1, NULL, true ); m_Poly->MakeKboolPoly( -1, -1, NULL, true );
int count = 0; int count = 0;
while( m_Poly->GetKboolEngine()->StartPolygonGet() ) while( m_Poly->GetKboolEngine()->StartPolygonGet() )
{ {
CPolyPt corner(0,0,false); CPolyPt corner( 0, 0, false );
while( m_Poly->GetKboolEngine()->PolygonHasMorePoints() ) while( m_Poly->GetKboolEngine()->PolygonHasMorePoints() )
{ {
corner.x = (int)m_Poly->GetKboolEngine()->GetPolygonXPoint(); corner.x = (int) m_Poly->GetKboolEngine()->GetPolygonXPoint();
corner.y = (int)m_Poly->GetKboolEngine()->GetPolygonYPoint(); corner.y = (int) m_Poly->GetKboolEngine()->GetPolygonYPoint();
corner.end_contour = false; corner.end_contour = false;
m_FilledPolysList.push_back(corner); m_FilledPolysList.push_back( corner );
count ++; count++;
} }
corner.end_contour = true; corner.end_contour = true;
m_FilledPolysList.pop_back(); m_FilledPolysList.pop_back();
m_FilledPolysList.push_back(corner); m_FilledPolysList.push_back( corner );
m_Poly->GetKboolEngine()->EndPolygonGet(); m_Poly->GetKboolEngine()->EndPolygonGet();
} }
m_Poly->FreeKboolEngine(); m_Poly->FreeKboolEngine();
/* For copper layers, we now must add holes in the Polygon list. /* For copper layers, we now must add holes in the Polygon list.
holes are pads and tracks with their clearance area * holes are pads and tracks with their clearance area
*/ */
if ( IsOnCopperLayer() ) if( IsOnCopperLayer() )
AddClearanceAreasPolygonsToPolysList( aPcb ); AddClearanceAreasPolygonsToPolysList( aPcb );
if ( m_FillMode ) // if fill mode uses segments, create them:
Fill_Zone_Areas_With_Segments( (WinEDA_PcbFrame*) aPcb->m_PcbFrame );
return count; return count;
} }
// Sort function to build filled zones
static bool SortByXValues( const int& a, const int &b)
{
return a < b;
}
/*****************************************************************************/ /***********************************************************************************/
int ZONE_CONTAINER::Fill_Zone( WinEDA_PcbFrame* frame, wxDC* DC, bool verbose ) int ZONE_CONTAINER::Fill_Zone_Areas_With_Segments( WinEDA_PcbFrame* aFrame )
/*****************************************************************************/ /***********************************************************************************/
/** Function Fill_Zone() /** Function Fill_Zone_Areas_With_Segments()
* Calculate the zone filling * Fill sub areas in a zone with segments with m_ZoneMinThickness width
* The zone outline is a frontier, and can be complex (with holes) * A scan is made line per line, on the whole filled areas, with a step of m_ZoneMinThickness.
* The filling starts from starting points like pads, tracks. * all intersecting points with the horizontal infinite line and polygons to fill are calculated
* @param frame = reference to the main frame * a list of SEGZONE items is built, line per line
* @param DC = current Device Context (can be NULL) * @param aFrame = reference to the main frame
* @param verbose = true to show error messages * @return number of segments created
* @return error level (0 = no error)
*/ */
{ {
int ii, jj; int ics, ice;
int error_level = 0; int count = 0;
int lp_tmp, lay_tmp_TOP, lay_tmp_BOTTOM; std::vector <int> x_coordinates;
int save_isol = g_DesignSettings.m_TrackClearence; bool error = false;
wxPoint ZoneStartFill;
wxString msg;
BOARD* Pcb = frame->m_Pcb;
if( g_GridRoutingSize < 25 )
g_GridRoutingSize = 25;
// Set the g_DesignSettings.m_TrackClearence (used to fill board map) to the max of m_TrackClearence and m_ZoneClearence
g_DesignSettings.m_TrackClearence = max ( g_DesignSettings.m_TrackClearence, m_ZoneClearance);
// In order to avoid ends of segments used to fill the zone, and to the clearence the radius of ends
// which is g_GridRoutingSize/2
g_DesignSettings.m_TrackClearence += g_GridRoutingSize/2;
g_HightLigth_NetCode = m_NetCode;
s_TimeStamp = m_TimeStamp;
// Delete the old filling, if any :
frame->Delete_Zone_Fill( DC, NULL, m_TimeStamp );
// calculate the fixed step of the routing matrix as 25 mils or more
E_scale = g_GridRoutingSize / 25;
// calculate the Ncols and Nrows, size of the routing matrix
ComputeMatriceSize( frame, g_GridRoutingSize );
// create the routing matrix in autorout.h's eda_global BOARDHEAD Board
Nb_Sides = ONE_SIDE;
if( Board.InitBoard() < 0 )
{
if( verbose )
DisplayError( frame, wxT( "Mo memory for creating zones" ) );
error_level = 1;
return error_level;
}
msg.Printf( wxT( "%d" ), Ncols );
Affiche_1_Parametre( frame, 1, wxT( "Cols" ), msg, GREEN );
msg.Printf( wxT( "%d" ), Nrows );
Affiche_1_Parametre( frame, 7, wxT( "Lines" ), msg, GREEN );
msg.Printf( wxT( "%d" ), Board.m_MemSize / 1024 );
Affiche_1_Parametre( frame, 14, wxT( "Mem(Ko)" ), msg, CYAN );
lay_tmp_BOTTOM = Route_Layer_BOTTOM;
lay_tmp_TOP = Route_Layer_TOP;
Route_Layer_BOTTOM = Route_Layer_TOP = m_Layer;
lp_tmp = g_DesignSettings.m_CurrentTrackWidth;
g_DesignSettings.m_CurrentTrackWidth = g_GridRoutingSize;
// trace the pcb edges (pcb contour) into the routing matrix
Route_Layer_BOTTOM = Route_Layer_TOP = EDGE_N;
PlaceCells( Pcb, -1, 0 );
Route_Layer_BOTTOM = Route_Layer_TOP = m_Layer;
/* Create the starting point for the zone:
* The starting point and all the tracks are suitable "starting points" */
TRACK* pt_segm = Pcb->m_Track;
for( ; pt_segm != NULL; pt_segm = pt_segm->Next() )
{
if( g_HightLigth_NetCode != pt_segm->GetNet() )
continue;
if( ! pt_segm->IsOnLayer( m_Layer ) )
continue;
// if( pt_segm->Type() != TYPETRACK )
// continue;
TraceSegmentPcb( Pcb, pt_segm, CELL_is_FRIEND, 0, WRITE_CELL );
}
// trace the zone edges into the routing matrix
int i_start_contour = 0;
for( unsigned ic = 0; ic < m_Poly->corner.size(); ic++ )
{
int xi = m_Poly->corner[ic].x - Pcb->m_BoundaryBox.m_Pos.x;
int yi = m_Poly->corner[ic].y - Pcb->m_BoundaryBox.m_Pos.y;
int xf, yf;
if( m_Poly->corner[ic].end_contour == FALSE && ic < m_Poly->corner.size() - 1 )
{
xf = m_Poly->corner[ic + 1].x - Pcb->m_BoundaryBox.m_Pos.x;
yf = m_Poly->corner[ic + 1].y - Pcb->m_BoundaryBox.m_Pos.y;
}
else
{
xf = m_Poly->corner[i_start_contour].x - Pcb->m_BoundaryBox.m_Pos.x;
yf = m_Poly->corner[i_start_contour].y - Pcb->m_BoundaryBox.m_Pos.y;
i_start_contour = ic + 1;
}
TraceLignePcb( xi, yi, xf, yf, -1, HOLE | CELL_is_EDGE, WRITE_CELL );
}
/* Create a starting point to create the zone filling, from pads */
LISTE_PAD* pad;
int cells_count = 0;
for( ii = 0, pad = frame->m_Pcb->m_Pads; ii < frame->m_Pcb->m_NbPads; ii++, pad++ )
{
if ( ! (*pad)->IsOnLayer( GetLayer() ) ) continue;
if ( (*pad)->GetNet() != GetNet() ) continue;
wxPoint pos = (*pad)->m_Pos;
if( m_Poly->TestPointInside( pos.x, pos.y ) )
{
pos -= Pcb->m_BoundaryBox.m_Pos;
ZoneStartFill.x = pos.x / g_GridRoutingSize;
ZoneStartFill.y = pos.y / g_GridRoutingSize;
BoardCell cell = GetCell( ZoneStartFill.y, ZoneStartFill.x, BOTTOM );
if ( (cell & CELL_is_EDGE) == 0 )
{
OrCell( ZoneStartFill.y, ZoneStartFill.x, BOTTOM, CELL_is_ZONE );
cells_count++;
}
}
}
/* Create a starting point to create the zone filling, from vias and tracks */
TRACK* track;
for( track = frame->m_Pcb->m_Track; track != NULL; track = track->Next() )
{
if ( ! track->IsOnLayer( GetLayer() ) ) continue;
if ( track->GetNet() != GetNet() ) continue;
wxPoint pos = track->m_Start;
if( m_Poly->TestPointInside( pos.x, pos.y ) )
{
pos -= Pcb->m_BoundaryBox.m_Pos;
ZoneStartFill.x = pos.x / g_GridRoutingSize;
ZoneStartFill.y = pos.y / g_GridRoutingSize;
BoardCell cell = GetCell( ZoneStartFill.y, ZoneStartFill.x, BOTTOM );
if ( (cell & CELL_is_EDGE) == 0 )
{
OrCell( ZoneStartFill.y, ZoneStartFill.x, BOTTOM, CELL_is_ZONE );
cells_count++;
}
}
pos = track->m_End;
if( m_Poly->TestPointInside( pos.x, pos.y ) )
{
pos -= Pcb->m_BoundaryBox.m_Pos;
ZoneStartFill.x = pos.x / g_GridRoutingSize;
ZoneStartFill.y = pos.y / g_GridRoutingSize;
BoardCell cell = GetCell( ZoneStartFill.y, ZoneStartFill.x, BOTTOM );
if ( (cell & CELL_is_EDGE) == 0 )
{
OrCell( ZoneStartFill.y, ZoneStartFill.x, BOTTOM, CELL_is_ZONE );
cells_count++;
}
}
}
if( cells_count == 0 )
{
if( verbose )
{
msg = _( "No pads or starting point found to fill this zone outline" );
msg << wxT("\n");
msg << MenuText( frame->m_Pcb );
DisplayError( frame, msg );
}
error_level = 2;
goto end_of_zone_fill;
}
// mark the cells forming part of the zone
ii = 1; jj = 1;
while( ii )
{
msg.Printf( wxT( "%d" ), jj++ );
Affiche_1_Parametre( frame, 50, wxT( "Iter." ), msg, CYAN );
ii = Propagation( frame );
}
// selection of the suitable cells for the points of anchoring of the zone int istart, iend; // index od the starting and the endif corner of one filled area in m_FilledPolysList
for( ii = 0; ii < Nrows; ii++ )
{
for( jj = 0; jj < Ncols; jj++ )
{
long cell = GetCell( ii, jj, BOTTOM );
if( (cell & CELL_is_ZONE) )
{
if( (cell & CELL_is_FRIEND) == 0 )
AndCell( ii, jj, BOTTOM, (BoardCell) ~(CELL_is_FRIEND | CELL_is_ZONE) );
}
}
}
if( Zone_Debug && DC ) int margin = m_ZoneMinThickness * 2 / 10;
{ margin = max (2, margin);
DisplayBoard( frame->DrawPanel, DC ); int step = m_ZoneMinThickness - margin;
} step = max(step, 2);
// now, all the cell candidates are marked
// place all the obstacles into the matrix, such as (pads, tracks, vias,
// pcb edges or segments)
ii = 0;
if( m_PadOption == PAD_NOT_IN_ZONE )
ii = FORCE_PADS;
Affiche_1_Parametre( frame, 42, wxT( "GenZone" ), wxEmptyString, RED );
PlaceCells( Pcb, g_HightLigth_NetCode, ii );
Affiche_1_Parametre( frame, -1, wxEmptyString, _( "Ok" ), RED );
/* Recreate zone limits on the routing matrix
* (could be deleted by PlaceCells()) : */
i_start_contour = 0;
for( unsigned ic = 0; ic < m_Poly->corner.size(); ic++ )
{
int xi = m_Poly->corner[ic].x - Pcb->m_BoundaryBox.m_Pos.x;
int yi = m_Poly->corner[ic].y - Pcb->m_BoundaryBox.m_Pos.y;
int xf, yf;
if( m_Poly->corner[ic].end_contour == FALSE && ic < m_Poly->corner.size() - 1 )
{
xf = m_Poly->corner[ic + 1].x - Pcb->m_BoundaryBox.m_Pos.x;
yf = m_Poly->corner[ic + 1].y - Pcb->m_BoundaryBox.m_Pos.y;
}
else
{
xf = m_Poly->corner[i_start_contour].x - Pcb->m_BoundaryBox.m_Pos.x;
yf = m_Poly->corner[i_start_contour].y - Pcb->m_BoundaryBox.m_Pos.y;
i_start_contour = ic + 1;
}
TraceLignePcb( xi, yi, xf, yf, -1, HOLE | CELL_is_EDGE, WRITE_CELL );
}
/* Init the starting point for zone filling : this is the mouse position // Read all filled areas in m_FilledPolysList
* (could be deleted by PlaceCells()) : */ istart = 0;
for( ii = 0, pad = frame->m_Pcb->m_Pads; ii < frame->m_Pcb->m_NbPads; ii++, pad++ ) int end_list = m_FilledPolysList.size()-1;
for( int ic = 0; ic <= end_list; ic++ )
{ {
if ( ! (*pad)->IsOnLayer( GetLayer() ) ) continue; CPolyPt* corner = &m_FilledPolysList[ic];
if ( (*pad)->GetNet() != GetNet() ) continue; if ( corner->end_contour || (ic == end_list) )
wxPoint pos = (*pad)->m_Pos;
if( m_Poly->TestPointInside( pos.x, pos.y ) )
{ {
pos -= Pcb->m_BoundaryBox.m_Pos; iend = ic;
ZoneStartFill.x = pos.x / g_GridRoutingSize; EDA_Rect rect = CalculateSubAreaBoundaryBox( istart, iend );
ZoneStartFill.y = pos.y / g_GridRoutingSize;
BoardCell cell = GetCell( ZoneStartFill.y, ZoneStartFill.x, BOTTOM );
if ( (cell & CELL_is_EDGE) == 0 )
OrCell( ZoneStartFill.y, ZoneStartFill.x, BOTTOM, CELL_is_ZONE );
}
}
// Calculate the y limits of the zone
int refy = rect.GetY();
int endy = rect.GetBottom();
/* Filling the cells of the matrix (this is the zone building)*/ for( ; refy < endy; refy += step )
ii = 1; jj = 1;
while( ii )
{ {
msg.Printf( wxT( "%d" ), jj++ ); // find all intersection points of an infinite line with polyline sides
Affiche_1_Parametre( frame, 50, wxT( "Iter." ), msg, CYAN ); x_coordinates.clear();
ii = Propagation( frame ); for( ics = istart, ice = iend; ics <= iend; ice = ics, ics++ )
}
if( Zone_Debug && DC )
{ {
DisplayBoard( frame->DrawPanel, DC ); if ( m_FilledPolysList[ice].utility )
} continue;
int seg_startX = m_FilledPolysList[ics].x;
// replace obstacles into the matrix(pads) int seg_startY = m_FilledPolysList[ics].y;
if( m_PadOption == THERMAL_PAD ) int seg_endX = m_FilledPolysList[ice].x;
PlaceCells( Pcb, g_HightLigth_NetCode, FORCE_PADS ); int seg_endY = m_FilledPolysList[ice].y;
if( Zone_Debug && DC )
DisplayBoard( frame->DrawPanel, DC );
/* Convert the matrix information (cells) to segments which are actually the zone */
if( g_HightLigth_NetCode < 0 )
Genere_Segments_Zone( frame, DC, 0, m_Layer );
else
Genere_Segments_Zone( frame, DC, g_HightLigth_NetCode, m_Layer );
/* Create the thermal reliefs */
g_DesignSettings.m_CurrentTrackWidth = lp_tmp;
if( m_PadOption == THERMAL_PAD )
frame->Genere_Pad_Connexion( DC, m_Layer );
end_of_zone_fill:
g_DesignSettings.m_TrackClearence = save_isol;
// free the memory
Board.UnInitBoard();
// restore original values unchanged
Route_Layer_TOP = lay_tmp_TOP;
Route_Layer_BOTTOM = lay_tmp_BOTTOM;
return error_level;
}
/* Trivial cases: skip if ref above or below the segment to test */
if( ( seg_startY > refy ) && (seg_endY > refy ) )
continue;
/*******************************************************************************************/ // segment below ref point, or its Y end pos on Y coordinate ref point: skip
static void Genere_Segments_Zone( WinEDA_PcbFrame* frame, wxDC* DC, int net_code, int layer ) if( ( seg_startY <= refy ) && (seg_endY <= refy ) )
/*******************************************************************************************/ continue;
/** Function Genere_Segments_Zone() /* at this point refy is between seg_startY and seg_endY
* Create the zone segments from the routing matrix structure * see if an horizontal line at Y = refy is intersecting this segment
* Algorithm:
* Search for consecutive cells (flagged "zone") , and create segments
* from the first cell to the last cell in the matrix
* 2 searchs are made
* 1 - From left to right and create horizontal zone segments
* 2 - From top to bottom, and create vertical zone segments
* @param net_code = net_code common to all segment zone created
* @param DC = current device context ( can be NULL )
* @param frame = current WinEDA_PcbFrame
* global: parameter TimeStamp: time stamp common to all segment zone created
*/ */
{ // calculate the x position of the intersection of this segment and the infinite line
int row, col; // this is more easier if we move the X,Y axis origin to the segment start point:
long current_cell, old_cell; seg_endX -= seg_startX;
int ux0 = 0, uy0 = 0, ux1 = 0, uy1 = 0; seg_endY -= seg_startY;
int Xmin = frame->m_Pcb->m_BoundaryBox.m_Pos.x; double newrefy = (double) (refy - seg_startY);
int Ymin = frame->m_Pcb->m_BoundaryBox.m_Pos.y; double intersec_x;
SEGZONE* pt_track; if ( seg_endY == 0 ) // horizontal segment on the same line: skip
int nbsegm = 0; continue;
wxString msg; // Now calculate the x intersection coordinate of the horizontal line at y = newrefy
// and the segment from (0,0) to (seg_endX,seg_endY)
/* Create horizontal segments */ // with the horizontal line at the new refy position
Affiche_1_Parametre( frame, 64, wxT( "Segm H" ), wxT( "0" ), BROWN ); // the line slope is slope = seg_endY/seg_endX; and inv_slope = seg_endX/seg_endY
for( row = 0; row < Nrows; row++ ) // and the x pos relative to the new origin is intersec_x = refy/slope = refy * inv_slope
{ // Note: because horizontal segments are already tested and skipped, slope exists (seg_end_y not O)
old_cell = 0; double inv_slope = (double)seg_endX / seg_endY;
uy0 = uy1 = (row * g_GridRoutingSize) + Ymin; intersec_x = newrefy * inv_slope;
for( col = 0; col < Ncols; col++ ) x_coordinates.push_back((int) intersec_x + seg_startX);
{ }
current_cell = GetCell( row, col, BOTTOM ) & CELL_is_ZONE;
if( current_cell ) /* ce point doit faire partie d'un segment */ // A line scan is finished: build list of segments
{
ux1 = (col * g_GridRoutingSize) + Xmin; // Sort intersection points by increasing x value:
if( old_cell == 0 ) // So 2 consecutive points are the ends of a segment
ux0 = ux1; sort( x_coordinates.begin(), x_coordinates.end(), SortByXValues );
}
// Create segments
if( !current_cell || (col == Ncols - 1) ) /* peut etre fin d'un segment */
{ if ( !error && ( x_coordinates.size() & 1 ) != 0 )
if( (old_cell) && (ux0 != ux1) ) { // An even number of coordinates is expected, because a segment has 2 ends.
{ // An if this algorithm always works, it must always find an even count.
/* un segment avait debute de longueur > 0 */ wxString msg = wxT("Fill Zone: odd number of points at y = ");
pt_track = new SEGZONE( frame->m_Pcb ); msg << refy;
pt_track->SetLayer( layer ); wxMessageBox(msg );
pt_track->SetNet( net_code ); error = true;
}
pt_track->m_Width = g_GridRoutingSize;
if ( error ) break;
pt_track->m_Start.x = ux0; int iimax = x_coordinates.size()-1;
pt_track->m_Start.y = uy0; for (int ii = 0; ii < iimax; ii +=2 )
{
pt_track->m_End.x = ux1; wxPoint seg_start, seg_end;
pt_track->m_End.y = uy1; count++;
seg_start.x = x_coordinates[ii];
pt_track->m_TimeStamp = s_TimeStamp; seg_start.y = refy;
seg_end.x = x_coordinates[ii+1];
pt_track->Insert( frame->m_Pcb, NULL ); seg_end.y = refy;
if ( DC ) SEGZONE* segment = new SEGZONE( aFrame->m_Pcb );
pt_track->Draw( frame->DrawPanel, DC, GR_OR ); segment->m_Start = seg_start;
nbsegm++; segment->m_End = seg_end;
} segment->SetNet( GetNet() );
} segment->m_TimeStamp = m_TimeStamp;
old_cell = current_cell; segment->m_Width = m_ZoneMinThickness;
} segment->SetLayer( GetLayer() );
aFrame->m_Pcb->Add( segment );
msg.Printf( wxT( "%d" ), nbsegm ); }
Affiche_1_Parametre( frame, -1, wxEmptyString, msg, BROWN ); } //End examine segments in one area
} if ( error ) break;
istart = iend + 1; // istart points the first corner of the next area
/* Create vertical segments */ } // End find one end of outline
Affiche_1_Parametre( frame, 72, wxT( "Segm V" ), wxT( "0" ), BROWN ); if ( error ) break;
for( col = 0; col < Ncols; col++ ) } // End examine all areas
{
old_cell = 0;
ux0 = ux1 = (col * g_GridRoutingSize) + Xmin;
for( row = 0; row < Nrows; row++ )
{
current_cell = GetCell( row, col, BOTTOM ) & CELL_is_ZONE;
if( current_cell ) /* ce point doit faire partie d'un segment */
{
uy1 = (row * g_GridRoutingSize) + Ymin;
if( old_cell == 0 )
uy0 = uy1;
}
if( !current_cell || (row == Nrows - 1) ) /* peut etre fin d'un segment */
{
if( (old_cell) && (uy0 != uy1) )
{
/* un segment avait debute de longueur > 0 */
pt_track = new SEGZONE( frame->m_Pcb );
pt_track->SetLayer( layer );
pt_track->m_Width = g_GridRoutingSize;
pt_track->SetNet( net_code );
pt_track->m_Start.x = ux0;
pt_track->m_Start.y = uy0;
pt_track->m_End.x = ux1;
pt_track->m_End.y = uy1;
pt_track->m_TimeStamp = s_TimeStamp;
pt_track->Insert( frame->m_Pcb, NULL );
if( DC )
pt_track->Draw( frame->DrawPanel, DC, GR_OR );
nbsegm++;
}
}
old_cell = current_cell;
}
msg.Printf( wxT( "%d" ), nbsegm ); return count;
Affiche_1_Parametre( frame, -1, wxEmptyString, msg, BROWN );
}
} }
/********************************************/ /********************************************/
int Propagation( WinEDA_PcbFrame* frame ) int Propagation( WinEDA_PcbFrame* frame )
/********************************************/ /********************************************/
...@@ -658,133 +357,3 @@ int Propagation( WinEDA_PcbFrame* frame ) ...@@ -658,133 +357,3 @@ int Propagation( WinEDA_PcbFrame* frame )
return nbpoints; return nbpoints;
} }
/*****************************************************************************/
bool WinEDA_PcbFrame::Genere_Pad_Connexion( wxDC* DC, int layer )
/*****************************************************************************/
/* Create the thermal relief for each pad in the zone:
* this is 4 small segments from the pad to the zone
*/
{
int ii, jj, Npads;
D_PAD* pt_pad;
LISTE_PAD* pt_liste_pad;
TRACK* pt_track, * loctrack;
int angle;
int cX, cY, dx, dy;
int sommet[4][2];
wxString msg;
if( m_Pcb->m_Zone == NULL )
return FALSE; /* error: no zone */
if( m_Pcb->m_Zone->m_TimeStamp != s_TimeStamp ) /* error: this is not the new zone */
return FALSE;
/* Count the pads, i.e. the thermal relief to create count, and displays it */
Affiche_1_Parametre( this, 50, wxT( "NPads" ), wxT( " " ), CYAN );
pt_liste_pad = (LISTE_PAD*) m_Pcb->m_Pads;
for( ii = 0, Npads = 0; ii < m_Pcb->m_NbPads; ii++, pt_liste_pad++ )
{
pt_pad = *pt_liste_pad;
/* Search pads relative to the selected net code */
if( pt_pad->GetNet() != g_HightLigth_NetCode )
continue;
/* Is the pad on the active layer ? */
if( (pt_pad->m_Masque_Layer & g_TabOneLayerMask[layer]) == 0 )
continue;
Npads++;
}
msg.Printf( wxT( "%d" ), Npads );
Affiche_1_Parametre( this, -1, wxEmptyString, msg, CYAN );
/* Create the thermal reliefs */
Affiche_1_Parametre( this, 57, wxT( "Pads" ), wxT( " " ), CYAN );
pt_liste_pad = (LISTE_PAD*) m_Pcb->m_Pads;
for( ii = 0, Npads = 0; ii < m_Pcb->m_NbPads; ii++, pt_liste_pad++ )
{
pt_pad = *pt_liste_pad;
/* Search pads relative to the selected net code */
if( pt_pad->GetNet() != g_HightLigth_NetCode )
continue;
/* Is the pad on the active layer ? */
if( (pt_pad->m_Masque_Layer & g_TabOneLayerMask[layer]) == 0 )
continue;
/* Create the theram relief for the current pad */
Npads++;
msg.Printf( wxT( "%d" ), Npads );
Affiche_1_Parametre( this, -1, wxEmptyString, msg, CYAN );
cX = pt_pad->GetPosition().x;
cY = pt_pad->GetPosition().y;
dx = pt_pad->m_Size.x / 2;
dy = pt_pad->m_Size.y / 2;
dx += g_DesignSettings.m_TrackClearence + g_GridRoutingSize;
dy += g_DesignSettings.m_TrackClearence + g_GridRoutingSize;
if( pt_pad->m_PadShape == PAD_TRAPEZOID )
{
dx += abs( pt_pad->m_DeltaSize.y ) / 2;
dy += abs( pt_pad->m_DeltaSize.x ) / 2;
}
/* calculate the 4 segment coordinates (starting from the pad centre cX,cY) */
sommet[0][0] = 0; sommet[0][1] = -dy;
sommet[1][0] = -dx; sommet[1][1] = 0;
sommet[2][0] = 0; sommet[2][1] = dy;
sommet[3][0] = dx; sommet[3][1] = 0;
angle = pt_pad->m_Orient;
for( jj = 0; jj < 4; jj++ )
{
RotatePoint( &sommet[jj][0], &sommet[jj][1], angle );
pt_track = new SEGZONE( m_Pcb );
pt_track->SetLayer( layer );
pt_track->m_Width = g_DesignSettings.m_CurrentTrackWidth;
pt_track->SetNet( g_HightLigth_NetCode );
pt_track->start = pt_pad;
pt_track->m_Start.x = cX; pt_track->m_Start.y = cY;
pt_track->m_End.x = cX + sommet[jj][0];
pt_track->m_End.y = cY + sommet[jj][1];
pt_track->m_TimeStamp = s_TimeStamp;
/* Test if the segment is allowed */
if( BAD_DRC==m_drc->DrcBlind( pt_track, m_Pcb->m_Track ) )
{
// Drc error, retry with a smaller width
// because some drc errors are due to a track width > filling zone size.
pt_track->m_Width = g_GridRoutingSize;
if( BAD_DRC==m_drc->DrcBlind( pt_track, m_Pcb->m_Track ) )
{
delete pt_track;
continue;
}
}
/* Search for a zone segment */
loctrack = Locate_Zone( m_Pcb->m_Zone, pt_track->m_End, layer );
if( (loctrack == NULL) || (loctrack->m_TimeStamp != s_TimeStamp) )
{
delete pt_track;
continue;
}
pt_track->Insert( m_Pcb, NULL );
if( DC )
pt_track->Draw( DrawPanel, DC, GR_OR );
}
}
return TRUE;
}
...@@ -907,17 +907,10 @@ int WinEDA_PcbFrame::Fill_Zone( wxDC* DC, ZONE_CONTAINER* zone_container, bool v ...@@ -907,17 +907,10 @@ int WinEDA_PcbFrame::Fill_Zone( wxDC* DC, ZONE_CONTAINER* zone_container, bool v
int error_level = 0; int error_level = 0;
zone_container->m_FilledPolysList.clear(); zone_container->m_FilledPolysList.clear();
if( zone_container->m_GridFillValue == 0 ) Delete_Zone_Fill( NULL, NULL, zone_container->m_TimeStamp );
{
zone_container->BuildFilledPolysListData( m_Pcb ); zone_container->BuildFilledPolysListData( m_Pcb );
if ( DC ) if ( DC )
DrawPanel->Refresh(); DrawPanel->Refresh();
}
else
{
g_GridRoutingSize = zone_container->m_GridFillValue;
error_level = zone_container->Fill_Zone( this, DC, verbose );
}
GetScreen()->SetModify(); GetScreen()->SetModify();
......
...@@ -954,6 +954,8 @@ int ZONE_CONTAINER::CopyPolygonsFromBoolengineToFilledPolysList( Bool_Engine* aB ...@@ -954,6 +954,8 @@ int ZONE_CONTAINER::CopyPolygonsFromBoolengineToFilledPolysList( Bool_Engine* aB
corner.x = (int) aBoolengine->GetPolygonXPoint(); corner.x = (int) aBoolengine->GetPolygonXPoint();
corner.y = (int) aBoolengine->GetPolygonYPoint(); corner.y = (int) aBoolengine->GetPolygonYPoint();
corner.end_contour = false; corner.end_contour = false;
// Flag this corner if starting a hole connection segment:
corner.utility = (aBoolengine->GetPolygonPointEdgeType() == KB_FALSE_EDGE) ? 1 : 0;
m_FilledPolysList.push_back( corner ); m_FilledPolysList.push_back( corner );
count++; count++;
} }
......
...@@ -15,283 +15,22 @@ using namespace std; ...@@ -15,283 +15,22 @@ using namespace std;
* At each crossing, the ray switches between inside and outside. * At each crossing, the ray switches between inside and outside.
* If odd count, the test point is inside the polygon * If odd count, the test point is inside the polygon
* This is called the Jordan curve theorem, or sometimes referred to as the "even-odd" test. * This is called the Jordan curve theorem, or sometimes referred to as the "even-odd" test.
* Take care to starting and ending points of segments outlines: * Take care to starting and ending points of segments outlines, when the horizontal line crosses a segment outline
* Only one must be used because the startingpoint of a segemnt is also the ending point of the previous. * exactly on an ending point:
* And we do no use twice the same segment, so we do NOT use both starting and ending points of segments. * Because the starting point of a segment is also the ending point of the previous, only one must be used.
* So we must use starting point but not ending point of each segment when calculating intersections * And we do no use twice the same segment, so we do NOT use both starting and ending points of these 2 segments.
* So we must use only one ending point of each segment when calculating intersections
* but it cannot be always the starting or the endind point. This depend on relative position of 2 consectutive segments
* Here, the ending point above the Y reference position is used
* and the ending point below or equal the Y reference position is NOT used
* Obviously, others cases are irrelevant because there is not intersection.
*/ */
/* 2 versions are given. #define OUTSIDE false
* the second version is GPL (currently used) #define INSIDE true
* the first version is for explanations and tests (used to test the second version)
* both use the same algorithm.
*/
#if 0
/* This text and the algorithm come from http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html
*
* PNPOLY - Point Inclusion in Polygon Test
* W. Randolph Franklin (WRF)
*
* Table of Contents
*
* 1. The C Code <#The C Code>
* 2. The Method <#The Method>
* 3. Originality <#Originality>
* 4. The Inequality Tests are Tricky <#The Inequality Tests are Tricky>
* 5. C Semantics <#C Semantics>
* 6. Point on a (Boundary) Edge <#Point on an Edge>
* 7. Multiple Components and Holes <#Listing the Vertices>
* 8. Testing Which One of Many Polygons Contains the Point <#Testing a
* Point Against Many Polygons>
* 9. Explanation of /"for (i = 0, j = nvert-1; i < nvert; j = i++)"/
* <#Explanation>
* 10. Fortran Code for the Point in Polygon Test <#Fortran Code for the
* Point in Polygon Test>
* 11. Converting the Code to All Integers <#Converting the Code to All
* Integers>
* 12. License to Use <#License to Use>
*
* The C Code
*
* Here is the code, for reference. Excluding lines with only braces, there
* are only /7 lines/ of code.
*
* int pnpoly(int nvert, float *vertx, float *verty, float ref_pointX, float ref_pointY)
* {
* int i, j, c = 0;
* for (i = 0, j = nvert-1; i < nvert; j = i++) {
* if ( ((verty[i]>ref_pointY) != (verty[j]>ref_pointY)) &&
* (ref_pointX < (vertx[j]-vertx[i]) * (ref_pointY-verty[i]) / (verty[j]-verty[i]) + vertx[i]) )
* c = !c;
* }
* return c;
* }
*
* Argument Meaning
* nvert Number of vertices in the polygon. Whether to repeat the first
* vertex at the end is discussed below.
* vertx, verty Arrays containing the x- and y-coordinates of the
* polygon's vertices.
* ref_pointX, ref_pointY X- and y-coordinate of the test point.
*
*
* The Method
*
* I run a semi-infinite ray horizontally (increasing x, fixed y) out from
* the test point, and count how many edges it crosses. At each crossing,
* the ray switches between inside and outside. This is called the /Jordan
* curve theorem/.
*
* The case of the ray going thru a vertex is handled correctly via a
* careful selection of inequalities. Don't mess with this code unless
* you're familiar with the idea of /Simulation of Simplicity/. This
* pretends to shift the ray infinitesimally to one side so that it either
* clearly intersects, or clearly doesn't touch. Since this is merely a
* conceptual, infinitesimal, shift, it never creates an intersection that
* didn't exist before, and never destroys an intersection that clearly
* existed before.
*
* The ray is tested against each edge thus:
*
* 1. Is the point in the half-plane below the extended edge? and
* 2. Is the point's X coordinate within the edge's X-range?
*
* Handling endpoints here is tricky.
*
*
* Originality
*
* I make no claim to having invented the idea. However in 1970, I did
* produce the Fortran code given below on my own, and include it in a
* package of cartographic SW publicly-distributed by David Douglas, Dept
* of Geography, Simon Fraser U and U of Ottawa.
*
* Earlier implementations of point-in-polygon testing presumably exist,
* tho the code might never have been released. Pointers to prior art,
* especially publicly available code, are welcome. One early publication,
* which doesn't handle the point on an edge, and has a typo, is this:
*
* M Shimrat, "Algorithm 112, Position of Point Relative to Polygon",
* /Comm. ACM/ 5(8), Aug 1962, p 434.
*
* A well-written recent summary is this:
*
* E Haines, /Point in Polygon Strategies/,
* http://www.acm.org/pubs/tog/editors/erich/ptinpoly/, 1994.
*
*
* The Inequality Tests are Tricky
*
* If translating the program to another language, be sure to get the
* inequalities in the conditional correct. They were carefully chosen to
* make the program work correctly when the point is vertically below a vertex.
*
* Several people have thought that my program was wrong, when really
* /they/ had gotten the inequalities wrong.
*
*
* C Semantics
*
* My code uses the fact that, in the C language, when executing the code
|a&&b|, if |a| is false, then |b| must not be evaluated. If your
* compiler doesn't do this, then it's not implementing C, and you will get
* a divide-by-zero, i.a., when the test point is vertically in line with a
* vertical edge. When translating this code to another language with
* different semantics, then you must implement this test explicitly.
*
*
* Point on a (Boundary) Edge
*
* PNPOLY partitions the plane into points inside the polygon and points
* outside the polygon. Points that are on the boundary are classified as
* either inside or outside.
*
* 1.
*
* Any particular point is always classified consistently the same
* way. In the following figure, consider what PNPOLY would say when
* the red point, /P/, is tested against the two triangles, /T_L /
* and /T_R /. Depending on internal roundoff errors, PNPOLY may say
* that /P/ is in /T_L / or in /T_R /. However it will always give
* the same answer when /P/ is tested against those triangles. That
* is, if PNPOLY finds that /P/ is in /T_L /, then it will find that
* /P/ is not /T_R /. If PNPOLY finds that /P/ is not in /T_L /, then
* it will find that /P/ is in /T_R /.
*
* 2. If you want to know when a point is exactly on the boundary, you
* need another program. This is only one of many functions that
* PNPOLY lacks; it also doesn't predict tomorrow's weather. You are
* free to extend PNPOLY's source code.
*
* 3. The first reason for this is the numerical analysis position that
* you should not be testing exact equality unless your input is
* exact. Even then, computational roundoff error would often make
* the result wrong.
*
* 4. The second reason is that, if you partition a region of the plane
* into polygons, i.e., form a planar graph, then PNPOLY will locate
* each point into exactly one polygon. In other words, PNPOLY
* considers each polygon to be topologically a semi-open set. This
* makes things simpler, i.e., causes fewer special cases, if you use
* PNPOLY as part of a larger system. Examples of this include
* locating a point in a planar graph, and intersecting two planar
* graphs.
*
*
* Explanation of /"for (i = 0, j = nvert-1; i < nvert; j = i++)"/
*
* The intention is to execute the loop for each i from 0 to nvert-1. For
* each iteration, j is i-1. However that wraps, so if i=0 then j=nvert-1.
* Therefore the current edge runs between verts j and i, and the loop is
* done once per edge. In detail:
*
* 1. Start by setting i and j:
* i = 0
* j = nvert-1
* 2. If i<nvert is false then exit the loop.
* 3. Do the loop body.
* 4. Set j=i and then
* add 1 to i and then
* 5. Go back to step 2.
*
*
*
* Converting the Code to All Integers
*
* If you want to convert the code from floats to integers, consider these
* issues.
*
* 1. On many current processors floats are at least as fast as ints.
* 2. If you move the denominator over to the other side of the
* inequality, remember that, when the denominator is negative, the
* inequality will flip.
* 3. If coordinates are large enough, the multiplication will silently
* overflow.
*
*
* License to Use
* Copyright (c) 1970-2003, Wm. Randolph Franklin
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimers.
* 2. Redistributions in binary form must reproduce the above copyright
* notice in the documentation and/or other materials provided with
* the distribution.
* 3. The name of W. Randolph Franklin may not be used to endorse or
* promote products derived from this Software without specific prior
* written permission.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*
* Copyright © 1994-2006, W Randolph Franklin (WRF)
* <http://wrfranklin.org/> You may use my material for non-profit research
* and education, provided that you credit me, and link back to my home page.
* http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html,
* 05/20/2008 20:36:42
*/
bool TestPointInsidePolygon( std::vector <CPolyPt> aPolysList, bool TestPointInsidePolygon( std::vector <CPolyPt> aPolysList,
int istart, int istart, int iend, int refx, int refy )
int iend,
int refx,
int refy )
/** Function TestPointInsidePolygon
* test if a point is inside or outside a polygon.
* @param aPolysList: the list of polygons
* @param istart: the starting point of a given polygon in m_FilledPolysList.
* @param iend: the ending point of the polygon in m_FilledPolysList.
* @param refx, refy: the point coordinate to test
* @return true if the point is inside, false for outside
*/
{
double ref_pointX = refx;
double ref_pointY = refy;
bool inside = false;
for( int ii = istart, jj = iend; ii <= iend; jj = ii++ )
{
double seg_startX, seg_startY; // starting point for the segment to test
seg_startX = aPolysList[ii].x;
seg_startY = aPolysList[ii].y;
double seg_endX, seg_endY; // ending point for the segment to test
seg_endX = aPolysList[jj].x;
seg_endY = aPolysList[jj].y;
if( ( ( seg_startY > ref_pointY ) != (seg_endY > ref_pointY ) )
&& (ref_pointX <
(seg_endX -
seg_startX) * (ref_pointY - seg_startY) / (seg_endY - seg_startY) + seg_startX) )
inside = not inside;
}
return inside;
}
#else
bool TestPointInsidePolygon( std::vector <CPolyPt> aPolysList,
int istart,
int iend,
int refx,
int refy )
/** Function TestPointInsidePolygon /** Function TestPointInsidePolygon
* test if a point is inside or outside a polygon. * test if a point is inside or outside a polygon.
...@@ -304,9 +43,9 @@ bool TestPointInsidePolygon( std::vector <CPolyPt> aPolysList, ...@@ -304,9 +43,9 @@ bool TestPointInsidePolygon( std::vector <CPolyPt> aPolysList,
* @return true if the point is inside, false for outside * @return true if the point is inside, false for outside
*/ */
{ {
// count intersection points to right of (refx,refy), if odd (refx,refy) is inside polyline // count intersection points to right of (refx,refy). If odd number, point (refx,refy) is inside polyline
int ics, ice; int ics, ice;
bool inside = false; int count = 0;
// find all intersection points of line with polyline sides // find all intersection points of line with polyline sides
for( ics = istart, ice = iend; ics <= iend; ice = ics++ ) for( ics = istart, ice = iend; ics <= iend; ice = ics++ )
...@@ -316,42 +55,39 @@ bool TestPointInsidePolygon( std::vector <CPolyPt> aPolysList, ...@@ -316,42 +55,39 @@ bool TestPointInsidePolygon( std::vector <CPolyPt> aPolysList,
int seg_endX = aPolysList[ice].x; int seg_endX = aPolysList[ice].x;
int seg_endY = aPolysList[ice].y; int seg_endY = aPolysList[ice].y;
/* Trivial cases: skip if ref above or below the segment to test /* Trivial cases: skip if ref above or below the segment to test */
* Note: end point segment is skipped, because we do not test twice the same point:
* If the start point of segments is tested, the end point must be skipped, because
* this is also the starting point of the next segment
*/
// segment above ref point: skip
if( ( seg_startY > refy ) && (seg_endY > refy ) ) if( ( seg_startY > refy ) && (seg_endY > refy ) )
continue; continue;
// segment below ref point, or its end on ref point: skip // segment below ref point, or one of its ends has the same Y pos as the ref point: skip
// Note: also we skip vertical segments // So we eliminate one end point of 2 consecutive segments.
// So points on vertical segments outlines are seen as outside the polygon // Note: also we skip horizontal segments if ref point is on this horizontal line
// So reference points on horizontal segments outlines always are seen as outside the polygon
if( ( seg_startY <= refy ) && (seg_endY <= refy ) ) if( ( seg_startY <= refy ) && (seg_endY <= refy ) )
continue; continue;
/* refy is between seg_startY and seg_endY. /* refy is between seg_startY and seg_endY.
* see if an horizontal line from refx is intersecting the segment * note: here: horizontal segments (seg_startY == seg_endY) are skipped,
* either by the first test or by the second test
* see if an horizontal semi infinite line from refx is intersecting the segment
*/ */
// calculate the x position of the intersection of this segment and the semi infinite line // calculate the x position of the intersection of this segment and the semi infinite line
// this is more easier if we move the X,Y axis origin to the segment start point: // this is more easier if we move the X,Y axis origin to the segment start point:
seg_endX -= seg_startX; seg_endX -= seg_startX;
seg_endY -= seg_startY; seg_endY -= seg_startY;
double newrefx = (double)(refx - seg_startX); double newrefx = (double) (refx - seg_startX);
double newrefy = (double) (refy - seg_startY); double newrefy = (double) (refy - seg_startY);
// Now calculate the x intersection coordinate of the line from (0,0) to (seg_endX,seg_endY) // Now calculate the x intersection coordinate of the line from (0,0) to (seg_endX,seg_endY)
// with the horizontal line at the new refy position // with the horizontal line at the new refy position
// the line slope is slope = seg_endY/seg_endX; // the line slope = seg_endY/seg_endX;
// and the x pos relative to the new origin is intersec_x = refy/slope // and the x pos relative to the new origin is intersec_x = refy/slope
// Note: because vertical segments are skipped, slope exists (seg_end_y not O) // Note: because horizontal segments are skipped, 1/slope exists (seg_end_y never == O)
double intersec_x = newrefy * seg_endX / seg_endY; double intersec_x = newrefy * seg_endX / seg_endY;
if( newrefx < intersec_x ) // Intersection found with the semi-infinite line from -infinite to refx if( newrefx < intersec_x ) // Intersection found with the semi-infinite line from refx to infinite
inside = not inside; count++;
} }
return inside; return count & 1 ? INSIDE : OUTSIDE;
} }
#endif
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment