More about copper zones filled without grid (by polygons)
This commit is contained in:
parent
7d1170c41e
commit
3683ab745b
|
@ -5,6 +5,20 @@ Started 2007-June-11
|
||||||
Please add newer entries at the top, list the date and your name with
|
Please add newer entries at the top, list the date and your name with
|
||||||
email address.
|
email address.
|
||||||
|
|
||||||
|
2008-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>
|
2008-Oct-6 UPDATE Dick Hollenbeck <dick@softplc.com>
|
||||||
================================================================================
|
================================================================================
|
||||||
|
|
Binary file not shown.
7075
internat/fr/kicad.po
7075
internat/fr/kicad.po
File diff suppressed because it is too large
Load Diff
|
@ -136,6 +136,11 @@ bool ZONE_CONTAINER::Save( FILE* aFile ) const
|
||||||
if( ret < 2 )
|
if( ret < 2 )
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
ret = fprintf( aFile, "ZOptions %d\n", m_GridFillValue);
|
||||||
|
if( ret < 1 )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
|
||||||
// Save the corner list
|
// Save the corner list
|
||||||
for( item_pos = 0; item_pos < corners_count; item_pos++ )
|
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;
|
int clearance = 200;
|
||||||
char padoption;
|
char padoption;
|
||||||
|
@ -738,6 +753,12 @@ void ZONE_CONTAINER::Display_Infos( WinEDA_DrawFrame* frame )
|
||||||
msg.Printf( wxT( "%d" ), m_Poly->corner.size() );
|
msg.Printf( wxT( "%d" ), m_Poly->corner.size() );
|
||||||
Affiche_1_Parametre( frame, text_pos, _( "Corners" ), msg, BLUE );
|
Affiche_1_Parametre( frame, text_pos, _( "Corners" ), msg, BLUE );
|
||||||
|
|
||||||
|
text_pos += 8;
|
||||||
|
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;
|
text_pos += 8;
|
||||||
msg.Printf( wxT( "%d" ), m_Poly->m_HatchLines.size() );
|
msg.Printf( wxT( "%d" ), m_Poly->m_HatchLines.size() );
|
||||||
Affiche_1_Parametre( frame, text_pos, _( "Hatch lines" ), msg, BLUE );
|
Affiche_1_Parametre( frame, text_pos, _( "Hatch lines" ), msg, BLUE );
|
||||||
|
|
|
@ -258,6 +258,8 @@ void WinEDA_ZoneFrame::OnInitDialog( wxInitDialogEvent& event )
|
||||||
|
|
||||||
SetFont( *g_DialogFont );
|
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 );
|
wxString title = _( "Zone clearance value:" ) + ReturnUnitSymbol( g_UnitMetric );
|
||||||
m_ClearanceValueTitle->SetLabel( title );
|
m_ClearanceValueTitle->SetLabel( title );
|
||||||
|
|
||||||
|
@ -277,15 +279,22 @@ void WinEDA_ZoneFrame::OnInitDialog( wxInitDialogEvent& event )
|
||||||
static const int GridList[4] = { 25, 50, 100, 250 };
|
static const int GridList[4] = { 25, 50, 100, 250 };
|
||||||
int selection = 0;
|
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++ )
|
for( unsigned ii = 0; ii < 4; ii++ )
|
||||||
{
|
{
|
||||||
wxString msg = ReturnStringFromValue( g_UnitMetric,
|
wxString msg = ReturnStringFromValue( g_UnitMetric,
|
||||||
GridList[ii],
|
GridList[ii],
|
||||||
m_Parent->m_InternalUnits );
|
m_Parent->m_InternalUnits );
|
||||||
m_GridCtrl->SetString( ii, msg );
|
m_GridCtrl->SetString( ii, msg );
|
||||||
if( g_GridRoutingSize == GridList[ii] )
|
if( grid_routing == GridList[ii] )
|
||||||
selection = ii;
|
selection = ii;
|
||||||
}
|
}
|
||||||
|
if( grid_routing == 0 ) // No Grid: fill with polygons
|
||||||
|
selection = 4;
|
||||||
|
|
||||||
m_GridCtrl->SetSelection( selection );
|
m_GridCtrl->SetSelection( selection );
|
||||||
|
|
||||||
|
@ -536,9 +545,9 @@ bool WinEDA_ZoneFrame::AcceptOptions(bool aPromptForErrors)
|
||||||
g_GridRoutingSize = 250;
|
g_GridRoutingSize = 250;
|
||||||
break;
|
break;
|
||||||
case 4:
|
case 4:
|
||||||
|
g_GridRoutingSize = 0;
|
||||||
wxMessageBox( wxT(
|
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"));
|
"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;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -42,6 +42,9 @@ int ZONE_CONTAINER::Fill_Zone( WinEDA_PcbFrame* frame, wxDC* DC, bool verbose )
|
||||||
wxString msg;
|
wxString msg;
|
||||||
BOARD* Pcb = frame->m_Pcb;
|
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
|
// 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);
|
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
|
// calculate the fixed step of the routing matrix as 25 mils or more
|
||||||
E_scale = g_GridRoutingSize / 25;
|
E_scale = g_GridRoutingSize / 25;
|
||||||
|
|
||||||
if( g_GridRoutingSize < 1 )
|
|
||||||
g_GridRoutingSize = 1;
|
|
||||||
|
|
||||||
// calculate the Ncols and Nrows, size of the routing matrix
|
// calculate the Ncols and Nrows, size of the routing matrix
|
||||||
ComputeMatriceSize( frame, g_GridRoutingSize );
|
ComputeMatriceSize( frame, g_GridRoutingSize );
|
||||||
|
|
|
@ -13,15 +13,22 @@ using namespace std;
|
||||||
|
|
||||||
#include "PolyLine.h"
|
#include "PolyLine.h"
|
||||||
|
|
||||||
|
// Local Functions:
|
||||||
void AddTrackWithClearancePolygon( Bool_Engine* aBooleng,
|
void AddTrackWithClearancePolygon( Bool_Engine* aBooleng,
|
||||||
TRACK& aTrack, int aClearanceValue );
|
TRACK& aTrack, int aClearanceValue );
|
||||||
void AddPadWithClearancePolygon( Bool_Engine* aBooleng,
|
void AddPadWithClearancePolygon( Bool_Engine* aBooleng, D_PAD& aPad, int aClearanceValue );
|
||||||
D_PAD& aPad, int aClearanceValue,
|
void AddThermalReliefPadPolygon( Bool_Engine* aBooleng,
|
||||||
bool bThermal, int spoke_w );
|
D_PAD& aPad,
|
||||||
|
int aThermalGap,
|
||||||
|
int aCopperTickness );
|
||||||
void AddRoundedEndsSegmentPolygon( Bool_Engine* aBooleng,
|
void AddRoundedEndsSegmentPolygon( Bool_Engine* aBooleng,
|
||||||
wxPoint aStart, wxPoint aEnd,
|
wxPoint aStart, wxPoint aEnd,
|
||||||
int aWidth );
|
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: */
|
/* how many segments are used to create a polygon from a circle: */
|
||||||
static int s_CircleToSegmentsCount = 16;
|
static int s_CircleToSegmentsCount = 16;
|
||||||
|
|
||||||
|
@ -82,10 +89,26 @@ void ZONE_CONTAINER::AddClearanceAreasPolygonsToPolysList( BOARD* aPcb )
|
||||||
{
|
{
|
||||||
if( !pad->IsOnLayer( GetLayer() ) )
|
if( !pad->IsOnLayer( GetLayer() ) )
|
||||||
continue;
|
continue;
|
||||||
if ( pad->GetNet() == GetNet() )
|
|
||||||
|
if( pad->GetNet() != GetNet() )
|
||||||
|
{
|
||||||
|
AddPadWithClearancePolygon( booleng, *pad, m_ZoneClearance );
|
||||||
continue;
|
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() ) )
|
if( !track->IsOnLayer( GetLayer() ) )
|
||||||
continue;
|
continue;
|
||||||
if ( track->GetNet() == GetNet() )
|
if( track->GetNet() == GetNet() )
|
||||||
continue;
|
continue;
|
||||||
AddTrackWithClearancePolygon( booleng, *track, m_ZoneClearance );
|
AddTrackWithClearancePolygon( booleng, *track, m_ZoneClearance );
|
||||||
}
|
}
|
||||||
|
@ -105,16 +128,22 @@ void ZONE_CONTAINER::AddClearanceAreasPolygonsToPolysList( BOARD* aPcb )
|
||||||
// Draw graphic items (copper texts) and board edges
|
// Draw graphic items (copper texts) and board edges
|
||||||
for( BOARD_ITEM* item = aPcb->m_Drawings; item; item = item->Next() )
|
for( BOARD_ITEM* item = aPcb->m_Drawings; item; item = item->Next() )
|
||||||
{
|
{
|
||||||
|
if( item->GetLayer() != GetLayer() && item->GetLayer() != EDGE_N )
|
||||||
|
continue;
|
||||||
|
|
||||||
switch( item->Type() )
|
switch( item->Type() )
|
||||||
{
|
{
|
||||||
case TYPEDRAWSEGMENT:
|
case TYPEDRAWSEGMENT:
|
||||||
|
AddRoundedEndsSegmentPolygon( booleng,
|
||||||
// TODO: add segment
|
( (DRAWSEGMENT*) item )->m_Start,
|
||||||
|
( (DRAWSEGMENT*) item )->m_End,
|
||||||
|
( (DRAWSEGMENT*) item )->m_Width + (2 * m_ZoneClearance) );
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TYPETEXTE:
|
case TYPETEXTE:
|
||||||
|
if( ( (TEXTE_PCB*) item )->GetLength() == 0 )
|
||||||
// TODO: add rectangular area
|
break;
|
||||||
|
AddTextBoxWithClearancePolygon( booleng, (TEXTE_PCB*) item, m_ZoneClearance );
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -153,44 +182,39 @@ void ZONE_CONTAINER::AddClearanceAreasPolygonsToPolysList( BOARD* aPcb )
|
||||||
* Convert arcs and circles to multiple straight lines
|
* Convert arcs and circles to multiple straight lines
|
||||||
*/
|
*/
|
||||||
void AddPadWithClearancePolygon( Bool_Engine* aBooleng,
|
void AddPadWithClearancePolygon( Bool_Engine* aBooleng,
|
||||||
D_PAD& aPad, int aClearanceValue,
|
D_PAD& aPad, int aClearanceValue )
|
||||||
bool bThermal, int spoke_w )
|
|
||||||
{
|
{
|
||||||
|
if( aBooleng->StartPolygonAdd( GROUP_B ) == 0 )
|
||||||
|
return;
|
||||||
wxPoint corner_position;
|
wxPoint corner_position;
|
||||||
int ii, angle;
|
int ii, angle;
|
||||||
int dx = (aPad.m_Size.x / 2) + aClearanceValue;
|
int dx = (aPad.m_Size.x / 2) + aClearanceValue;
|
||||||
int dy = (aPad.m_Size.y / 2) + aClearanceValue;
|
int dy = (aPad.m_Size.y / 2) + aClearanceValue;
|
||||||
|
|
||||||
int delta = 3600 / s_CircleToSegmentsCount; // rot angle in 0.1 degree
|
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 )
|
switch( aPad.m_PadShape )
|
||||||
{
|
{
|
||||||
case PAD_CIRCLE:
|
case PAD_CIRCLE:
|
||||||
if( aBooleng->StartPolygonAdd( GROUP_B ) )
|
|
||||||
{
|
|
||||||
for( ii = 0; ii < s_CircleToSegmentsCount; ii++ )
|
for( ii = 0; ii < s_CircleToSegmentsCount; ii++ )
|
||||||
{
|
{
|
||||||
corner_position = wxPoint( dx, 0 );
|
corner_position = wxPoint( dx, 0 );
|
||||||
angle = ii * delta;
|
angle = ii * delta;
|
||||||
RotatePoint( &corner_position, angle );
|
RotatePoint( &corner_position, angle );
|
||||||
corner_position += aPad.ReturnShapePos();
|
corner_position += PadShapePos;
|
||||||
aBooleng->AddPoint( corner_position.x, corner_position.y );
|
aBooleng->AddPoint( corner_position.x, corner_position.y );
|
||||||
}
|
}
|
||||||
|
|
||||||
aBooleng->EndPolygonAdd();
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PAD_OVAL:
|
case PAD_OVAL:
|
||||||
case PAD_RECT:
|
case PAD_RECT:
|
||||||
if( aBooleng->StartPolygonAdd( GROUP_B ) )
|
|
||||||
{
|
|
||||||
angle = aPad.m_Orient;
|
angle = aPad.m_Orient;
|
||||||
corner_position = wxPoint( -dx, -dy );
|
corner_position = wxPoint( -dx, -dy );
|
||||||
RotatePoint( &corner_position, angle );
|
RotatePoint( &corner_position, angle );
|
||||||
corner_position += aPad.ReturnShapePos();
|
corner_position += PadShapePos;
|
||||||
aBooleng->AddPoint( corner_position.x, corner_position.y );
|
aBooleng->AddPoint( corner_position.x, corner_position.y );
|
||||||
|
|
||||||
corner_position = wxPoint( -dx, +dy );
|
corner_position = wxPoint( -dx, +dy );
|
||||||
|
@ -200,108 +224,205 @@ void AddPadWithClearancePolygon( Bool_Engine* aBooleng,
|
||||||
|
|
||||||
corner_position = wxPoint( +dx, +dy );
|
corner_position = wxPoint( +dx, +dy );
|
||||||
RotatePoint( &corner_position, angle );
|
RotatePoint( &corner_position, angle );
|
||||||
corner_position += aPad.ReturnShapePos();
|
corner_position += PadShapePos;
|
||||||
aBooleng->AddPoint( corner_position.x, corner_position.y );
|
aBooleng->AddPoint( corner_position.x, corner_position.y );
|
||||||
|
|
||||||
corner_position = wxPoint( +dx, -dy );
|
corner_position = wxPoint( +dx, -dy );
|
||||||
RotatePoint( &corner_position, angle );
|
RotatePoint( &corner_position, angle );
|
||||||
corner_position += aPad.ReturnShapePos();
|
corner_position += PadShapePos;
|
||||||
aBooleng->AddPoint( corner_position.x, corner_position.y );
|
aBooleng->AddPoint( corner_position.x, corner_position.y );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
aBooleng->EndPolygonAdd();
|
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;
|
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;
|
corner += startp;
|
||||||
aBooleng->AddPoint( corner.x, corner.y );
|
aBooleng->AddPoint( corner.x, corner.y );
|
||||||
}
|
}
|
||||||
|
|
||||||
aBooleng->EndPolygonAdd();
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue