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-2022 KiCad Developers, see AUTHORS.txt for contributors.
6  * @author Tomasz Wlostowski <[email protected]>
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 
154 VECTOR2I PCB_GRID_HELPER::AlignToNearestPad( const VECTOR2I& aMousePos, PADS& aPads )
155 {
156  clearAnchors();
157 
158  for( BOARD_ITEM* item : aPads )
159  computeAnchors( item, aMousePos, true );
160 
161  double minDist = std::numeric_limits<double>::max();
162  ANCHOR* nearestOrigin = nullptr;
163 
164  for( ANCHOR& a : m_anchors )
165  {
166  BOARD_ITEM* item = static_cast<BOARD_ITEM*>( a.item );
167 
168  if( ( ORIGIN & a.flags ) != ORIGIN )
169  continue;
170 
171  if( !item->HitTest( wxPoint( aMousePos.x, aMousePos.y ) ) )
172  continue;
173 
174  double dist = a.Distance( aMousePos );
175 
176  if( dist < minDist )
177  {
178  minDist = dist;
179  nearestOrigin = &a;
180  }
181  }
182 
183  return nearestOrigin ? nearestOrigin->pos : aMousePos;
184 }
185 
186 
188  std::vector<BOARD_ITEM*>& aItems )
189 {
190  clearAnchors();
191 
192  for( BOARD_ITEM* item : aItems )
193  computeAnchors( item, aMousePos, true );
194 
195  double worldScale = m_toolMgr->GetView()->GetGAL()->GetWorldScale();
196  double lineSnapMinCornerDistance = 50.0 / worldScale;
197 
198  ANCHOR* nearestOutline = nearestAnchor( aMousePos, OUTLINE, LSET::AllLayersMask() );
199  ANCHOR* nearestCorner = nearestAnchor( aMousePos, CORNER, LSET::AllLayersMask() );
200  ANCHOR* nearestOrigin = nearestAnchor( aMousePos, ORIGIN, LSET::AllLayersMask() );
201  ANCHOR* best = nullptr;
202  double minDist = std::numeric_limits<double>::max();
203 
204  if( nearestOrigin )
205  {
206  minDist = nearestOrigin->Distance( aMousePos );
207  best = nearestOrigin;
208  }
209 
210  if( nearestCorner )
211  {
212  double dist = nearestCorner->Distance( aMousePos );
213 
214  if( dist < minDist )
215  {
216  minDist = dist;
217  best = nearestCorner;
218  }
219  }
220 
221  if( nearestOutline )
222  {
223  double dist = nearestOutline->Distance( aMousePos );
224 
225  if( minDist > lineSnapMinCornerDistance && dist < minDist )
226  best = nearestOutline;
227  }
228 
229  return best ? best->pos : aMousePos;
230 }
231 
232 
234 {
235  LSET layers;
236  std::vector<BOARD_ITEM*> item;
237 
238  if( aReferenceItem )
239  {
240  layers = aReferenceItem->GetLayerSet();
241  item.push_back( aReferenceItem );
242  }
243  else
244  {
245  layers = LSET::AllLayersMask();
246  }
247 
248  return BestSnapAnchor( aOrigin, layers, item );
249 }
250 
251 
252 VECTOR2I PCB_GRID_HELPER::BestSnapAnchor( const VECTOR2I& aOrigin, const LSET& aLayers,
253  const std::vector<BOARD_ITEM*>& aSkip )
254 {
255  // Tuning constant: snap radius in screen space
256  const int snapSize = 25;
257 
258  // Snapping distance is in screen space, clamped to the current grid to ensure that the grid
259  // points that are visible can always be snapped to.
260  // see https://gitlab.com/kicad/code/kicad/-/issues/5638
261  // see https://gitlab.com/kicad/code/kicad/-/issues/7125
262  double snapScale = snapSize / m_toolMgr->GetView()->GetGAL()->GetWorldScale();
263  int snapRange = std::min( KiROUND( snapScale ), GetGrid().x );
264  int snapDist = snapRange;
265 
266  //Respect limits of coordinates representation
267  BOX2I bb;
268  bb.SetOrigin( GetClampedCoords<double, int>( VECTOR2D( aOrigin ) - snapRange / 2 ) );
269  bb.SetEnd( GetClampedCoords<double, int>( VECTOR2D( aOrigin ) + snapRange / 2 ) );
270 
271  clearAnchors();
272 
273  for( BOARD_ITEM* item : queryVisible( bb, aSkip ) )
274  computeAnchors( item, aOrigin );
275 
276  ANCHOR* nearest = nearestAnchor( aOrigin, SNAPPABLE, aLayers );
277  VECTOR2I nearestGrid = Align( aOrigin );
278 
279  if( nearest )
280  snapDist = nearest->Distance( aOrigin );
281 
282  // Existing snap lines need priority over new snaps
284  {
285  bool snapLine = false;
286  int x_dist = std::abs( m_viewSnapLine.GetPosition().x - aOrigin.x );
287  int y_dist = std::abs( m_viewSnapLine.GetPosition().y - aOrigin.y );
288 
290  if( x_dist < snapRange && ( !nearest || snapDist > snapRange ) )
291  {
292  nearestGrid.x = m_viewSnapLine.GetPosition().x;
293  snapLine = true;
294  }
295 
296  if( y_dist < snapRange && ( !nearest || snapDist > snapRange ) )
297  {
298  nearestGrid.y = m_viewSnapLine.GetPosition().y;
299  snapLine = true;
300  }
301 
302  if( snapLine && m_skipPoint != VECTOR2I( m_viewSnapLine.GetPosition() ) )
303  {
304  m_viewSnapLine.SetEndPosition( nearestGrid );
305 
308  else
310 
311  return nearestGrid;
312  }
313  }
314 
315  if( nearest && m_enableSnap )
316  {
317  if( nearest->Distance( aOrigin ) <= snapRange )
318  {
319  m_viewSnapPoint.SetPosition( wxPoint( nearest->pos ) );
320  m_viewSnapLine.SetPosition( wxPoint( nearest->pos ) );
322 
325  else
327 
328  m_snapItem = nearest;
329  return nearest->pos;
330  }
331  }
332 
333  m_snapItem = nullptr;
336  return nearestGrid;
337 }
338 
339 
341 {
342  if( !m_snapItem )
343  return nullptr;
344 
345  return static_cast<BOARD_ITEM*>( m_snapItem->item );
346 }
347 
348 
349 std::set<BOARD_ITEM*> PCB_GRID_HELPER::queryVisible( const BOX2I& aArea,
350  const std::vector<BOARD_ITEM*>& aSkip ) const
351 {
352  std::set<BOARD_ITEM*> items;
353  std::vector<KIGFX::VIEW::LAYER_ITEM_PAIR> selectedItems;
354 
355  KIGFX::VIEW* view = m_toolMgr->GetView();
356  RENDER_SETTINGS* settings = view->GetPainter()->GetSettings();
357  const std::set<unsigned int>& activeLayers = settings->GetHighContrastLayers();
358  bool isHighContrast = settings->GetHighContrast();
359 
360  view->Query( aArea, selectedItems );
361 
362  for( const KIGFX::VIEW::LAYER_ITEM_PAIR& it : selectedItems )
363  {
364  BOARD_ITEM* item = static_cast<BOARD_ITEM*>( it.first );
365 
366  // If we are in the footprint editor, don't use the footprint itself
367  if( static_cast<PCB_TOOL_BASE*>( m_toolMgr->GetCurrentTool() )->IsFootprintEditor()
368  && item->Type() == PCB_FOOTPRINT_T )
369  {
370  continue;
371  }
372 
373  // The item must be visible and on an active layer
374  if( view->IsVisible( item )
375  && ( !isHighContrast || activeLayers.count( it.second ) )
376  && item->ViewGetLOD( it.second, view ) < view->GetScale() )
377  {
378  items.insert ( item );
379  }
380  }
381 
382  for( BOARD_ITEM* skipItem : aSkip )
383  items.erase( skipItem );
384 
385  return items;
386 }
387 
388 
389 void PCB_GRID_HELPER::computeAnchors( BOARD_ITEM* aItem, const VECTOR2I& aRefPos, bool aFrom )
390 {
391  KIGFX::VIEW* view = m_toolMgr->GetView();
392  RENDER_SETTINGS* settings = view->GetPainter()->GetSettings();
393  const std::set<unsigned int>& activeLayers = settings->GetHighContrastLayers();
394  bool isHighContrast = settings->GetHighContrast();
395 
396  auto handlePadShape =
397  [&]( PAD* aPad )
398  {
399  addAnchor( aPad->GetPosition(), ORIGIN | SNAPPABLE, aPad );
400 
402  if( aFrom )
403  return;
404 
405  const std::shared_ptr<SHAPE> eshape = aPad->GetEffectiveShape();
406 
407  wxASSERT( eshape->Type() == SH_COMPOUND );
408  const std::vector<SHAPE*> shapes =
409  static_cast<const SHAPE_COMPOUND*>( eshape.get() )->Shapes();
410 
411  for( const SHAPE* shape : shapes )
412  {
413  switch( shape->Type() )
414  {
415  case SH_RECT:
416  {
417  const SHAPE_RECT* rect = static_cast<const SHAPE_RECT*>( shape );
418  SHAPE_LINE_CHAIN outline = rect->Outline();
419 
420  for( int i = 0; i < outline.SegmentCount(); i++ )
421  {
422  const SEG& seg = outline.CSegment( i );
423  addAnchor( seg.A, OUTLINE | SNAPPABLE, aPad );
424  addAnchor( seg.Center(), OUTLINE | SNAPPABLE, aPad );
425  }
426 
427  break;
428  }
429 
430  case SH_SEGMENT:
431  {
432  const SHAPE_SEGMENT* segment = static_cast<const SHAPE_SEGMENT*>( shape );
433 
434  int offset = segment->GetWidth() / 2;
435  SEG seg = segment->GetSeg();
436  VECTOR2I normal = ( seg.B - seg.A ).Resize( offset ).Rotate( -M_PI_2 );
437 
438  /*
439  * TODO: This creates more snap points than necessary for rounded rect pads
440  * because they are built up of overlapping segments. We could fix this if
441  * desired by testing these to see if they are "inside" the pad.
442  */
443 
444  addAnchor( seg.A + normal, OUTLINE | SNAPPABLE, aPad );
445  addAnchor( seg.A - normal, OUTLINE | SNAPPABLE, aPad );
446  addAnchor( seg.B + normal, OUTLINE | SNAPPABLE, aPad );
447  addAnchor( seg.B - normal, OUTLINE | SNAPPABLE, aPad );
448  addAnchor( seg.Center() + normal, OUTLINE | SNAPPABLE, aPad );
449  addAnchor( seg.Center() - normal, OUTLINE | SNAPPABLE, aPad );
450 
451  normal = normal.Rotate( M_PI_2 );
452 
453  addAnchor( seg.A - normal, OUTLINE | SNAPPABLE, aPad );
454  addAnchor( seg.B + normal, OUTLINE | SNAPPABLE, aPad );
455  break;
456  }
457 
458  case SH_CIRCLE:
459  {
460  const SHAPE_CIRCLE* circle = static_cast<const SHAPE_CIRCLE*>( shape );
461 
462  int r = circle->GetRadius();
463  VECTOR2I start = circle->GetCenter();
464 
465  addAnchor( start + VECTOR2I( -r, 0 ), OUTLINE | SNAPPABLE, aPad );
466  addAnchor( start + VECTOR2I( r, 0 ), OUTLINE | SNAPPABLE, aPad );
467  addAnchor( start + VECTOR2I( 0, -r ), OUTLINE | SNAPPABLE, aPad );
468  addAnchor( start + VECTOR2I( 0, r ), OUTLINE | SNAPPABLE, aPad );
469  break;
470  }
471 
472  case SH_ARC:
473  {
474  const SHAPE_ARC* arc = static_cast<const SHAPE_ARC*>( shape );
475 
476  addAnchor( arc->GetP0(), OUTLINE | SNAPPABLE, aPad );
477  addAnchor( arc->GetP1(), OUTLINE | SNAPPABLE, aPad );
478  addAnchor( arc->GetArcMid(), OUTLINE | SNAPPABLE, aPad );
479  break;
480  }
481 
482  case SH_SIMPLE:
483  {
484  const SHAPE_SIMPLE* poly = static_cast<const SHAPE_SIMPLE*>( shape );
485 
486  for( size_t i = 0; i < poly->GetSegmentCount(); i++ )
487  {
488  const SEG& seg = poly->GetSegment( i );
489 
490  addAnchor( seg.A, OUTLINE | SNAPPABLE, aPad );
491  addAnchor( seg.Center(), OUTLINE | SNAPPABLE, aPad );
492 
493  if( i == poly->GetSegmentCount() - 1 )
494  addAnchor( seg.B, OUTLINE | SNAPPABLE, aPad );
495  }
496 
497  break;
498  }
499 
500  case SH_POLY_SET:
501  case SH_LINE_CHAIN:
502  case SH_COMPOUND:
504  case SH_NULL:
505  default:
506  break;
507  }
508  }
509  };
510 
511  switch( aItem->Type() )
512  {
513  case PCB_FOOTPRINT_T:
514  {
515  FOOTPRINT* footprint = static_cast<FOOTPRINT*>( aItem );
516 
517  for( PAD* pad : footprint->Pads() )
518  {
519  // Getting pads from the footprint requires re-checking that the pad is shown
521  && pad->GetBoundingBox().Contains( wxPoint( aRefPos.x, aRefPos.y ) )
522  && view->IsVisible( pad )
523  && ( !isHighContrast || activeLayers.count( pad->GetLayer() ) )
524  && pad->ViewGetLOD( pad->GetLayer(), view ) < view->GetScale() )
525  {
526  handlePadShape( pad );
527  break;
528  }
529  }
530 
531  // if the cursor is not over a pad, then drag the footprint by its origin
532  VECTOR2I position = footprint->GetPosition();
533  addAnchor( position, ORIGIN | SNAPPABLE, footprint );
534 
535  // Add the footprint center point if it is markedly different from the origin
536  VECTOR2I center = footprint->GetBoundingBox( false, false ).Centre();
537  VECTOR2I grid( GetGrid() );
538 
539  if( ( center - position ).SquaredEuclideanNorm() > grid.SquaredEuclideanNorm() )
540  addAnchor( center, ORIGIN | SNAPPABLE, footprint );
541 
542  break;
543  }
544 
545  case PCB_PAD_T:
546  {
548  {
549  PAD* pad = static_cast<PAD*>( aItem );
550  handlePadShape( pad );
551  }
552 
553  break;
554  }
555 
556  case PCB_FP_SHAPE_T:
557  case PCB_SHAPE_T:
558  {
560  break;
561 
562  PCB_SHAPE* shape = static_cast<PCB_SHAPE*>( aItem );
563  VECTOR2I start = shape->GetStart();
564  VECTOR2I end = shape->GetEnd();
565 
566  switch( shape->GetShape() )
567  {
568  case SHAPE_T::CIRCLE:
569  {
570  int r = ( start - end ).EuclideanNorm();
571 
572  addAnchor( start, ORIGIN | SNAPPABLE, shape );
573  addAnchor( start + VECTOR2I( -r, 0 ), OUTLINE | SNAPPABLE, shape );
574  addAnchor( start + VECTOR2I( r, 0 ), OUTLINE | SNAPPABLE, shape );
575  addAnchor( start + VECTOR2I( 0, -r ), OUTLINE | SNAPPABLE, shape );
576  addAnchor( start + VECTOR2I( 0, r ), OUTLINE | SNAPPABLE, shape );
577  break;
578  }
579 
580  case SHAPE_T::ARC:
581  addAnchor( shape->GetStart(), CORNER | SNAPPABLE, shape );
582  addAnchor( shape->GetEnd(), CORNER | SNAPPABLE, shape );
583  addAnchor( shape->GetArcMid(), CORNER | SNAPPABLE, shape );
584  addAnchor( shape->GetCenter(), ORIGIN | SNAPPABLE, shape );
585  break;
586 
587  case SHAPE_T::RECT:
588  {
589  VECTOR2I point2( end.x, start.y );
590  VECTOR2I point3( start.x, end.y );
591  SEG first( start, point2 );
592  SEG second( point2, end );
593  SEG third( end, point3 );
594  SEG fourth( point3, start );
595 
596  addAnchor( first.A, CORNER | SNAPPABLE, shape );
597  addAnchor( first.Center(), CORNER | SNAPPABLE, shape );
598  addAnchor( second.A, CORNER | SNAPPABLE, shape );
599  addAnchor( second.Center(), CORNER | SNAPPABLE, shape );
600  addAnchor( third.A, CORNER | SNAPPABLE, shape );
601  addAnchor( third.Center(), CORNER | SNAPPABLE, shape );
602  addAnchor( fourth.A, CORNER | SNAPPABLE, shape );
603  addAnchor( fourth.Center(), CORNER | SNAPPABLE, shape );
604  break;
605  }
606 
607  case SHAPE_T::SEGMENT:
608  addAnchor( start, CORNER | SNAPPABLE, shape );
609  addAnchor( end, CORNER | SNAPPABLE, shape );
610  addAnchor( shape->GetCenter(), CORNER | SNAPPABLE, shape );
611  break;
612 
613  case SHAPE_T::POLY:
614  {
615  SHAPE_LINE_CHAIN lc;
616  lc.SetClosed( true );
617  std::vector<wxPoint> poly;
618  shape->DupPolyPointsList( poly );
619 
620  for( const wxPoint& p : poly )
621  {
622  addAnchor( p, CORNER | SNAPPABLE, shape );
623  lc.Append( p );
624  }
625 
626  addAnchor( lc.NearestPoint( aRefPos ), OUTLINE, aItem );
627  break;
628  }
629 
630  case SHAPE_T::BEZIER:
631  addAnchor( start, CORNER | SNAPPABLE, shape );
632  addAnchor( end, CORNER | SNAPPABLE, shape );
634 
635  default:
636  addAnchor( shape->GetPosition(), ORIGIN | SNAPPABLE, shape );
637  break;
638  }
639  break;
640  }
641 
642  case PCB_TRACE_T:
643  case PCB_ARC_T:
644  {
646  {
647  PCB_TRACK* track = static_cast<PCB_TRACK*>( aItem );
648 
649  addAnchor( track->GetStart(), CORNER | SNAPPABLE, track );
650  addAnchor( track->GetEnd(), CORNER | SNAPPABLE, track );
651  addAnchor( track->GetCenter(), ORIGIN, track);
652  }
653 
654  break;
655  }
656 
657  case PCB_MARKER_T:
658  case PCB_TARGET_T:
659  addAnchor( aItem->GetPosition(), ORIGIN | CORNER | SNAPPABLE, aItem );
660  break;
661 
662  case PCB_VIA_T:
663  {
665  addAnchor( aItem->GetPosition(), ORIGIN | CORNER | SNAPPABLE, aItem );
666 
667  break;
668  }
669 
670  case PCB_ZONE_T:
671  {
672  const SHAPE_POLY_SET* outline = static_cast<const ZONE*>( aItem )->Outline();
673 
674  SHAPE_LINE_CHAIN lc;
675  lc.SetClosed( true );
676 
677  for( auto iter = outline->CIterateWithHoles(); iter; iter++ )
678  {
679  addAnchor( *iter, CORNER, aItem );
680  lc.Append( *iter );
681  }
682 
683  addAnchor( lc.NearestPoint( aRefPos ), OUTLINE, aItem );
684 
685  break;
686  }
687 
688  case PCB_FP_ZONE_T:
689  {
690  const SHAPE_POLY_SET* outline = static_cast<const FP_ZONE*>( aItem )->Outline();
691 
692  SHAPE_LINE_CHAIN lc;
693  lc.SetClosed( true );
694 
695  for( auto iter = outline->CIterateWithHoles(); iter; iter++ )
696  {
697  addAnchor( *iter, CORNER, aItem );
698  lc.Append( *iter );
699  }
700 
701  addAnchor( lc.NearestPoint( aRefPos ), OUTLINE, aItem );
702 
703  break;
704  }
705 
706  case PCB_DIM_ALIGNED_T:
708  {
709  const PCB_DIM_ALIGNED* dim = static_cast<const PCB_DIM_ALIGNED*>( aItem );
710  addAnchor( dim->GetCrossbarStart(), CORNER | SNAPPABLE, aItem );
711  addAnchor( dim->GetCrossbarEnd(), CORNER | SNAPPABLE, aItem );
712  addAnchor( dim->GetStart(), CORNER | SNAPPABLE, aItem );
713  addAnchor( dim->GetEnd(), CORNER | SNAPPABLE, aItem );
714  break;
715  }
716 
717  case PCB_DIM_CENTER_T:
718  {
719  const PCB_DIM_CENTER* dim = static_cast<const PCB_DIM_CENTER*>( aItem );
720  addAnchor( dim->GetStart(), CORNER | SNAPPABLE, aItem );
721  addAnchor( dim->GetEnd(), CORNER | SNAPPABLE, aItem );
722 
723  VECTOR2I start( dim->GetStart() );
724  VECTOR2I radial( dim->GetEnd() - dim->GetStart() );
725 
726  for( int i = 0; i < 2; i++ )
727  {
728  radial = radial.Rotate( DEG2RAD( 90 ) );
729  addAnchor( start + radial, CORNER | SNAPPABLE, aItem );
730  }
731 
732  break;
733  }
734 
735  case PCB_DIM_LEADER_T:
736  {
737  const PCB_DIM_LEADER* leader = static_cast<const PCB_DIM_LEADER*>( aItem );
738  addAnchor( leader->GetStart(), CORNER | SNAPPABLE, aItem );
739  addAnchor( leader->GetEnd(), CORNER | SNAPPABLE, aItem );
740  addAnchor( leader->Text().GetPosition(), CORNER | SNAPPABLE, aItem );
741  break;
742  }
743 
744  case PCB_FP_TEXT_T:
745  case PCB_TEXT_T:
746  addAnchor( aItem->GetPosition(), ORIGIN, aItem );
747  break;
748 
749  case PCB_GROUP_T:
750  {
751  const PCB_GROUP* group = static_cast<const PCB_GROUP*>( aItem );
752 
753  for( BOARD_ITEM* item : group->GetItems() )
754  computeAnchors( item, aRefPos, aFrom );
755 
756  break;
757  }
758 
759  default:
760  break;
761  }
762 }
763 
764 
766  LSET aMatchLayers )
767 {
768  double minDist = std::numeric_limits<double>::max();
769  ANCHOR* best = nullptr;
770 
771  for( ANCHOR& a : m_anchors )
772  {
773  BOARD_ITEM* item = static_cast<BOARD_ITEM*>( a.item );
774 
775  if( ( aMatchLayers & item->GetLayerSet() ) == 0 )
776  continue;
777 
778  if( ( aFlags & a.flags ) != aFlags )
779  continue;
780 
781  double dist = a.Distance( aPos );
782 
783  if( dist < minDist )
784  {
785  minDist = dist;
786  best = &a;
787  }
788  }
789 
790  return best;
791 }
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
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
int Distance(const SEG &aSeg) const
Compute minimum Euclidean distance to segment aSeg.
Definition: seg.cpp:318
Represent a simple polygon consisting of a zero-thickness closed chain of connected line segments.
Definition: shape_simple.h:41
Auxiliary items (guides, rule, etc)
Definition: layer_ids.h:229
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
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
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition: board_item.h:49
const wxPoint & GetStart() const
Return the starting point of the graphic.
Definition: eda_shape.h:106
class PCB_GROUP, a set of BOARD_ITEMs
Definition: typeinfo.h:108
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
const wxPoint & GetCrossbarEnd() const
CONST_ITERATOR CIterateWithHoles(int aOutline) const
void DupPolyPointsList(std::vector< wxPoint > &aBuffer) const
Duplicate the list of corners in a std::vector<wxPoint>
Definition: eda_shape.cpp:1193
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:208
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:321
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:251
std::set< BOARD_ITEM * > queryVisible(const BOX2I &aArea, const std::vector< BOARD_ITEM * > &aSkip) const
VECTOR2< int > VECTOR2I
Definition: vector2d.h:622
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:169
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.
For better understanding of the points that make a dimension:
VECTOR2I GetGrid() const
Definition: grid_helper.cpp:51
bool ApproxParallel(const SEG &aSeg, int aDistanceThreshold=1) const
Definition: seg.h:290
virtual bool HitTest(const wxPoint &aPosition, int aAccuracy=0) const
Test if aPosition is inside or on the boundary of this item.
Definition: eda_item.h:224
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,...
const wxPoint & GetEnd() const
Return the ending point of the graphic.
Definition: eda_shape.h:131
LSET is a set of PCB_LAYER_IDs.
Definition: layer_ids.h:516
VECTOR2I BestSnapAnchor(const VECTOR2I &aOrigin, BOARD_ITEM *aReferenceItem)
Chooses the "best" snap anchor around the given point, optionally taking layers from the reference it...
VECTOR2< double > VECTOR2D
Definition: vector2d.h:621
virtual wxPoint GetPosition() const override
Definition: pcb_text.h:76
OPT< VECTOR2I > OPT_VECTOR2I
Definition: seg.h:38
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:1556
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.h:79
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:81
static LSET AllLayersMask()
Definition: lset.cpp:796
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
E_SERIE r
Definition: eserie.cpp:41
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
void SetEnd(coord_type x, coord_type y)
Definition: box2.h:207
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
wxPoint GetPosition() const override
Definition: pcb_shape.h:77
bool GetHighContrast() const
virtual RENDER_SETTINGS * GetSettings()=0
Return a pointer to current settings that are going to be used when drawing items.
VECTOR2I AlignToNearestPad(const VECTOR2I &aMousePos, PADS &aPads)
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 containing arcs as well as line segments: A chain of connected line and/or arc s...
const EDA_RECT GetBoundingBox() const override
Return the orthogonal bounding box of this object for display purposes.
Definition: footprint.cpp:736
std::pair< VIEW_ITEM *, int > LAYER_ITEM_PAIR
Definition: view.h:73
class ZONE, managed by a footprint
Definition: typeinfo.h:94
wxPoint GetArcMid() const
Definition: eda_shape.cpp:437
VECTOR2I A
Definition: seg.h:48
void SetOrigin(const Vec &pos)
Definition: box2.h:193
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:187
wxPoint Centre() const
Definition: eda_rect.h:64
void SetVisible(VIEW_ITEM *aItem, bool aIsVisible=true)
Set the item visibility.
Definition: view.cpp:1516
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
virtual const wxPoint & GetEnd() const
virtual void Add(VIEW_ITEM *aItem, int aDrawPriority=-1)
Add a VIEW_ITEM to the view.
Definition: view.cpp:320
axis-aligned rectangle
Definition: shape.h:43
SHAPE_T GetShape() const
Definition: eda_shape.h:101
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:426
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
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:132
virtual LSET GetLayerSet() const
Return a std::bitset of all layers on which the item physically resides.
Definition: board_item.h:148
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:1570
MAGNETIC_OPTIONS tracks
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:112
line segment
Definition: shape.h:44
Position or shape has changed.
Definition: view_item.h:49
A color representation with 4 components: red, green, blue, alpha.
Definition: color4d.h:103
VECTOR2I B
Definition: seg.h:49