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 <pcb_dimension.h>
28#include <fp_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 double snapScale = snapSize / m_toolMgr->GetView()->GetGAL()->GetWorldScale();
289 int snapRange = std::min( KiROUND( snapScale ), GetGrid().x );
290 int snapDist = snapRange;
291
292 //Respect limits of coordinates representation
293 BOX2I bb;
294 bb.SetOrigin( GetClampedCoords<double, int>( VECTOR2D( aOrigin ) - snapRange / 2.0 ) );
295 bb.SetEnd( GetClampedCoords<double, int>( VECTOR2D( aOrigin ) + snapRange / 2.0 ) );
296
297 clearAnchors();
298
299 for( BOARD_ITEM* item : queryVisible( bb, aSkip ) )
300 computeAnchors( item, aOrigin );
301
302 ANCHOR* nearest = nearestAnchor( aOrigin, SNAPPABLE, aLayers );
303 VECTOR2I nearestGrid = Align( aOrigin );
304
305 if( nearest )
306 snapDist = nearest->Distance( aOrigin );
307
308 // Existing snap lines need priority over new snaps
310 {
311 bool snapLine = false;
312 int x_dist = std::abs( m_viewSnapLine.GetPosition().x - aOrigin.x );
313 int y_dist = std::abs( m_viewSnapLine.GetPosition().y - aOrigin.y );
314
316 if( x_dist < snapRange && ( !nearest || snapDist > snapRange ) )
317 {
318 nearestGrid.x = m_viewSnapLine.GetPosition().x;
319 snapLine = true;
320 }
321
322 if( y_dist < snapRange && ( !nearest || snapDist > snapRange ) )
323 {
324 nearestGrid.y = m_viewSnapLine.GetPosition().y;
325 snapLine = true;
326 }
327
328 if( snapLine && m_skipPoint != VECTOR2I( m_viewSnapLine.GetPosition() ) )
329 {
330 m_viewSnapLine.SetEndPosition( nearestGrid );
331
334 else
336
337 return nearestGrid;
338 }
339 }
340
341 if( nearest && m_enableSnap )
342 {
343 if( nearest->Distance( aOrigin ) <= snapRange )
344 {
345 m_viewSnapPoint.SetPosition( wxPoint( nearest->pos ) );
346 m_viewSnapLine.SetPosition( wxPoint( nearest->pos ) );
348
351 else
353
354 m_snapItem = nearest;
355 return nearest->pos;
356 }
357 }
358
359 m_snapItem = nullptr;
362 return nearestGrid;
363}
364
365
367{
368 if( !m_snapItem )
369 return nullptr;
370
371 return static_cast<BOARD_ITEM*>( m_snapItem->item );
372}
373
374
375std::set<BOARD_ITEM*> PCB_GRID_HELPER::queryVisible( const BOX2I& aArea,
376 const std::vector<BOARD_ITEM*>& aSkip ) const
377{
378 std::set<BOARD_ITEM*> items;
379 std::vector<KIGFX::VIEW::LAYER_ITEM_PAIR> selectedItems;
380
381 KIGFX::VIEW* view = m_toolMgr->GetView();
382 RENDER_SETTINGS* settings = view->GetPainter()->GetSettings();
383 const std::set<unsigned int>& activeLayers = settings->GetHighContrastLayers();
384 bool isHighContrast = settings->GetHighContrast();
385
386 view->Query( aArea, selectedItems );
387
388 for( const KIGFX::VIEW::LAYER_ITEM_PAIR& it : selectedItems )
389 {
390 BOARD_ITEM* item = static_cast<BOARD_ITEM*>( it.first );
391
392 // If we are in the footprint editor, don't use the footprint itself
394 && item->Type() == PCB_FOOTPRINT_T )
395 {
396 continue;
397 }
398
399 // The item must be visible and on an active layer
400 if( view->IsVisible( item )
401 && ( !isHighContrast || activeLayers.count( it.second ) )
402 && item->ViewGetLOD( it.second, view ) < view->GetScale() )
403 {
404 items.insert ( item );
405 }
406 }
407
408 for( BOARD_ITEM* skipItem : aSkip )
409 items.erase( skipItem );
410
411 return items;
412}
413
414
415void PCB_GRID_HELPER::computeAnchors( BOARD_ITEM* aItem, const VECTOR2I& aRefPos, bool aFrom,
416 const SELECTION_FILTER_OPTIONS* aSelectionFilter )
417{
418 KIGFX::VIEW* view = m_toolMgr->GetView();
419 RENDER_SETTINGS* settings = view->GetPainter()->GetSettings();
420 const std::set<unsigned int>& activeLayers = settings->GetHighContrastLayers();
421 bool isHighContrast = settings->GetHighContrast();
422
423 auto handlePadShape =
424 [&]( PAD* aPad )
425 {
426 addAnchor( aPad->GetPosition(), ORIGIN | SNAPPABLE, aPad );
427
429 if( aFrom )
430 return;
431
432 switch( aPad->GetShape() )
433 {
435 {
436 int r = aPad->GetSizeX() / 2;
437 VECTOR2I center = aPad->ShapePos();
438
439 addAnchor( center + VECTOR2I( -r, 0 ), OUTLINE | SNAPPABLE, aPad );
440 addAnchor( center + VECTOR2I( r, 0 ), OUTLINE | SNAPPABLE, aPad );
441 addAnchor( center + VECTOR2I( 0, -r ), OUTLINE | SNAPPABLE, aPad );
442 addAnchor( center + VECTOR2I( 0, r ), OUTLINE | SNAPPABLE, aPad );
443 break;
444 }
445
446 case PAD_SHAPE::OVAL:
447 {
448 VECTOR2I pos = aPad->ShapePos();
449 VECTOR2I half_size = aPad->GetSize() / 2;
450 int half_width = std::min( half_size.x, half_size.y );
451 VECTOR2I half_len( half_size.x - half_width, half_size.y - half_width );
452
453 RotatePoint( half_len, aPad->GetOrientation() );
454
455 VECTOR2I a( pos - half_len );
456 VECTOR2I b( pos + half_len );
457 VECTOR2I normal = b - a;
458 normal.Resize( half_width );
460
461 addAnchor( a + normal, OUTLINE | SNAPPABLE, aPad );
462 addAnchor( a - normal, OUTLINE | SNAPPABLE, aPad );
463 addAnchor( b + normal, OUTLINE | SNAPPABLE, aPad );
464 addAnchor( b - normal, OUTLINE | SNAPPABLE, aPad );
465 addAnchor( pos + normal, OUTLINE | SNAPPABLE, aPad );
466 addAnchor( pos - normal, OUTLINE | SNAPPABLE, aPad );
467
469
470 addAnchor( a - normal, OUTLINE | SNAPPABLE, aPad );
471 addAnchor( b + normal, OUTLINE | SNAPPABLE, aPad );
472 break;
473 }
474
475 case PAD_SHAPE::RECT:
479 {
480 VECTOR2I half_size( aPad->GetSize() / 2 );
481 VECTOR2I trap_delta( 0, 0 );
482
483 if( aPad->GetShape() == PAD_SHAPE::TRAPEZOID )
484 trap_delta = aPad->GetDelta() / 2;
485
486 SHAPE_LINE_CHAIN corners;
487
488 corners.Append( -half_size.x - trap_delta.y, half_size.y + trap_delta.x );
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.SetClosed( true );
493
494 corners.Rotate( aPad->GetOrientation() );
495 corners.Move( aPad->ShapePos() );
496
497 for( size_t ii = 0; ii < corners.GetSegmentCount(); ++ii )
498 {
499 const SEG& seg = corners.GetSegment( ii );
500 addAnchor( seg.A, OUTLINE | SNAPPABLE, aPad );
501 addAnchor( seg.Center(), OUTLINE | SNAPPABLE, aPad );
502
503 if( ii == corners.GetSegmentCount() - 1 )
504 addAnchor( seg.B, OUTLINE | SNAPPABLE, aPad );
505 }
506
507 break;
508 }
509
510 default:
511 {
512 const std::shared_ptr<SHAPE_POLY_SET>& outline = aPad->GetEffectivePolygon();
513
514 if( !outline->IsEmpty() )
515 {
516 for( const VECTOR2I& pt : outline->Outline( 0 ).CPoints() )
517 addAnchor( pt, OUTLINE | SNAPPABLE, aPad );
518 }
519
520 break;
521 }
522 }
523 };
524
525 auto handleShape =
526 [&]( PCB_SHAPE* shape )
527 {
528 VECTOR2I start = shape->GetStart();
529 VECTOR2I end = shape->GetEnd();
530
531 switch( shape->GetShape() )
532 {
533 case SHAPE_T::CIRCLE:
534 {
535 int r = ( start - end ).EuclideanNorm();
536
537 addAnchor( start, ORIGIN | SNAPPABLE, shape );
538 addAnchor( start + VECTOR2I( -r, 0 ), OUTLINE | SNAPPABLE, shape );
539 addAnchor( start + VECTOR2I( r, 0 ), OUTLINE | SNAPPABLE, shape );
540 addAnchor( start + VECTOR2I( 0, -r ), OUTLINE | SNAPPABLE, shape );
541 addAnchor( start + VECTOR2I( 0, r ), OUTLINE | SNAPPABLE, shape );
542 break;
543 }
544
545 case SHAPE_T::ARC:
546 addAnchor( shape->GetStart(), CORNER | SNAPPABLE, shape );
547 addAnchor( shape->GetEnd(), CORNER | SNAPPABLE, shape );
548 addAnchor( shape->GetArcMid(), CORNER | SNAPPABLE, shape );
549 addAnchor( shape->GetCenter(), ORIGIN | SNAPPABLE, shape );
550 break;
551
552 case SHAPE_T::RECT:
553 {
554 VECTOR2I point2( end.x, start.y );
555 VECTOR2I point3( start.x, end.y );
556 SEG first( start, point2 );
557 SEG second( point2, end );
558 SEG third( end, point3 );
559 SEG fourth( point3, start );
560
561 addAnchor( first.A, CORNER | SNAPPABLE, shape );
562 addAnchor( first.Center(), CORNER | SNAPPABLE, shape );
563 addAnchor( second.A, CORNER | SNAPPABLE, shape );
564 addAnchor( second.Center(), CORNER | SNAPPABLE, shape );
565 addAnchor( third.A, CORNER | SNAPPABLE, shape );
566 addAnchor( third.Center(), CORNER | SNAPPABLE, shape );
567 addAnchor( fourth.A, CORNER | SNAPPABLE, shape );
568 addAnchor( fourth.Center(), CORNER | SNAPPABLE, shape );
569 break;
570 }
571
572 case SHAPE_T::SEGMENT:
573 addAnchor( start, CORNER | SNAPPABLE, shape );
574 addAnchor( end, CORNER | SNAPPABLE, shape );
575 addAnchor( shape->GetCenter(), CORNER | SNAPPABLE, shape );
576 break;
577
578 case SHAPE_T::POLY:
579 {
581 lc.SetClosed( true );
582 std::vector<VECTOR2I> poly;
583 shape->DupPolyPointsList( poly );
584
585 for( const VECTOR2I& p : poly )
586 {
587 addAnchor( p, CORNER | SNAPPABLE, shape );
588 lc.Append( p );
589 }
590
591 addAnchor( lc.NearestPoint( aRefPos ), OUTLINE, aItem );
592 break;
593 }
594
595 case SHAPE_T::BEZIER:
596 addAnchor( start, CORNER | SNAPPABLE, shape );
597 addAnchor( end, CORNER | SNAPPABLE, shape );
599
600 default:
601 addAnchor( shape->GetPosition(), ORIGIN | SNAPPABLE, shape );
602 break;
603 }
604 };
605
606 switch( aItem->Type() )
607 {
608 case PCB_FOOTPRINT_T:
609 {
610 FOOTPRINT* footprint = static_cast<FOOTPRINT*>( aItem );
611
612 for( PAD* pad : footprint->Pads() )
613 {
614 if( aFrom )
615 {
616 if( aSelectionFilter && !aSelectionFilter->pads )
617 continue;
618 }
619 else
620 {
622 continue;
623 }
624
625 if( !view->IsVisible( pad ) || !pad->GetBoundingBox().Contains( aRefPos ) )
626 continue;
627
628 // Getting pads from a footprint requires re-checking that the pads are shown
629 bool onActiveLayer = !isHighContrast;
630 bool isLODVisible = false;
631
632 for( PCB_LAYER_ID layer : pad->GetLayerSet().Seq() )
633 {
634 if( !onActiveLayer && activeLayers.count( layer ) )
635 onActiveLayer = true;
636
637 if( !isLODVisible && pad->ViewGetLOD( layer, view ) < view->GetScale() )
638 isLODVisible = true;
639
640 if( onActiveLayer && isLODVisible )
641 {
642 handlePadShape( pad );
643 break;
644 }
645 }
646 }
647
648 if( aFrom && aSelectionFilter && !aSelectionFilter->footprints )
649 break;
650
651 // if the cursor is not over a pad, then drag the footprint by its origin
652 VECTOR2I position = footprint->GetPosition();
653 addAnchor( position, ORIGIN | SNAPPABLE, footprint );
654
655 // Add the footprint center point if it is markedly different from the origin
656 VECTOR2I center = footprint->GetBoundingBox( false, false ).Centre();
657 VECTOR2I grid( GetGrid() );
658
659 if( ( center - position ).SquaredEuclideanNorm() > grid.SquaredEuclideanNorm() )
660 addAnchor( center, ORIGIN | SNAPPABLE, footprint );
661
662 break;
663 }
664
665 case PCB_PAD_T:
666 if( aFrom )
667 {
668 if( aSelectionFilter && !aSelectionFilter->pads )
669 break;
670 }
671 else
672 {
674 break;
675 }
676
677 handlePadShape( static_cast<PAD*>( aItem ) );
678
679 break;
680
681 case PCB_FP_TEXTBOX_T:
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_FP_SHAPE_T:
698 case PCB_SHAPE_T:
699 if( aFrom )
700 {
701 if( aSelectionFilter && !aSelectionFilter->graphics )
702 break;
703 }
704 else
705 {
707 break;
708 }
709
710 handleShape( static_cast<PCB_SHAPE*>( aItem ) );
711 break;
712
713 case PCB_TRACE_T:
714 case PCB_ARC_T:
715 {
716 if( aFrom )
717 {
718 if( aSelectionFilter && !aSelectionFilter->tracks )
719 break;
720 }
721 else
722 {
724 break;
725 }
726
727 PCB_TRACK* track = static_cast<PCB_TRACK*>( aItem );
728
729 addAnchor( track->GetStart(), CORNER | SNAPPABLE, track );
730 addAnchor( track->GetEnd(), CORNER | SNAPPABLE, track );
731 addAnchor( track->GetCenter(), ORIGIN, track);
732
733 break;
734 }
735
736 case PCB_MARKER_T:
737 case PCB_TARGET_T:
738 addAnchor( aItem->GetPosition(), ORIGIN | CORNER | SNAPPABLE, aItem );
739 break;
740
741 case PCB_VIA_T:
742 if( aFrom )
743 {
744 if( aSelectionFilter && !aSelectionFilter->vias )
745 break;
746 }
747 else
748 {
750 break;
751 }
752
753 addAnchor( aItem->GetPosition(), ORIGIN | CORNER | SNAPPABLE, aItem );
754
755 break;
756
757 case PCB_ZONE_T:
758 {
759 if( aFrom && aSelectionFilter && !aSelectionFilter->zones )
760 break;
761
762 const SHAPE_POLY_SET* outline = static_cast<const ZONE*>( aItem )->Outline();
763
765 lc.SetClosed( true );
766
767 for( auto iter = outline->CIterateWithHoles(); iter; iter++ )
768 {
769 addAnchor( *iter, CORNER | SNAPPABLE, aItem );
770 lc.Append( *iter );
771 }
772
773 addAnchor( lc.NearestPoint( aRefPos ), OUTLINE, aItem );
774
775 break;
776 }
777
778 case PCB_FP_ZONE_T:
779 {
780 if( aFrom && aSelectionFilter && !aSelectionFilter->zones )
781 break;
782
783 const SHAPE_POLY_SET* outline = static_cast<const FP_ZONE*>( aItem )->Outline();
784
786 lc.SetClosed( true );
787
788 for( auto iter = outline->CIterateWithHoles(); iter; iter++ )
789 {
790 addAnchor( *iter, CORNER | SNAPPABLE, aItem );
791 lc.Append( *iter );
792 }
793
794 addAnchor( lc.NearestPoint( aRefPos ), OUTLINE, aItem );
795
796 break;
797 }
798
803 {
804 if( aFrom && aSelectionFilter && !aSelectionFilter->dimensions )
805 break;
806
807 const PCB_DIM_ALIGNED* dim = static_cast<const PCB_DIM_ALIGNED*>( aItem );
808 addAnchor( dim->GetCrossbarStart(), CORNER | SNAPPABLE, aItem );
809 addAnchor( dim->GetCrossbarEnd(), CORNER | SNAPPABLE, aItem );
810 addAnchor( dim->GetStart(), CORNER | SNAPPABLE, aItem );
811 addAnchor( dim->GetEnd(), CORNER | SNAPPABLE, aItem );
812 break;
813 }
814
815 case PCB_DIM_CENTER_T:
817 {
818 if( aFrom && aSelectionFilter && !aSelectionFilter->dimensions )
819 break;
820
821 const PCB_DIM_CENTER* dim = static_cast<const PCB_DIM_CENTER*>( aItem );
822 addAnchor( dim->GetStart(), CORNER | SNAPPABLE, aItem );
823 addAnchor( dim->GetEnd(), CORNER | SNAPPABLE, aItem );
824
825 VECTOR2I start( dim->GetStart() );
826 VECTOR2I radial( dim->GetEnd() - dim->GetStart() );
827
828 for( int i = 0; i < 2; i++ )
829 {
830 RotatePoint( radial, -ANGLE_90 );
831 addAnchor( start + radial, CORNER | SNAPPABLE, aItem );
832 }
833
834 break;
835 }
836
837 case PCB_DIM_RADIAL_T:
839 {
840 if( aFrom && aSelectionFilter && !aSelectionFilter->dimensions )
841 break;
842
843 const PCB_DIM_RADIAL* radialDim = static_cast<const PCB_DIM_RADIAL*>( aItem );
844 addAnchor( radialDim->GetStart(), CORNER | SNAPPABLE, aItem );
845 addAnchor( radialDim->GetEnd(), CORNER | SNAPPABLE, aItem );
846 addAnchor( radialDim->GetKnee(), CORNER | SNAPPABLE, aItem );
847 addAnchor( radialDim->Text().GetPosition(), CORNER | SNAPPABLE, aItem );
848 break;
849 }
850
851 case PCB_DIM_LEADER_T:
853 {
854 if( aFrom && aSelectionFilter && !aSelectionFilter->dimensions )
855 break;
856
857 const PCB_DIM_LEADER* leader = static_cast<const PCB_DIM_LEADER*>( aItem );
858 addAnchor( leader->GetStart(), CORNER | SNAPPABLE, aItem );
859 addAnchor( leader->GetEnd(), CORNER | SNAPPABLE, aItem );
860 addAnchor( leader->Text().GetPosition(), CORNER | SNAPPABLE, aItem );
861 break;
862 }
863
864 case PCB_FP_TEXT_T:
865 case PCB_TEXT_T:
866 if( aFrom && aSelectionFilter && !aSelectionFilter->text )
867 break;
868
869 addAnchor( aItem->GetPosition(), ORIGIN, aItem );
870 break;
871
872 case PCB_GROUP_T:
873 {
874 const PCB_GROUP* group = static_cast<const PCB_GROUP*>( aItem );
875
876 for( BOARD_ITEM* item : group->GetItems() )
877 computeAnchors( item, aRefPos, aFrom );
878
879 break;
880 }
881
882 default:
883 break;
884 }
885}
886
887
889 LSET aMatchLayers )
890{
891 double minDist = std::numeric_limits<double>::max();
892 ANCHOR* best = nullptr;
893
894 for( ANCHOR& a : m_anchors )
895 {
896 BOARD_ITEM* item = static_cast<BOARD_ITEM*>( a.item );
897
898 if( ( aMatchLayers & item->GetLayerSet() ) == 0 )
899 continue;
900
901 if( ( aFlags & a.flags ) != aFlags )
902 continue;
903
904 double dist = a.Distance( aPos );
905
906 if( dist < minDist )
907 {
908 minDist = dist;
909 best = &a;
910 }
911 }
912
913 return best;
914}
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition: board_item.h:58
virtual VECTOR2I GetCenter() const
This defaults to the center of the bounding box if not overridden.
Definition: board_item.h:93
virtual LSET GetLayerSet() const
Return a std::bitset of all layers on which the item physically resides.
Definition: board_item.h:185
void SetOrigin(const Vec &pos)
Definition: box2.h:202
Vec Centre() const
Definition: box2.h:70
void SetEnd(coord_type x, coord_type y)
Definition: box2.h:255
virtual VECTOR2I GetPosition() const
Definition: eda_item.h:251
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:224
PADS & Pads()
Definition: footprint.h:170
VECTOR2I GetPosition() const override
Definition: footprint.h:188
const BOX2I GetBoundingBox() const override
Return the orthogonal bounding box of this object for display purposes.
Definition: footprint.cpp:794
A specialization of ZONE for use in footprints.
Definition: zone.h:910
VECTOR2I m_skipPoint
Definition: grid_helper.h:140
virtual VECTOR2I Align(const VECTOR2I &aPoint) const
Definition: grid_helper.cpp:95
TOOL_MANAGER * m_toolMgr
Definition: grid_helper.h:130
VECTOR2I GetGrid() const
Definition: grid_helper.cpp:51
ANCHOR * m_snapItem
Definition: grid_helper.h:138
bool m_enableSnapLine
Definition: grid_helper.h:137
bool m_enableSnap
Definition: grid_helper.h:135
void addAnchor(const VECTOR2I &aPos, int aFlags, EDA_ITEM *aItem)
Definition: grid_helper.h:106
void clearAnchors()
Definition: grid_helper.h:112
KIGFX::ORIGIN_VIEWITEM m_viewSnapPoint
Definition: grid_helper.h:142
KIGFX::ORIGIN_VIEWITEM m_viewSnapLine
Definition: grid_helper.h:143
KIGFX::ORIGIN_VIEWITEM m_viewAxis
Definition: grid_helper.h:144
std::vector< ANCHOR > m_anchors
Definition: grid_helper.h:128
A color representation with 4 components: red, green, blue, alpha.
Definition: color4d.h:104
COLOR4D WithAlpha(double aAlpha) const
Return a color with the same color, but the given alpha.
Definition: color4d.h:321
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 COLOR4D & GetLayerColor(int aLayer) const
Return the color used to draw a layer.
bool GetHighContrast() const
const std::set< unsigned int > GetHighContrastLayers() const
Returns the set of currently high-contrast layers.
virtual double ViewGetLOD(int aLayer, VIEW *aView) const
Return the level of detail (LOD) of the item.
Definition: view_item.h:132
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:316
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:1586
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:1564
void SetVisible(VIEW_ITEM *aItem, bool aIsVisible=true)
Set the item visibility.
Definition: view.cpp:1524
LSET is a set of PCB_LAYER_IDs.
Definition: layer_ids.h:530
static LSET AllLayersMask()
Definition: lset.cpp:808
Definition: pad.h:59
PCB_TEXT & Text()
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
virtual VECTOR2I GetPosition() const override
Definition: pcb_text.h:76
bool IsFootprintEditor() const
const VECTOR2I & GetStart() const
Definition: pcb_track.h:112
const VECTOR2I & GetEnd() const
Definition: pcb_track.h:109
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:79
Handle a list of polygons defining a copper zone.
Definition: zone.h:57
static constexpr EDA_ANGLE & ANGLE_90
Definition: eda_angle.h:414
E_SERIE r
Definition: eserie.cpp:41
@ 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:401
std::optional< VECTOR2I > OPT_VECTOR2I
Definition: seg.h:39
double Distance(const VECTOR2I &aP) const
Definition: grid_helper.h:100
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_FP_DIM_ALIGNED_T
class PCB_DIM_ALIGNED, a linear dimension (graphic item)
Definition: typeinfo.h:95
@ 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:110
@ PCB_FP_SHAPE_T
class FP_SHAPE, a footprint edge
Definition: typeinfo.h:94
@ PCB_DIM_LEADER_T
class PCB_DIM_LEADER, a leader dimension (graphic item)
Definition: typeinfo.h:107
@ PCB_VIA_T
class PCB_VIA, a via (like a track segment on a copper layer)
Definition: typeinfo.h:102
@ PCB_FP_TEXTBOX_T
class FP_TEXTBOX, wrapped text in a footprint
Definition: typeinfo.h:93
@ PCB_DIM_CENTER_T
class PCB_DIM_CENTER, a center point marking (graphic item)
Definition: typeinfo.h:108
@ PCB_GROUP_T
class PCB_GROUP, a set of BOARD_ITEMs
Definition: typeinfo.h:115
@ 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:112
@ PCB_TEXT_T
class PCB_TEXT, text on a layer
Definition: typeinfo.h:90
@ PCB_FP_DIM_CENTER_T
class PCB_DIM_CENTER, a center point marking (graphic item)
Definition: typeinfo.h:97
@ PCB_MARKER_T
class PCB_MARKER, a marker used to show something
Definition: typeinfo.h:104
@ PCB_TARGET_T
class PCB_TARGET, a target (graphic item)
Definition: typeinfo.h:111
@ PCB_FP_DIM_ORTHOGONAL_T
class PCB_DIM_ORTHOGONAL, a linear dimension constrained to x/y
Definition: typeinfo.h:99
@ PCB_FP_DIM_LEADER_T
class PCB_DIM_LEADER, a leader dimension (graphic item)
Definition: typeinfo.h:96
@ 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:106
@ PCB_FP_ZONE_T
class ZONE, managed by a footprint
Definition: typeinfo.h:100
@ PCB_FP_DIM_RADIAL_T
class PCB_DIM_RADIAL, a radius or diameter dimension
Definition: typeinfo.h:98
@ PCB_PAD_T
class PAD, a pad in a footprint
Definition: typeinfo.h:87
@ PCB_FP_TEXT_T
class FP_TEXT, text in a footprint
Definition: typeinfo.h:92
@ PCB_ARC_T
class PCB_ARC, an arc track segment on a copper layer
Definition: typeinfo.h:103
@ PCB_TRACE_T
class PCB_TRACK, a track segment (segment on a copper layer)
Definition: typeinfo.h:101
@ PCB_DIM_RADIAL_T
class PCB_DIM_RADIAL, a radius or diameter dimension
Definition: typeinfo.h:109
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:617
VECTOR2< int > VECTOR2I
Definition: vector2d.h:618