First tests about copper zones filled by polygons, without grid (see changelog)

Only for tests! not for production.
This commit is contained in:
charras 2008-10-02 13:24:31 +00:00
parent f95db255fa
commit 4cccb0dd7e
14 changed files with 529 additions and 31 deletions

View File

@ -5,16 +5,29 @@ 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-02 UPDATE Jean-Pierre Charras <jean-pierre.charras@inpg.fr>
================================================================================
+pcbnew:
First tests about copper zones filled without grid (by polygons)
Currently for eyes and tests only.
To select this feature choose No Grid in zone grid filling.
Work in progress:
currently : not implemented:
thermal reliefs (pads are always covered by copper zones).
texts on copper zones.
Removing insulated copper islands.
2008-Oct-1 UPDATE Dick Hollenbeck <dick@softplc.com> 2008-Oct-1 UPDATE Dick Hollenbeck <dick@softplc.com>
================================================================================ ================================================================================
+pcbnew +pcbnew
gen_modules_placefile.cpp: backed out of the "Cu & Cmp" centric terminology gen_modules_placefile.cpp: backed out of the "Cu & Cmp" centric terminology
and moved towards using layer names which are BOARD specific. and moved towards using layer names which are BOARD specific.
2008-Sep-26 UPDATE Jean-Pierre Charras <jean-pierre.charras@inpg.fr> 2008-Sep-26 UPDATE Jean-Pierre Charras <jean-pierre.charras@inpg.fr>
================================================================================ ================================================================================
+pcbnew: +pcbnew:
more about use polygons in zone fill algos on techinals layers: more about use polygons in zone fill algos on technicals layers:
plot Ok. holes are handled plot Ok. holes are handled
2008-Sep-26 UPDATE Jean-Pierre Charras <jean-pierre.charras@inpg.fr> 2008-Sep-26 UPDATE Jean-Pierre Charras <jean-pierre.charras@inpg.fr>

View File

@ -9,7 +9,7 @@ COMMON_GLOBL wxString g_BuildVersion
# include "config.h" # include "config.h"
(wxT(KICAD_SVN_VERSION)) (wxT(KICAD_SVN_VERSION))
# else # else
(wxT("(20080920)")) /* main program version */ (wxT("(20081002-unstable)")) /* main program version */
# endif # endif
#endif #endif
; ;
@ -20,7 +20,7 @@ COMMON_GLOBL wxString g_BuildAboutVersion
# include "config.h" # include "config.h"
(wxT(KICAD_ABOUT_VERSION)) (wxT(KICAD_ABOUT_VERSION))
# else # else
(wxT("(20080920)")) /* svn date & rev (normally overridden) */ (wxT("(20081002-unstable)")) /* svn date & rev (normally overridden) */
# endif # endif
#endif #endif
; ;

View File

@ -139,9 +139,11 @@ set(PCBNEW_SRCS
via_edit.cpp via_edit.cpp
work.cpp work.cpp
xchgmod.cpp xchgmod.cpp
zone_filling_algorithm.cpp
zones_by_polygon.cpp zones_by_polygon.cpp
zones_test_and_combine_areas.cpp) zones_convert_brd_items_to_polygons.cpp
zone_filling_algorithm.cpp
zones_test_and_combine_areas.cpp
)
set(PCBNEW_EXTRA_SRCS set(PCBNEW_EXTRA_SRCS
../share/drawframe.cpp ../share/drawframe.cpp

View File

@ -143,9 +143,24 @@ public:
* Build m_FilledPolysList data from real outlines (m_Poly) * Build m_FilledPolysList data from real outlines (m_Poly)
* in order to have drawable (and plottable) filled polygons * in order to have drawable (and plottable) filled polygons
* drawable filled polygons are polygons without hole * drawable filled polygons are polygons without hole
* @param aPcb: the current board (can be NULL for non copper zones)
* @return number of polygons * @return number of polygons
* This function does not add holes for pads and tracks but calls
* AddClearanceAreasPolygonsToPolysList() to do that for copper layers
*/ */
int BuildFilledPolysListData( void ); int BuildFilledPolysListData( BOARD * aPcb );
/** function AddClearanceAreasPolygonsToPolysList
* Add non copper areas polygons (pads and tracks with clearence)
* to a filled copper area
* used in BuildFilledPolysListData when calculating filled areas in a zone
* Non copper areas are pads and track and their clearance area
* The filled copper area must be computed before
* BuildFilledPolysListData() call this function just after creating the
* filled copper area polygon (without clearence areas
* @param aPcb: the current board
*/
void AddClearanceAreasPolygonsToPolysList( BOARD * aPcb );
/** /**
* Function HitTestForCorner * Function HitTestForCorner

View File

@ -48,6 +48,8 @@ IMPLEMENT_DYNAMIC_CLASS( WinEDA_ZoneFrame, wxDialog )
BEGIN_EVENT_TABLE( WinEDA_ZoneFrame, wxDialog ) BEGIN_EVENT_TABLE( WinEDA_ZoneFrame, wxDialog )
////@begin WinEDA_ZoneFrame event table entries ////@begin WinEDA_ZoneFrame event table entries
EVT_INIT_DIALOG( WinEDA_ZoneFrame::OnInitDialog )
EVT_BUTTON( wxID_OK, WinEDA_ZoneFrame::OnOkClick ) EVT_BUTTON( wxID_OK, WinEDA_ZoneFrame::OnOkClick )
EVT_BUTTON( wxID_CANCEL, WinEDA_ZoneFrame::OnCancelClick ) EVT_BUTTON( wxID_CANCEL, WinEDA_ZoneFrame::OnCancelClick )
@ -133,12 +135,8 @@ bool WinEDA_ZoneFrame::Create( wxWindow* parent,
void WinEDA_ZoneFrame::CreateControls() void WinEDA_ZoneFrame::CreateControls()
{ {
BOARD* board = m_Parent->m_Pcb;
SetFont( *g_DialogFont );
////@begin WinEDA_ZoneFrame content construction ////@begin WinEDA_ZoneFrame content construction
// Generated by DialogBlocks, 24/01/2008 11:39:58 (unregistered) // Generated by DialogBlocks, 02/10/2008 15:53:10 (unregistered)
WinEDA_ZoneFrame* itemDialog1 = this; WinEDA_ZoneFrame* itemDialog1 = this;
@ -156,6 +154,7 @@ void WinEDA_ZoneFrame::CreateControls()
m_GridCtrlStrings.Add(_("0.00000")); m_GridCtrlStrings.Add(_("0.00000"));
m_GridCtrlStrings.Add(_("0.00000")); m_GridCtrlStrings.Add(_("0.00000"));
m_GridCtrlStrings.Add(_("0.00000")); m_GridCtrlStrings.Add(_("0.00000"));
m_GridCtrlStrings.Add(_("No Grid (For tests only!)"));
m_GridCtrl = new wxRadioBox( itemDialog1, ID_RADIOBOX_GRID_SELECTION, _("Grid Size for Filling:"), wxDefaultPosition, wxDefaultSize, m_GridCtrlStrings, 1, wxRA_SPECIFY_COLS ); m_GridCtrl = new wxRadioBox( itemDialog1, ID_RADIOBOX_GRID_SELECTION, _("Grid Size for Filling:"), wxDefaultPosition, wxDefaultSize, m_GridCtrlStrings, 1, wxRA_SPECIFY_COLS );
m_GridCtrl->SetSelection(0); m_GridCtrl->SetSelection(0);
itemBoxSizer4->Add(m_GridCtrl, 0, wxGROW|wxALL, 5); itemBoxSizer4->Add(m_GridCtrl, 0, wxGROW|wxALL, 5);
@ -246,7 +245,19 @@ void WinEDA_ZoneFrame::CreateControls()
m_NetSortingOption->SetValidator( wxGenericValidator(& m_NetSorting) ); m_NetSortingOption->SetValidator( wxGenericValidator(& m_NetSorting) );
////@end WinEDA_ZoneFrame content construction ////@end WinEDA_ZoneFrame content construction
// Initialise options }
/*!
* wxEVT_INIT_DIALOG event handler for ID_DIALOG
*/
// Initialise dialog options
void WinEDA_ZoneFrame::OnInitDialog( wxInitDialogEvent& event )
{
BOARD* board = m_Parent->m_Pcb;
SetFont( *g_DialogFont );
wxString title = _( "Zone clearance value:" ) + ReturnUnitSymbol( g_UnitMetric ); wxString title = _( "Zone clearance value:" ) + ReturnUnitSymbol( g_UnitMetric );
m_ClearanceValueTitle->SetLabel( title ); m_ClearanceValueTitle->SetLabel( title );
@ -266,7 +277,7 @@ void WinEDA_ZoneFrame::CreateControls()
static const int GridList[4] = { 25, 50, 100, 250 }; static const int GridList[4] = { 25, 50, 100, 250 };
int selection = 0; int selection = 0;
for( unsigned ii = 0; ii < (unsigned) m_GridCtrl->GetCount(); ii++ ) for( unsigned ii = 0; ii < 4; ii++ )
{ {
wxString msg = ReturnStringFromValue( g_UnitMetric, wxString msg = ReturnStringFromValue( g_UnitMetric,
GridList[ii], GridList[ii],
@ -409,6 +420,10 @@ void WinEDA_ZoneFrame::CreateControls()
} }
} }
} }
if (GetSizer())
{
GetSizer()->SetSizeHints(this);
}
} }
@ -520,6 +535,11 @@ bool WinEDA_ZoneFrame::AcceptOptions(bool aPromptForErrors)
case 3: case 3:
g_GridRoutingSize = 250; g_GridRoutingSize = 250;
break; break;
case 4:
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;
} }
wxString txtvalue = m_ZoneClearanceCtrl->GetValue(); wxString txtvalue = m_ZoneClearanceCtrl->GetValue();
@ -607,3 +627,5 @@ void WinEDA_ZoneFrame::OnOkClick( wxCommandEvent& event )
EndModal( ZONE_OK ); EndModal( ZONE_OK );
} }

View File

@ -77,7 +77,7 @@ public:
/// Constructors /// Constructors
WinEDA_ZoneFrame( ); WinEDA_ZoneFrame( );
WinEDA_ZoneFrame( WinEDA_PcbFrame* parent, WinEDA_ZoneFrame( WinEDA_PcbFrame* parent,
ZONE_CONTAINER * zone_container = NULL, ZONE_CONTAINER * zone_container,
wxWindowID id = SYMBOL_WINEDA_ZONEFRAME_IDNAME, wxWindowID id = SYMBOL_WINEDA_ZONEFRAME_IDNAME,
const wxString& caption = SYMBOL_WINEDA_ZONEFRAME_TITLE, const wxString& caption = SYMBOL_WINEDA_ZONEFRAME_TITLE,
const wxPoint& pos = SYMBOL_WINEDA_ZONEFRAME_POSITION, const wxPoint& pos = SYMBOL_WINEDA_ZONEFRAME_POSITION,
@ -92,6 +92,9 @@ public:
////@begin WinEDA_ZoneFrame event handler declarations ////@begin WinEDA_ZoneFrame event handler declarations
/// wxEVT_INIT_DIALOG event handler for ID_DIALOG
void OnInitDialog( wxInitDialogEvent& event );
/// wxEVT_COMMAND_BUTTON_CLICKED event handler for wxID_OK /// wxEVT_COMMAND_BUTTON_CLICKED event handler for wxID_OK
void OnOkClick( wxCommandEvent& event ); void OnOkClick( wxCommandEvent& event );

View File

@ -136,6 +136,7 @@
<long name="locked">0</long> <long name="locked">0</long>
<string name="template-name">""</string> <string name="template-name">""</string>
<bool name="dirty">1</bool> <bool name="dirty">1</bool>
<long name="makefile-last-written">-8519680</long>
<string name="Compiler name">""</string> <string name="Compiler name">""</string>
<string name="Build mode">"Debug"</string> <string name="Build mode">"Debug"</string>
<string name="Unicode mode">"ANSI"</string> <string name="Unicode mode">"ANSI"</string>
@ -177,6 +178,8 @@
<string name="wxWidgets build command">"%AUTO%"</string> <string name="wxWidgets build command">"%AUTO%"</string>
<string name="wxWidgets clean command">"%AUTO%"</string> <string name="wxWidgets clean command">"%AUTO%"</string>
<string name="PATH variable">"%AUTO%"</string> <string name="PATH variable">"%AUTO%"</string>
<bool name="Suppress source rules">0</bool>
<bool name="Enable makefile generation">1</bool>
</document> </document>
</document> </document>
</data> </data>
@ -218,6 +221,7 @@
<string name="id-suffix">""</string> <string name="id-suffix">""</string>
<long name="use-xrc">0</long> <long name="use-xrc">0</long>
<long name="working-mode">0</long> <long name="working-mode">0</long>
<string name="event-handler-0">"wxEVT_INIT_DIALOG|OnInitDialog|NONE||WinEDA_ZoneFrame"</string>
<string name="proxy-Id name">"ID_DIALOG"</string> <string name="proxy-Id name">"ID_DIALOG"</string>
<long name="proxy-Id value">10000</long> <long name="proxy-Id value">10000</long>
<string name="proxy-Class">"WinEDA_ZoneFrame"</string> <string name="proxy-Class">"WinEDA_ZoneFrame"</string>
@ -248,7 +252,6 @@
<bool name="proxy-wxDEFAULT_DIALOG_STYLE">0</bool> <bool name="proxy-wxDEFAULT_DIALOG_STYLE">0</bool>
<bool name="proxy-wxCAPTION">1</bool> <bool name="proxy-wxCAPTION">1</bool>
<bool name="proxy-wxRESIZE_BORDER">0</bool> <bool name="proxy-wxRESIZE_BORDER">0</bool>
<bool name="proxy-wxTHICK_FRAME">0</bool>
<bool name="proxy-wxSYSTEM_MENU">1</bool> <bool name="proxy-wxSYSTEM_MENU">1</bool>
<bool name="proxy-wxSTAY_ON_TOP">0</bool> <bool name="proxy-wxSTAY_ON_TOP">0</bool>
<bool name="proxy-wxDIALOG_NO_PARENT">0</bool> <bool name="proxy-wxDIALOG_NO_PARENT">0</bool>
@ -369,7 +372,7 @@
<string name="proxy-Member variable name">"m_GridCtrl"</string> <string name="proxy-Member variable name">"m_GridCtrl"</string>
<string name="proxy-Label">"Grid Size for Filling:"</string> <string name="proxy-Label">"Grid Size for Filling:"</string>
<long name="proxy-Major dimension count">1</long> <long name="proxy-Major dimension count">1</long>
<string name="proxy-Items">"0.00000|0.00000|0.00000|0.00000"</string> <string name="proxy-Items">"0.00000|0.00000|0.00000|0.00000|No Grid (For tests only!)"</string>
<long name="proxy-Initial value">0</long> <long name="proxy-Initial value">0</long>
<string name="proxy-Help text">""</string> <string name="proxy-Help text">""</string>
<string name="proxy-Tooltip text">""</string> <string name="proxy-Tooltip text">""</string>

View File

@ -1011,9 +1011,10 @@ int WinEDA_PcbFrame::ReadPcbFile( FILE* File, bool Append )
#ifdef PCBNEW #ifdef PCBNEW
if( m_Pcb->m_ZoneDescriptorList.size() > 0 ) if( m_Pcb->m_ZoneDescriptorList.size() > 0 )
{ // Build filled areas {
// Build filled areas
for( unsigned ia = 0; ia < m_Pcb->m_ZoneDescriptorList.size(); ia++ ) for( unsigned ia = 0; ia < m_Pcb->m_ZoneDescriptorList.size(); ia++ )
m_Pcb->m_ZoneDescriptorList[ia]->BuildFilledPolysListData( ); m_Pcb->m_ZoneDescriptorList[ia]->BuildFilledPolysListData( m_Pcb );
} }
// Build connectivity info // Build connectivity info

View File

@ -11,7 +11,9 @@ EXTRACPPFLAGS += -DPCBNEW -fno-strict-aliasing -I./ -Ibitmaps -I../include -I..
LIBVIEWER3D = ../3d-viewer/3d-viewer.a LIBVIEWER3D = ../3d-viewer/3d-viewer.a
ZONE_FILES = zones_by_polygon.o zones_test_and_combine_areas.o zone_filling_algorithm.o ZONE_FILES = zones_by_polygon.o zones_test_and_combine_areas.o\
zone_filling_algorithm.o\
zones_convert_brd_items_to_polygons.o
SPECCTRA_TOOLS = specctra.o specctra_export.o dsn.o specctra_import.o SPECCTRA_TOOLS = specctra.o specctra_export.o dsn.o specctra_import.o

View File

@ -518,7 +518,7 @@ int WinEDA_PcbFrame::Begin_Zone( wxDC* DC )
zone->SetLayer( ( (PCB_SCREEN*) GetScreen() )->m_Active_Layer ); zone->SetLayer( ( (PCB_SCREEN*) GetScreen() )->m_Active_Layer );
if( zone->IsOnCopperLayer() ) if( zone->IsOnCopperLayer() )
{ // Put a zone on a copper layer { // Put a zone on a copper layer
WinEDA_ZoneFrame* frame = new WinEDA_ZoneFrame( this ); WinEDA_ZoneFrame* frame = new WinEDA_ZoneFrame( this, zone );
diag = frame->ShowModal(); diag = frame->ShowModal();
frame->Destroy(); frame->Destroy();
} }
@ -758,7 +758,7 @@ void WinEDA_PcbFrame::Edit_Zone_Params( wxDC* DC, ZONE_CONTAINER* zone_container
DrawPanel->m_IgnoreMouseEvents = TRUE; DrawPanel->m_IgnoreMouseEvents = TRUE;
if( zone_container->GetLayer() < FIRST_NO_COPPER_LAYER ) if( zone_container->GetLayer() < FIRST_NO_COPPER_LAYER )
{ // edit a zone on a copper layer { // edit a zone on a copper layer
WinEDA_ZoneFrame* frame = new WinEDA_ZoneFrame( this ); WinEDA_ZoneFrame* frame = new WinEDA_ZoneFrame( this, zone_container );
diag = frame->ShowModal(); diag = frame->ShowModal();
frame->Destroy(); frame->Destroy();
} }
@ -889,8 +889,18 @@ int WinEDA_PcbFrame::Fill_Zone( wxDC* DC, ZONE_CONTAINER* zone_container, bool v
Affiche_1_Parametre( this, 22, _( "NetName" ), msg, RED ); Affiche_1_Parametre( this, 22, _( "NetName" ), msg, RED );
wxBusyCursor dummy; // Shows an hourglass cursor (removed by its destructor) wxBusyCursor dummy; // Shows an hourglass cursor (removed by its destructor)
int error_level = 0;
if( zone_container->m_GridFillValue == 0 )
{
zone_container->BuildFilledPolysListData( m_Pcb );
if ( DC )
DrawPanel->Refresh();
}
else
{
zone_container->m_GridFillValue = g_GridRoutingSize; zone_container->m_GridFillValue = g_GridRoutingSize;
int error_level = zone_container->Fill_Zone( this, DC, verbose ); error_level = zone_container->Fill_Zone( this, DC, verbose );
}
GetScreen()->SetModify(); GetScreen()->SetModify();

View File

@ -0,0 +1,414 @@
using namespace std;
#include <math.h>
#include <vector>
#include "fctsys.h"
#include "common.h"
#include "pcbnew.h"
#include "trigo.h"
#include "zones.h"
#include "PolyLine.h"
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 AddRoundedEndsSegmentPolygon( Bool_Engine* aBooleng,
wxPoint aStart, wxPoint aEnd,
int aWidth );
/* how many segments are used to create a polygon from a circle: */
static int s_CircleToSegmentsCount = 16;
/** function AddClearanceAreasPolygonsToPolysList
* Add non copper areas polygons (pads and tracks with clearence)
* to a filled copper area
* used in BuildFilledPolysListData when calculating filled areas in a zone
* Non copper areas are pads and track and their clearance area
* The filled copper area must be computed just before.
* BuildFilledPolysListData() call this function just after creating the
* filled copper area polygon (without clearence areas
* to do that this function:
* 1 - creates aBool_Engine,with option: holes are linked into outer contours by double overlapping segments
* 2 - Add the main outline (zone outline) in group A
* 3 - Add all non filled areas (pads, tracks) in group B
* 4 - calculates the polygon A - B
* 5 - put resulting list of polygons (filled areas) in m_FilledPolysList
*/
void ZONE_CONTAINER::AddClearanceAreasPolygonsToPolysList( BOARD* aPcb )
{
/* Uses a kbool engine to add holes in the m_FilledPolysList polygon.
* Because this function is called just after creating the m_FilledPolysList,
* only one polygon is in list.
* (initial holes in zonesare linked into outer contours by double overlapping segments).
* after adding holes, many polygons could be exist in this list.
*/
Bool_Engine* booleng = new Bool_Engine();
ArmBoolEng( booleng, true );
/* Add the main polygon (i.e. the filled area using only one outline)
* in GroupA in Bool_Engine
*/
unsigned corners_count = m_FilledPolysList.size();
unsigned ic = 0;
if( booleng->StartPolygonAdd( GROUP_A ) )
{
for( ; ic < corners_count; ic++ )
{
CPolyPt* corner = &m_FilledPolysList[ic];
booleng->AddPoint( corner->x, corner->y );
if( corner->end_contour )
break;
}
booleng->EndPolygonAdd();
}
/* Add holes (i.e. tracks and pads areas as polygons outlines)
* in GroupB in Bool_Engine
* First : Add pads
*/
for( MODULE* module = aPcb->m_Modules; module; module = module->Next() )
{
for( D_PAD* pad = module->m_Pads; pad != NULL; pad = pad->Next() )
{
if( !pad->IsOnLayer( GetLayer() ) )
continue;
AddPadWithClearancePolygon( booleng, *pad, m_ZoneClearance,
false, 0 );
}
}
/* Add holes (i.e. tracks and pads areas as polygons outlines)
* in GroupB in Bool_Engine
* Next : Add tracks and vias
*/
for( TRACK* track = aPcb->m_Track; track; track = track->Next() )
{
if( !track->IsOnLayer( GetLayer() ) )
continue;
AddTrackWithClearancePolygon( booleng, *track, m_ZoneClearance );
}
// Draw graphic items (copper texts) and board edges
for( BOARD_ITEM* item = aPcb->m_Drawings; item; item = item->Next() )
{
switch( item->Type() )
{
case TYPEDRAWSEGMENT:
// TODO: add segment
break;
case TYPETEXTE:
// TODO: add rectangular area
break;
default:
break;
}
}
/* compute copper areas */
booleng->Do_Operation( BOOL_A_SUB_B );
/* put these areas in m_FilledPolysList */
m_FilledPolysList.clear();
while( booleng->StartPolygonGet() )
{
CPolyPt corner( 0, 0, false );
while( booleng->PolygonHasMorePoints() )
{
corner.x = (int) booleng->GetPolygonXPoint();
corner.y = (int) booleng->GetPolygonYPoint();
corner.end_contour = false;
m_FilledPolysList.push_back( corner );
}
corner.end_contour = true;
m_FilledPolysList.pop_back();
m_FilledPolysList.push_back( corner );
booleng->EndPolygonGet();
}
delete booleng;
}
/** Function AddPadPolygonWithPadClearance
* Add a polygon cutout for a pad in a zone area
* Convert arcs and circles to multiple straight lines
*/
void AddPadWithClearancePolygon( Bool_Engine* aBooleng,
D_PAD& aPad, int aClearanceValue,
bool bThermal, int spoke_w )
{
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
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();
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();
aBooleng->AddPoint( corner_position.x, corner_position.y );
corner_position = wxPoint( -dx, +dy );
RotatePoint( &corner_position, angle );
corner_position += aPad.ReturnShapePos();
aBooleng->AddPoint( corner_position.x, corner_position.y );
corner_position = wxPoint( +dx, +dy );
RotatePoint( &corner_position, angle );
corner_position += aPad.ReturnShapePos();
aBooleng->AddPoint( corner_position.x, corner_position.y );
corner_position = wxPoint( +dx, -dy );
RotatePoint( &corner_position, angle );
corner_position += aPad.ReturnShapePos();
aBooleng->AddPoint( corner_position.x, corner_position.y );
aBooleng->EndPolygonAdd();
}
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;
}
/** Function AddTrackWithClearancePolygon
* Add a polygon cutout for a track in a zone area
* Convert arcs and circles to multiple straight lines
*/
void AddTrackWithClearancePolygon( Bool_Engine* aBooleng,
TRACK& aTrack, int aClearanceValue )
{
wxPoint corner_position;
int ii, angle;
int dx = (aTrack.m_Width / 2) + aClearanceValue;
int delta = 3600 / s_CircleToSegmentsCount; // rot angle in 0.1 degree
switch( aTrack.Type() )
{
case TYPEVIA:
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 += aTrack.m_Start;
aBooleng->AddPoint( corner_position.x, corner_position.y );
}
aBooleng->EndPolygonAdd();
}
break;
default:
AddRoundedEndsSegmentPolygon( aBooleng,
aTrack.m_Start, aTrack.m_End,
aTrack.m_Width + (2 * aClearanceValue) );
break;
}
}
/** Function AddRoundedEndsSegmentPolygon
* Add a polygon cutout for a segment (with rounded ends) in a zone area
* Convert arcs to multiple straight lines
*/
void AddRoundedEndsSegmentPolygon( Bool_Engine* aBooleng,
wxPoint aStart, wxPoint aEnd,
int aWidth )
{
int rayon = aWidth / 2;
wxPoint endp = aEnd - aStart; // end point coordinate for the same segment starting at (0,0)
wxPoint startp = aStart;
wxPoint corner;
int seg_len;
// normalize the position in order to have endp.x >= 0;
if( endp.x < 0 )
{
endp = aStart - aEnd;
startp = aEnd;
}
int delta_angle = ArcTangente( endp.y, endp.x ); // delta_angle is in 0.1 degrees
seg_len = (int) sqrt( (endp.y * endp.y) + (endp.x * endp.x) );
if( !aBooleng->StartPolygonAdd( GROUP_B ) )
return; // error!
int delta = 3600 / s_CircleToSegmentsCount; // rot angle in 0.1 degree
// Compute the outlines of the segment, and creates a polygon
corner = wxPoint( 0, rayon );
RotatePoint( &corner, -delta_angle );
corner += startp;
aBooleng->AddPoint( corner.x, corner.y );
corner = wxPoint( seg_len, rayon );
RotatePoint( &corner, -delta_angle );
corner += startp;
aBooleng->AddPoint( corner.x, corner.y );
// add right rounded end:
for( int ii = delta; ii < 1800; ii += delta )
{
corner = wxPoint( 0, rayon );
RotatePoint( &corner, ii );
corner.x += seg_len;
RotatePoint( &corner, -delta_angle );
corner += startp;
aBooleng->AddPoint( corner.x, corner.y );
}
corner = wxPoint( seg_len, -rayon );
RotatePoint( &corner, -delta_angle );
corner += startp;
aBooleng->AddPoint( corner.x, corner.y );
corner = wxPoint( 0, -rayon );
RotatePoint( &corner, -delta_angle );
corner += startp;
aBooleng->AddPoint( corner.x, corner.y );
// add left rounded end:
for( int ii = delta; ii < 1800; ii += delta )
{
corner = wxPoint( 0, -rayon );
RotatePoint( &corner, ii );
RotatePoint( &corner, -delta_angle );
corner += startp;
aBooleng->AddPoint( corner.x, corner.y );
}
aBooleng->EndPolygonAdd();
}

View File

@ -166,19 +166,23 @@ void DialogNonCopperZonesEditor::OnCancelClick( wxCommandEvent& event )
/***************************************************/ /***********************************************************/
int ZONE_CONTAINER::BuildFilledPolysListData( void ) int ZONE_CONTAINER::BuildFilledPolysListData( BOARD * aPcb )
/***************************************************/ /***********************************************************/
/** function BuildFilledPolysListData /** function BuildFilledPolysListData
* Build m_FilledPolysList data from real outlines (m_Poly) * Build m_FilledPolysList data from real outlines (m_Poly)
* in order to have drawable (and plottable) filled polygons * in order to have drawable (and plottable) filled polygons
* drawable filled polygons are polygons without hole * drawable filled polygons are polygons without hole
* @param aPcb: the current board (can be NULL for non copper zones)
* @return number of polygons * @return number of polygons
* Currently useable only for non copper zones * This function does not add holes for pads and tracks but calls
* AddClearanceAreasPolygonsToPolysList() to do that for copper layers
*/ */
{ {
/* Currently only for non copper zones */
if ( IsOnCopperLayer() ) // 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; return 0;
m_FilledPolysList.clear(); m_FilledPolysList.clear();
@ -206,5 +210,12 @@ int ZONE_CONTAINER::BuildFilledPolysListData( void )
m_Poly->FreeKboolEngine(); m_Poly->FreeKboolEngine();
/* For copper layers, we now must add holes in the Polygon list.
holes are pads and tracks with their clearance area
*/
if ( IsOnCopperLayer() )
AddClearanceAreasPolygonsToPolysList( aPcb );
return count; return count;
} }

View File

@ -343,7 +343,7 @@ int BOARD::AreaPolygonModified( ZONE_CONTAINER* modified_area,
{ {
for( unsigned ia = 0; ia < m_ZoneDescriptorList.size(); ia++ ) for( unsigned ia = 0; ia < m_ZoneDescriptorList.size(); ia++ )
if( m_ZoneDescriptorList[ia]->GetLayer() == layer ) if( m_ZoneDescriptorList[ia]->GetLayer() == layer )
m_ZoneDescriptorList[ia]->BuildFilledPolysListData( ); m_ZoneDescriptorList[ia]->BuildFilledPolysListData( this );
} }
} }
return test; return test;

View File

@ -199,7 +199,7 @@ int CPolyLine::NormalizeWithKbool( std::vector<CPolyLine*> * aExtraPolyList, boo
/** Function AddPolygonsToBoolEng /** Function AddPolygonsToBoolEng
* and edges contours to a kbool engine, preparing a boolean op between polygons * Add a CPolyLine to a kbool engine, preparing a boolean op between polygons
* @param aStart_contour: starting contour number (-1 = all, 0 is the outlines of zone, > 1 = holes in zone * @param aStart_contour: starting contour number (-1 = all, 0 is the outlines of zone, > 1 = holes in zone
* @param aEnd_contour: ending contour number (-1 = all after aStart_contour) * @param aEnd_contour: ending contour number (-1 = all after aStart_contour)
* @param arc_array: arc converted to poly segments (NULL if not exists) * @param arc_array: arc converted to poly segments (NULL if not exists)
@ -217,8 +217,10 @@ int CPolyLine::AddPolygonsToBoolEng( Bool_Engine* aBooleng,
if( (aGroup != GROUP_A) && (aGroup != GROUP_B ) ) if( (aGroup != GROUP_A) && (aGroup != GROUP_B ) )
return 0; //Error ! return 0; //Error !
/* Convert the current polyline contour to a kbool polygon: */
MakeKboolPoly( aStart_contour, aEnd_contour, arc_array ); MakeKboolPoly( aStart_contour, aEnd_contour, arc_array );
/* add the resulting kbool set of polygons to the current kcool engine */
while( m_Kbool_Poly_Engine->StartPolygonGet() ) while( m_Kbool_Poly_Engine->StartPolygonGet() )
{ {
if( aBooleng->StartPolygonAdd( GROUP_A ) ) if( aBooleng->StartPolygonAdd( GROUP_A ) )