zones_functions_for_undo_redo.cpp 11.5 KB
Newer Older
1 2 3
/**
 * @file zones_functions_for_undo_redo.cpp
 */
4 5

/*
6
 * This program source code file is part of KiCad, a free EDA CAD application.
7
 *
8
 * Copyright (C) 2009 Jean-Pierre Charras <jp.charras@wanadoo.fr>
9
 * Copyright (C) 2007 KiCad Developers, see change_log.txt for contributors.
10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
 *
 * 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)
 */

45 46 47 48
#include <fctsys.h>
#include <appl_wxstruct.h>
#include <class_drawpanel.h>
#include <wxPcbStruct.h>
49

50 51
#include <class_board.h>
#include <class_zone.h>
52

53 54 55
#include <pcbnew.h>
#include <zones.h>
#include <zones_functions_for_undo_redo.h>
56

57
/**
58
 * Function IsSame
59 60 61 62 63 64 65 66 67 68
 * 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;
69

70 71 72
    if( m_Netname != aZoneToCompare.m_Netname )
        return false;

73
    if( GetPriority() != aZoneToCompare.GetPriority() )
74 75 76
        return false;

    // Compare zone specific parameters
77
    if( GetIsKeepout() != aZoneToCompare.GetIsKeepout() )
78 79
        return false;

80
    if( GetIsKeepout() )
81
    {
82
        if(  GetDoNotAllowCopperPour() != aZoneToCompare.GetDoNotAllowCopperPour() )
83 84 85 86 87 88 89 90 91
            return false;

        if(  GetDoNotAllowVias() != aZoneToCompare.GetDoNotAllowVias() )
            return false;

        if(  GetDoNotAllowTracks() != aZoneToCompare.GetDoNotAllowTracks() )
            return false;
    }

92
    if( m_ArcToSegmentsCount != aZoneToCompare.m_ArcToSegmentsCount )
93 94
        return false;

95
    if( m_ZoneClearance != aZoneToCompare.m_ZoneClearance )
96
        return false;
97

98
    if( m_ZoneMinThickness != aZoneToCompare.m_ZoneMinThickness )
99
        return false;
100

101
    if( m_FillMode != aZoneToCompare.m_FillMode )
102
        return false;
103

104
    if( m_PadConnection != aZoneToCompare.m_PadConnection )
105
        return false;
106

107
    if( m_ThermalReliefGap != aZoneToCompare.m_ThermalReliefGap )
108
        return false;
109

110
    if( m_ThermalReliefCopperBridge != aZoneToCompare.m_ThermalReliefCopperBridge )
111 112
        return false;

113

114
    // Compare outlines
115
    wxASSERT( m_Poly );                                      // m_Poly == NULL Should never happen
116
    wxASSERT( aZoneToCompare.m_Poly );
117

118
    if( m_Poly->m_CornersList != aZoneToCompare.m_Poly->m_CornersList )    // Compare vector
119 120 121 122 123 124
        return false;

    return true;
}


125
/**
126
 * Function SaveCopyOfZones
127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143
 * 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 );
144

145 146
        if( zone == NULL )      // End of list
            break;
147

148 149
        if( aNetCode >= 0 && aNetCode != zone->GetNet() )
            continue;
150

151 152
        if( aLayer >= 0 && aLayer != zone->GetLayer() )
            continue;
153

154 155
        ZONE_CONTAINER* zoneDup = new ZONE_CONTAINER( *zone );
        zoneDup->SetParent( aPcb );
156 157
        ITEM_PICKER picker( zone, UR_CHANGED );
        picker.SetLink( zoneDup );
158 159 160 161 162 163 164 165
        aPickList.PushItem( picker );
        copyCount++;
    }

    return copyCount;
}


166
/**
167
 * Function UpdateCopyOfZonesList
168 169 170 171 172 173 174 175 176
 * 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:
177
 *  This list contains zones which were added or deleted during the zones combine process
jean-pierre charras's avatar
jean-pierre charras committed
178
 * aPickList :is a list of zones that can be modified (changed or deleted, or not modified)
179 180
 *  Typically, this is the list of existing zones on the layer of the edited zone,
 *  before any change.
181
 *  >> if the picked zone is not changed, it is removed from list
182 183 184 185 186 187 188 189
 *  >> if the picked zone was deleted (i.e. not found in board 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 after deleted ,
 *  perhaps combined with an other zone  (i.e. not found in board list):
 *          the picker is removed
 *          the zone itself if really deleted
 *          the aAuxiliaryList corresponding picker is removed (if not found : set an error)
190 191
 * After aPickList is cleaned, the aAuxiliaryList is read
 *  All pickers flagged UR_NEW are moved to aPickList
192 193 194 195 196
 * (the corresponding zones are zone that were created by the zone normalize and combine process,
 * mainly when adding cutout areas, or creating self intersecting contours)
 *  All pickers flagged UR_DELETED are removed, and the coresponding zones actually deleted
 * (the corresponding zones are new zone that were created by the zone normalize process,
 * when creating self intersecting contours, and after combined with an existing zone.
jean-pierre charras's avatar
jean-pierre charras committed
197 198 199
 * 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.)
200 201 202 203 204 205 206 207
 * 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++ )
    {
208
        UNDO_REDO_T  status = aPickList.GetPickedItemStatus( kk );
209 210

        ZONE_CONTAINER* ref = (ZONE_CONTAINER*) aPickList.GetPickedItem( kk );
211

212 213 214
        for( unsigned ii = 0; ; ii++ )  // analyse the main picked list
        {
            ZONE_CONTAINER* zone = aPcb->GetArea( ii );
215

216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233
            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 );
234

235 236 237 238
                    if( zcopy )
                        ref->Copy( zcopy );
                    else
                        wxMessageBox( wxT( "UpdateCopyOfZonesList() error: link = NULL" ) );
239

240 241
                    // the copy was deleted; the link does not exists now.
                    aPickList.SetPickedItemLink( NULL, kk );
242 243 244 245 246
                    delete zcopy;
                }

                // Remove this item from aAuxiliaryList, mainly for tests purpose
                bool notfound = true;
247

248 249 250 251 252 253 254 255 256 257 258
                for( unsigned nn = 0; nn < aAuxiliaryList.GetCount(); nn++ )
                {
                    if( aAuxiliaryList.GetPickedItem( nn ) == ref )
                    {
                        aAuxiliaryList.RemovePicker( nn );
                        notfound = false;
                        break;
                    }
                }

                if( notfound )
259 260
                    wxMessageBox( wxT( "UpdateCopyOfZonesList() error: item not found in aAuxiliaryList" ) );

261 262 263 264 265 266 267
                break;
            }
            if( zone == ref )      // picked zone found
            {
                if( aPickList.GetPickedItemStatus( kk ) != UR_NEW )
                {
                    ZONE_CONTAINER* zcopy = (ZONE_CONTAINER*) aPickList.GetPickedItemLink( kk );
268

269 270 271 272 273 274 275
                    if( zone->IsSame( *zcopy ) )    // Remove picked, because no changes
                    {
                        delete zcopy;               // Delete copy
                        aPickList.RemovePicker( kk );
                        kk--;
                    }
                }
276

277 278 279 280 281 282 283
                break;
            }
        }
    }


    // Add new zones in main pick list, and remove pickers from Auxiliary List
284
    for( unsigned ii = 0; ii < aAuxiliaryList.GetCount(); )
285 286 287 288 289 290 291
    {
        if( aAuxiliaryList.GetPickedItemStatus( ii ) == UR_NEW )
        {
            ITEM_PICKER picker = aAuxiliaryList.GetItemWrapper( ii );
            aPickList.PushItem( picker );
            aAuxiliaryList.RemovePicker( ii );
        }
292 293 294 295 296 297 298
        else if( aAuxiliaryList.GetPickedItemStatus( ii ) == UR_DELETED )
        {
            delete aAuxiliaryList.GetPickedItemLink( ii );
            aAuxiliaryList.RemovePicker( ii );
        }
        else
            ii++;
299 300 301 302 303 304
    }

    // Should not occur:
    if( aAuxiliaryList.GetCount()> 0 )
    {
        wxString msg;
305 306
        msg.Printf( wxT( "UpdateCopyOfZonesList() error: aAuxiliaryList not void: %d item left (status %d)" ),
                    aAuxiliaryList.GetCount(), aAuxiliaryList.GetPickedItemStatus( 0 ) );
307
        wxMessageBox( msg );
308 309

        while( aAuxiliaryList.GetCount() > 0 )
310 311 312 313 314 315
        {
            delete aAuxiliaryList.GetPickedItemLink( 0 );
            aAuxiliaryList.RemovePicker( 0 );
        }
    }
}