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 "pcb_grid_helper.h"
27
28#include <functional>
29
30#include <advanced_config.h>
31#include <pcb_dimension.h>
32#include <pcb_shape.h>
33#include <footprint.h>
34#include <pad.h>
35#include <pcb_group.h>
36#include <pcb_track.h>
37#include <zone.h>
40#include <geometry/nearest.h>
41#include <geometry/oval.h>
44#include <geometry/shape_rect.h>
48#include <macros.h>
49#include <math/util.h> // for KiROUND
50#include <gal/painter.h>
51#include <pcbnew_settings.h>
52#include <tool/tool_manager.h>
53#include <tools/pcb_tool_base.h>
54#include <view/view.h>
55
56namespace
57{
58
64std::optional<INTERSECTABLE_GEOM> GetBoardIntersectable( const BOARD_ITEM& aItem )
65{
66 switch( aItem.Type() )
67 {
68 case PCB_SHAPE_T:
69 {
70 const PCB_SHAPE& shape = static_cast<const PCB_SHAPE&>( aItem );
71
72 switch( shape.GetShape() )
73 {
74 case SHAPE_T::SEGMENT: return SEG{ shape.GetStart(), shape.GetEnd() };
75
76 case SHAPE_T::CIRCLE: return CIRCLE{ shape.GetCenter(), shape.GetRadius() };
77
78 case SHAPE_T::ARC:
79 return SHAPE_ARC{ shape.GetStart(), shape.GetArcMid(), shape.GetEnd(), 0 };
80
81 case SHAPE_T::RECTANGLE: return BOX2I::ByCorners( shape.GetStart(), shape.GetEnd() );
82
83 default: break;
84 }
85
86 break;
87 }
88
89 case PCB_TRACE_T:
90 {
91 const PCB_TRACK& track = static_cast<const PCB_TRACK&>( aItem );
92
93 return SEG{ track.GetStart(), track.GetEnd() };
94 }
95
96 case PCB_ARC_T:
97 {
98 const PCB_ARC& arc = static_cast<const PCB_ARC&>( aItem );
99
100 return SHAPE_ARC{ arc.GetStart(), arc.GetMid(), arc.GetEnd(), 0 };
101 }
102
103 default: break;
104 }
105
106 return std::nullopt;
107}
108
118std::optional<int64_t> FindSquareDistanceToItem( const BOARD_ITEM& item, const VECTOR2I& aPos )
119{
120 std::optional<INTERSECTABLE_GEOM> intersectable = GetBoardIntersectable( item );
121 std::optional<NEARABLE_GEOM> nearable;
122
123 if( intersectable )
124 {
125 // Exploit the intersectable as a nearable
126 std::visit(
127 [&]( auto& geom )
128 {
129 nearable = NEARABLE_GEOM( std::move( geom ) );
130 },
131 *intersectable );
132 }
133
134 // Whatever the item is, we don't have a nearable for it
135 if( !nearable )
136 return std::nullopt;
137
138 const VECTOR2I nearestPt = GetNearestPoint( *nearable, aPos );
139 return nearestPt.SquaredDistance( aPos );
140}
141
142} // namespace
143
145 GRID_HELPER( aToolMgr, LAYER_ANCHOR ), m_magneticSettings( aMagneticSettings )
146{
147 KIGFX::VIEW* view = m_toolMgr->GetView();
148 KIGFX::RENDER_SETTINGS* settings = view->GetPainter()->GetSettings();
149 KIGFX::COLOR4D auxItemsColor = settings->GetLayerColor( LAYER_AUX_ITEMS );
150
151 m_viewAxis.SetSize( 20000 );
153 m_viewAxis.SetColor( auxItemsColor.WithAlpha( 0.4 ) );
155 view->Add( &m_viewAxis );
156 view->SetVisible( &m_viewAxis, false );
157
160 m_viewSnapPoint.SetColor( auxItemsColor );
162 view->Add( &m_viewSnapPoint );
163 view->SetVisible( &m_viewSnapPoint, false );
164}
165
166
168{
169 KIGFX::VIEW* view = m_toolMgr->GetView();
170
171 view->Remove( &m_viewAxis );
172 view->Remove( &m_viewSnapPoint );
173}
174
175
176void PCB_GRID_HELPER::AddConstructionItems( std::vector<BOARD_ITEM*> aItems, bool aExtensionOnly,
177 bool aIsPersistent )
178{
179 if( !ADVANCED_CFG::GetCfg().m_EnableExtensionSnaps )
180 {
181 return;
182 }
183
184 // For all the elements that get drawn construction geometry,
185 // add something suitable to the construction helper.
186 // This can be nothing.
187 auto constructionItemsBatch = std::make_unique<CONSTRUCTION_MANAGER::CONSTRUCTION_ITEM_BATCH>();
188
189 std::vector<VECTOR2I> referenceOnlyPoints;
190
191 for( BOARD_ITEM* item : aItems )
192 {
193 std::vector<KIGFX::CONSTRUCTION_GEOM::DRAWABLE> constructionDrawables;
194
195 if( item->Type() == PCB_SHAPE_T )
196 {
197 PCB_SHAPE& shape = static_cast<PCB_SHAPE&>( *item );
198
199 switch( shape.GetShape() )
200 {
201 case SHAPE_T::SEGMENT:
202 {
203 if( !aExtensionOnly )
204 {
205 constructionDrawables.emplace_back( LINE{ shape.GetStart(), shape.GetEnd() } );
206 }
207 else
208 {
209 // Two rays, extending from the segment ends
210 const VECTOR2I segVec = shape.GetEnd() - shape.GetStart();
211 constructionDrawables.emplace_back(
212 HALF_LINE{ shape.GetStart(), shape.GetStart() - segVec } );
213 constructionDrawables.emplace_back(
214 HALF_LINE{ shape.GetEnd(), shape.GetEnd() + segVec } );
215 }
216
217 if( aIsPersistent )
218 {
219 // include the original endpoints as construction items
220 // (this allows H/V snapping)
221 constructionDrawables.emplace_back( shape.GetStart() );
222 constructionDrawables.emplace_back( shape.GetEnd() );
223
224 // But mark them as references, so they don't get snapped to themsevles
225 referenceOnlyPoints.emplace_back( shape.GetStart() );
226 referenceOnlyPoints.emplace_back( shape.GetEnd() );
227 }
228 break;
229 }
230 case SHAPE_T::ARC:
231 {
232 if( !aExtensionOnly )
233 {
234 constructionDrawables.push_back(
235 CIRCLE{ shape.GetCenter(), shape.GetRadius() } );
236 }
237 else
238 {
239 // The rest of the circle is the arc through the opposite point to the midpoint
240 const VECTOR2I oppositeMid =
241 shape.GetCenter() + ( shape.GetCenter() - shape.GetArcMid() );
242 constructionDrawables.push_back(
243 SHAPE_ARC{ shape.GetStart(), oppositeMid, shape.GetEnd(), 0 } );
244 }
245 constructionDrawables.push_back( shape.GetCenter() );
246
247 if( aIsPersistent )
248 {
249 // include the original endpoints as construction items
250 // (this allows H/V snapping)
251 constructionDrawables.emplace_back( shape.GetStart() );
252 constructionDrawables.emplace_back( shape.GetEnd() );
253
254 // But mark them as references, so they don't get snapped to themselves
255 referenceOnlyPoints.emplace_back( shape.GetStart() );
256 referenceOnlyPoints.emplace_back( shape.GetEnd() );
257 }
258
259 break;
260 }
261 case SHAPE_T::CIRCLE:
262 case SHAPE_T::RECTANGLE:
263 {
264 constructionDrawables.push_back( shape.GetCenter() );
265 break;
266 }
267 default:
268 // This shape doesn't have any construction geometry to draw
269 break;
270 }
271 }
272
273 // At this point, constructionDrawables can be empty, which is fine
274 // (it means there's no additional construction geometry to draw, but
275 // the item is still going to be proposed for activation)
276 constructionItemsBatch->emplace_back( CONSTRUCTION_MANAGER::CONSTRUCTION_ITEM{
278 item,
279 std::move( constructionDrawables ),
280 } );
281 }
282
283 if( referenceOnlyPoints.size() )
284 {
285 getSnapManager().SetReferenceOnlyPoints( std::move( referenceOnlyPoints ) );
286 }
287
288 // Let the manager handle it
290 std::move( constructionItemsBatch ), aIsPersistent );
291}
292
293
295{
296 const int c_gridSnapEpsilon_sq = 4;
297
298 VECTOR2I aligned = Align( aPoint );
299
300 if( !m_enableSnap )
301 return aligned;
302
303 std::vector<VECTOR2I> points;
304
305 const SEG testSegments[] = { SEG( aligned, aligned + VECTOR2( 1, 0 ) ),
306 SEG( aligned, aligned + VECTOR2( 0, 1 ) ),
307 SEG( aligned, aligned + VECTOR2( 1, 1 ) ),
308 SEG( aligned, aligned + VECTOR2( 1, -1 ) ) };
309
310 for( const SEG& seg : testSegments )
311 {
312 OPT_VECTOR2I vec = aSeg.IntersectLines( seg );
313
314 if( vec && aSeg.SquaredDistance( *vec ) <= c_gridSnapEpsilon_sq )
315 points.push_back( *vec );
316 }
317
318 VECTOR2I nearest = aligned;
320
321 // Snap by distance between pointer and endpoints
322 for( const VECTOR2I& pt : { aSeg.A, aSeg.B } )
323 {
324 SEG::ecoord d_sq = ( pt - aPoint ).SquaredEuclideanNorm();
325
326 if( d_sq < min_d_sq )
327 {
328 min_d_sq = d_sq;
329 nearest = pt;
330 }
331 }
332
333 // Snap by distance between aligned cursor and intersections
334 for( const VECTOR2I& pt : points )
335 {
336 SEG::ecoord d_sq = ( pt - aligned ).SquaredEuclideanNorm();
337
338 if( d_sq < min_d_sq )
339 {
340 min_d_sq = d_sq;
341 nearest = pt;
342 }
343 }
344
345 return nearest;
346}
347
348
350{
351 VECTOR2I aligned = Align( aPoint );
352
353 if( !m_enableSnap )
354 return aligned;
355
356 std::vector<VECTOR2I> points;
357
358 aArc.IntersectLine( SEG( aligned, aligned + VECTOR2( 1, 0 ) ), &points );
359 aArc.IntersectLine( SEG( aligned, aligned + VECTOR2( 0, 1 ) ), &points );
360 aArc.IntersectLine( SEG( aligned, aligned + VECTOR2( 1, 1 ) ), &points );
361 aArc.IntersectLine( SEG( aligned, aligned + VECTOR2( 1, -1 ) ), &points );
362
363 VECTOR2I nearest = aligned;
365
366 // Snap by distance between pointer and endpoints
367 for( const VECTOR2I& pt : { aArc.GetP0(), aArc.GetP1() } )
368 {
369 SEG::ecoord d_sq = ( pt - aPoint ).SquaredEuclideanNorm();
370
371 if( d_sq < min_d_sq )
372 {
373 min_d_sq = d_sq;
374 nearest = pt;
375 }
376 }
377
378 // Snap by distance between aligned cursor and intersections
379 for( const VECTOR2I& pt : points )
380 {
381 SEG::ecoord d_sq = ( pt - aligned ).SquaredEuclideanNorm();
382
383 if( d_sq < min_d_sq )
384 {
385 min_d_sq = d_sq;
386 nearest = pt;
387 }
388 }
389
390 return nearest;
391}
392
393
394VECTOR2I PCB_GRID_HELPER::SnapToPad( const VECTOR2I& aMousePos, std::deque<PAD*>& aPads )
395{
396 clearAnchors();
397
398 for( BOARD_ITEM* item : aPads )
399 {
400 if( item->HitTest( aMousePos ) )
401 computeAnchors( item, aMousePos, true, nullptr );
402 }
403
404 double minDist = std::numeric_limits<double>::max();
405 ANCHOR* nearestOrigin = nullptr;
406
407 for( ANCHOR& a : m_anchors )
408 {
409 if( ( ORIGIN & a.flags ) != ORIGIN )
410 continue;
411
412 double dist = a.Distance( aMousePos );
413
414 if( dist < minDist )
415 {
416 minDist = dist;
417 nearestOrigin = &a;
418 }
419 }
420
421 return nearestOrigin ? nearestOrigin->pos : aMousePos;
422}
423
424
426 std::vector<BOARD_ITEM*>& aItems,
427 GRID_HELPER_GRIDS aGrid,
428 const PCB_SELECTION_FILTER_OPTIONS* aSelectionFilter )
429{
430 clearAnchors();
431
432 computeAnchors( aItems, aMousePos, true, aSelectionFilter, nullptr, true );
433
434 double lineSnapMinCornerDistance = m_toolMgr->GetView()->ToWorld( 50 );
435
436 ANCHOR* nearestOutline = nearestAnchor( aMousePos, OUTLINE );
437 ANCHOR* nearestCorner = nearestAnchor( aMousePos, CORNER );
438 ANCHOR* nearestOrigin = nearestAnchor( aMousePos, ORIGIN );
439 ANCHOR* best = nullptr;
440 double minDist = std::numeric_limits<double>::max();
441
442 if( nearestOrigin )
443 {
444 minDist = nearestOrigin->Distance( aMousePos );
445 best = nearestOrigin;
446 }
447
448 if( nearestCorner )
449 {
450 double dist = nearestCorner->Distance( aMousePos );
451
452 if( dist < minDist )
453 {
454 minDist = dist;
455 best = nearestCorner;
456 }
457 }
458
459 if( nearestOutline )
460 {
461 double dist = nearestOutline->Distance( aMousePos );
462
463 if( minDist > lineSnapMinCornerDistance && dist < minDist )
464 best = nearestOutline;
465 }
466
467 return best ? best->pos : aMousePos;
468}
469
470
472 GRID_HELPER_GRIDS aGrid )
473{
474 LSET layers;
475 std::vector<BOARD_ITEM*> item;
476
477 if( aReferenceItem )
478 {
479 layers = aReferenceItem->GetLayerSet();
480 item.push_back( aReferenceItem );
481 }
482 else
483 {
484 layers = LSET::AllLayersMask();
485 }
486
487 return BestSnapAnchor( aOrigin, layers, aGrid, item );
488}
489
490
492 GRID_HELPER_GRIDS aGrid,
493 const std::vector<BOARD_ITEM*>& aSkip )
494{
495 // Tuning constant: snap radius in screen space
496 const int snapSize = 25;
497
498 // Snapping distance is in screen space, clamped to the current grid to ensure that the grid
499 // points that are visible can always be snapped to.
500 // see https://gitlab.com/kicad/code/kicad/-/issues/5638
501 // see https://gitlab.com/kicad/code/kicad/-/issues/7125
502 // see https://gitlab.com/kicad/code/kicad/-/issues/12303
503 double snapScale = m_toolMgr->GetView()->ToWorld( snapSize );
504 // warning: GetVisibleGrid().x sometimes returns a value > INT_MAX. Intermediate calculation
505 // needs double.
506 int snapRange = KiROUND( m_enableGrid ? std::min( snapScale, GetVisibleGrid().x ) : snapScale );
507
508 //Respect limits of coordinates representation
509 const BOX2I visibilityHorizon =
510 BOX2ISafe( VECTOR2D( aOrigin ) - snapRange / 2.0, VECTOR2D( snapRange, snapRange ) );
511
512 clearAnchors();
513
514 const std::vector<BOARD_ITEM*> visibleItems = queryVisible( visibilityHorizon, aSkip );
515 computeAnchors( visibleItems, aOrigin, false, nullptr, &aLayers, false );
516
517 ANCHOR* nearest = nearestAnchor( aOrigin, SNAPPABLE );
518 VECTOR2I nearestGrid = Align( aOrigin, aGrid );
519
521 {
522 ad->ClearAnchors();
523 for( const ANCHOR& anchor : m_anchors )
524 ad->AddAnchor( anchor.pos );
525
526 ad->SetNearest( nearest ? OPT_VECTOR2I{ nearest->pos } : std::nullopt );
528 }
529
530 // The distance to the nearest snap point, if any
531 std::optional<int> snapDist;
532 if( nearest )
533 snapDist = nearest->Distance( aOrigin );
534
536
537 SNAP_MANAGER& snapManager = getSnapManager();
538 SNAP_LINE_MANAGER& snapLineManager = snapManager.GetSnapLineManager();
539
540 const auto ptIsReferenceOnly = [&]( const VECTOR2I& aPt )
541 {
542 const std::vector<VECTOR2I>& referenceOnlyPoints = snapManager.GetReferenceOnlyPoints();
543 return std::find( referenceOnlyPoints.begin(), referenceOnlyPoints.end(), aPt )
544 != referenceOnlyPoints.end();
545 };
546
547 const auto proposeConstructionForItems = [&]( const std::vector<EDA_ITEM*>& aItems )
548 {
549 // Add any involved item as a temporary construction item
550 // (de-duplication with existing construction items is handled later)
551 std::vector<BOARD_ITEM*> items;
552
553 for( EDA_ITEM* item : aItems )
554 {
555 BOARD_ITEM* boardItem = static_cast<BOARD_ITEM*>( item );
556
557 // Null items are allowed to arrive here as they represent geometry that isn't
558 // specifically tied to a board item. For example snap lines from some
559 // other anchor.
560 // But they don't produce new construction items.
561 if( boardItem )
562 {
564 || ( ( aLayers & boardItem->GetLayerSet() ).any() ) )
565 {
566 items.push_back( boardItem );
567 }
568 }
569 }
570
571 // Temporary construction items are not persistent and don't
572 // overlay the items themselves (as the items will not be moved)
573 AddConstructionItems( items, true, false );
574 };
575
576 bool snapValid = false;
577
578 if( m_enableSnap )
579 {
580 // Existing snap lines need priority over new snaps
581 if( m_enableSnapLine )
582 {
583 OPT_VECTOR2I snapLineSnap = snapLineManager.GetNearestSnapLinePoint(
584 aOrigin, nearestGrid, snapDist, snapRange );
585
586 // We found a better snap point that the nearest one
587 if( snapLineSnap && m_skipPoint != *snapLineSnap )
588 {
589 snapLineManager.SetSnapLineEnd( *snapLineSnap );
590 snapValid = true;
591
592 // Don't show a snap point if we're snapping to a grid rather than an anchor
594 m_viewSnapPoint.SetSnapTypes( POINT_TYPE::PT_NONE );
595
596 // Only return the snap line end as a snap if it's not a reference point
597 // (we don't snap to reference points, but we can use them to update the snap line,
598 // without actually snapping)
599 if( !ptIsReferenceOnly( *snapLineSnap ) )
600 {
601 return *snapLineSnap;
602 }
603 }
604 }
605
606 // If there's a snap anchor within range, use it if we can
607 if( nearest && nearest->Distance( aOrigin ) <= snapRange )
608 {
609 const bool anchorIsConstructed = nearest->flags & ANCHOR_FLAGS::CONSTRUCTED;
610
611 // If the nearest anchor is a reference point, we don't snap to it,
612 // but we can update the snap line origin
613 if( ptIsReferenceOnly( nearest->pos ) )
614 {
615 // We can set the snap line origin, but don't mess with the
616 // accepted snap point
617 snapLineManager.SetSnapLineOrigin( nearest->pos );
618 }
619 else
620 {
621 // 'Intrinsic' points of items can trigger adding construction geometry
622 // for _that_ item by proximity. E.g. just mousing over the intersection
623 // of an item doesn't add a construction item for the second item).
624 // This is to make construction items less intrusive and more
625 // a result of user intent.
626 if( !anchorIsConstructed )
627 {
628 proposeConstructionForItems( nearest->items );
629 }
630
631 const auto shouldAcceptAnchor = [&]( const ANCHOR& aAnchor )
632 {
633 // If no extension snaps are enabled, don't inhibit
634 static const bool haveExtensions =
636 if( !haveExtensions )
637 return true;
638
639 // Check that any involved real items are 'active'
640 // (i.e. the user has moused over a key point previously)
641 // If any are not real (e.g. snap lines), they are allowed to be involved
642 //
643 // This is an area most likely to be controversial/need tuning,
644 // as some users will think it's fiddly; without 'activation', others will
645 // think the snaps are intrusive.
646 bool allRealAreInvolved =
648 aAnchor.items );
649 return allRealAreInvolved;
650 };
651
652 if( shouldAcceptAnchor( *nearest ) )
653 {
654 m_snapItem = *nearest;
655
656 // Set the snap line origin or end as needed
657 snapLineManager.SetSnappedAnchor( m_snapItem->pos );
658 // Show the correct snap point marker
659 updateSnapPoint( { m_snapItem->pos, m_snapItem->pointTypes } );
660
661 return m_snapItem->pos;
662 }
663 }
664
665 snapValid = true;
666 }
667 else
668 {
669 static const bool canActivateByHitTest =
671 if( canActivateByHitTest )
672 {
673 // An exact hit on an item, even if not near a snap point
674 // If it's tool hard to hit by hover, this can be increased
675 // to make it non-exact.
676 const int hoverAccuracy = 0;
677 for( BOARD_ITEM* item : visibleItems )
678 {
679 if( item->HitTest( aOrigin, hoverAccuracy ) )
680 {
681 proposeConstructionForItems( { item } );
682 snapValid = true;
683 break;
684 }
685 }
686 }
687 }
688
689 // If we got here, we didn't snap to an anchor or snap line
690
691 // If we're snapping to a grid, on-element snaps would be too intrusive
692 // but they're useful when there isn't a grid to snap to
693 if( !m_enableGrid )
694 {
695 OPT_VECTOR2I nearestPointOnAnElement =
697
698 // Got any nearest point - snap if in range
699 if( nearestPointOnAnElement
700 && nearestPointOnAnElement->Distance( aOrigin ) <= snapRange )
701 {
702 updateSnapPoint( { *nearestPointOnAnElement, POINT_TYPE::PT_ON_ELEMENT } );
703
704 // Clear the snap end, but keep the origin so touching another line
705 // doesn't kill a snap line
706 snapLineManager.SetSnapLineEnd( std::nullopt );
707 return *nearestPointOnAnElement;
708 }
709 }
710 }
711
712 // Completely failed to find any snap point, so snap to the grid
713
714 m_snapItem = std::nullopt;
715
716 if( !snapValid )
717 {
718 snapLineManager.ClearSnapLine();
720 }
721 else
722 {
723 snapLineManager.SetSnapLineEnd( std::nullopt );
724 }
725
727
728 return nearestGrid;
729}
730
731
733{
734 if( !m_snapItem )
735 return nullptr;
736
737 // The snap anchor doesn't have an item associated with it
738 // (odd, could it be entirely made of construction geometry?)
739 if( m_snapItem->items.empty() )
740 return nullptr;
741
742 return static_cast<BOARD_ITEM*>( m_snapItem->items[0] );
743}
744
745
747{
748 if( !aItem )
749 return GRID_CURRENT;
750
751 switch( aItem->Type() )
752 {
753 case PCB_FOOTPRINT_T:
754 case PCB_PAD_T:
755 return GRID_CONNECTABLE;
756
757 case PCB_TEXT_T:
758 case PCB_FIELD_T:
759 return GRID_TEXT;
760
761 case PCB_SHAPE_T:
762 case PCB_DIMENSION_T:
764 case PCB_TEXTBOX_T:
765 return GRID_GRAPHICS;
766
767 case PCB_TRACE_T:
768 case PCB_ARC_T:
769 return GRID_WIRES;
770
771 case PCB_VIA_T:
772 return GRID_VIAS;
773
774 default:
775 return GRID_CURRENT;
776 }
777}
778
779
781{
783 int idx = -1;
784
786
787 if( !grid.overrides_enabled )
788 return g;
789
790 switch( aGrid )
791 {
792 case GRID_CONNECTABLE:
793 if( grid.override_connected )
794 idx = grid.override_connected_idx;
795
796 break;
797
798 case GRID_WIRES:
799 if( grid.override_wires )
800 idx = grid.override_wires_idx;
801
802 break;
803
804 case GRID_VIAS:
805 if( grid.override_vias )
806 idx = grid.override_vias_idx;
807
808 break;
809
810 case GRID_TEXT:
811 if( grid.override_text )
812 idx = grid.override_text_idx;
813
814 break;
815
816 case GRID_GRAPHICS:
817 if( grid.override_graphics )
818 idx = grid.override_graphics_idx;
819
820 break;
821
822 default:
823 break;
824 }
825
826 if( idx >= 0 && idx < (int) grid.grids.size() )
827 g = grid.grids[idx].ToDouble( pcbIUScale );
828
829 return g;
830}
831
832
833std::vector<BOARD_ITEM*>
834PCB_GRID_HELPER::queryVisible( const BOX2I& aArea, const std::vector<BOARD_ITEM*>& aSkip ) const
835{
836 std::set<BOARD_ITEM*> items;
837 std::vector<KIGFX::VIEW::LAYER_ITEM_PAIR> selectedItems;
838
839 PCB_TOOL_BASE* currentTool = static_cast<PCB_TOOL_BASE*>( m_toolMgr->GetCurrentTool() );
840 KIGFX::VIEW* view = m_toolMgr->GetView();
841 RENDER_SETTINGS* settings = view->GetPainter()->GetSettings();
842 const std::set<int>& activeLayers = settings->GetHighContrastLayers();
843 bool isHighContrast = settings->GetHighContrast();
844
845 view->Query( aArea, selectedItems );
846
847 for( const auto& [ viewItem, layer ] : selectedItems )
848 {
849 BOARD_ITEM* boardItem = static_cast<BOARD_ITEM*>( viewItem );
850
851 if( currentTool->IsFootprintEditor() )
852 {
853 // If we are in the footprint editor, don't use the footprint itself
854 if( boardItem->Type() == PCB_FOOTPRINT_T )
855 continue;
856 }
857 else
858 {
859 // If we are not in the footprint editor, don't use footprint-editor-private items
860 if( FOOTPRINT* parentFP = boardItem->GetParentFootprint() )
861 {
862 if( IsPcbLayer( layer ) && parentFP->GetPrivateLayers().test( layer ) )
863 continue;
864 }
865 }
866
867 // The boardItem must be visible and on an active layer
868 if( view->IsVisible( boardItem )
869 && ( !isHighContrast || activeLayers.count( layer ) )
870 && boardItem->ViewGetLOD( layer, view ) < view->GetScale() )
871 {
872 items.insert ( boardItem );
873 }
874 }
875
876 std::function<void( BOARD_ITEM* )> skipItem =
877 [&]( BOARD_ITEM* aItem )
878 {
879 items.erase( aItem );
880
881 aItem->RunOnDescendants(
882 [&]( BOARD_ITEM* aChild )
883 {
884 skipItem( aChild );
885 } );
886 };
887
888 for( BOARD_ITEM* item : aSkip )
889 skipItem( item );
890
891 return {items.begin(), items.end()};
892}
893
894
896{
899
900 // Clang wants this constructor
902 Item( aItem ), Geometry( std::move( aSeg ) )
903 {
904 }
905};
906
907
908void PCB_GRID_HELPER::computeAnchors( const std::vector<BOARD_ITEM*>& aItems,
909 const VECTOR2I& aRefPos, bool aFrom,
910 const PCB_SELECTION_FILTER_OPTIONS* aSelectionFilter,
911 const LSET* aMatchLayers, bool aForDrag )
912{
913 std::vector<PCB_INTERSECTABLE> intersectables;
914
915 // These could come from a more granular snap mode filter
916 // But when looking for drag points, we don't want construction geometry
917 const bool computeIntersections = !aForDrag;
918 const bool computePointsOnElements = !aForDrag;
919 const bool excludeGraphics = aSelectionFilter && !aSelectionFilter->graphics;
920 const bool excludeTracks = aSelectionFilter && !aSelectionFilter->tracks;
921
922 const auto itemIsSnappable = [&]( const BOARD_ITEM& aItem )
923 {
924 // If we are filtering by layers, check if the item matches
925 if( aMatchLayers )
926 {
928 || ( ( *aMatchLayers & aItem.GetLayerSet() ).any() );
929 }
930 return true;
931 };
932
933 const auto processItem = [&]( BOARD_ITEM& item )
934 {
935 // Don't even process the item if it doesn't match the layers
936 if( !itemIsSnappable( item ) )
937 {
938 return;
939 }
940
941 // First, add all the key points of the item itself
942 computeAnchors( &item, aRefPos, aFrom, aSelectionFilter );
943
944 // If we are computing intersections, construct the relevant intersectables
945 // Points on elements also use the intersectables.
946 if( computeIntersections || computePointsOnElements )
947 {
948 std::optional<INTERSECTABLE_GEOM> intersectableGeom;
949 if( !excludeGraphics && item.Type() == PCB_SHAPE_T )
950 {
951 intersectableGeom = GetBoardIntersectable( item );
952 }
953 else if( !excludeTracks && ( item.Type() == PCB_TRACE_T || item.Type() == PCB_ARC_T ) )
954 {
955 intersectableGeom = GetBoardIntersectable( item );
956 }
957
958 if( intersectableGeom )
959 {
960 intersectables.emplace_back( &item, *intersectableGeom );
961 }
962 }
963 };
964
965 for( BOARD_ITEM* item : aItems )
966 {
967 processItem( *item );
968 }
969
971 getSnapManager().GetConstructionItems() )
972 {
973 for( const CONSTRUCTION_MANAGER::CONSTRUCTION_ITEM& constructionItem : batch )
974 {
975 BOARD_ITEM* involvedItem = static_cast<BOARD_ITEM*>( constructionItem.Item );
976
977
978 for( const KIGFX::CONSTRUCTION_GEOM::DRAWABLE& drawable :
979 constructionItem.Constructions )
980 {
981 std::visit(
982 [&]( const auto& visited )
983 {
984 using ItemType = std::decay_t<decltype( visited )>;
985
986 if constexpr( std::is_same_v<ItemType, LINE>
987 || std::is_same_v<ItemType, CIRCLE>
988 || std::is_same_v<ItemType, HALF_LINE>
989 || std::is_same_v<ItemType, SHAPE_ARC> )
990 {
991 intersectables.emplace_back( involvedItem, visited );
992 }
993 else if constexpr( std::is_same_v<ItemType, VECTOR2I> )
994 {
995 // Add any free-floating points as snap points.
996 addAnchor( visited, SNAPPABLE | CONSTRUCTED, involvedItem,
997 POINT_TYPE::PT_NONE );
998 }
999 },
1000 drawable );
1001 }
1002 }
1003 }
1004
1005 // Now, add all the intersections between the items
1006 // This is obviously quadratic, so performance may be a concern for large selections
1007 // But, so far up to ~20k comparisons seems not to be an issue with run times in the ms range
1008 // and it's usually only a handful of items.
1009
1010 if( computeIntersections )
1011 {
1012 for( std::size_t ii = 0; ii < intersectables.size(); ++ii )
1013 {
1014 const PCB_INTERSECTABLE& intersectableA = intersectables[ii];
1015
1016 for( std::size_t jj = ii + 1; jj < intersectables.size(); ++jj )
1017 {
1018 const PCB_INTERSECTABLE& intersectableB = intersectables[jj];
1019
1020 // An item and its own extension will often have intersections (as they are on top of each other),
1021 // but they not useful points to snap to
1022 if( intersectableA.Item == intersectableB.Item )
1023 continue;
1024
1025 std::vector<VECTOR2I> intersections;
1026 const INTERSECTION_VISITOR visitor{ intersectableA.Geometry, intersections };
1027
1028 std::visit( visitor, intersectableB.Geometry );
1029
1030 // For each intersection, add an intersection snap anchor
1031 for( const VECTOR2I& intersection : intersections )
1032 {
1033 std::vector<EDA_ITEM*> items = {
1034 intersectableA.Item,
1035 intersectableB.Item,
1036 };
1037 addAnchor( intersection, SNAPPABLE | CONSTRUCTED, std::move( items ),
1038 POINT_TYPE::PT_INTERSECTION );
1039 }
1040 }
1041 }
1042 }
1043
1044 // The intersectables can also be used for fall-back snapping to "point on line"
1045 // snaps if no other snap is found
1047 if( computePointsOnElements )
1048 {
1049 // For the moment, it's trivial to make a NEARABLE from an INTERSECTABLE,
1050 // because all INTERSECTABLEs are also NEARABLEs.
1051 for( const PCB_INTERSECTABLE& intersectable : intersectables )
1052 {
1053 std::visit(
1054 [&]( const auto& geom )
1055 {
1056 NEARABLE_GEOM nearable( geom );
1057 m_pointOnLineCandidates.emplace_back( nearable );
1058 },
1059 intersectable.Geometry );
1060 }
1061 }
1062}
1063
1064
1065void PCB_GRID_HELPER::computeAnchors( BOARD_ITEM* aItem, const VECTOR2I& aRefPos, bool aFrom,
1066 const PCB_SELECTION_FILTER_OPTIONS* aSelectionFilter )
1067{
1068 KIGFX::VIEW* view = m_toolMgr->GetView();
1069 RENDER_SETTINGS* settings = view->GetPainter()->GetSettings();
1070 const std::set<int>& activeLayers = settings->GetHighContrastLayers();
1071 bool isHighContrast = settings->GetHighContrast();
1072
1073 auto checkVisibility =
1074 [&]( BOARD_ITEM* item )
1075 {
1076 // New moved items don't yet have view flags so VIEW will call them invisible
1077 if( !view->IsVisible( item ) && !item->IsMoving() )
1078 return false;
1079
1080 bool onActiveLayer = !isHighContrast;
1081 bool isLODVisible = false;
1082
1083 for( PCB_LAYER_ID layer : item->GetLayerSet().Seq() )
1084 {
1085 if( !onActiveLayer && activeLayers.count( layer ) )
1086 onActiveLayer = true;
1087
1088 if( !isLODVisible && item->ViewGetLOD( layer, view ) < view->GetScale() )
1089 isLODVisible = true;
1090
1091 if( onActiveLayer && isLODVisible )
1092 return true;
1093 }
1094
1095 return false;
1096 };
1097
1098 // As defaults, these are probably reasonable to avoid spamming key points
1099 const KIGEOM::OVAL_KEY_POINT_FLAGS ovalKeyPointFlags =
1102
1103 auto handlePadShape = [&]( PAD* aPad, PCB_LAYER_ID aLayer )
1104 {
1105 addAnchor( aPad->GetPosition(), ORIGIN | SNAPPABLE, aPad, POINT_TYPE::PT_CENTER );
1106
1108 if( aFrom )
1109 return;
1110
1111 switch( aPad->GetShape( aLayer ) )
1112 {
1113 case PAD_SHAPE::CIRCLE:
1114 {
1115 const CIRCLE circle( aPad->ShapePos( aLayer ), aPad->GetSizeX() / 2 );
1116
1117 for( const TYPED_POINT2I& pt : KIGEOM::GetCircleKeyPoints( circle, false ) )
1118 {
1119 addAnchor( pt.m_point, OUTLINE | SNAPPABLE, aPad, pt.m_types );
1120 }
1121
1122 break;
1123 }
1124 case PAD_SHAPE::OVAL:
1125 {
1126 const OVAL oval( aPad->GetSize( aLayer ), aPad->GetPosition(), aPad->GetOrientation() );
1127
1128 for( const TYPED_POINT2I& pt : KIGEOM::GetOvalKeyPoints( oval, ovalKeyPointFlags ) )
1129 {
1130 addAnchor( pt.m_point, OUTLINE | SNAPPABLE, aPad, pt.m_types );
1131 }
1132
1133 break;
1134 }
1135 case PAD_SHAPE::RECTANGLE:
1136 case PAD_SHAPE::TRAPEZOID:
1137 case PAD_SHAPE::ROUNDRECT:
1138 case PAD_SHAPE::CHAMFERED_RECT:
1139 {
1140 VECTOR2I half_size( aPad->GetSize( aLayer ) / 2 );
1141 VECTOR2I trap_delta( 0, 0 );
1142
1143 if( aPad->GetShape( aLayer ) == PAD_SHAPE::TRAPEZOID )
1144 trap_delta = aPad->GetDelta( aLayer ) / 2;
1145
1146 SHAPE_LINE_CHAIN corners;
1147
1148 corners.Append( -half_size.x - trap_delta.y, half_size.y + trap_delta.x );
1149 corners.Append( half_size.x + trap_delta.y, half_size.y - trap_delta.x );
1150 corners.Append( half_size.x - trap_delta.y, -half_size.y + trap_delta.x );
1151 corners.Append( -half_size.x + trap_delta.y, -half_size.y - trap_delta.x );
1152 corners.SetClosed( true );
1153
1154 corners.Rotate( aPad->GetOrientation() );
1155 corners.Move( aPad->ShapePos( aLayer ) );
1156
1157 for( std::size_t ii = 0; ii < corners.GetSegmentCount(); ++ii )
1158 {
1159 const SEG& seg = corners.GetSegment( ii );
1160 addAnchor( seg.A, OUTLINE | SNAPPABLE, aPad, POINT_TYPE::PT_CORNER );
1161 addAnchor( seg.Center(), OUTLINE | SNAPPABLE, aPad, POINT_TYPE::PT_MID );
1162
1163 if( ii == corners.GetSegmentCount() - 1 )
1164 addAnchor( seg.B, OUTLINE | SNAPPABLE, aPad, POINT_TYPE::PT_CORNER );
1165 }
1166
1167 break;
1168 }
1169
1170 default:
1171 {
1172 const auto& outline = aPad->GetEffectivePolygon( aLayer, ERROR_INSIDE );
1173
1174 if( !outline->IsEmpty() )
1175 {
1176 for( const VECTOR2I& pt : outline->Outline( 0 ).CPoints() )
1177 addAnchor( pt, OUTLINE | SNAPPABLE, aPad );
1178 }
1179
1180 break;
1181 }
1182 }
1183
1184 if( aPad->HasHole() )
1185 {
1186 // Holes are at the pad centre (it's the shape that may be offset)
1187 const VECTOR2I hole_pos = aPad->GetPosition();
1188 const VECTOR2I hole_size = aPad->GetDrillSize();
1189
1190 std::vector<TYPED_POINT2I> snap_pts;
1191
1192 if( hole_size.x == hole_size.y )
1193 {
1194 // Circle
1195 const CIRCLE circle( hole_pos, hole_size.x / 2 );
1196 snap_pts = KIGEOM::GetCircleKeyPoints( circle, true );
1197 }
1198 else
1199 {
1200 // Oval
1201
1202 // For now there's no way to have an off-angle hole, so this is the
1203 // same as the pad. In future, this may not be true:
1204 // https://gitlab.com/kicad/code/kicad/-/issues/4124
1205 const OVAL oval( hole_size, hole_pos, aPad->GetOrientation() );
1206 snap_pts = KIGEOM::GetOvalKeyPoints( oval, ovalKeyPointFlags );
1207 }
1208
1209 for( const TYPED_POINT2I& snap_pt : snap_pts )
1210 addAnchor( snap_pt.m_point, OUTLINE | SNAPPABLE, aPad, snap_pt.m_types );
1211 }
1212 };
1213
1214 auto handleShape =
1215 [&]( PCB_SHAPE* shape )
1216 {
1217 VECTOR2I start = shape->GetStart();
1218 VECTOR2I end = shape->GetEnd();
1219
1220 switch( shape->GetShape() )
1221 {
1222 case SHAPE_T::CIRCLE:
1223 {
1224 const int r = ( start - end ).EuclideanNorm();
1225
1226 addAnchor( start, ORIGIN | SNAPPABLE, shape, POINT_TYPE::PT_CENTER );
1227
1228 addAnchor( start + VECTOR2I( -r, 0 ), OUTLINE | SNAPPABLE, shape,
1229 POINT_TYPE::PT_QUADRANT );
1230 addAnchor( start + VECTOR2I( r, 0 ), OUTLINE | SNAPPABLE, shape,
1231 POINT_TYPE::PT_QUADRANT );
1232 addAnchor( start + VECTOR2I( 0, -r ), OUTLINE | SNAPPABLE, shape,
1233 POINT_TYPE::PT_QUADRANT );
1234 addAnchor( start + VECTOR2I( 0, r ), OUTLINE | SNAPPABLE, shape,
1235 POINT_TYPE::PT_QUADRANT );
1236 break;
1237 }
1238
1239 case SHAPE_T::ARC:
1240 addAnchor( shape->GetStart(), CORNER | SNAPPABLE, shape,
1241 POINT_TYPE::PT_END );
1242 addAnchor( shape->GetEnd(), CORNER | SNAPPABLE, shape,
1243 POINT_TYPE::PT_END );
1244 addAnchor( shape->GetArcMid(), CORNER | SNAPPABLE, shape,
1245 POINT_TYPE::PT_MID );
1246 addAnchor( shape->GetCenter(), ORIGIN | SNAPPABLE, shape,
1247 POINT_TYPE::PT_CENTER );
1248 break;
1249
1250 case SHAPE_T::RECTANGLE:
1251 {
1252 VECTOR2I point2( end.x, start.y );
1253 VECTOR2I point3( start.x, end.y );
1254 SEG first( start, point2 );
1255 SEG second( point2, end );
1256 SEG third( end, point3 );
1257 SEG fourth( point3, start );
1258
1259 const int snapFlags = CORNER | SNAPPABLE;
1260
1261 addAnchor( shape->GetCenter(), snapFlags, shape, POINT_TYPE::PT_CENTER );
1262
1263 addAnchor( first.A, snapFlags, shape, POINT_TYPE::PT_CORNER );
1264 addAnchor( first.Center(), snapFlags, shape, POINT_TYPE::PT_MID );
1265 addAnchor( second.A, snapFlags, shape, POINT_TYPE::PT_CORNER );
1266 addAnchor( second.Center(), snapFlags, shape, POINT_TYPE::PT_MID );
1267 addAnchor( third.A, snapFlags, shape, POINT_TYPE::PT_CORNER );
1268 addAnchor( third.Center(), snapFlags, shape, POINT_TYPE::PT_MID );
1269 addAnchor( fourth.A, snapFlags, shape, POINT_TYPE::PT_CORNER );
1270 addAnchor( fourth.Center(), snapFlags, shape, POINT_TYPE::PT_MID );
1271 break;
1272 }
1273
1274 case SHAPE_T::SEGMENT:
1275 addAnchor( start, CORNER | SNAPPABLE, shape, POINT_TYPE::PT_END );
1276 addAnchor( end, CORNER | SNAPPABLE, shape, POINT_TYPE::PT_END );
1277 addAnchor( shape->GetCenter(), CORNER | SNAPPABLE, shape,
1278 POINT_TYPE::PT_MID );
1279 break;
1280
1281 case SHAPE_T::POLY:
1282 {
1284 lc.SetClosed( true );
1285 std::vector<VECTOR2I> poly;
1286 shape->DupPolyPointsList( poly );
1287
1288 for( const VECTOR2I& p : poly )
1289 {
1290 addAnchor( p, CORNER | SNAPPABLE, shape, POINT_TYPE::PT_CORNER );
1291 lc.Append( p );
1292 }
1293
1294 addAnchor( lc.NearestPoint( aRefPos ), OUTLINE, aItem );
1295 break;
1296 }
1297
1298 case SHAPE_T::BEZIER:
1299 addAnchor( start, CORNER | SNAPPABLE, shape, POINT_TYPE::PT_END );
1300 addAnchor( end, CORNER | SNAPPABLE, shape, POINT_TYPE::PT_END );
1302
1303 default:
1304 addAnchor( shape->GetPosition(), ORIGIN | SNAPPABLE, shape );
1305 break;
1306 }
1307 };
1308
1309 switch( aItem->Type() )
1310 {
1311 case PCB_FOOTPRINT_T:
1312 {
1313 FOOTPRINT* footprint = static_cast<FOOTPRINT*>( aItem );
1314
1315 for( PAD* pad : footprint->Pads() )
1316 {
1317 if( aFrom )
1318 {
1319 if( aSelectionFilter && !aSelectionFilter->pads )
1320 continue;
1321 }
1322 else
1323 {
1324 if( m_magneticSettings->pads != MAGNETIC_OPTIONS::CAPTURE_ALWAYS )
1325 continue;
1326 }
1327
1328 if( !checkVisibility( pad ) )
1329 continue;
1330
1331 if( !pad->GetBoundingBox().Contains( aRefPos ) )
1332 continue;
1333
1334 pad->Padstack().ForEachUniqueLayer(
1335 [&]( PCB_LAYER_ID aLayer )
1336 {
1337 if( !isHighContrast || activeLayers.count( aLayer ) )
1338 handlePadShape( pad, aLayer );
1339 } );
1340 }
1341
1342 if( aFrom && aSelectionFilter && !aSelectionFilter->footprints )
1343 break;
1344
1345 // If the cursor is not over a pad, snap to the anchor (if visible) or the center
1346 // (if markedly different from the anchor).
1347 VECTOR2I position = footprint->GetPosition();
1348 VECTOR2I center = footprint->GetBoundingBox( false ).Centre();
1349 VECTOR2I grid( GetGrid() );
1350
1351 if( view->IsLayerVisible( LAYER_ANCHOR ) )
1352 addAnchor( position, ORIGIN | SNAPPABLE, footprint, POINT_TYPE::PT_CENTER );
1353
1354 if( ( center - position ).SquaredEuclideanNorm() > grid.SquaredEuclideanNorm() )
1355 addAnchor( center, ORIGIN | SNAPPABLE, footprint, POINT_TYPE::PT_CENTER );
1356
1357 break;
1358 }
1359
1360 case PCB_PAD_T:
1361 if( aFrom )
1362 {
1363 if( aSelectionFilter && !aSelectionFilter->pads )
1364 break;
1365 }
1366 else
1367 {
1368 if( m_magneticSettings->pads != MAGNETIC_OPTIONS::CAPTURE_ALWAYS )
1369 break;
1370 }
1371
1372 if( checkVisibility( aItem ) )
1373 {
1374 PAD* pad = static_cast<PAD*>( aItem );
1375
1376 pad->Padstack().ForEachUniqueLayer(
1377 [&]( PCB_LAYER_ID aLayer )
1378 {
1379 if( !isHighContrast || activeLayers.count( aLayer ) )
1380 handlePadShape( pad, aLayer );
1381 } );
1382 }
1383
1384 break;
1385
1386 case PCB_TEXTBOX_T:
1387 if( aFrom )
1388 {
1389 if( aSelectionFilter && !aSelectionFilter->text )
1390 break;
1391 }
1392 else
1393 {
1395 break;
1396 }
1397
1398 if( checkVisibility( aItem ) )
1399 handleShape( static_cast<PCB_SHAPE*>( aItem ) );
1400
1401 break;
1402
1403 case PCB_SHAPE_T:
1404 if( aFrom )
1405 {
1406 if( aSelectionFilter && !aSelectionFilter->graphics )
1407 break;
1408 }
1409 else
1410 {
1412 break;
1413 }
1414
1415 if( checkVisibility( aItem ) )
1416 handleShape( static_cast<PCB_SHAPE*>( aItem ) );
1417
1418 break;
1419
1420 case PCB_TRACE_T:
1421 case PCB_ARC_T:
1422 if( aFrom )
1423 {
1424 if( aSelectionFilter && !aSelectionFilter->tracks )
1425 break;
1426 }
1427 else
1428 {
1429 if( m_magneticSettings->tracks != MAGNETIC_OPTIONS::CAPTURE_ALWAYS )
1430 break;
1431 }
1432
1433 if( checkVisibility( aItem ) )
1434 {
1435 PCB_TRACK* track = static_cast<PCB_TRACK*>( aItem );
1436
1437 addAnchor( track->GetStart(), CORNER | SNAPPABLE, track, POINT_TYPE::PT_END );
1438 addAnchor( track->GetEnd(), CORNER | SNAPPABLE, track, POINT_TYPE::PT_END );
1439 addAnchor( track->GetCenter(), ORIGIN, track, POINT_TYPE::PT_MID );
1440 }
1441
1442 break;
1443
1444 case PCB_MARKER_T:
1445 case PCB_TARGET_T:
1446 addAnchor( aItem->GetPosition(), ORIGIN | CORNER | SNAPPABLE, aItem,
1447 POINT_TYPE::PT_CENTER );
1448 break;
1449
1450 case PCB_VIA_T:
1451 if( aFrom )
1452 {
1453 if( aSelectionFilter && !aSelectionFilter->vias )
1454 break;
1455 }
1456 else
1457 {
1458 if( m_magneticSettings->tracks != MAGNETIC_OPTIONS::CAPTURE_ALWAYS )
1459 break;
1460 }
1461
1462 if( checkVisibility( aItem ) )
1463 addAnchor( aItem->GetPosition(), ORIGIN | CORNER | SNAPPABLE, aItem,
1464 POINT_TYPE::PT_CENTER );
1465
1466 break;
1467
1468 case PCB_ZONE_T:
1469 if( aFrom && aSelectionFilter && !aSelectionFilter->zones )
1470 break;
1471
1472 if( checkVisibility( aItem ) )
1473 {
1474 const SHAPE_POLY_SET* outline = static_cast<const ZONE*>( aItem )->Outline();
1475
1477 lc.SetClosed( true );
1478
1479 for( auto iter = outline->CIterateWithHoles(); iter; iter++ )
1480 {
1481 addAnchor( *iter, CORNER | SNAPPABLE, aItem, POINT_TYPE::PT_CORNER );
1482 lc.Append( *iter );
1483 }
1484
1485 addAnchor( lc.NearestPoint( aRefPos ), OUTLINE, aItem );
1486 }
1487
1488 break;
1489
1490 case PCB_DIM_ALIGNED_T:
1492 if( aFrom && aSelectionFilter && !aSelectionFilter->dimensions )
1493 break;
1494
1495 if( checkVisibility( aItem ) )
1496 {
1497 const PCB_DIM_ALIGNED* dim = static_cast<const PCB_DIM_ALIGNED*>( aItem );
1498 addAnchor( dim->GetCrossbarStart(), CORNER | SNAPPABLE, aItem );
1499 addAnchor( dim->GetCrossbarEnd(), CORNER | SNAPPABLE, aItem );
1500 addAnchor( dim->GetStart(), CORNER | SNAPPABLE, aItem );
1501 addAnchor( dim->GetEnd(), CORNER | SNAPPABLE, aItem );
1502 }
1503
1504 break;
1505
1506 case PCB_DIM_CENTER_T:
1507 if( aFrom && aSelectionFilter && !aSelectionFilter->dimensions )
1508 break;
1509
1510 if( checkVisibility( aItem ) )
1511 {
1512 const PCB_DIM_CENTER* dim = static_cast<const PCB_DIM_CENTER*>( aItem );
1513 addAnchor( dim->GetStart(), CORNER | SNAPPABLE, aItem );
1514 addAnchor( dim->GetEnd(), CORNER | SNAPPABLE, aItem );
1515
1516 VECTOR2I start( dim->GetStart() );
1517 VECTOR2I radial( dim->GetEnd() - dim->GetStart() );
1518
1519 for( int i = 0; i < 2; i++ )
1520 {
1521 RotatePoint( radial, -ANGLE_90 );
1522 addAnchor( start + radial, CORNER | SNAPPABLE, aItem );
1523 }
1524 }
1525
1526 break;
1527
1528 case PCB_DIM_RADIAL_T:
1529 if( aFrom && aSelectionFilter && !aSelectionFilter->dimensions )
1530 break;
1531
1532 if( checkVisibility( aItem ) )
1533 {
1534 const PCB_DIM_RADIAL* radialDim = static_cast<const PCB_DIM_RADIAL*>( aItem );
1535 addAnchor( radialDim->GetStart(), CORNER | SNAPPABLE, aItem );
1536 addAnchor( radialDim->GetEnd(), CORNER | SNAPPABLE, aItem );
1537 addAnchor( radialDim->GetKnee(), CORNER | SNAPPABLE, aItem );
1538 addAnchor( radialDim->GetTextPos(), CORNER | SNAPPABLE, aItem );
1539 }
1540
1541 break;
1542
1543 case PCB_DIM_LEADER_T:
1544 if( aFrom && aSelectionFilter && !aSelectionFilter->dimensions )
1545 break;
1546
1547 if( checkVisibility( aItem ) )
1548 {
1549 const PCB_DIM_LEADER* leader = static_cast<const PCB_DIM_LEADER*>( aItem );
1550 addAnchor( leader->GetStart(), CORNER | SNAPPABLE, aItem );
1551 addAnchor( leader->GetEnd(), CORNER | SNAPPABLE, aItem );
1552 addAnchor( leader->GetTextPos(), CORNER | SNAPPABLE, aItem );
1553 }
1554
1555 break;
1556
1557 case PCB_FIELD_T:
1558 case PCB_TEXT_T:
1559 if( aFrom && aSelectionFilter && !aSelectionFilter->text )
1560 break;
1561
1562 if( checkVisibility( aItem ) )
1563 addAnchor( aItem->GetPosition(), ORIGIN, aItem );
1564
1565 break;
1566
1567 case PCB_GROUP_T:
1568 for( BOARD_ITEM* item : static_cast<const PCB_GROUP*>( aItem )->GetItems() )
1569 {
1570 if( checkVisibility( item ) )
1571 computeAnchors( item, aRefPos, aFrom, nullptr );
1572 }
1573
1574 break;
1575
1576 default:
1577 break;
1578 }
1579}
1580
1581
1583{
1584 // Do this all in squared distances as we only care about relative distances
1586
1587 ecoord minDist = std::numeric_limits<ecoord>::max();
1588 std::vector<ANCHOR*> anchorsAtMinDistance;
1589
1590 for( ANCHOR& anchor : m_anchors )
1591 {
1592 // There is no need to filter by layers here, as the items are already filtered
1593 // by layer (if needed) when the anchors are computed.
1594 if( ( aFlags & anchor.flags ) != aFlags )
1595 continue;
1596
1597 if( !anchorsAtMinDistance.empty() && anchor.pos == anchorsAtMinDistance.front()->pos )
1598 {
1599 // Same distance as the previous best anchor
1600 anchorsAtMinDistance.push_back( &anchor );
1601 }
1602 else
1603 {
1604 const double dist = anchor.pos.SquaredDistance( aPos );
1605 if( dist < minDist )
1606 {
1607 // New minimum distance
1608 minDist = dist;
1609 anchorsAtMinDistance.clear();
1610 anchorsAtMinDistance.push_back( &anchor );
1611 }
1612 }
1613 }
1614
1615 // More than one anchor can be at the same distance, for example
1616 // two lines end-to-end each have the same endpoint anchor.
1617 // So, check which one has an involved item that's closest to the origin,
1618 // and use that one (which allows the user to choose which items
1619 // gets extended - it's the one nearest the cursor)
1620 ecoord minDistToItem = std::numeric_limits<ecoord>::max();
1621 ANCHOR* best = nullptr;
1622
1623 // One of the anchors at the minimum distance
1624 for( ANCHOR* const anchor : anchorsAtMinDistance )
1625 {
1626 ecoord distToNearestItem = std::numeric_limits<ecoord>::max();
1627 for( EDA_ITEM* const item : anchor->items )
1628 {
1629 if( !item )
1630 continue;
1631
1632 std::optional<ecoord> distToThisItem =
1633 FindSquareDistanceToItem( static_cast<const BOARD_ITEM&>( *item ), aPos );
1634
1635 if( distToThisItem )
1636 distToNearestItem = std::min( distToNearestItem, *distToThisItem );
1637 }
1638
1639 // If the item doesn't have any special min-dist handler,
1640 // just use the distance to the anchor
1641 distToNearestItem = std::min( distToNearestItem, minDist );
1642
1643 if( distToNearestItem < minDistToItem )
1644 {
1645 minDistToItem = distToNearestItem;
1646 best = anchor;
1647 }
1648 }
1649
1650 return best;
1651}
@ ERROR_INSIDE
Definition: approximation.h:34
constexpr EDA_IU_SCALE pcbIUScale
Definition: base_units.h:108
constexpr BOX2I BOX2ISafe(const BOX2D &aInput)
Definition: box2.h:929
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
Definition: box2.h:990
static const ADVANCED_CFG & GetCfg()
Get the singleton instance's config, which is shared by all consumers.
WINDOW_SETTINGS m_Window
Definition: app_settings.h:194
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition: board_item.h:79
virtual VECTOR2I GetCenter() const
This defaults to the center of the bounding box if not overridden.
Definition: board_item.h:111
FOOTPRINT * GetParentFootprint() const
Definition: board_item.cpp:298
virtual LSET GetLayerSet() const
Return a std::bitset of all layers on which the item physically resides.
Definition: board_item.h:257
virtual void RunOnDescendants(const std::function< void(BOARD_ITEM *)> &aFunction, int aDepth=0) const
Invoke a function on all descendants.
Definition: board_item.h:212
static constexpr BOX2< VECTOR2I > ByCorners(const VECTOR2I &aCorner1, const VECTOR2I &aCorner2)
Definition: box2.h:70
constexpr Vec Centre() const
Definition: box2.h:97
Represent basic circle geometry with utility geometry functions.
Definition: circle.h:33
void ProposeConstructionItems(std::unique_ptr< CONSTRUCTION_ITEM_BATCH > aBatch, bool aIsPersistent)
Add a batch of construction items to the helper.
void CancelProposal()
Cancel outstanding proposals for new geometry.
std::vector< CONSTRUCTION_ITEM > CONSTRUCTION_ITEM_BATCH
bool InvolvesAllGivenRealItems(const std::vector< EDA_ITEM * > &aItems) const
Check if all 'real' (non-null = constructed) the items in the batch are in the list of items currentl...
A base class for most all the KiCad significant classes used in schematics and boards.
Definition: eda_item.h:89
virtual VECTOR2I GetPosition() const
Definition: eda_item.h:243
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:101
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:216
bool IsMoving() const
Definition: eda_item.h:108
int GetRadius() const
Definition: eda_shape.cpp:826
SHAPE_T GetShape() const
Definition: eda_shape.h:132
const VECTOR2I & GetEnd() const
Return the ending point of the graphic.
Definition: eda_shape.h:174
void DupPolyPointsList(std::vector< VECTOR2I > &aBuffer) const
Duplicate the list of corners in a std::vector<VECTOR2I>
Definition: eda_shape.cpp:1554
const VECTOR2I & GetStart() const
Return the starting point of the graphic.
Definition: eda_shape.h:137
VECTOR2I GetArcMid() const
Definition: eda_shape.cpp:796
const VECTOR2I & GetTextPos() const
Definition: eda_text.h:257
std::deque< PAD * > & Pads()
Definition: footprint.h:206
VECTOR2I GetPosition() const override
Definition: footprint.h:224
const BOX2I GetBoundingBox() const override
Return the orthogonal bounding box of this object for display purposes.
Definition: footprint.cpp:1295
void addAnchor(const VECTOR2I &aPos, int aFlags, EDA_ITEM *aItem, int aPointTypes=POINT_TYPE::PT_NONE)
Definition: grid_helper.h:176
SNAP_MANAGER & getSnapManager()
Definition: grid_helper.h:206
VECTOR2I m_skipPoint
Definition: grid_helper.h:229
bool m_enableGrid
Definition: grid_helper.h:225
void showConstructionGeometry(bool aShow)
Definition: grid_helper.cpp:99
TOOL_MANAGER * m_toolMgr
Definition: grid_helper.h:219
VECTOR2D GetVisibleGrid() const
VECTOR2I GetGrid() const
bool m_enableSnapLine
Definition: grid_helper.h:226
bool m_enableSnap
Definition: grid_helper.h:224
void clearAnchors()
Definition: grid_helper.h:189
std::optional< ANCHOR > m_snapItem
Definition: grid_helper.h:227
KIGFX::ANCHOR_DEBUG * enableAndGetAnchorDebug()
Enable the anchor debug if permitted and return it.
Definition: grid_helper.cpp:85
KIGFX::SNAP_INDICATOR m_viewSnapPoint
Definition: grid_helper.h:231
void updateSnapPoint(const TYPED_POINT2I &aPoint)
KIGFX::ORIGIN_VIEWITEM m_viewAxis
Definition: grid_helper.h:232
std::vector< ANCHOR > m_anchors
Definition: grid_helper.h:217
View item to draw debug items for anchors.
Definition: anchor_debug.h:45
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:311
std::variant< SEG, LINE, HALF_LINE, CIRCLE, SHAPE_ARC, VECTOR2I > DRAWABLE
const VECTOR2D & GetGridSize() const
Return the grid size.
void SetColor(const KIGFX::COLOR4D &aColor)
void SetStyle(MARKER_STYLE aStyle)
void SetSize(int aSize)
void SetDrawAtZero(bool aDrawFlag)
Set the draw at zero flag.
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
void SetSnapTypes(int aSnapTypes)
Set a mask of point types that this snap item represents.
virtual double ViewGetLOD(int aLayer, VIEW *aView) const
Return the level of detail (LOD) of the item.
Definition: view_item.h:142
Hold a (potentially large) number of VIEW_ITEMs and renders them on a graphics device provided by the...
Definition: view.h:68
double GetScale() const
Definition: view.h:273
virtual void Add(VIEW_ITEM *aItem, int aDrawPriority=-1)
Add a VIEW_ITEM to the view.
Definition: view.cpp:299
virtual void Remove(VIEW_ITEM *aItem)
Remove a VIEW_ITEM from the view.
Definition: view.cpp:334
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:412
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:1669
GAL * GetGAL() const
Return the #GAL this view is using to draw graphical primitives.
Definition: view.h:199
VECTOR2D ToWorld(const VECTOR2D &aCoord, bool aAbsolute=true) const
Converts a screen space point/vector to a point/vector in world space coordinates.
Definition: view.cpp:459
bool IsLayerVisible(int aLayer) const
Return information about visibility of a particular layer.
Definition: view.h:419
PAINTER * GetPainter() const
Return the painter object used by the view for drawing #VIEW_ITEMS.
Definition: view.h:217
bool IsVisible(const VIEW_ITEM *aItem) const
Return information if the item is visible (or not).
Definition: view.cpp:1639
void SetVisible(VIEW_ITEM *aItem, bool aIsVisible=true)
Set the item visibility.
Definition: view.cpp:1596
Definition: line.h:36
LSET is a set of PCB_LAYER_IDs.
Definition: lset.h:36
static LSET AllLayersMask()
Definition: lset.cpp:711
LSEQ Seq(const LSEQ &aSequence) const
Return an LSEQ from the union of this LSET and a desired sequence.
Definition: lset.cpp:420
Class that represents an oval shape (rectangle with semicircular end caps)
Definition: oval.h:45
Definition: pad.h:54
int GetSizeX() const
Definition: pad.h:282
const VECTOR2I & GetDrillSize() const
Definition: pad.h:307
const VECTOR2I & GetDelta(PCB_LAYER_ID aLayer) const
Definition: pad.h:301
VECTOR2I GetPosition() const override
Definition: pad.h:210
PAD_SHAPE GetShape(PCB_LAYER_ID aLayer) const
Definition: pad.h:193
EDA_ANGLE GetOrientation() const
Return the rotation angle of the pad.
Definition: pad.h:410
const std::shared_ptr< SHAPE_POLY_SET > & GetEffectivePolygon(PCB_LAYER_ID aLayer, ERROR_LOC aErrorLoc=ERROR_INSIDE) const
Definition: pad.cpp:476
bool HasHole() const override
Definition: pad.h:104
VECTOR2I ShapePos(PCB_LAYER_ID aLayer) const
Definition: pad.cpp:973
const VECTOR2I & GetSize(PCB_LAYER_ID aLayer) const
Definition: pad.h:266
const VECTOR2I & GetMid() const
Definition: pcb_track.h:305
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
std::vector< NEARABLE_GEOM > m_pointOnLineCandidates
~PCB_GRID_HELPER() override
VECTOR2I AlignToArc(const VECTOR2I &aPoint, const SHAPE_ARC &aSeg)
VECTOR2I SnapToPad(const VECTOR2I &aMousePos, std::deque< PAD * > &aPads)
BOARD_ITEM * GetSnapped() const
Function GetSnapped If the PCB_GRID_HELPER has highlighted a snap point (target shown),...
VECTOR2D GetGridSize(GRID_HELPER_GRIDS aGrid) const override
Return the size of the specified grid.
VECTOR2I BestSnapAnchor(const VECTOR2I &aOrigin, BOARD_ITEM *aReferenceItem, GRID_HELPER_GRIDS aGrid=GRID_HELPER_GRIDS::GRID_CURRENT)
Chooses the "best" snap anchor around the given point, optionally taking layers from the reference it...
VECTOR2I BestDragOrigin(const VECTOR2I &aMousePos, std::vector< BOARD_ITEM * > &aItem, GRID_HELPER_GRIDS aGrid=GRID_HELPER_GRIDS::GRID_CURRENT, const PCB_SELECTION_FILTER_OPTIONS *aSelectionFilter=nullptr)
void AddConstructionItems(std::vector< BOARD_ITEM * > aItems, bool aExtensionOnly, bool aIsPersistent)
Add construction geometry for a set of board items.
ANCHOR * nearestAnchor(const VECTOR2I &aPos, int aFlags)
Find the nearest anchor point to the given position with matching flags.
MAGNETIC_SETTINGS * m_magneticSettings
GRID_HELPER_GRIDS GetItemGrid(const EDA_ITEM *aItem) const override
Gets the coarsest grid that applies to an item.
VECTOR2I AlignToSegment(const VECTOR2I &aPoint, const SEG &aSeg)
virtual VECTOR2I Align(const VECTOR2I &aPoint, GRID_HELPER_GRIDS aGrid) const
Definition: grid_helper.h:65
PCB_GRID_HELPER(TOOL_MANAGER *aToolMgr, MAGNETIC_SETTINGS *aMagneticSettings)
void computeAnchors(const std::vector< BOARD_ITEM * > &aItems, const VECTOR2I &aRefPos, bool aFrom, const PCB_SELECTION_FILTER_OPTIONS *aSelectionFilter, const LSET *aLayers, bool aForDrag)
computeAnchors inserts the local anchor points in to the grid helper for the specified container of b...
std::vector< BOARD_ITEM * > queryVisible(const BOX2I &aArea, const std::vector< BOARD_ITEM * > &aSkip) const
A set of BOARD_ITEMs (i.e., without duplicates).
Definition: pcb_group.h:52
VECTOR2I GetCenter() const override
This defaults to the center of the bounding box if not overridden.
Definition: pcb_shape.h:79
VECTOR2I GetPosition() const override
Definition: pcb_shape.h:77
bool IsFootprintEditor() const
const VECTOR2I & GetStart() const
Definition: pcb_track.h:122
const VECTOR2I & GetEnd() const
Definition: pcb_track.h:119
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:369
OPT_VECTOR2I IntersectLines(const SEG &aSeg) const
Compute the intersection point of lines passing through ends of (this) and aSeg.
Definition: seg.h:220
const VECTOR2I & GetP1() const
Definition: shape_arc.h:115
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:295
const VECTOR2I & GetP0() const
Definition: shape_arc.h:114
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
A class that manages the geometry of a "snap line".
void SetSnappedAnchor(const VECTOR2I &aAnchorPos)
Inform this manager that an anchor snap has been made.
OPT_VECTOR2I GetNearestSnapLinePoint(const VECTOR2I &aCursor, const VECTOR2I &aNearestGrid, std::optional< int > aDistToNearest, int snapRange) const
If the snap line is active, return the best snap point that is closest to the cursor.
void ClearSnapLine()
Clear the snap line origin and end points.
void SetSnapLineOrigin(const VECTOR2I &aOrigin)
The snap point is a special point that is located at the last point the cursor snapped to.
void SetSnapLineEnd(const OPT_VECTOR2I &aSnapPoint)
Set the end point of the snap line.
A SNAP_MANAGER glues together the snap line manager and construction manager., along with some other ...
SNAP_LINE_MANAGER & GetSnapLineManager()
CONSTRUCTION_MANAGER & GetConstructionManager()
const std::vector< VECTOR2I > & GetReferenceOnlyPoints() const
void SetReferenceOnlyPoints(std::vector< VECTOR2I > aPoints)
Set the reference-only points - these are points that are not snapped to, but can still be used for c...
Master controller class:
Definition: tool_manager.h:62
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:421
APP_SETTINGS_BASE * GetSettings() const
Definition: tool_manager.h:400
KIGFX::VIEW * GetView() const
Definition: tool_manager.h:391
constexpr extended_type SquaredDistance(const VECTOR2< T > &aVector) const
Compute the squared distance between two vectors.
Definition: vector2d.h:565
static constexpr extended_type ECOORD_MAX
Definition: vector2d.h:76
VECTOR2_TRAITS< int32_t >::extended_type extended_type
Definition: vector2d.h:73
Handle a list of polygons defining a copper zone.
Definition: zone.h:73
static constexpr EDA_ANGLE ANGLE_90
Definition: eda_angle.h:403
@ ARC
use RECTANGLE instead of RECT to avoid collision in a Windows header
GRID_HELPER_GRIDS
Definition: grid_helper.h:42
@ GRID_VIAS
Definition: grid_helper.h:48
@ GRID_TEXT
Definition: grid_helper.h:49
@ GRID_CURRENT
Definition: grid_helper.h:44
@ GRID_GRAPHICS
Definition: grid_helper.h:50
@ GRID_CONNECTABLE
Definition: grid_helper.h:46
@ GRID_WIRES
Definition: grid_helper.h:47
bool m_ExtensionSnapActivateOnHover
If extension snaps are enabled, 'activate' items on hover, even if not near a snap point.
bool m_EnableExtensionSnaps
Enable snap anchors based on item line extensions.
ItemType
std::variant< LINE, HALF_LINE, SEG, CIRCLE, SHAPE_ARC, BOX2I > INTERSECTABLE_GEOM
A variant type that can hold any of the supported geometry types for intersection calculations.
Definition: intersection.h:43
bool IsPcbLayer(int aLayer)
Test whether a layer is a valid layer for Pcbnew.
Definition: layer_ids.h:520
@ LAYER_AUX_ITEMS
Auxiliary items (guides, rule, etc)
Definition: layer_ids.h:223
@ LAYER_ANCHOR
anchor of items having an anchor point (texts, footprints)
Definition: layer_ids.h:202
PCB_LAYER_ID
A quick note on layer IDs:
Definition: layer_ids.h:60
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
std::vector< TYPED_POINT2I > GetOvalKeyPoints(const OVAL &aOval, OVAL_KEY_POINT_FLAGS aFlags)
Get a list of interesting points on an oval (rectangle with semicircular end caps)
Definition: oval.cpp:84
std::vector< TYPED_POINT2I > GetCircleKeyPoints(const CIRCLE &aCircle, bool aIncludeCenter)
Get key points of an CIRCLE.
@ OVAL_CAP_TIPS
Definition: oval.h:113
@ OVAL_SIDE_MIDPOINTS
Definition: oval.h:115
@ OVAL_CARDINAL_EXTREMES
Definition: oval.h:117
@ OVAL_CENTER
Definition: oval.h:112
unsigned int OVAL_KEY_POINT_FLAGS
Definition: oval.h:121
@ GEOMETRY
Position or shape has changed.
Definition: view_item.h:54
STL namespace.
VECTOR2I GetNearestPoint(const NEARABLE_GEOM &aGeom, const VECTOR2I &aPt)
Get the nearest point on a geometry to a given point.
Definition: nearest.cpp:58
std::variant< LINE, HALF_LINE, SEG, CIRCLE, SHAPE_ARC, BOX2I, VECTOR2I > NEARABLE_GEOM
A variant type that can hold any of the supported geometry types for nearest point calculations.
Definition: nearest.h:43
Class to handle a set of BOARD_ITEMs.
std::optional< VECTOR2I > OPT_VECTOR2I
Definition: seg.h:39
VECTOR2I::extended_type ecoord
Utility functions for working with shapes.
Items to be used for the construction of "virtual" anchors, for example, when snapping to a point inv...
std::vector< EDA_ITEM * > items
Definition: grid_helper.h:163
double Distance(const VECTOR2I &aP) const
Definition: grid_helper.h:165
A visitor that visits INTERSECTABLE_GEOM variant objects with another (which is held as state: m_othe...
Definition: intersection.h:53
MAGNETIC_OPTIONS tracks
MAGNETIC_OPTIONS pads
PCB_INTERSECTABLE(BOARD_ITEM *aItem, INTERSECTABLE_GEOM aSeg)
INTERSECTABLE_GEOM Geometry
This file contains data structures that are saved in the project file or project local settings file ...
bool graphics
Graphic lines, shapes, polygons.
bool footprints
Allow selecting entire footprints.
bool text
Text (free or attached to a footprint)
GRID_SETTINGS grid
Definition: app_settings.h:81
void RotatePoint(int *pX, int *pY, const EDA_ANGLE &aAngle)
Calculate the new point of coord coord pX, pY, for a rotation center 0, 0.
Definition: trigo.cpp:229
@ 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:105
@ PCB_DIM_LEADER_T
class PCB_DIM_LEADER, a leader dimension (graphic item)
Definition: typeinfo.h:102
@ PCB_VIA_T
class PCB_VIA, a via (like a track segment on a copper layer)
Definition: typeinfo.h:97
@ PCB_DIM_CENTER_T
class PCB_DIM_CENTER, a center point marking (graphic item)
Definition: typeinfo.h:103
@ PCB_GROUP_T
class PCB_GROUP, a set of BOARD_ITEMs
Definition: typeinfo.h:110
@ PCB_TEXTBOX_T
class PCB_TEXTBOX, wrapped text on a layer
Definition: typeinfo.h:93
@ PCB_ZONE_T
class ZONE, a copper pour area
Definition: typeinfo.h:107
@ PCB_TEXT_T
class PCB_TEXT, text on a layer
Definition: typeinfo.h:92
@ PCB_REFERENCE_IMAGE_T
class PCB_REFERENCE_IMAGE, bitmap on a layer
Definition: typeinfo.h:89
@ PCB_FIELD_T
class PCB_FIELD, text associated with a footprint property
Definition: typeinfo.h:90
@ PCB_MARKER_T
class PCB_MARKER, a marker used to show something
Definition: typeinfo.h:99
@ PCB_TARGET_T
class PCB_TARGET, a target (graphic item)
Definition: typeinfo.h:106
@ 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:101
@ 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:98
@ PCB_DIMENSION_T
class PCB_DIMENSION_BASE: abstract dimension meta-type
Definition: typeinfo.h:100
@ PCB_TRACE_T
class PCB_TRACK, a track segment (segment on a copper layer)
Definition: typeinfo.h:96
@ PCB_DIM_RADIAL_T
class PCB_DIM_RADIAL, a radius or diameter dimension
Definition: typeinfo.h:104
VECTOR2< int32_t > VECTOR2I
Definition: vector2d.h:691
VECTOR2< double > VECTOR2D
Definition: vector2d.h:690