814 lines
27 KiB
C++
814 lines
27 KiB
C++
/*
|
|
* This program source code file is part of KiCad, a free EDA CAD application.
|
|
*
|
|
* Copyright (C) 2007 Jean-Pierre Charras, jaen-pierre.charras@gipsa-lab.inpg.com
|
|
* Copyright (C) 2011 Wayne Stambaugh <stambaughw@verizon.net>
|
|
* Copyright (C) 1992-2011 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 "appl_wxstruct.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"
|
|
|
|
bool s_Verbose = false; // false if zone outline diags must not be shown
|
|
|
|
// 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 _AuxiliaryList; // a picked list to store zones that are deleted or added when combined
|
|
|
|
#include "dialog_copper_zones.h"
|
|
|
|
|
|
void PCB_EDIT_FRAME::Add_Similar_Zone( wxDC* DC, ZONE_CONTAINER* zone_container )
|
|
{
|
|
if ( zone_container == NULL )
|
|
return;
|
|
|
|
s_AddCutoutToCurrentZone = false;
|
|
s_CurrentZone = zone_container;
|
|
|
|
/* set zones setup to the current zone */
|
|
g_Zone_Default_Setting.ImportSetting( *zone_container );
|
|
|
|
// Use the general event handle to set others params (like toolbar) */
|
|
wxCommandEvent evt;
|
|
evt.SetId( ID_PCB_ZONES_BUTT );
|
|
OnSelectTool( evt );
|
|
}
|
|
|
|
|
|
void PCB_EDIT_FRAME::Add_Zone_Cutout( wxDC* DC, ZONE_CONTAINER* zone_container )
|
|
{
|
|
if ( zone_container == NULL )
|
|
return;
|
|
|
|
s_AddCutoutToCurrentZone = true;
|
|
s_CurrentZone = zone_container;
|
|
|
|
/* set zones setup to the current zone */
|
|
g_Zone_Default_Setting.ImportSetting( *zone_container );
|
|
|
|
// Use the general event handle to set others params (like toolbar) */
|
|
wxCommandEvent evt;
|
|
evt.SetId( ID_PCB_ZONES_BUTT );
|
|
OnSelectTool( evt );
|
|
}
|
|
|
|
|
|
int PCB_EDIT_FRAME::Delete_LastCreatedCorner( wxDC* DC )
|
|
{
|
|
ZONE_CONTAINER* zone = GetBoard()->m_CurrentZoneContour;
|
|
|
|
if( zone == NULL )
|
|
return 0;
|
|
|
|
if( zone->GetNumCorners() == 0 )
|
|
return 0;
|
|
|
|
zone->DrawWhileCreateOutline( m_canvas, DC, GR_XOR );
|
|
|
|
if( zone->GetNumCorners() > 2 )
|
|
{
|
|
zone->m_Poly->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->ClearFlags();
|
|
zone->RemoveAllContours();
|
|
}
|
|
|
|
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* zone_container,
|
|
int corner_id, bool IsNewCorner )
|
|
{
|
|
if( zone_container->IsOnCopperLayer() ) /* Show the Net */
|
|
{
|
|
if( GetBoard()->IsHighLightNetON() && DC )
|
|
{
|
|
HighLight( DC ); // Remove old highlight selection
|
|
}
|
|
|
|
g_Zone_Default_Setting.m_NetcodeSelection = zone_container->GetNet();
|
|
GetBoard()->SetHighLightNet( zone_container->GetNet() );
|
|
|
|
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 = zone_container->m_Poly->GetX( corner_id );
|
|
int cy = zone_container->m_Poly->GetY( corner_id );
|
|
|
|
if ( IsNewCorner )
|
|
zone_container->m_Poly->DeleteCorner( corner_id );
|
|
|
|
_AuxiliaryList.ClearListAndDeleteItems();
|
|
s_PickedList.ClearListAndDeleteItems();
|
|
|
|
SaveCopyOfZones( s_PickedList, GetBoard(), zone_container->GetNet(),
|
|
zone_container->GetLayer() );
|
|
|
|
if ( IsNewCorner )
|
|
zone_container->m_Poly->InsertCorner(corner_id-1, cx, cy );
|
|
|
|
zone_container->SetFlags( IN_EDIT );
|
|
m_canvas->SetMouseCapture( Show_Zone_Corner_Or_Outline_While_Move_Mouse,
|
|
Abort_Zone_Move_Corner_Or_Outlines );
|
|
s_CornerInitialPosition = zone_container->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* zone_container,
|
|
int corner_id )
|
|
{
|
|
zone_container->SetFlags( IS_DRAGGED );
|
|
zone_container->m_CornerSelection = corner_id;
|
|
m_canvas->SetMouseCapture( Show_Zone_Corner_Or_Outline_While_Move_Mouse,
|
|
Abort_Zone_Move_Corner_Or_Outlines );
|
|
s_CursorLastPosition = s_CornerInitialPosition = GetScreen()->GetCrossHairPosition();
|
|
s_AddCutoutToCurrentZone = false;
|
|
s_CurrentZone = NULL;
|
|
|
|
s_PickedList.ClearListAndDeleteItems();
|
|
_AuxiliaryList.ClearListAndDeleteItems();
|
|
SaveCopyOfZones( s_PickedList, GetBoard(), zone_container->GetNet(),
|
|
zone_container->GetLayer() );
|
|
}
|
|
|
|
|
|
void PCB_EDIT_FRAME::Start_Move_Zone_Outlines( wxDC* DC, ZONE_CONTAINER* zone_container )
|
|
{
|
|
/* Show the Net */
|
|
if( zone_container->IsOnCopperLayer() ) /* Show the Net */
|
|
{
|
|
if( GetBoard()->IsHighLightNetON() )
|
|
{
|
|
HighLight( DC ); // Remove old highlight selection
|
|
}
|
|
|
|
g_Zone_Default_Setting.m_NetcodeSelection = zone_container->GetNet();
|
|
GetBoard()->SetHighLightNet( zone_container->GetNet() );
|
|
HighLight( DC );
|
|
}
|
|
|
|
s_PickedList.ClearListAndDeleteItems();
|
|
_AuxiliaryList.ClearListAndDeleteItems();
|
|
SaveCopyOfZones( s_PickedList, GetBoard(), zone_container->GetNet(),
|
|
zone_container->GetLayer() );
|
|
|
|
zone_container->SetFlags( IS_MOVED );
|
|
m_canvas->SetMouseCapture( Show_Zone_Corner_Or_Outline_While_Move_Mouse,
|
|
Abort_Zone_Move_Corner_Or_Outlines );
|
|
s_CursorLastPosition = s_CornerInitialPosition = GetScreen()->GetCrossHairPosition();
|
|
s_CornerIsNew = false;
|
|
s_AddCutoutToCurrentZone = false;
|
|
s_CurrentZone = NULL;
|
|
}
|
|
|
|
|
|
void PCB_EDIT_FRAME::End_Move_Zone_Corner_Or_Outlines( wxDC* DC, ZONE_CONTAINER* zone_container )
|
|
{
|
|
zone_container->ClearFlags();
|
|
m_canvas->SetMouseCapture( NULL, NULL );
|
|
|
|
if( DC )
|
|
zone_container->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 */
|
|
wxBusyCursor dummy;
|
|
GetBoard()->AreaPolygonModified( &_AuxiliaryList, zone_container, true, s_Verbose );
|
|
m_canvas->Refresh();
|
|
|
|
|
|
int ii = GetBoard()->GetAreaIndex( zone_container ); // test if zone_container exists
|
|
|
|
if( ii < 0 )
|
|
zone_container = NULL; // was removed by combining zones
|
|
|
|
UpdateCopyOfZonesList( s_PickedList, _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( zone_container, true );
|
|
|
|
if( error_count )
|
|
{
|
|
DisplayError( this, _( "Area: DRC outline error" ) );
|
|
}
|
|
}
|
|
|
|
|
|
void PCB_EDIT_FRAME::Remove_Zone_Corner( wxDC* DC, ZONE_CONTAINER* zone_container )
|
|
{
|
|
OnModify();
|
|
|
|
if( zone_container->m_Poly->GetNumCorners() <= 3 )
|
|
{
|
|
m_canvas->RefreshDrawingRect( zone_container->GetBoundingBox() );
|
|
|
|
if( DC )
|
|
{ // Remove the full zone because this is no more an area
|
|
zone_container->UnFill();
|
|
zone_container->DrawFilledArea( m_canvas, DC, GR_XOR );
|
|
}
|
|
|
|
GetBoard()->Delete( zone_container );
|
|
return;
|
|
}
|
|
|
|
int layer = zone_container->GetLayer();
|
|
|
|
if( DC )
|
|
{
|
|
GetBoard()->RedrawAreasOutlines( m_canvas, DC, GR_XOR, layer );
|
|
GetBoard()->RedrawFilledAreas( m_canvas, DC, GR_XOR, layer );
|
|
}
|
|
|
|
_AuxiliaryList.ClearListAndDeleteItems();
|
|
s_PickedList. ClearListAndDeleteItems();
|
|
SaveCopyOfZones( s_PickedList, GetBoard(), zone_container->GetNet(),
|
|
zone_container->GetLayer() );
|
|
zone_container->m_Poly->DeleteCorner( zone_container->m_CornerSelection );
|
|
|
|
// modify zones outlines according to the new zone_container shape
|
|
GetBoard()->AreaPolygonModified( &_AuxiliaryList, zone_container, true, s_Verbose );
|
|
|
|
if( DC )
|
|
{
|
|
GetBoard()->RedrawAreasOutlines( m_canvas, DC, GR_OR, layer );
|
|
GetBoard()->RedrawFilledAreas( m_canvas, DC, GR_OR, layer );
|
|
}
|
|
|
|
UpdateCopyOfZonesList( s_PickedList, _AuxiliaryList, GetBoard() );
|
|
SaveCopyInUndoList(s_PickedList, UR_UNSPECIFIED);
|
|
s_PickedList.ClearItemsList(); // s_ItemsListPicker is no more owner of picked items
|
|
|
|
int ii = GetBoard()->GetAreaIndex( zone_container ); // test if zone_container exists
|
|
|
|
if( ii < 0 )
|
|
zone_container = NULL; // zone_container does not exist anymore, after combining zones
|
|
|
|
int error_count = GetBoard()->Test_Drc_Areas_Outlines_To_Areas_Outlines( zone_container, 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_container = (ZONE_CONTAINER*) pcbframe->GetCurItem();
|
|
|
|
if( zone_container->IsMoving() )
|
|
{
|
|
wxPoint offset;
|
|
offset = s_CornerInitialPosition - s_CursorLastPosition;
|
|
zone_container->Move( offset );
|
|
}
|
|
else if( zone_container->IsDragging() )
|
|
{
|
|
wxPoint offset;
|
|
offset = s_CornerInitialPosition - s_CursorLastPosition;
|
|
zone_container->MoveEdge( offset );
|
|
}
|
|
else
|
|
{
|
|
if( s_CornerIsNew )
|
|
{
|
|
zone_container->m_Poly->DeleteCorner( zone_container->m_CornerSelection );
|
|
}
|
|
else
|
|
{
|
|
wxPoint pos = s_CornerInitialPosition;
|
|
zone_container->m_Poly->MoveCorner( zone_container->m_CornerSelection, pos.x, pos.y );
|
|
}
|
|
}
|
|
|
|
Panel->SetMouseCapture( NULL, NULL );
|
|
_AuxiliaryList.ClearListAndDeleteItems();
|
|
s_PickedList. ClearListAndDeleteItems();
|
|
Panel->Refresh();
|
|
|
|
pcbframe->SetCurItem( NULL );
|
|
zone_container->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->GetScreen()->GetCrossHairPosition();
|
|
|
|
if( zone->IsMoving() )
|
|
{
|
|
wxPoint offset;
|
|
offset = pos - s_CursorLastPosition;
|
|
zone->Move( offset );
|
|
s_CursorLastPosition = pos;
|
|
}
|
|
else if( zone->IsDragging() )
|
|
{
|
|
wxPoint offset;
|
|
offset = pos - s_CursorLastPosition;
|
|
zone->MoveEdge( offset );
|
|
s_CursorLastPosition = pos;
|
|
}
|
|
else
|
|
{
|
|
zone->m_Poly->MoveCorner( zone->m_CornerSelection, pos.x, pos.y );
|
|
}
|
|
|
|
zone->Draw( aPanel, aDC, GR_XOR );
|
|
}
|
|
|
|
|
|
|
|
int PCB_EDIT_FRAME::Begin_Zone( wxDC* DC )
|
|
{
|
|
// 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;
|
|
}
|
|
|
|
// If no zone contour in progress, a new zone is being created:
|
|
if( GetBoard()->m_CurrentZoneContour == NULL )
|
|
GetBoard()->m_CurrentZoneContour = new ZONE_CONTAINER( GetBoard() );
|
|
|
|
ZONE_CONTAINER* zone = GetBoard()->m_CurrentZoneContour;
|
|
|
|
if( zone->GetNumCorners() == 0 ) // Start a new contour: init zone params (net, layer ...)
|
|
{
|
|
if( s_CurrentZone == NULL ) // A new outline is created, from scratch
|
|
{
|
|
int diag;
|
|
// 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 )
|
|
{
|
|
g_Zone_Default_Setting.m_NetcodeSelection = GetBoard()->GetHighLightNetCode();
|
|
|
|
zone->SetNet( g_Zone_Default_Setting.m_NetcodeSelection );
|
|
zone->SetNetNameFromNetCode( );
|
|
}
|
|
|
|
wxGetApp().GetSettings()->Read( ZONE_THERMAL_RELIEF_GAP_STRING_KEY,
|
|
&g_Zone_Default_Setting.m_ThermalReliefGap );
|
|
wxGetApp().GetSettings()->Read( ZONE_THERMAL_RELIEF_COPPER_WIDTH_STRING_KEY,
|
|
&g_Zone_Default_Setting.m_ThermalReliefCopperBridge );
|
|
|
|
g_Zone_Default_Setting.m_CurrentZone_Layer = zone->GetLayer();
|
|
DIALOG_COPPER_ZONE* frame = new DIALOG_COPPER_ZONE( this, &g_Zone_Default_Setting );
|
|
diag = frame->ShowModal();
|
|
frame->Destroy();
|
|
}
|
|
else // Put a zone on a non copper layer (technical layer)
|
|
{
|
|
diag = InstallDialogNonCopperZonesEditor( zone );
|
|
g_Zone_Default_Setting.m_NetcodeSelection = 0; // No net for non copper zones
|
|
}
|
|
|
|
m_canvas->MoveCursorToCrossHair();
|
|
m_canvas->SetIgnoreMouseEvents( false );
|
|
|
|
if( diag == ZONE_ABORT )
|
|
return 0;
|
|
|
|
// Switch active layer to the selected zone layer
|
|
setActiveLayer( g_Zone_Default_Setting.m_CurrentZone_Layer );
|
|
}
|
|
else // Start a new contour: init zone params (net and layer) from an existing
|
|
{ // zone (add cutout or similar zone)
|
|
g_Zone_Default_Setting.m_CurrentZone_Layer = s_CurrentZone->GetLayer();
|
|
setActiveLayer( s_CurrentZone->GetLayer() );
|
|
g_Zone_Default_Setting.ImportSetting( * s_CurrentZone);
|
|
}
|
|
|
|
/* Show the Net for zones on copper layers */
|
|
if( g_Zone_Default_Setting.m_CurrentZone_Layer < FIRST_NO_COPPER_LAYER )
|
|
{
|
|
if( s_CurrentZone )
|
|
g_Zone_Default_Setting.m_NetcodeSelection = s_CurrentZone->GetNet();
|
|
|
|
if( GetBoard()->IsHighLightNetON() )
|
|
{
|
|
HighLight( DC ); // Remove old highlight selection
|
|
}
|
|
|
|
GetBoard()->SetHighLightNet( g_Zone_Default_Setting.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 )
|
|
{
|
|
zone->SetFlags( IS_NEW );
|
|
zone->SetTimeStamp( GetNewTimeStamp() );
|
|
g_Zone_Default_Setting.ExportSetting( *zone );
|
|
zone->m_Poly->Start( g_Zone_Default_Setting.m_CurrentZone_Layer,
|
|
GetScreen()->GetCrossHairPosition().x,
|
|
GetScreen()->GetCrossHairPosition().y,
|
|
zone->GetHatchStyle() );
|
|
zone->AppendCorner( GetScreen()->GetCrossHairPosition() );
|
|
|
|
if( 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( !Drc_On || !zone->IsOnCopperLayer() || ( m_drc->Drc( zone, ii - 1 ) == OK_DRC ) )
|
|
{ // Ok, we can add a new corner
|
|
zone->AppendCorner( GetScreen()->GetCrossHairPosition() );
|
|
SetCurItem( zone ); // calls DisplayInfo().
|
|
}
|
|
}
|
|
}
|
|
|
|
return zone->GetNumCorners();
|
|
}
|
|
|
|
|
|
bool PCB_EDIT_FRAME::End_Zone( wxDC* DC )
|
|
{
|
|
ZONE_CONTAINER* zone = GetBoard()->m_CurrentZoneContour;
|
|
|
|
if( zone == NULL )
|
|
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;
|
|
}
|
|
|
|
// Validate the current edge:
|
|
int icorner = zone->GetNumCorners() - 1;
|
|
if( zone->IsOnCopperLayer() )
|
|
{
|
|
if( Drc_On && m_drc->Drc( zone, icorner - 1 ) == BAD_DRC ) // we can't validate last edge
|
|
return false;
|
|
|
|
if( 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
|
|
int 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
|
|
_AuxiliaryList.ClearListAndDeleteItems();
|
|
s_PickedList.ClearListAndDeleteItems();
|
|
SaveCopyOfZones(s_PickedList, GetBoard(), zone->GetNet(), zone->GetLayer() );
|
|
|
|
/* Put new zone in list */
|
|
if( s_CurrentZone == NULL )
|
|
{
|
|
zone->m_Poly->Close(); // 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->m_Poly->Close(); // 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()->AreaPolygonModified( &_AuxiliaryList, zone, true, s_Verbose );
|
|
|
|
// 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_container 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, _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->GetScreen()->GetCrossHairPosition();
|
|
ZONE_CONTAINER* zone = pcbframe->GetBoard()->m_CurrentZoneContour;
|
|
|
|
if( zone == NULL )
|
|
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( g_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* zone_container )
|
|
{
|
|
int diag;
|
|
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
|
|
*/
|
|
_AuxiliaryList.ClearListAndDeleteItems();
|
|
s_PickedList.ClearListAndDeleteItems();
|
|
SaveCopyOfZones(s_PickedList, GetBoard(), -1, -1 );
|
|
|
|
if( zone_container->GetLayer() < FIRST_NO_COPPER_LAYER )
|
|
{ // edit a zone on a copper layer
|
|
g_Zone_Default_Setting.ImportSetting(*zone_container);
|
|
DIALOG_COPPER_ZONE* frame = new DIALOG_COPPER_ZONE( this, &g_Zone_Default_Setting );
|
|
diag = frame->ShowModal();
|
|
frame->Destroy();
|
|
}
|
|
else // edit a zone on a non copper layer (technical layer)
|
|
{
|
|
diag = InstallDialogNonCopperZonesEditor( zone_container );
|
|
}
|
|
|
|
m_canvas->MoveCursorToCrossHair();
|
|
m_canvas->SetIgnoreMouseEvents( false );
|
|
|
|
if( diag == ZONE_ABORT )
|
|
{
|
|
_AuxiliaryList.ClearListAndDeleteItems();
|
|
s_PickedList.ClearListAndDeleteItems();
|
|
return;
|
|
}
|
|
|
|
if( diag == ZONE_EXPORT_VALUES )
|
|
{
|
|
UpdateCopyOfZonesList( s_PickedList, _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 );
|
|
}
|
|
|
|
g_Zone_Default_Setting.ExportSetting( *zone_container);
|
|
NETINFO_ITEM* net = GetBoard()->FindNet( g_Zone_Default_Setting.m_NetcodeSelection );
|
|
|
|
if( net ) // net == NULL should not occur
|
|
zone_container->m_Netname = net->GetNetname();
|
|
|
|
// Combine zones if possible :
|
|
GetBoard()->AreaPolygonModified( &_AuxiliaryList, zone_container, true, s_Verbose );
|
|
|
|
// Redraw the real new zone outlines:
|
|
GetBoard()->RedrawAreasOutlines( m_canvas, DC, GR_OR, -1 );
|
|
|
|
UpdateCopyOfZonesList( s_PickedList, _AuxiliaryList, GetBoard() );
|
|
SaveCopyInUndoList(s_PickedList, UR_UNSPECIFIED);
|
|
s_PickedList.ClearItemsList(); // s_ItemsListPicker is no more owner of picked items
|
|
|
|
OnModify();
|
|
}
|
|
|
|
|
|
void PCB_EDIT_FRAME::Delete_Zone_Contour( wxDC* DC, ZONE_CONTAINER* zone_container )
|
|
{
|
|
int ncont = zone_container->m_Poly->GetContour( zone_container->m_CornerSelection );
|
|
|
|
EDA_RECT dirty = zone_container->GetBoundingBox();
|
|
|
|
// For compatibility with old boards: remove old SEGZONE fill segments
|
|
Delete_OldZone_Fill( NULL, zone_container->GetTimeStamp() );
|
|
|
|
// Remove current filling:
|
|
zone_container->UnFill();
|
|
|
|
if( ncont == 0 ) // This is the main outline: remove all
|
|
{
|
|
SaveCopyInUndoList( zone_container, UR_DELETED );
|
|
GetBoard()->Remove( zone_container );
|
|
}
|
|
|
|
else
|
|
{
|
|
zone_container->m_Poly->RemoveContour( ncont );
|
|
}
|
|
|
|
m_canvas->RefreshDrawingRect( dirty );
|
|
|
|
OnModify();
|
|
}
|