diff --git a/CHANGELOG.txt b/CHANGELOG.txt index ccd15bd2ba..aea351f312 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -4,6 +4,25 @@ KiCad ChangeLog 2009 Please add newer entries at the top, list the date and your name with email address. +2009-sept-17 UPDATE Jean-Pierre Charras +================================================================================ +++pcbnew + Speed up ZONE_CONTAINER::Copy method + Speed up NETINFO_ITEM* BOARD::FindNet( const wxString& aNetname ) by using afast binary search + Switch to kbool V2.1. This version solves others problems in zones calculations. + Adding an other way to generate thermal shape; DO NOT USE: this is for kbool tests only + (I am thinking some bugs are remaining, so i am always working on kbool tests. + Klaas Olwerda is supporting me) + + +2009-sept-14 UPDATE Jean-Pierre Charras +================================================================================ +++pcbnew + moved copper layers properties (layers couns anf layers names) from Design rules + to a specific dialog. + This must be seen as a TEMPORARY work, until a volunteer creates a better dialog box, + because there is currently no other way to change copper layers names. + 2009-Sep-10 UPDATE Dick Hollenbeck ================================================================================ ++pcbnew @@ -22,7 +41,7 @@ email address. ++pcbnew Work on undo/redo in pcbnew finished. Switch to kbool V2.0. This version solves some problems in zones calculations but not all. - The Kbool's author, Klaas Holveda, is still working on these problems + The Kbool's author, Klaas Holweda, is still working on these problems Thanks to Klaas diff --git a/bitmaps/CMakeLists.txt b/bitmaps/CMakeLists.txt index a5242aea73..70999252d6 100644 --- a/bitmaps/CMakeLists.txt +++ b/bitmaps/CMakeLists.txt @@ -64,6 +64,7 @@ set(BITMAP_SRCS config.xpm CopyBlock.xpm copy.xpm + copper_layers_setup.cpp Cursor_Shape.xpm cursor.xpm cut.xpm diff --git a/bitmaps/copper_layers_setup.xpm b/bitmaps/copper_layers_setup.xpm new file mode 100644 index 0000000000..41a9bfa400 --- /dev/null +++ b/bitmaps/copper_layers_setup.xpm @@ -0,0 +1,23 @@ +/* XPM */ +const char * copper_layers_setup_xpm[] = { +"16 16 4 1", +" c None", +". c #B70000", +"s c #606020", +"# c #008F00", +".......... ", +".......... ", +".......... ", +"...ssssssssss ", +"...ssssssssss ", +"...ssssssssss ", +"...sss##########", +"...sss##########", +"...sss##########", +"...sss##########", +" sss##########", +" sss##########", +" sss##########", +" ##########", +" ##########", +" ##########"}; diff --git a/common/about_kicad.cpp b/common/about_kicad.cpp index 40dfaa129a..48ddc49400 100644 --- a/common/about_kicad.cpp +++ b/common/about_kicad.cpp @@ -72,9 +72,9 @@ void InitKiCadAbout( wxAboutDialogInfo& info ) /* Show Unicode or Ansi version */ #if wxUSE_UNICODE - << ( wxT( " Unicode\n" ) ); + << ( wxT( " Unicode " ) ); # else - << ( wxT( " Ansi\n" ) ); + << ( wxT( " Ansi " ) ); #endif @@ -107,7 +107,7 @@ void InitKiCadAbout( wxAboutDialogInfo& info ) #endif - /* Websites */ + /* Websites */ description << wxT( "\n\nKiCad on the web\n\n" ); description << wxT( "http://iut-tice.ujf-grenoble.fr/kicad \n" ); description << wxT( "http://kicad.sourceforge.net \n" ); diff --git a/eeschema/class_libentry.cpp b/eeschema/class_libentry.cpp index 4033e760b0..988e542940 100644 --- a/eeschema/class_libentry.cpp +++ b/eeschema/class_libentry.cpp @@ -340,11 +340,14 @@ void EDA_LibComponentStruct::Draw( WinEDA_DrawPanel* panel, wxDC* dc, } } + /* Enable this to draw the anchor of the component. */ +#if 0 int len = panel->GetScreen()->Unscale( 3 ); GRLine( &panel->m_ClipBox, dc, offset.x, offset.y - len, offset.x, offset.y + len, 0, color ); GRLine( &panel->m_ClipBox, dc, offset.x - len, offset.y, offset.x + len, offset.y, 0, color ); +#endif /* Enable this to draw the bounding box around the component to validate * the bounding box calculations. */ diff --git a/eeschema/class_sch_component.cpp b/eeschema/class_sch_component.cpp index 0446e42936..7ddf09c699 100644 --- a/eeschema/class_sch_component.cpp +++ b/eeschema/class_sch_component.cpp @@ -67,7 +67,10 @@ void DrawLibPartAux( WinEDA_DrawPanel* panel, wxDC* DC, Entry->Draw( panel, DC, Pos, Multi, convert, DrawMode, Color, TransMat, DrawPinText, false ); - if( g_DebugLevel > 4 ) /* Draw the component boundary box */ + /* Enable this to draw the bounding box around the component to validate + * the bounding box calculations. */ +#if 0 + /* Draw the component boundary box */ { EDA_Rect BoundaryBox; if( Component ) @@ -92,6 +95,7 @@ void DrawLibPartAux( WinEDA_DrawPanel* panel, wxDC* DC, y2 = BoundaryBox.GetBottom(); GRRect( &panel->m_ClipBox, DC, x1, y1, x2, y2, BROWN ); } +#endif } diff --git a/eeschema/libframe.cpp b/eeschema/libframe.cpp index 9672bd7ad4..e0d0e8b39d 100644 --- a/eeschema/libframe.cpp +++ b/eeschema/libframe.cpp @@ -309,7 +309,7 @@ void WinEDA_LibeditFrame::UpdatePartSelectList() return; - if( !m_SelpartBox->IsEmpty() ) + if( m_SelpartBox->GetCount() != 0 ) m_SelpartBox->Clear(); if( CurrentLibEntry == NULL || CurrentLibEntry->m_UnitCount <= 1 ) diff --git a/include/bitmaps.h b/include/bitmaps.h index e192e74f0d..a3803f8303 100644 --- a/include/bitmaps.h +++ b/include/bitmaps.h @@ -59,6 +59,7 @@ extern const char* cancel_xpm[]; extern const char* component_select_alternate_shape_xpm[]; extern const char* component_select_unit_xpm[]; extern const char* config_xpm[]; +extern const char* copper_layers_setup_xpm[]; extern const char* copyblock_xpm[]; extern const char* copy_button[]; extern const char* cursor_shape_xpm[]; diff --git a/include/id.h b/include/id.h index ba599596d8..1d80b8a722 100644 --- a/include/id.h +++ b/include/id.h @@ -469,7 +469,7 @@ enum main_id { ID_PCB_MIRE_BUTT, ID_PCB_SHOW_1_RATSNEST_BUTT, ID_PCB_PLACE_OFFSET_COORD_BUTT, - ID_PCB_UNUSED_BUTT0, + ID_PCB_COPPER_LAYERS_SETUP, ID_PCB_UNUSED_BUTT1, ID_PCB_UNUSED_BUTT2, ID_PCB_UNUSED_BUTT3, diff --git a/pcbnew/CMakeLists.txt b/pcbnew/CMakeLists.txt index 5f3baf501f..38efa46a8d 100644 --- a/pcbnew/CMakeLists.txt +++ b/pcbnew/CMakeLists.txt @@ -25,6 +25,8 @@ set(PCBNEW_SRCS cross-probing.cpp debug_kbool_key_file_fct.cpp deltrack.cpp + dialog_copper_layers_setup_base.cpp + dialog_copper_layers_setup.cpp dialog_copper_zones.cpp dialog_copper_zones_base.cpp dialog_design_rules.cpp diff --git a/pcbnew/class_board.cpp b/pcbnew/class_board.cpp index 8431df6ea3..ff4cdf1af5 100644 --- a/pcbnew/class_board.cpp +++ b/pcbnew/class_board.cpp @@ -827,7 +827,7 @@ SEARCH_RESULT BOARD::Visit( INSPECTOR* inspector, const void* testData, * Function FindNet * searches for a net with the given netcode. * @param anetcode The netcode to search for. - * @return EQUIPOT* - the net or NULL if not found. + * @return NETINFO_ITEM* - the net or NULL if not found. */ NETINFO_ITEM* BOARD::FindNet( int anetcode ) const { @@ -851,21 +851,66 @@ NETINFO_ITEM* BOARD::FindNet( int anetcode ) const * Function FindNet overlayed * searches for a net with the given name. * @param aNetname A Netname to search for. - * @return EQUIPOT* - the net or NULL if not found. + * @return NETINFO_ITEM* - the net or NULL if not found. */ NETINFO_ITEM* BOARD::FindNet( const wxString& aNetname ) const { // the first valid netcode is 1. // zero is reserved for "no connection" and is not used. - if( !aNetname.IsEmpty() ) + if( aNetname.IsEmpty() ) + return NULL; + + int ncount = m_NetInfo->GetCount(); + // Search for a netname = aNetname +#if 0 + // Use a sequencial search: easy to understand, but slow + printf("\nsearch %s, nets %d\n", CONV_TO_UTF8(aNetname), ncount); + + for( int ii = 1; ii < ncount; ii++ ) { - for( unsigned ii = 1; ii < m_NetInfo->GetCount(); ii++ ) + NETINFO_ITEM* item = m_NetInfo->GetNetItem( ii ); + if( item && item->GetNetname() == aNetname ) { - NETINFO_ITEM* item = m_NetInfo->GetNetItem( ii ); - if( item && item->GetNetname() == aNetname ) - return item; + printf(" found\n"); + return item; } } +#else + // Use a fast binary search, + // this is possible because Nets are alphabetically ordered in list + // see NETINFO_LIST::BuildListOfNets() and NETINFO_LIST::Build_Pads_Full_List() + int imax = ncount-1; + int index = imax; + while( ncount > 0 ) + { + int ii = ncount; + ncount >>= 1; + + if( (ii & 1) && ( ii > 1 ) ) + ncount++; + + NETINFO_ITEM* item = m_NetInfo->GetNetItem( index ); + if( item == NULL ) + return NULL; + int icmp = item->GetNetname().Cmp(aNetname); + + if (icmp == 0 ) // found ! + { + printf(" found\n"); + return item; + } + if( icmp < 0 ) // must search after item + { + index += ncount; + continue; + } + if( icmp > 0 ) // must search before item + { + index -= ncount; + continue; + } + } +#endif return NULL; } diff --git a/pcbnew/class_netclass.cpp b/pcbnew/class_netclass.cpp index 9c4cd59edb..4a286e0d4c 100644 --- a/pcbnew/class_netclass.cpp +++ b/pcbnew/class_netclass.cpp @@ -197,9 +197,9 @@ void BOARD::SynchronizeNetsAndNetClasses() { const wxString& netname = *member; - // @todo: although this overall function seems to be adequately fast, if you - // wanted to make an improvement it would be in FindNet( wxString ) which I - // think is a sequential search. + // although this overall function seems to be adequately fast, + // FindNet( wxString ) uses now a fast binary search and is fast + // event for large net lists NETINFO_ITEM* net = FindNet( netname ); if( net && net->GetClassName() == NETCLASS::Default ) diff --git a/pcbnew/class_netinfolist.cpp b/pcbnew/class_netinfolist.cpp index 526cfde420..ff782e107c 100644 --- a/pcbnew/class_netinfolist.cpp +++ b/pcbnew/class_netinfolist.cpp @@ -59,6 +59,10 @@ void NETINFO_LIST::AppendNet( NETINFO_ITEM* aNewElement ) /* sort function, to sort pad list by netnames + * this is a case sensitive sort. + * DO NOT change it because NETINFO_ITEM* BOARD::FindNet( const wxString& aNetname ) + * when search a net by its net name does a binary search + * and expects to have a nets list sorted by an alphabetic case sensitive sort */ static bool PadlistSortByNetnames( const D_PAD* a, const D_PAD* b ) @@ -74,10 +78,14 @@ void NETINFO_LIST::BuildListOfNets() /** * Compute and update the net_codes for PADS et and equipots (.m_NetCode member) * net_codes are >= 1 (net_code = 0 means not connected) - * Update the equipotents buffer + * Update the net buffer * Must be called after editing pads (netname, or deleting) or after read a netlist * set to 1 flag NET_CODE_OK of m_Pcb->m_Status_Pcb; * m_Pcb->m_NbNodes and m_Pcb->m_NbNets are updated + * Be aware NETINFO_ITEM* BOARD::FindNet( const wxString& aNetname ) + * when search a net by its net name does a binary search + * and expects to have a nets list sorted by an alphabetic case sensitive sort + * So do not change Build_Pads_Full_List() taht build a sorted list of pads */ { D_PAD* pad; @@ -139,12 +147,16 @@ void NETINFO_LIST::Build_Pads_Full_List() /*****************************************/ /** Function Build_Pads_Full_List - * Create the pad list, sorted by net names + * Create the pad list, sorted by net names (sorted by an alphabetic case sensitive sort) * initialise: * m_Pads (list of pads) * set m_Status_Pcb = LISTE_PAD_OK; * also clear m_Pcb->m_FullRatsnest that could have bad data * (m_Pcb->m_FullRatsnest uses pointer to pads) + * Be aware NETINFO_ITEM* BOARD::FindNet( const wxString& aNetname ) + * when search a net by its net name does a binary search + * and expects to have a nets list sorted by an alphabetic case sensitive sort + * So do not change the sort function used here */ { if( m_Parent->m_Status_Pcb & LISTE_PAD_OK ) @@ -167,6 +179,7 @@ void NETINFO_LIST::Build_Pads_Full_List() } // Sort pad list per net + // sort( m_PadsFullList.begin(), m_PadsFullList.end(), PadlistSortByNetnames ); m_Parent->m_Status_Pcb = LISTE_PAD_OK; diff --git a/pcbnew/class_zone.cpp b/pcbnew/class_zone.cpp index 5e17e52bd1..77c8f5e422 100644 --- a/pcbnew/class_zone.cpp +++ b/pcbnew/class_zone.cpp @@ -1142,7 +1142,8 @@ void ZONE_CONTAINER::Copy( ZONE_CONTAINER* src ) m_PadOption = src->m_PadOption; m_ThermalReliefGapValue = src->m_ThermalReliefGapValue; m_ThermalReliefCopperBridgeValue = src->m_ThermalReliefCopperBridgeValue; - m_Poly->SetHatch( src->m_Poly->GetHatchStyle() ); + m_Poly->m_HatchStyle = src->m_Poly->GetHatchStyle(); + m_Poly->m_HatchLines = src->m_Poly->m_HatchLines; // Copy vector m_FilledPolysList.clear(); m_FilledPolysList = src->m_FilledPolysList; m_FillSegmList.clear(); diff --git a/pcbnew/debug_kbool_key_file_fct.h b/pcbnew/debug_kbool_key_file_fct.h index fe637e116b..f4519a03d0 100644 --- a/pcbnew/debug_kbool_key_file_fct.h +++ b/pcbnew/debug_kbool_key_file_fct.h @@ -11,6 +11,9 @@ #ifdef CREATE_KBOOL_KEY_FILES +// Allows or not) 0 degree orientation thermal shapes, for kbool tests +//#define CREATE_KBOOL_KEY_FILES_WITH_0_DEG + #define KEYFILE_FILENAME "dbgfile.key" /** function CreateKeyFile diff --git a/pcbnew/dialog_copper_layers_setup.cpp b/pcbnew/dialog_copper_layers_setup.cpp new file mode 100644 index 0000000000..18fbbbe0c0 --- /dev/null +++ b/pcbnew/dialog_copper_layers_setup.cpp @@ -0,0 +1,216 @@ +///////////////////////////////////////////////////////////////////////////// + +// Name: dialog_design_rules.cpp +// Author: jean-pierre Charras +///////////////////////////////////////////////////////////////////////////// + +/* functions relatives to the design rules editor + */ +#include "fctsys.h" +#include "common.h" +#include "class_drawpanel.h" + +#include "confirm.h" +#include "pcbnew.h" +#include "wxPcbStruct.h" + +#include "id.h" +#include "dialog_copper_layers_setup.h" +#include "wx/generic/gridctrl.h" + + +// Fields Positions on layer grid +#define LAYERS_GRID_ROUTABLE_POSITION 0 +#define LAYERS_GRID_STATUS_POSITION 1 +#define LAYERS_GRID_NAME_POSITION 2 + + +/***********************************************************************************/ +DIALOG_COPPER_LAYERS_SETUP::DIALOG_COPPER_LAYERS_SETUP( WinEDA_PcbFrame* parent ) : + DIALOG_COPPER_LAYERS_SETUP_BASE( parent ) +/***********************************************************************************/ +{ + m_Parent = parent; + + Init(); + SetAutoLayout( true ); + GetSizer()->Fit( this ); + GetSizer()->SetSizeHints( this ); +} + + +/********************************************************************/ +void DIALOG_COPPER_LAYERS_SETUP::Init() +/********************************************************************/ +{ + SetFocus(); + SetReturnCode( 0 ); + + // Initialize the layers grid: + m_ActivesLayersCount = g_DesignSettings.m_CopperLayerCount; + m_Pcb = m_Parent->GetBoard(); + + m_LayersCountSelection->SetSelection( m_ActivesLayersCount / 2 ); + + // Initialize the Routable column + SetRoutableLayerStatus(); + + // Initialize the Status column (layers attribute) + LAYER_T typelist[4] = { LT_SIGNAL, LT_POWER, LT_MIXED, LT_JUMPER }; + for( int ii = 0; ii < 4; ii++ ) + { + m_LayersType[ii] = typelist[ii]; + m_LayersTypeName[ii] = CONV_FROM_UTF8( LAYER::ShowType( typelist[ii] ) ); + } + + for( int ii = 0; ii < m_gridLayersProperties->GetNumberRows(); ii++ ) + { + m_gridLayersProperties->SetCellEditor( ii, LAYERS_GRID_STATUS_POSITION, + new wxGridCellChoiceEditor( WXSIZEOF( + m_LayersTypeName ), + m_LayersTypeName ) ); + int select = LT_SIGNAL; + for( int jj = 0; jj < 4; jj++ ) + { + int layer = LAYER_CMP_N - ii; + if( m_Pcb->GetLayerType( layer ) == m_LayersType[jj] ) + { + select = m_LayersType[jj]; + break; + } + } + + m_gridLayersProperties->SetCellValue( ii, LAYERS_GRID_STATUS_POSITION, + m_LayersTypeName[select] ); + m_gridLayersProperties->SetCellOverflow( ii, LAYERS_GRID_STATUS_POSITION, false ); + } + + // Initialize the Name column + for( int ii = 0; ii < m_gridLayersProperties->GetNumberRows(); ii++ ) + { + wxString layer_name = m_Pcb->GetLayerName( LAYER_CMP_N - ii ); + m_gridLayersProperties->SetCellValue( ii, LAYERS_GRID_NAME_POSITION, layer_name ); + } +} + + +/* Initialize the Routable column, and the R/W property of some cells + */ +void DIALOG_COPPER_LAYERS_SETUP::SetRoutableLayerStatus() +{ + m_gridLayersProperties->SetColFormatBool( LAYERS_GRID_ROUTABLE_POSITION ); + for( int ii = 0; ii < m_gridLayersProperties->GetNumberRows(); ii++ ) + { + int layer = LAYER_CMP_N - ii; + wxString value = layer < (m_ActivesLayersCount - 1) ? wxT( "1" ) : wxT( "0" ); + if( m_ActivesLayersCount > 1 && layer == LAYER_CMP_N ) + value = wxT( "1" ); + if( layer == COPPER_LAYER_N ) + value = wxT( "1" ); + m_gridLayersProperties->SetCellValue( ii, LAYERS_GRID_ROUTABLE_POSITION, value ); + m_gridLayersProperties->SetReadOnly( ii, LAYERS_GRID_ROUTABLE_POSITION ); + + // Set to Read Only cell for non existing copper layers: + m_gridLayersProperties->SetReadOnly( ii, LAYERS_GRID_STATUS_POSITION, value != wxT( "1" ) ); + m_gridLayersProperties->SetReadOnly( ii, LAYERS_GRID_NAME_POSITION, value != wxT( "1" ) ); + } +} + + + +/*****************************************************************/ +void DIALOG_COPPER_LAYERS_SETUP::OnCancelButtonClick( wxCommandEvent& event ) +/*****************************************************************/ +{ + EndModal( 0 ); +} + + +/**************************************************************************/ +void DIALOG_COPPER_LAYERS_SETUP::OnOkButtonClick( wxCommandEvent& event ) +/**************************************************************************/ +{ + if( !TestDataValidity() ) + { + DisplayError( this, _( "Errors detected, Abort" ) ); + return; + } + + g_DesignSettings.m_CopperLayerCount = m_ActivesLayersCount; + + // Initialize the new layer name + for( int ii = 0; ii < m_gridLayersProperties->GetNumberRows(); ii++ ) + { + wxString layer_name = m_gridLayersProperties->GetCellValue( ii, LAYERS_GRID_NAME_POSITION ); + if( layer_name != m_Pcb->GetLayerName( LAYER_CMP_N - ii ) ) + { + m_Pcb->SetLayerName( LAYER_CMP_N - ii, layer_name ); + } + } + + // Initialize the layer type + for( int ii = 0; ii < m_gridLayersProperties->GetNumberRows(); ii++ ) + { + wxString txt = m_gridLayersProperties->GetCellValue( ii, LAYERS_GRID_STATUS_POSITION ); + int layer = LAYER_CMP_N - ii; + for( int jj = 0; jj < 3; jj++ ) + { + if( m_LayersTypeName[jj] == txt ) + { + m_Pcb->SetLayerType( layer, m_LayersType[jj] ); + break; + } + } + } + m_Parent->ReCreateLayerBox( NULL ); + + EndModal( wxID_OK ); +} + + +/**************************************************************************/ +void DIALOG_COPPER_LAYERS_SETUP::OnLayerCountClick( wxCommandEvent& event ) +/**************************************************************************/ +{ + m_ActivesLayersCount = m_LayersCountSelection->GetSelection() * 2; + if( m_ActivesLayersCount <= 0 ) + m_ActivesLayersCount = 1; + + // Reinit the routable layers status + SetRoutableLayerStatus(); +} + + +/* TestDataValidity + * Performs a control of data validity + * set the background of a bad cell in RED and display an info message + * @return true if Ok, false if error + */ +bool DIALOG_COPPER_LAYERS_SETUP::TestDataValidity() +{ + bool success = true; + m_MessagesList->SetPage(wxEmptyString); // Clear message list + + // Test duplicate layers names + for( int ii = 0; ii < m_gridLayersProperties->GetNumberRows() - 1; ii++ ) + { + wxString value = m_gridLayersProperties->GetCellValue( ii, LAYERS_GRID_NAME_POSITION ); + for( int jj = ii+1; jj < m_gridLayersProperties->GetNumberRows(); jj++ ) + { + wxString othervalue = m_gridLayersProperties->GetCellValue( ii, + LAYERS_GRID_NAME_POSITION ); + othervalue = m_gridLayersProperties->GetCellValue( jj, LAYERS_GRID_NAME_POSITION ); + if( value.CmpNoCase( othervalue ) == 0 ) // Already exists! + { + wxString text; + text.Printf( _( + "This layer name %s is already existing
" ), + value.GetData() ); + m_MessagesList->AppendToPage( text ); + success = false; + } + } + } + + return success; +} diff --git a/pcbnew/dialog_copper_layers_setup.h b/pcbnew/dialog_copper_layers_setup.h new file mode 100644 index 0000000000..bf430de12e --- /dev/null +++ b/pcbnew/dialog_copper_layers_setup.h @@ -0,0 +1,36 @@ +/////////////////////////////////////////////////////////////////////////////// +/// Class DIALOG_COPPER_LAYERS_SETUP +/////////////////////////////////////////////////////////////////////////////// + +#ifndef __dialog_design_rules_h_ +#define __dialog_design_rules_h_ + +#include "dialog_copper_layers_setup_base.h" + + +class DIALOG_COPPER_LAYERS_SETUP : public DIALOG_COPPER_LAYERS_SETUP_BASE +{ + private: + WinEDA_PcbFrame * m_Parent; + int m_ActivesLayersCount; + BOARD * m_Pcb; + LAYER_T m_LayersType[4]; + wxString m_LayersTypeName[4]; + + private: + void OnCancelButtonClick( wxCommandEvent& event ); + void OnOkButtonClick( wxCommandEvent& event ); + void OnLayerCountClick( wxCommandEvent& event ); + void OnLayerGridLeftClick( wxGridEvent& event ){ event.Skip(); } + void OnLayerGridRighttClick( wxGridEvent& event ){ event.Skip(); } + void Init(); + void SetRoutableLayerStatus( ); + bool TestDataValidity(); + + public: + DIALOG_COPPER_LAYERS_SETUP( WinEDA_PcbFrame* parent ); + ~DIALOG_COPPER_LAYERS_SETUP( ) { }; + +}; + +#endif //__dialog_design_rules_h_ diff --git a/pcbnew/dialog_copper_layers_setup_base.cpp b/pcbnew/dialog_copper_layers_setup_base.cpp new file mode 100644 index 0000000000..77bf404773 --- /dev/null +++ b/pcbnew/dialog_copper_layers_setup_base.cpp @@ -0,0 +1,114 @@ +/////////////////////////////////////////////////////////////////////////// +// C++ code generated with wxFormBuilder (version Apr 16 2008) +// http://www.wxformbuilder.org/ +// +// PLEASE DO "NOT" EDIT THIS FILE! +/////////////////////////////////////////////////////////////////////////// + +#include "dialog_copper_layers_setup_base.h" + +/////////////////////////////////////////////////////////////////////////// + +DIALOG_COPPER_LAYERS_SETUP_BASE::DIALOG_COPPER_LAYERS_SETUP_BASE( wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style ) : wxDialog( parent, id, title, pos, size, style ) +{ + this->SetSizeHints( wxSize( -1,-1 ), wxDefaultSize ); + + wxBoxSizer* bMainSizer; + bMainSizer = new wxBoxSizer( wxVERTICAL ); + + wxBoxSizer* bMainSizerLayers; + bMainSizerLayers = new wxBoxSizer( wxHORIZONTAL ); + + wxString m_LayersCountSelectionChoices[] = { _("1"), _("2"), _("4"), _("6"), _("8"), _("10"), _("12"), _("14"), _("16") }; + int m_LayersCountSelectionNChoices = sizeof( m_LayersCountSelectionChoices ) / sizeof( wxString ); + m_LayersCountSelection = new wxRadioBox( this, ID_LAYERS_COUNT_SELECTION, _("Layers Count"), wxDefaultPosition, wxDefaultSize, m_LayersCountSelectionNChoices, m_LayersCountSelectionChoices, 1, wxRA_SPECIFY_COLS ); + m_LayersCountSelection->SetSelection( 1 ); + bMainSizerLayers->Add( m_LayersCountSelection, 0, wxALL, 5 ); + + m_gridLayersProperties = new wxGrid( this, ID_LAYERS_PROPERTIES, wxDefaultPosition, wxDefaultSize, 0 ); + + // Grid + m_gridLayersProperties->CreateGrid( 16, 3 ); + m_gridLayersProperties->EnableEditing( true ); + m_gridLayersProperties->EnableGridLines( true ); + m_gridLayersProperties->EnableDragGridSize( false ); + m_gridLayersProperties->SetMargins( 0, 0 ); + + // Columns + m_gridLayersProperties->SetColSize( 0, 100 ); + m_gridLayersProperties->SetColSize( 1, 100 ); + m_gridLayersProperties->SetColSize( 2, 150 ); + m_gridLayersProperties->EnableDragColMove( false ); + m_gridLayersProperties->EnableDragColSize( true ); + m_gridLayersProperties->SetColLabelSize( 30 ); + m_gridLayersProperties->SetColLabelValue( 0, _("Active") ); + m_gridLayersProperties->SetColLabelValue( 1, _("Status") ); + m_gridLayersProperties->SetColLabelValue( 2, _("Name") ); + m_gridLayersProperties->SetColLabelAlignment( wxALIGN_CENTRE, wxALIGN_CENTRE ); + + // Rows + m_gridLayersProperties->AutoSizeRows(); + m_gridLayersProperties->EnableDragRowSize( true ); + m_gridLayersProperties->SetRowLabelSize( 80 ); + m_gridLayersProperties->SetRowLabelValue( 0, _("Top Layer") ); + m_gridLayersProperties->SetRowLabelValue( 1, _("Inner 14") ); + m_gridLayersProperties->SetRowLabelValue( 2, _("Inner 13") ); + m_gridLayersProperties->SetRowLabelValue( 3, _("Inner 12") ); + m_gridLayersProperties->SetRowLabelValue( 4, _("Inner 11") ); + m_gridLayersProperties->SetRowLabelValue( 5, _("Inner 10") ); + m_gridLayersProperties->SetRowLabelValue( 6, _("Inner 9") ); + m_gridLayersProperties->SetRowLabelValue( 7, _("Inner 8") ); + m_gridLayersProperties->SetRowLabelValue( 8, _("Inner 7") ); + m_gridLayersProperties->SetRowLabelValue( 9, _("Inner 6") ); + m_gridLayersProperties->SetRowLabelValue( 10, _("Inner 5") ); + m_gridLayersProperties->SetRowLabelValue( 11, _("Inner 4") ); + m_gridLayersProperties->SetRowLabelValue( 12, _("Inner 3") ); + m_gridLayersProperties->SetRowLabelValue( 13, _("Inner 2") ); + m_gridLayersProperties->SetRowLabelValue( 14, _("Inner 1") ); + m_gridLayersProperties->SetRowLabelValue( 15, _("Bottom Layer") ); + m_gridLayersProperties->SetRowLabelAlignment( wxALIGN_CENTRE, wxALIGN_CENTRE ); + + // Label Appearance + + // Cell Defaults + m_gridLayersProperties->SetDefaultCellAlignment( wxALIGN_CENTRE, wxALIGN_CENTRE ); + bMainSizerLayers->Add( m_gridLayersProperties, 1, wxALL|wxEXPAND, 5 ); + + bMainSizer->Add( bMainSizerLayers, 1, wxEXPAND, 5 ); + + wxStaticBoxSizer* sbSizer1; + sbSizer1 = new wxStaticBoxSizer( new wxStaticBox( this, wxID_ANY, _("Messages:") ), wxVERTICAL ); + + m_MessagesList = new wxHtmlWindow( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxHW_SCROLLBAR_AUTO ); + sbSizer1->Add( m_MessagesList, 1, wxEXPAND|wxBOTTOM|wxRIGHT|wxLEFT, 5 ); + + bMainSizer->Add( sbSizer1, 1, wxEXPAND, 5 ); + + m_sdbSizer1 = new wxStdDialogButtonSizer(); + m_sdbSizer1OK = new wxButton( this, wxID_OK ); + m_sdbSizer1->AddButton( m_sdbSizer1OK ); + m_sdbSizer1Cancel = new wxButton( this, wxID_CANCEL ); + m_sdbSizer1->AddButton( m_sdbSizer1Cancel ); + m_sdbSizer1->Realize(); + bMainSizer->Add( m_sdbSizer1, 0, wxALIGN_RIGHT, 5 ); + + this->SetSizer( bMainSizer ); + this->Layout(); + + // Connect Events + m_LayersCountSelection->Connect( wxEVT_COMMAND_RADIOBOX_SELECTED, wxCommandEventHandler( DIALOG_COPPER_LAYERS_SETUP_BASE::OnLayerCountClick ), NULL, this ); + m_gridLayersProperties->Connect( wxEVT_GRID_CELL_LEFT_CLICK, wxGridEventHandler( DIALOG_COPPER_LAYERS_SETUP_BASE::OnLayerGridLeftClick ), NULL, this ); + m_gridLayersProperties->Connect( wxEVT_GRID_CELL_RIGHT_CLICK, wxGridEventHandler( DIALOG_COPPER_LAYERS_SETUP_BASE::OnLayerGridRighttClick ), NULL, this ); + m_sdbSizer1Cancel->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_COPPER_LAYERS_SETUP_BASE::OnCancelButtonClick ), NULL, this ); + m_sdbSizer1OK->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_COPPER_LAYERS_SETUP_BASE::OnOkButtonClick ), NULL, this ); +} + +DIALOG_COPPER_LAYERS_SETUP_BASE::~DIALOG_COPPER_LAYERS_SETUP_BASE() +{ + // Disconnect Events + m_LayersCountSelection->Disconnect( wxEVT_COMMAND_RADIOBOX_SELECTED, wxCommandEventHandler( DIALOG_COPPER_LAYERS_SETUP_BASE::OnLayerCountClick ), NULL, this ); + m_gridLayersProperties->Disconnect( wxEVT_GRID_CELL_LEFT_CLICK, wxGridEventHandler( DIALOG_COPPER_LAYERS_SETUP_BASE::OnLayerGridLeftClick ), NULL, this ); + m_gridLayersProperties->Disconnect( wxEVT_GRID_CELL_RIGHT_CLICK, wxGridEventHandler( DIALOG_COPPER_LAYERS_SETUP_BASE::OnLayerGridRighttClick ), NULL, this ); + m_sdbSizer1Cancel->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_COPPER_LAYERS_SETUP_BASE::OnCancelButtonClick ), NULL, this ); + m_sdbSizer1OK->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_COPPER_LAYERS_SETUP_BASE::OnOkButtonClick ), NULL, this ); +} diff --git a/pcbnew/dialog_copper_layers_setup_base.fbp b/pcbnew/dialog_copper_layers_setup_base.fbp new file mode 100644 index 0000000000..4a1e87d3d8 --- /dev/null +++ b/pcbnew/dialog_copper_layers_setup_base.fbp @@ -0,0 +1,349 @@ + + + + + + C++ + 1 + UTF-8 + connect + dialog_copper_layers_setup_base + 1000 + none + 1 + dialog_copper_layers_setup_base + + . + + 1 + 0 + 0 + + + + + 1 + + + + 0 + wxID_ANY + + -1,-1 + DIALOG_COPPER_LAYERS_SETUP_BASE + + 558,479 + wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER + + Copper layers setup + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + bMainSizer + wxVERTICAL + none + + 5 + wxEXPAND + 1 + + + bMainSizerLayers + wxHORIZONTAL + none + + 5 + wxALL + 0 + + + "1" "2" "4" "6" "8" "10" "12" "14" "16" + + 1 + + + 0 + ID_LAYERS_COUNT_SELECTION + Layers Count + 1 + + + m_LayersCountSelection + protected + + 1 + + wxRA_SPECIFY_COLS + + + + + + + + + + + + + + + + + + + + + + + OnLayerCountClick + + + + + + + + + + 5 + wxALL|wxEXPAND + 1 + + 0 + 1 + + + + wxALIGN_CENTRE + + wxALIGN_CENTRE + wxALIGN_CENTRE + 30 + "Active" "Status" "Name" + wxALIGN_CENTRE + 3 + 100,100,150 + + 0 + 1 + 0 + 1 + 1 + 1 + + + + 1 + 0 + ID_LAYERS_PROPERTIES + + + + 0 + 0 + + -1,-1 + m_gridLayersProperties + protected + + wxALIGN_CENTRE + 80 + "Top Layer" "Inner 14" "Inner 13" "Inner 12" "Inner 11" "Inner 10" "Inner 9" "Inner 8" "Inner 7" "Inner 6" "Inner 5" "Inner 4" "Inner 3" "Inner 2" "Inner 1" "Bottom Layer" + wxALIGN_CENTRE + + 16 + + + + + + + + + + + OnLayerGridLeftClick + + OnLayerGridRighttClick + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxEXPAND + 1 + + wxID_ANY + Messages: + + sbSizer1 + wxVERTICAL + none + + + 5 + wxEXPAND|wxBOTTOM|wxRIGHT|wxLEFT + 1 + + + + 1 + + + 0 + wxID_ANY + + + m_MessagesList + protected + + + wxHW_SCROLLBAR_AUTO + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALIGN_RIGHT + 0 + + 0 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + + m_sdbSizer1 + protected + + OnCancelButtonClick + + + + OnOkButtonClick + + + + + + + + diff --git a/pcbnew/dialog_copper_layers_setup_base.h b/pcbnew/dialog_copper_layers_setup_base.h new file mode 100644 index 0000000000..bd6ece8cbe --- /dev/null +++ b/pcbnew/dialog_copper_layers_setup_base.h @@ -0,0 +1,60 @@ +/////////////////////////////////////////////////////////////////////////// +// C++ code generated with wxFormBuilder (version Apr 16 2008) +// http://www.wxformbuilder.org/ +// +// PLEASE DO "NOT" EDIT THIS FILE! +/////////////////////////////////////////////////////////////////////////// + +#ifndef __dialog_copper_layers_setup_base__ +#define __dialog_copper_layers_setup_base__ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/////////////////////////////////////////////////////////////////////////// + +#define ID_LAYERS_COUNT_SELECTION 1000 +#define ID_LAYERS_PROPERTIES 1001 + +/////////////////////////////////////////////////////////////////////////////// +/// Class DIALOG_COPPER_LAYERS_SETUP_BASE +/////////////////////////////////////////////////////////////////////////////// +class DIALOG_COPPER_LAYERS_SETUP_BASE : public wxDialog +{ + private: + + protected: + wxRadioBox* m_LayersCountSelection; + wxGrid* m_gridLayersProperties; + wxHtmlWindow* m_MessagesList; + wxStdDialogButtonSizer* m_sdbSizer1; + wxButton* m_sdbSizer1OK; + wxButton* m_sdbSizer1Cancel; + + // Virtual event handlers, overide them in your derived class + virtual void OnLayerCountClick( wxCommandEvent& event ){ event.Skip(); } + virtual void OnLayerGridLeftClick( wxGridEvent& event ){ event.Skip(); } + virtual void OnLayerGridRighttClick( wxGridEvent& event ){ event.Skip(); } + virtual void OnCancelButtonClick( wxCommandEvent& event ){ event.Skip(); } + virtual void OnOkButtonClick( wxCommandEvent& event ){ event.Skip(); } + + + public: + DIALOG_COPPER_LAYERS_SETUP_BASE( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("Copper layers setup"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( 558,479 ), long style = wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER ); + ~DIALOG_COPPER_LAYERS_SETUP_BASE(); + +}; + +#endif //__dialog_copper_layers_setup_base__ diff --git a/pcbnew/dialog_design_rules.cpp b/pcbnew/dialog_design_rules.cpp index 34f8cfd974..d28d393ba4 100644 --- a/pcbnew/dialog_design_rules.cpp +++ b/pcbnew/dialog_design_rules.cpp @@ -290,6 +290,9 @@ static void class2gridRow( wxGrid* grid, int row, NETCLASS* nc, int units ) grid->SetCellValue( row, GRID_uVIADRILL, msg ); } +/** Function InitRulesList() + * Fill the grid showing current rules with values + */ void DIALOG_DESIGN_RULES::InitRulesList() { NETCLASSES& netclasses = m_Pcb->m_NetClasses; @@ -300,8 +303,10 @@ void DIALOG_DESIGN_RULES::InitRulesList() m_grid->AppendRows( netclasses.GetCount()+1 - m_grid->GetNumberRows() ); } + // enter the Default NETCLASS. class2gridRow( m_grid, 0, netclasses.GetDefault(), m_Parent->m_InternalUnits ); + // enter others netclasses int row = 1; for( NETCLASSES::iterator i=netclasses.begin(); i!=netclasses.end(); ++i, ++row ) { @@ -326,7 +331,7 @@ static void gridRow2class( wxGrid* grid, int row, NETCLASS* nc, int units ) } -/* Copy the rules list to board +/* Copy the rules list from grid to board */ void DIALOG_DESIGN_RULES::CopyRulesListToBoard() { @@ -452,6 +457,44 @@ void DIALOG_DESIGN_RULES::OnRemoveNetclassClick( wxCommandEvent& event ) InitializeRulesSelectionBoxes(); } +/* + * Called on "Move Up" button click + * the selected(s) rules are moved up + * The default netclass is always the first rule + */ +void DIALOG_DESIGN_RULES::OnMoveUpSelectedNetClass( wxCommandEvent& event ) +{ + // Cannot move up rules if we have 1 or 2 rules only + if( m_grid->GetNumberRows() < 3 ) + return; + wxArrayInt select = m_grid->GetSelectedRows(); + + bool reinit = false; + for( unsigned irow = 0; irow < select.GetCount(); irow++ ) + { + int ii = select[irow]; + if( ii < 2 ) // The default netclass *must* be the first netclass + continue; // so we cannot move up line 0 and 1 + // Swap the rule and the previous rule + wxString curr_value, previous_value; + for( int icol = 0; icol < m_grid->GetNumberCols(); icol++ ) + { + reinit = true; + curr_value = m_grid->GetCellValue( ii, icol ); + previous_value = m_grid->GetCellValue( ii-1, icol ); + m_grid->SetCellValue( ii, icol, previous_value ); + m_grid->SetCellValue( ii-1, icol, curr_value ); + } + curr_value = m_grid->GetRowLabelValue( ii ); + previous_value = m_grid->GetRowLabelValue( ii-1 ); + m_grid->SetRowLabelValue(ii, previous_value ); + m_grid->SetRowLabelValue(ii-1, curr_value ); + } + + if( reinit ) + InitializeRulesSelectionBoxes(); +} + /* * Called on the left Choice Box selection diff --git a/pcbnew/dialog_design_rules.h b/pcbnew/dialog_design_rules.h index 7f8a565358..f57d3abbb3 100644 --- a/pcbnew/dialog_design_rules.h +++ b/pcbnew/dialog_design_rules.h @@ -42,15 +42,16 @@ private: NETCUPS m_AllNets; private: - void OnLayerCountClick( wxCommandEvent& event ); - void OnLayerGridLeftClick( wxGridEvent& event ){ event.Skip(); } - void OnLayerGridRighttClick( wxGridEvent& event ){ event.Skip(); } +// void OnLayerCountClick( wxCommandEvent& event ); +// void OnLayerGridLeftClick( wxGridEvent& event ){ event.Skip(); } +// void OnLayerGridRighttClick( wxGridEvent& event ){ event.Skip(); } void OnNetClassesGridLeftClick( wxGridEvent& event ){ event.Skip(); } void OnNetClassesGridRightClick( wxGridEvent& event ){ event.Skip(); } void OnCancelButtonClick( wxCommandEvent& event ); void OnOkButtonClick( wxCommandEvent& event ); void OnAddNetclassClick( wxCommandEvent& event ); void OnRemoveNetclassClick( wxCommandEvent& event ); + void OnMoveUpSelectedNetClass( wxCommandEvent& event ); void OnLeftCBSelection( wxCommandEvent& event ); void OnRightCBSelection( wxCommandEvent& event ); void OnRightToLeftCopyButton( wxCommandEvent& event ); diff --git a/pcbnew/dialog_design_rules_base.cpp b/pcbnew/dialog_design_rules_base.cpp index cce56e34b0..1d238a4013 100644 --- a/pcbnew/dialog_design_rules_base.cpp +++ b/pcbnew/dialog_design_rules_base.cpp @@ -1,5 +1,5 @@ /////////////////////////////////////////////////////////////////////////// -// C++ code generated with wxFormBuilder (version Sep 9 2009) +// C++ code generated with wxFormBuilder (version Apr 16 2008) // http://www.wxformbuilder.org/ // // PLEASE DO "NOT" EDIT THIS FILE! @@ -79,7 +79,7 @@ DIALOG_DESIGN_RULES_BASE::DIALOG_DESIGN_RULES_BASE( wxWindow* parent, wxWindowID buttonBoxSizer->Add( m_moveUpButton, 0, wxALL, 5 ); - sbSizer1->Add( buttonBoxSizer, 0, wxALIGN_CENTER_HORIZONTAL|wxBOTTOM, 5 ); + sbSizer1->Add( buttonBoxSizer, 0, wxALIGN_CENTER_HORIZONTAL, 5 ); bMainSizer->Add( sbSizer1, 1, wxALL|wxEXPAND, 5 ); @@ -138,7 +138,7 @@ DIALOG_DESIGN_RULES_BASE::DIALOG_DESIGN_RULES_BASE( wxWindow* parent, wxWindowID sbSizer4->Add( rghtNetSelectBoxSizer, 0, wxALL|wxEXPAND, 5 ); - bMainSizer->Add( sbSizer4, 2, wxALL|wxEXPAND, 5 ); + bMainSizer->Add( sbSizer4, 2, wxEXPAND|wxBOTTOM|wxRIGHT|wxLEFT, 5 ); wxStaticBoxSizer* sbSizer2; sbSizer2 = new wxStaticBoxSizer( new wxStaticBox( this, wxID_ANY, _("Messages:") ), wxHORIZONTAL ); @@ -146,7 +146,7 @@ DIALOG_DESIGN_RULES_BASE::DIALOG_DESIGN_RULES_BASE( wxWindow* parent, wxWindowID m_MessagesList = new wxHtmlWindow( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxHW_SCROLLBAR_AUTO|wxSUNKEN_BORDER ); m_MessagesList->SetMinSize( wxSize( -1,100 ) ); - sbSizer2->Add( m_MessagesList, 1, wxALL|wxEXPAND, 5 ); + sbSizer2->Add( m_MessagesList, 1, wxEXPAND|wxRIGHT|wxLEFT, 5 ); bMainSizer->Add( sbSizer2, 0, wxALL|wxEXPAND, 5 ); @@ -166,6 +166,7 @@ DIALOG_DESIGN_RULES_BASE::DIALOG_DESIGN_RULES_BASE( wxWindow* parent, wxWindowID m_grid->Connect( wxEVT_GRID_CELL_RIGHT_CLICK, wxGridEventHandler( DIALOG_DESIGN_RULES_BASE::OnNetClassesGridRightClick ), NULL, this ); m_addButton->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_DESIGN_RULES_BASE::OnAddNetclassClick ), NULL, this ); m_removeButton->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_DESIGN_RULES_BASE::OnRemoveNetclassClick ), NULL, this ); + m_moveUpButton->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_DESIGN_RULES_BASE::OnMoveUpSelectedNetClass ), NULL, this ); m_leftClassChoice->Connect( wxEVT_COMMAND_CHOICE_SELECTED, wxCommandEventHandler( DIALOG_DESIGN_RULES_BASE::OnLeftCBSelection ), NULL, this ); m_buttonRightToLeft->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_DESIGN_RULES_BASE::OnRightToLeftCopyButton ), NULL, this ); m_buttonLeftToRight->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_DESIGN_RULES_BASE::OnLeftToRightCopyButton ), NULL, this ); @@ -183,6 +184,7 @@ DIALOG_DESIGN_RULES_BASE::~DIALOG_DESIGN_RULES_BASE() m_grid->Disconnect( wxEVT_GRID_CELL_RIGHT_CLICK, wxGridEventHandler( DIALOG_DESIGN_RULES_BASE::OnNetClassesGridRightClick ), NULL, this ); m_addButton->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_DESIGN_RULES_BASE::OnAddNetclassClick ), NULL, this ); m_removeButton->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_DESIGN_RULES_BASE::OnRemoveNetclassClick ), NULL, this ); + m_moveUpButton->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_DESIGN_RULES_BASE::OnMoveUpSelectedNetClass ), NULL, this ); m_leftClassChoice->Disconnect( wxEVT_COMMAND_CHOICE_SELECTED, wxCommandEventHandler( DIALOG_DESIGN_RULES_BASE::OnLeftCBSelection ), NULL, this ); m_buttonRightToLeft->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_DESIGN_RULES_BASE::OnRightToLeftCopyButton ), NULL, this ); m_buttonLeftToRight->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_DESIGN_RULES_BASE::OnLeftToRightCopyButton ), NULL, this ); @@ -191,5 +193,4 @@ DIALOG_DESIGN_RULES_BASE::~DIALOG_DESIGN_RULES_BASE() m_rightClassChoice->Disconnect( wxEVT_COMMAND_CHOICE_SELECTED, wxCommandEventHandler( DIALOG_DESIGN_RULES_BASE::OnRightCBSelection ), NULL, this ); m_sdbSizer1Cancel->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_DESIGN_RULES_BASE::OnCancelButtonClick ), NULL, this ); m_sdbSizer1OK->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_DESIGN_RULES_BASE::OnOkButtonClick ), NULL, this ); - } diff --git a/pcbnew/dialog_design_rules_base.fbp b/pcbnew/dialog_design_rules_base.fbp index acac7ea2f6..035b13c158 100644 --- a/pcbnew/dialog_design_rules_base.fbp +++ b/pcbnew/dialog_design_rules_base.fbp @@ -1,12 +1,10 @@ - + C++ 1 - source_name - 0 UTF-8 connect dialog_design_rules_base @@ -18,16 +16,13 @@ . 1 - 1 0 0 - 1 1 - impl_virtual @@ -37,15 +32,11 @@ 600,520 DIALOG_DESIGN_RULES_BASE - 750,520 + 750,692 wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER Design Rules Editor - - wxFILTER_NONE - wxDefaultValidator - @@ -116,7 +107,6 @@ 6 100,100,100,100,100 - 1 0 1 0 @@ -148,10 +138,6 @@ Net Class parameters - - wxFILTER_NONE|wxFILTER_NUMERIC - wxDefaultValidator - wxHSCROLL|wxSIMPLE_BORDER|wxVSCROLL @@ -214,7 +200,7 @@ 5 - wxALIGN_CENTER_HORIZONTAL|wxBOTTOM + wxALIGN_CENTER_HORIZONTAL 0 @@ -228,7 +214,6 @@ - 1 0 1 @@ -245,10 +230,6 @@ Add another Net Class - - wxFILTER_NONE - wxDefaultValidator - @@ -285,7 +266,6 @@ - 1 0 1 @@ -302,10 +282,6 @@ Remove the currently select Net Class - - wxFILTER_NONE - wxDefaultValidator - @@ -342,7 +318,6 @@ - 1 0 1 @@ -359,14 +334,10 @@ Move the currently selected Net Class up one row - - wxFILTER_NONE - wxDefaultValidator - - + OnMoveUpSelectedNetClass @@ -398,7 +369,7 @@ 5 - wxALL|wxEXPAND + wxEXPAND|wxBOTTOM|wxRIGHT|wxLEFT 2 wxID_ANY @@ -425,7 +396,6 @@ - 1 1 @@ -440,10 +410,6 @@ - - wxFILTER_NONE - wxDefaultValidator - @@ -480,7 +446,6 @@ - 1 1 @@ -495,10 +460,6 @@ wxLC_HRULES|wxLC_REPORT|wxLC_VRULES - - wxFILTER_NONE - wxDefaultValidator - @@ -565,7 +526,6 @@ - 1 0 1 @@ -582,10 +542,6 @@ - - wxFILTER_NONE - wxDefaultValidator - @@ -622,7 +578,6 @@ - 1 0 1 @@ -639,10 +594,6 @@ - - wxFILTER_NONE - wxDefaultValidator - @@ -688,7 +639,6 @@ - 1 0 1 @@ -705,10 +655,6 @@ - - wxFILTER_NONE - wxDefaultValidator - @@ -745,7 +691,6 @@ - 1 0 1 @@ -762,10 +707,6 @@ - - wxFILTER_NONE - wxDefaultValidator - @@ -816,7 +757,6 @@ - 1 1 @@ -831,10 +771,6 @@ - - wxFILTER_NONE - wxDefaultValidator - @@ -871,7 +807,6 @@ - 1 1 @@ -886,10 +821,6 @@ wxLC_HRULES|wxLC_REPORT|wxLC_VRULES - - wxFILTER_NONE - wxDefaultValidator - @@ -956,12 +887,11 @@ 5 - wxALL|wxEXPAND + wxEXPAND|wxRIGHT|wxLEFT 1 - 1 1 @@ -976,10 +906,6 @@ wxHW_SCROLLBAR_AUTO - - wxFILTER_NONE - wxDefaultValidator - wxSUNKEN_BORDER diff --git a/pcbnew/dialog_design_rules_base.h b/pcbnew/dialog_design_rules_base.h index 705d9b505b..e4f5bba6b6 100644 --- a/pcbnew/dialog_design_rules_base.h +++ b/pcbnew/dialog_design_rules_base.h @@ -1,5 +1,5 @@ /////////////////////////////////////////////////////////////////////////// -// C++ code generated with wxFormBuilder (version Sep 9 2009) +// C++ code generated with wxFormBuilder (version Apr 16 2008) // http://www.wxformbuilder.org/ // // PLEASE DO "NOT" EDIT THIS FILE! @@ -59,23 +59,23 @@ class DIALOG_DESIGN_RULES_BASE : public wxDialog wxButton* m_sdbSizer1Cancel; // Virtual event handlers, overide them in your derived class - virtual void OnNetClassesGridLeftClick( wxGridEvent& event ) { event.Skip(); } - virtual void OnNetClassesGridRightClick( wxGridEvent& event ) { event.Skip(); } - virtual void OnAddNetclassClick( wxCommandEvent& event ) { event.Skip(); } - virtual void OnRemoveNetclassClick( wxCommandEvent& event ) { event.Skip(); } - virtual void OnLeftCBSelection( wxCommandEvent& event ) { event.Skip(); } - virtual void OnRightToLeftCopyButton( wxCommandEvent& event ) { event.Skip(); } - virtual void OnLeftToRightCopyButton( wxCommandEvent& event ) { event.Skip(); } - virtual void OnLeftSelectAllButton( wxCommandEvent& event ) { event.Skip(); } - virtual void OnRightSelectAllButton( wxCommandEvent& event ) { event.Skip(); } - virtual void OnRightCBSelection( wxCommandEvent& event ) { event.Skip(); } - virtual void OnCancelButtonClick( wxCommandEvent& event ) { event.Skip(); } - virtual void OnOkButtonClick( wxCommandEvent& event ) { event.Skip(); } + virtual void OnNetClassesGridLeftClick( wxGridEvent& event ){ event.Skip(); } + virtual void OnNetClassesGridRightClick( wxGridEvent& event ){ event.Skip(); } + virtual void OnAddNetclassClick( wxCommandEvent& event ){ event.Skip(); } + virtual void OnRemoveNetclassClick( wxCommandEvent& event ){ event.Skip(); } + virtual void OnMoveUpSelectedNetClass( wxCommandEvent& event ){ event.Skip(); } + virtual void OnLeftCBSelection( wxCommandEvent& event ){ event.Skip(); } + virtual void OnRightToLeftCopyButton( wxCommandEvent& event ){ event.Skip(); } + virtual void OnLeftToRightCopyButton( wxCommandEvent& event ){ event.Skip(); } + virtual void OnLeftSelectAllButton( wxCommandEvent& event ){ event.Skip(); } + virtual void OnRightSelectAllButton( wxCommandEvent& event ){ event.Skip(); } + virtual void OnRightCBSelection( wxCommandEvent& event ){ event.Skip(); } + virtual void OnCancelButtonClick( wxCommandEvent& event ){ event.Skip(); } + virtual void OnOkButtonClick( wxCommandEvent& event ){ event.Skip(); } public: - - DIALOG_DESIGN_RULES_BASE( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("Design Rules Editor"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( 750,520 ), long style = wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER ); + DIALOG_DESIGN_RULES_BASE( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("Design Rules Editor"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( 750,692 ), long style = wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER ); ~DIALOG_DESIGN_RULES_BASE(); }; diff --git a/pcbnew/menubarpcb.cpp b/pcbnew/menubarpcb.cpp index f270742d73..fd6ec850cf 100644 --- a/pcbnew/menubarpcb.cpp +++ b/pcbnew/menubarpcb.cpp @@ -185,6 +185,11 @@ void WinEDA_PcbFrame::ReCreateMenuBar() item->SetBitmap( preference_xpm ); configmenu->Append( item ); + item = new wxMenuItem( configmenu, ID_PCB_COPPER_LAYERS_SETUP, _( "Copper &Layers" ), + _( "Select copper layers count and layers names" ) ); + item->SetBitmap( copper_layers_setup_xpm ); + configmenu->Append( item ); + item = new wxMenuItem( configmenu, ID_PCB_DISPLAY_OPTIONS_SETUP, _( "&Display" ), _( "Select how items (pads, tracks texts ... ) are displayed" ) ); item->SetBitmap( display_options_xpm ); diff --git a/pcbnew/pcbcfg.cpp b/pcbnew/pcbcfg.cpp index e1e00db25f..c165efcf9f 100644 --- a/pcbnew/pcbcfg.cpp +++ b/pcbnew/pcbcfg.cpp @@ -18,6 +18,7 @@ #include "id.h" #include "hotkeys.h" #include "protos.h" +#include "dialog_copper_layers_setup.h" /* Routines Locales */ @@ -48,6 +49,13 @@ void WinEDA_PcbFrame::Process_Config( wxCommandEvent& event ) DisplayColorSetupFrame( this, pos ); break; + case ID_PCB_COPPER_LAYERS_SETUP: + { + DIALOG_COPPER_LAYERS_SETUP dialog( this ); + dialog.ShowModal(); + } + break; + case ID_CONFIG_REQ: // Creation de la fenetre de configuration InstallConfigFrame( pos ); break; diff --git a/pcbnew/pcbframe.cpp b/pcbnew/pcbframe.cpp index 6fd70055f5..1147395a3a 100644 --- a/pcbnew/pcbframe.cpp +++ b/pcbnew/pcbframe.cpp @@ -85,6 +85,7 @@ BEGIN_EVENT_TABLE( WinEDA_PcbFrame, WinEDA_BasePcbFrame ) EVT_MENU( ID_COLORS_SETUP, WinEDA_PcbFrame::Process_Config ) EVT_MENU( ID_OPTIONS_SETUP, WinEDA_PcbFrame::Process_Config ) + EVT_MENU( ID_PCB_COPPER_LAYERS_SETUP, WinEDA_PcbFrame::Process_Config ) EVT_MENU( ID_PCB_TRACK_SIZE_SETUP, WinEDA_PcbFrame::Process_Config ) EVT_MENU( ID_PCB_DRAWINGS_WIDTHS_SETUP, WinEDA_PcbFrame::Process_Config ) EVT_MENU( ID_PCB_PAD_SETUP, WinEDA_PcbFrame::Process_Config ) diff --git a/pcbnew/tool_pcb.cpp b/pcbnew/tool_pcb.cpp index 51f59ac2bf..d162ddba88 100644 --- a/pcbnew/tool_pcb.cpp +++ b/pcbnew/tool_pcb.cpp @@ -181,13 +181,13 @@ void WinEDA_PcbFrame::PrepareLayerIndicator() void WinEDA_PcbFrame::ReCreateHToolbar() /******************************************/ -/* Create the main horizontal toolbar for the board editor */ +/* Creates or updates the main horizontal toolbar for the board editor +*/ { wxString msg; if( m_HToolBar != NULL ) { - D(printf("ReCreateHToolbar\n");) SetToolbars(); return; } diff --git a/pcbnew/zones_convert_brd_items_to_polygons.cpp b/pcbnew/zones_convert_brd_items_to_polygons.cpp index 0c7fce48b7..7b8323e2f7 100644 --- a/pcbnew/zones_convert_brd_items_to_polygons.cpp +++ b/pcbnew/zones_convert_brd_items_to_polygons.cpp @@ -35,8 +35,9 @@ // So as a workaround we can use stubs (small tracks segments) to create thermal shape // Define USE_STUBS_FOR_THERMAL to work on this workaround // Currently under development: DO NOT USE -// because the code is not finished, and pcbnew does not work properly when used +// because the code is not really tested, pcbnew can do not work properly when used // Kbool 2.0 has solved some problems, but not all +// Kbool 2.1 has solved some others problems, but not all //#define USE_STUBS_FOR_THERMAL // Used to create data files to debug Kbool @@ -49,10 +50,13 @@ extern void Test_For_Copper_Island_And_Remove( BOARD* aPcb, ZONE_CONTAINER* aZone_container ); +#ifdef CREATE_KBOOL_KEY_FILES +bool s_GenDataForKbool = false; +#endif // Local Functions: #ifdef USE_STUBS_FOR_THERMAL -#warning USE_STUBS_FOR_THERMAL defined for test version: do not use for working pcbnew version +#warning USE_STUBS_FOR_THERMAL is defined: for test version only do not use for working pcbnew version void CreateStubsForThermalShapes(BOARD* aPcb, ZONE_CONTAINER* aZone_container, int aThermalGap, int aCopperThickness, int aMinThicknessValue); @@ -67,6 +71,10 @@ void AddThermalReliefPadPolygon( Bool_Engine* aBooleng, void AddRoundedEndsSegmentPolygon( Bool_Engine* aBooleng, wxPoint aStart, wxPoint aEnd, int aWidth ); +void AddSquareEndsSegmentPolygon( Bool_Engine* aBooleng, + wxPoint aStart, wxPoint aEnd, + int aWidth ); + void AddTextBoxWithClearancePolygon( Bool_Engine* aBooleng, TEXTE_PCB* aText, int aClearanceValue ); @@ -327,9 +335,18 @@ void ZONE_CONTAINER::AddClearanceAreasPolygonsToPolysList( BOARD* aPcb ) return; } +#ifdef CREATE_KBOOL_KEY_FILES + CreateKeyFile(); + OpenEntity("Layer"); + CopyPolygonsFromFilledPolysListToKeyFile(this, 0); +#endif CreateStubsForThermalShapes(aPcb, this, m_ThermalReliefGapValue, m_ThermalReliefCopperBridgeValue, m_ZoneMinThickness); Test_For_Copper_Island_And_Remove_Insulated_Islands( aPcb ); +#ifdef CREATE_KBOOL_KEY_FILES + CloseEntity(); + CloseKeyFile(); +#endif #else // Remove insulated islands: if( GetNet() > 0 ) @@ -448,7 +465,7 @@ void ZONE_CONTAINER::AddClearanceAreasPolygonsToPolysList( BOARD* aPcb ) { dx = (int) ( dx * s_Correction ); dy = dx; -#ifdef CREATE_KBOOL_KEY_FILES +#ifdef CREATE_KBOOL_KEY_FILES_WITH_0_DEG fAngle = 0; #else fAngle = 450; @@ -731,7 +748,18 @@ void CreateStubsForThermalShapes(BOARD* aPcb, ZONE_CONTAINER* aZone_conta int aCopperThickness, int aMinThicknessValue) { EDA_Rect zone_boundingbox = aZone_container->GetBoundingBox(); + bool have_poly_to_add = false; + Bool_Engine * booleng = new Bool_Engine(); + ArmBoolEng( booleng, true ); + TRACK dummy_track(aPcb); + + if( aCopperThickness <= aMinThicknessValue ) + return; + +#ifdef CREATE_KBOOL_KEY_FILES + s_GenDataForKbool = true; +#endif for( MODULE* module = aPcb->m_Modules; module; module = module->Next() ) { for( D_PAD* pad = module->m_Pads; pad != NULL; pad = pad->Next() ) @@ -782,33 +810,44 @@ void CreateStubsForThermalShapes(BOARD* aPcb, ZONE_CONTAINER* aZone_conta if( inside ) { - TRACK*track = new TRACK(aPcb); - track->m_Start = pad->ReturnShapePos(); - track->m_End = ptTest[i]; - track->SetNet(aZone_container->GetNet()); - track->SetLayer(aZone_container->GetLayer() ); - track->m_Width = aCopperThickness; - track->m_TimeStamp = aZone_container->m_TimeStamp; - track->SetState( BEGIN_ONPAD, ON ); - track->start = pad; + dummy_track.m_Start = pad->ReturnShapePos(); + dummy_track.m_End = ptTest[i]; + dummy_track.SetNet(aZone_container->GetNet()); + dummy_track.SetLayer(aZone_container->GetLayer() ); + dummy_track.m_Width = aCopperThickness; + dummy_track.SetState( BEGIN_ONPAD, ON ); + dummy_track.start = pad; // add stub WinEDA_PcbFrame* pcbFrame = (WinEDA_PcbFrame*) aPcb->m_PcbFrame; - if( pcbFrame->GetDrcController()->Drc( track, aPcb->m_Track ) == BAD_DRC ) - delete track; - else + if( pcbFrame->GetDrcController()->Drc( &dummy_track, aPcb->m_Track ) == OK_DRC ) { - // If this approach is developped, one must change the way the stubs are handles in pcbnew - // because insert these stubs as tracks does not work with undo/redo functions - // because these stubs must be deleted when refilling zones outside undo/redo calls - // This code is only for trial only, not for working pcbnew versions. - TRACK* insertBeforeMe = track->GetBestInsertPoint( aPcb ); - aPcb->m_Track.Insert( track, insertBeforeMe ); + have_poly_to_add = true; + // because stubs outlines are drawn with a pen size = aMinThicknessValue, + // the width of the stub is aCopperThickness - aMinThicknessValue + int thickness = dummy_track.m_Width - aMinThicknessValue; + AddRoundedEndsSegmentPolygon( booleng, dummy_track.m_Start, dummy_track.m_End, thickness ); } } } } } +#ifdef CREATE_KBOOL_KEY_FILES + s_GenDataForKbool = false; +#endif + if( have_poly_to_add ) + { + /* Add the main corrected polygon (i.e. the filled area using only one outline) + * in GroupA in Bool_Engine + */ + aZone_container->CopyPolygonsFromFilledPolysListToBoolengine( booleng, GROUP_A ); + /* remove thermal areas (non copper areas) */ + booleng->Do_Operation( BOOL_OR ); + /* put these areas in m_FilledPolysList */ + aZone_container->m_FilledPolysList.clear(); + aZone_container->CopyPolygonsFromBoolengineToFilledPolysList( booleng ); + } + delete booleng; } @@ -914,7 +953,7 @@ void AddThermalReliefPadPolygon( Bool_Engine* aBooleng, corner.x = copper_thickness.x / 2; int y = outer_radius - (aThermalGap / 4); corner.y = (int) sqrt( ( ( (double) y * y ) - (double) corner.x * corner.x ) ); -#ifndef CREATE_KBOOL_KEY_FILES +#ifndef CREATE_KBOOL_KEY_FILES_WITH_0_DEG corners_buffer.push_back( corner ); #endif @@ -951,7 +990,7 @@ void AddThermalReliefPadPolygon( Bool_Engine* aBooleng, // angle = 450 (45.0 degrees orientation) seems work fine. // angle = 0 with thermal shapes without angle < 90 deg has problems in rare circumstances // Note: with the 2 step build ( thermal shapes added after areas are built), 0 seems work -#ifdef CREATE_KBOOL_KEY_FILES +#ifdef CREATE_KBOOL_KEY_FILES_WITH_0_DEG angle = 0; #else angle = 450; @@ -1299,16 +1338,31 @@ void AddRoundedEndsSegmentPolygon( Bool_Engine* aBooleng, int delta = 3600 / s_CircleToSegmentsCount; // rot angle in 0.1 degree + +#ifdef CREATE_KBOOL_KEY_FILES + if( s_GenDataForKbool ) + StartPolygon(s_CircleToSegmentsCount+4, 1); +#endif + + // 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 ); +#ifdef CREATE_KBOOL_KEY_FILES + if( s_GenDataForKbool ) + AddPointXY(corner.x, corner.y); +#endif corner = wxPoint( seg_len, rayon ); RotatePoint( &corner, -delta_angle ); corner += startp; aBooleng->AddPoint( corner.x, corner.y ); +#ifdef CREATE_KBOOL_KEY_FILES + if( s_GenDataForKbool ) + AddPointXY(corner.x, corner.y); +#endif // add right rounded end: for( int ii = delta; ii < 1800; ii += delta ) @@ -1319,17 +1373,29 @@ void AddRoundedEndsSegmentPolygon( Bool_Engine* aBooleng, RotatePoint( &corner, -delta_angle ); corner += startp; aBooleng->AddPoint( corner.x, corner.y ); +#ifdef CREATE_KBOOL_KEY_FILES + if( s_GenDataForKbool ) + AddPointXY(corner.x, corner.y); +#endif } corner = wxPoint( seg_len, -rayon ); RotatePoint( &corner, -delta_angle ); corner += startp; aBooleng->AddPoint( corner.x, corner.y ); +#ifdef CREATE_KBOOL_KEY_FILES + if( s_GenDataForKbool ) + AddPointXY(corner.x, corner.y); +#endif corner = wxPoint( 0, -rayon ); RotatePoint( &corner, -delta_angle ); corner += startp; aBooleng->AddPoint( corner.x, corner.y ); +#ifdef CREATE_KBOOL_KEY_FILES + if( s_GenDataForKbool ) + AddPointXY(corner.x, corner.y); +#endif // add left rounded end: for( int ii = delta; ii < 1800; ii += delta ) @@ -1339,9 +1405,122 @@ void AddRoundedEndsSegmentPolygon( Bool_Engine* aBooleng, RotatePoint( &corner, -delta_angle ); corner += startp; aBooleng->AddPoint( corner.x, corner.y ); +#ifdef CREATE_KBOOL_KEY_FILES + if( s_GenDataForKbool ) + AddPointXY(corner.x, corner.y); +#endif } aBooleng->EndPolygonAdd(); +#ifdef CREATE_KBOOL_KEY_FILES + if( s_GenDataForKbool ) + EndElement(); +#endif +} + +/** Function AddSquareEndsSegmentPolygon + * Add a polygon cutout for a segment (with square ends) in a zone area + */ +void AddSquareEndsSegmentPolygon( 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( ( (double) endp.y * endp.y ) + ( (double) endp.x * endp.x ) ); + + if( !aBooleng->StartPolygonAdd( GROUP_B ) ) + return; // error! + + int delta = 900; // rot angle in 0.1 degree + +#ifdef CREATE_KBOOL_KEY_FILES + if( s_GenDataForKbool ) + StartPolygon(5, 1); +#endif + + // 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 ); +#ifdef CREATE_KBOOL_KEY_FILES + if( s_GenDataForKbool ) + AddPointXY(corner.x, corner.y); +#endif + + corner = wxPoint( seg_len, rayon ); + RotatePoint( &corner, -delta_angle ); + corner += startp; + aBooleng->AddPoint( corner.x, corner.y ); +#ifdef CREATE_KBOOL_KEY_FILES + if( s_GenDataForKbool ) + AddPointXY(corner.x, corner.y); +#endif + + // 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 ); +#ifdef CREATE_KBOOL_KEY_FILES + if( s_GenDataForKbool ) + AddPointXY(corner.x, corner.y); +#endif + } + + corner = wxPoint( seg_len, -rayon ); + RotatePoint( &corner, -delta_angle ); + corner += startp; + aBooleng->AddPoint( corner.x, corner.y ); +#ifdef CREATE_KBOOL_KEY_FILES + if( s_GenDataForKbool ) + AddPointXY(corner.x, corner.y); +#endif + + corner = wxPoint( 0, -rayon ); + RotatePoint( &corner, -delta_angle ); + corner += startp; + aBooleng->AddPoint( corner.x, corner.y ); +#ifdef CREATE_KBOOL_KEY_FILES + if( s_GenDataForKbool ) + AddPointXY(corner.x, corner.y); +#endif + + // 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 ); +#ifdef CREATE_KBOOL_KEY_FILES + if( s_GenDataForKbool ) + AddPointXY(corner.x, corner.y); +#endif + } + + aBooleng->EndPolygonAdd(); +#ifdef CREATE_KBOOL_KEY_FILES + if( s_GenDataForKbool ) + EndElement(); +#endif } @@ -1487,6 +1666,7 @@ int ZONE_CONTAINER::CopyPolygonsFromBoolengineToFilledPolysList( Bool_Engine* aB corner.end_contour = false; // Flag this corner if starting a hole connection segment: + // This is used by draw functions to draw only useful segments (and not extra segments) corner.utility = (aBoolengine->GetPolygonPointEdgeType() == KB_FALSE_EDGE) ? 1 : 0; m_FilledPolysList.push_back( corner ); count++; diff --git a/polygon/PolyLine.cpp b/polygon/PolyLine.cpp index f117d1ea5e..4f289defee 100644 --- a/polygon/PolyLine.cpp +++ b/polygon/PolyLine.cpp @@ -538,15 +538,17 @@ void ArmBoolEng( Bool_Engine* aBooleng, bool aConvertHoles ) Within the algorithm all input data is multiplied with DGRID, and the result is rounded to an integer. */ - double DGRID = 10.0; // round coordinate X or Y value in calculations to this (initial value = 1000.0 in kbool example) + double DGRID = 1.0; // round coordinate X or Y value in calculations to this (initial value = 1000.0 in kbool example) + // kbool uses DGRID to convert float user units to integer + // kbool unit = (int)(user unit * DGRID) // Note: in kicad, coordinates are already integer so DGRID could be set to 1 - // we choose a DGRID = 10 to have a MARGE = 1.0 + // we choose DGRID = 1.0 - double MARGE = 1.0; // snap with in this range points to lines in the intersection routines - // should always be > 1/DGRID a MARGE >= 10/DGRID is ok + double MARGE = 10.0; // snap with in this range points to lines in the intersection routines + // should always be >= 1/DGRID a MARGE >= 10/DGRID is ok // this is also used to remove small segments and to decide when // two segments are in line. ( initial value = 0.001 ) - // For kicad we choose MARGE = 1, with DGRID = 10 + // For kicad we choose MARGE = 10, with DGRID = 1.0 double CORRECTIONFACTOR = 0.0; // correct the polygons by this number: used in BOOL_CORRECTION operation // this operation shrinks a polygon if CORRECTIONFACTOR < 0 @@ -578,6 +580,10 @@ void ArmBoolEng( Bool_Engine* aBooleng, bool aConvertHoles ) if( aConvertHoles ) { +#if 1 // Can be set to 1 for kbool version >= 2.1, must be set to 0 for previous versions + // SetAllowNonTopHoleLinking() exists only in kbool >= 2.1 + aBooleng->SetAllowNonTopHoleLinking( false ); // Default = true, but i have problems (filling errors) when true +#endif aBooleng->SetLinkHoles( true ); // holes will be connected by double overlapping segments aBooleng->SetOrientationEntryMode( false ); // all polygons are contours, not holes } diff --git a/polygon/kbool/include/kbool/_dl_itr.h b/polygon/kbool/include/kbool/_dl_itr.h index 4c19972ba8..6e9c8ff073 100644 --- a/polygon/kbool/include/kbool/_dl_itr.h +++ b/polygon/kbool/include/kbool/_dl_itr.h @@ -5,7 +5,7 @@ Licence: see kboollicense.txt - RCS-ID: $Id: _dl_itr.h,v 1.5 2009/04/23 19:35:24 titato Exp $ + RCS-ID: $Id: _dl_itr.h,v 1.6 2009/09/10 17:04:09 titato Exp $ */ //! author="Klaas Holwerda" diff --git a/polygon/kbool/include/kbool/_lnk_itr.h b/polygon/kbool/include/kbool/_lnk_itr.h index 6f8791d9b1..3b077ca405 100644 --- a/polygon/kbool/include/kbool/_lnk_itr.h +++ b/polygon/kbool/include/kbool/_lnk_itr.h @@ -5,7 +5,7 @@ Licence: see kboollicense.txt - RCS-ID: $Id: _lnk_itr.h,v 1.3 2009/02/06 21:33:03 titato Exp $ + RCS-ID: $Id: _lnk_itr.h,v 1.4 2009/09/10 17:04:09 titato Exp $ */ //! author="Klaas Holwerda" diff --git a/polygon/kbool/include/kbool/booleng.h b/polygon/kbool/include/kbool/booleng.h index 00ad280871..a48601e260 100644 --- a/polygon/kbool/include/kbool/booleng.h +++ b/polygon/kbool/include/kbool/booleng.h @@ -5,7 +5,7 @@ Licence: see kboollicense.txt - RCS-ID: $Id: booleng.h,v 1.6 2009/09/07 19:23:28 titato Exp $ + RCS-ID: $Id: booleng.h,v 1.9 2009/09/14 18:18:03 titato Exp $ */ #ifndef BOOLENG_H @@ -85,7 +85,7 @@ using namespace std; #define A2DKBOOLDLLEXP_CTORFN #endif -#define KBOOL_VERSION "2.0" +#define KBOOL_VERSION "2.1" #define KBOOL_DEBUG 0 #define KBOOL_LOG 0 @@ -360,6 +360,13 @@ public: //! see SetWindingRule bool GetWindingRule(); + //! when set not only the top vertex of a hole is linked to the other holes and contours, + //! but also vertex other vertexes close to a hole can be used. + void SetAllowNonTopHoleLinking( bool allow ) { m_allowNonTopHoleLinking = allow; } + + //! see SetWindingRule + bool GetAllowNonTopHoleLinking() { return m_allowNonTopHoleLinking; } + //! the smallest accuracy used within the algorithm for comparing two real numbers. double GetAccur(); @@ -547,6 +554,7 @@ private: bool m_orientationEntryMode; bool m_doLinkHoles; + bool m_allowNonTopHoleLinking; //! used in the StartPolygonAdd, AddPt, EndPolygonAdd sequence kbGraph* m_GraphToAdd; diff --git a/polygon/kbool/include/kbool/graph.h b/polygon/kbool/include/kbool/graph.h index 38d153a552..acae6d8b26 100644 --- a/polygon/kbool/include/kbool/graph.h +++ b/polygon/kbool/include/kbool/graph.h @@ -5,10 +5,10 @@ Licence: see kboollicense.txt - RCS-ID: $Id: graph.h,v 1.4 2009/09/07 19:23:28 titato Exp $ + RCS-ID: $Id: graph.h,v 1.5 2009/09/10 17:04:09 titato Exp $ */ -/* @@(#) $Source: /cvsroot/wxart2d/wxArt2D/thirdparty/kbool/include/kbool/graph.h,v $ $Revision: 1.4 $ $Date: 2009/09/07 19:23:28 $ */ +/* @@(#) $Source: /cvsroot/wxart2d/wxArt2D/thirdparty/kbool/include/kbool/graph.h,v $ $Revision: 1.5 $ $Date: 2009/09/10 17:04:09 $ */ /* Program GRAPH.H diff --git a/polygon/kbool/include/kbool/graphlst.h b/polygon/kbool/include/kbool/graphlst.h index 1ed82dcfb2..9bbe771aac 100644 --- a/polygon/kbool/include/kbool/graphlst.h +++ b/polygon/kbool/include/kbool/graphlst.h @@ -5,10 +5,10 @@ Licence: see kboollicense.txt - RCS-ID: $Id: graphlst.h,v 1.3 2008/06/04 21:23:21 titato Exp $ + RCS-ID: $Id: graphlst.h,v 1.4 2009/09/10 17:04:09 titato Exp $ */ -/* @@(#) $Source: /cvsroot/wxart2d/wxArt2D/thirdparty/kbool/include/kbool/graphlst.h,v $ $Revision: 1.3 $ $Date: 2008/06/04 21:23:21 $ */ +/* @@(#) $Source: /cvsroot/wxart2d/wxArt2D/thirdparty/kbool/include/kbool/graphlst.h,v $ $Revision: 1.4 $ $Date: 2009/09/10 17:04:09 $ */ /* Program GRAPHLST.H diff --git a/polygon/kbool/include/kbool/line.h b/polygon/kbool/include/kbool/line.h index 4cd42bb375..351f8c72a4 100644 --- a/polygon/kbool/include/kbool/line.h +++ b/polygon/kbool/include/kbool/line.h @@ -6,7 +6,7 @@ Licence: see kboollicense.txt - RCS-ID: $Id: line.h,v 1.4 2009/09/07 19:23:28 titato Exp $ + RCS-ID: $Id: line.h,v 1.5 2009/09/10 17:04:09 titato Exp $ */ #ifndef LINE_H diff --git a/polygon/kbool/include/kbool/link.h b/polygon/kbool/include/kbool/link.h index 0995bd69de..c01f55c64e 100644 --- a/polygon/kbool/include/kbool/link.h +++ b/polygon/kbool/include/kbool/link.h @@ -6,7 +6,7 @@ Licence: see kboollicense.txt - RCS-ID: $Id: link.h,v 1.4 2009/09/07 19:23:28 titato Exp $ + RCS-ID: $Id: link.h,v 1.5 2009/09/10 17:04:09 titato Exp $ */ #ifndef LINK_H diff --git a/polygon/kbool/include/kbool/lpoint.h b/polygon/kbool/include/kbool/lpoint.h index 6c7e7ecde6..457a87742b 100644 --- a/polygon/kbool/include/kbool/lpoint.h +++ b/polygon/kbool/include/kbool/lpoint.h @@ -5,10 +5,10 @@ Licence: see kboollicense.txt - RCS-ID: $Id: lpoint.h,v 1.3 2008/06/04 21:23:22 titato Exp $ + RCS-ID: $Id: lpoint.h,v 1.4 2009/09/10 17:04:09 titato Exp $ */ -/* @@(#) $Source: /cvsroot/wxart2d/wxArt2D/thirdparty/kbool/include/kbool/lpoint.h,v $ $Revision: 1.3 $ $Date: 2008/06/04 21:23:22 $ */ +/* @@(#) $Source: /cvsroot/wxart2d/wxArt2D/thirdparty/kbool/include/kbool/lpoint.h,v $ $Revision: 1.4 $ $Date: 2009/09/10 17:04:09 $ */ /* Program LPOINT.H diff --git a/polygon/kbool/include/kbool/node.h b/polygon/kbool/include/kbool/node.h index f4a94e3e7d..4539cac2ac 100644 --- a/polygon/kbool/include/kbool/node.h +++ b/polygon/kbool/include/kbool/node.h @@ -6,7 +6,7 @@ Licence: see kboollicense.txt - RCS-ID: $Id: node.h,v 1.4 2009/09/07 19:23:28 titato Exp $ + RCS-ID: $Id: node.h,v 1.7 2009/09/14 16:50:12 titato Exp $ */ #ifndef NODE_H @@ -53,13 +53,15 @@ public: kbLink* GetMost( kbLink* const prev , LinkStatus whatside, BOOL_OP operation ); //! get link that is leading to a hole ( hole segment or linking segment ) - kbLink* GetMostHole( kbLink* const prev , LinkStatus whatside, BOOL_OP operation ); + kbLink* GetMostHole( kbLink* const prev , LinkStatus whatside, BOOL_OP operation, + bool searchholelink = true ); //! get link that is not vertical. kbLink* GetNotFlat(); //! get a link to a hole or from a hole. - kbLink* GetHoleLink( kbLink* const prev, bool checkbin, BOOL_OP operation ); + kbLink* GetHoleLink( kbLink* const prev, LinkStatus whatside, + bool checkbin, BOOL_OP operation ); int Merge( kbNode* ); void RemoveLink( kbLink* ); diff --git a/polygon/kbool/include/kbool/record.h b/polygon/kbool/include/kbool/record.h index 1f81834486..a3f7453d68 100644 --- a/polygon/kbool/include/kbool/record.h +++ b/polygon/kbool/include/kbool/record.h @@ -5,7 +5,7 @@ Licence: see kboollicense.txt - RCS-ID: $Id: record.h,v 1.4 2009/09/07 19:23:28 titato Exp $ + RCS-ID: $Id: record.h,v 1.5 2009/09/10 17:04:09 titato Exp $ */ #ifndef RECORD_H diff --git a/polygon/kbool/include/kbool/scanbeam.h b/polygon/kbool/include/kbool/scanbeam.h index bd3c0be419..6732995308 100644 --- a/polygon/kbool/include/kbool/scanbeam.h +++ b/polygon/kbool/include/kbool/scanbeam.h @@ -5,7 +5,7 @@ Licence: see kboollicense.txt - RCS-ID: $Id: scanbeam.h,v 1.5 2009/09/07 19:23:28 titato Exp $ + RCS-ID: $Id: scanbeam.h,v 1.6 2009/09/10 17:04:09 titato Exp $ */ #ifndef SCANBEAM_H diff --git a/polygon/kbool/src/booleng.cpp b/polygon/kbool/src/booleng.cpp index 788e4cb94e..ac61f3987d 100644 --- a/polygon/kbool/src/booleng.cpp +++ b/polygon/kbool/src/booleng.cpp @@ -5,7 +5,7 @@ Licence: see kboollicense.txt - RCS-ID: $Id: booleng.cpp,v 1.5 2009/09/07 19:23:28 titato Exp $ + RCS-ID: $Id: booleng.cpp,v 1.7 2009/09/14 16:50:12 titato Exp $ */ #include "kbool/booleng.h" @@ -95,6 +95,7 @@ Bool_Engine::Bool_Engine() m_orientationEntryMode = false; m_doLinkHoles = true; + m_allowNonTopHoleLinking = true; m_graphlist = new kbGraphList( this ); m_ACCUR = 1e-4; diff --git a/polygon/kbool/src/graph.cpp b/polygon/kbool/src/graph.cpp index 0c654fde13..67a53854f1 100644 --- a/polygon/kbool/src/graph.cpp +++ b/polygon/kbool/src/graph.cpp @@ -6,7 +6,7 @@ Licence: see kboollicense.txt - RCS-ID: $Id: graph.cpp,v 1.4 2009/09/07 19:23:28 titato Exp $ + RCS-ID: $Id: graph.cpp,v 1.7 2009/09/14 16:50:12 titato Exp $ */ // Grpah is the structure used to store polygons @@ -536,14 +536,14 @@ void kbGraph::CollectGraphLast( kbNode *current_node, BOOL_OP operation, bool de { if ( currentlink->GetHoleLink() ) { - //in case we entered the hole via the hole link just now, we followe the hole. + //in case we entered the hole via the hole link just now, we follow the hole. //This is taking as many holes as possible ( most right around) - nextlink = next_node->GetMostHole( currentlink, IS_RIGHT , operation ); + nextlink = next_node->GetMostHole( currentlink, IS_RIGHT , operation, false ); if ( !nextlink ) // hole done? //if we did get to this hole via a holelink?, then we might now be on the return link. //BTW it is also possible that holes are already found via a non linked hole path, //in that case, we did go to the HoleLink here, and directly return on the other holelink. - nextlink = next_node->GetHoleLink( currentlink, true, operation ); + nextlink = next_node->GetHoleLink( currentlink, IS_RIGHT, true, operation ); if ( !nextlink ) { //we did get to this hole via a holelink and we are on the returning holelink. @@ -554,9 +554,9 @@ void kbGraph::CollectGraphLast( kbNode *current_node, BOOL_OP operation, bool de } else { - nextlink = next_node->GetHoleLink( currentlink, true, operation ); // other linked holes first + nextlink = next_node->GetMostHole( currentlink, IS_RIGHT, operation ); // other holes first if ( !nextlink ) - nextlink = next_node->GetMostHole( currentlink, IS_RIGHT, operation ); // other holes first + nextlink = next_node->GetHoleLink( currentlink, IS_RIGHT, true, operation ); // other linked holes first if ( !nextlink ) { //We are leaving the hole. @@ -568,9 +568,11 @@ void kbGraph::CollectGraphLast( kbNode *current_node, BOOL_OP operation, bool de } else { + //nextlink = next_node->GetMost( currentlink, IS_RIGHT, operation ); + //if ( !nextlink ) //a hole link is preferred above a normal link. If not no holes would be linked in anyway. - nextlink = next_node->GetHoleLink( currentlink, true, operation ); + nextlink = next_node->GetHoleLink( currentlink, IS_RIGHT, true, operation ); if ( !nextlink ) //also if we can get to a hole directly within a contour, that is better (get as much as possible) nextlink = next_node->GetMostHole( currentlink, IS_RIGHT, operation ); @@ -1683,7 +1685,7 @@ void kbGraph::Boolean( BOOL_OP operation, kbGraphList* Result ) Merge_NodeToNode( 0 ); #if KBOOL_LOG == 1 - _GC->SetLog( true ); + //_GC->SetLog( true ); _GC->Write_Log( "LINKHOLES\n" ); #endif writegraph( false ); @@ -1698,7 +1700,7 @@ void kbGraph::Boolean( BOOL_OP operation, kbGraphList* Result ) { //to delete extra points //those extra points are caused by link holes - //and are eqaul + //and are eqaul ( the smallest number in integer is 1 ) DeleteZeroLines( 1 ); _GC->SetState( "extract simples last" ); @@ -2559,6 +2561,7 @@ void kbGraph::WriteKEY( Bool_Engine* GC, FILE* file ) void kbGraph::WriteGraphKEY(Bool_Engine* GC) { #if KBOOL_DEBUG + double scale = 1.0/GC->GetGrid()/GC->GetGrid(); FILE* file = fopen("keygraphfile.key", "w"); diff --git a/polygon/kbool/src/graphlst.cpp b/polygon/kbool/src/graphlst.cpp index 6a413db6ce..64049bae06 100644 --- a/polygon/kbool/src/graphlst.cpp +++ b/polygon/kbool/src/graphlst.cpp @@ -6,7 +6,7 @@ Licence: see kboollicense.txt - RCS-ID: $Id: graphlst.cpp,v 1.3 2008/06/04 21:23:22 titato Exp $ + RCS-ID: $Id: graphlst.cpp,v 1.4 2009/09/10 17:04:09 titato Exp $ */ //#include "debugdrv.h" diff --git a/polygon/kbool/src/line.cpp b/polygon/kbool/src/line.cpp index e626e7f0d1..fffe323dc1 100644 --- a/polygon/kbool/src/line.cpp +++ b/polygon/kbool/src/line.cpp @@ -6,7 +6,7 @@ Licence: see kboollicense.txt - RCS-ID: $Id: line.cpp,v 1.4 2009/09/07 19:23:28 titato Exp $ + RCS-ID: $Id: line.cpp,v 1.6 2009/09/13 18:34:06 titato Exp $ */ // Standard include files @@ -308,7 +308,11 @@ B_INT kbLine::Calculate_Y( B_INT X ) CalculateLineParameters(); if ( m_AA != 0 ) + { + //vertical line is undefined + assert( m_BB ); return ( B_INT )( -( m_AA * X + m_CC ) / m_BB ); + } else // horizontal line return m_link->GetBeginNode()->GetY(); diff --git a/polygon/kbool/src/lpoint.cpp b/polygon/kbool/src/lpoint.cpp index 6c049d0e65..737fedb1a4 100644 --- a/polygon/kbool/src/lpoint.cpp +++ b/polygon/kbool/src/lpoint.cpp @@ -6,7 +6,7 @@ Licence: see kboollicense.txt - RCS-ID: $Id: lpoint.cpp,v 1.3 2008/06/04 21:23:22 titato Exp $ + RCS-ID: $Id: lpoint.cpp,v 1.4 2009/09/10 17:04:09 titato Exp $ */ #include "kbool/lpoint.h" diff --git a/polygon/kbool/src/node.cpp b/polygon/kbool/src/node.cpp index 11677864aa..93ab8b1c20 100644 --- a/polygon/kbool/src/node.cpp +++ b/polygon/kbool/src/node.cpp @@ -6,7 +6,7 @@ Licence: see kboollicense.txt - RCS-ID: $Id: node.cpp,v 1.4 2009/09/07 19:23:28 titato Exp $ + RCS-ID: $Id: node.cpp,v 1.7 2009/09/14 16:50:12 titato Exp $ */ #include "kbool/node.h" @@ -387,7 +387,7 @@ kbLink* kbNode::GetMost( kbLink* const prev , LinkStatus whatside, BOOL_OP opera // on the node get the link // is the most right or left one // This function is used to collect the simple graphs from a graph -kbLink* kbNode::GetMostHole( kbLink* const prev, LinkStatus whatside, BOOL_OP operation ) +kbLink* kbNode::GetMostHole( kbLink* const prev, LinkStatus whatside, BOOL_OP operation, bool searchholelink ) { kbLink * reserve = 0; kbLink *Result = NULL, *link; @@ -397,7 +397,11 @@ kbLink* kbNode::GetMostHole( kbLink* const prev, LinkStatus whatside, BOOL_OP op { if ( ( link = ( kbLink* )_linklist->headitem() ) == prev ) //this is NOT the one to go on link = ( kbLink* )_linklist->tailitem(); - if ( link->GetHole() && !link->GetHoleLink() && !link->BeenHere() && SameSides( prev, link, operation ) ) + if ( + !link->BeenHere() && + link->GetHole() && + ( searchholelink && link->GetHoleLink() || !link->GetHoleLink() ) && + SameSides( prev, link, operation ) ) //we are back where we started (bin is true) return Null return link; return( 0 ); @@ -409,9 +413,10 @@ kbLink* kbNode::GetMostHole( kbLink* const prev, LinkStatus whatside, BOOL_OP op while( !_GC->_linkiter->hitroot() ) { link = _GC->_linkiter->item(); - if ( !link->BeenHere() && - link->GetHole() && - !link->GetHoleLink() && + if ( + !link->BeenHere() && + link->GetHole() && + ( searchholelink && link->GetHoleLink() || !link->GetHoleLink() ) && SameSides( prev, link, operation ) && link != prev //should be set to bin already ) @@ -443,7 +448,7 @@ kbLink* kbNode::GetMostHole( kbLink* const prev, LinkStatus whatside, BOOL_OP op } // this function gets the highest not flat link -kbLink* kbNode::GetHoleLink( kbLink* const prev, bool checkbin, BOOL_OP operation ) +kbLink* kbNode::GetHoleLink( kbLink* const prev, LinkStatus whatside, bool checkbin, BOOL_OP operation ) { kbLink * Result = NULL, *link; @@ -457,8 +462,14 @@ kbLink* kbNode::GetHoleLink( kbLink* const prev, bool checkbin, BOOL_OP operatio SameSides( prev, link, operation ) ) { - Result = link; - break; + if ( !Result ) + Result = link; //first one found sofar + else + { + if ( prev->PointOnCorner( Result, link ) == whatside ) + //more to the whatside than take this one + Result = link; + } } } diff --git a/polygon/kbool/src/record.cpp b/polygon/kbool/src/record.cpp index 0e76ba0e3a..d1e21fac86 100644 --- a/polygon/kbool/src/record.cpp +++ b/polygon/kbool/src/record.cpp @@ -5,7 +5,7 @@ Licence: see kboollicense.txt - RCS-ID: $Id: record.cpp,v 1.4 2009/09/07 19:23:28 titato Exp $ + RCS-ID: $Id: record.cpp,v 1.5 2009/09/10 17:04:09 titato Exp $ */ #include "kbool/booleng.h" diff --git a/polygon/kbool/src/scanbeam.cpp b/polygon/kbool/src/scanbeam.cpp index 7c384753f4..000bdeedca 100644 --- a/polygon/kbool/src/scanbeam.cpp +++ b/polygon/kbool/src/scanbeam.cpp @@ -5,7 +5,7 @@ Licence: see kboollicense.txt - RCS-ID: $Id: scanbeam.cpp,v 1.4 2009/09/07 19:23:28 titato Exp $ + RCS-ID: $Id: scanbeam.cpp,v 1.7 2009/09/14 16:50:12 titato Exp $ */ // class scanbeam @@ -401,7 +401,6 @@ bool ScanBeam::RemoveOld( SCANTYPE scantype, TDLI* _I, bool& holes ) bool found = false; bool foundnew = false; DL_Iter _BBI = DL_Iter(); - bool attached = false; _low = _I->item()->GetBeginNode(); @@ -971,7 +970,7 @@ void ScanBeam::Generate_INOUT( int graphnumber ) // // this function will search the closest link to a hole // step one, search for a link that is marked (this is a hole) -// step two, this is tricky, the closest link is the previous link in +// step two, the closest link is the previous link in // the beam, but only in the beam that contains the highest node // from the marked link. // why ? : if the marked link has for the begin and end node different @@ -998,6 +997,70 @@ bool ScanBeam::ProcessHoles( bool atinsert, TDLI* _LI ) kbRecord* record = _BI.item(); kbLink* link = record->GetLink(); + kbNode* _low = _LI->item()->GetBeginNode(); + + if( _GC->GetAllowNonTopHoleLinking() ) + { + _BI++; + if ( !_BI.hitroot() && _BI.item()->GetLink()->IsTopHole() ) + { + + kbLink* linkToThis = _BI.item()->GetLink(); + //calculate linkToThis its Y at X of topnode. + kbLine line( _GC ); + line.Set( linkToThis ); + B_INT Y; + kbNode * leftnode; //left node of clossest link + //link right now + if ( linkToThis->GetEndNode()->GetX() == _low->GetX() ) + Y = linkToThis->GetEndNode()->GetY(); + else if ( linkToThis->GetBeginNode()->GetX() == _low->GetX() ) + Y = linkToThis->GetBeginNode()->GetY(); + else + Y = line.Calculate_Y( _low->GetX() ); + + if ( linkToThis->GetBeginNode()->GetX() < linkToThis->GetEndNode()->GetX() ) + leftnode = linkToThis->GetBeginNode(); + else + leftnode = linkToThis->GetEndNode(); + kbNode *topnode = new kbNode( _low->GetX(), Y, _GC ); + kbLink *link_A = new kbLink( 0, topnode, leftnode, _GC ); + // the orginal linkToThis + linkToThis->Replace( leftnode, topnode ); + _LI->insbegin( link_A ); + //reset mark to flag that this hole has been processed + linkToThis->SetTopHole( false ); + + kbLink *link_B = new kbLink( 0, _low, topnode, _GC ); + kbLink *link_BB = new kbLink( 0, topnode, _low, _GC ); + _LI->insbegin( link_B ); + _LI->insbegin( link_BB ); + //mark those two segments as hole linking segments + link_B->SetHoleLink( true ); + link_BB->SetHoleLink( true ); + + //is where we come from/link to a hole + bool closest_is_hole = linkToThis->GetHole(); + + // if the polygon linked to, is a hole, this hole here + // just gets bigger, so we take over the links its hole marking. + link_A->SetHole( closest_is_hole ); + link_B->SetHole( closest_is_hole ); + link_BB->SetHole( closest_is_hole ); + + // we have only one operation at the time, taking + // over the operation flags is enough, since the linking segments will + // be part of that output for any operation done. + link_A->TakeOverOperationFlags( linkToThis ); + link_B->TakeOverOperationFlags( linkToThis ); + link_BB->TakeOverOperationFlags( linkToThis ); + + foundholes = true; + + SortTheBeam( atinsert ); + } + _BI--; + } if ( !record->GetLine()->CrossListEmpty() ) { @@ -1009,6 +1072,9 @@ bool ScanBeam::ProcessHoles( bool atinsert, TDLI* _LI ) // make new nodes and links and set them, re-use the old link, so the links // that still stand in the linecrosslist will not be lost. // There is a hole that must be linked to this link ! + + kbLink* linkToThis = link; + TDLI I( record->GetLine()->GetCrossList() ); I.tohead(); while( !I.hitroot() ) @@ -1016,11 +1082,43 @@ bool ScanBeam::ProcessHoles( bool atinsert, TDLI* _LI ) topnode = I.item(); I.remove(); + //calculate linkToThis its Y at X of topnode. kbLine line( _GC ); - line.Set( link ); + line.Set( linkToThis ); - B_INT Y = line.Calculate_Y( topnode->GetX() ); + kbNode * leftnode; //left node of clossest link + B_INT Y; + //check if flatlink ( i think is always linkBB from a topnode at same X coordinate. + //but lets accept all flatlinks + if ( linkToThis->GetEndNode()->GetX() == linkToThis->GetBeginNode()->GetX() ) + { + //we take the lowest of the flatlink nodes, which is right for + // a second hole at same X + if ( linkToThis->GetEndNode()->GetY() >= linkToThis->GetBeginNode()->GetY() ) + { + Y = linkToThis->GetBeginNode()->GetY(); + leftnode = linkToThis->GetBeginNode(); + } + else + { + Y = linkToThis->GetEndNode()->GetY(); + leftnode = linkToThis->GetEndNode(); + } + } + else + { + if ( linkToThis->GetEndNode()->GetX() == topnode->GetX() ) + Y = linkToThis->GetEndNode()->GetY(); + else if ( linkToThis->GetBeginNode()->GetX() == topnode->GetX() ) + Y = linkToThis->GetBeginNode()->GetY(); + else + Y = line.Calculate_Y( topnode->GetX() ); + if ( linkToThis->GetBeginNode()->GetX() < linkToThis->GetEndNode()->GetX() ) + leftnode = linkToThis->GetBeginNode(); + else + leftnode = linkToThis->GetEndNode(); + } // Now we'll create new nodes and new links to make the link between // the graphs. @@ -1031,30 +1129,25 @@ bool ScanBeam::ProcessHoles( bool atinsert, TDLI* _LI ) //because they are left around but the link is always on the //bottom of the hole - // linkA linkD + // linkA linkToThis // o-------->--------NodeA------->------------o - // | | - // | | - // linkB v ^ linkBB - // | | - // | | - // outgoing* | | incoming* + // leftnode | | + // | | + // linkB v ^ linkBB + // | | + // | | + // outgoing* | | incoming* // o------<---------topnode--------<----------o // // all holes are oriented left around - kbNode * leftnode; //left node of clossest link - ( link->GetBeginNode()->GetX() < link->GetEndNode()->GetX() ) ? - leftnode = link->GetBeginNode() : - leftnode = link->GetEndNode(); - kbNode *node_A = new kbNode( topnode->GetX(), Y, _GC ); kbLink *link_A = new kbLink( 0, leftnode, node_A, _GC ); kbLink *link_B = new kbLink( 0, node_A, topnode, _GC ); kbLink *link_BB = new kbLink( 0, topnode, node_A, _GC ); - kbLink *link_D = _BI.item()->GetLink(); - link_D->Replace( leftnode, node_A ); + // the orginal linkToThis + linkToThis->Replace( leftnode, node_A ); _LI->insbegin( link_A ); _LI->insbegin( link_B ); _LI->insbegin( link_BB ); @@ -1064,7 +1157,7 @@ bool ScanBeam::ProcessHoles( bool atinsert, TDLI* _LI ) link_BB->SetHoleLink( true ); //is where we come from/link to a hole - bool closest_is_hole = link->GetHole(); + bool closest_is_hole = linkToThis->GetHole(); // if the polygon linked to, is a hole, this hole here // just gets bigger, so we take over the links its hole marking. @@ -1075,9 +1168,19 @@ bool ScanBeam::ProcessHoles( bool atinsert, TDLI* _LI ) // we have only one operation at the time, taking // over the operation flags is enough, since the linking segments will // be part of that output for any operation done. - link_A->TakeOverOperationFlags( link ); - link_B->TakeOverOperationFlags( link ); - link_BB->TakeOverOperationFlags( link ); + link_A->TakeOverOperationFlags( linkToThis ); + link_B->TakeOverOperationFlags( linkToThis ); + link_BB->TakeOverOperationFlags( linkToThis ); + + // check next top node is at same X + if ( !I.hitroot() ) + { + kbNode *newtopnode = I.item(); + if ( topnode->GetX() == newtopnode->GetX() ) + linkToThis = link_BB; + else + linkToThis = link; + } } }