1024 lines
34 KiB
C++
1024 lines
34 KiB
C++
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Name: zones_by_polygon.cpp
|
|
// Licence: GPL License
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
#ifndef WX_PRECOMP
|
|
#include "wx/wx.h"
|
|
#endif
|
|
|
|
|
|
// For compilers that support precompilation, includes "wx/wx.h".
|
|
#include "wx/wxprec.h"
|
|
|
|
#ifdef __BORLANDC__
|
|
#pragma hdrstop
|
|
#endif
|
|
|
|
using namespace std;
|
|
|
|
#include "fctsys.h"
|
|
#include "gr_basic.h"
|
|
|
|
#include "common.h"
|
|
#include "pcbnew.h"
|
|
#include "autorout.h"
|
|
|
|
#include "id.h"
|
|
|
|
#include "protos.h"
|
|
|
|
#include "zones.h"
|
|
|
|
bool verbose = false; // false if zone outline diags must not be shown
|
|
|
|
// Outline creation:
|
|
static void Abort_Zone_Create_Outline( WinEDA_DrawPanel* Panel, wxDC* DC );
|
|
static void Show_New_Edge_While_Move_Mouse( WinEDA_DrawPanel* panel, wxDC* DC, bool erase );
|
|
|
|
// Corner moving
|
|
static void Abort_Zone_Move_Corner_Or_Outlines( WinEDA_DrawPanel* Panel, wxDC* DC );
|
|
static void Show_Zone_Corner_Or_Outline_While_Move_Mouse( WinEDA_DrawPanel* panel,
|
|
wxDC* DC,
|
|
bool erase );
|
|
|
|
/* 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 addes 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
|
|
|
|
#include "dialog_copper_zones.h"
|
|
|
|
/**********************************************************************************/
|
|
void WinEDA_PcbFrame::Add_Similar_Zone( wxDC* DC, ZONE_CONTAINER* zone_container )
|
|
/**********************************************************************************/
|
|
|
|
/**
|
|
* Function Add_Similar_Zone
|
|
* Add a zone to a given zone outline.
|
|
* if the zones are overlappeing they will be merged
|
|
* @param DC = current Device Context
|
|
* @param zone_container = parent zone outline
|
|
*/
|
|
{
|
|
if ( zone_container == NULL )
|
|
return;
|
|
s_AddCutoutToCurrentZone = false;
|
|
s_CurrentZone = zone_container;
|
|
|
|
/* set zones setup to the current zone */
|
|
g_Zone_Hatching = zone_container->m_Poly->GetHatchStyle();
|
|
g_Zone_Arc_Approximation = zone_container->m_ArcToSegmentsCount;
|
|
g_ThermalReliefGapValue = zone_container->m_ThermalReliefGapValue;
|
|
g_ThermalReliefCopperBridgeValue = zone_container->m_ThermalReliefCopperBridgeValue;
|
|
g_GridRoutingSize = zone_container->m_GridFillValue;
|
|
g_Zone_Pad_Options = zone_container->m_PadOption;
|
|
|
|
// Use the general event handle to set others params (like toolbar) */
|
|
wxCommandEvent evt;
|
|
evt.SetId( ID_PCB_ZONES_BUTT );
|
|
Process_Special_Functions( evt );
|
|
}
|
|
|
|
|
|
/**********************************************************************************/
|
|
void WinEDA_PcbFrame::Add_Zone_Cutout( wxDC* DC, ZONE_CONTAINER* zone_container )
|
|
/**********************************************************************************/
|
|
|
|
/**
|
|
* Function Add_Zone_Cutout
|
|
* Add a cutout zone to a given zone outline
|
|
* @param DC = current Device Context
|
|
* @param zone_container = parent zone outline
|
|
*/
|
|
{
|
|
if ( zone_container == NULL )
|
|
return;
|
|
s_AddCutoutToCurrentZone = true;
|
|
s_CurrentZone = zone_container;
|
|
|
|
/* set zones setup to the current zone */
|
|
g_Zone_Hatching = zone_container->m_Poly->GetHatchStyle();
|
|
g_Zone_Arc_Approximation = zone_container->m_ArcToSegmentsCount;
|
|
g_ThermalReliefGapValue = zone_container->m_ThermalReliefGapValue;
|
|
g_ThermalReliefCopperBridgeValue = zone_container->m_ThermalReliefCopperBridgeValue;
|
|
g_GridRoutingSize = zone_container->m_GridFillValue;
|
|
g_Zone_Pad_Options = zone_container->m_PadOption;
|
|
|
|
// Use the general event handle to set others params (like toolbar) */
|
|
wxCommandEvent evt;
|
|
evt.SetId( ID_PCB_ZONES_BUTT );
|
|
Process_Special_Functions( evt );
|
|
}
|
|
|
|
|
|
/**********************************************************************************/
|
|
void WinEDA_PcbFrame::Delete_Zone_Fill( wxDC* DC, SEGZONE* aZone, long aTimestamp )
|
|
/**********************************************************************************/
|
|
|
|
/** Function Delete_Zone_Fill
|
|
* Remove the zone fillig which include the segment aZone, or the zone which have the given time stamp.
|
|
* A zone is a group of segments which have the same TimeStamp
|
|
* @param DC = current Device Context (can be NULL)
|
|
* @param aZone = zone segment within the zone to delete. Can be NULL
|
|
* @param aTimestamp = Timestamp for the zone to delete, used if aZone == NULL
|
|
*/
|
|
{
|
|
int nb_segm = 0;
|
|
bool modify = false;
|
|
unsigned long TimeStamp;
|
|
|
|
if( aZone == NULL )
|
|
TimeStamp = aTimestamp;
|
|
else
|
|
TimeStamp = aZone->m_TimeStamp; // Save reference time stamp (aZone will be deleted)
|
|
|
|
SEGZONE* next;
|
|
for( SEGZONE* zone = m_Pcb->m_Zone; zone != NULL; zone = next )
|
|
{
|
|
next = zone->Next();
|
|
if( zone->m_TimeStamp == TimeStamp )
|
|
{
|
|
modify = TRUE;
|
|
|
|
/* Erase segment from screen */
|
|
if( DC )
|
|
Trace_Une_Piste( DrawPanel, DC, zone, nb_segm, GR_XOR );
|
|
/* remove item from linked list and free memory */
|
|
zone->DeleteStructure();
|
|
}
|
|
}
|
|
|
|
if( modify )
|
|
{
|
|
GetScreen()->SetModify();
|
|
GetScreen()->SetRefreshReq();
|
|
}
|
|
}
|
|
|
|
|
|
/*******************************************************/
|
|
int WinEDA_PcbFrame::Delete_LastCreatedCorner( wxDC* DC )
|
|
/*******************************************************/
|
|
|
|
/** Used **only** while creating a new zone outline
|
|
* Remove and delete the current outline segment in progress
|
|
* @return 0 if no corner in list, or corner number
|
|
* if no corner in list, close the outline creation
|
|
*/
|
|
{
|
|
ZONE_CONTAINER* zone = m_Pcb->m_CurrentZoneContour;
|
|
|
|
if( zone == NULL )
|
|
return 0;
|
|
|
|
if( zone->GetNumCorners() == 0 )
|
|
return 0;
|
|
|
|
zone->DrawWhileCreateOutline( DrawPanel, DC, GR_XOR );
|
|
|
|
if( zone->GetNumCorners() > 2 )
|
|
{
|
|
zone->m_Poly->DeleteCorner( zone->GetNumCorners() - 1 );
|
|
if( DrawPanel->ManageCurseur )
|
|
DrawPanel->ManageCurseur( DrawPanel, DC, false );
|
|
}
|
|
else
|
|
{
|
|
DrawPanel->ManageCurseur = NULL;
|
|
DrawPanel->ForceCloseManageCurseur = NULL;
|
|
SetCurItem( NULL );
|
|
zone->RemoveAllContours();
|
|
zone->m_Flags = 0;
|
|
}
|
|
return zone->GetNumCorners();
|
|
}
|
|
|
|
|
|
/*************************************************************************/
|
|
static void Abort_Zone_Create_Outline( WinEDA_DrawPanel* Panel, wxDC* DC )
|
|
/*************************************************************************/
|
|
|
|
/**
|
|
* Function Abort_Zone_Create_Outline
|
|
* cancels the Begin_Zone command if at least one EDGE_ZONE was created.
|
|
*/
|
|
{
|
|
WinEDA_PcbFrame* pcbframe = (WinEDA_PcbFrame*) Panel->m_Parent;
|
|
ZONE_CONTAINER* zone = pcbframe->m_Pcb->m_CurrentZoneContour;
|
|
|
|
if( zone )
|
|
{
|
|
zone->DrawWhileCreateOutline( Panel, DC, GR_XOR );
|
|
zone->m_Flags = 0;
|
|
zone->RemoveAllContours();
|
|
}
|
|
|
|
Panel->ManageCurseur = NULL;
|
|
Panel->ForceCloseManageCurseur = NULL;
|
|
pcbframe->SetCurItem( NULL );
|
|
s_AddCutoutToCurrentZone = false;
|
|
s_CurrentZone = NULL;
|
|
}
|
|
|
|
|
|
/*******************************************************************************************************/
|
|
void WinEDA_PcbFrame::Start_Move_Zone_Corner( wxDC* DC, ZONE_CONTAINER* zone_container,
|
|
int corner_id, bool IsNewCorner )
|
|
/*******************************************************************************************************/
|
|
|
|
/**
|
|
* Function Start_Move_Zone_Corner
|
|
* Initialise parametres to move an existing corner of a zone.
|
|
* if IsNewCorner is true, the Abort_Zone_Move_Corner_Or_Outlines will remove this corner, if called
|
|
*/
|
|
{
|
|
if( zone_container->IsOnCopperLayer() ) /* Show the Net */
|
|
{
|
|
if( g_HightLigt_Status && DC )
|
|
{
|
|
Hight_Light( DC ); // Remove old hightlight selection
|
|
}
|
|
|
|
g_HightLigth_NetCode = g_NetcodeSelection = zone_container->GetNet();
|
|
if( DC )
|
|
Hight_Light( DC );
|
|
}
|
|
|
|
zone_container->m_Flags = IN_EDIT;
|
|
DrawPanel->ManageCurseur = Show_Zone_Corner_Or_Outline_While_Move_Mouse;
|
|
DrawPanel->ForceCloseManageCurseur = Abort_Zone_Move_Corner_Or_Outlines;
|
|
s_CornerInitialPosition = zone_container->GetCornerPosition( corner_id );
|
|
s_CornerIsNew = IsNewCorner;
|
|
s_AddCutoutToCurrentZone = false;
|
|
s_CurrentZone = NULL;
|
|
}
|
|
|
|
|
|
/**************************************************************************************/
|
|
void WinEDA_PcbFrame::Start_Move_Zone_Drag_Outline_Edge( wxDC* DC,
|
|
ZONE_CONTAINER* zone_container,
|
|
int corner_id )
|
|
/**************************************************************************************/
|
|
|
|
/**
|
|
* Function Start_Move_Zone_Corner
|
|
* Prepares a drag edge for an existing zone outline,
|
|
*/
|
|
{
|
|
zone_container->m_Flags = IS_DRAGGED;
|
|
zone_container->m_CornerSelection = corner_id;
|
|
DrawPanel->ManageCurseur = Show_Zone_Corner_Or_Outline_While_Move_Mouse;
|
|
DrawPanel->ForceCloseManageCurseur = Abort_Zone_Move_Corner_Or_Outlines;
|
|
s_CursorLastPosition = s_CornerInitialPosition = GetScreen()->m_Curseur;
|
|
s_AddCutoutToCurrentZone = false;
|
|
s_CurrentZone = NULL;
|
|
}
|
|
|
|
|
|
/*******************************************************************************************************/
|
|
void WinEDA_PcbFrame::Start_Move_Zone_Outlines( wxDC* DC, ZONE_CONTAINER* zone_container )
|
|
/*******************************************************************************************************/
|
|
|
|
/**
|
|
* Function Start_Move_Zone_Outlines
|
|
* Initialise parametres to move an existing zone outlines.
|
|
*/
|
|
{
|
|
/* Show the Net */
|
|
if( zone_container->IsOnCopperLayer() ) /* Show the Net */
|
|
{
|
|
if( g_HightLigt_Status )
|
|
{
|
|
Hight_Light( DC ); // Remove old hightlight selection
|
|
}
|
|
|
|
g_HightLigth_NetCode = g_NetcodeSelection = zone_container->GetNet();
|
|
Hight_Light( DC );
|
|
}
|
|
|
|
zone_container->m_Flags = IS_MOVED;
|
|
DrawPanel->ManageCurseur = Show_Zone_Corner_Or_Outline_While_Move_Mouse;
|
|
DrawPanel->ForceCloseManageCurseur = Abort_Zone_Move_Corner_Or_Outlines;
|
|
s_CursorLastPosition = s_CornerInitialPosition = GetScreen()->m_Curseur;
|
|
s_CornerIsNew = false;
|
|
s_AddCutoutToCurrentZone = false;
|
|
s_CurrentZone = NULL;
|
|
}
|
|
|
|
|
|
/*************************************************************************************************/
|
|
void WinEDA_PcbFrame::End_Move_Zone_Corner_Or_Outlines( wxDC* DC, ZONE_CONTAINER* zone_container )
|
|
/*************************************************************************************************/
|
|
|
|
/**
|
|
* Function End_Move_Zone_Corner_Or_Outlines
|
|
* Terminates a move corner in a zone outline, or a move zone outlines
|
|
* @param DC = current Device Context (can be NULL)
|
|
* @param zone_container: the given zone
|
|
*/
|
|
{
|
|
zone_container->m_Flags = 0;
|
|
DrawPanel->ManageCurseur = NULL;
|
|
DrawPanel->ForceCloseManageCurseur = NULL;
|
|
if( DC )
|
|
zone_container->Draw( DrawPanel, DC, GR_OR );
|
|
GetScreen()->SetModify();
|
|
s_AddCutoutToCurrentZone = false;
|
|
s_CurrentZone = NULL;
|
|
|
|
SetCurItem( NULL ); // This outline can be deleted when merging outlines
|
|
|
|
/* Combine zones if possible */
|
|
wxBusyCursor dummy;
|
|
m_Pcb->AreaPolygonModified( zone_container, true, verbose );
|
|
DrawPanel->Refresh();
|
|
|
|
|
|
int ii = m_Pcb->GetAreaIndex( zone_container ); // test if zone_container exists
|
|
if( ii < 0 )
|
|
zone_container = NULL; // was removed by combining zones
|
|
|
|
int error_count = m_Pcb->Test_Drc_Areas_Outlines_To_Areas_Outlines( zone_container, true );
|
|
if( error_count )
|
|
{
|
|
DisplayError( this, _( "Area: DRC outline error" ) );
|
|
}
|
|
}
|
|
|
|
|
|
/*************************************************************************************/
|
|
void WinEDA_PcbFrame::Remove_Zone_Corner( wxDC* DC, ZONE_CONTAINER* zone_container )
|
|
/*************************************************************************************/
|
|
|
|
/**
|
|
* Function Remove_Zone_Corner
|
|
* Remove the currently selected corner in a zone outline
|
|
* the .m_CornerSelection is used as corner selection
|
|
* @param DC = Current deice context (can be NULL )
|
|
* @param zone_container = the zone that contains the selected corner
|
|
* the member .m_CornerSelection is used as selected corner
|
|
*/
|
|
{
|
|
GetScreen()->SetModify();
|
|
|
|
if( zone_container->m_Poly->GetNumCorners() <= 3 )
|
|
{
|
|
DrawPanel->PostDirtyRect( zone_container->GetBoundingBox() );
|
|
if( DC )
|
|
{
|
|
Delete_Zone_Fill( DC, NULL, zone_container->m_TimeStamp );
|
|
zone_container->DrawFilledArea( DrawPanel, DC, GR_XOR );
|
|
}
|
|
m_Pcb->Delete( zone_container );
|
|
return;
|
|
}
|
|
|
|
int layer = zone_container->GetLayer();
|
|
|
|
if( DC )
|
|
{
|
|
m_Pcb->RedrawAreasOutlines( DrawPanel, DC, GR_XOR, layer );
|
|
m_Pcb->RedrawFilledAreas( DrawPanel, DC, GR_XOR, layer );
|
|
}
|
|
|
|
zone_container->m_Poly->DeleteCorner( zone_container->m_CornerSelection );
|
|
|
|
// modify zones outlines according to the new zone_container shape
|
|
m_Pcb->AreaPolygonModified( zone_container, true, verbose );
|
|
if( DC )
|
|
{
|
|
m_Pcb->RedrawAreasOutlines( DrawPanel, DC, GR_OR, layer );
|
|
m_Pcb->RedrawFilledAreas( DrawPanel, DC, GR_OR, layer );
|
|
}
|
|
|
|
int ii = m_Pcb->GetAreaIndex( zone_container ); // test if zone_container exists
|
|
if( ii < 0 )
|
|
zone_container = NULL; // zone_container does not exist anymaore, after combining zones
|
|
int error_count = m_Pcb->Test_Drc_Areas_Outlines_To_Areas_Outlines( zone_container, true );
|
|
if( error_count )
|
|
{
|
|
DisplayError( this, _( "Area: DRC outline error" ) );
|
|
}
|
|
}
|
|
|
|
|
|
/**************************************************************************/
|
|
void Abort_Zone_Move_Corner_Or_Outlines( WinEDA_DrawPanel* Panel, wxDC* DC )
|
|
/**************************************************************************/
|
|
|
|
/**
|
|
* Function Abort_Zone_Move_Corner_Or_Outlines
|
|
* cancels the Begin_Zone state if at least one EDGE_ZONE has been created.
|
|
*/
|
|
{
|
|
WinEDA_PcbFrame* pcbframe = (WinEDA_PcbFrame*) Panel->m_Parent;
|
|
ZONE_CONTAINER* zone_container = (ZONE_CONTAINER*) pcbframe->GetCurItem();
|
|
|
|
// zone_container->Draw( Panel, DC, GR_XOR );
|
|
|
|
if( zone_container->m_Flags == IS_MOVED )
|
|
{
|
|
wxPoint offset;
|
|
offset = s_CornerInitialPosition - s_CursorLastPosition;
|
|
zone_container->Move( offset );
|
|
}
|
|
else if( zone_container->m_Flags == IS_DRAGGED )
|
|
{
|
|
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 );
|
|
}
|
|
}
|
|
|
|
// zone_container->Draw( Panel, DC, GR_XOR );
|
|
Panel->Refresh();
|
|
|
|
|
|
Panel->ManageCurseur = NULL;
|
|
Panel->ForceCloseManageCurseur = NULL;
|
|
pcbframe->SetCurItem( NULL );
|
|
zone_container->m_Flags = 0;
|
|
s_AddCutoutToCurrentZone = false;
|
|
s_CurrentZone = NULL;
|
|
}
|
|
|
|
|
|
/*************************************************************************************************/
|
|
void Show_Zone_Corner_Or_Outline_While_Move_Mouse( WinEDA_DrawPanel* Panel, wxDC* DC, bool erase )
|
|
/*************************************************************************************************/
|
|
|
|
/* Redraws the zone outline when moving a corner according to the cursor position
|
|
*/
|
|
{
|
|
WinEDA_PcbFrame* pcbframe = (WinEDA_PcbFrame*) Panel->m_Parent;
|
|
ZONE_CONTAINER* zone = (ZONE_CONTAINER*) pcbframe->GetCurItem();
|
|
|
|
if( erase ) /* Undraw edge in old position*/
|
|
{
|
|
zone->Draw( Panel, DC, GR_XOR );
|
|
}
|
|
|
|
wxPoint pos = pcbframe->GetScreen()->m_Curseur;
|
|
if( zone->m_Flags == IS_MOVED )
|
|
{
|
|
wxPoint offset;
|
|
offset = pos - s_CursorLastPosition;
|
|
zone->Move( offset );
|
|
s_CursorLastPosition = pos;
|
|
}
|
|
else if( zone->m_Flags == IS_DRAGGED )
|
|
{
|
|
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( Panel, DC, GR_XOR );
|
|
}
|
|
|
|
|
|
/*************************************************/
|
|
int WinEDA_PcbFrame::Begin_Zone( wxDC* DC )
|
|
/*************************************************/
|
|
|
|
/**
|
|
* Function Begin_Zone
|
|
* either initializes the first segment of a new zone, or adds an
|
|
* intermediate segment.
|
|
* A new zone can be:
|
|
* created from scratch: the user will be prompted to define parameters (layer, clearence ...)
|
|
* created from a similar zone (s_CurrentZone is used): parameters are copied from s_CurrentZone
|
|
* created as a cutout (an hole) inside s_CurrentZone
|
|
*/
|
|
{
|
|
// verify if s_CurrentZone exists (could be deleted since last selection) :
|
|
int ii;
|
|
for( ii = 0; ii < m_Pcb->GetAreaCount(); ii++ )
|
|
{
|
|
if( s_CurrentZone == m_Pcb->GetArea( ii ) )
|
|
break;
|
|
}
|
|
|
|
if( ii >= m_Pcb->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 beeing created:
|
|
if( m_Pcb->m_CurrentZoneContour == NULL )
|
|
m_Pcb->m_CurrentZoneContour = new ZONE_CONTAINER( m_Pcb );
|
|
|
|
ZONE_CONTAINER* zone = m_Pcb->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 reasonnable values
|
|
zone->SetLayer( ( (PCB_SCREEN*) GetScreen() )->m_Active_Layer );
|
|
|
|
// Prompt user for parameters:
|
|
DrawPanel->m_IgnoreMouseEvents = TRUE;
|
|
if( zone->IsOnCopperLayer() )
|
|
{ // Put a zone on a copper layer
|
|
if ( g_HightLigth_NetCode )
|
|
{
|
|
g_NetcodeSelection = g_HightLigth_NetCode;
|
|
zone->SetNet( g_NetcodeSelection );
|
|
EQUIPOT* net = m_Pcb->FindNet( g_NetcodeSelection );
|
|
if( net )
|
|
zone->m_Netname = net->m_Netname;
|
|
}
|
|
|
|
dialog_copper_zone* frame = new dialog_copper_zone( this, zone );
|
|
diag = frame->ShowModal();
|
|
frame->Destroy();
|
|
}
|
|
else // Put a zone on a non copper layer (technical layer)
|
|
{
|
|
diag = InstallDialogNonCopperZonesEditor( this, zone );
|
|
g_NetcodeSelection = 0; // No net for non copper zones
|
|
}
|
|
DrawPanel->MouseToCursorSchema();
|
|
DrawPanel->m_IgnoreMouseEvents = FALSE;
|
|
|
|
if( diag == ZONE_ABORT )
|
|
return 0;
|
|
|
|
( (PCB_SCREEN*) GetScreen() )->m_Active_Layer = g_CurrentZone_Layer; // Set by the dialog frame
|
|
}
|
|
else // Start a new contour: init zone params (net and layer) from an existing zone (add cutout or similar zone)
|
|
{
|
|
( (PCB_SCREEN*) GetScreen() )->m_Active_Layer = g_CurrentZone_Layer =
|
|
s_CurrentZone->GetLayer();
|
|
g_Zone_Hatching = s_CurrentZone->m_Poly->GetHatchStyle();
|
|
}
|
|
|
|
/* Show the Net for zones on copper layers */
|
|
if( g_CurrentZone_Layer < FIRST_NO_COPPER_LAYER )
|
|
{
|
|
if( s_CurrentZone )
|
|
g_NetcodeSelection = s_CurrentZone->GetNet();
|
|
if( g_HightLigt_Status )
|
|
{
|
|
Hight_Light( DC ); // Remove old hightlight selection
|
|
}
|
|
|
|
g_HightLigth_NetCode = g_NetcodeSelection;
|
|
Hight_Light( 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->m_Flags = IS_NEW;
|
|
zone->SetLayer( g_CurrentZone_Layer );
|
|
zone->SetNet( g_NetcodeSelection );
|
|
zone->m_TimeStamp = GetTimeStamp();
|
|
zone->m_PadOption = g_Zone_Pad_Options;
|
|
zone->m_ZoneClearance = g_DesignSettings.m_ZoneClearence;
|
|
zone->m_ThermalReliefGapValue = g_ThermalReliefGapValue;
|
|
zone->m_ThermalReliefCopperBridgeValue = g_ThermalReliefCopperBridgeValue;
|
|
zone->m_GridFillValue = g_GridRoutingSize;
|
|
zone->m_Poly->Start( g_CurrentZone_Layer,
|
|
GetScreen()->m_Curseur.x, GetScreen()->m_Curseur.y,
|
|
g_Zone_Hatching );
|
|
zone->AppendCorner( GetScreen()->m_Curseur );
|
|
if( Drc_On && (m_drc->Drc( zone, 0 ) == BAD_DRC) && zone->IsOnCopperLayer() )
|
|
{
|
|
zone->m_Flags = 0;
|
|
zone->RemoveAllContours();
|
|
|
|
// use the form of SetCurItem() which does not write to the msg panel,
|
|
// SCREEN::SetCurItem(), so the DRC error remains on screen.
|
|
// WinEDA_PcbFrame::SetCurItem() calls Display_Infos().
|
|
GetScreen()->SetCurItem( NULL );
|
|
DisplayError( this,
|
|
_( "DRC error: this start point is inside or too close an other area" ) );
|
|
return 0;
|
|
}
|
|
|
|
SetCurItem( zone );
|
|
DrawPanel->ManageCurseur = Show_New_Edge_While_Move_Mouse;
|
|
DrawPanel->ForceCloseManageCurseur = Abort_Zone_Create_Outline;
|
|
}
|
|
// edge in progress:
|
|
else
|
|
{
|
|
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 && m_drc->Drc( zone, ii - 1 ) == OK_DRC)
|
|
|| !zone->IsOnCopperLayer() ) // Ok, we can add a new corner
|
|
{
|
|
zone->AppendCorner( GetScreen()->m_Curseur );
|
|
SetCurItem( zone ); // calls Display_Infos().
|
|
}
|
|
}
|
|
}
|
|
|
|
return zone->GetNumCorners();
|
|
}
|
|
|
|
|
|
/*********************************************/
|
|
bool WinEDA_PcbFrame::End_Zone( wxDC* DC )
|
|
/*********************************************/
|
|
|
|
/** Function End_Zone
|
|
* Terminates a zone outline creation
|
|
* terminates (if no DRC error ) the zone edge creation process
|
|
* @param DC = current Device Context
|
|
* @return true if Ok, false if DRC error
|
|
* if ok, put it in the main list m_Pcb->m_ZoneDescriptorList (a vector<ZONE_CONTAINER*>)
|
|
*/
|
|
{
|
|
ZONE_CONTAINER* zone = m_Pcb->m_CurrentZoneContour;
|
|
|
|
if( zone == NULL )
|
|
return true;
|
|
|
|
// Validate the curren outline:
|
|
if( zone->GetNumCorners() <= 2 ) // An outline must have 3 corners or more
|
|
{
|
|
Abort_Zone_Create_Outline( DrawPanel, 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" ) );
|
|
DrawPanel->MouseToCursorSchema();
|
|
return false;
|
|
}
|
|
}
|
|
|
|
zone->m_Flags = 0;
|
|
|
|
zone->DrawWhileCreateOutline( DrawPanel, DC, GR_XOR );
|
|
|
|
DrawPanel->ManageCurseur = NULL;
|
|
DrawPanel->ForceCloseManageCurseur = NULL;
|
|
|
|
// Undraw old drawings, because they can have important changes
|
|
int layer = zone->GetLayer();
|
|
m_Pcb->RedrawAreasOutlines( DrawPanel, DC, GR_XOR, layer );
|
|
m_Pcb->RedrawFilledAreas( DrawPanel, DC, GR_XOR, layer );
|
|
|
|
/* Put edges in list */
|
|
if( s_CurrentZone == NULL )
|
|
{
|
|
zone->m_Poly->Close(); // Close the current corner list
|
|
m_Pcb->Add( zone );
|
|
m_Pcb->m_CurrentZoneContour = NULL;
|
|
}
|
|
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 outine can be deleted when merging outlines
|
|
|
|
// Combine zones if possible :
|
|
m_Pcb->AreaPolygonModified( zone, true, verbose );
|
|
|
|
// Redraw the real edge zone :
|
|
m_Pcb->RedrawAreasOutlines( DrawPanel, DC, GR_OR, layer );
|
|
m_Pcb->RedrawFilledAreas( DrawPanel, DC, GR_OR, layer );
|
|
|
|
int ii = m_Pcb->GetAreaIndex( zone ); // test if zone_container exists
|
|
if( ii < 0 )
|
|
zone = NULL; // was removed by combining zones
|
|
int error_count = m_Pcb->Test_Drc_Areas_Outlines_To_Areas_Outlines( zone, true );
|
|
if( error_count )
|
|
{
|
|
DisplayError( this, _( "Area: DRC outline error" ) );
|
|
}
|
|
|
|
GetScreen()->SetModify();
|
|
return true;
|
|
}
|
|
|
|
|
|
/******************************************************************************************/
|
|
static void Show_New_Edge_While_Move_Mouse( WinEDA_DrawPanel* panel, wxDC* DC, bool erase )
|
|
/******************************************************************************************/
|
|
|
|
/* Redraws the edge zone when moving mouse
|
|
*/
|
|
{
|
|
WinEDA_PcbFrame* pcbframe = (WinEDA_PcbFrame*) panel->m_Parent;
|
|
wxPoint c_pos = pcbframe->GetScreen()->m_Curseur;
|
|
ZONE_CONTAINER* zone = pcbframe->m_Pcb->m_CurrentZoneContour;
|
|
|
|
if( zone == NULL )
|
|
return;
|
|
|
|
int icorner = zone->GetNumCorners() - 1;
|
|
if ( icorner < 1 )
|
|
return; // We must have 2 (or more) corners
|
|
|
|
if( erase ) /* Undraw edge in old position*/
|
|
{
|
|
zone->DrawWhileCreateOutline( panel, DC );
|
|
}
|
|
|
|
/* Redraw the curent edge in its new position */
|
|
if( g_Zone_45_Only )
|
|
{
|
|
// calculate the new position as allowed
|
|
wxPoint StartPoint = zone->GetCornerPosition( icorner - 1 );
|
|
Calcule_Coord_Extremite_45( StartPoint.x, StartPoint.y,
|
|
&c_pos.x, &c_pos.y );
|
|
}
|
|
|
|
zone->SetCornerPosition( icorner, c_pos );
|
|
|
|
zone->DrawWhileCreateOutline( panel, DC );
|
|
}
|
|
|
|
|
|
/***********************************************************************************/
|
|
void WinEDA_PcbFrame::Edit_Zone_Params( wxDC* DC, ZONE_CONTAINER* zone_container )
|
|
/***********************************************************************************/
|
|
|
|
/**
|
|
* Function Edit_Zone_Params
|
|
* Edit params (layer, clearance, ...) for a zone outline
|
|
*/
|
|
{
|
|
int diag;
|
|
DrawPanel->m_IgnoreMouseEvents = TRUE;
|
|
if( zone_container->GetLayer() < FIRST_NO_COPPER_LAYER )
|
|
{ // edit a zone on a copper layer
|
|
dialog_copper_zone* frame = new dialog_copper_zone( this, zone_container );
|
|
diag = frame->ShowModal();
|
|
frame->Destroy();
|
|
}
|
|
else // edit a zone on a non copper layer (technical layer)
|
|
diag = InstallDialogNonCopperZonesEditor( this, zone_container );
|
|
|
|
DrawPanel->MouseToCursorSchema();
|
|
DrawPanel->m_IgnoreMouseEvents = FALSE;
|
|
|
|
if( diag == ZONE_ABORT )
|
|
return;
|
|
|
|
// Undraw old zone outlines
|
|
for( int ii = 0; ii < m_Pcb->GetAreaCount(); ii++ )
|
|
{
|
|
ZONE_CONTAINER* edge_zone = m_Pcb->GetArea( ii );
|
|
edge_zone->Draw( DrawPanel, DC, GR_XOR );
|
|
}
|
|
|
|
zone_container->SetLayer( g_CurrentZone_Layer );
|
|
zone_container->SetNet( g_NetcodeSelection );
|
|
EQUIPOT* net = m_Pcb->FindNet( g_NetcodeSelection );
|
|
if( net )
|
|
zone_container->m_Netname = net->m_Netname;
|
|
zone_container->m_Poly->SetHatch( g_Zone_Hatching );
|
|
zone_container->m_PadOption = g_Zone_Pad_Options;
|
|
zone_container->m_ZoneClearance = g_DesignSettings.m_ZoneClearence;
|
|
zone_container->m_GridFillValue = g_GridRoutingSize;
|
|
zone_container->m_ArcToSegmentsCount = g_Zone_Arc_Approximation;
|
|
zone_container->m_DrawOptions = g_FilledAreasShowMode;
|
|
zone_container->m_ThermalReliefGapValue = g_ThermalReliefGapValue;
|
|
zone_container->m_ThermalReliefCopperBridgeValue = g_ThermalReliefCopperBridgeValue;
|
|
|
|
|
|
// Combine zones if possible :
|
|
m_Pcb->AreaPolygonModified( zone_container, true, verbose );
|
|
|
|
// Redraw the real new zone outlines:
|
|
m_Pcb->RedrawAreasOutlines( DrawPanel, DC, GR_OR, -1 );
|
|
|
|
GetScreen()->SetModify();
|
|
}
|
|
|
|
|
|
/************************************************************************************/
|
|
void WinEDA_PcbFrame::Delete_Zone_Contour( wxDC* DC, ZONE_CONTAINER* zone_container )
|
|
/************************************************************************************/
|
|
|
|
/** Function Delete_Zone_Contour
|
|
* Remove the zone which include the segment aZone, or the zone which have the given time stamp.
|
|
* A zone is a group of segments which have the same TimeStamp
|
|
* @param DC = current Device Context (can be NULL)
|
|
* @param zone_container = zone to modify
|
|
* the member .m_CornerSelection is used to find the outline to remove.
|
|
* if the outline is the main outline, all the zone_container is removed (deleted)
|
|
* otherwise, the hole is deleted
|
|
*/
|
|
{
|
|
int ncont = zone_container->m_Poly->GetContour( zone_container->m_CornerSelection );
|
|
|
|
EDA_Rect dirty = zone_container->GetBoundingBox();
|
|
|
|
Delete_Zone_Fill( DC, NULL, zone_container->m_TimeStamp ); // Remove fill segments
|
|
|
|
if( ncont == 0 ) // This is the main outline: remove all
|
|
m_Pcb->Delete( zone_container );
|
|
|
|
else
|
|
{
|
|
zone_container->m_Poly->RemoveContour( ncont );
|
|
}
|
|
|
|
DrawPanel->PostDirtyRect( dirty );
|
|
|
|
GetScreen()->SetModify();
|
|
}
|
|
|
|
|
|
/***************************************************************************************/
|
|
int WinEDA_PcbFrame::Fill_Zone( wxDC* DC, ZONE_CONTAINER* zone_container, bool verbose )
|
|
/***************************************************************************************/
|
|
|
|
/** Function Fill_Zone()
|
|
* Calculate the zone filling for the outline zone_container
|
|
* The zone outline is a frontier, and can be complex (with holes)
|
|
* The filling starts from starting points like pads, tracks.
|
|
* If exists the old filling is removed
|
|
* @param DC = current Device Context
|
|
* @param zone_container = zone to fill
|
|
* @param verbose = true to show error messages
|
|
* @return error level (0 = no error)
|
|
*/
|
|
{
|
|
wxString msg;
|
|
|
|
MsgPanel->EraseMsgBox();
|
|
if( m_Pcb->ComputeBoundaryBox() == FALSE )
|
|
{
|
|
if( verbose )
|
|
DisplayError( this, wxT( "Board is empty!" ), 10 );
|
|
return -1;
|
|
}
|
|
|
|
/* Show the Net */
|
|
g_NetcodeSelection = zone_container->GetNet();
|
|
if( g_HightLigt_Status && (g_HightLigth_NetCode != g_NetcodeSelection) && DC )
|
|
{
|
|
Hight_Light( DC ); // Remove old hightlight selection
|
|
}
|
|
|
|
g_HightLigth_NetCode = g_NetcodeSelection;
|
|
if( DC )
|
|
Hight_Light( DC );
|
|
|
|
if( g_HightLigth_NetCode > 0 )
|
|
{
|
|
EQUIPOT* net = m_Pcb->FindNet( g_HightLigth_NetCode );
|
|
if( net == NULL )
|
|
{
|
|
if( g_HightLigth_NetCode > 0 )
|
|
{
|
|
if( verbose )
|
|
DisplayError( this, wxT( "Unable to find Net name" ) );
|
|
return -2;
|
|
}
|
|
}
|
|
else
|
|
msg = net->m_Netname;
|
|
}
|
|
else
|
|
msg = _( "No Net" );
|
|
|
|
Affiche_1_Parametre( this, 22, _( "NetName" ), msg, RED );
|
|
wxBusyCursor dummy; // Shows an hourglass cursor (removed by its destructor)
|
|
|
|
int error_level = 0;
|
|
zone_container->m_FilledPolysList.clear();
|
|
if( zone_container->m_GridFillValue == 0 )
|
|
{
|
|
zone_container->BuildFilledPolysListData( m_Pcb );
|
|
if ( DC )
|
|
DrawPanel->Refresh();
|
|
}
|
|
else
|
|
{
|
|
g_GridRoutingSize = zone_container->m_GridFillValue;
|
|
error_level = zone_container->Fill_Zone( this, DC, verbose );
|
|
}
|
|
|
|
GetScreen()->SetModify();
|
|
|
|
return error_level;
|
|
}
|
|
|
|
|
|
/************************************************************/
|
|
int WinEDA_PcbFrame::Fill_All_Zones( wxDC* DC, bool verbose )
|
|
/************************************************************/
|
|
|
|
/** Function Fill_All_Zones()
|
|
* Fill all zones on the board
|
|
* The old fillings are removed
|
|
* @param frame = reference to the main frame
|
|
* @param DC = current Device Context
|
|
* @param verbose = true to show error messages
|
|
* @return error level (0 = no error)
|
|
*/
|
|
{
|
|
ZONE_CONTAINER* zone_container;
|
|
int error_level = 0;
|
|
|
|
// Remove all zones :
|
|
if( m_Pcb->m_Zone )
|
|
{
|
|
m_Pcb->m_Zone->DeleteStructList();
|
|
m_Pcb->m_Zone = NULL;
|
|
m_Pcb->m_NbSegmZone = 0;
|
|
}
|
|
|
|
for( int ii = 0; ii < m_Pcb->GetAreaCount(); ii++ )
|
|
{
|
|
zone_container = m_Pcb->GetArea( ii );
|
|
error_level = Fill_Zone( NULL, zone_container, verbose );
|
|
if( error_level && !verbose )
|
|
break;
|
|
}
|
|
|
|
DrawPanel->Refresh( true );
|
|
return error_level;
|
|
}
|
|
|
|
|
|
/**
|
|
* Function SetAreasNetCodesFromNetNames
|
|
* Set the .m_NetCode member of all copper areas, according to the area Net Name
|
|
* The SetNetCodesFromNetNames is an equivalent to net name, for fas comparisons.
|
|
* However the Netcode is an arbitrary equivalence, it must be set after each netlist read
|
|
* or net change
|
|
* Must be called after pad netcodes are calculated
|
|
* @return : error count
|
|
* For non copper areas, netcode is set to 0
|
|
*/
|
|
int BOARD::SetAreasNetCodesFromNetNames( void )
|
|
{
|
|
int error_count = 0;
|
|
|
|
for( int ii = 0; ii < GetAreaCount(); ii++ )
|
|
{
|
|
if ( ! GetArea( ii )->IsOnCopperLayer() )
|
|
{
|
|
GetArea( ii )->SetNet( 0 );
|
|
continue;
|
|
}
|
|
|
|
const EQUIPOT* net = FindNet( GetArea( ii )->m_Netname );
|
|
if( net )
|
|
{
|
|
GetArea( ii )->SetNet( net->GetNet() );
|
|
}
|
|
else
|
|
{
|
|
error_count++;
|
|
GetArea( ii )->SetNet( -1 ); //keep Net Name ane set m_NetCode to -1 : error flag
|
|
}
|
|
}
|
|
|
|
return error_count;
|
|
}
|