From cfdb28394e4604e1170a0ca82ce70eaf2ef7697b Mon Sep 17 00:00:00 2001 From: charras Date: Sun, 23 Aug 2009 15:22:44 +0000 Subject: [PATCH] Pcbnew: Work on undo/redo in Pcbnew almost finished. --- CHANGELOG.txt | 5 + include/wxPcbStruct.h | 3 +- pcbnew/CMakeLists.txt | 2 + pcbnew/board_undo_redo.cpp | 3 +- pcbnew/class_board.cpp | 9 +- pcbnew/class_board.h | 59 ++-- pcbnew/class_zone.cpp | 8 +- pcbnew/class_zone.h | 9 +- pcbnew/dialog_copper_zones.cpp | 21 +- pcbnew/dialog_copper_zones.h | 29 +- pcbnew/dialog_pad_properties.cpp | 28 +- pcbnew/dialog_pad_properties_base.cpp | 4 +- pcbnew/dialog_pad_properties_base.fbp | 4 +- pcbnew/dialog_pad_properties_base.h | 2 +- pcbnew/edit.cpp | 5 +- pcbnew/zones.h | 6 +- pcbnew/zones_by_polygon.cpp | 264 ++++++------------ pcbnew/zones_by_polygon_fill_functions.cpp | 175 ++++++++++++ .../zones_convert_brd_items_to_polygons.cpp | 10 +- pcbnew/zones_functions_for_undo_redo.cpp | 258 +++++++++++++++++ pcbnew/zones_functions_for_undo_redo.h | 69 +++++ pcbnew/zones_test_and_combine_areas.cpp | 103 ++++--- polygon/PolyLine.cpp | 13 +- polygon/PolyLine.h | 6 + 24 files changed, 809 insertions(+), 286 deletions(-) create mode 100644 pcbnew/zones_by_polygon_fill_functions.cpp create mode 100644 pcbnew/zones_functions_for_undo_redo.cpp create mode 100644 pcbnew/zones_functions_for_undo_redo.h diff --git a/CHANGELOG.txt b/CHANGELOG.txt index 8ceb89c62d..d4be8c065c 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -4,6 +4,11 @@ KiCad ChangeLog 2009 Please add newer entries at the top, list the date and your name with email address. +2009-aug-23 UPDATE Jean-Pierre Charras +================================================================================ +++pcbnew + Work on undo/redo in pcbnew almost finished. + 2009-Aug-16 UPDATE Dick Hollenbeck ================================================================================ ++pcbnew diff --git a/include/wxPcbStruct.h b/include/wxPcbStruct.h index f75b028cf2..7d1cd8b33c 100644 --- a/include/wxPcbStruct.h +++ b/include/wxPcbStruct.h @@ -479,12 +479,11 @@ public: * The zone outline is a frontier, and can be complex (with holes) * The filling starts from starting points like pads, tracks. * If exists the old filling is removed - * @param DC = current Device Context * @param zone_container = zone to fill * @param verbose = true to show error messages * @return error level (0 = no error) */ - int Fill_Zone( wxDC* DC, ZONE_CONTAINER* zone_container, bool verbose = TRUE ); + int Fill_Zone( ZONE_CONTAINER* zone_container, bool verbose = TRUE ); /** Function Fill_All_Zones() * Fill all zones on the board diff --git a/pcbnew/CMakeLists.txt b/pcbnew/CMakeLists.txt index e86e6c45bb..0c69ba899a 100644 --- a/pcbnew/CMakeLists.txt +++ b/pcbnew/CMakeLists.txt @@ -149,8 +149,10 @@ set(PCBNEW_SRCS work.cpp xchgmod.cpp zones_by_polygon.cpp + zones_by_polygon_fill_functions.cpp zones_convert_brd_items_to_polygons.cpp zone_filling_algorithm.cpp + zones_functions_for_undo_redo.cpp zones_polygons_insulated_copper_islands.cpp zones_polygons_test_connections.cpp zones_test_and_combine_areas.cpp diff --git a/pcbnew/board_undo_redo.cpp b/pcbnew/board_undo_redo.cpp index 6bafce4b8e..fc7057fd6c 100644 --- a/pcbnew/board_undo_redo.cpp +++ b/pcbnew/board_undo_redo.cpp @@ -424,7 +424,8 @@ void WinEDA_PcbFrame::SaveCopyInUndoList( PICKED_ITEMS_LIST& aItemsList, */ if( commandToUndo->GetPickedItemLink( ii ) == NULL ) commandToUndo->SetPickedItemLink( DuplicateStruct( item ), ii ); - wxASSERT( commandToUndo->GetPickedItemLink( ii ) ); + if( commandToUndo->GetPickedItemLink( ii ) == NULL ) + wxMessageBox( wxT( "SaveCopyInUndoList() in UR_CHANGED mode: NULL link" ) ); break; case UR_MOVED: diff --git a/pcbnew/class_board.cpp b/pcbnew/class_board.cpp index e13e95212e..bee5ae99e8 100644 --- a/pcbnew/class_board.cpp +++ b/pcbnew/class_board.cpp @@ -252,7 +252,14 @@ void BOARD::Add( BOARD_ITEM* aBoardItem, int aControl ) // other types may use linked list default: - wxFAIL_MSG( wxT( "BOARD::Add() needs work: BOARD_ITEM type not handled" ) ); + { + wxString msg; + msg.Printf( + wxT( "BOARD::Add() needs work: BOARD_ITEM type (%d) not handled" ), + aBoardItem->Type() ); + wxFAIL_MSG(msg ); + } + break; } } diff --git a/pcbnew/class_board.h b/pcbnew/class_board.h index e8858ae9db..e464445c1f 100644 --- a/pcbnew/class_board.h +++ b/pcbnew/class_board.h @@ -1,6 +1,6 @@ -/**************************************************************/ +/*************************************************/ /* class_board.h - Class BOARD to handle a board */ -/**************************************************************/ +/*************************************************/ #ifndef CLASS_BOARD_H #define CLASS_BOARD_H @@ -474,19 +474,18 @@ public: /* Functions used in test, merge and cut outlines */ - /** - * Function AddArea - * add empty copper area to net + /** Function AddArea + * Add an empty copper area to board areas list + * @param aNewZonesList = a PICKED_ITEMS_LIST * where to store new areas pickers (useful in undo commands) + * can be NULL + * @param aNetcode = the necode of the copper area (0 = no net) + * @param aLayer = the layer of area + * @param aStartPointPosition = position of the first point of the polygon outline of this area + * @param aHatch = hacth option * @return pointer to the new area */ - ZONE_CONTAINER* AddArea( int netcode, int layer, int x, int y, int hatch ); - - /** - * remove copper area from net - * @param area = area to remove - * @return 0 - */ - int RemoveArea( ZONE_CONTAINER* area_to_remove ); + ZONE_CONTAINER* AddArea( PICKED_ITEMS_LIST* aNewZonesList, int aNetcode, + int aLayer, wxPoint aStartPointPosition, int aHatch ); /** * Function InsertArea @@ -522,15 +521,20 @@ public: * Function ClipAreaPolygon * Process an area that has been modified, by clipping its polygon against itself. * This may change the number and order of copper areas in the net. - * @param bMessageBoxInt == TRUE, shows message when clipping occurs. - * @param bMessageBoxArc == TRUE, shows message when clipping can't be done due to arcs. + * @param aNewZonesList = a PICKED_ITEMS_LIST * where to store new areas pickers (useful in undo commands) + * can be NULL + * @param aCurrArea = the zone to process + * @param bMessageBoxInt == true, shows message when clipping occurs. + * @param bMessageBoxArc == true, shows message when clipping can't be done due to arcs. + * @param bRetainArcs = true to handle arcs (not really used in kicad) * @return: * -1 if arcs intersect other sides, so polygon can't be clipped * 0 if no intersecting sides * 1 if intersecting sides * Also sets areas->utility1 flags if areas are modified */ - int ClipAreaPolygon( ZONE_CONTAINER* CurrArea, + int ClipAreaPolygon( PICKED_ITEMS_LIST * aNewZonesList, + ZONE_CONTAINER* aCurrArea, bool bMessageBoxArc, bool bMessageBoxInt, bool bRetainArcs = TRUE ); @@ -539,6 +543,8 @@ public: * Process an area that has been modified, by clipping its polygon against * itself and the polygons for any other areas on the same net. * This may change the number and order of copper areas in the net. + * @param aModifiedZonesList = a PICKED_ITEMS_LIST * where to store deleted or added areas + * (useful in undo commands. Can be NULL * @param modified_area = area to test * @param bMessageBox : if TRUE, shows message boxes when clipping occurs. * @return : @@ -546,20 +552,31 @@ public: * 0 if no intersecting sides * 1 if intersecting sides, polygon clipped */ - int AreaPolygonModified( ZONE_CONTAINER* modified_area, + int AreaPolygonModified( PICKED_ITEMS_LIST* aModifiedZonesList, + ZONE_CONTAINER* modified_area, bool bMessageBoxArc, bool bMessageBoxInt ); /** * Function CombineAllAreasInNet * Checks all copper areas in net for intersections, combining them if found + * @param aDeletedList = a PICKED_ITEMS_LIST * where to store deleted areas (useful in undo commands + * can be NULL * @param aNetCode = net to consider * @param bMessageBox : if true display warning message box * @param bUseUtility : if true, don't check areas if both utility flags are 0 * Sets utility flag = 1 for any areas modified * If an area has self-intersecting arcs, doesn't try to combine it */ - int CombineAllAreasInNet( int aNetCode, bool bMessageBox, bool bUseUtility ); + int CombineAllAreasInNet( PICKED_ITEMS_LIST* aDeletedList, int aNetCode, bool bMessageBox, bool bUseUtility ); + + /** Function RemoveArea + * remove copper area from net, and put it in a deleted list (if exists) + * @param aDeletedList = a PICKED_ITEMS_LIST * where to store deleted areas (useful in undo commands + * can be NULL + * @param area_to_remove = area to delete or put in deleted list + */ + void RemoveArea( PICKED_ITEMS_LIST* aDeletedList, ZONE_CONTAINER* area_to_remove ); /** * Function TestAreaIntersections @@ -583,13 +600,17 @@ public: /** * Function CombineAreas * If possible, combine 2 copper areas + * @param aDeletedList = a PICKED_ITEMS_LIST * where to store deleted areas (useful in undo commands + * can be NULL + * @param area_ref = tje main area (zone) + * @param area_to_combine = the zone that can be merged with area_ref * area_ref must be BEFORE area_to_combine * area_to_combine will be deleted, if areas are combined * @return : 0 if no intersection * 1 if intersection * 2 if arcs intersect */ - int CombineAreas( ZONE_CONTAINER* area_ref, ZONE_CONTAINER* area_to_combine ); + int CombineAreas( PICKED_ITEMS_LIST* aDeletedList, ZONE_CONTAINER* area_ref, ZONE_CONTAINER* area_to_combine ); /** * Function Test_Drc_Areas_Outlines_To_Areas_Outlines diff --git a/pcbnew/class_zone.cpp b/pcbnew/class_zone.cpp index 5740998564..5e17e52bd1 100644 --- a/pcbnew/class_zone.cpp +++ b/pcbnew/class_zone.cpp @@ -1133,13 +1133,19 @@ void ZONE_CONTAINER::Copy( ZONE_CONTAINER* src ) m_Layer = src->m_Layer; SetNet( src->GetNet() ); m_TimeStamp = src->m_TimeStamp; + m_Poly->RemoveAllContours(); m_Poly->Copy( src->m_Poly ); // copy outlines m_CornerSelection = -1; // For corner moving, corner index to drag, or -1 if no selection m_ZoneClearance = src->m_ZoneClearance; // clearance value - m_FillMode = src->m_FillMode; // Grid used for filling + m_FillMode = src->m_FillMode; // Filling mode (segments/polygons) + m_ArcToSegmentsCount = src->m_ArcToSegmentsCount; m_PadOption = src->m_PadOption; + m_ThermalReliefGapValue = src->m_ThermalReliefGapValue; + m_ThermalReliefCopperBridgeValue = src->m_ThermalReliefCopperBridgeValue; m_Poly->SetHatch( src->m_Poly->GetHatchStyle() ); + m_FilledPolysList.clear(); m_FilledPolysList = src->m_FilledPolysList; + m_FillSegmList.clear(); m_FillSegmList = src->m_FillSegmList; } diff --git a/pcbnew/class_zone.h b/pcbnew/class_zone.h index 1c0edfe48a..1887699072 100644 --- a/pcbnew/class_zone.h +++ b/pcbnew/class_zone.h @@ -42,7 +42,7 @@ public: int m_ZoneClearance; // clearance value int m_ZoneMinThickness; // Min thickness value in filled areas int m_FillMode; // How to fillingareas: 0 = use polygonal areas , != 0 fill with segments - int m_ArcToSegmentsCount; // number of segments to convert a cirlce to a polygon (uses 16 or 32) + int m_ArcToSegmentsCount; // number of segments to convert a circle to a polygon (uses 16 or 32) int m_PadOption; // int m_ThermalReliefGapValue; // tickness of the gap in thermal reliefs int m_ThermalReliefCopperBridgeValue; // tickness of the copper bridge in thermal reliefs @@ -369,6 +369,13 @@ public: { return m_Poly->GetHatchStyle(); } + /** function IsSame() + * test is 2 zones are equivalent: + * 2 zones are equivalent if they have same parameters and same outlines + * info relative to filling is not take in account + * @param aZoneToCompare = zone to compare with "this" + */ + bool IsSame( const ZONE_CONTAINER &aZoneToCompare); }; diff --git a/pcbnew/dialog_copper_zones.cpp b/pcbnew/dialog_copper_zones.cpp index 98010861c2..49a626714a 100644 --- a/pcbnew/dialog_copper_zones.cpp +++ b/pcbnew/dialog_copper_zones.cpp @@ -6,7 +6,7 @@ /// Licence: GNU License ///////////////////////////////////////////////////////////////////////////// -#if defined (__GNUG__) && !defined (NO_GCC_PRAGMA) +#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA) #pragma implementation "zones.h" #endif @@ -33,6 +33,8 @@ dialog_copper_zone::dialog_copper_zone( WinEDA_PcbFrame* parent, ZONE_SETTING* z m_Config = wxGetApp().m_EDA_Config; m_Zone_Setting = zone_setting; m_NetSorting = 1; // 0 = alphabetic sort, 1 = pad count sort, and filtering net names + m_OnExitCode = ZONE_ABORT; + if( m_Config ) { m_NetSorting = m_Config->Read( ZONE_NET_SORT_OPTION_KEY, 1l ); @@ -207,7 +209,7 @@ void dialog_copper_zone::OnInitDialog( wxInitDialogEvent& event ) void dialog_copper_zone::OnButtonCancelClick( wxCommandEvent& event ) /********************************************************************/ { - EndModal( ZONE_ABORT ); + EndModal( m_OnExitCode ); } @@ -270,7 +272,7 @@ bool dialog_copper_zone::AcceptOptions( bool aPromptForErrors, bool aUseExportab // Test if this is a reasonnable value for this parameter // A too large value can hang pcbnew #define CLEARANCE_MAX_VALUE 5000 // in 1/10000 inch - if ( m_Zone_Setting->m_ZoneClearance > CLEARANCE_MAX_VALUE ) + if( m_Zone_Setting->m_ZoneClearance > CLEARANCE_MAX_VALUE ) { DisplayError( this, _( "Error : Zone clearance is set to an unreasonnable value" ) ); return false; @@ -336,13 +338,13 @@ bool dialog_copper_zone::AcceptOptions( bool aPromptForErrors, bool aUseExportab return false; } - if ( ii == 0 ) // the not connected option was selected: this is not a good practice: warn: + if( ii == 0 ) // the not connected option was selected: this is not a good practice: warn: { - if( ! IsOK( this, _( - "You have chosen the \"not connected\" option. This will create insulated copper islands. Are you sure ?") ) + if( !IsOK( this, _( + "You have chosen the \"not connected\" option. This will create insulated copper islands. Are you sure ?" ) ) ) - return false; - } + return false; + } wxString net_name = m_ListNetNameSelection->GetString( ii ); @@ -351,7 +353,7 @@ bool dialog_copper_zone::AcceptOptions( bool aPromptForErrors, bool aUseExportab /* Search net_code for this net, if a net was selected */ if( m_ListNetNameSelection->GetSelection() > 0 ) { - NETINFO_ITEM* net = m_Parent->GetBoard()->FindNet(net_name); + NETINFO_ITEM* net = m_Parent->GetBoard()->FindNet( net_name ); if( net ) g_Zone_Default_Setting.m_NetcodeSelection = net->GetNet(); } @@ -435,6 +437,7 @@ void dialog_copper_zone::ExportSetupToOtherCopperZones( wxCommandEvent& event ) m_Zone_Setting->ExportSetting( *zone, false ); // false = partiel export m_Parent->GetScreen()->SetModify(); } + m_OnExitCode = ZONE_EXPORT_VALUES; // values are exported to others zones } diff --git a/pcbnew/dialog_copper_zones.h b/pcbnew/dialog_copper_zones.h index 6ed479388a..0fbf6c3df7 100644 --- a/pcbnew/dialog_copper_zones.h +++ b/pcbnew/dialog_copper_zones.h @@ -6,25 +6,30 @@ #include "dialog_copper_zones_base.h" /* here is the derivated class from dialog_copper_zone_frame created by wxFormBuilder -*/ -class dialog_copper_zone: public dialog_copper_zone_base + */ +class dialog_copper_zone : public dialog_copper_zone_base { public: WinEDA_PcbFrame* m_Parent; - wxConfig* m_Config; // Current config - ZONE_SETTING * m_Zone_Setting; - long m_NetSorting; - int m_LayerId[LAYER_COUNT]; // Handle the real layer number from layer name position in m_LayerSelectionCtrl + wxConfig* m_Config; // Current config + int m_OnExitCode; /* exit code: ZONE_ABORT if no change, + * ZONE_OK if new values accepted + * ZONE_EXPORT_VALUES if values are exported to others zones + */ + + ZONE_SETTING* m_Zone_Setting; + long m_NetSorting; + int m_LayerId[LAYER_COUNT]; // Handle the real layer number from layer name position in m_LayerSelectionCtrl public: - dialog_copper_zone( WinEDA_PcbFrame* parent, ZONE_SETTING * zone_setting); + dialog_copper_zone( WinEDA_PcbFrame* parent, ZONE_SETTING* zone_setting ); void OnInitDialog( wxInitDialogEvent& event ); - void OnButtonOkClick( wxCommandEvent& event ); - void OnButtonCancelClick( wxCommandEvent& event ); - bool AcceptOptions(bool aPromptForErrors, bool aUseExportableSetupOnly = false); + void OnButtonOkClick( wxCommandEvent& event ); + void OnButtonCancelClick( wxCommandEvent& event ); + bool AcceptOptions( bool aPromptForErrors, bool aUseExportableSetupOnly = false ); void OnNetSortingOptionSelected( wxCommandEvent& event ); - void ExportSetupToOtherCopperZones( wxCommandEvent& event ); - void OnPadsInZoneClick( wxCommandEvent& event ); + void ExportSetupToOtherCopperZones( wxCommandEvent& event ); + void OnPadsInZoneClick( wxCommandEvent& event ); }; #endif // #ifndef DIALOG_COPPER_ZONES diff --git a/pcbnew/dialog_pad_properties.cpp b/pcbnew/dialog_pad_properties.cpp index 6e50b0dd06..fee6369c4d 100644 --- a/pcbnew/dialog_pad_properties.cpp +++ b/pcbnew/dialog_pad_properties.cpp @@ -66,13 +66,14 @@ public: public: DialogPadProperties( WinEDA_BasePcbFrame* parent, D_PAD* Pad, wxDC* DC ); - void InitDialog( wxInitDialogEvent& event ); + void Init( ); void OnPadShapeSelection( wxCommandEvent& event ); void OnDrillShapeSelected( wxCommandEvent& event ); void PadOrientEvent( wxCommandEvent& event ); void PadTypeSelected( wxCommandEvent& event ); void PadPropertiesAccept( wxCommandEvent& event ); void SetPadLayersList( long layer_mask ); + void OnCancelButtonClick( wxCommandEvent& event ); }; @@ -90,6 +91,12 @@ DialogPadProperties::DialogPadProperties( WinEDA_BasePcbFrame* parent, D_PAD* Pa Current_PadNetName = m_CurrentPad->GetNetname(); g_Current_PadName = m_CurrentPad->ReturnStringPadName(); } + + Init( ); + if( GetSizer() ) + { + GetSizer()->SetSizeHints( this ); + } } @@ -104,7 +111,7 @@ void WinEDA_BasePcbFrame::InstallPadOptionsFrame( D_PAD* Pad, wxDC* DC, const wx /**************************************************************/ -void DialogPadProperties::InitDialog( wxInitDialogEvent& event ) +void DialogPadProperties::Init( ) /**************************************************************/ { int tmp; @@ -235,11 +242,6 @@ void DialogPadProperties::InitDialog( wxInitDialogEvent& event ) cmd_event.SetId( m_PadType->GetSelection() ); PadTypeSelected( cmd_event ); } - - if( GetSizer() ) - { - GetSizer()->SetSizeHints( this ); - } } @@ -475,8 +477,8 @@ void DialogPadProperties::PadPropertiesAccept( wxCommandEvent& event ) if( m_CurrentPad ) // Set Pad Name & Num { - m_Parent->SaveCopyInUndoList( m_Parent->GetBoard()->m_Modules, UR_CHANGED ); MODULE* Module = (MODULE*) m_CurrentPad->GetParent(); + m_Parent->SaveCopyInUndoList( Module, UR_CHANGED ); Module->m_LastEdit_Time = time( NULL ); if( m_DC ) // redraw the area where the pad was, without pad (delete pad on screen) @@ -580,10 +582,18 @@ void DialogPadProperties::PadPropertiesAccept( wxCommandEvent& event ) m_Parent->GetScreen()->SetModify(); } - Close(); + EndModal(1); if( m_DC ) m_Parent->DrawPanel->CursorOn( m_DC ); if( RastnestIsChanged ) // The net ratsnest must be recalculated m_Parent->GetBoard()->m_Status_Pcb = 0; } + +/*********************************************************************/ +void DialogPadProperties::OnCancelButtonClick( wxCommandEvent& event ) +/*********************************************************************/ +{ + EndModal(0); +} + diff --git a/pcbnew/dialog_pad_properties_base.cpp b/pcbnew/dialog_pad_properties_base.cpp index 0b8d8eb7d7..09a2fe2ef2 100644 --- a/pcbnew/dialog_pad_properties_base.cpp +++ b/pcbnew/dialog_pad_properties_base.cpp @@ -166,21 +166,21 @@ DialogPadPropertiesBase::DialogPadPropertiesBase( wxWindow* parent, wxWindowID i this->Centre( wxBOTH ); // Connect Events - this->Connect( wxEVT_INIT_DIALOG, wxInitDialogEventHandler( DialogPadPropertiesBase::InitDialog ) ); m_PadShape->Connect( wxEVT_COMMAND_RADIOBOX_SELECTED, wxCommandEventHandler( DialogPadPropertiesBase::OnPadShapeSelection ), NULL, this ); m_DrillShapeCtrl->Connect( wxEVT_COMMAND_RADIOBOX_SELECTED, wxCommandEventHandler( DialogPadPropertiesBase::OnDrillShapeSelected ), NULL, this ); m_PadOrient->Connect( wxEVT_COMMAND_RADIOBOX_SELECTED, wxCommandEventHandler( DialogPadPropertiesBase::PadOrientEvent ), NULL, this ); m_PadType->Connect( wxEVT_COMMAND_RADIOBOX_SELECTED, wxCommandEventHandler( DialogPadPropertiesBase::PadTypeSelected ), NULL, this ); m_buttonOk->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DialogPadPropertiesBase::PadPropertiesAccept ), NULL, this ); + m_buttonCancel->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DialogPadPropertiesBase::OnCancelButtonClick ), NULL, this ); } DialogPadPropertiesBase::~DialogPadPropertiesBase() { // Disconnect Events - this->Disconnect( wxEVT_INIT_DIALOG, wxInitDialogEventHandler( DialogPadPropertiesBase::InitDialog ) ); m_PadShape->Disconnect( wxEVT_COMMAND_RADIOBOX_SELECTED, wxCommandEventHandler( DialogPadPropertiesBase::OnPadShapeSelection ), NULL, this ); m_DrillShapeCtrl->Disconnect( wxEVT_COMMAND_RADIOBOX_SELECTED, wxCommandEventHandler( DialogPadPropertiesBase::OnDrillShapeSelected ), NULL, this ); m_PadOrient->Disconnect( wxEVT_COMMAND_RADIOBOX_SELECTED, wxCommandEventHandler( DialogPadPropertiesBase::PadOrientEvent ), NULL, this ); m_PadType->Disconnect( wxEVT_COMMAND_RADIOBOX_SELECTED, wxCommandEventHandler( DialogPadPropertiesBase::PadTypeSelected ), NULL, this ); m_buttonOk->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DialogPadPropertiesBase::PadPropertiesAccept ), NULL, this ); + m_buttonCancel->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DialogPadPropertiesBase::OnCancelButtonClick ), NULL, this ); } diff --git a/pcbnew/dialog_pad_properties_base.fbp b/pcbnew/dialog_pad_properties_base.fbp index 02bb0e6078..b2d583d4e5 100644 --- a/pcbnew/dialog_pad_properties_base.fbp +++ b/pcbnew/dialog_pad_properties_base.fbp @@ -49,7 +49,7 @@ - InitDialog + @@ -760,7 +760,7 @@ - + OnCancelButtonClick diff --git a/pcbnew/dialog_pad_properties_base.h b/pcbnew/dialog_pad_properties_base.h index edd917019d..5ec4ce6a29 100644 --- a/pcbnew/dialog_pad_properties_base.h +++ b/pcbnew/dialog_pad_properties_base.h @@ -78,12 +78,12 @@ class DialogPadPropertiesBase : public wxDialog wxCheckBox* m_PadLayerDraft; // Virtual event handlers, overide them in your derived class - virtual void InitDialog( wxInitDialogEvent& event ){ event.Skip(); } virtual void OnPadShapeSelection( wxCommandEvent& event ){ event.Skip(); } virtual void OnDrillShapeSelected( wxCommandEvent& event ){ event.Skip(); } virtual void PadOrientEvent( wxCommandEvent& event ){ event.Skip(); } virtual void PadTypeSelected( wxCommandEvent& event ){ event.Skip(); } virtual void PadPropertiesAccept( wxCommandEvent& event ){ event.Skip(); } + virtual void OnCancelButtonClick( wxCommandEvent& event ){ event.Skip(); } public: diff --git a/pcbnew/edit.cpp b/pcbnew/edit.cpp index 60677859e1..30d9d2b0a2 100644 --- a/pcbnew/edit.cpp +++ b/pcbnew/edit.cpp @@ -609,8 +609,7 @@ void WinEDA_PcbFrame::Process_Special_Functions( wxCommandEvent& event ) */ zone_cont->Draw( DrawPanel, &dc, GR_XOR ); zone_cont->m_Poly->InsertCorner( zone_cont->m_CornerSelection, - pos.x, - pos.y ); + pos.x, pos.y ); zone_cont->m_CornerSelection++; zone_cont->Draw( DrawPanel, &dc, GR_XOR ); DrawPanel->m_AutoPAN_Request = true; @@ -669,7 +668,7 @@ void WinEDA_PcbFrame::Process_Special_Functions( wxCommandEvent& event ) case ID_POPUP_PCB_FILL_ZONE: DrawPanel->MouseToCursorSchema(); - Fill_Zone( NULL, (ZONE_CONTAINER*) GetCurItem() ); + Fill_Zone( (ZONE_CONTAINER*) GetCurItem() ); test_1_net_connexion( NULL, ( (ZONE_CONTAINER*) GetCurItem() )->GetNet() ); GetBoard()->DisplayInfo( this ); DrawPanel->Refresh(); diff --git a/pcbnew/zones.h b/pcbnew/zones.h index 0103bc2403..9c58d0e856 100644 --- a/pcbnew/zones.h +++ b/pcbnew/zones.h @@ -16,9 +16,11 @@ #define ZONE_THERMAL_RELIEF_GAP_STRING_KEY wxT( "Zone_TH_Gap" ) #define ZONE_THERMAL_RELIEF_COPPER_WIDTH_STRING_KEY wxT( "Zone_TH_Copper_Width" ) +// Exit codes for dialog edit zones enum zone_cmd { - ZONE_ABORT, - ZONE_OK + ZONE_ABORT, // if no change + ZONE_OK, // if new values accepted + ZONE_EXPORT_VALUES // if values are exported to others zones }; diff --git a/pcbnew/zones_by_polygon.cpp b/pcbnew/zones_by_polygon.cpp index bbc4ce75ec..79970e0412 100644 --- a/pcbnew/zones_by_polygon.cpp +++ b/pcbnew/zones_by_polygon.cpp @@ -14,10 +14,9 @@ #include "zones.h" #include "id.h" #include "protos.h" +#include "zones_functions_for_undo_redo.h" -using namespace std; - -bool verbose = false; // false if zone outline diags must not be shown +bool s_Verbose = false; // false if zone outline diags must not be shown // Outline creation: static void Abort_Zone_Create_Outline( WinEDA_DrawPanel* Panel, wxDC* DC ); @@ -30,11 +29,13 @@ static void Show_Zone_Corner_Or_Outline_While_Move_Mouse( WinEDA_DrawPanel* pane bool erase ); /* Local variables */ -static wxPoint s_CornerInitialPosition; // Used to abort a move corner command +static wxPoint s_CornerInitialPosition; // Used to abort a move corner command static bool s_CornerIsNew; // Used to abort a move corner command (if it is a new corner, it must be deleted) static bool s_AddCutoutToCurrentZone; // if true, the next outline will be addes to s_CurrentZone static ZONE_CONTAINER* s_CurrentZone; // if != NULL, these ZONE_CONTAINER params will be used for the next zone static wxPoint s_CursorLastPosition; // in move zone outline, last cursor position. Used to calculate the move vector +static PICKED_ITEMS_LIST s_PickedList; // a picked list to save zones for undo/redo command +static PICKED_ITEMS_LIST _AuxiliaryList; // a picked list to store zones that are deleted or added when combined #include "dialog_copper_zones.h" @@ -91,59 +92,6 @@ void WinEDA_PcbFrame::Add_Zone_Cutout( wxDC* DC, ZONE_CONTAINER* zone_container } -/**********************************************************************************/ -void WinEDA_PcbFrame::Delete_Zone_Fill( SEGZONE* aZone, long aTimestamp ) -/**********************************************************************************/ - -/** Function Delete_Zone_Fill - * Remove the zone fillig which include the segment aZone, or the zone which have the given time stamp. - * A zone is a group of segments which have the same TimeStamp - * @param DC = current Device Context (can be NULL) - * @param aZone = zone segment within the zone to delete. Can be NULL - * @param aTimestamp = Timestamp for the zone to delete, used if aZone == NULL - */ -{ - bool modify = false; - unsigned long TimeStamp; - - if( aZone == NULL ) - TimeStamp = aTimestamp; - else - TimeStamp = aZone->m_TimeStamp; // Save reference time stamp (aZone will be deleted) - - SEGZONE* next; - for( SEGZONE* zone = GetBoard()->m_Zone; zone != NULL; zone = next ) - { - next = zone->Next(); - if( zone->m_TimeStamp == TimeStamp ) - { - modify = TRUE; - /* remove item from linked list and free memory */ - zone->DeleteStructure(); - } - } - - // Now delete the outlines of the corresponding copper areas (deprecated) - for( int ii = 0; ii < GetBoard()->GetAreaCount(); ii++ ) - { - ZONE_CONTAINER* zone = GetBoard()->GetArea( ii ); - if( zone->m_TimeStamp == TimeStamp ) - { - modify = TRUE; - zone->m_FilledPolysList.clear(); - zone->m_FillSegmList.clear(); - zone->m_IsFilled = false; - } - } - - if( modify ) - { - GetScreen()->SetModify(); - GetScreen()->SetRefreshReq(); - } -} - - /*******************************************************/ int WinEDA_PcbFrame::Delete_LastCreatedCorner( wxDC* DC ) /*******************************************************/ @@ -232,6 +180,22 @@ void WinEDA_PcbFrame::Start_Move_Zone_Corner( wxDC* DC, ZONE_CONTAINER* zone_con Hight_Light( DC ); } + + // Prepare copy of old zones, for undo/redo. + // if the corner is new, remove it from list, save and insert it in list + int cx = zone_container->m_Poly->GetX( corner_id ); + int cy = zone_container->m_Poly->GetY( corner_id ); + + if ( IsNewCorner ) + zone_container->m_Poly->DeleteCorner( corner_id ); + + _AuxiliaryList.ClearListAndDeleteItems(); + s_PickedList.ClearListAndDeleteItems(); + + SaveCopyOfZones(s_PickedList, GetBoard(), zone_container->GetNet(), zone_container->GetLayer() ); + if ( IsNewCorner ) + zone_container->m_Poly->InsertCorner(corner_id-1, cx, cy ); + zone_container->m_Flags = IN_EDIT; DrawPanel->ManageCurseur = Show_Zone_Corner_Or_Outline_While_Move_Mouse; DrawPanel->ForceCloseManageCurseur = Abort_Zone_Move_Corner_Or_Outlines; @@ -249,7 +213,7 @@ void WinEDA_PcbFrame::Start_Move_Zone_Drag_Outline_Edge( wxDC* DC, /**************************************************************************************/ /** - * Function Start_Move_Zone_Corner + * Function Start_Move_Zone_Drag_Outline_Edge * Prepares a drag edge for an existing zone outline, */ { @@ -260,6 +224,11 @@ void WinEDA_PcbFrame::Start_Move_Zone_Drag_Outline_Edge( wxDC* DC, s_CursorLastPosition = s_CornerInitialPosition = GetScreen()->m_Curseur; s_AddCutoutToCurrentZone = false; s_CurrentZone = NULL; + + s_PickedList.ClearListAndDeleteItems(); + _AuxiliaryList.ClearListAndDeleteItems(); + SaveCopyOfZones(s_PickedList, GetBoard(), zone_container->GetNet(), zone_container->GetLayer() ); + } @@ -284,6 +253,10 @@ void WinEDA_PcbFrame::Start_Move_Zone_Outlines( wxDC* DC, ZONE_CONTAINER* zone_c Hight_Light( DC ); } + s_PickedList.ClearListAndDeleteItems(); + _AuxiliaryList.ClearListAndDeleteItems(); + SaveCopyOfZones(s_PickedList, GetBoard(), zone_container->GetNet(), zone_container->GetLayer() ); + zone_container->m_Flags = IS_MOVED; DrawPanel->ManageCurseur = Show_Zone_Corner_Or_Outline_While_Move_Mouse; DrawPanel->ForceCloseManageCurseur = Abort_Zone_Move_Corner_Or_Outlines; @@ -318,7 +291,7 @@ void WinEDA_PcbFrame::End_Move_Zone_Corner_Or_Outlines( wxDC* DC, ZONE_CONTAINER /* Combine zones if possible */ wxBusyCursor dummy; - GetBoard()->AreaPolygonModified( zone_container, true, verbose ); + GetBoard()->AreaPolygonModified( &_AuxiliaryList, zone_container, true, s_Verbose ); DrawPanel->Refresh(); @@ -326,6 +299,10 @@ void WinEDA_PcbFrame::End_Move_Zone_Corner_Or_Outlines( wxDC* DC, ZONE_CONTAINER if( ii < 0 ) zone_container = NULL; // was removed by combining zones + UpdateCopyOfZonesList( s_PickedList, _AuxiliaryList, GetBoard() ); + SaveCopyInUndoList(s_PickedList, UR_UNSPECIFIED); + s_PickedList.ClearItemsList(); // s_ItemsListPicker is no more owner of picked items + int error_count = GetBoard()->Test_Drc_Areas_Outlines_To_Areas_Outlines( zone_container, true ); if( error_count ) { @@ -342,7 +319,7 @@ void WinEDA_PcbFrame::Remove_Zone_Corner( wxDC* DC, ZONE_CONTAINER* zone_contain * Function Remove_Zone_Corner * Remove the currently selected corner in a zone outline * the .m_CornerSelection is used as corner selection - * @param DC = Current deice context (can be NULL ) + * @param DC = Current device context (can be NULL ) * @param zone_container = the zone that contains the selected corner * the member .m_CornerSelection is used as selected corner */ @@ -369,16 +346,23 @@ void WinEDA_PcbFrame::Remove_Zone_Corner( wxDC* DC, ZONE_CONTAINER* zone_contain GetBoard()->RedrawFilledAreas( DrawPanel, DC, GR_XOR, layer ); } + _AuxiliaryList.ClearListAndDeleteItems(); + s_PickedList. ClearListAndDeleteItems(); + SaveCopyOfZones(s_PickedList, GetBoard(), zone_container->GetNet(), zone_container->GetLayer() ); zone_container->m_Poly->DeleteCorner( zone_container->m_CornerSelection ); // modify zones outlines according to the new zone_container shape - GetBoard()->AreaPolygonModified( zone_container, true, verbose ); + GetBoard()->AreaPolygonModified( &_AuxiliaryList, zone_container, true, s_Verbose ); if( DC ) { GetBoard()->RedrawAreasOutlines( DrawPanel, DC, GR_OR, layer ); GetBoard()->RedrawFilledAreas( DrawPanel, DC, GR_OR, layer ); } + UpdateCopyOfZonesList( s_PickedList, _AuxiliaryList, GetBoard() ); + SaveCopyInUndoList(s_PickedList, UR_UNSPECIFIED); + s_PickedList.ClearItemsList(); // s_ItemsListPicker is no more owner of picked items + int ii = GetBoard()->GetAreaIndex( zone_container ); // test if zone_container exists if( ii < 0 ) zone_container = NULL; // zone_container does not exist anymaore, after combining zones @@ -402,8 +386,6 @@ void Abort_Zone_Move_Corner_Or_Outlines( WinEDA_DrawPanel* Panel, wxDC* DC ) WinEDA_PcbFrame* pcbframe = (WinEDA_PcbFrame*) Panel->m_Parent; ZONE_CONTAINER* zone_container = (ZONE_CONTAINER*) pcbframe->GetCurItem(); -// zone_container->Draw( Panel, DC, GR_XOR ); - if( zone_container->m_Flags == IS_MOVED ) { wxPoint offset; @@ -429,10 +411,10 @@ void Abort_Zone_Move_Corner_Or_Outlines( WinEDA_DrawPanel* Panel, wxDC* DC ) } } -// zone_container->Draw( Panel, DC, GR_XOR ); + _AuxiliaryList.ClearListAndDeleteItems(); + s_PickedList. ClearListAndDeleteItems(); Panel->Refresh(); - Panel->ManageCurseur = NULL; Panel->ForceCloseManageCurseur = NULL; pcbframe->SetCurItem( NULL ); @@ -644,7 +626,7 @@ bool WinEDA_PcbFrame::End_Zone( wxDC* DC ) if( zone == NULL ) return true; - // Validate the curren outline: + // Validate the current outline: if( zone->GetNumCorners() <= 2 ) // An outline must have 3 corners or more { Abort_Zone_Create_Outline( DrawPanel, DC ); @@ -678,12 +660,20 @@ bool WinEDA_PcbFrame::End_Zone( wxDC* DC ) GetBoard()->RedrawAreasOutlines( DrawPanel, DC, GR_XOR, layer ); GetBoard()->RedrawFilledAreas( DrawPanel, DC, GR_XOR, layer ); - /* Put edges in list */ + // Save initial zones configuration, for undo/redo, before adding new zone + _AuxiliaryList.ClearListAndDeleteItems(); + s_PickedList.ClearListAndDeleteItems(); + SaveCopyOfZones(s_PickedList, GetBoard(), zone->GetNet(), zone->GetLayer() ); + + /* Put new zone in list */ if( s_CurrentZone == NULL ) { zone->m_Poly->Close(); // Close the current corner list GetBoard()->Add( zone ); GetBoard()->m_CurrentZoneContour = NULL; + // Add this zone in picked list, as new item + ITEM_PICKER picker( zone, UR_NEW ); + s_PickedList.PushItem( picker ); } else // Append this outline as a cutout to an existing zone { @@ -703,7 +693,7 @@ bool WinEDA_PcbFrame::End_Zone( wxDC* DC ) GetScreen()->SetCurItem( NULL ); // This outine can be deleted when merging outlines // Combine zones if possible : - GetBoard()->AreaPolygonModified( zone, true, verbose ); + GetBoard()->AreaPolygonModified( &_AuxiliaryList, zone, true, s_Verbose ); // Redraw the real edge zone : GetBoard()->RedrawAreasOutlines( DrawPanel, DC, GR_OR, layer ); @@ -712,12 +702,17 @@ bool WinEDA_PcbFrame::End_Zone( wxDC* DC ) int ii = GetBoard()->GetAreaIndex( zone ); // test if zone_container exists if( ii < 0 ) zone = NULL; // was removed by combining zones + int error_count = GetBoard()->Test_Drc_Areas_Outlines_To_Areas_Outlines( zone, true ); if( error_count ) { DisplayError( this, _( "Area: DRC outline error" ) ); } + UpdateCopyOfZonesList( s_PickedList, _AuxiliaryList, GetBoard() ); + SaveCopyInUndoList(s_PickedList, UR_UNSPECIFIED); + s_PickedList.ClearItemsList(); // s_ItemsListPicker is no more owner of picked items + GetScreen()->SetModify(); return true; } @@ -727,7 +722,7 @@ bool WinEDA_PcbFrame::End_Zone( wxDC* DC ) static void Show_New_Edge_While_Move_Mouse( WinEDA_DrawPanel* panel, wxDC* DC, bool erase ) /******************************************************************************************/ -/* Redraws the edge zone when moving mouse +/* Redraws the zone outlines when moving mouse */ { WinEDA_PcbFrame* pcbframe = (WinEDA_PcbFrame*) panel->m_Parent; @@ -772,6 +767,14 @@ void WinEDA_PcbFrame::Edit_Zone_Params( wxDC* DC, ZONE_CONTAINER* zone_container { int diag; DrawPanel->m_IgnoreMouseEvents = TRUE; + + /* Save initial zones configuration, for undo/redo, before adding new zone + * note the net name and the layer can be changed, so we must save all zones + */ + _AuxiliaryList.ClearListAndDeleteItems(); + s_PickedList.ClearListAndDeleteItems(); + SaveCopyOfZones(s_PickedList, GetBoard(), -1, -1 ); + if( zone_container->GetLayer() < FIRST_NO_COPPER_LAYER ) { // edit a zone on a copper layer g_Zone_Default_Setting.ImportSetting(*zone_container); @@ -786,7 +789,18 @@ void WinEDA_PcbFrame::Edit_Zone_Params( wxDC* DC, ZONE_CONTAINER* zone_container DrawPanel->m_IgnoreMouseEvents = FALSE; if( diag == ZONE_ABORT ) + { + _AuxiliaryList.ClearListAndDeleteItems(); + s_PickedList.ClearListAndDeleteItems(); return; + } + if( diag == ZONE_EXPORT_VALUES ) + { + UpdateCopyOfZonesList( s_PickedList, _AuxiliaryList, GetBoard() ); + SaveCopyInUndoList(s_PickedList, UR_UNSPECIFIED); + s_PickedList.ClearItemsList(); // s_ItemsListPicker is no more owner of picked items + return; + } // Undraw old zone outlines for( int ii = 0; ii < GetBoard()->GetAreaCount(); ii++ ) @@ -797,16 +811,19 @@ void WinEDA_PcbFrame::Edit_Zone_Params( wxDC* DC, ZONE_CONTAINER* zone_container g_Zone_Default_Setting.ExportSetting( *zone_container); NETINFO_ITEM* net = GetBoard()->FindNet( g_Zone_Default_Setting.m_NetcodeSelection ); - if( net ) // net === NULL should not occur + if( net ) // net == NULL should not occur zone_container->m_Netname = net->GetNetname(); - // Combine zones if possible : - GetBoard()->AreaPolygonModified( zone_container, true, verbose ); + GetBoard()->AreaPolygonModified( &_AuxiliaryList, zone_container, true, s_Verbose ); // Redraw the real new zone outlines: GetBoard()->RedrawAreasOutlines( DrawPanel, DC, GR_OR, -1 ); + UpdateCopyOfZonesList( s_PickedList, _AuxiliaryList, GetBoard() ); + SaveCopyInUndoList(s_PickedList, UR_UNSPECIFIED); + s_PickedList.ClearItemsList(); // s_ItemsListPicker is no more owner of picked items + GetScreen()->SetModify(); } @@ -847,106 +864,3 @@ void WinEDA_PcbFrame::Delete_Zone_Contour( wxDC* DC, ZONE_CONTAINER* zone_contai GetScreen()->SetModify(); } - -/***************************************************************************************/ -int WinEDA_PcbFrame::Fill_Zone( wxDC* DC, ZONE_CONTAINER* zone_container, bool verbose ) -/***************************************************************************************/ - -/** Function Fill_Zone() - * Calculate the zone filling for the outline zone_container - * The zone outline is a frontier, and can be complex (with holes) - * The filling starts from starting points like pads, tracks. - * If exists, the old filling is removed - * @param DC = current Device Context - * @param zone_container = zone to fill - * @param verbose = true to show error messages - * @return error level (0 = no error) - */ -{ - wxString msg; - - MsgPanel->EraseMsgBox(); - if( GetBoard()->ComputeBoundaryBox() == FALSE ) - { - if( verbose ) - DisplayError( this, wxT( "Board is empty!" ), 10 ); - return -1; - } - - /* Shows the Net */ - g_Zone_Default_Setting.m_NetcodeSelection = zone_container->GetNet(); - if( g_HightLigt_Status && (g_HightLigth_NetCode != g_Zone_Default_Setting.m_NetcodeSelection) && DC ) - { - Hight_Light( DC ); // Remove old highlight selection - } - - g_HightLigth_NetCode = g_Zone_Default_Setting.m_NetcodeSelection; - if( DC ) - Hight_Light( DC ); - - if( g_HightLigth_NetCode > 0 ) - { - NETINFO_ITEM* net = GetBoard()->FindNet( g_HightLigth_NetCode ); - if( net == NULL ) - { - if( g_HightLigth_NetCode > 0 ) - { - if( verbose ) - DisplayError( this, wxT( "Unable to find Net name" ) ); - return -2; - } - } - else - msg = net->GetNetname(); - } - else - msg = _( "No Net" ); - - Affiche_1_Parametre( this, 22, _( "NetName" ), msg, RED ); - wxBusyCursor dummy; // Shows an hourglass cursor (removed by its destructor) - - int error_level = 0; - zone_container->m_FilledPolysList.clear(); - Delete_Zone_Fill( NULL, zone_container->m_TimeStamp ); - zone_container->BuildFilledPolysListData( GetBoard() ); - - if ( DC ) - DrawPanel->Refresh(); - - GetScreen()->SetModify(); - - return error_level; -} - - -/************************************************************/ -int WinEDA_PcbFrame::Fill_All_Zones( bool verbose ) -/************************************************************/ - -/** Function Fill_All_Zones() - * Fill all zones on the board - * The old fillings are removed - * @param verbose = true to show error messages - * @return error level (0 = no error) - */ -{ - ZONE_CONTAINER* zone_container; - int error_level = 0; - - // Remove all zones : - GetBoard()->m_Zone.DeleteAll(); - - for( int ii = 0; ii < GetBoard()->GetAreaCount(); ii++ ) - { - zone_container = GetBoard()->GetArea( ii ); - error_level = Fill_Zone( NULL, zone_container, verbose ); - if( error_level && !verbose ) - break; - } - test_connexions( NULL ); - Tst_Ratsnest( NULL, 0 ); // Recalculate the active ratsnest, i.e. the unconnected links */ - DrawPanel->Refresh( true ); - return error_level; -} - - diff --git a/pcbnew/zones_by_polygon_fill_functions.cpp b/pcbnew/zones_by_polygon_fill_functions.cpp new file mode 100644 index 0000000000..8305a0a10d --- /dev/null +++ b/pcbnew/zones_by_polygon_fill_functions.cpp @@ -0,0 +1,175 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: zones_by_polygon_fill_functions.cpp +///////////////////////////////////////////////////////////////////////////// +/* + * This program source code file is part of KICAD, a free EDA CAD application. + * + * Copyright (C) 2009 Jean-Pierre Charras + * Copyright (C) 2007 Kicad Developers, see change_log.txt for contributors. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, you may find one here: + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html + * or you may search the http://www.gnu.org website for the version 2 license, + * or you may write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "fctsys.h" +#include "appl_wxstruct.h" +#include "common.h" +#include "class_drawpanel.h" +#include "pcbnew.h" +#include "wxPcbStruct.h" +#include "zones.h" + + +/**********************************************************************************/ +void WinEDA_PcbFrame::Delete_Zone_Fill( SEGZONE* aZone, long aTimestamp ) +/**********************************************************************************/ + +/** Function Delete_Zone_Fill + * Remove the zone fillig which include the segment aZone, or the zone which have the given time stamp. + * A zone is a group of segments which have the same TimeStamp + * @param DC = current Device Context (can be NULL) + * @param aZone = zone segment within the zone to delete. Can be NULL + * @param aTimestamp = Timestamp for the zone to delete, used if aZone == NULL + */ +{ + bool modify = false; + unsigned long TimeStamp; + + if( aZone == NULL ) + TimeStamp = aTimestamp; + else + TimeStamp = aZone->m_TimeStamp; // Save reference time stamp (aZone will be deleted) + + SEGZONE* next; + for( SEGZONE* zone = GetBoard()->m_Zone; zone != NULL; zone = next ) + { + next = zone->Next(); + if( zone->m_TimeStamp == TimeStamp ) + { + modify = TRUE; + /* remove item from linked list and free memory */ + zone->DeleteStructure(); + } + } + + // Now delete the outlines of the corresponding copper areas (deprecated) + for( int ii = 0; ii < GetBoard()->GetAreaCount(); ii++ ) + { + ZONE_CONTAINER* zone = GetBoard()->GetArea( ii ); + if( zone->m_TimeStamp == TimeStamp ) + { + modify = TRUE; + zone->m_FilledPolysList.clear(); + zone->m_FillSegmList.clear(); + zone->m_IsFilled = false; + } + } + + if( modify ) + { + GetScreen()->SetModify(); + GetScreen()->SetRefreshReq(); + } +} + + +/***************************************************************************************/ +int WinEDA_PcbFrame::Fill_Zone( ZONE_CONTAINER* zone_container, bool verbose ) +/***************************************************************************************/ + +/** Function Fill_Zone() + * Calculate the zone filling for the outline zone_container + * The zone outline is a frontier, and can be complex (with holes) + * The filling starts from starting points like pads, tracks. + * If exists, the old filling is removed + * @param zone_container = zone to fill + * @param verbose = true to show error messages + * @return error level (0 = no error) + */ +{ + wxString msg; + + MsgPanel->EraseMsgBox(); + if( GetBoard()->ComputeBoundaryBox() == false ) + { + if( verbose ) + wxMessageBox( wxT( "Board is empty!" ) ); + return -1; + } + + /* Shows the Net */ + g_Zone_Default_Setting.m_NetcodeSelection = zone_container->GetNet(); + + if( zone_container->GetNet() > 0 ) + { + NETINFO_ITEM* net = GetBoard()->FindNet( zone_container->GetNet() ); + if( net == NULL ) + { + if( verbose ) + wxMessageBox( wxT( "Unable to find Net name" ) ); + return -2; + } + else + msg = net->GetNetname(); + } + else + msg = _( "No Net" ); + + Affiche_1_Parametre( this, 22, _( "NetName" ), msg, RED ); + wxBusyCursor dummy; // Shows an hourglass cursor (removed by its destructor) + + zone_container->m_FilledPolysList.clear(); + Delete_Zone_Fill( NULL, zone_container->m_TimeStamp ); + zone_container->BuildFilledPolysListData( GetBoard() ); + + GetScreen()->SetModify(); + + return 0; +} + + +/************************************************************/ +int WinEDA_PcbFrame::Fill_All_Zones( bool verbose ) +/************************************************************/ + +/** Function Fill_All_Zones() + * Fill all zones on the board + * The old fillings are removed + * @param verbose = true to show error messages + * @return error level (0 = no error) + */ +{ + ZONE_CONTAINER* zone_container; + int error_level = 0; + + // Remove all zones : + GetBoard()->m_Zone.DeleteAll(); + + for( int ii = 0; ii < GetBoard()->GetAreaCount(); ii++ ) + { + zone_container = GetBoard()->GetArea( ii ); + error_level = Fill_Zone( zone_container, verbose ); + if( error_level && !verbose ) + break; + } + test_connexions( NULL ); + Tst_Ratsnest( NULL, 0 ); // Recalculate the active ratsnest, i.e. the unconnected links */ + DrawPanel->Refresh( true ); + return error_level; +} + + diff --git a/pcbnew/zones_convert_brd_items_to_polygons.cpp b/pcbnew/zones_convert_brd_items_to_polygons.cpp index 11d55868d1..c4e4c8c8d6 100644 --- a/pcbnew/zones_convert_brd_items_to_polygons.cpp +++ b/pcbnew/zones_convert_brd_items_to_polygons.cpp @@ -356,8 +356,8 @@ void ZONE_CONTAINER::AddClearanceAreasPolygonsToPolysList( BOARD* aPcb ) } // Now we remove all unused thermal stubs. -//define REMOVE_UNUSED_THERMAL_STUBS // Can be commented to skip unused thermal stubs calculations -//#ifdef REMOVE_UNUSED_THERMAL_STUBS +#define REMOVE_UNUSED_THERMAL_STUBS // Can be commented to skip unused thermal stubs calculations +#ifdef REMOVE_UNUSED_THERMAL_STUBS /* Add the main (corrected) polygon (i.e. the filled area using only one outline) * in GroupA in Bool_Engine to do a BOOL_A_SUB_B operation @@ -500,7 +500,7 @@ void ZONE_CONTAINER::AddClearanceAreasPolygonsToPolysList( BOARD* aPcb ) delete booleng; -//#endif +#endif } @@ -807,7 +807,7 @@ void AddThermalReliefPadPolygon( Bool_Engine* aBooleng, // this seems a bug in kbool polygon (exists in 1.9 kbool version) // 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 shpaes after correr areas build), 0 seems work + // Note: with the 2 step build ( thermal shapes added after areas are built), 0 seems work angle = 450; int angle_pad = aPad.m_Orient; // Pad orientation for( unsigned ihole = 0; ihole < 4; ihole++ ) @@ -1247,7 +1247,7 @@ void AddTextBoxWithClearancePolygon( Bool_Engine* aBooleng, corners[3].y = corners[2].y; corners[3].x = corners[0].x; - + if( aBooleng->StartPolygonAdd( GROUP_B ) ) { for( int ii = 0; ii < 4; ii ++ ) diff --git a/pcbnew/zones_functions_for_undo_redo.cpp b/pcbnew/zones_functions_for_undo_redo.cpp new file mode 100644 index 0000000000..0210566600 --- /dev/null +++ b/pcbnew/zones_functions_for_undo_redo.cpp @@ -0,0 +1,258 @@ +///////////////////////////////////////////////////////////////////////////// + +// Name: zones_functions_for_undo_redo.cpp +///////////////////////////////////////////////////////////////////////////// + +/* + * This program source code file is part of KICAD, a free EDA CAD application. + * + * Copyright (C) 2009 Jean-Pierre Charras + * Copyright (C) 2007 Kicad Developers, see change_log.txt for contributors. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, you may find one here: + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html + * or you may search the http://www.gnu.org website for the version 2 license, + * or you may write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + + +/* These functions are relative to undo redo function, when zones are involved. + * When a zone outline is modified (or created) this zone, or others zones on the same layer + * and with the same netcode can change or can be deleted + * This is due to the fact overlapping zones are merged + * Also, when a zone outline is modified by adding a cutout area, + * this zone can be converted to more than one area, if the outline is break to 2 or more outlines + * and therefore new zones are created + * + * Due to the complexity of potential changes, and the fact there are only few zones + * in a board, and a zone has only few segments outlines, the more easy way to + * undo redo changes is to make a copy of all zones that can be changed + * and see after zone edition or creation what zones that are really modified, + * and ones they are modified (changes, deletion or addition) + */ + +#include "fctsys.h" +#include "appl_wxstruct.h" +#include "common.h" +#include "class_drawpanel.h" +#include "pcbnew.h" +#include "wxPcbStruct.h" +#include "zones.h" +#include "zones_functions_for_undo_redo.h" + +/** function ZONE_CONTAINER::IsSame() + * test is 2 zones are equivalent: + * 2 zones are equivalent if they have same parameters and same outlines + * info relative to filling is not take in account + * @param aZoneToCompare = zone to compare with "this" + */ +bool ZONE_CONTAINER::IsSame( const ZONE_CONTAINER& aZoneToCompare ) +{ + // compare basic parameters: + if( GetLayer() != aZoneToCompare.GetLayer() ) + return false; + if( m_Netname != aZoneToCompare.m_Netname ) + return false; + + // Compare zone specfic parameters + if( m_ZoneClearance != aZoneToCompare.m_ZoneClearance ) + return false; + if( m_ZoneMinThickness != aZoneToCompare.m_ZoneMinThickness ) + return false; + if( m_FillMode != aZoneToCompare.m_FillMode ) + return false; + if( m_ArcToSegmentsCount != aZoneToCompare.m_ArcToSegmentsCount ) + return false; + if( m_PadOption != aZoneToCompare.m_PadOption ) + return false; + if( m_ThermalReliefGapValue != aZoneToCompare.m_ThermalReliefGapValue ) + return false; + if( m_ThermalReliefCopperBridgeValue != aZoneToCompare.m_ThermalReliefCopperBridgeValue ) + return false; + + // Compare outlines + wxASSERT( m_Poly ); // m_Poly == NULL Should never happen + wxASSERT( aZoneToCompare.m_Poly ); + if( m_Poly->corner != aZoneToCompare.m_Poly->corner ) // Compare vector + return false; + + return true; +} + + +/** function SaveCopyOfZones() + * creates a copy of zones having a given netcode on a given layer, + * and fill a pick list with pickers to handle these copies + * the UndoRedo status is set to UR_CHANGED for all items in list + * Later, UpdateCopyOfZonesList will change and update these pickers after a zone edition + * @param aPickList = the pick list + * @param aPcb = the Board + * @param aNetCode = the reference netcode. if aNetCode < 0 all netcodes are used + * @param aLayer = the layer of zones. if aLayer < 0, all layers are used + * @return the count of saved copies + */ +int SaveCopyOfZones( PICKED_ITEMS_LIST& aPickList, BOARD* aPcb, int aNetCode, int aLayer ) +{ + int copyCount = 0; + + for( unsigned ii = 0; ; ii++ ) + { + ZONE_CONTAINER* zone = aPcb->GetArea( ii ); + if( zone == NULL ) // End of list + break; + if( aNetCode >= 0 && aNetCode != zone->GetNet() ) + continue; + if( aLayer >= 0 && aLayer != zone->GetLayer() ) + continue; + ZONE_CONTAINER* zoneDup = new ZONE_CONTAINER( aPcb ); + zoneDup->Copy( zone ); + ITEM_PICKER picker( zone, UR_CHANGED ); + picker.m_Link = zoneDup; + picker.m_PickedItemType = zone->Type(); + aPickList.PushItem( picker ); + copyCount++; + } + + return copyCount; +} + + +/** function UpdateCopyOfZonesList() + * check a pick list to remove zones identical to their copies + * and set the type of operation in picker (UR_DELETED, UR_CHANGED) + * if an item is deleted, the initial values are retrievered, + * because they can have changed in edition + * @param aPickList = the main pick list + * @param aAuxiliaryList = the list of deleted or added (new created) items after calculations + * @param aPcb = the Board + * + * aAuxiliaryList is a list of pickers updated by zone algorithms: + * In this list are put zone taht were added or deleted during the zone combine process + * aPickList :is a list of zone that can be modified (changed or deleted, or not modified) + * >> if the picked zone is not changed, it is removed from list + * >> if the picked zone was deleted (i.e. not found in boad list), the picker is modified: + * - its status becomes UR_DELETED + * - the aAuxiliaryList corresponding picker is removed (if not found : set an error) + * >> if the picked zone was flagged as UR_NEW, and was deleted (i.e. not found in boad list), + * - the picker is removed + * - the zone itself if really deleted + * - the aAuxiliaryList corresponding picker is removed (if not found : set an error) + * After aPickList is cleaned, the aAuxiliaryList is read + * All pickers flagged UR_NEW are moved to aPickList + * (the corresponding zones are zone that were created by the zone combine process, mainly when adding cutaout areas) + * At the end of the update process the aAuxiliaryList must be void, because all pickers created by the combine process + * must have been removed (removed for new and deleted zones, or moved in aPickList.) + * If not an error is set. + */ +void UpdateCopyOfZonesList( PICKED_ITEMS_LIST& aPickList, + PICKED_ITEMS_LIST& aAuxiliaryList, + BOARD* aPcb ) +{ + for( unsigned kk = 0; kk < aPickList.GetCount(); kk++ ) + { + UndoRedoOpType status = aPickList.GetPickedItemStatus( kk ); + + ZONE_CONTAINER* ref = (ZONE_CONTAINER*) aPickList.GetPickedItem( kk ); + for( unsigned ii = 0; ; ii++ ) // analyse the main picked list + { + ZONE_CONTAINER* zone = aPcb->GetArea( ii ); + if( zone == NULL ) + { + /* End of list: the stored item is not found: + * it must be in aDeletedList: + * search it and restore initial values + * or + * if flagged UR_NEW: remove it definitively + */ + if( status == UR_NEW ) + { + delete ref; + aPickList.RemovePicker( kk ); + kk--; + } + else + { + ZONE_CONTAINER* zcopy = (ZONE_CONTAINER*) aPickList.GetPickedItemLink( kk ); + aPickList.SetPickedItemStatus( UR_DELETED, kk ); + if( zcopy ) + ref->Copy( zcopy ); + else + wxMessageBox( wxT( "UpdateCopyOfZonesList() error: link = NULL" ) ); + aPickList.SetPickedItemLink( NULL, kk ); // the copy was deleted; the link does not exists now + delete zcopy; + } + + // Remove this item from aAuxiliaryList, mainly for tests purpose + bool notfound = true; + for( unsigned nn = 0; nn < aAuxiliaryList.GetCount(); nn++ ) + { + if( aAuxiliaryList.GetPickedItem( nn ) == ref ) + { + aAuxiliaryList.RemovePicker( nn ); + notfound = false; + break; + } + } + + if( notfound ) + wxMessageBox( wxT( + "UpdateCopyOfZonesList() error: item not found in aAuxiliaryList" ) ); + break; + } + if( zone == ref ) // picked zone found + { + if( aPickList.GetPickedItemStatus( kk ) != UR_NEW ) + { + ZONE_CONTAINER* zcopy = (ZONE_CONTAINER*) aPickList.GetPickedItemLink( kk ); + if( zone->IsSame( *zcopy ) ) // Remove picked, because no changes + { + delete zcopy; // Delete copy + aPickList.RemovePicker( kk ); + kk--; + } + } + break; + } + } + } + + + // Add new zones in main pick list, and remove pickers from Auxiliary List + for( unsigned ii = 0; ii < aAuxiliaryList.GetCount(); ii++ ) + { + if( aAuxiliaryList.GetPickedItemStatus( ii ) == UR_NEW ) + { + ITEM_PICKER picker = aAuxiliaryList.GetItemWrapper( ii ); + aPickList.PushItem( picker ); + aAuxiliaryList.RemovePicker( ii ); + ii--; + } + } + + // Should not occur: + if( aAuxiliaryList.GetCount()> 0 ) + { + wxString msg; + msg.Printf( wxT( + "UpdateCopyOfZonesList() error: aAuxiliaryList not void: %d item left (status %d)" ), + aAuxiliaryList.GetCount(), aAuxiliaryList.GetPickedItemStatus( 0 ) ); + wxMessageBox( msg ); + while( aAuxiliaryList.GetCount()> 0 ) + { + delete aAuxiliaryList.GetPickedItemLink( 0 ); + aAuxiliaryList.RemovePicker( 0 ); + } + } +} diff --git a/pcbnew/zones_functions_for_undo_redo.h b/pcbnew/zones_functions_for_undo_redo.h new file mode 100644 index 0000000000..6c8959bcda --- /dev/null +++ b/pcbnew/zones_functions_for_undo_redo.h @@ -0,0 +1,69 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: zones_functions_for_undo_redo.h +///////////////////////////////////////////////////////////////////////////// +/* + * This program source code file is part of KICAD, a free EDA CAD application. + * + * Copyright (C) 2009 Jean-Pierre Charras + * Copyright (C) 2007 Kicad Developers, see change_log.txt for contributors. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, you may find one here: + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html + * or you may search the http://www.gnu.org website for the version 2 license, + * or you may write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + + +/* These functions are relative to undo redo function, when zones are involved. + * When a zone outline is modified (or created) this zone, or others zones on the same layer + * and with the same netcode can change or can be deleted + * This is due to the fact overlapping zones are merged + * Also, when a zone outline is modified by adding a cutout area, + * this zone can be converted to more than one area, if the outline is break to 2 or more outlines + * and therefore new zones are created + * + * Due to the complexity of potential changes, and the fact there are only few zones + * in a board, and a zone has only few segments outlines, the more easy way to + * undo redo changes is to make a copy of all zones that can be changed + * and see after zone edition or creation what zones that are really modified, + * and ones they are modified (changes, deletion or addition) +*/ + +#ifndef ZONES_FUNCTIONS_TO_UNDO_REDO_H +#define ZONES_FUNCTIONS_TO_UNDO_REDO_H + + +/** function SaveCopyOfZones() + * creates a copy of zones having a given netcode on a given layer, + * and fill a pick list with pickers to handle these copies + * @param aPickList = the pick list + * @param aPcb = the Board + * @param aNetCode = the reference netcode. if aNetCode < 0 all netcodes are used + * @param aLayer = the layer of zones. if aLayer < 0, all layers are used + * @return the count of saved copies + */ +int SaveCopyOfZones(PICKED_ITEMS_LIST & aPickList, BOARD* aPcb, int aNetCode, int aLayer ); + + +/** function UpdateCopyOfZonesList() + * check a pick list to remove zones identical to their copies + * and set the type of operation in picker (UR_DELETED, UR_CHANGED) + * @param aPickList = the main pick list + * @param aDeletedList = the list of dleted items + * @param aPcb = the Board + */ +void UpdateCopyOfZonesList( PICKED_ITEMS_LIST& aPickList, PICKED_ITEMS_LIST& aDeletedList, BOARD* aPcb ); + +#endif // ZONES_FUNCTIONS_TO_UNDO_REDO_H diff --git a/pcbnew/zones_test_and_combine_areas.cpp b/pcbnew/zones_test_and_combine_areas.cpp index 279169ed6a..8d4263fd9f 100644 --- a/pcbnew/zones_test_and_combine_areas.cpp +++ b/pcbnew/zones_test_and_combine_areas.cpp @@ -18,29 +18,52 @@ bool bDontShowIntersectionArcsWarning; bool bDontShowIntersectionWarning; -/** - * Function AddArea - * add empty copper area to net +/** Function AddArea + * Add an empty copper area to board areas list + * @param aNewZonesList = a PICKED_ITEMS_LIST * where to store new areas pickers (useful in undo commands) + * can be NULL + * @param aNetcode = the necode of the copper area (0 = no net) + * @param aLayer = the layer of area + * @param aStartPointPosition = position of the first point of the polygon outline of this area + * @param aHatch = hacth option * @return pointer to the new area */ -ZONE_CONTAINER* BOARD::AddArea( int netcode, int layer, int x, int y, int hatch ) +ZONE_CONTAINER* BOARD::AddArea( PICKED_ITEMS_LIST* aNewZonesList, int aNetcode, + int aLayer, wxPoint aStartPointPosition, int aHatch ) { - ZONE_CONTAINER* new_area = InsertArea( netcode, m_ZoneDescriptorList.size( - ) - 1, layer, x, y, hatch ); + ZONE_CONTAINER* new_area = InsertArea( aNetcode, + m_ZoneDescriptorList.size( ) - 1, + aLayer, aStartPointPosition.x, aStartPointPosition.y, aHatch ); + if( aNewZonesList ) + { + ITEM_PICKER picker( new_area, UR_NEW ); + picker.m_PickedItemType = new_area->Type(); + aNewZonesList->PushItem( picker ); + } return new_area; } -/** - * remove copper area from net - * @param area = area to remove - * @return 0 +/** Function RemoveArea + * remove copper area from net, and put it in a deleted list (if exists) + * @param aDeletedList = a PICKED_ITEMS_LIST * where to store deleted areas (useful in undo commands) + * can be NULL + * @param area_to_remove = area to delete or put in deleted list */ -int BOARD::RemoveArea( ZONE_CONTAINER* area_to_remove ) +void BOARD::RemoveArea( PICKED_ITEMS_LIST* aDeletedList, ZONE_CONTAINER* area_to_remove ) { - Delete( area_to_remove ); - return 0; + if( area_to_remove == NULL ) + return; + if( aDeletedList ) + { + ITEM_PICKER picker( area_to_remove, UR_DELETED ); + picker.m_PickedItemType = area_to_remove->Type(); + aDeletedList->PushItem( picker ); + Remove( area_to_remove ); // remove from zone list, but does not delete it + } + else + Delete( area_to_remove ); } @@ -82,9 +105,8 @@ int BOARD::CompleteArea( ZONE_CONTAINER* area_to_complete, int style ) return 1; } else - { - RemoveArea( area_to_complete ); - } + Delete( area_to_complete ); + return 0; } @@ -206,19 +228,24 @@ int BOARD::TestAreaPolygon( ZONE_CONTAINER* CurrArea ) * Function ClipAreaPolygon * Process an area that has been modified, by clipping its polygon against itself. * This may change the number and order of copper areas in the net. + * @param aNewZonesList = a PICKED_ITEMS_LIST * where to store new areas pickers (useful in undo commands) + * can be NULL + * @param aCurrArea = the zone to process * @param bMessageBoxInt == true, shows message when clipping occurs. * @param bMessageBoxArc == true, shows message when clipping can't be done due to arcs. + * @param bRetainArcs = true to handle arcs (not really used in kicad) * @return: * -1 if arcs intersect other sides, so polygon can't be clipped * 0 if no intersecting sides * 1 if intersecting sides * Also sets areas->utility1 flags if areas are modified */ -int BOARD::ClipAreaPolygon( ZONE_CONTAINER* CurrArea, +int BOARD::ClipAreaPolygon( PICKED_ITEMS_LIST * aNewZonesList, + ZONE_CONTAINER* aCurrArea, bool bMessageBoxArc, bool bMessageBoxInt, bool bRetainArcs ) { - CPolyLine* curr_polygon = CurrArea->m_Poly; - int test = TestAreaPolygon( CurrArea ); // this sets utility2 flag + CPolyLine* curr_polygon = aCurrArea->m_Poly; + int test = TestAreaPolygon( aCurrArea ); // this sets utility2 flag if( test == -1 && !bRetainArcs ) test = 1; @@ -229,7 +256,7 @@ int BOARD::ClipAreaPolygon( ZONE_CONTAINER* CurrArea, { wxString str; str.Printf( wxT( "Area %8.8X of net \"%s\" has arcs intersecting other sides.\n" ), - CurrArea->m_TimeStamp, CurrArea->m_Netname.GetData() ); + aCurrArea->m_TimeStamp, aCurrArea->m_Netname.GetData() ); str += wxT( "This may cause problems with other editing operations,\n" ); str += wxT( "such as adding cutouts. It can't be fixed automatically.\n" ); str += wxT( "Manual correction is recommended." ); @@ -242,7 +269,7 @@ int BOARD::ClipAreaPolygon( ZONE_CONTAINER* CurrArea, for( unsigned ia = 0; ia < m_ZoneDescriptorList.size(); ia++ ) m_ZoneDescriptorList[ia]->utility = 0; - CurrArea->utility = 1; + aCurrArea->utility = 1; if( test == 1 ) { @@ -252,7 +279,7 @@ int BOARD::ClipAreaPolygon( ZONE_CONTAINER* CurrArea, wxString str; str.Printf( wxT( "Area %8.8X of net \"%s\" is self-intersecting and will be clipped.\n" ), - CurrArea->m_TimeStamp, CurrArea->m_Netname.GetData() ); + aCurrArea->m_TimeStamp, aCurrArea->m_Netname.GetData() ); str += wxT( "This may result in splitting the area.\n" ); str += wxT( "If the area is complex, this may take a few seconds." ); wxMessageBox( str ); @@ -266,7 +293,7 @@ int BOARD::ClipAreaPolygon( ZONE_CONTAINER* CurrArea, { std::vector* pa = new std::vector; curr_polygon->Undraw(); - int n_poly = CurrArea->m_Poly->NormalizeAreaOutlines( pa, bRetainArcs ); + int n_poly = aCurrArea->m_Poly->NormalizeAreaOutlines( pa, bRetainArcs ); if( n_poly > 1 ) // i.e if clipping has created some polygons, we must add these new copper areas { ZONE_CONTAINER* NewArea; @@ -274,7 +301,8 @@ int BOARD::ClipAreaPolygon( ZONE_CONTAINER* CurrArea, { // create new copper area and copy poly into it CPolyLine* new_p = (*pa)[ip - 1]; - NewArea = AddArea( CurrArea->GetNet(), CurrArea->GetLayer(), 0, 0, 0 ); + NewArea = AddArea( aNewZonesList, aCurrArea->GetNet(), aCurrArea->GetLayer(), + wxPoint(0, 0), CPolyLine::NO_HATCH ); // remove the poly that was automatically created for the new area // and replace it with a poly from NormalizeWithKbool @@ -295,6 +323,8 @@ int BOARD::ClipAreaPolygon( ZONE_CONTAINER* CurrArea, * Process an area that has been modified, by clipping its polygon against * itself and the polygons for any other areas on the same net. * This may change the number and order of copper areas in the net. + * @param aModifiedZonesList = a PICKED_ITEMS_LIST * where to store deleted or added areas (useful in undo commands + * can be NULL * @param modified_area = area to test * @param bMessageBoxInt == true, shows message when clipping occurs. * @param bMessageBoxArc == true, shows message when clipping can't be done due to arcs. @@ -303,12 +333,13 @@ int BOARD::ClipAreaPolygon( ZONE_CONTAINER* CurrArea, * 0 if no intersecting sides * 1 if intersecting sides, polygon clipped */ -int BOARD::AreaPolygonModified( ZONE_CONTAINER* modified_area, +int BOARD::AreaPolygonModified( PICKED_ITEMS_LIST* aModifiedZonesList, + ZONE_CONTAINER* modified_area, bool bMessageBoxArc, bool bMessageBoxInt ) { // clip polygon against itself - int test = ClipAreaPolygon( modified_area, bMessageBoxArc, bMessageBoxInt ); + int test = ClipAreaPolygon( aModifiedZonesList, modified_area, bMessageBoxArc, bMessageBoxInt ); if( test == -1 ) return test; @@ -321,7 +352,7 @@ int BOARD::AreaPolygonModified( ZONE_CONTAINER* modified_area, else bCheckAllAreas = TestAreaIntersections( modified_area ); if( bCheckAllAreas ) - CombineAllAreasInNet( modified_area->GetNet(), bMessageBoxInt, true ); + CombineAllAreasInNet( aModifiedZonesList, modified_area->GetNet(), bMessageBoxInt, true ); if( layer >= FIRST_NO_COPPER_LAYER ) // Refill non copper zones on this layer { @@ -343,7 +374,7 @@ int BOARD::AreaPolygonModified( ZONE_CONTAINER* modified_area, // Remove zone because it is incorrect: else - RemoveArea( zone ); + RemoveArea( aModifiedZonesList, zone ); } return test; @@ -353,13 +384,15 @@ int BOARD::AreaPolygonModified( ZONE_CONTAINER* modified_area, /** * Function CombineAllAreasInNet * Checks all copper areas in net for intersections, combining them if found + * @param aDeletedList = a PICKED_ITEMS_LIST * where to store deleted areas (useful in undo commands + * can be NULL * @param aNetCode = net to consider * @param bMessageBox : if true display warning message box * @param bUseUtility : if true, don't check areas if both utility flags are 0 * Sets utility flag = 1 for any areas modified * If an area has self-intersecting arcs, doesn't try to combine it */ -int BOARD::CombineAllAreasInNet( int aNetCode, bool bMessageBox, bool bUseUtility ) +int BOARD::CombineAllAreasInNet( PICKED_ITEMS_LIST* aDeletedList, int aNetCode, bool bMessageBox, bool bUseUtility ) { if( m_ZoneDescriptorList.size() <= 1 ) return 0; @@ -397,7 +430,7 @@ int BOARD::CombineAllAreasInNet( int aNetCode, bool bMessageBox, bool bUseUtilit { int ret = TestAreaIntersection( curr_area, area2 ); if( ret == 1 ) - ret = CombineAreas( curr_area, area2 ); + ret = CombineAreas( aDeletedList, curr_area, area2 ); if( ret == 1 ) { mod_ia1 = true; @@ -671,13 +704,17 @@ int BOARD::TestAreaIntersection( ZONE_CONTAINER* area_ref, ZONE_CONTAINER* area_ /** * Function CombineAreas * If possible, combine 2 copper areas - * area_ref must be BEFORE area_to_combine in m_ZoneDescriptorList + * @param aDeletedList = a PICKED_ITEMS_LIST * where to store deleted areas (useful in undo commands + * can be NULL + * @param area_ref = tje main area (zone) + * @param area_to_combine = the zone that can be merged with area_ref + * area_ref must be BEFORE area_to_combine * area_to_combine will be deleted, if areas are combined * @return : 0 if no intersection * 1 if intersection * 2 if arcs intersect */ -int BOARD::CombineAreas( ZONE_CONTAINER* area_ref, ZONE_CONTAINER* area_to_combine ) +int BOARD::CombineAreas( PICKED_ITEMS_LIST* aDeletedList, ZONE_CONTAINER* area_ref, ZONE_CONTAINER* area_to_combine ) { if( area_ref == area_to_combine ) { @@ -780,7 +817,7 @@ int BOARD::CombineAreas( ZONE_CONTAINER* area_ref, ZONE_CONTAINER* area_to_combi } if( !keep_area_to_combine ) - RemoveArea( area_to_combine ); + RemoveArea( aDeletedList, area_to_combine ); area_ref->utility = 1; area_ref->m_Poly->RestoreArcs( &arc_array1 ); diff --git a/polygon/PolyLine.cpp b/polygon/PolyLine.cpp index 669ca47b1b..221e287043 100644 --- a/polygon/PolyLine.cpp +++ b/polygon/PolyLine.cpp @@ -1489,14 +1489,11 @@ bool CPolyLine::TestPointInsideContour( int icont, int px, int py ) void CPolyLine::Copy( CPolyLine* src ) { Undraw(); - - // copy corners - for( unsigned ii = 0; ii < src->corner.size(); ii++ ) - corner.push_back( src->corner[ii] ); - - // copy side styles - for( unsigned ii = 0; ii < src->side_style.size(); ii++ ) - side_style.push_back( src->side_style[ii] ); + m_HatchStyle = src->m_HatchStyle; + // copy corners, using vector copy + corner = src->corner; + // copy side styles, using vector copy + side_style = src->side_style; } diff --git a/polygon/PolyLine.h b/polygon/PolyLine.h index 8f401695b2..c4a4e1284b 100644 --- a/polygon/PolyLine.h +++ b/polygon/PolyLine.h @@ -102,6 +102,12 @@ public: int y; bool end_contour; int utility; + + bool operator == (const CPolyPt& cpt2 ) const + { return (x == cpt2.x) && (y == cpt2.y) && (end_contour == cpt2.end_contour); } + + bool operator != (CPolyPt& cpt2 ) const + { return (x != cpt2.x) || (y != cpt2.y) || (end_contour != cpt2.end_contour); } }; #include "polygon_test_point_inside.h"