Commit cfdb2839 authored by charras's avatar charras

Pcbnew: Work on undo/redo in Pcbnew almost finished.

parent 856b7c79
......@@ -4,6 +4,11 @@ KiCad ChangeLog 2009
Please add newer entries at the top, list the date and your name with
email address.
2009-aug-23 UPDATE Jean-Pierre Charras <jean-pierre.charras@gipsa-lab.inpg.fr>
================================================================================
++pcbnew
Work on undo/redo in pcbnew almost finished.
2009-Aug-16 UPDATE Dick Hollenbeck <dick@softplc.com>
================================================================================
++pcbnew
......
......@@ -479,12 +479,11 @@ public:
* 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)
*/
int Fill_Zone( wxDC* DC, ZONE_CONTAINER* zone_container, bool verbose = TRUE );
int Fill_Zone( ZONE_CONTAINER* zone_container, bool verbose = TRUE );
/** Function Fill_All_Zones()
* Fill all zones on the board
......
......@@ -149,8 +149,10 @@ set(PCBNEW_SRCS
work.cpp
xchgmod.cpp
zones_by_polygon.cpp
zones_by_polygon_fill_functions.cpp
zones_convert_brd_items_to_polygons.cpp
zone_filling_algorithm.cpp
zones_functions_for_undo_redo.cpp
zones_polygons_insulated_copper_islands.cpp
zones_polygons_test_connections.cpp
zones_test_and_combine_areas.cpp
......
......@@ -424,7 +424,8 @@ void WinEDA_PcbFrame::SaveCopyInUndoList( PICKED_ITEMS_LIST& aItemsList,
*/
if( commandToUndo->GetPickedItemLink( ii ) == NULL )
commandToUndo->SetPickedItemLink( DuplicateStruct( item ), ii );
wxASSERT( commandToUndo->GetPickedItemLink( ii ) );
if( commandToUndo->GetPickedItemLink( ii ) == NULL )
wxMessageBox( wxT( "SaveCopyInUndoList() in UR_CHANGED mode: NULL link" ) );
break;
case UR_MOVED:
......
......@@ -252,7 +252,14 @@ void BOARD::Add( BOARD_ITEM* aBoardItem, int aControl )
// other types may use linked list
default:
wxFAIL_MSG( wxT( "BOARD::Add() needs work: BOARD_ITEM type not handled" ) );
{
wxString msg;
msg.Printf(
wxT( "BOARD::Add() needs work: BOARD_ITEM type (%d) not handled" ),
aBoardItem->Type() );
wxFAIL_MSG(msg );
}
break;
}
}
......
/**************************************************************/
/*************************************************/
/* class_board.h - Class BOARD to handle a board */
/**************************************************************/
/*************************************************/
#ifndef CLASS_BOARD_H
#define CLASS_BOARD_H
......@@ -474,19 +474,18 @@ public:
/* Functions used in test, merge and cut outlines */
/**
* Function AddArea
* add empty copper area to net
/** Function AddArea
* Add an empty copper area to board areas list
* @param aNewZonesList = a PICKED_ITEMS_LIST * where to store new areas pickers (useful in undo commands)
* can be NULL
* @param aNetcode = the necode of the copper area (0 = no net)
* @param aLayer = the layer of area
* @param aStartPointPosition = position of the first point of the polygon outline of this area
* @param aHatch = hacth option
* @return pointer to the new area
*/
ZONE_CONTAINER* AddArea( int netcode, int layer, int x, int y, int hatch );
/**
* remove copper area from net
* @param area = area to remove
* @return 0
*/
int RemoveArea( ZONE_CONTAINER* area_to_remove );
ZONE_CONTAINER* AddArea( PICKED_ITEMS_LIST* aNewZonesList, int aNetcode,
int aLayer, wxPoint aStartPointPosition, int aHatch );
/**
* Function InsertArea
......@@ -522,15 +521,20 @@ public:
* Function ClipAreaPolygon
* Process an area that has been modified, by clipping its polygon against itself.
* This may change the number and order of copper areas in the net.
* @param bMessageBoxInt == TRUE, shows message when clipping occurs.
* @param bMessageBoxArc == TRUE, shows message when clipping can't be done due to arcs.
* @param aNewZonesList = a PICKED_ITEMS_LIST * where to store new areas pickers (useful in undo commands)
* can be NULL
* @param aCurrArea = the zone to process
* @param bMessageBoxInt == true, shows message when clipping occurs.
* @param bMessageBoxArc == true, shows message when clipping can't be done due to arcs.
* @param bRetainArcs = true to handle arcs (not really used in kicad)
* @return:
* -1 if arcs intersect other sides, so polygon can't be clipped
* 0 if no intersecting sides
* 1 if intersecting sides
* Also sets areas->utility1 flags if areas are modified
*/
int ClipAreaPolygon( ZONE_CONTAINER* CurrArea,
int ClipAreaPolygon( PICKED_ITEMS_LIST * aNewZonesList,
ZONE_CONTAINER* aCurrArea,
bool bMessageBoxArc,
bool bMessageBoxInt,
bool bRetainArcs = TRUE );
......@@ -539,6 +543,8 @@ public:
* Process an area that has been modified, by clipping its polygon against
* itself and the polygons for any other areas on the same net.
* This may change the number and order of copper areas in the net.
* @param aModifiedZonesList = a PICKED_ITEMS_LIST * where to store deleted or added areas
* (useful in undo commands. Can be NULL
* @param modified_area = area to test
* @param bMessageBox : if TRUE, shows message boxes when clipping occurs.
* @return :
......@@ -546,20 +552,31 @@ public:
* 0 if no intersecting sides
* 1 if intersecting sides, polygon clipped
*/
int AreaPolygonModified( ZONE_CONTAINER* modified_area,
int AreaPolygonModified( PICKED_ITEMS_LIST* aModifiedZonesList,
ZONE_CONTAINER* modified_area,
bool bMessageBoxArc,
bool bMessageBoxInt );
/**
* Function CombineAllAreasInNet
* Checks all copper areas in net for intersections, combining them if found
* @param aDeletedList = a PICKED_ITEMS_LIST * where to store deleted areas (useful in undo commands
* can be NULL
* @param aNetCode = net to consider
* @param bMessageBox : if true display warning message box
* @param bUseUtility : if true, don't check areas if both utility flags are 0
* Sets utility flag = 1 for any areas modified
* If an area has self-intersecting arcs, doesn't try to combine it
*/
int CombineAllAreasInNet( int aNetCode, bool bMessageBox, bool bUseUtility );
int CombineAllAreasInNet( PICKED_ITEMS_LIST* aDeletedList, int aNetCode, bool bMessageBox, bool bUseUtility );
/** Function RemoveArea
* remove copper area from net, and put it in a deleted list (if exists)
* @param aDeletedList = a PICKED_ITEMS_LIST * where to store deleted areas (useful in undo commands
* can be NULL
* @param area_to_remove = area to delete or put in deleted list
*/
void RemoveArea( PICKED_ITEMS_LIST* aDeletedList, ZONE_CONTAINER* area_to_remove );
/**
* Function TestAreaIntersections
......@@ -583,13 +600,17 @@ public:
/**
* Function CombineAreas
* If possible, combine 2 copper areas
* @param aDeletedList = a PICKED_ITEMS_LIST * where to store deleted areas (useful in undo commands
* can be NULL
* @param area_ref = tje main area (zone)
* @param area_to_combine = the zone that can be merged with area_ref
* area_ref must be BEFORE area_to_combine
* area_to_combine will be deleted, if areas are combined
* @return : 0 if no intersection
* 1 if intersection
* 2 if arcs intersect
*/
int CombineAreas( ZONE_CONTAINER* area_ref, ZONE_CONTAINER* area_to_combine );
int CombineAreas( PICKED_ITEMS_LIST* aDeletedList, ZONE_CONTAINER* area_ref, ZONE_CONTAINER* area_to_combine );
/**
* Function Test_Drc_Areas_Outlines_To_Areas_Outlines
......
......@@ -1133,13 +1133,19 @@ void ZONE_CONTAINER::Copy( ZONE_CONTAINER* src )
m_Layer = src->m_Layer;
SetNet( src->GetNet() );
m_TimeStamp = src->m_TimeStamp;
m_Poly->RemoveAllContours();
m_Poly->Copy( src->m_Poly ); // copy outlines
m_CornerSelection = -1; // For corner moving, corner index to drag, or -1 if no selection
m_ZoneClearance = src->m_ZoneClearance; // clearance value
m_FillMode = src->m_FillMode; // Grid used for filling
m_FillMode = src->m_FillMode; // Filling mode (segments/polygons)
m_ArcToSegmentsCount = src->m_ArcToSegmentsCount;
m_PadOption = src->m_PadOption;
m_ThermalReliefGapValue = src->m_ThermalReliefGapValue;
m_ThermalReliefCopperBridgeValue = src->m_ThermalReliefCopperBridgeValue;
m_Poly->SetHatch( src->m_Poly->GetHatchStyle() );
m_FilledPolysList.clear();
m_FilledPolysList = src->m_FilledPolysList;
m_FillSegmList.clear();
m_FillSegmList = src->m_FillSegmList;
}
......
......@@ -42,7 +42,7 @@ public:
int m_ZoneClearance; // clearance value
int m_ZoneMinThickness; // Min thickness value in filled areas
int m_FillMode; // How to fillingareas: 0 = use polygonal areas , != 0 fill with segments
int m_ArcToSegmentsCount; // number of segments to convert a cirlce to a polygon (uses 16 or 32)
int m_ArcToSegmentsCount; // number of segments to convert a circle to a polygon (uses 16 or 32)
int m_PadOption; //
int m_ThermalReliefGapValue; // tickness of the gap in thermal reliefs
int m_ThermalReliefCopperBridgeValue; // tickness of the copper bridge in thermal reliefs
......@@ -369,6 +369,13 @@ public:
{
return m_Poly->GetHatchStyle();
}
/** function IsSame()
* test is 2 zones are equivalent:
* 2 zones are equivalent if they have same parameters and same outlines
* info relative to filling is not take in account
* @param aZoneToCompare = zone to compare with "this"
*/
bool IsSame( const ZONE_CONTAINER &aZoneToCompare);
};
......
......@@ -6,7 +6,7 @@
/// Licence: GNU License
/////////////////////////////////////////////////////////////////////////////
#if defined (__GNUG__) && !defined (NO_GCC_PRAGMA)
#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
#pragma implementation "zones.h"
#endif
......@@ -33,6 +33,8 @@ dialog_copper_zone::dialog_copper_zone( WinEDA_PcbFrame* parent, ZONE_SETTING* z
m_Config = wxGetApp().m_EDA_Config;
m_Zone_Setting = zone_setting;
m_NetSorting = 1; // 0 = alphabetic sort, 1 = pad count sort, and filtering net names
m_OnExitCode = ZONE_ABORT;
if( m_Config )
{
m_NetSorting = m_Config->Read( ZONE_NET_SORT_OPTION_KEY, 1l );
......@@ -207,7 +209,7 @@ void dialog_copper_zone::OnInitDialog( wxInitDialogEvent& event )
void dialog_copper_zone::OnButtonCancelClick( wxCommandEvent& event )
/********************************************************************/
{
EndModal( ZONE_ABORT );
EndModal( m_OnExitCode );
}
......@@ -270,7 +272,7 @@ bool dialog_copper_zone::AcceptOptions( bool aPromptForErrors, bool aUseExportab
// Test if this is a reasonnable value for this parameter
// A too large value can hang pcbnew
#define CLEARANCE_MAX_VALUE 5000 // in 1/10000 inch
if ( m_Zone_Setting->m_ZoneClearance > CLEARANCE_MAX_VALUE )
if( m_Zone_Setting->m_ZoneClearance > CLEARANCE_MAX_VALUE )
{
DisplayError( this, _( "Error : Zone clearance is set to an unreasonnable value" ) );
return false;
......@@ -336,10 +338,10 @@ bool dialog_copper_zone::AcceptOptions( bool aPromptForErrors, bool aUseExportab
return false;
}
if ( ii == 0 ) // the not connected option was selected: this is not a good practice: warn:
if( ii == 0 ) // the not connected option was selected: this is not a good practice: warn:
{
if( ! IsOK( this, _(
"You have chosen the \"not connected\" option. This will create insulated copper islands. Are you sure ?") )
if( !IsOK( this, _(
"You have chosen the \"not connected\" option. This will create insulated copper islands. Are you sure ?" ) )
)
return false;
}
......@@ -351,7 +353,7 @@ bool dialog_copper_zone::AcceptOptions( bool aPromptForErrors, bool aUseExportab
/* Search net_code for this net, if a net was selected */
if( m_ListNetNameSelection->GetSelection() > 0 )
{
NETINFO_ITEM* net = m_Parent->GetBoard()->FindNet(net_name);
NETINFO_ITEM* net = m_Parent->GetBoard()->FindNet( net_name );
if( net )
g_Zone_Default_Setting.m_NetcodeSelection = net->GetNet();
}
......@@ -435,6 +437,7 @@ void dialog_copper_zone::ExportSetupToOtherCopperZones( wxCommandEvent& event )
m_Zone_Setting->ExportSetting( *zone, false ); // false = partiel export
m_Parent->GetScreen()->SetModify();
}
m_OnExitCode = ZONE_EXPORT_VALUES; // values are exported to others zones
}
......
......@@ -6,22 +6,27 @@
#include "dialog_copper_zones_base.h"
/* here is the derivated class from dialog_copper_zone_frame created by wxFormBuilder
*/
class dialog_copper_zone: public dialog_copper_zone_base
*/
class dialog_copper_zone : public dialog_copper_zone_base
{
public:
WinEDA_PcbFrame* m_Parent;
wxConfig* m_Config; // Current config
ZONE_SETTING * m_Zone_Setting;
int m_OnExitCode; /* exit code: ZONE_ABORT if no change,
* ZONE_OK if new values accepted
* ZONE_EXPORT_VALUES if values are exported to others zones
*/
ZONE_SETTING* m_Zone_Setting;
long m_NetSorting;
int m_LayerId[LAYER_COUNT]; // Handle the real layer number from layer name position in m_LayerSelectionCtrl
public:
dialog_copper_zone( WinEDA_PcbFrame* parent, ZONE_SETTING * zone_setting);
dialog_copper_zone( WinEDA_PcbFrame* parent, ZONE_SETTING* zone_setting );
void OnInitDialog( wxInitDialogEvent& event );
void OnButtonOkClick( wxCommandEvent& event );
void OnButtonCancelClick( wxCommandEvent& event );
bool AcceptOptions(bool aPromptForErrors, bool aUseExportableSetupOnly = false);
bool AcceptOptions( bool aPromptForErrors, bool aUseExportableSetupOnly = false );
void OnNetSortingOptionSelected( wxCommandEvent& event );
void ExportSetupToOtherCopperZones( wxCommandEvent& event );
void OnPadsInZoneClick( wxCommandEvent& event );
......
......@@ -66,13 +66,14 @@ public:
public:
DialogPadProperties( WinEDA_BasePcbFrame* parent, D_PAD* Pad, wxDC* DC );
void InitDialog( wxInitDialogEvent& event );
void Init( );
void OnPadShapeSelection( wxCommandEvent& event );
void OnDrillShapeSelected( wxCommandEvent& event );
void PadOrientEvent( wxCommandEvent& event );
void PadTypeSelected( wxCommandEvent& event );
void PadPropertiesAccept( wxCommandEvent& event );
void SetPadLayersList( long layer_mask );
void OnCancelButtonClick( wxCommandEvent& event );
};
......@@ -90,6 +91,12 @@ DialogPadProperties::DialogPadProperties( WinEDA_BasePcbFrame* parent, D_PAD* Pa
Current_PadNetName = m_CurrentPad->GetNetname();
g_Current_PadName = m_CurrentPad->ReturnStringPadName();
}
Init( );
if( GetSizer() )
{
GetSizer()->SetSizeHints( this );
}
}
......@@ -104,7 +111,7 @@ void WinEDA_BasePcbFrame::InstallPadOptionsFrame( D_PAD* Pad, wxDC* DC, const wx
/**************************************************************/
void DialogPadProperties::InitDialog( wxInitDialogEvent& event )
void DialogPadProperties::Init( )
/**************************************************************/
{
int tmp;
......@@ -235,11 +242,6 @@ void DialogPadProperties::InitDialog( wxInitDialogEvent& event )
cmd_event.SetId( m_PadType->GetSelection() );
PadTypeSelected( cmd_event );
}
if( GetSizer() )
{
GetSizer()->SetSizeHints( this );
}
}
......@@ -475,8 +477,8 @@ void DialogPadProperties::PadPropertiesAccept( wxCommandEvent& event )
if( m_CurrentPad ) // Set Pad Name & Num
{
m_Parent->SaveCopyInUndoList( m_Parent->GetBoard()->m_Modules, UR_CHANGED );
MODULE* Module = (MODULE*) m_CurrentPad->GetParent();
m_Parent->SaveCopyInUndoList( Module, UR_CHANGED );
Module->m_LastEdit_Time = time( NULL );
if( m_DC ) // redraw the area where the pad was, without pad (delete pad on screen)
......@@ -580,10 +582,18 @@ void DialogPadProperties::PadPropertiesAccept( wxCommandEvent& event )
m_Parent->GetScreen()->SetModify();
}
Close();
EndModal(1);
if( m_DC )
m_Parent->DrawPanel->CursorOn( m_DC );
if( RastnestIsChanged ) // The net ratsnest must be recalculated
m_Parent->GetBoard()->m_Status_Pcb = 0;
}
/*********************************************************************/
void DialogPadProperties::OnCancelButtonClick( wxCommandEvent& event )
/*********************************************************************/
{
EndModal(0);
}
......@@ -166,21 +166,21 @@ DialogPadPropertiesBase::DialogPadPropertiesBase( wxWindow* parent, wxWindowID i
this->Centre( wxBOTH );
// Connect Events
this->Connect( wxEVT_INIT_DIALOG, wxInitDialogEventHandler( DialogPadPropertiesBase::InitDialog ) );
m_PadShape->Connect( wxEVT_COMMAND_RADIOBOX_SELECTED, wxCommandEventHandler( DialogPadPropertiesBase::OnPadShapeSelection ), NULL, this );
m_DrillShapeCtrl->Connect( wxEVT_COMMAND_RADIOBOX_SELECTED, wxCommandEventHandler( DialogPadPropertiesBase::OnDrillShapeSelected ), NULL, this );
m_PadOrient->Connect( wxEVT_COMMAND_RADIOBOX_SELECTED, wxCommandEventHandler( DialogPadPropertiesBase::PadOrientEvent ), NULL, this );
m_PadType->Connect( wxEVT_COMMAND_RADIOBOX_SELECTED, wxCommandEventHandler( DialogPadPropertiesBase::PadTypeSelected ), NULL, this );
m_buttonOk->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DialogPadPropertiesBase::PadPropertiesAccept ), NULL, this );
m_buttonCancel->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DialogPadPropertiesBase::OnCancelButtonClick ), NULL, this );
}
DialogPadPropertiesBase::~DialogPadPropertiesBase()
{
// Disconnect Events
this->Disconnect( wxEVT_INIT_DIALOG, wxInitDialogEventHandler( DialogPadPropertiesBase::InitDialog ) );
m_PadShape->Disconnect( wxEVT_COMMAND_RADIOBOX_SELECTED, wxCommandEventHandler( DialogPadPropertiesBase::OnPadShapeSelection ), NULL, this );
m_DrillShapeCtrl->Disconnect( wxEVT_COMMAND_RADIOBOX_SELECTED, wxCommandEventHandler( DialogPadPropertiesBase::OnDrillShapeSelected ), NULL, this );
m_PadOrient->Disconnect( wxEVT_COMMAND_RADIOBOX_SELECTED, wxCommandEventHandler( DialogPadPropertiesBase::PadOrientEvent ), NULL, this );
m_PadType->Disconnect( wxEVT_COMMAND_RADIOBOX_SELECTED, wxCommandEventHandler( DialogPadPropertiesBase::PadTypeSelected ), NULL, this );
m_buttonOk->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DialogPadPropertiesBase::PadPropertiesAccept ), NULL, this );
m_buttonCancel->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DialogPadPropertiesBase::OnCancelButtonClick ), NULL, this );
}
......@@ -49,7 +49,7 @@
<event name="OnHibernate"></event>
<event name="OnIconize"></event>
<event name="OnIdle"></event>
<event name="OnInitDialog">InitDialog</event>
<event name="OnInitDialog"></event>
<event name="OnKeyDown"></event>
<event name="OnKeyUp"></event>
<event name="OnKillFocus"></event>
......@@ -760,7 +760,7 @@
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style"></property>
<event name="OnButtonClick"></event>
<event name="OnButtonClick">OnCancelButtonClick</event>
<event name="OnChar"></event>
<event name="OnEnterWindow"></event>
<event name="OnEraseBackground"></event>
......
......@@ -78,12 +78,12 @@ class DialogPadPropertiesBase : public wxDialog
wxCheckBox* m_PadLayerDraft;
// Virtual event handlers, overide them in your derived class
virtual void InitDialog( wxInitDialogEvent& event ){ event.Skip(); }
virtual void OnPadShapeSelection( wxCommandEvent& event ){ event.Skip(); }
virtual void OnDrillShapeSelected( wxCommandEvent& event ){ event.Skip(); }
virtual void PadOrientEvent( wxCommandEvent& event ){ event.Skip(); }
virtual void PadTypeSelected( wxCommandEvent& event ){ event.Skip(); }
virtual void PadPropertiesAccept( wxCommandEvent& event ){ event.Skip(); }
virtual void OnCancelButtonClick( wxCommandEvent& event ){ event.Skip(); }
public:
......
......@@ -609,8 +609,7 @@ void WinEDA_PcbFrame::Process_Special_Functions( wxCommandEvent& event )
*/
zone_cont->Draw( DrawPanel, &dc, GR_XOR );
zone_cont->m_Poly->InsertCorner( zone_cont->m_CornerSelection,
pos.x,
pos.y );
pos.x, pos.y );
zone_cont->m_CornerSelection++;
zone_cont->Draw( DrawPanel, &dc, GR_XOR );
DrawPanel->m_AutoPAN_Request = true;
......@@ -669,7 +668,7 @@ void WinEDA_PcbFrame::Process_Special_Functions( wxCommandEvent& event )
case ID_POPUP_PCB_FILL_ZONE:
DrawPanel->MouseToCursorSchema();
Fill_Zone( NULL, (ZONE_CONTAINER*) GetCurItem() );
Fill_Zone( (ZONE_CONTAINER*) GetCurItem() );
test_1_net_connexion( NULL, ( (ZONE_CONTAINER*) GetCurItem() )->GetNet() );
GetBoard()->DisplayInfo( this );
DrawPanel->Refresh();
......
......@@ -16,9 +16,11 @@
#define ZONE_THERMAL_RELIEF_GAP_STRING_KEY wxT( "Zone_TH_Gap" )
#define ZONE_THERMAL_RELIEF_COPPER_WIDTH_STRING_KEY wxT( "Zone_TH_Copper_Width" )
// Exit codes for dialog edit zones
enum zone_cmd {
ZONE_ABORT,
ZONE_OK
ZONE_ABORT, // if no change
ZONE_OK, // if new values accepted
ZONE_EXPORT_VALUES // if values are exported to others zones
};
......
......@@ -14,10 +14,9 @@
#include "zones.h"
#include "id.h"
#include "protos.h"
#include "zones_functions_for_undo_redo.h"
using namespace std;
bool verbose = false; // false if zone outline diags must not be shown
bool s_Verbose = false; // false if zone outline diags must not be shown
// Outline creation:
static void Abort_Zone_Create_Outline( WinEDA_DrawPanel* Panel, wxDC* DC );
......@@ -35,6 +34,8 @@ static bool s_CornerIsNew; // Used to abort
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
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"
......@@ -91,59 +92,6 @@ void WinEDA_PcbFrame::Add_Zone_Cutout( wxDC* DC, ZONE_CONTAINER* zone_container
}
/**********************************************************************************/
void WinEDA_PcbFrame::Delete_Zone_Fill( 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
*/
{
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 = GetBoard()->m_Zone; zone != NULL; zone = next )
{
next = zone->Next();
if( zone->m_TimeStamp == TimeStamp )
{
modify = TRUE;
/* remove item from linked list and free memory */
zone->DeleteStructure();
}
}
// Now delete the outlines of the corresponding copper areas (deprecated)
for( int ii = 0; ii < GetBoard()->GetAreaCount(); ii++ )
{
ZONE_CONTAINER* zone = GetBoard()->GetArea( ii );
if( zone->m_TimeStamp == TimeStamp )
{
modify = TRUE;
zone->m_FilledPolysList.clear();
zone->m_FillSegmList.clear();
zone->m_IsFilled = false;
}
}
if( modify )
{
GetScreen()->SetModify();
GetScreen()->SetRefreshReq();
}
}
/*******************************************************/
int WinEDA_PcbFrame::Delete_LastCreatedCorner( wxDC* DC )
/*******************************************************/
......@@ -232,6 +180,22 @@ void WinEDA_PcbFrame::Start_Move_Zone_Corner( wxDC* DC, ZONE_CONTAINER* zone_con
Hight_Light( 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->m_Flags = IN_EDIT;
DrawPanel->ManageCurseur = Show_Zone_Corner_Or_Outline_While_Move_Mouse;
DrawPanel->ForceCloseManageCurseur = Abort_Zone_Move_Corner_Or_Outlines;
......@@ -249,7 +213,7 @@ void WinEDA_PcbFrame::Start_Move_Zone_Drag_Outline_Edge( wxDC* DC,
/**************************************************************************************/
/**
* Function Start_Move_Zone_Corner
* Function Start_Move_Zone_Drag_Outline_Edge
* Prepares a drag edge for an existing zone outline,
*/
{
......@@ -260,6 +224,11 @@ void WinEDA_PcbFrame::Start_Move_Zone_Drag_Outline_Edge( wxDC* DC,
s_CursorLastPosition = s_CornerInitialPosition = GetScreen()->m_Curseur;
s_AddCutoutToCurrentZone = false;
s_CurrentZone = NULL;
s_PickedList.ClearListAndDeleteItems();
_AuxiliaryList.ClearListAndDeleteItems();
SaveCopyOfZones(s_PickedList, GetBoard(), zone_container->GetNet(), zone_container->GetLayer() );
}
......@@ -284,6 +253,10 @@ void WinEDA_PcbFrame::Start_Move_Zone_Outlines( wxDC* DC, ZONE_CONTAINER* zone_c
Hight_Light( DC );
}
s_PickedList.ClearListAndDeleteItems();
_AuxiliaryList.ClearListAndDeleteItems();
SaveCopyOfZones(s_PickedList, GetBoard(), zone_container->GetNet(), zone_container->GetLayer() );
zone_container->m_Flags = IS_MOVED;
DrawPanel->ManageCurseur = Show_Zone_Corner_Or_Outline_While_Move_Mouse;
DrawPanel->ForceCloseManageCurseur = Abort_Zone_Move_Corner_Or_Outlines;
......@@ -318,7 +291,7 @@ void WinEDA_PcbFrame::End_Move_Zone_Corner_Or_Outlines( wxDC* DC, ZONE_CONTAINER
/* Combine zones if possible */
wxBusyCursor dummy;
GetBoard()->AreaPolygonModified( zone_container, true, verbose );
GetBoard()->AreaPolygonModified( &_AuxiliaryList, zone_container, true, s_Verbose );
DrawPanel->Refresh();
......@@ -326,6 +299,10 @@ void WinEDA_PcbFrame::End_Move_Zone_Corner_Or_Outlines( wxDC* DC, ZONE_CONTAINER
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 )
{
......@@ -342,7 +319,7 @@ void WinEDA_PcbFrame::Remove_Zone_Corner( wxDC* DC, ZONE_CONTAINER* zone_contain
* 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 DC = Current device context (can be NULL )
* @param zone_container = the zone that contains the selected corner
* the member .m_CornerSelection is used as selected corner
*/
......@@ -369,16 +346,23 @@ void WinEDA_PcbFrame::Remove_Zone_Corner( wxDC* DC, ZONE_CONTAINER* zone_contain
GetBoard()->RedrawFilledAreas( DrawPanel, 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( zone_container, true, verbose );
GetBoard()->AreaPolygonModified( &_AuxiliaryList, zone_container, true, s_Verbose );
if( DC )
{
GetBoard()->RedrawAreasOutlines( DrawPanel, DC, GR_OR, layer );
GetBoard()->RedrawFilledAreas( DrawPanel, 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 anymaore, after combining zones
......@@ -402,8 +386,6 @@ void Abort_Zone_Move_Corner_Or_Outlines( WinEDA_DrawPanel* Panel, wxDC* DC )
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;
......@@ -429,10 +411,10 @@ void Abort_Zone_Move_Corner_Or_Outlines( WinEDA_DrawPanel* Panel, wxDC* DC )
}
}
// zone_container->Draw( Panel, DC, GR_XOR );
_AuxiliaryList.ClearListAndDeleteItems();
s_PickedList. ClearListAndDeleteItems();
Panel->Refresh();
Panel->ManageCurseur = NULL;
Panel->ForceCloseManageCurseur = NULL;
pcbframe->SetCurItem( NULL );
......@@ -644,7 +626,7 @@ bool WinEDA_PcbFrame::End_Zone( wxDC* DC )
if( zone == NULL )
return true;
// Validate the curren outline:
// Validate the current outline:
if( zone->GetNumCorners() <= 2 ) // An outline must have 3 corners or more
{
Abort_Zone_Create_Outline( DrawPanel, DC );
......@@ -678,12 +660,20 @@ bool WinEDA_PcbFrame::End_Zone( wxDC* DC )
GetBoard()->RedrawAreasOutlines( DrawPanel, DC, GR_XOR, layer );
GetBoard()->RedrawFilledAreas( DrawPanel, DC, GR_XOR, layer );
/* Put edges in list */
// 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
{
......@@ -703,7 +693,7 @@ bool WinEDA_PcbFrame::End_Zone( wxDC* DC )
GetScreen()->SetCurItem( NULL ); // This outine can be deleted when merging outlines
// Combine zones if possible :
GetBoard()->AreaPolygonModified( zone, true, verbose );
GetBoard()->AreaPolygonModified( &_AuxiliaryList, zone, true, s_Verbose );
// Redraw the real edge zone :
GetBoard()->RedrawAreasOutlines( DrawPanel, DC, GR_OR, layer );
......@@ -712,12 +702,17 @@ bool WinEDA_PcbFrame::End_Zone( wxDC* DC )
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
GetScreen()->SetModify();
return true;
}
......@@ -727,7 +722,7 @@ bool WinEDA_PcbFrame::End_Zone( wxDC* DC )
static void Show_New_Edge_While_Move_Mouse( WinEDA_DrawPanel* panel, wxDC* DC, bool erase )
/******************************************************************************************/
/* Redraws the edge zone when moving mouse
/* Redraws the zone outlines when moving mouse
*/
{
WinEDA_PcbFrame* pcbframe = (WinEDA_PcbFrame*) panel->m_Parent;
......@@ -772,6 +767,14 @@ void WinEDA_PcbFrame::Edit_Zone_Params( wxDC* DC, ZONE_CONTAINER* zone_container
{
int diag;
DrawPanel->m_IgnoreMouseEvents = 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);
......@@ -786,7 +789,18 @@ void WinEDA_PcbFrame::Edit_Zone_Params( wxDC* DC, ZONE_CONTAINER* zone_container
DrawPanel->m_IgnoreMouseEvents = 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++ )
......@@ -797,16 +811,19 @@ void WinEDA_PcbFrame::Edit_Zone_Params( wxDC* DC, ZONE_CONTAINER* zone_container
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
if( net ) // net == NULL should not occur
zone_container->m_Netname = net->GetNetname();
// Combine zones if possible :
GetBoard()->AreaPolygonModified( zone_container, true, verbose );
GetBoard()->AreaPolygonModified( &_AuxiliaryList, zone_container, true, s_Verbose );
// Redraw the real new zone outlines:
GetBoard()->RedrawAreasOutlines( DrawPanel, 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
GetScreen()->SetModify();
}
......@@ -847,106 +864,3 @@ void WinEDA_PcbFrame::Delete_Zone_Contour( wxDC* DC, ZONE_CONTAINER* zone_contai
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( GetBoard()->ComputeBoundaryBox() == FALSE )
{
if( verbose )
DisplayError( this, wxT( "Board is empty!" ), 10 );
return -1;
}
/* Shows the Net */
g_Zone_Default_Setting.m_NetcodeSelection = zone_container->GetNet();
if( g_HightLigt_Status && (g_HightLigth_NetCode != g_Zone_Default_Setting.m_NetcodeSelection) && DC )
{
Hight_Light( DC ); // Remove old highlight selection
}
g_HightLigth_NetCode = g_Zone_Default_Setting.m_NetcodeSelection;
if( DC )
Hight_Light( DC );
if( g_HightLigth_NetCode > 0 )
{
NETINFO_ITEM* net = GetBoard()->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->GetNetname();
}
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();
Delete_Zone_Fill( NULL, zone_container->m_TimeStamp );
zone_container->BuildFilledPolysListData( GetBoard() );
if ( DC )
DrawPanel->Refresh();
GetScreen()->SetModify();
return error_level;
}
/************************************************************/
int WinEDA_PcbFrame::Fill_All_Zones( bool verbose )
/************************************************************/
/** Function Fill_All_Zones()
* Fill all zones on the board
* The old fillings are removed
* @param verbose = true to show error messages
* @return error level (0 = no error)
*/
{
ZONE_CONTAINER* zone_container;
int error_level = 0;
// Remove all zones :
GetBoard()->m_Zone.DeleteAll();
for( int ii = 0; ii < GetBoard()->GetAreaCount(); ii++ )
{
zone_container = GetBoard()->GetArea( ii );
error_level = Fill_Zone( NULL, zone_container, verbose );
if( error_level && !verbose )
break;
}
test_connexions( NULL );
Tst_Ratsnest( NULL, 0 ); // Recalculate the active ratsnest, i.e. the unconnected links */
DrawPanel->Refresh( true );
return error_level;
}
/////////////////////////////////////////////////////////////////////////////
// Name: zones_by_polygon_fill_functions.cpp
/////////////////////////////////////////////////////////////////////////////
/*
* This program source code file is part of KICAD, a free EDA CAD application.
*
* Copyright (C) 2009 Jean-Pierre Charras <jean-pierre.charras@gipsa-lab.inpg.fr>
* Copyright (C) 2007 Kicad Developers, see change_log.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
*/
#include "fctsys.h"
#include "appl_wxstruct.h"
#include "common.h"
#include "class_drawpanel.h"
#include "pcbnew.h"
#include "wxPcbStruct.h"
#include "zones.h"
/**********************************************************************************/
void WinEDA_PcbFrame::Delete_Zone_Fill( 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
*/
{
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 = GetBoard()->m_Zone; zone != NULL; zone = next )
{
next = zone->Next();
if( zone->m_TimeStamp == TimeStamp )
{
modify = TRUE;
/* remove item from linked list and free memory */
zone->DeleteStructure();
}
}
// Now delete the outlines of the corresponding copper areas (deprecated)
for( int ii = 0; ii < GetBoard()->GetAreaCount(); ii++ )
{
ZONE_CONTAINER* zone = GetBoard()->GetArea( ii );
if( zone->m_TimeStamp == TimeStamp )
{
modify = TRUE;
zone->m_FilledPolysList.clear();
zone->m_FillSegmList.clear();
zone->m_IsFilled = false;
}
}
if( modify )
{
GetScreen()->SetModify();
GetScreen()->SetRefreshReq();
}
}
/***************************************************************************************/
int WinEDA_PcbFrame::Fill_Zone( 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 zone_container = zone to fill
* @param verbose = true to show error messages
* @return error level (0 = no error)
*/
{
wxString msg;
MsgPanel->EraseMsgBox();
if( GetBoard()->ComputeBoundaryBox() == false )
{
if( verbose )
wxMessageBox( wxT( "Board is empty!" ) );
return -1;
}
/* Shows the Net */
g_Zone_Default_Setting.m_NetcodeSelection = zone_container->GetNet();
if( zone_container->GetNet() > 0 )
{
NETINFO_ITEM* net = GetBoard()->FindNet( zone_container->GetNet() );
if( net == NULL )
{
if( verbose )
wxMessageBox( wxT( "Unable to find Net name" ) );
return -2;
}
else
msg = net->GetNetname();
}
else
msg = _( "No Net" );
Affiche_1_Parametre( this, 22, _( "NetName" ), msg, RED );
wxBusyCursor dummy; // Shows an hourglass cursor (removed by its destructor)
zone_container->m_FilledPolysList.clear();
Delete_Zone_Fill( NULL, zone_container->m_TimeStamp );
zone_container->BuildFilledPolysListData( GetBoard() );
GetScreen()->SetModify();
return 0;
}
/************************************************************/
int WinEDA_PcbFrame::Fill_All_Zones( bool verbose )
/************************************************************/
/** Function Fill_All_Zones()
* Fill all zones on the board
* The old fillings are removed
* @param verbose = true to show error messages
* @return error level (0 = no error)
*/
{
ZONE_CONTAINER* zone_container;
int error_level = 0;
// Remove all zones :
GetBoard()->m_Zone.DeleteAll();
for( int ii = 0; ii < GetBoard()->GetAreaCount(); ii++ )
{
zone_container = GetBoard()->GetArea( ii );
error_level = Fill_Zone( zone_container, verbose );
if( error_level && !verbose )
break;
}
test_connexions( NULL );
Tst_Ratsnest( NULL, 0 ); // Recalculate the active ratsnest, i.e. the unconnected links */
DrawPanel->Refresh( true );
return error_level;
}
......@@ -356,8 +356,8 @@ void ZONE_CONTAINER::AddClearanceAreasPolygonsToPolysList( BOARD* aPcb )
}
// Now we remove all unused thermal stubs.
//define REMOVE_UNUSED_THERMAL_STUBS // Can be commented to skip unused thermal stubs calculations
//#ifdef REMOVE_UNUSED_THERMAL_STUBS
#define REMOVE_UNUSED_THERMAL_STUBS // Can be commented to skip unused thermal stubs calculations
#ifdef REMOVE_UNUSED_THERMAL_STUBS
/* Add the main (corrected) polygon (i.e. the filled area using only one outline)
* in GroupA in Bool_Engine to do a BOOL_A_SUB_B operation
......@@ -500,7 +500,7 @@ void ZONE_CONTAINER::AddClearanceAreasPolygonsToPolysList( BOARD* aPcb )
delete booleng;
//#endif
#endif
}
......@@ -807,7 +807,7 @@ void AddThermalReliefPadPolygon( Bool_Engine* aBooleng,
// this seems a bug in kbool polygon (exists in 1.9 kbool version)
// angle = 450 (45.0 degrees orientation) seems work fine.
// angle = 0 with thermal shapes without angle < 90 deg has problems in rare circumstances
// Note: with the 2 step build ( thermal shpaes after correr areas build), 0 seems work
// Note: with the 2 step build ( thermal shapes added after areas are built), 0 seems work
angle = 450;
int angle_pad = aPad.m_Orient; // Pad orientation
for( unsigned ihole = 0; ihole < 4; ihole++ )
......
/////////////////////////////////////////////////////////////////////////////
// Name: zones_functions_for_undo_redo.cpp
/////////////////////////////////////////////////////////////////////////////
/*
* This program source code file is part of KICAD, a free EDA CAD application.
*
* Copyright (C) 2009 Jean-Pierre Charras <jean-pierre.charras@gipsa-lab.inpg.fr>
* Copyright (C) 2007 Kicad Developers, see change_log.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
*/
/* These functions are relative to undo redo function, when zones are involved.
* When a zone outline is modified (or created) this zone, or others zones on the same layer
* and with the same netcode can change or can be deleted
* This is due to the fact overlapping zones are merged
* Also, when a zone outline is modified by adding a cutout area,
* this zone can be converted to more than one area, if the outline is break to 2 or more outlines
* and therefore new zones are created
*
* Due to the complexity of potential changes, and the fact there are only few zones
* in a board, and a zone has only few segments outlines, the more easy way to
* undo redo changes is to make a copy of all zones that can be changed
* and see after zone edition or creation what zones that are really modified,
* and ones they are modified (changes, deletion or addition)
*/
#include "fctsys.h"
#include "appl_wxstruct.h"
#include "common.h"
#include "class_drawpanel.h"
#include "pcbnew.h"
#include "wxPcbStruct.h"
#include "zones.h"
#include "zones_functions_for_undo_redo.h"
/** function ZONE_CONTAINER::IsSame()
* test is 2 zones are equivalent:
* 2 zones are equivalent if they have same parameters and same outlines
* info relative to filling is not take in account
* @param aZoneToCompare = zone to compare with "this"
*/
bool ZONE_CONTAINER::IsSame( const ZONE_CONTAINER& aZoneToCompare )
{
// compare basic parameters:
if( GetLayer() != aZoneToCompare.GetLayer() )
return false;
if( m_Netname != aZoneToCompare.m_Netname )
return false;
// Compare zone specfic parameters
if( m_ZoneClearance != aZoneToCompare.m_ZoneClearance )
return false;
if( m_ZoneMinThickness != aZoneToCompare.m_ZoneMinThickness )
return false;
if( m_FillMode != aZoneToCompare.m_FillMode )
return false;
if( m_ArcToSegmentsCount != aZoneToCompare.m_ArcToSegmentsCount )
return false;
if( m_PadOption != aZoneToCompare.m_PadOption )
return false;
if( m_ThermalReliefGapValue != aZoneToCompare.m_ThermalReliefGapValue )
return false;
if( m_ThermalReliefCopperBridgeValue != aZoneToCompare.m_ThermalReliefCopperBridgeValue )
return false;
// Compare outlines
wxASSERT( m_Poly ); // m_Poly == NULL Should never happen
wxASSERT( aZoneToCompare.m_Poly );
if( m_Poly->corner != aZoneToCompare.m_Poly->corner ) // Compare vector
return false;
return true;
}
/** function SaveCopyOfZones()
* creates a copy of zones having a given netcode on a given layer,
* and fill a pick list with pickers to handle these copies
* the UndoRedo status is set to UR_CHANGED for all items in list
* Later, UpdateCopyOfZonesList will change and update these pickers after a zone edition
* @param aPickList = the pick list
* @param aPcb = the Board
* @param aNetCode = the reference netcode. if aNetCode < 0 all netcodes are used
* @param aLayer = the layer of zones. if aLayer < 0, all layers are used
* @return the count of saved copies
*/
int SaveCopyOfZones( PICKED_ITEMS_LIST& aPickList, BOARD* aPcb, int aNetCode, int aLayer )
{
int copyCount = 0;
for( unsigned ii = 0; ; ii++ )
{
ZONE_CONTAINER* zone = aPcb->GetArea( ii );
if( zone == NULL ) // End of list
break;
if( aNetCode >= 0 && aNetCode != zone->GetNet() )
continue;
if( aLayer >= 0 && aLayer != zone->GetLayer() )
continue;
ZONE_CONTAINER* zoneDup = new ZONE_CONTAINER( aPcb );
zoneDup->Copy( zone );
ITEM_PICKER picker( zone, UR_CHANGED );
picker.m_Link = zoneDup;
picker.m_PickedItemType = zone->Type();
aPickList.PushItem( picker );
copyCount++;
}
return copyCount;
}
/** function UpdateCopyOfZonesList()
* check a pick list to remove zones identical to their copies
* and set the type of operation in picker (UR_DELETED, UR_CHANGED)
* if an item is deleted, the initial values are retrievered,
* because they can have changed in edition
* @param aPickList = the main pick list
* @param aAuxiliaryList = the list of deleted or added (new created) items after calculations
* @param aPcb = the Board
*
* aAuxiliaryList is a list of pickers updated by zone algorithms:
* In this list are put zone taht were added or deleted during the zone combine process
* aPickList :is a list of zone that can be modified (changed or deleted, or not modified)
* >> if the picked zone is not changed, it is removed from list
* >> if the picked zone was deleted (i.e. not found in boad list), the picker is modified:
* - its status becomes UR_DELETED
* - the aAuxiliaryList corresponding picker is removed (if not found : set an error)
* >> if the picked zone was flagged as UR_NEW, and was deleted (i.e. not found in boad list),
* - the picker is removed
* - the zone itself if really deleted
* - the aAuxiliaryList corresponding picker is removed (if not found : set an error)
* After aPickList is cleaned, the aAuxiliaryList is read
* All pickers flagged UR_NEW are moved to aPickList
* (the corresponding zones are zone that were created by the zone combine process, mainly when adding cutaout areas)
* At the end of the update process the aAuxiliaryList must be void, because all pickers created by the combine process
* must have been removed (removed for new and deleted zones, or moved in aPickList.)
* If not an error is set.
*/
void UpdateCopyOfZonesList( PICKED_ITEMS_LIST& aPickList,
PICKED_ITEMS_LIST& aAuxiliaryList,
BOARD* aPcb )
{
for( unsigned kk = 0; kk < aPickList.GetCount(); kk++ )
{
UndoRedoOpType status = aPickList.GetPickedItemStatus( kk );
ZONE_CONTAINER* ref = (ZONE_CONTAINER*) aPickList.GetPickedItem( kk );
for( unsigned ii = 0; ; ii++ ) // analyse the main picked list
{
ZONE_CONTAINER* zone = aPcb->GetArea( ii );
if( zone == NULL )
{
/* End of list: the stored item is not found:
* it must be in aDeletedList:
* search it and restore initial values
* or
* if flagged UR_NEW: remove it definitively
*/
if( status == UR_NEW )
{
delete ref;
aPickList.RemovePicker( kk );
kk--;
}
else
{
ZONE_CONTAINER* zcopy = (ZONE_CONTAINER*) aPickList.GetPickedItemLink( kk );
aPickList.SetPickedItemStatus( UR_DELETED, kk );
if( zcopy )
ref->Copy( zcopy );
else
wxMessageBox( wxT( "UpdateCopyOfZonesList() error: link = NULL" ) );
aPickList.SetPickedItemLink( NULL, kk ); // the copy was deleted; the link does not exists now
delete zcopy;
}
// Remove this item from aAuxiliaryList, mainly for tests purpose
bool notfound = true;
for( unsigned nn = 0; nn < aAuxiliaryList.GetCount(); nn++ )
{
if( aAuxiliaryList.GetPickedItem( nn ) == ref )
{
aAuxiliaryList.RemovePicker( nn );
notfound = false;
break;
}
}
if( notfound )
wxMessageBox( wxT(
"UpdateCopyOfZonesList() error: item not found in aAuxiliaryList" ) );
break;
}
if( zone == ref ) // picked zone found
{
if( aPickList.GetPickedItemStatus( kk ) != UR_NEW )
{
ZONE_CONTAINER* zcopy = (ZONE_CONTAINER*) aPickList.GetPickedItemLink( kk );
if( zone->IsSame( *zcopy ) ) // Remove picked, because no changes
{
delete zcopy; // Delete copy
aPickList.RemovePicker( kk );
kk--;
}
}
break;
}
}
}
// Add new zones in main pick list, and remove pickers from Auxiliary List
for( unsigned ii = 0; ii < aAuxiliaryList.GetCount(); ii++ )
{
if( aAuxiliaryList.GetPickedItemStatus( ii ) == UR_NEW )
{
ITEM_PICKER picker = aAuxiliaryList.GetItemWrapper( ii );
aPickList.PushItem( picker );
aAuxiliaryList.RemovePicker( ii );
ii--;
}
}
// Should not occur:
if( aAuxiliaryList.GetCount()> 0 )
{
wxString msg;
msg.Printf( wxT(
"UpdateCopyOfZonesList() error: aAuxiliaryList not void: %d item left (status %d)" ),
aAuxiliaryList.GetCount(), aAuxiliaryList.GetPickedItemStatus( 0 ) );
wxMessageBox( msg );
while( aAuxiliaryList.GetCount()> 0 )
{
delete aAuxiliaryList.GetPickedItemLink( 0 );
aAuxiliaryList.RemovePicker( 0 );
}
}
}
/////////////////////////////////////////////////////////////////////////////
// Name: zones_functions_for_undo_redo.h
/////////////////////////////////////////////////////////////////////////////
/*
* This program source code file is part of KICAD, a free EDA CAD application.
*
* Copyright (C) 2009 Jean-Pierre Charras <jean-pierre.charras@gipsa-lab.inpg.fr>
* Copyright (C) 2007 Kicad Developers, see change_log.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
*/
/* These functions are relative to undo redo function, when zones are involved.
* When a zone outline is modified (or created) this zone, or others zones on the same layer
* and with the same netcode can change or can be deleted
* This is due to the fact overlapping zones are merged
* Also, when a zone outline is modified by adding a cutout area,
* this zone can be converted to more than one area, if the outline is break to 2 or more outlines
* and therefore new zones are created
*
* Due to the complexity of potential changes, and the fact there are only few zones
* in a board, and a zone has only few segments outlines, the more easy way to
* undo redo changes is to make a copy of all zones that can be changed
* and see after zone edition or creation what zones that are really modified,
* and ones they are modified (changes, deletion or addition)
*/
#ifndef ZONES_FUNCTIONS_TO_UNDO_REDO_H
#define ZONES_FUNCTIONS_TO_UNDO_REDO_H
/** function SaveCopyOfZones()
* creates a copy of zones having a given netcode on a given layer,
* and fill a pick list with pickers to handle these copies
* @param aPickList = the pick list
* @param aPcb = the Board
* @param aNetCode = the reference netcode. if aNetCode < 0 all netcodes are used
* @param aLayer = the layer of zones. if aLayer < 0, all layers are used
* @return the count of saved copies
*/
int SaveCopyOfZones(PICKED_ITEMS_LIST & aPickList, BOARD* aPcb, int aNetCode, int aLayer );
/** function UpdateCopyOfZonesList()
* check a pick list to remove zones identical to their copies
* and set the type of operation in picker (UR_DELETED, UR_CHANGED)
* @param aPickList = the main pick list
* @param aDeletedList = the list of dleted items
* @param aPcb = the Board
*/
void UpdateCopyOfZonesList( PICKED_ITEMS_LIST& aPickList, PICKED_ITEMS_LIST& aDeletedList, BOARD* aPcb );
#endif // ZONES_FUNCTIONS_TO_UNDO_REDO_H
......@@ -18,29 +18,52 @@ bool bDontShowIntersectionArcsWarning;
bool bDontShowIntersectionWarning;
/**
* Function AddArea
* add empty copper area to net
/** Function AddArea
* Add an empty copper area to board areas list
* @param aNewZonesList = a PICKED_ITEMS_LIST * where to store new areas pickers (useful in undo commands)
* can be NULL
* @param aNetcode = the necode of the copper area (0 = no net)
* @param aLayer = the layer of area
* @param aStartPointPosition = position of the first point of the polygon outline of this area
* @param aHatch = hacth option
* @return pointer to the new area
*/
ZONE_CONTAINER* BOARD::AddArea( int netcode, int layer, int x, int y, int hatch )
ZONE_CONTAINER* BOARD::AddArea( PICKED_ITEMS_LIST* aNewZonesList, int aNetcode,
int aLayer, wxPoint aStartPointPosition, int aHatch )
{
ZONE_CONTAINER* new_area = InsertArea( netcode, m_ZoneDescriptorList.size(
) - 1, layer, x, y, hatch );
ZONE_CONTAINER* new_area = InsertArea( aNetcode,
m_ZoneDescriptorList.size( ) - 1,
aLayer, aStartPointPosition.x, aStartPointPosition.y, aHatch );
if( aNewZonesList )
{
ITEM_PICKER picker( new_area, UR_NEW );
picker.m_PickedItemType = new_area->Type();
aNewZonesList->PushItem( picker );
}
return new_area;
}
/**
* remove copper area from net
* @param area = area to remove
* @return 0
/** Function RemoveArea
* remove copper area from net, and put it in a deleted list (if exists)
* @param aDeletedList = a PICKED_ITEMS_LIST * where to store deleted areas (useful in undo commands)
* can be NULL
* @param area_to_remove = area to delete or put in deleted list
*/
int BOARD::RemoveArea( ZONE_CONTAINER* area_to_remove )
void BOARD::RemoveArea( PICKED_ITEMS_LIST* aDeletedList, ZONE_CONTAINER* area_to_remove )
{
if( area_to_remove == NULL )
return;
if( aDeletedList )
{
ITEM_PICKER picker( area_to_remove, UR_DELETED );
picker.m_PickedItemType = area_to_remove->Type();
aDeletedList->PushItem( picker );
Remove( area_to_remove ); // remove from zone list, but does not delete it
}
else
Delete( area_to_remove );
return 0;
}
......@@ -82,9 +105,8 @@ int BOARD::CompleteArea( ZONE_CONTAINER* area_to_complete, int style )
return 1;
}
else
{
RemoveArea( area_to_complete );
}
Delete( area_to_complete );
return 0;
}
......@@ -206,19 +228,24 @@ int BOARD::TestAreaPolygon( ZONE_CONTAINER* CurrArea )
* Function ClipAreaPolygon
* Process an area that has been modified, by clipping its polygon against itself.
* This may change the number and order of copper areas in the net.
* @param aNewZonesList = a PICKED_ITEMS_LIST * where to store new areas pickers (useful in undo commands)
* can be NULL
* @param aCurrArea = the zone to process
* @param bMessageBoxInt == true, shows message when clipping occurs.
* @param bMessageBoxArc == true, shows message when clipping can't be done due to arcs.
* @param bRetainArcs = true to handle arcs (not really used in kicad)
* @return:
* -1 if arcs intersect other sides, so polygon can't be clipped
* 0 if no intersecting sides
* 1 if intersecting sides
* Also sets areas->utility1 flags if areas are modified
*/
int BOARD::ClipAreaPolygon( ZONE_CONTAINER* CurrArea,
int BOARD::ClipAreaPolygon( PICKED_ITEMS_LIST * aNewZonesList,
ZONE_CONTAINER* aCurrArea,
bool bMessageBoxArc, bool bMessageBoxInt, bool bRetainArcs )
{
CPolyLine* curr_polygon = CurrArea->m_Poly;
int test = TestAreaPolygon( CurrArea ); // this sets utility2 flag
CPolyLine* curr_polygon = aCurrArea->m_Poly;
int test = TestAreaPolygon( aCurrArea ); // this sets utility2 flag
if( test == -1 && !bRetainArcs )
test = 1;
......@@ -229,7 +256,7 @@ int BOARD::ClipAreaPolygon( ZONE_CONTAINER* CurrArea,
{
wxString str;
str.Printf( wxT( "Area %8.8X of net \"%s\" has arcs intersecting other sides.\n" ),
CurrArea->m_TimeStamp, CurrArea->m_Netname.GetData() );
aCurrArea->m_TimeStamp, aCurrArea->m_Netname.GetData() );
str += wxT( "This may cause problems with other editing operations,\n" );
str += wxT( "such as adding cutouts. It can't be fixed automatically.\n" );
str += wxT( "Manual correction is recommended." );
......@@ -242,7 +269,7 @@ int BOARD::ClipAreaPolygon( ZONE_CONTAINER* CurrArea,
for( unsigned ia = 0; ia < m_ZoneDescriptorList.size(); ia++ )
m_ZoneDescriptorList[ia]->utility = 0;
CurrArea->utility = 1;
aCurrArea->utility = 1;
if( test == 1 )
{
......@@ -252,7 +279,7 @@ int BOARD::ClipAreaPolygon( ZONE_CONTAINER* CurrArea,
wxString str;
str.Printf( wxT(
"Area %8.8X of net \"%s\" is self-intersecting and will be clipped.\n" ),
CurrArea->m_TimeStamp, CurrArea->m_Netname.GetData() );
aCurrArea->m_TimeStamp, aCurrArea->m_Netname.GetData() );
str += wxT( "This may result in splitting the area.\n" );
str += wxT( "If the area is complex, this may take a few seconds." );
wxMessageBox( str );
......@@ -266,7 +293,7 @@ int BOARD::ClipAreaPolygon( ZONE_CONTAINER* CurrArea,
{
std::vector<CPolyLine*>* pa = new std::vector<CPolyLine*>;
curr_polygon->Undraw();
int n_poly = CurrArea->m_Poly->NormalizeAreaOutlines( pa, bRetainArcs );
int n_poly = aCurrArea->m_Poly->NormalizeAreaOutlines( pa, bRetainArcs );
if( n_poly > 1 ) // i.e if clipping has created some polygons, we must add these new copper areas
{
ZONE_CONTAINER* NewArea;
......@@ -274,7 +301,8 @@ int BOARD::ClipAreaPolygon( ZONE_CONTAINER* CurrArea,
{
// create new copper area and copy poly into it
CPolyLine* new_p = (*pa)[ip - 1];
NewArea = AddArea( CurrArea->GetNet(), CurrArea->GetLayer(), 0, 0, 0 );
NewArea = AddArea( aNewZonesList, aCurrArea->GetNet(), aCurrArea->GetLayer(),
wxPoint(0, 0), CPolyLine::NO_HATCH );
// remove the poly that was automatically created for the new area
// and replace it with a poly from NormalizeWithKbool
......@@ -295,6 +323,8 @@ int BOARD::ClipAreaPolygon( ZONE_CONTAINER* CurrArea,
* Process an area that has been modified, by clipping its polygon against
* itself and the polygons for any other areas on the same net.
* This may change the number and order of copper areas in the net.
* @param aModifiedZonesList = a PICKED_ITEMS_LIST * where to store deleted or added areas (useful in undo commands
* can be NULL
* @param modified_area = area to test
* @param bMessageBoxInt == true, shows message when clipping occurs.
* @param bMessageBoxArc == true, shows message when clipping can't be done due to arcs.
......@@ -303,12 +333,13 @@ int BOARD::ClipAreaPolygon( ZONE_CONTAINER* CurrArea,
* 0 if no intersecting sides
* 1 if intersecting sides, polygon clipped
*/
int BOARD::AreaPolygonModified( ZONE_CONTAINER* modified_area,
int BOARD::AreaPolygonModified( PICKED_ITEMS_LIST* aModifiedZonesList,
ZONE_CONTAINER* modified_area,
bool bMessageBoxArc,
bool bMessageBoxInt )
{
// clip polygon against itself
int test = ClipAreaPolygon( modified_area, bMessageBoxArc, bMessageBoxInt );
int test = ClipAreaPolygon( aModifiedZonesList, modified_area, bMessageBoxArc, bMessageBoxInt );
if( test == -1 )
return test;
......@@ -321,7 +352,7 @@ int BOARD::AreaPolygonModified( ZONE_CONTAINER* modified_area,
else
bCheckAllAreas = TestAreaIntersections( modified_area );
if( bCheckAllAreas )
CombineAllAreasInNet( modified_area->GetNet(), bMessageBoxInt, true );
CombineAllAreasInNet( aModifiedZonesList, modified_area->GetNet(), bMessageBoxInt, true );
if( layer >= FIRST_NO_COPPER_LAYER ) // Refill non copper zones on this layer
{
......@@ -343,7 +374,7 @@ int BOARD::AreaPolygonModified( ZONE_CONTAINER* modified_area,
// Remove zone because it is incorrect:
else
RemoveArea( zone );
RemoveArea( aModifiedZonesList, zone );
}
return test;
......@@ -353,13 +384,15 @@ int BOARD::AreaPolygonModified( ZONE_CONTAINER* modified_area,
/**
* Function CombineAllAreasInNet
* Checks all copper areas in net for intersections, combining them if found
* @param aDeletedList = a PICKED_ITEMS_LIST * where to store deleted areas (useful in undo commands
* can be NULL
* @param aNetCode = net to consider
* @param bMessageBox : if true display warning message box
* @param bUseUtility : if true, don't check areas if both utility flags are 0
* Sets utility flag = 1 for any areas modified
* If an area has self-intersecting arcs, doesn't try to combine it
*/
int BOARD::CombineAllAreasInNet( int aNetCode, bool bMessageBox, bool bUseUtility )
int BOARD::CombineAllAreasInNet( PICKED_ITEMS_LIST* aDeletedList, int aNetCode, bool bMessageBox, bool bUseUtility )
{
if( m_ZoneDescriptorList.size() <= 1 )
return 0;
......@@ -397,7 +430,7 @@ int BOARD::CombineAllAreasInNet( int aNetCode, bool bMessageBox, bool bUseUtilit
{
int ret = TestAreaIntersection( curr_area, area2 );
if( ret == 1 )
ret = CombineAreas( curr_area, area2 );
ret = CombineAreas( aDeletedList, curr_area, area2 );
if( ret == 1 )
{
mod_ia1 = true;
......@@ -671,13 +704,17 @@ int BOARD::TestAreaIntersection( ZONE_CONTAINER* area_ref, ZONE_CONTAINER* area_
/**
* Function CombineAreas
* If possible, combine 2 copper areas
* area_ref must be BEFORE area_to_combine in m_ZoneDescriptorList
* @param aDeletedList = a PICKED_ITEMS_LIST * where to store deleted areas (useful in undo commands
* can be NULL
* @param area_ref = tje main area (zone)
* @param area_to_combine = the zone that can be merged with area_ref
* area_ref must be BEFORE area_to_combine
* area_to_combine will be deleted, if areas are combined
* @return : 0 if no intersection
* 1 if intersection
* 2 if arcs intersect
*/
int BOARD::CombineAreas( ZONE_CONTAINER* area_ref, ZONE_CONTAINER* area_to_combine )
int BOARD::CombineAreas( PICKED_ITEMS_LIST* aDeletedList, ZONE_CONTAINER* area_ref, ZONE_CONTAINER* area_to_combine )
{
if( area_ref == area_to_combine )
{
......@@ -780,7 +817,7 @@ int BOARD::CombineAreas( ZONE_CONTAINER* area_ref, ZONE_CONTAINER* area_to_combi
}
if( !keep_area_to_combine )
RemoveArea( area_to_combine );
RemoveArea( aDeletedList, area_to_combine );
area_ref->utility = 1;
area_ref->m_Poly->RestoreArcs( &arc_array1 );
......
......@@ -1489,14 +1489,11 @@ bool CPolyLine::TestPointInsideContour( int icont, int px, int py )
void CPolyLine::Copy( CPolyLine* src )
{
Undraw();
// copy corners
for( unsigned ii = 0; ii < src->corner.size(); ii++ )
corner.push_back( src->corner[ii] );
// copy side styles
for( unsigned ii = 0; ii < src->side_style.size(); ii++ )
side_style.push_back( src->side_style[ii] );
m_HatchStyle = src->m_HatchStyle;
// copy corners, using vector copy
corner = src->corner;
// copy side styles, using vector copy
side_style = src->side_style;
}
......
......@@ -102,6 +102,12 @@ public:
int y;
bool end_contour;
int utility;
bool operator == (const CPolyPt& cpt2 ) const
{ return (x == cpt2.x) && (y == cpt2.y) && (end_contour == cpt2.end_contour); }
bool operator != (CPolyPt& cpt2 ) const
{ return (x != cpt2.x) || (y != cpt2.y) || (end_contour != cpt2.end_contour); }
};
#include "polygon_test_point_inside.h"
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment