KiCad PCB EDA Suite
pcb_grid_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) 2014 CERN
5  * Copyright (C) 2018-2021 KiCad Developers, see AUTHORS.txt for contributors.
6  * @author Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License
10  * as published by the Free Software Foundation; either version 2
11  * of the License, or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, you may find one here:
20  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
21  * or you may search the http://www.gnu.org website for the version 2 license,
22  * or you may write to the Free Software Foundation, Inc.,
23  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
24  */
25 
26 #include <functional>
27 #include <board.h>
28 #include <pcb_dimension.h>
29 #include <fp_shape.h>
30 #include <footprint.h>
31 #include <pad.h>
32 #include <pcb_group.h>
33 #include <pcb_track.h>
34 #include <zone.h>
35 #include <geometry/shape_circle.h>
37 #include <geometry/shape_rect.h>
38 #include <geometry/shape_segment.h>
39 #include <geometry/shape_simple.h>
40 #include <macros.h>
41 #include <math/util.h> // for KiROUND
42 #include <painter.h>
43 #include <pcbnew_settings.h>
44 #include <tool/tool_manager.h>
45 #include <tools/pcb_tool_base.h>
46 #include <view/view.h>
47 #include "pcb_grid_helper.h"
48 
49 
51  GRID_HELPER( aToolMgr ),
52  m_magneticSettings( aMagneticSettings )
53 {
54  KIGFX::VIEW* view = m_toolMgr->GetView();
55  KIGFX::RENDER_SETTINGS* settings = view->GetPainter()->GetSettings();
56  KIGFX::COLOR4D auxItemsColor = settings->GetLayerColor( LAYER_AUX_ITEMS );
57  KIGFX::COLOR4D umbilicalColor = settings->GetLayerColor( LAYER_ANCHOR );
58 
59  m_viewAxis.SetSize( 20000 );
61  m_viewAxis.SetColor( auxItemsColor.WithAlpha( 0.4 ) );
62  m_viewAxis.SetDrawAtZero( true );
63  view->Add( &m_viewAxis );
64  view->SetVisible( &m_viewAxis, false );
65 
67  m_viewSnapPoint.SetColor( auxItemsColor );
69  view->Add( &m_viewSnapPoint );
70  view->SetVisible( &m_viewSnapPoint, false );
71 
73  m_viewSnapLine.SetColor( umbilicalColor );
75  view->Add( &m_viewSnapLine );
76  view->SetVisible( &m_viewSnapLine, false );
77 }
78 
79 
81 {
82  OPT_VECTOR2I pts[6];
83 
84  const int c_gridSnapEpsilon = 2;
85 
86  if( !m_enableSnap )
87  return aPoint;
88 
89  VECTOR2I nearest = Align( aPoint );
90 
91  SEG pos_slope( nearest + VECTOR2I( -1, 1 ), nearest + VECTOR2I( 1, -1 ) );
92  SEG neg_slope( nearest + VECTOR2I( -1, -1 ), nearest + VECTOR2I( 1, 1 ) );
93  int max_i = 2;
94 
95  pts[0] = aSeg.A;
96  pts[1] = aSeg.B;
97 
98  if( !aSeg.ApproxParallel( pos_slope ) )
99  pts[max_i++] = aSeg.IntersectLines( pos_slope );
100 
101  if( !aSeg.ApproxParallel( neg_slope ) )
102  pts[max_i++] = aSeg.IntersectLines( neg_slope );
103 
104  int min_d = std::numeric_limits<int>::max();
105 
106  for( int i = 0; i < max_i; i++ )
107  {
108  if( pts[i] && aSeg.Distance( *pts[i] ) <= c_gridSnapEpsilon )
109  {
110  int d = (*pts[i] - aPoint).EuclideanNorm();
111 
112  if( d < min_d )
113  {
114  min_d = d;
115  nearest = *pts[i];
116  }
117  }
118  }
119 
120  return nearest;
121 }
122 
123 
125 {
126  if( !m_enableSnap )
127  return aPoint;
128 
129  const VECTOR2D gridOffset( GetOrigin() );
130  const VECTOR2D gridSize( GetGrid() );
131 
132  VECTOR2I nearest( KiROUND( ( aPoint.x - gridOffset.x ) / gridSize.x ) * gridSize.x + gridOffset.x,
133  KiROUND( ( aPoint.y - gridOffset.y ) / gridSize.y ) * gridSize.y + gridOffset.y );
134 
135  int min_d = std::numeric_limits<int>::max();
136 
137  for( auto pt : { aArc.GetP0(), aArc.GetP1() } )
138  {
139  int d = ( pt - aPoint ).EuclideanNorm();
140 
141  if( d < min_d )
142  {
143  min_d = d;
144  nearest = pt;
145  }
146  else
147  break;
148  }
149 
150  return nearest;
151 }
152 
153 
155  std::vector<BOARD_ITEM*>& aItems )
156 {
157  clearAnchors();
158 
159  for( BOARD_ITEM* item : aItems )
160  computeAnchors( item, aMousePos, true );
161 
162  double worldScale = m_toolMgr->GetView()->GetGAL()->GetWorldScale();
163  double lineSnapMinCornerDistance = 50.0 / worldScale;
164 
165  ANCHOR* nearestOutline = nearestAnchor( aMousePos, OUTLINE, LSET::AllLayersMask() );
166  ANCHOR* nearestCorner = nearestAnchor( aMousePos, CORNER, LSET::AllLayersMask() );
167  ANCHOR* nearestOrigin = nearestAnchor( aMousePos, ORIGIN, LSET::AllLayersMask() );
168  ANCHOR* best = nullptr;
169  double minDist = std::numeric_limits<double>::max();
170 
171  if( nearestOrigin )
172  {
173  minDist = nearestOrigin->Distance( aMousePos );
174  best = nearestOrigin;
175  }
176 
177  if( nearestCorner )
178  {
179  double dist = nearestCorner->Distance( aMousePos );
180 
181  if( dist < minDist )
182  {
183  minDist = dist;
184  best = nearestCorner;
185  }
186  }
187 
188  if( nearestOutline )
189  {
190  double dist = nearestOutline->Distance( aMousePos );
191 
192  if( minDist > lineSnapMinCornerDistance && dist < minDist )
193  best = nearestOutline;
194  }
195 
196  return best ? best->pos : aMousePos;
197 }
198 
199 
201 {
202  LSET layers;
203  std::vector<BOARD_ITEM*> item;
204 
205  if( aReferenceItem )
206  {
207  layers = aReferenceItem->GetLayerSet();
208  item.push_back( aReferenceItem );
209  }
210  else
211  {
212  layers = LSET::AllLayersMask();
213  }
214 
215  return BestSnapAnchor( aOrigin, layers, item );
216 }
217 
218 
219 VECTOR2I PCB_GRID_HELPER::BestSnapAnchor( const VECTOR2I& aOrigin, const LSET& aLayers,
220  const std::vector<BOARD_ITEM*>& aSkip )
221 {
222  // Tuning constant: snap radius in screen space
223  const int snapSize = 25;
224 
225  // Snapping distance is in screen space, clamped to the current grid to ensure that the grid
226  // points that are visible can always be snapped to.
227  // see https://gitlab.com/kicad/code/kicad/-/issues/5638
228  // see https://gitlab.com/kicad/code/kicad/-/issues/7125
229  double snapScale = snapSize / m_toolMgr->GetView()->GetGAL()->GetWorldScale();
230  int snapRange = std::min( KiROUND( snapScale ), GetGrid().x );
231  int snapDist = snapRange;
232 
233  BOX2I bb( VECTOR2I( aOrigin.x - snapRange / 2, aOrigin.y - snapRange / 2 ),
234  VECTOR2I( snapRange, snapRange ) );
235 
236  clearAnchors();
237 
238  for( BOARD_ITEM* item : queryVisible( bb, aSkip ) )
239  computeAnchors( item, aOrigin );
240 
241  ANCHOR* nearest = nearestAnchor( aOrigin, SNAPPABLE, aLayers );
242  VECTOR2I nearestGrid = Align( aOrigin );
243 
244  if( nearest )
245  snapDist = nearest->Distance( aOrigin );
246 
247  // Existing snap lines need priority over new snaps
249  {
250  bool snapLine = false;
251  int x_dist = std::abs( m_viewSnapLine.GetPosition().x - aOrigin.x );
252  int y_dist = std::abs( m_viewSnapLine.GetPosition().y - aOrigin.y );
253 
255  if( x_dist < snapRange && ( !nearest || snapDist > snapRange ) )
256  {
257  nearestGrid.x = m_viewSnapLine.GetPosition().x;
258  snapLine = true;
259  }
260 
261  if( y_dist < snapRange && ( !nearest || snapDist > snapRange ) )
262  {
263  nearestGrid.y = m_viewSnapLine.GetPosition().y;
264  snapLine = true;
265  }
266 
267  if( snapLine && m_skipPoint != VECTOR2I( m_viewSnapLine.GetPosition() ) )
268  {
269  m_viewSnapLine.SetEndPosition( nearestGrid );
270 
273  else
275 
276  return nearestGrid;
277  }
278  }
279 
280  if( nearest && m_enableSnap )
281  {
282  if( nearest->Distance( aOrigin ) <= snapRange )
283  {
284  m_viewSnapPoint.SetPosition( wxPoint( nearest->pos ) );
285  m_viewSnapLine.SetPosition( wxPoint( nearest->pos ) );
287 
290  else
292 
293  m_snapItem = nearest;
294  return nearest->pos;
295  }
296  }
297 
298  m_snapItem = nullptr;
301  return nearestGrid;
302 }
303 
304 
306 {
307  if( !m_snapItem )
308  return nullptr;
309 
310  return static_cast<BOARD_ITEM*>( m_snapItem->item );
311 }
312 
313 
314 std::set<BOARD_ITEM*> PCB_GRID_HELPER::queryVisible( const BOX2I& aArea,
315  const std::vector<BOARD_ITEM*>& aSkip ) const
316 {
317  std::set<BOARD_ITEM*> items;
318  std::vector<KIGFX::VIEW::LAYER_ITEM_PAIR> selectedItems;
319 
320  KIGFX::VIEW* view = m_toolMgr->GetView();
321  RENDER_SETTINGS* settings = view->GetPainter()->GetSettings();
322  const std::set<unsigned int>& activeLayers = settings->GetHighContrastLayers();
323  bool isHighContrast = settings->GetHighContrast();
324 
325  view->Query( aArea, selectedItems );
326 
327  for( const KIGFX::VIEW::LAYER_ITEM_PAIR& it : selectedItems )
328  {
329  BOARD_ITEM* item = static_cast<BOARD_ITEM*>( it.first );
330 
331  // If we are in the footprint editor, don't use the footprint itself
332  if( static_cast<PCB_TOOL_BASE*>( m_toolMgr->GetCurrentTool() )->IsFootprintEditor()
333  && item->Type() == PCB_FOOTPRINT_T )
334  {
335  continue;
336  }
337 
338  // The item must be visible and on an active layer
339  if( view->IsVisible( item )
340  && ( !isHighContrast || activeLayers.count( it.second ) )
341  && item->ViewGetLOD( it.second, view ) < view->GetScale() )
342  {
343  items.insert ( item );
344  }
345  }
346 
347  for( BOARD_ITEM* skipItem : aSkip )
348  items.erase( skipItem );
349 
350  return items;
351 }
352 
353 
354 void PCB_GRID_HELPER::computeAnchors( BOARD_ITEM* aItem, const VECTOR2I& aRefPos, bool aFrom )
355 {
356  KIGFX::VIEW* view = m_toolMgr->GetView();
357  RENDER_SETTINGS* settings = view->GetPainter()->GetSettings();
358  const std::set<unsigned int>& activeLayers = settings->GetHighContrastLayers();
359  bool isHighContrast = settings->GetHighContrast();
360 
361  auto handlePadShape =
362  [&]( PAD* aPad )
363  {
364  addAnchor( aPad->GetPosition(), ORIGIN | SNAPPABLE, aPad );
365 
367  if( aFrom )
368  return;
369 
370  const std::shared_ptr<SHAPE> eshape = aPad->GetEffectiveShape( aPad->GetLayer() );
371 
372  wxASSERT( eshape->Type() == SH_COMPOUND );
373  const std::vector<SHAPE*> shapes =
374  static_cast<const SHAPE_COMPOUND*>( eshape.get() )->Shapes();
375 
376  for( const SHAPE* shape : shapes )
377  {
378  switch( shape->Type() )
379  {
380  case SH_RECT:
381  {
382  const SHAPE_RECT* rect = static_cast<const SHAPE_RECT*>( shape );
383  SHAPE_LINE_CHAIN outline = rect->Outline();
384 
385  for( int i = 0; i < outline.SegmentCount(); i++ )
386  {
387  const SEG& seg = outline.CSegment( i );
388  addAnchor( seg.A, OUTLINE | SNAPPABLE, aPad );
389  addAnchor( seg.Center(), OUTLINE | SNAPPABLE, aPad );
390  }
391 
392  break;
393  }
394 
395  case SH_SEGMENT:
396  {
397  const SHAPE_SEGMENT* segment = static_cast<const SHAPE_SEGMENT*>( shape );
398 
399  int offset = segment->GetWidth() / 2;
400  SEG seg = segment->GetSeg();
401  VECTOR2I normal = ( seg.B - seg.A ).Resize( offset ).Rotate( -M_PI_2 );
402 
403  /*
404  * TODO: This creates more snap points than necessary for rounded rect pads
405  * because they are built up of overlapping segments. We could fix this if
406  * desired by testing these to see if they are "inside" the pad.
407  */
408 
409  addAnchor( seg.A + normal, OUTLINE | SNAPPABLE, aPad );
410  addAnchor( seg.A - normal, OUTLINE | SNAPPABLE, aPad );
411  addAnchor( seg.B + normal, OUTLINE | SNAPPABLE, aPad );
412  addAnchor( seg.B - normal, OUTLINE | SNAPPABLE, aPad );
413  addAnchor( seg.Center() + normal, OUTLINE | SNAPPABLE, aPad );
414  addAnchor( seg.Center() - normal, OUTLINE | SNAPPABLE, aPad );
415 
416  normal = normal.Rotate( M_PI_2 );
417 
418  addAnchor( seg.A - normal, OUTLINE | SNAPPABLE, aPad );
419  addAnchor( seg.B + normal, OUTLINE | SNAPPABLE, aPad );
420  break;
421  }
422 
423  case SH_CIRCLE:
424  {
425  const SHAPE_CIRCLE* circle = static_cast<const SHAPE_CIRCLE*>( shape );
426 
427  int r = circle->GetRadius();
428  VECTOR2I start = circle->GetCenter();
429 
430  addAnchor( start + VECTOR2I( -r, 0 ), OUTLINE | SNAPPABLE, aPad );
431  addAnchor( start + VECTOR2I( r, 0 ), OUTLINE | SNAPPABLE, aPad );
432  addAnchor( start + VECTOR2I( 0, -r ), OUTLINE | SNAPPABLE, aPad );
433  addAnchor( start + VECTOR2I( 0, r ), OUTLINE | SNAPPABLE, aPad );
434  break;
435  }
436 
437  case SH_ARC:
438  {
439  const SHAPE_ARC* arc = static_cast<const SHAPE_ARC*>( shape );
440 
441  addAnchor( arc->GetP0(), OUTLINE | SNAPPABLE, aPad );
442  addAnchor( arc->GetP1(), OUTLINE | SNAPPABLE, aPad );
443  addAnchor( arc->GetArcMid(), OUTLINE | SNAPPABLE, aPad );
444  break;
445  }
446 
447  case SH_SIMPLE:
448  {
449  const SHAPE_SIMPLE* poly = static_cast<const SHAPE_SIMPLE*>( shape );
450 
451  for( size_t i = 0; i < poly->GetSegmentCount(); i++ )
452  {
453  const SEG& seg = poly->GetSegment( i );
454 
455  addAnchor( seg.A, OUTLINE | SNAPPABLE, aPad );
456  addAnchor( seg.Center(), OUTLINE | SNAPPABLE, aPad );
457 
458  if( i == poly->GetSegmentCount() - 1 )
459  addAnchor( seg.B, OUTLINE | SNAPPABLE, aPad );
460  }
461 
462  break;
463  }
464 
465  case SH_POLY_SET:
466  case SH_LINE_CHAIN:
467  case SH_COMPOUND:
469  case SH_NULL:
470  default:
471  break;
472  }
473  }
474  };
475 
476  switch( aItem->Type() )
477  {
478  case PCB_FOOTPRINT_T:
479  {
480  FOOTPRINT* footprint = static_cast<FOOTPRINT*>( aItem );
481 
482  for( PAD* pad : footprint->Pads() )
483  {
484  // Getting pads from the footprint requires re-checking that the pad is shown
486  && pad->GetBoundingBox().Contains( wxPoint( aRefPos.x, aRefPos.y ) )
487  && view->IsVisible( pad )
488  && ( !isHighContrast || activeLayers.count( pad->GetLayer() ) )
489  && pad->ViewGetLOD( pad->GetLayer(), view ) < view->GetScale() )
490  {
491  handlePadShape( pad );
492  break;
493  }
494  }
495 
496  // if the cursor is not over a pad, then drag the footprint by its origin
497  VECTOR2I position = footprint->GetPosition();
498  addAnchor( position, ORIGIN | SNAPPABLE, footprint );
499 
500  // Add the footprint center point if it is markedly different from the origin
501  VECTOR2I center = footprint->GetBoundingBox( false, false ).Centre();
502  VECTOR2I grid( GetGrid() );
503 
504  if( ( center - position ).SquaredEuclideanNorm() > grid.SquaredEuclideanNorm() )
505  addAnchor( center, ORIGIN | SNAPPABLE, footprint );
506 
507  break;
508  }
509 
510  case PCB_PAD_T:
511  {
513  {
514  PAD* pad = static_cast<PAD*>( aItem );
515  handlePadShape( pad );
516  }
517 
518  break;
519  }
520 
521  case PCB_FP_SHAPE_T:
522  case PCB_SHAPE_T:
523  {
525  break;
526 
527  PCB_SHAPE* shape = static_cast<PCB_SHAPE*>( aItem );
528  VECTOR2I start = shape->GetStart();
529  VECTOR2I end = shape->GetEnd();
530 
531  switch( shape->GetShape() )
532  {
533  case SHAPE_T::CIRCLE:
534  {
535  int r = ( start - end ).EuclideanNorm();
536 
537  addAnchor( start, ORIGIN | SNAPPABLE, shape );
538  addAnchor( start + VECTOR2I( -r, 0 ), OUTLINE | SNAPPABLE, shape );
539  addAnchor( start + VECTOR2I( r, 0 ), OUTLINE | SNAPPABLE, shape );
540  addAnchor( start + VECTOR2I( 0, -r ), OUTLINE | SNAPPABLE, shape );
541  addAnchor( start + VECTOR2I( 0, r ), OUTLINE | SNAPPABLE, shape );
542  break;
543  }
544 
545  case SHAPE_T::ARC:
546  addAnchor( shape->GetArcStart(), CORNER | SNAPPABLE, shape );
547  addAnchor( shape->GetArcEnd(), CORNER | SNAPPABLE, shape );
548  addAnchor( shape->GetArcMid(), CORNER | SNAPPABLE, shape );
549  addAnchor( shape->GetCenter(), ORIGIN | SNAPPABLE, shape );
550  break;
551 
552  case SHAPE_T::RECT:
553  {
554  VECTOR2I point2( end.x, start.y );
555  VECTOR2I point3( start.x, end.y );
556  SEG first( start, point2 );
557  SEG second( point2, end );
558  SEG third( end, point3 );
559  SEG fourth( point3, start );
560 
561  addAnchor( first.A, CORNER | SNAPPABLE, shape );
562  addAnchor( first.Center(), CORNER | SNAPPABLE, shape );
563  addAnchor( second.A, CORNER | SNAPPABLE, shape );
564  addAnchor( second.Center(), CORNER | SNAPPABLE, shape );
565  addAnchor( third.A, CORNER | SNAPPABLE, shape );
566  addAnchor( third.Center(), CORNER | SNAPPABLE, shape );
567  addAnchor( fourth.A, CORNER | SNAPPABLE, shape );
568  addAnchor( fourth.Center(), CORNER | SNAPPABLE, shape );
569  break;
570  }
571 
572  case SHAPE_T::SEGMENT:
573  addAnchor( start, CORNER | SNAPPABLE, shape );
574  addAnchor( end, CORNER | SNAPPABLE, shape );
575  addAnchor( shape->GetCenter(), CORNER | SNAPPABLE, shape );
576  break;
577 
578  case SHAPE_T::POLY:
579  {
580  SHAPE_LINE_CHAIN lc;
581  lc.SetClosed( true );
582  std::vector<wxPoint> poly;
583  shape->DupPolyPointsList( poly );
584 
585  for( const wxPoint& p : poly )
586  {
587  addAnchor( p, CORNER | SNAPPABLE, shape );
588  lc.Append( p );
589  }
590 
591  addAnchor( lc.NearestPoint( aRefPos ), OUTLINE, aItem );
592  break;
593  }
594 
595  case SHAPE_T::BEZIER:
596  addAnchor( start, CORNER | SNAPPABLE, shape );
597  addAnchor( end, CORNER | SNAPPABLE, shape );
599 
600  default:
601  addAnchor( shape->GetStart(), ORIGIN | SNAPPABLE, shape );
602  break;
603  }
604  break;
605  }
606 
607  case PCB_TRACE_T:
608  case PCB_ARC_T:
609  {
611  {
612  PCB_TRACK* track = static_cast<PCB_TRACK*>( aItem );
613 
614  addAnchor( track->GetStart(), CORNER | SNAPPABLE, track );
615  addAnchor( track->GetEnd(), CORNER | SNAPPABLE, track );
616  addAnchor( track->GetCenter(), ORIGIN, track);
617  }
618 
619  break;
620  }
621 
622  case PCB_MARKER_T:
623  case PCB_TARGET_T:
624  addAnchor( aItem->GetPosition(), ORIGIN | CORNER | SNAPPABLE, aItem );
625  break;
626 
627  case PCB_VIA_T:
628  {
630  addAnchor( aItem->GetPosition(), ORIGIN | CORNER | SNAPPABLE, aItem );
631 
632  break;
633  }
634 
635  case PCB_ZONE_T:
636  {
637  const SHAPE_POLY_SET* outline = static_cast<const ZONE*>( aItem )->Outline();
638 
639  SHAPE_LINE_CHAIN lc;
640  lc.SetClosed( true );
641 
642  for( auto iter = outline->CIterateWithHoles(); iter; iter++ )
643  {
644  addAnchor( *iter, CORNER, aItem );
645  lc.Append( *iter );
646  }
647 
648  addAnchor( lc.NearestPoint( aRefPos ), OUTLINE, aItem );
649 
650  break;
651  }
652 
653  case PCB_DIM_ALIGNED_T:
655  {
656  const PCB_DIM_ALIGNED* dim = static_cast<const PCB_DIM_ALIGNED*>( aItem );
657  addAnchor( dim->GetCrossbarStart(), CORNER | SNAPPABLE, aItem );
658  addAnchor( dim->GetCrossbarEnd(), CORNER | SNAPPABLE, aItem );
659  addAnchor( dim->GetStart(), CORNER | SNAPPABLE, aItem );
660  addAnchor( dim->GetEnd(), CORNER | SNAPPABLE, aItem );
661  break;
662  }
663 
664  case PCB_DIM_CENTER_T:
665  {
666  const PCB_DIM_CENTER* dim = static_cast<const PCB_DIM_CENTER*>( aItem );
667  addAnchor( dim->GetStart(), CORNER | SNAPPABLE, aItem );
668  addAnchor( dim->GetEnd(), CORNER | SNAPPABLE, aItem );
669 
670  VECTOR2I start( dim->GetStart() );
671  VECTOR2I radial( dim->GetEnd() - dim->GetStart() );
672 
673  for( int i = 0; i < 2; i++ )
674  {
675  radial = radial.Rotate( DEG2RAD( 90 ) );
676  addAnchor( start + radial, CORNER | SNAPPABLE, aItem );
677  }
678 
679  break;
680  }
681 
682  case PCB_DIM_LEADER_T:
683  {
684  const PCB_DIM_LEADER* leader = static_cast<const PCB_DIM_LEADER*>( aItem );
685  addAnchor( leader->GetStart(), CORNER | SNAPPABLE, aItem );
686  addAnchor( leader->GetEnd(), CORNER | SNAPPABLE, aItem );
687  addAnchor( leader->Text().GetPosition(), CORNER | SNAPPABLE, aItem );
688  break;
689  }
690 
691  case PCB_FP_TEXT_T:
692  case PCB_TEXT_T:
693  addAnchor( aItem->GetPosition(), ORIGIN, aItem );
694  break;
695 
696  case PCB_GROUP_T:
697  {
698  const PCB_GROUP* group = static_cast<const PCB_GROUP*>( aItem );
699 
700  for( BOARD_ITEM* item : group->GetItems() )
701  computeAnchors( item, aRefPos, aFrom );
702 
703  break;
704  }
705 
706  default:
707  break;
708  }
709 }
710 
711 
713  LSET aMatchLayers )
714 {
715  double minDist = std::numeric_limits<double>::max();
716  ANCHOR* best = nullptr;
717 
718  for( ANCHOR& a : m_anchors )
719  {
720  BOARD_ITEM* item = static_cast<BOARD_ITEM*>( a.item );
721 
722  if( ( aMatchLayers & item->GetLayerSet() ) == 0 )
723  continue;
724 
725  if( ( aFlags & a.flags ) != aFlags )
726  continue;
727 
728  double dist = a.Distance( aPos );
729 
730  if( dist < minDist )
731  {
732  minDist = dist;
733  best = &a;
734  }
735  }
736 
737  return best;
738 }
double EuclideanNorm(const wxPoint &vector)
Euclidean norm of a 2D vector.
Definition: trigo.h:146
void SetPosition(const wxPoint &aPosition) override
compound shape, consisting of multiple simple shapes
Definition: shape.h:49
wxPoint GetArcEnd() const
Definition: pcb_shape.cpp:417
virtual const SEG GetSegment(int aIndex) const override
Definition: shape_simple.h:174
const std::set< unsigned int > GetHighContrastLayers() const
Returns the set of currently high-contrast layers.
KIGFX::VIEW * GetView() const
Definition: tool_manager.h:283
Arcs (with rounded ends)
int Distance(const SEG &aSeg) const
Compute minimum Euclidean distance to segment aSeg.
Definition: seg.cpp:285
Represent a simple polygon consisting of a zero-thickness closed chain of connected line segments.
Definition: shape_simple.h:41
Bezier Curve.
Auxiliary items (guides, rule, etc)
Definition: layer_ids.h:217
class PCB_DIM_ALIGNED, a linear dimension (graphic item)
Definition: typeinfo.h:100
class PCB_DIM_LEADER, a leader dimension (graphic item)
Definition: typeinfo.h:101
wxPoint GetPosition() const override
ANCHOR * m_snapItem
Definition: grid_helper.h:137
class FP_TEXT, text in a footprint
Definition: typeinfo.h:92
void addAnchor(const VECTOR2I &aPos, int aFlags, EDA_ITEM *aItem)
Definition: grid_helper.h:106
const SHAPE_LINE_CHAIN Outline() const
Definition: shape_rect.h:170
const wxPoint & GetCrossbarStart() const
polygon (not yet used for tracks, but could be in microwave apps)
int GetRadius() const
Definition: shape_circle.h:107
Container for all the knowledge about how graphical objects are drawn on any output surface/device.
const wxPoint & GetEnd() const
Definition: pcb_track.h:105
const wxPoint & GetEnd() const
Return the ending point of the graphic.
Definition: pcb_shape.h:134
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition: board_item.h:80
class PCB_GROUP, a set of BOARD_ITEMs
Definition: typeinfo.h:108
SHAPE_T GetShape() const
Definition: pcb_shape.h:110
A set of BOARD_ITEMs (i.e., without duplicates).
Definition: pcb_group.h:50
PCB_TEXT & Text()
class PCB_DIM_CENTER, a center point marking (graphic item)
Definition: typeinfo.h:102
TOOL_MANAGER * m_toolMgr
Definition: grid_helper.h:129
#define M_PI_2
Definition: transline.cpp:40
KIGFX::ORIGIN_VIEWITEM m_viewAxis
Definition: grid_helper.h:143
VECTOR2I GetOrigin() const
Definition: grid_helper.cpp:59
usual segment : line with rounded ends
const wxPoint & GetCrossbarEnd() const
CONST_ITERATOR CIterateWithHoles(int aOutline) const
const COLOR4D & GetLayerColor(int aLayer) const
Return the color used to draw a layer.
class PCB_TEXT, text on a layer
Definition: typeinfo.h:91
anchor of items having an anchor point (texts, footprints)
Definition: layer_ids.h:196
class PCB_ARC, an arc track segment on a copper layer
Definition: typeinfo.h:97
COLOR4D WithAlpha(double aAlpha) const
Return a color with the same color, but the given alpha.
Definition: color4d.h:308
GAL * GetGAL() const
Return the #GAL this view is using to draw graphical primitives.
Definition: view.h:190
MAGNETIC_SETTINGS * m_magneticSettings
class FP_SHAPE, a footprint edge
Definition: typeinfo.h:93
class PAD, a pad in a footprint
Definition: typeinfo.h:89
#define KI_FALLTHROUGH
The KI_FALLTHROUGH macro is to be used when switch statement cases should purposely fallthrough from ...
Definition: macros.h:83
OPT_VECTOR2I IntersectLines(const SEG &aSeg) const
Compute the intersection point of lines passing through ends of (this) and aSeg.
Definition: seg.h:209
void SetEndPosition(const VECTOR2D &aPosition)
const VECTOR2I GetCenter() const
Definition: shape_circle.h:112
VECTOR2I Center() const
Definition: seg.h:386
virtual wxPoint GetPosition() const
Definition: eda_item.h:252
std::set< BOARD_ITEM * > queryVisible(const BOX2I &aArea, const std::vector< BOARD_ITEM * > &aSkip) const
VECTOR2< int > VECTOR2I
Definition: vector2d.h:623
void DupPolyPointsList(std::vector< wxPoint > &aBuffer) const
Duplicate the list of corners in a std::vector<wxPoint>
Definition: pcb_shape.cpp:1277
PAINTER * GetPainter() const
Return the painter object used by the view for drawing #VIEW_ITEMS.
Definition: view.h:208
const SEG & GetSeg() const
class PCB_TRACK, a track segment (segment on a copper layer)
Definition: typeinfo.h:95
void Append(int aX, int aY, bool aAllowDuplication=false)
Append a new point at the end of the line chain.
PADS & Pads()
Definition: footprint.h:168
const VECTOR2I NearestPoint(const VECTOR2I &aP, bool aAllowInternalShapePoints=true) const
Find a point on the line chain that is closest to point aP.
This file contains miscellaneous commonly used macros and functions.
wxPoint GetArcStart() const
Definition: pcb_shape.h:156
For better understanding of the points that make a dimension:
VECTOR2I GetGrid() const
Definition: grid_helper.cpp:51
KIGFX::ORIGIN_VIEWITEM m_viewSnapPoint
Definition: grid_helper.h:141
Master controller class:
Definition: tool_manager.h:54
VECTOR2I AlignToArc(const VECTOR2I &aPoint, const SHAPE_ARC &aSeg)
ANCHOR * nearestAnchor(const VECTOR2I &aPos, int aFlags, LSET aMatchLayers)
virtual const wxPoint & GetStart() const
The dimension's origin is the first feature point for the dimension.
void SetClosed(bool aClosed)
Mark the line chain as closed (i.e.
PCB_GRID_HELPER(TOOL_MANAGER *aToolMgr, MAGNETIC_SETTINGS *aMagneticSettings)
void computeAnchors(BOARD_ITEM *aItem, const VECTOR2I &aRefPos, bool aFrom=false)
computeAnchors inserts the local anchor points in to the grid helper for the specified board item,...
LSET is a set of PCB_LAYER_IDs.
Definition: layer_ids.h:502
VECTOR2I BestSnapAnchor(const VECTOR2I &aOrigin, BOARD_ITEM *aReferenceItem)
Chooses the "best" snap anchor around the given point, optionally taking layers from the reference it...
virtual wxPoint GetPosition() const override
Definition: pcb_text.h:76
OPT< VECTOR2I > OPT_VECTOR2I
Definition: seg.h:38
bool ApproxParallel(const SEG &aSeg) const
Definition: seg.h:290
double Distance(const VECTOR2I &aP) const
Definition: grid_helper.h:100
bool IsVisible(const VIEW_ITEM *aItem) const
Return information if the item is visible (or not).
Definition: view.cpp:1504
Represent a set of closed polygons.
SHAPE_LINE_CHAIN & Outline(int aIndex)
void SetSize(int aSize)
const VECTOR2I & GetP0() const
Definition: shape_arc.h:111
wxPoint GetCenter() const override
This defaults to the center of the bounding box if not overridden.
Definition: pcb_shape.cpp:385
const wxPoint & GetStart() const
Return the starting point of the graphic.
Definition: pcb_shape.h:124
Mark the center of a circle or arc with a cross shape.
void SetDrawAtZero(bool aDrawFlag)
Set the draw at zero flag.
const VECTOR2I & GetArcMid() const
Definition: shape_arc.h:113
circular arc
Definition: shape.h:50
virtual wxPoint GetCenter() const
This defaults to the center of the bounding box if not overridden.
Definition: board_item.h:112
static LSET AllLayersMask()
Definition: lset.cpp:787
VECTOR2I BestDragOrigin(const VECTOR2I &aMousePos, std::vector< BOARD_ITEM * > &aItem)
class ZONE, a copper pour area
Definition: typeinfo.h:105
An abstract shape on 2D plane.
Definition: shape.h:116
bool m_enableSnap
Definition: grid_helper.h:134
TOOL_BASE * GetCurrentTool() const
Return the tool that is on the top of the active tools stack (was invoked the most recently).
Definition: tool_manager.h:313
bool m_enableSnapLine
Definition: grid_helper.h:136
int SegmentCount() const
Return the number of segments in this line chain.
circle
Definition: shape.h:46
class PCB_TARGET, a target (graphic item)
Definition: typeinfo.h:104
class FOOTPRINT, a footprint
Definition: typeinfo.h:88
Definition: seg.h:40
virtual size_t GetSegmentCount() const override
Definition: shape_simple.h:176
virtual VECTOR2I Align(const VECTOR2I &aPoint) const
Definition: grid_helper.cpp:95
bool GetHighContrast() const
virtual RENDER_SETTINGS * GetSettings()=0
Return a pointer to current settings that are going to be used when drawing items.
VECTOR2< T > Rotate(double aAngle) const
Rotate the vector by a given angle.
Definition: vector2d.h:371
set of polygons (with holes, etc.)
Definition: shape.h:48
class PCB_MARKER, a marker used to show something
Definition: typeinfo.h:98
a single triangle belonging to a POLY_SET triangulation
Definition: shape.h:52
const SEG CSegment(int aIndex) const
Return a constant copy of the aIndex segment in the line chain.
double DEG2RAD(double deg)
Definition: trigo.h:229
Represent a polyline (an zero-thickness chain of connected line segments).
const EDA_RECT GetBoundingBox() const override
Return the orthogonal bounding box of this object for display purposes.
Definition: footprint.cpp:676
std::pair< VIEW_ITEM *, int > LAYER_ITEM_PAIR
Definition: view.h:73
VECTOR2I A
Definition: seg.h:48
MAGNETIC_OPTIONS pads
empty shape (no shape...),
Definition: shape.h:51
VECTOR2I m_skipPoint
Definition: grid_helper.h:139
constexpr ret_type KiROUND(fp_type v)
Round a floating point number to an integer using "round halfway cases away from zero".
Definition: util.h:73
void SetColor(const KIGFX::COLOR4D &aColor)
line chain (polyline)
Definition: shape.h:45
wxPoint GetPosition() const override
Definition: footprint.h:186
wxPoint Centre() const
Definition: eda_rect.h:55
void SetVisible(VIEW_ITEM *aItem, bool aIsVisible=true)
Set the item visibility.
Definition: view.cpp:1464
BOARD_ITEM * GetSnapped() const
Function GetSnapped If the PCB_GRID_HELPER has highlighted a snap point (target shown),...
A leader is a dimension-like object pointing to a specific point.
class PCB_DIM_ORTHOGONAL, a linear dimension constrained to x/y
Definition: typeinfo.h:103
class PCB_VIA, a via (like a track segment on a copper layer)
Definition: typeinfo.h:96
wxPoint GetArcMid() const
Definition: pcb_shape.cpp:435
virtual const wxPoint & GetEnd() const
virtual void Add(VIEW_ITEM *aItem, int aDrawPriority=-1)
Add a VIEW_ITEM to the view.
Definition: view.cpp:323
axis-aligned rectangle
Definition: shape.h:43
virtual int Query(const BOX2I &aRect, std::vector< LAYER_ITEM_PAIR > &aResult) const
Find all visible items that touch or are within the rectangle aRect.
Definition: view.cpp:429
KIGFX::ORIGIN_VIEWITEM m_viewSnapLine
Definition: grid_helper.h:142
Hold a (potentially large) number of VIEW_ITEMs and renders them on a graphics device provided by the...
Definition: view.h:68
segment with non rounded ends
Definition: pad.h:57
void SetStyle(MARKER_STYLE aStyle)
double GetScale() const
Definition: view.h:264
double GetWorldScale() const
Get the world scale.
std::vector< ANCHOR > m_anchors
Definition: grid_helper.h:127
int GetWidth() const
class PCB_SHAPE, a segment not on copper layers
Definition: typeinfo.h:90
simple polygon
Definition: shape.h:47
const VECTOR2I & GetP1() const
Definition: shape_arc.h:112
VECTOR2I AlignToSegment(const VECTOR2I &aPoint, const SEG &aSeg)
void clearAnchors()
Definition: grid_helper.h:112
const wxPoint & GetStart() const
Definition: pcb_track.h:108
virtual double ViewGetLOD(int aLayer, VIEW *aView) const
Return the level of detail (LOD) of the item.
Definition: view_item.h:137
virtual LSET GetLayerSet() const
Return a std::bitset of all layers on which the item physically resides.
Definition: board_item.h:176
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:1518
MAGNETIC_OPTIONS tracks
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:113
line segment
Definition: shape.h:44
Position or shape has changed.
Definition: view_item.h:54
A color representation with 4 components: red, green, blue, alpha.
Definition: color4d.h:103
VECTOR2I B
Definition: seg.h:49