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.
		
		
		
		
		
			
		
			
				
					
					
						
							1020 lines
						
					
					
						
							33 KiB
						
					
					
				
			
		
		
		
			
			
			
		
		
	
	
							1020 lines
						
					
					
						
							33 KiB
						
					
					
				
								/*
							 | 
						|
								 * This program source code file is part of KiCad, a free EDA CAD application.
							 | 
						|
								 *
							 | 
						|
								 * Copyright (C) 2015 Jean-Pierre Charras, jp.charras at wanadoo.fr
							 | 
						|
								 * Copyright (C) 2012 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
							 | 
						|
								 * Copyright (C) 2012 Wayne Stambaugh <stambaughw@verizon.net>
							 | 
						|
								 * Copyright (C) 1992-2017 KiCad Developers, see AUTHORS.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
							 | 
						|
								 */
							 | 
						|
								
							 | 
						|
								/**
							 | 
						|
								 * @file zones_by_polygon.cpp
							 | 
						|
								 */
							 | 
						|
								
							 | 
						|
								#include <fctsys.h>
							 | 
						|
								#include <kiface_i.h>
							 | 
						|
								#include <class_drawpanel.h>
							 | 
						|
								#include <confirm.h>
							 | 
						|
								#include <pcb_edit_frame.h>
							 | 
						|
								#include <board_commit.h>
							 | 
						|
								#include <view/view.h>
							 | 
						|
								
							 | 
						|
								#include <class_board.h>
							 | 
						|
								#include <class_zone.h>
							 | 
						|
								
							 | 
						|
								#include <pcbnew.h>
							 | 
						|
								#include <zones.h>
							 | 
						|
								#include <pcbnew_id.h>
							 | 
						|
								#include <protos.h>
							 | 
						|
								#include <zones_functions_for_undo_redo.h>
							 | 
						|
								#include <drc.h>
							 | 
						|
								#include <connectivity/connectivity_data.h>
							 | 
						|
								
							 | 
						|
								#include <widgets/progress_reporter.h>
							 | 
						|
								
							 | 
						|
								#include <zone_filler.h>
							 | 
						|
								
							 | 
						|
								// Outline creation:
							 | 
						|
								static void Abort_Zone_Create_Outline( EDA_DRAW_PANEL* Panel, wxDC* DC );
							 | 
						|
								static void Show_New_Edge_While_Move_Mouse( EDA_DRAW_PANEL* aPanel, wxDC* aDC,
							 | 
						|
								                                            const wxPoint& aPosition, bool aErase );
							 | 
						|
								
							 | 
						|
								// Corner moving
							 | 
						|
								static void Abort_Zone_Move_Corner_Or_Outlines( EDA_DRAW_PANEL* Panel, wxDC* DC );
							 | 
						|
								static void Show_Zone_Corner_Or_Outline_While_Move_Mouse( EDA_DRAW_PANEL* aPanel,
							 | 
						|
								                                                          wxDC*           aDC,
							 | 
						|
								                                                          const wxPoint&  aPosition,
							 | 
						|
								                                                          bool            aErase );
							 | 
						|
								
							 | 
						|
								// Local variables
							 | 
						|
								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 added 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 s_AuxiliaryList;           // a picked list to store zones that are deleted or added when combined
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								void PCB_EDIT_FRAME::Add_Similar_Zone( wxDC* DC, ZONE_CONTAINER* aZone )
							 | 
						|
								{
							 | 
						|
								    if( !aZone )
							 | 
						|
								        return;
							 | 
						|
								
							 | 
						|
								    s_AddCutoutToCurrentZone = false;
							 | 
						|
								    s_CurrentZone = aZone;
							 | 
						|
								
							 | 
						|
								    // set zone settings to the current zone
							 | 
						|
								    ZONE_SETTINGS  zoneInfo = GetZoneSettings();
							 | 
						|
								    zoneInfo << *aZone;
							 | 
						|
								    SetZoneSettings( zoneInfo );
							 | 
						|
								
							 | 
						|
								    // Use the general event handler to set others params (like toolbar)
							 | 
						|
								    wxCommandEvent evt;
							 | 
						|
								    evt.SetId( aZone->GetIsKeepout() ? ID_PCB_KEEPOUT_AREA_BUTT : ID_PCB_ZONES_BUTT );
							 | 
						|
								    OnSelectTool( evt );
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								void PCB_EDIT_FRAME::Add_Zone_Cutout( wxDC* DC, ZONE_CONTAINER* aZone )
							 | 
						|
								{
							 | 
						|
								    if( !aZone )
							 | 
						|
								        return;
							 | 
						|
								
							 | 
						|
								    s_AddCutoutToCurrentZone = true;
							 | 
						|
								    s_CurrentZone = aZone;
							 | 
						|
								
							 | 
						|
								    // set zones setup to the current zone
							 | 
						|
								    ZONE_SETTINGS zoneInfo = GetZoneSettings();
							 | 
						|
								    zoneInfo << *aZone;
							 | 
						|
								    SetZoneSettings( zoneInfo );
							 | 
						|
								
							 | 
						|
								    // Use the general event handle to set others params (like toolbar)
							 | 
						|
								    wxCommandEvent evt;
							 | 
						|
								    evt.SetId( aZone->GetIsKeepout() ? ID_PCB_KEEPOUT_AREA_BUTT : ID_PCB_ZONES_BUTT );
							 | 
						|
								    OnSelectTool( evt );
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								void PCB_EDIT_FRAME::duplicateZone( wxDC* aDC, ZONE_CONTAINER* aZone )
							 | 
						|
								{
							 | 
						|
								    ZONE_SETTINGS zoneSettings;
							 | 
						|
								    zoneSettings << *aZone;
							 | 
						|
								    int dialogResult;
							 | 
						|
								
							 | 
						|
								    if( aZone->GetIsKeepout() )
							 | 
						|
								        dialogResult = InvokeKeepoutAreaEditor( this, &zoneSettings );
							 | 
						|
								    else if( aZone->IsOnCopperLayer() )
							 | 
						|
								        dialogResult = InvokeCopperZonesEditor( this, &zoneSettings );
							 | 
						|
								    else
							 | 
						|
								        dialogResult = InvokeNonCopperZonesEditor( this, &zoneSettings );
							 | 
						|
								
							 | 
						|
								    if( dialogResult != wxID_OK )
							 | 
						|
								        return;
							 | 
						|
								
							 | 
						|
								    // If the new zone is on the same layer as the the initial zone we'll end up combining
							 | 
						|
								    // them which will result in a no-op.  Might as well exit here.
							 | 
						|
								    if( aZone->GetIsKeepout() && ( aZone->GetLayerSet() == zoneSettings.m_Layers ) )
							 | 
						|
								    {
							 | 
						|
								        DisplayErrorMessage( this, _( "The duplicated zone cannot be on the same layers as the original zone." ) );
							 | 
						|
								        return;
							 | 
						|
								    }
							 | 
						|
								    else if( !aZone->GetIsKeepout() && ( aZone->GetLayer() == zoneSettings.m_CurrentZone_Layer ) )
							 | 
						|
								    {
							 | 
						|
								        DisplayErrorMessage( this, _(  "The duplicated zone cannot be on the same layer as the original zone." ) );
							 | 
						|
								        return;
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    ZONE_CONTAINER* newZone = new ZONE_CONTAINER( *aZone );
							 | 
						|
								    newZone->UnFill();
							 | 
						|
								    zoneSettings.ExportSetting( *newZone );
							 | 
						|
								    newZone->Hatch();
							 | 
						|
								
							 | 
						|
								    s_AuxiliaryList.ClearListAndDeleteItems();
							 | 
						|
								    s_PickedList.ClearListAndDeleteItems();
							 | 
						|
								    SaveCopyOfZones( s_PickedList, GetBoard(), newZone->GetNetCode(), newZone->GetLayer() );
							 | 
						|
								    GetBoard()->Add( newZone );
							 | 
						|
								
							 | 
						|
								    ITEM_PICKER picker( newZone, UR_NEW );
							 | 
						|
								    s_PickedList.PushItem( picker );
							 | 
						|
								
							 | 
						|
								    GetScreen()->SetCurItem( NULL );       // This outline may be deleted when merging outlines
							 | 
						|
								
							 | 
						|
								    // Combine zones if possible
							 | 
						|
								    GetBoard()->OnAreaPolygonModified( &s_AuxiliaryList, newZone );
							 | 
						|
								
							 | 
						|
								    // Redraw zones
							 | 
						|
								    GetBoard()->RedrawAreasOutlines( m_canvas, aDC, GR_OR, newZone->GetLayer() );
							 | 
						|
								    GetBoard()->RedrawFilledAreas( m_canvas, aDC, GR_OR, newZone->GetLayer() );
							 | 
						|
								
							 | 
						|
								    DRC drc( this );
							 | 
						|
								
							 | 
						|
								    if( GetBoard()->GetAreaIndex( newZone ) >= 0 && drc.TestZoneToZoneOutline( newZone, true ) )
							 | 
						|
								        DisplayInfoMessage( this, _( "Warning: The new zone fails DRC" ) );
							 | 
						|
								
							 | 
						|
								    UpdateCopyOfZonesList( s_PickedList, s_AuxiliaryList, GetBoard() );
							 | 
						|
								    SaveCopyInUndoList( s_PickedList, UR_UNSPECIFIED );
							 | 
						|
								    s_PickedList.ClearItemsList();
							 | 
						|
								
							 | 
						|
								    OnModify();
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								int PCB_EDIT_FRAME::Delete_LastCreatedCorner( wxDC* DC )
							 | 
						|
								{
							 | 
						|
								    ZONE_CONTAINER* zone = GetBoard()->m_CurrentZoneContour;
							 | 
						|
								
							 | 
						|
								    if( !zone )
							 | 
						|
								        return 0;
							 | 
						|
								
							 | 
						|
								    if( !zone->GetNumCorners() )
							 | 
						|
								        return 0;
							 | 
						|
								
							 | 
						|
								    zone->DrawWhileCreateOutline( m_canvas, DC, GR_XOR );
							 | 
						|
								
							 | 
						|
								    if( zone->GetNumCorners() > 2 )
							 | 
						|
								    {
							 | 
						|
								        zone->Outline()->RemoveVertex( zone->GetNumCorners() - 1 );
							 | 
						|
								
							 | 
						|
								        if( m_canvas->IsMouseCaptured() )
							 | 
						|
								            m_canvas->CallMouseCapture( DC, wxDefaultPosition, false );
							 | 
						|
								    }
							 | 
						|
								    else
							 | 
						|
								    {
							 | 
						|
								        m_canvas->SetMouseCapture( NULL, NULL );
							 | 
						|
								        SetCurItem( NULL );
							 | 
						|
								        zone->RemoveAllContours();
							 | 
						|
								        zone->ClearFlags();
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    return zone->GetNumCorners();
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								/**
							 | 
						|
								 * Function Abort_Zone_Create_Outline
							 | 
						|
								 * cancels the Begin_Zone command if at least one EDGE_ZONE was created.
							 | 
						|
								 */
							 | 
						|
								static void Abort_Zone_Create_Outline( EDA_DRAW_PANEL* Panel, wxDC* DC )
							 | 
						|
								{
							 | 
						|
								    PCB_EDIT_FRAME* pcbframe = (PCB_EDIT_FRAME*) Panel->GetParent();
							 | 
						|
								    ZONE_CONTAINER* zone = pcbframe->GetBoard()->m_CurrentZoneContour;
							 | 
						|
								
							 | 
						|
								    if( zone )
							 | 
						|
								    {
							 | 
						|
								        zone->DrawWhileCreateOutline( Panel, DC, GR_XOR );
							 | 
						|
								        zone->RemoveAllContours();
							 | 
						|
								        if( zone->IsNew() )
							 | 
						|
								        {
							 | 
						|
								            delete zone;
							 | 
						|
								            pcbframe->GetBoard()->m_CurrentZoneContour = NULL;
							 | 
						|
								        }
							 | 
						|
								        else
							 | 
						|
								            zone->ClearFlags();
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    pcbframe->SetCurItem( NULL );
							 | 
						|
								    s_AddCutoutToCurrentZone = false;
							 | 
						|
								    s_CurrentZone = NULL;
							 | 
						|
								    Panel->SetMouseCapture( NULL, NULL );
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								void PCB_EDIT_FRAME::Start_Move_Zone_Corner( wxDC* DC, ZONE_CONTAINER* aZone,
							 | 
						|
								                                             int corner_id, bool IsNewCorner )
							 | 
						|
								{
							 | 
						|
								    if( aZone->IsOnCopperLayer() ) // Show the Net
							 | 
						|
								    {
							 | 
						|
								        if( GetBoard()->IsHighLightNetON() && DC )
							 | 
						|
								        {
							 | 
						|
								            HighLight( DC );  // Remove old highlight selection
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        ZONE_SETTINGS zoneInfo = GetZoneSettings();
							 | 
						|
								        zoneInfo.m_NetcodeSelection = aZone->GetNetCode();
							 | 
						|
								        SetZoneSettings( zoneInfo );
							 | 
						|
								
							 | 
						|
								        GetBoard()->SetHighLightNet( aZone->GetNetCode() );
							 | 
						|
								
							 | 
						|
								        if( DC )
							 | 
						|
								            HighLight( DC );
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								    // Prepare copy of old zones, for undo/redo.
							 | 
						|
								    // if the corner is new, remove it from list, save and insert it in list
							 | 
						|
								    VECTOR2I corner = aZone->Outline()->Vertex( corner_id );
							 | 
						|
								
							 | 
						|
								    if ( IsNewCorner )
							 | 
						|
								        aZone->Outline()->RemoveVertex( corner_id );
							 | 
						|
								
							 | 
						|
								    s_AuxiliaryList.ClearListAndDeleteItems();
							 | 
						|
								    s_PickedList.ClearListAndDeleteItems();
							 | 
						|
								
							 | 
						|
								    SaveCopyOfZones( s_PickedList, GetBoard(), aZone->GetNetCode(), aZone->GetLayer() );
							 | 
						|
								
							 | 
						|
								    if ( IsNewCorner )
							 | 
						|
								        aZone->Outline()->InsertVertex(corner_id-1, corner );
							 | 
						|
								
							 | 
						|
								    aZone->SetFlags( IN_EDIT );
							 | 
						|
								    m_canvas->SetMouseCapture( Show_Zone_Corner_Or_Outline_While_Move_Mouse,
							 | 
						|
								                                Abort_Zone_Move_Corner_Or_Outlines );
							 | 
						|
								    s_CornerInitialPosition = static_cast<wxPoint>( aZone->GetCornerPosition( corner_id ) );
							 | 
						|
								    s_CornerIsNew = IsNewCorner;
							 | 
						|
								    s_AddCutoutToCurrentZone = false;
							 | 
						|
								    s_CurrentZone = NULL;
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								void PCB_EDIT_FRAME::Start_Move_Zone_Drag_Outline_Edge( wxDC*           DC,
							 | 
						|
								                                                        ZONE_CONTAINER* aZone,
							 | 
						|
								                                                        int             corner_id )
							 | 
						|
								{
							 | 
						|
								    aZone->SetFlags( IS_DRAGGED );
							 | 
						|
								    aZone->SetSelectedCorner( corner_id );
							 | 
						|
								    m_canvas->SetMouseCapture( Show_Zone_Corner_Or_Outline_While_Move_Mouse,
							 | 
						|
								                                Abort_Zone_Move_Corner_Or_Outlines );
							 | 
						|
								    s_CursorLastPosition     = s_CornerInitialPosition = GetCrossHairPosition();
							 | 
						|
								    s_AddCutoutToCurrentZone = false;
							 | 
						|
								    s_CurrentZone = NULL;
							 | 
						|
								
							 | 
						|
								    s_PickedList.ClearListAndDeleteItems();
							 | 
						|
								    s_AuxiliaryList.ClearListAndDeleteItems();
							 | 
						|
								    SaveCopyOfZones( s_PickedList, GetBoard(), aZone->GetNetCode(), aZone->GetLayer() );
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								void PCB_EDIT_FRAME::Start_Move_Zone_Outlines( wxDC* DC, ZONE_CONTAINER* aZone )
							 | 
						|
								{
							 | 
						|
								    // Show the Net
							 | 
						|
								    if( aZone->IsOnCopperLayer() ) // Show the Net
							 | 
						|
								    {
							 | 
						|
								        if( GetBoard()->IsHighLightNetON() )
							 | 
						|
								        {
							 | 
						|
								            HighLight( DC );  // Remove old highlight selection
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        ZONE_SETTINGS zoneInfo = GetZoneSettings();
							 | 
						|
								        zoneInfo.m_NetcodeSelection = aZone->GetNetCode();
							 | 
						|
								        SetZoneSettings( zoneInfo );
							 | 
						|
								
							 | 
						|
								        GetBoard()->SetHighLightNet( aZone->GetNetCode() );
							 | 
						|
								        HighLight( DC );
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    s_PickedList.ClearListAndDeleteItems();
							 | 
						|
								    s_AuxiliaryList.ClearListAndDeleteItems();
							 | 
						|
								    SaveCopyOfZones( s_PickedList, GetBoard(), aZone->GetNetCode(), aZone->GetLayer() );
							 | 
						|
								
							 | 
						|
								    aZone->SetFlags( IS_MOVED );
							 | 
						|
								    m_canvas->SetMouseCapture( Show_Zone_Corner_Or_Outline_While_Move_Mouse,
							 | 
						|
								                                Abort_Zone_Move_Corner_Or_Outlines );
							 | 
						|
								    s_CursorLastPosition = s_CornerInitialPosition = GetCrossHairPosition();
							 | 
						|
								    s_CornerIsNew = false;
							 | 
						|
								    s_AddCutoutToCurrentZone = false;
							 | 
						|
								    s_CurrentZone = NULL;
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								void PCB_EDIT_FRAME::End_Move_Zone_Corner_Or_Outlines( wxDC* DC, ZONE_CONTAINER* aZone )
							 | 
						|
								{
							 | 
						|
								    aZone->ClearFlags();
							 | 
						|
								    m_canvas->SetMouseCapture( NULL, NULL );
							 | 
						|
								
							 | 
						|
								    if( DC )
							 | 
						|
								        aZone->Draw( m_canvas, DC, GR_OR );
							 | 
						|
								
							 | 
						|
								    OnModify();
							 | 
						|
								    s_AddCutoutToCurrentZone = false;
							 | 
						|
								    s_CurrentZone = NULL;
							 | 
						|
								
							 | 
						|
								    SetCurItem( NULL );       // This outline can be deleted when merging outlines
							 | 
						|
								
							 | 
						|
								    // Combine zones if possible
							 | 
						|
								    GetBoard()->OnAreaPolygonModified( &s_AuxiliaryList, aZone );
							 | 
						|
								    m_canvas->Refresh();
							 | 
						|
								
							 | 
						|
								    int ii = GetBoard()->GetAreaIndex( aZone );     // test if aZone exists
							 | 
						|
								
							 | 
						|
								    if( ii < 0 )
							 | 
						|
								        aZone = NULL;                          // was removed by combining zones
							 | 
						|
								
							 | 
						|
								    UpdateCopyOfZonesList( s_PickedList, s_AuxiliaryList, GetBoard() );
							 | 
						|
								    SaveCopyInUndoList(s_PickedList, UR_UNSPECIFIED);
							 | 
						|
								    s_PickedList.ClearItemsList(); // s_ItemsListPicker is no more owner of picked items
							 | 
						|
								
							 | 
						|
								    DRC drc( this );
							 | 
						|
								    int error_count = drc.TestZoneToZoneOutline( aZone, true );
							 | 
						|
								
							 | 
						|
								    if( error_count )
							 | 
						|
								    {
							 | 
						|
								        DisplayErrorMessage( this, _( "Area: DRC outline error" ) );
							 | 
						|
								    }
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								void PCB_EDIT_FRAME::Remove_Zone_Corner( wxDC* DC, ZONE_CONTAINER* aZone )
							 | 
						|
								{
							 | 
						|
								    OnModify();
							 | 
						|
								
							 | 
						|
								    if( aZone->Outline()->TotalVertices() <= 3 )
							 | 
						|
								    {
							 | 
						|
								        m_canvas->RefreshDrawingRect( aZone->GetBoundingBox() );
							 | 
						|
								
							 | 
						|
								        if( DC )
							 | 
						|
								        {  // Remove the full zone because this is no more an area
							 | 
						|
								            aZone->UnFill();
							 | 
						|
								            aZone->DrawFilledArea( m_canvas, DC, GR_XOR );
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        GetBoard()->Delete( aZone );
							 | 
						|
								        return;
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    PCB_LAYER_ID layer = aZone->GetLayer();
							 | 
						|
								
							 | 
						|
								    if( DC )
							 | 
						|
								    {
							 | 
						|
								        GetBoard()->RedrawAreasOutlines( m_canvas, DC, GR_XOR, layer );
							 | 
						|
								        GetBoard()->RedrawFilledAreas( m_canvas, DC, GR_XOR, layer );
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    s_AuxiliaryList.ClearListAndDeleteItems();
							 | 
						|
								    s_PickedList. ClearListAndDeleteItems();
							 | 
						|
								    SaveCopyOfZones( s_PickedList, GetBoard(), aZone->GetNetCode(), aZone->GetLayer() );
							 | 
						|
								    aZone->Outline()->RemoveVertex( aZone->GetSelectedCorner() );
							 | 
						|
								
							 | 
						|
								    // modify zones outlines according to the new aZone shape
							 | 
						|
								    GetBoard()->OnAreaPolygonModified( &s_AuxiliaryList, aZone );
							 | 
						|
								
							 | 
						|
								    if( DC )
							 | 
						|
								    {
							 | 
						|
								        GetBoard()->RedrawAreasOutlines( m_canvas, DC, GR_OR, layer );
							 | 
						|
								        GetBoard()->RedrawFilledAreas( m_canvas, DC, GR_OR, layer );
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    UpdateCopyOfZonesList( s_PickedList, s_AuxiliaryList, GetBoard() );
							 | 
						|
								    SaveCopyInUndoList(s_PickedList, UR_UNSPECIFIED);
							 | 
						|
								    s_PickedList.ClearItemsList(); // s_ItemsListPicker is no more owner of picked items
							 | 
						|
								
							 | 
						|
								    int ii = GetBoard()->GetAreaIndex( aZone );     // test if aZone exists
							 | 
						|
								
							 | 
						|
								    if( ii < 0 )
							 | 
						|
								        aZone = NULL;   // aZone does not exist anymore, after combining zones
							 | 
						|
								
							 | 
						|
								    DRC drc( this );
							 | 
						|
								    int error_count = drc.TestZoneToZoneOutline( aZone, true );
							 | 
						|
								
							 | 
						|
								    if( error_count )
							 | 
						|
								    {
							 | 
						|
								        DisplayErrorMessage( this, _( "Area: DRC outline error" ) );
							 | 
						|
								    }
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								/**
							 | 
						|
								 * Function Abort_Zone_Move_Corner_Or_Outlines
							 | 
						|
								 * cancels the Begin_Zone state if at least one EDGE_ZONE has been created.
							 | 
						|
								 */
							 | 
						|
								void Abort_Zone_Move_Corner_Or_Outlines( EDA_DRAW_PANEL* Panel, wxDC* DC )
							 | 
						|
								{
							 | 
						|
								    PCB_EDIT_FRAME* pcbframe = (PCB_EDIT_FRAME*) Panel->GetParent();
							 | 
						|
								    ZONE_CONTAINER* zone     = (ZONE_CONTAINER*) pcbframe->GetCurItem();
							 | 
						|
								
							 | 
						|
								    if( zone->IsMoving() )
							 | 
						|
								    {
							 | 
						|
								        wxPoint offset;
							 | 
						|
								        offset = s_CornerInitialPosition - s_CursorLastPosition;
							 | 
						|
								        zone->Move( offset );
							 | 
						|
								    }
							 | 
						|
								    else if( zone->IsDragging() )
							 | 
						|
								    {
							 | 
						|
								        wxPoint offset = s_CornerInitialPosition - s_CursorLastPosition;
							 | 
						|
								        int selection = zone->GetSelectedCorner();
							 | 
						|
								        zone->MoveEdge( offset, selection );
							 | 
						|
								    }
							 | 
						|
								    else
							 | 
						|
								    {
							 | 
						|
								        if( s_CornerIsNew )
							 | 
						|
								        {
							 | 
						|
								            zone->Outline()->RemoveVertex( zone->GetSelectedCorner() );
							 | 
						|
								        }
							 | 
						|
								        else
							 | 
						|
								        {
							 | 
						|
								            wxPoint pos = s_CornerInitialPosition;
							 | 
						|
								            zone->Outline()->Vertex( zone->GetSelectedCorner() ) = pos;
							 | 
						|
								        }
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    Panel->SetMouseCapture( NULL, NULL );
							 | 
						|
								    s_AuxiliaryList.ClearListAndDeleteItems();
							 | 
						|
								    s_PickedList. ClearListAndDeleteItems();
							 | 
						|
								    Panel->Refresh();
							 | 
						|
								
							 | 
						|
								    pcbframe->SetCurItem( NULL );
							 | 
						|
								    zone->ClearFlags();
							 | 
						|
								    s_AddCutoutToCurrentZone = false;
							 | 
						|
								    s_CurrentZone = NULL;
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								/// Redraws the zone outline when moving a corner according to the cursor position
							 | 
						|
								void Show_Zone_Corner_Or_Outline_While_Move_Mouse( EDA_DRAW_PANEL* aPanel, wxDC* aDC,
							 | 
						|
								                                                   const wxPoint& aPosition, bool aErase )
							 | 
						|
								{
							 | 
						|
								    PCB_EDIT_FRAME* pcbframe = (PCB_EDIT_FRAME*) aPanel->GetParent();
							 | 
						|
								    ZONE_CONTAINER* zone = (ZONE_CONTAINER*) pcbframe->GetCurItem();
							 | 
						|
								
							 | 
						|
								    if( aErase )    // Undraw edge in old position
							 | 
						|
								    {
							 | 
						|
								        zone->Draw( aPanel, aDC, GR_XOR );
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    wxPoint pos = pcbframe->GetCrossHairPosition();
							 | 
						|
								
							 | 
						|
								    if( zone->IsMoving() )
							 | 
						|
								    {
							 | 
						|
								        wxPoint offset;
							 | 
						|
								        offset = pos - s_CursorLastPosition;
							 | 
						|
								        zone->Move( offset );
							 | 
						|
								        s_CursorLastPosition = pos;
							 | 
						|
								    }
							 | 
						|
								    else if( zone->IsDragging() )
							 | 
						|
								    {
							 | 
						|
								        wxPoint offset = pos - s_CursorLastPosition;
							 | 
						|
								        int selection = zone->GetSelectedCorner();
							 | 
						|
								        zone->MoveEdge( offset, selection );
							 | 
						|
								        s_CursorLastPosition = pos;
							 | 
						|
								    }
							 | 
						|
								    else
							 | 
						|
								    {
							 | 
						|
								        zone->Outline()->Vertex( zone->GetSelectedCorner() ) = pos;
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    zone->Draw( aPanel, aDC, GR_XOR );
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								int PCB_EDIT_FRAME::Begin_Zone( wxDC* DC )
							 | 
						|
								{
							 | 
						|
								    ZONE_SETTINGS zoneInfo = GetZoneSettings();
							 | 
						|
								
							 | 
						|
								    // verify if s_CurrentZone exists (could be deleted since last selection) :
							 | 
						|
								    int ii;
							 | 
						|
								    for( ii = 0; ii < GetBoard()->GetAreaCount(); ii++ )
							 | 
						|
								    {
							 | 
						|
								        if( s_CurrentZone == GetBoard()->GetArea( ii ) )
							 | 
						|
								            break;
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    if( ii >= GetBoard()->GetAreaCount() ) // Not found: could be deleted since last selection
							 | 
						|
								    {
							 | 
						|
								        s_AddCutoutToCurrentZone = false;
							 | 
						|
								        s_CurrentZone = NULL;
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    ZONE_CONTAINER* zone = GetBoard()->m_CurrentZoneContour;
							 | 
						|
								
							 | 
						|
								    // Verify if a new zone is allowed on this layer:
							 | 
						|
								    if( zone == NULL  )
							 | 
						|
								    {
							 | 
						|
								        if( GetToolId() == ID_PCB_KEEPOUT_AREA_BUTT && !IsCopperLayer( GetActiveLayer() ) )
							 | 
						|
								        {
							 | 
						|
								            DisplayErrorMessage( this,
							 | 
						|
								                          _( "Error: a keepout area is allowed only on copper layers" ) );
							 | 
						|
								            return 0;
							 | 
						|
								        }
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    // If no zone contour in progress, a new zone is being created,
							 | 
						|
								    if( zone == NULL )
							 | 
						|
								    {
							 | 
						|
								        zone = GetBoard()->m_CurrentZoneContour = new ZONE_CONTAINER( GetBoard() );
							 | 
						|
								        zone->SetFlags( IS_NEW );
							 | 
						|
								        zone->SetTimeStamp( GetNewTimeStamp() );
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    if( zone->GetNumCorners() == 0 )    // Start a new contour: init zone params (net, layer ...)
							 | 
						|
								    {
							 | 
						|
								        if( !s_CurrentZone )            // A new outline is created, from scratch
							 | 
						|
								        {
							 | 
						|
								            int dialogResult;
							 | 
						|
								
							 | 
						|
								            // Prompt user for parameters:
							 | 
						|
								            m_canvas->SetIgnoreMouseEvents( true );
							 | 
						|
								
							 | 
						|
								            if( IsCopperLayer( GetActiveLayer() ) )
							 | 
						|
								            {
							 | 
						|
								                // Put a zone on a copper layer
							 | 
						|
								                if( GetBoard()->GetHighLightNetCode() > 0 )
							 | 
						|
								                {
							 | 
						|
								                    zoneInfo.m_NetcodeSelection = GetBoard()->GetHighLightNetCode();
							 | 
						|
								                    zone->SetNetCode( zoneInfo.m_NetcodeSelection );
							 | 
						|
								                }
							 | 
						|
								
							 | 
						|
								                double tmp = ZONE_THERMAL_RELIEF_GAP_MIL;
							 | 
						|
								
							 | 
						|
								                wxConfigBase* cfg = Kiface().KifaceSettings();
							 | 
						|
								                cfg->Read( ZONE_THERMAL_RELIEF_GAP_STRING_KEY, &tmp );
							 | 
						|
								                zoneInfo.m_ThermalReliefGap = KiROUND( tmp * IU_PER_MILS);
							 | 
						|
								
							 | 
						|
								                tmp = ZONE_THERMAL_RELIEF_COPPER_WIDTH_MIL;
							 | 
						|
								                cfg->Read( ZONE_THERMAL_RELIEF_COPPER_WIDTH_STRING_KEY, &tmp );
							 | 
						|
								                zoneInfo.m_ThermalReliefCopperBridge = KiROUND( tmp * IU_PER_MILS );
							 | 
						|
								
							 | 
						|
								                tmp = ZONE_CLEARANCE_MIL;
							 | 
						|
								                cfg->Read( ZONE_CLEARANCE_WIDTH_STRING_KEY, &tmp );
							 | 
						|
								                zoneInfo.m_ZoneClearance = KiROUND( tmp * IU_PER_MILS );
							 | 
						|
								
							 | 
						|
								                tmp = ZONE_THICKNESS_MIL;
							 | 
						|
								                cfg->Read( ZONE_MIN_THICKNESS_WIDTH_STRING_KEY, &tmp );
							 | 
						|
								                zoneInfo.m_ZoneMinThickness = KiROUND( tmp * IU_PER_MILS );
							 | 
						|
								
							 | 
						|
								                if( GetToolId() == ID_PCB_KEEPOUT_AREA_BUTT )
							 | 
						|
								                {
							 | 
						|
								                    zoneInfo.SetIsKeepout( true );
							 | 
						|
								                    // Netcode, netname and some other settings are irrelevant,
							 | 
						|
								                    // so ensure they are cleared
							 | 
						|
								                    zone->SetNetCode( NETINFO_LIST::UNCONNECTED );
							 | 
						|
								                    zoneInfo.SetCornerSmoothingType( ZONE_SETTINGS::SMOOTHING_NONE );
							 | 
						|
								                    zoneInfo.SetCornerRadius( 0 );
							 | 
						|
								
							 | 
						|
								                    dialogResult = InvokeKeepoutAreaEditor( this, &zoneInfo );
							 | 
						|
								                }
							 | 
						|
								                else
							 | 
						|
								                {
							 | 
						|
								                    zoneInfo.m_CurrentZone_Layer = GetActiveLayer();    // Preselect a layer
							 | 
						|
								                    zoneInfo.SetIsKeepout( false );
							 | 
						|
								                    dialogResult = InvokeCopperZonesEditor( this, &zoneInfo );
							 | 
						|
								                }
							 | 
						|
								            }
							 | 
						|
								            else   // Put a zone on a non copper layer (technical layer)
							 | 
						|
								            {
							 | 
						|
								                zoneInfo.m_CurrentZone_Layer = GetActiveLayer();   // Preselect a layer
							 | 
						|
								                zoneInfo.SetIsKeepout( false );
							 | 
						|
								                zoneInfo.m_NetcodeSelection = 0;                   // No net for non copper zones
							 | 
						|
								                dialogResult = InvokeNonCopperZonesEditor( this, &zoneInfo );
							 | 
						|
								            }
							 | 
						|
								
							 | 
						|
								            m_canvas->MoveCursorToCrossHair();
							 | 
						|
								            m_canvas->SetIgnoreMouseEvents( false );
							 | 
						|
								
							 | 
						|
								            if( dialogResult == wxID_CANCEL )
							 | 
						|
								            {
							 | 
						|
								                GetBoard()->m_CurrentZoneContour = NULL;
							 | 
						|
								                delete zone;
							 | 
						|
								                return 0;
							 | 
						|
								            }
							 | 
						|
								
							 | 
						|
								            // Switch active layer to the selected zone layer
							 | 
						|
								            SetActiveLayer( zoneInfo.m_CurrentZone_Layer );
							 | 
						|
								            SetZoneSettings( zoneInfo );
							 | 
						|
								            OnModify();
							 | 
						|
								        }
							 | 
						|
								        else
							 | 
						|
								        {
							 | 
						|
								            // Start a new contour: init zone params (net and layer) from an existing
							 | 
						|
								            // zone (add cutout or similar zone)
							 | 
						|
								
							 | 
						|
								            zoneInfo.m_CurrentZone_Layer = s_CurrentZone->GetLayer();
							 | 
						|
								            SetActiveLayer( s_CurrentZone->GetLayer() );
							 | 
						|
								
							 | 
						|
								            zoneInfo << *s_CurrentZone;
							 | 
						|
								
							 | 
						|
								            SetZoneSettings( zoneInfo );
							 | 
						|
								            OnModify();
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        // Show the Net for zones on copper layers
							 | 
						|
								        if( IsCopperLayer( zoneInfo.m_CurrentZone_Layer ) &&
							 | 
						|
								            !zoneInfo.GetIsKeepout() )
							 | 
						|
								        {
							 | 
						|
								            if( s_CurrentZone )
							 | 
						|
								            {
							 | 
						|
								                zoneInfo.m_NetcodeSelection = s_CurrentZone->GetNetCode();
							 | 
						|
								                GetBoard()->SetZoneSettings( zoneInfo );
							 | 
						|
								            }
							 | 
						|
								
							 | 
						|
								            if( GetBoard()->IsHighLightNetON() )
							 | 
						|
								            {
							 | 
						|
								                HighLight( DC );    // Remove old highlight selection
							 | 
						|
								            }
							 | 
						|
								
							 | 
						|
								            GetBoard()->SetHighLightNet( zoneInfo.m_NetcodeSelection );
							 | 
						|
								            HighLight( DC );
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        if( !s_AddCutoutToCurrentZone )
							 | 
						|
								            s_CurrentZone = NULL; // the zone is used only once ("add similar zone" command)
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    // if first segment
							 | 
						|
								    if( zone->GetNumCorners() == 0 )
							 | 
						|
								    {
							 | 
						|
								        zoneInfo.ExportSetting( *zone );
							 | 
						|
								
							 | 
						|
								        // A duplicated corner is needed; null segments are removed when the zone is finished.
							 | 
						|
								        zone->AppendCorner( GetCrossHairPosition(), -1 );
							 | 
						|
								        // Add the duplicate corner:
							 | 
						|
								        zone->AppendCorner( GetCrossHairPosition(), -1, true );
							 | 
						|
								
							 | 
						|
								        if( Settings().m_legacyDrcOn && (m_drc->DrcOnCreatingZone( zone, 0 ) == BAD_DRC)
							 | 
						|
								            && zone->IsOnCopperLayer() )
							 | 
						|
								        {
							 | 
						|
								            zone->ClearFlags();
							 | 
						|
								            zone->RemoveAllContours();
							 | 
						|
								
							 | 
						|
								            // use the form of SetCurItem() which does not write to the msg panel,
							 | 
						|
								            // SCREEN::SetCurItem(), so the DRC error remains on screen.
							 | 
						|
								            // PCB_EDIT_FRAME::SetCurItem() calls DisplayInfo().
							 | 
						|
								            GetScreen()->SetCurItem( NULL );
							 | 
						|
								            DisplayErrorMessage( this, _( "DRC error: this start point is inside or too close another area" ) );
							 | 
						|
								            return 0;
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        SetCurItem( zone );
							 | 
						|
								        m_canvas->SetMouseCapture( Show_New_Edge_While_Move_Mouse, Abort_Zone_Create_Outline );
							 | 
						|
								    }
							 | 
						|
								    else    // edge in progress:
							 | 
						|
								    {
							 | 
						|
								        ii = zone->GetNumCorners() - 1;
							 | 
						|
								
							 | 
						|
								        // edge in progress : the current corner coordinate was set
							 | 
						|
								        // by Show_New_Edge_While_Move_Mouse
							 | 
						|
								        if( zone->GetCornerPosition( ii - 1 ) != zone->GetCornerPosition( ii ) )
							 | 
						|
								        {
							 | 
						|
								            if( !Settings().m_legacyDrcOn || !zone->IsOnCopperLayer()
							 | 
						|
								                || ( m_drc->DrcOnCreatingZone( zone, ii - 1 ) == OK_DRC ) )
							 | 
						|
								            {
							 | 
						|
								                // Ok, we can add a new corner
							 | 
						|
								                if( m_canvas->IsMouseCaptured() )
							 | 
						|
								                    m_canvas->CallMouseCapture( DC, wxPoint(0,0), false );
							 | 
						|
								
							 | 
						|
								                // It is necessary to allow duplication of the points, as we have to handle the
							 | 
						|
								                // continuous drawing while creating the zone at the same time as we build it. Null
							 | 
						|
								                // segments are removed when the zone is finished, in End_Zone.
							 | 
						|
								                zone->AppendCorner( GetCrossHairPosition(), -1, true );
							 | 
						|
								
							 | 
						|
								                SetCurItem( zone );     // calls DisplayInfo().
							 | 
						|
								
							 | 
						|
								                if( m_canvas->IsMouseCaptured() )
							 | 
						|
								                    m_canvas->CallMouseCapture( DC, wxPoint(0,0), false );
							 | 
						|
								            }
							 | 
						|
								        }
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    return zone->GetNumCorners();
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								bool PCB_EDIT_FRAME::End_Zone( wxDC* DC )
							 | 
						|
								{
							 | 
						|
								    ZONE_CONTAINER* zone = GetBoard()->m_CurrentZoneContour;
							 | 
						|
								
							 | 
						|
								    if( !zone )
							 | 
						|
								        return true;
							 | 
						|
								
							 | 
						|
								    // Validate the current outline:
							 | 
						|
								    if( zone->GetNumCorners() <= 2 )   // An outline must have 3 corners or more
							 | 
						|
								    {
							 | 
						|
								        Abort_Zone_Create_Outline( m_canvas, DC );
							 | 
						|
								        return true;
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    // Remove the last corner if is is at the same location as the prevoius corner
							 | 
						|
								    zone->Outline()->RemoveNullSegments();
							 | 
						|
								
							 | 
						|
								    // Validate the current edge:
							 | 
						|
								    int icorner = zone->GetNumCorners() - 1;
							 | 
						|
								    if( zone->IsOnCopperLayer() )
							 | 
						|
								    {
							 | 
						|
								        if( Settings().m_legacyDrcOn &&
							 | 
						|
								            m_drc->DrcOnCreatingZone( zone, icorner - 1 ) == BAD_DRC )  // we can't validate last edge
							 | 
						|
								            return false;
							 | 
						|
								
							 | 
						|
								        if( Settings().m_legacyDrcOn &&
							 | 
						|
								            m_drc->DrcOnCreatingZone( zone, icorner ) == BAD_DRC )      // we can't validate the closing edge
							 | 
						|
								        {
							 | 
						|
								            DisplayErrorMessage( this, _( "DRC error: closing this area creates a DRC error with another area" ) );
							 | 
						|
								            m_canvas->MoveCursorToCrossHair();
							 | 
						|
								            return false;
							 | 
						|
								        }
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    zone->ClearFlags();
							 | 
						|
								
							 | 
						|
								    zone->DrawWhileCreateOutline( m_canvas, DC, GR_XOR );
							 | 
						|
								
							 | 
						|
								    m_canvas->SetMouseCapture( NULL, NULL );
							 | 
						|
								
							 | 
						|
								    // Undraw old drawings, because they can have important changes
							 | 
						|
								    PCB_LAYER_ID layer = zone->GetLayer();
							 | 
						|
								    GetBoard()->RedrawAreasOutlines( m_canvas, DC, GR_XOR, layer );
							 | 
						|
								    GetBoard()->RedrawFilledAreas( m_canvas, DC, GR_XOR, layer );
							 | 
						|
								
							 | 
						|
								    // Save initial zones configuration, for undo/redo, before adding new zone
							 | 
						|
								    s_AuxiliaryList.ClearListAndDeleteItems();
							 | 
						|
								    s_PickedList.ClearListAndDeleteItems();
							 | 
						|
								    SaveCopyOfZones(s_PickedList, GetBoard(), zone->GetNetCode(), zone->GetLayer() );
							 | 
						|
								
							 | 
						|
								    // Put new zone in list
							 | 
						|
								    if( !s_CurrentZone )
							 | 
						|
								    {
							 | 
						|
								        GetBoard()->Add( zone );
							 | 
						|
								
							 | 
						|
								        // 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
							 | 
						|
								    {
							 | 
						|
								        s_CurrentZone->Outline()->AddHole( zone->Outline()->Outline( 0 ) );
							 | 
						|
								
							 | 
						|
								        zone->RemoveAllContours();      // All corners are copied in s_CurrentZone. Free corner list.
							 | 
						|
								        zone = s_CurrentZone;
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    s_AddCutoutToCurrentZone = false;
							 | 
						|
								    s_CurrentZone = NULL;
							 | 
						|
								    GetBoard()->m_CurrentZoneContour = NULL;
							 | 
						|
								
							 | 
						|
								    GetScreen()->SetCurItem( NULL );       // This outline can be deleted when merging outlines
							 | 
						|
								
							 | 
						|
								    // Combine zones if possible :
							 | 
						|
								    GetBoard()->OnAreaPolygonModified( &s_AuxiliaryList, zone );
							 | 
						|
								
							 | 
						|
								    // Redraw the real edge zone :
							 | 
						|
								    GetBoard()->RedrawAreasOutlines( m_canvas, DC, GR_OR, layer );
							 | 
						|
								    GetBoard()->RedrawFilledAreas( m_canvas, DC, GR_OR, layer );
							 | 
						|
								
							 | 
						|
								    int ii = GetBoard()->GetAreaIndex( zone );   // test if zone exists
							 | 
						|
								
							 | 
						|
								    if( ii < 0 )
							 | 
						|
								        zone = NULL;                        // was removed by combining zones
							 | 
						|
								
							 | 
						|
								    DRC drc( this );
							 | 
						|
								    int error_count = drc.TestZoneToZoneOutline( zone, true );
							 | 
						|
								
							 | 
						|
								    if( error_count )
							 | 
						|
								    {
							 | 
						|
								        DisplayErrorMessage( this, _( "Area: DRC outline error" ) );
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    UpdateCopyOfZonesList( s_PickedList, s_AuxiliaryList, GetBoard() );
							 | 
						|
								    SaveCopyInUndoList(s_PickedList, UR_UNSPECIFIED);
							 | 
						|
								    s_PickedList.ClearItemsList(); // s_ItemsListPicker is no more owner of picked items
							 | 
						|
								
							 | 
						|
								    OnModify();
							 | 
						|
								    return true;
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								/* Redraws the zone outlines when moving mouse
							 | 
						|
								 */
							 | 
						|
								static void Show_New_Edge_While_Move_Mouse( EDA_DRAW_PANEL* aPanel, wxDC* aDC,
							 | 
						|
								                                            const wxPoint& aPosition, bool aErase )
							 | 
						|
								{
							 | 
						|
								    PCB_EDIT_FRAME* pcbframe = (PCB_EDIT_FRAME*) aPanel->GetParent();
							 | 
						|
								    wxPoint         c_pos    = pcbframe->GetCrossHairPosition();
							 | 
						|
								    ZONE_CONTAINER* zone = pcbframe->GetBoard()->m_CurrentZoneContour;
							 | 
						|
								
							 | 
						|
								    if( !zone )
							 | 
						|
								        return;
							 | 
						|
								
							 | 
						|
								    int icorner = zone->GetNumCorners() - 1;
							 | 
						|
								
							 | 
						|
								    if( icorner < 1 )
							 | 
						|
								        return;     // We must have 2 (or more) corners
							 | 
						|
								
							 | 
						|
								    if( aErase )    // Undraw edge in old position
							 | 
						|
								    {
							 | 
						|
								        zone->DrawWhileCreateOutline( aPanel, aDC );
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    // Redraw the current edge in its new position
							 | 
						|
								    if( pcbframe->GetZoneSettings().m_Zone_45_Only )
							 | 
						|
								    {
							 | 
						|
								        // calculate the new position as allowed
							 | 
						|
								        wxPoint StartPoint = static_cast<wxPoint>( zone->GetCornerPosition( icorner - 1 ) );
							 | 
						|
								        c_pos = CalculateSegmentEndPoint( c_pos, StartPoint );
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    zone->SetCornerPosition( icorner, c_pos );
							 | 
						|
								
							 | 
						|
								    zone->DrawWhileCreateOutline( aPanel, aDC );
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								void PCB_EDIT_FRAME::Edit_Zone_Params( wxDC* DC, ZONE_CONTAINER* aZone )
							 | 
						|
								{
							 | 
						|
								    int           dialogResult;
							 | 
						|
								    ZONE_SETTINGS zoneInfo = GetZoneSettings();
							 | 
						|
								
							 | 
						|
								    BOARD_COMMIT commit( this );
							 | 
						|
								    m_canvas->SetIgnoreMouseEvents( 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
							 | 
						|
								    s_AuxiliaryList.ClearListAndDeleteItems();
							 | 
						|
								    s_PickedList.ClearListAndDeleteItems();
							 | 
						|
								    SaveCopyOfZones( s_PickedList, GetBoard(), -1, UNDEFINED_LAYER );
							 | 
						|
								
							 | 
						|
								    if( aZone->GetIsKeepout() )
							 | 
						|
								    {
							 | 
						|
								        // edit a keepout area on a copper layer
							 | 
						|
								        zoneInfo << *aZone;
							 | 
						|
								        dialogResult = InvokeKeepoutAreaEditor( this, &zoneInfo );
							 | 
						|
								    }
							 | 
						|
								    else if( IsCopperLayer( aZone->GetLayer() ) )
							 | 
						|
								    {
							 | 
						|
								        // edit a zone on a copper layer
							 | 
						|
								        zoneInfo << *aZone;
							 | 
						|
								        dialogResult = InvokeCopperZonesEditor( this, &zoneInfo );
							 | 
						|
								    }
							 | 
						|
								    else
							 | 
						|
								    {
							 | 
						|
								        zoneInfo << *aZone;
							 | 
						|
								        dialogResult = InvokeNonCopperZonesEditor( this, &zoneInfo );
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    m_canvas->MoveCursorToCrossHair();
							 | 
						|
								    m_canvas->SetIgnoreMouseEvents( false );
							 | 
						|
								
							 | 
						|
								    if( dialogResult == wxID_CANCEL )
							 | 
						|
								    {
							 | 
						|
								        s_AuxiliaryList.ClearListAndDeleteItems();
							 | 
						|
								        s_PickedList.ClearListAndDeleteItems();
							 | 
						|
								        return;
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    SetZoneSettings( zoneInfo );
							 | 
						|
								    OnModify();
							 | 
						|
								
							 | 
						|
								    if( dialogResult == ZONE_EXPORT_VALUES )
							 | 
						|
								    {
							 | 
						|
								        UpdateCopyOfZonesList( s_PickedList, s_AuxiliaryList, GetBoard() );
							 | 
						|
								        commit.Stage( s_PickedList );
							 | 
						|
								        commit.Push( _( "Modify zone properties" ) );
							 | 
						|
								        s_PickedList.ClearItemsList(); // s_ItemsListPicker is no more owner of picked items
							 | 
						|
								        return;
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    wxBusyCursor dummy;
							 | 
						|
								
							 | 
						|
								    // Undraw old zone outlines
							 | 
						|
								    for( int ii = 0; ii < GetBoard()->GetAreaCount(); ii++ )
							 | 
						|
								    {
							 | 
						|
								        ZONE_CONTAINER* edge_zone = GetBoard()->GetArea( ii );
							 | 
						|
								        edge_zone->Draw( m_canvas, DC, GR_XOR );
							 | 
						|
								
							 | 
						|
								        if( IsGalCanvasActive() )
							 | 
						|
								        {
							 | 
						|
								            GetGalCanvas()->GetView()->Update( edge_zone );
							 | 
						|
								        }
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    zoneInfo.ExportSetting( *aZone );
							 | 
						|
								
							 | 
						|
								    NETINFO_ITEM* net = GetBoard()->FindNet( zoneInfo.m_NetcodeSelection );
							 | 
						|
								
							 | 
						|
								    if( net )   // net == NULL should not occur
							 | 
						|
								        aZone->SetNetCode( net->GetNet() );
							 | 
						|
								
							 | 
						|
								    // Combine zones if possible
							 | 
						|
								    GetBoard()->OnAreaPolygonModified( &s_AuxiliaryList, aZone );
							 | 
						|
								
							 | 
						|
								    // Redraw the real new zone outlines
							 | 
						|
								    GetBoard()->RedrawAreasOutlines( m_canvas, DC, GR_OR, UNDEFINED_LAYER );
							 | 
						|
								
							 | 
						|
								    UpdateCopyOfZonesList( s_PickedList, s_AuxiliaryList, GetBoard() );
							 | 
						|
								
							 | 
						|
								    // refill zones with the new properties applied
							 | 
						|
								    std::vector<ZONE_CONTAINER*> zones_to_refill;
							 | 
						|
								
							 | 
						|
								    for( unsigned i = 0; i < s_PickedList.GetCount(); ++i )
							 | 
						|
								    {
							 | 
						|
								        ZONE_CONTAINER* zone = dyn_cast<ZONE_CONTAINER*>( s_PickedList.GetPickedItem( i ) );
							 | 
						|
								
							 | 
						|
								        if( zone == nullptr )
							 | 
						|
								        {
							 | 
						|
								            wxASSERT_MSG( false, "Expected a zone after zone properties edit" );
							 | 
						|
								            continue;
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        if( zone->IsFilled() )
							 | 
						|
								            zones_to_refill.push_back( zone );
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    if( zones_to_refill.size() )
							 | 
						|
								    {
							 | 
						|
								        ZONE_FILLER filler ( GetBoard() );
							 | 
						|
								        wxString title;
							 | 
						|
								        title.Printf( _( "Refill %d Zones" ), (int)zones_to_refill.size() );
							 | 
						|
								        std::unique_ptr<WX_PROGRESS_REPORTER> progressReporter(
							 | 
						|
								                                new WX_PROGRESS_REPORTER( this, title, 4 ) );
							 | 
						|
								
							 | 
						|
								        filler.SetProgressReporter( progressReporter.get() );
							 | 
						|
								        filler.Fill( zones_to_refill );
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    commit.Stage( s_PickedList );
							 | 
						|
								    commit.Push( _( "Modify zone properties" ) );
							 | 
						|
								    GetBoard()->GetConnectivity()->RecalculateRatsnest();
							 | 
						|
								
							 | 
						|
								    s_PickedList.ClearItemsList();  // s_ItemsListPicker is no longer owner of picked items
							 | 
						|
								
							 | 
						|
								    if( !IsGalCanvasActive() )
							 | 
						|
								        m_canvas->Refresh();
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								void PCB_EDIT_FRAME::Delete_Zone_Contour( wxDC* DC, ZONE_CONTAINER* aZone )
							 | 
						|
								{
							 | 
						|
								    // Get contour in which the selected corner is
							 | 
						|
								    SHAPE_POLY_SET::VERTEX_INDEX indices;
							 | 
						|
								
							 | 
						|
								    // If the selected corner does not exist, abort
							 | 
						|
								    if( !aZone->Outline()->GetRelativeIndices( aZone->GetSelectedCorner(), &indices ) )
							 | 
						|
								        throw( std::out_of_range( "Zone selected corner does not exist" ) );
							 | 
						|
								
							 | 
						|
								    EDA_RECT dirty = aZone->GetBoundingBox();
							 | 
						|
								
							 | 
						|
								    // For compatibility with old boards: remove old SEGZONE fill segments
							 | 
						|
								    Delete_OldZone_Fill( NULL, aZone->GetTimeStamp() );
							 | 
						|
								
							 | 
						|
								    // Remove current filling:
							 | 
						|
								    aZone->UnFill();
							 | 
						|
								
							 | 
						|
								    if( indices.m_contour == 0 )    // This is the main outline: remove all
							 | 
						|
								    {
							 | 
						|
								        SaveCopyInUndoList( aZone, UR_DELETED );
							 | 
						|
								        GetBoard()->Remove( aZone );
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    else
							 | 
						|
								    {
							 | 
						|
								        SaveCopyInUndoList( aZone, UR_CHANGED );
							 | 
						|
								        aZone->Outline()->RemoveContour( indices.m_contour, indices.m_polygon );
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    m_canvas->RefreshDrawingRect( dirty );
							 | 
						|
								
							 | 
						|
								    OnModify();
							 | 
						|
								}
							 |