KiCad PCB EDA Suite
zone_create_helper.cpp
Go to the documentation of this file.
1 /*
2  * This program source code file is part of KiCad, a free EDA CAD application.
3  *
4  * Copyright (C) 2017-2019 KiCad Developers, see AUTHORS.txt for contributors.
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, you may find one here:
18  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
19  * or you may search the http://www.gnu.org website for the version 2 license,
20  * or you may write to the Free Software Foundation, Inc.,
21  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
22  */
23 
25 #include <tool/tool_manager.h>
26 #include <class_zone.h>
27 #include <pcb_shape.h>
28 #include <fp_shape.h>
29 #include <board_commit.h>
30 #include <pcb_painter.h>
31 #include <tools/pcb_actions.h>
32 #include <tools/selection_tool.h>
33 #include <zone_filler.h>
34 
36  m_tool( aTool ),
37  m_params( aParams ),
38  m_parentView( *aTool.getView() )
39 {
41 }
42 
43 
45 {
46  // remove the preview from the view
49 }
50 
51 
52 std::unique_ptr<ZONE_CONTAINER> ZONE_CREATE_HELPER::createNewZone( bool aKeepout )
53 {
55  BOARD* board = frame->GetBoard();
58  std::set<int> highlightedNets = board->GetHighLightNetCodes();
59 
60  // Get the current default settings for zones
61  ZONE_SETTINGS zoneInfo = frame->GetZoneSettings();
62  zoneInfo.m_Layers.reset().set( m_params.m_layer ); // TODO(JE) multilayer defaults?
63  zoneInfo.m_NetcodeSelection = highlightedNets.empty() ? -1 : *highlightedNets.begin();
64  zoneInfo.SetIsRuleArea( m_params.m_keepout );
66 
67  // If we don't have a net from highlighing, maybe we can get one from the selection
68  SELECTION_TOOL* selectionTool = m_tool.GetManager()->GetTool<SELECTION_TOOL>();
69 
70  if( selectionTool && !selectionTool->GetSelection().Empty()
71  && zoneInfo.m_NetcodeSelection == -1 )
72  {
73  EDA_ITEM* item = *selectionTool->GetSelection().GetItems().begin();
74 
75  if( BOARD_CONNECTED_ITEM* bci = dynamic_cast<BOARD_CONNECTED_ITEM*>( item ) )
76  zoneInfo.m_NetcodeSelection = bci->GetNetCode();
77  }
78 
80  {
81  // Get the current default settings for zones
82 
83  // Show options dialog
84  int dialogResult;
85 
86  if( m_params.m_keepout )
87  dialogResult = InvokeRuleAreaEditor( frame, &zoneInfo );
88  else
89  {
90  // TODO(JE) combine these dialogs?
91  if( ( zoneInfo.m_Layers & LSET::AllCuMask() ).any() )
92  dialogResult = InvokeCopperZonesEditor( frame, &zoneInfo );
93  else
94  dialogResult = InvokeNonCopperZonesEditor( frame, &zoneInfo );
95  }
96 
97  if( dialogResult == wxID_CANCEL )
98  return nullptr;
99 
100  controls->WarpCursor( controls->GetCursorPosition(), true );
101  }
102 
103  // The new zone is a ZONE_CONTAINER if created in the board editor
104  // and a MODULE_ZONE_CONTAINER if created in the footprint editor
105  wxASSERT( !m_tool.m_editModules || ( parent->Type() == PCB_MODULE_T ) );
106 
107  std::unique_ptr<ZONE_CONTAINER> newZone = m_tool.m_editModules ?
108  std::make_unique<MODULE_ZONE_CONTAINER>( parent ) :
109  std::make_unique<ZONE_CONTAINER>( parent );
110 
111  // Apply the selected settings
112  zoneInfo.ExportSetting( *newZone );
113 
114  return newZone;
115 }
116 
117 
118 std::unique_ptr<ZONE_CONTAINER> ZONE_CREATE_HELPER::createZoneFromExisting(
119  const ZONE_CONTAINER& aSrcZone )
120 {
121  auto& board = *m_tool.getModel<BOARD>();
122 
123  auto newZone = std::make_unique<ZONE_CONTAINER>( &board );
124 
125  ZONE_SETTINGS zoneSettings;
126  zoneSettings << aSrcZone;
127 
128  zoneSettings.ExportSetting( *newZone );
129 
130  return newZone;
131 }
132 
133 
135 {
136  BOARD_COMMIT commit( &m_tool );
137  BOARD* board = m_tool.getModel<BOARD>();
138  std::vector<ZONE_CONTAINER*> newZones;
139 
140  // Clear the selection before removing the old zone
141  auto toolMgr = m_tool.GetManager();
142  toolMgr->RunAction( PCB_ACTIONS::selectionClear, true );
143 
144  SHAPE_POLY_SET originalOutline( *aZone.Outline() );
145  originalOutline.BooleanSubtract( *aCutout.Outline(), SHAPE_POLY_SET::PM_FAST );
146 
147  // After substracting the hole, originalOutline can have more than one
148  // main outline.
149  // But a zone can have only one main outline, so create as many zones as
150  // originalOutline contains main outlines:
151  for( int outline = 0; outline < originalOutline.OutlineCount(); outline++ )
152  {
153  auto newZoneOutline = new SHAPE_POLY_SET;
154  newZoneOutline->AddOutline( originalOutline.Outline( outline ) );
155 
156  // Add holes (if any) to thez new zone outline:
157  for (int hole = 0; hole < originalOutline.HoleCount( outline ) ; hole++ )
158  newZoneOutline->AddHole( originalOutline.CHole( outline, hole ) );
159 
160  auto newZone = new ZONE_CONTAINER( aZone );
161  newZone->SetOutline( newZoneOutline );
162  newZone->SetLocalFlags( 1 );
163  newZone->HatchBorder();
164  newZones.push_back( newZone );
165  commit.Add( newZone );
166  }
167 
168  commit.Remove( &aZone );
169 
170  ZONE_FILLER filler( board, &commit );
171 
172  if( !filler.Fill( newZones ) )
173  {
174  commit.Revert();
175  return;
176  }
177 
178  commit.Push( _( "Add a zone cutout" ) );
179 
180  // Select the new zone and set it as the source for the next cutout
181  if( newZones.empty() )
182  {
183  m_params.m_sourceZone = nullptr;
184  }
185  else
186  {
187  m_params.m_sourceZone = newZones[0];
188  toolMgr->RunAction( PCB_ACTIONS::selectItem, true, newZones[0] );
189  }
190 
191 }
192 
193 
194 void ZONE_CREATE_HELPER::commitZone( std::unique_ptr<ZONE_CONTAINER> aZone )
195 {
196  switch ( m_params.m_mode )
197  {
198  case ZONE_MODE::CUTOUT:
199  // For cutouts, subtract from the source
201  break;
202 
203  case ZONE_MODE::ADD:
204  case ZONE_MODE::SIMILAR:
205  {
206  BOARD_COMMIT bCommit( &m_tool );
207 
208  aZone->HatchBorder();
209  bCommit.Add( aZone.get() );
210 
211  if( !m_params.m_keepout )
212  {
213  ZONE_FILLER filler( m_tool.getModel<BOARD>(), &bCommit );
214  std::vector<ZONE_CONTAINER*> toFill = { aZone.get() };
215 
216  if( !filler.Fill( toFill ) )
217  {
218  bCommit.Revert();
219  break;
220  }
221  }
222 
223  bCommit.Push( _( "Add a zone" ) );
224  m_tool.GetManager()->RunAction( PCB_ACTIONS::selectItem, true, aZone.release() );
225  break;
226  }
227 
229  {
230  BOARD_COMMIT bCommit( &m_tool );
232  LSET graphicPolygonsLayers = LSET::AllLayersMask();
233 
234  graphicPolygonsLayers.reset( Edge_Cuts ).reset( F_CrtYd ).reset( B_CrtYd );
235 
236  if( graphicPolygonsLayers.Contains( m_params.m_layer ) )
237  {
238  auto poly = m_tool.m_editModules ? new FP_SHAPE((MODULE *) parent )
239  : new PCB_SHAPE();
240  poly->SetShape ( S_POLYGON );
241  poly->SetLayer( m_params.m_layer );
242  poly->SetPolyShape ( *aZone->Outline() );
243  bCommit.Add( poly );
245  }
246  else
247  {
248  SHAPE_POLY_SET* outline = aZone->Outline();
249 
250  for( auto seg = outline->CIterateSegments( 0 ); seg; seg++ )
251  {
252  PCB_SHAPE* new_seg = m_tool.m_editModules ? new FP_SHAPE( (MODULE *) parent )
253  : new PCB_SHAPE();
254  new_seg->SetShape( S_SEGMENT );
255  new_seg->SetLayer( m_params.m_layer );
256  new_seg->SetStart( wxPoint( seg.Get().A.x, seg.Get().A.y ) );
257  new_seg->SetEnd( wxPoint( seg.Get().B.x, seg.Get().B.y ) );
258  bCommit.Add( new_seg );
259  }
260  }
261 
262  bCommit.Push( _( "Add a graphical polygon" ) );
263 
264  break;
265  }
266  }
267 }
268 
269 
271 {
272  // if we don't have a zone, create one
273  // the user's choice here can affect things like the colour of the preview
274  if( !m_zone )
275  {
276  if( m_params.m_sourceZone )
278  else
280 
281  if( m_zone )
282  {
284 
285  // set up poperties from zone
286  const auto& settings = *m_parentView.GetPainter()->GetSettings();
287  COLOR4D color = settings.GetColor( nullptr, m_zone->GetLayer() );
288 
290  m_previewItem.SetFillColor( color.WithAlpha( 0.2 ) );
291 
293 
296  }
297  }
298 
299  return m_zone != nullptr;
300 }
301 
302 
304 {
305  // send the points to the preview item
308 }
309 
310 
312 {
313  auto& finalPoints = aMgr.GetLockedInPoints();
314 
315  if( finalPoints.PointCount() < 3 )
316  {
317  // just scrap the zone in progress
318  m_zone = nullptr;
319  }
320  else
321  {
322  // if m_params.m_mode == DRAWING_TOOL::ZONE_MODE::CUTOUT, m_zone
323  // will be merged to the existing zone as a new hole.
324  m_zone->Outline()->NewOutline();
325  auto* outline = m_zone->Outline();
326 
327  for( int i = 0; i < finalPoints.PointCount(); ++i )
328  outline->Append( finalPoints.CPoint( i ) );
329 
330  // In DEG45 mode, we may have intermediate points in the leader that should be
331  // included as they are shown in the preview. These typically maintain the
332  // 45 constraint
334  {
335  const auto& pts = aMgr.GetLeaderLinePoints();
336  for( int i = 1; i < pts.PointCount(); i++ )
337  outline->Append( pts.CPoint( i ) );
338  }
339 
340  outline->Outline( 0 ).SetClosed( true );
341  outline->RemoveNullSegments();
342  outline->Simplify( SHAPE_POLY_SET::PM_FAST );
343 
344  // hand the zone over to the committer
345  commitZone( std::move( m_zone ) );
346  m_zone = nullptr;
347  }
348 
350 }
static TOOL_ACTION selectionClear
Clears the current selection.
Definition: pcb_actions.h:62
static LSET AllCuMask(int aCuLayerCount=MAX_CU_LAYERS)
Return a mask holding the requested number of Cu PCB_LAYER_IDs.
Definition: lset.cpp:749
usual segment : line with rounded ends
ZONE_CONTAINER handles a list of polygons defining a copper zone.
Definition: class_zone.h:61
std::unique_ptr< ZONE_CONTAINER > createZoneFromExisting(const ZONE_CONTAINER &aSrcZone)
Function createZoneFromExisting.
void OnComplete(const POLYGON_GEOM_MANAGER &aMgr) override
Called when the polygon is complete
Add a new zone with the same settings as an existing one.
T * getModel() const
Function getModel()
Definition: tool_base.h:201
void SetStrokeColor(const COLOR4D &aNewColor)
Set the stroke colour to set before drawing preview
virtual void SetLayer(PCB_LAYER_ID aLayer)
Function SetLayer sets the layer this item is on.
COMMIT & Add(EDA_ITEM *aItem)
Adds a new item to the model
Definition: commit.h:78
const SHAPE_LINE_CHAIN & GetLeaderLinePoints() const
Get the points comprising the leader line (the line from the last locked-in point to the current curs...
SELECTION_TOOL.
int InvokeNonCopperZonesEditor(PCB_BASE_FRAME *aParent, ZONE_SETTINGS *aSettings)
Function InvokeNonCopperZonesEditor invokes up a modal dialog window for non-copper zone editing.
virtual void Revert() override
Revertes the commit by restoring the modifed items state.
ZONE_CREATE_HELPER(DRAWING_TOOL &aTool, PARAMS &aParams)
bool Contains(PCB_LAYER_ID aLayer)
See if the layer set contains a PCB layer.
int color
Definition: DXF_plotter.cpp:60
virtual void Remove(VIEW_ITEM *aItem)
Function Remove() Removes a VIEW_ITEM from the view.
Definition: view.cpp:357
SHAPE_POLY_SET * Outline()
Definition: class_zone.h:300
PCB_LAYER_ID m_layer
Layer to begin drawing
bool RunAction(const std::string &aActionName, bool aNow=false, T aParam=NULL)
Function RunAction() Runs the specified action.
Definition: tool_manager.h:141
void commitZone(std::unique_ptr< ZONE_CONTAINER > aZone)
Commit the current zone-in-progress to the BOARD.
std::unique_ptr< ZONE_CONTAINER > m_zone
The zone-in-progress
KIGFX::PREVIEW::POLYGON_ITEM m_previewItem
The preview item to display
Parameters used to fully describe a zone creation process.
void SetLeaderMode(LEADER_MODE aMode)
Set the leader mode to use when calculating the leader/returner lines.
LEADER_MODE GetLeaderMode() const
BOARD_CONNECTED_ITEM is a base class derived from BOARD_ITEM for items that can be connected and have...
PAINTER * GetPainter() const
Function GetPainter() Returns the painter object used by the view for drawing VIEW_ITEMS.
Definition: view.h:201
void Append(int aX, int aY, bool aAllowDuplication=false)
Function Append()
TOOL_MANAGER * GetManager() const
Function GetManager() Returns the instance of TOOL_MANAGER that takes care of the tool.
Definition: tool_base.h:143
PCBNEW_SELECTION & GetSelection()
Function GetSelection()
int m_NetcodeSelection
Definition: zone_settings.h:93
void performZoneCutout(ZONE_CONTAINER &aZone, ZONE_CONTAINER &aCutout)
Function performZoneCutout()
class MODULE, a footprint
Definition: typeinfo.h:89
virtual void WarpCursor(const VECTOR2D &aPosition, bool aWorldCoordinates=false, bool aWarpView=false)=0
Function WarpCursor() If enabled (.
Unconstrained point-to-point
LSET is a set of PCB_LAYER_IDs.
void SetShape(PCB_SHAPE_TYPE_T aShape)
Definition: pcb_shape.h:113
DRAWING_TOOL.
Definition: drawing_tool.h:50
SHAPE_POLY_SET.
SHAPE_LINE_CHAIN & Outline(int aIndex)
Returns the reference to aIndex-th outline in the set
ZONE_CONTAINER * m_sourceZone
Zone settings source (for similar and cutout zones)
const ZONE_SETTINGS & GetZoneSettings() const
KIGFX::VIEW & m_parentView
view that show the preview item
const std::deque< EDA_ITEM * > GetItems() const
Definition: selection.h:132
VIEW_CONTROLS is an interface for classes handling user events controlling the view behaviour (such a...
Add a new zone/keepout with fresh settings.
bool OnFirstPoint(POLYGON_GEOM_MANAGER &aMgr) override
Called before the first point is added - clients can do initialisation here, and can veto the start o...
static LSET AllLayersMask()
Definition: lset.cpp:786
COMMIT & Remove(EDA_ITEM *aItem)
Removes a new item from the model
Definition: commit.h:90
void SetFillColor(const COLOR4D &aNewColor)
Set the fill colour to set before drawing preview
void ExportSetting(ZONE_CONTAINER &aTarget, bool aFullExport=true) const
Function ExportSetting copy settings to a given zone.
virtual void Update(VIEW_ITEM *aItem, int aUpdateFlags)
For dynamic VIEWs, informs the associated VIEW that the graphical representation of this item has cha...
Definition: view.cpp:1513
void SetIsRuleArea(bool aEnable)
int InvokeRuleAreaEditor(PCB_BASE_FRAME *aCaller, ZONE_SETTINGS *aSettings)
Function InvokeRuleAreaEditor invokes up a modal dialog window for copper zone editing.
Make a cutout to an existing zone.
bool Empty() const
Checks if there is anything selected.
Definition: selection.h:121
PCB_BASE_EDIT_FRAME * m_frame
Definition: drawing_tool.h:230
ZONE_SETTINGS handles zones parameters.
Definition: zone_settings.h:67
PARAMS & m_params
Parameters of the zone to be drawn
virtual BOARD_ITEM_CONTAINER * GetModel() const =0
Function GetModel()
Definition: color4d.h:49
int AddOutline(const SHAPE_LINE_CHAIN &aOutline)
Adds a new outline to the set and returns its index
virtual RENDER_SETTINGS * GetSettings()=0
Function GetAdapter Returns pointer to current settings that are going to be used when drawing items.
KIGFX::VIEW_CONTROLS * GetViewControls() const
Definition: tool_manager.h:292
void OnGeometryChange(const POLYGON_GEOM_MANAGER &aMgr) override
Sent when the polygon geometry changes
std::unique_ptr< ZONE_CONTAINER > createNewZone(bool aKeepout)
Function createNewZone()
Common, abstract interface for edit frames.
void SetStart(const wxPoint &aStart)
Definition: pcb_shape.h:132
Information pertinent to a Pcbnew printed circuit board.
Definition: class_board.h:186
polygon (not yet used for tracks, but could be in microwave apps)
#define _(s)
Definition: 3d_actions.cpp:33
static TOOL_ACTION selectItem
Selects an item (specified as the event parameter).
Definition: pcb_actions.h:65
EDA_ITEM is a base class for most all the KiCad significant classes, used in schematics and boards.
Definition: eda_item.h:148
virtual void Push(const wxString &aMessage=wxT("A commit"), bool aCreateUndoEntry=true, bool aSetDirtyBit=true) override
Executes the changes.
void SetPoints(const SHAPE_LINE_CHAIN &aLockedInPts, const SHAPE_LINE_CHAIN &aLeaderPts)
Set the polygon points.
T * getEditFrame() const
Function getEditFrame()
Definition: tool_base.h:187
int InvokeCopperZonesEditor(PCB_BASE_FRAME *aCaller, ZONE_SETTINGS *aSettings)
Function InvokeCopperZonesEditor invokes up a modal dialog window for copper zone editing.
void SetVisible(VIEW_ITEM *aItem, bool aIsVisible=true)
Sets the item visibility.
Definition: view.cpp:1459
virtual void Add(VIEW_ITEM *aItem, int aDrawPriority=-1)
Function Add() Adds a VIEW_ITEM to the view.
Definition: view.cpp:327
const SHAPE_LINE_CHAIN & GetLockedInPoints() const
Get the "locked-in" points that describe the polygon itself.
void BooleanSubtract(const SHAPE_POLY_SET &b, POLYGON_MODE aFastMode)
Performs boolean polyset difference For aFastMode meaning, see function booleanOp
CONST_SEGMENT_ITERATOR CIterateSegments(int aFirst, int aLast, bool aIterateHoles=false) const
Returns an iterator object, for iterating between aFirst and aLast outline, with or without holes (de...
Abstract interface for BOARD_ITEMs capable of storing other items inside.
BOARD * GetBoard() const
POLYGON_GEOM_MANAGER::LEADER_MODE m_leaderMode
Zone leader mode
bool m_keepout
Should create a keepout zone?
bool Fill(std::vector< ZONE_CONTAINER * > &aZones, bool aCheck=false, wxWindow *aParent=nullptr)
Definition: zone_filler.cpp:87
Class that handles the drawing of a polygon, including management of last corner deletion and drawing...
ZONE_MODE m_mode
The zone mode to operate in
void SetEnd(const wxPoint &aEnd)
Definition: pcb_shape.h:143
VECTOR2D GetCursorPosition() const
Returns the current cursor position in world coordinates.
KICAD_T Type() const
Function Type()
Definition: eda_item.h:182
Color has changed.
Definition: view_item.h:59
COLOR4D is the color representation with 4 components: red, green, blue, alpha.
Definition: color4d.h:100