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.
This commit is contained in:
parent
7de4bfe6e1
commit
75b3c3bf37
|
@ -5,6 +5,14 @@ Started 2007-June-11
|
|||
Please add newer entries at the top, list the date and your name with
|
||||
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>
|
||||
================================================================================
|
||||
++build fixes
|
||||
|
|
|
@ -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. */
|
||||
/************************************************************************/
|
||||
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 )
|
||||
{
|
||||
if( !IsGRSPolyDrawable( ClipBox, n, Points ) )
|
||||
|
@ -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 */
|
||||
/******************************************************************************/
|
||||
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 );
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
|
||||
|
@ -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. */
|
||||
/************************************************************************/
|
||||
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;
|
||||
|
||||
|
@ -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 */
|
||||
/**************************************************************************/
|
||||
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 );
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
|
||||
|
|
|
@ -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 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,
|
||||
int Fill, int width, int Color, int BgColor);
|
||||
void GRClosedPoly(EDA_Rect * ClipBox, wxDC * DC, int n, int *Points,
|
||||
int Fill, int Color, int BgColor);
|
||||
void GRClosedPoly(EDA_Rect * ClipBox, wxDC * DC, int n, int *Points,
|
||||
int 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);
|
||||
bool Fill, int width, int Color, int BgColor);
|
||||
void GRClosedPoly(EDA_Rect * ClipBox, wxDC * DC, int n, int *Points, bool 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 GRSPoly(EDA_Rect * ClipBox, wxDC * DC, int n, int *Points, bool 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 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 GRFilledCircle(EDA_Rect * ClipBox, wxDC * DC, int x, int y, int r,
|
||||
|
|
|
@ -53,7 +53,7 @@ BOARD::BOARD( EDA_BaseStruct* parent, WinEDA_BasePcbFrame* frame ) :
|
|||
m_Pads = NULL; // pointeur liste d'acces aux pads
|
||||
m_Ratsnest = NULL; // pointeur liste rats
|
||||
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
|
||||
|
||||
for( int layer=0; layer<NB_COPPER_LAYERS; ++layer )
|
||||
|
@ -84,6 +84,13 @@ BOARD::~BOARD()
|
|||
m_Zone->DeleteStructList();
|
||||
m_Zone = 0;
|
||||
|
||||
while ( m_ZoneDescriptorList.size() )
|
||||
{
|
||||
ZONE_CONTAINER* area_to_remove = m_ZoneDescriptorList[0];
|
||||
Delete( area_to_remove );
|
||||
}
|
||||
|
||||
|
||||
MyFree( m_Pads );
|
||||
m_Pads = 0;
|
||||
|
||||
|
@ -264,6 +271,18 @@ void BOARD::Add( BOARD_ITEM* aBoardItem, int aControl )
|
|||
}
|
||||
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:
|
||||
// this is an insert, not an append which may also be needed.
|
||||
{
|
||||
|
@ -278,7 +297,7 @@ void BOARD::Add( BOARD_ITEM* aBoardItem, int aControl )
|
|||
|
||||
// other types may use linked list
|
||||
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
|
|||
if( ret < 1 )
|
||||
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 );
|
||||
if( ret < 3 )
|
||||
return false;
|
||||
|
@ -176,7 +176,7 @@ bool ZONE_CONTAINER::Save( FILE* aFile ) const
|
|||
for( item_pos = 0; item_pos < m_FilledPolysList.size(); 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 )
|
||||
return false;
|
||||
}
|
||||
|
@ -287,16 +287,16 @@ int ZONE_CONTAINER::ReadDescr( FILE* aFile, int* aLineNum )
|
|||
}
|
||||
if( strnicmp( Line, "ZOptions", 8 ) == 0 ) // Options info found
|
||||
{
|
||||
int gridsize = 50;
|
||||
int fillmode = 1;
|
||||
int arcsegmentcount = 16;
|
||||
char drawopt = 'F';
|
||||
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 );
|
||||
if( ret < 1 ) // Must find 1 or more args.
|
||||
return false;
|
||||
else
|
||||
m_GridFillValue = gridsize;
|
||||
m_FillMode = fillmode ? 1 : 0;
|
||||
|
||||
if( arcsegmentcount >= 32 )
|
||||
m_ArcToSegmentsCount = 32;
|
||||
|
@ -354,11 +354,13 @@ int ZONE_CONTAINER::ReadDescr( FILE* aFile, int* aLineNum )
|
|||
if( strnicmp( Line, "$endPOLYSCORNERS", 4 ) == 0 )
|
||||
break;
|
||||
CPolyPt corner;
|
||||
int itmp;
|
||||
ret = sscanf( Line, "%d %d %d", &corner.x, &corner.y, &itmp );
|
||||
int end_contour, utility;
|
||||
utility = 0;
|
||||
ret = sscanf( Line, "%d %d %d %d", &corner.x, &corner.y, &end_contour, &utility );
|
||||
if( ret < 3 )
|
||||
return false;
|
||||
corner.end_contour = itmp ? true : false;
|
||||
corner.end_contour = end_contour ? true : false;
|
||||
corner.utility = utility;
|
||||
m_FilledPolysList.push_back( corner );
|
||||
}
|
||||
}
|
||||
|
@ -371,7 +373,7 @@ int ZONE_CONTAINER::ReadDescr( FILE* aFile, int* aLineNum )
|
|||
|
||||
if( !IsOnCopperLayer() )
|
||||
{
|
||||
m_GridFillValue = 0;
|
||||
m_FillMode = 0;
|
||||
SetNet( 0 );
|
||||
}
|
||||
|
||||
|
@ -424,6 +426,8 @@ void ZONE_CONTAINER::Draw( WinEDA_DrawPanel* panel, wxDC* DC, int draw_mode, con
|
|||
if( color & HIGHT_LIGHT_FLAG )
|
||||
color = ColorRefs[color & MASKCOLOR].m_LightColor;
|
||||
|
||||
SetAlpha( &color, 150 );
|
||||
|
||||
// draw the lines
|
||||
int i_start_contour = 0;
|
||||
for( int ic = 0; ic < GetNumCorners(); ic++ )
|
||||
|
@ -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,
|
||||
|
@ -467,9 +484,10 @@ void ZONE_CONTAINER::DrawFilledArea( WinEDA_DrawPanel* panel,
|
|||
* @param aDrawMode = GR_OR, GR_XOR, GR_COPY ..
|
||||
*/
|
||||
{
|
||||
static int* CornersBuffer = NULL;
|
||||
static unsigned CornersBufferSize = 0;
|
||||
bool sketch_mode = m_DrawOptions; // false to show filled polys, true to show polygons outlines only (test and debug purposes)
|
||||
static vector < char > CornersTypeBuffer;
|
||||
static vector < corner_coord > CornersBuffer;
|
||||
|
||||
bool outline_mode = m_DrawOptions; // false to show filled polys, true to show polygons outlines only (test and debug purposes)
|
||||
|
||||
if( DC == NULL )
|
||||
return;
|
||||
|
@ -477,9 +495,7 @@ void ZONE_CONTAINER::DrawFilledArea( WinEDA_DrawPanel* panel,
|
|||
if( !DisplayOpt.DisplayZones )
|
||||
return;
|
||||
|
||||
unsigned imax = m_FilledPolysList.size();
|
||||
|
||||
if( imax == 0 ) // Nothing to draw
|
||||
if( m_FilledPolysList.size() == 0 ) // Nothing to draw
|
||||
return;
|
||||
|
||||
int curr_layer = ( (PCB_SCREEN*) panel->GetScreen() )->m_Active_Layer;
|
||||
|
@ -509,55 +525,60 @@ void ZONE_CONTAINER::DrawFilledArea( WinEDA_DrawPanel* panel,
|
|||
if( color & HIGHT_LIGHT_FLAG )
|
||||
color = ColorRefs[color & MASKCOLOR].m_LightColor;
|
||||
|
||||
// We need a buffer to store corners coordinates:
|
||||
if( CornersBuffer == NULL )
|
||||
{
|
||||
CornersBufferSize = imax * 4;
|
||||
CornersBuffer = (int*) MyMalloc( CornersBufferSize * sizeof(int) );
|
||||
}
|
||||
SetAlpha( &color, 150 );
|
||||
|
||||
if( (imax * 4) > CornersBufferSize )
|
||||
{
|
||||
CornersBufferSize = imax * 4;
|
||||
CornersBuffer = (int*) realloc( CornersBuffer, CornersBufferSize * sizeof(int) );
|
||||
}
|
||||
CornersTypeBuffer.clear();
|
||||
CornersBuffer.clear();
|
||||
|
||||
// Draw all filled areas
|
||||
int corners_count = 0;
|
||||
for( unsigned ic = 0, ii = 0; ic < imax; ic++ )
|
||||
int imax = m_FilledPolysList.size() - 1;
|
||||
for( int ic = 0; ic <= imax; ic++ )
|
||||
{
|
||||
CPolyPt* corner = &m_FilledPolysList[ic];
|
||||
CornersBuffer[ii++] = corner->x + offset.x;
|
||||
CornersBuffer[ii++] = corner->y + offset.y;
|
||||
corners_count++;
|
||||
if( corner->end_contour )
|
||||
{ // Draw the current filled area
|
||||
if( sketch_mode )
|
||||
GRClosedPoly( &panel->m_ClipBox, DC, corners_count, CornersBuffer,
|
||||
false, 0, color, color );
|
||||
else
|
||||
corner_coord coord;
|
||||
coord.x = corner->x + offset.x;
|
||||
coord.y = corner->y + offset.y;
|
||||
CornersBuffer.push_back(coord);
|
||||
CornersTypeBuffer.push_back((char) corner->utility);
|
||||
if( (corner->end_contour) || (ic == imax) ) // the last corner of a filled area is found: draw it
|
||||
{ /* Draw the current filled area: draw segments ouline first
|
||||
* Curiously, draw segments ouline first and after draw filled polygons
|
||||
* 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:
|
||||
if ( m_ZoneMinThickness > 1 )
|
||||
if ( (m_ZoneMinThickness > 1) || outline_mode )
|
||||
{
|
||||
int ilim = corners_count * 2;
|
||||
for ( int is = 0, ie = ilim-2; is < ilim; ie = is, is+=2 )
|
||||
int ilim = CornersBuffer.size()-1;
|
||||
for ( int is = 0, ie = ilim; is <= ilim; ie = is, is++ )
|
||||
{
|
||||
int x0 = CornersBuffer[is];
|
||||
int y0 = CornersBuffer[is+1];
|
||||
int x1 = CornersBuffer[ie];
|
||||
int y1 = CornersBuffer[ie+1];
|
||||
int x0 = CornersBuffer[is].x;
|
||||
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
|
||||
{
|
||||
if( (!DisplayOpt.DisplayPcbTrackFill) || GetState( FORCE_SKETCH ) )
|
||||
GRCSegm( &panel->m_ClipBox, DC,
|
||||
x0, y0, x1 , y1,
|
||||
m_ZoneMinThickness, color );
|
||||
else
|
||||
GRFillCSegm( &panel->m_ClipBox, DC,
|
||||
x0, y0, x1 , y1,
|
||||
m_ZoneMinThickness, color );
|
||||
}
|
||||
}
|
||||
}
|
||||
// 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 );
|
||||
}
|
||||
corners_count = 0;
|
||||
ii = 0;
|
||||
CornersTypeBuffer.clear();
|
||||
CornersBuffer.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -884,11 +905,11 @@ void ZONE_CONTAINER::Display_Infos( WinEDA_DrawFrame* frame )
|
|||
Affiche_1_Parametre( frame, text_pos, _( "Corners" ), msg, BLUE );
|
||||
|
||||
text_pos += 6;
|
||||
if( m_GridFillValue )
|
||||
msg.Printf( wxT( "%d" ), m_GridFillValue );
|
||||
if( m_FillMode )
|
||||
msg.Printf( _( "Segments" ), m_FillMode );
|
||||
else
|
||||
msg = _( "No Grid" );
|
||||
Affiche_1_Parametre( frame, text_pos, _( "Fill Grid" ), msg, BROWN );
|
||||
msg = _( "Polygons" );
|
||||
Affiche_1_Parametre( frame, text_pos, _( "Fill mode" ), msg, BROWN );
|
||||
|
||||
// Useful for statistics :
|
||||
text_pos += 9;
|
||||
|
@ -913,12 +934,21 @@ void ZONE_CONTAINER::Display_Infos( WinEDA_DrawFrame* frame )
|
|||
*/
|
||||
void ZONE_CONTAINER::Move( const wxPoint& offset )
|
||||
{
|
||||
/* move outlines */
|
||||
for( unsigned ii = 0; ii < m_Poly->corner.size(); ii++ )
|
||||
{
|
||||
SetCornerPosition( ii, GetCornerPosition( ii ) + offset );
|
||||
}
|
||||
|
||||
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 )
|
|||
m_Poly->Copy( src->m_Poly ); // copy outlines
|
||||
m_CornerSelection = -1; // For corner moving, corner index to drag, or -1 if no selection
|
||||
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_Poly->SetHatch( src->m_Poly->GetHatchStyle() );
|
||||
}
|
||||
|
|
|
@ -27,7 +27,7 @@ public:
|
|||
int m_CornerSelection; // For corner moving, corner index to drag, or -1 if no selection
|
||||
int m_ZoneClearance; // clearance value
|
||||
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_PadOption; //
|
||||
int m_ThermalReliefGapValue; // tickness of the gap in thermal reliefs
|
||||
|
@ -255,6 +255,17 @@ public:
|
|||
*/
|
||||
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: */
|
||||
|
||||
/**
|
||||
|
|
|
@ -24,9 +24,9 @@
|
|||
|
||||
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_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_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
|
||||
|
@ -46,7 +46,7 @@ ZONE_SETTING::ZONE_SETTING( void )
|
|||
*/
|
||||
void ZONE_SETTING::ImportSetting( const ZONE_CONTAINER& aSource )
|
||||
{
|
||||
m_GridFillValue = aSource.m_GridFillValue;
|
||||
m_FillMode = aSource.m_FillMode;
|
||||
m_ZoneClearance = aSource.m_ZoneClearance;
|
||||
m_ZoneMinThickness = aSource.m_ZoneMinThickness;
|
||||
m_NetcodeSelection = aSource.GetNet();
|
||||
|
@ -63,20 +63,25 @@ void ZONE_SETTING::ImportSetting( const ZONE_CONTAINER& aSource )
|
|||
/** function ExportSetting
|
||||
* copy settings to a 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
|
||||
*/
|
||||
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_ZoneMinThickness = m_ZoneMinThickness;
|
||||
aTarget.SetNet( m_NetcodeSelection );
|
||||
aTarget.SetLayer( m_CurrentZone_Layer );
|
||||
aTarget.m_Poly->SetHatch( m_Zone_HatchingStyle );
|
||||
aTarget.m_ArcToSegmentsCount = m_ArcToSegmentsCount;
|
||||
aTarget.m_DrawOptions = m_FilledAreasShowMode;
|
||||
aTarget.m_ThermalReliefGapValue = m_ThermalReliefGapValue;
|
||||
aTarget.m_ThermalReliefCopperBridgeValue = m_ThermalReliefCopperBridgeValue;
|
||||
aTarget.m_PadOption = m_Zone_Pad_Options;
|
||||
if ( aFullExport )
|
||||
{
|
||||
aTarget.SetNet( m_NetcodeSelection );
|
||||
aTarget.SetLayer( m_CurrentZone_Layer );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
class ZONE_SETTING
|
||||
{
|
||||
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_ZoneMinThickness; // Min thickness value in filled areas
|
||||
int m_NetcodeSelection; // Net code selection for the current zone
|
||||
|
@ -41,8 +41,12 @@ public:
|
|||
/** function ExportSetting
|
||||
* copy settings to a 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 )
|
|||
|
||||
wxString msg;
|
||||
|
||||
msg = m_GridCtrl->GetLabel() + ReturnUnitSymbol( g_UnitMetric );
|
||||
m_GridCtrl->SetLabel( msg );
|
||||
|
||||
if( g_Zone_45_Only )
|
||||
m_OrientEdgesOpt->SetSelection( 1 );
|
||||
|
||||
static const int GridList[4] = { 25, 50, 100, 250 };
|
||||
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 );
|
||||
m_FillModeCtrl->SetSelection(m_Zone_Setting->m_FillMode ? 1 : 0);
|
||||
|
||||
AddUnitSymbol( *m_ClearanceValueTitle, g_UnitMetric );
|
||||
msg = ReturnStringFromValue( g_UnitMetric,
|
||||
|
@ -294,29 +273,7 @@ bool dialog_copper_zone::AcceptOptions( bool aPromptForErrors, bool aUseExportab
|
|||
m_Config->Write( ZONE_NET_FILTER_STRING_KEY, Filter );
|
||||
}
|
||||
|
||||
switch( m_GridCtrl->GetSelection() )
|
||||
{
|
||||
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;
|
||||
}
|
||||
m_Zone_Setting->m_FillMode = (m_FillModeCtrl->GetSelection() == 0) ? 0 : 1;
|
||||
|
||||
wxString txtvalue = m_ZoneClearanceCtrl->GetValue();
|
||||
m_Zone_Setting->m_ZoneClearance =
|
||||
|
@ -325,6 +282,12 @@ bool dialog_copper_zone::AcceptOptions( bool aPromptForErrors, bool aUseExportab
|
|||
txtvalue = m_ZoneMinThicknessCtrl->GetValue();
|
||||
m_Zone_Setting->m_ZoneMinThickness =
|
||||
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 )
|
||||
g_Zone_45_Only = FALSE;
|
||||
|
@ -462,14 +425,12 @@ void dialog_copper_zone::ExportSetupToOtherCopperZones( wxCommandEvent& event )
|
|||
if( !AcceptOptions( true, true ) )
|
||||
return;
|
||||
|
||||
// Export settings ( but layer ) to others zones:
|
||||
// Export settings ( but layer and netcode ) to others zones:
|
||||
BOARD* pcb = m_Parent->m_Pcb;
|
||||
for( int ii = 0; ii < pcb->GetAreaCount(); ii++ )
|
||||
{
|
||||
ZONE_CONTAINER* zone = pcb->GetArea( ii );
|
||||
int zone_layer = zone->GetLayer();
|
||||
m_Zone_Setting->ExportSetting( *zone );
|
||||
zone->SetLayer( zone_layer );
|
||||
m_Zone_Setting->ExportSetting( *zone, false ); // false = partiel export
|
||||
m_Parent->GetScreen()->SetModify();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -37,24 +37,34 @@ dialog_copper_zone_base::dialog_copper_zone_base( wxWindow* parent, wxWindowID i
|
|||
wxStaticBoxSizer* m_FillOptionsBox;
|
||||
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!)") };
|
||||
int m_GridCtrlNChoices = sizeof( m_GridCtrlChoices ) / 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_GridCtrl->SetSelection( 1 );
|
||||
m_FillOptionsBox->Add( m_GridCtrl, 0, wxALL|wxEXPAND, 5 );
|
||||
wxString m_FillModeCtrlChoices[] = { _("Use polygons"), _("Use segments") };
|
||||
int m_FillModeCtrlNChoices = sizeof( m_FillModeCtrlChoices ) / sizeof( wxString );
|
||||
m_FillModeCtrl = new wxRadioBox( this, ID_RADIOBOX_FILL_MODE_SELECTION, _("Filling Mode:"), wxDefaultPosition, wxDefaultSize, m_FillModeCtrlNChoices, m_FillModeCtrlChoices, 1, wxRA_SPECIFY_COLS );
|
||||
m_FillModeCtrl->SetSelection( 1 );
|
||||
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") };
|
||||
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->SetSelection( 1 );
|
||||
m_FillOptionsBox->Add( m_PadInZoneOpt, 0, wxALL|wxEXPAND, 5 );
|
||||
m_PadInZoneOpt->SetSelection( 0 );
|
||||
m_FillOptionsBox->Add( m_PadInZoneOpt, 0, wxEXPAND|wxBOTTOM|wxRIGHT|wxLEFT, 5 );
|
||||
|
||||
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->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->SetToolTip( _("Define the gap around the pad") );
|
||||
|
@ -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->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->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
|
|||
wxString m_OutlineAppearanceCtrlChoices[] = { _("Line"), _("Hatched outline"), _("Full hatched") };
|
||||
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->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_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;
|
||||
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
|
|||
|
||||
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_ExportableSetupSizer->Add( m_MiddleBox, 1, wxEXPAND, 5 );
|
||||
|
@ -156,12 +153,17 @@ dialog_copper_zone_base::dialog_copper_zone_base( wxWindow* parent, wxWindowID i
|
|||
wxBoxSizer* m_RightBoxSizer;
|
||||
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->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_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 );
|
||||
|
@ -172,7 +174,7 @@ dialog_copper_zone_base::dialog_copper_zone_base( wxWindow* parent, wxWindowID i
|
|||
wxString m_NetSortingOptionChoices[] = { _("Alphabetic"), _("Advanced") };
|
||||
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->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_NetSortOptSizer->Add( m_NetSortingOption, 0, wxALL|wxEXPAND, 5 );
|
||||
|
|
|
@ -32,7 +32,7 @@
|
|||
<property name="minimum_size"></property>
|
||||
<property name="name">dialog_copper_zone_base</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="subclass"></property>
|
||||
<property name="title">Fill Zones Options</property>
|
||||
|
@ -119,29 +119,29 @@
|
|||
<event name="OnUpdateUI"></event>
|
||||
<object class="sizeritem" expanded="1">
|
||||
<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">"0.00000" "0.00000" "0.00000" "0.00000" "No grid (For tests only!)"</property>
|
||||
<property name="choices">"Use polygons" "Use segments"</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"> ID_RADIOBOX_GRID_SELECTION</property>
|
||||
<property name="label">Grid Size for Filling</property>
|
||||
<property name="id"> ID_RADIOBOX_FILL_MODE_SELECTION</property>
|
||||
<property name="label">Filling Mode:</property>
|
||||
<property name="majorDimension">1</property>
|
||||
<property name="maximum_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="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"></property>
|
||||
<property name="tooltip">Filled areas can use solid polygons or segments.
Depending on the complexity and the size of the zone,
sometime polygons are better and sometime segments are better</property>
|
||||
<property name="window_extra_style"></property>
|
||||
<property name="window_name"></property>
|
||||
<property name="window_style"></property>
|
||||
|
@ -173,7 +173,61 @@
|
|||
</object>
|
||||
<object class="sizeritem" expanded="1">
|
||||
<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">"16 segments / 360 deg" "32 segments / 360 deg"</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.
16 segment is faster to calculate and when redraw screen.
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>
|
||||
<object class="wxRadioBox" expanded="1">
|
||||
<property name="bg"></property>
|
||||
|
@ -191,7 +245,7 @@
|
|||
<property name="name">m_PadInZoneOpt</property>
|
||||
<property name="permission">protected</property>
|
||||
<property name="pos"></property>
|
||||
<property name="selection">1</property>
|
||||
<property name="selection">0</property>
|
||||
<property name="size"></property>
|
||||
<property name="style">wxRA_SPECIFY_COLS</property>
|
||||
<property name="subclass"></property>
|
||||
|
@ -231,7 +285,7 @@
|
|||
<property name="proportion">0</property>
|
||||
<object class="wxStaticBoxSizer" expanded="1">
|
||||
<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="name">m_ThermalShapesParamsSizer</property>
|
||||
<property name="orient">wxVERTICAL</property>
|
||||
|
@ -239,7 +293,7 @@
|
|||
<event name="OnUpdateUI"></event>
|
||||
<object class="sizeritem" expanded="1">
|
||||
<property name="border">5</property>
|
||||
<property name="flag">wxTOP|wxRIGHT|wxLEFT</property>
|
||||
<property name="flag">wxRIGHT|wxLEFT</property>
|
||||
<property name="proportion">0</property>
|
||||
<object class="wxStaticText" expanded="1">
|
||||
<property name="bg"></property>
|
||||
|
@ -345,7 +399,7 @@
|
|||
</object>
|
||||
<object class="sizeritem" expanded="1">
|
||||
<property name="border">5</property>
|
||||
<property name="flag">wxTOP|wxRIGHT|wxLEFT</property>
|
||||
<property name="flag">wxRIGHT|wxLEFT</property>
|
||||
<property name="proportion">0</property>
|
||||
<object class="wxStaticText" expanded="1">
|
||||
<property name="bg"></property>
|
||||
|
@ -569,7 +623,7 @@
|
|||
<property name="name">m_OutlineAppearanceCtrl</property>
|
||||
<property name="permission">protected</property>
|
||||
<property name="pos"></property>
|
||||
<property name="selection">1</property>
|
||||
<property name="selection">0</property>
|
||||
<property name="size"></property>
|
||||
<property name="style">wxRA_SPECIFY_COLS</property>
|
||||
<property name="subclass"></property>
|
||||
|
@ -603,60 +657,6 @@
|
|||
<event name="OnUpdateUI"></event>
|
||||
</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">"16 segments / 360 deg" "32 segments / 360 deg"</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.
16 segment is faster to calculate and when redraw screen.
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</property>
|
||||
|
@ -937,9 +937,34 @@
|
|||
</object>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
<object class="sizeritem" expanded="1">
|
||||
<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>
|
||||
<object class="wxButton" expanded="1">
|
||||
<property name="bg"></property>
|
||||
|
@ -950,7 +975,7 @@
|
|||
<property name="font"></property>
|
||||
<property name="hidden">0</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="minimum_size"></property>
|
||||
<property name="name">m_ExportSetupButton</property>
|
||||
|
@ -989,34 +1014,9 @@
|
|||
<event name="OnUpdateUI"></event>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
<object class="sizeritem" expanded="1">
|
||||
<property name="border">5</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</property>
|
||||
<property name="flag">wxALL|wxALIGN_CENTER_HORIZONTAL|wxEXPAND</property>
|
||||
<property name="proportion">0</property>
|
||||
<object class="wxButton" expanded="1">
|
||||
<property name="bg"></property>
|
||||
|
@ -1068,7 +1068,7 @@
|
|||
</object>
|
||||
<object class="sizeritem" expanded="1">
|
||||
<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>
|
||||
<object class="wxButton" expanded="1">
|
||||
<property name="bg"></property>
|
||||
|
@ -1160,7 +1160,7 @@
|
|||
<property name="name">m_NetSortingOption</property>
|
||||
<property name="permission">protected</property>
|
||||
<property name="pos"></property>
|
||||
<property name="selection">1</property>
|
||||
<property name="selection">0</property>
|
||||
<property name="size"></property>
|
||||
<property name="style">wxRA_SPECIFY_COLS</property>
|
||||
<property name="subclass"></property>
|
||||
|
|
|
@ -47,12 +47,12 @@ class dialog_copper_zone_base : public wxDialog
|
|||
protected:
|
||||
enum
|
||||
{
|
||||
ID_RADIOBOX_GRID_SELECTION = 1000,
|
||||
ID_RADIOBOX_FILL_MODE_SELECTION = 1000,
|
||||
wxID_ARC_APPROX,
|
||||
wxID_PADS_IN_ZONE_OPTIONS,
|
||||
wxID_ANTIPAD_SIZE,
|
||||
wxID_COPPER_BRIDGE_VALUE,
|
||||
ID_RADIOBOX_OUTLINES_OPTION,
|
||||
wxID_ARC_APPROX,
|
||||
wxID_BUTTON_EXPORT,
|
||||
ID_NET_SORTING_OPTION,
|
||||
ID_TEXTCTRL_NETNAMES_FILTER,
|
||||
|
@ -60,7 +60,8 @@ class dialog_copper_zone_base : public wxDialog
|
|||
ID_LAYER_CHOICE,
|
||||
};
|
||||
|
||||
wxRadioBox* m_GridCtrl;
|
||||
wxRadioBox* m_FillModeCtrl;
|
||||
wxRadioBox* m_ArcApproximationOpt;
|
||||
wxRadioBox* m_PadInZoneOpt;
|
||||
wxStaticText* m_AntipadSizeText;
|
||||
wxTextCtrl* m_AntipadSizeValue;
|
||||
|
@ -69,14 +70,13 @@ class dialog_copper_zone_base : public wxDialog
|
|||
|
||||
wxRadioBox* m_OrientEdgesOpt;
|
||||
wxRadioBox* m_OutlineAppearanceCtrl;
|
||||
wxRadioBox* m_ArcApproximationOpt;
|
||||
wxCheckBox* m_ShowFilledAreasInSketchOpt;
|
||||
wxStaticText* m_ClearanceValueTitle;
|
||||
wxTextCtrl* m_ZoneClearanceCtrl;
|
||||
wxStaticText* m_MinThicknessValueTitle;
|
||||
wxTextCtrl* m_ZoneMinThicknessCtrl;
|
||||
wxButton* m_ExportSetupButton;
|
||||
|
||||
wxButton* m_ExportSetupButton;
|
||||
wxButton* m_OkButton;
|
||||
wxButton* m_ButtonCancel;
|
||||
|
||||
|
@ -98,7 +98,7 @@ class dialog_copper_zone_base : public wxDialog
|
|||
|
||||
|
||||
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();
|
||||
|
||||
};
|
||||
|
|
|
@ -748,6 +748,7 @@ void PlotFilledAreas( ZONE_CONTAINER * aZone, int aFormat )
|
|||
corners_count++;
|
||||
if( corner->end_contour )
|
||||
{ // 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 );
|
||||
if ( aZone->m_ZoneMinThickness > 0 )
|
||||
PlotPolygon( aFormat, corners_count, CornersBuffer, aZone->m_ZoneMinThickness );
|
||||
|
|
|
@ -2,6 +2,9 @@
|
|||
* Algos used to fill a zone defined by a polygon and a filling starting point
|
||||
*/
|
||||
|
||||
|
||||
#include <algorithm> // sort
|
||||
|
||||
#include "fctsys.h"
|
||||
#include "gr_basic.h"
|
||||
|
||||
|
@ -15,18 +18,14 @@
|
|||
#include "protos.h"
|
||||
|
||||
/* Local functions */
|
||||
static void Genere_Segments_Zone( WinEDA_PcbFrame* frame, wxDC* DC, int net_code, int layer );
|
||||
|
||||
/* 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
|
||||
* Build m_FilledPolysList data from real outlines (m_Poly)
|
||||
* in order to have drawable (and plottable) filled polygons
|
||||
|
@ -37,488 +36,188 @@ int ZONE_CONTAINER::BuildFilledPolysListData( BOARD * aPcb )
|
|||
* 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();
|
||||
|
||||
/* 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
|
||||
*/
|
||||
|
||||
if ( GetNumCorners( ) <= 2 ) // malformed zone. Kbool does not like it ...
|
||||
if( GetNumCorners() <= 2 ) // malformed zone. Kbool does not like it ...
|
||||
return 0;
|
||||
|
||||
m_Poly->MakeKboolPoly( -1, -1, NULL, true );
|
||||
int count = 0;
|
||||
while( m_Poly->GetKboolEngine()->StartPolygonGet() )
|
||||
{
|
||||
CPolyPt corner(0,0,false);
|
||||
CPolyPt corner( 0, 0, false );
|
||||
while( m_Poly->GetKboolEngine()->PolygonHasMorePoints() )
|
||||
{
|
||||
corner.x = (int)m_Poly->GetKboolEngine()->GetPolygonXPoint();
|
||||
corner.y = (int)m_Poly->GetKboolEngine()->GetPolygonYPoint();
|
||||
corner.x = (int) m_Poly->GetKboolEngine()->GetPolygonXPoint();
|
||||
corner.y = (int) m_Poly->GetKboolEngine()->GetPolygonYPoint();
|
||||
corner.end_contour = false;
|
||||
m_FilledPolysList.push_back(corner);
|
||||
count ++;
|
||||
m_FilledPolysList.push_back( corner );
|
||||
count++;
|
||||
}
|
||||
|
||||
corner.end_contour = true;
|
||||
m_FilledPolysList.pop_back();
|
||||
m_FilledPolysList.push_back(corner);
|
||||
m_FilledPolysList.push_back( corner );
|
||||
m_Poly->GetKboolEngine()->EndPolygonGet();
|
||||
}
|
||||
|
||||
m_Poly->FreeKboolEngine();
|
||||
|
||||
/* 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 );
|
||||
|
||||
if ( m_FillMode ) // if fill mode uses segments, create them:
|
||||
Fill_Zone_Areas_With_Segments( (WinEDA_PcbFrame*) aPcb->m_PcbFrame );
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
int ZONE_CONTAINER::Fill_Zone( WinEDA_PcbFrame* frame, wxDC* DC, bool verbose )
|
||||
/*****************************************************************************/
|
||||
|
||||
/** Function Fill_Zone()
|
||||
* Calculate the zone filling
|
||||
* The zone outline is a frontier, and can be complex (with holes)
|
||||
* The filling starts from starting points like pads, tracks.
|
||||
* @param frame = reference to the main frame
|
||||
* @param DC = current Device Context (can be NULL)
|
||||
* @param verbose = true to show error messages
|
||||
* @return error level (0 = no error)
|
||||
*/
|
||||
// Sort function to build filled zones
|
||||
static bool SortByXValues( const int& a, const int &b)
|
||||
{
|
||||
int ii, jj;
|
||||
int error_level = 0;
|
||||
int lp_tmp, lay_tmp_TOP, lay_tmp_BOTTOM;
|
||||
int save_isol = g_DesignSettings.m_TrackClearence;
|
||||
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
|
||||
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 )
|
||||
{
|
||||
DisplayBoard( frame->DrawPanel, DC );
|
||||
}
|
||||
// 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
|
||||
* (could be deleted by PlaceCells()) : */
|
||||
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 );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Filling the cells of the matrix (this is the zone building)*/
|
||||
ii = 1; jj = 1;
|
||||
while( ii )
|
||||
{
|
||||
msg.Printf( wxT( "%d" ), jj++ );
|
||||
Affiche_1_Parametre( frame, 50, wxT( "Iter." ), msg, CYAN );
|
||||
ii = Propagation( frame );
|
||||
}
|
||||
|
||||
if( Zone_Debug && DC )
|
||||
{
|
||||
DisplayBoard( frame->DrawPanel, DC );
|
||||
}
|
||||
|
||||
// replace obstacles into the matrix(pads)
|
||||
if( m_PadOption == THERMAL_PAD )
|
||||
PlaceCells( Pcb, g_HightLigth_NetCode, FORCE_PADS );
|
||||
|
||||
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;
|
||||
return a < b;
|
||||
}
|
||||
|
||||
/***********************************************************************************/
|
||||
int ZONE_CONTAINER::Fill_Zone_Areas_With_Segments( WinEDA_PcbFrame* aFrame )
|
||||
/***********************************************************************************/
|
||||
|
||||
/*******************************************************************************************/
|
||||
static void Genere_Segments_Zone( WinEDA_PcbFrame* frame, wxDC* DC, int net_code, int layer )
|
||||
/*******************************************************************************************/
|
||||
|
||||
/** Function Genere_Segments_Zone()
|
||||
* Create the zone segments from the routing matrix structure
|
||||
* 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 segmùents
|
||||
* @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
|
||||
/** 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 row, col;
|
||||
long current_cell, old_cell;
|
||||
int ux0 = 0, uy0 = 0, ux1 = 0, uy1 = 0;
|
||||
int Xmin = frame->m_Pcb->m_BoundaryBox.m_Pos.x;
|
||||
int Ymin = frame->m_Pcb->m_BoundaryBox.m_Pos.y;
|
||||
SEGZONE* pt_track;
|
||||
int nbsegm = 0;
|
||||
wxString msg;
|
||||
int ics, ice;
|
||||
int count = 0;
|
||||
std::vector <int> x_coordinates;
|
||||
bool error = false;
|
||||
|
||||
/* Create horizontal segments */
|
||||
Affiche_1_Parametre( frame, 64, wxT( "Segm H" ), wxT( "0" ), BROWN );
|
||||
for( row = 0; row < Nrows; row++ )
|
||||
int istart, iend; // index od the starting and the endif corner of one filled area in m_FilledPolysList
|
||||
|
||||
int margin = m_ZoneMinThickness * 2 / 10;
|
||||
margin = max (2, margin);
|
||||
int step = m_ZoneMinThickness - margin;
|
||||
step = max(step, 2);
|
||||
|
||||
// Read all filled areas in m_FilledPolysList
|
||||
istart = 0;
|
||||
int end_list = m_FilledPolysList.size()-1;
|
||||
for( int ic = 0; ic <= end_list; ic++ )
|
||||
{
|
||||
old_cell = 0;
|
||||
uy0 = uy1 = (row * g_GridRoutingSize) + Ymin;
|
||||
for( col = 0; col < Ncols; col++ )
|
||||
CPolyPt* corner = &m_FilledPolysList[ic];
|
||||
if ( corner->end_contour || (ic == end_list) )
|
||||
{
|
||||
current_cell = GetCell( row, col, BOTTOM ) & CELL_is_ZONE;
|
||||
if( current_cell ) /* ce point doit faire partie d'un segment */
|
||||
iend = ic;
|
||||
EDA_Rect rect = CalculateSubAreaBoundaryBox( istart, iend );
|
||||
|
||||
// Calculate the y limits of the zone
|
||||
int refy = rect.GetY();
|
||||
int endy = rect.GetBottom();
|
||||
|
||||
for( ; refy < endy; refy += step )
|
||||
{
|
||||
ux1 = (col * g_GridRoutingSize) + Xmin;
|
||||
if( old_cell == 0 )
|
||||
ux0 = ux1;
|
||||
// find all intersection points of an infinite line with polyline sides
|
||||
x_coordinates.clear();
|
||||
for( ics = istart, ice = iend; ics <= iend; ice = ics, ics++ )
|
||||
{
|
||||
if ( m_FilledPolysList[ice].utility )
|
||||
continue;
|
||||
int seg_startX = m_FilledPolysList[ics].x;
|
||||
int seg_startY = m_FilledPolysList[ics].y;
|
||||
int seg_endX = m_FilledPolysList[ice].x;
|
||||
int seg_endY = m_FilledPolysList[ice].y;
|
||||
|
||||
|
||||
/* 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
|
||||
if( ( seg_startY <= refy ) && (seg_endY <= refy ) )
|
||||
continue;
|
||||
|
||||
/* at this point refy is between seg_startY and seg_endY
|
||||
* see if an horizontal line at Y = refy is intersecting this segment
|
||||
*/
|
||||
// calculate the x position of the intersection of this segment and the infinite line
|
||||
// this is more easier if we move the X,Y axis origin to the segment start point:
|
||||
seg_endX -= seg_startX;
|
||||
seg_endY -= seg_startY;
|
||||
double newrefy = (double) (refy - seg_startY);
|
||||
double intersec_x;
|
||||
if ( seg_endY == 0 ) // horizontal segment on the same line: skip
|
||||
continue;
|
||||
// Now calculate the x intersection coordinate of the horizontal line at y = newrefy
|
||||
// and the segment from (0,0) to (seg_endX,seg_endY)
|
||||
// with the horizontal line at the new refy position
|
||||
// the line slope is slope = seg_endY/seg_endX; and inv_slope = seg_endX/seg_endY
|
||||
// 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)
|
||||
double inv_slope = (double)seg_endX / seg_endY;
|
||||
intersec_x = newrefy * inv_slope;
|
||||
x_coordinates.push_back((int) intersec_x + seg_startX);
|
||||
}
|
||||
|
||||
if( !current_cell || (col == Ncols - 1) ) /* peut etre fin d'un segment */
|
||||
// A line scan is finished: build list of segments
|
||||
|
||||
// Sort intersection points by increasing x value:
|
||||
// So 2 consecutive points are the ends of a segment
|
||||
sort( x_coordinates.begin(), x_coordinates.end(), SortByXValues );
|
||||
|
||||
// Create segments
|
||||
|
||||
if ( !error && ( x_coordinates.size() & 1 ) != 0 )
|
||||
{ // 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.
|
||||
wxString msg = wxT("Fill Zone: odd number of points at y = ");
|
||||
msg << refy;
|
||||
wxMessageBox(msg );
|
||||
error = true;
|
||||
}
|
||||
|
||||
if ( error ) break;
|
||||
int iimax = x_coordinates.size()-1;
|
||||
for (int ii = 0; ii < iimax; ii +=2 )
|
||||
{
|
||||
if( (old_cell) && (ux0 != ux1) )
|
||||
{
|
||||
/* un segment avait debute de longueur > 0 */
|
||||
pt_track = new SEGZONE( frame->m_Pcb );
|
||||
pt_track->SetLayer( layer );
|
||||
pt_track->SetNet( net_code );
|
||||
|
||||
pt_track->m_Width = g_GridRoutingSize;
|
||||
|
||||
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;
|
||||
wxPoint seg_start, seg_end;
|
||||
count++;
|
||||
seg_start.x = x_coordinates[ii];
|
||||
seg_start.y = refy;
|
||||
seg_end.x = x_coordinates[ii+1];
|
||||
seg_end.y = refy;
|
||||
SEGZONE* segment = new SEGZONE( aFrame->m_Pcb );
|
||||
segment->m_Start = seg_start;
|
||||
segment->m_End = seg_end;
|
||||
segment->SetNet( GetNet() );
|
||||
segment->m_TimeStamp = m_TimeStamp;
|
||||
segment->m_Width = m_ZoneMinThickness;
|
||||
segment->SetLayer( GetLayer() );
|
||||
aFrame->m_Pcb->Add( segment );
|
||||
}
|
||||
} //End examine segments in one area
|
||||
if ( error ) break;
|
||||
istart = iend + 1; // istart points the first corner of the next area
|
||||
} // End find one end of outline
|
||||
if ( error ) break;
|
||||
} // End examine all areas
|
||||
|
||||
msg.Printf( wxT( "%d" ), nbsegm );
|
||||
Affiche_1_Parametre( frame, -1, wxEmptyString, msg, BROWN );
|
||||
}
|
||||
|
||||
/* Create vertical segments */
|
||||
Affiche_1_Parametre( frame, 72, wxT( "Segm V" ), wxT( "0" ), BROWN );
|
||||
for( col = 0; col < Ncols; col++ )
|
||||
{
|
||||
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 );
|
||||
Affiche_1_Parametre( frame, -1, wxEmptyString, msg, BROWN );
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/********************************************/
|
||||
int Propagation( WinEDA_PcbFrame* frame )
|
||||
/********************************************/
|
||||
|
@ -658,133 +357,3 @@ int Propagation( WinEDA_PcbFrame* frame )
|
|||
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
|
|||
|
||||
int error_level = 0;
|
||||
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 );
|
||||
if ( DC )
|
||||
DrawPanel->Refresh();
|
||||
}
|
||||
else
|
||||
{
|
||||
g_GridRoutingSize = zone_container->m_GridFillValue;
|
||||
error_level = zone_container->Fill_Zone( this, DC, verbose );
|
||||
}
|
||||
|
||||
GetScreen()->SetModify();
|
||||
|
||||
|
|
|
@ -954,6 +954,8 @@ int ZONE_CONTAINER::CopyPolygonsFromBoolengineToFilledPolysList( Bool_Engine* aB
|
|||
corner.x = (int) aBoolengine->GetPolygonXPoint();
|
||||
corner.y = (int) aBoolengine->GetPolygonYPoint();
|
||||
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 );
|
||||
count++;
|
||||
}
|
||||
|
|
Binary file not shown.
|
@ -15,283 +15,22 @@ using namespace std;
|
|||
* At each crossing, the ray switches between inside and outside.
|
||||
* 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.
|
||||
* Take care to starting and ending points of segments outlines:
|
||||
* Only one must be used because the startingpoint of a segemnt is also the ending point of the previous.
|
||||
* And we do no use twice the same segment, so we do NOT use both starting and ending points of segments.
|
||||
* So we must use starting point but not ending point of each segment when calculating intersections
|
||||
* Take care to starting and ending points of segments outlines, when the horizontal line crosses a segment outline
|
||||
* exactly on an ending point:
|
||||
* Because the starting point of a segment is also the ending point of the previous, only one must be used.
|
||||
* 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.
|
||||
* the second version is GPL (currently used)
|
||||
* 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
|
||||
*/
|
||||
#define OUTSIDE false
|
||||
#define INSIDE true
|
||||
|
||||
bool TestPointInsidePolygon( std::vector <CPolyPt> aPolysList,
|
||||
int istart,
|
||||
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 )
|
||||
int istart, int iend, int refx, int refy )
|
||||
|
||||
/** Function TestPointInsidePolygon
|
||||
* test if a point is inside or outside a polygon.
|
||||
|
@ -304,9 +43,9 @@ bool TestPointInsidePolygon( std::vector <CPolyPt> aPolysList,
|
|||
* @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;
|
||||
bool inside = false;
|
||||
int count = 0;
|
||||
|
||||
// find all intersection points of line with polyline sides
|
||||
for( ics = istart, ice = iend; ics <= iend; ice = ics++ )
|
||||
|
@ -316,42 +55,39 @@ bool TestPointInsidePolygon( std::vector <CPolyPt> aPolysList,
|
|||
int seg_endX = aPolysList[ice].x;
|
||||
int seg_endY = aPolysList[ice].y;
|
||||
|
||||
/* 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
|
||||
/* 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 end on ref point: skip
|
||||
// Note: also we skip vertical segments
|
||||
// So points on vertical segments outlines are seen as outside the polygon
|
||||
// segment below ref point, or one of its ends has the same Y pos as the ref point: skip
|
||||
// So we eliminate one end point of 2 consecutive segments.
|
||||
// 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 ) )
|
||||
continue;
|
||||
|
||||
/* 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
|
||||
// this is more easier if we move the X,Y axis origin to the segment start point:
|
||||
seg_endX -= seg_startX;
|
||||
seg_endY -= seg_startY;
|
||||
double newrefx = (double)(refx - seg_startX);
|
||||
double newrefx = (double) (refx - seg_startX);
|
||||
double newrefy = (double) (refy - seg_startY);
|
||||
|
||||
// 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
|
||||
// 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
|
||||
// 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;
|
||||
if( newrefx < intersec_x ) // Intersection found with the semi-infinite line from -infinite to refx
|
||||
inside = not inside;
|
||||
if( newrefx < intersec_x ) // Intersection found with the semi-infinite line from refx to infinite
|
||||
count++;
|
||||
}
|
||||
|
||||
return inside;
|
||||
return count & 1 ? INSIDE : OUTSIDE;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue