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-2022 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
24#include <core/spinlock.h>
27#include <tool/tool_manager.h>
28#include <zone.h>
29#include <pcb_shape.h>
30#include <footprint.h>
31#include <fp_shape.h>
32#include <board_commit.h>
34#include <pcb_painter.h>
35#include <pcbnew_settings.h>
36#include <tools/pcb_actions.h>
38#include <zone_filler.h>
39
41 m_tool( aTool ),
42 m_params( aParams ),
43 m_parentView( *aTool.getView() )
44{
46}
47
48
50{
51 // remove the preview from the view
54}
55
56
58{
60 BOARD* board = frame->GetBoard();
61
62 // By default, new zones get the first unused priority
63 std::set<unsigned> priorities;
64
65 for( ZONE* zone : board->Zones() )
66 {
67 if( zone->GetTeardropAreaType() == TEARDROP_TYPE::TD_NONE
68 && ( zone->GetLayerSet() & LSET::AllCuMask() ).any()
69 && !zone->GetIsRuleArea() )
70 {
71 priorities.insert( zone->GetAssignedPriority() );
72 }
73 }
74
75 unsigned priority = 0;
76
77 for( unsigned exist_priority : priorities )
78 {
79 if( priority != exist_priority )
80 break;
81
82 ++priority;
83 }
84
85 aZoneInfo.m_ZonePriority = priority;
86}
87
88
89std::unique_ptr<ZONE> ZONE_CREATE_HELPER::createNewZone( bool aKeepout )
90{
92 BOARD* board = frame->GetBoard();
95 std::set<int> highlightedNets = board->GetHighLightNetCodes();
96
97 // Get the current default settings for zones
98 ZONE_SETTINGS zoneInfo = frame->GetZoneSettings();
99 zoneInfo.m_Layers.reset().set( m_params.m_layer ); // TODO(JE) multilayer defaults?
100 zoneInfo.m_NetcodeSelection = highlightedNets.empty() ? -1 : *highlightedNets.begin();
101 zoneInfo.SetIsRuleArea( m_params.m_keepout );
102
104 && ( zoneInfo.m_Layers & LSET::AllCuMask() ).any() )
105 {
106 setUniquePriority( zoneInfo );
107 }
108
109 // If we don't have a net from highlighting, maybe we can get one from the selection
111
112 if( selectionTool && !selectionTool->GetSelection().Empty()
113 && zoneInfo.m_NetcodeSelection == -1 )
114 {
115 EDA_ITEM* item = *selectionTool->GetSelection().GetItems().begin();
116
117 if( BOARD_CONNECTED_ITEM* bci = dynamic_cast<BOARD_CONNECTED_ITEM*>( item ) )
118 zoneInfo.m_NetcodeSelection = bci->GetNetCode();
119 }
120
122 {
123 // Get the current default settings for zones
124
125 // Show options dialog
126 int dialogResult;
127
128 if( m_params.m_keepout )
129 dialogResult = InvokeRuleAreaEditor( frame, &zoneInfo );
130 else
131 {
132 // TODO(JE) combine these dialogs?
133 if( ( zoneInfo.m_Layers & LSET::AllCuMask() ).any() )
134 dialogResult = InvokeCopperZonesEditor( frame, &zoneInfo );
135 else
136 dialogResult = InvokeNonCopperZonesEditor( frame, &zoneInfo );
137 }
138
139 if( dialogResult == wxID_CANCEL )
140 return nullptr;
141
142 controls->WarpMouseCursor( controls->GetCursorPosition(), true );
143 }
144
145 // The new zone is a ZONE if created in the board editor and a FP_ZONE if created in the
146 // footprint editor
147 wxASSERT( !m_tool.m_isFootprintEditor || ( parent->Type() == PCB_FOOTPRINT_T ) );
148
149 std::unique_ptr<ZONE> newZone = m_tool.m_isFootprintEditor ?
150 std::make_unique<FP_ZONE>( parent ) :
151 std::make_unique<ZONE>( parent );
152
153 // Apply the selected settings
154 zoneInfo.ExportSetting( *newZone );
155
156 return newZone;
157}
158
159
160std::unique_ptr<ZONE> ZONE_CREATE_HELPER::createZoneFromExisting( const ZONE& aSrcZone )
161{
162 BOARD* board = m_tool.getModel<BOARD>();
163
164 std::unique_ptr<ZONE> newZone = std::make_unique<ZONE>( board );
165
166 ZONE_SETTINGS zoneSettings;
167 zoneSettings << aSrcZone;
168
169 zoneSettings.ExportSetting( *newZone );
170
171 return newZone;
172}
173
174
175void ZONE_CREATE_HELPER::performZoneCutout( ZONE& aZone, const ZONE& aCutout )
176{
177 BOARD_COMMIT commit( &m_tool );
178 std::vector<ZONE*> newZones;
179
180 // Clear the selection before removing the old zone
181 auto toolMgr = m_tool.GetManager();
182 toolMgr->RunAction( PCB_ACTIONS::selectionClear, true );
183
184 SHAPE_POLY_SET originalOutline( *aZone.Outline() );
185 originalOutline.BooleanSubtract( *aCutout.Outline(), SHAPE_POLY_SET::PM_FAST );
186
187 // After substracting the hole, originalOutline can have more than one
188 // main outline.
189 // But a zone can have only one main outline, so create as many zones as
190 // originalOutline contains main outlines:
191 for( int outline = 0; outline < originalOutline.OutlineCount(); outline++ )
192 {
193 auto newZoneOutline = new SHAPE_POLY_SET;
194 newZoneOutline->AddOutline( originalOutline.Outline( outline ) );
195
196 // Add holes (if any) to thez new zone outline:
197 for (int hole = 0; hole < originalOutline.HoleCount( outline ) ; hole++ )
198 newZoneOutline->AddHole( originalOutline.CHole( outline, hole ) );
199
200 auto newZone = new ZONE( aZone );
201 newZone->SetOutline( newZoneOutline );
202 newZone->SetLocalFlags( 1 );
203 newZone->HatchBorder();
204 newZone->UnFill();
205 newZones.push_back( newZone );
206 commit.Add( newZone );
207 }
208
209 commit.Remove( &aZone );
210
211 // TODO Refill zones when KiCad supports auto re-fill
212
213 commit.Push( _( "Add a zone cutout" ) );
214
215 // Select the new zone and set it as the source for the next cutout
216 if( newZones.empty() )
217 {
218 m_params.m_sourceZone = nullptr;
219 }
220 else
221 {
222 m_params.m_sourceZone = newZones[0];
223 toolMgr->RunAction( PCB_ACTIONS::selectItem, true, newZones[0] );
224 }
225
226}
227
228
229void ZONE_CREATE_HELPER::commitZone( std::unique_ptr<ZONE> aZone )
230{
231 switch ( m_params.m_mode )
232 {
234 // For cutouts, subtract from the source
236 break;
237
238 case ZONE_MODE::ADD:
240 {
241 BOARD_COMMIT commit( &m_tool );
242
243 aZone->HatchBorder();
244
245 commit.Add( aZone.get() );
246 commit.Push( _( "Add a zone" ) );
247
248 m_tool.GetManager()->RunAction( PCB_ACTIONS::selectItem, true, aZone.release() );
249 break;
250 }
251
253 {
254 BOARD_COMMIT commit( &m_tool );
255 BOARD* board = m_tool.getModel<BOARD>();
257 PCB_SHAPE* poly;
258
260 poly = new FP_SHAPE( static_cast<FOOTPRINT*>( m_tool.m_frame->GetModel() ) );
261 else
262 poly = new PCB_SHAPE();
263
264 poly->SetShape( SHAPE_T::POLY );
265
266 if( layer == Edge_Cuts || layer == F_CrtYd || layer == B_CrtYd )
267 poly->SetFilled( false );
268 else
269 poly->SetFilled( true );
270
273 poly->SetLayer( layer );
274 poly->SetPolyShape( *aZone->Outline() );
275
276 commit.Add( poly );
278
279 commit.Push( _( "Add a graphical polygon" ) );
280
281 break;
282 }
283 }
284}
285
286
288{
289 // if we don't have a zone, create one
290 // the user's choice here can affect things like the colour of the preview
291 if( !m_zone )
292 {
295 else
297
298 if( m_zone )
299 {
301
302 // set up properties from zone
303 const auto& settings = *m_parentView.GetPainter()->GetSettings();
304 COLOR4D color = settings.GetColor( nullptr, m_zone->GetFirstLayer() );
305
307 m_previewItem.SetFillColor( color.WithAlpha( 0.2 ) );
308
310
313 }
314 }
315
316 return m_zone != nullptr;
317}
318
319
321{
322 // send the points to the preview item
324 aMgr.GetLoopLinePoints() );
326}
327
328
330{
331 auto& finalPoints = aMgr.GetLockedInPoints();
332
333 if( finalPoints.PointCount() < 3 )
334 {
335 // just scrap the zone in progress
336 m_zone = nullptr;
337 }
338 else
339 {
340 // if m_params.m_mode == DRAWING_TOOL::ZONE_MODE::CUTOUT, m_zone
341 // will be merged to the existing zone as a new hole.
342 m_zone->Outline()->NewOutline();
343 auto* outline = m_zone->Outline();
344
345 for( int i = 0; i < finalPoints.PointCount(); ++i )
346 outline->Append( finalPoints.CPoint( i ) );
347
348 // In DEG45 mode, we may have intermediate points in the leader that should be
349 // included as they are shown in the preview. These typically maintain the
350 // 45 constraint
352 {
353 const SHAPE_LINE_CHAIN leaderPts = aMgr.GetLeaderLinePoints();
354 for( int i = 1; i < leaderPts.PointCount(); i++ )
355 outline->Append( leaderPts.CPoint( i ) );
356
357 const SHAPE_LINE_CHAIN loopPts = aMgr.GetLoopLinePoints();
358 for( int i = 1; i < loopPts.PointCount() - 1; i++ )
359 outline->Append( loopPts.CPoint( i ) );
360 }
361
362 SHAPE_LINE_CHAIN& chain = outline->Outline( 0 );
363
364 chain.SetClosed( true );
365 chain.Simplify( true );
366
367 // Remove the start point if it lies on the line between neighbouring points.
368 // Simplify doesn't handle that currently.
369 if( chain.PointCount() >= 3 )
370 {
371 SEG seg( chain.CPoint( -1 ), chain.CPoint( 1 ) );
372
373 if( seg.LineDistance( chain.CPoint( 0 ) ) <= 1 )
374 chain.Remove( 0 );
375 }
376
377 // hand the zone over to the committer
378 commitZone( std::move( m_zone ) );
379 m_zone = nullptr;
380 }
381
383}
int color
Definition: DXF_plotter.cpp:57
virtual void Push(const wxString &aMessage=wxT("A commit"), int aCommitFlags=0) override
Revert the commit by restoring the modified items state.
A base class derived from BOARD_ITEM for items that can be connected and have a net,...
int GetLineThickness(PCB_LAYER_ID aLayer) const
Return the default graphic segment thickness from the layer class for the given layer.
Abstract interface for BOARD_ITEMs capable of storing other items inside.
virtual void SetLayer(PCB_LAYER_ID aLayer)
Set the layer this item is on.
Definition: board_item.h:226
Information pertinent to a Pcbnew printed circuit board.
Definition: board.h:269
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition: board.cpp:704
COMMIT & Remove(EDA_ITEM *aItem)
Notify observers that aItem has been removed.
Definition: commit.h:90
COMMIT & Add(EDA_ITEM *aItem)
Notify observers that aItem has been added.
Definition: commit.h:78
Tool responsible for drawing graphical elements like lines, arcs, circles, etc.
Definition: drawing_tool.h:51
PCB_BASE_EDIT_FRAME * m_frame
Definition: drawing_tool.h:342
A base class for most all the KiCad significant classes used in schematics and boards.
Definition: eda_item.h:85
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:97
void SetFilled(bool aFlag)
Definition: eda_shape.h:95
void SetPolyShape(const SHAPE_POLY_SET &aShape)
Definition: eda_shape.h:255
void SetShape(SHAPE_T aShape)
Definition: eda_shape.h:112
A color representation with 4 components: red, green, blue, alpha.
Definition: color4d.h:102
virtual RENDER_SETTINGS * GetSettings()=0
Return a pointer to current settings that are going to be used when drawing items.
void SetPoints(const SHAPE_LINE_CHAIN &aLockedInPts, const SHAPE_LINE_CHAIN &aLeaderPts, const SHAPE_LINE_CHAIN &aLoopPts)
Set the polygon points.
void SetFillColor(const COLOR4D &aNewColor)
Set the line width to set before drawing preview.
void SetStrokeColor(const COLOR4D &aNewColor)
Set the fill color to set before drawing preview.
An interface for classes handling user events controlling the view behavior such as zooming,...
virtual void WarpMouseCursor(const VECTOR2D &aPosition, bool aWorldCoordinates=false, bool aWarpView=false)=0
If enabled (.
VECTOR2D GetCursorPosition() const
Return the current cursor position in world coordinates.
virtual void Add(VIEW_ITEM *aItem, int aDrawPriority=-1)
Add a VIEW_ITEM to the view.
Definition: view.cpp:316
virtual void Remove(VIEW_ITEM *aItem)
Remove a VIEW_ITEM from the view.
Definition: view.cpp:349
virtual void Update(const VIEW_ITEM *aItem, int aUpdateFlags) const
For dynamic VIEWs, inform the associated VIEW that the graphical representation of this item has chan...
Definition: view.cpp:1591
PAINTER * GetPainter() const
Return the painter object used by the view for drawing #VIEW_ITEMS.
Definition: view.h:213
void SetVisible(VIEW_ITEM *aItem, bool aIsVisible=true)
Set the item visibility.
Definition: view.cpp:1529
static LSET AllCuMask(int aCuLayerCount=MAX_CU_LAYERS)
Return a mask holding the requested number of Cu PCB_LAYER_IDs.
Definition: lset.cpp:773
static TOOL_ACTION selectionClear
Clear the current selection.
Definition: pcb_actions.h:59
static TOOL_ACTION selectItem
Select an item (specified as the event parameter).
Definition: pcb_actions.h:62
Common, abstract interface for edit frames.
const ZONE_SETTINGS & GetZoneSettings() const
BOARD * GetBoard() const
virtual BOARD_ITEM_CONTAINER * GetModel() const =0
The selection tool: currently supports:
PCB_SELECTION & GetSelection()
void SetStroke(const STROKE_PARAMS &aStroke) override
Definition: pcb_shape.h:72
virtual bool Is45Limited() const
Should the tool use its 45° mode option?
bool m_isFootprintEditor
Class that handles the drawing of a polygon, including management of last corner deletion and drawing...
const SHAPE_LINE_CHAIN & GetLockedInPoints() const
Get the "locked-in" points that describe the polygon itself.
@ DIRECT
Unconstrained point-to-point.
LEADER_MODE GetLeaderMode() const
void SetLeaderMode(LEADER_MODE aMode)
Set the leader mode to use when calculating the leader/returner lines.
const SHAPE_LINE_CHAIN & GetLoopLinePoints() const
Get the points from the current cursor position to the polygon start point.
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...
Definition: seg.h:42
int LineDistance(const VECTOR2I &aP, bool aDetermineSide=false) const
Return the closest Euclidean distance between point aP and the line defined by the ends of segment (t...
Definition: seg.cpp:341
const std::deque< EDA_ITEM * > GetItems() const
Definition: selection.h:120
bool Empty() const
Checks if there is anything selected.
Definition: selection.h:109
Represent a polyline containing arcs as well as line segments: A chain of connected line and/or arc s...
SHAPE_LINE_CHAIN & Simplify(bool aRemoveColinear=true)
Simplify the line chain by removing colinear adjacent segments and duplicate vertices.
void SetClosed(bool aClosed)
Mark the line chain as closed (i.e.
int PointCount() const
Return the number of points (vertices) in this line chain.
void Append(int aX, int aY, bool aAllowDuplication=false)
Append a new point at the end of the line chain.
const VECTOR2I & CPoint(int aIndex) const
Return a reference to a given point in the line chain.
void Remove(int aStartIndex, int aEndIndex)
Remove the range of points [start_index, end_index] from the line chain.
Represent a set of closed polygons.
void BooleanSubtract(const SHAPE_POLY_SET &b, POLYGON_MODE aFastMode)
Perform boolean polyset intersection For aFastMode meaning, see function booleanOp.
int AddOutline(const SHAPE_LINE_CHAIN &aOutline)
Adds a new hole to the given outline (default: last) and returns its index.
int HoleCount(int aOutline) const
Return the reference to aIndex-th outline in the set.
SHAPE_LINE_CHAIN & Outline(int aIndex)
const SHAPE_LINE_CHAIN & CHole(int aOutline, int aHole) const
int OutlineCount() const
Return the number of vertices in a given outline/hole.
Simple container to manage line stroke parameters.
Definition: stroke_params.h:88
TOOL_MANAGER * GetManager() const
Return the instance of TOOL_MANAGER that takes care of the tool.
Definition: tool_base.h:144
T * getEditFrame() const
Return the application window object, casted to requested user type.
Definition: tool_base.h:185
T * getModel() const
Return the model object if it matches the requested type.
Definition: tool_base.h:197
bool RunAction(const std::string &aActionName, bool aNow=false, T aParam=NULL)
Run the specified action.
Definition: tool_manager.h:142
KIGFX::VIEW_CONTROLS * GetViewControls() const
Definition: tool_manager.h:287
void commitZone(std::unique_ptr< ZONE > aZone)
Commit the current zone-in-progress to the BOARD.
PARAMS & m_params
The preview item to display.
bool OnFirstPoint(POLYGON_GEOM_MANAGER &aMgr) override
Called before the first point is added - clients can do initialization here, and can veto the start o...
ZONE_CREATE_HELPER(DRAWING_TOOL &aTool, PARAMS &aParams)
std::unique_ptr< ZONE > createNewZone(bool aKeepout)
Prompt the user for new zone settings, and create a new zone with those settings.
void performZoneCutout(ZONE &aZone, const ZONE &aCutout)
Cut one zone out of another one (i.e.
void setUniquePriority(ZONE_SETTINGS &aZoneInfo)
Choose a new priority for @aZoneInfo.
void OnGeometryChange(const POLYGON_GEOM_MANAGER &aMgr) override
Called when the polygon is complete.
std::unique_ptr< ZONE > m_zone
std::unique_ptr< ZONE > createZoneFromExisting(const ZONE &aSrcZone)
Create a new zone with the settings from an existing zone.
KIGFX::PREVIEW::POLYGON_ITEM m_previewItem
view that show the preview item
void OnComplete(const POLYGON_GEOM_MANAGER &aMgr) override
KIGFX::VIEW & m_parentView
The zone-in-progress.
DRAWING_TOOL & m_tool
Parameters of the zone to be drawn.
ZONE_SETTINGS handles zones parameters.
Definition: zone_settings.h:70
void SetIsRuleArea(bool aEnable)
int m_NetcodeSelection
Definition: zone_settings.h:95
void ExportSetting(ZONE &aTarget, bool aFullExport=true) const
Function ExportSetting copy settings to a given zone.
unsigned m_ZonePriority
Definition: zone_settings.h:81
Handle a list of polygons defining a copper zone.
Definition: zone.h:57
SHAPE_POLY_SET * Outline()
Definition: zone.h:318
@ WHITE
Definition: color4d.h:46
int InvokeCopperZonesEditor(PCB_BASE_FRAME *aCaller, ZONE_SETTINGS *aSettings, CONVERT_SETTINGS *aConvertSettings)
Function InvokeCopperZonesEditor invokes up a modal dialog window for copper zone editing.
int InvokeNonCopperZonesEditor(PCB_BASE_FRAME *aParent, ZONE_SETTINGS *aSettings, CONVERT_SETTINGS *aConvertSettings)
Function InvokeNonCopperZonesEditor invokes up a modal dialog window for non-copper zone editing.
int InvokeRuleAreaEditor(PCB_BASE_FRAME *aCaller, ZONE_SETTINGS *aZoneSettings, CONVERT_SETTINGS *aConvertSettings)
Function InvokeRuleAreaEditor invokes up a modal dialog window for copper zone editing.
#define _(s)
PCB_LAYER_ID
A quick note on layer IDs:
Definition: layer_ids.h:59
@ F_CrtYd
Definition: layer_ids.h:117
@ Edge_Cuts
Definition: layer_ids.h:113
@ B_CrtYd
Definition: layer_ids.h:116
@ GEOMETRY
Position or shape has changed.
Definition: view_item.h:49
@ SIMILAR
Add a new zone with the same settings as an existing one.
@ CUTOUT
Make a cutout to an existing zone.
@ ADD
Add a new zone/keepout with fresh settings.
Parameters used to fully describe a zone creation process.
ZONE_MODE m_mode
Zone settings source (for similar and cutout zones)
bool m_keepout
< Should create a keepout zone?
ZONE * m_sourceZone
Zone leader mode.
PCB_LAYER_ID m_layer
The zone mode to operate in.
@ PCB_FOOTPRINT_T
class FOOTPRINT, a footprint
Definition: typeinfo.h:86