summaryrefslogtreecommitdiff
path: root/pcbnew/zones_by_polygon.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'pcbnew/zones_by_polygon.cpp')
-rw-r--r--pcbnew/zones_by_polygon.cpp968
1 files changed, 968 insertions, 0 deletions
diff --git a/pcbnew/zones_by_polygon.cpp b/pcbnew/zones_by_polygon.cpp
new file mode 100644
index 0000000..31db133
--- /dev/null
+++ b/pcbnew/zones_by_polygon.cpp
@@ -0,0 +1,968 @@
+/*
+ * 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-2015 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 <wxPcbStruct.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_stuff.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_CONTAINER* newZone = new ZONE_CONTAINER( GetBoard() );
+ newZone->Copy( aZone );
+ newZone->UnFill();
+ ZONE_SETTINGS zoneSettings;
+ zoneSettings << *aZone;
+
+ bool success;
+
+ if( aZone->GetIsKeepout() )
+ success = InvokeKeepoutAreaEditor( this, &zoneSettings );
+ else if( aZone->IsOnCopperLayer() )
+ success = InvokeCopperZonesEditor( this, &zoneSettings );
+ else
+ success = InvokeNonCopperZonesEditor( this, aZone, &zoneSettings );
+
+ // If the new zone is on the same layer as the the initial zone,
+ // do nothing
+ if( success && ( aZone->GetLayer() == zoneSettings.m_CurrentZone_Layer ) )
+ {
+ DisplayError( this,
+ _( "The duplicated zone is on the same layer as the initial zone, which has no sense.\n"
+ "Please, choose an other layer for the new zone") );
+ success = false;
+ }
+
+ if( success )
+ {
+ zoneSettings.ExportSetting( *newZone );
+ newZone->Outline()->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() );
+
+ if( GetBoard()->GetAreaIndex( newZone ) >= 0
+ && GetBoard()->Test_Drc_Areas_Outlines_To_Areas_Outlines( newZone, true ) )
+ {
+ DisplayError( this,
+ _( "The outline of the duplicated zone fails DRC check!" ) );
+ }
+
+ UpdateCopyOfZonesList( s_PickedList, s_AuxiliaryList, GetBoard() );
+ SaveCopyInUndoList( s_PickedList, UR_UNSPECIFIED );
+ s_PickedList.ClearItemsList();
+
+ OnModify();
+ }
+ else
+ delete newZone;
+}
+
+
+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()->DeleteCorner( 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
+ int cx = aZone->Outline()->GetX( corner_id );
+ int cy = aZone->Outline()->GetY( corner_id );
+
+ if ( IsNewCorner )
+ aZone->Outline()->DeleteCorner( corner_id );
+
+ s_AuxiliaryList.ClearListAndDeleteItems();
+ s_PickedList.ClearListAndDeleteItems();
+
+ SaveCopyOfZones( s_PickedList, GetBoard(), aZone->GetNetCode(), aZone->GetLayer() );
+
+ if ( IsNewCorner )
+ aZone->Outline()->InsertCorner(corner_id-1, cx, cy );
+
+ aZone->SetFlags( IN_EDIT );
+ m_canvas->SetMouseCapture( Show_Zone_Corner_Or_Outline_While_Move_Mouse,
+ Abort_Zone_Move_Corner_Or_Outlines );
+ s_CornerInitialPosition = 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
+
+ int error_count = GetBoard()->Test_Drc_Areas_Outlines_To_Areas_Outlines( aZone, true );
+
+ if( error_count )
+ {
+ DisplayError( this, _( "Area: DRC outline error" ) );
+ }
+}
+
+
+void PCB_EDIT_FRAME::Remove_Zone_Corner( wxDC* DC, ZONE_CONTAINER* aZone )
+{
+ OnModify();
+
+ if( aZone->Outline()->GetCornersCount() <= 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;
+ }
+
+ 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()->DeleteCorner( 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
+
+ int error_count = GetBoard()->Test_Drc_Areas_Outlines_To_Areas_Outlines( aZone, true );
+
+ if( error_count )
+ {
+ DisplayError( 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()->DeleteCorner( zone->GetSelectedCorner() );
+ }
+ else
+ {
+ wxPoint pos = s_CornerInitialPosition;
+ zone->Outline()->MoveCorner( zone->GetSelectedCorner(), pos.x, pos.y );
+ }
+ }
+
+ 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()->MoveCorner( zone->GetSelectedCorner(), pos.x, pos.y );
+ }
+
+ 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() ) )
+ {
+ DisplayError( 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
+ {
+ ZONE_EDIT_T edited;
+
+ // Init zone params to reasonable values
+ zone->SetLayer( GetActiveLayer() );
+
+ // Prompt user for parameters:
+ m_canvas->SetIgnoreMouseEvents( true );
+
+ if( zone->IsOnCopperLayer() )
+ {
+ // 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 );
+
+ zoneInfo.m_CurrentZone_Layer = zone->GetLayer();
+
+ 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 );
+
+ edited = InvokeKeepoutAreaEditor( this, &zoneInfo );
+ }
+ else
+ {
+ zoneInfo.SetIsKeepout( false );
+ edited = InvokeCopperZonesEditor( this, &zoneInfo );
+ }
+ }
+ else // Put a zone on a non copper layer (technical layer)
+ {
+ zoneInfo.SetIsKeepout( false );
+ zoneInfo.m_NetcodeSelection = 0; // No net for non copper zones
+ edited = InvokeNonCopperZonesEditor( this, zone, &zoneInfo );
+ }
+
+ m_canvas->MoveCursorToCrossHair();
+ m_canvas->SetIgnoreMouseEvents( false );
+
+ if( edited == ZONE_ABORT )
+ {
+ GetBoard()->m_CurrentZoneContour = NULL;
+ delete zone;
+ return 0;
+ }
+
+ // Switch active layer to the selected zone layer
+ SetActiveLayer( zoneInfo.m_CurrentZone_Layer );
+ SetZoneSettings( zoneInfo );
+ }
+ 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 );
+ }
+
+ // 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 );
+
+ zone->Outline()->Start( zoneInfo.m_CurrentZone_Layer,
+ GetCrossHairPosition().x,
+ GetCrossHairPosition().y,
+ zone->GetHatchStyle() );
+
+ zone->AppendCorner( GetCrossHairPosition() );
+
+ if( g_Drc_On && (m_drc->Drc( 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 );
+ DisplayError( this,
+ _( "DRC error: this start point is inside or too close an other 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( !g_Drc_On || !zone->IsOnCopperLayer() || ( m_drc->Drc( zone, ii - 1 ) == OK_DRC ) )
+ {
+ // Ok, we can add a new corner
+ if( m_canvas->IsMouseCaptured() )
+ m_canvas->CallMouseCapture( DC, wxPoint(0,0), false );
+ zone->AppendCorner( GetCrossHairPosition() );
+ 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( g_Drc_On && m_drc->Drc( zone, icorner - 1 ) == BAD_DRC ) // we can't validate last edge
+ return false;
+
+ if( g_Drc_On && m_drc->Drc( zone, icorner ) == BAD_DRC ) // we can't validate the closing edge
+ {
+ DisplayError( this,
+ _( "DRC error: closing this area creates a DRC error with an other 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
+ 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 )
+ {
+ zone->Outline()->CloseLastContour(); // Close the current corner list
+ GetBoard()->Add( zone );
+ GetBoard()->m_CurrentZoneContour = NULL;
+
+ // Add this zone in picked list, as new item
+ ITEM_PICKER picker( zone, UR_NEW );
+ s_PickedList.PushItem( picker );
+ }
+ else // Append this outline as a cutout to an existing zone
+ {
+ for( int ii = 0; ii < zone->GetNumCorners(); ii++ )
+ {
+ s_CurrentZone->AppendCorner( zone->GetCornerPosition( ii ) );
+ }
+
+ s_CurrentZone->Outline()->CloseLastContour(); // Close the current corner list
+ zone->RemoveAllContours(); // All corners are copied in s_CurrentZone. Free corner list.
+ zone = s_CurrentZone;
+ }
+
+ s_AddCutoutToCurrentZone = false;
+ s_CurrentZone = 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
+
+ int error_count = GetBoard()->Test_Drc_Areas_Outlines_To_Areas_Outlines( zone, true );
+
+ if( error_count )
+ {
+ DisplayError( this, _( "Area: DRC outline error" ) );
+ }
+
+ UpdateCopyOfZonesList( s_PickedList, 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 = zone->GetCornerPosition( icorner - 1 );
+ CalculateSegmentEndPoint( c_pos, StartPoint.x, StartPoint.y, &c_pos.x, &c_pos.y );
+ }
+
+ zone->SetCornerPosition( icorner, c_pos );
+
+ zone->DrawWhileCreateOutline( aPanel, aDC );
+}
+
+
+void PCB_EDIT_FRAME::Edit_Zone_Params( wxDC* DC, ZONE_CONTAINER* aZone )
+{
+ ZONE_EDIT_T edited;
+ ZONE_SETTINGS zoneInfo = GetZoneSettings();
+
+ 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;
+ edited = InvokeKeepoutAreaEditor( this, &zoneInfo );
+ }
+ else if( IsCopperLayer( aZone->GetLayer() ) )
+ {
+ // edit a zone on a copper layer
+
+ zoneInfo << *aZone;
+
+ edited = InvokeCopperZonesEditor( this, &zoneInfo );
+ }
+ else
+ {
+ edited = InvokeNonCopperZonesEditor( this, aZone, &zoneInfo );
+ }
+
+ m_canvas->MoveCursorToCrossHair();
+ m_canvas->SetIgnoreMouseEvents( false );
+
+ if( edited == ZONE_ABORT )
+ {
+ s_AuxiliaryList.ClearListAndDeleteItems();
+ s_PickedList.ClearListAndDeleteItems();
+ return;
+ }
+
+ SetZoneSettings( zoneInfo );
+
+ if( edited == ZONE_EXPORT_VALUES )
+ {
+ UpdateCopyOfZonesList( s_PickedList, s_AuxiliaryList, GetBoard() );
+ SaveCopyInUndoList(s_PickedList, UR_UNSPECIFIED);
+ s_PickedList.ClearItemsList(); // s_ItemsListPicker is no more owner of picked items
+ return;
+ }
+
+ // Undraw old zone outlines
+ for( int ii = 0; ii < GetBoard()->GetAreaCount(); ii++ )
+ {
+ ZONE_CONTAINER* edge_zone = GetBoard()->GetArea( ii );
+ edge_zone->Draw( m_canvas, DC, GR_XOR );
+ }
+
+ 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() );
+ SaveCopyInUndoList(s_PickedList, UR_UNSPECIFIED);
+
+ s_PickedList.ClearItemsList(); // s_ItemsListPicker is no longer owner of picked items
+
+ OnModify();
+}
+
+
+void PCB_EDIT_FRAME::Delete_Zone_Contour( wxDC* DC, ZONE_CONTAINER* aZone )
+{
+ int ncont = aZone->Outline()->GetContour( aZone->GetSelectedCorner() );
+
+ 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( ncont == 0 ) // This is the main outline: remove all
+ {
+ SaveCopyInUndoList( aZone, UR_DELETED );
+ GetBoard()->Remove( aZone );
+ }
+
+ else
+ {
+ SaveCopyInUndoList( aZone, UR_CHANGED );
+ aZone->Outline()->RemoveContour( ncont );
+ }
+
+ m_canvas->RefreshDrawingRect( dirty );
+
+ OnModify();
+}