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.

318 lines
12 KiB

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