More about copper zones filled without grid (by polygons)

This commit is contained in:
charras 2008-10-07 09:32:56 +00:00
parent 7d1170c41e
commit 3683ab745b
7 changed files with 3921 additions and 3640 deletions

View File

@ -5,6 +5,20 @@ Started 2007-June-11
Please add newer entries at the top, list the date and your name with
email address.
2008-oct-07 UPDATE Jean-Pierre Charras <jean-pierre.charras@inpg.fr>
================================================================================
+pcbnew:
More about copper zones filled without grid (by polygons)
Currently for eyes and tests only.
now working
thermal reliefs.
texts on copper zones.
To select this feature choose No Grid in zone grid filling.
Work in progress:
currently : not implemented:
Removing insulated copper islands.
trapezoidal pads
2008-Oct-6 UPDATE Dick Hollenbeck <dick@softplc.com>
================================================================================

Binary file not shown.

File diff suppressed because it is too large Load Diff

View File

@ -136,6 +136,11 @@ bool ZONE_CONTAINER::Save( FILE* aFile ) const
if( ret < 2 )
return false;
ret = fprintf( aFile, "ZOptions %d\n", m_GridFillValue);
if( ret < 1 )
return false;
// Save the corner list
for( item_pos = 0; item_pos < corners_count; item_pos++ )
{
@ -246,7 +251,17 @@ int ZONE_CONTAINER::ReadDescr( FILE* aFile, int* aLineNum )
}
}
}
if( strnicmp( Line, "ZClearance", 10 ) == 0 ) // aux info found
if( strnicmp( Line, "ZOptions", 8 ) == 0 ) // Options info found
{
int gridsize = 50;
text = Line + 8;
ret = sscanf( text, "%d", &gridsize );
if( ret < 1 )
return false;
else
m_GridFillValue = gridsize;
}
if( strnicmp( Line, "ZClearance", 10 ) == 0 ) // Clearence and pad options info found
{
int clearance = 200;
char padoption;
@ -738,6 +753,12 @@ void ZONE_CONTAINER::Display_Infos( WinEDA_DrawFrame* frame )
msg.Printf( wxT( "%d" ), m_Poly->corner.size() );
Affiche_1_Parametre( frame, text_pos, _( "Corners" ), msg, BLUE );
text_pos += 8;
if ( m_GridFillValue )
msg.Printf( wxT( "%d" ), m_GridFillValue );
else msg = _("No Grid");
Affiche_1_Parametre( frame, text_pos, _( "Fill Grid" ), msg, BROWN );
text_pos += 8;
msg.Printf( wxT( "%d" ), m_Poly->m_HatchLines.size() );
Affiche_1_Parametre( frame, text_pos, _( "Hatch lines" ), msg, BLUE );

View File

@ -258,6 +258,8 @@ void WinEDA_ZoneFrame::OnInitDialog( wxInitDialogEvent& event )
SetFont( *g_DialogFont );
SetFocus(); // Required under wxGTK if we want to demiss the dialog with the ESC key
wxString title = _( "Zone clearance value:" ) + ReturnUnitSymbol( g_UnitMetric );
m_ClearanceValueTitle->SetLabel( title );
@ -277,15 +279,22 @@ void WinEDA_ZoneFrame::OnInitDialog( wxInitDialogEvent& event )
static const int GridList[4] = { 25, 50, 100, 250 };
int selection = 0;
int grid_routing = g_GridRoutingSize;
if( m_Zone_Container )
grid_routing = m_Zone_Container->m_GridFillValue;
for( unsigned ii = 0; ii < 4; ii++ )
{
wxString msg = ReturnStringFromValue( g_UnitMetric,
GridList[ii],
m_Parent->m_InternalUnits );
m_GridCtrl->SetString( ii, msg );
if( g_GridRoutingSize == GridList[ii] )
if( grid_routing == GridList[ii] )
selection = ii;
}
if( grid_routing == 0 ) // No Grid: fill with polygons
selection = 4;
m_GridCtrl->SetSelection( selection );
@ -536,9 +545,9 @@ bool WinEDA_ZoneFrame::AcceptOptions(bool aPromptForErrors)
g_GridRoutingSize = 250;
break;
case 4:
g_GridRoutingSize = 0;
wxMessageBox( wxT(
"You are using No grid for filling zones\nThis is currently in development and for tests only.\n Do not use for production"));
g_GridRoutingSize = 0;
break;
}

View File

@ -42,6 +42,9 @@ int ZONE_CONTAINER::Fill_Zone( WinEDA_PcbFrame* frame, wxDC* DC, bool verbose )
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, g_DesignSettings.m_ZoneClearence);
@ -59,8 +62,6 @@ int ZONE_CONTAINER::Fill_Zone( WinEDA_PcbFrame* frame, wxDC* DC, bool verbose )
// calculate the fixed step of the routing matrix as 25 mils or more
E_scale = g_GridRoutingSize / 25;
if( g_GridRoutingSize < 1 )
g_GridRoutingSize = 1;
// calculate the Ncols and Nrows, size of the routing matrix
ComputeMatriceSize( frame, g_GridRoutingSize );

View File

@ -13,15 +13,22 @@ using namespace std;
#include "PolyLine.h"
// Local Functions:
void AddTrackWithClearancePolygon( Bool_Engine* aBooleng,
TRACK& aTrack, int aClearanceValue );
void AddPadWithClearancePolygon( Bool_Engine* aBooleng,
D_PAD& aPad, int aClearanceValue,
bool bThermal, int spoke_w );
void AddPadWithClearancePolygon( Bool_Engine* aBooleng, D_PAD& aPad, int aClearanceValue );
void AddThermalReliefPadPolygon( Bool_Engine* aBooleng,
D_PAD& aPad,
int aThermalGap,
int aCopperTickness );
void AddRoundedEndsSegmentPolygon( Bool_Engine* aBooleng,
wxPoint aStart, wxPoint aEnd,
int aWidth );
void AddTextBoxWithClearancePolygon( Bool_Engine* aBooleng,
TEXTE_PCB* aText, int aClearanceValue );
// Local Variables:
/* how many segments are used to create a polygon from a circle: */
static int s_CircleToSegmentsCount = 16;
@ -82,10 +89,26 @@ void ZONE_CONTAINER::AddClearanceAreasPolygonsToPolysList( BOARD* aPcb )
{
if( !pad->IsOnLayer( GetLayer() ) )
continue;
if ( pad->GetNet() == GetNet() )
if( pad->GetNet() != GetNet() )
{
AddPadWithClearancePolygon( booleng, *pad, m_ZoneClearance );
continue;
AddPadWithClearancePolygon( booleng, *pad, m_ZoneClearance,
false, 0 );
}
switch( m_PadOption )
{
case PAD_NOT_IN_ZONE:
AddPadWithClearancePolygon( booleng, *pad, m_ZoneClearance );
break;
case THERMAL_PAD:
AddThermalReliefPadPolygon( booleng, *pad, 100, 100 );
break;
case PAD_IN_ZONE:
break;
}
}
}
@ -97,7 +120,7 @@ void ZONE_CONTAINER::AddClearanceAreasPolygonsToPolysList( BOARD* aPcb )
{
if( !track->IsOnLayer( GetLayer() ) )
continue;
if ( track->GetNet() == GetNet() )
if( track->GetNet() == GetNet() )
continue;
AddTrackWithClearancePolygon( booleng, *track, m_ZoneClearance );
}
@ -105,16 +128,22 @@ void ZONE_CONTAINER::AddClearanceAreasPolygonsToPolysList( BOARD* aPcb )
// Draw graphic items (copper texts) and board edges
for( BOARD_ITEM* item = aPcb->m_Drawings; item; item = item->Next() )
{
if( item->GetLayer() != GetLayer() && item->GetLayer() != EDGE_N )
continue;
switch( item->Type() )
{
case TYPEDRAWSEGMENT:
// TODO: add segment
AddRoundedEndsSegmentPolygon( booleng,
( (DRAWSEGMENT*) item )->m_Start,
( (DRAWSEGMENT*) item )->m_End,
( (DRAWSEGMENT*) item )->m_Width + (2 * m_ZoneClearance) );
break;
case TYPETEXTE:
// TODO: add rectangular area
if( ( (TEXTE_PCB*) item )->GetLength() == 0 )
break;
AddTextBoxWithClearancePolygon( booleng, (TEXTE_PCB*) item, m_ZoneClearance );
break;
default:
@ -153,44 +182,39 @@ void ZONE_CONTAINER::AddClearanceAreasPolygonsToPolysList( BOARD* aPcb )
* Convert arcs and circles to multiple straight lines
*/
void AddPadWithClearancePolygon( Bool_Engine* aBooleng,
D_PAD& aPad, int aClearanceValue,
bool bThermal, int spoke_w )
D_PAD& aPad, int aClearanceValue )
{
if( aBooleng->StartPolygonAdd( GROUP_B ) == 0 )
return;
wxPoint corner_position;
int ii, angle;
int dx = (aPad.m_Size.x / 2) + aClearanceValue;
int dy = (aPad.m_Size.y / 2) + aClearanceValue;
int delta = 3600 / s_CircleToSegmentsCount; // rot angle in 0.1 degree
wxPoint PadShapePos = aPad.ReturnShapePos(); /* Note: for pad having a shape offset,
* the pad position is NOT the shape position */
if( !bThermal )
{
switch( aPad.m_PadShape )
{
case PAD_CIRCLE:
if( aBooleng->StartPolygonAdd( GROUP_B ) )
{
for( ii = 0; ii < s_CircleToSegmentsCount; ii++ )
{
corner_position = wxPoint( dx, 0 );
angle = ii * delta;
RotatePoint( &corner_position, angle );
corner_position += aPad.ReturnShapePos();
corner_position += PadShapePos;
aBooleng->AddPoint( corner_position.x, corner_position.y );
}
aBooleng->EndPolygonAdd();
}
break;
case PAD_OVAL:
case PAD_RECT:
if( aBooleng->StartPolygonAdd( GROUP_B ) )
{
angle = aPad.m_Orient;
corner_position = wxPoint( -dx, -dy );
RotatePoint( &corner_position, angle );
corner_position += aPad.ReturnShapePos();
corner_position += PadShapePos;
aBooleng->AddPoint( corner_position.x, corner_position.y );
corner_position = wxPoint( -dx, +dy );
@ -200,108 +224,205 @@ void AddPadWithClearancePolygon( Bool_Engine* aBooleng,
corner_position = wxPoint( +dx, +dy );
RotatePoint( &corner_position, angle );
corner_position += aPad.ReturnShapePos();
corner_position += PadShapePos;
aBooleng->AddPoint( corner_position.x, corner_position.y );
corner_position = wxPoint( +dx, -dy );
RotatePoint( &corner_position, angle );
corner_position += aPad.ReturnShapePos();
corner_position += PadShapePos;
aBooleng->AddPoint( corner_position.x, corner_position.y );
break;
}
aBooleng->EndPolygonAdd();
}
/** function AddThermalReliefPadPolygon
* Add holes around a pad to create a thermal relief
* copper tickness is min (dx/2, aCopperWitdh) or min (dy/2, aCopperWitdh)
* gap is aThermalGap
*/
/* thermal reliefs are created as 4 polygons.
* each corner of a polygon if calculated for a pad at position 0, 0, orient 0,
* and then moved and rotated acroding to the pad position and orientation
*/
void AddThermalReliefPadPolygon( Bool_Engine* aBooleng,
D_PAD& aPad,
int aThermalGap,
int aCopperTickness )
{
wxPoint corner, corner_start, corner_end;
wxPoint PadShapePos = aPad.ReturnShapePos(); /* Note: for pad having a shape offset,
* the pad position is NOT the shape position */
int angle = 0;
wxSize copper_tickness;
int dx = aPad.m_Size.x / 2;
int dy = aPad.m_Size.y / 2;
int delta = 3600 / s_CircleToSegmentsCount; // rot angle in 0.1 degree
copper_tickness.x = min( dx, aCopperTickness );
copper_tickness.y = min( dy, aCopperTickness );
switch( aPad.m_PadShape )
{
case PAD_CIRCLE: // Add 4 similar holes
{
// Build the hole pattern, for the hole in the X >0, Y > 0 plane:
std::vector <int> corners_buffer;
// calculate the starting point of the inner arc
corner.y = copper_tickness.x / 2; // note dx is the pad radius, so copper_tickness.x is the value to use
double dtmp = ( (double) dx * dx ) - ( (double) corner.y * corner.y );
corner.x = (int) sqrt( dtmp );
corner_start = corner;
// calculate the ending point of the inner arc
corner_end.x = corner.y;
corner_end.y = corner.x;
// calculate intermediate points (y coordinate from corner.y to corner_end.y)
while( (corner.y < corner_end.y) && (corner.x > corner_end.x) )
{
corners_buffer.push_back( corner.x );
corners_buffer.push_back( corner.y );
RotatePoint( &corner, -delta );
}
corners_buffer.push_back( corner_end.x );
corners_buffer.push_back( corner_end.y );
// calculate the starting point of the outter arc
dx += aThermalGap; // The radius of the outter arc is dx = pad radius + aThermalGap
corner.x = corner_end.x;
dtmp = ( (double) dx * dx ) - ( (double) corner.x * corner.x );
corner.y = (int) sqrt( dtmp );
// calculate the ending point of the outter arc
corner_end.x = corner.y;
corner_end.y = corner_start.y;
// calculate intermediate points (y coordinate from corner.y to corner_end.y
while( (corner.y > corner_end.y) && (corner.x < corner_end.x))
{
corners_buffer.push_back( corner.x );
corners_buffer.push_back( corner.y );
RotatePoint( &corner, delta );
}
corners_buffer.push_back( corner_end.x );
corners_buffer.push_back( corner_end.y );
// Now, add the 4 holes ( each is the pattern, rotated by 0, 90, 180 and 270 deg
angle = 0;
for( unsigned ihole = 0; ihole < 4; ihole++ )
{
if( aBooleng->StartPolygonAdd( GROUP_B ) )
{
for( unsigned ii = 0; ii < corners_buffer.size(); ii += 2 )
{
corner = wxPoint( corners_buffer[ii], corners_buffer[ii+1] );
RotatePoint( &corner, angle );
corner += PadShapePos;
aBooleng->AddPoint( corner.x, corner.y );
}
aBooleng->EndPolygonAdd();
angle += 900; // Note: angle in in 0.1 deg.
}
}
}
break;
case PAD_OVAL:
case PAD_RECT: // draw 4 Holes
{
// First, create an hole like:
// 1 ------- 2
// 0 ----- |
// 5 | |
// | |
// 4 | | 3
wxPoint corners_hole[6]; // buffer for 6 corners
// Create 1 hole, for a pad centered at0,0, orient 0
// Calculate coordinates for corner 0 to corner 5:
corners_hole[0] = wxPoint( (copper_tickness.x / 2), -dy );
corners_hole[1] = wxPoint( (copper_tickness.x / 2), -dy - aThermalGap );
corners_hole[2] = wxPoint( dx + aThermalGap, -dy - aThermalGap );
corners_hole[3] = wxPoint( dx + aThermalGap, -(copper_tickness.y / 2) );
corners_hole[4] = wxPoint( dx, -(copper_tickness.y / 2) );
corners_hole[5] = wxPoint( dx, -dy );
/* Create 2 holes, rotated by pad rotation.
* corners_hole[6] is the hole 1
* hole 3 is the same as hole 1, rotated 180 deg
* 4 ------ 1
* | |
* | |
* | |
* | |
* 3 ------ 2
*/
angle = aPad.m_Orient;
for( int irect = 0; irect < 2; irect++ )
{
if( aBooleng->StartPolygonAdd( GROUP_B ) )
{
for( int ic = 0; ic < 6; ic++ )
{
wxPoint cpos = corners_hole[ic];
RotatePoint( &cpos, angle );
cpos += PadShapePos;
aBooleng->AddPoint( cpos.x, cpos.y );
}
aBooleng->EndPolygonAdd();
angle += 1800; // this is calculate hole 3
if( angle >= 3600 )
angle -= 3600;
}
}
// Create a holes, like:
// -------
// | -----
// | |
// | |
// | |
// this is the mirrored of the previous hole
corners_hole[0].x = -corners_hole[0].x;
corners_hole[1].x = -corners_hole[1].x;
corners_hole[2].x = -corners_hole[2].x;
corners_hole[3].x = -corners_hole[3].x;
corners_hole[4].x = -corners_hole[4].x;
corners_hole[5].x = -corners_hole[5].x;
// Now add corner 4 and 2 (2 is the corner 4 rotated by 180 deg
angle = aPad.m_Orient;
for( int irect = 0; irect < 2; irect++ )
{
if( aBooleng->StartPolygonAdd( GROUP_B ) )
{
for( int ic = 0; ic < 6; ic++ )
{
wxPoint cpos = corners_hole[ic];
RotatePoint( &cpos, angle );
cpos += PadShapePos;
aBooleng->AddPoint( cpos.x, cpos.y );
}
aBooleng->EndPolygonAdd();
angle += 1800;
if( angle >= 3600 )
angle -= 3600;
}
}
}
break;
}
}
else
{
// thermal relief (from FreePCB: must be converted to pcbnew data)
#if 0
if( type == PAD_ROUND || (type == PAD_NONE && hole_w > 0) )
{
// draw 4 "wedges"
double r = max( w / 2 + fill_clearance, hole_w / 2 + hole_clearance );
double start_angle = asin( spoke_w / (2.0 * r) );
double th1, th2, corner_x, corner_y;
th1 = th2 = corner_x = corner_y = 0; // gcc warning fix
for( int i = 0; i<4; i++ )
{
if( i == 0 )
{
corner_x = spoke_w / 2;
corner_y = spoke_w / 2;
th1 = start_angle;
th2 = pi / 2.0 - start_angle;
}
else if( i == 1 )
{
corner_x = -spoke_w / 2;
corner_y = spoke_w / 2;
th1 = pi / 2.0 + start_angle;
th2 = pi - start_angle;
}
else if( i == 2 )
{
corner_x = -spoke_w / 2;
corner_y = -spoke_w / 2;
th1 = -pi + start_angle;
th2 = -pi / 2.0 - start_angle;
}
else if( i == 3 )
{
corner_x = spoke_w / 2;
corner_y = -spoke_w / 2;
th1 = -pi / 2.0 + start_angle;
th2 = -start_angle;
}
AppendCorner( to_int( x + corner_x ), to_int( y + corner_y ), STRAIGHT, 0 );
AppendCorner( to_int( x + r * cos( th1 ) ), to_int( y + r * sin(
th1 ) ), STRAIGHT, 0 );
AppendCorner( to_int( x + r * cos( th2 ) ), to_int( y + r * sin(
th2 ) ), ARC_CCW, 0 );
Close( STRAIGHT );
}
}
else if( type == PAD_SQUARE || type == PAD_RECT
|| type == PAD_RRECT || type == PAD_OVAL )
{
// draw 4 rectangles
int xL = x - dx;
int xR = x - spoke_w / 2;
int yB = y - dy;
int yT = y - spoke_w / 2;
AppendCorner( xL, yB, STRAIGHT, 0 );
AppendCorner( xR, yB, STRAIGHT, 0 );
AppendCorner( xR, yT, STRAIGHT, 0 );
AppendCorner( xL, yT, STRAIGHT, 0 );
Close( STRAIGHT );
xL = x + spoke_w / 2;
xR = x + dx;
AppendCorner( xL, yB, STRAIGHT, 0 );
AppendCorner( xR, yB, STRAIGHT, 0 );
AppendCorner( xR, yT, STRAIGHT, 0 );
AppendCorner( xL, yT, STRAIGHT, 0 );
Close( STRAIGHT );
xL = x - dx;
xR = x - spoke_w / 2;
yB = y + spoke_w / 2;
yT = y + dy;
AppendCorner( xL, yB, STRAIGHT, 0 );
AppendCorner( xR, yB, STRAIGHT, 0 );
AppendCorner( xR, yT, STRAIGHT, 0 );
AppendCorner( xL, yT, STRAIGHT, 0 );
Close( STRAIGHT );
xL = x + spoke_w / 2;
xR = x + dx;
AppendCorner( xL, yB, STRAIGHT, 0 );
AppendCorner( xR, yB, STRAIGHT, 0 );
AppendCorner( xR, yT, STRAIGHT, 0 );
AppendCorner( xL, yT, STRAIGHT, 0 );
Close( STRAIGHT );
}
#endif
}
return;
}
@ -414,5 +535,49 @@ void AddRoundedEndsSegmentPolygon( Bool_Engine* aBooleng,
corner += startp;
aBooleng->AddPoint( corner.x, corner.y );
}
aBooleng->EndPolygonAdd();
}
/** function AddTextBoxWithClearancePolygon
* creates a polygon containing the text and add it to bool engine
*/
void AddTextBoxWithClearancePolygon( Bool_Engine* aBooleng,
TEXTE_PCB* aText, int aClearanceValue )
{
int corners[8]; // Buffer of coordinates
int ii;
int dx = aText->Pitch() * aText->GetLength();
int dy = aText->m_Size.y + aText->m_Width;
/* Creates bounding box (rectangle) for an horizontal text */
dx /= 2; dy /= 2; /* dx et dy = demi dimensionx X et Y */
dx += aClearanceValue;
dy += aClearanceValue;
corners[0] = aText->m_Pos.x - dx;
corners[1] = aText->m_Pos.y - dy;
corners[2] = aText->m_Pos.x + dx;
corners[3] = aText->m_Pos.y - dy;
corners[4] = aText->m_Pos.x + dx;
corners[5] = aText->m_Pos.y + dy;
corners[6] = aText->m_Pos.x - dx;
corners[7] = aText->m_Pos.y + dy;
// Rotate rectangle
RotatePoint( &corners[0], &corners[1], aText->m_Pos.x, aText->m_Pos.y, aText->m_Orient );
RotatePoint( &corners[2], &corners[3], aText->m_Pos.x, aText->m_Pos.y, aText->m_Orient );
RotatePoint( &corners[4], &corners[5], aText->m_Pos.x, aText->m_Pos.y, aText->m_Orient );
RotatePoint( &corners[6], &corners[7], aText->m_Pos.x, aText->m_Pos.y, aText->m_Orient );
if( aBooleng->StartPolygonAdd( GROUP_B ) )
{
for( ii = 0; ii < 8; ii += 2 )
{
aBooleng->AddPoint( corners[ii], corners[ii + 1] );
}
aBooleng->EndPolygonAdd();
}
}