From 4cccb0dd7eab7db461747bebbbb442a3bfb22f4d Mon Sep 17 00:00:00 2001 From: charras Date: Thu, 2 Oct 2008 13:24:31 +0000 Subject: [PATCH] First tests about copper zones filled by polygons, without grid (see changelog) Only for tests! not for production. --- change_log.txt | 15 +- include/build_version.h | 4 +- pcbnew/CMakeLists.txt | 6 +- pcbnew/class_zone.h | 17 +- pcbnew/dialog_zones_by_polygon.cpp | 36 +- pcbnew/dialog_zones_by_polygon.h | 5 +- pcbnew/dialog_zones_by_polygon.pjd | 7 +- pcbnew/ioascii.cpp | 5 +- pcbnew/makefile.include | 4 +- pcbnew/zones_by_polygon.cpp | 18 +- .../zones_convert_brd_items_to_polygons.cpp | 414 ++++++++++++++++++ pcbnew/zones_non_copper_type_functions.cpp | 23 +- pcbnew/zones_test_and_combine_areas.cpp | 2 +- polygon/PolyLine.cpp | 4 +- 14 files changed, 529 insertions(+), 31 deletions(-) create mode 100644 pcbnew/zones_convert_brd_items_to_polygons.cpp diff --git a/change_log.txt b/change_log.txt index eb4a8807b5..d51cdf39d8 100644 --- a/change_log.txt +++ b/change_log.txt @@ -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 +================================================================================ ++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 ================================================================================ +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 ================================================================================ +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 diff --git a/include/build_version.h b/include/build_version.h index 615a1e6c5c..0ca081feec 100644 --- a/include/build_version.h +++ b/include/build_version.h @@ -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 ; diff --git a/pcbnew/CMakeLists.txt b/pcbnew/CMakeLists.txt index 0d35296bab..beea66d3fa 100644 --- a/pcbnew/CMakeLists.txt +++ b/pcbnew/CMakeLists.txt @@ -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 diff --git a/pcbnew/class_zone.h b/pcbnew/class_zone.h index b55987c0e2..21960d3444 100644 --- a/pcbnew/class_zone.h +++ b/pcbnew/class_zone.h @@ -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 diff --git a/pcbnew/dialog_zones_by_polygon.cpp b/pcbnew/dialog_zones_by_polygon.cpp index 5e706b9a48..5d34a3326b 100644 --- a/pcbnew/dialog_zones_by_polygon.cpp +++ b/pcbnew/dialog_zones_by_polygon.cpp @@ -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 ); } + + diff --git a/pcbnew/dialog_zones_by_polygon.h b/pcbnew/dialog_zones_by_polygon.h index 3ee9b471ca..4fbd537037 100644 --- a/pcbnew/dialog_zones_by_polygon.h +++ b/pcbnew/dialog_zones_by_polygon.h @@ -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 ); diff --git a/pcbnew/dialog_zones_by_polygon.pjd b/pcbnew/dialog_zones_by_polygon.pjd index f408d14f17..774bddff6d 100644 --- a/pcbnew/dialog_zones_by_polygon.pjd +++ b/pcbnew/dialog_zones_by_polygon.pjd @@ -136,6 +136,7 @@ 0 "" 1 + -8519680 "" "Debug" "ANSI" @@ -177,6 +178,8 @@ "%AUTO%" "%AUTO%" "%AUTO%" + 0 + 1 @@ -218,6 +221,7 @@ "" 0 0 + "wxEVT_INIT_DIALOG|OnInitDialog|NONE||WinEDA_ZoneFrame" "ID_DIALOG" 10000 "WinEDA_ZoneFrame" @@ -248,7 +252,6 @@ 0 1 0 - 0 1 0 0 @@ -369,7 +372,7 @@ "m_GridCtrl" "Grid Size for Filling:" 1 - "0.00000|0.00000|0.00000|0.00000" + "0.00000|0.00000|0.00000|0.00000|No Grid (For tests only!)" 0 "" "" diff --git a/pcbnew/ioascii.cpp b/pcbnew/ioascii.cpp index d3770655d2..514d7ec583 100644 --- a/pcbnew/ioascii.cpp +++ b/pcbnew/ioascii.cpp @@ -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 diff --git a/pcbnew/makefile.include b/pcbnew/makefile.include index d6f1050238..0dbc67442f 100644 --- a/pcbnew/makefile.include +++ b/pcbnew/makefile.include @@ -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 diff --git a/pcbnew/zones_by_polygon.cpp b/pcbnew/zones_by_polygon.cpp index 6378790ee7..80283fbca6 100644 --- a/pcbnew/zones_by_polygon.cpp +++ b/pcbnew/zones_by_polygon.cpp @@ -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(); diff --git a/pcbnew/zones_convert_brd_items_to_polygons.cpp b/pcbnew/zones_convert_brd_items_to_polygons.cpp new file mode 100644 index 0000000000..c5c54486b4 --- /dev/null +++ b/pcbnew/zones_convert_brd_items_to_polygons.cpp @@ -0,0 +1,414 @@ +using namespace std; + +#include +#include + +#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(); +} diff --git a/pcbnew/zones_non_copper_type_functions.cpp b/pcbnew/zones_non_copper_type_functions.cpp index de8e5992be..4226ae5eee 100644 --- a/pcbnew/zones_non_copper_type_functions.cpp +++ b/pcbnew/zones_non_copper_type_functions.cpp @@ -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; } diff --git a/pcbnew/zones_test_and_combine_areas.cpp b/pcbnew/zones_test_and_combine_areas.cpp index 795c59636e..b4fbb9addc 100644 --- a/pcbnew/zones_test_and_combine_areas.cpp +++ b/pcbnew/zones_test_and_combine_areas.cpp @@ -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; diff --git a/polygon/PolyLine.cpp b/polygon/PolyLine.cpp index 65b2ca66db..2b4e510961 100644 --- a/polygon/PolyLine.cpp +++ b/polygon/PolyLine.cpp @@ -199,7 +199,7 @@ int CPolyLine::NormalizeWithKbool( std::vector * 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 ) )