KiCad PCB EDA Suite
Loading...
Searching...
No Matches
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-2023 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 <board_commit.h>
33#include <pcb_painter.h>
34#include <tools/pcb_actions.h>
36#include <view/view_controls.h>
37
39 m_tool( aTool ),
40 m_params( aParams ),
41 m_parentView( *aTool.getView() )
42{
44}
45
46
48{
49 // remove the preview from the view
52}
53
54
56{
58 BOARD* board = frame->GetBoard();
59
60 // By default, new zones get the first unused priority
61 std::set<unsigned> priorities;
62
63 for( ZONE* zone : board->Zones() )
64 {
65 if( zone->GetTeardropAreaType() == TEARDROP_TYPE::TD_NONE
66 && ( zone->GetLayerSet() & LSET::AllCuMask() ).any()
67 && !zone->GetIsRuleArea() )
68 {
69 priorities.insert( zone->GetAssignedPriority() );
70 }
71 }
72
73 unsigned priority = 0;
74
75 for( unsigned exist_priority : priorities )
76 {
77 if( priority != exist_priority )
78 break;
79
80 ++priority;
81 }
82
83 aZoneInfo.m_ZonePriority = priority;
84}
85
86
87std::unique_ptr<ZONE> ZONE_CREATE_HELPER::createNewZone( bool aKeepout )
88{
90 BOARD* board = frame->GetBoard();
93 std::set<int> highlightedNets = board->GetHighLightNetCodes();
94
95 // Get the current default settings for zones
96 ZONE_SETTINGS zoneInfo = board->GetDesignSettings().GetDefaultZoneSettings();
97 zoneInfo.m_Layers.reset().set( m_params.m_layer ); // TODO(JE) multilayer defaults?
98 zoneInfo.m_NetcodeSelection = highlightedNets.empty() ? -1 : *highlightedNets.begin();
100
101 if( m_params.m_mode != ZONE_MODE::GRAPHIC_POLYGON
102 && ( zoneInfo.m_Layers & LSET::AllCuMask() ).any() )
103 {
104 setUniquePriority( zoneInfo );
105 }
106
107 // If we don't have a net from highlighting, maybe we can get one from the selection
109
110 if( selectionTool && !selectionTool->GetSelection().Empty()
111 && zoneInfo.m_NetcodeSelection == -1 )
112 {
113 EDA_ITEM* item = *selectionTool->GetSelection().GetItems().begin();
114
115 if( BOARD_CONNECTED_ITEM* bci = dynamic_cast<BOARD_CONNECTED_ITEM*>( item ) )
116 zoneInfo.m_NetcodeSelection = bci->GetNetCode();
117 }
118
119 if( m_params.m_mode != ZONE_MODE::GRAPHIC_POLYGON )
120 {
121 // Show options dialog
122 int dialogResult;
123
124 if( m_params.m_keepout )
125 dialogResult = InvokeRuleAreaEditor( frame, &zoneInfo );
126 else if( ( zoneInfo.m_Layers & LSET::AllCuMask() ).any() )
127 dialogResult = InvokeCopperZonesEditor( frame, &zoneInfo );
128 else
129 dialogResult = InvokeNonCopperZonesEditor( frame, &zoneInfo );
130
131 if( dialogResult == wxID_CANCEL )
132 return nullptr;
133
134 controls->WarpMouseCursor( controls->GetCursorPosition(), true );
135 frame->GetCanvas()->SetFocus();
136 }
137
138 wxASSERT( !m_tool.m_isFootprintEditor || ( parent->Type() == PCB_FOOTPRINT_T ) );
139
140 std::unique_ptr<ZONE> newZone = std::make_unique<ZONE>( parent );
141
142 // Apply the selected settings
143 zoneInfo.ExportSetting( *newZone );
144
145 return newZone;
146}
147
148
149std::unique_ptr<ZONE> ZONE_CREATE_HELPER::createZoneFromExisting( const ZONE& aSrcZone )
150{
151 BOARD* board = m_tool.getModel<BOARD>();
152
153 std::unique_ptr<ZONE> newZone = std::make_unique<ZONE>( board );
154
155 ZONE_SETTINGS zoneSettings;
156 zoneSettings << aSrcZone;
157
158 zoneSettings.ExportSetting( *newZone );
159
160 return newZone;
161}
162
163
164void ZONE_CREATE_HELPER::performZoneCutout( ZONE& aZone, const ZONE& aCutout )
165{
166 BOARD_COMMIT commit( &m_tool );
167 std::vector<ZONE*> newZones;
168
169 // Clear the selection before removing the old zone
170 auto toolMgr = m_tool.GetManager();
172
173 SHAPE_POLY_SET originalOutline( *aZone.Outline() );
174 originalOutline.BooleanSubtract( *aCutout.Outline(), SHAPE_POLY_SET::PM_FAST );
175
176 // After substracting the hole, originalOutline can have more than one main outline.
177 // But a zone can have only one main outline, so create as many zones as originalOutline
178 // contains main outlines:
179 for( int outline = 0; outline < originalOutline.OutlineCount(); outline++ )
180 {
181 auto newZoneOutline = new SHAPE_POLY_SET;
182 newZoneOutline->AddOutline( originalOutline.Outline( outline ) );
183
184 // Add holes (if any) to the new zone outline:
185 for (int hole = 0; hole < originalOutline.HoleCount( outline ) ; hole++ )
186 newZoneOutline->AddHole( originalOutline.CHole( outline, hole ) );
187
188 auto newZone = new ZONE( aZone );
189 newZone->SetOutline( newZoneOutline );
190 newZone->SetLocalFlags( 1 );
191 newZone->HatchBorder();
192 newZone->UnFill();
193 newZones.push_back( newZone );
194 commit.Add( newZone );
195 }
196
197 commit.Remove( &aZone );
198 commit.Push( _( "Add Zone Cutout" ) );
199
200 // Select the new zone and set it as the source for the next cutout
201 if( newZones.empty() )
202 {
203 m_params.m_sourceZone = nullptr;
204 }
205 else
206 {
207 m_params.m_sourceZone = newZones[0];
208 toolMgr->RunAction<EDA_ITEM*>( PCB_ACTIONS::selectItem, newZones[0] );
209 }
210}
211
212
213void ZONE_CREATE_HELPER::commitZone( std::unique_ptr<ZONE> aZone )
214{
215 switch ( m_params.m_mode )
216 {
217 case ZONE_MODE::CUTOUT:
218 // For cutouts, subtract from the source
220 break;
221
222 case ZONE_MODE::ADD:
223 case ZONE_MODE::SIMILAR:
224 {
225 BOARD_COMMIT commit( &m_tool );
226
227 aZone->HatchBorder();
228
229 commit.Add( aZone.get() );
230 commit.Push( _( "Add a zone" ) );
231
233 break;
234 }
235
236 case ZONE_MODE::GRAPHIC_POLYGON:
237 {
238 BOARD_COMMIT commit( &m_tool );
239 BOARD* board = m_tool.getModel<BOARD>();
241 PCB_SHAPE* poly = new PCB_SHAPE( m_tool.m_frame->GetModel() );
242
243 poly->SetShape( SHAPE_T::POLY );
244 poly->SetFilled( layer != Edge_Cuts && layer != F_CrtYd && layer != B_CrtYd );
245
247 LINE_STYLE::SOLID ) );
248 poly->SetLayer( layer );
249 poly->SetPolyShape( *aZone->Outline() );
250
251 commit.Add( poly );
252 commit.Push( _( "Add Polygon" ) );
253
255 break;
256 }
257 }
258}
259
260
262{
263 // if we don't have a zone, create one
264 if( !m_zone )
265 {
268 else
270
271 if( m_zone )
272 {
274
275 // set up properties from zone
276 const auto& settings = *m_parentView.GetPainter()->GetSettings();
277 COLOR4D color = settings.GetColor( nullptr, m_zone->GetFirstLayer() );
278
279 m_previewItem.SetStrokeColor( COLOR4D::WHITE );
280 m_previewItem.SetFillColor( color.WithAlpha( 0.2 ) );
281
283
286 }
287 }
288
289 return m_zone != nullptr;
290}
291
292
294{
295 // Handle a cancel-interactive
296 if( m_zone && !aMgr.IsPolygonInProgress() )
297 {
298 m_zone = nullptr;
300 return;
301 }
302
303 // send the points to the preview item
305 aMgr.GetLoopLinePoints() );
307}
308
309
311{
312 auto& finalPoints = aMgr.GetLockedInPoints();
313
314 if( finalPoints.PointCount() < 3 )
315 {
316 // just scrap the zone in progress
317 m_zone = nullptr;
318 }
319 else
320 {
321 // if m_params.m_mode == DRAWING_TOOL::ZONE_MODE::CUTOUT, m_zone will be merged to the
322 // existing zone as a new hole.
323 m_zone->Outline()->NewOutline();
324 auto* outline = m_zone->Outline();
325
326 for( int i = 0; i < finalPoints.PointCount(); ++i )
327 outline->Append( finalPoints.CPoint( i ) );
328
329 // In DEG45 mode, we may have intermediate points in the leader that should be included
330 // as they are shown in the preview. These typically maintain the 45 constraint
332 {
333 const SHAPE_LINE_CHAIN leaderPts = aMgr.GetLeaderLinePoints();
334 for( int i = 1; i < leaderPts.PointCount(); i++ )
335 outline->Append( leaderPts.CPoint( i ) );
336
337 const SHAPE_LINE_CHAIN loopPts = aMgr.GetLoopLinePoints();
338 for( int i = 1; i < loopPts.PointCount() - 1; i++ )
339 outline->Append( loopPts.CPoint( i ) );
340 }
341
342 SHAPE_LINE_CHAIN& chain = outline->Outline( 0 );
343
344 chain.SetClosed( true );
345 chain.Simplify( true );
346
347 // Remove the start point if it lies on the line between neighbouring points.
348 // Simplify doesn't handle that currently.
349 if( chain.PointCount() >= 3 )
350 {
351 SEG seg( chain.CPoint( -1 ), chain.CPoint( 1 ) );
352
353 if( seg.LineDistance( chain.CPoint( 0 ) ) <= 1 )
354 chain.Remove( 0 );
355 }
356
357 // hand the zone over to the committer
358 commitZone( std::move( m_zone ) );
359 m_zone = nullptr;
360 }
361
363}
int color
Definition: DXF_plotter.cpp:58
virtual void Push(const wxString &aMessage=wxEmptyString, 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.
Information pertinent to a Pcbnew printed circuit board.
Definition: board.h:282
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition: board.cpp:794
COMMIT & Remove(EDA_ITEM *aItem, BASE_SCREEN *aScreen=nullptr)
Notify observers that aItem has been removed.
Definition: commit.h:92
COMMIT & Add(EDA_ITEM *aItem, BASE_SCREEN *aScreen=nullptr)
Notify observers that aItem has been added.
Definition: commit.h:80
Tool responsible for drawing graphical elements like lines, arcs, circles, etc.
Definition: drawing_tool.h:55
PCB_BASE_EDIT_FRAME * m_frame
Definition: drawing_tool.h:354
void SetFocus() override
A base class for most all the KiCad significant classes used in schematics and boards.
Definition: eda_item.h:88
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:100
void SetFilled(bool aFlag)
Definition: eda_shape.h:96
void SetPolyShape(const SHAPE_POLY_SET &aShape)
Definition: eda_shape.h:282
void SetShape(SHAPE_T aShape)
Definition: eda_shape.h:119
A color representation with 4 components: red, green, blue, alpha.
Definition: color4d.h:104
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:315
virtual void Remove(VIEW_ITEM *aItem)
Remove a VIEW_ITEM from the view.
Definition: view.cpp:354
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:1631
PAINTER * GetPainter() const
Return the painter object used by the view for drawing #VIEW_ITEMS.
Definition: view.h:215
void SetVisible(VIEW_ITEM *aItem, bool aIsVisible=true)
Set the item visibility.
Definition: view.cpp:1558
static LSET AllCuMask(int aCuLayerCount=MAX_CU_LAYERS)
Return a mask holding the requested number of Cu PCB_LAYER_IDs.
Definition: lset.cpp:863
static TOOL_ACTION selectionClear
Clear the current selection.
Definition: pcb_actions.h:68
static TOOL_ACTION selectItem
Select an item (specified as the event parameter).
Definition: pcb_actions.h:71
Common, abstract interface for edit frames.
PCB_DRAW_PANEL_GAL * GetCanvas() const override
Return a pointer to GAL-based canvas of given EDA draw frame.
BOARD * GetBoard() const
virtual BOARD_ITEM_CONTAINER * GetModel() const =0
The selection tool: currently supports:
PCB_SELECTION & GetSelection()
void SetLayer(PCB_LAYER_ID aLayer) override
Set the layer this item is on.
Definition: pcb_shape.cpp:315
void SetStroke(const STROKE_PARAMS &aStroke) override
Definition: pcb_shape.h:86
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:121
bool Empty() const
Checks if there is anything selected.
Definition: selection.h:110
Represent a polyline containing arcs as well as line segments: A chain of connected line and/or arc s...
void SetClosed(bool aClosed)
Mark the line chain as closed (i.e.
void Simplify(int aMaxError=0)
Simplify the line chain by removing colinear adjacent segments and duplicate vertices.
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 difference For aFastMode meaning, see function booleanOp.
int AddOutline(const SHAPE_LINE_CHAIN &aOutline)
Adds a new outline to the set and returns its index.
int HoleCount(int aOutline) const
Returns the number of holes in a given outline.
SHAPE_LINE_CHAIN & Outline(int aIndex)
Return the reference to aIndex-th outline in the set.
const SHAPE_LINE_CHAIN & CHole(int aOutline, int aHole) const
int OutlineCount() const
Return the number of outlines in the set.
Simple container to manage line stroke parameters.
Definition: stroke_params.h:81
TOOL_MANAGER * GetManager() const
Return the instance of TOOL_MANAGER that takes care of the tool.
Definition: tool_base.h:145
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, T aParam)
Run the specified action immediately, pausing the current action to run the new one.
Definition: tool_manager.h:150
KIGFX::VIEW_CONTROLS * GetViewControls() const
Definition: tool_manager.h:393
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:71
void SetIsRuleArea(bool aEnable)
int m_NetcodeSelection
Definition: zone_settings.h:96
void ExportSetting(ZONE &aTarget, bool aFullExport=true) const
Function ExportSetting copy settings to a given zone.
unsigned m_ZonePriority
Definition: zone_settings.h:82
Handle a list of polygons defining a copper zone.
Definition: zone.h:72
SHAPE_POLY_SET * Outline()
Definition: zone.h:336
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:60
@ 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:54
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