KiCad PCB EDA Suite
Loading...
Searching...
No Matches
dialog_global_edit_teardrops.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 The 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, see <https://www.gnu.org/licenses/>.
18 */
19
20#include <algorithm>
21
22#include <widgets/unit_binder.h>
23#include <pcb_edit_frame.h>
24#include <board.h>
27#include <pad.h>
28#include <pcb_track.h>
29#include <pcb_group.h>
30#include <footprint.h>
31#include <teardrop/teardrop.h>
32#include <zone_filler.h>
35#include <tool/tool_manager.h>
38
39// Globals to remember filters during a session
40static wxString g_netclassFilter;
41static wxString g_netFilter;
42
43
45{
46public:
49
50 bool TransferDataToWindow() override;
51 bool TransferDataFromWindow() override;
52
53protected:
54 void onSpecifiedValuesUpdateUi( wxUpdateUIEvent& event ) override
55 {
56 event.Enable( m_specifiedValues->GetValue() );
57 }
58
59 void onFilterUpdateUi( wxUpdateUIEvent& event ) override
60 {
61 event.Enable( !m_trackToTrack->GetValue() );
62 }
63
64 // Track-to-track teardrops always follow the document-wide settings (there are no teardrop
65 // properties on individual track segments as they're too ephemeral). Therefore we disable
66 // Set-to-specified-values when track-to-track is selected.
67 void onTrackToTrack( wxCommandEvent& event ) override
68 {
69 if( event.IsChecked() && m_specifiedValues->GetValue() )
70 {
71 m_specifiedValues->SetValue( false );
72 m_addTeardrops->SetValue( true );
73 }
74 }
75
76 // These just improve usability so that you don't have to click twice to enable a filter.
77 void OnNetclassFilterSelect( wxCommandEvent& event ) override
78 {
79 m_netclassFilterOpt->SetValue( true );
80 }
81
82 void OnLayerFilterSelect( wxCommandEvent& event ) override
83 {
84 m_layerFilterOpt->SetValue( true );
85 }
86
87 void OnNetFilterSelect( wxCommandEvent& event )
88 {
89 m_netFilterOpt->SetValue( true );
90 }
91
92 // Remove "add" terminology when updating only existing teardrops.
93 void OnExistingFilterSelect( wxCommandEvent& event ) override
94 {
95 if( event.IsChecked() )
96 {
97 m_addTeardrops->SetLabel( _( "Set teardrops to default values for shape" ) );
98 m_specifiedValues->SetLabel( _( "Set teardrops to specified values:" ) );
99 }
100 else
101 {
102 m_addTeardrops->SetLabel( _( "Add teardrops with default values for shape" ) );
103 m_specifiedValues->SetLabel( _( "Add teardrops with specified values:" ) );
104 }
105 }
106
107 void setSpecifiedParams( TEARDROP_PARAMETERS* targetParams );
108 void visitItem( BOARD_COMMIT* aCommit, BOARD_CONNECTED_ITEM* aItem,bool aSelectAlways );
109 void processItem( BOARD_COMMIT* aCommit, BOARD_CONNECTED_ITEM* aItem );
110
111 void onShowBoardSetup( wxHyperlinkEvent& event ) override
112 {
113 m_parent->ShowBoardSetupDialog( _( "Teardrops" ) );
114 }
115
116 void buildFilterLists();
117
118private:
121
127};
128
129
137{
138 m_parent = aParent;
139 m_brd = m_parent->GetBoard();
140
142
146
147 m_minTrackWidthHint->SetFont( KIUI::GetStatusFont( this ).Italic() );
148
150
151 SetupStandardButtons( { { wxID_OK, _( "Apply and Close" ) },
152 { wxID_CANCEL, _( "Close" ) } } );
153
154 m_netFilter->Connect( FILTERED_ITEM_SELECTED,
156 nullptr, this );
157
159}
160
161
163{
164 g_netclassFilter = m_netclassFilter->GetStringSelection();
165 g_netFilter = m_netFilter->GetSelectedNetname();
166
167 m_netFilter->Disconnect( FILTERED_ITEM_SELECTED,
169 nullptr, this );
170}
171
172
174{
175 // Populate the net filter list with net names
176 m_netFilter->SetNetInfo( &m_brd->GetNetInfo() );
177
178 if( !m_brd->GetHighLightNetCodes().empty() )
179 m_netFilter->SetSelectedNetcode( *m_brd->GetHighLightNetCodes().begin() );
180
181 // Populate the netclass filter list with netclass names
182 wxArrayString netclassNames;
183 std::shared_ptr<NET_SETTINGS>& settings = m_brd->GetDesignSettings().m_NetSettings;
184
185 netclassNames.push_back( settings->GetDefaultNetclass()->GetName() );
186
187 for( const auto& [name, netclass] : settings->GetNetclasses() )
188 netclassNames.push_back( name );
189
190 m_netclassFilter->Set( netclassNames );
191 m_netclassFilter->SetStringSelection( m_brd->GetDesignSettings().GetCurrentNetClassName() );
192
193 // Populate the layer filter list
194 m_layerFilter->SetBoardFrame( m_parent );
195 m_layerFilter->SetLayersHotkeys( false );
196 m_layerFilter->SetNotAllowedLayerSet( LSET::AllNonCuMask() );
197 m_layerFilter->Resync();
198 m_layerFilter->SetLayerSelection( m_parent->GetActiveLayer() );
199}
200
201
203{
204 BOARD_DESIGN_SETTINGS& bds = m_brd->GetDesignSettings();
205
210
211 m_netclassFilter->SetStringSelection( g_netclassFilter );
212 m_netFilter->SetSelectedNet( g_netFilter );
213
214 m_cbPreferZoneConnection->Set3StateValue( wxCHK_UNDETERMINED );
215 m_cbTeardropsUseNextTrack->Set3StateValue( wxCHK_UNDETERMINED );
221 m_curvedEdges->Set3StateValue( wxCHK_UNDETERMINED );
222
223 return true;
224}
225
226
228{
229 if( m_cbPreferZoneConnection->Get3StateValue() != wxCHK_UNDETERMINED )
230 targetParams->m_TdOnPadsInZones = !m_cbPreferZoneConnection->GetValue();
231
232 if( m_cbTeardropsUseNextTrack->Get3StateValue() != wxCHK_UNDETERMINED )
233 targetParams->m_AllowUseTwoTracks = m_cbTeardropsUseNextTrack->GetValue();
234
235 if( !m_teardropHDPercent.IsIndeterminate() )
236 targetParams->m_WidthtoSizeFilterRatio = m_teardropHDPercent.GetDoubleValue() / 100.0;
237
238 if( !m_teardropLenPercent.IsIndeterminate() )
239 targetParams->m_BestLengthRatio = m_teardropLenPercent.GetDoubleValue() / 100.0;
240
241 if( !m_teardropMaxLen.IsIndeterminate() )
242 targetParams->m_TdMaxLen = m_teardropMaxLen.GetIntValue();
243
244 if( !m_teardropHeightPercent.IsIndeterminate() )
245 targetParams->m_BestWidthRatio = m_teardropHeightPercent.GetDoubleValue() / 100.0;
246
247 if( !m_teardropMaxHeight.IsIndeterminate() )
248 targetParams->m_TdMaxWidth = m_teardropMaxHeight.GetIntValue();
249
250 if( m_curvedEdges->Get3StateValue() != wxCHK_UNDETERMINED )
251 targetParams->m_CurvedEdges = m_curvedEdges->GetValue();
252}
253
254
256{
257 BOARD_DESIGN_SETTINGS& brdSettings = m_brd->GetDesignSettings();
258 TEARDROP_PARAMETERS& targetParams = aItem->GetTeardropParams();
259
260 aCommit->Stage( aItem, CHT_MODIFY );
261
262 if( m_removeTeardrops->GetValue() || m_removeAllTeardrops->GetValue() )
263 {
264 targetParams.m_Enabled = false;
265 }
266 else if( m_addTeardrops->GetValue() )
267 {
269 targetParams = *brdSettings.GetTeadropParamsList()->GetParameters( TARGET_ROUND );
270 else
271 targetParams = *brdSettings.GetTeadropParamsList()->GetParameters( TARGET_RECT );
272
273 targetParams.m_Enabled = true;
274 }
275 else if( m_specifiedValues->GetValue() )
276 {
277 setSpecifiedParams( &targetParams );
278
279 if( !m_existingFilter->GetValue() )
280 targetParams.m_Enabled = true;
281 }
282}
283
284
286 bool aSelectAlways )
287{
288 if( m_selectedItemsFilter->GetValue() )
289 {
290 if( !aItem->IsSelected() )
291 {
292 EDA_GROUP* group = aItem->GetParentGroup();
293
294 while( group && !group->AsEdaItem()->IsSelected() )
295 group = group->AsEdaItem()->GetParentGroup();
296
297 if( !group )
298 return;
299 }
300 }
301
302 if( aSelectAlways )
303 {
304 processItem( aCommit, aItem );
305 return;
306 }
307
308 if( m_netFilterOpt->GetValue() && m_netFilter->GetSelectedNetcode() >= 0 )
309 {
310 if( aItem->GetNetCode() != m_netFilter->GetSelectedNetcode() )
311 return;
312 }
313
314 if( m_netclassFilterOpt->GetValue() && !m_netclassFilter->GetStringSelection().IsEmpty() )
315 {
316 wxString filterNetclass = m_netclassFilter->GetStringSelection();
317 NETCLASS* netclass = aItem->GetEffectiveNetClass();
318
319 if( !netclass->ContainsNetclassWithName( filterNetclass ) )
320 return;
321 }
322
323 if( m_layerFilterOpt->GetValue() && m_layerFilter->GetLayerSelection() != UNDEFINED_LAYER )
324 {
325 if( aItem->GetLayer() != m_layerFilter->GetLayerSelection() )
326 return;
327 }
328
329 if( m_roundPadsFilter->GetValue() )
330 {
332 return;
333 }
334
335 if( m_existingFilter->GetValue() )
336 {
337 if( !aItem->GetTeardropParams().m_Enabled )
338 return;
339 }
340
341 processItem( aCommit, aItem );
342}
343
344
346{
347 m_brd->SetLegacyTeardrops( false );
348
349 BOARD_COMMIT commit( m_parent );
350 wxBusyCursor dummy;
351
352 // Save some dialog options
353 BOARD_DESIGN_SETTINGS& bds = m_brd->GetDesignSettings();
354
355 bds.m_TeardropParamsList.m_TargetVias = m_vias->GetValue();
360
361 bool remove_all = m_removeAllTeardrops->GetValue();
362
363 if( m_vias->GetValue() || remove_all )
364 {
365 for( PCB_TRACK* track : m_brd->Tracks() )
366 {
367 if ( track->Type() == PCB_VIA_T )
368 visitItem( &commit, track, remove_all );
369 }
370 }
371
372 for( FOOTPRINT* footprint : m_brd->Footprints() )
373 {
374 for( PAD* pad : footprint->Pads() )
375 {
376 if( remove_all )
377 {
378 visitItem( &commit, pad, true );
379 continue;
380 }
381
382 if( m_pthPads->GetValue() && pad->GetAttribute() == PAD_ATTRIB::PTH )
383 {
384 visitItem( &commit, pad, false );
385 }
386 else if( m_smdPads->GetValue() && ( pad->GetAttribute() == PAD_ATTRIB::SMD
387 || pad->GetAttribute() == PAD_ATTRIB::CONN ) )
388 {
389 visitItem( &commit, pad, false );
390 }
391 }
392 }
393
394 // "Remove all" has to reach track-to-track too, or the update below rebuilds them at once.
395 if( m_trackToTrack->GetValue() || remove_all )
396 {
397 TEARDROP_PARAMETERS_LIST* paramsList = m_brd->GetDesignSettings().GetTeadropParamsList();
398 TEARDROP_PARAMETERS* targetParams = paramsList->GetParameters( TARGET_TRACK );
399 TEARDROP_MANAGER teardropManager( m_brd, m_parent->GetToolManager() );
400
401 teardropManager.DeleteTrackToTrackTeardrops( commit );
402
403 if( m_removeTeardrops->GetValue() || m_removeAllTeardrops->GetValue() )
404 {
405 targetParams->m_Enabled = false;
406 }
407 else if( m_addTeardrops->GetValue() )
408 {
409 targetParams->m_Enabled = true;
410 teardropManager.BuildTrackCaches();
411 teardropManager.AddTeardropsOnTracks( commit, nullptr, true );
412 }
413 }
414
415 // If there are no filters then a force-full-update is equivalent, and will be faster.
416 if( !m_netFilterOpt->GetValue()
417 && !m_netclassFilterOpt->GetValue()
418 && !m_layerFilterOpt->GetValue()
419 && !m_roundPadsFilter->GetValue()
420 && !m_existingFilter->GetValue()
421 && !m_selectedItemsFilter->GetValue() )
422 {
423 commit.Push( _( "Edit Teardrops" ), SKIP_TEARDROPS );
424
425 TEARDROP_MANAGER teardropMgr( m_brd, m_parent->GetToolManager() );
426 teardropMgr.UpdateTeardrops( commit, nullptr, nullptr, true /* forceFullUpdate */ );
427 commit.Push( _( "Edit Teardrops" ), SKIP_TEARDROPS | APPEND_UNDO );
428 }
429 else
430 {
431 commit.Push( _( "Edit Teardrops" ) );
432 }
433
434 // Showing the unfilled, fully cross-hatched teardrops seems to be working fairly well, and
435 // accurate fills can then be manually generated by doing a zone fill.
436 //
437 // But here's the old code which allowed for either "draft" fills or an automatic full zone
438 // fill in case we decide the current situation isn't good enough:
439#if 0
440 if( aFillAfter )
441 {
442 ZONE_FILLER filler( m_board, aCommit );
443
444 if( m_reporter )
445 filler.SetProgressReporter( m_reporter );
446
447 filler.Fill( m_board->Zones() );
448
449 if( aCommit )
450 aCommit->Push( _( "Edit Teardrops" ), APPEND_UNDO );
451 }
452 else
453 {
454 // Fill raw teardrop shapes. This is a rough calculation, just to show a filled
455 // shape on screen without the (potentially large) performance hit of a zone refill
456 int epsilon = pcbIUScale.mmToIU( 0.001 );
457 int allowed_error = pcbIUScale.mmToIU( 0.005 );
458
459 for( ZONE* zone: m_createdTdList )
460 {
461 int half_min_width = zone->GetMinThickness() / 2;
462 int numSegs = GetArcToSegmentCount( half_min_width, allowed_error, FULL_CIRCLE );
463 SHAPE_POLY_SET filledPolys = *zone->Outline();
464
465 filledPolys.Deflate( half_min_width - epsilon, numSegs );
466
467 // Re-inflate after pruning of areas that don't meet minimum-width criteria
468 if( half_min_width - epsilon > epsilon )
469 filledPolys.Inflate( half_min_width - epsilon, numSegs );
470
471 zone->SetFilledPolysList( zone->GetFirstLayer(), filledPolys );
472 }
473 }
474#endif
475
476 m_parent->Refresh();
477 return true;
478}
479
480
482{
484 DIALOG_GLOBAL_EDIT_TEARDROPS dlg( editFrame );
485
486 dlg.ShowQuasiModal(); // QuasiModal required for NET_SELECTOR
487 return 0;
488}
const char * name
constexpr EDA_IU_SCALE pcbIUScale
Definition base_units.h:121
wxBitmapBundle KiBitmapBundle(BITMAPS aBitmap, int aMinHeight)
Definition bitmap.cpp:106
#define SKIP_TEARDROPS
virtual void Push(const wxString &aMessage=wxEmptyString, int aCommitFlags=0) override
Execute the changes.
COMMIT & Stage(EDA_ITEM *aItem, CHANGE_TYPE aChangeType, BASE_SCREEN *aScreen=nullptr, RECURSE_MODE aRecurse=RECURSE_MODE::NO_RECURSE) override
Add a change of the item aItem of type aChangeType to the change list.
A base class derived from BOARD_ITEM for items that can be connected and have a net,...
virtual NETCLASS * GetEffectiveNetClass() const
Return the NETCLASS for this item.
PCB_LAYER_ID GetLayer() const override
Return the primary layer this item is on.
TEARDROP_PARAMETERS & GetTeardropParams()
Container for design settings for a BOARD object.
TEARDROP_PARAMETERS_LIST * GetTeadropParamsList()
TEARDROP_PARAMETERS_LIST m_TeardropParamsList
The parameters of teardrops for the different teardrop targets (via/pad, track end).
Information pertinent to a Pcbnew printed circuit board.
Definition board.h:409
DIALOG_GLOBAL_EDIT_TEARDROPS_BASE(wxWindow *parent, wxWindowID id=wxID_ANY, const wxString &title=_("Set Teardrops"), const wxPoint &pos=wxDefaultPosition, const wxSize &size=wxSize(-1,-1), long style=wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER)
void processItem(BOARD_COMMIT *aCommit, BOARD_CONNECTED_ITEM *aItem)
void visitItem(BOARD_COMMIT *aCommit, BOARD_CONNECTED_ITEM *aItem, bool aSelectAlways)
void OnNetFilterSelect(wxCommandEvent &event)
void setSpecifiedParams(TEARDROP_PARAMETERS *targetParams)
void OnNetclassFilterSelect(wxCommandEvent &event) override
DIALOG_GLOBAL_EDIT_TEARDROPS(PCB_EDIT_FRAME *aParent)
void onTrackToTrack(wxCommandEvent &event) override
void onSpecifiedValuesUpdateUi(wxUpdateUIEvent &event) override
void OnExistingFilterSelect(wxCommandEvent &event) override
void onShowBoardSetup(wxHyperlinkEvent &event) override
void onFilterUpdateUi(wxUpdateUIEvent &event) override
void OnLayerFilterSelect(wxCommandEvent &event) override
void SetupStandardButtons(std::map< int, wxString > aLabels={})
void finishDialogSettings()
In all dialogs, we must call the same functions to fix minimal dlg size, the default position and per...
A set of EDA_ITEMs (i.e., without duplicates).
Definition eda_group.h:43
virtual EDA_GROUP * GetParentGroup() const
Definition eda_item.h:116
bool IsSelected() const
Definition eda_item.h:134
int EditTeardrops(const TOOL_EVENT &aEvent)
static LSET AllNonCuMask()
Return a mask holding all layer minus CU layers.
Definition lset.cpp:623
A collection of nets and the parameters used to route or test these nets.
Definition netclass.h:43
bool ContainsNetclassWithName(const wxString &netclass) const
Determines if the given netclass name is a constituent of this (maybe aggregate) netclass.
Definition netclass.cpp:324
Definition pad.h:61
The main frame for Pcbnew.
Represent a set of closed polygons.
void Inflate(int aAmount, CORNER_STRATEGY aCornerStrategy, int aMaxError, bool aSimplify=false)
Perform outline inflation/deflation.
SHAPE_LINE_CHAIN & Outline(int aIndex)
Return the reference to aIndex-th outline in the set.
void Deflate(int aAmount, CORNER_STRATEGY aCornerStrategy, int aMaxError)
TEARDROP_MANAGER manage and build teardrop areas A teardrop area is a polygonal area (a copper ZONE) ...
Definition teardrop.h:86
static bool IsUniformlyRound(BOARD_ITEM *aItem)
void UpdateTeardrops(BOARD_COMMIT &aCommit, const std::vector< BOARD_ITEM * > *dirtyPadsAndVias, const std::set< PCB_TRACK * > *dirtyTracks, bool aForceFullUpdate=false)
Update teardrops on a list of items.
Definition teardrop.cpp:422
void AddTeardropsOnTracks(BOARD_COMMIT &aCommit, const std::set< PCB_TRACK * > *aTracks, bool aForceFullUpdate=false, bool aSetPriorities=true)
Add teardrop on tracks of different sizes connected by their end.
Definition teardrop.cpp:682
void DeleteTrackToTrackTeardrops(BOARD_COMMIT &aCommit)
Definition teardrop.cpp:604
TEARDROP_PARAMETERS_LIST is a helper class to handle the list of TEARDROP_PARAMETERS needed to build ...
bool m_UseRoundShapesOnly
True to create teardrops for round shapes only.
bool m_TargetVias
True to create teardrops for vias.
bool m_TargetPTHPads
True to create teardrops for pads with holes.
bool m_TargetTrack2Track
True to create teardrops at the end of a track connected to the end of another track having a differe...
TEARDROP_PARAMETERS * GetParameters(TARGET_TD aTdType)
bool m_TargetSMDPads
True to create teardrops for pads SMD, edge connectors,.
TEARDROP_PARAMETARS is a helper class to handle parameters needed to build teardrops for a board thes...
double m_BestWidthRatio
The height of a teardrop as ratio between height and size of pad/via.
int m_TdMaxLen
max allowed length for teardrops in IU. <= 0 to disable
bool m_AllowUseTwoTracks
True to create teardrops using 2 track segments if the first in too small.
int m_TdMaxWidth
max allowed height for teardrops in IU. <= 0 to disable
double m_BestLengthRatio
The length of a teardrop as ratio between length and size of pad/via.
double m_WidthtoSizeFilterRatio
The ratio (H/D) between the via/pad size and the track width max value to create a teardrop 1....
bool m_TdOnPadsInZones
A filter to exclude pads inside zone fills.
bool m_Enabled
Flag to enable teardrops.
bool m_CurvedEdges
True if the teardrop should be curved.
T * getEditFrame() const
Return the application window object, casted to requested user type.
Definition tool_base.h:182
Generic, UI-independent tool event.
Definition tool_event.h:167
void SetProgressReporter(PROGRESS_REPORTER *aReporter)
bool Fill(const std::vector< ZONE * > &aZones, bool aCheck=false, wxWindow *aParent=nullptr)
Fills the given list of zones.
Handle a list of polygons defining a copper zone.
Definition zone.h:70
@ CHT_MODIFY
Definition commit.h:40
static wxString g_netclassFilter
static wxString g_netFilter
#define _(s)
static constexpr EDA_ANGLE FULL_CIRCLE
Definition eda_angle.h:420
int GetArcToSegmentCount(int aRadius, int aErrorMax, const EDA_ANGLE &aArcAngle)
@ UNDEFINED_LAYER
Definition layer_ids.h:57
KICOMMON_API wxFont GetStatusFont(wxWindow *aWindow)
@ SMD
Smd pad, appears on the solder paste layer (default)
Definition padstack.h:98
@ PTH
Plated through hole pad.
Definition padstack.h:97
@ CONN
Like smd, does not appear on the solder paste layer (default) Note: also has a special attribute in G...
Definition padstack.h:99
Class to handle a set of BOARD_ITEMs.
const double epsilon
#define APPEND_UNDO
Definition sch_commit.h:39
std::vector< FAB_LAYER_COLOR > dummy
@ TARGET_ROUND
@ TARGET_RECT
@ TARGET_TRACK
@ PCB_VIA_T
class PCB_VIA, a via (like a track segment on a copper layer)
Definition typeinfo.h:89
#define INDETERMINATE_ACTION
Definition ui_common.h:47