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 <[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  BOX2I bb( VECTOR2I( aOrigin.x - snapRange / 2, aOrigin.y - snapRange / 2 ),
267  VECTOR2I( snapRange, snapRange ) );
268 
269  clearAnchors();
270 
271  for( BOARD_ITEM* item : queryVisible( bb, aSkip ) )
272  computeAnchors( item, aOrigin );
273 
274  ANCHOR* nearest = nearestAnchor( aOrigin, SNAPPABLE, aLayers );
275  VECTOR2I nearestGrid = Align( aOrigin );
276 
277  if( nearest )
278  snapDist = nearest->Distance( aOrigin );
279 
280  // Existing snap lines need priority over new snaps
282  {
283  bool snapLine = false;
284  int x_dist = std::abs( m_viewSnapLine.GetPosition().x - aOrigin.x );
285  int y_dist = std::abs( m_viewSnapLine.GetPosition().y - aOrigin.y );
286 
288  if( x_dist < snapRange && ( !nearest || snapDist > snapRange ) )
289  {
290  nearestGrid.x = m_viewSnapLine.GetPosition().x;
291  snapLine = true;
292  }
293 
294  if( y_dist < snapRange && ( !nearest || snapDist > snapRange ) )
295  {
296  nearestGrid.y = m_viewSnapLine.GetPosition().y;
297  snapLine = true;
298  }
299 
300  if( snapLine && m_skipPoint != VECTOR2I( m_viewSnapLine.GetPosition() ) )
301  {
302  m_viewSnapLine.SetEndPosition( nearestGrid );
303 
306  else
308 
309  return nearestGrid;
310  }
311  }
312 
313  if( nearest && m_enableSnap )
314  {
315  if( nearest->Distance( aOrigin ) <= snapRange )
316  {
317  m_viewSnapPoint.SetPosition( wxPoint( nearest->pos ) );
318  m_viewSnapLine.SetPosition( wxPoint( nearest->pos ) );
320 
323  else
325 
326  m_snapItem = nearest;
327  return nearest->pos;
328  }
329  }
330 
331  m_snapItem = nullptr;
334  return nearestGrid;
335 }
336 
337 
339 {
340  if( !m_snapItem )
341  return nullptr;
342 
343  return static_cast<BOARD_ITEM*>( m_snapItem->item );
344 }
345 
346 
347 std::set<BOARD_ITEM*> PCB_GRID_HELPER::queryVisible( const BOX2I& aArea,
348  const std::vector<BOARD_ITEM*>& aSkip ) const
349 {
350  std::set<BOARD_ITEM*> items;
351  std::vector<KIGFX::VIEW::LAYER_ITEM_PAIR> selectedItems;
352 
353  KIGFX::VIEW* view = m_toolMgr->GetView();
354  RENDER_SETTINGS* settings = view->GetPainter()->GetSettings();
355  const std::set<unsigned int>& activeLayers = settings->GetHighContrastLayers();
356  bool isHighContrast = settings->GetHighContrast();
357 
358  view->Query( aArea, selectedItems );
359 
360  for( const KIGFX::VIEW::LAYER_ITEM_PAIR& it : selectedItems )
361  {
362  BOARD_ITEM* item = static_cast<BOARD_ITEM*>( it.first );
363 
364  // If we are in the footprint editor, don't use the footprint itself
365  if( static_cast<PCB_TOOL_BASE*>( m_toolMgr->GetCurrentTool() )->IsFootprintEditor()
366  && item->Type() == PCB_FOOTPRINT_T )
367  {
368  continue;
369  }
370 
371  // The item must be visible and on an active layer
372  if( view->IsVisible( item )
373  && ( !isHighContrast || activeLayers.count( it.second ) )
374  && item->ViewGetLOD( it.second, view ) < view->GetScale() )
375  {
376  items.insert ( item );
377  }
378  }
379 
380  for( BOARD_ITEM* skipItem : aSkip )
381  items.erase( skipItem );
382 
383  return items;
384 }
385 
386 
387 void PCB_GRID_HELPER::computeAnchors( BOARD_ITEM* aItem, const VECTOR2I& aRefPos, bool aFrom )
388 {
389  KIGFX::VIEW* view = m_toolMgr->GetView();
390  RENDER_SETTINGS* settings = view->GetPainter()->GetSettings();
391  const std::set<unsigned int>& activeLayers = settings->GetHighContrastLayers();
392  bool isHighContrast = settings->GetHighContrast();
393 
394  auto handlePadShape =
395  [&]( PAD* aPad )
396  {
397  addAnchor( aPad->GetPosition(), ORIGIN | SNAPPABLE, aPad );
398 
400  if( aFrom )
401  return;
402 
403  const std::shared_ptr<SHAPE> eshape = aPad->GetEffectiveShape( aPad->GetLayer() );
404 
405  wxASSERT( eshape->Type() == SH_COMPOUND );
406  const std::vector<SHAPE*> shapes =
407  static_cast<const SHAPE_COMPOUND*>( eshape.get() )->Shapes();
408 
409  for( const SHAPE* shape : shapes )
410  {
411  switch( shape->Type() )
412  {
413  case SH_RECT:
414  {
415  const SHAPE_RECT* rect = static_cast<const SHAPE_RECT*>( shape );
416  SHAPE_LINE_CHAIN outline = rect->Outline();
417 
418  for( int i = 0; i < outline.SegmentCount(); i++ )
419  {
420  const SEG& seg = outline.CSegment( i );
421  addAnchor( seg.A, OUTLINE | SNAPPABLE, aPad );
422  addAnchor( seg.Center(), OUTLINE | SNAPPABLE, aPad );
423  }
424 
425  break;
426  }
427 
428  case SH_SEGMENT:
429  {
430  const SHAPE_SEGMENT* segment = static_cast<const SHAPE_SEGMENT*>( shape );
431 
432  int offset = segment->GetWidth() / 2;
433  SEG seg = segment->GetSeg();
434  VECTOR2I normal = ( seg.B - seg.A ).Resize( offset ).Rotate( -M_PI_2 );
435 
436  /*
437  * TODO: This creates more snap points than necessary for rounded rect pads
438  * because they are built up of overlapping segments. We could fix this if
439  * desired by testing these to see if they are "inside" the pad.
440  */
441 
442  addAnchor( seg.A + normal, OUTLINE | SNAPPABLE, aPad );
443  addAnchor( seg.A - normal, OUTLINE | SNAPPABLE, aPad );
444  addAnchor( seg.B + normal, OUTLINE | SNAPPABLE, aPad );
445  addAnchor( seg.B - normal, OUTLINE | SNAPPABLE, aPad );
446  addAnchor( seg.Center() + normal, OUTLINE | SNAPPABLE, aPad );
447  addAnchor( seg.Center() - normal, OUTLINE | SNAPPABLE, aPad );
448 
449  normal = normal.Rotate( M_PI_2 );
450 
451  addAnchor( seg.A - normal, OUTLINE | SNAPPABLE, aPad );
452  addAnchor( seg.B + normal, OUTLINE | SNAPPABLE, aPad );
453  break;
454  }
455 
456  case SH_CIRCLE:
457  {
458  const SHAPE_CIRCLE* circle = static_cast<const SHAPE_CIRCLE*>( shape );
459 
460  int r = circle->GetRadius();
461  VECTOR2I start = circle->GetCenter();
462 
463  addAnchor( start + VECTOR2I( -r, 0 ), OUTLINE | SNAPPABLE, aPad );
464  addAnchor( start + VECTOR2I( r, 0 ), OUTLINE | SNAPPABLE, aPad );
465  addAnchor( start + VECTOR2I( 0, -r ), OUTLINE | SNAPPABLE, aPad );
466  addAnchor( start + VECTOR2I( 0, r ), OUTLINE | SNAPPABLE, aPad );
467  break;
468  }
469 
470  case SH_ARC:
471  {
472  const SHAPE_ARC* arc = static_cast<const SHAPE_ARC*>( shape );
473 
474  addAnchor( arc->GetP0(), OUTLINE | SNAPPABLE, aPad );
475  addAnchor( arc->GetP1(), OUTLINE | SNAPPABLE, aPad );
476  addAnchor( arc->GetArcMid(), OUTLINE | SNAPPABLE, aPad );
477  break;
478  }
479 
480  case SH_SIMPLE:
481  {
482  const SHAPE_SIMPLE* poly = static_cast<const SHAPE_SIMPLE*>( shape );
483 
484  for( size_t i = 0; i < poly->GetSegmentCount(); i++ )
485  {
486  const SEG& seg = poly->GetSegment( i );
487 
488  addAnchor( seg.A, OUTLINE | SNAPPABLE, aPad );
489  addAnchor( seg.Center(), OUTLINE | SNAPPABLE, aPad );
490 
491  if( i == poly->GetSegmentCount() - 1 )
492  addAnchor( seg.B, OUTLINE | SNAPPABLE, aPad );
493  }
494 
495  break;
496  }
497 
498  case SH_POLY_SET:
499  case SH_LINE_CHAIN:
500  case SH_COMPOUND:
502  case SH_NULL:
503  default:
504  break;
505  }
506  }
507  };
508 
509  switch( aItem->Type() )
510  {
511  case PCB_FOOTPRINT_T:
512  {
513  FOOTPRINT* footprint = static_cast<FOOTPRINT*>( aItem );
514 
515  for( PAD* pad : footprint->Pads() )
516  {
517  // Getting pads from the footprint requires re-checking that the pad is shown
519  && pad->GetBoundingBox().Contains( wxPoint( aRefPos.x, aRefPos.y ) )
520  && view->IsVisible( pad )
521  && ( !isHighContrast || activeLayers.count( pad->GetLayer() ) )
522  && pad->ViewGetLOD( pad->GetLayer(), view ) < view->GetScale() )
523  {
524  handlePadShape( pad );
525  break;
526  }
527  }
528 
529  // if the cursor is not over a pad, then drag the footprint by its origin
530  VECTOR2I position = footprint->GetPosition();
531  addAnchor( position, ORIGIN | SNAPPABLE, footprint );
532 
533  // Add the footprint center point if it is markedly different from the origin
534  VECTOR2I center = footprint->GetBoundingBox( false, false ).Centre();
535  VECTOR2I grid( GetGrid() );
536 
537  if( ( center - position ).SquaredEuclideanNorm() > grid.SquaredEuclideanNorm() )
538  addAnchor( center, ORIGIN | SNAPPABLE, footprint );
539 
540  break;
541  }
542 
543  case PCB_PAD_T:
544  {
546  {
547  PAD* pad = static_cast<PAD*>( aItem );
548  handlePadShape( pad );
549  }
550 
551  break;
552  }
553 
554  case PCB_FP_SHAPE_T:
555  case PCB_SHAPE_T:
556  {
558  break;
559 
560  PCB_SHAPE* shape = static_cast<PCB_SHAPE*>( aItem );
561  VECTOR2I start = shape->GetStart();
562  VECTOR2I end = shape->GetEnd();
563 
564  switch( shape->GetShape() )
565  {
566  case SHAPE_T::CIRCLE:
567  {
568  int r = ( start - end ).EuclideanNorm();
569 
570  addAnchor( start, ORIGIN | SNAPPABLE, shape );
571  addAnchor( start + VECTOR2I( -r, 0 ), OUTLINE | SNAPPABLE, shape );
572  addAnchor( start + VECTOR2I( r, 0 ), OUTLINE | SNAPPABLE, shape );
573  addAnchor( start + VECTOR2I( 0, -r ), OUTLINE | SNAPPABLE, shape );
574  addAnchor( start + VECTOR2I( 0, r ), OUTLINE | SNAPPABLE, shape );
575  break;
576  }
577 
578  case SHAPE_T::ARC:
579  addAnchor( shape->GetStart(), CORNER | SNAPPABLE, shape );
580  addAnchor( shape->GetEnd(), CORNER | SNAPPABLE, shape );
581  addAnchor( shape->GetArcMid(), CORNER | SNAPPABLE, shape );
582  addAnchor( shape->GetCenter(), ORIGIN | SNAPPABLE, shape );
583  break;
584 
585  case SHAPE_T::RECT:
586  {
587  VECTOR2I point2( end.x, start.y );
588  VECTOR2I point3( start.x, end.y );
589  SEG first( start, point2 );
590  SEG second( point2, end );
591  SEG third( end, point3 );
592  SEG fourth( point3, start );
593 
594  addAnchor( first.A, CORNER | SNAPPABLE, shape );
595  addAnchor( first.Center(), CORNER | SNAPPABLE, shape );
596  addAnchor( second.A, CORNER | SNAPPABLE, shape );
597  addAnchor( second.Center(), CORNER | SNAPPABLE, shape );
598  addAnchor( third.A, CORNER | SNAPPABLE, shape );
599  addAnchor( third.Center(), CORNER | SNAPPABLE, shape );
600  addAnchor( fourth.A, CORNER | SNAPPABLE, shape );
601  addAnchor( fourth.Center(), CORNER | SNAPPABLE, shape );
602  break;
603  }
604 
605  case SHAPE_T::SEGMENT:
606  addAnchor( start, CORNER | SNAPPABLE, shape );
607  addAnchor( end, CORNER | SNAPPABLE, shape );
608  addAnchor( shape->GetCenter(), CORNER | SNAPPABLE, shape );
609  break;
610 
611  case SHAPE_T::POLY:
612  {
613  SHAPE_LINE_CHAIN lc;
614  lc.SetClosed( true );
615  std::vector<wxPoint> poly;
616  shape->DupPolyPointsList( poly );
617 
618  for( const wxPoint& p : poly )
619  {
620  addAnchor( p, CORNER | SNAPPABLE, shape );
621  lc.Append( p );
622  }
623 
624  addAnchor( lc.NearestPoint( aRefPos ), OUTLINE, aItem );
625  break;
626  }
627 
628  case SHAPE_T::BEZIER:
629  addAnchor( start, CORNER | SNAPPABLE, shape );
630  addAnchor( end, CORNER | SNAPPABLE, shape );
632 
633  default:
634  addAnchor( shape->GetPosition(), ORIGIN | SNAPPABLE, shape );
635  break;
636  }
637  break;
638  }
639 
640  case PCB_TRACE_T:
641  case PCB_ARC_T:
642  {
644  {
645  PCB_TRACK* track = static_cast<PCB_TRACK*>( aItem );
646 
647  addAnchor( track->GetStart(), CORNER | SNAPPABLE, track );
648  addAnchor( track->GetEnd(), CORNER | SNAPPABLE, track );
649  addAnchor( track->GetCenter(), ORIGIN, track);
650  }
651 
652  break;
653  }
654 
655  case PCB_MARKER_T:
656  case PCB_TARGET_T:
657  addAnchor( aItem->GetPosition(), ORIGIN | CORNER | SNAPPABLE, aItem );
658  break;
659 
660  case PCB_VIA_T:
661  {
663  addAnchor( aItem->GetPosition(), ORIGIN | CORNER | SNAPPABLE, aItem );
664 
665  break;
666  }
667 
668  case PCB_ZONE_T:
669  {
670  const SHAPE_POLY_SET* outline = static_cast<const ZONE*>( aItem )->Outline();
671 
672  SHAPE_LINE_CHAIN lc;
673  lc.SetClosed( true );
674 
675  for( auto iter = outline->CIterateWithHoles(); iter; iter++ )
676  {
677  addAnchor( *iter, CORNER, aItem );
678  lc.Append( *iter );
679  }
680 
681  addAnchor( lc.NearestPoint( aRefPos ), OUTLINE, aItem );
682 
683  break;
684  }
685 
686  case PCB_DIM_ALIGNED_T:
688  {
689  const PCB_DIM_ALIGNED* dim = static_cast<const PCB_DIM_ALIGNED*>( aItem );
690  addAnchor( dim->GetCrossbarStart(), CORNER | SNAPPABLE, aItem );
691  addAnchor( dim->GetCrossbarEnd(), CORNER | SNAPPABLE, aItem );
692  addAnchor( dim->GetStart(), CORNER | SNAPPABLE, aItem );
693  addAnchor( dim->GetEnd(), CORNER | SNAPPABLE, aItem );
694  break;
695  }
696 
697  case PCB_DIM_CENTER_T:
698  {
699  const PCB_DIM_CENTER* dim = static_cast<const PCB_DIM_CENTER*>( aItem );
700  addAnchor( dim->GetStart(), CORNER | SNAPPABLE, aItem );
701  addAnchor( dim->GetEnd(), CORNER | SNAPPABLE, aItem );
702 
703  VECTOR2I start( dim->GetStart() );
704  VECTOR2I radial( dim->GetEnd() - dim->GetStart() );
705 
706  for( int i = 0; i < 2; i++ )
707  {
708  radial = radial.Rotate( DEG2RAD( 90 ) );
709  addAnchor( start + radial, CORNER | SNAPPABLE, aItem );
710  }
711 
712  break;
713  }
714 
715  case PCB_DIM_LEADER_T:
716  {
717  const PCB_DIM_LEADER* leader = static_cast<const PCB_DIM_LEADER*>( aItem );
718  addAnchor( leader->GetStart(), CORNER | SNAPPABLE, aItem );
719  addAnchor( leader->GetEnd(), CORNER | SNAPPABLE, aItem );
720  addAnchor( leader->Text().GetPosition(), CORNER | SNAPPABLE, aItem );
721  break;
722  }
723 
724  case PCB_FP_TEXT_T:
725  case PCB_TEXT_T:
726  addAnchor( aItem->GetPosition(), ORIGIN, aItem );
727  break;
728 
729  case PCB_GROUP_T:
730  {
731  const PCB_GROUP* group = static_cast<const PCB_GROUP*>( aItem );
732 
733  for( BOARD_ITEM* item : group->GetItems() )
734  computeAnchors( item, aRefPos, aFrom );
735 
736  break;
737  }
738 
739  default:
740  break;
741  }
742 }
743 
744 
746  LSET aMatchLayers )
747 {
748  double minDist = std::numeric_limits<double>::max();
749  ANCHOR* best = nullptr;
750 
751  for( ANCHOR& a : m_anchors )
752  {
753  BOARD_ITEM* item = static_cast<BOARD_ITEM*>( a.item );
754 
755  if( ( aMatchLayers & item->GetLayerSet() ) == 0 )
756  continue;
757 
758  if( ( aFlags & a.flags ) != aFlags )
759  continue;
760 
761  double dist = a.Distance( aPos );
762 
763  if( dist < minDist )
764  {
765  minDist = dist;
766  best = &a;
767  }
768  }
769 
770  return best;
771 }
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:285
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:218
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:97
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:1168
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:197
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:122
LSET is a set of PCB_LAYER_IDs.
Definition: layer_ids.h:505
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
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
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
wxPoint GetArcMid() const
Definition: eda_shape.cpp:437
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:187
wxPoint Centre() const
Definition: eda_rect.h:55
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:92
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:147
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