First tests about copper zones filled by polygons, without grid (see changelog)
Only for tests! not for production.
This commit is contained in:
parent
f95db255fa
commit
4cccb0dd7e
|
@ -5,16 +5,29 @@ Started 2007-June-11
|
|||
Please add newer entries at the top, list the date and your name with
|
||||
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>
|
||||
================================================================================
|
||||
+pcbnew
|
||||
gen_modules_placefile.cpp: backed out of the "Cu & Cmp" centric terminology
|
||||
and moved towards using layer names which are BOARD specific.
|
||||
|
||||
|
||||
2008-Sep-26 UPDATE Jean-Pierre Charras <jean-pierre.charras@inpg.fr>
|
||||
================================================================================
|
||||
+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
|
||||
|
||||
2008-Sep-26 UPDATE Jean-Pierre Charras <jean-pierre.charras@inpg.fr>
|
||||
|
|
|
@ -9,7 +9,7 @@ COMMON_GLOBL wxString g_BuildVersion
|
|||
# include "config.h"
|
||||
(wxT(KICAD_SVN_VERSION))
|
||||
# else
|
||||
(wxT("(20080920)")) /* main program version */
|
||||
(wxT("(20081002-unstable)")) /* main program version */
|
||||
# endif
|
||||
#endif
|
||||
;
|
||||
|
@ -20,7 +20,7 @@ COMMON_GLOBL wxString g_BuildAboutVersion
|
|||
# include "config.h"
|
||||
(wxT(KICAD_ABOUT_VERSION))
|
||||
# else
|
||||
(wxT("(20080920)")) /* svn date & rev (normally overridden) */
|
||||
(wxT("(20081002-unstable)")) /* svn date & rev (normally overridden) */
|
||||
# endif
|
||||
#endif
|
||||
;
|
||||
|
|
|
@ -139,9 +139,11 @@ set(PCBNEW_SRCS
|
|||
via_edit.cpp
|
||||
work.cpp
|
||||
xchgmod.cpp
|
||||
zone_filling_algorithm.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
|
||||
../share/drawframe.cpp
|
||||
|
|
|
@ -143,9 +143,24 @@ public:
|
|||
* Build m_FilledPolysList data from real outlines (m_Poly)
|
||||
* in order to have drawable (and plottable) filled polygons
|
||||
* drawable filled polygons are polygons without hole
|
||||
* @param aPcb: the current board (can be NULL for non copper zones)
|
||||
* @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
|
||||
|
|
|
@ -48,6 +48,8 @@ IMPLEMENT_DYNAMIC_CLASS( WinEDA_ZoneFrame, wxDialog )
|
|||
BEGIN_EVENT_TABLE( WinEDA_ZoneFrame, wxDialog )
|
||||
|
||||
////@begin WinEDA_ZoneFrame event table entries
|
||||
EVT_INIT_DIALOG( WinEDA_ZoneFrame::OnInitDialog )
|
||||
|
||||
EVT_BUTTON( wxID_OK, WinEDA_ZoneFrame::OnOkClick )
|
||||
|
||||
EVT_BUTTON( wxID_CANCEL, WinEDA_ZoneFrame::OnCancelClick )
|
||||
|
@ -133,12 +135,8 @@ bool WinEDA_ZoneFrame::Create( wxWindow* parent,
|
|||
|
||||
void WinEDA_ZoneFrame::CreateControls()
|
||||
{
|
||||
BOARD* board = m_Parent->m_Pcb;
|
||||
|
||||
SetFont( *g_DialogFont );
|
||||
|
||||
////@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;
|
||||
|
||||
|
@ -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(_("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->SetSelection(0);
|
||||
itemBoxSizer4->Add(m_GridCtrl, 0, wxGROW|wxALL, 5);
|
||||
|
@ -246,7 +245,19 @@ void WinEDA_ZoneFrame::CreateControls()
|
|||
m_NetSortingOption->SetValidator( wxGenericValidator(& m_NetSorting) );
|
||||
////@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 );
|
||||
m_ClearanceValueTitle->SetLabel( title );
|
||||
|
||||
|
@ -266,7 +277,7 @@ void WinEDA_ZoneFrame::CreateControls()
|
|||
static const int GridList[4] = { 25, 50, 100, 250 };
|
||||
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,
|
||||
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:
|
||||
g_GridRoutingSize = 250;
|
||||
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();
|
||||
|
@ -607,3 +627,5 @@ void WinEDA_ZoneFrame::OnOkClick( wxCommandEvent& event )
|
|||
EndModal( ZONE_OK );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -77,7 +77,7 @@ public:
|
|||
/// Constructors
|
||||
WinEDA_ZoneFrame( );
|
||||
WinEDA_ZoneFrame( WinEDA_PcbFrame* parent,
|
||||
ZONE_CONTAINER * zone_container = NULL,
|
||||
ZONE_CONTAINER * zone_container,
|
||||
wxWindowID id = SYMBOL_WINEDA_ZONEFRAME_IDNAME,
|
||||
const wxString& caption = SYMBOL_WINEDA_ZONEFRAME_TITLE,
|
||||
const wxPoint& pos = SYMBOL_WINEDA_ZONEFRAME_POSITION,
|
||||
|
@ -92,6 +92,9 @@ public:
|
|||
|
||||
////@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
|
||||
void OnOkClick( wxCommandEvent& event );
|
||||
|
||||
|
|
|
@ -136,6 +136,7 @@
|
|||
<long name="locked">0</long>
|
||||
<string name="template-name">""</string>
|
||||
<bool name="dirty">1</bool>
|
||||
<long name="makefile-last-written">-8519680</long>
|
||||
<string name="Compiler name">""</string>
|
||||
<string name="Build mode">"Debug"</string>
|
||||
<string name="Unicode mode">"ANSI"</string>
|
||||
|
@ -177,6 +178,8 @@
|
|||
<string name="wxWidgets build command">"%AUTO%"</string>
|
||||
<string name="wxWidgets clean command">"%AUTO%"</string>
|
||||
<string name="PATH variable">"%AUTO%"</string>
|
||||
<bool name="Suppress source rules">0</bool>
|
||||
<bool name="Enable makefile generation">1</bool>
|
||||
</document>
|
||||
</document>
|
||||
</data>
|
||||
|
@ -218,6 +221,7 @@
|
|||
<string name="id-suffix">""</string>
|
||||
<long name="use-xrc">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>
|
||||
<long name="proxy-Id value">10000</long>
|
||||
<string name="proxy-Class">"WinEDA_ZoneFrame"</string>
|
||||
|
@ -248,7 +252,6 @@
|
|||
<bool name="proxy-wxDEFAULT_DIALOG_STYLE">0</bool>
|
||||
<bool name="proxy-wxCAPTION">1</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-wxSTAY_ON_TOP">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-Label">"Grid Size for Filling:"</string>
|
||||
<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>
|
||||
<string name="proxy-Help text">""</string>
|
||||
<string name="proxy-Tooltip text">""</string>
|
||||
|
|
|
@ -1011,9 +1011,10 @@ int WinEDA_PcbFrame::ReadPcbFile( FILE* File, bool Append )
|
|||
|
||||
#ifdef PCBNEW
|
||||
if( m_Pcb->m_ZoneDescriptorList.size() > 0 )
|
||||
{ // Build filled areas
|
||||
{
|
||||
// Build filled areas
|
||||
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
|
||||
|
|
|
@ -11,7 +11,9 @@ EXTRACPPFLAGS += -DPCBNEW -fno-strict-aliasing -I./ -Ibitmaps -I../include -I..
|
|||
|
||||
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
|
||||
|
||||
|
|
|
@ -518,7 +518,7 @@ int WinEDA_PcbFrame::Begin_Zone( wxDC* DC )
|
|||
zone->SetLayer( ( (PCB_SCREEN*) GetScreen() )->m_Active_Layer );
|
||||
if( zone->IsOnCopperLayer() )
|
||||
{ // 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();
|
||||
frame->Destroy();
|
||||
}
|
||||
|
@ -758,7 +758,7 @@ void WinEDA_PcbFrame::Edit_Zone_Params( wxDC* DC, ZONE_CONTAINER* zone_container
|
|||
DrawPanel->m_IgnoreMouseEvents = TRUE;
|
||||
if( zone_container->GetLayer() < FIRST_NO_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();
|
||||
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 );
|
||||
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;
|
||||
int error_level = zone_container->Fill_Zone( this, DC, verbose );
|
||||
error_level = zone_container->Fill_Zone( this, DC, verbose );
|
||||
}
|
||||
|
||||
GetScreen()->SetModify();
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
|
@ -166,19 +166,23 @@ void DialogNonCopperZonesEditor::OnCancelClick( wxCommandEvent& event )
|
|||
|
||||
|
||||
|
||||
/***************************************************/
|
||||
int ZONE_CONTAINER::BuildFilledPolysListData( void )
|
||||
/***************************************************/
|
||||
/***********************************************************/
|
||||
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
|
||||
* drawable filled polygons are polygons without hole
|
||||
* @param aPcb: the current board (can be NULL for non copper zones)
|
||||
* @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;
|
||||
|
||||
m_FilledPolysList.clear();
|
||||
|
@ -206,5 +210,12 @@ int ZONE_CONTAINER::BuildFilledPolysListData( void )
|
|||
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -343,7 +343,7 @@ int BOARD::AreaPolygonModified( ZONE_CONTAINER* modified_area,
|
|||
{
|
||||
for( unsigned ia = 0; ia < m_ZoneDescriptorList.size(); ia++ )
|
||||
if( m_ZoneDescriptorList[ia]->GetLayer() == layer )
|
||||
m_ZoneDescriptorList[ia]->BuildFilledPolysListData( );
|
||||
m_ZoneDescriptorList[ia]->BuildFilledPolysListData( this );
|
||||
}
|
||||
}
|
||||
return test;
|
||||
|
|
|
@ -199,7 +199,7 @@ int CPolyLine::NormalizeWithKbool( std::vector<CPolyLine*> * aExtraPolyList, boo
|
|||
|
||||
|
||||
/** 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 aEnd_contour: ending contour number (-1 = all after aStart_contour)
|
||||
* @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 ) )
|
||||
return 0; //Error !
|
||||
|
||||
/* Convert the current polyline contour to a kbool polygon: */
|
||||
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() )
|
||||
{
|
||||
if( aBooleng->StartPolygonAdd( GROUP_A ) )
|
||||
|
|
Loading…
Reference in New Issue