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
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>

View File

@ -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
;

View File

@ -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

View File

@ -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

View File

@ -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 );
}

View File

@ -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 );

View File

@ -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>

View File

@ -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

View File

@ -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

View File

@ -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)
zone_container->m_GridFillValue = g_GridRoutingSize;
int error_level = zone_container->Fill_Zone( this, DC, verbose );
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;
error_level = zone_container->Fill_Zone( this, DC, verbose );
}
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
* 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();
@ -205,6 +209,13 @@ 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;
}

View File

@ -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;

View File

@ -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 ) )