KiCad PCB EDA Suite
Loading...
Searching...
No Matches
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-2023 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 <pcb_dimension.h>
28#include <pcb_shape.h>
29#include <footprint.h>
30#include <pad.h>
31#include <pcb_group.h>
32#include <pcb_track.h>
33#include <zone.h>
36#include <geometry/shape_rect.h>
39#include <macros.h>
40#include <math/util.h> // for KiROUND
41#include <painter.h>
42#include <pcbnew_settings.h>
43#include <tool/tool_manager.h>
44#include <tools/pcb_tool_base.h>
45#include <view/view.h>
46#include "pcb_grid_helper.h"
47
48
50 GRID_HELPER( aToolMgr ),
51 m_magneticSettings( aMagneticSettings )
52{
53 KIGFX::VIEW* view = m_toolMgr->GetView();
54 KIGFX::RENDER_SETTINGS* settings = view->GetPainter()->GetSettings();
55 KIGFX::COLOR4D auxItemsColor = settings->GetLayerColor( LAYER_AUX_ITEMS );
56 KIGFX::COLOR4D umbilicalColor = settings->GetLayerColor( LAYER_ANCHOR );
57
58 m_viewAxis.SetSize( 20000 );
60 m_viewAxis.SetColor( auxItemsColor.WithAlpha( 0.4 ) );
62 view->Add( &m_viewAxis );
63 view->SetVisible( &m_viewAxis, false );
64
66 m_viewSnapPoint.SetColor( auxItemsColor );
68 view->Add( &m_viewSnapPoint );
69 view->SetVisible( &m_viewSnapPoint, false );
70
72 m_viewSnapLine.SetColor( umbilicalColor );
74 view->Add( &m_viewSnapLine );
75 view->SetVisible( &m_viewSnapLine, false );
76}
77
78
80{
81 const int c_gridSnapEpsilon_sq = 4;
82
83 VECTOR2I aligned = Align( aPoint );
84
85 if( !m_enableSnap )
86 return aligned;
87
88 std::vector<VECTOR2I> points;
89
90 const SEG testSegments[] = { SEG( aligned, aligned + VECTOR2( 1, 0 ) ),
91 SEG( aligned, aligned + VECTOR2( 0, 1 ) ),
92 SEG( aligned, aligned + VECTOR2( 1, 1 ) ),
93 SEG( aligned, aligned + VECTOR2( 1, -1 ) ) };
94
95 for( const SEG& seg : testSegments )
96 {
97 OPT_VECTOR2I vec = aSeg.IntersectLines( seg );
98
99 if( vec && aSeg.SquaredDistance( *vec ) <= c_gridSnapEpsilon_sq )
100 points.push_back( *vec );
101 }
102
103 VECTOR2I nearest = aligned;
105
106 // Snap by distance between pointer and endpoints
107 for( const VECTOR2I& pt : { aSeg.A, aSeg.B } )
108 {
109 SEG::ecoord d_sq = ( pt - aPoint ).SquaredEuclideanNorm();
110
111 if( d_sq < min_d_sq )
112 {
113 min_d_sq = d_sq;
114 nearest = pt;
115 }
116 }
117
118 // Snap by distance between aligned cursor and intersections
119 for( const VECTOR2I& pt : points )
120 {
121 SEG::ecoord d_sq = ( pt - aligned ).SquaredEuclideanNorm();
122
123 if( d_sq < min_d_sq )
124 {
125 min_d_sq = d_sq;
126 nearest = pt;
127 }
128 }
129
130 return nearest;
131}
132
133
135{
136 VECTOR2I aligned = Align( aPoint );
137
138 if( !m_enableSnap )
139 return aligned;
140
141 std::vector<VECTOR2I> points;
142
143 aArc.IntersectLine( SEG( aligned, aligned + VECTOR2( 1, 0 ) ), &points );
144 aArc.IntersectLine( SEG( aligned, aligned + VECTOR2( 0, 1 ) ), &points );
145 aArc.IntersectLine( SEG( aligned, aligned + VECTOR2( 1, 1 ) ), &points );
146 aArc.IntersectLine( SEG( aligned, aligned + VECTOR2( 1, -1 ) ), &points );
147
148 VECTOR2I nearest = aligned;
150
151 // Snap by distance between pointer and endpoints
152 for( const VECTOR2I& pt : { aArc.GetP0(), aArc.GetP1() } )
153 {
154 SEG::ecoord d_sq = ( pt - aPoint ).SquaredEuclideanNorm();
155
156 if( d_sq < min_d_sq )
157 {
158 min_d_sq = d_sq;
159 nearest = pt;
160 }
161 }
162
163 // Snap by distance between aligned cursor and intersections
164 for( const VECTOR2I& pt : points )
165 {
166 SEG::ecoord d_sq = ( pt - aligned ).SquaredEuclideanNorm();
167
168 if( d_sq < min_d_sq )
169 {
170 min_d_sq = d_sq;
171 nearest = pt;
172 }
173 }
174
175 return nearest;
176}
177
178
180{
181 clearAnchors();
182
183 for( BOARD_ITEM* item : aPads )
184 computeAnchors( item, aMousePos, true );
185
186 double minDist = std::numeric_limits<double>::max();
187 ANCHOR* nearestOrigin = nullptr;
188
189 for( ANCHOR& a : m_anchors )
190 {
191 BOARD_ITEM* item = static_cast<BOARD_ITEM*>( a.item );
192
193 if( ( ORIGIN & a.flags ) != ORIGIN )
194 continue;
195
196 if( !item->HitTest( aMousePos ) )
197 continue;
198
199 double dist = a.Distance( aMousePos );
200
201 if( dist < minDist )
202 {
203 minDist = dist;
204 nearestOrigin = &a;
205 }
206 }
207
208 return nearestOrigin ? nearestOrigin->pos : aMousePos;
209}
210
211
213 std::vector<BOARD_ITEM*>& aItems,
214 const SELECTION_FILTER_OPTIONS* aSelectionFilter )
215{
216 clearAnchors();
217
218 for( BOARD_ITEM* item : aItems )
219 computeAnchors( item, aMousePos, true, aSelectionFilter );
220
221 double worldScale = m_toolMgr->GetView()->GetGAL()->GetWorldScale();
222 double lineSnapMinCornerDistance = 50.0 / worldScale;
223
224 ANCHOR* nearestOutline = nearestAnchor( aMousePos, OUTLINE, LSET::AllLayersMask() );
225 ANCHOR* nearestCorner = nearestAnchor( aMousePos, CORNER, LSET::AllLayersMask() );
226 ANCHOR* nearestOrigin = nearestAnchor( aMousePos, ORIGIN, LSET::AllLayersMask() );
227 ANCHOR* best = nullptr;
228 double minDist = std::numeric_limits<double>::max();
229
230 if( nearestOrigin )
231 {
232 minDist = nearestOrigin->Distance( aMousePos );
233 best = nearestOrigin;
234 }
235
236 if( nearestCorner )
237 {
238 double dist = nearestCorner->Distance( aMousePos );
239
240 if( dist < minDist )
241 {
242 minDist = dist;
243 best = nearestCorner;
244 }
245 }
246
247 if( nearestOutline )
248 {
249 double dist = nearestOutline->Distance( aMousePos );
250
251 if( minDist > lineSnapMinCornerDistance && dist < minDist )
252 best = nearestOutline;
253 }
254
255 return best ? best->pos : aMousePos;
256}
257
258
260{
261 LSET layers;
262 std::vector<BOARD_ITEM*> item;
263
264 if( aReferenceItem )
265 {
266 layers = aReferenceItem->GetLayerSet();
267 item.push_back( aReferenceItem );
268 }
269 else
270 {
271 layers = LSET::AllLayersMask();
272 }
273
274 return BestSnapAnchor( aOrigin, layers, item );
275}
276
277
279 const std::vector<BOARD_ITEM*>& aSkip )
280{
281 // Tuning constant: snap radius in screen space
282 const int snapSize = 25;
283
284 // Snapping distance is in screen space, clamped to the current grid to ensure that the grid
285 // points that are visible can always be snapped to.
286 // see https://gitlab.com/kicad/code/kicad/-/issues/5638
287 // see https://gitlab.com/kicad/code/kicad/-/issues/7125
288 // see https://gitlab.com/kicad/code/kicad/-/issues/12303
289 int snapScale = KiROUND( snapSize / m_toolMgr->GetView()->GetGAL()->GetWorldScale() );
290 int snapRange = m_enableGrid ? std::min( snapScale, GetVisibleGrid().x ) : snapScale;
291 int snapDist = snapRange;
292
293 //Respect limits of coordinates representation
294 BOX2I bb;
295 bb.SetOrigin( GetClampedCoords<double, int>( VECTOR2D( aOrigin ) - snapRange / 2.0 ) );
296 bb.SetEnd( GetClampedCoords<double, int>( VECTOR2D( aOrigin ) + snapRange / 2.0 ) );
297
298 clearAnchors();
299
300 for( BOARD_ITEM* item : queryVisible( bb, aSkip ) )
301 computeAnchors( item, aOrigin );
302
303 ANCHOR* nearest = nearestAnchor( aOrigin, SNAPPABLE, aLayers );
304 VECTOR2I nearestGrid = Align( aOrigin );
305
306 if( nearest )
307 snapDist = nearest->Distance( aOrigin );
308
309 // Existing snap lines need priority over new snaps
311 {
312 bool snapLine = false;
313 int x_dist = std::abs( m_viewSnapLine.GetPosition().x - aOrigin.x );
314 int y_dist = std::abs( m_viewSnapLine.GetPosition().y - aOrigin.y );
315
317 if( x_dist < snapRange && ( !nearest || snapDist > snapRange ) )
318 {
319 nearestGrid.x = m_viewSnapLine.GetPosition().x;
320 snapLine = true;
321 }
322
323 if( y_dist < snapRange && ( !nearest || snapDist > snapRange ) )
324 {
325 nearestGrid.y = m_viewSnapLine.GetPosition().y;
326 snapLine = true;
327 }
328
329 if( snapLine && m_skipPoint != VECTOR2I( m_viewSnapLine.GetPosition() ) )
330 {
331 m_viewSnapLine.SetEndPosition( nearestGrid );
332
335 else
337
338 return nearestGrid;
339 }
340 }
341
342 if( nearest && m_enableSnap )
343 {
344 if( nearest->Distance( aOrigin ) <= snapRange )
345 {
346 m_viewSnapPoint.SetPosition( nearest->pos );
347 m_viewSnapLine.SetPosition( nearest->pos );
349
352 else
354
355 m_snapItem = nearest;
356 return nearest->pos;
357 }
358 }
359
360 m_snapItem = nullptr;
363 return nearestGrid;
364}
365
366
368{
369 if( !m_snapItem )
370 return nullptr;
371
372 return static_cast<BOARD_ITEM*>( m_snapItem->item );
373}
374
375
376std::set<BOARD_ITEM*> PCB_GRID_HELPER::queryVisible( const BOX2I& aArea,
377 const std::vector<BOARD_ITEM*>& aSkip ) const
378{
379 std::set<BOARD_ITEM*> items;
380 std::vector<KIGFX::VIEW::LAYER_ITEM_PAIR> selectedItems;
381
382 KIGFX::VIEW* view = m_toolMgr->GetView();
383 RENDER_SETTINGS* settings = view->GetPainter()->GetSettings();
384 const std::set<int>& activeLayers = settings->GetHighContrastLayers();
385 bool isHighContrast = settings->GetHighContrast();
386
387 view->Query( aArea, selectedItems );
388
389 for( const KIGFX::VIEW::LAYER_ITEM_PAIR& it : selectedItems )
390 {
391 BOARD_ITEM* item = static_cast<BOARD_ITEM*>( it.first );
392
393 // If we are in the footprint editor, don't use the footprint itself
395 && item->Type() == PCB_FOOTPRINT_T )
396 {
397 continue;
398 }
399
400 // The item must be visible and on an active layer
401 if( view->IsVisible( item )
402 && ( !isHighContrast || activeLayers.count( it.second ) )
403 && item->ViewGetLOD( it.second, view ) < view->GetScale() )
404 {
405 items.insert ( item );
406 }
407 }
408
409 for( BOARD_ITEM* skipItem : aSkip )
410 items.erase( skipItem );
411
412 return items;
413}
414
415
416void PCB_GRID_HELPER::computeAnchors( BOARD_ITEM* aItem, const VECTOR2I& aRefPos, bool aFrom,
417 const SELECTION_FILTER_OPTIONS* aSelectionFilter )
418{
419 KIGFX::VIEW* view = m_toolMgr->GetView();
420 RENDER_SETTINGS* settings = view->GetPainter()->GetSettings();
421 const std::set<int>& activeLayers = settings->GetHighContrastLayers();
422 bool isHighContrast = settings->GetHighContrast();
423
424 auto handlePadShape =
425 [&]( PAD* aPad )
426 {
427 addAnchor( aPad->GetPosition(), ORIGIN | SNAPPABLE, aPad );
428
430 if( aFrom )
431 return;
432
433 switch( aPad->GetShape() )
434 {
435 case PAD_SHAPE::CIRCLE:
436 {
437 int r = aPad->GetSizeX() / 2;
438 VECTOR2I center = aPad->ShapePos();
439
440 addAnchor( center + VECTOR2I( -r, 0 ), OUTLINE | SNAPPABLE, aPad );
441 addAnchor( center + VECTOR2I( r, 0 ), OUTLINE | SNAPPABLE, aPad );
442 addAnchor( center + VECTOR2I( 0, -r ), OUTLINE | SNAPPABLE, aPad );
443 addAnchor( center + VECTOR2I( 0, r ), OUTLINE | SNAPPABLE, aPad );
444 break;
445 }
446
447 case PAD_SHAPE::OVAL:
448 {
449 VECTOR2I pos = aPad->ShapePos();
450 VECTOR2I half_size = aPad->GetSize() / 2;
451 int half_width = std::min( half_size.x, half_size.y );
452 VECTOR2I half_len( half_size.x - half_width, half_size.y - half_width );
453
454 RotatePoint( half_len, aPad->GetOrientation() );
455
456 VECTOR2I a( pos - half_len );
457 VECTOR2I b( pos + half_len );
458 VECTOR2I normal = b - a;
459 normal.Resize( half_width );
461
462 addAnchor( a + normal, OUTLINE | SNAPPABLE, aPad );
463 addAnchor( a - normal, OUTLINE | SNAPPABLE, aPad );
464 addAnchor( b + normal, OUTLINE | SNAPPABLE, aPad );
465 addAnchor( b - normal, OUTLINE | SNAPPABLE, aPad );
466 addAnchor( pos + normal, OUTLINE | SNAPPABLE, aPad );
467 addAnchor( pos - normal, OUTLINE | SNAPPABLE, aPad );
468
470
471 addAnchor( a - normal, OUTLINE | SNAPPABLE, aPad );
472 addAnchor( b + normal, OUTLINE | SNAPPABLE, aPad );
473 break;
474 }
475
476 case PAD_SHAPE::RECTANGLE:
477 case PAD_SHAPE::TRAPEZOID:
478 case PAD_SHAPE::ROUNDRECT:
479 case PAD_SHAPE::CHAMFERED_RECT:
480 {
481 VECTOR2I half_size( aPad->GetSize() / 2 );
482 VECTOR2I trap_delta( 0, 0 );
483
484 if( aPad->GetShape() == PAD_SHAPE::TRAPEZOID )
485 trap_delta = aPad->GetDelta() / 2;
486
487 SHAPE_LINE_CHAIN corners;
488
489 corners.Append( -half_size.x - trap_delta.y, half_size.y + trap_delta.x );
490 corners.Append( half_size.x + trap_delta.y, half_size.y - trap_delta.x );
491 corners.Append( half_size.x - trap_delta.y, -half_size.y + trap_delta.x );
492 corners.Append( -half_size.x + trap_delta.y, -half_size.y - trap_delta.x );
493 corners.SetClosed( true );
494
495 corners.Rotate( aPad->GetOrientation() );
496 corners.Move( aPad->ShapePos() );
497
498 for( size_t ii = 0; ii < corners.GetSegmentCount(); ++ii )
499 {
500 const SEG& seg = corners.GetSegment( ii );
501 addAnchor( seg.A, OUTLINE | SNAPPABLE, aPad );
502 addAnchor( seg.Center(), OUTLINE | SNAPPABLE, aPad );
503
504 if( ii == corners.GetSegmentCount() - 1 )
505 addAnchor( seg.B, OUTLINE | SNAPPABLE, aPad );
506 }
507
508 break;
509 }
510
511 default:
512 {
513 const std::shared_ptr<SHAPE_POLY_SET>& outline = aPad->GetEffectivePolygon();
514
515 if( !outline->IsEmpty() )
516 {
517 for( const VECTOR2I& pt : outline->Outline( 0 ).CPoints() )
518 addAnchor( pt, OUTLINE | SNAPPABLE, aPad );
519 }
520
521 break;
522 }
523 }
524 };
525
526 auto handleShape =
527 [&]( PCB_SHAPE* shape )
528 {
529 VECTOR2I start = shape->GetStart();
530 VECTOR2I end = shape->GetEnd();
531
532 switch( shape->GetShape() )
533 {
534 case SHAPE_T::CIRCLE:
535 {
536 int r = ( start - end ).EuclideanNorm();
537
538 addAnchor( start, ORIGIN | SNAPPABLE, shape );
539 addAnchor( start + VECTOR2I( -r, 0 ), OUTLINE | SNAPPABLE, shape );
540 addAnchor( start + VECTOR2I( r, 0 ), OUTLINE | SNAPPABLE, shape );
541 addAnchor( start + VECTOR2I( 0, -r ), OUTLINE | SNAPPABLE, shape );
542 addAnchor( start + VECTOR2I( 0, r ), OUTLINE | SNAPPABLE, shape );
543 break;
544 }
545
546 case SHAPE_T::ARC:
547 addAnchor( shape->GetStart(), CORNER | SNAPPABLE, shape );
548 addAnchor( shape->GetEnd(), CORNER | SNAPPABLE, shape );
549 addAnchor( shape->GetArcMid(), CORNER | SNAPPABLE, shape );
550 addAnchor( shape->GetCenter(), ORIGIN | SNAPPABLE, shape );
551 break;
552
553 case SHAPE_T::RECT:
554 {
555 VECTOR2I point2( end.x, start.y );
556 VECTOR2I point3( start.x, end.y );
557 SEG first( start, point2 );
558 SEG second( point2, end );
559 SEG third( end, point3 );
560 SEG fourth( point3, start );
561
562 addAnchor( first.A, CORNER | SNAPPABLE, shape );
563 addAnchor( first.Center(), CORNER | SNAPPABLE, shape );
564 addAnchor( second.A, CORNER | SNAPPABLE, shape );
565 addAnchor( second.Center(), CORNER | SNAPPABLE, shape );
566 addAnchor( third.A, CORNER | SNAPPABLE, shape );
567 addAnchor( third.Center(), CORNER | SNAPPABLE, shape );
568 addAnchor( fourth.A, CORNER | SNAPPABLE, shape );
569 addAnchor( fourth.Center(), CORNER | SNAPPABLE, shape );
570 break;
571 }
572
573 case SHAPE_T::SEGMENT:
574 addAnchor( start, CORNER | SNAPPABLE, shape );
575 addAnchor( end, CORNER | SNAPPABLE, shape );
576 addAnchor( shape->GetCenter(), CORNER | SNAPPABLE, shape );
577 break;
578
579 case SHAPE_T::POLY:
580 {
582 lc.SetClosed( true );
583 std::vector<VECTOR2I> poly;
584 shape->DupPolyPointsList( poly );
585
586 for( const VECTOR2I& p : poly )
587 {
588 addAnchor( p, CORNER | SNAPPABLE, shape );
589 lc.Append( p );
590 }
591
592 addAnchor( lc.NearestPoint( aRefPos ), OUTLINE, aItem );
593 break;
594 }
595
596 case SHAPE_T::BEZIER:
597 addAnchor( start, CORNER | SNAPPABLE, shape );
598 addAnchor( end, CORNER | SNAPPABLE, shape );
600
601 default:
602 addAnchor( shape->GetPosition(), ORIGIN | SNAPPABLE, shape );
603 break;
604 }
605 };
606
607 switch( aItem->Type() )
608 {
609 case PCB_FOOTPRINT_T:
610 {
611 FOOTPRINT* footprint = static_cast<FOOTPRINT*>( aItem );
612
613 for( PAD* pad : footprint->Pads() )
614 {
615 if( aFrom )
616 {
617 if( aSelectionFilter && !aSelectionFilter->pads )
618 continue;
619 }
620 else
621 {
622 if( m_magneticSettings->pads != MAGNETIC_OPTIONS::CAPTURE_ALWAYS )
623 continue;
624 }
625
626 if( !view->IsVisible( pad ) || !pad->GetBoundingBox().Contains( aRefPos ) )
627 continue;
628
629 // Getting pads from a footprint requires re-checking that the pads are shown
630 bool onActiveLayer = !isHighContrast;
631 bool isLODVisible = false;
632
633 for( PCB_LAYER_ID layer : pad->GetLayerSet().Seq() )
634 {
635 if( !onActiveLayer && activeLayers.count( layer ) )
636 onActiveLayer = true;
637
638 if( !isLODVisible && pad->ViewGetLOD( layer, view ) < view->GetScale() )
639 isLODVisible = true;
640
641 if( onActiveLayer && isLODVisible )
642 {
643 handlePadShape( pad );
644 break;
645 }
646 }
647 }
648
649 if( aFrom && aSelectionFilter && !aSelectionFilter->footprints )
650 break;
651
652 // if the cursor is not over a pad, then drag the footprint by its origin
653 VECTOR2I position = footprint->GetPosition();
654 addAnchor( position, ORIGIN | SNAPPABLE, footprint );
655
656 // Add the footprint center point if it is markedly different from the origin
657 VECTOR2I center = footprint->GetBoundingBox( false, false ).Centre();
658 VECTOR2I grid( GetGrid() );
659
660 if( ( center - position ).SquaredEuclideanNorm() > grid.SquaredEuclideanNorm() )
661 addAnchor( center, ORIGIN | SNAPPABLE, footprint );
662
663 break;
664 }
665
666 case PCB_PAD_T:
667 if( aFrom )
668 {
669 if( aSelectionFilter && !aSelectionFilter->pads )
670 break;
671 }
672 else
673 {
674 if( m_magneticSettings->pads != MAGNETIC_OPTIONS::CAPTURE_ALWAYS )
675 break;
676 }
677
678 handlePadShape( static_cast<PAD*>( aItem ) );
679
680 break;
681
682 case PCB_TEXTBOX_T:
683 if( aFrom )
684 {
685 if( aSelectionFilter && !aSelectionFilter->text )
686 break;
687 }
688 else
689 {
691 break;
692 }
693
694 handleShape( static_cast<PCB_SHAPE*>( aItem ) );
695 break;
696
697 case PCB_SHAPE_T:
698 if( aFrom )
699 {
700 if( aSelectionFilter && !aSelectionFilter->graphics )
701 break;
702 }
703 else
704 {
706 break;
707 }
708
709 handleShape( static_cast<PCB_SHAPE*>( aItem ) );
710 break;
711
712 case PCB_TRACE_T:
713 case PCB_ARC_T:
714 {
715 if( aFrom )
716 {
717 if( aSelectionFilter && !aSelectionFilter->tracks )
718 break;
719 }
720 else
721 {
722 if( m_magneticSettings->tracks != MAGNETIC_OPTIONS::CAPTURE_ALWAYS )
723 break;
724 }
725
726 PCB_TRACK* track = static_cast<PCB_TRACK*>( aItem );
727
728 addAnchor( track->GetStart(), CORNER | SNAPPABLE, track );
729 addAnchor( track->GetEnd(), CORNER | SNAPPABLE, track );
730 addAnchor( track->GetCenter(), ORIGIN, track);
731
732 break;
733 }
734
735 case PCB_MARKER_T:
736 case PCB_TARGET_T:
737 addAnchor( aItem->GetPosition(), ORIGIN | CORNER | SNAPPABLE, aItem );
738 break;
739
740 case PCB_VIA_T:
741 if( aFrom )
742 {
743 if( aSelectionFilter && !aSelectionFilter->vias )
744 break;
745 }
746 else
747 {
748 if( m_magneticSettings->tracks != MAGNETIC_OPTIONS::CAPTURE_ALWAYS )
749 break;
750 }
751
752 addAnchor( aItem->GetPosition(), ORIGIN | CORNER | SNAPPABLE, aItem );
753
754 break;
755
756 case PCB_ZONE_T:
757 {
758 if( aFrom && aSelectionFilter && !aSelectionFilter->zones )
759 break;
760
761 const SHAPE_POLY_SET* outline = static_cast<const ZONE*>( aItem )->Outline();
762
764 lc.SetClosed( true );
765
766 for( auto iter = outline->CIterateWithHoles(); iter; iter++ )
767 {
768 addAnchor( *iter, CORNER | SNAPPABLE, aItem );
769 lc.Append( *iter );
770 }
771
772 addAnchor( lc.NearestPoint( aRefPos ), OUTLINE, aItem );
773
774 break;
775 }
776
779 {
780 if( aFrom && aSelectionFilter && !aSelectionFilter->dimensions )
781 break;
782
783 const PCB_DIM_ALIGNED* dim = static_cast<const PCB_DIM_ALIGNED*>( aItem );
784 addAnchor( dim->GetCrossbarStart(), CORNER | SNAPPABLE, aItem );
785 addAnchor( dim->GetCrossbarEnd(), CORNER | SNAPPABLE, aItem );
786 addAnchor( dim->GetStart(), CORNER | SNAPPABLE, aItem );
787 addAnchor( dim->GetEnd(), CORNER | SNAPPABLE, aItem );
788 break;
789 }
790
791 case PCB_DIM_CENTER_T:
792 {
793 if( aFrom && aSelectionFilter && !aSelectionFilter->dimensions )
794 break;
795
796 const PCB_DIM_CENTER* dim = static_cast<const PCB_DIM_CENTER*>( aItem );
797 addAnchor( dim->GetStart(), CORNER | SNAPPABLE, aItem );
798 addAnchor( dim->GetEnd(), CORNER | SNAPPABLE, aItem );
799
800 VECTOR2I start( dim->GetStart() );
801 VECTOR2I radial( dim->GetEnd() - dim->GetStart() );
802
803 for( int i = 0; i < 2; i++ )
804 {
805 RotatePoint( radial, -ANGLE_90 );
806 addAnchor( start + radial, CORNER | SNAPPABLE, aItem );
807 }
808
809 break;
810 }
811
812 case PCB_DIM_RADIAL_T:
813 {
814 if( aFrom && aSelectionFilter && !aSelectionFilter->dimensions )
815 break;
816
817 const PCB_DIM_RADIAL* radialDim = static_cast<const PCB_DIM_RADIAL*>( aItem );
818 addAnchor( radialDim->GetStart(), CORNER | SNAPPABLE, aItem );
819 addAnchor( radialDim->GetEnd(), CORNER | SNAPPABLE, aItem );
820 addAnchor( radialDim->GetKnee(), CORNER | SNAPPABLE, aItem );
821 addAnchor( radialDim->GetTextPos(), CORNER | SNAPPABLE, aItem );
822 break;
823 }
824
825 case PCB_DIM_LEADER_T:
826 {
827 if( aFrom && aSelectionFilter && !aSelectionFilter->dimensions )
828 break;
829
830 const PCB_DIM_LEADER* leader = static_cast<const PCB_DIM_LEADER*>( aItem );
831 addAnchor( leader->GetStart(), CORNER | SNAPPABLE, aItem );
832 addAnchor( leader->GetEnd(), CORNER | SNAPPABLE, aItem );
833 addAnchor( leader->GetTextPos(), CORNER | SNAPPABLE, aItem );
834 break;
835 }
836
837 case PCB_TEXT_T:
838 if( aFrom && aSelectionFilter && !aSelectionFilter->text )
839 break;
840
841 addAnchor( aItem->GetPosition(), ORIGIN, aItem );
842 break;
843
844 case PCB_GROUP_T:
845 {
846 const PCB_GROUP* group = static_cast<const PCB_GROUP*>( aItem );
847
848 for( BOARD_ITEM* item : group->GetItems() )
849 computeAnchors( item, aRefPos, aFrom );
850
851 break;
852 }
853
854 default:
855 break;
856 }
857}
858
859
861 LSET aMatchLayers )
862{
863 double minDist = std::numeric_limits<double>::max();
864 ANCHOR* best = nullptr;
865
866 for( ANCHOR& a : m_anchors )
867 {
868 BOARD_ITEM* item = static_cast<BOARD_ITEM*>( a.item );
869
870 if( ( aMatchLayers & item->GetLayerSet() ) == 0 )
871 continue;
872
873 if( ( aFlags & a.flags ) != aFlags )
874 continue;
875
876 double dist = a.Distance( aPos );
877
878 if( dist < minDist )
879 {
880 minDist = dist;
881 best = &a;
882 }
883 }
884
885 return best;
886}
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition: board_item.h:71
virtual VECTOR2I GetCenter() const
This defaults to the center of the bounding box if not overridden.
Definition: board_item.h:106
virtual LSET GetLayerSet() const
Return a std::bitset of all layers on which the item physically resides.
Definition: board_item.h:201
void SetOrigin(const Vec &pos)
Definition: box2.h:203
Vec Centre() const
Definition: box2.h:71
void SetEnd(coord_type x, coord_type y)
Definition: box2.h:256
virtual VECTOR2I GetPosition() const
Definition: eda_item.h:232
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:97
virtual bool HitTest(const VECTOR2I &aPosition, int aAccuracy=0) const
Test if aPosition is inside or on the boundary of this item.
Definition: eda_item.h:205
const VECTOR2I & GetTextPos() const
Definition: eda_text.h:216
PADS & Pads()
Definition: footprint.h:172
VECTOR2I GetPosition() const override
Definition: footprint.h:190
const BOX2I GetBoundingBox() const override
Return the orthogonal bounding box of this object for display purposes.
Definition: footprint.cpp:806
VECTOR2I m_skipPoint
Definition: grid_helper.h:141
bool m_enableGrid
Definition: grid_helper.h:137
VECTOR2I GetVisibleGrid() const
Definition: grid_helper.cpp:59
virtual VECTOR2I Align(const VECTOR2I &aPoint) const
TOOL_MANAGER * m_toolMgr
Definition: grid_helper.h:131
VECTOR2I GetGrid() const
Definition: grid_helper.cpp:51
ANCHOR * m_snapItem
Definition: grid_helper.h:139
bool m_enableSnapLine
Definition: grid_helper.h:138
bool m_enableSnap
Definition: grid_helper.h:136
void addAnchor(const VECTOR2I &aPos, int aFlags, EDA_ITEM *aItem)
Definition: grid_helper.h:107
void clearAnchors()
Definition: grid_helper.h:113
KIGFX::ORIGIN_VIEWITEM m_viewSnapPoint
Definition: grid_helper.h:143
KIGFX::ORIGIN_VIEWITEM m_viewSnapLine
Definition: grid_helper.h:144
KIGFX::ORIGIN_VIEWITEM m_viewAxis
Definition: grid_helper.h:145
std::vector< ANCHOR > m_anchors
Definition: grid_helper.h:129
A color representation with 4 components: red, green, blue, alpha.
Definition: color4d.h:103
COLOR4D WithAlpha(double aAlpha) const
Return a color with the same color, but the given alpha.
Definition: color4d.h:310
double GetWorldScale() const
Get the world scale.
void SetPosition(const VECTOR2I &aPosition) override
void SetColor(const KIGFX::COLOR4D &aColor)
VECTOR2I GetPosition() const override
void SetStyle(MARKER_STYLE aStyle)
void SetSize(int aSize)
void SetDrawAtZero(bool aDrawFlag)
Set the draw at zero flag.
void SetEndPosition(const VECTOR2D &aPosition)
virtual RENDER_SETTINGS * GetSettings()=0
Return a pointer to current settings that are going to be used when drawing items.
Container for all the knowledge about how graphical objects are drawn on any output surface/device.
const std::set< int > GetHighContrastLayers() const
Returns the set of currently high-contrast layers.
const COLOR4D & GetLayerColor(int aLayer) const
Return the color used to draw a layer.
bool GetHighContrast() const
virtual double ViewGetLOD(int aLayer, VIEW *aView) const
Return the level of detail (LOD) of the item.
Definition: view_item.h:134
Hold a (potentially large) number of VIEW_ITEMs and renders them on a graphics device provided by the...
Definition: view.h:69
double GetScale() const
Definition: view.h:269
virtual void Add(VIEW_ITEM *aItem, int aDrawPriority=-1)
Add a VIEW_ITEM to the view.
Definition: view.cpp:314
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:422
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:1608
GAL * GetGAL() const
Return the #GAL this view is using to draw graphical primitives.
Definition: view.h:195
std::pair< VIEW_ITEM *, int > LAYER_ITEM_PAIR
Definition: view.h:73
PAINTER * GetPainter() const
Return the painter object used by the view for drawing #VIEW_ITEMS.
Definition: view.h:213
bool IsVisible(const VIEW_ITEM *aItem) const
Return information if the item is visible (or not).
Definition: view.cpp:1586
void SetVisible(VIEW_ITEM *aItem, bool aIsVisible=true)
Set the item visibility.
Definition: view.cpp:1546
LSET is a set of PCB_LAYER_IDs.
Definition: layer_ids.h:536
static LSET AllLayersMask()
Definition: lset.cpp:808
Definition: pad.h:59
virtual const VECTOR2I & GetStart() const
The dimension's origin is the first feature point for the dimension.
virtual const VECTOR2I & GetEnd() const
For better understanding of the points that make a dimension:
const VECTOR2I & GetCrossbarStart() const
const VECTOR2I & GetCrossbarEnd() const
Mark the center of a circle or arc with a cross shape.
A leader is a dimension-like object pointing to a specific point.
A radial dimension indicates either the radius or diameter of an arc or circle.
VECTOR2I GetKnee() const
VECTOR2I AlignToArc(const VECTOR2I &aPoint, const SHAPE_ARC &aSeg)
VECTOR2I BestSnapAnchor(const VECTOR2I &aOrigin, BOARD_ITEM *aReferenceItem)
Chooses the "best" snap anchor around the given point, optionally taking layers from the reference it...
void computeAnchors(BOARD_ITEM *aItem, const VECTOR2I &aRefPos, bool aFrom=false, const SELECTION_FILTER_OPTIONS *aSelectionFilter=nullptr)
computeAnchors inserts the local anchor points in to the grid helper for the specified board item,...
BOARD_ITEM * GetSnapped() const
Function GetSnapped If the PCB_GRID_HELPER has highlighted a snap point (target shown),...
VECTOR2I BestDragOrigin(const VECTOR2I &aMousePos, std::vector< BOARD_ITEM * > &aItem, const SELECTION_FILTER_OPTIONS *aSelectionFilter=nullptr)
std::set< BOARD_ITEM * > queryVisible(const BOX2I &aArea, const std::vector< BOARD_ITEM * > &aSkip) const
ANCHOR * nearestAnchor(const VECTOR2I &aPos, int aFlags, LSET aMatchLayers)
MAGNETIC_SETTINGS * m_magneticSettings
VECTOR2I AlignToSegment(const VECTOR2I &aPoint, const SEG &aSeg)
PCB_GRID_HELPER(TOOL_MANAGER *aToolMgr, MAGNETIC_SETTINGS *aMagneticSettings)
VECTOR2I AlignToNearestPad(const VECTOR2I &aMousePos, PADS &aPads)
A set of BOARD_ITEMs (i.e., without duplicates).
Definition: pcb_group.h:51
bool IsFootprintEditor() const
const VECTOR2I & GetStart() const
Definition: pcb_track.h:113
const VECTOR2I & GetEnd() const
Definition: pcb_track.h:110
Definition: seg.h:42
VECTOR2I A
Definition: seg.h:49
ecoord SquaredDistance(const SEG &aSeg) const
Definition: seg.cpp:75
VECTOR2I::extended_type ecoord
Definition: seg.h:44
VECTOR2I B
Definition: seg.h:50
VECTOR2I Center() const
Definition: seg.h:362
OPT_VECTOR2I IntersectLines(const SEG &aSeg) const
Compute the intersection point of lines passing through ends of (this) and aSeg.
Definition: seg.h:210
const VECTOR2I & GetP1() const
Definition: shape_arc.h:113
int IntersectLine(const SEG &aSeg, std::vector< VECTOR2I > *aIpsBuffer) const
Find intersection points between this arc and aSeg, treating aSeg as an infinite line.
Definition: shape_arc.cpp:273
const VECTOR2I & GetP0() const
Definition: shape_arc.h:112
Represent a polyline containing arcs as well as line segments: A chain of connected line and/or arc s...
void Move(const VECTOR2I &aVector) override
void SetClosed(bool aClosed)
Mark the line chain as closed (i.e.
void Append(int aX, int aY, bool aAllowDuplication=false)
Append a new point at the end of the line chain.
void Rotate(const EDA_ANGLE &aAngle, const VECTOR2I &aCenter={ 0, 0 }) override
Rotate all vertices by a given angle.
virtual const SEG GetSegment(int aIndex) const override
const VECTOR2I NearestPoint(const VECTOR2I &aP, bool aAllowInternalShapePoints=true) const
Find a point on the line chain that is closest to point aP.
virtual size_t GetSegmentCount() const override
Represent a set of closed polygons.
CONST_ITERATOR CIterateWithHoles(int aOutline) const
Master controller class:
Definition: tool_manager.h:55
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:315
KIGFX::VIEW * GetView() const
Definition: tool_manager.h:285
static constexpr extended_type ECOORD_MAX
Definition: vector2d.h:75
Handle a list of polygons defining a copper zone.
Definition: zone.h:72
static constexpr EDA_ANGLE & ANGLE_90
Definition: eda_angle.h:431
@ LAYER_AUX_ITEMS
Auxiliary items (guides, rule, etc)
Definition: layer_ids.h:222
@ LAYER_ANCHOR
anchor of items having an anchor point (texts, footprints)
Definition: layer_ids.h:201
PCB_LAYER_ID
A quick note on layer IDs:
Definition: layer_ids.h:59
This file contains miscellaneous commonly used macros and functions.
#define KI_FALLTHROUGH
The KI_FALLTHROUGH macro is to be used when switch statement cases should purposely fallthrough from ...
Definition: macros.h:83
@ GEOMETRY
Position or shape has changed.
Definition: view_item.h:49
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
Definition: eda_angle.h:418
Class to handle a set of BOARD_ITEMs.
std::optional< VECTOR2I > OPT_VECTOR2I
Definition: seg.h:39
double Distance(const VECTOR2I &aP) const
Definition: grid_helper.h:101
MAGNETIC_OPTIONS tracks
MAGNETIC_OPTIONS pads
This file contains data structures that are saved in the project file or project local settings file ...
bool graphics
Graphic lines, shapes, polygons.
bool text
Text (free or attached to a footprint)
bool footprints
Allow selecting entire footprints.
bool dimensions
Dimension items.
void RotatePoint(int *pX, int *pY, const EDA_ANGLE &aAngle)
Definition: trigo.cpp:183
double EuclideanNorm(const VECTOR2I &vector)
Definition: trigo.h:129
@ PCB_SHAPE_T
class PCB_SHAPE, a segment not on copper layers
Definition: typeinfo.h:88
@ PCB_DIM_ORTHOGONAL_T
class PCB_DIM_ORTHOGONAL, a linear dimension constrained to x/y
Definition: typeinfo.h:101
@ PCB_DIM_LEADER_T
class PCB_DIM_LEADER, a leader dimension (graphic item)
Definition: typeinfo.h:98
@ PCB_VIA_T
class PCB_VIA, a via (like a track segment on a copper layer)
Definition: typeinfo.h:93
@ PCB_DIM_CENTER_T
class PCB_DIM_CENTER, a center point marking (graphic item)
Definition: typeinfo.h:99
@ PCB_GROUP_T
class PCB_GROUP, a set of BOARD_ITEMs
Definition: typeinfo.h:106
@ PCB_TEXTBOX_T
class PCB_TEXTBOX, wrapped text on a layer
Definition: typeinfo.h:91
@ PCB_ZONE_T
class ZONE, a copper pour area
Definition: typeinfo.h:103
@ PCB_TEXT_T
class PCB_TEXT, text on a layer
Definition: typeinfo.h:90
@ PCB_MARKER_T
class PCB_MARKER, a marker used to show something
Definition: typeinfo.h:95
@ PCB_TARGET_T
class PCB_TARGET, a target (graphic item)
Definition: typeinfo.h:102
@ PCB_FOOTPRINT_T
class FOOTPRINT, a footprint
Definition: typeinfo.h:86
@ PCB_DIM_ALIGNED_T
class PCB_DIM_ALIGNED, a linear dimension (graphic item)
Definition: typeinfo.h:97
@ PCB_PAD_T
class PAD, a pad in a footprint
Definition: typeinfo.h:87
@ PCB_ARC_T
class PCB_ARC, an arc track segment on a copper layer
Definition: typeinfo.h:94
@ PCB_TRACE_T
class PCB_TRACK, a track segment (segment on a copper layer)
Definition: typeinfo.h:92
@ PCB_DIM_RADIAL_T
class PCB_DIM_RADIAL, a radius or diameter dimension
Definition: typeinfo.h:100
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:85
VECTOR2< double > VECTOR2D
Definition: vector2d.h:587
VECTOR2< int > VECTOR2I
Definition: vector2d.h:588