KiCad PCB EDA Suite
Loading...
Searching...
No Matches
dialog_via_stitch_properties.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, 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
26#include <boost/random/mersenne_twister.hpp>
27#include <boost/random/uniform_real_distribution.hpp>
28
29#include <board.h>
30#include <board_commit.h>
36#include <origin_viewitem.h>
37#include <pcb_base_edit_frame.h>
38#include <pcb_painter.h>
39#include <pcb_track.h>
40#include <pgm_base.h>
45#include <widgets/unit_binder.h>
46#include <view/view.h>
47
48
52static constexpr int PREVIEW_TILE_PITCHES = 6;
53
54
56 PCB_VIA_STITCH* aStitch ) :
58 m_frame( aFrame ),
59 m_stitch( aStitch )
60{
61 wxCHECK( m_frame && m_stitch, /* void */ );
62
63 SetTitle( _( "Via Stitching Properties" ) );
64
65 m_pitchBinder = std::make_unique<UNIT_BINDER>( m_frame, m_pitchLabel, m_pitchCtrl,
67 m_posXBinder = std::make_unique<UNIT_BINDER>( m_frame, m_posXLabel, m_posXCtrl,
69 m_posYBinder = std::make_unique<UNIT_BINDER>( m_frame, m_posYLabel, m_posYCtrl,
71
72 auto onNetChanged =
73 [this]( wxCommandEvent& aEvt )
74 {
77 aEvt.Skip();
78 };
79
80 m_netSelector->SetNetInfo( &m_frame->GetBoard()->GetNetInfo() );
81 m_netSelector->Bind( FILTERED_ITEM_SELECTED, onNetChanged );
82
83 m_guardNetSelector->SetNetInfo( &m_frame->GetBoard()->GetNetInfo() );
84 m_guardNetSelector->Bind( FILTERED_ITEM_SELECTED, onNetChanged );
85
86 // Work on a detached clone so changes don't touch the live stitch until OK.
87 m_workingCopy.reset( static_cast<PCB_VIA_STITCH*>( m_stitch->Clone() ) );
88 m_workingCopy->SetParent( m_frame->GetBoard() );
89
91}
92
93
95{
97 {
98 m_panelShowPreview->StopDrawing();
99
100 KIGFX::VIEW* view = m_panelShowPreview->GetView();
101
102 for( std::unique_ptr<PCB_VIA>& via : m_previewVias )
103 view->Remove( via.get() );
104
105 for( std::unique_ptr<PCB_TRACK>& track : m_previewTracks )
106 view->Remove( track.get() );
107
108 if( m_axisOrigin )
109 view->Remove( m_axisOrigin );
110 }
111
112 delete m_axisOrigin;
113}
114
115
117{
118 if( !DIALOG_VIA_STITCH_PROPERTIES_BASE::TransferDataToWindow() )
119 return false;
120
121 m_netSelector->SetSelectedNetcode( m_stitch->GetNetCode() );
122 m_guardNetSelector->SetSelectedNetcode( m_stitch->GetGuardedNetCode() );
123
124 VECTOR2I pos = m_stitch->GetPosition();
125 m_posXBinder->SetValue( pos.x );
126 m_posYBinder->SetValue( pos.y );
127
128 m_pitchBinder->SetValue( m_stitch->GetPitch() );
129
130 m_modeCombo->SetSelection( static_cast<int>( m_stitch->GetMode() ) );
131 m_patternCombo->SetSelection( static_cast<int>( m_stitch->GetLayout() ) );
132 m_seedCtrl->SetValue( wxString::Format( wxT( "%u" ), m_stitch->GetSeed() ) );
133
137
138 // Force the preview to recompute its viewport once the dialog is on screen.
139 PostSizeEvent();
140
141 return true;
142}
143
144
146{
148
149 int newNetCode = m_netSelector->GetSelectedNetcode();
150 if( newNetCode >= 0 )
151 m_stitch->SetNetCode( newNetCode );
152
153 int newGuardedNetCode = m_guardNetSelector->GetSelectedNetcode();
154 if( newGuardedNetCode >= 0 )
155 m_stitch->SetGuardedNetCode( newGuardedNetCode );
156
157 m_stitch->SetPitch( m_pitchBinder->GetIntValue() );
158 m_stitch->SetMode( static_cast<PCB_VIA_STITCH_MODE>( m_modeCombo->GetSelection() ) );
159 m_stitch->SetLayout(
160 static_cast<PCB_VIA_STITCH_LAYOUT>( m_patternCombo->GetSelection() ) );
161
162 unsigned long seedVal = 0;
163 if( m_seedCtrl->GetValue().ToULong( &seedVal ) )
164 m_stitch->SetSeed( static_cast<uint32_t>( seedVal ) );
165
166 // Position: translate the outline to land on the requested first vertex.
167 VECTOR2I newPos( m_posXBinder->GetIntValue(), m_posYBinder->GetIntValue() );
168 VECTOR2I delta = newPos - m_stitch->GetPosition();
169
170 if( delta != VECTOR2I( 0, 0 ) )
171 m_stitch->Move( delta );
172
173 // Propagate any via-template edits the user made via the Configure button.
174 m_stitch->SetTemplateItem( wxS( "via" ),
175 std::make_unique<PCB_VIA>( *m_workingCopy->ViaTemplate() ) );
176
177 return true;
178}
179
180
182{
185 event.Skip();
186}
187
188
190{
192
193 if( dlg.ShowModal() == wxID_OK )
195}
196
197
198void DIALOG_VIA_STITCH_PROPERTIES::OnCancel( wxCommandEvent& event )
199{
200 // Stop the GAL from drawing into a window that's about to be torn down.
202 m_panelShowPreview->StopDrawing();
203
204 event.Skip();
205}
206
207
208void DIALOG_VIA_STITCH_PROPERTIES::OnUpdateUI( wxUpdateUIEvent& event )
209{
210 PCB_VIA_STITCH_MODE mode = static_cast<PCB_VIA_STITCH_MODE>( m_modeCombo->GetSelection() );
211 bool stitching = ( mode == PCB_VIA_STITCH_MODE::STITCH );
212
213 m_patternLabel->Enable( stitching );
214 m_patternCombo->Enable( stitching );
215
216 // ...and the net being guarded means nothing outside of guard mode.
217 m_guardNet->Enable( !stitching );
218 m_guardNetSelector->Enable( !stitching );
219
220 // The seed control is only used for the Poisson layout.
221 PCB_VIA_STITCH_LAYOUT layout =
222 static_cast<PCB_VIA_STITCH_LAYOUT>( m_patternCombo->GetSelection() );
223 bool poisson = stitching && ( layout == PCB_VIA_STITCH_LAYOUT::POISSON );
224
225 m_seedLabel->Enable( poisson );
226 m_seedCtrl->Enable( poisson );
227}
228
229
231{
232 if( !m_workingCopy )
233 return;
234
235 int newNetCode = m_netSelector->GetSelectedNetcode();
236 if( newNetCode >= 0 )
237 m_workingCopy->SetNetCode( newNetCode );
238
239 int newGuardedNetCode = m_guardNetSelector->GetSelectedNetcode();
240 if( newGuardedNetCode >= 0 )
241 m_workingCopy->SetGuardedNetCode( newGuardedNetCode );
242
243 m_workingCopy->SetPitch( m_pitchBinder->GetIntValue() );
244 m_workingCopy->SetMode( static_cast<PCB_VIA_STITCH_MODE>( m_modeCombo->GetSelection() ) );
245 m_workingCopy->SetLayout(
246 static_cast<PCB_VIA_STITCH_LAYOUT>( m_patternCombo->GetSelection() ) );
247
248 unsigned long seedVal = 0;
249 if( m_seedCtrl->GetValue().ToULong( &seedVal ) )
250 m_workingCopy->SetSeed( static_cast<uint32_t>( seedVal ) );
251}
252
253
255{
257 return;
258
259 KIGFX::VIEW* view = m_panelShowPreview->GetView();
260
261 m_panelShowPreview->UpdateColors();
262 m_panelShowPreview->SetStealsFocus( false );
263 m_panelShowPreview->ShowScrollbars( wxSHOW_SB_NEVER, wxSHOW_SB_NEVER );
264
265 auto settings = static_cast<KIGFX::PCB_RENDER_SETTINGS*>( view->GetPainter()->GetSettings() );
266 settings->SetHighContrast( false );
267 settings->m_ContrastModeDisplay = HIGH_CONTRAST_MODE::NORMAL;
268
269 view->GetGAL()->SetGridVisibility( false );
270 view->GetGAL()->SetAxesEnabled( false );
271
272 // A faint crosshair at the tile origin as a reference point
273 COLOR4D axisColor =
274 m_frame->GetColorSettings()->GetColor( LAYER_GRID );
276 100000, VECTOR2D( 0, 0 ) );
277 m_axisOrigin->SetDrawAtZero( true );
278 view->Add( m_axisOrigin );
279
280 m_panelShowPreview->StartDrawing();
281 m_canvasInitialized = true;
282
283 m_panelShowPreview->Bind( wxEVT_SIZE,
284 [this]( wxSizeEvent& aEvt )
285 {
286 aEvt.Skip();
287
288 CallAfter(
289 [this]()
290 {
291 fitPreview();
292 } );
293 } );
294}
295
296
298{
300 return;
301
302 KIGFX::VIEW* view = m_panelShowPreview->GetView();
303
304 // Drop everything old
305 for( std::unique_ptr<PCB_VIA>& via : m_previewVias )
306 view->Remove( via.get() );
307
308 m_previewVias.clear();
309
310 for( std::unique_ptr<PCB_TRACK>& track : m_previewTracks )
311 view->Remove( track.get() );
312
313 m_previewTracks.clear();
314
315 if( m_workingCopy->GetPitch() <= 0 )
316 {
317 m_previewExtent = 0;
318 m_panelShowPreview->Refresh();
319 return;
320 }
321
322 std::vector<VECTOR2I> samples;
323 int previewExtent;
324
325 if( m_workingCopy->GetMode() == PCB_VIA_STITCH_MODE::GUARD )
326 previewExtent = buildGuardPreview( samples );
327 else
328 previewExtent = buildStitchPreview( samples );
329
330 for( const VECTOR2I& pt : samples )
331 {
332 std::unique_ptr<PCB_VIA> via(
333 static_cast<PCB_VIA*>( m_workingCopy->ViaTemplate()->Clone() ) );
334 via->ResetUuidDirect();
335 via->SetParent( m_frame->GetBoard() );
336 via->SetPosition( pt );
337 via->SetIsFree( true );
338
339 view->Add( via.get() );
340 m_previewVias.push_back( std::move( via ) );
341 }
342
343 m_previewExtent = previewExtent;
344 fitPreview();
345
346 m_panelShowPreview->Refresh();
347}
348
349
350int DIALOG_VIA_STITCH_PROPERTIES::buildStitchPreview( std::vector<VECTOR2I>& aSamples )
351{
352 const int pitch = m_workingCopy->GetPitch();
353
354 PCB_VIA_STITCH_LAYOUT layout = m_workingCopy->GetLayout();
355
356 if( layout == PCB_VIA_STITCH_LAYOUT::POISSON )
357 {
358 // The seed only affects the per-seed sub-tile origin shift — so to see its
359 // effect the preview has to span more than one tile. Show a 2x2 grid of
360 // tiles with the seed-driven shift applied, matching what buildPlacementCells
361 // does for the real placement.
362 const std::vector<VECTOR2D>& tile = PCB_VIA_STITCH::bakedPoissonTile();
363 const int tileSize = pitch * PCB_VIA_STITCH::POISSON_TILE_PITCHES;
364 const int numTiles = 2;
365 const int previewExtent = tileSize * numTiles;
366
367 boost::random::mt19937 seedRng( m_workingCopy->GetSeed() );
368 boost::random::uniform_real_distribution<double> uniform( 0.0, 1.0 );
369 const double offsetX = uniform( seedRng ) * tileSize;
370 const double offsetY = uniform( seedRng ) * tileSize;
371
372 const int firstTileX = (int) std::floor( ( 0.0 - offsetX ) / (double) tileSize );
373 const int firstTileY = (int) std::floor( ( 0.0 - offsetY ) / (double) tileSize );
374 const int lastTileX = (int) std::floor( ( (double) previewExtent - offsetX )
375 / (double) tileSize );
376 const int lastTileY = (int) std::floor( ( (double) previewExtent - offsetY )
377 / (double) tileSize );
378
379 for( int ty = firstTileY; ty <= lastTileY; ++ty )
380 {
381 for( int tx = firstTileX; tx <= lastTileX; ++tx )
382 {
383 for( const VECTOR2D& s : tile )
384 {
385 VECTOR2I pt( (int) std::round( offsetX + ( tx + s.x ) * tileSize ),
386 (int) std::round( offsetY + ( ty + s.y ) * tileSize ) );
387
388 // Clip to the preview window so we don't draw far-off vias that
389 // would force the autozoom out.
390 if( pt.x < 0 || pt.x > previewExtent
391 || pt.y < 0 || pt.y > previewExtent )
392 continue;
393
394 aSamples.push_back( pt );
395 }
396 }
397 }
398
399 return previewExtent;
400 }
401
402 for( int row = 0; row < PREVIEW_TILE_PITCHES; ++row )
403 {
404 int xShift = ( layout == PCB_VIA_STITCH_LAYOUT::STAGGERED && ( row % 2 ) ) ? pitch / 2
405 : 0;
406
407 for( int col = 0; col < PREVIEW_TILE_PITCHES; ++col )
408 aSamples.emplace_back( col * pitch + xShift, row * pitch );
409 }
410
411 return pitch * PREVIEW_TILE_PITCHES;
412}
413
414
415int DIALOG_VIA_STITCH_PROPERTIES::buildGuardPreview( std::vector<VECTOR2I>& aSamples )
416{
417 const int pitch = m_workingCopy->GetPitch();
418 const int extent = pitch * PREVIEW_TILE_PITCHES;
419
420 int viaSize = m_workingCopy->ViaTemplate()->GetWidth( PADSTACK::ALL_LAYERS );
421
422 if( viaSize <= 0 )
423 viaSize = pcbIUScale.mmToIU( 0.6 );
424
425 BOARD* board = m_frame->GetBoard();
427
428 const int trackWidth = std::max( bds.GetCurrentTrackWidth(), pcbIUScale.mmToIU( 0.05 ) );
429 // Determine the clearance for a semi-accurate preview
431
432 for( NET_SELECTOR* selector : { m_netSelector, m_guardNetSelector } )
433 {
434 NETINFO_ITEM* net = board->FindNet( selector->GetSelectedNetcode() );
435
436 if( net && net->GetNetClass() )
437 {
438 if( net->GetNetClass()->HasClearance() )
439 clearance = std::max( clearance, net->GetNetClass()->GetClearance() );
440 }
441 }
442
443 const std::vector<VECTOR2I> corners = {
444 { extent * 12 / 100, extent * 78 / 100 },
445 { extent * 38 / 100, extent * 78 / 100 },
446 { extent * 62 / 100, extent * 22 / 100 },
447 { extent * 88 / 100, extent * 22 / 100 },
448 };
449
450 const int polyApproxError = bds.m_MaxError;
451 const int safetyMargin = polyApproxError + pcbIUScale.mmToIU( 0.002 );
452 const int margin = viaSize / 2 + clearance + safetyMargin;
453
454 KIGFX::VIEW* view = m_panelShowPreview->GetView();
455 SHAPE_POLY_SET envelope;
456 SHAPE_POLY_SET guarded;
457
458 for( size_t ii = 1; ii < corners.size(); ++ii )
459 {
460 std::unique_ptr<PCB_TRACK> track = std::make_unique<PCB_TRACK>( board );
461 track->SetLayer( F_Cu );
462 track->SetWidth( trackWidth );
463 track->SetStart( corners[ii - 1] );
464 track->SetEnd( corners[ii] );
465
466 track->TransformShapeToPolygon( envelope, F_Cu, margin, polyApproxError, ERROR_OUTSIDE );
467 track->TransformShapeToPolygon( guarded, F_Cu, 0, polyApproxError, ERROR_OUTSIDE );
468
469 view->Add( track.get() );
470 m_previewTracks.push_back( std::move( track ) );
471 }
472
473 envelope.Simplify();
474 guarded.Simplify();
475
476 aSamples = PCB_VIA_STITCH::SampleGuardEnvelope( envelope, guarded, pitch,
477 []( const VECTOR2I& )
478 {
479 return true;
480 } );
481
482 return extent;
483}
484
485
487{
489 return;
490
491 KIGFX::VIEW* view = m_panelShowPreview->GetView();
492
493 // Make sure we don't try fit too early
494 if( view->GetGAL()->GetScreenPixelSize().x <= 0
495 || view->GetGAL()->GetScreenPixelSize().y <= 0 )
496 {
497 return;
498 }
499
500 // Frame the preview window with a bit of margin.
501 int margin = m_workingCopy->GetPitch() > 0 ? m_workingCopy->GetPitch() : 1;
502 BOX2D viewBox( VECTOR2D( 0, 0 ), VECTOR2D( m_previewExtent, m_previewExtent ) );
503
504 viewBox.Inflate( margin );
505 view->SetViewport( viewBox );
506
507 m_panelShowPreview->Refresh();
508}
@ ERROR_OUTSIDE
constexpr EDA_IU_SCALE pcbIUScale
Definition base_units.h:121
@ NORMAL
Inactive layers are shown normally (no high-contrast mode)
BOX2< VECTOR2D > BOX2D
Definition box2.h:928
Container for design settings for a BOARD object.
std::shared_ptr< NET_SETTINGS > m_NetSettings
Information pertinent to a Pcbnew printed circuit board.
Definition board.h:409
NETINFO_ITEM * FindNet(int aNetcode) const
Search for a net with the given netcode.
Definition board.cpp:2980
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition board.cpp:1299
constexpr BOX2< Vec > & Inflate(coord_type dx, coord_type dy)
Inflates the rectangle horizontally by dx and vertically by dy.
Definition box2.h:553
void SetupStandardButtons(std::map< int, wxString > aLabels={})
int ShowModal() override
DIALOG_VIA_STITCH_PROPERTIES_BASE(wxWindow *parent, wxWindowID id=wxID_DIALOG_EDIT_PAD, const wxString &title=_("Via Stitch Properties"), const wxPoint &pos=wxDefaultPosition, const wxSize &size=wxSize(-1,-1), long style=wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER)
void OnCancel(wxCommandEvent &event) override
std::unique_ptr< UNIT_BINDER > m_posYBinder
std::vector< std::unique_ptr< PCB_VIA > > m_previewVias
Vias currently in the preview canvas, used for both Guard and Stitch mode previews.
DIALOG_VIA_STITCH_PROPERTIES(PCB_BASE_EDIT_FRAME *aFrame, PCB_VIA_STITCH *aStitch)
std::unique_ptr< PCB_VIA_STITCH > m_workingCopy
Off-board clone of m_stitch used to drive the preview without touching the board.
void OnUpdateUI(wxUpdateUIEvent &event) override
int m_previewExtent
Side length of the tile drawn by the last redrawPreview(), in IU; 0 if nothing is currently drawn.
int buildStitchPreview(std::vector< VECTOR2I > &aSamples)
Builds a preview for stitch mode.
int buildGuardPreview(std::vector< VECTOR2I > &aSamples)
Builds a preview for guard mode.
void OnViaConfigureClicked(wxCommandEvent &event) override
std::vector< std::unique_ptr< PCB_TRACK > > m_previewTracks
Tracks currently in the preview canvas, only used for Guard mode preview.
void redrawPreview()
Push the GAL preview to reflect the current m_workingCopy state.
std::unique_ptr< UNIT_BINDER > m_pitchBinder
PCB_VIA_STITCH * m_stitch
The live generator being edited. Only written back on OK.
void OnValuesChanged(wxCommandEvent &event) override
void prepareCanvas()
First-time set-up of m_panelShowPreview — colors, view layers, board attachment.
void updateWorkingCopyFromUI()
Pull values out of UI controls into m_workingCopy, regenerate its children, and re-zoom the preview c...
std::unique_ptr< UNIT_BINDER > m_posXBinder
void fitPreview()
Autozoom the preview canvas onto the last-rendered tile.
A color representation with 4 components: red, green, blue, alpha.
Definition color4d.h:101
void SetAxesEnabled(bool aAxesEnabled)
Enable drawing the axes.
const VECTOR2I & GetScreenPixelSize() const
Return GAL canvas size in pixels.
void SetGridVisibility(bool aVisibility)
Set the visibility setting of the grid.
PCB specific render settings.
Definition pcb_painter.h:84
void SetHighContrast(bool aEnabled)
Turns on/off high contrast display mode.
Hold a (potentially large) number of VIEW_ITEMs and renders them on a graphics device provided by the...
Definition view.h:63
void SetViewport(const BOX2D &aViewport)
Set the visible area of the VIEW.
Definition view.cpp:627
virtual void Add(VIEW_ITEM *aItem, int aDrawPriority=-1)
Add a VIEW_ITEM to the view.
Definition view.cpp:301
virtual void Remove(VIEW_ITEM *aItem)
Remove a VIEW_ITEM from the view.
Definition view.cpp:416
GAL * GetGAL() const
Return the GAL this view is using to draw graphical primitives.
Definition view.h:207
PAINTER * GetPainter() const
Return the painter object used by the view for drawing #VIEW_ITEMS.
Definition view.h:225
int GetClearance() const
Definition netclass.h:131
bool HasClearance() const
Definition netclass.h:130
Handle the data for a net.
Definition netinfo.h:50
NETCLASS * GetNetClass()
Definition netinfo.h:101
std::shared_ptr< NETCLASS > GetDefaultNetclass() const
Gets the default netclass for the project.
static constexpr PCB_LAYER_ID ALL_LAYERS
! The layer identifier to use for the single defintion on normal padstacks
Definition padstack.h:179
Common, abstract interface for edit frames.
static std::vector< VECTOR2I > SampleGuardEnvelope(const SHAPE_POLY_SET &aEnvelope, const SHAPE_POLY_SET &aGuarded, int aPitch, const std::function< bool(const VECTOR2I &)> &aIsValid)
Determine via positions around the perimeter of a guard envelope.
static const std::vector< VECTOR2D > & bakedPoissonTile()
Helper method to cache the poisson tile we pattern.
static constexpr int POISSON_TILE_PITCHES
Tile size for the POISSON layout, in units of pitch.
Represent a set of closed polygons.
void Simplify()
Simplify the polyset (merges overlapping polys, eliminates degeneracy/self-intersections)
static constexpr int PREVIEW_TILE_PITCHES
How many pitches to show on a side of the preview tile.
#define _(s)
@ LAYER_GRID
Definition layer_ids.h:250
@ F_Cu
Definition layer_ids.h:60
PCB_VIA_STITCH_MODE
@ STITCH
Fill the outline with vias with a pattern.
@ GUARD
Place vias to guard a net contained within.
PCB_VIA_STITCH_LAYOUT
@ POISSON
Tiled poisson distribution.
@ STAGGERED
Odd rows shifted by half the pitch.
see class PGM_BASE
int clearance
int delta
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:683
VECTOR2< double > VECTOR2D
Definition vector2d.h:682