You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

303 lines
11 KiB

  1. /*
  2. * This program source code file is part of KiCad, a free EDA CAD application.
  3. *
  4. * Copyright (C) 2009 Jean-Pierre Charras <jp.charras@wanadoo.fr>
  5. * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
  6. *
  7. * This program is free software; you can redistribute it and/or
  8. * modify it under the terms of the GNU General Public License
  9. * as published by the Free Software Foundation; either version 2
  10. * of the License, or (at your option) any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License
  18. * along with this program; if not, you may find one here:
  19. * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
  20. * or you may search the http://www.gnu.org website for the version 2 license,
  21. * or you may write to the Free Software Foundation, Inc.,
  22. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
  23. */
  24. /* These functions are relative to undo redo function, when zones are involved.
  25. *
  26. * When a zone outline is modified (or created) this zone, or others zones on the same layer
  27. * and with the same netcode can change or can be deleted due to the fact overlapping zones are
  28. * merged. Also, when a zone outline is modified by adding a cutout area, this zone can be
  29. * converted to more than one area, if the outline is break to 2 or more outlines and therefore
  30. * new zones are created
  31. *
  32. * Due to the complexity of potential changes, and the fact there are only few zones in a board,
  33. * and a zone has only few segments outlines, the more easy way to undo redo changes is to make
  34. * a copy of all zones that can be changed and see after zone editing or creation what zones that
  35. * are really modified, and ones they are modified (changes, deletion or addition)
  36. */
  37. #include <pcb_edit_frame.h>
  38. #include <board.h>
  39. #include <zone.h>
  40. #include <zones.h>
  41. #include <zones_functions_for_undo_redo.h>
  42. /**
  43. * Function IsSame
  44. * test is 2 zones are equivalent:
  45. * 2 zones are equivalent if they have same parameters and same outlines
  46. * info relative to filling is not take in account
  47. * @param aZoneToCompare = zone to compare with "this"
  48. */
  49. bool ZONE::IsSame( const ZONE& aZoneToCompare )
  50. {
  51. // compare basic parameters:
  52. if( GetLayerSet() != aZoneToCompare.GetLayerSet() )
  53. return false;
  54. if( GetNetCode() != aZoneToCompare.GetNetCode() )
  55. return false;
  56. if( GetAssignedPriority() != aZoneToCompare.GetAssignedPriority() )
  57. return false;
  58. // Compare zone specific parameters
  59. if( GetIsRuleArea() != aZoneToCompare.GetIsRuleArea() )
  60. return false;
  61. if( GetDoNotAllowCopperPour() != aZoneToCompare.GetDoNotAllowCopperPour() )
  62. return false;
  63. if( GetDoNotAllowVias() != aZoneToCompare.GetDoNotAllowVias() )
  64. return false;
  65. if( GetDoNotAllowTracks() != aZoneToCompare.GetDoNotAllowTracks() )
  66. return false;
  67. if( GetDoNotAllowPads() != aZoneToCompare.GetDoNotAllowPads() )
  68. return false;
  69. if( GetDoNotAllowFootprints() != aZoneToCompare.GetDoNotAllowFootprints() )
  70. return false;
  71. if( GetRuleAreaPlacementEnabled() != aZoneToCompare.GetRuleAreaPlacementEnabled() )
  72. return false;
  73. if( GetRuleAreaPlacementSourceType() != aZoneToCompare.GetRuleAreaPlacementSourceType() )
  74. return false;
  75. if( GetRuleAreaPlacementSource() != aZoneToCompare.GetRuleAreaPlacementSource() )
  76. return false;
  77. if( m_ZoneClearance != aZoneToCompare.m_ZoneClearance )
  78. return false;
  79. if( m_ZoneMinThickness != aZoneToCompare.GetMinThickness() )
  80. return false;
  81. if( m_fillMode != aZoneToCompare.GetFillMode() )
  82. return false;
  83. if( m_PadConnection != aZoneToCompare.m_PadConnection )
  84. return false;
  85. if( m_thermalReliefGap != aZoneToCompare.m_thermalReliefGap )
  86. return false;
  87. if( m_thermalReliefSpokeWidth != aZoneToCompare.m_thermalReliefSpokeWidth )
  88. return false;
  89. if( m_zoneName != aZoneToCompare.m_zoneName )
  90. return false;
  91. if( m_islandRemovalMode != aZoneToCompare.m_islandRemovalMode )
  92. return false;
  93. if( m_minIslandArea != aZoneToCompare.m_minIslandArea )
  94. return false;
  95. // Compare outlines
  96. wxASSERT( m_Poly ); // m_Poly == NULL Should never happen
  97. wxASSERT( aZoneToCompare.Outline() );
  98. if( Outline() != aZoneToCompare.Outline() ) // Compare vector
  99. return false;
  100. return true;
  101. }
  102. /**
  103. * Function SaveCopyOfZones
  104. * creates a copy of zones having a given netcode on a given layer,
  105. * and fill a pick list with pickers to handle these copies
  106. * the UndoRedo status is set to CHANGED for all items in list
  107. * Later, UpdateCopyOfZonesList will change and update these pickers after a zone editing
  108. * @param aPickList = the pick list
  109. * @param aPcb = the Board
  110. */
  111. void SaveCopyOfZones( PICKED_ITEMS_LIST& aPickList, BOARD* aPcb )
  112. {
  113. for( ZONE* zone : aPcb->Zones() )
  114. {
  115. ZONE* zoneDup = new ZONE( *zone );
  116. zoneDup->SetParent( aPcb );
  117. zoneDup->SetParentGroup( nullptr );
  118. ITEM_PICKER picker( nullptr, zone, UNDO_REDO::CHANGED );
  119. picker.SetLink( zoneDup );
  120. aPickList.PushItem( picker );
  121. }
  122. }
  123. /**
  124. * Function UpdateCopyOfZonesList
  125. * Check a pick list to remove zones identical to their copies and set the type of operation in
  126. * picker (DELETED, CHANGED). If an item is deleted, the initial values are retrievered,
  127. * because they can have changed during editing.
  128. * @param aPickList = the main pick list
  129. * @param aAuxiliaryList = the list of deleted or added (new created) items after calculations
  130. * @param aPcb = the Board
  131. *
  132. * aAuxiliaryList is a list of pickers updated by zone algorithms:
  133. * This list contains zones which were added or deleted during the zones combine process
  134. * aPickList :is a list of zones that can be modified (changed or deleted, or not modified)
  135. * Typically, this is the list of existing zones on the layer of the edited zone,
  136. * before any change.
  137. * >> if the picked zone is not changed, it is removed from list
  138. * >> if the picked zone was deleted (i.e. not found in board list), the picker is modified:
  139. * its status becomes DELETED
  140. * the aAuxiliaryList corresponding picker is removed (if not found : set an error)
  141. * >> if the picked zone was flagged as NEWITEM, and was after deleted ,
  142. * perhaps combined with another zone (i.e. not found in board list):
  143. * the picker is removed
  144. * the zone itself if really deleted
  145. * the aAuxiliaryList corresponding picker is removed (if not found : set an error)
  146. * After aPickList is cleaned, the aAuxiliaryList is read
  147. * All pickers flagged NEWITEM are moved to aPickList
  148. * (the corresponding zones are zone that were created by the zone normalize and combine process,
  149. * mainly when adding cutout areas, or creating self intersecting contours)
  150. * All pickers flagged DELETED are removed, and the corresponding zones actually deleted
  151. * (the corresponding zones are new zone that were created by the zone normalize process,
  152. * when creating self intersecting contours, and after combined with an existing zone.
  153. * At the end of the update process the aAuxiliaryList must be void,
  154. * because all pickers created by the combine process
  155. * must have been removed (removed for new and deleted zones, or moved in aPickList.)
  156. * If not an error is set.
  157. */
  158. void UpdateCopyOfZonesList( PICKED_ITEMS_LIST& aPickList, PICKED_ITEMS_LIST& aAuxiliaryList,
  159. BOARD* aPcb )
  160. {
  161. for( unsigned kk = 0; kk < aPickList.GetCount(); kk++ )
  162. {
  163. UNDO_REDO status = aPickList.GetPickedItemStatus( kk );
  164. ZONE* ref = (ZONE*) aPickList.GetPickedItem( kk );
  165. for( unsigned ii = 0; ; ii++ ) // analyse the main picked list
  166. {
  167. ZONE* zone = aPcb->GetArea( ii );
  168. if( zone == nullptr )
  169. {
  170. /* End of list: the stored item is not found:
  171. * it must be in aDeletedList:
  172. * search it and restore initial values
  173. * or
  174. * if flagged NEWITEM: remove it definitively
  175. */
  176. if( status == UNDO_REDO::NEWITEM )
  177. {
  178. delete ref;
  179. ref = nullptr;
  180. aPickList.RemovePicker( kk );
  181. kk--;
  182. }
  183. else
  184. {
  185. ZONE* zcopy = (ZONE*) aPickList.GetPickedItemLink( kk );
  186. aPickList.SetPickedItemStatus( UNDO_REDO::DELETED, kk );
  187. wxASSERT_MSG( zcopy != nullptr,
  188. wxT( "UpdateCopyOfZonesList() error: link = NULL" ) );
  189. ref->SwapItemData( zcopy );
  190. // the copy was deleted; the link does not exists now.
  191. aPickList.SetPickedItemLink( nullptr, kk );
  192. delete zcopy;
  193. }
  194. // Remove this item from aAuxiliaryList, mainly for tests purpose
  195. bool notfound = true;
  196. for( unsigned nn = 0; nn < aAuxiliaryList.GetCount(); nn++ )
  197. {
  198. if( ref != nullptr && aAuxiliaryList.GetPickedItem( nn ) == ref )
  199. {
  200. aAuxiliaryList.RemovePicker( nn );
  201. notfound = false;
  202. break;
  203. }
  204. }
  205. if( notfound ) // happens when the new zone overlaps an existing zone
  206. // and these zones are combined
  207. {
  208. #if defined(DEBUG)
  209. printf( "UpdateCopyOfZonesList(): item not found in aAuxiliaryList,"
  210. "combined with another zone\n" );
  211. fflush(nullptr);
  212. #endif
  213. }
  214. break;
  215. }
  216. if( zone == ref ) // picked zone found
  217. {
  218. if( aPickList.GetPickedItemStatus( kk ) != UNDO_REDO::NEWITEM )
  219. {
  220. ZONE* zcopy = (ZONE*) aPickList.GetPickedItemLink( kk );
  221. if( zone->IsSame( *zcopy ) ) // Remove picked, because no changes
  222. {
  223. delete zcopy; // Delete copy
  224. aPickList.RemovePicker( kk );
  225. kk--;
  226. }
  227. }
  228. break;
  229. }
  230. }
  231. }
  232. // Add new zones in main pick list, and remove pickers from Auxiliary List
  233. for( unsigned ii = 0; ii < aAuxiliaryList.GetCount(); )
  234. {
  235. if( aAuxiliaryList.GetPickedItemStatus( ii ) == UNDO_REDO::NEWITEM )
  236. {
  237. ITEM_PICKER picker = aAuxiliaryList.GetItemWrapper( ii );
  238. aPickList.PushItem( picker );
  239. aAuxiliaryList.RemovePicker( ii );
  240. }
  241. else if( aAuxiliaryList.GetPickedItemStatus( ii ) == UNDO_REDO::DELETED )
  242. {
  243. delete aAuxiliaryList.GetPickedItemLink( ii );
  244. aAuxiliaryList.RemovePicker( ii );
  245. }
  246. else
  247. {
  248. ii++;
  249. }
  250. }
  251. // Should not occur:
  252. wxASSERT_MSG( aAuxiliaryList.GetCount() == 0,
  253. wxT( "UpdateCopyOfZonesList() error: aAuxiliaryList not empty." ) );
  254. }